StaffDeck 数字员工跑到一半停了 / 先看任务日志还是模型返回?

文章导读
任务跑到一半停了,先看任务日志,不要一上来就翻模型返回。任务日志能直接告诉你是停在哪一步、上一步成功到哪,模型返回和工具调用日志都是围绕这一步去取的证据。如果先从模型返回开始看,容易在一堆正常请求里翻很久,仍不知道失败发生在哪个阶段。合理的顺序是:任务日志定位步骤,模型返回排除超时和截断,工具调用入参出参区分外部报错和参数拼装错误,最后用同一条输入做最小复现。
📋 目录
  1. 壹 先在任务记录里确认停在了哪一步
  2. 贰 把这一轮的模型请求和返回单独找出来
  3. 叁 检查工具调用这一层的入参和出参
  4. 肆 用同一条输入做最小复现
A A

任务跑到一半停了,先看任务日志,不要一上来就翻模型返回。任务日志能直接告诉你是停在哪一步、上一步成功到哪,模型返回和工具调用日志都是围绕这一步去取的证据。如果先从模型返回开始看,容易在一堆正常请求里翻很久,仍不知道失败发生在哪个阶段。合理的顺序是:任务日志定位步骤,模型返回排除超时和截断,工具调用入参出参区分外部报错和参数拼装错误,最后用同一条输入做最小复现。

建议按“任务日志 → 模型返回 → 工具调用 → 最小复现”四步走。任务日志只用来确认最后一个成功步骤和第一个失败步骤;模型返回只看失败那一步的 status、duration、finish_reason 和 error;工具调用看请求体和响应体是否成对出现。三步都指向同一处时再改配置或提工单,只看到一处异常不要直接下结论。

先在任务记录里确认停在了哪一步

进控制台的运行记录(不同版本可能叫任务历史、执行记录或 Run 列表),按时间或 run_id 找到这次运行,点进详情页的“执行轨迹”或“步骤详情”标签。页面上通常会给出每一步的状态、开始结束时间和耗时,以及失败原因。这一步的目标不是读懂全部日志,而是拿到两个锚点:最后一个 success 的步骤,和第一个非 success 的步骤。

字段含义怎么用
run_id运行实例 ID后续所有日志过滤都靠它
step_id / step_name步骤标识与名称确定停在哪个环节
statuspending / running / success / failed / skipped找第一个非 success 的步骤
started_at / ended_at步骤起止时间戳算出实际耗时,与超时配置对比
duration_ms步骤耗时接近超时阈值时优先怀疑超时
attempt重试次数有重试但都失败,说明不是单次抖动
error_code / error_message失败分类与原始报错决定下一步看模型还是看工具
trace_id / span_id链路标识用它把模型日志和工具日志串起来

如果失败步骤的 error_code 属于超时或连接类,下一步直接去看该步骤的模型请求,不用再往后翻;如果失败步骤名本身是工具调用,就跳到第三段。步骤状态里出现 running 长时间不结束,一般也先按超时处理。

StaffDeck 数字员工跑到一半停了 / 先看任务日志还是模型返回?

把这一轮的模型请求和返回单独找出来

按 run_id 和阶段过滤,把范围从“整轮对话”缩到“失败那一次模型调用”。下面命令假设日志是每行一条 JSON,字段名按你实际环境替换:

# 先看这一轮有哪些阶段
jq -r 'select(.run_id=="<run_id>") | .stage' staffdeck.log | sort | uniq -c

# 再单独取模型请求与返回
jq -c 'select(.run_id=="<run_id>" and .stage=="llm")
  | {ts, model, status, duration_ms, finish_reason, error, prompt_tokens, completion_tokens}' staffdeck.log

如果不是 JSON 日志,用 grep 先粗筛再人工看:

grep '<run_id>' staffdeck.log | grep -i 'llm\|model' | tail -n 50

要看的字段有三个:status 是正常返回、超时还是中断;duration_ms 是否贴着配置的请求超时;finish_reason 是 stop、length、tool_calls 还是空值。区分方式比较直接:duration 接近超时阈值且没有响应体,通常是请求超时;有连接重置一类的 error.type、响应体为空,通常是连接中断;finish_reason 是 length 或返回 JSON 解析不完整,多半是内容被截断,报错会出现在解析层而不是请求层。注意确认日志级别,有些部署默认只在 warning 以上才打印模型返回,需要临时调高才能看到完整响应。

StaffDeck 数字员工跑到一半停了 / 先看任务日志还是模型返回?

检查工具调用这一层的入参和出参

工具调用的日志要成对看请求和响应,只有 request 没有 response,说明请求没发出去或连接就断了;两者都有但 response 里带 error,就要看 error.code 是参数校验还是外部系统故障。日志样例:

{
  "ts": "<ts>",
  "run_id": "<run_id>",
  "step": "call_crm_query",
  "stage": "tool",
  "tool": "crm.search_customer",
  "status": "failed",
  "duration_ms": 812,
  "attempt": 1,
  "request": {"query": null, "page_size": "20"},
  "response": {"error": {"code": "INVALID_PARAM", "message": "query must be a non-empty string"}}
}

失败入参的典型形态有几种:必填字段是 null 或空字符串,往往来自上一步模型返回的 JSON 键名大小写不一致或输出被截断;类型错,数字传成字符串、布尔传成 "true";层级错,该传列表的地方传了对象;模板占位符没被替换,比如参数里还留着 {{customer_id}};枚举值超出外部系统接受范围。对应的返回片段通常分两类:4xx 加明确的 error.code,属于参数问题;5xx 或请求超时,属于外部系统或网络问题。前者回头查模型返回结构和参数拼装代码,后者查外部服务状态和凭据,不要混在一起改。

StaffDeck 数字员工跑到一半停了 / 先看任务日志还是模型返回?

用同一条输入做最小复现

复现时不要重新组织输入,直接从任务详情里复制原始用户输入和上下文参数,跳过前面已成功的步骤,只跑失败那一步。每次只改一个变量,比如只调超时、只换模型参数、只关掉某个工具,否则改了也不知道是哪一项生效。

# 仅示意,替换成实际的命令或 SDK 调用方式
INPUT='<从任务详情复制的原始输入>'
for i in 1 2 3; do
  echo "=== attempt $i ==="
  staffdeck run `--step` call_crm_query `--input` "$INPUT" `--no-cache`
  echo "--- end attempt $i ---"
done

每次重放记录这几项:失败是否落在同一个 step、error_code 是否一致、模型 duration 是否接近超时阈值、工具入参是否每次都在同一个字段出错。建议直接用一张表记,列是 attempt、失败步骤、error_code、duration_ms、finish_reason、入参差异。稳定复现基本可以按配置或参数拼装问题处理;偶尔才失败,优先怀疑超时、限流或外部系统抖动,这时去看同一时间段是否有其他 run 也在同一步失败,再决定是改配置还是先观察。