3. 函数调用入门
大语言模型本身只能生成文本,它无法直接查询实时股价、读取数据库或执行交易指令。函数调用(Function Calling)正是打通“语言理解”与“真实业务动作”之间的桥梁。本节将从概念、工作原理、 接口结构到金融场景示例,带你完成第一次真正意义上的工具调用。
一、核心原理:函数调用到底在做什么
函数调用的本质,是让模型在对话过程中输出一段结构化的调用意图,而不是直接执行代码。模型负责“决定调用哪个函数、传什么参数”,真正的执行由你的后端程序完成,再把结果回传给模型,由模型生成最终自然语言回答。
这个过程可以拆解为三个角色:
- 模型:理解用户意图,判断是否需要调用工具,并生成符合约定的参数 JSON。
- 应用程序:接收模型的调用请求,执行真实的函数逻辑(如查数据库、调 API)。
- 函数/工具:具体业务能力的实现,例如
get_stock_price、calculate_loan_rate。
关键认知:模型不会“执行”函数,它只是“提议”调用。执行权始终在你手中,这也是金融场景安全可控的基础。
下图展示了用户提问、模型决策、应用执行、结果回传的完整数据流:
二、 Function Calling 接口结构
在 Chat Completions 接口中,函数调用通过 tools 参数声明可用工具,模型返回 tool_calls 字段表达调用意图。核心字段如下:
| 字段 | 位置 | 作用 |
|---|---|---|
tools | 请求体 | 声明可用函数列表,含名称、描述、参数 schema |
tool_choice | 请求体 | 控制是否强制调用,如 auto、none 或指定函数 |
tool_calls | 响应体 | 模型返回的调用意图,含函数名与参数 JSON |
role: "tool" | 后续消息 | 回传函数执行结果,需带 tool_call_id |
一次完整的请求与响应结构如下:
// 请求
{
"model": "-mini",
"messages": [{"role": "user", "content": "查询贵州茅台最新股价"}],
"tools": [{
"type": "function",
"function": {
"name": "get_stock_price",
"description": "根据股票代码查询最新股价",
"parameters": {
"type": "object",
"properties": {
"symbol": {"type": "string", "description": "股票代码,如 600519"}
},
"required": ["symbol"]
}
}
}]
}
// 模型响应
{
"choices": [{
"message": {
"role": "assistant",
"tool_calls": [{
"id": "call_abc123",
"type": "function",
"function": {
"name": "get_stock_price",
"arguments": "{\"symbol\": \"600519\"}"
}
}]
}
}]
}
注意:
arguments 是字符串形式的 JSON,需要先 json.loads 解析后再使用,直接当字典用会报错。三、金融函数示例:从声明到执行
下面是一个最小可运行的金融函数调用闭环,包含函数声明、模型调用、结果回传三步:
import json
from import
client = ()
def get_stock_price(symbol: str) -> dict:
# 实际场景应调用行情 API
mock = {"600519": 1680.5, "000001": 11.2}
return {"symbol": symbol, "price": mock.get(symbol, 0)}
tools = [{
"type": "function",
"function": {
"name": "get_stock_price",
"description": "查询 A 股最新股价",
"parameters": {
"type": "object",
"properties": {"symbol": {"type": "string"}},
"required": ["symbol"]
}
}
}]
messages = [{"role": "user", "content": "茅台现在多少钱?"}]
resp = client.chat.completions.create(
model="-mini", messages=messages, tools=tools
)
msg = resp.choices[0].message
if msg.tool_calls:
call = msg.tool_calls[0]
args = json.loads(call.function.arguments)
result = get_stock_price(**args)
messages.append(msg)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": json.dumps(result, ensure_ascii=False)
})
final = client.chat.completions.create(
model="-mini", messages=messages, tools=tools
)
print(final.choices[0].message.content)
典型应用场景包括:
- 行情查询:实时股价、汇率、指数点位。
- 财务计算:贷款月供、复利收益、风险敞口。
- 数据检索:从内部数据库拉取客户持仓、交易流水。
- 合规校验:调用风控规则接口判断交易是否越限。
四、常见误区与复盘
- 把函数调用当成自动执行:模型只返回意图,必须由应用层显式执行并回传结果,否则对话会中断。
- 函数描述写得过于简略:
description是模型选择工具的主要依据,描述模糊会导致误调用或漏调用。 - 忽略参数校验:模型可能生成非法参数,金融场景必须在执行前做类型、范围、权限校验。
- 忘记回传
tool_call_id:回传结果时缺少该字段,接口会报错,无法完成闭环。 - 一次声明过多工具:工具数量过多会降低选择准确率,建议按业务域拆分或使用
tool_choice约束。
复盘要点:函数调用的可靠性 = 清晰的函数描述 + 严格的参数校验 + 完整的消息闭环。三者缺一,金融智能体就可能“说得多、做得错”。
掌握本节内容后,你已经能让模型从“只会聊天”升级为“能查、能算、能调”的金融助手。下一阶段将围绕多函数编排与调用链设计展开,让智能体处理更复杂的业务任务。