从原理构建Agent&ClaudeCode

构建一个AI Coding Agent的最小实现

1.工具定义
Agent 没有能力,只有工具。大模型不会“执行代码”,它只会决定要不要调用某个工具。

2.MCP最小等价形式
MCP 的本质:用结构化方式,把工具能力描述进 prompt。

3.system prompt:Rules / Skills 的本体
Rules、Best Practices、Coding Guideline,全部都是 system prompt。

4.Agent 主循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
while True:  # ← 内层循环:Agent 自主执行
# Think: LLM 推理
response = client.chat.completions.create(
messages=messages, # ← 完整的上下文历史
tools=TOOLS_SCHEMA, # ← 可用工具列表
)

# Act: 执行工具
if message.tool_calls:
for tool_call in message.tool_calls:
result = AVAILABLE_FUNCTIONS[func_name](**func_args)
# Observe: 将结果反馈给 Agent
messages.append({
"role": "tool",
"content": result, # ← 执行结果注入 context
})
continue # ← 继续循环
else:
break # ← 没有工具调用,任务完成

这就是 ReAct 模式(Reasoning + Acting):

  • Reasoning:LLM 思考下一步该做什么
  • Acting:调用工具执行动作
  • Observing:观察结果,更新上下文
  • 循环:重复上述过程直到任务完成

这就是 AI Coding Agent 的完整控制流,无论是 Claude Code、Cline、Cursor 都万变不离其中。但是对于对 AI 来说:只有「下一轮 prompt」是什么

完整代码实现

只要替换一个 openai 兼容的 key 就可以跑起来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
import os
import json
import subprocess
from openai import OpenAI

# =============================================================================
# 1. 定义工具 (Define Tools)
# =============================================================================

def execute_bash(command: str) -> str:
"""执行 Bash 命令"""
print(f" > [执行命令] \033[93m{command}\033[0m")
print(f" > [执行中] {command}")
result = subprocess.run(
command, shell=True, capture_output=True, text=True, timeout=30
)
output = result.stdout + result.stderr
if output:
print(f" > [输出]\n{output.rstrip()}")
# 截断过长的输出
if len(output) > 2000:
output = output[:2000] + "\n... (输出过长已截断)"
return output.strip() or "(无输出)"

def read_file(path: str) -> str:
"""读取文件内容"""
print(f" > [读取文件] {path}")
if not os.path.exists(path):
return f"文件不存在: {path}"
with open(path, "r", encoding="utf-8") as f:
content = f.read()
# 给代码加上行号,方便 Agent 指定修改位置
lines = content.splitlines()
numbered_lines = [f"{i+1:4d} | {line}" for i, line in enumerate(lines)]
return "\n".join(numbered_lines)

def write_file(path: str, content: str) -> str:
"""写入文件内容"""
print(f" > [写入文件] {path}")
os.makedirs(os.path.dirname(os.path.abspath(path)), exist_ok=True)
with open(path, "w", encoding="utf-8") as f:
f.write(content)
return f"成功写入 {len(content)} 字节到 {path}"

def list_files(path: str = ".") -> str:
"""列出当前目录下的文件结构"""
print(f" > [列出文件] {path}")
# 简单的递归列出文件
file_list = []
for root, dirs, files in os.walk(path):
for file in files:
if not file.startswith('.'):
rel_path = os.path.relpath(os.path.join(root, file), path)
file_list.append(rel_path)

result = "\n".join(file_list[:50]) # 限制返回数量
print(f" > 包含文件:\n{result}")
return result

# =============================================================================
# 2. 定义工具描述 (Define Tool Schemas)
# =============================================================================

TOOLS_SCHEMA = [
{
"type": "function",
"function": {
"name": "execute_bash",
"description": "执行 shell 命令。用于运行测试、安装依赖或文件操作。",
"parameters": {
"type": "object",
"properties": {
"command": {"type": "string", "description": "要执行的 bash 命令"}
},
"required": ["command"],
},
},
},
{
"type": "function",
"function": {
"name": "read_file",
"description": "读取文件内容。内容会包含行号。",
"parameters": {
"type": "object",
"properties": {
"path": {"type": "string", "description": "文件路径"}
},
"required": ["path"],
},
},
},
{
"type": "function",
"function": {
"name": "write_file",
"description": "创建或覆盖文件内容。",
"parameters": {
"type": "object",
"properties": {
"path": {"type": "string", "description": "文件路径"},
"content": {"type": "string", "description": "要写入的完整内容"},
},
"required": ["path", "content"],
},
},
},
{
"type": "function",
"function": {
"name": "list_files",
"description": "列出当前项目的文件结构。",
"parameters": {
"type": "object",
"properties": {
"path": {"type": "string", "description": "目录路径,默认为 '.'"}
},
"required": [],
},
},
},
]

AVAILABLE_FUNCTIONS = {
"execute_bash": execute_bash,
"read_file": read_file,
"write_file": write_file,
"list_files": list_files,
}

# =============================================================================
# 3. Agent 主循环 (The Agent Loop)
# =============================================================================

def run_toy_claude():
client = OpenAI()

# 系统提示词:设定人设
system_prompt = """
你是一个智能编程助手。
你的目标是帮助用户编写、调试和理解代码。

工作原则:
1. 在修改代码前,先使用 list_files 查看项目结构,或使用 read_file 读取相关文件。
2. 每次修改文件后,尽量运行代码或测试来验证修改(使用 execute_bash)。
3. 保持回答简洁,专注于解决问题。
"""

messages = [{"role": "system", "content": system_prompt}]

print("🤖 Toy Claude Code 已启动 (输入 'exit' 退出)")
print("--------------------------------------------")

# 外层循环:处理用户输入 (REPL)
while True:
try:
user_input = input("\n👤 你: ")
if user_input.lower() in ['exit', 'quit']:
print("再见!")
break

messages.append({"role": "user", "content": user_input})

# 内层循环:Agent 自主执行 (Think -> Act -> Observe)
# 只要 Agent 还在调用工具,就一直在这个循环里
while True:
response = client.chat.completions.create(
model="gpt-5-codex",
messages=messages,
tools=TOOLS_SCHEMA,
)

message = response.choices[0].message
messages.append(message)

if message.tool_calls:
print(f"\n🤖 思考: {message.content or '(准备调用工具...)'}")

for tool_call in message.tool_calls:
func_name = tool_call.function.name
func_args = json.loads(tool_call.function.arguments)

if func_name in AVAILABLE_FUNCTIONS:
# 执行工具
result = AVAILABLE_FUNCTIONS[func_name](**func_args)
else:
result = f"错误: 未知工具 {func_name}"

# 将结果反馈给 Agent
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"name": func_name,
"content": result,
})
else:
# 没有工具调用,说明是最终回复
print(f"\n🤖 回复:\n{message.content}")
break

except KeyboardInterrupt:
print("\n操作已取消。")
break
except Exception as e:
print(f"\n发生错误: {e}")
break

if __name__ == "__main__":
run_toy_claude()
Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2025-2026 AKi
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信