Function Calling(函数调用),更准确的称呼是“工具调用(Tool Calling)”,它是指大语言模型(LLM)在生成回复时,不直接输出纯文本,而是输出一个结构化的指令(JSON),这个指令指明了“该调用哪个外部函数,以及传入什么参数”。
核心一句话:LLM 只负责“决定”要不要调用工具、调用哪个工具、传什么参数,但它“绝不执行”这个工具。真正的执行由你的代码(Agent)来完成。
1. 完整的工作流程(结合你的 LangGraph 代码)
这和你之前写的llm.bind_tools(tools)和ToolNode完全对应:
- 注册工具:你用
llm.bind_tools([get_weather, search_web])把工具的定义(名称、描述、参数 Schema)告诉 LLM。LLM 知道有这些工具存在。 - 用户提问:用户说 “北京今天天气怎么样?”
- LLM 决策:LLM 推理后,决定调用
get_weather工具,并生成一个 JSON 结构(即tool_calls):{"name":"get_weather","args":{"city":"北京"}} - Agent 拦截与执行:你的 LangGraph 代码(
ToolNode)解析这个 JSON,在 Python 中实际执行get_weather("北京")函数,拿到结果(如 “晴天 25°C”)。 - 结果回传:
ToolNode把结果包装成ToolMessage送回给 LLM。 - 最终回复:LLM 看到工具结果后,组织语言回复用户:“北京今天天气晴朗,25°C。”
2. 在你代码中的具体体现(LangGraph)
你之前写的这段代码,就是 Function Calling 的完整实现:
# 1. 绑定工具(让 LLM 知道这些工具的存在)llm_with_tools=llm.bind_tools(tools)# 2. LLM 生成 tool_calls(函数调用指令)response=awaitllm_with_tools.ainvoke(state["messages"])# response.tool_calls 就是那个 JSON 数组# 3. ToolNode 自动解析并执行,返回 ToolMessage# 这就是 LangGraph 内置的 ToolNode 帮你做的事情3. Function Calling 的三大价值(面试必答)
- 结构化输出:输出是严谨的 JSON,而不是自然语言,便于程序解析。
- 确定性调度:模型明确告诉你“我要用这个工具”,而不是让你去猜测它的意图。
- 解耦:模型只需理解工具功能,无需关心工具的具体实现(比如天气接口是 HTTP 还是 gRPC)。
4. 面试高频追问:“Function Calling 和 MCP 有什么关系?”
这是对你之前学过的 MCP 知识的极佳串联,你可以这样回答:
“Function Calling 是 LLM 的‘决策协议’,规定了大模型如何表达‘我想调用工具’这一意图(即
tool_calls的格式)。而MCP(Model Context Protocol)是‘工具部署协议’,规定了工具如何被注册、发现和通信(stdio/SSE)。通俗理解:Function Calling 是 LLM下达指令的标准(填什么单子);MCP 是工具上架的标准(工具在哪、怎么调用)。在 LangChain 中,
bind_tools处理的是 Function Calling(让模型学会填单子),MultiServerMCPClient处理的是 MCP(帮你去远程货架取工具)。两者配合,才能让 Agent 既能做出正确决策,又能灵活接入跨语言、跨进程的庞大工具生态。”
5. 技术细节补充(拉开差距的回答)
如果面试官追问“Function Calling 的实现原理是什么?”
“在训练阶段,模型被微调(Fine-tuned)来学习识别特殊的
<tool_call>标记或特定的 JSON Schema。在推理时,模型通过约束解码(Constrained Decoding),每一步生成 token 时都受到 JSON Schema 的限制,从而保证输出的args一定是有效的 JSON,并且参数名和类型与定义完全匹配。这也是为什么tool_choice="required"能强制模型必须调用工具——因为我们在解码层直接屏蔽了输出普通文本的可能性。”