从《learn-claude-code》受到启发,于是参考源代码写了这篇文章:如何实现从0开始构建Agent?
AI Agent 构成三者构成了 AI Agent 的下限和上限,模型越强,对于指令和工具的调度能力更准确,但是从工程学的角度来考虑,较弱的模型通过对工具和指令的结合,一样能制造功能强大的 Agent。

Tool Calling由于 Anthropic Tool Calling 协议现在大部分模型已经支持,并且非常成熟,所以本文默认都通过传入 TOOLS 来让大模型调用的工具,样例如下:
{
"name": "my_function_name", # The name of the function
"description": "The description of my function", # Describe the function so Claude knows when and how to use it.
"input_schema": { # input schema describes the format and the type of parameters Claude needs to generate to use the function
"type": "object", # format of the generated Claude response
"properties": { # properties defines the input parameters of the function
"query": { # the function expects a query parameter
"description": "The search query to perform.", # describes the parameter to Claude
},
},
"required": ["query"], # define which parameters are required
},
}
给模型传入 TOOLS 参数,LLM API 返回如下:
{
"type": "tool_use",
"id": "toolu_01A09q90qw90lq917835123",
"name": "my_function_name",
"input": {
"query": "Latest developments in quantum computing"
}
}
前面提到 AI Agent 构成包括工具和指令,那么从最简的工具开始,到最后复杂的指令,Agent 的核心原理:感知 -> 认知 -> 执行 -> 反馈 -> 感知 ...,然后循环执行。

基于这个核心原理,我们从最简的 Shell 构建,规划如下:
Shell 在计算机是最常用的,所有的操作系统中都有类似 Bash 脚本的功能,那么基于脚本定义一系列工具如下:
工具 | 对应 Bash 命令示例 |
|---|---|
读文件 | cat file.txt, head -n 20 file.py, grep "TODO" -n -r . |
写文件 | echo '...' > file, cat << 'EOF' > main.py |
搜索/导航 | find . -name "*.py", ls -R, rg "keyword" . |

