Appearance
附录
A. 怎样阅读源码并动手实现
本书以架构与原理为主,不内嵌大段可运行代码:每个机制讲清“为什么这样设计、解决了什么、放弃了什么”,并在多个动手章的“自建起步”小节列出最少需要哪些对象、每个对象怎样工作,以及必须处理哪些异常情况。需要看真实代码时,书里直接给出成熟项目的源码路径。
书中已有的"自建起步"小节速查:
| 章 | 小节主题 | 关键设计 |
|---|---|---|
| 第 4 章 | 循环五个要点 / 四步校验 | 使用一个工具注册表、按 id 配对结果、限制轮数;依次检查流式片段、完整响应、修复结果和工具参数,错误要告诉模型位置、原因和下一步 |
| 第 8 章 | 最简 run():管道 spawn + 超时杀 + 尾部截断 | 短命令能跑通;长命令被超时误杀、常驻命令等不到结束、交互命令没人回答、输出可能超大——四处碰壁分别引出 7.2~7.5 的设计 |
| 第 9 章 | 最小审批检查 | 命令含 shell 运算符时询问用户、argv 符合允许清单时直接运行、没有收到回答时默认拒绝 |
| 第 16 章 | 最小 spawn | 干净上下文+同一循环;规矩写进工具描述;任务书即协议 |
| 第 17 章 | 最小 MCP 客户端 | 先握手再列工具、按 id 配对、行缓冲解析、命名空间前缀、进程清理 |
| 第 19 章 | 能发现连接卡住的流式调用 | 七个决定:检测多久没收到数据、完整响应到齐后再提交、保留跨数据块内容、按序号拼工具参数、不同错误分别处理、检查内容是否被截断、隔离每次请求 |
| 第 20 章 | 随机拆流验收练习 | 比较完整输入和随机切块输入:最终结果相同、重复事件不重复追加、序号有缺口时暂停处理 |
推荐实现顺序:TypeScript 读者可以先看 pi 的小型 Agent loop,再看 dsh 怎样把同一循环放进插件体系;需要理解受控执行和大型 Rust 工程时,再读 codex 与 grok-build。四家源码的精读入口见附录 B。
B. 参考项目速查
codex 与 grok-build 是大型生产级 agent 实现;dsh 是功能较完整的预发布参考实现(developer preview);pi 是核心较小、扩展优先的终端 Harness。第 3~20 章用四者说明具体机制,工具对照见附录 D。
| 项目 | 技术栈 | 阅读特点 | 精读入口 |
|---|---|---|---|
| codex(OpenAI) | Rust | 大型 Rust workspace | codex-rs/core/src/session/turn.rs(loop)、codex-rs/core/src/compact.rs(本地压缩)、codex-rs/core/src/compact_remote.rs(远程压缩)、codex-rs/core/src/tools/spec_plan.rs(工具装配)、codex-rs/core/src/exec_policy.rs(命令判定) |
| grok-build(SpaceXAI) | Rust | 多 crate Rust workspace | crates/common/xai-grok-compaction/src/code_compaction/(整段替换压缩)、crates/codegen/xai-grok-shell/src/session/compaction.rs(触发、输入降级与恢复)、crates/codegen/xai-grok-tools/src/implementations/(工具)、crates/codegen/xai-grok-workspace/src/permission/(审批) |
| dsh(DeepSeek) | TypeScript | TypeScript 插件式 workspace | packages/core/agent-loop/src/agent.ts(loop)、packages/compaction/compaction-basic/(摘要与区间替换)、packages/compaction/compaction-tool-result-pruner/(工具结果剪裁)、packages/fs/tool-fs/src/edit.ts(编辑)、packages/sandbox/sandbox/src/escalation.ts(申请额外权限) |
| pi(earendil-works) | TypeScript | 小核心 + SDK + 扩展 | packages/agent/src/agent-loop.ts(loop)、packages/coding-agent/src/core/tools/(工具)、packages/coding-agent/src/core/compaction/(压缩)、packages/evals/src/pi-harness.ts(评估) |
B.1 按问题精读源码
下面的入口不是“出现了一个同名类就算实现”,而是本版正文实际追过的运行时、失败分支和测试附近。文件会随上游版本移动,阅读时优先从列出的入口继续跟调用链。
| 问题 | codex | grok-build | dsh | pi |
|---|---|---|---|---|
| 工具装配与注册 | codex-rs/core/src/tools/spec_plan.rs、registry.rs、router.rs、handlers/tool_search.rs | crates/codegen/xai-grok-tools/src/registry/、bridge.rs | packages/core/tools/src/index.ts、schema.ts、json-schema.ts | packages/agent/src/types.ts、packages/coding-agent/src/core/tools/index.ts |
| 多工具调度与取消 | codex-rs/core/src/tools/parallel.rs、orchestrator.rs | crates/codegen/xai-grok-shell/src/session/acp_session_impl/tool_calls.rs、xai-grok-tools/src/bridge.rs | packages/core/agent-loop/src/tool-calls.ts | packages/agent/src/agent-loop.ts |
| 编辑与实际 diff | codex-rs/core/src/tools/handlers/apply_patch.rs、turn_diff_tracker.rs、tools/events.rs | crates/codegen/xai-grok-tools/src/implementations/grok_build/、xai-grok-workspace/src/session/file_state.rs | packages/fs/tool-str-replace-editor/src/index.ts、fs-local/src/fsio.ts、fs-local/src/index.ts | packages/coding-agent/src/core/tools/edit.ts、edit-diff.ts、file-mutation-queue.ts |
| 回滚与检查点 | 当前核心无文件回滚;历史路径不要当现状 | crates/codegen/xai-grok-workspace/src/session/checkpoint.rs、checkpoint_store.rs、file_state.rs、git.rs | 编辑事件保存 before/after,但无统一文件回滚命令 | 会话树在 packages/coding-agent/src/core/session-manager.ts,不回滚工作区文件 |
| 沙箱、审批与升级 | codex-rs/core/src/tools/orchestrator.rs、tools/sandboxing.rs、exec_policy.rs | crates/codegen/xai-grok-pager/docs/user-guide/18-sandbox.md、xai-grok-workspace/src/permission/ | packages/sandbox/sandbox/、packages/guard/timeout-policy/src/index.ts | 核心工具直接使用宿主权限;before/after hook 见 packages/agent/src/agent-loop.ts |
| 模型重试 | codex-rs/core/src/responses_retry.rs、util.rs | crates/codegen/xai-grok-sampler/src/retry.rs | packages/llm/llm-retry/src/index.ts、packages/llm/llm/src/retry-policy.ts | packages/ai/src/utils/provider-retry.ts、retry.ts |
| 熔断组件 | 模型主路径未见通用三态熔断;不要与 guardian 的拒绝保护混写 | crates/common/xai-circuit-breaker/src/breaker.rs、state.rs;需继续核对具体业务接线 | 模型主路径未见通用三态熔断 | 模型主路径未见通用三态熔断 |
| 上下文压缩 | codex-rs/core/src/compact.rs、compact_remote.rs、context_manager/ | crates/common/xai-grok-compaction/src/code_compaction/、xai-grok-shell/src/session/compaction.rs | packages/compaction/compaction-basic/、compaction-tool-result-pruner/ | packages/coding-agent/src/core/compaction/ |
| 跨会话记忆 | 写管线 codex-rs/memories/write/(两阶段)、读注入 codex-rs/memories/read/ 与 codex-rs/ext/memories/,状态在 codex-rs/state/ | crates/codegen/xai-grok-memory/(storage/index/dream_lock) | 无长期记忆模块 | 核心无;packages/agent/src/harness/session/memory.ts 只是存储后端形态 |
| 子 Agent 与结果结算 | codex-rs/core/src/session/multi_agents.rs、tools/handlers/multi_agents_v2/ | crates/codegen/xai-grok-tools/src/implementations/grok_build/task/coordinator.rs、coordinator_state.rs、types.rs | packages/subagent/ 与会话 fork 实现 | 核心无统一协议;示例扩展在 packages/coding-agent/examples/extensions/subagent/ |
C. 名词表
| 术语 | 一句话定义 | 详见 |
|---|---|---|
| provider | 模型服务方:提供大模型 API 的厂商或服务(OpenAI、DeepSeek、Anthropic 等);书中"provider 的规则"多指其 API 对请求格式的校验 | 第 1 章 |
| KV Cache | 一次模型推理中缓存已经计算过的注意力键和值,避免后续 token 重算这段内容 | 第 2 章 |
| 跨请求前缀缓存 | 模型服务尝试在多次请求之间复用相同前缀的计算结果;是否命中、最低长度和计费规则由服务决定 | 第 2 章 |
| MoE | 混合专家:每个 token 只选择部分专家参与计算;不同模型的总参数量和每次激活量并不相同 | 选读章 |
| 思考模型 | 在回答前投入额外推理计算的模型;API 可能只返回答案或推理摘要,不一定展示完整思维过程 | 选读章 |
| Harness | 组织 LLM、上下文和工具,并负责权限、沙箱、状态、恢复与验证的 Agent 运行程序 | 第 3 章 |
| agentic loop | 模型和程序多轮交换消息、调用工具并检查结果,直到完成或停止;ReAct 是其中一种常见提示与行动方式,不是所有循环的同义词 | 第 4 章 |
| function calling | 模型按 schema 输出结构化工具调用的 API 能力 | 第 4、5 章 |
| 工具调用 ID 配对 | 每个工具结果必须带回对应调用的 ID;tool_call_id 是 OpenAI API 的字段名,其他服务可能使用不同字段名 | 第 5 章 |
| freeform 工具 | 不裹 JSON、用自定义语法定义参数的工具(如 apply_patch) | 第 7 章 |
| 乐观并发 | 写回时携带读取时的版本号,版本已经变化就拒绝覆盖 | 第 7 章 |
| PTY | 伪终端,给子进程伪造"真终端"的执行环境 | 第 8 章 |
| spill | 输出过长时在设定上限内另存文件,只返回预览和路径;超过留存上限时可能只剩尾部,必须明确说明内容有丢失 | 第 8、14 章 |
| compaction | 上下文压缩:摘要旧区间,保留近期原文 | 第 13 章 |
| grep/read 逐步查找 | 不建索引,让模型反复缩小目录与关键词范围,最后读取真实文件确认 | 第 11 章 |
| 注入导致数据外泄的三个条件 | 同时接触私有数据、不可信内容和外部通信时,注入攻击才可能把数据带走;这不是说缺少其中一项就没有其他注入风险 | 第 6、9、18 章 |
| fail-closed | 出错时默认拒绝(而非默认放行) | 第 9 章 |
| 事件溯源 | 只追加事件日志,需要当前状态时再按顺序计算;可以从历史某处创建新会话 | 第 14 章 |
| durable / transient | 程序重启后仍必须保留的事件 / 只用于当前实时显示的事件 | 第 14、20 章 |
| attempt | 同一 turn 中一次独立模型请求或重试,失败输出不得与下一次拼接 | 第 4、14 章 |
| outcome unknown | 副作用已可能发生但结果未持久化,恢复时禁止盲重试 | 第 4、14 章 |
| tool settled | 工具本体已经停止并给出结果或错误;收到取消信号、调用者超时都不等于已经 settled | 第 10、19 章 |
| checkpoint | 已经完整保存、可以从这里恢复的位置;使用时要说明是文件、上下文压缩、会话还是 Goal 的检查点 | 第 7、13、14、19 章 |
| Goal | 独立于对话保存的任务目标,包含当前状态和可选预算 | 第 19 章 |
| Agent eval | 在可重置环境中评估完整 Agent 的任务结果、执行过程、安全和成本 | 第 21 章 |
| handoff | 共享上下文的角色移交(与 spawn 相对) | 第 16 章 |
| MCP | Model Context Protocol,让客户端和服务器交换工具、资源、提示模板等能力的协议 | 第 17 章 |
| Skill | Agent 按需读取的任务说明和相关资源 | 第 17 章 |
| watchdog | 根据“多久没有收到新数据”判断调用是否卡住的计时器 | 第 19 章 |
| circuit breaker | 下游持续失败时暂时拒绝新请求,冷却后只放少量探测的三态保护;与单次请求重试不同 | 第 19 章 |
D. 四个 Agent 的工具对照表
按用途比较四个 Agent 暴露给模型的工具,数据均来自源码核实。同名但实现不同时会在括号中说明。pi 这一列要特别注意“默认内置”和“可由扩展实现”的区别。
D.1 九类工具
表中列的是审阅时源码可见的能力。实际会话会受版本、配置、feature flag、preset 和运行环境影响,不保证每次都加载全部工具。
| 类别 | codex(OpenAI) | grok-build(SpaceXAI,grok_build 风味) | dsh(DeepSeek,standard preset) | pi(默认) |
|---|---|---|---|---|
| ① Shell/执行 | exec_command + write_stdin(yield 统一) | bash(前后台分治) | bash/pwsh(无状态+jobs) | bash(一次调用一个前台进程;后台交给 tmux 或扩展) |
| ② 文件读写编辑 | 无专用读工具(shell cat);apply_patch(freeform) | read_file + search_replace / 三编辑器并存 | read/write/edit(+str_replace_editor 移植) | read/write/edit(old/new 多处替换,同文件写入串行) |
| ③ 检索 | 无专用工具(shell rg/find);tool_search(工具发现) | grep(ripgrep)+ lsp + list_dir | grep/glob(ripgrep)+ lsp | 默认 coding 工具让 bash 跑 rg/find;只读工具组另有 grep/find/ls |
| ④ 规划与状态 | update_plan + get/create/update_goal | todo + enter/exit_plan_mode + update_goal | todo_write + get/create/update_goal + plan mode | 不内置 plan/todo;写文件或装扩展 |
| ⑤ 用户交互 | request_permissions + request_user_input | ask_user_question | ask_user_question | 不内置提问/审批工具;扩展可注册 |
| ⑥ 子 Agent/并行 | spawn_agent/send_message/followup_task/wait_agent/list_agents/interrupt_agent(v2) | task(子代理委派) | subagent/subagent_fork + send_message/interrupt_agent/list_agents;外驱 Codex/Claude Code 的实现默认不在 preset 中启用 | 不内置;示例扩展以独立 pi 进程实现 |
| ⑦ 后台任务管理 | (exec 会话即后台) | get_task_output/wait_tasks/kill_task/monitor | job_output/job_kill | 不内置;推荐 tmux 或扩展 |
| ⑧ 扩展接入 | MCP 资源工具(list/templates/read) + skills.list/read + 插件工具 | skill + MCP | skill + MCP(mcp__server__tool) | Skill + TypeScript extension + Pi Package;MCP 由扩展接入 |
| ⑨ 环境与元信息 | view_image/clock.curr_time/clock.sleep/get_context_remaining/new_context/wait_for_environment | read_image(于 read)/scheduler/web_fetch/web_search/image_gen/image_edit/video_gen/workflow | read_image/web(fetch/search)/workflow/ralph/run_code(code preset) | read 可返回图片;额外能力由扩展与 Skill 提供 |
D.2 六点比较
- 真正的共同最小集:四家默认都有模型循环、Shell、文件读取和修改。计划、审批、后台任务和子 Agent 并不是 Code Agent 能运行的前提;pi 有意把它们移到扩展层,反过来说明了核心边界。
- 代码检索做法不同:codex 和 pi 的默认 coding 工具都让 shell 运行 rg/cat/find;pi 的只读模式另有专用 grep/find/ls。grok-build 和 dsh 还提供 LSP 工具。
- 编辑器策略不同:codex 一个 apply_patch;pi 一个支持一批不重叠替换的 edit;dsh 两个;grok 三个。数量不同反映模型适配、兼容性和维护成本的取舍,不是成熟度排名。
- 工具数量反映产品范围:grok-build 的内置工具最多;codex 通过托管工具或扩展补能力;dsh 根据 preset 组装;pi 只保留小核心,把产品化能力交给扩展和包。先确定产品边界,再决定数量。
- 工具名和描述都是模型接口:dsh、grok-build、pi 常用
read、edit、bash等短名;codex 常用exec_command、update_plan等长名。改名或改 schema 后都要重新评估工具选择与参数准确率。 - 外置不等于没有成本:pi 用 tmux 替代内置后台任务、用容器替代内置权限边界、用扩展接 MCP 和子 Agent。核心代码更少,但安装来源、权限、恢复和跨扩展一致性需要应用方负责。
E. 后续待办
F. 尚未充分展开的主题
外部评审(2026-08)推动本版补齐了状态恢复、Goal、后台任务冷恢复、前端事件协议与 pi 对比。以下是仍未充分展开的主题:
- 怎样兼容不同模型服务:还需要处理 Chat Completions、Responses 和 Anthropic content blocks 的数据差异,以及 tool streaming、refusal、reasoning、usage、finish_reason、token 上限和 strict 支持情况。标为 "OpenAI-compatible" 的服务也不一定支持完全相同的 API;第 4、5 章主要用 Chat Completions 说明循环和工具调用,生产实现仍需为每种 API 编写适配层。
- 更完整的安全与数据管理:第 6、9、15、17、18 章已讨论注入防御、SSRF、沙箱与资源限制、记忆访问控制,以及把经验做成工具时的权限;仍缺 DNS rebinding/SSRF、MCP/plugin 供应链签名、企业密钥管理、合规留存与多租户隔离的完整实现。
- 工作区完整性:保护用户已有的 dirty changes(未提交修改,别把它们卷进回滚);binary/EOL/编码/文件权限/符号链接/submodule 的特殊处理;worktree 合并与冲突后的总体验证。
- 后台任务资源分配:第 9 章已列 CPU、内存、磁盘、PID 和最长运行时间,第 8、19、20 章已讲任务从开始到结束、程序重启后的恢复和 UI;仍缺启动完成检查、健康检查、带过期时间且只允许一个进程继续运行的执行权记录、跨机器接管与公平分配资源。
- 大规模评测:第 21 章已讨论判定分层、用例集生命周期、指标与统计、CI 门禁和小流量发布;仍未展开样本量估算、高级统计方法、评价模型变化监控和长期污染检测。
- 运行记录与隐私:不要记录所有 prompt,而要记录脱敏后的证据字段、内容哈希、版本和退出码,并让每条记录可以追查来源;第 19 章的最小事件只是起点,还不等于满足隐私合规要求。