源文件:chapter5/coding-agent/README.md 综合编码 Agent - 纯 Python 实现 一个基于 Claude 构建、面向生产的 AI 编码 Agent,用纯 Python 工具实现了第 2 章的全部技术——无需任何命令行依赖! 核心特性 纯 Python 实现 所有工具都不依赖任何命令行工具: 无需 、 (ripgrep)、 命令 不依赖任何系统工具 100% 纯 Python 实现 在任何装有 Python 3.8+ 的系统上都能运行 尤其适合没有命令行工具的 Mac 用户 完整工具套件 tools.
源文件:chapter5/coding-agent/README.md
一个基于 Claude 构建、面向生产的 AI 编码 Agent,用纯 Python 工具实现了第 2 章的全部技术——无需任何命令行依赖!
所有工具都不依赖任何命令行工具:
grep、rg(ripgrep)、find 命令tools.json 中的全部 16 个工具均已完整实现:
文件操作(纯 Python):
Read - 文件读取,支持图像 / PDF / notebookWrite - 文件写入,带自动 lint 检查Edit - 查找并替换编辑MultiEdit - 一次操作中完成多处编辑搜索工具(纯 Python,不依赖 rg/grep):
Grep - 纯 Python 正则检索,与 ripgrep 功能完全对齐
Glob - 文件模式匹配LS - 目录列表Shell 操作:
Bash - 持久化 shell 会话BashOutput - 后台任务输出KillBash - 终止 shell项目管理:
TodoWrite - 任务列表管理ExitPlanMode - 退出计划模式高级:
NotebookEdit - Jupyter notebook 编辑WebFetch - 网页内容抓取(桩实现)WebSearch - 网页检索(桩实现)Task - 子 Agent 启动器(桩实现)在 Write/Edit/MultiEdit 之后:
coding-agent/ ├── agent.py # 主 Agent 实现 ├── system_state.py # 系统状态跟踪 ├── tool_registry.py # 工具名 → 实现的映射 ├── tools/ # 所有工具实现 │ ├── __init__.py │ ├── base.py # 基础工具类 │ ├── bash_tool.py # Shell 执行 │ ├── bash_output_tool.py # 后台任务输出 │ ├── kill_bash_tool.py # Shell 终止 │ ├── read_tool.py # 文件读取 │ ├── write_tool.py # 文件写入 │ ├── edit_tool.py # 文件编辑 │ ├── multi_edit_tool.py # 多处编辑 │ ├── grep_tool.py # 纯 Python 正则检索(无需 rg!) │ ├── glob_tool.py # 文件模式匹配 │ ├── ls_tool.py # 目录列表 │ ├── todo_write_tool.py # TODO 管理 │ ├── exit_plan_mode_tool.py │ ├── notebook_edit_tool.py │ ├── web_fetch_tool.py │ ├── web_search_tool.py │ ├── task_tool.py │ └── shell_session.py # Shell 会话管理 ├── tools.json # 工具定义 ├── system-prompt.md # 系统提示 ├── config.py # 配置 ├── requirements.txt # 依赖 └── README.md # 本文件
# 进入项目目录 cd /Users/boj/ai-agent-book/projects/week5/coding-agent # 安装依赖 pip install -r requirements.txt # 配置环境 cp .env.example .env # 编辑 .env 并配置你的提供商
编辑 .env 文件:
# 选择你的提供商(anthropic、openai 或 openrouter) PROVIDER=anthropic # 为所选提供商添加 API 密钥 ANTHROPIC_API_KEY=sk-ant-api03-... # 或 OPENROUTER_API_KEY=sk-or-v1-... # 或 OPENAI_API_KEY=sk-... # 为所选提供商选择合适的模型 DEFAULT_MODEL=claude-sonnet-5
详细的提供商配置指南见 PROVIDERS.md。
核心依赖:
anthropic - 用于 Anthropic APIopenai - 用于 OpenAI/OpenRouter APIpython-dotenv - 用于配置可选(用于增强功能):
PyPDF2 - 用于 PDF 读取requests、beautifulsoup4、html2text - 用于 WebFetch无需任何命令行工具! 在没有 Homebrew 包的 macOS 上也能运行。
Agent 会自动处理各提供商不同的 API 格式。
你无需直接的 Anthropic 或 OpenAI 密钥就能运行 Agent。如果
所请求的直连提供商密钥缺失,只要设置了OPENROUTER_API_KEY,Agent 就会透明地回退到
OpenRouter(经由 OpenAI 兼容 SDK):
PROVIDER=anthropic 且有 ANTHROPIC_API_KEY → Anthropic SDK,行为不变(默认)。PROVIDER=anthropic 但无 ANTHROPIC_API_KEY(且设置了 OPENROUTER_API_KEY)→ 经由 OpenRouter 路由。PROVIDER=openai 且有 OPENAI_API_KEY → OpenAI SDK,行为不变。PROVIDER=openai 但无 OPENAI_API_KEY(且设置了 OPENROUTER_API_KEY)→ 经由 OpenRouter 路由。回退时,原生模型 id 会被加前缀 / 映射为 OpenRouter id:
| 请求的模型 | 使用的 OpenRouter id |
|---|---|
claude-sonnet-*(如 claude-sonnet-5) |
anthropic/claude-sonnet-4.6 |
claude-haiku-* |
anthropic/claude-haiku-4.5 |
claude-opus-* / 其他 claude-* |
anthropic/claude-opus-4.8 |
gpt-* / o1-*(如 gpt-5.6-luna) |
openai/<model> |
已带前缀(vendor/model) |
原样透传 |
因此,一个只有 OPENROUTER_API_KEY 的用户也能运行,例如:
# 无需 ANTHROPIC_API_KEY——自动回退到 OpenRouter python main.py --provider anthropic --model claude-sonnet-5 -p "..." # gpt-5.6-luna 经由 OpenRouter 路由(无需 OPENAI_API_KEY) python main.py --provider openai --model gpt-5.6-luna -p "..."
如果你想在不做任何映射的情况下指定某个 OpenRouter 模型,可显式设置PROVIDER=openrouter(并使用 vendor/model 形式的 id)。
main.py)main.py 是唯一推荐的入口,提供统一的 argparse 命令行界面。运行python main.py --help 查看完整的中文帮助:
python main.py --help
主要参数:
| 参数 | 说明 |
|---|---|
| (无参数) | 进入交互式对话(默认行为) |
-p, --prompt "任务" |
非交互模式:执行单个任务后退出,适合脚本 / CI |
--list-tools |
离线列出全部已注册工具及简介(无需 API Key,可用于自检) |
--provider {anthropic,openai,openrouter} |
临时覆盖 .env 中的 PROVIDER |
--model 模型名 |
临时覆盖 .env 中的 DEFAULT_MODEL |
--base-url URL |
临时覆盖 API Base URL(自建网关 / 兼容 OpenAI 的服务) |
--max-iterations N |
单个任务的最大 Agent 迭代轮数(默认 50) |
--no-color |
禁用彩色输出(无 TTY 时自动禁用) |
先确认工具集加载正常:
$ python main.py --list-tools 共 16 个工具: Task Launch a new agent to handle complex, multi-step tasks autonomously. Bash Executes a given bash command in a persistent shell session ... Glob - Fast file pattern matching tool that works with any codebase size Grep A powerful search tool built on ripgrep ...
配置好 .env(见上文 Configuration)后,用一条命令让 Agent 创建并运行一个脚本:
python main.py -p "创建 hello_world.py:打印 Hello, World!,包含一个按姓名问候的函数和一个 main 演示块,然后运行它验证输出。"
成功时的终端输出结构大致如下(示意,实际轮次/调用次数取决于模型):
✓ Agent initialized successfully You: 创建 hello_world.py ... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 🔧 Calling tool: Write ✓ Completed (call #1) ✓ No lint errors File: hello_world.py 🔧 Calling tool: Bash ✓ Completed (call #2) Output: Hello, World! Hello, Alice! ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ✅ Task completed! Iterations: 2 Tool calls: 2
判定成功的标志:Agent 依次调用
Write写文件、Bash运行脚本,
终端出现脚本的真实输出,并以✅ Task completed!收尾。
(quickstart.py是同一任务的脚本化版本,可作对照。)
不带 -p 直接运行即进入交互式会话:
python main.py
特性:
会话内命令(在对话中输入):
/help - 显示帮助信息/quit 或 /exit - 退出 CLI/reset - 重置对话历史/clear - 清屏/status - 显示 Agent 状态(工具调用、TODO 等)python quickstart.py # 基础快速上手(与上文端到端示例同款任务) python example_complex_task.py # 复杂多步任务 python example_with_system_hints.py # 系统提示(System Hint)技术演示
from agent import CodingAgent agent = CodingAgent(api_key="your-key") for event in agent.run("List all Python files"): if event["type"] == "text_delta": print(event["delta"], end="", flush=True) elif event["type"] == "done": print("\n✅ Done!")
Grep 工具完全用纯 Python 实现,不依赖任何 grep、rg 或其他命令行工具。它提供了 ripgrep 的全部功能:
# 示例:在文件中检索模式 { "name": "Grep", "input": { "pattern": "def.*test", "path": "/path/to/search", "output_mode": "content", "-i": True, # 大小写不敏感 "-C": 3, # 3 行上下文 "-n": True, # 显示行号 "glob": "*.py", # 仅 Python 文件 "multiline": False # 单行匹配 } }
特性:
re 模块)-i)-A、-B、-C)-n)glob 参数)type 参数)content、files_with_matches、count每个工具都实现为继承自 BaseTool 的独立类:
class MyTool(BaseTool): @property def name(self) -> str: return "MyTool" def _execute_impl(self, params: Dict[str, Any]) -> Dict[str, Any]: # 工具实现 return {"result": "success"}
ToolRegistry 把工具名映射到实现:
registry = ToolRegistry() tool = registry.get_tool("Grep", system_state) result = tool.execute(params)
SystemState 跟踪:
系统提示在每次 LLM 调用前注入:
<system_hint> # System State Current Time: 2025-10-12 15:30:45 Working Directory: /Users/boj/coding-agent OS: Darwin Python: Python 3.11.5 # Tool Call Statistics - Grep: 2 calls - Write: 1 calls # Current TODO List ✅ [1] Search for files (completed) 🔄 [2] Implement feature (in_progress) ⬜ [3] Write tests (pending) </system_hint>
原因: 最大化的可移植性与兼容性
原因: 可维护性与可扩展性
原因: 可靠性与可控性
pathlib.glob()os 和 pathlib原因: 更好的 Agent 行为
| 技术 | 状态 | 实现 |
|---|---|---|
| 标准 OpenAI 工具格式 | 支持 | Anthropic SDK |
| 流式工具调用 | 支持 | 实时 JSON delta 解析 |
| 并行工具调用 | 支持 | 每次响应多个工具 |
| 纯 Python 工具 | 支持 | 无命令行依赖 |
| 无需 rg 的 Grep | 支持 | 纯 Python 正则检索 |
| 时间戳 | 支持 | 所有消息 / 工具 |
| 工具调用计数 | 支持 | 3 次以上告警 |
| TODO 列表 | 支持 | TodoWrite 工具 |
| 系统状态 | 支持 | 工作目录、OS、Python |
| 持久化 Shell | 支持 | Shell 会话 |
| 自动 lint 检测 | 支持 | Write/Edit/MultiEdit 之后 |
.env 文件:
# 必需 ANTHROPIC_API_KEY=your_key_here # 可选 DEFAULT_MODEL=claude-sonnet-5 MAX_ITERATIONS=50 MAX_TOKENS=8192
tools/ 中创建工具文件:# tools/my_tool.py from .base import BaseTool class MyTool(BaseTool): @property def name(self) -> str: return "MyTool" def _execute_impl(self, params): # 实现 return {"result": "success"}
tools/__init__.py 中注册:from .my_tool import MyTool __all__ = [..., 'MyTool']
tool_registry.py 中添加:self._tools = { ..., "MyTool": MyTool, }
tools.json 中添加定义确认你是从项目目录运行的:
cd /Users/boj/ai-agent-book/projects/week5/coding-agent python agent.py
检查:
确认:
/bin/bash 可用包含 130+ 测试的完整测试套件,覆盖所有工具特性。
# 安装测试依赖 pip install -r requirements.txt # 运行全部测试 pytest # 带覆盖率运行 pytest --cov=tools --cov-report=html # 运行特定工具的测试 pytest tests/test_grep_tool.py pytest tests/test_bash_tool.py # 详细输出 pytest -v
详细测试文档见 tests/README.md。
python main.py(交互式 CLI)python quickstart.pypython example_with_system_hints.pytools/grep_tool.pypytest -v 观察所有特性tools.jsonsystem-prompt.md不依赖外部工具
模块化架构
面向生产
教学价值
MIT
这是一个教学实现。欢迎自由改编与扩展!
用纯 Python 打造,追求最大的可移植性与学习价值!