《AI Agent 从入门到精通》· 第 1 期类型: 技术教学 · 入门 | 预计阅读: 10 分钟 | 前置: 会 Python、有一个能调用大模型的 API Key
🎯 一句话概括
市面上把 AI Agent 讲得云里雾里,又是框架又是黑话。但剥开外壳,它的内核就是一个 while 循环 + 让模型调用工具。这一期,我们不装框架、不抄模板,用 ~50 行 Python 从零手写一个能查天气的 Agent,把"智能体"这层神秘感彻底拆穿。
🤔 为什么从"手写"开始
你可能已经刷到过无数"LangChain 10 分钟搭 Agent"的教程。问题是:跟着敲完,你会用了,但完全不知道它背后发生了什么——模型怎么知道要调工具?参数哪来的?循环是谁在转?
这正是初级和高级 Agent 工程师的分水岭。所以本系列反其道而行:前几期一行框架都不用,先把 Agent 的发动机手写出来。等你看清了发动机,再用框架(第 9 期)时,它对你就不再是黑盒,而是"哦,它不过是帮我把这个循环包了一层"。
📖 核心概念:Agent 到底是什么
一句话定义:
Agent = 大模型(会思考)+ 工具(能动手)+ 循环(持续推进)+ 终止条件(知道何时停)。
为什么需要这四样?因为大模型本身只会"说话",不会"做事"。
你问它"北京现在几度",它要么瞎编一个数(它没有实时数据),要么诚实地说"我查不到"。它没有手,碰不到真实世界。
Agent 干的事,就是给模型装上手(工具),然后在一个循环里,让它反复地「想 → 调工具 → 看结果 → 再想」,直到任务完成。
⚙️ 原理:一次 Agent 循环里发生了什么
把一次"查天气"拆开看,模型和你的代码是这样配合的:
你: 北京现在天气怎么样? │ ▼ 模型: (我答不了,但我看到有个 get_weather 工具) → 我要调用 get_weather(city="北京") ← 模型只是"提议"调用 │ ▼ 你的代码:真正执行 get_weather("北京") → "晴,12℃" ← 真正动手的是你的代码! 把结果塞回去给模型 │ ▼ 模型: (拿到结果了)北京现在天气晴,气温 12℃。 ← 不再调工具 = 循环结束
这里有一个最关键、也最反直觉的认知:
模型从来没有真的调用任何工具。它只是输出一段"我想调用 get_weather,参数是北京"的结构化文本。真正执行工具的,永远是你的代码。
记住这一点,你以后就不会写出失控的 Agent——因为每一个动作都掌握在你手里。
那个反复"想→调→看→再想"的过程,就是 agent loop(智能体循环)。模型不再要求调工具时,循环就停。
🛠️ 动手实操:50 行手写天气 Agent
第 0 步:装库、配 Key
pipinstallanthropic
# Windows PowerShell$env:ANTHROPIC_API_KEY="你的key"
第 1 步:定义一个"工具"
工具的本质,是一段普通的 Python 函数 + 一份给模型看的说明书(JSON Schema)。说明书告诉模型:这个工具叫什么、干什么用、需要什么参数。
# 1) 工具的"说明书"——模型靠它决定要不要调、参数怎么填WEATHER_TOOL={"name":"get_weather","description":"查询某个城市的当前天气。当用户询问天气时调用。","input_schema":{"type":"object","properties":{"city":{"type":"string","description":"城市名,如:北京"}},"required":["city"],},}# 2) 工具的"真身"——真正干活的函数(这里先写死,真实场景换成天气 API)defget_weather(city:str)->str:fake_db={"北京":"晴,12℃","上海":"多云,18℃","广州":"小雨,24℃"}returnfake_db.get(city,f"暂无 {city} 的天气数据")
💡 这里天气是写死的假数据,为的是让你聚焦"循环"本身。第 2 期我们会接真实工具。
第 2 步:手写 agent loop
这是整个 Agent 的心脏。逐行读懂它,你就懂了 80% 的 Agent:
import anthropicclient=anthropic.Anthropic()# 自动读环境变量里的 ANTHROPIC_API_KEYdefrun_agent(user_input:str)->str:messages=[{"role":"user","content":user_input}]whileTrue:# ← 这就是传说中的 agent loopresp=client.messages.create(model="claude-opus-4-8",max_tokens=1024,tools=[WEATHER_TOOL],# 把工具"说明书"交给模型messages=messages,)# 情况 A:模型不再调工具,说明它要给最终答复了 → 收工ifresp.stop_reason=="end_turn":returnnext(b.textforbinresp.contentifb.type=="text")# 情况 B:模型提议调用工具# 先把模型这一轮的输出(含 tool_use)原样存进历史messages.append({"role":"assistant","content":resp.content})# 找出所有 tool_use 块,逐个真正执行tool_results=[]forblockinresp.content:ifblock.type=="tool_use":result=get_weather(**block.input)# ← 你的代码真正动手tool_results.append({"type":"tool_result","tool_use_id":block.id,# 用 id 把结果和请求配对"content":result,})# 把工具结果作为一条 user 消息塞回去,进入下一轮循环messages.append({"role":"user","content":tool_results})
第 3 步:跑起来
if__name__=="__main__":print(run_agent("北京现在天气怎么样?适合穿短袖吗?"))
运行后你会看到,它先自己调了 get_weather("北京"),拿到"晴,12℃",再结合常识回答"12℃ 偏凉,不建议穿短袖"。你没写任何 if-else 去判断它该不该查天气——是模型自己决定的。 这就是 Agent 的"自主性"第一次显形。
⚠️ 常见误区
| |
|---|
| |
| |
| |
tool_result | 必须用 tool_use_id 和请求一一配对,否则模型对不上号 |
| 它是模型决定"调不调、怎么调"的唯一依据,必须写清楚 |
📌 要点回顾
- Agent = 模型 + 工具 + 循环 + 终止条件
- 大模型只会"说话",工具给了它"手";但真正执行工具的是你的代码。
- 一轮循环 = 模型提议调工具 → 你执行 → 结果回填 → 模型继续,直到
stop_reason == "end_turn"。 - 工具 = 普通函数 + 一份 JSON Schema 说明书。
- 看懂这 50 行,你已经超过了一大批"只会调框架不懂原理"的人。
✍️ 动手练习
- 加一个工具:照着
WEATHER_TOOL 的样子,再写一个 get_time(timezone) 查时间的工具,挂进 tools=[...],问它"东京现在几点、天气如何",观察它连调两个工具。 - 故意写错 description:把
get_weather 的 description 改成空字符串,看模型还会不会调它——体会"说明书"有多重要。 - 打印中间过程:在循环里
print(resp.stop_reason) 和每次调用的 block.input,亲眼看它"想→调→看→再想"的全过程。
把第 1 题做出来,你就为第 3 期的"多步任务规划"埋好了种子。
🔮 下期预告
第 2 期《工具调用(Function Calling)原理:Agent 的"手"是怎么长出来的》——这一期我们只用了一个工具。下期深入拆解:模型到底怎么决定调哪个工具、参数从哪来、多个工具怎么调度、调错了怎么兜底。我们会给 Agent 挂上"计算器 + 搜索 + 读文件"三件套。
《AI Agent 从入门到精通》第 1 期 · 2026-06-11