Skip to main content

Claude Code

Written: 2026.05 Claude Code 本身就是 T0 级别的 Vibe Coding 工具,非常值得大家学习。不要把视野只局限在自己公司的工具上,比如腾讯内部可能会用 CodeBuddy,但不同工具之间的差异其实很大 很多厉害的人,慢慢都会倾向于使用 Claude Code。之前面试时,面试官问我会用什么 Vibe Coding 工具,我就回答 GitHub Copilot。当时我还觉得这只是一个很普通的问题,后来才意识到:你如何使用和比较这些工具,本身就能体现你是否关注时代变化,是否能聪明、高效地使用 AI 真正厉害的人,一定会主动使用最好的工具。这其实也是一种专业素养。面试官很喜欢问 /insights,而这正是 Claude Code 的一个特点。所以从面试角度看,我们确实也需要掌握 Claude Code 从实际使用层面来说,我也希望大家能真正用上 Claude Code,并且思考它和其他工具的区别。我们公司也在推荐使用 Claude Code,而整个行业也都在研究 Claude Code 该怎么用、怎么用得更好 举个例子,本节讲了如何用 Claude Code 做自动化。如果这套方法能用在你的工作里,那你绝对是领先行业的。在我们公司,真正研究 Claude Code 高级用法的人也只是少数。如果你能学会,并在工作中使用,比如用 Claude Code 自动完成工作测试或者部署,再分享给公司同事,一定会得到领导认可。同时,这些也可以在面试中讲出来,成为加分项 通过本期内容,你会了解 Claude Code 的相关用法和知识。但更重要的是,希望你真正把它用起来。用起来之后,把这些技巧迁移到自己的工作中,提高自己使用 AI 工具的能力。这会成为新时代非常重要的技能护城河

1.Claude Code概述

1.1 什么是 Claude Code

Claude Code 是 Anthropic 推出的 AI 编程 Agent。以对话的方式帮助开发者构建、调试、重构代码,以及构建自动化工作流。它不同于传统的代码补全工具(如 GitHub Copilot),而是一个可以自主规划、执行任务、调用外部工具的智能代理 Claude Code 本质上是一个通用编程 Agent,并不与 Claude 模型强绑定。你可以用 Anthropic 官方订阅(Pro/Max 会员)或 API Key 驱动它,也可以配置环境变量让它使用国产大模型(如 GLM、MiniMax 等)驱动。市面上同类产品(Codex、OpenCode 等)的功能和用法与 Claude Code 高度相似,学会 Claude Code 就能举一反三

1.2 Claude Code 能做什么

Claude Code 可以:
  • 根据自然语言需求从零生成完整项目代码
  • 读取、修改、重构现有代码文件
  • 执行终端命令(安装依赖、运行测试、启动服务器等)
  • 调用 MCP 外部工具(连接 Figma、GitHub、数据库、Slack 等第三方服务)
  • 构建并自动执行复杂的多步骤自动化工作流
  • 并发运行多个子任务(SubAgent 并行处理)
  • 自我修复:遇到错误时能分析原因、修改代码、重新测试
一个实际案例:在一次对话中,Claude Code 自动发现并抓取了 30 个 YouTube 频道的 187 个视频数据,生成了 6 张图表,制作了一份 9 页的 PowerPoint 演示文稿,导出到了 Google Sheets,并通过 Gmail 发送了带有 PDF 附件的周报 这一切只需要一段自然语言描述 实现过程简述: Plan Mode 下用一句话描述需求,Claude Code 联网调研后反问几个问题(追踪哪些频道、发送频率、收件邮箱等) Claude Code 自动生成项目结构:一个描述步骤的 Markdown 工作流文件 + 7 个 Python 工具文件(抓取数据、分析、生成图表、生成 PPT、发邮件、导出 Sheets、发现频道) 人工只需完成一件事:去 Google Cloud 控制台开通 YouTube Data API / Gmail / Sheets,下载 OAuth JSON 凭据文件拖入项目;API Key 填入 .env 文件 Claude Code 自动安装依赖、测试 API 连通性、跑完整流水线,发现问题自行修复 最终通过 Modal 将工作流部署到云端,配置每周一早 6 点定时触发,API Key 存为 Modal Secrets,不写入代码
想完整了解实现过程,参考视频:Master 95% of Claude Code in 36 Minutes 视频以这个 YouTube 周报自动化项目为主线,从界面安装到部署上线全程实操演示

1.3 访问方式

Claude Code 常见有三种访问方式:Claude-AppClaude-CLIIDE-Plugins,其中最推荐的是 Claude-CLI 形式
  • Claude-CLI:在终端直接执行 claude 命令启动,这是 Claude Code 的核心使用方式。它不依赖 IDE,适合项目开发、脚本自动化、服务器环境和长任务执行
  • Claude-App:通过 Claude 桌面端或网页端使用,更适合日常对话、资料整理、轻量代码问答和多模态输入,但不适合作为主力工程执行环境
  • IDE-Plugins:嵌入到 VS Code、Cursor 等编辑器中使用,优点是和代码编辑窗口结合紧密,适合边写边问;但自动化能力、终端控制和跨项目任务编排不如 CLI 直接
使用门槛上,Claude Code 需要 Claude 付费订阅,通常从 Pro 计划起可用,高频使用建议升级 Max

1.4 收费标准

Claude Code 包含在 Claude 的付费订阅中,无需单独购买。 • Pro: $17 / 月(按年付),约 $20 / 月(按月付)。包含 Claude Code 访问权、更多模型、无限 Projects、Deep Research、extended thinking、Google Workspace 集成、Remote MCP 集成等。适合入门和轻度使用 • Max: 从 $100 / 月起(按月付),可选 5x 或 20x 用量档位。在 Pro 基础上增加更高用量上限、更高输出限制、高峰期优先访问、新功能抢先体验。适合高频使用、复杂工作流和长对话场景 建议:初学者从 Pro 起步,一旦频繁跑自动化工作流、遇到用量限制,再升级到 Max

1.5 中国区安装

由于政策原因,中国区域是没法直接安装和使用 Claude Code,不过网上也有很多教程教你如何绕过这一限制,相关视频很多,大家可以自行搜索,这个过程还是需要花一些功夫去配置的,就像龙虾的安装,本身也是有一定门槛。但是网上资料很多,很多博主也会分享,相信你可以搞定的

2. 核心特性与用法

2.1 CLAUDE.md

是什么: CLAUDE.md 是放置在项目根目录(或用户目录)的 Markdown 文件,Claude Code 每次启动时会自动读取它,相当于给 Agent 的持久化系统提示。 解决什么问题: Claude Code 每次新会话都是“失忆”的,不知道你的项目结构、编码偏好、注意事项。CLAUDE.md 解决了这个问题,让 Agent 每次启动就能快速进入状态。 怎么用:
  • 在 Claude Code 对话中输入 /init,它会根据当前项目自动生成一份 CLAUDE.md
  • 输入 /memory 可以快速打开并编辑 CLAUDE.md
  • 分为项目级(放在项目目录,对该项目生效)和用户级(放在用户目录,对所有项目生效)
  • 内容可以包括:编码规范、项目结构说明、注意事项(比如“每次回答结尾都追加 Happy Coding”)、技术栈偏好等
CLAUDE.md
# 项目规范
- 使用 React + TypeScript + Vite 技术栈
- 所有组件必须有对应的单元测试
- 禁止在代码中硬编码任何 API Key
- 提交代码前必须运行 lint 检查
进阶:Rules 文件夹(.claude/rules/) 当规则越来越多时,单个 CLAUDE.md 会变得臃肿难维护。Claude Code 官方支持将规则拆分到 .claude/rules/ 目录下,按关注点分模块管理,Claude Code 启动时会自动读取所有文件:
目录结构
.claude/rules/
├─ security.md       # 安全规则:不能硬编码密钥,要验证输入
├─ coding-style.md   # 代码风格:不可变性、模块化
├─ testing.md        # 测试规则:TDD 流程、80% 覆盖率
├─ git-workflow.md   # Git 规范:提交格式、PR 流程
└─ agents.md         # 何时委托给 SubAgent
CLAUDE.md vs Rules 文件夹:两者功能相同,都是持久化系统指令;区别在于组织方式。 CLAUDE.md 适合放项目总览和简单规则,Rules 文件夹适合规则较多、需要分模块维护的团队项目,不同角色可以维护各自的规则文件。

2.2 三种交互模式

Claude Code 通过 Shift + Tab 键在三种模式间循环切换: 默认模式(底部显示 for shortcuts): 最谨慎,每次创建或修改文件前都会询问用户确认。适合对重要代码做修改时使用。 自动模式(底部显示 accept edits on): 本次会话内所有文件操作自动通过,不再打扰用户。适合已信任的任务,节省时间。 规划模式(Plan Mode)(底部显示 Plan Mode On): 只讨论、只阅读,不修改任何文件。Claude 会深入分析需求、阅读项目文件、提出问题、生成详细的执行计划,确认后才能切换到执行模式。这是处理复杂任务的推荐第一步。 注意: 即使在自动模式下,执行终端命令(如 npm installmkdir)仍然需要单独确认,因为这类操作被认为风险更高。如果想跳过所有权限检查,可以在启动时加 --dangerously-skip-permissions 参数,但官方已将 dangerously 写在参数名里警告风险,务必谨慎使用。

2.3 Checkpoints

是什么: Claude Code 每次提交修改前,都会自动为当前代码创建一个快照(回滚点) 怎么用:
  • 输入 /rewind 或连续按两次 ESC 进入回滚界面
  • 选择要回滚的时间点后,有四个选项:回滚代码+会话、只回滚会话、只回滚代码、放弃回滚
  • 也可直接输入 /checkpoints 查看文件级别的回滚点
局限性: Claude Code 只能回滚它自己写入的文件,由终端命令生成的文件(如 npm install 产生的 node_modules)无法回滚。精细回滚建议配合 Git 使用。

2.4 权限管理

是什么: 控制 Claude Code 可以执行哪些操作的机制 怎么用: 在对话中输入 /permissions 打开交互式权限菜单,可以将安全的操作(如运行测试、提交代码)加入白名单,将危险操作(如删除文件)加入黑名单 权限保存位置 settings.local.json(本地项目级,不提交 Git) settings.json(项目级,随 Git 分发给所有团队成员) • 用户目录配置(用户级,对该用户所有项目生效) 经验: 建议从保守权限开始,随着对工作流的信任逐步放开。权限设置是速度与安全的平衡。

2.5 Plan Mode

使用 Shift + Tab 切换到 Plan Mode(或在对话框按 Shift + Tab 两次)。 在规划模式下,Claude 会: • 深度阅读你的项目所有相关文件 • 通过提问澄清需求细节(如:频率是每天还是每周?是否需要导出到 Google Sheets?) • 生成包含目标、步骤、文件结构的详细执行计划 • 列出依赖项和注意事项 计划产出后有三个选项:直接执行(自动同意模式)、执行但保留逐步确认、继续修改计划 何时必须用 Plan Mode:处理重构、多文件改动、新功能开发等复杂任务前,强烈推荐先用 Plan Mode 规划,可以避免 Claude 误改文件、浪费 Token

2.6 Hooks

是什么: 在 Claude Code 工作流程的特定时机自动执行的脚本,无需人工干预 六种触发时机 PreToolUse:工具执行前(用于验证、提醒) PostToolUse:工具执行后(用于格式化、反馈) UserPromptSubmit:用户发送消息时 Stop:Claude 完成响应时(适合记录总结) PreCompact:上下文压缩前(适合保存重要状态) Notification:权限请求时 典型用法举例: 配置一个 PostToolUse Hook,在 Claude 写完代码后自动调用 Prettier 格式化文件,实现代码自动美化,整个过程无需用户操作 怎么配置: 输入 /hooks 进入配置界面,选择触发时机 -> 选择匹配的工具(如 WriteEdit)-> 填写具体执行命令。命令通过 JSON 标准输入接收上下文信息,其中 file_path 字段为刚编辑的文件路径 Hook 存储级别: 本地项目级(不入 Git)、项目级(随 Git 分发给团队)、用户级(对当前用户所有项目生效)

2.7 MCP

是什么: MCP 是一个开放协议,允许任何人为 AI Agent 构建和暴露外部工具接入。类比一个“通用 USB 接口”,只需连接一次,Claude 就能使用该服务的所有功能 与直接调用 API 的区别: 传统 API 调用需要开发者明确指定每个端点和参数。MCP 是一种提示驱动的封装,让 Claude 能自己判断调用哪个工具、传什么参数,更灵活 常用 MCP 场景: Figma MCP:Claude 可直接读取设计稿的截图、组件间距、字体样式,实现精准的设计稿还原 GitHub MCP:管理 PR、Issues、代码审查 Supabase/数据库 MCP:直接执行 SQL 查询,拉取特定数据 Gmail/Calendar MCP:发送邮件、创建日历事件 Slack MCP:读取和发送消息 怎么用: 输入 /mcp 查看已安装的 MCP 工具及其状态;安装 MCP Server 后重启 Claude Code 生效;使用 /mcp 可以进入认证、查看工具列表等操作 多模态输入: 除了 MCP,也可以直接向 Claude Code 传图片。将图片拖入对话框,或复制图片后按 Ctrl+V(macOS 也是 Ctrl+V,不是 Command+V)粘贴

2.8 Skills (Agent Skill)

是什么: 技能文件(Skill.md)是预定义的指令集,包含名称、描述和具体步骤说明。Claude Code 根据用户请求自动识别并加载相关 Skill,而不是每次都重新理解相同的流程 CLAUDE.md 的区别: CLAUDE.md 是每次都加载的全局记忆;Skill 是按需动态加载的,只在需要时才占用上下文窗口,更节省 Token 与 MCP 的区别: MCP 负责获取数据和执行外部操作;Skill 是知识型的自定义指令,相当于“告诉 Claude 怎么做某件事”的操作手册 技能存放位置:
  • 全局:~/.claude/skills/(对所有项目生效)
  • 项目:项目目录下的 .claude/skills/
怎么触发:
  • 自动触发:Claude 识别到请求与某个 Skill 相关时,自动请求用户确认加载
  • 手动触发:在输入框中输入 /技能名称 直接调用
Skill 文件结构示例(以每日日报 Skill 为例)
---
name: daily-report
description: 当用户要求写每日总结时调用此技能
---
日报格式要求、日期
- 开发摘要(不超过3条)
- 开发详情(每条需包含:实现内容、遇到的问题、解决方案)
- 明日计划

2.9 SubAgent

是什么: SubAgent 是独立运行的 Claude 实例,拥有完全独立的上下文、工具集和权限,专注于完成某一特定任务,完成后只向主代理汇报最终结果 与 Agent Skill 的核心区别: Agent Skill 运行时完全继承并共享当前主对话的上下文,执行过程中产生的所有中间日志和思考过程都会进入主上下文,容易造成 Token 膨胀 SubAgent 拥有独立上下文,执行的所有中间过程(读了哪些文件、中间分析过程)都不回传给主对话,只返回最终结果,主对话上下文始终保持干净 适用场景:
  • Agent Skill 适合:与主上下文关联紧密,不会产生大量中间数据的任务(如“写一份今日开发总结”)
  • SubAgent 适合:需要大量探索,会产生海量中间上下文的任务(如“审查整个代码库的安全漏洞”)
怎么创建: 输入 /agentCreate new agent → 选择项目级或用户级 → 选择 Claude 辅助生成或手动创建 → 填写任务描述 → 选择可用工具(如只读工具) → 选择模型和角色

2.10 Plugins

