Claude Code 源码深度解析:Agent 架构的工程实现
Claude Code 源码深度解析:Agent 架构的工程实现
Claude Code 不仅仅是一个「AI 写代码工具」,它代表了当前 AI Agent 工程化的最佳实践之一。本文从源码层面拆解其核心设计思想,揭示一个真正可用的 Agent 系统是如何被构建出来的。
一、Claude Code 的定位与能力边界
1.1 官方定义
Claude Code 是一个终端原生的 AI 编程助手,能够:
-
读取和编辑文件:理解项目结构,精确修改代码 -
执行终端命令:运行测试、安装依赖、Git 操作 -
理解项目上下文:跨文件推理,理解代码依赖关系 -
自主完成多步骤任务:从需求到实现的全流程自动化
1.2 能力边界
Claude Code 能做什么:
-
代码重构与优化 -
Bug 修复与调试 -
项目脚手架生成 -
文档编写与更新 -
测试用例生成
Claude Code 不能做什么:
-
直接访问外部网络(除非通过工具) -
执行需要交互式输入的命令 -
绕过用户确认执行危险操作 -
超出 token 预算的超长上下文推理
1.3 与传统 IDE 插件的区别
| 维度 | 传统 IDE 插件 | Claude Code |
|---|---|---|
| 交互方式 | 问答式 | 任务式 |
| 执行能力 | 仅提供建议 | 可直接执行 |
| 上下文范围 | 当前文件 | 整个项目 |
| 错误恢复 | 无 | 自动重试与修正 |
二、Agent 核心架构:三层设计
2.1 整体架构
Claude Code 采用经典的三层 Agent 架构:
┌─────────────────────────────────────────────────────────┐
│ Claude Code │
├─────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 感知层 │ │ 决策层 │ │ 执行层 │ │
│ │ (Perceive) │→ │ (Decide) │→ │ (Execute) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ↑ ↓ │
│ └────────────────────────────────────┘ │
│ 反馈循环 (Feedback) │
└─────────────────────────────────────────────────────────┘
2.2 感知层(Perception Layer)
职责:收集环境信息,构建 Agent 的「世界观」
核心组件:
| 组件 | 功能 | 实现细节 |
|---|---|---|
| File Reader | 读取文件内容 | 支持分块读取、编码检测 |
| Directory Scanner | 扫描目录结构 | 递归遍历、排除规则 |
| Command Output Parser | 解析命令输出 | 提取关键信息、错误识别 |
| Context Aggregator | 聚合上下文 | 优先级排序、token 预算控制 |
感知策略:
-
渐进式感知:先读取目录结构,再按需加载文件 -
关键词触发:检测到特定关键词时主动扩展感知范围 -
差异感知:只感知变化的部分,避免重复计算
2.3 决策层(Decision Layer)
职责:基于感知信息,规划下一步行动
核心组件:
| 组件 | 功能 | 关键技术 |
|---|---|---|
| LLM Core | 核心推理 | Claude 3.5 / 4 系列 |
| Planner | 任务分解 | 将复杂任务拆解为子任务 |
| Tool Selector | 工具选择 | 基于上下文选择最合适的工具 |
| Priority Queue | 任务队列 | 管理待执行任务 |
决策流程:
用户请求 → 意图理解 → 任务分解 → 工具选择 → 参数生成
2.4 执行层(Execution Layer)
职责:调用工具,执行具体操作
核心组件:
| 组件 | 功能 | 安全措施 |
|---|---|---|
| File Editor | 文件编辑 | 原子操作、备份机制 |
| Shell Runner | 命令执行 | 沙箱隔离、超时控制 |
| Git Operator | 版本控制 | 操作审计、回滚能力 |
| Result Validator | 结果验证 | 检查执行结果是否符合预期 |
执行保障:
-
原子性:每个操作要么成功,要么回滚 -
幂等性:同一操作多次执行结果一致 -
可观测性:所有操作都有日志记录
2.5 反馈循环(Feedback Loop)
职责:将执行结果反馈给感知层,形成闭环
反馈类型:
| 类型 | 说明 | 处理策略 |
|---|---|---|
| 成功反馈 | 操作成功完成 | 更新上下文,继续下一步 |
| 错误反馈 | 操作失败 | 分析原因,尝试恢复 |
| 警告反馈 | 部分成功 | 记录警告,评估是否需要干预 |
| 用户反馈 | 用户主动输入 | 调整策略,响应用户意图 |
三、工具系统:Agent 的能力边界
3.1 工具接口设计
Claude Code 采用 Tool-Use Pattern,所有能力都封装为统一接口的工具:
interface Tool {
name: string; // 工具名称(唯一标识)
description: string; // LLM 可理解的描述
parameters: JSONSchema; // 参数的 JSON Schema 定义
execute(params: any): Promise<ToolResult>;
}
interface ToolResult {
success: boolean;
output: string;
error?: string;
metadata?: Record<string, any>;
}
3.2 核心工具清单
文件操作类
| 工具 | 用途 | 关键参数 |
|---|---|---|
read_file |
读取文件内容 | path, offset, limit |
write_file |
创建或覆盖文件 | path, content |
edit_file |
精确编辑文件 | path, oldText, newText |
create_directory |
创建目录 | path |
delete_file |
删除文件 | path |
命令执行类
| 工具 | 用途 | 关键参数 |
|---|---|---|
execute_command |
执行 shell 命令 | command, timeout, cwd |
run_script |
执行脚本文件 | script_path, args |
搜索类
| 工具 | 用途 | 关键参数 |
|---|---|---|
search_files |
搜索文件内容 | pattern, path, file_pattern |
list_directory |
列出目录内容 | path |
find_files |
查找文件 | pattern, path |
Git 操作类
| 工具 | 用途 | 关键参数 |
|---|---|---|
git_status |
查看状态 | path |
git_diff |
查看差异 | path, cached |
git_commit |
提交更改 | message, paths |
3.3 工具描述的重要性
每个工具都有 description 字段,这个描述会被 LLM 理解,决定何时、如何调用工具。
好的描述示例:
edit_file: 精确编辑文件,只修改指定的文本片段。
适用于:修改函数名、修复 bug、更新配置项。
参数:
- path: 文件路径
- oldText: 要替换的原文(必须精确匹配)
- newText: 替换后的新文本
注意:oldText 必须与文件中完全一致,包括空白字符。
差的描述示例:
edit_file: 编辑文件
3.4 工具选择的决策逻辑
Claude Code 如何决定使用哪个工具?
-
语义匹配:LLM 理解用户意图,匹配工具描述 -
上下文约束:当前上下文限制了可用工具(如未在 Git 仓库中则禁用 Git 工具) -
历史偏好:基于历史成功案例调整选择概率 -
参数验证:尝试生成参数,验证是否合法
四、上下文管理:Token 预算下的智慧
4.1 问题背景
LLM 有固定的 token 预算(如 200k),而项目代码可能远超这个限制。如何在有限预算内保留最有价值的信息?
4.2 多级上下文策略
Claude Code 采用多级上下文结构:
Context Layers:
├── System Prompt (固定,约 5k tokens)
├── Project Context (项目级缓存,约 20k tokens)
│ ├── 目录结构树
│ ├── 关键文件摘要
│ ├── 技术栈识别结果
│ └── 依赖关系图
├── Conversation History (对话历史,约 50k tokens)
│ ├── 用户请求序列
│ ├── Agent 行动记录
│ └── 工具调用与结果
└── Working Memory (当前任务,约 125k tokens)
├── 当前编辑的文件内容
├── 最近命令的输出
├── 错误信息栈
└── 相关代码片段
4.3 上下文压缩技术
文件摘要
对大型文件生成结构化摘要:
{
"path": "src/core/engine.ts",
"size": 5000,
"exports": ["Engine", "Config", "createEngine"],
"imports": ["./utils", "./types"],
"key_functions": [
{"name": "process", "signature": "(data: Data) => Result"},
{"name": "validate", "signature": "(config: Config) => boolean"}
],
"summary": "核心引擎模块,处理数据流转换和验证"
}
滑动窗口
对话历史使用滑动窗口,保留最近 N 轮对话,更早的对话被压缩为摘要。
差量更新
只传递变化的上下文:
-
文件修改:只传递 diff -
命令输出:只传递新增内容 -
状态变化:只传递变化字段
4.4 上下文优先级
当 token 预算不足时,按以下优先级截断:
-
最高优先级:用户当前请求 -
高优先级:当前编辑的文件、最近的错误信息 -
中优先级:对话历史中的关键决策 -
低优先级:项目级缓存的详细信息 -
最低优先级:历史对话的非关键部分
4.5 实现细节
class ContextManager {
private tokenBudget: number = 200000;
private layers: ContextLayer[] = [];
buildContext(task: Task): PromptContext {
let tokens = 0;
const context: PromptContext = {};
// 1. 系统提示词(固定)
context.system = this.getSystemPrompt();
tokens += this.countTokens(context.system);
// 2. 项目上下文(缓存)
const projectCtx = this.getProjectContext();
if (tokens + projectCtx.tokens < this.tokenBudget * 0.3) {
context.project = projectCtx;
tokens += projectCtx.tokens;
}
// 3. 对话历史(滑动窗口)
const history = this.getRecentHistory(this.tokenBudget * 0.25);
context.history = history;
tokens += this.countTokens(history);
// 4. 工作记忆(剩余预算)
const workingMemory = this.buildWorkingMemory(
this.tokenBudget - tokens
);
context.working = workingMemory;
return context;
}
}
五、决策循环:Agent Loop 的实现
5.1 核心循环结构
def agent_loop(task: Task, context: Context) -> Result:
iterations = 0
max_iterations = 50
while iterations < max_iterations:
iterations += 1
# 1. 感知:收集当前状态
current_state = perceive(context)
# 2. 决策:LLM 选择行动
decision = llm.decide(
system_prompt=AGENT_SYSTEM_PROMPT,
context=current_state,
available_tools=TOOLS,
task=task
)
# 3. 执行:调用工具
if decision.type == "tool_call":
result = execute_tool(decision.tool, decision.params)
# 4. 反馈:更新上下文
context.update(result)
# 5. 检查是否需要用户确认
if requires_confirmation(decision):
user_response = ask_user(decision)
if not user_response.approved:
context.add(user_response.feedback)
continue
# 6. 检查终止条件
if decision.type == "task_complete":
return Result(success=True, output=decision.output)
if decision.type == "need_help":
return Result(success=False, need_user_input=True)
return Result(success=False, reason="max_iterations_reached")
5.2 终止条件
Agent 循环在以下情况下终止:
| 条件 | 说明 | 处理 |
|---|---|---|
| task_complete | LLM 认为任务完成 | 返回成功结果 |
| need_help | LLM 需要用户帮助 | 暂停,等待用户输入 |
| max_iterations | 达到最大迭代次数 | 返回超时错误 |
| error | 遇到不可恢复的错误 | 返回错误信息 |
| user_cancel | 用户主动取消 | 终止执行 |
5.3 迭代次数的控制
为什么设置 max_iterations?
-
成本控制:每次迭代都消耗 API 调用 -
防止死循环:Agent 可能陷入无限尝试 -
用户体验:长时间无响应会让用户焦虑
典型值:
-
简单任务:5-10 次 -
中等任务:20-30 次 -
复杂任务:50-100 次
5.4 防止退化
Agent 可能陷入以下退化模式:
| 退化模式 | 表现 | 解决方案 |
|---|---|---|
| 重复尝试 | 反复执行相同操作 | 检测重复,强制跳过 |
| 绕圈子 | 在多个工具间循环 | 记录路径,阻止重复序列 |
| 过度思考 | 分析多过行动 | 设置思考/行动比例限制 |
| 放弃过早 | 轻易声明无法完成 | 要求提供具体阻碍原因 |
六、错误恢复:智能体的核心能力
6.1 错误分类
| 错误类型 | 示例 | 恢复策略 |
|---|---|---|
| 参数错误 | 文件路径不存在 | 修正参数,重试 |
| 权限错误 | 没有写权限 | 提示用户,请求权限 |
| 依赖错误 | 缺少包 | 安装依赖,重试 |
| 语法错误 | 代码有 bug | 分析错误,修复代码 |
| 网络错误 | 下载失败 | 重试,换源 |
| 逻辑错误 | 结果不符合预期 | 回滚,换策略 |
6.2 恢复流程
错误发生 → 解析错误信息 → 分类错误类型
↓
选择恢复策略
↓
┌────┴────┐
↓ ↓
可恢复 不可恢复
↓ ↓
执行恢复 请求用户帮助
↓
验证恢复结果
6.3 错误信息解析
Claude Code 如何理解错误?
def parse_error(error: Exception) -> ErrorInfo:
"""解析错误信息,提取关键要素"""
error_str = str(error)
error_type = type(error).__name__
# 常见错误模式匹配
patterns = {
"file_not_found": r"ENOENT.*'([^']+)'",
"permission_denied": r"EACCES|Permission denied",
"syntax_error": r"SyntaxError.*line (\d+)",
"import_error": r"ModuleNotFoundError.*'([^']+)'",
"command_not_found": r"command not found: (\w+)",
}
for error_kind, pattern in patterns.items():
match = re.search(pattern, error_str)
if match:
return ErrorInfo(
kind=error_kind,
details=match.groups(),
raw=error_str
)
return ErrorInfo(kind="unknown", raw=error_str)
6.4 恢复策略执行
def execute_recovery(error_info: ErrorInfo, context: Context) -> RecoveryResult:
"""执行恢复策略"""
strategies = {
"file_not_found": lambda e: create_file_or_fix_path(e),
"permission_denied": lambda e: request_permission(e),
"syntax_error": lambda e: fix_syntax(e, context),
"import_error": lambda e: install_package(e.details[0]),
"command_not_found": lambda e: install_command(e.details[0]),
}
strategy = strategies.get(error_info.kind, ask_user_for_help)
return strategy(error_info)
6.5 恢复次数限制
每次操作最多尝试恢复 N 次,超过则放弃并请求用户帮助。
class RecoveryLimiter:
def __init__(self, max_attempts: int = 3):
self.attempts = defaultdict(int)
self.max_attempts = max_attempts
def can_retry(self, operation_id: str) -> bool:
return self.attempts[operation_id] < self.max_attempts
def record_attempt(self, operation_id: str):
self.attempts[operation_id] += 1
七、人机协作:半自动化的边界
7.1 为什么不是全自动?
-
安全考虑: rm -rf等危险操作需要确认 -
意图对齐:LLM 可能误解用户意图 -
责任归属:用户需要对关键决策负责 -
信任建立:逐步建立用户信任
7.2 需要确认的操作
| 操作类型 | 触发条件 | 确认方式 |
|---|---|---|
| 删除文件 | rm、delete 命令 |
显式确认 |
| 大规模修改 | 修改超过 N 个文件 | 摘要确认 |
| Git 强制操作 | force push、reset --hard |
显式确认 |
| 安装软件 | npm install、pip install |
首次确认 |
| 网络请求 | 访问外部 API | 首次确认 |
7.3 确认交互设计
Agent: 检测到删除操作,确认继续?
将删除以下文件:
- /src/old_module.ts
- /src/deprecated.ts
User: 确认 / 取消 / 查看详情
7.4 学习用户偏好
Claude Code 会学习用户的确认偏好:
class UserPreferenceLearner:
def __init__(self):
self.preferences = {
"auto_approve_npm_install": False,
"auto_approve_git_commit": False,
"auto_approve_file_delete": False,
}
def learn_from_response(self, operation: str, approved: bool):
"""从用户响应中学习"""
# 连续 3 次批准同一类操作,自动批准
key = f"auto_approve_{operation}"
if approved:
self.approval_counts[key] = self.approval_counts.get(key, 0) + 1
if self.approval_counts[key] >= 3:
self.preferences[key] = True
def should_auto_approve(self, operation: str) -> bool:
return self.preferences.get(f"auto_approve_{operation}", False)
7.5 进度可见性
Agent 执行过程中,实时显示:
[1/5] 读取项目结构...
[2/5] 分析依赖关系...
[3/5] 执行重构...
- 重命名 UserService → AccountService
- 更新 12 处引用
[4/5] 运行测试...
✓ 23 passed, 0 failed
[5/5] 生成总结...
八、安全机制:沙箱与审计
8.1 命令执行沙箱
class CommandSandbox:
BLACKLIST = [
"rm -rf /",
"dd if=",
":(){ :|:& };:", # Fork bomb
"chmod -R 777",
"> /dev/sda",
]
def validate(self, command: str) -> ValidationResult:
# 1. 黑名单检查
for pattern in self.BLACKLIST:
if pattern in command:
return ValidationResult(
allowed=False,
reason=f"黑名单命令: {pattern}"
)
# 2. 权限检查
if self.requires_elevation(command):
return ValidationResult(
allowed=False,
reason="需要提升权限",
need_confirmation=True
)
# 3. 网络检查
if self.accesses_network(command) and not self.network_allowed:
return ValidationResult(
allowed=False,
reason="网络访问未授权",
need_confirmation=True
)
return ValidationResult(allowed=True)
8.2 文件访问控制
class FileAccessControl:
def __init__(self, allowed_paths: List[str]):
self.allowed_paths = [Path(p).resolve() for p in allowed_paths]
def can_access(self, path: str, mode: str) -> bool:
resolved = Path(path).resolve()
for allowed in self.allowed_paths:
if str(resolved).startswith(str(allowed)):
return True
return False
8.3 操作审计日志
class AuditLogger:
def log_operation(self, op: Operation):
entry = {
"timestamp": datetime.now().isoformat(),
"operation": op.type,
"params": op.params,
"result": op.result,
"duration_ms": op.duration_ms,
}
self.entries.append(entry)
def export_log(self) -> str:
return json.dumps(self.entries, indent=2)
九、性能优化:让 Agent 更快
9.1 缓存策略
| 缓存类型 | 内容 | 失效条件 |
|---|---|---|
| 项目结构 | 目录树、文件列表 | 文件变化 |
| 依赖关系 | import 关系图 | 代码变化 |
| LLM 响应 | 相同 prompt 的结果 | 新对话 |
| 工具结果 | 只读操作的结果 | 输入变化 |
9.2 并行执行
独立操作并行执行:
async def execute_parallel(operations: List[Operation]):
tasks = [execute_op(op) for op in operations]
results = await asyncio.gather(*tasks, return_exceptions=True)
return results
9.3 流式响应
LLM 响应流式返回,用户可以提前看到部分结果:
Agent: 正在分析代码...
发现 3 处可以优化的地方:
1. UserService 的缓存逻辑...
2. DatabaseManager 的连接池...
3. Logger 的异步写入...
十、测试与调试
10.1 工具测试
每个工具都有单元测试:
def test_edit_file():
# 准备测试文件
test_file = create_test_file("hello world")
# 执行编辑
result = edit_file(
path=test_file,
oldText="hello",
newText="goodbye"
)
# 验证结果
assert result.success
assert read_file(test_file) == "goodbye world"
10.2 Agent 集成测试
def test_agent_refactor():
"""测试重构任务"""
project = create_test_project("""
// src/user.ts
export class UserService {
getUser(id: string) { ... }
}
""")
result = agent.execute(
task="将 UserService 重命名为 AccountService"
)
assert result.success
assert project.has_file("src/account.ts")
assert project.file_content("src/account.ts").contains("AccountService")
10.3 调试模式
启用调试模式后,输出详细信息:
DEBUG [perception] 扫描目录: src/
DEBUG [perception] 发现文件: 23 个
DEBUG [decision] LLM 输出: {"tool": "read_file", "params": {"path": "src/main.ts"}}
DEBUG [execution] 执行 read_file
DEBUG [execution] 结果: 成功, 1234 tokens
DEBUG [feedback] 上下文更新: +1234 tokens, 当前 15678/200000
十一、总结:Agent 工程化的核心启示
11.1 设计原则
Claude Code 的成功揭示了 AI Agent 工程化的核心原则:
1. 工具优先
先定义能力边界(工具),再设计交互(Prompt)。Agent 能做什么,完全由工具集定义。
2. 反馈为王
错误信息是最好的训练数据。Agent 的智能体现在错误恢复能力,而非单次决策正确率。
3. 上下文是瓶颈
所有优化都围绕 token 预算展开。压缩、缓存、优先级,本质都是在做信息取舍。
4. 人是决策者
危险操作需要确认,模糊意图需要澄清。Agent 是副驾驶,不是驾驶员。
5. 安全内置
沙箱、审计、权限控制,这些不是事后补充,而是架构的一部分。
11.2 技术栈总览
| 层级 | 技术选型 |
|---|---|
| LLM | Claude 3.5 / 4 系列 |
| 编程语言 | TypeScript / Python |
| 工具框架 | 自研 Tool-Use 协议 |
| 沙箱 | Docker / namespaces |
| 存储 | SQLite / 文件系统 |
| 日志 | 结构化 JSON |
11.3 未来方向
-
多模态支持:理解图片、图表、UI 截图 -
主动学习:从用户反馈中持续改进 -
协作模式:多 Agent 协作完成复杂任务 -
领域特化:针对特定领域(前端、后端、数据)优化
11.4 最终思考
AI Agent 的终极形态,不是「替代人类」,而是「放大人类的意图」。
工具越来越强,但决策权始终在人手中。这才是 Agent 工程化的正确方向。
本文基于公开信息和技术推断撰写,具体实现以官方源码为准。
夜雨聆风