Function Calling 是 LLM 连接外部世界的桥梁——不是让 LLM 直接执行代码,而是让 LLM 告诉系统应该调用哪个函数和什么参数,系统执行后再把结果返回给 LLM。
一、工作原理
1 2 3 4 5 6 7 8
| 用户: "今天北京天气怎么样?"
LLM 判断: 需要调用 get_weather 函数 → 返回 function_call: {name: "get_weather", arguments: {city: "北京"}}
系统: 执行 get_weather(city="北京") → "25°C,晴"
LLM 接收函数结果: "今天北京天气晴朗,温度25°C"
|
OpenAI 格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| { "model": "gpt-4", "messages": [{"role": "user", "content": "今天北京天气怎么样?"}], "tools": [{ "type": "function", "function": { "name": "get_weather", "description": "获取指定城市的天气信息", "parameters": { "type": "object", "properties": { "city": {"type": "string", "description": "城市名称"} }, "required": ["city"] } } }] }
|
LLM 返回:
1 2 3 4 5 6 7 8 9
| { "role": "assistant", "tool_calls": [{ "function": { "name": "get_weather", "arguments": "{\"city\": \"北京\"}" } }] }
|
二、实现循环
真正的 Agent 需要多次调用 Function Calling:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| def run_agent(user_query, tools, max_iterations=5): messages = [{"role": "user", "content": user_query}] for _ in range(max_iterations): response = llm.invoke(messages, tools=tools) msg = response.choices[0].message if msg.tool_calls: messages.append(msg) for tool_call in msg.tool_calls: result = execute_tool(tool_call) messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": result }) else: return msg.content
|
三、关键设计
LLM 根据 description 决定何时调用哪个工具——一个模糊的 description 会导致 LLM 不调用或调用错误。
1 2 3 4 5 6 7 8 9 10 11
| {"name": "process", "description": "处理数据"}
{ "name": "query_database", "description": "执行 SQL 查询并返回结果。仅在用户明确要求查询数据库时使用。", "parameters": { "sql": {"type": "string", "description": "要执行的 SQL 语句"} } }
|
强制调用
有些场景需要强制调用工具,可以设置 tool_choice:
1 2 3 4 5 6
| { "tool_choice": { "type": "function", "function": {"name": "get_weather"} } }
|
并行调用
LLM 可以同时返回多个 tool_calls(并行执行无依赖的工具):
1 2 3 4 5 6
| { "tool_calls": [ {"function": {"name": "get_weather", "arguments": "{\"city\":\"北京\"}"}}, {"function": {"name": "get_weather", "arguments": "{\"city\":\"上海\"}"}} ] }
|
四、与 LangGraph 的结合
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| from langgraph.graph import StateGraph, END
def decide_next(state): response = llm.invoke(state["messages"], tools=tools) if response.tool_calls: return "execute_tools" return "end"
graph.add_node("llm", call_llm) graph.add_node("tools", execute_tools) graph.add_conditional_edges("llm", decide_next, {"execute_tools": "tools", "end": END}) graph.add_edge("tools", "llm")
|
五、小结
Function Calling 的核心不是”LLM 调用函数”,而是”LLM 说出它想调用什么”。执行权始终在系统端——这意味着你可以加入权限控制、人工审批、调用审计等安全机制。这是 Agent 安全性的重要保障。