--- title: CLAUDE.md source_url: https://mp.weixin.qq.com/s/uHbvBbANCU7fHwvGhsr9sw publish_date: 2026-05-07 tags: [wechat, article, claude, agent, harness, llm] review_value: 7 review_confidence: 7 review_recommendation: neutral sha256: ac1e3b0ab01cb775241e8f5dedbf5189421135904936bae0a5ee5237e058cef7 --- ## 文章概要 Anthropic Claude Code 源码泄露事件(.map 文件未排除,1900+ TypeScript 文件,51万+ 行代码)让外界首次完整审视生产级 AI Agent 系统。本文顺着请求完整生命周期拆解每个环节——LLM 调用只是一行代码,真正让 Agent 可用的是围绕它精心设计的 Agent Harness。 ## 核心循环:8步生命周期 ``` 用户输入消息 ↓ 步骤1:组装上下文(系统提示词 + CLAUDE.md + 记忆 + 对话历史) ↓ 步骤2:调用 Claude API(异步生成器,流式传输) ↓ 步骤3:解析响应(text 块 + tool_use 块) ↓ 步骤4:权限检查(拒绝规则 → 允许规则 → 分类器 → 询问用户) ↓ 步骤5:执行工具(只读并行,写操作串行) ↓ 步骤6:反馈结果(工具结果变成对话消息) ↓ 步骤7:上下文检查(太大则压缩,否则回到步骤2) ↓ 步骤8:终止(无更多工具调用?完成。出错?恢复或退出) ``` **核心驱动**:`query.ts` 中的 `query()` 异步生成器函数,代码库里其他所有内容都为它服务。 ## 步骤1:上下文组装 ### buildEffectiveSystemPrompt() 系统提示词通过 `buildEffectiveSystemPrompt()` 拼装,分多部分:环境信息、工具使用说明、语气和风格等。 **两类内容:** | 类型 | 说明 | 缓存策略 | |------|------|----------| | **缓存部分** | 大多数内容(OS、项目结构等,会话过程基本不变) | 只算一次,每轮复用 | | **非缓存部分** | MCP 服务器相关指令(会话中可能动态变化) | 每轮重新计算 | 两组内容用 `SYSTEM_PROMPT_DYNAMIC_BOUNDARY` 标记分隔——边界前内容可跨用户共享 API 全局缓存范围。 ### 系统提示词内容清单 | 部分 | 是否缓存 | 内容说明 | |------|----------|----------| | 介绍 | 是 | 角色定义、安全指令、URL 处理规则 | | 系统 | 是 | 工具调用规则、权限行为、上下文压缩策略 | | 执行任务 | 是 | 编码规范、验证方式、安全要求 | | 操作 | 是 | 风险控制:可逆性检查、破坏性操作提示 | | 使用工具 | 是 | 工具使用偏好(如用 Read 而不是 cat) | | 语调和风格 | 是 | 输出风格、简洁性、代码引用格式 | | 会话指导 | 是 | 当前可用能力、Agent 类型说明 | | 记忆 | 是 | CLAUDE.md 中的项目约定和规则 | | 环境 | 是 | 工作目录、git 状态、系统信息等 | | MCP 指令 | 否 | 当前连接的 MCP 服务(动态变化) | | 总结结果 | 是 | 上下文被清理前保留的关键信息 | ### CLAUDE.md 四级加载 `getMemoryFiles()` 从当前工作目录向上遍历到根目录,在每级收集指令文件: **加载顺序(根→当前,越近优先级越高):** ``` 1. /etc/claude-code/CLAUDE.md (系统级) 2. ~/.claude/CLAUDE.md (用户级) 3. ~/.claude/rules/*.md (用户级) 4. /Users/me/projects/CLAUDE.md (项目级) 5. /Users/me/projects/myapp/CLAUDE.md (项目级) 6. /Users/me/projects/myapp/.claude/CLAUDE.md (项目级) 7. /Users/me/projects/myapp/.claude/rules/*.md (项目级) 8. /Users/me/projects/myapp/CLAUDE.local.md (本地级,gitignore) ``` ### @include 指令 CLAUDE.md 支持 `@include` 语法(最多5层深度): ```markdown # CLAUDE.md See our API conventions: @./docs/api-conventions.md And our testing standards: @./docs/testing.md ``` ### 完整上下文包 当用户输入"修复登录 bug"时,实际发送给 Claude 的内容: | 内容 | 大小 | |------|------| | 系统提示词 | ~15,000 tokens | | CLAUDE.md 文件 | ~2,000 tokens | | 记忆 | ~500 tokens | | MCP 指令 | ~300 tokens | | 对话历史 | ~5,000 tokens | | 用户消息 | ~10 tokens | ### 技能发现机制 `getSkillListingAttachments()` 收集所有可用技能,只保留名字和简单描述塞进系统提示词: ```xml The following skills are available for use with the Skill tool: - commit: Create a new git commit with a descriptive message. - review-pr: Review a pull request for code quality and correctness. - write-blog: Write blog posts for siddharthbharath.com. ``` **技能预算控制:** - 所有技能描述加起来最多占上下文 1%(200K 模型约 2000 tokens) - 每个技能描述 ≤ 250 字符 - 超出预算按需截断,详细定义按需通过 `ToolSearchTool` 拿取 ## 步骤2:API调用与异步生成器 ### queryLoop() 无限循环 核心是 `queryLoop()` 里跑 `while (true)`,每轮循环 = 一次完整 API 往返。 每轮开始时: 1. 发 `stream_request_start` 事件通知 UI 2. 控制工具返回体积(太大则裁掉) 3. 必要时对前一条回复做轻量压缩 4. 用 `appendSystemContext()` 拼出最终系统提示词 5. 发起请求,开始流式接收 ### State 对象的状态传递 每轮循环都会读、改、传 `State` 对象: - 压缩上下文后 → 更新 `state.messages` - token 限制触发重试 → 增加 `state.maxOutputTokensRecoveryCount` - 工具执行改变能力范围 → 更新 `state.toolUseContext` **关键:每一轮的决策都会影响下一轮的行为。** ## 步骤3:响应解析 ### text + tool_use 块 Claude 响应是流式生成的一块块内容: - `text`:要对用户说的话 - `tool_use`:要调用的工具 典型响应示例: ```json [ {"type": "text", "text": "让我看一下登录代码..."}, {"type": "tool_use", "id": "toolu_1", "name": "GrepTool", "input": {"pattern": "login", "glob": "**/*.ts"}}, {"type": "tool_use", "id": "toolu_2", "name": "GrepTool", "input": {"pattern": "authenticate", "glob": "**/*.ts"}} ] ``` Claude 可以在同一轮响应中**一边说话,一边发起工具调用**。 ### 43个内置工具 | 类别 | 工具 | |------|------| | 文件 I/O | FileReadTool, FileEditTool, FileWriteTool, NotebookEditTool | | 搜索 | GlobTool, GrepTool | | 执行 | BashTool | | Web | WebFetchTool, WebSearchTool | | Agents | AgentTool, SendMessageTool | | 任务 | TaskCreateTool, TaskGetTool, TaskUpdateTool, TaskListTool | | 规划 | EnterPlanModeTool, ExitPlanModeTool | | 用户交互 | AskUserQuestionTool | | 技能 | SkillTool | | MCP | ListMcpResourcesTool, ReadMcpResourceTool | ## 步骤4:权限检查 ### 四层判断机制 ``` 工具调用进来 ↓ 1. 命中拒绝规则 → 直接拦掉 ↓ 2. 命中允许规则 → 直接放行 ↓ 3. Bash 分类器 → 异步判断(最多等 2 秒) ↓ 4. 交互提示 → 询问用户 ``` 配置示例: ```json { "permissions": { "allow": ["Read", "Glob", "Grep", "BashTool(grep:*)"], "deny": ["BashTool(rm -rf:*)"] } } ``` ### 分类器判断逻辑 | 判断结果 | 行为 | |----------|------| | 只读操作(如 `git status`、`ls`) | 直接放行 | | 有风险操作(如 `rm`、`git push --force`) | 交给用户确认 | | 2秒内无法判断 | 进入交互提示 | ### 不同工具的通过路径 | 工具调用 | 层1拒绝 | 层2允许 | 层3分类器 | 层4询问 | 结果 | |----------|---------|---------|-----------|---------|------| | GrepTool("login") | 通过 | 命中允许规则 | - | - | 自动通过 | | BashTool("git status") | 通过 | 通过 | 判断为只读 | - | 自动通过 | | BashTool("rm -rf /") | 命中拒绝规则 | - | - | - | 直接拦截 | | FileEditTool("app.ts") | 通过 | 通过 | 通过 | 需要确认 | 弹出提示 | | BashTool("npm install") | 通过 | 通过 | 不确定(超时) | 需要确认 | 弹出提示 | ## 步骤5:工具执行 ### 工具统一接口 ```typescript type Tool = { name: string description(input, context): string inputSchema: ZodSchema execute(input, context): Promise isConcurrencySafe(input): boolean // 关键:标记能否并发执行 isReadOnly(input): boolean } ``` ### 并发/串行执行策略 执行前先看 `isConcurrencySafe()` 标记: - **只读操作**:并发执行(默认最多10个并行) - **写操作**:串行执行,避免冲突 ### 实际效果 - 一次要读多个文件 → 同时进行 - 一旦涉及改文件 → 串行执行 ## 关键要点 1. **LLM 调用只是一行代码**——真正让 Agent 可用的是围绕它的 Agent Harness 2. **上下文不只是"你的消息"**——是消息+项目规则+个人偏好+Agent记忆+对话历史 3. **系统提示词分两类**:缓存(跨用户共享)和非缓存(会话特定),用 `SYSTEM_PROMPT_DYNAMIC_BOUNDARY` 分隔 4. **CLAUDE.md 四级加载**:系统→用户→项目→本地,优先级从低到高 5. **技能预算控制**:描述占上下文 ≤1%,每个 ≤250 字符 6. **State 对象串联每轮循环**:每轮决策影响下一轮 7. **权限四层设计**:拒绝→允许→分类器→询问,分类器最多等2秒 8. **isConcurrencySafe 决定并发策略**:只读并行,写操作串行 ## 关联 - [[concepts/managed-agents-architecture]] — Anthropic Managed Agents 架构 - [[concepts/harness-engineering-framework]] — Harness Engineering 框架