← AI Agent

Agent 的 Run / Step 运行记录表怎么设计?

中等 运行记录与可观测 · 第 2 / 2 问 更新于 2026/09/29
AI Agent可观测性运行记录数据库设计时间线
本题落地项目AI Agent旅游行程智能规划平台

简化版

用两张表:Run 表一次执行一行,记这次执行的身份(唯一编号、属于哪个业务对象、谁发起的)、状态(运行中 / 已完成 / 失败)、进度(当前第几步、共几步)、输入快照、输出摘要、失败原因和耗时;Step 表每一步一行,记属于哪次运行、第几步、给人看的步骤名、调了哪个工具、入参、返回、状态、错误和耗时。写入时机很关键:Run 在执行开始时就插一条「运行中」,失败也要回写状态和原因;Step 在工具执行前先插一条「运行中」拿到 ID,执行完再回填结果,这样执行卡住或中断时也能看到停在哪一步。大字段要截断,完整报文可以放到按工具组织的调用日志里,两边用运行 ID 和步骤 ID 对上。

详细版

agent_run(一次执行一行)
  id / run_no(唯一,可读)/ 业务对象 ID / user_id / run_type
  status:运行中 → 已完成 / 运行失败
  current_step / total_step          进度
  input_snapshot / output_summary    输入快照、输出摘要
  error_message(截断)/ start_time / end_time / cost_millis

agent_step(每一步一行)
  id / run_id / step_index(第几步)/ step_name(给人看)
  tool_code / request_params / response_result(截断)
  status:运行中 → 已完成 / 运行失败
  error_message / cost_millis / create_time
设计点做法目的
先插后回填Step 执行前插「运行中」,执行后更新卡住、中断时能看到停在哪一步
失败也落库Run、Step 在异常分支里都回写状态和原因失败的运行才是最需要排查的
关联业务产物产物落库后把产物 ID 回填到 Run从结果能查到过程,从过程能查到结果
输入快照把本次执行依赖的输入序列化存下数据后来变了,也能复现当时的条件
大字段截断入参、返回、错误各有长度上限避免单行过大拖慢查询
与调用日志分工步骤记摘要看流程,工具日志记全文看细节各自按最常用的维度组织

完整版教学

一、为什么要单独记运行过程

Agent 的步骤由模型临场决定,同一个输入跑两次,调用的工具和次数都可能不同。只存最终结果,出了问题只能看着一个不满意的答案猜原因:是模型没去查,还是查到的数据不对,还是查对了但结论写错了?

把每次执行和每一步都落库之后,这些问题都能回答:

这次调了哪些工具、按什么顺序        → Step 按序号排列
每一步传了什么、拿到了什么          → Step 的入参和返回
卡在哪一步、为什么失败              → 状态为「运行中」或「失败」的那一步
整体花了多久、成功率多少            → Run 的状态和耗时聚合

所以运行记录不是可有可无的日志,它是自主决策的 Agent 能被排查、被信任的前提。有了这些记录之后怎么评估和监控 Agent,见「如何评估和监控 AI Agent?为什么不能只看最终答案?」。

二、Run 表:一次执行的身份证

Run 表的字段可以按「谁、什么、怎么样」分组:

分组字段说明
身份主键、运行编号编号要唯一且人能读,如「前缀 + 时间 + 业务 ID」
归属业务对象 ID、发起人、运行类型按业务对象和发起人查询、做权限过滤
状态运行中 / 已完成 / 运行失败三态足以覆盖同步执行;有中断恢复时再加「已中断」等
进度当前步数、总步数运行中也能显示「3 / 5」
输入输出输入快照、输出摘要快照存执行时依赖的条件;摘要不点进详情也能看懂结果
失败错误信息写库前截断,给出能照着处理的中文原因
时间开始、结束、耗时统计平均耗时、找慢运行

输入快照值得单独说:Agent 执行时依赖的数据(候选资源、用户偏好、配置阈值)以后可能被修改,只存 ID 的话,过一个月就没法知道当时模型看到的是什么。把执行那一刻的关键输入序列化存下,复盘时才能还原条件。

