引言
2025年,终端 AI 编程助手赛道迎来了百花齐放的局面。除了 Claude Code、DeepSeek-TUI 等知名工具外,一个名为 OpenClaw 的开源项目正在开发者社区中赢得越来越多的关注。
OpenClaw 是一个开源的 AI 编程助手 CLI 工具,作为 Claude Code 的轻量级开源替代方案而设计。它通过 pip 或 npm 即可安装,支持多种模型提供商(OpenAI、Anthropic、Ollama 本地模型等),并专注于提供终端中的交互式编程体验。与其他同类工具不同,OpenClaw 将 轻量、开源、多后端兼容 作为核心设计理念。
本文将深入剖析 OpenClaw 的架构设计,揭示这款开源编程 Agent 的内部运作机制及其与 Claude Code 的关键差异。
整体架构概览
OpenClaw 采用 模块化四层架构,各层职责清晰、可独立替换。这种设计使得它天然适合多模型提供商支持和社区插件扩展。
┌─────────────────────────────────────────────────────────┐
│ OpenClaw 架构总览 │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────────────────┐ │
│ │ CLI 交互层 (CLI Layer) │ │
│ │ ┌──────────┐ ┌──────────┐ ┌────────────────┐ │ │
│ │ │ 参数解析 │ │ 交互式 │ │ 输出格式化 │ │ │
│ │ │ (Argparse)│ │ REPL │ │ (彩色/JSON) │ │ │
│ │ └──────────┘ └──────────┘ └────────────────┘ │ │
│ └────────────────────┬──────────────────────────────┘ │
│ │ │
│ ┌────────────────────▼──────────────────────────────┐ │
│ │ Agent 核心层 (Agent Core) │ │
│ │ ┌──────────┐ ┌──────────┐ ┌────────────────┐ │ │
│ │ │ 对话管理 │ │ 上下文 │ │ ReAct 推理 │ │ │
│ │ │ (Session) │ │ 管理 │ │ 引擎 │ │ │
│ │ └──────────┘ └──────────┘ └────────────────┘ │ │
│ └────────────────────┬──────────────────────────────┘ │
│ │ │
│ ┌────────────────────▼──────────────────────────────┐ │
│ │ 工具系统层 (Tool Layer) │ │
│ │ ┌──────────┐ ┌──────────┐ ┌────────────────┐ │ │
│ │ │ 文件操作 │ │ Shell │ │ 搜索/Glob │ │ │
│ │ │ 工具 │ │ 执行器 │ │ 工具 │ │ │
│ │ └──────────┘ └──────────┘ └────────────────┘ │ │
│ │ ┌──────────┐ ┌──────────┐ │ │
│ │ │ 编辑/补丁 │ │ Git │ │ │
│ │ │ 工具 │ │ 集成 │ │ │
│ │ └──────────┘ └──────────┘ │ │
│ └────────────────────┬──────────────────────────────┘ │
│ │ │
│ ┌────────────────────▼──────────────────────────────┐ │
│ │ 模型适配层 (LLM Adapter Layer) │ │
│ │ ┌──────────┐ ┌──────────┐ ┌────────────────┐ │ │
│ │ │ OpenAI │ │ Anthropic│ │ Ollama/本地 │ │ │
│ │ │ 适配器 │ │ 适配器 │ │ 适配器 │ │ │
│ │ └──────────┘ └──────────┘ └────────────────┘ │ │
│ │ 统一接口: chat_completion(), stream_chat() │ │
│ └───────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
各层核心职责
| 层级 | 核心组件 | 主要职责 |
|---|---|---|
| CLI 交互层 | Argparse 解析器、REPL 循环、彩色输出 | 处理命令行参数,提供交互式会话,格式化输出 |
| Agent 核心层 | 会话管理器、上下文窗口、ReAct 引擎 | 管理对话生命周期,维护上下文,执行推理-执行循环 |
| 工具系统层 | 文件操作、Shell 执行、编辑/补丁 | 提供与操作系统交互的能力,执行代码修改 |
| 模型适配层 | 多提供商适配器、统一接口 | 屏蔽不同 LLM API 差异,提供统一的调用接口 |
这种分层设计的关键优势在于:每一层都可以独立替换。你可以更换模型提供商而不影响工具系统,也可以扩展工具而无需改动 LLM 适配逻辑。
Tool-use 实现方式
OpenClaw 的工具系统是其核心能力所在。与 Claude Code 使用 Anthropic 自定义的 XML 格式不同,OpenClaw 采用了与 OpenAI 兼容的 Function Calling 规范,这使得它可以无缝对接大量支持此规范的模型和服务。
工具注册机制
OpenClaw 使用 声明式注册 模式来定义工具。每个工具通过一个包含名称、描述和参数 JSON Schema 的字典注册到工具注册表中:
# 伪代码:OpenClaw 工具注册
TOOL_REGISTRY = {
"read_file": {
"description": "读取文件内容,支持行号范围过滤",
"parameters": {
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "文件路径"
},
"offset": {
"type": "integer",
"description": "起始行号(从1开始)"
},
"limit": {
"type": "integer",
"description": "最大读取行数"
}
},
"required": ["path"]
},
"handler": read_file_handler
},
"edit_file": {
"description": "对文件执行精确的查找替换编辑",
"parameters": {
"type": "object",
"properties": {
"path": {"type": "string", "description": "文件路径"},
"old_string": {"type": "string", "description": "要替换的原文"},
"new_string": {"type": "string", "description": "替换后的内容"}
},
"required": ["path", "old_string", "new_string"]
},
"handler": edit_file_handler
},
"execute_command": {
"description": "在 Shell 中执行命令并返回输出",
"parameters": {
"type": "object",
"properties": {
"command": {"type": "string", "description": "要执行的命令"},
"timeout": {"type": "integer", "description": "超时时间(秒)"}
},
"required": ["command"]
},
"handler": execute_command_handler
}
}
工具调用流程
LLM 生成工具调用的完整流程如下:
用户输入 → LLM 推理 → Function Calling JSON → 验证 → 执行 → 结果返回
步骤1: 用户输入自然语言描述 "帮我修改 server.js 中的端口号"
步骤2: 将用户输入 + 系统提示 + 工具定义 发送给 LLM
步骤3: LLM 返回 Function Call:
{
"name": "edit_file",
"arguments": {
"path": "server.js",
"old_string": "port = 3000",
"new_string": "port = 8080"
}
}
步骤4: 解析并验证参数(类型检查、路径安全检查)
步骤5: 执行对应 handler 函数
步骤6: 将执行结果(observation)返回给 LLM 继续推理
步骤7: LLM 确认修改完成,或继续下一步操作
核心工具列表
OpenClaw 预置了以下核心工具:
| 工具名称 | 功能描述 | 关键参数 |
|---|---|---|
read_file | 读取文件内容 | path, offset?, limit? |
write_file | 创建或覆盖文件 | path, content |
edit_file | 精确查找替换编辑 | path, old_string, new_string |
execute_command | 执行 Shell 命令 | command, timeout? |
search_files | 文件内容搜索 | pattern, path?, glob? |
glob_files | 按模式列出文件 | pattern |
create_directory | 创建目录 | path |
delete_file | 删除文件或目录 | path |
git_status | Git 状态查询 | 无参数 |
diff | 查看工作区修改 | path? |
其中 edit_file 工具是 OpenClaw 中最有特色的设计之一。它基于精确的字符串匹配进行查找替换,而不是简单地覆盖整个文件。这种方式避免了大量重新生成的 Token 消耗,也使得模型可以精确控制对已有代码的修改。
LLM 集成设计:多提供商兼容
OpenClaw 最具特色的设计就是其 多提供商模型适配层。它不绑定任何特定的模型或 API,而是通过统一的抽象接口来支持多种后端。
适配器模式
┌────────────────────────┐
│ LLM Adapter 接口 │
│ (抽象基类) │
│ + chat_completion() │
│ + stream_chat() │
│ + count_tokens() │
└───────────┬────────────┘
│
┌───────────────────┼───────────────────┐
│ │ │
┌───────▼───────┐ ┌───────▼───────┐ ┌───────▼───────┐
│ OpenAIAdapter │ │ Anthropic │ │ Ollama │
│ │ │ Adapter │ │ Adapter │
│ - GPT-4o │ │ - Claude 3.5 │ │ - Llama 3 │
│ - GPT-4o-mini │ │ - Claude 3 │ │ - CodeLlama │
│ - 兼容API │ │ │ │ - DeepSeek │
└────────────────┘ └───────────────┘ └───────────────┘
每个适配器需要实现三个核心方法:
# 伪代码:LLM Adapter 接口
class LLMAdapter(ABC):
"""所有 LLM 提供商的统一接口"""
@abstractmethod
async def chat_completion(
self,
messages: list[dict],
tools: list[dict] | None = None,
temperature: float = 0.0
) -> ChatResponse:
"""非流式对话完成,返回完整响应"""
pass
@abstractmethod
async def stream_chat(
self,
messages: list[dict],
tools: list[dict] | None = None
) -> AsyncIterator[StreamChunk]:
"""流式对话完成,逐块返回"""
pass
@abstractmethod
def count_tokens(self, text: str) -> int:
"""估算 Token 数量"""
pass
多提供商配置
用户可以在配置文件中指定要使用的模型提供商:
# OpenClaw 配置文件
llm:
provider: openai # 可选: openai, anthropic, ollama
# OpenAI 配置
openai:
api_key: ${OPENAI_API_KEY}
model: gpt-4o
base_url: https://api.openai.com/v1 # 可自定义,兼容第三方API
# Anthropic 配置
anthropic:
api_key: ${ANTHROPIC_API_KEY}
model: claude-sonnet-4-20250514
# Ollama 本地模型配置
ollama:
base_url: http://localhost:11434
model: llama3.2
这种设计使得用户可以根据自己的需求灵活选择:
- 预算优先:选择便宜的模型(如 GPT-4o-mini、Ollama 本地模型)
- 性能优先:选择最强的模型(如 Claude Sonnet、GPT-4o)
- 隐私优先:使用 Ollama 运行本地模型,数据完全不离开本机
- 国产模型:通过兼容 API 对接 DeepSeek、Qwen 等
Function Calling 格式兼容性
不同模型对 Function Calling 的格式支持存在差异,OpenClaw 的适配层会进行格式转换:
| 提供商 | Function Calling 格式 | OpenClaw 处理方式 |
|---|---|---|
| OpenAI | 原生 JSON Schema | 直接传递 |
| Anthropic | XML 格式 tool_use | 适配器内部转换 JSON → XML |
| Ollama (Llama 3) | 自定义 JSON 格式 | 适配层规范化 |
| 兼容 API | OpenAI 兼容格式 | 直接传递 |
这种适配意味着即使用户使用 Ollama 运行本地模型,也可以获得与 OpenAI 一致的工具调用体验。
文件操作模型
OpenClaw 的文件操作设计体现了 安全性与精确性的平衡。
编辑而非重写
与其他工具动辄覆盖整个文件不同,OpenClaw 推荐使用 edit_file 工具进行精确的查找替换编辑:
# 伪代码:edit_file 的实现
def edit_file_handler(path: str, old_string: str, new_string: str) -> str:
"""精确的查找替换编辑"""
# 1. 读取文件
with open(path, 'r', encoding='utf-8') as f:
content = f.read()
# 2. 找到匹配位置
index = content.find(old_string)
if index == -1:
# 尝试去掉首尾空白后查找
stripped = old_string.strip()
index = content.find(stripped)
if index == -1:
return f"错误:找不到匹配的文本 '{old_string[:40]}...'"
# 3. 执行替换
new_content = content[:index] + new_string + content[index + len(old_string):]
# 4. 写回文件
with open(path, 'w', encoding='utf-8') as f:
f.write(new_content)
# 5. 生成差异报告
diff = generate_diff(content, new_content, path)
return f"编辑成功!\n{diff}"
这种方式的优点:
- 精确性:只修改需要修改的部分,避免误改
- 效率:Token 消耗远小于重新写入整个文件
- 可追溯:自动生成差异报告,用户可以清楚看到改了什么
- 安全:查找失败时会友好报错,不会破坏原文件
文件操作的安全策略
# 伪代码:文件操作安全层
class FileSecurityLayer:
ALLOWED_EXTENSIONS = {'.py', '.js', '.ts', '.jsx', '.tsx', '.json',
'.yaml', '.yml', '.toml', '.md', '.html', '.css'}
BLOCKED_PATTERNS = [
'/etc/passwd', '/etc/shadow', '/etc/sudoers',
'~/.ssh/', '/root/.ssh/'
]
@classmethod
def validate_operation(cls, path: str, operation: str) -> bool:
"""验证文件操作是否允许"""
import os
abs_path = os.path.abspath(os.path.expanduser(path))
# 检查是否在禁止列表中
for blocked in cls.BLOCKED_PATTERNS:
if blocked in abs_path:
return False
# 检查文件类型(写操作时)
if operation in ('write', 'edit'):
ext = os.path.splitext(abs_path)[1].lower()
if ext and ext not in cls.ALLOWED_EXTENSIONS:
# 非代码文件需要用户确认
return False # 需要用户确认
return True
会话管理
会话生命周期
OpenClaw 将会话管理设计为三个阶段:
创建阶段 运行阶段 结束阶段
┌──────────┐ ┌────────────────┐ ┌──────────┐
│ 初始化 │ ───────→ │ 消息循环 │ ───────→ │ 持久化 │
│ · 加载配置 │ │ · 用户输入 │ │ · 保存 │
│ · 初始化 │ │ · Agent 推理 │ │ 对话 │
│ 适配器 │ │ · 工具执行 │ │ · 清理 │
│ · 设置 │ │ · 结果返回 │ │ 资源 │
│ 工作目录 │ │ · 继续/终止 │ └──────────┘
└──────────┘ └────────────────┘
上下文窗口管理
OpenClaw 实现了智能上下文压缩来应对模型上下文窗口限制:
| 策略 | 触发条件 | 处理方式 |
|---|---|---|
| 滑动窗口 | 消息超过 N 轮 | 保留最近的 K 轮对话 |
| 摘要压缩 | Token 使用率 > 75% | 对早期对话生成摘要 |
| 工具结果截断 | 单个工具输出 > 1500 tokens | 截断并添加 ”…” 标记 |
| 关键上下文保留 | 用户标记或自动检测 | 系统提示中的关键指令永远保留 |
# 伪代码:上下文窗口管理
class ContextManager:
def __init__(self, max_tokens: int = 64000):
self.max_tokens = max_tokens
self.messages: list[dict] = []
self.system_prompt: str = ""
self.summary: str | None = None
async def add_message(self, message: dict):
"""添加消息并检查是否需要压缩"""
self.messages.append(message)
# 估算当前 Token 数
current_tokens = self.estimate_tokens()
if current_tokens > self.max_tokens * 0.75:
await self.compress()
async def compress(self):
"""压缩上下文"""
# 策略1: 提取早期对话摘要
if not self.summary and len(self.messages) > 10:
early_messages = self.messages[:-10]
self.summary = await self.generate_summary(early_messages)
self.messages = [
{"role": "system", "content": self.system_prompt},
{"role": "system", "content": f"【历史对话摘要】{self.summary}"},
*self.messages[-10:]
]
# 策略2: 截断过长的工具结果
for msg in self.messages:
if msg.get("role") == "tool" and len(msg["content"]) > 1500:
msg["content"] = msg["content"][:1500] + "\n...(截断)"
与 Claude Code 的架构对比
OpenClaw 作为 Claude Code 的开源替代,两者在架构设计上既有相似之处,也有根本性的差异:
| 维度 | OpenClaw | Claude Code |
|---|---|---|
| 底层模型 | 任意(通过适配器) | Claude 系列独家 |
| 开源 | ✅ 完全开源 (MIT) | ❌ 闭源 |
| 安装方式 | pip / npm 一键安装 | npm install -g @anthropic-ai/claude-code |
| 模型成本 | 自由选择(免费到高价) | 较高(Claude API 定价) |
| 本地模型 | ✅ 支持 (Ollama) | ❌ 不支持 |
| 工具格式 | JSON Function Calling | XML 格式 |
| 文件编辑 | 精确查找替换 (edit_file) | 区块替换 |
| 配置文件 | YAML 文件 | JSON 文件 |
| 会话存储 | JSON / SQLite | SQLite |
| 社区扩展 | ✅ 可自定义工具 | ❌ 受限 |
| 隐私保护 | ✅ 完全本地可控 | 依赖 Anthropic API |
关键架构差异
1. 模型绑定的差异
Claude Code 与其底层模型 Claude 深度绑定,这种设计使得 Anthropic 可以针对自己的模型进行极致优化,例如专用的 XML 工具调用格式和对 Claude 特有能力的利用。
OpenClaw 则完全相反——它通过适配器层与具体模型解耦。这意味着你可以用同一个工具体验不同的模型,但代价是无法针对某个模型做深度优化。
2. 工具调用格式
OpenClaw (JSON Function Calling):
{
"function": {
"name": "edit_file",
"arguments": {"path": "app.js", "old_string": "...", "new_string": "..."}
}
}
Claude Code (XML Tool Use):
<antml:function_calls>
<antml:invoke name="Edit">
<antml:parameter name="command">edit</antml:parameter>
<antml:parameter name="path">app.js</antml:parameter>
<antml:parameter name="old_string">...</antml:parameter>
<antml:parameter name="new_string">...</antml:parameter>
</antml:invoke>
</antml:function_calls>
JSON 格式的优势在于与 OpenAI 生态的广泛兼容性,而 XML 格式在 Anthropic 自家的模型中表现更优。
3. 安全模型的差异
Claude Code 采用分级审批安全模型——危险操作需要用户确认,而文件读取等安全操作可以自动执行。OpenClaw 也采用了类似的策略,但实现更加开放:用户可以自定义安全规则、白名单路径和允许的命令列表。
开源社区驱动的开发模式
OpenClaw 的开发完全由社区驱动,遵循开源软件的最佳实践:
- MIT 许可证:商业友好,可自由使用和修改
- GitHub 主仓库:Issues、PR、Discussions 全部公开
- 插件式工具:社区可以通过 PR 贡献新的工具
- 配置驱动:无需修改源码即可调整行为
- 文档优先:完善的 CLI 帮助文档和 Markdown Wiki
社区贡献的工具
目前社区已经贡献了多种工具扩展:
| 工具 | 贡献者 | 功能 |
|---|---|---|
docker_exec | 社区 | 在 Docker 容器中执行命令 |
kubectl | 社区 | Kubernetes 集群管理 |
github_api | 社区 | 调用 GitHub API |
sql_query | 社区 | 执行 SQL 查询并返回结果 |
轻量级 Agent 的优势与局限
优势
- 零依赖运行:无需 IDE、无需 GUI,一个终端即可
- 极低内存占用:相比 IDE 插件动辄几百 MB 的内存,OpenClaw 的常驻内存不到 50MB
- 即装即用:
pip install openclaw后立即可用 - 离线友好:配合 Ollama 本地模型可实现完全离线运行
- 脚本集成:可以轻松嵌入 Shell 脚本和 CI/CD 流水线
- 隐私可控:本地模型方案确保代码数据不出本机
局限
- 无图形界面:无法直接展示图片、图表等可视化内容
- 上下文限制:受限于底层模型的上下文窗口大小
- 无多模态:目前不支持图片输入(除非底层模型支持)
- 安全边界:CLI 工具对系统有直接访问权限,需要用户自行评估安全风险
- 调试体验:不如 IDE 插件那样与调试器深度集成
- 模型能力依赖:最终生成质量完全取决于所选模型
总结
OpenClaw 的架构设计体现了 简单、开放、可替换 的理念。通过四层模块化架构、适配器模式和多提供商兼容设计,它在 Claude Code 之外为开发者提供了一个强大且灵活的开源选择。
其核心设计哲学可以概括为:
- 不绑定模型:模型只是后端,用户说了算
- 工具驱动:一切与系统的交互都通过工具完成
- 安全为先:每一层都有安全检查机制
- 社区共建:架构设计支持社区扩展和贡献
对于追求开源自控、预算敏感或需要本地运行的开发者来说,OpenClaw 的架构设计提供了极具吸引力的技术方案。在下一篇文章中,我们将详细介绍如何安装、配置和使用 OpenClaw,帮助读者快速上手这款工具。