手把手书写你的第一个 AI Agent:当 Skill 有了记忆、角色和主动性
前端 AI Skill 体系 · 第 6 篇(Agent 篇)
上一篇,我们花 15 分钟写了一个日报生成器 Skill。30 行 Markdown,AI 从此不再每天失忆。
但用了一周之后,我发现一个问题:Skill 不会主动干活。
我不说"写日报",它就沉默。我不说"审查代码",它就装死。它像一个只会听指令的实习生------你推一下,它动一下。
我想要的是一个同事:自己记得上下文,自己判断下一步做什么,做完了还会主动告诉我结果。
这就是 Agent。今天这篇,我们从零搭一个。
一、先搞清楚:Agent 和 Skill 到底什么区别
上一篇发布后,评论区问得最多的就是:"Skill 和 Agent 不就是叫法不同吗?"
不是。区别是本质性的。
一句话版本
Skill 是岗位说明书,Agent 是一个活人。
说明书贴在工位上,谁来都照着做。它不会主动思考,不会记住昨天发生了什么,更不会在发现问题时自己去找隔壁部门协调。
Agent 会。
展开说
| 维度 | Skill | Agent |
|---|---|---|
| 本质 | 一份 Markdown 指令 | 一个可运行的程序 |
| 触发 | 被动------你说话它才动 | 主动------自己决定何时行动 |
| 记忆 | 无。每次对话从零开始 | 有。短期工作记忆 + 长期持久化 |
| 工具 | 描述"应该做什么",AI 自行决定 | 代码级绑定,确定性执行 |
| 决策 | 线性流程,不会回溯 | 观察→思考→行动→再观察,循环 |
| 协作 | 独立存在,互不感知 | Handoff 给其他 Agent、组队 |
| 部署 | 放项目目录就行 | 需要 Python/Node 运行时 |
| 成本 | 零(纯文本) | API 调用费 / 本地算力 |
什么时候该用哪个?
我现在的判断标准很简单:
如果任务需要"做完一步,看看结果,再决定下一步"------用 Agent。 如果任务是"输入→固定流程→输出"------用 Skill。
举几个实际例子:
| 场景 | 选择 | 为什么 |
|---|---|---|
| 统一代码风格 | Skill | 规则固定,不需要决策 |
| 生成日报 | Skill | 流程固定,一次执行完事 |
| 自动修 Bug | Agent | 要观察报错→定位原因→修复→验证→没修好再来 |
| 多文件重构 | Agent | 要规划顺序、跨文件协调、改完一个检查另一个 |
| 客服问答 | Agent | 要记住上下文、查知识库、判断是否需要转人工 |
| 代码审查 | Skill + Agent | Skill 定审查规则,Agent 执行多轮审查 |
它们不是替代关系,是互补关系。 Skill 定义"怎么做",Agent 决定"什么时候做、找谁做、做完了怎么办"。
我现在的体系里,31 个 Skill 定义规范,3 个 Agent 负责编排和执行。Skill 是法律条文,Agent 是法官。
二、项目目录结构
简单 Agent:5 个文件搞定
bash
my-first-agent/
├── agent.py # Agent 定义(角色 + 指令 + 工具绑定)
├── tools.py # 工具函数(Agent 的手和脚)
├── main.py # 运行入口
├── requirements.txt # 依赖:openai-agents
└── .env # API Key(别提交 Git)
就这么多。别一上来就搞 20 个目录。
复杂 Agent:5 层架构
当你的 Agent 从 1 个变成 3 个、5 个,目录就需要分层了:
perl
my-agent-system/
│
├── agents/ # 🧠 角色层:谁干什么
│ ├── orchestrator.py # 编排者------决定任务分配
│ ├── researcher.py # 研究员------搜索和整理信息
│ ├── coder.py # 开发者------写代码、修 Bug
│ └── reviewer.py # 审查者------质量把关
│
├── tools/ # 🔧 能力层:能做什么
│ ├── web_search.py # 网络搜索
│ ├── file_ops.py # 文件读写
│ ├── code_exec.py # 代码执行(沙箱)
│ └── git_ops.py # Git 操作
│
├── memory/ # 💾 记忆层:记得什么
│ ├── short_term.py # 当前对话上下文
│ ├── long_term.py # 跨会话持久化(SQLite/Redis)
│ └── vector_store.py # 语义检索(向量数据库)
│
├── config/ # ⚙️ 配置层:用什么模型、什么参数
│ ├── models.py # 模型配置(可切换 OpenAI/Claude/Ollama)
│ ├── prompts.py # System Prompt 模板
│ └── settings.py # 全局设置(max_iterations、timeout)
│
├── workflows/ # 🔄 编排层:怎么协作
│ ├── code_review.py # 代码审查流程
│ └── feature_dev.py # 功能开发流程(含回退重试)
│
├── main.py # 入口
├── requirements.txt
├── .env.example
└── README.md
各层一句话
| 层 | 一句话 | 类比 |
|---|---|---|
agents/ |
定义"谁"------角色、目标、边界 | 公司组织架构 |
tools/ |
定义"能做什么"------具体能力 | 员工的工具箱 |
memory/ |
定义"记得什么"------上下文和知识 | 员工的大脑 |
config/ |
定义"用什么模型" | 公司制度 |
workflows/ |
定义"怎么协作" | 项目流程 |
原则:先跑通 5 个文件的简单版,再按需拆层。 别一上来就搭 5 层架构------那是第 3 个 Agent 出现之后才需要的事。
三、5 个我踩过的坑
这些坑我全踩过。每一个都浪费了我至少半天。
坑 1:以为长 Prompt = Agent
我最初的"Agent"就是一个 3000 字的 System Prompt,里面写了"你要先搜索,再分析,再输出"。
它不是 Agent。它是一个带长说明书的 Chatbot。
Agent 的核心不是 Prompt 长度,是循环:
python
# ❌ 这不是 Agent,这是一个函数调用
response = llm.call("帮我调研 xxx")
# ✅ Agent 的核心是这个循环
while not done:
observation = agent.observe(environment) # 看到了什么
thought = agent.think(observation) # 怎么想的
action = agent.decide(thought) # 决定做什么
result = agent.act(action) # 执行
done = agent.evaluate(result) # 够了吗?不够就再来
这个循环叫 ReAct(Reasoning + Acting)。没有它,就不是 Agent。
坑 2:给 Agent 接了 30 个工具
"工具越多越强大嘛!"------我当初是这么想的。
结果:Agent 开始"选择困难"。让它搜个东西,它先去读了个文件。让它写代码,它先去搜了个网页。
实测体感:
| 工具数量 | 任务准确率(体感) |
|---|---|
| 3-5 个 | ~90% |
| 10-15 个 | ~70% |
| 30+ 个 | 开始随机调工具,~50% |
原则:每个 Agent 最多 5-7 个工具。 需要更多能力?拆成多个 Agent,每个 Agent 只管自己那几把刀。
坑 3:造了一个"全能 Agent"
python
# ❌ 我最初写的
agent = Agent(
name="Everything",
instructions="你能搜索、写代码、审查代码、部署、写文档、做PPT..."
)
它什么都做,什么都做不好。
后来我拆成了 3 个:Researcher 只管搜、Coder 只管写、Reviewer 只管审。每个 Agent 的 instructions 不超过 200 字。
效果立竿见影:单个 Agent 的输出质量从"勉强能用"变成"基本不用改"。
坑 4:没设最大循环次数
有一天晚上我让 Agent 调研一个技术方案,然后去吃饭了。
回来一看:它还在跑。 搜了 47 次网页,每次都觉得"信息不够充分,再搜一次"。Token 烧了 $3.2。
python
# ✅ 必须设上限
result = await Runner.run(
agent,
"调研 xxx",
max_turns=10, # 最多 10 轮工具调用,超了就停
)
教训:Agent 没有"够了"的概念,你必须替它设。
坑 5:没做 Human-in-the-loop
我让 Agent 帮我"清理项目里的临时文件"。
它很勤快地执行了 rm -rf node_modules .git dist。
.git 没了。
python
# ✅ 危险操作必须暂停等人确认
from agents import Agent, function_tool
@function_tool(needs_approval=True) # 关键:执行前暂停等人确认
def delete_file(path: str) -> str:
"""删除指定文件"""
os.remove(path)
return f"已删除 {path}"
2026 年了,Agent 仍然需要人类把关。 尤其是:删除操作、金钱相关、权限变更、面向外部的输出。
个人 vs 企业:方向不同
| 维度 | 个人开发者(我) | 企业团队 |
|---|---|---|
| 起步 | OpenAI Agents SDK,单文件 | LangGraph / CrewAI + 编排平台 |
| 模型 | OpenAI / Claude API | 私有部署 + API 混合 |
| 记忆 | 本地 SQLite | Redis + 向量数据库 |
| 部署 | 本地跑 / 简单脚本 | K8s + 监控 + 告警 |
| 安全 | .env 管 Key |
Vault + RBAC + 审计日志 |
| 月成本 | $10-50 | 预算制,需成本监控 |
| 可观测 | print + Tracing 面板 | LangSmith / 专业 Tracing |
如果你是一个人,别搞企业那套。 一个 .py 文件 + 一个 .env,够了。
四、15 分钟:搭一个能搜索、能写文件的 Research Agent
框架选择:OpenAI Agents SDK。 原因:5 行代码跑起来,内置 Tracing,支持 100+ 模型,2026 年社区最活跃。 后面复杂版也用它,不换框架。
Step 1:环境准备(2 分钟)
前置要求 :Python 3.10+(
python3 --version检查)。 前端同学如果没装过 Python:macOS 用brew install python@3.12,Windows 去 python.org 下载安装。
bash
mkdir my-first-agent && cd my-first-agent
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install openai-agents python-dotenv
# 环境变量(这里用阿里百炼/通义千问,国内直连,不用翻墙)
# 到 https://bailian.console.aliyun.com 开通,免费额度够跑几十次
cat > .env << EOF
OPENAI_API_KEY=sk-xxx # 百炼的 API Key
OPENAI_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
TAVILY_API_KEY=tvly-xxx # 搜索工具用,https://tavily.com 免费注册
EOF
echo ".env" >> .gitignore
为什么用百炼而不是 OpenAI? 三个原因:国内直连不用代理、免费额度够学习用、qwen-plus 的中文能力很强。后面第六章会讲怎么切回 OpenAI 或本地 Ollama。
Step 2:写工具(5 分钟)
工具就是 Agent 的手和脚。没有工具的 Agent 只是一个会说话的嘴。
python
# tools.py
import subprocess
from pathlib import Path
from agents import function_tool
@function_tool
def web_search(query: str) -> str:
"""搜索网络获取最新信息。当需要查找实时数据、技术文档、新闻时使用。
Args:
query: 搜索关键词,尽量具体。比如"OpenAI Agents SDK 2026 新特性"比"AI框架"好。
"""
import json, os
api_key = os.getenv("TAVILY_API_KEY", "")
if not api_key:
return "错误:未设置 TAVILY_API_KEY 环境变量。请到 https://tavily.com 免费注册获取。"
try:
result = subprocess.run(
["curl", "-s", "-X", "POST", "https://api.tavily.com/search",
"-H", "Content-Type: application/json",
"-d", json.dumps({"api_key": api_key, "query": query, "max_results": 3})],
capture_output=True, text=True, timeout=15
)
data = json.loads(result.stdout)
summaries = [f"- {r.get('title', '')}: {r.get('content', '')[:300]}" for r in data.get("results", [])]
return "\n".join(summaries)[:2000] if summaries else "未找到相关结果"
except (subprocess.TimeoutExpired, json.JSONDecodeError) as e:
return f"搜索失败:{e},请换个关键词重试"
@function_tool
def read_file(file_path: str) -> str:
"""读取本地文件内容。当需要查看代码、文档、配置文件时使用。
Args:
file_path: 文件的相对或绝对路径
"""
path = Path(file_path)
if not path.exists():
return f"文件不存在:{file_path}"
if path.stat().st_size > 50_000:
return f"文件过大({path.stat().st_size} 字节),请指定行号范围"
return path.read_text(encoding="utf-8")[:5000]
@function_tool
def write_file(file_path: str, content: str) -> str:
"""将内容写入文件。当需要保存研究结果、生成报告时使用。
Args:
file_path: 目标文件路径
content: 要写入的完整内容
"""
path = Path(file_path)
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(content, encoding="utf-8")
return f"✅ 已写入 {file_path}({len(content)} 字符)"
3 个细节,都是踩坑后加的:
- docstring 里写"什么时候用"------Agent 靠这段话决定调不调这个工具
- 返回值必须截断 (
[:2000])------不截断,一次搜索就吃掉 50% 上下文 - 错误要返回字符串,不要抛异常------Agent 看到错误信息会自己重试
Step 3:定义 Agent(3 分钟)
python
# agent.py
from agents import Agent
from tools import web_search, read_file, write_file
research_agent = Agent(
name="Research Assistant",
model="qwen-plus", # 百炼模型名。用 OpenAI 就改成 "gpt-4o"
instructions="""你是一个研究助理。
## 工作流程
1. 理解用户的研究问题,拆解为 2-3 个子问题
2. 对每个子问题使用 web_search 搜索
3. 评估信息是否充分------不够就换关键词再搜
4. 整理为结构化报告,用 write_file 保存到 reports/ 目录
## 规则
- 每次搜索后问自己:"信息够回答问题了吗?"不够就继续
- 报告必须标注信息来源 URL
- 不确定的信息标注【待验证】
- 最多搜索 5 次。5 次还不够,就如实说"信息有限"
- 报告用中文,技术术语保留英文""",
tools=[web_search, read_file, write_file],
)
注意 instructions 的写法:
- 有明确的工作流程(不是"你帮我调研一下"这种模糊指令)
- 有退出条件("最多 5 次")------防止坑 4 的无限循环
- 有输出规范("标注来源"、"用中文")
model字段指定模型------百炼用qwen-plus,OpenAI 用gpt-4o,本地用llama3.1:8b
Step 4:运行(2 分钟)
python
# main.py
from dotenv import load_dotenv
load_dotenv()
import os
os.environ["OPENAI_AGENTS_DISABLE_TRACING"] = "true"
import asyncio
from agents import Runner, set_default_openai_api
from agent import research_agent
# 百炼不支持 Responses API,强制走 Chat Completions API
set_default_openai_api("chat_completions")
async def main():
user_input = input("请输入你的研究问题(直接回车使用默认问题):\n> ").strip()
if not user_input:
user_input = "调研 2026 年主流 AI Agent 框架(OpenAI Agents SDK、LangGraph、CrewAI)的优劣对比"
result = await Runner.run(
research_agent,
input=user_input,
max_turns=10,
)
print(result.final_output)
if __name__ == "__main__":
asyncio.run(main())
bash
python main.py
两行"丑代码",但缺了直接报错:
| 代码 | 为什么需要 | 用 OpenAI 时 |
|---|---|---|
OPENAI_AGENTS_DISABLE_TRACING=true |
百炼不支持 OpenAI 的 Tracing 上报 | 删掉,享受内置 Tracing |
set_default_openai_api("chat_completions") |
百炼只支持 Chat Completions API | 删掉,SDK 默认即可 |
Step 5:看它怎么想的(3 分钟)
运行后你会在终端看到 Agent 的完整决策链:
css
Turn 1: Agent 思考 → 拆解为 3 个子问题
Turn 2: 调用 web_search("OpenAI Agents SDK features 2026")
Turn 3: 调用 web_search("LangGraph vs CrewAI comparison")
Turn 4: 调用 web_search("AI agent framework benchmark 2026")
Turn 5: Agent 思考 → 信息充分,开始写报告
Turn 6: 调用 write_file("reports/agent-frameworks-2026.md", ...)
Turn 7: 输出最终摘要
如果你用的是 OpenAI 官方 API(没关 Tracing),还可以打开 platform.openai.com/traces 看可视化面板。
这就是 Agent 和 Chatbot 的区别:Chatbot 给你一坨文字,Agent 给你一条可审计的决策链。
最终文件清单
bash
my-first-agent/
├── agent.py # 22 行:Agent 定义
├── tools.py # 50 行:3 个工具
├── main.py # 25 行:运行入口
├── requirements.txt # 2 行:openai-agents + python-dotenv
└── .env # 3 行:API Key + Base URL + Tavily Key
~100 行代码。一个能搜索、能读写文件、有决策循环的 Agent。国内直连,不用代理。
五、45 分钟:搭一个 3 人协作的开发团队
还是 OpenAI Agents SDK。不换框架。 从 1 个 Agent 到 3 个,核心变化是:Handoff(任务移交)。
目标
输入一句需求:"实现一个 React useDebounce Hook"。
3 个 Agent 自动协作:
- PM Agent 分析需求 → 输出技术方案
- Coder Agent 根据方案写代码 → 输出到
src/ - Reviewer Agent 审查代码 → 通过或打回
如果审查不通过,自动打回给 Coder 重写,最多重试 2 次。
环境准备
和第四章一样,需要 Python 3.10+ 环境。如果你已经跑通了第四章,直接复用那个虚拟环境即可------依赖完全相同。
bash
# 如果还没装过:
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
本章复用第四章的
tools.py和requirements.txt,不需要额外安装任何新依赖。
Step 1:定义 3 个 Agent
python
# agents.py
from agents import Agent, function_tool
from tools import read_file, write_file
# ---------- PM Agent ----------
pm_agent = Agent(
name="PM",
model="qwen-plus",
instructions="""你是技术产品经理。
## 职责
将用户需求转化为可执行的技术方案。
## 输出格式(严格遵守)
### 功能描述
一句话说明做什么。
### 接口定义
- 输入:参数名、类型、默认值
- 输出:返回值类型
- 用法示例:```tsx 代码块
### 边界条件(至少 3 个)
1. ...
2. ...
3. ...
### 验收标准(可测试的 checklist)
- [ ] ...
- [ ] ...
## 规则
- 先问"用户真正想要什么",不要直接设计
- 如果需求模糊,列出你的假设
- 不写代码,只写方案""",
tools=[read_file],
)
# ---------- Coder Agent ----------
coder_agent = Agent(
name="Coder",
model="qwen-plus",
instructions="""你是高级前端工程师。
## 职责
根据技术方案编写代码。
## 规则
- 代码写入 src/ 目录(用 write_file 工具)
- 主文件:src/index.ts
- 测试文件:src/index.test.ts
- 所有函数必须有 JSDoc 注释
- 错误处理不能省略
- 如果方案有歧义,在代码注释中标注 // TODO: 方案歧义 - xxx
- 使用 TypeScript strict 模式""",
tools=[read_file, write_file],
)
# ---------- Reviewer Agent ----------
reviewer_agent = Agent(
name="Reviewer",
model="qwen-plus",
instructions="""你是代码审查专家。
## 审查维度(按优先级)
1. 逻辑正确性------对照技术方案的验收标准逐条检查
2. 边界条件------方案里列的边界条件是否都处理了
3. 错误处理------有没有吞掉异常
4. 类型安全------有没有 any
5. 性能------有没有不必要的重渲染/重复计算
## 输出格式
如果通过:
"LGTM ✅" + 一句话总结亮点
如果不通过:
"NEEDS_REVISION ❌" + 具体问题列表(精确到行号 + 修改建议)
## 规则
- 目标是帮助,不是刁难
- 风格问题(分号、缩进)不提
- 最多提 5 个问题,挑最严重的""",
tools=[read_file],
)
Step 2:定义 Handoff 和编排
python
# workflow.py
from agents import Agent, Runner, handoff
from agents.stream_events import RunItemStreamEvent, AgentUpdatedStreamEvent
from agent import pm_agent, coder_agent, reviewer_agent
# 给 PM 添加 Handoff:分析完交给 Coder
pm_agent.handoffs = [handoff(coder_agent)]
# 给 Coder 添加 Handoff:写完交给 Reviewer
coder_agent.handoffs = [handoff(reviewer_agent)]
# Reviewer 的 Handoff:打回给 Coder(条件触发)
reviewer_agent.handoffs = [handoff(coder_agent)]
def _format_event(event):
"""格式化流式事件为可读输出"""
if isinstance(event, AgentUpdatedStreamEvent):
print(f"\n🤖 [{event.new_agent.name}] 接管中...")
elif isinstance(event, RunItemStreamEvent):
name = event.name
item = event.item
if name == "message_output_created":
text = getattr(item, 'raw_item', None)
if text:
content = getattr(text, 'content', '')
if isinstance(content, list):
for c in content:
if hasattr(c, 'text') and c.text:
print(f" 💬 {c.text[:200]}")
elif isinstance(content, str) and content.strip():
print(f" 💬 {content[:200]}")
elif name == "tool_called":
tool_name = getattr(item, 'name', 'unknown')
print(f" 🔧 调用工具: {tool_name}")
elif name == "tool_output":
print(f" ✅ 工具执行完成")
elif name == "handoff_requested":
print(f" ➡️ 请求交接...")
elif name == "handoff_occured":
print(f" 🔀 交接完成")
async def run_dev_team(requirement: str) -> str:
"""运行开发团队,实时展示每个 Agent 的执行过程"""
result = Runner.run_streamed(
pm_agent,
input=f"需求:{requirement}\n\n请分析需求并输出技术方案,然后交给 Coder 实现。",
max_turns=20,
)
async for event in result.stream_events():
_format_event(event)
return result.final_output
这里用了
Runner.run_streamed替代Runner.run------区别在于你能实时看到每个 Agent 在干什么:谁接管了、调了什么工具、输出了什么。调试多 Agent 协作时,这比等最终结果强太多。
Step 3:加入重试逻辑
python
# main.py
from dotenv import load_dotenv
load_dotenv()
import os
os.environ["OPENAI_AGENTS_DISABLE_TRACING"] = "true"
import asyncio
from agents import set_default_openai_api
from workflow import run_dev_team
# 百炼/通义千问不支持 Responses API,强制使用 Chat Completions API
set_default_openai_api("chat_completions")
async def main():
default_req = "实现一个 React Hook:useDebounce,支持自定义延迟(默认 300ms)、取消、立即执行(flush)"
user_input = input(f"请输入开发需求(直接回车使用默认需求):\n> ").strip()
requirement = user_input if user_input else default_req
max_retries = 2
for attempt in range(max_retries + 1):
print(f"\n{'='*50}")
print(f"🚀 第 {attempt + 1} 轮")
print(f"{'='*50}")
result = await run_dev_team(requirement)
if "LGTM" in result:
print("\n✅ 审查通过!代码已写入 src/ 目录")
break
elif attempt < max_retries:
print(f"\n❌ 审查未通过,打回重写(剩余 {max_retries - attempt} 次机会)")
requirement += f"\n\n上一轮审查意见:\n{result}"
else:
print("\n⚠️ 重试次数用完,需要人工介入")
print(result)
if __name__ == "__main__":
asyncio.run(main())
和第四章一样,三件套不能少:
load_dotenv()加载.env、禁用 Tracing、强制 Chat Completions API。忘了任何一行都会报错。
Step 4:运行
bash
python main.py
你会看到:
csharp
==================================================
🚀 第 1 轮
==================================================
[PM] 分析需求...
→ 输出技术方案:接口定义、边界条件、验收标准
→ Handoff to Coder
[Coder] 编写代码...
→ write_file("src/index.ts", ...)
→ write_file("src/index.test.ts", ...)
→ Handoff to Reviewer
[Reviewer] 审查代码...
→ NEEDS_REVISION ❌
→ 问题 1: src/index.ts:23 - flush 后没有清除 timer
→ 问题 2: src/index.test.ts - 缺少 cancel 的测试用例
❌ 审查未通过,打回重写(剩余 2 次机会)
==================================================
🚀 第 2 轮
==================================================
[Coder] 根据审查意见修改...
→ 修复 flush 逻辑
→ 补充 cancel 测试
→ Handoff to Reviewer
[Reviewer] 再次审查...
→ LGTM ✅ 逻辑完整,边界条件全覆盖
✅ 审查通过!代码已写入 src/ 目录
架构图
css
┌──────────────────────────────────────────────────────┐
│ Dev Team Workflow │
│ │
│ ┌────────┐ Handoff ┌────────┐ Handoff ┌────────┐│
│ │ PM │─────────▶│ Coder │─────────▶│Reviewer││
│ │ 需求分析│ │ 编码实现│ │ 代码审查││
│ └────────┘ └────────┘ └───┬────┘│
│ ▲ │ │
│ │ NEEDS_REVISION │ │
│ └──────────────────┘ │
│ │
│ 外部循环:main.py 控制最多重试 2 次 │
│ 超过 2 次 → 人工介入 │
└──────────────────────────────────────────────────────┘
和简单版的区别:
| 维度 | 简单版(1 Agent) | 复杂版(3 Agent) |
|---|---|---|
| Agent 数量 | 1 | 3 |
| 工具分配 | 1 个 Agent 拿所有工具 | 每个 Agent 只拿自己需要的 |
| 协作方式 | 无 | Handoff 移交 |
| 质量控制 | 自己检查自己 | 独立 Reviewer |
| 失败处理 | 无 | 打回重写 + 重试上限 |
六、换模型:从 OpenAI 到本地 Ollama
前面用的都是云端 API(百炼)。但有些场景你需要换:
- 隐私:代码不能出公司
- 成本:高频简单任务,API 费太贵
- 离线:没网也得跑
方案对比(一张表)
| 方案 | 适合谁 | 月成本 | 速度 | 能力 |
|---|---|---|---|---|
| OpenAI API | 快速原型、复杂推理 | $10-50 | 200+ tok/s | ⭐⭐⭐⭐⭐ |
| Claude API | 长文本、代码审查 | $10-50 | 150+ tok/s | ⭐⭐⭐⭐⭐ |
| Ollama 本地 | 隐私、离线、高频简单任务 | 硬件一次性 | 20-40 tok/s | ⭐⭐⭐ |
| vLLM 自部署 | 企业私有化、高并发 | 服务器成本 | 100+ tok/s | 取决于模型 |
| LiteLLM 代理 | 多模型统一入口 | 透传 | 透传 | 透传 |
换 Ollama:3 步搞定
bash
# 1. 安装 Ollama
curl -fsSL https://ollama.com/install.sh | sh
# 2. 拉模型
ollama pull llama3.1:8b
ollama pull qwen2.5-coder:7b
python
# 3. 改 2 行代码
from openai import AsyncOpenAI
from agents import Agent, Runner, set_default_openai_client
local_client = AsyncOpenAI(
base_url="http://localhost:11434/v1",
api_key="ollama",
)
set_default_openai_client(local_client, use_for_tracing=False)
agent = Agent(
name="Local Agent",
instructions="你是一个本地运行的助手",
model="llama3.1:8b",
)
import asyncio
result = asyncio.run(Runner.run(agent, "用 Python 写一个二分查找"))
print(result.final_output)
就这么多。 工具定义不用改,Agent 逻辑不用改,只改模型连接。
换 Claude:通过 LiteLLM 桥接
bash
pip install 'openai-agents[litellm]'
python
agent = Agent(
name="Claude Agent",
instructions="...",
model="litellm/anthropic/claude-sonnet-4-20250514",
)
企业级:vLLM 部署
bash
vllm serve meta-llama/Llama-3.1-8B-Instruct \
--host 0.0.0.0 --port 8000 \
--max-model-len 8192
接入方式和 Ollama 一样,只是 base_url 换成你的服务器地址。
多模型统一入口:LiteLLM 代理
yaml
# litellm_config.yaml
model_list:
- model_name: fast
litellm_params:
model: openai/gpt-4o-mini
- model_name: smart
litellm_params:
model: anthropic/claude-sonnet-4-20250514
- model_name: private
litellm_params:
model: ollama/llama3.1:8b
api_base: http://localhost:11434
bash
litellm --config litellm_config.yaml --port 4000
选型决策树
markdown
你的数据敏感吗?
├── 是 → 本地部署
│ ├── 个人用 → Ollama(一行命令搞定)
│ └── 企业用 → vLLM(高并发 + 多 GPU)
└── 不敏感 → 任务复杂吗?
├── 复杂推理/代码 → OpenAI / Claude API
└── 简单/高频 → 本地 Ollama 省钱
我的实际配置 :日常用 gpt-4o-mini(便宜),复杂推理切 gpt-4o,涉及公司代码走本地 Ollama。一个月 $15 左右。
七、Q&A:你们问得最多的 7 个问题
Q1: 我已经有 31 个 Skill 了,还需要 Agent 吗?
看你的痛点:
| 痛点 | 解法 |
|---|---|
| AI 不遵守 Skill 里的规则 | 优化 Skill 本身(不是 Agent 的问题) |
| 每次都要手动触发 | Agent(主动性) |
| 跨会话记不住上下文 | Agent + Memory |
| 复杂任务需要多步协调 | Multi-Agent |
| 想自动化整个开发流程 | 必须 Agent |
Skill 和 Agent 不是替代关系。 我现在的体系:31 个 Skill 定规范,3 个 Agent 做编排。Skill 是法律,Agent 是法官。
Q2: 哪个框架适合新手?
| 框架 | 学习曲线 | 一句话 |
|---|---|---|
| OpenAI Agents SDK | ⭐ 最低 | 5 行代码跑起来 |
| CrewAI | ⭐⭐ | 给 Agent 一个"职位" |
| LangGraph | ⭐⭐⭐ | Agent 的 Kubernetes |
| AutoGen | ⭐⭐⭐⭐ | 学术味最重 |
新手路径:OpenAI Agents SDK(理解概念)→ CrewAI(多 Agent 角色分工)→ LangGraph(生产级状态机)
Q3: Agent 的 Token 成本怎么控制?
我实测一个 Research Agent 单次任务的消耗:
| 环节 | Token | 占比 |
|---|---|---|
| System Prompt | ~500 | 5% |
| 工具描述 | ~300 | 3% |
| 工具返回结果 | ~5000 | 50% |
| Agent 推理 | ~3000 | 30% |
| 最终输出 | ~1000 | 10% |
大头是工具返回值。 控制策略:
- 工具返回必须截断(
[:2000]) - 简单判断用
gpt-4o-mini,复杂推理用gpt-4o - 设
max_turns防无限循环 - 缓存重复查询
Q4: 本地模型能跑 Agent 吗?
能,但要看模型大小:
| 模型 | 内存需求 | Agent 能力 | 适合场景 |
|---|---|---|---|
| 7B | 8GB+ | 单工具、简单 ReAct | 文件操作、格式转换 |
| 13B | 16GB+ | 多工具、简单规划 | 代码生成、问答 |
| 70B | 48GB+ | 接近云端 | 复杂推理 |
实测体感:7B 模型跑 3 个工具的 Agent,成功率约 60%。同样任务 GPT-4o 是 95%+。
Q5: 多 Agent 之间怎么通信?
三种主流模式:
css
模式 1:Handoff 移交(本文用的)
PM → Coder → Reviewer
模式 2:中心调度
Orchestrator
/ | \
Agent A Agent B Agent C
模式 3:群聊协商(AutoGen 风格)
Agent A ←→ Agent B ←→ Agent C
新手从模式 1 开始。模式 2 和 3 等你有 5+ Agent 时再考虑。
Q6: Agent 会"跑飞"怎么办?
7 道防线,按重要性排序:
max_turns:最多 N 轮工具调用,超了强制停- 工具白名单 :不给
rm -rf的能力 needs_approval=True:危险操作暂停等人确认- Guardrails:输入/输出校验(SDK 内置)
- 沙箱执行:代码在隔离环境跑
- Tracing:每步有日志,出问题能回溯
- 成本熔断:token 超阈值自动终止
python
# Guardrails 示例:拦截危险输入
from agents import Agent, input_guardrail, GuardrailFunctionOutput, RunContextWrapper
@input_guardrail
async def block_dangerous(
ctx: RunContextWrapper, agent: Agent, input: str | list
) -> GuardrailFunctionOutput:
text = input if isinstance(input, str) else str(input)
dangerous = ["删除所有", "rm -rf", "drop table", "format c:"]
is_safe = not any(word in text.lower() for word in dangerous)
return GuardrailFunctionOutput(
output_info={"safe": is_safe},
tripwire_triggered=not is_safe,
)
agent = Agent(
name="Safe Agent",
instructions="你是一个安全的助手",
input_guardrails=[block_dangerous],
)
Q7: 自定义 GPTs 算 Agent 吗?
算"体验版"。它有 System Prompt(≈ Skill)+ 知识库(≈ RAG)+ 少量工具,但:
- ❌ 没有自主循环
- ❌ 没有持久记忆
- ❌ 没有多 Agent 协作
- ❌ 没有代码级控制
真正的 Agent 需要代码。自定义 GPTs 是让你体验 Agent 的感觉,但做不到 Agent 的事。
结语
上一篇,我们给 AI 写了一份岗位说明书。 这一篇,我们招了一个人。
arduino
Skill: "你告诉我怎么做,我就怎么做。"
Agent: "你告诉我目标,我自己想办法。"
82 行代码,一个会搜索、会写文件、会自己判断"够不够"的 Research Agent。
再加 100 行,它有了两个同事:一个写代码,一个审代码。审查不通过,自己打回重写。
这不是科幻。这是 2026 年一个周二下午,我坐在工位上干的事。
OpenAI 做了 Agents SDK。10 万开发者已经在用了。
现在轮到你了。
从那个你每天都要手动协调 3 个步骤才能完成的任务开始。 把它交给一个 Agent。 然后看着它自己跑完。
那种感觉------就像你终于招到了一个不用催的同事。
系列回顾:
- 第 1 篇:《基于四层Skill体系的前端团队AI提效实践》
- *第 2 篇:《别再凭感觉调 Prompt 了:8 个 Demo 带你把 Prompt 当代码管》
- 第 3 篇:《一份 AGENTS.md,让 AI 代码规范率从 60% 飙升到 95%》
- 第 4 篇:《你的 AI Skill 越多越蠢?Token 上下文爆炸的求生指南》
- 第 5 篇:《手把手书写你的第一个 AI Skill》
参考来源
| 来源 | 内容 |
|---|---|
| OpenAI Agents SDK | 官方文档 + GitHub README(Agent / Handoff / Guardrails / Tracing) |
| CrewAI | GitHub README(Crews + Flows 双模式) |
| LangGraph | GitHub README(状态机 / 持久执行 / Human-in-the-loop) |
| AutoGen | Microsoft GitHub(Actor 模型 / 事件驱动) |
| Ollama | GitHub README(本地部署 / REST API / OpenAI 兼容接口) |
| Anthropic | Agentic Systems 官方文档 |
| LiteLLM | 多模型统一代理 |