三、Step 表:每一步的回放材料

Step 表最重要的是能按顺序还原过程,几个字段各有讲究:

step_index   第几步,同一次运行内连续递增;时间线按它排序,而不是按时间排序
step_name    给人看的中文名(如「按偏好查询点位」)
tool_code    代码里的工具编码,能对上源码和工具日志
request_params / response_result   模型传的参数、工具返回给模型的内容(即 Observation)

中文名和编码都要存:中文让人一眼看懂,编码让人对得上代码。最后如果模型给出了最终结论,也可以补一条「最终结论」步骤,工具编码留空,这样时间线从第一步读到最后一步就是完整的执行过程。

四、写入时机:先插后回填

步骤记录有两种写法:执行完一次性插入,或者执行前先插「运行中」、执行后回填。推荐后者:

执行前:INSERT step(status=运行中, request_params=…)  → 拿到 step_id
执行中:工具调用、写工具日志时带上 run_id + step_id
执行后:UPDATE step SET status=已完成/运行失败, response_result=…, cost=…
        同时推进 run.current_step

先插的好处有三个:执行卡住或进程被杀时,库里能看到有一步停在「运行中」;工具日志能拿到步骤 ID,两张表可以一一对应;页面轮询时能实时看到「正在调用某某工具」。无论成功失败都要回填,失败时写上错误原因。

记忆钩子:步骤先占位、后填空;失败也要填完再走。

五、多轮、多版本怎么组织

有外层循环的 Agent(比如排完一版不合格再排一版),一次执行里会有好几版。组织方式有两种:每一版一条 Run,或者一次执行一条 Run、步骤上带版次号。后者更常见:

agent_run:1 条(这次执行)
agent_step:round_no = 1 的 60 步,round_no = 2 的 45 步 ……
step_index 在整次执行里连续编号:第 2 版的第一步是第 61 步

版次号让时间线能按版分组,连续编号让整次执行读下来不断档。Run 上可以再记当前在跑第几版、最终跑了几版。

六、大字段与调用日志的分工

入参和返回可能很大,工具返回几百条候选时一次就是几万字。用一组示意上限估算存储:

一次执行最多 180 步,入参上限 2000 字、返回上限 20000 字
最坏情况:180 × (2000 + 20000) = 3,960,000 字 ≈ 一次执行约 400 万字

所以要截断,而且要分清步骤表和工具调用日志的用途:步骤表按运行、版次组织,给时间线看流程,可以只存摘要或截断后的内容;工具调用日志按工具组织,给工具统计和排查细节,存完整报文。两边通过运行 ID 和步骤 ID 对上。

七、查询和权限

运行记录里常常带着用户的原始输入和内部检索结果,查询时要做权限控制:普通用户只能看自己发起的运行,或者整个执行记录只对管理员开放。前端轮询进度时,只取数字和最近一步即可,不要每两秒把几百步的完整报文重新拉一遍。按运行查步骤、按业务对象查运行、按状态筛失败的运行,这几个最常用的查询都要有索引。

八、常见误区与追问

  • 误区:只存最终结果就够了。 自主决策的过程每次不同,不记步骤就没法排查是查错了还是写错了。
  • 误区:步骤执行完再一次性插入。 卡住或中断时库里什么都没有,也没法让工具日志关联到步骤。
  • 误区:失败的运行没价值,可以不记。 失败的运行正是最需要排查的,要写明停在哪一步、什么原因。
  • 误区:入参返回原样全存。 大报文会让表迅速膨胀,步骤表截断存摘要,完整内容交给调用日志。
  • 误区:多版本就建多条 Run。 一次执行一条 Run、步骤带版次号更便于把整次执行串起来看。
  • 追问:时间线按什么排序? 按步骤序号,不按时间;一次运行几秒钟跑完,时间戳几乎一样。
  • 追问:为什么要存输入快照? 执行依赖的数据会被修改,只存 ID 没法还原当时模型看到的条件。

九、加强记忆

