AgentLink 串起多个智能体后任务卡住,先翻执行记录找断点

文章导读
多个智能体串成一条链路后卡在中间,界面只写“运行中”,最常见的处理误区是整条重跑一遍,把前面已经产出的结果冲掉。更省事的做法是先翻执行记录:按顺序找出最后一个有返回的智能体,把卡点范围缩到相邻两步之间,再判断是上游没产出、下游没接住,还是那一步在等外部返回。确认之后只重跑断点之后的那一段,前面的产物保留不动。下面四步都是可以在记录页面、日志或命令行里直接核对的,不依赖猜测。
📋 目录
  1. A 在执行记录里找出最后一个有返回的智能体
  2. B 对比相邻两步的输入和输出是否对得上
  3. C 确认卡住那一步是不是在等外部返回
  4. D 只重跑断点之后的那一段
A A

多个智能体串成一条链路后卡在中间,界面只写“运行中”,最常见的处理误区是整条重跑一遍,把前面已经产出的结果冲掉。更省事的做法是先翻执行记录:按顺序找出最后一个有返回的智能体,把卡点范围缩到相邻两步之间,再判断是上游没产出、下游没接住,还是那一步在等外部返回。确认之后只重跑断点之后的那一段,前面的产物保留不动。下面四步都是可以在记录页面、日志或命令行里直接核对的,不依赖猜测。

先不要重新提交整条流程。进入执行记录,按步骤顺序找到最后一个状态为成功、且有输出内容的步骤,把它记为断点前的最后一个成功步骤;再对比该步骤的输出字段和下一手的输入字段是否对得上。对得上但下一步仍无返回,多半是在等外部返回或超时;对不上则是交接消息缺失,可走“上游补产出”或“下游加默认值”两条修复路径。确认后再以单步或指定步骤为最小单位重跑,重跑前把前驱步骤的输出另存一份,避免覆盖已有产物。

在执行记录里找出最后一个有返回的智能体

执行记录列表通常按开始时间排序,但多智能体链路里并行分支会让时间顺序失真,建议先切到按步骤序号(或 DAG 拓扑顺序)展示,再按时间做辅助判断。看不全的时候,按条目顺序看三列就够:步骤名与所属智能体、状态、结束时间。

状态字段一般会出现这几种取值:等待调度、运行中、成功、失败、超时、跳过。要留意两点:状态为“运行中”的步骤不一定真的在跑,可能已经卡在那里很久;结束时间为空也表示没有返回。所以“最后一个有返回的智能体”= 状态成功 + 有结束时间 + 输出内容非空,三者同时满足的最后一步。

如果记录能导出成 JSON,用一条命令就能定位,不必肉眼逐行翻:

# run.json 为导出的执行记录,steps 为步骤数组
jq -r '.steps | sort_by(.step_index)
  | map(select(.status=="succeeded" and (.output_payload|length)>0))
  | last
  | {step_id, agent, step_index, started_at, finished_at}' run.json

把输出的 step_id 抄下来,它就是断点前的最后成功步骤,后续所有对比都以它为基准,不要从第一步重新核。

AgentLink 串起多个智能体后任务卡住,先翻执行记录找断点

对比相邻两步的输入和输出是否对得上

拿到最后成功步骤后,取它和下一步(就是卡住的那一步)的输入输出做对照。交接字段一般包括:上游输出中的结果字段(正文、结构化 JSON、文件路径或引用 ID)、下游输入中期望同名字段、上下文变量(会话 ID、任务 ID、上游产出的文件名)、以及失败兜底字段。逐项确认下游输入的每个必填键,在上游输出里有没有对应来源。

记录里“字段为空”和“字段缺失”是两种表现,处理方式不同:字段缺失是下游输入的 JSON 里根本没有这个键,通常表现为上游改了输出结构、字段改名,或某个分支没走;字段为空是键存在但值是 null 或空字符串,通常是上游跑了但没产出内容,比如模型返回空、检索没命中、外部接口返回空集合。用 has() 区分最直接:

jq '.steps[3].input_payload
    | {has_summary: has("summary"), summary_value: .summary}' run.json
# has_summary=false -> 字段缺失;true 且 summary_value 为 null/"" -> 字段为空

修复方向通常是两条,选哪条取决于字段该由谁负责。第一条是从上游补产出:确认上游智能体的输出模板或输出解析规则,把该字段明确写进输出结构,并在交接处加一次轻量校验(必填键不存在就让这一步直接失败,而不是把空值传给下游),代价是要重跑上游。第二条是在下游适配:在卡住那一步的输入映射里给该字段设默认值、改成选填,或加一个取兜底值的分支,好处是不动上游,风险是掩盖了上游真实的产出问题,只适合该字段确实可缺省的场景。

确认卡住那一步是不是在等外部返回

如果相邻两步的输入输出完全对得上,但下一步始终没有输出,就要区分是流程编排问题还是外部调用没回来。先看超时设置在哪一层:智能体自身配置里的单步超时、连接两个智能体之间的边或调用配置里的超时、以及整条运行(run)级别的总超时。三层都可能生效,实际拦截点通常是最先到期的那个。

AgentLink 串起多个智能体后任务卡住,先翻执行记录找断点

界面上的等待状态也有差别可看:步骤卡片一直是“运行中”、有持续的心跳或流式输出,说明还在等;步骤卡片上出现计时且计时明显超过单步超时值,说明超时配置可能没读到。日志里则表现为最后一条记录停在发出外部请求,只有 request_id 没有 response。命令行里快速筛一下:

grep -n 'request_id\|response\|timeout\|error' agentlink-run.log | tail -n 40

超时发生之后的记录形态也比较好认:状态变成超时或失败,带 error 字段,步骤耗时接近配置的超时值,输出为空。这类卡点不需要改编排,先去核对那个外部服务的可达性和凭据;如果确认要等更久,再调大对应层的超时,注意调大之后整条 run 的总超时也要一起看,否则会在别的层被截断。

只重跑断点之后的那一段

可重跑的最小单位通常是单个步骤的一次尝试(step + attempt),其次是“从某一步开始继续”(resume from step)。优先用单步重跑验证修复是否生效,确认没问题再放行后面几步,避免一次把后半段全放开又卡在同一个地方。重跑前必须留存中间结果:把断点前最后一个成功步骤的输出导出成文件,记下本次 run_id、产物路径和下游是否会写同名产物。如果下游是按固定文件名写结果,重跑前先改名或另存一份,否则新结果会盖掉旧产物,出问题就没法回看。

# 通用骨架,字段名需按自己环境的接口文档替换
POST /api/runs/{run_id}/resume
{
  "from_step": "step-04-summarize",
  "reuse_previous_outputs": true,
  "overwrite_artifacts": false
}

重跑发起后,回到执行记录确认三件事:新的一次尝试是否挂在同一个 step_id 下、前驱步骤是否被复用而没有重新执行、以及断点那一步的输入是否已经带上修复后或补默认值的字段。三项都对上,再看它是否走到下一步;如果仍在同一步停住,说明前面的字段判断还需要再核对一次,而不是继续加大重跑范围。