Claude Code 写代码 Agent 完整逻辑分析,学习顶级公司的agent设计思路 本文共有16672个字,关键词: > 基于本仓库源码梳理。Claude Code 的核心范式是:**LLM + 工具循环(Agentic Loop)**。宿主不做独立的“需求 NLU / 代码 AST 分析器”,而是通过 System Prompt、上下文注入、工具执行与上下文压缩,让 Claude 模型自主完成理解、探索、写码与验证。 --- ## 1. 总览:一句话架构 ``` 用户输入 → processUserInput(解析 / 斜杠命令 / 附件) → 组装 System Prompt + CLAUDE.md + git 上下文 + 记忆 → queryLoop(无限循环) → 压缩上下文 → 流式调用 Anthropic Messages API → 若有 tool_use → 执行工具 → 把 tool_result 写回 messages → 继续下一轮 → 无 tool_use 时结束本轮,回复用户 ``` **代码如何“准确”落盘**:模型通过 Grep/Glob/Read 先读真实文件,再用 FileEdit(精确字符串替换)或 FileWrite 写入;工具层强制「先读后写」、校验 `old_string` 唯一匹配;可选 Plan Mode、AskUserQuestion、Verification 子代理进一步提高正确性。 --- ## 2. 关键文件地图 | 路径 | 职责 | |------|------| | `entrypoints/cli.tsx` | CLI 引导入口 | | `main.tsx` | Commander 主程序:会话、REPL / print 模式 | | `screens/REPL.tsx` | 交互 TUI:`onQuery` → `query()` | | `utils/handlePromptSubmit.ts` | 用户回车后的提交编排 | | `utils/processUserInput/processUserInput.ts` | 输入解析:斜杠命令 / 文本 / bash / 图片 | | `QueryEngine.ts` | SDK / 无头会话:`submitMessage()` | | **`query.ts`** | **Agent 主循环** `query()` / `queryLoop()` | | `constants/prompts.ts` | 默认 System Prompt 组装 | | `utils/systemPrompt.ts` | System Prompt 优先级(override / agent / custom / default) | | `utils/queryContext.ts` | `fetchSystemPromptParts`:system + userContext + systemContext | | `context.ts` | `getUserContext`(CLAUDE.md)/ `getSystemContext`(git status) | | `Tool.ts` / `tools.ts` | 工具类型与注册表 | | `services/tools/toolOrchestration.ts` | `runTools()`:并发 / 串行执行 | | `services/tools/toolExecution.ts` | 单工具权限 + 调用 | | `services/tools/StreamingToolExecutor.ts` | 流式边收边执行工具 | | `services/api/claude.ts` | `queryModelWithStreaming`:Anthropic API | | `services/compact/*` | micro / auto / reactive / snip 压缩 | | `memdir/*` | 长期记忆目录、MEMORY.md、相关记忆检索 | | `utils/attachments.ts` | 附件注入(记忆、IDE 选区、@文件等) | | `tools/{Grep,Glob,FileRead,FileEdit,Bash,Agent}Tool/` | 探索与改码工具 | | `utils/sessionStorage.ts` | 会话 transcript 持久化 / resume | --- ## 3. 端到端流程(用户输入 → 代码输出) ```mermaid flowchart TD A[用户输入 / SDK prompt] --> B[handlePromptSubmit / QueryEngine.submitMessage] B --> C[processUserInput] C -->|斜杠命令本地处理| C1[不进入 query 或带特殊副作用] C -->|普通 prompt| D[创建 UserMessage + Attachments] D --> E[组装 SystemPrompt + userContext + systemContext] E --> F[query / queryLoop while true] F --> G[上下文预处理: budget / snip / microcompact / autocompact] G --> H[callModel = queryModelWithStreaming] H --> I{assistant 含 tool_use?} I -->|否| J[stop hooks / token budget / 结束本轮] I -->|是| K[runTools / StreamingToolExecutor] K --> L[权限 canUseTool → tool.call] L --> M[tool_result 用户消息 + attachments] M --> N[messages = 旧消息 + assistant + toolResults] N --> F J --> O[UI 显示文本 / 文件已由 Edit/Write 落盘] ``` ### 3.1 入口 - **交互模式**:`cli.tsx` → `main.tsx` → Ink `REPL` → 回车 → `handlePromptSubmit` → `onQuery` → `query()` - **SDK / 无头**:`QueryEngine.submitMessage()` → `processUserInput` → `query()` ### 3.2 用户输入处理(`processUserInput`) 1. 识别 `/slash` 斜杠命令、bash 模式、粘贴图片、`@` 提及 2. 执行 `UserPromptSubmit` hooks(可拦截) 3. 生成 `UserMessage` 4. 通过 `getAttachmentMessages` 注入: - IDE 打开文件 / 选区 - `@file` 提及的文件内容 - 嵌套目录的 `CLAUDE.md` / rules - 相关记忆预取结果等 5. 返回 `shouldQuery`:纯本地命令(如 `/help`)可不调模型 ### 3.3 Agent 主循环(`queryLoop`) 核心在 `query.ts`: ```ts // query.ts — 伪结构 async function* queryLoop(params) { using pendingMemoryPrefetch = startRelevantMemoryPrefetch(...) while (true) { // 1. 裁剪过大 tool 输出 / snip / microcompact / autocompact messagesForQuery = await applyToolResultBudget(...) messagesForQuery = snipCompactIfNeeded(...) messagesForQuery = await microcompact(...) // 可能触发 autocompact → 用摘要替换长历史 // 2. 流式调模型 for await (const message of deps.callModel({ messages: prependUserContext(messagesForQuery, userContext), systemPrompt: fullSystemPrompt, tools: toolUseContext.options.tools, ... })) { // 收集 assistant 消息;若出现 tool_use → needsFollowUp = true // 可选 StreamingToolExecutor 边流边执行 } // 3. 无 tool_use → stop hooks / 结束 if (!needsFollowUp) { ... return / continue recovery ... } // 4. 有 tool_use → runTools → 拼 tool_result → continue state.messages = [...messagesForQuery, ...assistantMessages, ...toolResults] continue } } ``` **终止条件**:无 `tool_use` 且 stop hooks 不阻塞;或 abort、maxTurns、prompt_too_long(无法恢复)、hook_stopped、blocking_limit 等。 --- ## 4. 如何分析用户需求 **结论:宿主侧没有独立意图分类器。** 需求理解由 Claude 模型完成,宿主提供行为规范与澄清手段。 ### 4.1 System Prompt 行为约束 `constants/prompts.ts` → `getSystemPrompt()` 组装多段指令,核心包括: | 段落 | 作用 | |------|------| | Intro | 「你是交互式软件工程 agent」 | | `getActionsSection` | 可逆操作可大胆做;破坏性操作先确认 | | `getUsingYourToolsSection` | 强制用专用工具而非滥用 Bash | | Plan / AskUserQuestion | 复杂任务先调研;歧义时提问 | | Memory 段 | 何时读写长期记忆 | | Env / Language / Output Style | 环境、语言、输出风格 | 典型身份定义: ```text You are an interactive agent that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user. ``` ### 4.2 辅助「理解」机制 | 机制 | 位置 | 作用 | |------|------|------| | Thinking blocks | `thinkingConfig` + API thinking | 模型内部多步推理 | | Plan Mode | `EnterPlanModeTool` / `ExitPlanModeV2Tool` | 复杂任务先调研再实现;限制写权限 | | AskUserQuestion | `AskUserQuestionTool` | 澄清歧义选项 | | Todo / Task 工具 | `TodoWriteTool` / `TaskCreateTool` | 拆解任务并跟踪进度 | | Side query 记忆选择 | `memdir/findRelevantMemories.ts` | 用较小模型从记忆索引挑相关文件 | | Ultraplan 等关键字 | `processUserInput` | 特殊触发词改变流程 | ### 4.3 实际「需求分析」过程(模型侧) 典型模型行为(由 prompt + 工具驱动): 1. 读用户原话 + CLAUDE.md + 相关记忆 attachment 2. 若任务模糊 → `AskUserQuestion` 或先探索再确认 3. 若任务复杂 → 进入 Plan Mode 或写 Todo 4. 用 Grep/Glob/Read/Bash 收集证据后再改代码 5. 改完后用 Bash 跑测试 / 可选 Verification Agent --- ## 5. 如何分析用户已有代码 **结论:不做全局预索引灌入模型。** 模型按需用只读工具探索;种子上下文来自 CLAUDE.md、@文件、IDE 选区。 ### 5.1 探索工具 | 工具 | 文件 | 行为 | |------|------|------| | **Grep** | `tools/GrepTool/` | ripgrep:`pattern/path/glob/type`;可并发 | | **Glob** | `tools/GlobTool/` | 文件名通配 | | **FileRead** | `tools/FileReadTool/` | 按行读;支持 offset、PDF、notebook、图片;维护 `readFileState` | | **Bash** | `tools/BashTool/` | `git status`、测试、构建、复杂 shell | | **LSP** | `tools/LSPTool/` | 诊断 / 符号(需开启) | | **Agent(Explore)** | `tools/AgentTool/built-in/exploreAgent` | 专用探索子代理,保护主上下文 | | **WebFetch / WebSearch** | 对应 tools/ | 外部文档 | System Prompt 明确要求: ```text To read files use FileRead instead of cat/head/tail/sed To search for files use Glob instead of find/ls To search content use Grep instead of grep/rg Reserve Bash for system commands that truly need a shell ``` ### 5.2 种子上下文(无需工具即可看到) | 来源 | 实现 | 说明 | |------|------|------| | CLAUDE.md 树 | `context.ts` → `getUserContext()` → `getClaudeMds` / `getMemoryFiles` | 项目约定、编码规范 | | Git 快照 | `getSystemContext()` → `getGitStatus()` | 分支、status、最近 5 条 commit(会话开始时缓存) | | `@file` / IDE | `utils/attachments.ts` | 直接注入文件或选区 | | 嵌套 CLAUDE.md | 读路径时触发 | 进入子目录时追加规则 | ### 5.3 `readFileState`:读后缓存 `FileRead` 会把内容与时间戳写入 `toolUseContext.readFileState`。后续 `FileEdit` **强制要求先读过目标文件**,且文件未被外部修改,否则拒绝编辑并提示重新 Read——这是防止「幻觉改码」的关键硬约束。 --- ## 6. 记忆与上下文体系 ### 6.1 分层结构 ``` ┌─────────────────────────────────────────────────────────┐ │ System Prompt(静态可缓存段 + 动态边界后内容) │ │ + memory 段:MEMORY.md 机制说明 + 入口内容 │ ├─────────────────────────────────────────────────────────┤ │ userContext:CLAUDE.md 树 + currentDate │ │ systemContext:gitStatus(会话开始快照) │ ├─────────────────────────────────────────────────────────┤ │ Conversation messages[](API 历史 + tool_use/result) │ │ + Attachments(相关记忆、提醒、MCP delta…) │ ├─────────────────────────────────────────────────────────┤ │ 磁盘:session transcript / memdir / SessionMemory 摘要 │ └─────────────────────────────────────────────────────────┘ ``` ### 6.2 各层说明 | 层 | 关键实现 | 说明 | |----|---------|------| | 项目指令 | `utils/claudemd.ts`、`getUserContext` | 各级 CLAUDE.md | | Auto memory | `memdir/memdir.ts`:`loadMemoryPrompt`、`ENTRYPOINT_NAME=MEMORY.md` | 教模型读写记忆目录;入口最多约 200 行 / 25KB | | 相关记忆预取 | `startRelevantMemoryPrefetch` → `findRelevantMemories` | 每用户 turn 启动;Sonnet sideQuery 选 ≤5 个相关记忆文件,settled 后注入 attachment | | 会话消息 | `QueryEngine.mutableMessages` / REPL `messages` | 完整对话;发 API 前经 compact 投影 | | 压缩 | microcompact / autocompact / reactiveCompact / snip / contextCollapse | 控制上下文窗口 | | Session Memory | `services/SessionMemory/` | 后台摘要,辅助 compact | | Transcript | `sessionStorage` | 持久化与 `--resume` | | 输入历史 | `history.ts` | 仅 UI ↑ 键历史,**不进模型上下文** | ### 6.3 相关记忆选择(Side Query) `memdir/findRelevantMemories.ts`: 1. `scanMemoryFiles` 扫描记忆文件 header(文件名 + 描述) 2. 用独立 `sideQuery`(较小模型,如 Sonnet)按用户 query 挑选最多 5 个文件 3. 主循环在工具阶段消费预取结果,注入为 attachment(不阻塞首轮 API) 选择器 system prompt 要求「只选确定有用的;不确定则不选」。 ### 6.4 上下文压缩(Compaction) 每轮 API 调用前按层处理: 1. **Tool result budget**(`applyToolResultBudget`):裁剪过大工具输出 2. **Snip**(`HISTORY_SNIP`):剪历史尾部 3. **Microcompact**:轻量清理旧 tool 结果等 4. **Context collapse**:分块折叠投影 5. **Autocompact**:接近阈值时 fork 模型写 summary,用摘要替换长历史 6. **Reactive compact**:API 413 / media size 错误后再压 设计目标:在有限 context window 下保持「无限会话」体验(system prompt 中也写明 *unlimited context through automatic summarization*)。 ### 6.5 User Context 注入形态 `prependUserContext` 把 CLAUDE.md 等包成 meta user 消息: ```xml As you answer... use the following context: # claudeMd ...CLAUDE.md contents... # currentDate Today's date is ... IMPORTANT: this context may or may not be relevant... ``` --- ## 7. 如何请求 AI 接口并得到准确代码 ### 7.1 API 调用链 ``` queryLoop → deps.callModel(默认 queryModelWithStreaming) → queryModel(services/api/claude.ts) → anthropic.beta.messages.create({ stream: true }) (或 Bedrock / Vertex / Foundry 客户端) ``` ### 7.2 请求组装要点 | 字段 | 来源 / 处理 | |------|-------------| | `messages` | `normalizeMessagesForAPI` + `prependUserContext` | | `system` | `buildSystemPromptBlocks`:按 `SYSTEM_PROMPT_DYNAMIC_BOUNDARY` 拆静态/动态,配合 prompt cache | | `tools` | 从 `Tool` 列表转 Anthropic tool schema;可延迟加载(ToolSearch) | | `thinking` | 按 `thinkingConfig`(adaptive / disabled) | | 其它 | `cache_control`、effort、task_budget、fallback model | 流式解析 content blocks → 产出 `AssistantMessage` / `stream_event`;失败可回落非流式请求。 ### 7.3 工具反馈回模型(准确性的核心闭环) ``` assistant: [text?, thinking?, tool_use{id, name, input}] ↓ runTools / StreamingToolExecutor user: [tool_result{tool_use_id, content, is_error?}] ↓ 合并进 messages 下一轮 callModel:模型看到真实文件内容 / 测试输出后再决策 ``` `runTools`(`toolOrchestration.ts`): - 连续 `isConcurrencySafe` 的只读工具 **并行**(默认并发 10) - 写工具 / 非并发安全工具 **串行** - 每个 `tool.call` 前经 `canUseTool`(权限:default / plan / bypass / auto 等) 权限拒绝也会写成 `is_error` 的 `tool_result`,模型可改策略。 ### 7.4 代码写入路径与硬校验 | 工具 | 行为 | 准确性保障 | |------|------|------------| | **FileEdit** | `old_string` → `new_string` 精确替换 | ① 必须先 Read(`readFileState`)② 文件 mtime 未变 ③ `old_string` 必须在文件中唯一匹配(或 `replace_all`)④ 可做 quote / whitespace 归一化匹配 | | **FileWrite** | 整文件写 | 适合新建或大幅重写 | | **NotebookEdit** | 改 notebook cell | 结构化编辑 | | **Bash** | 脚本 / 格式化 / 测试 | 用真实命令结果验证 | FileEdit 拒绝示例(来自校验逻辑): - `File has not been read yet. Read it first before writing to it.` - `File has been modified since read... Read it again...` - `String to replace not found in file.` - `Found N matches... provide more context to uniquely identify` 这保证模型不能凭记忆瞎改;必须以磁盘真实内容为锚点。 ### 7.5 进一步提高「准确逻辑」的机制 1. **先探索后改**:prompt 引导用 Grep/Read,禁止空猜 2. **Plan Mode**:大改前先调研,限制写操作 3. **并行只读、串行写入**:减少竞态 4. **Verification Agent**(可选):非平凡改动后,独立子代理对抗式验证 5. **Hooks**:UserPromptSubmit / PostToolUse / Stop 等可拦截或反馈 6. **自测**:模型用 Bash 跑测试、lint、typecheck,把输出当下一轮上下文 **没有**单独的「生成代码后强制编译通过」硬门槛;正确性主要靠工具反馈闭环 + 可选验证子代理。 --- ## 8. System Prompt 组装优先级 `buildEffectiveSystemPrompt` 大致优先级: 0. `overrideSystemPrompt`(完全替换) 1. Coordinator mode 2. Main-thread agent definition(proactive 时 append,否则 replace) 3. `--system-prompt` custom 4. `getSystemPrompt()` default + 总是可 append `appendSystemPrompt` `getSystemPrompt` 典型段落顺序: ``` Intro → system reminders → doing tasks → actions → using tools → agent/verification → tone → [DYNAMIC BOUNDARY] → session guidance → memory → env → language → output style → MCP → scratchpad → FRC ... ``` 静态段可跨组织缓存;动态段(记忆、环境、语言等)在 boundary 之后,避免污染 prompt cache。 --- ## 9. 子 Agent 与多代理 | 能力 | 实现 | 说明 | |------|------|------| | AgentTool | `tools/AgentTool/` → `runAgent` | 再跑同一套 `query()`,独立 `agentId`、工具子集、system prompt | | Explore Agent | `built-in/exploreAgent` | 专用探索,减少主上下文噪声 | | Verification Agent | `VERIFICATION_AGENT_TYPE` | 对抗式验收 | | Coordinator / Swarm | `coordinator/`、`TeamCreate`、`SendMessage` | 多代理协同(feature 门控) | | Worktree | `EnterWorktreeTool` | 隔离工作树 | 子代理默认 prompt(`DEFAULT_AGENT_PROMPT`): ```text You are an agent for Claude Code... Complete the task fully— don't gold-plate, but don't leave it half-done. When you complete the task, respond with a concise report... ``` --- ## 10. 工具注册一览(写代码相关) `tools.ts` → `getAllBaseTools()` 注册,写代码主路径常用: | 类别 | 工具 | |------|------| | 探索 | Grep、Glob、FileRead、LSP、Agent(Explore) | | 修改 | FileEdit、FileWrite、NotebookEdit | | 执行 | Bash、REPL(ant-only) | | 规划 | EnterPlanMode、ExitPlanMode、TodoWrite、Task* | | 澄清 | AskUserQuestion | | 外部 | WebFetch、WebSearch、MCP 工具 | | 扩展 | Skill、ToolSearch、DiscoverSkills | --- ## 11. ASCII 总架构图 ``` ┌─────────────────── CLI / SDK / Bridge ───────────────────┐ │ entrypoints/cli.tsx → main.tsx → REPL | QueryEngine │ └──────────────────────────┬───────────────────────────────┘ │ user text / ContentBlocks ▼ ┌──────────────── processUserInput + attachments ──────────┐ │ slash cmds | UserMessage | CLAUDE.md / @files / IDE │ │ + relevant memory prefetch (sideQuery) │ └──────────────────────────┬───────────────────────────────┘ │ ▼ ┌──────────────────── queryLoop (while true) ──────────────┐ │ compact → API stream → tools? → tool_results → recurse │ │ │ │ ┌────────────┐ ┌─────────────┐ ┌─────────────────┐ │ │ │ prompts.ts │→→│ claude.ts │→→│ Anthropic API │ │ │ │ context.ts │ │ (streaming) │ │ Messages+Tools │ │ │ └────────────┘ └─────────────┘ └────────┬────────┘ │ │ │ tool_use │ │ ┌───────────────────────────────────────────▼────────┐ │ │ │ Grep Glob Read Edit Write Bash Agent MCP Plan ... │ │ │ │ toolOrchestration + permissions │ │ │ └───────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────┘ │ ▼ 终端 UI / SDK events / 磁盘文件变更 ``` --- ## 12. 对照四个核心问题的结论 ### Q1:如何分析用户需求? 宿主不做 NLU。靠 **System Prompt 行为规范 + Thinking + Plan/AskUserQuestion + 工具探索闭环**,由 Claude 理解任务。可选 sideQuery 做记忆筛选、job/skill classifier(实验性)。 ### Q2:如何分析用户已有代码? 模型驱动 **Grep / Glob / Read / Bash / LSP / Explore Agent** 按需探索;**CLAUDE.md + @文件 + IDE 选区** 提供种子上下文。`readFileState` 保证编辑基于真实文件。 ### Q3:如何做记忆? 多层: 1. **CLAUDE.md**(项目级持久指令) 2. **memdir / MEMORY.md**(可读写长期记忆 + 每 turn 相关记忆预取) 3. **会话 messages**(短期工作记忆) 4. **Compaction / SessionMemory**(长会话摘要压缩) 5. **Transcript 落盘**(resume) ### Q4:如何请求 AI 并得到准确代码? `queryModelWithStreaming` 流式 Messages API;模型在 tool 闭环中读真实代码再 Edit/Write。**准确性来自:先读后写硬校验、精确字符串匹配、工具结果反馈、权限与 Plan、可选 Verification Agent 与自测**——而非一次性「生成完整正确代码」。 --- ## 13. 建议阅读顺序(深入源码) 1. `query.ts` — `queryLoop` 主循环(约 300–1700 行) 2. `constants/prompts.ts` — `getSystemPrompt` / `getUsingYourToolsSection` 3. `context.ts` + `utils/queryContext.ts` — 上下文三件套 4. `services/api/claude.ts` — `queryModelWithStreaming` 5. `services/tools/toolOrchestration.ts` + `toolExecution.ts` 6. `tools/FileEditTool/FileEditTool.ts` — 先读后写校验 7. `memdir/memdir.ts` + `findRelevantMemories.ts` — 记忆 8. `services/compact/autoCompact.ts` — 上下文压缩 9. `QueryEngine.ts` / `screens/REPL.tsx` — 会话边界 --- ## 14. 小结 Claude Code 的写代码 Agent **不是规则引擎,而是编排良好的 Tool-use Agent**: - **理解需求** = Prompt + 模型推理 + 提问/规划工具 - **理解代码** = 按需工具探索 + 项目记忆注入 - **记忆** = CLAUDE.md + memdir + 对话历史 + 压缩摘要 - **准确写码** = API 流式采样 ↔ 工具真实反馈的多轮闭环,外加 FileEdit 硬校验与可选验证 宿主的价值在于:**可靠的工具、权限、压缩、记忆注入与会话编排**;「智能」本身仍在 Claude 模型中。 × yihong (๑>ڡ<)☆谢谢老板~ 2元 5元 10元 50元 100元 任意金额 2元 使用微信扫描二维码完成支付 版权声明:本文为作者原创,如需转载须联系作者本人同意,未经作者本人同意不得擅自转载。 码农心得,Python,Nodejs,Vue,教程类 2026-07-23 评论 21 次浏览