Run / Step 记「一次一行、一步一行、先占位后填空」:Run 表记身份(唯一可读编号)、归属(业务对象、发起人)、三态状态、进度、输入快照、输出摘要、截断后的错误和耗时,产物落库后回填产物 ID。Step 表记第几步(连续编号、时间线按它排)、中文名加工具编码、入参和返回、状态、错误、耗时,最终结论也可以补一步。写入先插「运行中」再回填,失败也回填。多版本用一条 Run 加步骤上的版次号,大字段截断、完整报文交给按工具组织的调用日志,两边用运行 ID 和步骤 ID 对齐。

项目实战落地

项目里怎么做的

《AI Agent旅游行程智能规划平台》一次「开始规划」可能排好几版行程,运行记录这样组织:

  • 一次执行一条 agent_run:运行编号是「TR + 14 位时间 + 横杠 + 行程单 ID」,唯一;带行程单、发起人、运行类型(行程编排);current_round 记当前在排第几版,total_round 建记录时写轮次上限、收尾时改成实际跑过的版数;input_snapshot 存候选池快照(各类数量与每城、每段的 ID 清单);错误信息截到 500 字以内;
  • 步骤跨版连续编号:agent_step 带 round_no 区分是第几版的步骤,step_index 在整次执行里连续往后排,时间线读下来就是完整的执行过程;
  • 截断:步骤记录里的入参截到 2000 字以内,工具返回截到 20000 字以内再入库,交给模型的返回不截断;
  • 两张表两个用途:每次工具调用同时写一条 agent_step 和一条 tool_call_log,前者按运行、版次组织给执行过程页的时间线,后者按工具组织给工具调用日志页和看板。

《AI Agent 智慧医院智能导诊就诊系统》的步骤是「先插后回填」:工具执行器在执行前插一条「运行中」的 agent_step 拿回主键,带着运行 ID 和步骤 ID 进工具执行入口写调用日志,执行完回填返回、状态和耗时并推进运行的当前步数;循环结束后补一条「Final Answer」步骤;分诊结果落库后把结果 ID 回填到 agent_run.task_id;执行时间线只对管理员开放。

《AI 多Agent智能相亲交友匹配平台》是多个角色写同一条运行记录:一次匹配一条 agent_run(运行类型「匹配编排」),agent_step 用 step_type 分出三种步骤:

步骤类型谁写记什么
调度红娘主管派谁、给的交代、主管的理由;入参存的是这一轮主管看到的进展文本
工具调用子角色的执行器工具编码、入参、返回、状态与耗时
角色结论子角色的执行器这个角色这一轮的结论,主管下一轮拼进展时读的就是这一条

一次运行实际调度了几轮不放在内存变量里,而是数这条运行下「调度」步骤的条数:进程重启之后再看这条记录,数出来的还是真实的轮次。

为什么这样取舍

  • 一次执行一条运行记录:各版的步骤靠 round_no 区分、序号连续,整次执行的过程在一条时间线上读完。
  • 时间线只对管理员开放:执行过程里带着患者主诉和内部检索结果,医生和患者账号即使拿到地址也读不到。

面试官还会追问

  • 运行摘要 output_summary 是怎么拼出来的?里面哪些内容来自代码、哪些来自模型?
  • 运营看板的「反思轮次分布」为什么只统计运行状态为「已完成」的记录?

学完《AI Agent旅游行程智能规划平台》,上面这些追问你都会迎刃而解。

本题落地项目地狱锤炼AI Agent旅游行程智能规划平台基于 SpringBoot + LangChain4j、攻略知识库 RAG、MySQL 向量检索、Function Calling 与数据库驱动工具中心,实现候选池预热与工具收窄、多城联游行程编排、14 条代码硬校验驱动的反思重排、教训记忆与多版本对比、三道闸防空转、编排前探活、预算测算和 Agent 执行时间线,覆盖从需求识别到行程交付的完整闭环。SpringbootLangChain4JAgentRAGFunction Calling源码+SQL喂饭学习教程配套面试文档环境安装文档项目运行文档 学习这个项目 也可以学AI Agent 智慧医院智能导诊就诊系统地狱锤炼 查看项目 也可以学AI 多Agent智能相亲交友匹配平台地狱锤炼 查看项目