跳到主要内容

深入理解 Claude Code 设计原则(三):设计决策框架

· 阅读需 14 分钟
Jiajie Wu
一名崭新水手

本系列第三篇。前两篇拆解了 Claude Code 具体怎么做的。这一篇退后一步,看看它在每个设计岔路口选了哪条路,为什么选那条,以及你如果自己造一个 Agent 系统,同样的岔路口会怎么走。

深入理解 Claude Code 设计原则 · 系列导航

  1. 项目全局认知与资源导航
  2. 核心机制深潜
  3. 设计决策框架
  4. 论文精读与剖析

写在前面

"Build Your Own Agent" 是论文配套文档中我觉得写得最好的一份。它不教你写代码,而是把构建生产级 Agent 系统时必须做的设计决策摊开来讲。每个决策都给出了 Claude Code 的选择、替代方案和各自的 tradeoff。

这篇文章沿着同样的结构,但我会加入更多自己的理解和对比分析。


决策一:推理逻辑放在哪里

这是所有决策里最根本的一个。你的 Agent 系统里,多少决策交给模型,多少由你的代码控制?

三种主流做法:

最小脚手架(Claude Code 的选择):只有约 1.6% 的代码涉及 AI 决策。Agent 循环就是个 while 循环,模型想调什么工具就调什么工具,harness 只负责权限检查和结果处理。模型有最大的自由度。

显式状态图(LangGraph 的路线):开发者用图结构定义 Agent 的行为流程,每个节点是一步操作,边是条件分支。流程清晰、可预测、容易调试。但模型被限制在预定义的路径里,你需要提前考虑到所有可能的分支。

重型规划脚手架(Devin 的路线):模型先生成详细的多步计划,然后按计划执行,执行过程中持续跟踪进度。对复杂工作流的完成度比较可靠。但规划系统本身就是一大坨需要维护的代码。

Claude Code 选最小脚手架的逻辑是这样的:前沿模型的能力在快速趋同。SWE-bench 上排名前三的模型得分差距在 1% 以内。既然模型能力越来越强,给模型加约束的那些脚手架代码会逐渐变成技术债。不如把工程投入放在确定性的基础设施(上下文管理、安全、恢复)上,这些东西不管模型怎么进化都需要。

从另一个角度想:如果你的 harness 做得好,换一个更强的模型,系统表现直接提升。如果你的逻辑全在脚手架里,换模型可能还要改脚手架。

不过这个选择不是没代价。最小脚手架意味着模型有时候会做蠢事,因为没有预设流程来限制它。Claude Code 靠权限系统和恢复机制来兜底,但用户偶尔还是会遇到 Agent 走偏的情况。对于合规要求严格的场景(金融、医疗),显式状态图的可预测性可能是必需的,而不是可选的。

你应该问自己的问题

  • 你用的模型有多强?越强的模型需要越少的脚手架
  • 你的工作流对可预测性的要求有多高?受监管的领域可能需要显式图
  • 模型能力提升有多快?重型脚手架容易变成维护负担

决策二:安全姿态

Agent 能执行 shell 命令、修改文件、发网络请求。你怎么防止它做不该做的事?

四种路线:

deny-first + 分层防御(Claude Code):默认拒绝一切,7 层独立安全检查,渐进式信任光谱让用户逐步放宽限制。非常安全,但 93% 的权限提示被用户不假思索地批准了。

容器隔离(SWE-Agent、OpenHands):Agent 在 Docker 容器里运行。容器内部随便干,容器外面碰不到。边界清晰,但粒度很粗。你没法说"允许读取这个目录但禁止删除那个文件"。

VCS 回滚(Aider):Agent 做的所有文件修改通过 git 管理。搞砸了就 rollback。简单轻量。但只能保护文件。网络请求、数据库操作、shell 副作用一概管不了。

纯审批(基础聊天机器人):每个操作都问用户。用户说行才执行。看起来最安全。但用户会审批疲劳。Claude Code 的数据已经证明了这一点:93% 的提示被直接批准。

Claude Code 从第四种路线(纯审批)遇到了问题后进化到第一种。他们发现用户不会认真看权限提示,多弹几次只会让审批率更高而不是更低。解决方案不是更多的警告,而是重新划分边界:用沙箱和 ML 分类器创建安全区域,让 Agent 在区域内自主运行,减少需要用户决策的次数。

但 deny-first + 分层防御也有自己的问题。论文指出,当各安全层共享同一种约束时,"深度防御"就退化了。Claude Code 的多个安全层都依赖 token 预算。超过 50 个子命令的情况下安全分析被完全跳过。这不是独立的失效模式。

预信任窗口

更微妙的问题是初始化阶段的安全。钩子和 MCP 服务器在系统初始化时就开始执行,这时候用户还没看到信任对话框。4 个 CVE 中有 2 个的根因都是这个。

