我可以自己开发一个自己的“Claude Code“吗?——从零拆解终端 AI 编程助手的架构与实现
当你看到 Claude Code 在终端里行云流水地读代码、改文件、跑命令,是不是也想拥有一个属于自己的版本?本文从架构拆解到核心代码实现,带你一步步构建自己的终端 AI 编程助手。

一、为什么想自己造一个?
2025 年以来,"终端 AI 编程助手"这个品类迎来爆发。Anthropic 的 Claude Code、OpenAI 的 Codex CLI、Google 的 Gemini CLI 相继登场,开源社区的 OpenCode、Aider、Goose 等项目也各自收获了数万 Star。这类工具有一个共同特征:运行在终端里,通过 Agent 循环自主调用工具,完成从读代码到写代码再到执行命令的完整工作流。
对于开发者来说,使用现成工具当然方便,但自己造一个的动机同样充分:
- 深度理解 Agent 架构。纸上得来终觉浅,只有自己实现一遍 ReAct 循环、工具调度、上下文管理,才能真正理解 AI Agent 的工程本质。
- 定制能力。你可以接入私有模型、自定义工具链、适配公司内部的代码规范和发布流程。
- 数据安全。所有代码和交互都在本地处理,不经过第三方服务器,这对企业场景至关重要。
- 成本可控。使用自有 API Key 甚至本地部署开源模型,避免订阅费用。
好消息是:这件事的门槛比你想象的低。Claude Code 的核心并不是什么黑科技,而是一套精心设计的工程实践。下面我们就来拆解它。
二、Claude Code 的架构到底长什么样?
通过对 Claude Code 开源代码的深入分析(参考 Dive-into-Claude-Code 项目的逆向工程),可以将其架构归纳为七层分离设计:
┌─────────────────────────────────────────────┐
│ 1. UI 层(React + Ink 终端渲染) │
├─────────────────────────────────────────────┤
│ 2. Hook 层(27 个生命周期钩子) │
├─────────────────────────────────────────────┤
│ 3. 核心引擎(Agent Loop + 状态机) │
├─────────────────────────────────────────────┤
│ 4. 工具层(54 个标准化工具) │
├─────────────────────────────────────────────┤
│ 5. 服务层(LLM API / MCP 协议) │
├─────────────────────────────────────────────┤
│ 6. 基础设施(日志 / 缓存 / 存储) │
├─────────────────────────────────────────────┤
│ 7. 运行时(Node.js / Bun) │
└─────────────────────────────────────────────┘
其中最关键的三个部分是:
Agent Loop(智能体循环):本质是一个 while 循环。每轮循环中,系统收集上下文、调用 LLM、解析返回的工具调用指令、执行工具、将结果追加到上下文,然后进入下一轮,直到 LLM 返回纯文本(不再调用工具)为止。用一句话概括就是:
Agent = While Loop + Tools
工具系统(Tool System):所有能力都被抽象为"工具"——读文件是工具、写文件是工具、执行 Shell 命令是工具、甚至搜索代码也是工具。每个工具有统一的接口定义,包含名称、描述、输入 Schema 和执行函数。Claude Code 最多支持 54 个工具,通过 Builder 模式声明式定义。
权限系统(Permission System):采用"拒绝优先"策略,设计了六层纵深防御。以执行 Shell 命令为例,一条命令需要经过语法树解析、语义检测、沙箱隔离、规则匹配、LLM 意图分类、最终人工确认这六道关卡。这确保了 AI 不会在未经授权的情况下执行危险操作。
三、自己实现一个需要哪些核心模块?
理解了 Claude Code 的架构之后,我们自己动手实现时需要关注以下五个核心模块:
3.1 Agent Loop:一切的发动机
Agent Loop 是整个系统的心脏。它的伪代码异常简单:
def agent_loop(user_message: str, context: ConversationContext):
context.add_user_message(user_message)
while True:
# 1. 构建完整的消息列表(含系统提示词、历史、工具定义)
messages = context.build_messages()
# 2. 调用 LLM,流式获取响应
response = llm.chat(messages=messages, tools=tool_registry.get_schemas())
# 3. 如果 LLM 返回纯文本,退出循环
if response.type == "text":
print(response.content)
break
# 4. 如果 LLM 请求调用工具,逐个执行
for tool_call in response.tool_calls:
result = tool_registry.execute(tool_call.name, tool_call.arguments)
context.add_tool_result(tool_call.id, result)
# 循环继续,将工具结果送回 LLM
这个循环看似简单,但有几个关键设计决策需要注意:
- 异步生成器模式:实际实现中应使用异步生成器(
async generator),实现流式输出,让用户不必等待整个响应完成就能看到中间结果。 - 最大循环次数:必须设置上限(如 50 轮),防止 LLM 陷入无限工具调用死循环。
- 错误恢复:工具执行失败时,应将错误信息作为工具结果返回给 LLM,让它自行决定如何修复,而非直接中断循环。
3.2 工具系统:能力的基石
工具系统的设计原则是"一切皆工具,接口统一"。以下是一个最小化的工具注册与执行框架:
import json
import subprocess
from typing import Any, Callable
from dataclasses import dataclass, field
@dataclass
class Tool:
"""工具定义"""
name: str
description: str
parameters: dict # JSON Schema 格式
handler: Callable[..., Any]
class ToolRegistry:
"""工具注册中心"""
def __init__(self):
self._tools: dict[str, Tool] = {}
def register(self, tool: Tool):
self._tools[tool.name] = tool
def get_schemas(self) -> list[dict]:
"""生成 OpenAI / Anthropic 兼容的工具 Schema"""
return [
{
"type": "function",
"function": {
"name": t.name,
"description": t.description,
"parameters": t.parameters,
},
}
for t in self._tools.values()
]
def execute(self, name: str, arguments: dict) -> str:
"""执行工具并返回结果字符串"""
tool = self._tools.get(name)
if not tool:
return f"Error: unknown tool '{name}'"
try:
result = tool.handler(**arguments)
return str(result) if not isinstance(result, str) else result
except Exception as e:
return f"Error executing {name}: {e}"
有了注册中心之后,定义具体工具就变得非常直观。下面是四个最核心的内置工具实现(注意:我们在 run_command 中加入了基础安全防护机制):
import os
import re
# 基础黑名单:防止 LLM 幻觉产生破坏性操作(实际工程中需更严格的语法树解析与沙箱隔离)
DANGEROUS_PATTERNS = [
r"rm\s+-rf\s+/", # 递归删除根目录
r"mkfs\.", # 格式化磁盘
r"dd\s+if=.*of=/dev/", # 覆盖块设备
r":\(\)\{\s*:\|:&\s*\};:", # Fork 炸弹
r">\s*/dev/sda", # 清空磁盘设备
r"shutdown", # 关机
r"reboot" # 重启
]
def read_file(path: str, offset: int = 0, limit: int = 500) -> str:
"""读取文件内容,支持分页"""
abs_path = os.path.abspath(path)
if not os.path.isfile(abs_path):
return f"File not found: {abs_path}"
with open(abs_path, "r", encoding="utf-8", errors="replace") as f:
lines = f.readlines()
total = len(lines)
selected = lines[offset : offset + limit]
numbered = [f"{i+1:6d} {line}" for i, line in enumerate(selected, start=offset)]
header = f"File: {abs_path} ({total} lines total, showing {offset+1}-{offset+len(selected)})\n"
return header + "".join(numbered)
def write_file(path: str, content: str) -> str:
"""写入文件(整体覆盖)"""
abs_path = os.path.abspath(path)
os.makedirs(os.path.dirname(abs_path), exist_ok=True)
with open(abs_path, "w", encoding="utf-8") as f:
f.write(content)
return f"Successfully wrote {len(content)} chars to {abs_path}"
def edit_file(path: str, old_text: str, new_text: str) -> str:
"""精确替换文件中的文本片段"""
abs_path = os.path.abspath(path)
with open(abs_path, "r", encoding="utf-8") as f:
content = f.read()
if old_text not in content:
return f"Error: old_text not found in {abs_path}"
new_content = content.replace(old_text, new_text, 1)
with open(abs_path, "w", encoding="utf-8") as f:
f.write(new_content)
return f"Successfully edited {abs_path}"
def run_command(command: str, timeout: int = 30) -> str:
"""执行 Shell 命令并返回输出"""
# 安全防线:拦截高危命令模式
for pattern in DANGEROUS_PATTERNS:
if re.search(pattern, command):
return f"Error: Blocked dangerous command pattern '{pattern}'. Operation aborted for safety."
try:
result = subprocess.run(
command, shell=True, capture_output=True, text=True, timeout=timeout,
)
output = ""
if result.stdout:
output += f"STDOUT:\n{result.stdout[-5000:]}" # 截断过长输出
if result.stderr:
output += f"\nSTDERR:\n{result.stderr[-2000:]}"
output += f"\nExit code: {result.returncode}"
return output
except subprocess.TimeoutExpired:
return f"Command timed out after {timeout}s"
将这四个工具注册到 ToolRegistry 中,你就拥有了一个能读、能写、能改、能(相对安全地)执行命令的最小编程助手。
3.3 上下文管理:有限窗口的无限智慧
上下文管理是 Agent 系统中最容易被低估、却又最影响体验的部分。LLM 的上下文窗口是有限的(即便是 200K token 的模型,面对大型代码库也远远不够),因此必须设计分级的上下文压缩策略。
Claude Code 采用的是三级压缩策略:
- Level 1:逐轮微压缩。每轮自动执行,用占位符替换冗长的工具输出(如大文件的中间部分),保留首尾关键信息。
- Level 2:阈值触发摘要。当 token 使用量达到窗口的 80% 时,自动调用 LLM 对早期对话生成摘要,保留核心决策和文件引用。
- Level 3:手动干预兜底。用户主动输入
/compact命令,触发强制压缩。
下面是一个简化版的上下文管理器实现(已补全add_assistant_message方法,并优化了 LLM 摘要逻辑):
import tiktoken
class ConversationContext:
"""对话上下文管理器"""
def __init__(self, system_prompt: str, max_tokens: int = 128_000):
self.system_prompt = system_prompt
self.max_tokens = max_tokens
self.messages: list[dict] = []
self._encoder = tiktoken.encoding_for_model("gpt-4o")
def add_user_message(self, content: str):
self.messages.append({"role": "user", "content": content})
def add_assistant_message(self, content: str, tool_calls: list | None = None):
"""记录助手的回复及工具调用意图"""
msg = {"role": "assistant", "content": content}
if tool_calls:
msg["tool_calls"] = tool_calls
self.messages.append(msg)
def add_tool_result(self, tool_call_id: str, result: str):
# Level 1 微压缩:截断超长工具输出
max_result_tokens = 4000
if len(self._encoder.encode(result)) > max_result_tokens:
result = self._truncate_middle(result, max_result_tokens)
self.messages.append({
"role": "tool",
"tool_call_id": tool_call_id,
"content": result,
})
def build_messages(self, llm_provider=None) -> list[dict]:
# Level 2 检查:token 使用率超 80% 时触发摘要压缩
current_tokens = self._count_tokens()
if current_tokens > self.max_tokens * 0.8:
self._compact_early_messages(llm_provider)
return [
{"role": "system", "content": self.system_prompt},
*self.messages,
]
def _count_tokens(self) -> int:
all_text = self.system_prompt + "".join(
m.get("content", "") for m in self.messages
)
return len(self._encoder.encode(all_text))
def _truncate_middle(self, text: str, max_tokens: int) -> str:
"""保留首尾,压缩中间部分"""
lines = text.split("\n")
if len(lines) <= 20:
return text
keep_head = lines[:10]
keep_tail = lines[-10:]
omitted = len(lines) - 20
return "\n".join(keep_head) + f"\n... [{omitted} lines omitted] ...\n" + "\n".join(keep_tail)
def _compact_early_messages(self, llm_provider=None):
"""压缩早期消息为摘要"""
if len(self.messages) < 10:
return
# 保留最近 5 条消息,将前面的工具交互提取出来
early = self.messages[:-5]
recent = self.messages[-5:]
summary_parts = []
for msg in early:
if msg["role"] == "user":
summary_parts.append(f"User asked: {msg['content'][:200]}")
elif msg["role"] == "assistant":
summary_parts.append(f"Assistant replied: {msg.get('content', '')[:200]}")
elif msg["role"] == "tool":
summary_parts.append(f"Tool result: {msg['content'][:100]}")
# 如果传入了 llm_provider,则调用 LLM 生成更高质量的自然语言摘要
# 实际工程中必须这么做以保留语义逻辑,为保持示例独立性,此处做了兼容处理
if llm_provider:
prompt = "请将以下历史对话精简提炼为一段摘要,保留关键决策和文件路径:\n" + "\n".join(summary_parts)
summary = llm_provider.chat([{"role": "user", "content": prompt}]).content
else:
# 退化方案:简单拼接截断
summary = "\n".join(summary_parts)
self.messages = [
{"role": "system", "content": f"[Earlier conversation summary]\n{summary}"},
*recent,
]
3.4 系统提示词:Agent 的灵魂
系统提示词决定了 AI 助手的行为方式。它不是简单的"你是一个编程助手",而是一份详尽的行为规范。Claude Code 的系统提示词据分析超过 1 万 token,涵盖了角色定义、工具使用规范、安全约束、输出格式等多个维度。
以下是一个经过实战验证的系统提示词框架:
SYSTEM_PROMPT = """你是一个专业的终端 AI 编程助手,运行在用户的工作目录中。
## 核心能力
你可以读取文件、写入文件、编辑文件、执行 Shell 命令,帮助用户完成编程任务。
## 工作流程
1. 收到任务后,先通过 read_file 和 run_command 了解项目结构和代码现状
2. 制定修改方案,必要时分步骤执行
3. 使用 edit_file 进行精确修改(优先于 write_file 的整体覆盖)
4. 修改完成后,运行测试或 lint 命令验证结果
## 工具使用规范
- 每次只调用 1-2 个工具,避免一次性发起大量并行调用
- 优先使用 edit_file 而非 write_file,减少对文件的破坏性修改
- 执行命令前先确认当前工作目录
- 如果命令执行失败,分析错误原因后再重试
## 安全约束
- 不得执行 rm -rf、format、del 等破坏性命令
- 不得修改 .env、credentials 等敏感文件
- 不得向外部网络发送请求(除非用户明确要求)
- 遇到不确定的操作,先询问用户
## 输出格式
- 直接给出可执行的操作,减少冗余解释
- 代码修改时说明改了什么、为什么改
- 出错时先给出诊断,再给出修复方案
"""
3.5 多模型适配层:不绑死一家 API
一个实用的终端编程助手应该支持多种 LLM 后端。无论是 OpenAI、Anthropic、Google,还是国内的大模型 API,甚至是本地部署的 Ollama,都应该能通过统一接口切换。
from abc import ABC, abstractmethod
from dataclasses import dataclass
@dataclass
class LLMResponse:
"""统一的 LLM 响应格式"""
content: str
tool_calls: list | None = None
finish_reason: str = "stop" # "stop" | "tool_calls"
class LLMProvider(ABC):
"""LLM 提供者抽象基类"""
@abstractmethod
def chat(self, messages: list[dict], tools: list[dict] | None = None, stream: bool = False) -> LLMResponse:
...
class OpenAIProvider(LLMProvider):
"""OpenAI API 适配器"""
def __init__(self, api_key: str, model: str = "gpt-4o"):
from openai import OpenAI
self.client = OpenAI(api_key=api_key)
self.model = model
def chat(self, messages, tools=None, stream=False) -> LLMResponse:
kwargs = {"model": self.model, "messages": messages}
if tools:
kwargs["tools"] = tools
kwargs["tool_choice"] = "auto"
response = self.client.chat.completions.create(**kwargs)
choice = response.choices[0]
if choice.message.tool_calls:
return LLMResponse(
content=choice.message.content or "",
tool_calls=[
{
"id": tc.id,
"name": tc.function.name,
"arguments": tc.function.arguments,
}
for tc in choice.message.tool_calls
],
finish_reason="tool_calls",
)
return LLMResponse(content=choice.message.content or "")
class AnthropicProvider(LLMProvider):
"""Anthropic Claude API 适配器"""
def __init__(self, api_key: str, model: str = "claude-sonnet-4-20250514"):
from anthropic import Anthropic
self.client = Anthropic(api_key=api_key)
self.model = model
def chat(self, messages, tools=None, stream=False) -> LLMResponse:
# Anthropic API 的消息格式与 OpenAI 不同,需要适配
system_msg = next((m["content"] for m in messages if m["role"] == "system"), "")
user_msgs = [m for m in messages if m["role"] != "system"]
kwargs = {
"model": self.model,
"max_tokens": 8192,
"system": system_msg,
"messages": user_msgs,
}
if tools:
# 转换 tool schema 为 Anthropic 格式
kwargs["tools"] = [
{
"name": t["function"]["name"],
"description": t["function"]["description"],
"input_schema": t["function"]["parameters"],
}
for t in tools
]
response = self.client.messages.create(**kwargs)
tool_uses = [b for b in response.content if b.type == "tool_use"]
text_blocks = [b for b in response.content if b.type == "text"]
if tool_uses:
return LLMResponse(
content=" ".join(b.text for b in text_blocks),
tool_calls=[
{"id": t.id, "name": t.name, "arguments": t.input}
for t in tool_uses
],
finish_reason="tool_calls",
)
return LLMResponse(content=" ".join(b.text for b in text_blocks))
通过这种策略模式,用户可以在配置文件中一行切换模型后端,而上层的 Agent Loop 和工具系统完全不受影响。
四、把它们组装起来:一个完整的最小实现
将上面的所有模块整合到一起,就得到一个可运行的最小终端编程助手:
import json
import os
import sys
from rich.console import Console
from rich.markdown import Markdown
console = Console()
def create_agent(work_dir: str = "."):
"""创建并配置一个编程助手实例"""
registry = ToolRegistry()
# 注册四个核心工具,附带 JSON Schema 描述
registry.register(Tool(
name="read_file",
description="读取指定路径的文件内容,支持分页",
parameters={
"type": "object",
"properties": {
"path": {"type": "string", "description": "文件路径"},
"offset": {"type": "integer", "description": "起始行号", "default": 0},
"limit": {"type": "integer", "description": "读取行数", "default": 500},
},
"required": ["path"],
},
handler=read_file,
))
registry.register(Tool(
name="write_file",
description="将内容写入指定文件(覆盖写入)",
parameters={
"type": "object",
"properties": {
"path": {"type": "string", "description": "文件路径"},
"content": {"type": "string", "description": "文件内容"},
},
"required": ["path", "content"],
},
handler=write_file,
))
registry.register(Tool(
name="edit_file",
description="精确替换文件中的文本片段",
parameters={
"type": "object",
"properties": {
"path": {"type": "string", "description": "文件路径"},
"old_text": {"type": "string", "description": "要被替换的原文"},
"new_text": {"type": "string", "description": "替换后的新文本"},
},
"required": ["path", "old_text", "new_text"],
},
handler=edit_file,
))
registry.register(Tool(
name="run_command",
description="执行 Shell 命令并返回输出",
parameters={
"type": "object",
"properties": {
"command": {"type": "string", "description": "Shell 命令"},
"timeout": {"type": "integer", "description": "超时秒数", "default": 30},
},
"required": ["command"],
},
handler=run_command,
))
# 根据环境变量选择 LLM 后端
provider = OpenAIProvider(api_key=os.environ.get("OPENAI_API_KEY", ""))
context = ConversationContext(system_prompt=SYSTEM_PROMPT)
return provider, context, registry
def main():
"""主交互循环"""
provider, context, registry = create_agent()
max_turns = 50 # 防止无限循环
console.print("[bold green]MyCodeAgent[/] ready. Type your task (Ctrl+C to exit):")
while True:
try:
user_input = console.input("\n[bold cyan]> [/]").strip()
if not user_input:
continue
except (KeyboardInterrupt, EOFError):
console.print("\n[dim]Goodbye![/]")
break
context.add_user_message(user_input)
turn = 0
while turn < max_turns:
turn += 1
# 构建消息时传入 provider 用于上下文压缩的 LLM 摘要
messages = context.build_messages(llm_provider=provider)
response = provider.chat(messages, tools=registry.get_schemas())
# 显示 AI 的文本输出
if response.content:
console.print(Markdown(response.content))
# 如果没有工具调用,本轮结束
if not response.tool_calls:
break
# 执行所有工具调用
context.add_assistant_message(
response.content, tool_calls=response.tool_calls
)
for tc in response.tool_calls:
name = tc["name"]
args = tc["arguments"]
if isinstance(args, str):
args = json.loads(args)
console.print(f" [dim]⚙ {name}({json.dumps(args, ensure_ascii=False)})[/]")
result = registry.execute(name, args)
context.add_tool_result(tc["id"], result)
# 显示工具输出的前 500 字符
preview = result[:500] + "..." if len(result) > 500 else result
console.print(f" [dim]{preview}[/]")
if __name__ == "__main__":
main()
运行效果大致如下:
MyCodeAgent ready. Type your task (Ctrl+C to exit):
> 帮我看看当前目录下有哪些 Python 文件,然后给每个文件加一个 UTF-8 编码声明
⚙ run_command({"command": "find . -name '*.py' -type f"})
STDOUT:
./main.py
./utils.py
Exit code: 0
⚙ read_file({"path": "./main.py"})
...
⚙ edit_file({"path": "./main.py", "old_text": "...", "new_text": "# -*- coding: utf-8 -*-\n..."})
Successfully edited ./main.py
⚙ edit_file({"path": "./utils.py", ...})
Successfully edited ./utils.py
已完成,为 main.py 和 utils.py 添加了 UTF-8 编码声明。
五、与开源方案的横向对比
自己从零实现固然能学到很多,但生产环境下建议结合成熟开源项目。下表对比了当前主流开源终端编程助手(数据截至 2025 年初):
| 项目 | 语言 | Star (近似) | 核心特色 | 适用场景 |
|---|---|---|---|---|
| Aider | Python | 25K+ | Git 深度集成,自动 commit,AST 级别代码理解 | 注重版本管理的团队 |
| OpenHands | Python | 40K+ | 浏览器操作 + 文件编辑 + CI 集成 | 端到端自动化开发 |
| Goose | Rust | 10K+ | 通用 Agent,支持 70+ MCP 扩展 | 不限于编程的通用自动化 |
| OpenCode | TypeScript | 5K+ | 双 Agent 模式(Plan + Build),LSP 集成 | 大型项目开发 |
| Cline | TypeScript | 20K+ | VS Code 深度集成,可中断的工具审批流 | IDE 内重度依赖开发者 |
| 如果你希望快速获得一个可用的工具,直接使用 Aider 或 OpenHands 是最高效的选择。如果你希望深度定制或学习原理,自己实现一遍 Agent Loop 非常有价值。两者并不矛盾——你完全可以在理解原理的基础上,fork 一个开源项目做二次开发。 |
六、进阶优化方向
完成最小实现之后,以下方向可以进一步提升系统的实用性:
6.1 Diff 编辑替代整文件替换
write_file 会覆盖整个文件,对大型项目风险较高。更安全的做法是采用 diff-based 编辑——让 LLM 输出类似 git diff 的补丁格式,逐块应用修改。Aider 在这方面做得非常好,它使用 “search/replace block” 格式,兼顾了准确性和效率。
6.2 子 Agent 与并行执行
当任务复杂时,主 Agent 可以将子任务委派给独立的子 Agent 执行。子 Agent 拥有独立的上下文窗口,避免主上下文被无关信息污染。Claude Code 的 SubAgent 机制正是这样设计的——子 Agent 在隔离环境中运行,完成后将精简结果返回给主 Agent。
6.3 MCP 协议支持
Model Context Protocol(MCP) 是 Anthropic 提出的工具扩展标准。支持 MCP 后,你的 Agent 可以动态加载外部工具服务器,获得数据库查询、API 调用、浏览器操作等无限扩展能力,而无需修改核心代码。
6.4 持久化与记忆
当前实现每次启动都是"无记忆"状态。可以通过以下方式增加记忆能力:将项目结构摘要保存到本地文件,启动时自动加载;对话历史持久化到 SQLite,支持搜索和恢复;使用 CLAUDE.md 或 MEMORY.md 风格的 Markdown 文件作为项目级记忆。
6.5 安全沙箱
虽然我们在 run_command 中加入了正则黑名单,但对于执行 Shell 命令这类高风险操作,这仍显不足。更稳妥的方案是在 Docker 容器或系统级沙箱(如 Firejail 或 macOS Seatbelt)中运行。OpenAI 的 Codex CLI 默认在隔离沙箱中执行命令,这是一个值得借鉴的安全实践。
七、总结
回到标题的问题:我可以自己开发一个自己的"Claude Code"吗?
答案是肯定的,而且核心工作量远比你想象的小。一个能用的最小实现大约 500 行 Python 代码,核心就是三件事:
- Agent Loop:一个 while 循环,不断在"调用 LLM → 解析工具调用 → 执行工具 → 返回结果"之间往复。
- Tool System:统一的工具注册与执行接口,让 LLM 通过标准化的 Schema 调用外部能力。
- Context Management:智能管理有限的上下文窗口,确保关键信息不被丢弃。
从这个最小实现出发,你可以逐步加入权限控制、多模型适配、子 Agent、MCP 扩展等高级特性。更重要的是,在这个过程中你会深刻理解 AI Agent 的工程本质——它不是魔法,而是精心设计的工程实践。
项目依赖清单(最小实现所需):
openai(或anthropic)、tiktoken、rich。安装命令:pip install openai tiktoken rich
如果这篇文章对你有帮助,欢迎点赞、收藏、关注。有问题欢迎评论区交流!
参考资源:
- Dive-into-Claude-Code:Claude Code 源码深度分析
- OpenHands:端到端自动化开发助手
- Aider:Git 深度集成的 Python 编程助手
- Model Context Protocol:MCP 工具扩展协议
- Best Open Source CLI Coding Agents (2025):开源 CLI 编程助手全面对比
更多推荐
所有评论(0)