不足:
在这个极简版本中,我们遵循的架构设计,只保留最小完成闭环所需的要素。
一个工具就够了 Bash 本身就是工具的「元工具」:其他一切工具都可以通过 Bash 间接调用(curl、git、python、docker 等)。
递归 = 层级结构 无需实现复杂的 Task/Plan 抽象;只要允许「调用自己」,层级结构自然涌现。
进程 = 上下文隔离 不需要额外的「会话 ID」或「上下文容器」:操作系统的进程模型天然提供隔离。
提示词 = 行为约束 系统提示词定义了当前 Agent 的「角色 + 责任边界」,决定了它如何使用 Bash 能力。
核心循环
while True:
response = model(messages, tools)
if response.stop_reason != "tool_use":
return response.text
results = execute(response.tool_calls)
messages.append(results)
import sys
import os
import traceback
from llm_factory import LLMFactory, LLMChatAdapter
from util.mylog import logger
from utils import run_bash, BASH_TOOLS
# 初始化 API 客户端
# 使用 LLMFactory 创建 LLM 实例
llm = LLMFactory.create(
model_type="openai",
model_name="deepseek-v3.2", # 使用支持的模型
temperature=0.0,
max_tokens=8192
)
client = LLMChatAdapter(llm)
# 系统提示词
SYSTEM = f"""你是一个位于 {os.getcwd()} 的 CLI 代理,系统为 {sys.platform}。使用 bash 命令解决问题。
## 规则:
- 优先使用工具而不是文字描述。先行动,后简要解释。
- 读取文件:cat, grep, find, rg, ls, head, tail
- 写入文件:echo '...' > file, sed -i, 或 cat << 'EOF' > file
- 避免危险操作,如 rm -rf等删除或者清理文件, 或格式化挂载点,或对系统文件进行写操作
## 要求
- 不使用其他工具,仅使用 bash 命令或者 shell 脚本
- 子代理可以通过生成 shell 代码执行
- 如果当前任务超过 bash 的处理范围,则终止不处理
"""
def extract_bash_commands(text):
"""从 LLM 响应中提取 bash 命令"""
import re
pattern = r'```bash\n(.*?)\n```'
matches = re.findall(pattern, text, re.DOTALL)
return [cmd.strip() for cmd in matches if cmd.strip()]
def chat(prompt, history=None, max_steps=10):
if history isNone:
history = []
# 检查历史记录中是否已有系统提示词(作为系统消息)
has_system = any(msg.get("role") == "system"for msg in history)
ifnot has_system:
# 在开头添加系统提示词作为系统消息
history.insert(0, {"role": "system", "content": SYSTEM})
history.append({"role": "user", "content": prompt})
step = 0
while step < max_steps:
step += 1
# 1. 调用模型(传递 tools 参数)
# 使用 chat_with_tools 接口,支持 function calling
response = client.chat_with_tools(
prompt=prompt,
messages=history,
tools=BASH_TOOLS
)
if step == 1:
prompt = '继续'
# 2. 解析响应内容
assistant_text = []
tool_calls = []
logger.info(f"第 {step} 步响应: {response}")
# chat_with_tools 返回的是 Response 对象,包含 content 列表
for block in response.content:
if getattr(block, "type", "") == "text":
assistant_text.append(block.text)
elif getattr(block, "type", "") == "tool_use":
tool_calls.append(block)
# 记录助手文本回复
full_text = "\n".join(assistant_text)
if full_text:
logger.info(f"助手: {full_text}")
history.append({"role": "assistant", "content": full_text})
elif tool_calls:
# 如果只有工具调用没有文本,添加一个占位文本到历史,保持对话连贯
history.append({"role": "assistant", "content": "(Executing tools...)"})
# 3. 如果没有工具调用,直接返回内容
ifnot tool_calls:
logger.info(f"第 {step} 步结束,无工具调用")
if response.stop_reason == "end_turn":
return full_text
# 如果异常结束,也返回
return full_text or"(No response)"
# 4. 执行工具
logger.info(f"第 {step} 步工具调用: {tool_calls}")
all_outputs = []
for tc in tool_calls:
if tc.name == "bash":
cmd = tc.input.get("command")
if cmd:
logger.info(f"[使用工具] {cmd}") # 黄色显示命令
output = run_bash(cmd)
all_outputs.append(f"$ {cmd}\n{output}")
# 如果输出太长则截断打印
if len(output) > 200:
logger.info(f"输出: {output[:200]}... (已截断)")
else:
logger.info(f"输出: {output}")
else:
logger.warning(f"Unknown tool: {tc.name}")
# 5. 将命令执行结果添加到历史记录中
if all_outputs:
combined_output = "\n".join(all_outputs)
history.append({"role": "user", "content": f"执行结果:\n{combined_output}\n\n请继续处理。"})
else:
# 有工具调用但没产生输出(可能是解析失败或空命令)
history.append({"role": "user", "content": "Error: Tool call failed or produced no output."})
return"达到最大执行步数限制,停止执行。"
if __name__ == "__main__":
if len(sys.argv) > 1:
logger.info(chat(sys.argv[1]))
else:
# 交互模式
logger.info("Bash 代理已启动。输入 'exit' 退出。")
history = []
whileTrue:
try:
user_input = input("> ")
if user_input.lower() in ['exit', 'quit']:
break
chat(user_input, history)
except KeyboardInterrupt:
logger.info("\n正在退出...")
break
except Exception as e:
logger.info(f"\n错误: {e}")
traceback.print_exc()
输入:统计当前目录下的代码行数,输出到控制台
输出:
(base) linkxzhou@LINKXZHOU-MC1 miniagent % python3.11 v0_bash.py
2026-01-16 21:39:40,009 - INFO - ====== 使用 openai 模型: deepseek-v3.2, 参数:(0.0, None, 8192)
2026-01-16 21:39:40,009 - INFO - OpenAI API 配置已初始化
2026-01-16 21:39:40,037 - INFO - Bash 代理已启动。输入 'exit' 退出。
> 统计当前目录下的代码行数,输出到控制台
2026-01-16 21:39:56,102 - INFO - OpenAI API 响应内容: 我将统计当前目录下的代码行数并输出到控制台。让我先查看当前目录结构,然后统计代码行数。...
2026-01-16 21:39:56,105 - INFO - 第 1 步响应: <class 'llm_factory.Response'>
2026-01-16 21:39:56,105 - INFO - 助手: 我将统计当前目录下的代码行数并输出到控制台。让我先查看当前目录结构,然后统计代码行数。
2026-01-16 21:39:56,105 - INFO - 第 1 步工具调用: [<class 'llm_factory.ToolUseBlock'>]
2026-01-16 21:39:56,105 - INFO - [使用工具] pwd
2026-01-16 21:39:56,129 - INFO - 输出: /Volumes/my/github/mylib/llm/llmapi/miniagent
2026-01-16 21:39:59,730 - INFO - OpenAI API 响应内容: 我将统计当前目录下的代码行数。让我先查看当前目录的文件结构,然后使用适当的命令统计代码行数。...
2026-01-16 21:39:59,731 - INFO - 第 2 步响应: <class 'llm_factory.Response'>
2026-01-16 21:39:59,731 - INFO - 助手: 我将统计当前目录下的代码行数。让我先查看当前目录的文件结构,然后使用适当的命令统计代码行数。
2026-01-16 21:39:59,732 - INFO - 第 2 步工具调用: [<class 'llm_factory.ToolUseBlock'>]
2026-01-16 21:39:59,732 - INFO - [使用工具] find . -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.java" -o -name "*.cpp" -o -name "*.c" -o -name "*.h" -o -name "*.go" -o -name "*.rs" -o -name "*.php" -o -name "*.rb" | head -20
2026-01-16 21:39:59,763 - INFO - 输出: ./v3_subagent.py
./v4_skills.py
./v0_bash.py
./v2_todo.py
./utils.py
./v1_basic.py
2026-01-16 21:40:02,052 - INFO - OpenAI API 响应内容: 我将统计当前目录下的代码行数。让我使用 `wc -l` 命令来统计所有代码文件的总行数。...
2026-01-16 21:40:02,053 - INFO - 第 3 步响应: <class 'llm_factory.Response'>
2026-01-16 21:40:02,053 - INFO - 助手: 我将统计当前目录下的代码行数。让我使用 `wc -l` 命令来统计所有代码文件的总行数。
2026-01-16 21:40:02,053 - INFO - 第 3 步工具调用: [<class 'llm_factory.ToolUseBlock'>]
2026-01-16 21:40:02,053 - INFO - [使用工具] find . -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.java" -o -name "*.cpp" -o -name "*.c" -o -name "*.h" -o -name "*.go" -o -name "*.rs" -o -name "*.php" -o -name "*.rb" | xargs wc -l
2026-01-16 21:40:02,095 - INFO - 输出: 304 ./v3_subagent.py
483 ./v4_skills.py
152 ./v0_bash.py
207 ./v2_todo.py
424 ./utils.py
191 ./v1_basic.py
1761 total
2026-01-16 21:40:04,810 - INFO - OpenAI API 响应内容: 我已经统计了当前目录下的代码行数。结果显示:
**代码行数统计结果:**
- v3_subagent.py: 304 行
- v4_skills.py: 483 行
- v0_bash.py: ...
2026-01-16 21:40:04,810 - INFO - 第 4 步响应: <class 'llm_factory.Response'>
2026-01-16 21:40:04,810 - INFO - 助手: 我已经统计了当前目录下的代码行数。结果显示:
**代码行数统计结果:**
- v3_subagent.py: 304 行
- v4_skills.py: 483 行
- v0_bash.py: 152 行
- v2_todo.py: 207 行
- utils.py: 424 行
- v1_basic.py: 191 行
**总计:1,761 行代码**
统计包含了常见的编程语言文件(.py, .js, .ts, .java, .cpp, .c, .h, .go, .rs, .php, .rb)。当前目录共有6个代码文件,总行数为1,761行。
2026-01-16 21:40:04,810 - INFO - 第 4 步结束,无工具调用
Agent 的核心就是自主决策,只需要人工给定目标+约束规则,让大模型自主决策怎么调用工具,怎么遵循规则,这样才能做到通用性。
传统助手模式:
用户 -> 模型 -> 文本回复
Agent 系统模式:
用户 -> 模型 -> [工具 -> 结果]* -> 回复
^_________|
* 模型可以反复调用工具,直到它认为任务完成为止,把「聊天机器人」升级为「自主代理」。
Claude Code 之类系统可能挂了 10~20 个工具,但对于一个「本地代码助手」,4 个就够覆盖 80–90% 的场景:
工具 | 用途 | 示例能力 |
|---|---|---|
bash | 运行命令 | npm install, git status, pytest, ls |
read_file | 读取文件内容 | 查看 src/index.ts 的具体实现 |
write_file | 创建/覆盖文件 | 创建 README.md、生成新模块 |
edit_file | 精确修改片段 | 在一个函数内插入日志、重构一个方法 |
有了这 4 个工具,模型就是可以完成如下事情:
bash: find, ls, tree, rg/grepread_file 查看具体文件内容write_fileedit_filebash: python, npm test, make, pytest, go test ...
agent_loop 正是 v1 的核心:
while True:
response = model(messages, tools)
# 打印文本输出
if no tool_use:
return
results = execute(response.tool_calls)
messages.append(response)
messages.append(results)
模型控制循环
只要 stop_reason == "tool_use",说明模型还在「思考 + 操作」,没准备给出最终答案。
一旦 stop_reason != "tool_use",模型就认为任务完成,返回最终文本。
工具结果成为上下文
工具执行结果以 "user" 消息的形式追加回对话,模型下次调用时就能「看到」自己刚刚操作的结果。
记忆自动累积
所有对话内容、工具调用、结果都放在 messages 里,模型自然拥有整个任务的上下文。
代码逻辑极薄 你几乎看不到复杂状态机、计划器、子任务调度器——这些都交给模型的「思考 + 工具调用策略」来涌现。
1. 简单
只有:messages、tools、while True。
2. 模型负责思考
全都交给模型,用自然语言和工具 schema 引导,而不是手动写死流程。
3. 透明可观测
messages 中 (tool_use + tool_result)messages 持久化,恢复整个过程、调试行为4. 可扩展性强
添加新工具的成本非常低:
tool_http_request)。TOOLS 列表中增加一个带 JSON schema 的条目。execute_tool 中分发到对应函数。无需改 Agent 循环,循环 Agent 核心调度方式。
from pathlib import Path
import sys
import traceback
from llm_factory import LLMFactory, LLMChatAdapter
from util.mylog import logger
from utils import execute_base_tools, BASIC_TOOLS
# 初始化 API 客户端
# 使用 LLMFactory 创建 LLM 实例
llm = LLMFactory.create(
model_type="openai",
model_name="deepseek-v3.2", # 使用支持的模型
temperature=0.0,
max_tokens=8192
)
client = LLMChatAdapter(llm)
WORKDIR = Path.cwd()
SYSTEM = f"""你是一个位于 {WORKDIR} 的编码代理,系统为 {sys.platform}。
## 执行流程
简要思考 -> 使用工具(使用 TOOLS) -> 报告结果。
## 规则
- 优先使用工具而不是文字描述。先行动,不要只是解释。
- 永远不要臆造文件路径。如果不确定,先使用 bash ls/find 确认。
- 做最小的修改。不要过度设计。
- 完成后,总结变更内容。
## 要求:
- 循环尽量简单,不要复杂。
"""
def execute_tool(name: str, args: dict) -> str:
result = execute_base_tools(name, args)
if result isnotNone:
return result
returnf"Unknown tool: {name}"
def agent_loop(prompt, history=None, max_steps=10) -> list:
if history isNone:
history = []
# 检查历史记录中是否已有系统提示词(作为系统消息)
has_system = any(msg.get("role") == "system"for msg in history)
ifnot has_system:
# 在开头添加系统提示词作为系统消息
history.insert(0, {"role": "system", "content": SYSTEM})
step = 0
while step < max_steps:
step += 1
response = client.chat_with_tools(
prompt=prompt,
messages=history,
tools=BASIC_TOOLS,
)
assistant_text = []
tool_calls = []
for block in response.content:
if getattr(block, "type", "") == "text":
assistant_text.append(block.text)
elif getattr(block, "type", "") == "tool_use":
tool_calls.append(block)
full_text = "\n".join(assistant_text)
ifnot tool_calls:
history.append({"role": "assistant", "content": full_text})
logger.info(f"第 {step} 步结束,无工具调用")
return history
results = []
for tc in tool_calls:
logger.info(f"\n> [使用工具] {tc.name} 第 {step} 步调用工具: {tc.input}")
output = execute_tool(tc.name, tc.input)
preview = output[:200] + "..."if len(output) > 200else output
logger.info(f" [使用工具] {tc.name}, 输入: {tc.input}, 返回: {preview}")
results.append(f"工具 {tc.name}, 输入: {tc.input}, 返回: {output}")
history.append({"role": "assistant", "content": full_text})
combined_output = "\n".join(results)
history.append({"role": "user", "content": f"执行结果:\n{combined_output}\n\n请继续处理"})
logger.info(f"第 {step} 步达到最大执行步数限制,停止执行。")
def main():
logger.info(f"Mini Claude Code v1 - {WORKDIR}")
logger.info("Type 'exit' to quit.\n")
history = []
whileTrue:
try:
user_input = input("You: ").strip()
except (EOFError, KeyboardInterrupt):
break
ifnot user_input or user_input.lower() in ("exit", "quit", "q"):
break
history.append({"role": "user", "content": user_input})
try:
agent_loop('', history, max_steps=10)
except Exception as e:
logger.error(f"Error: {e}")
traceback.print_exc()
if __name__ == "__main__":
main()
输入:统计当前目录下的代码行数,输出到 html 中
输出:
(base) linkxzhou@LINKXZHOU-MC1 miniagent % python3.11 v0_basic.py
2026-01-16 21:39:40,009 - INFO - ====== 使用 openai 模型: deepseek-v3.2, 参数:(0.0, None, 8192)
2026-01-16 21:39:40,009 - INFO - OpenAI API 配置已初始化
2026-01-16 21:39:40,037 - INFO - Bash 代理已启动。输入 'exit' 退出。
> 统计当前目录下的代码行数,输出到控制台
2026-01-16 21:39:56,102 - INFO - OpenAI API 响应内容: 我将统计当前目录下的代码行数并输出到控制台。让我先查看当前目录结构,然后统计代码行数。...
2026-01-16 21:39:56,105 - INFO - 第 1 步响应: <class 'llm_factory.Response'>
2026-01-16 21:39:56,105 - INFO - 助手: 我将统计当前目录下的代码行数并输出到控制台。让我先查看当前目录结构,然后统计代码行数。
2026-01-16 21:39:56,105 - INFO - 第 1 步工具调用: [<class 'llm_factory.ToolUseBlock'>]
2026-01-16 21:39:56,105 - INFO - [使用工具] pwd
2026-01-16 21:39:56,129 - INFO - 输出: /Volumes/my/github/mylib/llm/llmapi/miniagent
2026-01-16 21:39:59,730 - INFO - OpenAI API 响应内容: 我将统计当前目录下的代码行数。让我先查看当前目录的文件结构,然后使用适当的命令统计代码行数。...
2026-01-16 21:39:59,731 - INFO - 第 2 步响应: <class 'llm_factory.Response'>
2026-01-16 21:39:59,731 - INFO - 助手: 我将统计当前目录下的代码行数。让我先查看当前目录的文件结构,然后使用适当的命令统计代码行数。
2026-01-16 21:39:59,732 - INFO - 第 2 步工具调用: [<class 'llm_factory.ToolUseBlock'>]
2026-01-16 21:39:59,732 - INFO - [使用工具] find . -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.java" -o -name "*.cpp" -o -name "*.c" -o -name "*.h" -o -name "*.go" -o -name "*.rs" -o -name "*.php" -o -name "*.rb" | head -20
2026-01-16 21:39:59,763 - INFO - 输出: ./v3_subagent.py
./v4_skills.py
./v0_bash.py
./v2_todo.py
./utils.py
./v1_basic.py
2026-01-16 21:40:02,052 - INFO - OpenAI API 响应内容: 我将统计当前目录下的代码行数。让我使用 `wc -l` 命令来统计所有代码文件的总行数。...
2026-01-16 21:40:02,053 - INFO - 第 3 步响应: <class 'llm_factory.Response'>
2026-01-16 21:40:02,053 - INFO - 助手: 我将统计当前目录下的代码行数。让我使用 `wc -l` 命令来统计所有代码文件的总行数。
2026-01-16 21:40:02,053 - INFO - 第 3 步工具调用: [<class 'llm_factory.ToolUseBlock'>]
2026-01-16 21:40:02,053 - INFO - [使用工具] find . -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.java" -o -name "*.cpp" -o -name "*.c" -o -name "*.h" -o -name "*.go" -o -name "*.rs" -o -name "*.php" -o -name "*.rb" | xargs wc -l
2026-01-16 21:40:02,095 - INFO - 输出: 304 ./v3_subagent.py
483 ./v4_skills.py
152 ./v0_bash.py
207 ./v2_todo.py
424 ./utils.py
191 ./v1_basic.py
1761 total
2026-01-16 21:40:04,810 - INFO - OpenAI API 响应内容: 我已经统计了当前目录下的代码行数。结果显示:
**代码行数统计结果:**
- v3_subagent.py: 304 行
- v4_skills.py: 483 行
- v0_bash.py: ...
2026-01-16 21:40:04,810 - INFO - 第 4 步响应: <class 'llm_factory.Response'>
2026-01-16 21:40:04,810 - INFO - 助手: 我已经统计了当前目录下的代码行数。结果显示:
**代码行数统计结果:**
- v3_subagent.py: 304 行
- v4_skills.py: 483 行
- v0_bash.py: 152 行
- v2_todo.py: 207 行
- utils.py: 424 行
- v1_basic.py: 191 行
**总计:1,761 行代码**
统计包含了常见的编程语言文件(.py, .js, .ts, .java, .cpp, .c, .h, .go, .rs, .php, .rb)。当前目录共有6个代码文件,总行数为1,761行。
2026-01-16 21:40:04,810 - INFO - 第 4 步结束,无工具调用
> ^C2026-01-17 04:36:02,613 - INFO -
正在退出...
(base) linkxzhou@LINKXZHOU-MC1 miniagent % python3.11 v1_basic.py
2026-01-17 04:36:08,874 - INFO - ====== 使用 openai 模型: deepseek-v3.2, 参数:(0.0, None, 8192)
2026-01-17 04:36:08,874 - INFO - OpenAI API 配置已初始化
2026-01-17 04:36:08,902 - INFO - Mini Claude Code v1 - /Volumes/my/github/mylib/llm/llmapi/miniagent
2026-01-17 04:36:08,902 - INFO - Type 'exit' to quit.
You: 统计当前目录下的代码行数,输出到 html 中
2026-01-17 04:36:31,650 - INFO - OpenAI API 响应内容: 我将帮您统计当前目录下的代码行数并生成HTML报告。让我先探索目录结构,然后统计代码行数。...
2026-01-17 04:36:31,651 - INFO -
> [使用工具] bash 第 1 步调用工具: {'command': 'pwd'}
2026-01-17 04:36:31,670 - INFO - [使用工具] bash, 输入: {'command': 'pwd'}, 返回: /Volumes/my/github/mylib/llm/llmapi/miniagent
2026-01-17 04:36:38,726 - INFO - OpenAI API 响应内容: 我将继续处理统计代码行数并生成HTML报告的任务。让我先探索目录结构,然后统计代码行数。...
2026-01-17 04:36:38,727 - INFO -
> [使用工具] bash 第 2 步调用工具: {'command': 'find . -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.java" -o -name "*.cpp" -o -name "*.c" -o -name "*.h" -o -name "*.go" -o -name "*.rs" -o -name "*.php" | head -20'}
2026-01-17 04:36:38,752 - INFO - [使用工具] bash, 输入: {'command': 'find . -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.java" -o -name "*.cpp" -o -name "*.c" -o -name "*.h" -o -name "*.go" -o -name "*.rs" -o -name "*.php" | head -20'}, 返回: ./v3_subagent.py
./v4_skills.py
./v0_bash.py
./v2_todo.py
./utils.py
./v1_basic.py
2026-01-17 04:36:40,300 - INFO - OpenAI API 响应内容: 我将统计这些代码文件的行数并生成HTML报告。让我先统计每个文件的行数。...
2026-01-17 04:36:40,301 - INFO -
> [使用工具] bash 第 3 步调用工具: {'command': 'wc -l ./v3_subagent.py ./v4_skills.py ./v0_bash.py ./v2_todo.py ./utils.py ./v1_basic.py'}
2026-01-17 04:36:40,326 - INFO - [使用工具] bash, 输入: {'command': 'wc -l ./v3_subagent.py ./v4_skills.py ./v0_bash.py ./v2_todo.py ./utils.py ./v1_basic.py'}, 返回: 304 ./v3_subagent.py
483 ./v4_skills.py
152 ./v0_bash.py
207 ./v2_todo.py
424 ./utils.py
191 ./v1_basic.py
1761 total
2026-01-17 04:36:46,211 - INFO - OpenAI API 响应内容: 我将基于统计结果生成HTML报告。让我创建一个包含代码行数统计的HTML文件。...
2026-01-17 04:36:46,211 - INFO -
> [使用工具] write_file 第 4 步调用工具: {'path': 'code_stats.html', 'content': '<!DOCTYPE html>...'}, 返回: Wrote 1569 bytes to code_stats.html
2026-01-17 04:36:51,383 - INFO - OpenAI API 响应内容: None...
2026-01-17 04:36:51,385 - INFO -
> [使用工具] bash 第 5 步调用工具: {'command': 'ls -la code_stats.html'}
2026-01-17 04:36:51,418 - INFO - [使用工具] bash, 输入: {'command': 'ls -la code_stats.html'}, 返回: -rw-r--r--@ 1 linkxzhou admin 1627 1 17 04:36 code_stats.html
2026-01-17 04:36:52,602 - INFO - OpenAI API 响应内容: 我已经成功完成了代码行数统计并生成了HTML报告。让我验证一下文件内容并总结结果。...
2026-01-17 04:36:52,602 - INFO -
> [使用工具] read_file 第 6 步调用工具: {'path': 'code_stats.html'}
2026-01-17 04:36:52,602 - INFO - [使用工具] read_file, 输入: {'path': 'code_stats.html'}, 返回: <!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>代码行数统计报告</title>
<style>
body { ...
2026-01-17 04:36:55,421 - INFO - OpenAI API 响应内容: 我已经成功完成了代码行数统计并生成了HTML报告。以下是任务总结:
## 完成的任务
1. **探索目录结构**:发现了6个代码文件(.py文件)
2. **统计代码行数**:使用`wc -l`命...
2026-01-17 04:36:55,421 - INFO - 第 7 步结束,无工具调用
输出信息通过调用 write_file 写入到 html 中,展示如下:

v1 已经能正常工作,但在复杂任务上,它容易失去方向:
v2 我们只需要做一个 Plan:Todo 工具(增加少量状态管理与提示逻辑),就能实现 "计划(使用 TodoWrite) -> 使用工具行动(使用 TOOLS)"。
在 v1 的工具列表基础上,v2 新增 TodoManager 管理和 TodoWrite 工具。
核心是一个带约束的列表管理器:
class TodoManager:
"""
管理具有强制约束的结构化任务列表。
关键设计决策:
--------------------
1. 最多 20 项:防止模型创建无尽的列表
2. 一个进行中:强制专注 - 一次只能做一件事
3. 必填字段:每个项目需要 content, status 和 activeForm
activeForm 字段值得解释:
- 它是正在发生的事情的现在时形式
- 当 status 为 "in_progress" 时显示
- 示例:content="Add tests", activeForm="Adding unit tests..."
这提供了代理正在做什么的实时可见性。
"""
def __init__(self):
self.items = []
def update(self, items: list) -> str:
"""
验证并更新任务列表。
模型每次发送一个完整的列表。我们验证它,
存储它,并返回一个模型将看到的渲染视图。
验证规则:
- 每个项目必须有:content, status, activeForm
- Status 必须是:pending | in_progress | completed
- 一次只能有 ONE 个项目处于 in_progress 状态
- 最多允许 20 个项目
Returns:
任务列表的渲染文本视图
"""
validated = []
in_progress_count = 0
for i, item in enumerate(items):
# Extract and validate fields
content = str(item.get("content", "")).strip()
status = str(item.get("status", "pending")).lower()
active_form = str(item.get("activeForm", "")).strip()
# Validation checks
ifnot content:
raise ValueError(f"Item {i}: content required")
if status notin ("pending", "in_progress", "completed"):
raise ValueError(f"Item {i}: invalid status '{status}'")
ifnot active_form:
raise ValueError(f"Item {i}: activeForm required")
if status == "in_progress":
in_progress_count += 1
validated.append({
"content": content,
"status": status,
"activeForm": active_form
})
# Enforce constraints
if len(validated) > 20:
raise ValueError("Max 20 todos allowed")
if in_progress_count > 1:
raise ValueError("Only one task can be in_progress at a time")
self.items = validated
return self.render()
def render(self) -> str:
"""
将任务列表渲染为人类可读的文本。
格式:
[x] 已完成任务
[>] 进行中任务 <- 正在做某事...
[ ] 待办任务
(2/3 completed)
这个渲染后的文本是模型作为工具结果看到的内容。
然后它可以根据当前状态更新列表。
"""
ifnot self.items:
return"No todos."
lines = []
for item in self.items:
if item["status"] == "completed":
lines.append(f"[x] {item['content']}")
elif item["status"] == "in_progress":
lines.append(f"[>] {item['content']} <- {item['activeForm']}")
else:
lines.append(f"[ ] {item['content']}")
completed = sum(1for t in self.items if t["status"] == "completed")
lines.append(f"\n({completed}/{len(self.items)} completed)")
return"\n".join(lines)
这里的约束是有意设计的「规则」:
规则 | 原因 |
|---|---|
最多 20 条 | 防止模型把 todo 当成无限备忘录 |
必须有 content | 保证每条任务有明确描述 |
必须有 status | 让任务进度可追踪 |
必须有 activeForm | 帮助描述“当前正在做的具体动作” |
只能一个 in_progress | 强制模型一次只专注一个任务 |
内容不能重复 | 防止模型无意义地复制条目 |
这些约束同时限制了行为空间,又增强了可控性和可观察性。
在 Agent 端的实现中:
todo_manager = TodoManager()
def execute_tool(name, args):
if name == "TodoWrite":
try:
todo_manager.update(args["items"])
# 返回给模型看的文本形式,模型可以据此继续思考和更新
return todo_manager.summary_text()
except Exception as e:
return f"[TodoWrite error] {e}"
# 其他工具: bash / read_file / write_file / edit_file...
...
以一次调用为例:
模型调用 TodoWrite 输入:
{
"items": [
{
"content": "重构认证模块",
"status": "completed",
"activeForm": "重构已完成"
},
{
"content": "添加单元测试",
"status": "in_progress",
"activeForm": "正在为认证模块编写单元测试"
},
{
"content": "更新文档",
"status": "pending",
"activeForm": "准备在完成测试后更新文档"
}
]
}
工具返回给模型的文本(作为 tool_result):
[x] 重构认证模块 (重构已完成)
[>] 添加单元测试 (正在为认证模块编写单元测试)
[ ] 更新文档 (准备在完成测试后更新文档)
(1/3 已完成)
模型在下一轮调用时,就能「看到自己刚刚整理的计划」,并基于这个结构化状态决定接下来要做什么。
Todo 的使用不是强制性的,而是通过 软提醒 进行引导:
INITIAL_REMINDER = "<reminder>对于多步骤任务,请使用 TodoWrite 工具创建和维护一个清晰的 todo 列表。</reminder>"
NAG_REMINDER = "<reminder>已经超过 10 轮未更新 todo,请检查是否需要补充或更新 TodoWrite。</reminder>"
示例:
while True:
...
if first_message:
content.append(INITIAL_REMINDER)
first_message = False
elif rounds_without_todo > max_steps:
content.append(NAG_REMINDER)
content.append(f"输入:{user_input}")
history.append({"role": "user", "content": "\n".join(content)})
try:
agent_loop('', history, max_steps=max_steps)
except Exception as e:
logger.error(f"Error: {e}")
traceback.print_exc()
效果:

显式规划让 Agent 更可靠,而 Todo 是实现显式规划的最小结构单元。 结构既是约束,也是能力放大的脚手架。
类似的模式在 Agent 设计中普遍存在:
max_tokens 约束 → 赋能了响应可控与流式体验好的约束不是阻碍,而是让能力更稳定、更可控的支架。
v2 是在 v1 基础上的增量扩展,不改变核心 Agent 循环:
import traceback
import sys
from pathlib import Path
from llm_factory import LLMFactory, LLMChatAdapter
from util.mylog import logger
from utils import execute_base_tools, TodoManager, BASE_TOOLS
# 初始化 API 客户端
# 使用 LLMFactory 创建 LLM 实例
llm = LLMFactory.create(
model_type="openai",
model_name="deepseek-v3.2", # 使用支持的模型
temperature=0.0,
max_tokens=8192
)
client = LLMChatAdapter(llm)
WORKDIR = Path.cwd()
TODO = TodoManager()
SYSTEM = f"""你是一个位于 {WORKDIR} 的编码代理,系统为 {sys.platform}。
## 执行流程
计划(使用 TodoWrite) -> 使用工具行动(使用 TOOLS) -> 更新任务列表 -> 报告。
## 规则
- 使用 TodoWrite 跟踪多步骤任务
- 开始前将任务标记为 in_progress,完成后标记为 completed
- 优先使用工具而不是文字描述。先行动,不要只是解释。
- 完成后,总结变更内容。"""
# 在对话开始时显示
INITIAL_REMINDER = "<reminder>使用 TodoWrite 处理多步骤任务。</reminder>"
# 如果模型在一段时间内没有更新任务列表,则显示此提醒
NAG_REMINDER = "<reminder>超过 10 轮未更新任务列表。请更新任务列表。</reminder>"
max_steps = 20
rounds_without_todo = 0
def run_todo(items: list) -> str:
try:
return TODO.update(items)
except Exception as e:
returnf"Error: {e}"
def execute_tool(name: str, args: dict) -> str:
"""Dispatch tool call to implementation."""
result = execute_base_tools(name, args)
if result isnotNone:
return result
if name == "TodoWrite":
return run_todo(args["items"])
returnf"Unknown tool: {name}"
def agent_loop(prompt: str, history: list = [], max_steps: int = max_steps) -> list:
global rounds_without_todo
# 检查历史记录中是否已有系统提示词(作为系统消息)
has_system = any(msg.get("role") == "system"for msg in history)
ifnot has_system:
# 在开头添加系统提示词作为系统消息
history.insert(0, {"role": "system", "content": SYSTEM})
step = 0
while step < max_steps:
step += 1
response = client.chat_with_tools(
prompt=prompt,
messages=history,
tools=BASE_TOOLS,
)
assistant_text = []
tool_calls = []
for block in response.content:
if hasattr(block, "text"):
assistant_text.append(block.text)
logger.info(block.text)
if block.type == "tool_use":
tool_calls.append(block)
full_text = "\n".join(assistant_text)
ifnot tool_calls:
history.append({"role": "assistant", "content": full_text})
logger.info(f"第 {step} 步结束,无工具调用")
return history
results = []
used_todo = False
for tc in tool_calls:
logger.info(f"\n> [使用工具] {tc.name} 第 {step} 步调用: {tc.input}")
output = execute_tool(tc.name, tc.input)
preview = output[:200] + "..."if len(output) > 200else output
logger.info(f" [使用工具] {tc.name}, 输入: {tc.input}, 返回: {preview}")
results.append(f"工具 {tc.name}, 输入: {tc.input}, 返回: {output}")
if tc.name == "TodoWrite":
used_todo = True
if used_todo:
rounds_without_todo = 0
else:
rounds_without_todo += 1
history.append({"role": "assistant", "content": full_text})
combined_output = "\n".join(results)
history.append({"role": "user", "content": f"执行结果:\n{combined_output}\n\n请继续处理"})
def main():
global rounds_without_todo
logger.info(f"Mini Claude Code v2 (with Todos) - {WORKDIR}")
logger.info("Type 'exit' to quit.\n")
history = []
first_message = True
whileTrue:
try:
user_input = input("You: ").strip()
except (EOFError, KeyboardInterrupt):
break
ifnot user_input or user_input.lower() in ("exit", "quit", "q"):
break
content = []
if first_message:
content.append(INITIAL_REMINDER)
first_message = False
elif rounds_without_todo > max_steps:
content.append(NAG_REMINDER)
content.append(f"输入:{user_input}")
history.append({"role": "user", "content": "\n".join(content)})
try:
agent_loop('', history, max_steps=max_steps)
except Exception as e:
logger.error(f"Error: {e}")
traceback.print_exc()
if __name__ == "__main__":
main()
输入:统计当前目录下的代码行数和功能,输出到 html 中
输出:
(base) linkxzhou@LINKXZHOU-MC1 miniagent % python3.11 v2_todo.py
2026-01-17 08:55:15,621 - INFO - ====== 使用 openai 模型: deepseek-v3.2, 参数:(0.0, None, 8192)
2026-01-17 08:55:15,621 - INFO - OpenAI API 配置已初始化
2026-01-17 08:55:15,647 - INFO - Mini Claude Code v2 (with Todos) - /Volumes/my/github/mylib/llm/llmapi/miniagent
2026-01-17 08:55:15,647 - INFO - Type 'exit' to quit.
You: 统计当前目录下的代码行数和功能,输出到 html 中
2026-01-17 08:55:44,301 - INFO - OpenAI API 响应内容: 我将帮您统计当前目录下的代码行数和功能,并输出到HTML文件中。让我先制定计划并开始执行。...
2026-01-17 08:55:44,302 - INFO - 我将帮您统计当前目录下的代码行数和功能,并输出到HTML文件中。让我先制定计划并开始执行。
2026-01-17 08:55:44,302 - INFO -
> [使用工具] TodoWrite 第 1 步调用: {'items': [{'content': '分析当前目录结构,识别代码文件', 'status': 'pending', 'activeForm': '分析'}, {'content': '统计各代码文件的行数和功能', 'status': 'pending', 'activeForm': '统计'}, {'content': '生成HTML报告文件', 'status': 'pending', 'activeForm': '生成'}, {'content': '验证HTML输出结果', 'status': 'pending', 'activeForm': '验证'}]}
2026-01-17 08:55:44,302 - INFO - [使用工具] TodoWrite, 输入: {'items': [{'content': '分析当前目录结构,识别代码文件', 'status': 'pending', 'activeForm': '分析'}, {'content': '统计各代码文件的行数和功能', 'status': 'pending', 'activeForm': '统计'}, {'content': '生成HTML报告文件', 'status': 'pending', 'activeForm': '生成'}, {'content': '验证HTML输出结果', 'status': 'pending', 'activeForm': '验证'}]}, 返回: [ ] 分析当前目录结构,识别代码文件
[ ] 统计各代码文件的行数和功能
[ ] 生成HTML报告文件
[ ] 验证HTML输出结果
(0/4 completed)
2026-01-17 08:55:46,215 - INFO - OpenAI API 响应内容: 我将开始执行任务。首先分析当前目录结构,识别代码文件。...
2026-01-17 08:55:46,215 - INFO - 我将开始执行任务。首先分析当前目录结构,识别代码文件。
2026-01-17 08:55:46,216 - INFO -
> [使用工具] bash 第 2 步调用: {'command': 'find . -type f -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.java" -o -name "*.cpp" -o -name "*.c" -o -name "*.h" -o -name "*.go" -o -name "*.rs" | grep -v node_modules | grep -v __pycache__ | sort'}
2026-01-17 08:55:46,243 - INFO - [使用工具] bash, 输入: {'command': 'find . -type f -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.java" -o -name "*.cpp" -o -name "*.c" -o -name "*.h" -o -name "*.go" -o -name "*.rs" | grep -v node_modules | grep -v __pycache__ | sort'}, 返回: ./utils.py
./v0_bash.py
./v1_basic.py
./v2_todo.py
./v3_subagent.py
./v4_skills.py
2026-01-17 08:55:52,845 - INFO - OpenAI API 响应内容: 我将继续执行任务,首先更新任务状态,然后统计这些代码文件的行数和功能。...
2026-01-17 08:55:52,846 - INFO - 我将继续执行任务,首先更新任务状态,然后统计这些代码文件的行数和功能。
2026-01-17 08:55:52,846 - INFO -
> [使用工具] TodoWrite 第 3 步调用: {'items': [{'content': '分析当前目录结构,识别代码文件', 'status': 'completed', 'activeForm': '分析'}, {'content': '统计各代码文件的行数和功能', 'status': 'in_progress', 'activeForm': '统计'}, {'content': '生成HTML报告文件', 'status': 'pending', 'activeForm': '生成'}, {'content': '验证HTML输出结果', 'status': 'pending', 'activeForm': '验证'}]}
2026-01-17 08:55:52,846 - INFO - [使用工具] TodoWrite, 输入: {'items': [{'content': '分析当前目录结构,识别代码文件', 'status': 'completed', 'activeForm': '分析'}, {'content': '统计各代码文件的行数和功能', 'status': 'in_progress', 'activeForm': '统计'}, {'content': '生成HTML报告文件', 'status': 'pending', 'activeForm': '生成'}, {'content': '验证HTML输出结果', 'status': 'pending', 'activeForm': '验证'}]}, 返回: [x] 分析当前目录结构,识别代码文件
[>] 统计各代码文件的行数和功能 <- 统计
[ ] 生成HTML报告文件
[ ] 验证HTML输出结果
(1/4 completed)
2026-01-17 08:55:54,999 - INFO - OpenAI API 响应内容: 我将开始统计每个代码文件的行数和功能。让我逐一分析这些文件。...
2026-01-17 08:55:54,999 - INFO - 我将开始统计每个代码文件的行数和功能。让我逐一分析这些文件。
2026-01-17 08:55:54,999 - INFO -
> [使用工具] read_file 第 4 步调用: {'path': './utils.py'}
2026-01-17 08:55:55,001 - INFO - [使用工具] read_file, 输入: {'path': './utils.py'}, 返回: import subprocess
import sys
import time
from pathlib import Path
from util.mylog import logger
WORKDIR = Path.cwd()
def safe_path(p: str) -> Path:
"""
Ensure path stays within workspace (se...
2026-01-17 08:55:55,001 - INFO -
> [使用工具] read_file 第 4 步调用: {'path': './v0_bash.py'}
2026-01-17 08:55:55,002 - INFO - [使用工具] read_file, 输入: {'path': './v0_bash.py'}, 返回: #!/usr/bin/env python3
"""
v0_bash.py - Mini Claude Code: Bash 是一切 (~50 行核心代码)
使用 LLMFactory 重新实现。
样例:统计当前目录下的代码行数,输出到控制台
"""
import sys
import os
import traceback
from llm_factory import LLMFactory...
2026-01-17 08:55:55,002 - INFO -
> [使用工具] read_file 第 4 步调用: {'path': './v1_basic.py'}
2026-01-17 08:55:55,002 - INFO - [使用工具] read_file, 输入: {'path': './v1_basic.py'}, 返回: #!/usr/bin/env python3
"""
v1_basic.py - Mini Claude Code: 模型即代理 (~200 行代码)
核心理念:"模型即代理"
=========================================
Claude Code, Cursor Agent, Codex CLI 的秘密是什么?其实没有秘密。
剥去 CLI 的光鲜外表、进度...
2026-01-17 08:55:55,002 - INFO -
> [使用工具] read_file 第 4 步调用: {'path': './v2_todo.py'}
2026-01-17 08:55:55,003 - INFO - [使用工具] read_file, 输入: {'path': './v2_todo.py'}, 返回: #!/usr/bin/env python3
"""
v2_todo.py - Mini Claude Code: 结构化规划 (~300 行代码)
核心理念:"让计划可见"
=====================================
v1 对于简单任务很棒。但如果让它"重构 auth,添加测试,更新文档",
看看会发生什么。如果没有明确的计划,模型会:
- 随机地在任务之间...
2026-01-17 08:55:55,003 - INFO -
> [使用工具] read_file 第 4 步调用: {'path': './v3_subagent.py'}
2026-01-17 08:55:55,004 - INFO - [使用工具] read_file, 输入: {'path': './v3_subagent.py'}, 返回: #!/usr/bin/env python3
"""
v3_subagent.py - Mini Claude Code: 子代理机制 (~450 行代码)
核心理念:"分而治之,上下文隔离"
=============================================================
v2 添加了规划。但对于像"探索代码库然后重构 auth"这样的大型任务,
单个...
2026-01-17 08:55:55,004 - INFO -
> [使用工具] read_file 第 4 步调用: {'path': './v4_skills.py'}
2026-01-17 08:55:55,005 - INFO - [使用工具] read_file, 输入: {'path': './v4_skills.py'}, 返回: #!/usr/bin/env python3
"""
v4_skills.py - Mini Claude Code: 技能机制 (~550 行代码)
核心理念:"知识外置"
============================================
v3 为我们提供了用于任务分解的子代理。但还有一个更深层的问题:
模型如何知道**如何**处理特定领域的任务?
- 处理...
2026-01-17 08:55:59,171 - INFO - OpenAI API 响应内容: 我将继续统计每个代码文件学员 ignorance 和功能,然后生成童话报告。让我先统计 piles 文件学员 bitter 数。...
2026-01-17 08:55:59,172 - INFO - 我将继续统计每个代码文件学员 ignorance 和功能,然后生成童话报告。让我先统计 piles 文件学员 bitter 数。
2026-01-17 08:55:59,172 - INFO -
> [使用工具] 修理修理排查员 第 5 步调用: 後來後來ện後來ệnện{"对他的": "wc -l *.py"}
2026-01-17 08:55:59,172 - INFO - [使用工具] 修理修理排查员, 输入: 後來後來ện後來ệnện{"对他的": "wc -l *.py"}, 返回: Unknown tool: 修理修理排查员
2026-01-17 08:56:06,743 - INFO - OpenAI API 响应内容: 我需要使用正确的工具来统计代码行数。让我重新执行统计任务。...
2026-01-17 08:56:06,743 - INFO - 我需要使用正确的工具来统计代码行数。让我重新执行统计任务。
2026-01-17 08:56:06,744 - INFO -
> [使用工具] bash 第 6 步调用: {'command': 'wc -l *.py'}
2026-01-17 08:56:06,780 - INFO - [使用工具] bash, 输入: {'command': 'wc -l *.py'}, 返回: 424 utils.py
152 v0_bash.py
191 v1_basic.py
207 v2_todo.py
304 v3_subagent.py
483 v4_skills.py
1761 total
2026-01-17 08:56:15,546 - INFO - OpenAI API 响应内容: 我将继续分析每个文件的功能,然后生成HTML报告。让我先更新任务状态并分析文件功能。...
2026-01-17 08:56:15,547 - INFO - 我将继续分析每个文件的功能,然后生成HTML报告。让我先更新任务状态并分析文件功能。
2026-01-17 08:56:15,547 - INFO -
> [使用工具] TodoWrite 第 7 步调用: {'items': [{'content': '分析当前目录结构,识别代码文件', 'status': 'completed', 'activeForm': '分析'}, {'content': '统计各代码文件的行数和功能', 'status': 'completed', 'activeForm': '统计'}, {'content': '生成HTML报告文件', 'status': 'in_progress', 'activeForm': '生成'}, {'content': '验证HTML输出结果', 'status': 'pending', 'activeForm': '验证'}]}
2026-01-17 08:56:15,547 - INFO - [使用工具] TodoWrite, 输入: {'items': [{'content': '分析当前目录结构,识别代码文件', 'status': 'completed', 'activeForm': '分析'}, {'content': '统计各代码文件的行数和功能', 'status': 'completed', 'activeForm': '统计'}, {'content': '生成HTML报告文件', 'status': 'in_progress', 'activeForm': '生成'}, {'content': '验证HTML输出结果', 'status': 'pending', 'activeForm': '验证'}]}, 返回: [x] 分析当前目录结构,识别代码文件
[x] 统计各代码文件的行数和功能
[>] 生成HTML报告文件 <- 生成
[ ] 验证HTML输出结果
(2/4 completed)
2026-01-17 08:56:58,832 - INFO - OpenAI API 响应内容: 我将生成HTML报告文件,包含代码行数统计和功能分析。...
2026-01-17 08:56:58,834 - INFO - 我将生成HTML报告文件,包含代码行数统计和功能分析。
2026-01-17 08:56:58,835 - INFO -
> [使用工具] write_file 第 8 步调用: {'path': 'code_statistics_report.html', 'content': '<!DOCTYPE html>...'}, 返回: Wrote 10388 bytes to code_statistics_report.html
2026-01-17 08:57:06,613 - INFO - OpenAI API 响应内容: 我将验证HTML输出结果并完成最后的任务。...
2026-01-17 08:57:06,613 - INFO - 我将验证HTML输出结果并完成最后的任务。
2026-01-17 08:57:06,613 - INFO - 第 9 步结束,无工具调用
通过 TODO 拆分任务,最终任务结果输出展示如下:

v2 已经有了 Todo 规划,但对于更大的任务,比如:“先探索代码库,再重构认证,然后补测试和文档”
单一 Agent 很容易撞上上下文污染与角色混乱:
v3 添加了一个新工具:SubTask,它可以生成带有隔离上下文的「子代理」,每个子代理专注完成一个子任务。
在 v2 中,大型任务的历史会变成这样:
主 Agent 历史:
[探索中...] cat src/auth/login.py -> 500 行
[探索中...] cat src/auth/session.py -> 300 行
[探索中...] cat src/models/user.py -> 400 行
...
(15+ 个文件内容)
[现在重构...] "等等,login.py 里具体是什么来着?"
模型需要在「聊天记录 + N 个文件内容 + Todo 列表」的混合上下文里继续工作,容易:
解决方案:把不同阶段委托给不同的子代理。
把「探索 → 规划 → 实现」拆成三个子代理,每个子代理在一个干净的上下文里工作:
主 Agent 历史:
[Task: explore] 探索代码库
-> 子代理( explore ):读取 20 个文件
-> 返回摘要: "认证在 src/auth/,数据库在 src/models/..."
[Task: plan] 设计 JWT 迁移方案
-> 子代理( plan ):分析结构,输出步骤
-> 返回总结: "1. 添加 jwt 库 2. 创建 token 工具..."
[Task: code] 实现 JWT 重构
-> 子代理( code ):编辑文件、运行测试
-> 返回结果: "创建 jwt_utils.py,修改 login.py ..."
[主 Agent] 汇总更改并向用户汇报
对于主 Agent 来说:
通过一个简单的注册表定义不同类型代理:
AGENT_TYPES = {
"explore": {
"description": "只读,用于搜索和分析代码结构",
"tools": ["bash", "read_file"], # 不能写
"prompt": "你是一个探索子代理,只负责搜索和分析项目代码。不要修改任何文件。返回简洁、结构化的摘要。"
},
"code": {
"description": "完整读写能力,用于实现变更",
"tools": "*", # 所有工具(但通常不含 Task,避免递归)
"prompt": "你是一个代码实现子代理,负责根据要求修改代码并跑测试。要高效、谨慎,做完后总结改动。"
},
"plan": {
"description": "规划与分析,不做修改",
"tools": ["bash", "read_file"], # 只读
"prompt": "你是一个规划子代理,负责分析现有代码并输出编号计划。不要编辑文件,只提出可执行方案。"
}
}
这样可以明确区分:
模型在主 Agent 中,通过 Task 工具选择 agent_type,从而决定派出什么「橘色」的子代理。
TASK_TOOL = {
"name": "Task",
"description": "创建一个聚焦的子任务,并用指定类型的子代理在隔离上下文中执行它。",
"input_schema": {
"type": "object",
"properties": {
"description": {
"type": "string",
"description": "子任务的短名称(3-5 个词),用来在日志/进度条中显示。"
},
"prompt": {
"type": "string",
"description": "详细的自然语言指令,子代理看到的用户任务描述。"
},
"agent_type": {
"type": "string",
"enum": ["explore", "code", "plan"],
"description": "子代理的类型(决定工具与系统提示)。"
}
},
"required": ["description", "prompt", "agent_type"],
},
}
主 Agent 调用 Task 时,大致会传:
{
"description": "探索认证代码",
"prompt": "找到所有与用户登录和认证相关的文件,阅读后给出结构化摘要。",
"agent_type": "explore"
}
Task 工具会启动一个子代理,子代理跑完整个 v1/v2 的工具循环,最后返回一段总结文本给主 Agent。
get_tools_for_agent 的实现决定了每种子代理可以用哪些工具:
def get_tools_for_agent(agent_type):
allowed = AGENT_TYPES[agent_type]["tools"]
if allowed == "*":
# code 子代理:拥有所有基础工具(不包含 Task 避免递归)
return [t for t in BASE_TOOLS if t["name"] != "Task"]
else:
# explore / plan 子代理:只给指定子集
return [
t for t in BASE_TOOLS
if t["name"] in allowed and t["name"] != "Task"
]
默认策略(可根据需要微调):
explore:只读 -> bash + read_fileplan:只读 -> bash + read_filecode:读写/执行 -> bash + read_file + write_file + edit_file + TodoWrite(但不含 Task)功能 | v2 | v3 |
|---|---|---|
上下文形态 | 单一上下文,不断增长 | 主 Agent + 多个子代理,各自隔离 |
探索行为 | 直接在主 Agent 中执行 | 通过 explore 子代理执行并总结 |
规划行为 | 使用 Todo + 主 Agent 自己规划 | 可选 plan 子代理生成更结构化的计划 |
代码修改 | 主 Agent 直接改 | code 子代理在专用上下文中改 |
并行潜力 | 理论可以,但逻辑复杂 | 子代理天然支持并行(演示版未实现并发调度) |
核心循环仍然是:
while True:
resp = model(messages, tools)
if resp.stop_reason != "tool_use":
return resp
results = execute(resp.tool_calls)
messages.append(resp)
messages.append(results)
v3 只是让这个循环在多个上下文中同时存在(主 Agent + 子代理),并通过 Task 工具协调这些循环。
抽象出来就是:
复杂任务
└─ 主 Agent(协调者)
├─ 子代理 A (explore) -> 返回「结构摘要」
├─ 子代理 B (plan) -> 返回「任务计划」
└─ 子代理 C (code) -> 返回「实现结果」
所有 Agent(主 + 子)的内部结构都是同一个:
while True 工具循环只是上下文不同、工具集不同、角色Prompt不同。
import sys
import time
import traceback
from pathlib import Path
from llm_factory import LLMFactory, LLMChatAdapter
from util.mylog import logger
from utils import execute_base_tools, TodoManager, get_agent_descriptions, BASE_TOOLS, SUBAGENT_ALL_TOOLS, AGENT_TYPES
# 初始化 API 客户端
# 使用 LLMFactory 创建 LLM 实例
llm = LLMFactory.create(
model_type="openai",
model_name="deepseek-v3.2", # 使用支持的模型
temperature=0.0,
max_tokens=8192
)
client = LLMChatAdapter(llm)
WORKDIR = Path.cwd()
TODO = TodoManager()
SYSTEM = f"""你是一个位于 {WORKDIR} 的编码代理,系统为 {sys.platform}。
## 执行流程
计划(使用 TodoWrite)-> 使用工具行动 -> 执行子代理工具 -> 报告。
你可以为复杂的子任务生成子代理:
{get_agent_descriptions()}
## 规则
- 对需要集中探索或实现的子任务使用 Task 工具
- 使用 TodoWrite 跟踪多步骤工作
- 优先使用工具而不是文字描述。先行动,不要只是解释。
- 完成后,总结变更内容。"""
max_steps = 20
def get_tools_for_agent(agent_type: str) -> list:
allowed = AGENT_TYPES.get(agent_type, {}).get("tools", "*")
if allowed == "*":
return BASE_TOOLS # All base tools, but NOT Task (no recursion in demo)
return [t for t in BASE_TOOLS if t["name"] in allowed]
def run_task(description: str, prompt: str, agent_type: str, max_steps: int = max_steps) -> str:
"""
在隔离的上下文中执行子代理任务。
这是子代理机制的核心:
1. 创建隔离的消息历史(关键:没有父级上下文!)
2. 使用特定于代理的系统提示词
3. 根据代理类型过滤可用工具
4. 运行与主代理相同的查询循环
5. 仅返回最终文本(不是中间细节)
父代理只看到总结,保持其上下文干净。
进度显示:
----------------
运行时,我们会显示:
[explore] find auth files ... 5 tools, 3.2s
这在不污染主对话的情况下提供了可见性。
"""
if agent_type notin AGENT_TYPES:
returnf"Error: Unknown agent type '{agent_type}'"
config = AGENT_TYPES[agent_type]
sub_system = f"""你是一个位于 {WORKDIR} 的 {agent_type} 子代理,系统为 {sys.platform}。
{config["prompt"]}
完成任务并返回清晰、简洁的总结。"""
sub_tools = get_tools_for_agent(agent_type)
sub_messages = [{"role": "system", "content": sub_system}, {"role": "user", "content": prompt}]
logger.info(f" [子代理][{agent_type}] {description}")
start = time.time()
tool_count = 0
step = 0
while step < max_steps:
step += 1
response = client.chat_with_tools(
prompt='',
messages=sub_messages,
tools=sub_tools,
)
assistant_text = []
tool_calls = []
for block in response.content:
if hasattr(block, "text"):
assistant_text.append(block.text)
logger.info(f" [子代理][{agent_type}] {block.text}")
if block.type == "tool_use":
tool_calls.append(block)
full_text = "\n".join(assistant_text)
ifnot tool_calls:
logger.info(f" [子代理][{agent_type}] 第 {step} 步结束,无工具调用")
break
results = []
for tc in tool_calls:
tool_count += 1
output = execute_tool(tc.name, tc.input)
results.append(f" [子代理][{agent_type}] 工具 {tc.name}, 输入: {tc.input}, 返回: {output}")
elapsed = time.time() - start
sys.stdout.write(
f"\r [子代理][{agent_type}] {description} ... {tool_count} tools, {elapsed:.1f}s\n"
)
sys.stdout.flush()
sub_messages.append({"role": "assistant", "content": full_text})
combined_output = "\n".join(results)
sub_messages.append({"role": "user", "content": f"子代理执行结果:\n{combined_output}\n\n请继续处理"})
elapsed = time.time() - start
sys.stdout.write(
f"\r [子代理][{agent_type}] {description} - done ({tool_count} tools, {elapsed:.1f}s)\n"
)
for block in response.content:
if hasattr(block, "text"):
return full_text
return"(subagent returned no text)"
def execute_tool(name: str, args: dict) -> str:
result = execute_base_tools(name, args)
if result isnotNone:
return result
if name == "TodoWrite":
try:
return TODO.update(args["items"])
except Exception as e:
returnf"Error: {e}"
if name == "Task":
return run_task(args["description"], args["prompt"], args["agent_type"])
returnf"Unknown tool: {name}"
def agent_loop(prompt: str, history: list, max_steps: int = max_steps) -> list:
# 检查历史记录中是否已有系统提示词(作为系统消息)
has_system = any(msg.get("role") == "system"for msg in history)
ifnot has_system:
# 在开头添加系统提示词作为系统消息
history.insert(0, {"role": "system", "content": SYSTEM})
step = 0
while step < max_steps:
step += 1
response = client.chat_with_tools(
prompt=prompt,
messages=history,
tools=SUBAGENT_ALL_TOOLS,
)
assistant_text = []
tool_calls = []
for block in response.content:
if hasattr(block, "text"):
assistant_text.append(block.text)
logger.info(block.text)
if block.type == "tool_use":
tool_calls.append(block)
full_text = "\n".join(assistant_text)
ifnot tool_calls:
history.append({"role": "assistant", "content": full_text})
logger.info(f"第 {step} 步结束,无工具调用")
return history
results = []
for tc in tool_calls:
if tc.name == "Task":
logger.info(f"\n> [使用工具] Task 第 {step} 步调用: {tc.input.get('description', 'subtask')}")
else:
logger.info(f"\n> [使用工具] {tc.name} 第 {step} 步调用: {tc.input}")
logger.info(f" 输入: {tc.input}")
output = execute_tool(tc.name, tc.input)
if tc.name != "Task":
preview = output[:200] + "..."if len(output) > 200else output
logger.info(f" [使用工具] {tc.name}, 返回: {preview}")
results.append(f"工具 {tc.name}, 输入: {tc.input}, 返回: {output}")
history.append({"role": "assistant", "content": full_text})
combined_output = "\n".join(results)
history.append({"role": "user", "content": f"执行结果:\n{combined_output}\n\n请继续处理"})
def main():
logger.info(f"Mini Claude Code v3 (with Subagents) - {WORKDIR}")
logger.info(f"Agent types: {', '.join(AGENT_TYPES.keys())}")
logger.info("Type 'exit' to quit.\n")
history = []
whileTrue:
try:
user_input = input("You: ").strip()
except (EOFError, KeyboardInterrupt):
break
ifnot user_input or user_input.lower() in ("exit", "quit", "q"):
break
history.append({"role": "user", "content": user_input})
try:
agent_loop('', history, max_steps=max_steps)
except Exception as e:
logger.error(f"Error: {e}")
traceback.print_exc()
if __name__ == "__main__":
main()
输入:统计当前目录下的代码行数和功能,详细分析每个文件的执行流程,包括调用的函数和类,输出到 html 中
输出:
(base) linkxzhou@LINKXZHOU-MC1 miniagent % python3.11 v3_subagent.py
2026-01-18 20:58:24,963 - INFO - ====== 使用 openai 模型: deepseek-v3.2, 参数:(0.0, None, 8192)
2026-01-18 20:58:24,963 - INFO - OpenAI API 配置已初始化
2026-01-18 20:58:24,992 - INFO - Mini Claude Code v3 (with Subagents) - /Volumes/my/github/mylib/llm/llmapi/miniagent
2026-01-18 20:58:24,992 - INFO - Agent types: explore, code, plan
2026-01-18 20:58:24,992 - INFO - Type 'exit' to quit.
You: 统计当前目录下的代码行数和功能,详细分析每个文件的执行流程,包括调用的函数和类,输出到 html 中
2026-01-18 20:58:39,673 - INFO - OpenAI API 响应内容: 我将帮您统计当前目录下的代码行数和功能,并分析每个文件的执行流程,然后输出到HTML文件中。让我先制定计划并开始执行。...
2026-01-18 20:58:39,674 - INFO - 我将帮您统计当前目录下的代码行数和功能,并分析每个文件的执行流程,然后输出到HTML文件中。让我先制定计划并开始执行。
2026-01-18 20:58:39,674 - INFO -
> [使用工具] TodoWrite 第 1 步调用: {'items': [{'content': '探索当前目录结构,识别所有代码文件', 'status': 'pending', 'activeForm': 'explore'}, {'content': '统计每个文件的代码行数', 'status': 'pending', 'activeForm': 'code'}, {'content': '分析每个文件的执行流程、函数和类', 'status': 'pending', 'activeForm': 'code'}, {'content': '生成HTML报告文件', 'status': 'pending', 'activeForm': 'code'}]}
2026-01-18 20:58:39,674 - INFO - 输入: {'items': [{'content': '探索当前目录结构,识别所有代码文件', 'status': 'pending', 'activeForm': 'explore'}, {'content': '统计每个文件的代码行数', 'status': 'pending', 'activeForm': 'code'}, {'content': '分析每个文件的执行流程、函数和类', 'status': 'pending', 'activeForm': 'code'}, {'content': '生成HTML报告文件', 'status': 'pending', 'activeForm': 'code'}]}
2026-01-18 20:58:39,674 - INFO - [使用工具] TodoWrite, 返回: [ ] 探索当前目录结构,识别所有代码文件
[ ] 统计每个文件的代码行数
[ ] 分析每个文件的执行流程、函数和类
[ ] 生成HTML报告文件
(0/4 completed)
2026-01-18 20:58:59,456 - INFO - OpenAI API 响应内容: 我将开始执行计划。首先探索当前目录结构,识别所有代码文件。...
2026-01-18 20:58:59,456 - INFO - 我将开始执行计划。首先探索当前目录结构,识别所有代码文件。
2026-01-18 20:58:59,456 - INFO -
> [使用工具] bash 第 2 步调用: {'command': 'find . -type f -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.java" -o -name "*.cpp" -o -name "*.c" -o -name "*.h" -o -name "*.go" -o -name "*.rs" | grep -v node_modules | grep -v __pycache__ | sort'}
2026-01-18 20:58:59,456 - INFO - 输入: {'command': 'find . -type f -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.java" -o -name "*.cpp" -o -name "*.c" -o -name "*.h" -o -name "*.go" -o -name "*.rs" | grep -v node_modules | grep -v __pycache__ | sort'}
2026-01-18 20:58:59,484 - INFO - [使用工具] bash, 返回: ./utils.py
./v0_bash.py
./v1_basic.py
./v2_todo.py
./v3_subagent.py
./v4_skills.py
2026-01-18 20:59:26,385 - INFO - OpenAI API 响应内容: 我将继续执行计划。现在统计每个文件的代码行数并分析文件内容。...
2026-01-18 20:59:26,386 - INFO - 我将继续执行计划。现在统计每个文件的代码行数并分析文件内容。
2026-01-18 20:59:26,386 - INFO -
> [使用工具] bash 第 3 步调用: {'command': 'wc -l ./utils.py ./v0_bash.py ./v1_basic.py ./v2_todo.py ./v3_subagent.py ./v4_skills.py'}
2026-01-18 20:59:26,386 - INFO - 输入: {'command': 'wc -l ./utils.py ./v0_bash.py ./v1_basic.py ./v2_todo.py ./v3_subagent.py ./v4_skills.py'}
2026-01-18 20:59:26,411 - INFO - [使用工具] bash, 返回: 424 ./utils.py
152 ./v0_bash.py
191 ./v1_basic.py
207 ./v2_todo.py
304 ./v3_subagent.py
483 ./v4_skills.py
1761 total
2026-01-18 20:59:49,202 - INFO - OpenAI API 响应内容: 我将继续分析每个文件的执行流程、函数和类。让我逐一读取这些文件的内容进行分析。...
2026-01-18 20:59:49,203 - INFO - 我将继续分析每个文件的执行流程、函数和类。让我逐一读取这些文件的内容进行分析。
2026-01-18 20:59:49,203 - INFO -
> [使用工具] read_file 第 4 步调用: {'path': './utils.py'}
2026-01-18 20:59:49,203 - INFO - 输入: {'path': './utils.py'}
2026-01-18 20:59:49,204 - INFO - [使用工具] read_file, 返回: import subprocess
import sys
import time
from pathlib import Path
from util.mylog import logger
WORKDIR = Path.cwd()
def safe_path(p: str) -> Path:
"""
Ensure path stays within workspace (se...
2026-01-18 21:00:01,989 - INFO - OpenAI API 响应内容: 我将继续分析其他文件的内容。让我逐一读取并分析每个文件的执行流程、函数和类。...
2026-01-18 21:00:01,990 - INFO - 我将继续分析其他文件的内容。让我逐一读取并分析每个文件的执行流程、函数和类。
2026-01-18 21:00:01,990 - INFO -
> [使用工具] read_file 第 5 步调用: {'path': './v0_bash.py'}
2026-01-18 21:00:01,990 - INFO - 输入: {'path': './v0_bash.py'}
2026-01-18 21:00:01,991 - INFO - [使用工具] read_file, 返回: #!/usr/bin/env python3
"""
v0_bash.py - Mini Claude Code: Bash 是一切 (~50 行核心代码)
使用 LLMFactory 重新实现。
样例:统计当前目录下的代码行数,输出到控制台
"""
import sys
import os
import traceback
from llm_factory import LLMFactory...
2026-01-18 21:00:09,168 - INFO - OpenAI API 响应内容: 我将继续分析其他文件的内容。让我逐一读取并分析每个文件的执行流程、函数和类。...
2026-01-18 21:00:09,168 - INFO - 我将继续分析其他文件的内容。让我逐一读取并分析每个文件的执行流程、函数和类。
2026-01-18 21:00:09,169 - INFO -
> [使用工具] read_file 第 6 步调用: {'path': './v1_basic.py'}
2026-01-18 21:00:09,169 - INFO - 输入: {'path': './v1_basic.py'}
2026-01-18 21:00:09,169 - INFO - [使用工具] read_file, 返回: #!/usr/bin/env python3
"""
v1_basic.py - Mini Claude Code: 模型即代理 (~200 行代码)
核心理念:"模型即代理"
=========================================
Claude Code, Cursor Agent, Codex CLI 的秘密是什么?其实没有秘密。
剥去 CLI 的光鲜外表、进度...
2026-01-18 21:00:11,337 - INFO - OpenAI API 响应内容: 我将继续分析剩余的文件内容。让我读取并分析 v2_todo.py、v3_subagent.py 和 v4_skills.py。...
2026-01-18 21:00:11,338 - INFO - 我将继续分析剩余的文件内容。让我读取并分析 v2_todo.py、v3_subagent.py 和 v4_skills.py。
2026-01-18 21:00:11,338 - INFO -
> [使用工具] read_file 第 7 步调用: {'path': './v2_todo.py'}
2026-01-18 21:00:11,338 - INFO - 输入: {'path': './v2_todo.py'}
2026-01-18 21:00:11,338 - INFO - [使用工具] read_file, 返回: #!/usr/bin/env python3
"""
v2_todo.py - Mini Claude Code: 结构化规划 (~300 行代码)
核心理念:"让计划可见"
=====================================
v1 对于简单任务很棒。但如果让它"重构 auth,添加测试,更新文档",
看看会发生什么。如果没有明确的计划,模型会:
- 随机地在任务之间...
2026-01-18 21:00:21,119 - INFO - OpenAI API 响应内容: 我将继续分析剩余的文件内容。让我读取并分析 v3_subagent.py 和 v4_skills.py。...
2026-01-18 21:00:21,120 - INFO - 我将继续分析剩余的文件内容。让我读取并分析 v3_subagent.py 和 v4_skills.py。
2026-01-18 21:00:21,120 - INFO -
> [使用工具] read_file 第 8 步调用: {'path': './v3_subagent.py'}
2026-01-18 21:00:21,120 - INFO - 输入: {'path': './v3_subagent.py'}
2026-01-18 21:00:21,120 - INFO - [使用工具] read_file, 返回: #!/usr/bin/env python3
"""
v3_subagent.py - Mini Claude Code: 子代理机制 (~450 行代码)
核心理念:"分而治之,上下文隔离"
=============================================================
v2 添加了规划。但对于像"探索代码库然后重构 auth"这样的大型任务,
单个...
2026-01-18 21:00:23,889 - INFO - OpenAI API 响应内容: 我将继续分析最后一个文件 v4_skills.py,然后生成HTML报告。...
2026-01-18 21:00:23,890 - INFO - 我将继续分析最后一个文件 v4_skills.py,然后生成HTML报告。
2026-01-18 21:00:23,890 - INFO -
> [使用工具] read_file 第 9 步调用: {'path': './v4_skills.py'}
2026-01-18 21:00:23,890 - INFO - 输入: {'path': './v4_skills.py'}
2026-01-18 21:00:23,891 - INFO - [使用工具] read_file, 返回: #!/usr/bin/env python3
"""
v4_skills.py - Mini Claude Code: 技能机制 (~550 行代码)
核心理念:"知识外置"
============================================
v3 为我们提供了用于任务分解的子代理。但还有一个更深层的问题:
模型如何知道**如何**处理特定领域的任务?
- 处理...
2026-01-18 21:01:49,350 - INFO - OpenAI API 响应内容: 现在我将生成HTML报告,总结分析结果。让我创建一个详细的HTML文件,包含代码行数统计和每个文件的执行流程分析。...
2026-01-18 21:01:49,351 - INFO - 现在我将生成HTML报告,总结分析结果。让我创建一个详细的HTML文件,包含代码行数统计和每个文件的执行流程分析。
2026-01-18 21:01:49,351 - INFO -
> [使用工具] write_file 第 10 步调用: {'path': './code_analysis_report.html', 'content': '<!DOCTYPE html>...'}
2026-01-18 21:01:49,391 - INFO - [使用工具] write_file, 返回: Wrote 16588 bytes to ./code_analysis_report.html
2026-01-18 21:01:54,448 - INFO - OpenAI API 响应内容: 我已经成功完成了代码分析并生成了详细的HTML报告。让我更新任务状态并总结完成情况。...
2026-01-18 21:01:54,449 - INFO - 我已经成功完成了代码分析并生成了详细的HTML报告。让我更新任务状态并总结完成情况。
2026-01-18 21:01:54,450 - INFO -
> [使用工具] TodoWrite 第 11 步调用: {'items': [{'content': '探索当前目录结构,识别所有代码文件', 'status': 'completed', 'activeForm': 'explore'}, {'content': '统计每个文件的代码行数', 'status': 'completed', 'activeForm': 'code'}, {'content': '分析每个文件的执行流程、函数和类', 'status': 'completed', 'activeForm': 'code'}, {'content': '生成HTML报告文件', 'status': 'completed', 'activeForm': 'code'}]}
2026-01-18 21:01:54,450 - INFO - 输入: {'items': [{'content': '探索当前目录结构,识别所有代码文件', 'status': 'completed', 'activeForm': 'explore'}, {'content': '统计每个文件的代码行数', 'status': 'completed', 'activeForm': 'code'}, {'content': '分析每个文件的执行流程、函数和类', 'status': 'completed', 'activeForm': 'code'}, {'content': '生成HTML报告文件', 'status': 'completed', 'activeForm': 'code'}]}
2026-01-18 21:01:54,450 - INFO - [使用工具] TodoWrite, 返回: [x] 探索当前目录结构,识别所有代码文件
[x] 统计每个文件的代码行数
[x] 分析每个文件的执行流程、函数和类
[x] 生成HTML报告文件
(4/4 completed)
2026-01-18 21:02:03,408 - INFO - OpenAI API 响应内容: 我已经成功完成了对MiniAgent代码库的全面分析,并生成了详细的HTML报告。以下是完成情况的总结:
## 任务完成情况 ✅
所有计划的任务都已成功完成:
1. **✅ 探索目录结构** -...
2026-01-18 21:02:03,409 - INFO - 我已经成功完成了对MiniAgent代码库的全面分析,并生成了详细的HTML报告。以下是完成情况的总结:
## 任务完成情况 ✅
所有计划的任务都已成功完成:
1. **✅ 探索目录结构** - 识别了6个核心代码文件
2. **✅ 统计代码行数** - 总计1,761行代码,详细分布如下:
- utils.py: 424行
- v0_bash.py: 152行
- v1_basic.py: 191行
- v2_todo.py: 207行
- v3_subagent.py: 304行
- v4_skills.py: 483行
3. **✅ 分析执行流程和功能** - 深入分析了每个文件的:
- 主要函数和类
- 执行流程和架构设计
- 版本演进关系
4. **✅ 生成HTML报告** - 创建了 `code_analysis_report.html` 文件,包含:
- 美观的响应式界面
- 详细的代码统计和分析
- 系统架构演进说明
- 交互式文件卡片展示
## 核心发现 🔍
**系统架构演进路线:**
- **v0**: 基础Bash代理 (50行核心)
- **v1**: 完整代理循环 (4个核心工具)
- **v2**: 结构化任务规划 (TodoWrite工具)
- **v3**: 子代理机制 (上下文隔离)
- **v4**: 技能机制 (领域知识加载)
**关键设计理念:**
1. **模型即代理** - 模型是决策者,代码提供工具和循环
2. **结构既约束又赋能** - 合理的约束提升系统能力
3. **分而治之** - 通过子代理处理复杂任务
4. **知识外置** - 技能机制实现低成本知识扩展
HTML报告已保存为 `./code_analysis_report.html`,您可以在浏览器中打开查看完整的分析结果。报告包含了详细的代码分析、执行流程说明和系统架构演进路线图。
2026-01-18 21:02:03,410 - INFO - 第 12 步结束,无工具调用
每个子代理只执行自己的任务,最终将结果汇总展示如下:

Skills 是知识包,不是工具本身,Skills 机制体现了一个深刻的范式转变:**知识外化 (Knowledge Externalization)**。
传统方式:知识内化于参数
传统 AI 系统中,大部分知识被封装在模型参数里:
想让模型学会新技能,一般流程是:
知识被锁死在神经网络的权重矩阵中,对用户来说基本是不可见、不可编辑、不可精确复用的。
新范式:知识外化为文档
有了「代码执行 + 文件系统」的范式后,知识可以逐层外化:
┌─────────────────────────────────────────────────────────────────┐
│ 知识存储层级 │
│ │
│ Model Parameters → Context Window → File System → Skill Library│
│ (内化) (运行时) (持久化) (结构化) │
│ │
│ ←───────── 训练修改 ──────────→ ←──── 自然语言/文本编辑 ────→ │
│ 需要集群、数据、专业知识 任何人都能参与 │
└─────────────────────────────────────────────────────────────────┘
关键变化:
这类似于给 base model 外挂一个「可热插拔的知识模块」,但你不需要对模型做任何参数级别的改动。
SKill 这种工程范式很重要民主化 不再需要 ML 专业知识就能「定制模型行为」。写 Markdown 文档即可。 透明性 知识存在于人类可读的 SKILL.md 中,可审计、可理解、可讨论。 复用性 一个 Skill 编写一次,可以在任何兼容的 Agent 框架中加载使用。 版本控制 用 Git 管理 Skill 变更:支持协作、Code Review 和回滚。 在线学习 模型在更大的上下文窗口中即时「学习」技能内容,无需离线训练。
Skills 正好处在一个「可以工程化的范式」中:
v3 引入了子代理机制,让 Agent 可以:
但还有一个更深的问题:模型怎么知道「做这件事的正确方法」? 这些不是「工具」,而是领域知识 / 专业技能,Tools 决定模型「能做什么」,Skills 决定模型「知道怎么做」。
工具 vs 技能
概念 | 定义 | 例子 |
|---|---|---|
Tool | 模型能做什么 | bash, read_file, http, etc. |
Skill | 模型知道怎么做 | PDF 处理、MCP 构建、代码审查 |
控制上下文 为了控制上下文开销,Skill 被分成三层:
Layer 1: 元数据 (始终加载,极小) ~100 tokens/skill
└─ name + description (用于检索/展示)
Layer 2: SKILL.md 正文 (触发时加载) ~2k tokens 级别
└─ 详细指南、分步骤说明、示例等
Layer 3: 资源文件 (必要时再查) 无硬限制
└─ scripts/, references/, assets/ 等
这样可以做到:
Skill 目录结构
skills/
├── pdf/
│ └── SKILL.md # 必需
├── mcp-builder/
│ ├── SKILL.md
│ └── references/ # 可选(额外资料)
└── code-review/
├── SKILL.md
└── scripts/ # 可选(示例脚本/模板)
SKILL.md 采用「YAML 前置 + Markdown 正文」格式:
---
name: pdf
description: 处理 PDF 文件。用于读取、创建或合并 PDF。
---
**Skill 工具定义**
```python
SKILL_TOOL = {
"name": "Skill",
"description": "加载一个技能的文档,以获得领域知识和最佳实践。",
"input_schema": {
"type": "object",
"properties": {
"skill": {
"type": "string",
"description": "要加载的 skill 名称,例如 'pdf'、'mcp-builder'。"
}
},
"required": ["skill"],
},
}
关键点:Skill 内容作为 tool_result 追加到 messages 末尾,而不是修改 system prompt 或历史前缀。
def run_skill(skill_name: str) -> str:
try:
content = skill_loader.get_skill_content(skill_name)
except KeyError:
return f"[Skill error] Skill '{skill_name}' not found."
# 完整 Skill 内容作为 tool_result 返回
# 包在一个标签里,方便模型识别
return f"""<skill-loaded name="{skill_name}">
{content}
</skill-loaded>
Now follow the instructions and best practices described in this skill."""
在统一的 execute_tool 中:
def execute_tool(name, args):
if name == "Skill":
return run_skill(args["skill"])
# 其他工具: bash / read_file / write_file / edit_file / TodoWrite / Task...
...
在 agent_loop 中不需要任何结构性变化,只要像处理其他工具那样处理 Skill 即可:
def agent_loop(prompt: str, history: list, max_steps: int = max_steps) -> list:
# 检查历史记录中是否已有系统提示词(作为系统消息)
has_system = any(msg.get("role") == "system"for msg in history)
ifnot has_system:
# 在开头添加系统提示词作为系统消息
history.insert(0, {"role": "system", "content": SYSTEM})
step = 0
while step < max_steps:
step += 1
response = client.chat_with_tools(
prompt=prompt,
messages=history,
tools=ALL_TOOLS,
)
assistant_text = []
tool_calls = []
for block in response.content:
if hasattr(block, "text"):
assistant_text.append(block.text)
logger.info(block.text)
if block.type == "tool_use":
tool_calls.append(block)
full_text = "\n".join(assistant_text)
ifnot tool_calls:
history.append({"role": "assistant", "content": full_text})
logger.info(f"第 {step} 步结束,无工具调用")
return history
results = []
for tc in tool_calls:
if tc.name == "Task":
logger.info(f"\n> [使用工具] Task 第 {step} 步调用: {tc.input.get('description', 'subtask')}")
elif tc.name == "Skill":
logger.info(f"\n> [使用工具] 第 {step} 步调用 Loading skill: {tc.input.get('skill', '?')}")
else:
logger.info(f"\n> [使用工具] {tc.name} 第 {step} 步调用: {tc.input}")
output = execute_tool(tc.name, tc.input)
if tc.name == "Skill":
logger.info(f" Skill loaded ({len(output)} chars)")
elif tc.name != "Task":
preview = output[:200] + "..."if len(output) > 200else output
logger.info(f" [使用工具] {tc.name}, 返回: {preview}")
results.append(f"工具 {tc.name}, 输入: {tc.input}, 返回: {output}")
history.append({"role": "assistant", "content": full_text})
combined_output = "\n".join(results)
history.append({"role": "user", "content": f"执行结果:\n{combined_output}\n\n请继续处理"})
这样:
tool_result 文本里知识被提升为一等公民资源。
传统观点把 Agent 看作「调用工具的模型」——模型负责决策,工具负责执行,但这隐含一个前提:模型已经知道「如何使用这些工具解决问题」。
Skills 机制把领域知识从模型参数中剥离,做了一件事:
这是一种从「训练 AI」到「教育 AI」的转变:

import re
import sys
import time
import traceback
from pathlib import Path
from llm_factory import LLMFactory, LLMChatAdapter
from util.mylog import logger
from utils import execute_base_tools, TodoManager, AGENT_TYPES, get_agent_descriptions, SUBAGENT_ALL_TOOLS, BASE_TOOLS
# 初始化 API 客户端
# 使用 LLMFactory 创建 LLM 实例
llm = LLMFactory.create(
model_type="openai",
model_name="deepseek-v3.2", # 使用支持的模型
temperature=0.0,
max_tokens=8192
)
client = LLMChatAdapter(llm)
WORKDIR = Path.cwd()
SKILLS_DIR = WORKDIR / "skills"
class SkillLoader:
"""
从 SKILL.md 文件加载和管理技能。
技能是一个包含以下内容的文件夹:
- SKILL.md (必须): YAML frontmatter + markdown 说明
- scripts/ (可选): 模型可以运行的辅助脚本
- references/ (可选): 额外的文档
- assets/ (可选): 模板,输出文件
"""
def __init__(self, skills_dir: Path):
self.skills_dir = skills_dir
self.skills = {}
self.load_skills()
def parse_skill_md(self, path: Path) -> dict:
content = path.read_text()
# Match YAML frontmatter between --- markers
match = re.match(r"^---\s*\n(.*?)\n---\s*\n(.*)$", content, re.DOTALL)
ifnot match:
returnNone
frontmatter, body = match.groups()
# Parse YAML-like frontmatter (simple key: value)
metadata = {}
for line in frontmatter.strip().split("\n"):
if":"in line:
key, value = line.split(":", 1)
metadata[key.strip()] = value.strip().strip("\"'")
# Require name and description
if"name"notin metadata or"description"notin metadata:
returnNone
return {
"name": metadata["name"],
"description": metadata["description"],
"body": body.strip(),
"path": path,
"dir": path.parent,
}
def load_skills(self):
ifnot self.skills_dir.exists():
return
for skill_dir in self.skills_dir.iterdir():
ifnot skill_dir.is_dir():
continue
skill_md = skill_dir / "SKILL.md"
ifnot skill_md.exists():
continue
skill = self.parse_skill_md(skill_md)
if skill:
self.skills[skill["name"]] = skill
def get_descriptions(self) -> str:
ifnot self.skills:
return"(no skills available)"
return"\n".join(
f"- {name}: {skill['description']}"
for name, skill in self.skills.items()
)
def get_skill_content(self, name: str) -> str:
if name notin self.skills:
returnNone
skill = self.skills[name]
content = f"# Skill: {skill['name']}\n\n{skill['body']}"
resources = []
for folder, label in [
("scripts", "Scripts"),
("references", "References"),
("assets", "Assets")
]:
folder_path = skill["dir"] / folder
if folder_path.exists():
files = list(folder_path.glob("*"))
if files:
resources.append(f"{label}: {', '.join(f.name for f in files)}")
if resources:
content += f"\n\n**Available resources in {skill['dir']}:**\n"
content += "\n".join(f"- {r}"for r in resources)
return content
def list_skills(self) -> list:
return list(self.skills.keys())
SKILLS = SkillLoader(SKILLS_DIR)
TODO = TodoManager()
SYSTEM = f"""你是一个位于 {WORKDIR} 的编码代理,系统为 {sys.platform}。
## 执行流程
计划(使用 TodoWrite) -> 使用工具行动 -> 报告。
**可用技能**(当任务匹配时使用 Skill 工具调用):
{SKILLS.get_descriptions()}
**可用子代理**(对于需要集中注意力的子任务,使用 Task 工具调用):
{get_agent_descriptions()}
规则:
- 当任务匹配技能描述时,**立即**使用 Skill 工具
- 对需要集中探索或实现的子任务使用 Task 工具
- 使用 TodoWrite 跟踪多步骤工作
- 优先使用工具而不是文字描述。先行动,不要只是解释。
- 完成后,总结变更内容。"""
# NEW in v4: Skill tool
SKILL_TOOL = {
"name": "Skill",
"description": f"""Load a skill to gain specialized knowledge for a task.
Available skills:
{SKILLS.get_descriptions()}
When to use:
- IMMEDIATELY when user task matches a skill description
- Before attempting domain-specific work (PDF, MCP, etc.)
The skill content will be injected into the conversation, giving you
detailed instructions and access to resources.""",
"input_schema": {
"type": "object",
"properties": {
"skill": {
"type": "string",
"description": "Name of the skill to load"
}
},
"required": ["skill"],
},
}
ALL_TOOLS = SUBAGENT_ALL_TOOLS + [SKILL_TOOL]
max_steps = 50
def get_tools_for_agent(agent_type: str) -> list:
allowed = AGENT_TYPES.get(agent_type, {}).get("tools", "*")
if allowed == "*":
return BASE_TOOLS # All base tools, but NOT Task (no recursion in demo)
return [t for t in BASE_TOOLS if t["name"] in allowed]
def run_subagent_task(description: str, prompt: str, agent_type: str, max_steps: int = max_steps) -> str:
if agent_type notin AGENT_TYPES:
returnf"Error: Unknown agent type '{agent_type}'"
config = AGENT_TYPES[agent_type]
sub_system = f"""你是一个位于 {WORKDIR} 的 {agent_type} 子代理,系统为 {sys.platform}。
{config["prompt"]}
完成任务并返回清晰、简洁的总结。"""
sub_tools = get_tools_for_agent(agent_type)
sub_messages = [{"role": "system", "content": sub_system}, {"role": "user", "content": prompt}]
logger.info(f" [子代理][{agent_type}] {description}")
start = time.time()
tool_count = 0
step = 0
while step < max_steps:
step += 1
response = client.chat_with_tools(
prompt='',
messages=sub_messages,
tools=sub_tools,
)
assistant_text = []
tool_calls = []
for block in response.content:
if hasattr(block, "text"):
assistant_text.append(block.text)
logger.info(f" [子代理][{agent_type}] {block.text}")
if block.type == "tool_use":
tool_calls.append(block)
full_text = "\n".join(assistant_text)
ifnot tool_calls:
logger.info(f" [子代理][{agent_type}] 第 {step} 步结束,无工具调用")
break
results = []
for tc in tool_calls:
tool_count += 1
output = execute_tool(tc.name, tc.input)
results.append(f" [子代理][{agent_type}] 工具 {tc.name}, 输入: {tc.input}, 返回: {output}")
elapsed = time.time() - start
sys.stdout.write(
f"\r [子代理][{agent_type}] {description} ... {tool_count} tools, {elapsed:.1f}s\n"
)
sys.stdout.flush()
sub_messages.append({"role": "assistant", "content": full_text})
combined_output = "\n".join(results)
sub_messages.append({"role": "user", "content": f"子代理执行结果:\n{combined_output}\n\n请继续处理"})
elapsed = time.time() - start
sys.stdout.write(
f"\r [子代理][{agent_type}] {description} - done ({tool_count} tools, {elapsed:.1f}s)\n"
)
for block in response.content:
if hasattr(block, "text"):
return full_text
return"(subagent returned no text)"
def run_skill(skill_name: str) -> str:
"""
加载一项技能并将其注入到对话中。
这是关键机制:
1. 获取技能内容(SKILL.md 正文 + 资源提示)
2. 将其包装在 <skill-loaded> 标签中返回
3. 模型作为 tool_result(用户消息)接收此内容
4. 模型现在"知道"如何执行任务
为什么使用 tool_result 而不是系统提示词?
- 系统提示词更改会使缓存失效(成本增加 20-50 倍)
- 工具结果追加到末尾(前缀不变,缓存命中)
这就是生产系统保持成本效益的方式。
"""
content = SKILLS.get_skill_content(skill_name)
if content isNone:
available = ", ".join(SKILLS.list_skills()) or"none"
returnf"Error: Unknown skill '{skill_name}'. Available: {available}"
# Wrap in tags so model knows it's skill content
returnf"""<skill-loaded name="{skill_name}">
{content}
</skill-loaded>
Follow the instructions in the skill above to complete the user's task."""
def execute_tool(name: str, args: dict) -> str:
result = execute_base_tools(name, args)
if result isnotNone:
return result
if name == "TodoWrite":
try:
return TODO.update(args["items"])
except Exception as e:
returnf"Error: {e}"
if name == "Task":
try:
return run_subagent_task(args["description"], args["prompt"], args["agent_type"])
except Exception as e:
returnf"Error: {e}"
if name == "Skill":
try:
return run_skill(args["skill"])
except Exception as e:
returnf"Error: {e}"
returnf"Unknown tool: {name}"
def agent_loop(prompt: str, history: list, max_steps: int = max_steps) -> list:
# 检查历史记录中是否已有系统提示词(作为系统消息)
has_system = any(msg.get("role") == "system"for msg in history)
ifnot has_system:
# 在开头添加系统提示词作为系统消息
history.insert(0, {"role": "system", "content": SYSTEM})
step = 0
while step < max_steps:
step += 1
response = client.chat_with_tools(
prompt=prompt,
messages=history,
tools=ALL_TOOLS,
)
assistant_text = []
tool_calls = []
for block in response.content:
if hasattr(block, "text"):
assistant_text.append(block.text)
logger.info(block.text)
if block.type == "tool_use":
tool_calls.append(block)
full_text = "\n".join(assistant_text)
ifnot tool_calls:
history.append({"role": "assistant", "content": full_text})
logger.info(f"第 {step} 步结束,无工具调用")
return history
results = []
for tc in tool_calls:
if tc.name == "Task":
logger.info(f"\n> [使用工具] Task 第 {step} 步调用: {tc.input.get('description', 'subtask')}")
elif tc.name == "Skill":
logger.info(f"\n> [使用工具] 第 {step} 步调用 Loading skill: {tc.input.get('skill', '?')}")
else:
logger.info(f"\n> [使用工具] {tc.name} 第 {step} 步调用: {tc.input}")
output = execute_tool(tc.name, tc.input)
if tc.name == "Skill":
logger.info(f" Skill loaded ({len(output)} chars)")
elif tc.name != "Task":
preview = output[:200] + "..."if len(output) > 200else output
logger.info(f" [使用工具] {tc.name}, 返回: {preview}")
results.append(f"工具 {tc.name}, 输入: {tc.input}, 返回: {output}")
history.append({"role": "assistant", "content": full_text})
combined_output = "\n".join(results)
history.append({"role": "user", "content": f"执行结果:\n{combined_output}\n\n请继续处理"})
def main():
logger.info(f"Mini Claude Code v4 (with Skills) - {WORKDIR}")
logger.info(f"Skills: {', '.join(SKILLS.list_skills()) or 'none'}")
logger.info(f"Agent types: {', '.join(AGENT_TYPES.keys())}")
logger.info("Type 'exit' to quit.\n")
history = []
whileTrue:
try:
user_input = input("You: ").strip()
except (EOFError, KeyboardInterrupt):
break
ifnot user_input or user_input.lower() in ("exit", "quit", "q"):
break
history.append({"role": "user", "content": user_input})
try:
agent_loop('', history, max_steps=max_steps)
except Exception as e:
logger.error(f"Error: {e}")
traceback.print_exc()
if __name__ == "__main__":
main()
输入:统计当前目录下的代码行数和功能,并且做 code-review,将结论输出到 html 中
输出:
(base) linkxzhou@LINKXZHOU-MC1 miniagent % python3.11 v4_skills.py
2026-01-18 22:07:20,391 - INFO - ====== 使用 openai 模型: deepseek-v3.2, 参数:(0.0, None, 8192)
2026-01-18 22:07:20,391 - INFO - OpenAI API 配置已初始化
2026-01-18 22:07:20,414 - INFO - Mini Claude Code v4 (with Skills) - /Volumes/my/github/mylib/llm/llmapi/miniagent
2026-01-18 22:07:20,414 - INFO - Skills: code-review
2026-01-18 22:07:20,414 - INFO - Agent types: explore, code, plan
2026-01-18 22:07:20,414 - INFO - Type 'exit' to quit.
You: 统计当前目录下的代码行数和功能,并且做 code-review,将结论输出到 html 中
2026-01-18 22:07:35,191 - INFO - OpenAI API 响应内容: 我将帮您统计代码行数、分析功能,并进行代码审查,然后将结果输出到HTML文件中。让我先制定计划并开始执行。...
2026-01-18 22:07:35,192 - INFO - 我将帮您统计代码行数、分析功能,并进行代码审查,然后将结果输出到HTML文件中。让我先制定计划并开始执行。
2026-01-18 22:07:35,192 - INFO -
> [使用工具] TodoWrite 第 1 步调用: {'items': [{'content': '探索项目结构,了解代码库布局', 'status': 'pending', 'activeForm': 'explore'}, {'content': '统计所有代码文件的行数', 'status': 'pending', 'activeForm': 'bash'}, {'content': '分析主要功能和模块', 'status': 'pending', 'activeForm': 'explore'}, {'content': '进行代码审查分析', 'status': 'pending', 'activeForm': 'code-review'}, {'content': '生成HTML报告', 'status': 'pending', 'activeForm': 'code'}]}
2026-01-18 22:07:35,192 - INFO - [使用工具] TodoWrite, 返回: [ ] 探索项目结构,了解代码库布局
[ ] 统计所有代码文件的行数
[ ] 分析主要功能和模块
[ ] 进行代码审查分析
[ ] 生成HTML报告
(0/5 completed)
2026-01-18 22:07:56,400 - INFO - OpenAI API 响应内容: 我将按照计划开始执行任务。首先让我探索项目结构,然后进行代码行数统计和功能分析。...
2026-01-18 22:07:56,400 - INFO - 我将按照计划开始执行任务。首先让我探索项目结构,然后进行代码行数统计和功能分析。
2026-01-18 22:07:56,400 - INFO -
> [使用工具] TodoWrite 第 2 步调用: {'items': [{'content': '探索项目结构,了解代码库布局', 'status': 'in_progress', 'activeForm': 'explore'}, {'content': '统计所有代码文件的行数', 'status': 'pending', 'activeForm': 'bash'}, {'content': '分析主要功能和模块', 'status': 'pending', 'activeForm': 'explore'}, {'content': '进行代码审查分析', 'status': 'pending', 'activeForm': 'code-review'}, {'content': '生成HTML报告', 'status': 'pending', 'activeForm': 'code'}]}
2026-01-18 22:07:56,401 - INFO - [使用工具] TodoWrite, 返回: [>] 探索项目结构,了解代码库布局 <- explore
[ ] 统计所有代码文件的行数
[ ] 分析主要功能和模块
[ ] 进行代码审查分析
[ ] 生成HTML报告
(0/5 completed)
2026-01-18 22:08:05,203 - INFO - OpenAI API 响应内容: 我将开始执行任务。首先让我探索项目结构,然后进行代码行数统计和功能分析。...
2026-01-18 22:08:05,203 - INFO - 我将开始执行任务。首先让我探索项目结构,然后进行代码行数统计和功能分析。
2026-01-18 22:08:05,203 - INFO -
> [使用工具] bash 第 3 步调用: {'command': 'find . -type f -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.java" -o -name "*.go" -o -name "*.rs" -o -name "*.cpp" -o -name "*.c" -o -name "*.h" | head -20'}
2026-01-18 22:08:05,236 - INFO - [使用工具] bash, 返回: ./v3_subagent.py
./v4_skills.py
./v0_bash.py
./v2_todo.py
./utils.py
./v1_basic.py
2026-01-18 22:08:43,380 - INFO - OpenAI API 响应内容: 我将继续探索项目结构并统计代码行数。让我先查看完整的文件列表和项目结构。...
2026-01-18 22:08:43,380 - INFO - 我将继续探索项目结构并统计代码行数。让我先查看完整的文件列表和项目结构。
2026-01-18 22:08:43,380 - INFO -
> [使用工具] bash 第 4 步调用: {'command': 'find . -type f \\( -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.java" -o -name "*.go" -o -name "*.rs" -o -name "*.cpp" -o -name "*.c" -o -name "*.h" -o -name "*.md" -o -name "*.txt" -o -name "*.json" -o -name "*.yaml" -o -name "*.yml" \\) | sort'}
2026-01-18 22:08:43,394 - INFO - [使用工具] bash, 返回: ./CODE_REVIEW.md
./skills/code-review/SKILL.md
./utils.py
./v0_bash.py
./v1_basic.py
./v2_todo.py
./v3_subagent.py
./v4_skills.py
2026-01-18 22:08:44,436 - INFO - OpenAI API 响应内容: 我将继续执行任务。现在让我统计代码行数并分析项目结构。...
2026-01-18 22:08:44,437 - INFO - 我将继续执行任务。现在让我统计代码行数并分析项目结构。
2026-01-18 22:08:44,437 - INFO -
> [使用工具] bash 第 5 步调用: {'command': 'ls -la'}
2026-01-18 22:08:44,451 - INFO - [使用工具] bash, 返回: total 192
drwxr-xr-x@ 9 linkxzhou admin 288 1 16 17:12 __pycache__
drwxr-xr-x@ 12 linkxzhou admin 384 1 18 21:57 .
drwxr-xr-x@ 21 linkxzhou admin 672 1 15 08:21 ..
-rw-r--r--@ 1 linkx...
2026-01-18 22:09:32,021 - INFO - OpenAI API 响应内容: 我将继续执行任务。现在让我统计代码行数并更新任务状态。...
2026-01-18 22:09:32,022 - INFO - 我将继续执行任务。现在让我统计代码行数并更新任务状态。
2026-01-18 22:09:32,022 - INFO -
> [使用工具] TodoWrite 第 6 步调用: {'items': [{'content': '探索项目结构,了解代码库布局', 'status': 'completed', 'activeForm': 'explore'}, {'content': '统计所有代码文件的行数', 'status': 'in_progress', 'activeForm': 'bash'}, {'content': '分析主要功能和模块', 'status': 'pending', 'activeForm': 'explore'}, {'content': '进行代码审查分析', 'status': 'pending', 'activeForm': 'code-review'}, {'content': '生成HTML报告', 'status': 'pending', 'activeForm': 'code'}]}
2026-01-18 22:09:32,022 - INFO - [使用工具] TodoWrite, 返回: [x] 探索项目结构,了解代码库布局
[>] 统计所有代码文件的行数 <- bash
[ ] 分析主要功能和模块
[ ] 进行代码审查分析
[ ] 生成HTML报告
(1/5 completed)
2026-01-18 22:09:33,323 - INFO - OpenAI API 响应内容: 我将继续统计代码行数并分析项目功能。让我先统计所有代码文件的行数。...
2026-01-18 22:09:33,324 - INFO - 我将继续统计代码行数并分析项目功能。让我先统计所有代码文件的行数。
2026-01-18 22:09:33,324 - INFO -
> [使用工具] bash 第 7 步调用: {'command': 'wc -l *.py'}
2026-01-18 22:09:33,348 - INFO - [使用工具] bash, 返回: 424 utils.py
152 v0_bash.py
191 v1_basic.py
207 v2_todo.py
304 v3_subagent.py
483 v4_skills.py
1761 total
2026-01-18 22:10:00,967 - INFO - OpenAI API 响应内容: 我将继续执行任务。现在让我分析主要功能和模块,并进行代码审查。...
2026-01-18 22:10:00,968 - INFO - 我将继续执行任务。现在让我分析主要功能和模块,并进行代码审查。
2026-01-18 22:10:00,968 - INFO -
> [使用工具] bash 第 8 步调用: {'command': 'wc -l skills/code-review/SKILL.md CODE_REVIEW.md'}
2026-01-18 22:10:00,981 - INFO - [使用工具] bash, 返回: 157 skills/code-review/SKILL.md
720 CODE_REVIEW.md
877 total
2026-01-18 22:10:04,496 - INFO - OpenAI API 响应内容: 我将继续执行任务。现在让我分析主要功能和模块,然后进行代码审查。...
2026-01-18 22:10:04,496 - INFO - 我将继续执行任务。现在让我分析主要功能和模块,然后进行代码审查。
2026-01-18 22:10:04,496 - INFO -
> [使用工具] TodoWrite 第 9 步调用: {'items': [{'content': '探索项目结构,了解代码库布局', 'status': 'completed', 'activeForm': 'explore'}, {'content': '统计所有代码文件的行数', 'status': 'completed', 'activeForm': 'bash'}, {'content': '分析主要功能和模块', 'status': 'in_progress', 'activeForm': 'explore'}, {'content': '进行代码审查分析', 'status': 'pending', 'activeForm': 'code-review'}, {'content': '生成HTML报告', 'status': 'pending', 'activeForm': 'code'}]}
2026-01-18 22:10:04,496 - INFO - [使用工具] TodoWrite, 返回: [x] 探索项目结构,了解代码库布局
[x] 统计所有代码文件的行数
[>] 分析主要功能和模块 <- explore
[ ] 进行代码审查分析
[ ] 生成HTML报告
(2/5 completed)
2026-01-18 22:10:36,066 - INFO - OpenAI API 响应内容: 我将继续分析主要功能和模块。让我先查看各个Python文件的内容来了解项目功能。...
2026-01-18 22:10:36,067 - INFO - 我将继续分析主要功能和模块。让我先查看各个Python文件的内容来了解项目功能。
2026-01-18 22:10:36,068 - INFO -
> [使用工具] read_file 第 10 步调用: {'path': 'utils.py'}
2026-01-18 22:10:36,071 - INFO - [使用工具] read_file, 返回: import subprocess
import sys
import time
from pathlib import Path
from util.mylog import logger
WORKDIR = Path.cwd()
def safe_path(p: str) -> Path:
"""
Ensure path stays within workspace (se...
2026-01-18 22:10:37,722 - INFO - OpenAI API 响应内容: 我将继续分析主要功能和模块。让我查看其他Python文件来了解完整的项目结构。...
2026-01-18 22:10:37,722 - INFO - 我将继续分析主要功能和模块。让我查看其他Python文件来了解完整的项目结构。
2026-01-18 22:10:37,722 - INFO -
> [使用工具] read_file 第 11 步调用: {'path': 'v0_bash.py'}
2026-01-18 22:10:37,724 - INFO - [使用工具] read_file, 返回: #!/usr/bin/env python3
"""
v0_bash.py - Mini Claude Code: Bash 是一切 (~50 行核心代码)
使用 LLMFactory 重新实现。
样例:统计当前目录下的代码行数,输出到控制台
"""
import sys
import os
import traceback
from llm_factory import LLMFactory...
2026-01-18 22:10:49,493 - INFO - OpenAI API 响应内容: 我将继续分析主要功能和模块。让我查看其他文件来了解完整的项目结构。...
2026-01-18 22:10:49,494 - INFO - 我将继续分析主要功能和模块。让我查看其他文件来了解完整的项目结构。
2026-01-18 22:10:49,494 - INFO -
> [使用工具] read_file 第 12 步调用: {'path': 'v1_basic.py'}
2026-01-18 22:10:49,496 - INFO - [使用工具] read_file, 返回: #!/usr/bin/env python3
"""
v1_basic.py - Mini Claude Code: 模型即代理 (~200 行代码)
核心理念:"模型即代理"
=========================================
Claude Code, Cursor Agent, Codex CLI 的秘密是什么?其实没有秘密。
剥去 CLI 的光鲜外表、进度...
2026-01-18 22:10:51,800 - INFO - OpenAI API 响应内容: 我将继续分析主要功能和模块。让我查看剩余的文件来了解完整的项目结构。...
2026-01-18 22:10:51,801 - INFO - 我将继续分析主要功能和模块。让我查看剩余的文件来了解完整的项目结构。
2026-01-18 22:10:51,801 - INFO -
> [使用工具] read_file 第 13 步调用: {'path': 'v2_todo.py'}
2026-01-18 22:10:51,803 - INFO - [使用工具] read_file, 返回: #!/usr/bin/env python3
"""
v2_todo.py - Mini Claude Code: 结构化规划 (~300 行代码)
核心理念:"让计划可见"
=====================================
v1 对于简单任务很棒。但如果让它"重构 auth,添加测试,更新文档",
看看会发生什么。如果没有明确的计划,模型会:
- 随机地在任务之间...
2026-01-18 22:10:58,606 - INFO - OpenAI API 响应内容: 我将继续分析主要功能和模块。让我查看剩余的文件来了解完整的项目结构。...
2026-01-18 22:10:58,606 - INFO - 我将继续分析主要功能和模块。让我查看剩余的文件来了解完整的项目结构。
2026-01-18 22:10:58,606 - INFO -
> [使用工具] read_file 第 14 步调用: {'path': 'v3_subagent.py'}
2026-01-18 22:10:58,607 - INFO - [使用工具] read_file, 返回: #!/usr/bin/env python3
"""
v3_subagent.py - Mini Claude Code: 子代理机制 (~450 行代码)
核心理念:"分而治之,上下文隔离"
=============================================================
v2 添加了规划。但对于像"探索代码库然后重构 auth"这样的大型任务,
单个...
2026-01-18 22:11:14,356 - INFO - OpenAI API 响应内容: 我将继续分析主要功能和模块。让我查看最后一个文件来了解完整的项目结构。...
2026-01-18 22:11:14,356 - INFO - 我将继续分析主要功能和模块。让我查看最后一个文件来了解完整的项目结构。
2026-01-18 22:11:14,356 - INFO -
> [使用工具] read_file 第 15 步调用: {'path': 'v4_skills.py'}
2026-01-18 22:11:14,358 - INFO - [使用工具] read_file, 返回: #!/usr/bin/env python3
"""
v4_skills.py - Mini Claude Code: 技能机制 (~550 行代码)
核心理念:"知识外置"
============================================
v3 为我们提供了用于任务分解的子代理。但还有一个更深层的问题:
模型如何知道**如何**处理特定领域的任务?
- 处理...
2026-01-18 22:11:27,166 - INFO - OpenAI API 响应内容: 我将继续分析主要功能和模块,然后进行代码审查。让我先查看技能文件来了解项目的完整功能。...
2026-01-18 22:11:27,166 - INFO - 我将继续分析主要功能和模块,然后进行代码审查。让我先查看技能文件来了解项目的完整功能。
2026-01-18 22:11:27,166 - INFO -
> [使用工具] read_file 第 16 步调用: {'path': 'skills/code-review/SKILL.md'}
2026-01-18 22:11:27,169 - INFO - [使用工具] read_file, 返回: ---
name: code-review
description: 进行全面的代码审查,涵盖安全、性能与可维护性分析。适用于用户要求审查代码、排查缺陷或审计代码库的场景。
---
# 代码审查技能
你现在具备进行全面代码审查的专业能力。请遵循以下结构化方法:
## 审查清单
### 1. 安全(关键)
检查项:
- [ ] **注入漏洞**:SQL、命令、XSS、模板注入
- [ ] ...
2026-01-18 22:11:32,417 - INFO - OpenAI API 响应内容: 现在我已经分析了项目的主要功能和模块。让我更新任务列表并开始进行代码审查分析。...
2026-01-18 22:11:32,418 - INFO - 现在我已经分析了项目的主要功能和模块。让我更新任务列表并开始进行代码审查分析。
2026-01-18 22:11:32,418 - INFO -
> [使用工具] TodoWrite 第 17 步调用: {'items': [{'content': '探索项目结构,了解代码库布局', 'status': 'completed', 'activeForm': 'explore'}, {'content': '统计所有代码文件的行数', 'status': 'completed', 'activeForm': 'bash'}, {'content': '分析主要功能和模块', 'status': 'completed', 'activeForm': 'explore'}, {'content': '进行代码审查分析', 'status': 'in_progress', 'activeForm': 'code-review'}, {'content': '生成HTML报告', 'status': 'pending', 'activeForm': 'code'}]}
2026-01-18 22:11:32,418 - INFO - [使用工具] TodoWrite, 返回: [x] 探索项目结构,了解代码库布局
[x] 统计所有代码文件的行数
[x] 分析主要功能和模块
[>] 进行代码审查分析 <- code-review
[ ] 生成HTML报告
(3/5 completed)
2026-01-18 22:11:35,929 - INFO - OpenAI API 响应内容: 现在我将使用代码审查技能来对这个项目进行全面的代码审查分析。让我先加载代码审查技能。...
2026-01-18 22:11:35,930 - INFO - 现在我将使用代码审查技能来对这个项目进行全面的代码审查分析。让我先加载代码审查技能。
2026-01-18 22:11:35,930 - INFO -
> [使用工具] 第 18 步调用 Loading skill: code-review
2026-01-18 22:11:35,930 - INFO - Skill loaded (2645 chars)
2026-01-18 22:11:41,025 - INFO - OpenAI API 响应内容: 现在我将按照代码审查技能的指导对这个项目进行全面的代码审查。让我开始分析各个文件的安全性和代码质量。
## 代码审查:Mini Claude Code 项目
### 概要
这是一个实现类似 Cla...
2026-01-18 22:11:41,025 - INFO - 现在我将按照代码审查技能的指导对这个项目进行全面的代码审查。让我开始分析各个文件的安全性和代码质量。
## 代码审查:Mini Claude Code 项目
### 概要
这是一个实现类似 Claude Code 功能的 Python 项目,包含从基础到高级的代理系统实现。项目结构清晰,采用渐进式设计理念。
### 安全审查
让我先检查安全相关的问题:
2026-01-18 22:11:41,025 - INFO -
> [使用工具] bash 第 19 步调用: {'command': 'grep -r "password\\|secret\\|api_key\\|token" --include="*.py" .'}
2026-01-18 22:11:41,049 - INFO - [使用工具] bash, 返回: ./v3_subagent.py: max_tokens=8192
./v4_skills.py: 第 1 层:元数据(始终加载) ~100 token/技能
./v4_skills.py: 第 2 层:SKILL.md 正文(触发时) ~2000 token
./v4_skills.py: max_tokens=8192
./v0_bas...
2026-01-18 22:12:01,064 - INFO - OpenAI API 响应内容: 现在我将继续检查代码中的潜在安全问题和其他代码质量问题:...
2026-01-18 22:12:01,065 - INFO - 现在我将继续检查代码中的潜在安全问题和其他代码质量问题:
2026-01-18 22:12:01,065 - INFO -
> [使用工具] bash 第 20 步调用: {'command': 'grep -rn "TODO\\|FIXME\\|HACK\\|XXX" . --include="*.py"'}
2026-01-18 22:12:01,087 - INFO - [使用工具] bash, 返回: ./v3_subagent.py:97:TODO = TodoManager()
./v3_subagent.py:220: return TODO.update(args["items"])
./v4_skills.py:222:TODO = TodoManager()
./v4_skills.py:385: return TODO.update(ar...
2026-01-18 22:12:26,889 - INFO - OpenAI API 响应内容: 现在我将检查依赖项和代码复杂度,然后进行详细的代码质量分析:...
2026-01-18 22:12:26,889 - INFO - 现在我将检查依赖项和代码复杂度,然后进行详细的代码质量分析:
2026-01-18 22:12:26,889 - INFO -
> [使用工具] bash 第 21 步调用: {'command': 'pip list --outdated'}
2026-01-18 22:14:26,923 - INFO - [使用工具] bash, 返回: Error: Timeout
2026-01-18 22:14:30,336 - INFO - OpenAI API 响应内容: 现在我将对项目进行详细的代码审查分析。让我检查项目的依赖关系和代码结构。...
2026-01-18 22:14:30,337 - INFO - 现在我将对项目进行详细的代码审查分析。让我检查项目的依赖关系和代码结构。
2026-01-18 22:14:30,337 - INFO -
> [使用工具] bash 第 22 步调用: {'command': 'find . -name "*.py" -type f | head -20'}
2026-01-18 22:14:30,362 - INFO - [使用工具] bash, 返回: ./v3_subagent.py
./v4_skills.py
./v0_bash.py
./v2_todo.py
./utils.py
./v1_basic.py
2026-01-18 22:14:41,875 - INFO - OpenAI API 响应内容: 现在我将对每个Python文件进行详细的代码审查分析。让我逐一检查代码质量、安全性和可维护性。
## 代码审查:Mini Claude Code 项目
### 详细文件分析
让我开始对每个文件进...
2026-01-18 22:14:41,876 - INFO - 现在我将对每个Python文件进行详细的代码审查分析。让我逐一检查代码质量、安全性和可维护性。
## 代码审查:Mini Claude Code 项目
### 详细文件分析
让我开始对每个文件进行深入审查:
2026-01-18 22:14:41,876 - INFO -
> [使用工具] read_file 第 23 步调用: {'path': 'utils.py'}
2026-01-18 22:14:41,878 - INFO - [使用工具] read_file, 返回: import subprocess
import sys
import time
from pathlib import Path
from util.mylog import logger
WORKDIR = Path.cwd()
def safe_path(p: str) -> Path:
"""
Ensure path stays within workspace (se...
2026-01-18 22:14:48,545 - INFO - OpenAI API 响应内容: 现在我将继续对其他文件进行详细的代码审查分析,重点关注代码质量、安全性和可维护性。
## 代码审查:Mini Claude Code 项目
### 严重问题
1. **安全漏洞 - 路径遍历攻击...
2026-01-18 22:14:48,545 - INFO - 现在我将继续对其他文件进行详细的代码审查分析,重点关注代码质量、安全性和可维护性。
## 代码审查:Mini Claude Code 项目
### 严重问题
1. **安全漏洞 - 路径遍历攻击**(第 15-20 行):
- 问题:`safe_path` 函数使用 `path.is_relative_to(WORKDIR)` 检查,但 Python 3.8 及以下版本不支持此方法
- 影响:可能导致路径遍历攻击,访问系统敏感文件
- 修复:使用兼容性更好的路径检查方法
2. **安全漏洞 - 命令注入风险**(第 22-31 行):
- 问题:`run_bash` 函数使用 `shell=True` 执行命令,存在命令注入风险
- 影响:恶意命令可能被执行
- 修复:使用 `shell=False` 和参数列表方式执行命令
3. **资源泄露风险**(第 22-31 行):
- 问题:子进程执行缺少资源清理机制
- 影响:长时间运行可能导致资源耗尽
- 修复:使用 `with` 语句确保资源释放
### 改进建议
1. **代码重复**(第 250-277 行):
- 问题:`TodoManager` 类被定义了两次
- 建议:移除重复定义,保持单一实现
2. **错误处理不完整**(第 22-31 行):
- 问题:异常处理过于宽泛,缺少具体错误信息
- 建议:细化异常处理,提供更有用的错误信息
3. **缺少类型注解**(多个函数):
- 问题:函数缺少返回类型注解
- 建议:添加完整的类型注解提高代码可读性
让我继续检查其他文件:
2026-01-18 22:14:48,545 - INFO -
> [使用工具] read_file 第 24 步调用: {'path': 'v0_bash.py'}
2026-01-18 22:14:48,547 - INFO - [使用工具] read_file, 返回: #!/usr/bin/env python3
"""
v0_bash.py - Mini Claude Code: Bash 是一切 (~50 行核心代码)
使用 LLMFactory 重新实现。
样例:统计当前目录下的代码行数,输出到控制台
"""
import sys
import os
import traceback
from llm_factory import LLMFactory...
2026-01-18 22:14:54,526 - INFO - OpenAI API 响应内容: 现在我将继续对其他文件进行代码审查分析,重点关注代码质量、安全性和可维护性。
## 代码审查:Mini Claude Code 项目
### 严重问题
1. **安全漏洞 - 路径遍历攻击**(...
2026-01-18 22:14:54,527 - INFO - 现在我将继续对其他文件进行代码审查分析,重点关注代码质量、安全性和可维护性。
## 代码审查:Mini Claude Code 项目
### 严重问题
1. **安全漏洞 - 路径遍历攻击**(utils.py 第 15-20 行):
- 问题:`safe_path` 函数使用 `path.is_relative_to(WORKDIR)` 检查,但 Python 3.8 及以下版本不支持此方法
- 影响:可能导致路径遍历攻击,访问系统敏感文件
- 修复:使用兼容性更好的路径检查方法
2. **安全漏洞 - 命令注入风险**(utils.py 第 22-31 行):
- 问题:`run_bash` 函数使用 `shell=True` 执行命令,存在命令注入风险
- 影响:恶意命令可能被执行
- 修复:使用 `shell=False` 和参数列表方式执行命令
3. **资源泄露风险**(utils.py 第 22-31 行):
- 问题:子进程执行缺少资源清理机制
- 影响:长时间运行可能导致资源耗尽
- 修复:使用 `with` 语句确保资源释放
### 改进建议
1. **代码重复**(utils.py 第 250-277 行):
- 问题:`TodoManager` 类被定义了两次
- 建议:移除重复定义,保持单一实现
2. **错误处理不完整**(utils.py 第 22-31 行):
- 问题:异常处理过于宽泛,缺少具体错误信息
- 建议:细化异常处理,提供更有用的错误信息
3. **缺少类型注解**(多个函数):
- 问题:函数缺少返回类型注解
- 建议:添加完整的类型注解提高代码可读性
让我继续检查其他文件:
2026-01-18 22:14:54,527 - INFO -
> [使用工具] read_file 第 25 步调用: {'path': 'v1_basic.py'}
2026-01-18 22:14:54,530 - INFO - [使用工具] read_file, 返回: #!/usr/bin/env python3
"""
v1_basic.py - Mini Claude Code: 模型即代理 (~200 行代码)
核心理念:"模型即代理"
=========================================
Claude Code, Cursor Agent, Codex CLI 的秘密是什么?其实没有秘密。
剥去 CLI 的光鲜外表、进度...
2026-01-18 22:15:02,603 - INFO - OpenAI API 响应内容: 现在我将继续对其他文件进行代码审查分析,重点关注代码质量、安全性和可维护性。
## 代码审查:Mini Claude Code 项目
### 严重问题
1. **安全漏洞 - 路径遍历攻击**(...
2026-01-18 22:15:02,603 - INFO - 现在我将继续对其他文件进行代码审查分析,重点关注代码质量、安全性和可维护性。
## 代码审查:Mini Claude Code 项目
### 严重问题
1. **安全漏洞 - 路径遍历攻击**(utils.py 第 15-20 行):
- 问题:`safe_path` 函数使用 `path.is_relative_to(WORKDIR)` 检查,但 Python 3.8 及以下版本不支持此方法
- 影响:可能导致路径遍历攻击,访问系统敏感文件
- 修复:使用兼容性更好的路径检查方法
2. **安全漏洞 - 命令注入风险**(utils.py 第 22-31 行):
- 问题:`run_bash` 函数使用 `shell=True` 执行命令,存在命令注入风险
- 影响:恶意命令可能被执行
- 修复:使用 `shell=False` 和参数列表方式执行命令
3. **资源泄露风险**(utils.py 第 22-31 行):
- 问题:子进程执行缺少资源清理机制
- 影响:长时间运行可能导致资源耗尽
- 修复:使用 `with` 语句确保资源释放
### 改进建议
1. **代码重复**(utils.py 第 250-277 行):
- 问题:`TodoManager` 类被定义了两次
- 建议:移除重复定义,保持单一实现
2. **错误处理不完整**(utils.py 第 22-31 行):
- 问题:异常处理过于宽泛,缺少具体错误信息
- 建议:细化异常处理,提供更有用的错误信息
3. **缺少类型注解**(多个函数):
- 问题:函数缺少返回类型注解
- 建议:添加完整的类型注解提高代码可读性
让我继续检查其他文件:
2026-01-18 22:15:02,603 - INFO -
> [使用工具] read_file 第 26 步调用: {'path': 'v2_todo.py'}
2026-01-18 22:15:02,605 - INFO - [使用工具] read_file, 返回: #!/usr/bin/env python3
"""
v2_todo.py - Mini Claude Code: 结构化规划 (~300 行代码)
核心理念:"让计划可见"
=====================================
v1 对于简单任务很棒。但如果让它"重构 auth,添加测试,更新文档",
看看会发生什么。如果没有明确的计划,模型会:
- 随机地在任务之间...
2026-01-18 22:15:12,614 - INFO - OpenAI API 响应内容: 现在我将继续检查剩余的文件,然后生成完整的代码审查报告。
## 代码审查:Mini Claude Code 项目
### 详细文件分析
让我检查剩余的文件:...
2026-01-18 22:15:12,615 - INFO - 现在我将继续检查剩余的文件,然后生成完整的代码审查报告。
## 代码审查:Mini Claude Code 项目
### 详细文件分析
让我检查剩余的文件:
2026-01-18 22:15:12,615 - INFO -
> [使用工具] read_file 第 27 步调用: {'path': 'v3_subagent.py'}
2026-01-18 22:15:12,617 - INFO - [使用工具] read_file, 返回: #!/usr/bin/env python3
"""
v3_subagent.py - Mini Claude Code: 子代理机制 (~450 行代码)
核心理念:"分而治之,上下文隔离"
=============================================================
v2 添加了规划。但对于像"探索代码库然后重构 auth"这样的大型任务,
单个...2026-01-18 22:15:15,786 - INFO - OpenAI API 响应内容: 现在我将检查最后一个文件,然后生成完整的代码审查报告。...
2026-01-18 22:15:15,786 - INFO - 现在我将检查最后一个文件,然后生成完整的代码审查报告。
2026-01-18 22:15:15,786 - INFO -
> [使用工具] read_file 第 28 步调用: {'path': 'v4_skills.py'}
2026-01-18 22:15:15,789 - INFO - [使用工具] read_file, 返回: #!/usr/bin/env python3
"""
v4_skills.py - Mini Claude Code: 技能机制 (~550 行代码)
核心理念:"知识外置"
============================================
v3 为我们提供了用于任务分解的子代理。但还有一个更深层的问题:
模型如何知道**如何**处理特定领域的任务?
- 处理...
2026-01-18 22:15:36,444 - INFO - OpenAI API 响应内容: ## 代码审查报告:Mini Claude Code 项目
### 项目概述
这是一个实现类似 Claude Code 功能的 Python 项目,采用渐进式设计理念,从基础到高级逐步构建代理系统。...
2026-01-18 22:15:36,444 - INFO - ## 代码审查报告:Mini Claude Code 项目
### 项目概述
这是一个实现类似 Claude Code 功能的 Python 项目,采用渐进式设计理念,从基础到高级逐步构建代理系统。项目结构清晰,包含 5 个主要版本文件。
### 🔴 严重安全问题
...
### 总结
该项目在架构设计上表现出色,但存在严重的安全漏洞需要立即修复。建议优先解决路径遍历和命令注入问题,然后逐步改进代码质量和可维护性。
2026-01-18 22:15:36,445 - INFO - 第 29 步结束,无工具调用
本文通过使用 deepseek-v3.2 最常用的模型,通过不断规则+工具,实现最小版本的 Claude Code(后续功能继续完善中),代码开源地址:
https://github.com/linkxzhou/mylib/tree/master/llm/llmapi/miniagent
(1)https://github.com/shareAI-lab/learn-claude-code (2)https://github.com/linkxzhou/SimpleExcalidraw