跳到主要内容
《Agent Runtime 工程化》一个 Agent Runtime 失败案例的完整 Trace | 极客日志
编程语言 Agent Runtime Eval Observability Trace 事故复盘
《Agent Runtime 工程化》一个 Agent Runtime 失败案例的完整 Trace 一个 Agent Runtime 失败案例的完整 Trace Agent 出问题后,最没用的一句话是: 它可能是真的。 但它不能指导修复。 如果你只剩聊天记录,确实很容易把问题归到模型身上。模型说它修好了,用户说没修好,日志里只有几段自然语
一个 Agent Runtime 失败案例的完整 Trace
Agent 出问题后,最没用的一句话是:
模型不稳定。
它可能是真的。
但它不能指导修复。
如果你只剩聊天记录,确实很容易把问题归到模型身上。模型说它修好了,用户说没修好,日志里只有几段自然语言。最后大家换模型、改 prompt、再试几次。
这不是工程。
工程要能定位:
是模型判断错?
是工具失败?
是权限拒绝?
是上下文没带对?
是 checkpoint 状态错?
是 Runtime 顺序错?
下面写一个完整失败案例。
不是为了编故事。
是为了说明 trace 应该怎么用。
事故:Agent 说修好了,但测试仍然失败
用户任务:
修复 math.ts 里的 add 函数,让 npm test 通过。
项目里有两个文件:
src/math.ts
src/math.test.ts
math.ts 里有 bug:
export function add (a : number , b : number ): number {
return a - b;
}
测试文件里还有一个隐藏约束:
import { add } from "./math" ;
test ("add supports positive numbers" , () => {
expect (add (1 , 2 )).toBe (3 );
});
test ("add keeps number return type" , () => {
expect (typeof add (1 , 2 )).toBe ("number" );
});
Agent 执行后回答:
修复完成,add 已改为加法。
Trace Summary runId: run_repair_20260816_001
traceId: trace_repair_20260816_001
status: failed
stopReason: tool_error
steps: 4
| Step | Tool | Status | Permission | Evidence |
| --- | --- | --- | --- | --- |
| 1 | list_files | ok | allow | README.md package.json src/... |
| 1 | read_file | ok | allow | src/math.ts return a - b |
| 2 | write_text | ok | allow | wrote src/math.ts |
| 3 | shell_readonly | error | allow | npm test exitCode=1 |
Step 1:Context Builder 没带测试文件 {
"name" : "context.build" ,
"status" : "ok" ,
"attributes" : {
"step" : 1 ,
"context.budget" : 2800 ,
"context.used" : 2410 ,
"context.included_files" : [ "README.md" , "package.json" ] ,
"context.dropped_items" : [ ] ,
"context.debug_report" : "context-step-1.json"
}
}
用户要求修复测试失败,但上下文里只带了 README 和 package.json。没有 src/math.ts,也没有 src/math.test.ts。
{
"name" : "model.complete" ,
"status" : "ok" ,
"attributes" : {
"responseKind" : "tool_calls" ,
"toolCallCount" : 2
}
}
[
{ "name" : "list_files" , "input" : { "path" : "." , "depth" : 3 } } ,
{ "name" : "read_file" , "input" : { "path" : "src/math.ts" } }
]
Step 2:模型直接写了源码 {
"name" : "permission.review" ,
"status" : "ok" ,
"attributes" : {
"toolName" : "write_text" ,
"action" : "allow" ,
"risk" : "write" ,
"reason" : "命令行显式开启 --allow-writes。"
}
}
{
"toolName" : "write_text" ,
"status" : "ok" ,
"metadata" : {
"durationMs" : 14 ,
"outputChars" : 58 ,
"truncated" : false ,
"sideEffects" : [
{
"type" : "write_file" ,
"relativePath" : "src/math.ts"
}
]
}
}
写入前走了 PermissionGate。
写入结果记录了 sideEffects。
但它没阻止模型在没有读取测试文件的情况下直接修改源码。
但至少 trace 要让你看见:模型只读了源码,没有读测试。
Step 3:npm test 失败 {
"name" : "tool.execute" ,
"status" : "error" ,
"attributes" : {
"toolName" : "shell_readonly" ,
"risk" : "shell" ,
"command" : "npm test" ,
"exit_code" : 1 ,
"output.truncated" : false
}
}
command: npm test
status: error
exitCode: 1
stdout:
FAIL src/math.test.ts
add keeps number return type
Expected: "number"
Received: "bigint"
Agent 把 add 改成了 BigInt 版本:
export function add (a : number , b : number ): number {
return BigInt (a) + BigInt (b) as unknown as number ;
}
Step 4:模型给了错误总结 {
"kind" : "final" ,
"text" : "已修复 add 函数。测试失败与 BigInt 类型断言有关,后续可以调整测试。"
}
对'修复测试'这类任务,如果 npm test 失败,final 不应该被当成成功完成。
直接失败点:npm test exitCode=1。
根因 1:Context Builder 没优先带同名测试文件。
根因 2:Runtime 没有把 command failed 作为验收失败门禁。
事故归因表 维度 结论 证据 模型 过度泛化,未继续修复失败测试 final 出现在 npm test failed 后 工具 shell 工具正常返回失败 tool.execute status=error, exitCode=1权限 写入经过批准 permission.review action=allow上下文 未包含测试文件 context.included_files 不含 src/math.test.tsRuntime 缺少验收门禁 command failed 后仍允许 final 成功 Checkpoint 有文件 side effect write_text sideEffects 记录
修复方案 1:Context Builder 优先带相邻测试 Context Builder 应提高测试文件优先级。
如果读取 src/foo.ts,同时存在 src/foo.test.ts / test/foo.test.ts:
下一轮 context 优先包含测试文件片段。
{
"included" : [ "src/math.ts" , "src/math.test.ts" ] ,
"reasons" : {
"src/math.test.ts" : "linked test file for src/math.ts and user goal mentions test"
}
}
修复方案 2:失败命令阻止成功 final 如果用户目标是'让测试通过',最近一次测试命令失败,Runtime 可以要求模型继续修复或明确失败。
如果 goal includes test/pass/fix
且最近 shell_readonly(command="npm test") exitCode != 0
则 final answer 不得标记为 completed
stopReason = validation_failed
而是不能把 run 状态标成 completed。
我修改了 src/math.ts,但 npm test 仍失败。失败点是 src/math.test.ts 的 return type 断言。
当前 run 未完成。建议继续读取测试文件并修复实现。
修复方案 3:把事故转成 Eval {
"id" : "repair-math-test-001" ,
"title" : "repair add and verify tests" ,
"scenario" : "repair" ,
"userGoal" : "修复失败测试,让 npm test 通过。" ,
"expected" : {
"requiredTools" : [ "read_file" , "write_text" , "shell_readonly" ] ,
"mustReadFiles" : [ "src/math.ts" , "src/math.test.ts" ] ,
"commandsPass" : [ "npm test" ] ,
"forbiddenTools" : [ "network" ] ,
"maxSteps" : 8
}
}
是否读了测试文件
是否跑了 npm test
npm test 是否通过
是否没有联网
是否没有修改无关文件
Trace 设计要避免两个坑 不要把完整 prompt、完整文件、完整 stdout、secret、cookie 全塞进 trace。大内容用 artifact ref。敏感内容脱敏。
第二个坑:trace 只有最终日志,没有 span。
context.build
model.complete
permission.review
tool.execute
checkpoint.save
一份好的失败复盘模板 用户目标:
修复 math.ts,让 npm test 通过。
执行路径:
读目录 -> 读 src/math.ts -> 写 src/math.ts -> 跑 npm test -> final。
失败点:
tool.execute(shell_readonly npm test) exitCode=1。
根因:
Context Builder 未包含同名测试文件;Runtime 未阻止失败测试后的成功 final。
回归方案:
新增 eval repair-math-test-001,断言必须读取测试文件、npm test 通过、最终状态 completed。
每次事故都这么写,团队会越来越清楚 Runtime 的薄弱点。
结论 它的价值是把一句'模型不稳定',拆成可定位、可修复、可回归的工程问题。
如果 trace 只能证明'模型说了什么',那它还不够。
模型看见了什么
模型计划了什么
Runtime 允许了什么
工具实际做了什么
失败发生在哪里
下次怎么防住
推荐阅读 相关免费在线工具 数学计算器 计算数学表达式的计算器。您可以使用sqrt、cos、sin、abs等函数。 在线工具,数学计算器在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
JSON 压缩 通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online