是什么: 将多个 Skill、Hook、SubAgent、MCP 等能力打包成一个可安装单元,类似 macOS 的 DMG 安装包。一键安装即获得整套能力,方便团队共享配置 怎么用: 输入 /plugin 进入插件管理器 → Discover 发现新插件,Installed 查看已安装,Marketplaces 管理插件市场 推荐插件: frontend-design:打破大模型“深紫色主题”惯性的前端设计 Skill,让生成的界面更有设计感 hookify:用对话方式创建 Hook,无需手写 JSON 配置 typescript-lsp / pyright-lsp:在编辑器外使用 Claude Code 时提供类型检查和智能补全 mgrep:比 ripgrep 更高效的代码搜索工具,平均减少约 50% 的 Token 消耗

2.11 上下文管理

Claude Code 拥有约 200,000 Token 的上下文窗口,管理好上下文是高效使用的关键 查看上下文: 输入 /context 查看当前上下文的用量分布(CLAUDE.md、Skill、MCP 工具描述、对话历史各占多少) 压缩上下文: 输入 /compact(可附加保留策略,如“重点保留用户的原始需求”),Claude 会将对话压缩为摘要,保留关键决策,释放空间 清空上下文: 输入 /clear 完全清空所有上下文。适用于开始一个全新的、与之前任务完全无关的任务 恢复历史对话: • 输入 /resume 可查看历史会话列表并选择恢复 • 启动时加 -c 参数(claude -c)自动恢复上次的对话 后台任务管理: • 启动的服务器或长时命令会阻塞 Claude Code,按 Ctrl + B 将其放入后台 • 输入 /tasks 查看后台运行的任务 • 在任务界面按 K 可终止任务

2.12 斜杠命令

常用斜杠命令速查:
• /init — 自动生成当前项目的 CLAUDE.md
• /memory — 快速打开 CLAUDE.md 编辑
• /compact — 手动压缩上下文
• /clear — 清空所有上下文
• /context — 查看上下文用量
• /rewind — 进入代码回滚界面
• /checkpoints — 查看文件级回滚点
• /resume — 恢复历史对话
• /tasks — 查看后台任务
• /mcp — 查看和管理 MCP 工具
• /hooks — 配置 Hook
• /skills — 查看已安装的 Skill
• /agent — 创建和管理 SubAgent
• /plugin — 插件管理器
• /permissions — 权限管理
• /fork — 分叉当前会话,用于并行执行不重叠的任务
• /rename — 重命名当前会话
• /insights — 生成个人 Claude Code 使用分析报告
• /statusline — 自定义状态栏显示内容

2.13 Insights

这个是最近(2026.3月)面试喜欢考的一个特性
Claude Code 的 /insights 命令可以分析你所有的历史使用数据(跨项目),生成一份 HTML 格式的个人使用报告,保存在用户目录的 ~/.claude/usage-data/report.html 位置 报告内容包含:
  • 你使用 Claude Code 的典型模式和习惯
  • 做得好的地方(Impressive Things)
  • 哪些地方在阻碍你的效率(Where Things Go Wrong)
  • 值得尝试的新功能和使用模式
  • 工作流自动化建议
实用技巧: 生成报告后,可以将 HTML 文件上传给 ChatGPT 或其他 AI 工具,让它提炼最值得执行的 3-5 条行动建议(用不同 AI 分析避免数据偏向性)

3. 最佳实践经验

以下最佳实践来自 everything-claude-code 项目(Anthropic Hackathon 获奖作品,作者每日使用 Claude Code 超过 10 个月的实战总结)

3.1 项目初始化必做三件事

在任何新项目开始前,先完成以下配置,后续效率会高很多: 第一件: 创建 CLAUDE.md,写清楚技术栈、编码规范、项目结构、禁止事项(如禁止硬编码密钥、禁止使用 emoji 等) 第二件: 如果是说项目本身的描述比较多,可以将 CLAUDE.md 的内容下放 Rules 文件夹(.claude/rules/),按关注点分模块管理规则(但并不是所有项目都必须写 rules,项目简单规则就放在 CLAUDE.md 中就行):
CLAUDE.md
security.md       # 安全规则:不能硬编码密钥,要验证输入
coding-style.md   # 代码风格:不可变性、模块化
testing.md        # 测试规则:TDD 流程、80% 覆盖率
git-workflow.md   # Git 规范:提交格式、PR 流程
agents.md         # 何时委托给 SubAgent
第三件: 选择合适的 Skill 和 MCP,使用 /plugin 一键安装团队共用配置

3.2 先规划,再执行(Plan Mode 优先)

复杂任务一定要先进入 Plan Mode,让 Claude 充分理解需求后再执行。盲目执行会导致:
  • 修改了错误的文件
  • 产生大量无用的中间 Token 消耗
  • 后期难以回滚
Plan Mode 中,尽可能把需求描述清楚,包括目标、功能点、边界条件、期望输出格式,Claude 会主动提问补充细节

3.3 控制上下文,定期”清理”

上下文窗口满了之后,Claude 的表现会急剧下降(变慢、变傻),建议:
  • 关闭不需要的 MCP:即使安装了 20-30 个 MCP,也只保持少于 10 个处于启用状态,活跃工具不超过 80 个。过多的 MCP 工具描述会占用大量上下文,200k 的窗口可能只剩 70k 可用
  • 在完成一个大阶段任务后,手动执行 /compact 压缩,保留关键决策,释放空间
  • 开始全新任务前用 /clear 完全清空,避免旧上下文干扰
  • /context 定期检查上下文用量,在自动压缩前主动手动压缩以获得更好的控制效果

3.4 跨会话记忆持久化

Claude Code 默认不跨会话记忆,可以通过以下方式解决: 方案一:Session 文件: 在每次会话结束前,让 Claude 生成一份会话总结文件,记录:本次完成了什么、什么方式有效、什么方式无效、还剩什么未完成。下次会话开始时,提供这个文件路径即可续上 方案二:Stop Hook: 配置一个 Stop Hook,在每次 Claude 完成响应时自动将关键信息追加到 .claude/session.md 文件,下次启动时加载。使用 Stop Hook 而非 UserPromptSubmit(每条消息都触发),避免增加响应延迟 方案三:动态系统提示注入:
动态系统提示注入
# 按上下文切换不同的记忆文件
alias claude-dev='claude --system-prompt "$(ca

3.5 SubAgent 模式提升效率

两实例启动模式: 新项目开始时,同时打开两个 Claude Code 实例:
  • 实例一(Scaffolding Agent):负责搭建项目骨架、建立 CLAUDE.md 和 Rules
  • 实例二(Research Agent):负责调研技术选型、生成详细需求文档(PRD)、绘制架构图
顺序执行模式(Orchestrator with Sequential Phases):
Multi-Agent 协作流程
第一阶段:用 Explore 子Agent做代码调研 -> 输出 `research-summary.md`
第二阶段:用 Planner 子Agent制定计划 -> 输出 `plan.md`
第三阶段:用 TDD-Guide 子Agent实现代码 -> 输出代码变更
第四阶段:用 Code-Reviewer 子Agent审查 -> 输出 `review-comments.md`
第五阶段:如有构建错误,用 Build-Error-Resolver -> 循环直到通过
每个子Agent接收一个明确的输入文件,产出一个明确的输出文件,前一阶段的输出是下一阶段的输入,使用 /clear 在各阶段之间隔离上下文

3.6 Token 优化策略

模型选择策略(根据任务复杂度降级使用更便宜的模型):
  • 代码库探索、文件搜索 → Haiku(速度快、成本低,够用)
  • 单文件改动 → Haiku
  • 多文件实现 → Sonnet(编程任务最优平衡)
  • 复杂架构设计 → Opus(深度推理)
  • 安全漏洞分析 → Opus(不允许遗漏)
  • PR 审查 → Sonnet
  • 写文档 → Haiku
90% 的编程任务使用 Sonnet 即可。首次尝试失败、跨越 5+ 文件、架构决策、安全关键代码时升级到 Opus 代码模块化: 将代码拆分为小文件(几百行而非几千行)不仅是好的工程实践,也直接降低 Token 消耗,提高首次执行成功率 工具替换: 使用 mgrep 替代 grep / ripgrep,在 50 个任务的基准测试中,mgrep 平均减少约 50% 的 Token 消耗,查询质量持平或更优

3.7 有效的提示与沟通技巧

  • 把需求当作给团队成员写 SOP: 越具体越好,包含目标、输入、输出、边界条件
  • WAT 框架(Workflows-Agent-Tools):将任务分为工作流(markdown SOP)、代理(负责任协调)、工具(Python 脚本执行具体操作)三层,分离概率性 AI 推理和确定性代码执行
  • 不要只描述目标,还要描述你的顾虑:在让 Claude 部署代码前,说“先做安全审查,确保 API Key 没有暴露,然后再告诉我部署方案”
  • 反复出现的提示应该变成 Skill:如果你发现自己多次给 Claude 相同的指令,就应该把它写成 Skill 文件,让 Claude 自动加载
  • Ctrl+G 打开 VSCode 编辑器输入框:当在终端输入框里需要多行复杂提示时,按 Ctrl+G 打开 VSCode 编辑,方便多行修改,保存后自动回填

3.8 安全最佳实践

  • 绝对不要将 API Key 硬编码进任何文件,应使用环境变量(.env 文件)或 Modal Secrets 等密钥管理服务
  • **部署前主动要求安全审查:**让 Claude Code 检查代码中的漏洞,特别是 Webhook 是否有认证、Key 是否暴露
  • **在 CLAUDE.md 中明确禁止规则:**如“禁止在代码中包含任何 API Key 或密码”
  • **精确控制 SubAgent 的工具权限:**代码审查 SubAgent 只需只读工具,不应有写权限
  • 使用沙盒模式测试可能影响系统的危险操作
  • --dangerously-skip-permissions 意味着 Claude 拥有和你一样的终端权限,仅在受控的开发环境中使用

3.9 并行工作流

Fork 对话: 输入 /fork 分叉当前会话,在两个分支上并行执行不重叠的任务(例如:一个分支做后端 API 开发,另一个分支做前端 UI 开发) Git Worktrees 多实例并行: 当多个 Claude 实例需要在有代码重叠的分支上并行工作时,使用 Git Worktrees 避免冲突:
Git Worktrees
git worktree add ../feature-branch-a feature-a
git worktree add ../feature-branch-b feature-b
不同目录分别启动 Claude 实例
Cascade 方法: 在多终端并行时,用从左到右的顺序组织标签页(最旧的在左),使用 /rename 给每个会话命名,专注于最多 3-4 个并行任务,避免在过多实例间切换引发混乱。 原则: 以最少的并行实例完成最多的工作,并行不是越多越好。

3.10 连续学习机制

当 Claude 发现了有价值的调试技巧、项目特定的模式或处理边界情况的方法时,将这些经验保存为新的 Skill 文件,下次遇到类似问题时自动加载,避免重复“教” Claude 同样的知识,节省大量 Token 和时间

4.ClaudeCode 源码解读 / 架构拆解

26年三月底,Claude Code 源码泄露。一经泄露,面试就成近期必考的问题。有同学反应面试官直接问他,Claude Code 代码泄露 2 天了?你还没看吗?所以对于这一部分,近期是非常重要的考点 另外其实除开最近热点事件外,学习 ClaudeCode 本身就是非常有帮助的,他本质是一个 CodingAgent。我们学习 Agent 可以分成三步:
  1. 掌握了 Agent 的基础知识 .
  2. 可以典型的 Agent 架构,比如笔记已经有的 Openclaw 架构分析,本期的 Claude Code 架构以及马上会出的字节的 Deerflow2.0 的 Agent 架构,建立审美。
  3. 设计一个自己的 Agent 项目架构,写文档,用 Harness 工程来完成。
有了项目后,我们就可以面试了。所以学习经典的 Agent 架构是很有帮助的,本节就一起来学习这个经典的 CodingAgent - Claude Code

4.1 事件概述

这节就讲下事件起因,大家看看就好,了解事件的来龙去脉。算是近期(2026年4月)的一个谈资

4.1.1 怎么泄漏的

2026 年 3 月底,安全研究者 Chowan Chow 发现 Anthropic 发布在 npm 上的 @anthropic-ai/claude-code@2.1.88 包中意外包含了一个约 60MB 的 source map 文件(.map),这个调试文件直接映射回了 Claude Code 的完整未压缩 TypeScript 源码,甚至可以通过 Anthropic 自己的 R2 云存储桶以 zip 包形式直接下载。一共 1,902 个文件,约 51.2 万行 TypeScript 代码就此公之于众 根本原因是一个低级的配置遗漏,开发团队忘记在 .npmignore 中添加 *.map。Claude Code 的创建者 Boris Cherny 确认这是人为失误,与打包工具 Bun 的 bug 无关。讽刺的是,这已经是第二次发生同样的错误。Anthropic 随后迅速发起 DMCA 下架通知,但代码已被广泛分发归档,无法收回。需要明确的是,此次泄漏仅涉及产品代码(Agent 框架),不包含任何客户数据、API 密钥或模型权重

4.1.2 泄漏揭示了什么

泄漏的代码完整揭示了 Claude Code 的内部架构。它本质上是一个用 TypeScript 编写的 AI Coding Agent,核心是经典的查询循环(Query Loop)+ 工具系统架构,外加多层记忆系统、上下文压缩算法、权限与安全机制等工程组件。本文后续章节将从以下几个维度逐一深入分析:
  • 核心架构: Query Loop、工具系统、System Prompt 分层设计、终端 UI 引擎
  • 记忆与上下文: 多层记忆架构、5 级上下文压缩(Compaction)策略
  • 安全与权限:** 权限模式、YOLO Classifier、Prompt Injection 防御
  • 多 Agent 协作: 子代理模型(Fork / Teammate / Work Tree)、Coordinator Mode
此外,代码中包含 44 个编译时 Feature Flag,暴露了大量尚未公开的内容:
  • 未发布功能: 24/7 自主守护进程 Kairos、记忆整合的 Dream System、30 分钟深度规划 Ultra Plan、反蒸馏防御 Anti-Distillation、卧底模式 Undercover Mode 等
  • 未发布模型: Capybara/Mythos(全新产品线)、Numbat(完全未知)、Opus 4.7 / 4.8 等下一代模型代号

4.1.3 社区反应

这里我们在笔记的 Harness Engineering 工程中,来讲解这个 Claw Code 开源项目。学习这个项目,可以进一步帮助理解 Harness 工程(无疑这个也是 26 年的高频考点)。你自己其实也可以更深入学习这个项目,自己仿照这个也来做一个 Claude Code,是一个很好的学习 Claude Code、Agent 的机会,同时也是一个练手 Harness 工程的机会。具体请看笔记的 Harness 工程的 Claw Code 讲解
泄漏发生后数小时内,社区迅速行动:有开发者连夜将核心功能从 TypeScript 移植到 Python(以规避 DMCA 版权风波),推送到 GitHub 后迅速成为有记录以来最快达到 10 万星的仓库(Claw Code),随后又被用 Rust 重写了一遍。甚至有人用 Claude Code 本身生成了一个 PR,试图将全部泄漏源码提交回 Anthropic 的官方仓库 一个讽刺性的版权争议也随之浮现:如果 Anthropic 声称的“80% 的代码由 AI 编写”为真,那么根据美国现行法律,AI 生成的内容不受版权保护,Anthropic 理论上没有 DMCA 下架的法律基础

4.2 记忆功能