你在设计自己的系统时需要特别注意启动阶段。稳态运行时安全检查做得再好,如果初始化阶段有缝隙,攻击者可以在那个窗口里做很多事。

你应该问自己的问题

  • Agent 能做的最坏的事是什么?删生产数据?发邮件?窃取代码?答案决定了你需要多重的安全
  • 你能不能用沙箱来减少用户需要做的决策数量?
  • 你的安全层之间是不是共享同一种失效模式?

决策三:上下文管理

上下文窗口是有限的。长对话会不断积累,工具返回的内容可能很大。你怎么决定模型看到什么?

五种思路:

渐进式压缩管道(Claude Code,5 层):从最便宜的压缩手段开始用,不够了再用贵的,尽量推迟不可逆的操作。保留信息的时间最长。但实现复杂,压缩过程对用户不可见。

简单截断:超过窗口就砍掉最早的消息。好写,好懂。但可能丢掉关键的上下文。比如用户在对话开头定义的需求被截掉了,后面的执行就可能偏离。

滑动窗口:保留最近 N 条消息。行为可预测。但完全不考虑消息的重要性。

RAG 检索增强:需要的时候从向量数据库里检索相关内容。可以访问整个代码库。但检索质量是瓶颈,而且检索到的片段可能缺少上下文。

单次摘要:一次压缩搞定。但一次压缩可能丢失细节。

Claude Code 的渐进式方案是我见过的上下文管理里工程量最大的。5 层策略各有各的触发条件和副作用,它们之间的交互本身就是一个复杂系统。但论文的论点很有说服力:上下文是整个架构中约束最硬的资源,几乎所有其他设计决策都被它影响。

懒加载(只在需要时加载工具 schema)、延迟工具注册(模型不主动用就不注册)、子 agent 只回传摘要、每个工具返回结果有大小预算。这些散落在系统各处的优化,根源都是一个:上下文很贵。

如果你在设计自己的 Agent 系统,论文的建议是:从第一天就按上下文稀缺来设计。不要等到上下文溢出了才开始想办法。

你应该问自己的问题

  • 你的上下文窗口有多大?窗口越小,压缩策略需要越激进
  • 你需要支持长会话(几个小时的工作)吗?简单截断扛不住
  • 你能不能把"指导性上下文"(指令、规则)和"工作上下文"(对话历史)分开管理?

决策四:可扩展性

外部工具、自定义指令、用户配置怎么接入你的系统?

三种路线:

渐进式上下文成本机制(Claude Code):不同种类的扩展有不同的上下文成本。Hooks 零成本,Skills 低成本,Plugins 中成本,MCP 高成本。复杂度高,但能把有限的上下文预算分配给真正需要它的扩展。

单一 API:所有扩展走同一个接口。好理解,好开发。但每个扩展都消耗上下文。扩展一多,上下文就不够用了。

插件市场:生态丰富。但质量控制和安全审查会成为瓶颈。

Claude Code 的思路是:不是所有扩展都需要消耗上下文 token。一个 PreToolUse 钩子在工具执行前跑一段 shell 脚本检查安全性,完全不需要往上下文窗口里塞任何东西。一个 Skill 在被激活之前也不占用上下文。只有当 MCP 服务器注册新工具时,工具的 schema 描述才会进入上下文。

这个分级策略的好处是:你可以挂很多 Hooks 而不影响模型的可用上下文。如果用单一 API,每多加一个扩展都在挤压模型的思考空间。

3 个注入点

不管你选哪种扩展方案,Agent 循环里总共就 3 个地方可以被外部干预:

  1. assemble():控制模型看到什么。你可以往上下文里注入指令、工具描述、额外信息
  2. model():控制模型能调用什么。注册新工具、屏蔽已有工具
  3. execute():控制工具调用是否执行以及怎么执行。权限检查、前后钩子、拦截

理解这三个注入点比理解四种扩展机制更重要。因为扩展机制可能会变(今天是 MCP,明天可能是别的协议),但注入点是由 Agent 循环的结构决定的,相对稳定。

你应该问自己的问题

  • 你的 Agent 需要支持多少工具?越多的工具意味着越大的上下文压力
  • 你需要第三方扩展吗?那就需要考虑安全和质量控制
  • 你能不能延迟加载工具的 schema?模型不用的工具不需要提前描述

决策五:子 agent 架构

Agent 派生子任务时,子任务和父任务共享上下文还是各自独立?

三种方案:

隔离上下文 + 摘要回传(Claude Code):每个子 agent 在自己的上下文窗口里工作。完成后只把摘要还给父 agent,完整历史不进入父级上下文。防止上下文爆炸。但子 agent 之间没法共享细粒度的状态。

共享上下文:所有 agent 看到同样的信息,协作顺畅。但 N 个 agent 可能消耗 N 倍的上下文空间。

消息传递(Actor 模式):agent 之间通过消息通信。边界清晰。但需要设计通信协议。

