Agent Harness 有了“眼睛”和“手”:更细的 Trace 事件 + 自动错误恢复 Agent Harness 有了“眼睛”和“手”更细的 Trace 事件 自动错误恢复系列博客第三篇 · 2026-06-29从“看得清”到“自己会修”一、前情回顾前两天的成果Day 1跑通最小闭环用户输入 → 模型 → 工具 → 输出能跑了。Day 2抽离 ContextBuilder 统一管理上下文新增 Trace Report 把 JSON 变成可读的复盘报告。到了 Day 2 结束时我手上有这样一个 Agent Harness能跑—— 基础闭环完整。能复盘—— Trace Report 让我知道哪里出错了。但复盘完发现问题后还是得手动改代码、重新跑。而且 Trace 本身也不够细——我只能看到“调了哪个工具、成功还是失败”但看不到“ContextBuilder 给了模型什么信息”“用了哪个 Engine”“工具耗时多少”。所以 Day 3 的目标很明确让 Trace 更细把执行过程中的每个关键节点都记录下来。新增两个实用工具让 Agent 能搜网页、能跑 shell 命令。让系统学会自己修遇到常见错误时自动恢复而不是直接放弃。二、让 Trace 长出“骨架”context_built 和 engine_started2.1 之前的 Trace 长这样之前的事件流run_started → tool_call → tool_result → done但如果我想知道这次任务用的是哪个 EngineChat 还是 ToolContextBuilder 给模型注入了什么规则每次工具调用耗时多久成功了还是失败了抱歉JSON 里没有。2.2 本次新增的两个关键事件我往src/runtime/events.ts里加了两个新事件context_built记录 ContextBuilder 构造完上下文后的快照{type:context_built,payload:{mode:tool,workspaceRoot:C:/Users/ts/Desktop/zcy/mini-agent-harness,systemPromptLength:2048,toolWorkflowSteps:5}}engine_started记录这次执行用的是哪个 Engine、最大轮数是多少{type:engine_started,payload:{engine:DeepSeekToolEngine,maxTurns:5}}2.3 增强tool_result把关键指标抽出来以前tool_result只记录原始返回现在我会额外抽取{type:tool_result,payload:{tool:read_file,ok:false,durationMs:312,errorCode:FILE_NOT_FOUND}}这样一来Trace Report 就能直接统计工具调用总次数失败次数和失败率总耗时最常见的错误类型2.4 现在的事件流更丰满了run_started - context_built ← 新增知道模型看到了什么 - engine_started ← 新增知道用了哪个引擎 - text_delta / tool_call / tool_result / error - doneTrace Report 里也多了几个关键字段toolFailureCounttotalToolDurationMsengine2.5 一个小小的感悟Trace 事件的设计本质上是在回答一个问题如果这次执行出了岔子我需要哪些信息才能快速定位你越能精准地回答这个问题你的系统就越容易调优。很多开源框架的 Trace 做得非常重但我选择逐步加事件——每次只加当前阶段最需要的那几个保持轻量但足够用。三、给 Agent 装上两只“新手”search_web 和 run_shell之前 Agent 只有三个本地工具read_file、grep、write_file。它只能在项目文件夹里读读写写出不去。但很多时候我需要它去外面看看“搜索一下 DeepSeek MLA 是什么”“在项目里跑一下npm run check告诉我有没有类型错误”所以这次我加了两个新工具。3.1search_web让 Agent 能上网查资料实现方式很简单——通过DuckDuckGo 的 HTML 搜索不需要申请 API Key完全免费。输入搜索关键词 limit默认 5 条 输出title / url / snippet 结构化列表我在ContextBuilder的toolWorkflow里加了一条规则如果用户问题涉及实时信息或公开知识优先使用 search_web 获取参考资料。举个例子npm run dev--搜索一下 DeepSeek MLA 是什么然后总结Agent 会先调用search_web获取搜索结果再根据搜索结果生成总结。3.2run_shell让 Agent 能执行命令这个工具让 Agent 可以在workspaceRoot下执行任意 shell 命令输入shell 命令 timeout默认 30 秒 输出stdout / stderr / exitCode但 shell 命令很危险所以我在shellSafety.ts里维护了一个黑名单constBLACKLIST[rm -rf,sudo,chmod 777,dd if,mkfs,// ...];任何匹配黑名单的命令都会被拒绝执行并返回友好的错误提示。同时run_shell还有两个保护机制超时限制默认 30 秒防止命令卡死。输出大小限制最多返回 1MB防止日志爆炸。3.3 策略层同步更新TaskPolicy里新增了对 shell / web / npm / git 等关键词的识别如果用户输入包含这些词就会自动走 Tool Engine而不是 Chat Engine。四、让 Agent 学会“自己修”Error Recovery这部分是我今天最兴奋的一个改动。4.1 之前失败就失败了没有第二次机会以前工具执行失败后ToolResult里虽然有error.suggestion但能不能恢复完全看模型自己——它得读懂建议、想清楚怎么补救、再发起新调用。现实是大部分情况下模型就直接放弃了。4.2 系统级恢复失败后自动“补一刀”我新增了src/recovery/ErrorRecovery.ts它的职责很简单当工具返回okfalse且error.recoverabletrue时系统自动判断能不能帮模型“补一刀”。目前支持三种恢复场景失败场景自动恢复动作read_file/grep/write_file路径错误自动调用list_files列出目录内容list_files参数无效回退到 workspace 根目录列表TOOL_NOT_FOUND工具不存在自动调用list_files帮助重新规划4.3 恢复后的闭环恢复流程是这样的tool_result (failed) - tool_error (记录失败详情) - recovery_started (如果有恢复计划) - recovery_result (执行恢复成功或失败) - 把「原始失败信息 恢复结果」一起喂回模型模型拿到的是这样的上下文你刚才调用read_file(README2.md)失败了因为文件不存在。我帮你执行了list_files当前目录下有这些文件README.mdpackage.jsonsrc/请根据这个信息重新规划你的操作。这样模型就不用“猜”了它拿到了真实的环境信息。4.4 防止无限恢复的保险机制每次 run 最多自动恢复3 次超过就停止。同一种失败不会重复恢复比如同一路径失败两次第二次不再尝试。4.5 Trace 里的恢复记录新增了三个 Trace 事件tool_error记录工具失败详情和suggestionrecovery_started记录准备执行哪种恢复recovery_result记录恢复是否成功Trace Report 里也会新增recoveryAttemptCountrecoverySuccessCount这样一来我可以清楚地知道系统帮模型救回了多少次失败。五、一个实际的运行例子今天我用这个命令测试了一下npm run dev--在项目里运行 npm run check告诉我有没有类型错误流程是这样的TaskPolicy识别到npm run check判定为 tool 任务。ContextBuilder构造上下文注入了工具工作流规则。DeepSeekToolEngine启动调用run_shell(npm run check)。命令执行成功返回 stdout。模型根据输出告诉我“没有类型错误”。所有事件context_built、engine_started、tool_call、tool_result都记录在 trace JSON 里。我运行npm run trace:report -- runs/run_xxx.json生成复盘报告。整个过程不到 10 秒Agent 自己完成了从“理解任务”到“执行命令”到“反馈结果”的闭环。六、记录6.1 Trace 是越挖越深的一开始我只记录tool_call和tool_result已经觉得够了。但随着问题变复杂我发现需要context_built来确认模型“看到了什么”需要engine_started来确认“用了什么策略”。Trace 不是一次性设计好的它是随着你对系统理解的深入逐步生长的。6.2 让系统自己修比让模型自己悟更可靠Error Recovery 让我意识到有些失败的修复是“机械的”——路径错了就列一下目录工具不存在就看一看可用清单。这些逻辑用代码写死比等模型“读懂 suggestion”要可靠得多、快得多。这就像开车你可以让司机自己看路牌找路模型读 suggestion也可以直接给导航系统自动恢复。导航更稳。6.3 工具不是越多越好而是越“安全”越好新增run_shell的时候我花了一半时间在写黑名单、超时、输出限制。一个工具如果会炸掉系统那它再强大也等于零。安全是工具的第一性。