其实大家看各种 Agent 的开源项目,每个 Agent 项目,我们都需要关注最重要的几个点,也是 Agent 项目的核心:比如记忆、架构、Agent 的交互对吧。所以不管看哪个 Agent 项目,都该特别解析关注这个记忆模块。我们在笔记的 openclaw 部分已经解析了小龙虾的记忆功能,今天我们来看 ClaudeCode 的记忆功能,二者对比,体会成熟的 Agent 项目的记忆功能背后的设计哲学
学习 Agent 的记忆模块的设计可以从这几个方面思考: 它由什么组成(4 种记忆存储),以及它怎么运作(加载、压缩、写入三大策略)。我们笔记按这个思路来讲。下图是 Claude Code 记忆功能架构 image.png

4.2.1 四层记忆存储

指令文件其实在 CC 的核心用法就讲过,这里 Claude.md 系列文件的维护,需要人工维护的。
1.指令文件(CLAUDE.md 族)—— 人写的规则 唯一由人手动编写的记忆,告诉 Claude 项目的规则和约束。分 4 个层级:
  • 管理员全局/etc/claude-code/CLAUDE.md —— IT 管理员设定的全局规则
  • 用户全局~/.claude/CLAUDE.md —— 个人偏好(跨项目生效)
  • 项目级CLAUDE.md.claude/CLAUDE.md.claude/rules/*.md —— 随 Git 提交,团队共享
  • 本地私有CLAUDE.local.md —— 不提交 Git,个人使用
支持 @include 指令引用其他文件。上限 40,000 字符。Boris(Claude Code 工程负责人)建议写法是短、有主见、可操作,不是项目历史小说,而是决策规则和约束
就是大模型多轮对话的数组,每个 Agent 都有
2.对话上下文(messages[])—— 短期记忆 当前对话的消息数组,所有 LLM 应用都有。Claude Code 的特别之处在于配套了一套多层压缩策略来管理它
这个就是随着每次会话记录的,Claude Code特有的设计
3.Session Memory —— 当前会话的结构化笔记 一个后台子代理(Fork Agent)在你工作时同时持续维护的结构化笔记文件。不是上下文压缩,而是独立的信息提取。内容包括:任务标题和描述、当前状态、涉及的文件列表、遇到的错误和解决方案、经验教训、工作日志 触发条件: 对话 token 超过 10K 后启动,之后每 5K tokens 更新一次。后台执行,不阻塞工作 它的价值:
  • /resume 恢复会话时,从这个文件快速恢复上下文,无需重新喂全部历史
  • 上下文压缩时可作为摘要来源(见 3.1.3 第 3 层)
  • /skillify 可以将其转化为可复用的 SKILL.md 文件
4.持久记忆(Memdir)—— 跨会话的长期记忆 最核心的长期记忆系统,位于 ~/.claude/memory/。存 4 类信息:
  • user:用户角色、偏好、技能水平。例:“偏好函数式风格”、“是后端工程师”
  • feedback:用户对 AI 的纠正和确认。例:“上次用 forEach 被要求改成 map”
  • project:项目目标、决策、截止日期。例:“Q3 要迁移到 TypeScript”
  • reference:外部系统指针。例:“Bug tracker 在 Linear: xxx”
注意这里故意不存代码事实(如“函数 X 在第 30 行”),因为代码会变但记忆不会自动更新,过时的代码记忆会变成危险的误导。代码相关的事实永远用 grep/glob 实时搜索,只有人的偏好和判断才值得持久化 存储结构:
记忆目录结构
~/.claude/memory/
├─ MEMORY.md                ← 索引文件(每次会话自动加载)
├─ user_role.md             ← 主题文件:用户角色
├─ feedback_testing.md      ← 主题文件:测试相关反馈
├─ project_migration.md     ← 主题文件:迁移计划
└─ reference_tracker.md     ← 主题文件:外部系统指针
MEMORY.md 是索引,不存记忆内容本身。每行只有一个指向主题文件的链接和一句话摘要(≤150 字符),格式如- [用户角色](user_role.md) — 后端工程师,偏好函数式风格。上限 200 行 / 25KB 实际的记忆内容存在各个主题文件中,按语义主题命名(不是固定 4 个文件),每个文件带 YAML frontmatter 声明 namedescriptiontype(对应上面的 user / feedback / project / reference 四种类型)。查询时系统通过扫描 frontmatter 来判断哪些文件与当前对话相关 团队记忆: Memdir 下有 team/ 子目录,支持跨用户共享的项目记忆。会话开始时自动同步。敏感信息(API 密钥等)禁止存入。Feature flag TEAMMEM 控制

4.2.2 上下文组装

每轮对话开始时,系统从上述 4 种存储中组装完整的上下文注入 system prompt 指令文件的加载: 所有层级的 CLAUDE.md 都会被拼接在一起注入,不会互相覆盖。但拼接顺序有讲究。源码注释写道: “Files are loaded in reverse order of priority, i.e. the latest files are highest priority with the model paying more attention to them.” 这利用了 LLM 的一个已知特性:模型对 prompt 末尾的内容天然给予更高注意力(recency bias)。因此排在后面的文件在实践中“优先级更高” 加载顺序(排在越后面,模型越关注):管理员全局 → 用户全局 → 项目级 → 本地私有。举例:如果管理员规则说“用 npm”,但项目级 CLAUDE.md 说“用 pnpm”,模型会倾向于遵循后者 持久记忆的加载
  1. MEMORY.md 前 200 行每次会话自动加载到 system prompt
  2. 用 Sonnet(非主力模型,不是主模型 Opus)扫描所有记忆文件的标题和 frontmatter 描述,选出最多 5 条最相关的,作为 relevant_memories 附注入上下文
  3. 排除本次会话已召回过的记忆(避免重复)
  4. 超过 1 天的记忆自动过期警告: “这条记忆是 N 天前的… 关于代码行为的声明可能已过时,请先验证。”
  5. 会话总预算 60KB
值得一提的是,记忆召回没有使用 RAG(检索增强生成)。Boris 在播客中透露,早期版本曾尝试过本地向量数据库 + 云端 embedding 的 RAG 方案,但遇到了多个问题: 代码修改后索引不同步(新写的函数搜不到)、索引的权限管控复杂(谁能访问、如何防止越权)。最终发现 agentic search(模型自主调用 glob + grep)全面优于 RAG
Boris 的原话是: “agentic search just outperformed everything, and when I say agentic search, this is a fancy word for glob and grep.”

4.2.3 压缩

压缩是 Agent 里面的一个核心技巧。怎么样压缩保证模型能记住最重要的东西,直接影响接下来对话的好坏。我们可以看到 Claude Code 的压缩策略其实非常复杂,是用心在设计的
对话越来越长,上下文窗口终会被填满。Claude Code 设计了一套 5 层压缩流水线,在每轮查询循环中按固定顺序依次执行,每层有独立的触发条件,不是每层每次都触发,而是逐层检查、按需执行,越往后越激进:
Claude Code 5层压缩流水线
第1层 Tool Result Budget  ← 每轮都跑,限制单条消息体积
第2层 Microcompact        ← 清理旧工具结果内容
第3层 Auto-compact        ← 触发 LLM 做全量摘要(核心层)
第4层 Blocking Limit      ← 硬拒绝:上面都压不下来就报错
第5层 Reactive Compact    ← API 返回 413 后的兜底重试
第一层是为了压缩工具,如果工具调用结果返回内容太多,就只给索引,按需加载。有点像 Skill 的思想,渐进式披露
第 1 层:Tool Result Budget(工具结果预算) 每轮都执行。当你一轮让 Claude 跑了多个并行工具调用(比如 6 个 grep),每个返回几十 KB,单条消息的工具结果累计可能超过 200K 字符的预算上限。这时系统会把最大的工具结果存到磁盘,原位替换成约 2KB 的预览 + 文件路径。模型后续需要完整内容时,可以用 Read 工具去读磁盘上的完整文件。这本质上是一种“渐进式披露(Progressive Disclosure)”的思想:先给模型足够判断的预览,让它自己决定要不要加载全量。很多时候 2KB 预览就够用了,完整文件可能永远不会被读取
这一层设计就是为了清理工具。多轮调用后,工具的结果会一直跟随在上下文中(没压缩前)。这里要解决的核心就是适当处理过期的工具调用结果
第 2 层:Microcompact(工具结果清理) 理解这一层需要先了解 Prompt Cache 机制: Claude Code 的每次 API 调用都会把完整对话历史(system prompt + 所有消息)重新发送给服务端。随着对话进行,这个输入可能达到 100K+ tokens。服务端会缓存这个输入的前缀(TTL 约 60 分钟),后续请求如果前缀相同就直接复用,不需要从头处理 这缓存的是“你发过去的问题”,不是“模型返回的回答” 这意味着:如果客户端修改了对话历史中的任何旧内容,前缀就变了,缓存失效,服务端要重新处理全部 tokens,更贵、更慢 这一层要解决的问题是:怎么清理旧的工具结果,同时尽量不破坏这个输入缓存。有两个子策略,按优先级尝试,命中一个就停:
  1. 基于时间的 Microcompact: 如果距上次助手回复超过 60 分钟(缓存 TTL 已自然过期),直接将旧的工具结果内容替换为 [Old tool result content cleared],只保留最近 5 条 适用的工具类型: ReadBashGrepGlobWebSearchWebFetchEditWrite 因为缓存已经失效,直接改内容不会有额外损失。
  2. 基于缓存编辑的 Microcompact(Anthropic 内部): 客户端消息完全不改,而是额外发一条 cache_edits 指令,告诉服务端“在你缓存的副本里删掉这些工具结果” 这样 prompt 前缀不变,缓存继续有效,省钱 客户端本地的消息数组保持完整(用于 session 持久化、resume 等),但模型实际看到的上下文已经被浓缩了
如果两个都不适用,本层不做任何压缩,把压力交给后面的 Auto-compact
上面两层都是在上下文窗口还没有很大的时候就尝试压缩,这是 Claude Code 的巧思。很多 Agent 都是在上下文快满了才压缩,包括 openclaw。第三步,自动压缩也就是所有 Agent 都会做的,窗口满了,一定要压缩的策略。
第 3 层:Auto-compact(自动全量压缩)—— 核心层 触发阈值(以 200K 上下文窗口为例):
触发阈值
有效窗口 = 200,000 - min(maxOutputTokens, 20,000) = 180,000
自动压缩阈值 = 180,000 - 13,000 = 167,000 tokens
即当前对话 token 数超过 167K 时自动触发 触发后有两个子策略,先尝试轻量的,不行再用重量的:
  1. Session Memory Compact(轻量) 用已经由后台代理提取好的 Session Memory 文件作为摘要,保留最近 10K~40K tokens 的原始对话(至少保留 5 条含文本的消息)不需要额外的 LLM 调用,所以很便宜
  2. Full LLM Compact(重量) 把整段对话发给 LLM 做结构化摘要。摘要输出上限 20K tokens,包含 9 个固定段落:
    • 核心请求(Primary Request)
    • 关键概念(Key Concepts)
    • 涉及文件列表(Files)
    • 代码错误与修复(Errors)
    • 问题解决过程(Problem Solving)
    • 所有用户消息(User Messages)
    • 待办事项(Pending Tasks)
    • 当前工作(Current Work)
    • 下一步计划(Next Step)
  3. 压缩后自动恢复文件上下文: 压缩会丢弃旧消息,但会话期间所有被读过、写过、编辑过的文件都记录在 readFileState 缓存中(包括 agent 调用 FileRead / FileEdit / FileWrite / Bash 工具操作的文件,以及 memdir 系统和 Sonnet 预取自动加载的记忆文件) 压缩完成后,系统会从这个缓存中排除 CLAUDE.md 和 Plan 文件(它们有各自的恢复机制),再按最近访问时间排序,取最多 5 个文件从磁盘重新读取(不用旧缓存,确保内容是最新的),以每文件 ≤5K tokens、总计 ≤50K tokens 的预算注入到压缩后的上下文中,让模型不需要在下一轮重新读取这些文件就能继续工作。如果会话中没有操作过任何文件,则不会恢复
  4. 防御机制: 连续失败 3 次后触发熔断,不再尝试。如果压缩调用本身也报 prompt-too-long,会从最旧的消息开始截断,最多重试 3 次
手动触发: 用户可以随时用 /compact 命令手动触发 Full LLM Compact,还可以附带提示词指定保留什么,比如 /compact 重点保留决策和待办事项。手动触发的阈值更宽松(buffer 只留 3K 而不是 13K) 和 Openclaw 的对比
这里我们不妨把两个架构的压缩策略对比
OpenClaw 只有一级压缩,但做得更精细 保留最近 ~20K tokens 原文不动,只压缩更早的旧消息,旧消息按 token 数分成多个块逐块总结,再合并成一个连贯摘要。压缩前还会静默运行一轮,提醒 Agent 把重要内容写入记忆文件(Pre-Compaction Memory Flush),防止关键信息随压缩丢失。压缩后结构为: [合并摘要] + [最近 ~20K tokens 原文] Claude Code 则是两级梯度设计 轻量级的 Session Memory Compact 效果类似 OpenClaw(摘要 + 保留最近原文),但摘要不是现场生成的,而是后台子代理提前维护好的,所以不需要额外 LLM 调用,更省成本。只有轻量级扛不住才上 Full LLM Compact 这一步更激进,把全部对话压缩成结构化摘要,旧消息全部丢弃 核心差异: OpenClaw 一步到位但精细(分块 + 合并 + 预刷记忆),Claude Code 分两步走(先便宜后贵),用梯度换成本效率 下图是 Claude Code 的压缩策略 vs Openclaw 的压缩策略 image.png
四五两层其实就比较简单,就是兜底策略。一个从客户端兜底,一个从服务端兜底。出现了问题,压缩后还是上下文爆炸,就直接给用户提示,用户可以手动来 /compact 来继续对话
第 4 层:Blocking Limit(硬拒绝) 如果经过前 3 层之后 token 数仍然超过硬上限(有效窗口 - 3,000,约 177K),直接向用户输出 PROMPT_TOO_LONG_ERROR_MESSAGE 并终止本轮。这是发起 API 调用之前的最后一道门 第 5 层:Reactive Compact(事后兜底) 在 API 调用之后触发: 当 API 返回 prompt_too_long(413)或媒体文件过大错误时,拦截错误,对旧消息做一次摘要压缩,然后重试 API 调用。每轮最多尝试 1 次,防止死循环 为什么建议主动 /compact 社区分析源码后的一个关键建议是: 主动使用 /compact,不要等系统自动压缩(出自 “I Read 512,000 Lines of Leaked Claude Code” 视频)原因很简单: 自动压缩触发时,你无法控制保留什么,系统按自己的 9 段模板做摘要,可能会丢掉你认为重要的上下文。而手动 /compact 可以附带指令,比如 /compact 重点保留决策和待办事项,让 LLM 知道什么该保留。Boris 在播客中也提到自动压缩是实现“本质上无限上下文”(essentially infinite context)的核心手段,但这更多是系统兜底,用户主动管理上下文效果会更好 总结:压缩策略的设计哲学 这 5 层形成一个从 xied 层会触发,Full Compact 是中等频率事件,Blocking Limit 和 Reactive Compact 是极少触发的兜底

4.2.4 记忆写入

上面讲了 4 种存储和加载 / 压缩策略,但记忆是怎么写进去的?有 3 个写入机制:
  1. extractMemories(持久记忆提取): 在每次完整查询循环结束后(模型给出最终回复,没有更多工具要调用时),由一个 Fork Agent 后台执行:
  • 继承父对话的完整上下文,共享 prompt cache(不额外消耗 token)
  • 严格权限沙箱:只能读文件 + 只能写记忆目录,不能执行 bash,不能调 MCP,不能启动子代理
  • 高效的 2 轮模式:第 1 轮并行读所有需要更新的文件 -> 第 2 轮并行写所有有变更
  • 有频率限制,不是每轮都跑
  1. Session Memory 更新: 对话 token 超过 10K 后启动,之后每 5K tokens 由后台 Fork Agent 更新一次结构化笔记文件
  2. AutoDream(记忆整合)—— “睡眠整理” 定期运行的后台代理,对持久记忆做整理、合并、去重、清理。灵感来自人类睡眠时整理白天记忆的过程。下图是 AutoDream 图片展示 image.png
触发条件(三个门全部通过才执行):
  1. 距上次整合 ≥ 24 小时(最先检查,成本最低,一次 stat 调用)
  2. 距上次整合 ≥ 5 个会话
  3. 获取 consolidation lock(PID 文件锁,防并发;超过 1 小时且 PID 已死则可回收)
执行 4 阶段:
  • Orient:读取 MEMORY.md 索引,浏览现有主题文件,了解当前状态
  • Gather:扫描每日日志和会话记录(JSONL),窄范围 grep,不穷举
  • Consolidate:新信息合并到现有主题文件,修复矛盾,相对日期转绝对日期
  • Prune:保持 MEMORY.md ≤ 200 行,删除过时条目,精简冗长描述
System prompt:
*"You are performing a dream — a reflective pass over your memory files. Synthesize what you've learned recently into durable, well-organized memories so that future sessions can orient quickly."*
整合期间只读访问:可以看代码文件,但只能写记忆目录。由 Fork Agent 执行,UI 底栏显示 "dreaming" 标签。 三者对比:
维度extractMemoriesSessionMemoryAutoDream
一句话定位从对话中提取新记忆写入持久存储维护当前会话的结构化工作笔记定期整理已有的持久记忆
写入目标~/.claude/memory/*.md + MEMORY.md 索引会话临时目录下的单个笔记文件~/.claude/memory/*.md + MEMORY.md 索引
生命周期永久(跨会话)仅当前会话永久(跨会话)
操作性质新增/更新记忆条目维护/覆盖一份工作纪要合并/去重/删除/精简已有条目
触发时机每轮查询结束后(主 Agent 自己没写记忆时)token 超 10K 后启动,每 5K tokens 更新>=24h>=5 个会话,且获取文件锁
频率高(每轮或每 N 轮)中(按 token 增量)极低(天级)
信息来源最近 N 条对话消息当前会话内容已有记忆文件 + 会话日志
写什么user / feedback / project / reference 四类持久事实任务描述、进度、涉及文件、错误、经验不产生新信息,只重组织已有信息
下游用途未来新会话加载时注入上下文1. /resume 恢复会话 2. 压缩时当现成摘要保持记忆库整洁、<=200
权限范围只读代码 + 只写 memory 目录只能编辑那一个 session memory 文件只读代码 + 只写 memory 目录
执行方式Fork Agent 后台执行Fork Agent 后台执行Fork Agent 后台执行(UI 显示 "dreaming")
类比上课记笔记写会议纪要周末整理笔记本

4.2.5 Claude Code vs OpenClaw:记忆设计思路对比

两者解决的是同一个问题 —— 有限上下文窗口下如何让 Agent 不失忆,但设计思路有几处根本性的分歧 检索路线之争:Agentic Search vs RAG 这是两者最大的分歧。Claude Code 明确拒绝 RAG,Boris 透露早期试过向量数据库 + embedding 方案,但发现代码修改后索引不同步、权限管控复杂,最终结论是让 Agent 自己调 glob + grep 实时搜索(agentic search)全面优于 RAG。OpenClaw 则走了完全相反的路 —— 用 SQLite 建本地索引,向量语义匹配 + BM25 关键词匹配加权混合并做混合检索 本质上这是“每次多花点 token 换实时准确” vs “建索引省 token 但要维护一致性”的取舍。对 coding agent 来说,代码文件变化极频繁,索引的一致性成本很高,所以 Claude Code 选择了不建索引;而 OpenClaw 面向更通用的 Agent 场景(聊天、知识管理),记忆文件相对稳定,RAG 的收益更明显 压缩策略:梯度递进 vs 一步到位
压缩策略
Claude Code 设计了 5 层压缩流水线,从温和到激进逐层升级 —— 先清理工具输出碎片、再考虑缓存优化、然后才做 LLM 摘要,最后硬拒绝和兜底。大部分情况下前两层(不需要 LLM 调用)就能把 token 压下来,真正的 LLM 压缩是中低频事件。这是一种用工程复杂度换成本效率的思路。

OpenClaw 只有一级压缩,但流程更精细:划分保留区(最近 ~20K tokens 原封不动)、压缩区分块逐块总结、多块摘要再合并成一个连贯总结。每次触发都需要 LLM 调用,成本更高,但实现简单、行为可预测
记忆写入:自动化 vs 显式写入
记忆写入
Claude Code 做了重度的写入自动化 —— 三个后台 Agent 分工:extractMemories 每轮结束后自动提取持久记忆,Session Memory 持续维护会话笔记,AutoDream 定期整合去重。用户不需要主动“存档”,系统自动帮你把重要信息沉淀下来

OpenClaw 更依赖显式写入。它的文档反复强调一个常见失误:聊天中说的指令不会自动保存到文件 —— 不写入文件就会被压缩丢掉。作为补偿,OpenClaw 在压缩前有一个 Pre-Compaction Memory Flush —— 静默提醒 Agent 把重要内容写入记忆文件。但这本质上是“事到临头才保存”,而 Claude Code 是“一直在保存”
记忆加载:Push vs Pull
记忆加载模式
Claude Code 是系统层面硬编码的 push 模式——每轮对话前,系统必定用 Sonnet(轻量小模型)扫一遍所有记忆文件的标题和描述,挑出最相关的几条,直接塞进上下文。主模型开始思考时,相关记忆已经摆在眼前了,不需要它主动去找。类比:秘书在你开会前,把相关资料提前放在桌上。代价是每轮都要占固定的上下文空间,不管用不用得上。

OpenClaw 是 pull 模式——系统不会提前塞记忆,而是把 `memory_search` 作为一个普通工具暴露给模型。模型在推理过程中自己判断“这轮要不要查记忆”,跟它决定要不要调 `bash`、要不要读文件是一样的逻辑。更灵活省空间,但风险在于模型不知道自己不知道什么——比如你上周说过“我讨厌 forEach”,这条记忆存在文件里了,但今天聊到循环时模型可能根本没想到要去搜“用户的代码风格偏好”,就直接写了 forEach。Push 模式下这条记忆会被小模型提前捞出来,就不会犯这个错。
设计哲学总结 Claude Code 走的是工程优化路线:梯度压缩能省则省、后台 Agent 自动写入、小模型做筛选降低成本——处处体现“怎么用更少的 token 做更多的事”。OpenClaw 走的是架构清晰路线:四层对标计算机存储层次(硬盘 -> 日志 -> 内存 -> 搜索引擎),每层职责明确,系统更易理解和调试。面试时两者结合讲,既能展示工程优化思维,又能体现架构设计能力。

4.3 Agent架构

本节分析 Claude Code 的 Agent 架构设计:它采用了什么架构、为什么选择这个架构、具体是怎么运行的、Agent 之间如何通信。分析了以后其实发现 Claude Code 很简单,看这个图,简单地说:用户输入 -> 组装提示词,然后就是由主 Agent 一直循环,判断是否调用工具,工具又分两种类型:一种是普通工具,另一种是子 Agent(子 Agent 内部自循环) 如果你看了笔记的 Openclaw 的解析,你可以发现他们很类似,都是将子 Agent 变成工具,然后主 Agent 调用。从架构上,CC 比 Openclaw 简单,它不用处理各种 channels,没有 Gateway 层。本节也会对这两个 Agent 框架做对比 同时,本节会结合之前笔记的理论部分,Agent 架构,Agent 通信,面试真题来讲解。你会发现如果你笔记前面的很多内容你学了,学到这个架构上,他们是彼此呼应的。所以推荐从理论到实践,先把我们笔记中的 Agent 八股、基础知识推荐的资料看好了,再看这些成熟架构的解析,会容易一些

4.3.1 中心化星型拓扑

在多智能体架构的五种经典分类(单智能体 SAS、独立型 Independent、中心化 Centralized、去中心化 Decentralized、混合型 Hybrid中,Claude Code 采用的是中心化架构(Centralized)——准确地说,是一种星型拓扑:一个主 Agent 居中,所有子代理围绕它呈辐射状分布,信息只在主 Agent 与子代理之间流动,子代理之间没有任何直接连接。
中心化星型拓扑

        ┌───────┐
        │ 用户  │
        └───────┘


    ┌────────────────┐
    │   主 Agent     │  ← 唯一的中央控制节点
    │ (Query Loop)   │
    └────────────────┘
       ↙     ↓     ↘
      ↗      ↑      ↙
 ┌────────┐ ┌────────┐ ┌────────┐
 │子代理A │ │子代理B │ │子代理C │
 └────────┘ └────────┘ └────────┘
        X   互不通信   X


4.3.2 为什么选中心化?

其实架构这个事情上,你很难说谁对谁错,为什么 CC 选择中心化,不选择去中心化。这些理论是我自己分析,结合我们之前学习的笔记、论文来分析的。这里没有标准答案,谁对谁错,但是我希望大家是可以一步步去理解,去思考。你自己想清楚了,觉得合理了,那么就可以和面试官去探讨,沟通,这是一个开放性问题 所以我希望大家还是有一些自己的思考。特别是对于 Agent 的架构设计这块,本身比较难。包括面试要是问你设计一个系统架构,都是比较难的。但是通过我们八股、论文,以及我们现在已经看了两个 Agent 架构了,大家理解了以后去分析、去消化,慢慢地建立自己地思考。建立了自己的想法的时候,在面试中有东西说,在设计自己项目架构的时候,也知道怎么设计,设计得更复杂。而不是让 AI 生成一个最普通的架构,你也没有任何的修改意见
从工程实践和理论两个角度来分析 工程角度:安全与简单 安全是第一驱动力。Claude Code 的设计核心是 human-in-the-loop(人在回路中)——所有工具调用都必须经过权限系统审批。如果让 agent 之间自由通信、自主决策,那么谁来审批 agent B 被 agent A 指使去执行的命令?权限链条立刻断裂。中心化的星型拓扑保证了一个清晰的控制点:所有决策都由主 Agent 发起,所有行为都在用户可监督的范围内。Boris 在播客中反复用 “Swiss cheese model”(瑞士奶酪模型)来形容安全设计——叠加多层防御,每层都可能有漏洞,但叠在一起漏洞被覆盖。中心化架构本身就是其中一层:单一控制点 = 单一审计点 简单是第二驱动力。Boris 明确说过架构 “very simple”。中心化意味着不需要处理 agent 间的消息路由、协商协议、冲突解决、共享状态同步等复杂问题。主 Agent 的 query loop 就是整个系统的唯一调度器——加一个子代理就是多一个工具调用,减一个子代理就是少一个工具调用,没有额外的基础设施 理论角度:与 Agent Theory 章节中 Multi-Agent 架构理论的呼应 这个架构选型与 Agent Theory 中引用的 Google 论文《Towards a Science of Scaling Agent Systems》(arXiv: 2512.08296v1)的实验结论一致。论文用 180 种对照配置量化比较了五种架构,核心结论直接解释了 Claude Code 的选择:
  • Coding 是工具密集 + 顺序推理场景:论文指出单体基线 >=45% 时,盲目加多 Agent 反而因协调减效。Claude Code 的核心就是单体 Query Loop,只在需要并行时才派生子代理
  • 中心化控制错误放大:独立多体错误放大 17.2 倍,中心化只有 4.4 倍——coding 场景下错误扩散代价极高,必须有统一收敛点
  • 去中心化通信开销 O(D·N²) 不划算:论文只在高熵、路径不唯一的场景观测到去中心化优势,coding 工作流结构化、路径确定,不适用。所谓“高熵”,就是完成任务的正确路径不唯一、信息分散、需要探索的场景。动态网页导航就是典型例子:要找某公司的碳排放数据,可以查官网、查媒体报道、查监管机构,信息散布在不同来源,没有一条确定的标准路径,每个 Agent 独立探索一个方向然后互相校验反而更高效。相反,coding 是低熵的——“读代码 -> 改代码 -> 跑测试”的路径是固定的,不需要多个 Agent 去“探索”不同的编码路径然后辩论哪个更好
  • 匹配“可拆分 + 统一验收”场景:主 Agent 拆解任务、分派子代理、统一验收,和笔记中 Orchestrator 模式的描述完全一致
OpenClaw 同样选择了中心化,原因一致。为什么选 Centralized:对话本身的结构就是中心化的——用户发一条消息进来,最终必须有一条连贯的回复发回去,这个“一进一出”要求有且只有一个 Agent 对最终回复负责。如果换成去中心化(P2P 协商),最终谁来发回复没有确定答案;如果换成 Independent(各自独立),结果无法拼合成一条完整回复。两个项目从不同角度得出了相同结论:Claude Code 从安全(单一审计点)和任务特征(工具密集、顺序推理)出发,OpenClaw 从对话结构的“一进一出”约束出发,殊途同归选择了中心化 一句话:工具密集 + 顺序推理 + 需要质量门控 + 对话结构天然一进一出 -> 中心化是最优解,Claude Code、OpenClaw 的工程判断和 Google 论文数据指向同一个结论

4.3.3 运行机制

宏观全景:整个系统只有一个循环 + 一组工具 先看完整的架构全景图,再分层展开:
Agent 查询循环全景
用户输入

组装 System Prompt(CLAUDE.md + 记忆 + 工具定义 + 权限规则)

┌→ 调用 LLM API
│   ↓
│   模型返回:
│   ├─ 纯文本 → 输出给用户,循环结束
│   └─ 工具调用(模型自主选择)
│       │
│       ├─ Bash / Read / Write / Grep / Glob ...  ← 普通工具:直接执行
│       │   │
│       │   └→ 返回结果追加到上下文
│       │
│       └─ Agent 工具(也是普通工具之一)        ← 特殊之处:结果来自另一个循环
│           │
│           └→ 派生子代理(Fork / Teammate / WorkTree)
│               │
│               └→ 子代理启动自己的 Query Loop  ← 递归:内核完全相同
│               |    ├─ 调用 LLM API
│               |    ├─ 调用普通工具(但不能再派生子代理)
│               |    └─ 输出最终文本
│               └→ 子代理的输出作为这次工具调用的返回值

└── 带着工具结果继续问模型(无论结果来自普通工具还是子代理)
核心洞察: 整个架构的精妙之处在于,子代理不是一个独立的系统——它只是 Agent 工具的“内部实现”。主 Agent 的 query loop 调用 Agent 工具和调用 Bash 工具的方式完全一样:发送输入、等待返回值。唯一的区别是,Bash 工具内部跑的是一条 shell 命令,而 Agent 工具内部跑的是一个完整的 query loop。对主 Agent 来说,这只是一次工具调用——它不关心子代理内部执行了多少步、调了什么工具,它只看到最终返回的文本 模型自主决定调用什么工具、调用几次、什么时候停止。代码中没有硬编码的步骤编排——不存在“第一步搜索、第二步修改、第三步测试”的预设流程。Boris 的原话:“模型就是想用工具。你给它一个工具,它就会搞清楚怎么用它来达成目标” 既然没有流程编排,核心就在提示词设计 那这个“模型自主决策”在代码里是怎么实现的? 打开 src/src/query.ts,核心是 queryLoop() 函数(约第 241 行),它的控制流极简单:
Query Loop 控制流
while (true) {
  1. 把当前消息发给模型 → 拿到模型的回复
  2. 检查回复里有没有 tool_use block
     - 有 → needsFollowUp = true → 执行这些工具 → 把工具结果拼回消息 → continue(回到第 1 步)
     - 没有 → needsFollowUp = false → break,循环结束
}
就这么多。注意这里没有任何 if-else 判断“应该调什么工具”,没有“如果用户问代码就调 FileRead”“如果要搜索就调 Grep”——这些路由逻辑在传统框架里是开发者写的,在 Claude Code 里完全不存在。query loop 的角色就是一个“执行器”:模型说调工具就调,模型说停就停,它不参与任何决策 子代理的调用也是同理——query loop 不会判断“这个任务该不该派子代理”。模型在回复中输出一个 Agent 工具的 tool_use block,query loop 就像执行任何其他工具一样执行它。对 loop 来说,派子代理和读文件没有区别,都只是一次工具调用。而子代理内部又启动了自己的 query loop——同样的 while(true) 循环,同样由模型自主决定调什么工具、什么时候停止。这就是 Agent 调 Agent 的递归本质:每一层都是同一个循环结构,只是上下文不同 工具的并行与串行调度 模型可以在一轮中请求多个工具调用,源码中 toolOrchestration.tspartitionToolCalls() 会按工具的 isConcurrencySafe 属性自动分批:只读工具(Grep / Glob / Read 等)合并为一批并行执行,写操作工具(Edit / Write / Bash 等)串行执行。这是 query loop 内部的调度细节,模型不需要感知。 三种子代理派生方式 泄露代码揭示了 Agent 工具内部的三种派生机制(它们是正交的维度,不是互斥的类型): Fork:同进程派生,共享 API prompt cache —— 记忆提取、网页摘要等轻量后台任务。成本最低,因为共享缓存意味着不需要重新处理静态 prompt Teammate:独立终端进程,通过文件信箱通信 —— Agent Teams 中的并行 worker。用户可以在独立的终端窗格中观察每个 worker 的工作 WorkTree(隔离模式):任何子代理都可以附加的 isolation 参数,在独立 Git worktree 中工作 —— 并行开发不同功能分支时互不干扰 派生方式的决策机制:一个工具,参数决定模式 三种派生方式都是同一个 Agent 工具的不同参数组合,由模型在调用工具时通过参数选择决定,用户不需要指定:
Agent 工具输入结构
type AgentToolInput = {
  prompt: string              // 任务描述
  description: string         // 3-5 字简述
  subagent_type?: string      // 省略 -> Fork; 指定 -> 特定子代理
  name?: string               // 提供 name + team_name -> Teammate
  team_name?: string
  isolation?: 'worktree'      // 提供 -> WorkTree 隔离
  model?: 'sonnet' | 'opus' | 'haiku'
  run_in_background?: boolean
}
模型如何知道什么时候该用哪种?靠的是工具参数描述 + 系统 prompt 中的决策指南。系统 prompt(src/src/tools/AgentTool/prompt.ts)注入了详细的 “When to fork” 指南,告诉模型判断标准:
Fork yourself (omit subagent_type) when the intermediate tool output isn’t worth keeping in your context. The criterion is qualitative — “will I need this output again” — not task size.
  • Research: fork open-ended questions. If research can be broken into independent questions, launch parallel forks in one message. A fork beats a fresh subagent for this — it inherits context and shares your cache.
  • Implementation: prefer to fork implementation work that requires more than a couple of edits.
Teammate 和 WorkTree 的选择也类似——工具 schema 的 .describe() 描述了每个参数的用途,模型根据任务性质自主判断该填哪些参数。本质上和模型自己决定什么时候调 Bash、什么时候调 Read 是同一个机制。
希望大家可以对比着去理解。我们看了两个架构,Openclaw 和 CC 都是用的主 Agent 来使用工具调用的方法,来 fork 子 Agent,不同的 Agent 形式由工具参数决定。这是一致的。不一致的地方,是对于子 Agent 的形式,有一些不同,也就是工具的参数。大家看了本章,在设计自己的架构的时候,可以参考这一套。但是思考一下你的场景中的子 Agent 需要是什么形式,有哪些 type,是起一个新的进程还是作为 subagent 合适?
与 OpenClaw 的对比 这套“一个工具 + 参数决定模式 + LLM 自主判断”的设计,和 OpenClaw 的 sessions_spawn 工具几乎同构。两者的核心相同点和差异:
维度Claude CodeOpenClaw
实现方式一个 Agent 工具,参数组合决定模式一个 sessions_spawn 工具,参数决定模式
决策者LLM 根据系统 prompt 指南自主判断LLM 根据系统 prompt 规则自主判断
指导方式参数 .describe() + prompt "When to fork" 指南工具描述 + prompt "If a task is more complex, spawn a sub-agent"
安全约束feature_gate + 子代理工具列表物理移除 Agent 工具maxSpawnDepth + maxChildrenPerAgent + 叶子节点物理移除工具
派生维度3 个正交维度可组合(Fork / Teammate / WorkTree)2 种互斥 runtime(subagent / acp)
轻量模式Fork:同进程,共享 prompt cache,继承完整上下文subagent:同进程,继承 workspace 目录
重量模式Teammate:独立终端进程,用户可观察acp:独立进程,可对接 Codex 等外部 CLI
隔离能力WorkTree:独立 git worktree,可叠加在任何模式上无对应机制
组合性Fork + WorkTree 可组合(正交维度)subagentacp 互斥(同一参数不同值)
本质区别在于解决的问题维度不同。Claude Code 的三种模式各解决一个独立问题: Fork 解决上下文效率(共享缓存、不污染父上下文),Teammate 解决人机协作(用户能在独立终端观察和干预),WorkTree 解决代码隔离(并行改代码不冲突) 而 OpenClaw 的两种 runtime 解决的是执行环境问题:subagent 是内部轻量执行,acp 是对接外部工具链。Claude Code 维度更细、可组合;OpenClaw 模型更简单、二选一。但核心设计理念完全一致——把选择标准写进 prompt,信任模型判断

4.3.4 Agent通信

Agent 之间如何通信,其实也是面试官喜欢考的。所以在解析 Agent 架构的时候,我都会注重这一点,包括 Openclaw。但是拆解了两个架构后,其实我们发现,这些出名的架构,Agent 通信也不会特别复杂,比如 A2A 啊。相反,他们都是主 Agent 生成子 Agent,而子 Agent 之间不交互,只是把结果交给主 Agent。背后的思想其实省去 Agent 之间的通信,一定会减少各种开销和难度,成熟的架构都这么设计,我们也可以这么设计,也不用担心自己没有复杂的 Agent 通信是不是就意味着项目浅
短回答: 子代理之间不通信。所有通信都必须经过主 Agent 中转 Boris 将这个设计称为 “uncorrelated context windows”(不相关的上下文窗口) 每个子代理的上下文窗口都是全新的——它看不到主 Agent 的对话历史,也不知道其他子代理的存在。它能看到的唯一信息,就是主 Agent 在调用 Agent 工具时传入的那段 prompt 具体的通信方式:
子代理通信路径
主 Agent 上下文窗口

├─ 调用 Agent 工具 -> prompt 作为"下行消息" -> 子代理 A
│                                               │
│         子代理 A 的返回值作为"上行消息" <────────┘

├─ 调用 Agent 工具 -> prompt 作为"下行消息" -> 子代理 B
│                                               │
│         子代理 B 的返回值作为"上行消息" <────────┘

└─ 主 Agent 拿到 A 和 B 的结果后,在自己的上下文中综合处理
  • 下行通信(主 -> 子): 通过 Agent 工具调用的 prompt 参数。主 Agent 必须在这个 prompt 中放入子代理完成任务所需的全部信息,因为子代理看不到其他任何上下文
  • 上行通信(子 -> 主): 子代理 query loop 结束时的最终文本输出,作为工具调用的返回值传回主 Agent 的上下文
  • 横向通信(子 ↔ 子): 不存在。如果子代理 A 的结果需要被子代理 B 使用,唯一的路径是:A 的结果先返回主 Agent,主 Agent 把 A 的结果写进 B 的 prompt 里,再派生 B
这带来一个重要的实践含义:并行的子代理适合独立任务,串行依赖的任务必须由主 Agent 协调先后顺序 Boris 提到他见过 Agent Teams 中 “agents 之间讨论问题” 的场景,但这种“讨论”本质上是 lead agent 在做信息中转——读取一个 worker 的输出,提炼后塞进另一个 worker 的 prompt。看起来像对话,实际是星型路由

4.3.5 与 Agent 通信理论的呼应

这一节我是专门加的,我们在 Agent Theory 中,学习了理论部分。我想让大家看看,其实我们学到理论,都是没问题的,主流 Agent 框架用的就是我们学的东西。希望通过这一节,大家能够让理论对应实践,相互呼应,有更深入的理解
上面的分析到这里,你会发现它和 Agent Theory [Agent 之间通信和状态管理]讲的理论完全呼应上了。我们从通信模式和消息传递两个维度来对照: 通信模式 —— 工具调用(Tool Call),而非移交(Hand off) Agent Theory Agent通信理论 讲过 Agent 间通信有两种模式:移交(Hand off,交出控制权,自己退出)和工具调用(Tool Call,委托任务但保留控制权) Claude Code 和 OpenClaw 都选了工具调用模式。Claude Code 的子代理就是一个普通的工具调用——主 Agent 把任务描述作为参数传给 Agent 工具,等子代理执行完拿到返回值后,自己决定下一步。OpenClaw 同理,sessions_spawn 也被注册为一个普通工具,和 execweb_search 地位相同,LLM 自主判断什么时候调用。两者的主 Agent 始终保留控制权,负责最终回复,不会把执行权交出去 消息传递——仅共享最终结果,不传递推理链 Agent通信理论 消息传递的两种策略 共享完整推理数据(中间步骤全部写入共享通道,协作强但上下文膨胀快)和仅共享最终结果(私有空间完成计算,只把结论写入共享区) Claude Code 和 OpenClaw 都选了仅共享最终结果: Claude Code 子代理内部执行了多少 tool call、有多少 thinking 过程,父 Agent 一概看不到,只拿到最终的纯文本输出 OpenClaw 的实现更加明确——子 Agent 完成任务后,把最终回复蒸馏成一条消息异步推回父 Agent 的消息队列,中间的 tool call 链和 chain-of-thought 全部留在子 Agent 自己的私有 session 里 不同的是 Claude Code 默认是同步返回(子代理执行完直接返回结果),而 OpenClaw 是异步 push-based(spawn 立刻返回,子 Agent 完成后通过消息通知父 Agent) 面试呼应
这几个问题是我之前面试被问到过的,我以这个举例子,告诉大家我们学的东西其实都面试考的。而且你学完了,都是直接对你面试有帮助的。没学这个小节之前,面试官问你 Agent 如何通信,当然你可以回答理论部分。学了以后,加入了 CC 和 Openclaw,一定回答得更好了。所以很多问题的答案,是在我们学习的过程,不断总结提炼出更好的答案的
这里直接对应 Agent Theory [Agent 之间通信和状态管理] 末尾的那道快速测试(面试原题):
Agent Theory 快速测试(面试原题): 如果 Agent 之间通信,某些东西不想给另一个 Agent 看到,应该怎么做? 笔记里给的答案方向是“仅共享最终结果”。现在结合 Claude Code 和 OpenClaw 的源码实践,面试时可以更具体地这么回答:
面试原题回答
采用“仅共享最终结果”的消息传递策略。每个子 Agent 拥有独立的上下文空间,所有中间推理过程——包括中间的工具调用链、思维链——都留在子 Agent 的私有空间里,执行完成后只把最终结论提取出来返回给父 Agent,父 Agent 看不到任何中间步骤。这样做的好处有两个:

一是隐私隔离,某个子 Agent 的中间数据不会泄露给其他 Agent;

二是控制上下文膨胀,如果把所有中间步骤都传回去,父 Agent 的上下文窗口会快速撑满。

这个策略在实际项目中是主流做法,比如 Claude Code 的子代理只返回纯文本结果,OpenClaw 的子 Agent 也是只把蒸馏后的最终回复推送给父 Agent。
另一道同样来自Agent Theory的高频考点——Agent 间通信模式的选择,面试中通常这样问: Agent Theory 高频考点:你的 Agent 之间是如何通信的?(或者:你项目里的多 Agent 是怎么协作的?)
Agent 通信模式回答
面试时可以从三个层面回答:

一.架构选型:
我们采用中心化架构,一个主 Agent 作为编排者,通过工具调用的方式委派任务给子 Agent。选择中心化而非去中心化的原因是,对话场景天然是“一进一出”的结构——用户发一条消息,最终要有一条连贯的回复,必须有且只有一个 Agent 对最终输出负责。中心化的星型拓扑正好对应这个模型:主 Agent 是唯一的回复责任人。

二.通信模式:
使用工具调用而非移交。主 Agent 保留控制权,把子任务作为参数发给子 Agent,等结果回来后自己整合决策。子 Agent 之间不直接通信,如果 A 的结果需要被 B 使用,必须由主 Agent 中转——先拿到 A 的结果,再把相关信息写进 B 的任务描述中。

三.消息内容:
仅传递最终结果,不传递中间推理链。子 Agent 在自己的独立上下文中完成全部推理和工具调用,只把最终结论返回给主 Agent。这样既保护了各 Agent 的中间数据隐私,也有效控制了主 Agent 的上下文膨胀。

4.4 权限系统与安全审查

学习 ClaudeCode 的权限处理,除了应对面试官问你 CC 权限系统是如何设计的这个问题(有朋友被问过)。另外你也可以应对面试官问你 Agent 安全相关的问题,比如如何避免 Agent 乱调用工具对系统产生破坏。除此之外也希望大家学会了本节,在设计自己 Agent 项目的时候可以在 Agent 的权限系统 / 安全上进行设计,会让自己的项目更加有深度,不被置疑是玩具项目。最后学了本节,其实你在使用 ClaudeCode 不同模式的时候,其实也可以知道里面的运行原理。
本节分析 Claude Code 的权限与安全机制。无论是主 Agent 还是子代理,每次调用工具(写文件、执行命令等)都要经过同一套权限管道的审查。Boris 用“瑞士奶酪模型”形容这套设计——叠加多层防御,每层都可能有漏洞,但叠在一起漏洞被覆盖

4.4.1 总览:四层权限管道

当主 AI 请求执行任何操作时,都要依次经过四层安全过滤。每一层都可以直接做出“放行”或“拒绝”的终审判决,只有当本层说“我没意见”时,请求才会继续流入下一层 image.png 每一层解决什么问题? 第一层(规则过滤): 解决“用户已经明确知道哪些操作安全、哪些危险”的场景。比如你知道 python 命令在你的项目里是安全的,就配一条 allow 规则永久放行,不用每次都确认。这是用户意志的直接表达——提前告诉系统“这个我信任”或“这个绝不允许”,与当前处于什么模式完全无关。 第二层(工具自检): 解决“规则覆盖不到的,需要理解操作内容才能判断的场景”。规则是按“工具名 + 命令模式”做粗粒度匹配的(比如 Bash(rm:*)),但它无法理解操作的语义。比如 Write 工具被允许了,但写入目标是 .git/config —— 这种“路径是否越界”的判断只有工具自己的代码才能做。Bash 工具更复杂,它会用 shell AST 解析器分析命令结构,检测命令替换、进程替换、注入攻击等。这一层的本质是:每个工具根据自己对操作内容的专业理解,用确定性的代码逻辑做细粒度安全判断。 第三层(模式兜底): 解决“规则没覆盖到、工具也没意见时怎么办”的问题。到了这一层,说明前面的确定性检查都没有做出判决,需要一个“兜底策略”。不同模式代表不同的风险偏好:bypass 信任一切,default 什么都问人,dontAsk 什么都拒绝,auto 交给 AI 判断。这一层的本质是:把最终决定权交给用户选择的风险偏好。 第四层(AI 分类器): 只有 auto 模式才会走到这里。它解决的是“不想每次都手动确认,但又不像 bypass 那样完全放弃安全检查”的矛盾。方案是引入一个独立的 AI 分类器来代替人做判断——它读取对话上下文,理解当前操作的意图,判断是否安全。为了省钱,分类器前面有两条快速路径:安全工具白名单(Read / Grep 等零副作用工具直接跳过)和工作目录内编辑(项目内改代码不需要审查)。只有这两条都不适用时,才真正调用 AI 分类器。 为什么是四层而不是一层? 这四层的设计遵循“瑞士奶酪模型”——每层都可能有漏洞,但叠在一起漏洞被覆盖。同时,四层的排列顺序也体现了从确定性到不确定性的递进:
权限判断递进
确定性高 -----------------------------------------------> 确定性低

第一层                第二层                第三层                第四层
规则过滤              工具自检              模式兜底              AI 分类器
──────               ──────               ──────               ──────
纯配置匹配            代码逻辑判断          策略分流              AI 推理判断
← 零成本 →            ← 零成本 →            ← 零成本 →            ← 额外 API 调用 →
越靠前的层越“刚性”(确定性高、成本低、不可覆盖),越靠后的层越“柔性”(需要推理、有成本、可降级)。这样设计的好处是:大部分操作在前三层就被处理了(要么放行要么拒绝),只有少数“不确定”的操作才需要走到最后的 AI 分类器——既保证了安全,又控制了成本 下面逐层展开

4.4.2 第一层:规则过滤

这一层我在使用 github copilot 的时候也有,大家有没有注意到在使用 copilot 的时候,如果有一个工具,他让你点击 approve,下面有选项(是否 always approve),如果你点了是,其实就在对应 copilot 的配置文件(json)中把这个命令设置为 allow,下次执行相同内容就不会再 approve 了。 这个方法是 CodingAgent 的通用技巧,设置规则,下次直接按照规则命中。
这一层与当前处于什么模式完全无关,是一道纯粹的静态匹配。 什么是规则? 规则是用户在 settings.json 中配置的、针对具体工具的白/黑名单。每条规则指定一个行为(allow / deny / ask)和一个匹配模式:
权限规则示例
{
  "permissions": {
    "allow": [
      "Bash(ls *)",        // 允许所有 ls 命令
      "Bash(mkdir:*)",     // 允许所有 mkdir 命令
      "Bash(python:*)"     // 允许所有 python 命令
    ],
    "deny": [
      "Bash(rm -rf:*)"     // 禁止所有 rm -rf 命令
    ]
  }
}
格式是 工具名(内容匹配),例如 Bash(npm test) 只匹配 npm test 命令,Write 匹配所有文件写入,mcp__server1 匹配指定 MCP 服务的全部工具
这些细节也不用强行记住,就是给大家看一下,重要的是这个思路,具体细节面试问的少。
规则有 6 个配置层级,优先级从高到低:
层级说明典型场景
policySettings管理员/企业策略公司统一禁止 rm -rf
userSettings用户全局设置个人习惯:允许 python:*
projectSettings项目级设置项目约定:允许 npm test
localSettings本地设置本机特殊配置
cliArg命令行参数单次启动时临时指定
session会话级运行中弹框时用户选了“始终允许”
执行逻辑:
deny 规则命中 -> 直接拒绝(终审),allow 规则命中 -> 直接放行(终审),ask 规则命中或无规则命中 -> 流入下一层。 关键设计: deny 规则是不可覆盖的。即使在 bypass 模式下,deny 规则仍然生效。这确保了管理员策略能够硬性约束用户行为。

4.4.3 第二层:工具自检

每个工具内部都可以实现一个 checkPermissions() 方法,根据本次操作的具体内容做安全判断。这不是配置驱动的,而是工具代码中写死的安全逻辑。 典型例子:
  • Bash 工具:检查命令本身是否属于高风险操作
  • Write/Edit 工具:检查目标文件路径是否合法
  • 安全路径检查:.git/.claude/ 等关键目录有特殊保护 —— 即使在 bypass 模式下也不能跳过,源码注释称之为 “bypass-immune”(免疫 bypass)
工具自检有三种返回值:
  • 拒绝:终审,直接拒绝操作
  • 放行:终审,直接通过
  • 无意见:不做判断,流入下一层
这一层的意义在于:规则是按“工具名 + 命令模式”做粗粒度匹配的,无法理解操作的语义。比如规则允许了 Write,但工具自检可以进一步检查“写入的目标是不是 .git/config”——这种细粒度判断只有工具自己能做

4.4.4 第三层:模式兜底

设置模式。这个大家在使用 CC 的时候相比有印象。在 CLI 下方有:acceptEdits on 等提示。学习了本节你更会理解在不同的模式下的预期行为。 大家可能困惑为啥自己使用 CC 切换不到某种模式。要注意的是,里面有一些模式,比如 bypassPermissions 是要通过命令行参数启动的,dontAsk 并不可用(只是源码里有),auto 是需要使用 feature flag 才能开启的。
走到这一层,说明前两层都没有做出判决——没有命中规则,工具也没有意见。此时由当前的权限模式决定兜底行为。 Claude Code 有 5 种用户可设置的模式和 2 种内部模式:
模式类型行为说明
default用户可设⏸ 弹框问用户最谨慎,每次都需要人工确认
acceptEdits用户可设项目内编辑在第二层就放行,其余弹框Shift+Tab 可切换,最常用的效率模式
plan用户可设写操作在第二层就拒绝,其余弹框只读规划模式,Shift+Tab 可切换
bypassPermissions用户可设✅ 直接放行对应 --dangerously-skip-permissions
dontAsk用户可设❌ 直接拒绝只允许规则明确放行的操作,其余全部拒绝
auto内部模式进入第四层分类器管道Shift+Tab 可切换(需 feature flag 开启)
bubble内部模式权限冒泡到父 Agent子代理使用
注意 acceptEdits 和 plan 的特殊之处: 它们的核心逻辑不在第三层,而是在第二层工具自检时就生效了。acceptEdits 下的 Write 工具检测到项目内编辑直接放行,plan 下的 Write 工具直接拒绝写操作——走到第三层时,剩下的操作和 default 行为相同(弹框问用户)。 重点说明两个容易误解的模式: bypass 不是无敌模式。它排在第三层, 意味着第一层的 deny 规则和第二层的安全路径检查(bypass-immune)已经先执行过了。bypass 只是“如果前面的层都没有拦你,那我也不拦你”——它跳过的是本层的确认弹框,而非整个安全管道。 dontAsk 不是“全部允许”,而是“全部拒绝”。它的语义是“不要问我,直接拒绝所有没有被规则明确放行的操作”。适合无人值守场景:只跑规则白名单内的操作,其余一律拦截。

4.4.5 第四层:AI分类器(动态审查)

这一层就是有一个分类器,也就是使用 AI 最后来判断,是否允许还是拒绝还是人工 approve。只不过这一层也有策略,先固定规则跑 - AI 弱分类(省 Token)- AI 强分类 - 错误处理兜底。所以这就是企业项目和自己做的项目的区别。大家自己做,用 AI 分类,可能就调用个 API 写个提示词就完了,但是企业项目是用了多层的调用。看了这些架构我们也应该有意识对齐,当然自己做项目肯定不如企业项目复杂,但是我们可以尽量设计地更复杂,更稳健,让面试官觉得我们的项目并不简单
只有 auto 模式才会走到这一层。这就是视频文稿中提到的“背后跑了两个 AI”——主 AI 负责干活,另一个独立的 AI 做安全分类,审查每个操作是否安全。 快速路径(省钱优化) 在真正调用 AI 分类器之前,先检查两条快速路径:
  1. 安全工具白名单: ReadGrepGlobSleepTodoWrite 等完全无副作用的工具,直接放行,无需分类器审查。设计原则是——只有零副作用的工具才进白名单,WriteEditBash 这些有副作用的工具一律不在。
  2. 工作目录内的编辑: 如果操作是在项目目录内编辑文件(模拟 acceptEdits 行为),也直接放行。
大部分日常操作(读文件、搜索、在项目内写代码)在快速路径就被放行了,只有少数操作需要真正调用分类器。 两阶段分类器(先粗筛后精筛) 快速路径都不适用时,调用 AI 分类器。它不是简单地问一次“安全吗?”,而是同一个问题问两遍,用不同的力度:
两阶段分类器
Stage 1:快速粗筛(64 token,偏保守)
提示词要求 "Err on the side of blocking"(宁可错拦,不可漏放)

├─ 判断为安全 -> ✅ 直接放行(完成)
│                 大部分安全操作在这里就结束了

├─ 判断为危险 -> 进入 Stage 2
└─ 无法判断   -> 进入 Stage 2



Stage 2:深度精筛(4096 token,带推理链)
要求 AI 先写下推理过程,再给结论

├─ 判断为安全 -> ✅ 放行(翻案成功)
├─ 判断为危险 -> ❌ 阻止
└─ 无法判断   -> ❌ 阻止(安全优先)
设计理念: Stage 1 偏向保守(提示词原文 “Err on the side of blocking”,即宁可错拦),只用 64 token 做一个快速的安全 / 危险判断——如果连保守策略都认为安全,那确实安全,不需要进一步审查。 Stage 2 给被误拦的操作一次“翻案”机会,用 4096 token 让 AI 写下完整的推理链再做结论,减少误报。如果 Stage 2 也无法给出明确结论,默认阻止(fail closed)。 为什么不直接用一个阶段?省钱。 大部分操作在 Stage 1 就完成了(64 token,快且便宜),只有被 Stage 1 标记为“可疑”的操作才需要 Stage 2 的深度推理(4096 token,慢且贵)。 防注入设计 分类器的输入经过精心过滤。最关键的一点:对话记录中故意排除了主 AI 的文本输出,只保留用户消息和工具调用记录。 原因是:恶意代码文件可能包含 prompt injection 指令,让主 AI 输出特定文本来说服分类器放行危险操作。通过排除主 AI 的文本,分类器只看到“做了什么”(工具调用),看不到主 AI “说了什么”——从源头上阻断注入攻击路径。 分类器还有自己独立的系统提示词,读取 CLAUDE.md 作为用户意图上下文,与主 AI 的提示词体系完全隔离 容错与降级 分类器不是 100% 可靠的系统,源码设计了三种降级机制:
异常场景处理方式设计原则
分类器 API 不可用Iron Gate 机制:退回用户手动确认Fail Closed,宁可中断也不放过
连续多次拒绝自动降级为用户确认模式防止分类器误判阻塞工作流
对话记录超出上文交互模式退回手动确认,无人值守模式直接终止确定性错误不重试

4.4.6 设计思想

回顾整个四层管道,有三个核心设计思想值得展开: 第一.纵深防御(Defense in Depth) 不依赖单一安全机制,而是叠加四层——静态规则做快速过滤,工具自检做细粒度判断,模式做策略兜底,AI 分类器做上下文感知的最终审查。每层都可能有漏洞,但叠在一起漏洞被覆盖。这就是 Boris 所说的“瑞士奶酪模型” 第二.Fail Closed(默认拒绝) 贯穿整个管道的基调是“不确定就拒绝”: 分类器解析失败 -> 阻止,分类器 API 不可用 -> 返回用户确认,dontAsk 模式下无规则覆盖 -> 拒绝。系统不会因为任何故障而放过潜在危险操作 第三.安全与效率的平衡 用 AI 做安全审查更准但更贵(每次操作都要额外 API 调用)。源码通过三级优化降低开销: 安全工具白名单(零副作用工具直接跳过)、acceptEdits 快速路径(项目内编辑直接通过)、两阶段分类器(Stage 1 用 64 token 快速过滤大部分安全操作) 最终,真正需要完整分类器推理的操作是少数 面试呼应
  1. 这套权限系统直接关联笔 Agent 安全设计 章节 和 Agent 通信安全章节。如果面试中被问到“Agent 项目怎么做安全控制”,可以从这三个层面回答:多层防御(不靠单点) -> Fail Closed(不确定就拒绝) -> 防注入(从信息流源头过滤,分类器只看工具调用,不看模型文本输出
  2. 与 OpenClaw 的对比也值得一提:OpenClaw 用规则 + 沙箱实现安全,没有独立 AI 审查;Claude Code 用独立 AI 分类器理解上下文做判断,更安全但成本更高。两者代表了“静态规则 vs 动态 AI 审查”两种安全哲学

4.5 成本追踪与速率限制

一个成熟的 Agent 产品和一个玩具项目的核心区别之一,就是有没有完善的成本控制机制。你自己做项目可能不太关心花了多少 token,但是一个商业产品必须精确追踪每一次 API 调用的消耗,同时要避免用户在不知情的情况下撞上配额或烧掉大量额度 这也是 Agent 面试里很容易被追问的一类问题:
  • 你的 Agent 如何控制成本?
  • 如何监控每次调用和每个会话的成本?
  • 如何防止用户一次任务把 token 预算打爆?
  • 如果用户快被限流了,你的系统怎么提前感知?
很多人回答这类问题时只会说“设置 max_tokens”或者“限制调用次数”,这其实不够。真正产品级的成本控制,至少要同时回答两个问题:能不能继续用,以及已经消耗了多少。所以这一节不只是分析 Claude Code 的源码,也是在提炼一套我们自己做 Agent 项目时可以复用的成本监测设计。 Claude Code 的成本控制可以用一个很简单的框架理解:一边限制速率,一边限制花费。
  • 限制速率:回答“按当前消耗速度,还能不能继续调 API”。它关注账号配额、时间窗口、配额消耗速度、限流状态,以及限流后的处理策略。
  • 限制花费:回答“这次以及这个会话消耗了多少”。它关注 token 用量、模型单价、缓存读写成本、单次查询预算,以及会话级累计。 这两条线合在一起,构成 Claude Code 的成本闭环:前者防止用户把账号配额用爆,后者防止一次会话或一次查询无节制地消耗 token。
读完这一节,应该能得到两类收获:
  1. 面试回答思路:当面试官问“Agent 如何做成本控制”时,可以从速率限制、实时计费、缓存成本、预算保护、会话持久化几个角度系统回答。当面试官问你,如何防止 Agent 进入无线循环、无限消耗TOKEN时,我们也能够借助今天的问题有一个回答。我也会结合今天的知识,总结一些常见的面试问题。
  2. 项目设计启发:首先我们要有一个意识,就是我们在做自己的Agent项目的时候,需要考虑成本模块。所以你最好能够在你的项目中设计出一个模块专门负责成本控制的。另一方面成本控制模块也可以从两个方面,比如设计两个类。一类专门统计速率,按照现在的消耗,是否需要限速,需要提示消耗过多,及时提醒?第二个类统计花费,持久化每一次请求工作的Token消耗,并从输入、输出、缓存读写、网页搜索、模型维度等方面去统计。这些就是看完本篇给我们的启示。

4.5.1 总览:两条成本控制路线

调用LLM的API 响应回来以后,Claude Code 会从两个方向处理成本问题:
成本控制路线总览
API 响应返回 
├─ 路线一:限制速率(当前配额消耗速度是否正常) 
│ ├─ 输入:服务端返回的配额/限流信号 
│ ├─ 处理:解析多时间窗口配额 + 判断消耗速度 
│ ├─ 状态:汇总成统一的配额状态 
│ └─ 输出:限流状态、提前预警、额外用量/升级/等待策略、企业策略限制 

└─ 路线二:限制花费(这次到底消耗了多少) 
	├─ 输入:usage token/tool 计数 
	├─ 处理:按模型价格把 usage 换算成费用 
	├─ 状态:费用累加到会话状态 + 按模型统计 
	└─ 输出:会话成本累计、Token Budget、保存/恢复
一般讲到成本,我们通常会先想到 token 花费,但 Claude Code 这里其实把问题拆成了两层:按当前速度,服务端配额还能不能继续支撑使用,以及客户端已经花了多少钱,具体来讲:
  1. 速率 / 配额问题:用户的订阅或账号额度是不是快被服务端限制了?如果快被限制,系统如何提前知道?如果已经被拒绝,系统如何决定下一步?
  2. 花费 / 账单问题:本次调用用了多少 token?按当前模型价格折算多少钱?这个会话累计花了多少?单次查询有没有继续跑下去的必要?
换句话说,速率路线关心的是 quota 按当前消耗速度是否还能支撑继续调用;花费路线关心的是 usage 如何换算成成本并累计到会话。前者主要读服务端返回的限流/配额信号,后者主要读响应里的 usage 统计
项目启发:做 Agent 成本控制时,不要只设计一个“费用统计器”。更合理的拆法是:一个模块负责配额/速率状态,一个模块负责 token/费用累计。两者数据源不同、处理逻辑不同、触发的保护动作也不同
下面就按照这两条路线展开

4.5.2 路线一:限制速率

这里的“速率”不是传统意义上的“每分钟最多访问多少次 API”。它更接近 quota burn rate(配额消耗速度):按照当前消耗速度,用户离额度上限还有多远?是在正常消耗,还是消耗得太快? 所以速率路线的目标是:在服务端真正拒绝请求之前,尽早感知配额消耗速度是否异常;如果已经被限流,就给出可执行的处理策略。 它不是一堆零散判断,而是一条连续流程:
速率控制流程
API 调用完成 

读取服务端配额信号 

整理成统一的配额状态 

按照短期 / 长期 / 模型等维度判断风险 

判断当前消耗速度是正常还是偏快 

如果按当前速度可能提前耗尽:提前预警 

如果已经被限制:给出等待、加额度、升级、组织协作等处理策略 

企业策略再做一层能力管控
下面按这个流程来看:
  1. API 调用后读取服务端配额信号 Claude Code 不靠客户端自己猜“用户还能不能继续用”。每次 API 调用之后,服务端都会把当前账号的配额状态返回给客户端。客户端要先读到这些信号,才能知道当前请求到底处于哪种状态:
  • 还能正常继续调用;
  • 已经接近某个额度上限;
  • 已经被服务端限制;
  • 虽然基础额度不足,但可能还有额外用量、升级或等待恢复等路径。 这一层解决的是“信息来源”问题:配额状态必须以服务端判断为准,而不是客户端自己估算。 因为真正决定能不能继续调用的,是服务端的账号、订阅、组织和额度系统。
  1. 把零散信号整理成统一状态 读到配额信号以后,Claude Code 不会让上层业务到处自己判断,而是先把它们整理成统一的配额状态。这个状态只需要回答三个问题:
  • 当前是否可用:还能不能继续调用。
  • 风险在哪里:是短期额度、长期额度,还是某类高价模型额度有风险。
  • 下一步怎么办:继续、提醒、等待、申请额度、升级,还是换一种执行策略。 这一步很关键。因为后面的提前预警、限流处理、任务调度,都不应该直接面对一堆底层信号,而应该面对一个统一状态。否则每个模块都会写一套判断逻辑,最后很容易不一致。
  1. 多个维度判断配额消耗速度 有了统一状态以后,Claude Code 会继续判断“当前消耗速度是否合理”。它不是只看一个“总额度”,而是把配额拆成多个维度:
控制维度解决的问题
短期窗口防止短时间内爆发式调用,把额度瞬间打满
长期窗口防止一个周期内总用量持续失控
模型维度防止高价模型被过度使用
额外用量判断基础额度不足后,是否还能进入兜底付费路径
所以速率控制不是简单的“限制调用次数”,也不是只问“现在用了多少”。它真正关心的是:按照当前速度继续用,会不会比预期更早撞上上限。 短期窗口看短时间内是不是烧得太快,长期窗口看整个周期内是不是会提前耗尽,模型维度看高价模型是不是消耗过快,额外用量则决定额度耗尽后的补救路径
  1. 如果消耗速度偏快,就提前预警 如果服务端还没有真正拒绝请求,但系统发现消耗速度过快,就会进入提前预警。这里的判断逻辑不是只看“用了多少”,而是看“用掉这些额度时,时间才过去了多少”。 核心思想是:使用率高 + 时间还早 = 消耗过快。 同样是用掉一部分额度,如果发生在周期刚开始,说明后面很可能会提前耗尽;如果发生在周期快结束,就不一定危险。 所以提前预警做的是中间层保护:它不是直接阻止用户,也不是等到服务端拒绝才处理,而是在“还能用,但按当前速度会提前耗尽”的阶段提醒用户调整节奏
  2. 如果已经被限流,就给出下一步策略 如果请求已经被服务端限制,Claude Code 也不是简单报错退出,而是把“不能继续”进一步翻译成“接下来能做什么”。常见处理路径包括:
  • 等待恢复:告诉用户什么时候可以继续,避免无意义重试
  • 增加额度:如果账号支持额外用量,引导用户进入额外用量路径
  • 升级计划:如果当前套餐额度不够,引导用户升级
  • 组织协作:如果是团队或企业账号,可能需要管理员开通额度或调整组织策略
  • 调整任务:降低任务规模、换低价模型、拆分任务,减少继续撞限流的概率 这里的产品价值是:系统不仅知道“不能继续”,还知道“为什么不能继续”以及“下一步怎么继续”。这比简单返回一个错误码更符合 Agent 产品的使用场景。
  1. 企业策略做更高层的能力管控 最后,Claude Code 还会叠加一层企业策略。它和 API 配额不是同一层问题:配额回答“额度够不够”,企业策略回答“组织允不允许” 比如企业可能允许普通对话,但限制远程执行、外部工具、高价模型或敏感数据相关能力。这类策略一般需要服务端统一配置、客户端本地缓存、定期刷新,并且在策略服务不可用时有明确的降级原则:普通能力可以尽量不阻塞,合规或敏感能力则应该更保守 小结:这一条速率路线的核心特点可以概括成四个词:
    1. 服务端可信:能不能继续调用,以服务端配额状态为准。
    2. 状态统一:不要到处散落判断,先汇总成统一配额状态。
    3. 分层判断:短期、长期、模型、额外用量分开看,判断当前消耗速度是否偏快。
    4. 可执行处理:预警和限流都要给出下一步,而不是只报错。
项目启发:做自己的 Agent 时,可以把速率控制设计成一个独立的 Rate Limit Manager。它负责读取服务商配额信号、归一化状态、多维度判断消耗速度、触发预警、处理真正限流,并和组织策略联动。这样任务调度、重试、降级、提醒都会围绕同一条流程展开,而不是散落在各个模块里。

4.5.3 路线二:限制花费

花费路线的目标是:把每次 API 调用产生的 token / 工具 / 缓存消耗,换算成可理解、可累计、可控制的会话成本。 它和速率路线一样,也不是几个孤立功能,而是一条连续流程:
花费控制流程
API 调用完成 

读取本次调用的 usage 

拆成输入、输出、缓存、工具等账单项 

按模型价格换算成本 

累加到会话级成本状态 

用 Token Budget 判断单次查询是否值得继续 

把会话成本保存下来,下一次恢复
下面按这个流程来看:
  1. API 调用后读取 usage 花费路线的起点,是每次模型调用结束后拿到本次调用的 usage。这里的 usage 不只是一个“总 token 数”,而是成本计算的原始账单数据。 从 Claude Code 的统计口径看,它关心的不是“这次一共用了多少 token”这么粗的数字,而是会把 usage 拆成几类消耗来源:
usage 统计项它回答的问题
输入 token这次请求送进模型的上下文有多长
输出 token模型这次生成了多少内容
缓存读取 token有多少上下文是从缓存里复用的
缓存写入 token有多少上下文被写入缓存,供后续复用
网页搜索次数本次调用是否触发了额外计费的搜索能力
模型名称这些 token 是在哪个模型上消耗的
本次费用这些消耗按当前模型价格折算后是多少钱
这一层解决的是“成本数据从哪里来”的问题:没有结构化 usage,就没有后面的计费、累计、预算和优化。 所以 Claude Code 总结 usage 的第一步,其实是在回答:这次模型调用的钱,到底花在输入、输出、缓存、搜索,还是高价模型上?
  1. 把 usage 拆成可计费的账单项 读到 usage 之后,Claude Code 会把一次调用拆成多个账单项,而不是只记录一个 token 总数:
账单项为什么要单独记录
输入 token输入越长,上下文成本越高
输出 token输出通常比输入更贵,长回答会明显增加成本
模型类型不同模型单价不同,高价模型需要单独观察
服务端工具网页搜索这类能力可能有额外计费
缓存读写缓存命中和缓存写入的成本差异很大
这一步的意义是把“模型调用”变成“结构化账单”。只有账单项拆得足够清楚,后面才能知道成本到底来自哪里:是输入上下文太长,输出太多,高价模型用太频繁,还是搜索和缓存策略没有设计好。
项目启发:我们自己做项目时,不能只说“我要统计 token”,还要说清楚统计哪些 token(比如输入,输出,Tool, SKILL)等、按什么维度聚合、最后要回答什么成本问题
  1. 按模型价格换算成真实成本 有了账单项之后,Claude Code 会结合模型价格,把 token、缓存和搜索消耗换算成金额。这里要注意两点: 第一,不同模型价格不同。同样的 token 数,用在便宜模型和高价模型上,最终成本可能完全不同。所以成本计算必须带上模型维度,不能只看 token 总数。 第二,缓存也要进入成本模型。缓存写入通常更像一次“前期投入”,后续缓存读取才是“节省成本”。所以 Prompt Cache 不能只当作性能优化,它本身也是成本模型的一部分。 完整公式不需要记具体数字,只要抓住一个原则:
总费用 = 输入成本 + 输出成本 + 缓存写入成本 + 缓存读取成本 + 搜索等额外成本。 如果遇到未知模型,也应该有默认估算和异常记录,避免成本计算直接断掉。
  1. 累加到会话级成本状态 单次调用算完以后,费用不会只停留在这一轮请求里,而是会累加到会话状态。Claude Code 这里有一个很重要的设计:它不是只维护一个总费用,而是按模型维护一份 usage 汇总 也就是说,每个模型都会有自己的结构化账单,大致包括:
按模型聚合的统计项用来回答什么问题
输入 token 总数这个模型一共吃进了多少上下文
输出 token 总数这个模型一共生成了多少内容
缓存读取 token 总数这个模型复用了多少缓存上下文
缓存写入 token 总数这个模型创建了多少缓存上下文
网页搜索次数这个模型触发了多少次搜索类额外成本
成本总额这个模型累计花了多少钱
上下文窗口 / 最大输出能力这个模型本身的容量边界是多少
在这个基础上,会话级追踪再把各个模型的账单汇总起来:
会话级成本追踪
会话级追踪: 
├─ 总费用 
├─ 总输入 / 输出 token 
├─ 缓存读取 / 缓存写入 token 
├─ 网页搜索次数 
├─ 工具耗时 
├─ API 调用耗时和重试成本 
├─ 代码修改规模 
└─ 按模型分类的使用量
这一步解决的是“成本归属”问题。只看全局总成本是不够的,至少要能回答:这个会话花了多少钱?哪个模型最贵?输入贵还是输出贵?缓存有没有省钱?搜索有没有带来额外成本?哪类任务最容易爆预算?
  1. 用 Token Budget 判断单次查询是否值得继续 会话级累计解决的是“已经花了多少”,但还不够。Agent 最大的问题是:一次任务可能不断续跑、不断调用工具、不断扩上下文,最后在用户没注意的时候消耗大量 token 所以 Claude Code 还有单次查询级别的预算管理。它不只是看“有没有超过上限”,还会看“继续跑有没有收益”:
    • 如果预算还比较充足,而且本轮输出仍然有明显增量,就允许继续。
    • 如果已经接近预算上限,就停止继续消耗。
    • 如果连续几轮输出增量都很低,说明进入收益递减,也应该停止。 这一步的关键是:成本控制不能只看上限,还要看收益。 如果模型已经在原地打转,哪怕还没完全用完预算,也应该及时停下来,让用户重新确认方向。
这里对我们也是一个很好的启示。也就是我们怎么防止Agent无限调用。我们知道我们讲的ClaudeCode也好,Openclaw也好,它内部用了ReAct是自己在循环中思考,推理的。所以如何防止他无限调用呢?设置最大此处我觉得大家都可以想到吧,但是看到这里,我们的有了新的思路:可以从预算以及输出增量的角度,前者从成本上控制,后者从收益上控制是否需要继续迭代。我也会将这个思路总结到后面面试题目中
  1. 保存并恢复会话成本
最后,费用数据不能只存在内存里。Claude Code 会把会话费用保存到本地,确保终端关闭或A会话切换后,成本统计不会直接丢失 保存的重点不是某个具体字段,而是保留会话成本上下文:累计费用、token 用量、模型分布、工具耗时、任务规模、会话 ID 等。恢复时再通过会话 ID 判断是不是同一个会话:如果匹配,就接着之前的成本状态继续累计;如果不匹配,就从零开始,避免串账。 这一步解决的是“成本连续性”问题:用户关掉终端再回来,仍然能接上同一个会话的成本上下文。 限制花费路线小结 这一条花费路线的核心特点可以概括成四个词:
  1. 账单结构化:每次调用都拆成输入、输出、缓存、工具、模型等账单项。
  2. 价格模型化:不同模型、缓存读写、网页搜索等额外消耗要进入同一套成本公式
  3. 会话可观测:成本要按会话、模型、工具、任务类型累计,而不是只记总数
  4. 预算可中断:单次任务不仅看是否超预算,还要看继续运行是否还有收益
项目启发:做自己的 Agent 时,可以把花费控制设计成一个独立的 Cost Manager:它负责采集 usage、拆账单项、换算费用、按会话累计、判断单次任务是否值得继续,并把成本状态持久化。这样成本控制就不只是日志,而是能参与任务停止、模型选择、缓存优化和后续分析的产品能力。

4.5.4 设计思想总结

现在再回到最开始的主线:Claude Code 的成本控制其实就是两条路线
成本控制双路线
限制速率:控制“按当前速度还能用多久” 
	- 多时间窗口配额 
	- 配额消耗速度判断 
	- 提前预警
	- 限流后的升级 / 额外用量 / 等待策略 
	- 企业策略限制
	  
限制花费:控制“已经消耗了多少” 
	- usage 实时计费
	- 模型定价表 
	- Prompt Cache 读写成本 
	- 会话级累计 
	- Token Budget 
	- 会话费用持久化与恢复
这两个方向解决的是不同问题:
  • 速率路线更像“配额消耗速度保护”:判断用户按当前速度会不会提前撞上限流墙
  • 花费路线更像“账单保护”:防止一次调用、一次会话、一次查询无节制地消耗
面试时如果被问“Agent 项目怎么做成本控制”,可以按这个框架回答:
  1. 先分两条线:限制速率 + 限制花费,不要混在一起讲。
  2. 限制速率:服务端给出配额状态,客户端结合时间窗口判断消耗速度是否偏快,提前预警,并在限流后提供升级 / 额外用量 / 等待策略。
  3. 限制花费:每次 API 调用后用 usage + 模型定价表算成本,包含 Prompt Cache 和网页搜索等额外成本,按会话 / 模型累计。
  4. 加预算控制:单次查询 Token Budget、会话级累计、会话持久化恢复。
  5. 企业管控:团队或企业场景下,还可以通过组织策略远程禁用特定能力。
这样讲比单纯说“设一个 max_tokens”更完整:它同时覆盖了配额、成本、预算和企业管控

4.5.5 成本控制面试问题

可以先把成本控制拆成两条线:限制速率和限制花费第一条线是速率检测,负责判断配额消耗速度。系统会读取服务商返回的配额状态,结合短期、长期、模型等窗口判断当前消耗是否偏快,以及按这个速度继续使用会不会提前撞上服务端配额上限。如果只是接近风险区间,就提前预警;如果已经被限流,就给出等待恢复、增加额度、升级计划或调整任务的处理策略第二条线是花费统计,负责回答“已经消耗了多少”。每次模型调用后,系统会根据 usage 拆出输入 token、输出 token、缓存读取、缓存写入、网页搜索次数和模型信息,再结合模型定价表换算成本,并按会话和模型维度累计。这样不仅能看到总花费,还能知道钱具体花在输入、输出、缓存、搜索还是高价模型上最后还要加一层预算保护,比如单次查询的 Token Budget。它不只是限制最大 token,还会判断 Agent 内部续跑是否还有明显收益,避免一次任务不断循环、持续烧 token
我会分三层做成本监控第一层是单次调用级别。每次模型调用结束后,都记录结构化 usage,包括模型名、输入 token、输出 token、缓存读取、缓存写入、工具调用情况和估算费用。这样可以知道单次请求的钱具体花在哪里第二层是会话聚合级别。把多次调用按会话、模型、用户、任务类型聚合,同时补充工具耗时、API 耗时、代码改动规模等信息。这样可以回答“这个会话总共花了多少钱”“哪个模型最贵”“哪类任务最容易爆预算”第三层是成本归因级别。拿到聚合数据后,要进一步分析成本来源:是高价模型用太多,还是输入上下文太长?是输出太多,还是缓存命中率太低?是搜索等额外能力带来了额外成本,还是某类任务本身就更贵?这样监控成本就不是只看一个总金额,而是能定位成本来源,并为后续优化模型选择、上下文裁剪、缓存策略和工具使用提供依据
可以分三层控制第一层是硬性预算控制。给一次用户任务设置 token budget,持续记录这次任务已经消耗了多少 token、还剩多少预算。如果已经接近预算上限,就停止继续自动续跑,避免一次任务无限消耗第二层是续跑次数控制。Agent 内部可能会经历多轮“模型思考 -> 工具调用 -> 读取结果 -> 再次思考”的循环,所以要记录已经自动续跑了几次。即使还没用完预算,也不能让它无限循环第三层是收益递减判断。只限制最大轮数还不够,因为有些任务可能前几轮就已经没有明显产出了。Claude Code 的思路是看每轮新增输出是否还有明显增量:如果连续几轮新增内容很少,说明模型可能在原地检查、重复总结或低价值补充,这时继续续跑的收益已经很低,就应该提前停止所以更完整的答案不是“设置最大轮数”这么简单,而是:预算控制负责限制成本,续跑次数负责限制循环长度,输出增量负责判断继续运行是否还有收益。 这三者结合,才能比较可靠地防止 Agent 在一个任务里持续烧 token
我会拆成五个部分:
  1. Usage Collector:采集每次模型调用的输入 token、输出 token、缓存读写、网页搜索次数和模型信息
  2. Cost Calculator:根据模型定价表、缓存读写、网页搜索等额外成本计算费用
  3. Budget Manager:维护请求级、会话级、用户级、模型级预算
  4. Rate Limit Manager:解析服务商配额信号,维护多时间窗口配额和提前预警
  5. Persistence & Analytics:把会话成本持久化,并按模型、工具、任务类型做聚合分析
这样设计的好处是,成本控制不再是一个零散的日志功能,而是一个完整的产品能力:能监控、能预警、能解释、能恢复,也能给后续优化提供数据

5. 面试问答

A: Claude Code 是 Anthropic 推出的 AI 编程 Agent。可以通过自然语言对话来完成代码编写、重构、调试,以及构建自动化工作流。它不只是代码补全工具,而是一个能自主规划、执行终端命令、调用外部服务的智能代理。可以在 VS Code 等编辑器中使用,也可以独立在终端中运行
CLAUDE.md 是放在项目根目录的 Markdown 文件,Claude Code 每次启动时会自动读取它,起到“持久化系统提示”的作用。它解决了 Claude Code 新会话“失忆”的问题。内容通常包括编码规范、技术栈说明、注意事项等。用 /init 命令可以让 Claude 自动生成一份,用 /memory 命令可以快速打开编辑。
有几条我认为最关键的实践: 第一,复杂任务先用 Plan Mode 规划,让 Claude 充分理解需求再执行,避免误改文件。 第二,控制 MCP 数量,只启用当前任务需要的 MCP,保持上下文窗口充裕。 第三,把反复使用的提示写成 Skill 文件,减少重复提示和 Token 浪费。 第四,部署代码前主动要求 Claude 做安全审查。 第五,始终将 API Key 存在 .env 或密钥管理服务里,绝不硬编码在代码中。
Hooks 是在 Claude Code 工作流特定时机自动触发的脚本,有 PreToolUse、PostToolUse 等六种类型。一个典型用法是配置 PostToolUse Hook,在 Claude 写完代码后自动调用 Prettier 格式化文件,无需人工干预。还可以利用 Stop Hook 在会话结束时自动保存当前进度摘要,实现跨会话记忆持久化。
A: /insights 是一个斜杠命令,运行后会分析你所有的 Claude Code 历史使用数据(跨项目),生成一份 HTML 格式的使用洞察报告,存放在用户目录的 ~/.claude/usage-data/report.html。报告会展示你的使用习惯、效率瓶颈、值得尝试的新功能等。一个实用技巧是把这个 HTML 文件上传给 ChatGPT,让它提炼出最值得优先执行的几条改进建议。
A: 几个关键策略:保持启用的 MCP 少于 10 个(虽然可以安装 20-30 个,但大多数时候禁用);在完成阶段性任务后手动 /compact 压缩;开始全新任务前 /clear 清空;对于需要跨会话延续的任务,在 CLAUDE.md 或专用文件中记录进度;使用 SubAgent 处理探索性任务,避免大量中间日志污染主对话。
Claude Code 有三层权限控制:文件操作权限(默认要确认,选择自动模式后本次会话内自动通过)、终端命令权限(即使在自动模式下,执行终端命令默认仍需确认)、完全绕过权限(使用 --dangerously-skip-permissions 参数,官方明确标注危险,需谨慎)。可以通过 /permissions 命令把信任的操作加入白名单,把危险操作加入黑名单,权限配置可以保存到项目级或用户级配置文件。
Claude Code 的记忆系统由 4 种存储和 3 大运作机制组成4 种存储:第一种是指令文件,也就是 CLAUDE.md。这是唯一由人手动编写的记忆,告诉 Claude 项目的规则和约束。它分 4 个层级:管理员全局、用户全局、项目级和本地私有,支持 include 指令引用其他文件,上限 4 万字符第二种是对话上下文,就是当前对话的消息数组,所有 LLM 应用都有,Claude Code 的特别之处在于配套了一套 5 层压缩策略来管理它。第三种是 Session Memory,是一个后台子代理在你工作时自动维护的结构化笔记。对话 token 超过 1 万后启动,之后每 5000 tokens 更新一次。它的作用是恢复会话时快速加载上下文,以及在上下文压缩时充当现成的摘要来源。第四种是持久记忆 Memdir,存在用户目录下的 memory 文件夹里,分 user、feedback、project、reference 四类。用一个索引文件 MEMORY.md 做入口,上限 200 行。这里有一个重要的设计决策:它故意不存代码事实,比如“某函数在第 30 行”这种信息。因为代码会变,但记忆不会自动更新,过时的代码记忆会变成危险的误导。代码相关的查询永远用 grep 和 glob 实时搜索,只有人的偏好和判断才值得持久化。3 大运作机制:加载方面,每轮对话前,所有层级的 CLAUDE.md 会被拼接在一起注入 system prompt。拼接顺序是利用了 LLM 的 recency bias,模型对 prompt 末尾内容天然给予更高注意力,所以排在后面的文件实际优先级更高。MEMORY.md 前 200 行自动加载,再用 Sonnet 小模型扫描所有记忆文件的标题,选出最多 5 条最相关的注入上下文。这是一种 push 模式,不用 RAG。写入方面,三个后台 Agent 分工合作。extractMemories 在每轮查询结束后自动提取持久记忆,Session Memory 按 token 增量持续更新笔记,AutoDream 每隔至少 24 小时且至少 5 个会话后做一次记忆整合去重,类似人类睡眠时整理白天记忆的过程。压缩方面则是 5 层流水线,从温和到激进逐层升级,这个下一章会展开核心设计思想可以用一句话概括:会变的东西实时搜,不变的东西持久存
版本一:以 OpenClaw 为例OpenClaw 采用一级压缩,但流程很精细。首先划分保留区,最近大约 2 万 tokens 的原始对话原封不动保留。然后把更早的旧消息按 token 数分成多个块,逐块调用 LLM 做总结,再把多块摘要合并成一个连贯的总结。压缩前还有一步叫 Pre-Compaction Memory Flush,会静默运行一轮提醒 Agent 把重要内容写入记忆文件,防止关键信息随压缩丢失。压缩后的结构就是一个合并摘要加上最近 2 万 tokens 的原文。这种方式的特点是每次触发都需要 LLM 调用,成本更高,但实现简单、行为可预测。版本二:以 Claude Code 为例Claude Code 设计了 5 层压缩流水线,逐层检查、按需执行,越往后越激进。第一层叫 Tool Result Budget,每轮都跑。当一轮对话中多个工具的返回结果累计超过 20 万字符时,系统会把最大的结果存到磁盘,原位替换成大约 2KB 的预览加一个文件路径。模型后续需要完整内容时可以自己去读。这是一种渐进式披露的思想,先给模型足够判断的预览,让它自己决定要不要加载全量。第二层叫 Microcompact,清理旧的工具结果。它会利用 Prompt Cache 的 60 分钟 TTL,如果缓存已过期就直接清旧内容,没有额外损失。或者通过 cache_edits 指令在服务端缓存副本中删除内容,客户端消息不改,缓存继续有效,省钱。第三层是核心层 Auto-compact,token 数超过大约 16.7 万时触发。它先尝试轻量方案,用后台已经维护好的 Session Memory 笔记充当摘要,不需要额外的 LLM 调用。如果轻量方案扛不住,再上 Full LLM Compact,把整段对话压缩成不超过 2 万 tokens 的结构化摘要,包含 9 个固定段落比如核心请求、涉及文件、待办事项等,压缩后还会自动恢复最多 5 个关键文件的内容让模型不至于完全失去文件上下文。第四层是硬拒绝,前面都压不下来就直接报错终止本轮。第五层是事后兜底,API 返回 413 错误后做一次摘要压缩再重试,每轮最多一次。两者的核心差异是: OpenClaw 一步到位但精细,分块加合并加预刷记忆。Claude Code 分两步走,先便宜后贵,用梯度设计换成本效率。大部分情况下前两层不需要 LLM 调用就够用了,Full Compact 是中低频事件。实践上建议主动用 /compact 命令并附带指令,比如“重点保留决策和待办”,比等系统自动压缩效果好,因为你能控制保留什么。
版本一:以 OpenClaw 为例OpenClaw 采用一级压缩,但流程很精细。首先划分保留区,最近大约 2 万 tokens 的原始对话原封不动保留。然后把更早的旧消息按 token 数分成多个块,逐块调用 LLM 做总结,再把多块摘要合并成一个连贯的总结。压缩前还有一步叫 Pre-Compaction Memory Flush,会静默运行一轮提醒 Agent 把重要内容写入记忆文件,防止关键信息随压缩丢失。压缩后的结构就是一个合并摘要加上最近 2 万 tokens 的原文。这种方式的特点是每次触发都需要 LLM 调用,成本更高,但实现简单、行为可预测。版本二:以 Claude Code 为例Claude Code 设计了 5 层压缩流水线,逐层检查、按需执行,越往后越激进。第一层叫 Tool Result Budget,每轮都跑。当一轮对话中多个工具的返回结果累计超过 20 万字符时,系统会把最大的结果存到磁盘,原位替换成大约 2KB 的预览加一个文件路径。模型后续需要完整内容时可以自己去读。这是一种渐进式披露的思想,先给模型足够判断的预览,让它自己决定要不要加载全量。第二层叫 Microcompact,清理旧的工具结果。它会利用 Prompt Cache 的 60 分钟 TTL,如果缓存已过期就直接清旧内容,没有额外损失。或者通过 cache_edits 指令在服务端缓存副本中删除内容,客户端消息不改,缓存继续有效,省钱。第三层是核心层 Auto-compact,token 数超过大约 16.7 万时触发。它先尝试轻量方案,用后台已经维护好的 Session Memory 笔记充当摘要,不需要额外的 LLM 调用。如果轻量方案扛不住,再上 Full LLM Compact,把整段对话压缩成不超过 2 万 tokens 的结构化摘要,包含 9 个固定段落比如核心请求、涉及文件、待办事项等,压缩后还会自动恢复最多 5 个关键文件的内容让模型不至于完全失去文件上下文。第四层是硬拒绝,前面都压不下来就直接报错终止本轮。第五层是事后兜底,API 返回 413 错误后做一次摘要压缩再重试,每轮最多一次。两者的核心差异是: OpenClaw 一步到位但精细,分块加合并加预刷记忆。Claude Code 分两步走,先便宜后贵,用梯度设计换成本效率。大部分情况下前两层不需要 LLM 调用就够用了,Full Compact 是中低频事件。实践上建议主动用 /compact 命令并附带指令,比如“重点保留决策和待办”,比等系统自动压缩效果好,因为你能控制保留什么。
A: 最根本的办法是不相信 Agent,而是让每个工具调用都经过多层权限约束。这样即使 Agent 想滥用工具,也很难突破多重防线。以 Claude Code 为例,它采用四层权限管道的设计:第一层是规则过滤——用户配置 allow/deny 规则,做快速匹配。关键是 deny 规则不可绕过,即使在完全信任模式下也生效,确保管理员的硬约束永远有效。第二层是工具自检——每个工具根据操作内容做细粒度判断。比如 Write 工具会检查是否试图写入 .git/.claude/ 等关键目录(bypass-immune,免疫绕过),这些目录在任何模式下都受保护。第三层是模式兜底——定义 5 种权限模式(default/acceptEdits/plan/bypass/dontAsk),代表不同风险偏好。模式选择本身约束了 Agent 的权限上界——再聪明的 Agent 也无法超出。第四层是 AI 分类器(仅 auto 模式)——独立 AI 根据上下文判断操作安全性。特意只看工具调用记录,不看模型输出,防止 prompt injection。两阶段判决:快速粗筛(64 token)+ 深度精筛(4096 token),既保证安全又控制成本。核心原则: Fail Closed(不确定就拒绝)+ Defense in Depth(纵深防御,不靠单点)。

6. 参考资料

Everything Claude Code 源代码

affaan-m 开源的 Everything Claude Code 主仓库,适合查看 Claude Code 实战指南、配置示例、Hooks、Skills 和安全实践