Agent 开发入门:Function Call 实战
接上篇《RAG 优化实战》。RAG 让模型"有资料可答",Function Call 让模型"能动手干活"——这是 Agent 的地基。今天讲透两种实现:原生 API + 手动 Prompt。
目录
一、Function Call 是什么
二、两种实现方式
方式A:原生API自动调用(框架帮你编排)
方式B:手动Prompt拼JSON(理解原理)
三、完整可运行代码
四、工具设计原则
五、过关清单
六、常见坑
七、下一步:从Function Call到Agent
一、Function Call 是什么
模型不会真的去查天气,它只会"说:我想调天气工具,参数是北京"。真正执行的是你的代码,执行完把结果塞回对话,模型再总结成自然语言。
用户提问 → 模型选工具+填参数 → 你的代码执行 → 结果塞回对话 → 模型总结回答
后端类比:模型=会自己选路由的Controller,执行权在你手里(你是Service层)
二、两种实现方式
方式A:原生API自动调用(框架帮你编排)
工具描述成JSON Schema随消息发给模型,模型选工具你执行。类比Spring @Autowired
方式B:手动Prompt拼JSON(理解原理)
提示词里写"可输出{"action":"..","params":{..}}",自己json.loads+switch分发。
价值:手动写一遍才真懂底层原理,面试讲原理不心虚;还能跑在不支持function call的模型上
三、完整可运行代码
def native_fc(question: str) -> str: """方式 A:原生 Function Call(框架帮你编排)。""" msgs = [{"role": "user", "content": question}] resp = client.chat.completions.create( model=FC_MODEL, messages=msgs, tools=TOOL_SCHEMAS ) msg = resp.choices[0].message if msg.tool_calls: # 把模型的"我想调工具"这条消息原样塞回去 msgs.append(msg.model_dump()) for call in msg.tool_calls: name = call.function.name args = json.loads(call.function.arguments) result = TOOLS_IMPL[name](**args) # 执行权在你:你跑,模型不跑 msgs.append({ "role": "tool", "tool_call_id": call.id, "name": name, "content": str(result) # 强制转字符串,防止JSON类型错误 }) # 结果塞回对话后,再让模型总结成自然语言 final = client.chat.completions.create(model=FC_MODEL, messages=msgs) return final.choices[0].message.content return msg.contentdef manual_fc(question: str) -> str: """方式 B:手动 Prompt(自己拼 JSON + 分发执行)。""" msgs = [ {"role": "system", "content": MANUAL_SYS}, {"role": "user", "content": question}, ] resp = client.chat.completions.create( model=FC_MODEL, messages=msgs, response_format={"type": "json_object"} ) out = resp.choices[0].message.content try: decision = json.loads(out) # 自己解析模型吐出的 JSON name = decision.get("action") if name in TOOLS_IMPL: # switch 分发:按 action 找到对应函数执行 result = TOOLS_IMPL[name](**decision.get("params", {})) msgs += [ {"role": "assistant", "content": out}, {"role": "user", "content": f"工具返回:{result},请据此回答。"}, ] final = client.chat.completions.create(model=FC_MODEL, messages=msgs) return final.choices[0].message.content except Exception as e: return f"解析失败:{e}" return out效果:问"北京今天多少度加3等于几"→模型自动调天气(25度)+计算(25+3=28)→输出"北京25度,加3等于28"
四、工具设计原则
单一职责(一工具一事)|参数清晰(类型/说明/范围)|结构化返回|执行权在你
五、过关清单
☐ 系统提示词让模型稳定按指定格式回答
☐ 原生FC:复合问题选≥2工具并按序调用
☐ 手动版:能解析JSON并正确执行工具
☐ 能讲清"原生vs手动"区别和适用场景
☐ 工具出错时模型能换工具或告知用户
六、常见坑
1. description写含糊→选错工具(写清含义/举例)
2. 工具返回一坨原始数据→裁剪成精简摘要
3. 模型输出不合法JSON→正则抽取或response_format强约束
4. 执行结果直接当答案→让模型再总结一轮
5. 写操作没确认→危险操作加白名单/人工确认
七、下一步:从Function Call到Agent
Function Call是"单次调用工具"。升级成循环(思考→行动→观察→再思考)就是Agent:ReAct循环。
下一篇预告:《Agent开发:ReAct循环与工具调用实战——从单次调用到自主Agent》。欢迎关注专栏,持续更新。
👉 关注公众号「程序员AI工坊」,回复「避坑」,免费领《后端转AI落地避坑清单》(8 个核心坑全文)。
📌 配套代码:(Star支持🔥)
https://github.com/cxy-ai-gongfang/backend-to-ai-guide/blob/main/function-call-demo/README.md
