Anthropic 90% 的代码是由 Claude Agent 编写的。 不是工程师在聊天窗口里打字。而是由自主 Agent 运行循环、调用工具并在团队睡觉时交付代码。
关注我的 Substack 获取最新 AI 动态:
这就是完整的设置。一步一步来。从第一次 API 调用到能够处理任何任务的可用 Agent。
本文涵盖:
1 - 为什么大多数人构建的 "Agent" 并不是真正的 Agent
2 - 每个可用 Agent 需要的 5 个部分
3 - 如何使用 Claude 和代码构建每个部分
4 - 在 Agent 交付之前就搞砸它的错误
收藏本文。下面的每个代码块都可用。
01. 大多数 "AI Agent" 并非真正的 Agent
我构建和破坏过的 Agent 比我能数清的还多。看着它们整夜燃烧 token 却毫无产出。看着它们重写同一个文件 30 次。看着它们通过删除测试来通过自己的测试。

每次失败都教会我同一个道理:模型不是问题,模型周围的架构才是。这份指南是我学到的所有东西,压缩成我能给你的最短路径。
以下是大多数人在说 "AI Agent" 时构建的东西:
1while True:2 user_input = input("> ")3 response = call_claude(user_input)4 print(response)
那是聊天机器人。它等着你,它按你说的做,它会忘记会话之间的所有事情。当你关闭标签页时,它就停止了。
Agent 是一个不需要你坐在面前就能朝着目标工作的系统。它发现需要做什么,制定计划,执行,检查结果,如果没有完成——就再试一次。你设定方向,Agent 完成工作。
"Claude Code 从零起步,在几个月内达到了 4 亿美元的收入。它始于一个黑客马拉松项目。至今仍然只使用公开 API。" -
Boris Cherny,Claude Code 负责人
同样的 API,你现在就能访问。同样的模型。区别在于模型周围的架构。

02. 真正 Agent 的 5 个部分
每个可用的 Agent——Claude Code、Devin、Codex 或你自己构建的任何东西——都由五个部分组成。缺少一个,它就坏了。

03. API 层
一切从这里开始。你调用 Claude,Claude 响应。但调用方式决定了你得到的是聊天机器人还是 Agent。

三件事很重要:系统提示词、结构化输出和温度。
系统提示词不是问候语。它是 Agent 的操作手册。所有规则、约束和行为都放在这里。没有它,Claude 会猜测你想要什么。有了它,Claude 会遵循你的规范。
1import anthropic23client = anthropic.Anthropic()45response = client.messages.create(6 model="claude-sonnet-4-6",7 max_tokens=4096,8 system="""你是一个代码审查 Agent。910规则:11- 阅读整个 diff 后再评论12- 只标记真正的 bug,而不是风格偏好13- 如果没有任何问题,回复 "LGTM" 并停止14- 永远不要建议你没有在脑子里测试过的更改15- 输出格式:{file, line, issue, fix} 的 JSON 数组""",16 messages=[{"role": "user", "content": diff_content}]17)
结构化输出让你的 Agent 的响应可被机器读取。如果 Claude 返回自由文本,你的代码必须解析它。如果 Claude 返回 JSON,你的代码可以直接使用它。
1# 强制 JSON 输出,告诉 Claude 确切的结构2system = """只返回有效的 JSON。不要 Markdown。不要解释。3Schema:4{5 "status": "pass" | "fail",6 "issues": [{"file": str, "line": int, "issue": str}],7 "summary": str8}"""
温度。 对于确定性 Agent 设为 0。对于创造性工作设为 0.3-0.5。默认值(1.0)会增加你几乎从不想在 Agent 中看到的随机性。
04. 工具
没有工具的模型可以推理但不能行动。它可以告诉你该编辑哪个文件,但不能编辑它。它可以描述一个查询,但不能运行它。

Claude 的工具使用功能让你定义模型可以调用的函数。你描述函数,Claude 决定何时调用,你执行它并返回结果,Claude 使用结果继续推理。
1tools = [{2 "name": "run_sql",3 "description": "对数据库执行只读 SQL 查询",4 "input_schema": {5 "type": "object",6 "properties": {7 "query": {8 "type": "string",9 "description": "要执行的 SQL SELECT 查询"10 }11 },12 "required": ["query"]13 }14},15{16 "name": "write_file",17 "description": "将内容写入磁盘上的文件",18 "input_schema": {19 "type": "object",20 "properties": {21 "path": {"type": "string"},22 "content": {"type": "string"}23 },24 "required": ["path", "content"]25 }26}]
工具描述比你想象的重要。Claude 读取它来决定何时以及如何使用工具。模糊的描述导致错误的调用,精确的描述导致准确的调用。
从 3-5 个工具开始。读取文件、写入文件、运行命令、搜索,以及一个针对你用例的领域特定工具。这覆盖了 90% 的 Agent 任务。