Claude Code 的数据:子 agent 会话的 token 消耗大约是标准会话的 7 倍。如果用共享上下文方案,这个倍数还要更高。只回传摘要是控制成本的必要手段。

7 倍是一个让人重新考虑子 agent 使用频率的数字。不是说不能用子 agent,而是说每次派生子 agent 都应该有明确的理由:这个任务如果在主上下文里做,会严重污染上下文;或者这个任务需要不同的权限配置。

权限继承

子 agent 的权限配置值得单独说。

默认情况下,子 agent 用自己的 permissionMode 运行。但如果父 agent 处于 bypassPermissionsacceptEditsauto 模式,父 agent 的权限会覆盖子 agent 的默认设置。

这个逻辑是:用户的显式决策优先。如果用户已经决定了"我信任这个 Agent,让它自由运行",子 agent 不应该再弹出权限提示。

你应该问自己的问题

  • 你的子任务需要看到彼此的工作成果吗?
  • 你怎么防止 N 个子 agent 消耗 N 倍上下文?
  • 子 agent 继承父 agent 的权限,还是建立自己的权限?

决策六:会话持久化

会话结束后保存什么?下次恢复时恢复什么?

三种方案:

Append-only JSONL(Claude Code):所有事件追加写入 JSONL 文件。可审计,可重建,简单。查询能力弱。

数据库:支持复杂查询,检索速度快。但引入了外部依赖,降低了透明度。

无状态:最简单。但没有 resume、没有 fork、没有审计记录。

Claude Code 的选择反映了一个明确的优先级排序:审计性 > 查询能力。

你可以用 cat 命令看完整的对话历史。你可以用 grep 搜索特定的工具调用。你可以用 git 追踪会话文件的变化。不需要安装数据库,不需要写 SQL,不需要专用的管理工具。

代价是你没法高效地做复杂查询。比如"找出过去一周所有涉及文件删除的操作",在 JSONL 上做这件事需要扫描所有文件。如果用数据库,一条 WHERE 语句就行。

权限不跨会话持久化

这是一个 Anthropic 做了明确表态的设计决策:恢复会话时,权限永远不自动恢复

上次你 approve 了某个工具,这次恢复会话还得再 approve 一次。每个会话都从零开始建立信任。

这会造成用户摩擦。但 Anthropic 认为安全不应该有"记住我"功能。如果你的设备在两次会话之间被入侵了,自动恢复上次的权限等于自动给攻击者开权限。


三个反复出现的元模式

跨六个决策看下来,Claude Code 的架构里有三个反复出现的模式:

渐进分层而不是单一方案。 安全有 7 层,上下文压缩有 5 层,扩展机制有 4 级成本,权限有 7 种模式。每一个复杂问题都被拆成了多个独立的层级,从低成本到高成本排列。

这个模式的好处是弹性:你不需要一上来就用最重的方案,大部分时候轻量方案就够了。坏处是调试困难:一个行为可能是多个层级组合的结果,定位问题需要理解整个层级栈。

Append-only 设计,审计性优先于查询能力。 会话日志是 append-only 的 JSONL。上下文压缩(Context Collapse)是非破坏性的读取投影。磁盘上的数据永远不会被就地修改。

这个选择让数据恢复变得简单(所有原始数据都在),让审计变得简单(完整的历史记录),但让数据查询变得困难(没有索引,没有关系映射)。

模型判断 + 确定性 harness。 1.6% 对 98.4% 的比例不是偶然的。模型负责理解意图、选择工具、生成代码,这些需要判断力的事情。Harness 负责权限检查、上下文管理、错误恢复,这些需要可靠性的事情。

模型的输出是概率性的,可能出错。Harness 的行为是确定性的,不会出错(或者说,出错是 bug 而不是概率)。把这两类职责分开,让整个系统的可靠性不完全依赖模型的表现。


如果你要自己做

基于这六个决策框架,我整理了一个快速检查清单。不是说 Claude Code 的选择就是最优的,而是说这些问题你都得想清楚:

  1. 你打算用多少脚手架来约束模型的行为?你的场景对可预测性的要求有多高?
  2. 你的安全策略的各个层之间是否有独立的失效模式?初始化阶段的安全你考虑了吗?
  3. 你的上下文管理策略在窗口用完时会怎样?你有几级降级方案?
  4. 你的扩展机制是不是每个都消耗上下文?有没有零成本的选项?
  5. 子 agent 回传什么给父 agent?完整历史还是摘要?你能承受多少倍的 token 消耗?
  6. 会话恢复时自动恢复权限吗?你的审计需求是什么?

这些问题没有标准答案。Claude Code 选了一套答案,OpenHands 选了另一套,SWE-Agent 又是另一套。你的选择取决于你的用户群、安全要求、预算约束和技术偏好。重要的是每个决策都经过了有意识的权衡,而不是随手一写就定了。


上一篇:核心机制深潜 下一篇:论文精读与剖析

评论