🏗️ Claw Code 项目完整架构分析
Claude Code Python + Rust - 双版本 AI Agent 系统技术架构深度解析(Python代码详解)
📋 执行摘要
项目定位
Claw Code 是对 Anthropic Claude Code 的 clean-room 重写项目,包含两个版本:
- Python 原型版本:快速验证、完整功能、易于学习的参考实现
- Rust 生产版本:高性能、安全、生产就绪的优化实现
学习价值
- ✅ Python代码易学:清晰的逻辑,完整的AI Agent实现
- ✅ 架构对比学习:原型 vs 生产,理解工程化演进
- ✅ 完整功能实现:命令系统、工具系统、运行时引擎
- ✅ 现代AI Agent模式:工具调用、对话管理、权限控制
学习路线建议
- 先学Python版本:理解业务逻辑和架构设计
- 再看Rust版本:学习性能优化和安全加固
- 对比思考:理解从原型到生产的演进路径
🐍 第一部分:Python版本架构详解(学习重点)
1.1 Python版本整体架构
1.1.1 项目结构(src/目录)
src/
├── main.py # 命令行入口(学习起点)
├── runtime.py # 运行时引擎核心(对话循环)
├── query_engine.py # AI交互引擎(调用Claude API)
├── commands.py # 命令系统管理
├── tools.py # 工具系统管理
├── permissions.py # 权限控制系统
├── models.py # 数据模型定义
├── session_store.py # 会话状态管理
├── setup.py # 工作区初始化
├── context.py # 上下文管理
└── ... 其他支持模块
1.1.2 运行Python版本
# 查看所有命令
python -m src.main --help
# 运行工作区摘要
python -m src.main summary
# 查看移植清单
python -m src.main manifest
# 尝试提示路由
python -m src.main route "帮我读取文件"
1.2 核心模块深度解析(带详细代码解释)
1.2.1 主入口模块 (main.py) - 系统入口
代码结构解析:
def build_parser() -> argparse.ArgumentParser:
"""构建命令行解析器 - 这是CLI的入口"""
parser = argparse.ArgumentParser(
description='Python porting workspace for the Claude Code rewrite effort'
)
subparsers = parser.add_subparsers(dest='command', required=True)
# 添加所有支持的命令
subparsers.add_parser('summary', help='渲染Python移植工作区的Markdown摘要')
subparsers.add_parser('manifest', help='打印当前Python工作区清单')
subparsers.add_parser('parity-audit', help='与TypeScript存档进行代码对比审计')
# ... 更多命令
return parser
命令分发机制:
def main(argv: list[str] | None = None) -> int:
"""主函数 - 命令路由中心"""
parser = build_parser()
args = parser.parse_args(argv)
manifest = build_port_manifest() # 构建移植清单
# 根据命令类型分发处理
if args.command == 'summary':
# 调用查询引擎生成摘要
print(QueryEnginePort(manifest).render_summary())
return 0
if args.command == 'manifest':
# 打印移植清单
print(manifest.to_markdown())
return 0
if args.command == 'parity-audit':
# 运行代码对比审计
print(run_parity_audit().to_markdown())
return 0
# ... 其他命令处理
return 0
学习要点:
- argparse模块:Python标准库的命令行解析
- 子命令模式:清晰的命令组织结构
- 工厂模式:每个命令对应一个处理函数
1.2.2 运行时引擎 (runtime.py) - AI Agent大脑
核心数据结构:
@dataclass
class RuntimeSession:
"""运行时会话 - 存储对话状态"""
prompt: str # 用户输入的提示
context: PortContext # 运行时上下文(工作区信息)
setup: WorkspaceSetup # 工作区设置(Python版本、平台等)
setup_report: SetupReport # 启动报告
system_init_message: str # 系统初始化消息
history: HistoryLog # 历史日志
routed_matches: list[RoutedMatch] # 路由匹配结果(命令/工具)
turn_result: TurnResult # 对话轮次结果
# ... 其他字段
提示路由算法(核心AI逻辑):
class PortRuntime:
"""运行时引擎 - 负责提示路由和对话管理"""
def route_prompt(self, prompt: str, limit: int = 5) -> list[RoutedMatch]:
"""
提示路由算法 - 将用户提示映射到命令/工具
算法步骤:
1. 分词处理
2. 按类型收集匹配(命令 vs 工具)
3. 优先级排序
4. 返回最佳匹配
"""
# 1. 分词处理(简单实现)
tokens = {
token.lower()
for token in prompt.replace('/', ' ').replace('-', ' ').split()
if token
}
# 2. 按类型收集匹配
by_kind = {
'command': self._collect_matches(tokens, PORTED_COMMANDS, 'command'),
'tool': self._collect_matches(tokens, PORTED_TOOLS, 'tool'),
}
# 3. 优先级排序:先取每种类型的最佳匹配
selected: list[RoutedMatch] = []
for kind in ('command', 'tool'):
if by_kind[kind]:
selected.append(by_kind[kind].pop(0))
# 4. 合并剩余结果
leftovers = sorted(
[match for matches in by_kind.values() for match in matches],
key=lambda item: (-item.score, item.kind, item.name),
)
selected.extend(leftovers[: max(0, limit - len(selected))])
return selected[:limit]
@staticmethod
def _score(tokens: set[str], module: PortingModule) -> int:
"""
评分算法 - 基于词频的简单匹配
参数:
- tokens: 用户提示分词后的集合
- module: 要评分的模块(命令或工具)
返回:匹配分数(匹配的token数量)
"""
# 在多个字段中搜索token
haystacks = [
module.name.lower(),
module.source_hint.lower(),
module.responsibility.lower()
]
score = 0
for token in tokens:
if any(token in haystack for haystack in haystacks):
score += 1
return score
学习要点:
- dataclass装饰器:简化数据类定义
- 类型提示:Python 3.11+的类型系统
- 算法设计:简单的基于词频的匹配算法
- 设计模式:策略模式(可替换的评分算法)
1.2.3 查询引擎 (query_engine.py) - AI交互核心
对话轮次管理:
class QueryEnginePort:
"""查询引擎 - 负责与Claude API交互"""
def submit_message(
self,
prompt: str,
matched_commands: tuple[str, ...] = (),
matched_tools: tuple[str, ...] = (),
denied_tools: tuple[PermissionDenial, ...] = (),
) -> TurnResult:
"""
提交消息给AI并获取响应
处理流程:
1. 构建系统提示(包含上下文)
2. 准备对话历史
3. 调用AI API
4. 解析响应
5. 更新会话状态
"""
# 1. 构建系统提示
system_prompt = self._build_system_prompt(
matched_commands,
matched_tools,
denied_tools
)
# 2. 准备对话历史
messages = self._prepare_messages(prompt)
# 3. 调用AI API(这里是模拟,实际需要API密钥)
response = self._call_ai_api(system_prompt, messages)
# 4. 解析响应
parsed = self._parse_ai_response(response)
# 5. 更新会话状态
self._update_session(prompt, parsed)
return TurnResult(
output=parsed.text,
matched_commands=matched_commands,
matched_tools=matched_tools,
permission_denials=denied_tools,
stop_reason=parsed.stop_reason,
)
def _build_system_prompt(self, commands, tools, denials) -> str:
"""构建系统提示 - 告诉AI可用的命令和工具"""
lines = ["你是一个AI助手,可以执行以下操作:"]
if commands:
lines.append("\n可用命令:")
lines.extend(f"- {cmd}" for cmd in commands)
if tools:
lines.append("\n可用工具:")
lines.extend(f"- {tool}" for tool in tools)
if denials:
lines.append("\n权限限制:")
lines.extend(f"- {denial.tool_name}: {denial.reason}" for denial in denials)
return "\n".join(lines)
流式处理版本:
def stream_submit_message(self, prompt: str, **kwargs) -> Iterator[dict[str, object]]:
"""
流式提交消息 - 支持实时响应
使用生成器逐步返回响应,适合长对话
"""
for chunk in self._stream_ai_api(prompt, **kwargs):
# 解析每个数据块
parsed_chunk = self._parse_stream_chunk(chunk)
yield parsed_chunk
学习要点:
- API设计:清晰的接口设计
- 提示工程:如何构建有效的系统提示
- 流式处理:使用生成器实现流式响应
- 错误处理:完整的错误处理机制
1.2.4 命令系统 (commands.py) - 功能扩展
命令注册机制:
# 移植的命令定义 - 从TypeScript版本移植过来的命令
PORTED_COMMANDS: tuple[PortingModule, ...] = (
PortingModule(
name="summary",
source_hint="mirrored from TypeScript snapshot",
responsibility="render a Markdown summary of the Python porting workspace",
),
PortingModule(
name="manifest",
source_hint="mirrored from TypeScript snapshot",
responsibility="print the current Python workspace manifest",
),
PortingModule(
name="parity-audit",
source_hint="mirrored from TypeScript snapshot",
responsibility="compare the Python workspace against the local ignored TypeScript archive",
),
# ... 更多命令
)
def get_commands(
include_plugin_commands: bool = True,
include_skill_commands: bool = True,
) -> tuple[PortingModule, ...]:
"""
获取所有可用的命令
参数:
- include_plugin_commands: 是否包含插件命令
- include_skill_commands: 是否包含技能命令
返回:所有可用命令的元组
"""
commands = list(PORTED_COMMANDS) # 基础命令
# 动态加载插件命令
if include_plugin_commands:
commands.extend(_load_plugin_commands())
# 动态加载技能命令
if include_skill_commands:
commands.extend(_load_skill_commands())
return tuple(commands) # 返回不可变元组
命令执行:
def execute_command(name: str, prompt: str) -> str:
"""
执行指定命令
参数:
- name: 命令名称
- prompt: 用户提示
返回:命令执行结果
"""
# 查找命令
command = None
for cmd in get_commands():
if cmd.name == name:
command = cmd
break
if not command:
return f"错误:未找到命令 '{name}'"
# 根据命令类型执行
if name == "summary":
return render_workspace_summary()
elif name == "manifest":
return render_manifest()
# ... 其他命令处理
return f"命令 '{name}' 执行完成"
学习要点:
- 注册表模式:集中管理所有命令
- 插件系统:支持动态扩展
- 不可变数据结构:使用tuple确保数据安全
- 查找算法:线性搜索简单有效
1.2.5 工具系统 (tools.py) - 能力扩展
工具注册机制:
# 移植的工具定义 - 核心工具集
PORTED_TOOLS: tuple[PortingModule, ...] = (
PortingModule(
name="read_file",
source_hint="mirrored from TypeScript snapshot",
responsibility="从工作区读取文本文件",
),
PortingModule(
name="write_file",
source_hint="mirrored from TypeScript snapshot",
responsibility="在工作区写入文本文件",
),
PortingModule(
name="edit_file",
source_hint="mirrored from TypeScript snapshot",
responsibility="编辑工作区中的文件",
),
PortingModule(
name="bash",
source_hint="mirrored from TypeScript snapshot",
responsibility="执行Shell命令",
),
PortingModule(
name="WebSearch",
source_hint="mirrored from TypeScript snapshot",
responsibility="搜索网络获取最新信息",
),
# ... 更多工具
)
def get_tools(
simple_mode: bool = False,
include_mcp: bool = True,
permission_context: ToolPermissionContext | None = None,
) -> tuple[PortingModule, ...]:
"""
获取所有可用的工具
参数:
- simple_mode: 简单模式(排除复杂工具)
- include_mcp: 是否包含MCP工具
- permission_context: 权限上下文(用于过滤)
返回:过滤后的工具列表
"""
tools = list(PORTED_TOOLS)
# 加载MCP工具(Model Context Protocol)
if include_mcp and not simple_mode:
tools.extend(_load_mcp_tools())
# 应用权限过滤
if permission_context:
tools = [t for t in tools if permission_context.allows(t.name)]
return tuple(tools)
工具执行示例:
def execute_tool(name: str, payload: str) -> str:
"""
执行指定工具
参数:
- name: 工具名称
- payload: JSON格式的输入参数
返回:工具执行结果(JSON字符串)
"""
import json
try:
# 解析输入参数
params = json.loads(payload)
if name == "read_file":
# 读取文件工具
path = params.get("path")
if not path:
return json.dumps({"error": "缺少path参数"})
try:
with open(path, 'r', encoding='utf-8') as f:
content = f.read()
return json.dumps({"content": content})
except Exception as e:
return json.dumps({"error": str(e)})
elif name == "bash":
# 执行Shell命令
import subprocess
command = params.get("command")
if not command:
return json.dumps({"error": "缺少command参数"})
try:
result = subprocess.run(
command,
shell=True,
capture_output=True,
text=True,
timeout=params.get("timeout", 30)
)
return json.dumps({
"stdout": result.stdout,
"stderr": result.stderr,
"returncode": result.returncode
})
except subprocess.TimeoutExpired:
return json.dumps({"error": "命令执行超时"})
except Exception as e:
return json.dumps({"error": str(e)})
# ... 其他工具处理
else:
return json.dumps({"error": f"未知工具: {name}"})
except json.JSONDecodeError:
return json.dumps({"error": "无效的JSON输入"})
学习要点:
- JSON Schema:工具输入输出使用JSON格式
- 错误处理:完整的错误处理机制
- 子进程管理:安全执行Shell命令
- 权限控制:基于上下文的工具过滤
1.2.6 权限系统 (permissions.py) - 安全控制
权限上下文:
@dataclass(frozen=True)
class ToolPermissionContext:
"""
工具权限上下文 - 控制哪些工具可用
使用不可变数据类确保线程安全
"""
denied_tools: tuple[str, ...] # 明确拒绝的工具列表
denied_prefixes: tuple[str, ...] # 拒绝的工具前缀
@classmethod
def from_iterables(cls, denied_tools: list[str], denied_prefixes: list[str]) -> ToolPermissionContext:
"""从列表创建权限上下文"""
return cls(
denied_tools=tuple(denied_tools),
denied_prefixes=tuple(denied_prefixes),
)
def allows(self, tool_name: str) -> bool:
"""
检查是否允许使用指定工具
检查逻辑:
1. 检查完全匹配(denied_tools)
2. 检查前缀匹配(denied_prefixes)
"""
# 1. 检查完全匹配
if tool_name in self.denied_tools:
return False
# 2. 检查前缀匹配
for prefix in self.denied_prefixes:
if tool_name.startswith(prefix):
return False
return True
def with_additional_denials(self, tools: list[str], prefixes: list[str]) -> ToolPermissionContext:
"""创建新的权限上下文,添加额外的拒绝规则"""
new_tools = list(self.denied_tools) + tools
new_prefixes = list(self.denied_prefixes) + prefixes
return self.from_iterables(new_tools, new_prefixes)
权限拒绝记录:
@dataclass(frozen=True)
class PermissionDenial:
"""权限拒绝记录 - 记录为什么拒绝工具使用"""
tool_name: str # 被拒绝的工具名称
reason: str # 拒绝原因
def __str__(self) -> str:
return f"{self.tool_name}: {self.reason}"
学习要点:
- 不可变设计:使用frozen dataclass确保线程安全
- 前缀匹配:灵活的权限控制策略
- 建造者模式:with_additional_denials方法
- 审计日志:记录权限拒绝原因
1.3 Python版本设计模式总结
1.3.1 使用的设计模式
| 设计模式 | 在Python版本中的应用 | 代码示例 |
|---|---|---|
| 注册表模式 | 命令/工具注册表 | PORTED_COMMANDS, PORTED_TOOLS |
| 工厂模式 | 运行时对象创建 | PortRuntime() |
| 策略模式 | 提示路由算法 | route_prompt()的不同实现 |
| 建造者模式 | 权限上下文构建 | with_additional_denials() |
| 观察者模式 | 事件监听机制 | 历史日志记录 |
1.3.2 Python特性应用
| Python特性 | 在项目中的应用 | 学习价值 |
|---|---|---|
| 类型提示 | 所有函数和类 | 提高代码可读性和可维护性 |
| dataclass | 数据模型定义 | 简化数据类定义 |
| 生成器 | 流式处理 | 实现实时响应 |
| 装饰器 | 权限检查等 | 横切关注点分离 |
| 上下文管理器 | 资源管理 | 自动清理资源 |
🦀 第二部分:Rust版本架构对比学习
2.1 从Python到Rust的演进
2.1.1 相同功能的Rust实现对比
示例:权限系统的演进
# Python版本:简单的权限过滤
class ToolPermissionContext:
def allows(self, tool_name: str) -> bool:
if tool_name in self.denied_tools:
return False
for prefix in self.denied_prefixes:
if tool_name.startswith(prefix):
return False
return True
// Rust版本:多层权限模型
pub enum PermissionMode {
ReadOnly, // 只读模式
WorkspaceWrite, // 工作区写入
DangerFullAccess, // 完全访问
Prompt, // 需要用户提示
Allow, // 允许所有
}
impl PermissionPolicy {
pub fn authorize(&self, tool_name: &str, input: &str) -> PermissionOutcome {
// 更复杂的权限检查逻辑
let required = self.required_mode_for(tool_name);
let current = self.active_mode();
if current >= required {
PermissionOutcome::Allow
} else {
PermissionOutcome::Deny {
reason: format!("需要{}权限", required),
}
}
}
}
2.1.2 Python没有的Rust特性
智能上下文压缩:
pub fn compact_session(session: &Session, config: CompactionConfig) -> CompactionResult {
// 计算Token数量,自动压缩长对话
// Python版本没有此功能
}
高性能流式处理:
pub async fn stream_messages(&self, request: MessageRequest) -> Result<impl Stream<Item=Result<StreamEvent, ApiError>>> {
// 异步流式处理,高性能
// Python版本只有基础流式支持
}
2.2 学习建议:如何从Python过渡到Rust
2.2.1 先理解Python逻辑
# 先彻底理解Python版本的业务逻辑
# 比如:提示路由算法、工具执行流程、权限检查
def route_prompt(prompt: str) -> list[RoutedMatch]:
# 理解算法逻辑
tokens = tokenize(prompt)
matches = find_matches(tokens)
return rank_matches(matches)
2.2.2 再看Rust实现
// 然后看Rust如何实现相同逻辑
pub fn route_prompt(&self, prompt: &str) -> Vec<RoutedMatch> {
// 注意:所有权、引用、错误处理等Rust特有概念
let tokens = self.tokenize(prompt);
let matches = self.find_matches(&tokens);
self.rank_matches(matches)
}
2.2.3 对比学习重点
| 学习重点 | Python版本 | Rust版本 | 对比收获 |
|---|---|---|---|
| 错误处理 | 异常机制 | Result类型 | 理解显式错误处理的价值 |
| 并发处理 | 异步IO + GIL | 无GC真正并发 | 理解Rust的并发优势 |
| 内存管理 | GC自动管理 | 所有权系统 | 理解内存安全的重要性 |
| 类型系统 | 动态类型 | 静态类型 | 理解类型安全的好处 |
🎯 第三部分:Python版本学习实践项目
3.1 实践项目建议
项目1:添加一个新工具
# 1. 在PORTED_TOOLS中添加新工具
PORTED_TOOLS = (
# ... 现有工具
PortingModule(
name="calculate",
source_hint="new tool for learning",
responsibility="执行数学计算",
),
)
# 2. 在execute_tool函数中添加处理逻辑
def execute_tool(name: str, payload: str) -> str:
if name == "calculate":
# 解析数学表达式并计算
import ast
expression = params.get("expression")
try:
result = eval(expression, {"__builtins__": {}}, {})
return json.dumps({"result": result})
except Exception as e:
return json.dumps({"error": str(e)})
项目2:增强提示路由算法
def enhanced_route_prompt(self, prompt: str) -> list[RoutedMatch]:
"""
增强版提示路由算法
改进点:
1. 使用更复杂的分词(考虑中文)
2. 添加语义相似度匹配
3. 考虑上下文历史
"""
# 改进的分词
tokens = self.advanced_tokenize(prompt)
# 语义相似度匹配
matches = self.semantic_match(tokens)
# 上下文感知排序
ranked = self.context_aware_rank(matches)
return ranked
项目3:添加插件系统
class PluginSystem:
"""简单的插件系统"""
def __init__(self):
self.plugins = {}
def register_plugin(self, name: str, plugin: Callable):
"""注册插件"""
self.plugins[name] = plugin
def execute_plugin(self, name: str, *args, **kwargs):
"""执行插件"""
if name in self.plugins:
return self.plugins[name](*args, **kwargs)
else:
raise ValueError(f"插件未找到: {name}")
3.2 调试和学习技巧
使用Python调试器
# 在代码中插入断点
import pdb
def debug_function():
pdb.set_trace() # 在这里暂停,进入调试模式
# 调试代码
代码跟踪技巧
# 使用trace模块跟踪代码执行
python -m trace --trace -m src.main route "test"
# 使用cProfile分析性能
python -m cProfile -s time -m src.main route "test"
可视化调用图
# 生成简单的调用图
import graphviz
def generate_call_graph():
"""生成函数调用关系图"""
dot = graphviz.Digraph()
dot.node('main', 'main.py')
dot.node('runtime', 'runtime.py')
dot.node('commands', 'commands.py')
dot.edge('main', 'runtime')
dot.edge('main', 'commands')
dot.render('call_graph')
📚 第四部分:学习资源和下一步
4.1 推荐学习资源
Python相关
- Python官方文档:docs.python.org/3/
- argparse模块:命令行解析
- dataclasses模块:数据类定义
- typing模块:类型提示
AI Agent相关
- Claude API文档:docs.anthropic.com/claude/refe…
- 工具调用模式:Function Calling
- 提示工程:如何构建有效的系统提示
软件设计
- 设计模式:Python实现版
- Clean Code:编写可维护的代码
- 架构模式:分层架构、插件架构等
4.2 下一步学习建议
短期(1-2周)
- 运行所有Python命令:理解每个命令的功能
- 阅读核心模块源码:main.py, runtime.py, query_engine.py
- 修改一个小功能:比如添加新命令或工具
- 写学习笔记:记录关键算法和设计
中期(2-4周)
- 对比Python和Rust实现:选择2-3个核心功能对比
- 理解Rust特有功能:权限系统、上下文压缩等
- 运行Rust版本:构建和测试
- 分析性能差异:理解为什么需要Rust
长期(1-2月)
- 贡献代码:修复bug或添加新功能
- 深入架构设计:理解整个系统的设计决策
- 应用到自己的项目:借鉴架构模式
- 分享学习成果:写博客或做分享
4.3 常见问题解答
Q: 为什么Python版本没有实际调用Claude API?
A: Python版本主要是移植验证和原型,实际API调用需要API密钥。你可以修改query_engine.py添加真实的API调用。
Q: 如何添加真实的AI功能?
# 修改query_engine.py添加真实API调用
import requests
def real_ai_call(prompt: str, api_key: str) -> str:
headers = {
"x-api-key": api_key,
"Content-Type": "application/json",
"anthropic-version": "2023-06-01"
}
data = {
"model": "claude-3-opus-20240229",
"max_tokens": 1000,
"messages": [{"role": "user", "content": prompt}]
}
response = requests.post(
"https://api.anthropic.com/v1/messages",
headers=headers,
json=data
)
return response.json()["content"][0]["text"]
Q: 这个项目适合初学者吗?
A: 适合有一定Python基础的学习者。如果你是Python初学者,建议先学习Python基础,然后再来学习这个项目。
🎉 总结
Claw Code项目的Python版本是一个绝佳的学习资源,因为它:
- 完整的AI Agent实现:涵盖了命令系统、工具系统、运行时引擎等核心组件
- 清晰的代码结构:模块化设计,易于理解和学习
- 现代Python特性:类型提示、dataclass、异步编程等
- 架构设计范例:展示了如何设计可扩展的AI Agent系统
学习路径建议:
- 从Python版本开始:理解业务逻辑和架构
- 动手实践:运行代码、修改代码、添加功能
- 对比学习:理解从原型到生产的演进
- 深入思考:为什么这样设计?如何改进?
记住:这个项目的价值不仅在于代码本身,更在于它展示了一个完整的软件工程实践——从原型验证到生产优化的完整流程。
开始你的学习之旅吧!从运行第一个命令开始:
cd /Users/hudachang/claudeCode/claw-code
python -m src.main --help
祝学习愉快!