05. 循环
这是将脚本变成 Agent 的部分。没有循环,你的代码调用一次 Claude 就停止。有了循环,你的代码调用 Claude,检查结果,再调用,直到工作完成。

三个组件:
- 验证器。 检查输出是否良好的东西。测试套件、类型检查器、linter、带有严格标准的第二次 Claude 调用。没有这个,Agent 会不断跟自己达成一致。
- 状态。 记录发生了什么。什么成功了,什么失败了,下一步该尝试什么。没有状态,Agent 每次循环都会犯同样的错误。
- 停止条件。 目标达成,或者硬性限制说 "N 次尝试后停止并报告"。没有这个,循环会永远运行并耗尽你的账户。
1import json2from pathlib import Path34def run_agent(task: str, max_attempts: int = 5):5 state = {"task": task, "attempts": [], "done": False}67 for i in range(max_attempts):8 # 从状态构建上下文9 context = build_prompt(state)1011 # 使用工具调用 Claude12 result = call_claude(context, tools)1314 # 执行任何工具调用15 output = execute_tools(result)1617 # 验证结果18 check = verify(output)1920 # 更新状态21 state["attempts"].append({22 "attempt": i + 1,23 "action": result.summary,24 "passed": check.passed,25 "reason": check.reason26 })2728 if check.passed:29 state["done"] = True30 break3132 # 为下一次运行保存状态33 Path("state.json").write_text(json.dumps(state, indent=2))34 return state
这就是完整的骨架。每个生产级 Agent 都是这个模式的变体。细节会变,形状不会。
06. 记忆
没有记忆,每次会话都会从零开始。Agent 重新发现你的项目结构,重新学习你的约定,重新犯昨天犯过的错误。

Claude Agent 使用三层记忆:
CLAUDE.md 是项目根目录下的一个 Markdown 文件。Claude Code 在每次会话开始时自动读取它。你的规则、技术栈、约定。写一次,永远读取。
1# CLAUDE.md23## 项目4任务管理 API。Python 3.12,FastAPI,PostgreSQL。56## 规则7- 所有响应:{data, error, meta} 模式8- 每个新端点都需要测试9- 提交信息:type(scope): description10- 永远不要使用 print() 记录日志。使用 structlog。1112## 已知问题13- Auth 中间件期望 x-auth-token,而不是 Authorization14- 测试套件全量运行需要 45 秒。迭代时使用 --filter。
技能 捕捉整个工作流程。不仅仅是提示词——而是完整的形态:输入格式、步骤、输出格式、验证规则。第一次运行需要 20 分钟。回放只需 30 秒。
经验教训文件 是一个持续运行的错误日志。Agent 在每次会话后写入,下次会话时读取。错误会一直重复直到被写下来,然后它们就停止了。
1# learnings.md23- 支付 API 期望幂等键在 header 中,而不是 body4- PostgreSQL NOTIFY 需要在连接池中显式 LISTEN5- 速率限制器按 key 计数,而不是按 IP。测试需要唯一的 key。
07. 验证门
门是最难构建的部分,也是最容易被跳过。大多数人跳过它。这就是为什么大多数 Agent 在生产环境中崩溃。

