第 03 章 · 解剖学:六个要素与事件流
本篇目标:能从一个会话日志,完整重建模型当时看到的每一次请求。 这一章决定你是「用 Agent 的人」还是「能修 Agent 的人」。
3.1 为什么日志不是聊天记录
第 02 章的 messages 是一个数组。它在进程里够用,但有三个致命缺陷:
| 缺陷 | 后果 |
|---|---|
| 进程崩溃即丢失 | 无法复盘,无法续跑 |
| 只存最终态 | 看不到「系统提示词当时到底拼了什么」 |
| 无法分叉 | 不能从第三步另开一条分支试不同方案 |
官方 DSH 的做法是把会话建模成 append-only 事件日志,而不是消息数组。官网原句:
模型看到的一切都会写入仅追加设计的会话日志,包括系统提示词、思维链、工具调用与结果、子 Agent 调度,以及每一次上下文注入。恢复、分叉、检索与回放也共享同一份事件流。
docs/architecture.md 里有一条极强的工程不变量:
"Model-visible means logged." —— 每一次模型请求都必须能从日志重建。新增任何模型可见的输入,都必须新增会话事件。
这句话是本章的核心。它意味着:日志不是观测的副产品,日志是上下文的唯一真相来源。模型看到的消息由 deriveMessages() 从日志投影出来,而不是另外维护一份。
3.2 一个最小事件流样例
官方 DSH 的 durable 事件包括 turn/*、step/*、system/message、user/message、assistant/message、assistant/attempt、tool/*。下面是概念化 JSONL(字段名用于说明结构,实际 schema 以 reference/persistence-catalog.md 为准):
{"t":0,"type":"session/created","session_id":"s-9f2","workspace":"/repo"}
{"t":1,"type":"turn/start","turn_id":"t-1","model_selection":"deepseek-v4-pro"}
{"t":2,"type":"system/message","sections":["identity","tool_schemas","workspace","clock"],"text":"..."}
{"t":3,"type":"user/message","text":"重构登录模块,先跑测试建基线"}
{"t":4,"type":"step/start","step_id":"st-1","admitted_tools":["bash","read_file","edit","plan"]}
{"t":5,"type":"request/header","reason":"series","model":"deepseek-v4-pro","effort":"high"}
{"t":6,"type":"request/context","injected":["AGENTS.md","git_status"],"token_estimate":10842}
{"t":7,"type":"tool/call","call_id":"c-1","name":"bash","args":{"cmd":"npm test"}}
{"t":8,"type":"tool/result","call_id":"c-1","exit":1,"stderr":"3 failing","bytes":2048}
{"t":9,"type":"assistant/message","text":"基线 3 个失败,先定位根因…","compact_stream":"..."}
{"t":10,"type":"step/end","step_id":"st-1"}
{"t":11,"type":"step/start","step_id":"st-2", ...}
{"t":20,"type":"assistant/attempt","reason":"cancelled","adds_model_history":false}
{"t":25,"type":"turn/end","turn_id":"t-1"}
三个关键设计:
assistant/attempt不进模型历史。失败、重试、取消、流错误的尝试被保留下来供诊断,但不污染后续上下文。- 每次 attempt 会刷新运行时事实、重新协调提示词、冻结请求。官方 原文:「The loop sends immutable requests with live cancellation」。
- 上下文注入本身是事件(
request/context)。这一条最容易被忽略,也是排查「模型为什么突然说了句莫名其妙的话」的入口。
3.3 六要素逐格展开
| 要素 | 关键问题 | 失败模式 | DSH 的接缝 官方 |
|---|---|---|---|
| Loop | 何时算「欠一次请求」? | 早停 / 死循环 / 过度扩张 | agent/turn-stopping、agent/pre-step |
| Tools | schema 由谁组装、何时准入 | 工具描述歧义、工具过多 | ctx.tools、step-admitted tool schemas |
| State | 什么必须跨 reload 存活 | 重启即失忆 | SessionEvent、ctx.sessions |
| Context | 每轮进窗口什么、什么被压缩 | 信息缺失 / 提示词互相冲突 | ctx.systemPrompt、subsystems/compaction |
| Sandbox | 生成代码在哪跑 | 越权、外联、凭据泄露 | ctx.sandbox、subsystems/approval |
| Guardrails | 谁能拦下一次调用 | 规则写成建议 | permission-presets、tools/pre-execute |
官方 架构文档给出一个更精确的抽象:Capability Seam(能力接缝)。一个 seam 有三个角色:
Service Definition(声明接口) + Service Provider(实现) + Consumer(通常是模型-facing 工具)
原文:"Seams are why one provider swap changes the whole product. Filesystem and subprocess providers share one execution world, so pointing them at a remote sandbox moves Bash, PTY, and LSP with them, with no provider forks."
这是「一切皆插件」能成立的机制:不是把代码拆散,是把依赖方向反转成「定义—实现—消费」三元组,让替换发生在配置层。
3.4 信息对等:一条常被忽略的判据
社区 Harness 工程里有个概念叫 information parity:
如果某条信息人能看到、Agent 看不到,Harness 就有一个洞。
每一份你读过的文档、每一个团队「大家默认都知道」的约定、每一次口头交代的部署步骤,只要没有编码进 Harness,Agent 就会犯一个人绝不会犯的错。
实操清单:
| 人知道什么 | 编码进哪里 |
|---|---|
| 构建/测试/格式化用什么命令 | AGENTS.md 顶部 3–5 行 |
| 哪些目录是生成的、不能改 | AGENTS.md + PreToolUse hook 双重 |
迁移必须放 prisma/migrations/、不许改已有迁移 |
规则 + coverage test |
| 某个 API 的字段含义 | Skill(按需加载,不常驻上下文) |
| 上次这个任务为什么失败 | Trajectory / MEMORY.md / 复盘文档 |
| 现在几点、什么时区 | 时钟上下文(原文 极简模式把「时钟上下文」也砍掉了) |
判据 5:排查「模型怎么这么笨」之前,先问「这条信息它有没有地方能拿到」。绝大多数「能力不足」其实是「信息不对等」。
官方 架构文档还给出一个实现层的对应物:agent.inject() —— 新增模型可见上下文的正规入口,它落在下一次被准入的请求里。绕过它直接改消息,就会破坏「Model-visible means logged」。
3.5 三类事件,三种用途
官方 docs/architecture.md 把扩展点分成三个域:
| 域 | 例子 | 是否持久化 | 用途 |
|---|---|---|---|
| Session events | tool/result、user/message |
✅ durable | 必须跨 reload 存活的事实 |
| Agent events | agent/*(inbox / step / status / request / validation) |
❌ live | 观察或拦截进行中的工作 |
| Capability events | fs/*、tools/*、telemetry/* |
❌ live | 给接缝挂策略与适配器,不 import loop |
另有水瀑布(waterfall)语义:agent/pre-step、agent/request、llm/stream、tools/* 三类监听器必须调用 next() 委托,否则会截断流水线;agent/turn-stopping 是串行且没有 next()。这是写插件时的高频坑。
3.6 本章产出与验收
核心产出:一张你当前系统的事件流图 + 一条真实会话的 JSONL,能指出每个 durable 事件的类型与消费者。
验收点:
- 能从日志回答「这次请求的系统提示词由哪几节拼成」
- 能解释为什么
assistant/attempt不进模型历史 - 能区分 durable session event 与 live agent event,并说明插件该挂哪个
- 列出自己项目里 3 条「人知道、Agent 不知道」的信息,并给出编码位置
延伸阅读
| 来源 | URL | 等级 |
|---|---|---|
| DSH 架构 · Session log / Events / Capability seams | https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/architecture.md | 官方 |
| 官方文档 · 持久化事件目录 | https://deepseek-harness.github.io/deepseek-harness/reference/persistence-catalog | 官方 |
| 官方文档 · 能力服务接缝 | https://deepseek-harness.github.io/deepseek-harness/reference/capability-seams | 官方 |
| 官方文档 · 会话子系统 | https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/session | 官方 |
| 官方文档 · Tool 执行流水线 | https://deepseek-harness.github.io/deepseek-harness/reference/tool-execution-pipeline | 官方 |
| 官方站 llms.txt(95 页全量索引) | https://deepseek-harness.github.io/deepseek-harness/llms.txt | 官方 |