3. 函数调用入门

大语言模型本身只能生成文本,它无法直接查询实时股价、读取数据库或执行交易指令。函数调用(Function Calling)正是打通“语言理解”与“真实业务动作”之间的桥梁。本节将从概念、工作原理、 接口结构到金融场景示例,带你完成第一次真正意义上的工具调用。

一、核心原理:函数调用到底在做什么

函数调用的本质,是让模型在对话过程中输出一段结构化的调用意图,而不是直接执行代码。模型负责“决定调用哪个函数、传什么参数”,真正的执行由你的后端程序完成,再把结果回传给模型,由模型生成最终自然语言回答。

这个过程可以拆解为三个角色:

  • 模型:理解用户意图,判断是否需要调用工具,并生成符合约定的参数 JSON。
  • 应用程序:接收模型的调用请求,执行真实的函数逻辑(如查数据库、调 API)。
  • 函数/工具:具体业务能力的实现,例如 get_stock_price、calculate_loan_rate。
关键认知:模型不会“执行”函数,它只是“提议”调用。执行权始终在你手中,这也是金融场景安全可控的基础。

下图展示了用户提问、模型决策、应用执行、结果回传的完整数据流:

函数调用数据流 用户提问 “茅台现在多少钱?” 大语言模型 判断需调用函数 应用程序 解析参数并执行 金融函数 get_stock_price 返回函数执行结果(JSON) 模型生成最终回答

二、 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)

典型应用场景包括:

  • 行情查询:实时股价、汇率、指数点位。
  • 财务计算:贷款月供、复利收益、风险敞口。
  • 数据检索:从内部数据库拉取客户持仓、交易流水。
  • 合规校验:调用风控规则接口判断交易是否越限。

四、常见误区与复盘

  1. 把函数调用当成自动执行:模型只返回意图,必须由应用层显式执行并回传结果,否则对话会中断。
  2. 函数描述写得过于简略:description 是模型选择工具的主要依据,描述模糊会导致误调用或漏调用。
  3. 忽略参数校验:模型可能生成非法参数,金融场景必须在执行前做类型、范围、权限校验。
  4. 忘记回传 tool_call_id:回传结果时缺少该字段,接口会报错,无法完成闭环。
  5. 一次声明过多工具:工具数量过多会降低选择准确率,建议按业务域拆分或使用 tool_choice 约束。
复盘要点:函数调用的可靠性 = 清晰的函数描述 + 严格的参数校验 + 完整的消息闭环。三者缺一,金融智能体就可能“说得多、做得错”。

掌握本节内容后,你已经能让模型从“只会聊天”升级为“能查、能算、能调”的金融助手。下一阶段将围绕多函数编排与调用链设计展开,让智能体处理更复杂的业务任务。