什么是Function Calling?
Function Calling是一种让大语言模型(LLM)能够与外部工具和系统交互的机制。它允许模型在需要时识别并调用适当的工具来获取信息或执行作。
工作原理
- 工具定义: 首先,开发者需要定义模型可以使用的工具列表,每个工具包括:
- 名称(name)
- 描述(description)
- 参数信息(parameters),通常使用JSON Schema格式
- 模型决策: 当用户提出问题时,模型会:
- 分析问题是否需要外部工具
- 如果需要,决定调用哪个工具
- 生成符合要求的参数
- 结构化输出: 模型会输出一个结构化的响应,通常是类似这样的JSON格式:
{
"name": "get_weather",
"arguments": {
"location": "北京"
}
}
- 后端执行: 应用程序的后端会执行如下操作。
- 解析模型的输出
- 根据工具名称找到对应的函数
- 使用提供的参数执行该函数
- 获取执行结果
- 结果反馈: 执行结果会作为新的上下文提供给模型,模型基于这些信息生成最终的自然语言响应。
为什么 Function Calling 不够用,要有 MCP?
Function Calling 有哪些问题?
- 格式依赖和脆弱性问题
- 模型可能输出不规范的JSON
- 可能缺少必要字段或参数
- 格式错误导致整个工具调用失败
- 需要复杂的Prompt工程来约束输出格式
- 缺乏标准化
- 工具难以在不同平台间移植
- 需要为每个平台重新实现工具集成
- 增加了开发和维护成本
- 工具发现机制不足
- 工具列表通常在会话开始时静态定义
- 难以动态添加或移除工具
- 工具元数据描述能力有限
- 错误处理不统一
- 每个实现都有自己的一套错误处理机制
- 难以建立统一的错误恢复策略
- 错误信息传递不规范
MCP 如何解决?
1. 标准化的通信协议
MCP基于JSON-RPC 2.0标准:
// 标准的MCP工具调用请求
{
"jsonrpc": "2.0",
"id": "1",
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": {
"location": "北京"
}
}
}
// 标准的响应格式
{
"jsonrpc": "2.0",
"id": "1",
"result": {
"temperature": "25°C",
"condition": "晴天"
}
}
// 标准的错误格式
{
"jsonrpc": "2.0",
"id": "1",
"error": {
"code": -32601,
"message": "Method not found"
}
}
2. 动态工具发现
// 工具发现请求
{
"jsonrpc": "2.0",
"id": "2",
"method": "tools/list",
"params": {}
}
// 工具列表响应
{
"jsonrpc": "2.0",
"id": "2",
"result": [
{
"name": "get_weather",
"description": "获取指定地点的天气信息",
"inputSchema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "地点名称"
}
}
}
}
]
}
3. 标准化的初始化和能力协商
// 初始化请求
{
"jsonrpc": "2.0",
"id": "init-1",
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": {},
"resources": {}
},
"clientInfo": {
"name": "MyAIApp",
"version": "1.0.0"
}
}
}
场景对比
-
Function Calling场景
- 开发者需要为每个LLM平台编写不同的工具集成代码
- 工具调用容易因模型输出格式问题而失败
- 工具管理复杂,难以动态扩展
-
MCP场景
- 一次编写,到处使用(Write Once, Run Everywhere)
- 标准化协议确保工具调用的可靠性
- 动态工具发现和注册机制便于扩展