验证门是一种检查 Agent 工作成果的东西,而不让 Agent 给自己打分。编写代码的模型在给自己的作业打分时过于慷慨。你需要第二次检查。
三种有效的模式:
1. 自动化测试。 Agent 编写代码,测试套件运行。如果测试失败,Agent 获取错误输出并重试。这就是 Claude Code 内部的工作方式。
1def verify(output):2 # 运行测试套件3 result = subprocess.run(4 ["pytest", "tests/", "-x", "--tb=short"],5 capture_output=True, text=True6 )7 return {8 "passed": result.returncode == 0,9 "reason": result.stdout if result.returncode != 0 else "所有测试通过"10 }
2. 类型检查器 / linter。 每次更改后运行 mypy、ruff 或 tsc --noEmit。无需编写任何测试就能捕获整个类别的错误。
3. 第二个模型作为审查者。 使用独立的 Claude 调用,带有只查找问题的严格系统提示词。编写者快速且便宜,审查者缓慢且严格。这种分离是质量的关键。
1# 审查者提示词 - 与构建者分离2reviewer_system = """你是一个严格的代码审查者。3你唯一的任务是发现问题。45检查:6- 代码是否符合规范?7- 是否有未捕获的边界情况?8- 所有测试是否真的测试了正确的东西?910如果一切正确,回复:{"passed": true}11如果有任何错误,回复:{"passed": false, "issues": [...]}1213不要提出改进建议。只标记真正的 bug。"""
编写者快速且便宜,审查者缓慢且严格。这种分离是质量的关键。
08. 整合在一起
这是一个完整的 Agent,它接受一个 GitHub issue URL,读取 issue,编写代码,运行测试,并打开一个 PR。五个部分协同工作。
1import anthropic, subprocess, json2from pathlib import Path34client = anthropic.Anthropic()5CLAUDE_MD = Path("CLAUDE.md").read_text()6LEARNINGS = Path("learnings.md").read_text()78SYSTEM = f"""你是一个编码 Agent。9阅读 issue,编写修复,运行测试。1011项目上下文:12{CLAUDE_MD}1314已知问题:15{LEARNINGS}1617规则:18- 在更改任何内容之前阅读完整代码库19- 为每次更改编写测试20- 如果测试失败,修复代码,而不是测试21- 当所有测试通过时停止"""2223TOOLS = [24 read_file_tool,25 write_file_tool,26 run_command_tool,27 search_codebase_tool,28]2930def run(issue_text, max_attempts=5):31 messages = [{"role": "user", "content": issue_text}]3233 for attempt in range(max_attempts):34 # 调用 Claude35 response = client.messages.create(36 model="claude-sonnet-4-6",37 max_tokens=8192,38 system=SYSTEM,39 tools=TOOLS,40 messages=messages41 )4243 # 执行工具调用44 messages = handle_tool_use(response, messages)4546 # 验证:运行测试47 test_result = subprocess.run(48 ["pytest", "-x", "--tb=short"],49 capture_output=True, text=True50 )5152 if test_result.returncode == 0:53 print(f"在 {attempt + 1} 次尝试后完成")54 return True5556 # 将失败反馈到循环中57 messages.append({58 "role": "user",59 "content": f"测试失败:\n{test_result.stdout}\n修复并重试。"60 })6162 return False
这就是一个可用的 Agent。带有系统提示词和 CLAUDE.md 的 API 层。用于文件操作的工具。带有重试的循环。来自 learnings.md 的记忆。通过 pytest 的验证门。
不到 50 行。与 Claude Code 内部使用的架构相同。
**
09. 破坏每个 Agent 的 5 个错误
- 没有验证门。 Agent 给自己打分。它编写代码,说 "看起来不错",然后继续。输出看起来正确,但在生产环境中崩溃。
- 没有停止条件。 循环一直运行直到你的 API 账单达到 200 美元。没有硬性限制,Agent 会永远重试,重写同一个文件 40 次。始终设置 max_attempts。始终设置。
- 没有状态文件。 第 1 次尝试和第 50 次尝试犯同样的错误。Agent 不知道它已经尝试过什么,因为它连续三次提出同样的错误修复,没有记录失败。
- 工具太多。 你给 Claude 20 个工具,它选错了。一个有 5 个清晰工具的模型比一个有 20 个重叠工具的模型做出更好的选择。从小处着手。只有当 Agent 遇到瓶颈时才添加工具。
- 系统提示词模糊。 "做一个好的编码助手" 给你泛泛的输出。"所有响应必须是有效的 JSON,每次更改都需要测试,永远不要修改 /src 之外的文件" 给你一个行为可预测的 Agent。
结论:
可用的 Agent 不是更好的提示词。它是一个系统:API + 工具 + 循环 + 记忆 + 验证门。五个部分,缺少一个,它就坏了。
大多数人会阅读本文,收藏它,然后继续将 Claude 当作聊天机器人使用。他们会一次粘贴一个问题,手动将响应复制到代码库中。
那些构建了循环的人会在他们睡觉时交付工作。同样的模型,同样的 API,同样的价格,不同的架构。
上面的代码块都可用。复制它们,运行它们,针对你的用例进行修改。
本周构建一个 Agent。把它指向你每天做的任务。让它运行。





