任务失败后直接重跑,多数情况下只是把同一个失败再复现一次。更省时间的做法是先打开运行记录(trace、执行日志或步骤列表),找到最后一次成功的步骤和它的产物,再抄下失败步骤实际收到的输入,把原因归到「缺输入」「工具报错」「判断偏差」三类中的一类,最后只改一处再重跑对比。改提示词、改流程、补数据这三件事成本差别很大,定位不到步骤就无从选择。
任务失败后不要先改提示词。建议先做三件事:在运行记录里找到最后一次成功步骤及其产物,抄下失败步骤实际收到的入参快照,再按缺输入、工具报错、判断偏差归类。判断依据是日志里能看到的字段、返回状态和异常信息,不是猜测。确认类别后只改一个变量重跑,用同一现象是否消失来验证。边界:当日志被截断、步骤并行执行或中间产物被覆盖时,定位结论只能算初步判断,需要结合运行时的配置再确认。
在运行记录里定位最后一次成功的步骤
打开运行记录后,先按状态筛出成功记录的最后一条,再取它相邻的那条失败记录。两次记录之间的步骤名、时间戳和参数,是把失败范围缩小到相邻两步之间的依据——失败通常发生在「上一步的产物」被下一步引用的时候。
需要确认两件事:成功步骤产出了什么(一段文本、结构化 JSON、文件路径、工具返回体),以及下一步是怎么引用它的(变量名、字段路径、文件位置、字符串拼接)。如果被引用的是一个空变量或已经不存在的路径,问题多半出在衔接口,不在模型本身。
# 只做定位用:先找最后一条成功,再找它后面的第一条失败
# 字段名按你所用框架的日志格式替换
grep -n '"status": *"ok"' run.log | tail -n 1
grep -n '"status": *"error"' run.log | head -n 1
# 有步骤名时,直接看末尾若干条记录锁定相邻两步
grep -n 'step' run.log | tail -n 20
把定位结果填成一张表,后面的判断都对着这张表做,避免边猜边改。
| 最后成功步骤 | 失败步骤 | 失败步骤实际收到的输入 | 现象 | 疑似类别 | 最小修正动作 |
|---|---|---|---|---|---|
| extract_faq | summarize | source_text 为空字符串 | 摘要步骤直接报错退出 | 缺输入 | 补上 source_text 的字段传递 |
| fetch_page | parse | url 正常,工具返回超时错误 | 解析函数拿不到页面内容 | 工具报错 | 对工具返回值加失败分支或重试上限 |
| classify | reply | category 字段被写成自造标签 | 匹配不到任何一条回复模板 | 判断偏差 | 在提示词里固定可选标签集合 |
表格不必一次填满。先填「最后成功步骤」「失败步骤」「现象」三列,等核对完输入内容再补后两列。
抄下失败步骤实际收到的输入
这一步的关键是区分「你以为它收到的」和「它实际收到的」。运行记录里通常能看到该步骤的入参快照,把它原样复制出来,和你在上一步定义的预期输入逐字段对比,不要只看结论性描述。
- 原始输入内容:整段复制,不要只挑看起来可疑的部分。
- 缺失字段:字段不存在、值为空串、值为 null,这三者在很多框架里的处理方式不同,需要分开记录。
- 差异点:字段名大小写、嵌套层级、类型(数字还是字符串)、编码、换行与转义。
{
"step": "summarize",
"input": {
"source_text": "",
"target_lang": "zh",
"max_words": 300
}
}
在步骤入口加一段输入校验,能让一部分失败提前暴露,而不是等模型输出完才发现。下面是通用骨架,字段名和异常类型按你的技术栈替换。
required = ['source_text', 'target_lang']
missing = [k for k in required if not payload.get(k)]
if missing:
raise ValueError('缺字段: %s' % missing) # 让失败点前移到步骤入口
如果校验通过、输入齐全,结果仍然不对,问题更可能落在工具返回值或模型判断上,进入下一步分类。
区分三类失败:缺输入、工具报错、判断偏差
三类的修正方向完全不同,混在一起改,容易把一个本来能跑通的步骤改坏。
- 缺输入:典型现象是空指针、字段不存在、模板渲染出空内容、模型回答「没有提供相关资料」。确认类别的证据是入参快照里字段为空或缺失,同时工具调用记录正常。
- 工具报错:典型现象是超时、返回 401/403/404、返回体结构不符合预期、连接被重置。确认证据是工具调用记录里有非 2xx 状态、异常堆栈,或返回体里带错误字段。这类问题改提示词通常无效。
- 判断偏差:典型现象是输入完整、工具正常,但模型选错选项、漏掉必需字段、把标签写成自造值。确认证据是输入输出都在,只是输出不符合约定格式或业务规则。
三类失败的对应修正动作清单,建议按这个顺序试:
- 缺输入:修字段传递、补默认值、在步骤入口加必填校验,让同类问题下次在前端暴露。
- 工具报错:补重试与超时上限、处理非 2xx 分支、把工具错误转成明确的失败状态,而不是带着错误返回体继续往下走。
- 判断偏差:收紧提示词里的输出约束(固定可选标签、给出字段示例、要求先输出判断依据再给结果),必要时在代码侧再做一次格式校验。
如果日志被截断、步骤并行执行,或者中间产物被后续步骤覆盖,类别判断只能算初步结论,需要结合当时的配置再确认。
按类别写一条最小修正动作并重跑
一次只改一个变量,重跑结果才有可比性。改两处以上,即使跑通了也不知道哪一处起了作用;没跑通也说不清是哪一处还在拦着。
最小修正动作建议写成一句可核查的话,连同重跑结果一起记录,例如:
改动内容: 在 summarize 步骤前补上 source_text 的传递(上一步产物字段名由 text 改为 source_text)
重跑结果: 该步骤不再报错,输出内容不再为空
是否解决原失败现象: 是。空字段现象消失,未出现新的报错
重跑后按三种情况处理:原现象消失,说明定位正确,可以把这条修正固化到流程或校验里;现象变成另一个,说明还有第二个变量在起作用,回到运行记录重新定位;现象完全相同,说明改动没有落到失败步骤的输入上,需要检查改动是否真的生效——配置是否被加载、是否还走着旧分支、产物是否被复用。
整个排查过程需要保留的产物其实只有三样:最后一次成功步骤的记录、失败步骤的入参快照、这一次的修正说明。同类失败再次出现时,直接和这三样比对,比从头重跑更快,也更容易判断该改提示词、改流程还是补数据。