前面所有应用都是「你问它答」。Agent 不同:给它一个目标,它自己拆步骤、选工具、看结果、再决策—— 今天手写 ReAct 循环(一个 while + Function Calling),不用任何 Agent 框架。
| 时间 | 环节 | 要点 |
|---|---|---|
| 0–8 | 开场对比 | 「123×456」普通对话可能算错;Agent 自己决定调计算器——精准 |
| 8–20 | ReAct 框架 | 思考→行动→观察循环;做菜类比;人类也这么解决问题 |
| 20–34 | 手写核心循环 | while + max_steps + 工具字典 + Function Calling——没有魔法 |
| 34–46 | 动手练习 | 运行场:人肉走一遍 ReAct(补全单位换算函数) |
| 46–58 | 实战工具设计 | 搜索/计算器/自定义工具;description 是写给 AI 的说明书 |
| 58–70 | 三种故障与防护 | 无限循环(max_steps)/错误传播(try+ERROR标注)/选择不当(描述分明) |
| 70–82 | 实战 Agent 演示 | 三步任务:搜面积→换算→计算——完整思考轨迹打印 |
| 82–92 | 边界讨论 | 什么任务交 Agent(路径未知)什么用确定代码(固定流程) |
| 92–100 | 小测 | 随堂小测 3 题 |
手写循环是本课核心——理解它,Agent 框架就再无魔法。
tools = {"calculator": calc_fn, "search": search_fn, "now": time_fn}
messages = [{"role": "user", "content": "中国面积能装下多少个足球场?"}]
for step in range(8): # max_steps:防无限循环!
resp = llm(messages, tools=tool_schemas) # 把工具说明书给模型
if not resp.tool_calls: # 不再调工具 = 任务完成
print("✓ 完成:", resp.text)
break
for call in resp.tool_calls:
print(f" 思考→行动: {call.name}({call.args})")
result = tools[call.name](**call.args) # 执行永远是代码的事
messages.append(tool_result(result)) # 结果喂回去,进入下一轮
整个 Agent = 一个循环 + 工具字典 + Function Calling。没有魔法。
补完 to_square_km 再运行——你刚刚执行了 Agent 的第三个工具调用。
深入阅读:M5 模块页 · FastAPI 实战续(异步/CORS)