从零搭建实用Agent:让AI学会用工具(收藏版,小白程序员进阶必看)
本文通过裸API和CrewAI框架两种方式,详细介绍了如何构建一个能使用工具的AI Agent。首先,通过裸API实现最小功能的Agent,帮助读者理解核心机制;其次,使用CrewAI框架快速实现相同功能,展示框架如何简化开发流程;最后,对比两种方式,分析何时适合使用框架,何时需要手动编写代码。文章包含可运行代码,适合想要学习大模型开发的程序小白。
但我不会一上来就甩框架代码。如果你不知道底层发生了什么,用框架就是"会开车但不知道发动机怎么转"——能跑,但出了问题不知道去哪修。
所以这篇的路线是:
先用裸 API 搭一个最小的 Tool Use Agent——理解核心机制
再用 CrewAI 实现同样的功能——感受框架帮你省了什么
对比两种方式——你就知道什么时候该用框架,什么时候裸写够了
全程可运行代码,跟着做就能跑。
一、Tool Use 到底是怎么回事
先搞清楚一件事:AI 不会直接执行任何操作。
很多人以为 Tool Use 是"AI 直接调 API",其实不是。整个过程是这样的:
用户提问:“北京明天天气怎么样?”
AI 判断:这个问题我自己答不了,但我有一个
get_weather工具可以用AI 发出请求:
get_weather(location="北京")——注意,AI 只是说它要用这个工具你的代码执行:你写的代码真正去调天气 API,拿到结果
结果返回给 AI:
{"temp": 22, "condition": "晴"}AI 生成回答:“北京明天 22 度,晴天,适合出门。”
AI 是"大脑",你的代码是"手脚"。 AI 决定做什么,你的代码去执行。这也是 Tool Use 安全的原因——你完全控制哪些工具可用、怎么执行。
二、裸 API 实现:先懂发动机
我们用 Claude 的 API 来做最小实现。选 Claude 是因为它的 Tool Use 设计更清晰——用stop_reason明确告诉你"我需要调工具",而不是让你猜。文末附 OpenAI 版本差异对照。
2.1 环境准备
pip install anthropic设置 API Key:
# Windows set ANTHROPIC_API_KEY=sk-ant-你的key # Mac/Linux export ANTHROPIC_API_KEY="sk-ant-你的key"2.2 第一步:定义工具
工具定义就是一份 JSON “说明书”——告诉 AI 你有什么工具、需要什么参数:
tools = [ { "name": "get_weather", "description": "获取指定城市的当前天气信息。当用户询问天气相关问题时使用。", "input_schema": { "type": "object", "properties": { "location": { "type": "string", "description": "城市名称,如'北京'、'上海'" } }, "required": ["location"] } } ]重点:
description要写清楚"什么时候用这个工具"。写得越具体,AI 判断越准。
2.3 第二步:写执行函数
工具描述是给 AI 看的,执行函数是给你写的:
import json def get_weather(location: str) -> str: """模拟天气查询(实际项目替换为真实 API)""" weather_data = { "北京": {"temp": 22, "condition": "晴", "humidity": 45}, "上海": {"temp": 26, "condition": "多云", "humidity": 72}, "深圳": {"temp": 30, "condition": "阵雨", "humidity": 85}, } data = weather_data.get(location, {"temp": 20, "condition": "未知", "humidity": 50}) return json.dumps(data, ensure_ascii=False)2.4 第三步:完整的 Tool Use 循环
核心代码——AI 判断 → 工具调用 → 结果返回 → AI 回答:
from anthropic import Anthropic import json client = Anthropic() # 工具注册表(名字 → 函数) tool_registry = { "get_weather": get_weather, } def chat_with_tools(user_message: str): messages = [{"role": "user", "content": user_message}] while True: # 调用 Claude,带上工具列表 response = client.messages.create( model="claude-sonnet-4-6", max_tokens=1024, system="你是一个有用的助手,可以查询天气信息。", tools=tools, messages=messages, ) # Claude 明确告诉你:我需要调工具 if response.stop_reason == "tool_use": # 把 AI 的回复加入对话历史 messages.append({"role": "assistant", "content": response.content}) # 找到 tool_use 块,执行对应函数 for block in response.content: if block.type == "tool_use": func = tool_registry.get(block.name) result = func(block.input) if func else '{"error": "未知工具"}' # 把工具结果告诉 Claude messages.append({ "role": "user", "content": [{ "type": "tool_result", "tool_use_id": block.id, "content": result }] }) # 继续循环,让 Claude 处理结果 else: # 不再需要工具,返回最终回答 return response.content[0].text # 测试 print(chat_with_tools("北京今天天气怎么样?")) # → 北京今天晴朗,气温 22°C,湿度 45%,非常适合外出。 print(chat_with_tools("什么是量子力学?")) # → 量子力学是物理学的一个分支...(没有调用工具)这段代码大约 40 行。 记住这个数字,等下跟 CrewAI 对比。
Claude 的 Tool Use 有一个优雅的设计:stop_reason == "tool_use"明确告诉你"我停下来是因为要用工具"。加上while True循环,Claude 可以连续调用多个工具——比如你问"北京和上海天气怎么样",它会连续调两次get_weather。
把这个过程画成时序图,会更直观:
关键点:每次调用 API 时,messages数组都要把之前的所有历史完整传回去。AI 没有真正的"记忆",它的"上下文"就是你传给它的 messages。
2.5 完整项目结构
跟着上面跑通后,你的项目长这样——4 个文件就够了:
my-first-agent/ ├── .env # ANTHROPIC_API_KEY=sk-ant-xxx ├── requirements.txt # anthropic ├── tools.py # 工具函数(执行层) └── agent.py # 主程序(描述层 + 编排层)为什么是这个结构?
tools.py单独放:加新工具只动这个文件,不污染主逻辑
tool_registry字典分派:加工具就是字典 + 工具描述各加一项,主循环不动
主循环写一次能用:while True + stop_reason处理任意复杂的多轮工具调用
不要agents/子目录、不要__init__.py:项目还小,别过度组织
扩展时怎么加? 接真实天气 API 只改tools.py里函数体;加新工具就tools.py加函数 +agent.py的tool_registry和tools各加一项。
三、CrewAI 实现:开自动挡
同样的功能——查天气的 Agent,用 CrewAI 怎么写?
3.1 安装
pip install crewai crewai-tools3.2 定义工具
CrewAI 用装饰器定义工具,比写 JSON Schema 直观得多:
from crewai.tools import tool @tool("查询天气") def get_weather(location: str) -> str: """获取指定城市的当前天气信息。当用户询问天气时使用。 Args: location: 城市名称,如'北京'、'上海' """ weather_data = { "北京": {"temp": 22, "condition": "晴", "humidity": 45}, "上海": {"temp": 26, "condition": "多云", "humidity": 72}, "深圳": {"temp": 30, "condition": "阵雨", "humidity": 85}, } data = weather_data.get(location, {"temp": 20, "condition": "未知", "humidity": 50}) return str(data)注意:同样的执行逻辑,但不需要手写 JSON Schema。CrewAI 从函数签名和 docstring 自动生成工具描述。
3.3 定义 Agent 和 Task
from crewai import Agent, Task, Crew # 定义 Agent(角色) weather_agent = Agent( role="天气助手", goal="准确回答用户的天气查询", backstory="你是一个专业的天气查询助手,能获取各城市的实时天气信息。", tools=[get_weather], verbose=True # 打印推理过程,方便调试 ) # 定义 Task(任务) weather_task = Task( description="用户问:{query}", expected_output="用自然语言回答天气情况,包含温度、天气状况和建议", agent=weather_agent, ) # 组建 Crew(团队) crew = Crew( agents=[weather_agent], tasks=[weather_task], verbose=True )3.4 运行
result = crew.kickoff(inputs={"query": "北京今天天气怎么样?"}) print(result)输出(verbose 模式会打印推理过程):
> Entering new CrewAgentExecutor chain... I need to check the weather in Beijing. Action: 查询天气 Action Input: {"location": "北京"} Observation: {'temp': 22, 'condition': '晴', 'humidity': 45} Thought: I now have the weather data for Beijing. Final Answer: 北京今天天气晴朗,气温 22°C,湿度 45%,适合出门活动。这段日志其实就是 Agent 的"内心独白"——Thought(思考)→ Action(行动)→ Observation(观察) 的循环,直到收敛到最终答案:
这个 Thought-Action-Observation 模式叫 ReAct(Reasoning + Acting),是 Agent 推理的经典范式。我们在第 3 篇《Agent 怎么想问题》里详细讲过。CrewAI 默认就是这个模式。
CrewAI 版核心代码大约 20 行。 裸 API 版 40 行。框架帮你省了一半。
3.5 完整项目结构
CrewAI 版结构比裸 API 还简单——3 个文件就够了:
my-crewai-agent/ ├── .env # ANTHROPIC_API_KEY=sk-ant-xxx ├── requirements.txt # crewai + crewai-tools └── agent.py # 工具 + Agent + Task + Crew 全在一起为什么比裸 API 还少一个文件?@tool装饰器把"工具描述"和"工具实现"合并了——不需要单独维护 JSON Schema。
几个 CrewAI 特有的坑要注意:
依赖比较重:首次pip install要几分钟(几十个包)。建议用独立虚拟环境,跟裸 API 项目分开
默认走 OpenAI:要用 Claude 必须显式LLM(model="claude-..."),否则会去找OPENAI_API_KEY而报错
verbose=True是金矿:能看到完整的 Thought → Action → Observation 推理日志,调试必开
不要写 system prompt:CrewAI 用role + goal + backstory三件套替代,强行写 system 会冲突
四、对比:框架到底帮你省了什么?
两种方式实现同样的功能,区别在哪?
| 维度 | 裸 API | CrewAI |
|---|---|---|
| 工具定义 | 手写 JSON Schema(容易出错) | 装饰器 + docstring(自动生成) |
| 对话循环 | 自己写 if/while 判断 | 框架自动处理 |
| 工具分派 | 自己写if func_name == "xxx" | 框架自动根据工具名分派 |
| 错误处理 | 自己加 try-except | 框架有内置重试机制 |
| 推理过程 | 看不到(除非手动打印) | verbose=True直接看 |
| 核心代码行数 | ~40 行 | ~20 行 |
| 多工具扩展 | 每加一个工具,要改分派逻辑 | 往tools=[]列表加就行 |
框架帮你省的不是"写代码的时间",而是"出错的概率"。 JSON Schema 手写一个字段名拼错,调试半天。对话循环多一个 append 少一个 append,结果完全不同。框架把这些容易出错的部分标准化了。
那什么时候用裸 API? 当你的 Agent 逻辑极简(就一个工具、一轮对话),或者你需要极致性能(框架有额外开销),裸 API 反而更合适。
五、进阶:多工具 Agent
不管裸 API 还是 CrewAI,真正有用的 Agent 需要多个工具。我们加一个"记笔记"功能。
CrewAI 版(推荐)
from crewai.toolsimporttool notes=[]@tool("记笔记")def add_note(content: str)->str:"""当用户要求记录、保存、备忘某些信息时,调用此工具保存笔记。 Args: content: 要记录的笔记内容""" notes.append(content)returnf"已记录,当前共 {len(notes)} 条笔记"@tool("查看笔记")def list_notes()->str:"""当用户要求查看、列出已有笔记时调用。"""ifnot notes:return"暂无笔记"return"\n".join(f"{i+1}. {n}"fori, ninenumerate(notes))# Agent 直接挂上多个工具assistant=Agent(role="私人助手",goal="帮用户查天气、记笔记,做一个贴心的助手",backstory="你是用户的私人AI助手,能查天气也能记笔记。",tools=[get_weather, add_note, list_notes],verbose=True)加工具就是往tools=[]列表里加——不用改分派逻辑、不用改对话循环。 这就是框架的价值。
AI 会自动判断用户意图:
“北京天气” → 调get_weather
“帮我记一下明天开会” → 调add_note
“我记了什么” → 调list_notes
“1+1等于几” → 不调工具,直接答
六、三个常见坑
不管用哪种方式,这三个坑你大概率会踩:
6.1 工具描述太模糊,AI 不会用
症状:你问"帮我记个事儿",AI 没调add_note,而是回复"好的,你要记什么?"
解法:description 写清楚触发条件:
# 模糊 ❌ """一个笔记工具""" # 清晰 ✓ """当用户要求记录、保存、备忘某些信息时,调用此工具保存笔记内容"""6.2 工具执行出错,AI 编造结果
症状:天气 API 超时,AI 回复了一个编造的天气。
解法:把错误信息明确返回:
@tool("查询天气") def get_weather(location: str) -> str: """...""" try: data = call_real_api(location) return str(data) except Exception as e: return f"查询失败:{str(e)}"AI 收到错误信息,会如实告诉用户"天气查询暂时不可用",而不是编数据。
6.3 工具太多,AI 选错了
症状:你注册了 20 个工具,AI 经常选错或同时调多个不相关的工具。
解法:
工具数量建议控制在 10 个以内
工具名和描述要互相区分,避免"记笔记"和"保存笔记"这种歧义
复杂场景考虑分 Agent——每个 Agent 只挂 3-5 个相关工具
七、OpenAI 版本差异速查
如果你用 OpenAI 而不是 Claude,核心逻辑完全一样,只是 API 格式不同:
| 差异点 | Claude(本文主线) | OpenAI |
|---|---|---|
| 安装 | pip install anthropic | pip install openai |
| 工具参数名 | input_schema | parameters(外包一层function) |
| 判断是否调工具 | stop_reason == "tool_use" | msg.tool_calls非空 |
| 返回工具结果 | type: "tool_result" | role: "tool" |
| 循环方式 | while True(天然支持多轮工具调用) | 通常两轮(请求→工具→回答) |
但如果你用 CrewAI,这些差异完全不用管。 CrewAI 底层自动适配不同模型,你换个 model 名字就行。这是用框架的另一个好处——屏蔽底层差异。
总结
这篇我们用两种方式搭了一个能用工具的 Agent:
裸 API(理解原理):
Tool Use = AI 说"我要用什么工具" + 你的代码去执行
核心是对话循环:用户 → AI 判断 → 工具调用 → 结果返回 → AI 回答
~40 行代码,适合极简场景
CrewAI(框架实现):
工具用装饰器定义,Agent 用角色描述,一键启动
自动处理工具分派、对话循环、推理日志
~20 行代码,适合大多数场景
如何学习大模型 AI ?
由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。
但是具体到个人,只能说是:
“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。
这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。
我在一线科技企业深耕十二载,见证过太多因技术卡位而跃迁的案例。那些率先拥抱 AI 的同事,早已在效率与薪资上形成代际优势,我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在大模型的学习中的很多困惑。我们整理出这套AI 大模型突围资料包:
- ✅ 从零到一的 AI 学习路径图
- ✅ 大模型调优实战手册(附医疗/金融等大厂真实案例)
- ✅ 百度/阿里专家闭门录播课
- ✅ 大模型当下最新行业报告
- ✅ 真实大厂面试真题
- ✅ 2026 最新岗位需求图谱
所有资料 ⚡️ ,朋友们如果有需要《AI大模型入门+进阶学习资源包》,下方扫码获取~
① 全套AI大模型应用开发视频教程
(包含提示工程、RAG、LangChain、Agent、模型微调与部署、DeepSeek等技术点)
② 大模型系统化学习路线
作为学习AI大模型技术的新手,方向至关重要。 正确的学习路线可以为你节省时间,少走弯路;方向不对,努力白费。这里我给大家准备了一份最科学最系统的学习成长路线图和学习规划,带你从零基础入门到精通!
③ 大模型学习书籍&文档
学习AI大模型离不开书籍文档,我精选了一系列大模型技术的书籍和学习文档(电子版),它们由领域内的顶尖专家撰写,内容全面、深入、详尽,为你学习大模型提供坚实的理论基础。
④ AI大模型最新行业报告
2025最新行业报告,针对不同行业的现状、趋势、问题、机会等进行系统地调研和评估,以了解哪些行业更适合引入大模型的技术和应用,以及在哪些方面可以发挥大模型的优势。
⑤ 大模型项目实战&配套源码
学以致用,在项目实战中检验和巩固你所学到的知识,同时为你找工作就业和职业发展打下坚实的基础。
⑥ 大模型大厂面试真题
面试不仅是技术的较量,更需要充分的准备。在你已经掌握了大模型技术之后,就需要开始准备面试,我精心整理了一份大模型面试题库,涵盖当前面试中可能遇到的各种技术问题,让你在面试中游刃有余。
以上资料如何领取?
为什么大家都在学大模型?
最近科技巨头英特尔宣布裁员2万人,传统岗位不断缩减,但AI相关技术岗疯狂扩招,有3-5年经验,大厂薪资就能给到50K*20薪!
不出1年,“有AI项目经验”将成为投递简历的门槛。
风口之下,与其像“温水煮青蛙”一样坐等被行业淘汰,不如先人一步,掌握AI大模型原理+应用技术+项目实操经验,“顺风”翻盘!
这些资料真的有用吗?
这份资料由我和鲁为民博士(北京清华大学学士和美国加州理工学院博士)共同整理,现任上海殷泊信息科技CEO,其创立的MoPaaS云平台获Forrester全球’强劲表现者’认证,服务航天科工、国家电网等1000+企业,以第一作者在IEEE Transactions发表论文50+篇,获NASA JPL火星探测系统强化学习专利等35项中美专利。本套AI大模型课程由清华大学-加州理工双料博士、吴文俊人工智能奖得主鲁为民教授领衔研发。
资料内容涵盖了从入门到进阶的各类视频教程和实战项目,无论你是小白还是有些技术基础的技术人员,这份资料都绝对能帮助你提升薪资待遇,转行大模型岗位。
