设计启示
Agent 系统作者:前面几章源码级观察抽出的 10 条跨主题原则,每条绑定到具体源文件——这是一张可以直接评估自研 agent 的检查表。
这一章的用途
前 4 章(system-prompt / compaction / memory / sandbox)讲了 Claude Code 源码层面做了什么。这一章把 “为什么那样做” 的原则抽出来,每条都绑定到具体的源文件,让你能直接评估和修正你自研 agent 的设计。
每条按同一结构展开:
- 原则——一句话
- 源码证据——
path:line级引用 - 自研 agent 怎么落地——可执行的动作
- 违反信号 (smell)——什么现象说明你违反了这条
1. 渐进披露 (Progressive Disclosure) 是通用模式
原则:任何会随时间无界增长的信息,永远保持”索引常驻 + 详细内容按需”,别一次性塞进 prompt。
源码证据:
- Auto memory:
memdir/memdir.ts的MAX_ENTRYPOINT_LINES = 200+MAX_ENTRYPOINT_BYTES = 25_000——双上限 + 截断警告 - Tools:Claude Code 的工具 schema 用 deferred tools 机制,只把名字常驻,schema 按需
ToolSearch加载 - Skills:L1 metadata 进 prompt,L2/L3 按需(见 系统提示词组装)
- MCP:
mcp_instructionsdelta 机制——新连接的 MCP 只发 delta,不重发全量 instruction
自研 agent 怎么落地:
- 任何文档 / 记忆 / 技能:先问”能不能索引 + 按需”。如果能就做
- 索引本身要有硬上限(如 200 行),并且配用户可见的截断警告——告诉他们怎么 fix(“move detail into topic files”)
- 用多维上限(行数 + 字节)——p97 / p100 数据告诉你单一上限必漏 case
违反信号:system prompt > 20k tokens 还在涨;每加一个 skill / memory / tool prompt 就变长;明显有”老的没人用但占着地”的条目。
2. Subagent 是上下文防火墙,不是并行原语
原则:任何 5+ 步的 ReAct 循环都应该被包成 subagent——不是为了并行,是为了防止探索细节污染主上下文。
源码证据:
tools/AgentTool/AgentTool.tsx第 622-633 行——默认路径forkContextMessages: undefined——子 agent 不继承父对话- 只有 fork path 才继承父 messages + 父 system prompt(特殊场景)
tools/AgentTool/agentMemory.ts——subagent 有自己 3-scope 的独立持久化记忆(user/project/local)
自研 agent 怎么落地:
- 识别:哪些”一次工具调用”实际含 10+ 步循环?(browser、复杂查询、探索搜索)
- 把它们包成 subagent:一次调用进,摘要出
- Subagent 可以有独立 model(haiku 更便宜)、独立 permission mode、独立 working directory / worktree isolation
- 记忆也要隔离——不同 subagent type 学到的经验不串门
违反信号:主对话长期充斥 grep 残渣、ls 输出;每轮 token 消耗在膨胀但决策密度没增加。
3. Hook 和 Prompt 回答不同问题
原则:prompt 说应该做什么(模型判断);hook 说一定做什么(harness 强制)。两者不能互换。
源码证据:
utils/hooks.ts定义了 10 种 hook 事件 + 完整 JSON schema(continue / decision / permissionDecision / updatedInput / systemMessage / additionalContext)TOOL_HOOK_EXECUTION_TIMEOUT_MS = 10 * 60 * 1000——hook 是一等公民(10 分钟超时),不是快速拦截器- Hook 可以修改工具参数 (
updatedInput)、注入 system message、打断 agent 循环 (continue: false)
自研 agent 怎么落地:
- 列清所有”从现在起每次 X 都要 Y”的需求,评估严重性——严重 → 必须 hook
- Hook API 分三层:plain text(简单)→ JSON decision(中)→ updatedInput + systemMessage(高级)
- 必须同时提供 prompt 层和 hook 层——只有 prompt 时自动化需求会悄悄失效
违反信号:“我在 prompt 里写了要 X,但 agent 经常不做”——prompt 层解决不了,需要 hook。
4. 信任是产品 Surface,不是配置
原则:用户的信任级别必须UI 一等公民 + per-turn 可切换,不能是启动参数或配置文件里的布尔值。
源码证据:
utils/permissions/PermissionMode.ts的PERMISSION_MODE_CONFIG——7 种 mode 各自有title、shortTitle、symbol、color、external- Plan mode 的
PAUSE_ICON、acceptEdits/bypass的⏵⏵fast-forward 符号——视觉强化当前状态 --dangerously-skip-permissions——刻意起得难看的 CLI flag
自研 agent 怎么落地:
- Permission modes 做成 UI 可切换(per-turn),不是启动 flag
- 状态栏 / title bar 持续显示当前 mode
- 危险 mode 的命名违反 UX 惯例——
bypass/dangerously
违反信号:“agent 突然自己跑了 rm”——几小时前的启动 flag 被忘了;config 里有 auto_approve: true——错误的抽象。
5. Trust-but-verify 是对抗幻觉的基础设施
原则:任何 agent 的自述都要被当作 intent,不是 fact。关键断言需要读回或 grep 验证。
源码证据:
utils/claudemd.ts注入的 memory guidance 第 3 条:“A memory that names a specific function, file, or flag is a claim that it existed when the memory was written. It may have been renamed… Before recommending it [verify]”- Edit 工具的 description:“You must use your
Readtool at least once in the conversation before editing”——强制读再改 - Compaction summary 第 9 段:“Optional Next Step: include direct quotes from the most recent conversation”——强制原文引用防意图漂移
自研 agent 怎么落地:
- 关键工具操作后,下一步强制是一次验证读取
- 记忆系统必须配”引用前 grep”的操作守则
- 多 agent 系统:子 agent 摘要要可被父 agent 校验
违反信号:agent 说”改好了”实际没改;记忆里有 “X 文件在 Y 位置” 搜了没有;log 里 “完成了 task” 但交付物有问题。
6. Error Message 是 Prompt 的延伸
原则:工具返回的 error 不是状态码,是教 agent 下一步怎么走的文本。认真写每一条。
源码证据:
- Edit 工具的 error text:“This tool will error if you attempt an edit without reading the file”——读到这个 agent 自动去先 Read
- Claude Code 的工具描述整体读起来像使用教程而不是 schema doc——包括失败模式、对齐要求、uniqueness 约束
- Compaction 的
NO_TOOLS_PREAMBLE+NO_TOOLS_TRAILER——长 prompt 前后都重复关键约束(遥测数据:Sonnet 4.6 工具尝试率 2.79% vs 4.5 的 0.01%)
自研 agent 怎么落地:
- 每个自研工具的 error,过一遍:“读到这条,模型知道下一步做什么吗”
- 错:
"Invalid argument";对:"This tool requires parameter X to be set first. Typical usage: ..." - 长 prompt 的前后都要重复硬约束——模型会忘中间的指令
违反信号:agent 遇 error 死循环重试;工具描述只有 schema 类型没有用例;同一个错反复问用户。
7. 晚绑定 (Late Binding) 保 Prompt Cache
原则:System prompt 的层按稳定性排序——越稳定越靠前。时间戳 / session state / 动态内容放到后面。
源码证据:
constants/prompts.ts第 572 行:SYSTEM_PROMPT_DYNAMIC_BOUNDARY = '__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__'——字面量 marker,注释明写 “BOUNDARY MARKER - DO NOT MOVE OR REMOVE”DANGEROUS_uncachedSystemPromptSection工厂函数——名字刻意吓人,让破 cache 的段在 review 时无法隐身services/api/promptCacheBreakDetection.ts的notifyCompaction——压缩时主动通知 cache miss 告警,避免 20% false positive(源码 BQ 数据)
自研 agent 怎么落地:
- 画 prompt 层级表:每层稳定性是什么
- 不稳定的内容不管多”重要”都放后面
- 不要为了”让模型先看到重要的东西”把时间戳 / user id 放前面——prompt cache 加载付不起这个成本
- 任何会破 cache 的段要显式标注,评审时可见
违反信号:prompt cache 命中率 < 50%;每次请求都全价;prompt 长度不大但 token 成本高。
8. 短期对话和长期记忆是两层
原则:对话历史是短期(每次任务结束可清空),记忆层是长期(跨 session 存)。两者不要混。
源码证据:
utils/messages.ts的createCompactBoundaryMessage——压缩是消息流事件,不是上下文重置/clear命令只清对话,不动CLAUDE.md/ auto memory / session memoryservices/compact/compact.ts里 三档:auto-compact(防线)//compact(主动)//clear(重开)getMessagesAfterCompactBoundary——压缩边界之后的消息才参与下次压缩,不重复压
自研 agent 怎么落地:
- 提供三档控制:自动防线 / 用户主动压 / 彻底清空
- 写”学到的偏好”到记忆层,不留在对话里等着被 clear
- 压缩不触 system prompt——保护 cache prefix
- 用显式 boundary message 标记压缩事件,而不是静默改消息流
违反信号:用户 “reset conversation” 后 agent 忘了基础偏好——偏好本该在记忆层;/clear 等价于重装产品——记忆层设计失效。
9. 数据驱动的 Prompt 工程
原则:prompt 里的每条指令都应该有”为什么这么写”的答案——不靠数据的指令长期必失控。
源码证据:
constants/prompts.ts的numeric_length_anchors:“Length limits: keep text between tool calls to ≤25 words”——注释明写 “research shows ~1.2% output token reduction vs qualitative ‘be concise’“。ant-only 先灰度测services/compact/autoCompact.ts:MAX_OUTPUT_TOKENS_FOR_SUMMARY = 20_000——注释 “Based on p99.99 of compact summary output being 17,387 tokens”。基于生产遥测调的memdir/memdir.ts:MAX_ENTRYPOINT_BYTES = 25_000——注释 “At p97 today; catches long-line indexes… (p100 observed: 197KB under 200 lines)“——p100 数据直接写在注释里services/compact/prompt.ts的NO_TOOLS_PREAMBLE——注释 “(2.79% on 4.6 vs 0.01% on 4.5)“——遥测数字直接作为 prompt 设计依据
自研 agent 怎么落地:
- 每条 prompt 指令 / 每个 threshold 常量,都要能回答”为什么是这个数”
- 量化措辞(“≤25 words”)先用数据验证再推广——先 ant-only / 灰度
- 把 prompt 当作可 A/B test 的代码,不是无序的规则堆积
- 产品遥测要能回流到 prompt 设计——p97、p99.99、百分点差异都是有效信号
违反信号:prompt 里有一条没人能解释的指令;threshold 常量是”拍脑袋”写的;改 prompt 前后没有量化对比。
10. Fail-closed + Circuit Breaker
原则:关键路径必须 fail-closed(出错时拒绝,不是放行);无法恢复的失败必须 circuit break(连续失败 N 次就停),不能无限重试。
源码证据:
services/compact/autoCompact.ts的MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES = 3——注释 “BQ 2026-03-10: 1,279 sessions had 50+ consecutive failures (up to 3,272) in a single session, wasting ~250K API calls/day globally”。没熔断器 = 每天浪费 25 万次 API 调用- Permission 系统:deny 始终胜过 allow(
bypassPermissions也不能绕 deny list / hook),fail-closed 默认 utils/permissions/dangerousPatterns.ts:auto-mode 启动时自动剥离Bash(python:*)这种”表面限制但实际放任”的规则——不信任用户的宽松配置
自研 agent 怎么落地:
- 所有重试路径配熔断器:N 次连续失败后停下记日志,而不是继续消耗资源
- 权限合并算法:deny 永远胜过 allow;“最大权限” mode 不能跳过 deny
- 危险的宽松配置要预处理时主动剥离,不是在运行时逐个拦截
违反信号:生产日志里看到同一错误在短时间内重复 100+ 次;有用户把自己限制了一半的 config 开成了完全放行;每次 “bypass all” 都真的 bypass 了所有。
自检清单
对自研 agent 的快速评分表:
| # | 原则 | 做到了吗 |
|---|---|---|
| 1 | 渐进披露(索引 + 按需) | □ |
| 2 | Subagent 作为上下文防火墙 | □ |
| 3 | Hook 和 Prompt 分层 | □ |
| 4 | 信任作为产品 surface | □ |
| 5 | Trust-but-verify 的操作守则 | □ |
| 6 | Error message 写得像 prompt | □ |
| 7 | Late binding 保 cache | □ |
| 8 | 短期 / 长期记忆分层 | □ |
| 9 | 数据驱动的 prompt 工程 | □ |
| 10 | Fail-closed + circuit breaker | □ |
超过 2 条没做到,回前面 4 章精读对应部分。
落到代码:继续读下一章
以上 10 条是原则——抽象层。如果你要立刻把这些原则落到 AI SDK 的代码行,下一章 应用到自研 Agent (AI SDK) 把每条原则映射到 streamText 生命周期的具体嵌入点,告诉你在哪行代码、怎么做、什么时候该做什么时候不该做。
如果你已经在用 AI SDK 写 agent,下一章还有一张10 项自检清单——直接对着扫你现在的 codebase。
不是普世真理,是当前最佳实践
三条 caveat:
- Agent 工程是新学科——三年后这些原则可能部分被推翻。不要把它们当教条
- Claude Code 也在迭代——三年后源码会变;回看如果不一样了,是它们在变
- 真正的资产不是这 10 条,是”遇到问题先看好实现怎么做”的方法——把 Claude Code 源码当 case 拆过一次,下次遇到 Devin、Cursor、Codex CLI 的新特性也能拆
源码阅读指南:本章所有引用的文件都在 claude-code/ 目录。按重要性排:
services/compact/{compact, autoCompact, microCompact, prompt}.ts—— 最精彩的部分constants/prompts.ts+utils/systemPrompt.ts—— prompt 装配的核心utils/claudemd.ts+memdir/—— 记忆系统types/permissions.ts+utils/hooks.ts—— 权限 + hook 完整模型
这些文件加起来约 15000 行。过一遍的时间约等于一周——但每一行都是真实 production 系统的凝练,远胜读任何 agent 论文。
延伸阅读
- 本章引用的所有前置章节:Overview · System Prompt · Compaction · Memory · Agent Loop · Permissions · Execution Environment
- 理论背景:Harness Engineering · Context Engineering
- 实践参照:BUA Architecture——subagent 作为上下文防火墙的实际案例