第 06 章 · 读日志比换模型重要
本篇目标:出问题时先有证据,再有结论。 原文那句「出问题时先看日志,别急着甩锅给模型」,是有严格工程含义的。
6.1 为什么日志能定责
官方 官网:模型看到的一切都进 append-only 会话日志,包括系统提示词、思维链、工具调用与结果、子 Agent 调度、以及每一次上下文注入;Trajectory 视图可按来源查看;resume / fork / search / replay 共享同一份事件流。
于是「模型为什么这么说」不再需要猜。你能逐项核对:
| 检查项 | 在日志里找什么 | 能定什么责 |
|---|---|---|
| 系统提示词 | system/message 的 sections 与全文 |
规则有没有被拼进去、有没有互相打架 |
| 工具 schema | step-admitted tool schemas |
描述是否有歧义、参数是否自相矛盾 |
| 上下文注入 | request/context |
有没有注入了它不该看到 / 没注入它该看到的 |
| 工具结果 | tool/result |
是不是工具返回了截断、报错、或误导性输出 |
| 失败尝试 | assistant/attempt(reason: cancelled / retried / stream-error) |
重试是否吞掉了关键信号 |
| 压缩 | compaction 记录 | 关键约束有没有被压掉 |
| 模型选择 | AssembleContext.modelSelection 快照 |
是不是中途换了模型 / effort |
官方 架构文档补充:重试会保留 model selection 快照,不重复 assembly 与 agent/pre-step;每次 attempt 会刷新运行时事实、重新协调 prompt、冻结请求。所以「同一轮里前后行为不一致」往往不是模型抽风,是 attempt 之间运行时事实变了。
6.2 二分法:模型问题还是环境问题
原文 给出一条极干净的判别路径,用极简模式当对照组:
同一题面、同一模型
├─ 极简模式能做对,标准模式做不对 → 环境有问题
│ └─ 候选:工具 schema 歧义 / 提示词互相冲突 / 上下文被压缩策略搞乱
│ / 上下文注入污染 / 权限预设拦了关键操作 / 插件副作用
└─ 极简模式也做不对 → 模型能力问题(或题面本身有问题)
推断 补一个更严的第三组:把 PTC 也拉进来。若极简对、标准错、PTC 对,说明问题集中在多轮中间结果回灌造成的上下文污染,而不是工具本身。
判据 8(定责):任何「模型不行」的结论,必须附带一次极简模式对照。没有对照组的判断是猜测。
6.3 故障定位决策表
| 症状 | 先查 | 高频根因 | 修复 |
|---|---|---|---|
| 模型反复读同一个文件 | tool/call 序列 |
停止条件缺失 / inbox 重复投递 | 加 max_steps;检查 agent/turn-stopping |
| 明明写了「只读」,还是改了文件 | system/message + 权限预设 |
把约束写成建议而非强制 | 迁到 PreToolUse hook / 沙箱(第 08 章) |
| 长任务后半段开始胡说 | compaction 记录 + request/context |
关键规则被压缩掉 | 把规则做成 hook 或常驻 section |
| 工具调用参数格式总错 | step-admitted schema | 描述歧义、枚举没写全、示例缺失 | 收窄 schema + 给 one-shot 示例 |
| 同一题面两次结果不同 | temperature / effort / modelSelection |
采样温度非 0 / 中途换模型 | 执行型任务固定 temperature=0 |
| 突然提到一个没给过的文件名 | request/context 注入来源 |
插件注入了幽灵上下文 | 按来源关插件,二分定位 |
| 工具返回成功但结果不对 | tool/result 原始字节 |
输出被截断 / 只回传了摘要 | 调大返回上限或落盘再读 |
| 换了模型立刻变好 | — | 别急着庆祝 | 先跑极简对照,可能是新模型对坏 Harness 更鲁棒 |
| 定时任务没执行 | 宿主行为 + 时区 | 宿主关闭期间调度停止 | 见 6.5 |
| 子 Agent 说没有定时工具 | 委派行 deny 列表 | schedule_* 已被 deny 原文 |
由主 Agent 统一调度 |
6.4 「信息对等」复盘法
社区 遇到 Agent 犯一个「人绝不会犯」的错,按固定三问复盘:
- 这条信息当时在日志里吗? 不在 → 是 Harness 的洞,去补注入 / 文档 / Skill(第 03 章判据 5)。
- 在日志里,但被别的内容淹了吗? 是 → 上下文预算问题,去第 09、10 章。
- 在日志里且清晰,模型仍选错? 才是模型能力问题,或该把这条规则升级成确定性约束。
社区 Addy Osmani 的表述可以直接贴在墙上:AGENTS.md 的每一行都应能追溯到一次具体的失败。反过来用也成立:每一次失败都应产出一行可追溯的规则。第 07 章讲这套 ratchet。
6.5 定时任务的宿主边界(高频踩坑)
原文 整理如下,全部属于「不是 bug,是设计」:
| 场景 | 行为 |
|---|---|
| 宿主运行期间到期 | 恢复原 Session 并排入 follow-up,不打断当前工作 |
| 宿主重启后 | 补投逾期的一次性提醒,或每条重复任务最近错过的一次 |
| 宿主关闭 | 调度停止,直到宿主再次启动 |
| 同一 Session 多个到期任务 | 可共用一条消息投递 |
| 投递语义 | 不保证恰好一次(收件箱持久化、任务写入失败、已投递但未记入发送记录都可能导致重复) |
工程结论 原文:对精确性要求高的场景(对外通知、发消息、扣款),把自动化任务当触发器,在指令里让 Agent 先检查再执行——例如「先确认今天这份简报是不是已经写过了」。唯一性必须由业务逻辑保证,不能由调度器保证。
时区必须显式写 IANA(如 Asia/Shanghai),别依赖浏览器上报;原文 夏令时规则:不存在的每日本地时间直接跳过,重叠时间取当天较早一次,绝对时间遇到不存在的本地时间直接拒绝。
子 Agent 看不见定时任务:委派行已 deny schedule_create / schedule_list / schedule_update / schedule_delete。派活时别把「设个定时」交给子 Agent。
6.6 本章产出与验收
核心产出:一份真实故障复盘,含 Trajectory 截图、根因归类、修复前后对照、以及一条新增的规则与其测试。
验收点:
- 能从日志重建任意一次模型请求的完整输入
- 能说出
assistant/attempt为何不进模型历史 - 面对一次失败,能先跑极简对照再下结论
- 能解释「投递不保证恰好一次」对业务设计的约束
- 能列出 3 条自己项目里「人知道、Agent 不知道」的信息
延伸阅读
| 来源 | URL | 等级 |
|---|---|---|
| 官网 · 每一次运行都有迹可循 | https://www.deepseek.com/harness/zh/ | 官方 |
| 架构 · Session log / Turn flow | https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/architecture.md | 官方 |
| 官方文档 · Trajectory / 会话查询 | https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/session-query | 官方 |
| 官方文档 · 上下文压缩 | https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/compaction | 官方 |
| 官方文档 · 定时提醒 | https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/schedule | 官方 |
| 官方文档 · 会话内提醒(用户向) | https://deepseek-harness.github.io/deepseek-harness/guide/schedule | 官方 |
| Addy Osmani, Agent Harness Engineering | https://addyosmani.com/blog/agent-harness-engineering/ | 社区 |