大模型 Function Call 的原理及应用
目录
什么是 Function Call
Function Call 的工作原理
Function Call 的单一函数应用
Function Call 的多个函数应用
Function Call 实现数据库查询应用
什么是 Function Call
2023 年 6 月 13 日 OpenAI 公布了 Function Call(函数调用)功能,该功能指的是在语言模型中集成外部功能或 API 的调用能力,这意味着模型可以在生成文本的过程中调用外部函数或服务,获取额外的数据或执行特定的务。
Function Call 应用基本流程(简化):
Function Call 的功能
Function Call 可以解决大模型什么问题:
01、信息实时性,大模型训练的数据集无法包含最新的信息,如最新的新闻、实时股价等。通过 Function Call,模型可以实时获取最新数据,提供更加时效的服务。
02、数据局限性,模型训练数据虽多但有限,无法覆盖所有领域,如医学、法律等领域的专业咨询,Function Call 允许模型调用外部数据库或 API,获取特定领域的详细信息。
03、功能扩展性,大模型虽然功能强大,但不可能内置所有可能需要的功能。通过 FunctionCall,可以轻松扩展模型能力,如调用外部工具进行复杂计算、数据分析等。
Function Call 工作原理
当没有函数调用 (Function-call) 时候,我们调用 GPT 构建 AI 应用的模式非常简单。
主要步骤:
用户 (Client) 发请求给我们的服务 (Chat Server)
我们的服务 (Chat Server) 给 GPT 提示词
重复执行
当有函数调用 (Function-call) 时候,我们调用 GPT 构建 AI 应用的模式比之前要复杂一些。
主要步骤:
用户 (Client) 发请求 prompt 以及 functions 给我们的服务 (ChatServer)
GPT 模型根据用户的 prompt,判断是用普通文本还是函数调用的格式响应我们的服务 (Chat Server)
如果是函数调用格式,那么 Chat Server 就会执行这个函数,并且将结果返回给 GPT
然后模型使用提供的数据,用连贯的文本响应。返回
注意:大模型的 Function call 不会调用函数,仅返回函数的参数。开发者利用模型输出的参数在应用中调用函数。
思考总结
1、什么是 Function Call?
答案:在语言模型中集成外部功能或 API 的调用能力。
2、LLM 模型是否能够直接运行 function?
答案:不会调用函数,仅返回函数的参数。开发者利用模型输出的参数在应用中调用函数。
单一函数应用
假设我们要创建一个具备查询实时天气的聊天机器人。
基本流程如下:
1、准备工作,申请 API-KEY,配置环境变量。
2、定义 Funtion Tools,定义外部函数,描述函数功能
3、模型应用 Function Call 输入 prompt,模型输出函数参数,然后调用本地函数得到结果,融合消息再次送入模型,得到结果。
第一步:准备工作
模型选择:
国内外支持 Function Call 的模型,如:Deepseek、ChatGPT,智谱 ChatGLM3 等。
此次应用基于 ollama 的 qwen3:1.7b 来实现
第二步:定义 Function Tools
Function Tools
- 目的:定义查询天气的外部函数;2.描述函数功能;3.解析模型参数调用函数
- 代码路径:
./ChatGLM3_FunctionCall/weather/tools.py
- 具体代码:一共包含 2 个自定义函数,一个函数功能描述,具体请看下文
自定义 get_current_weather 函数
import json
import requests
from langchain_core.tools import tool
@tool
def get_current_weather(location):
"""得到给定地址的当前天气信息"""
# 读取城市及对应的邮政编码
str_data = open('./city_code.json', 'r', encoding='utf-8').read()
json_data = json.loads(str_data)
city_code = ""
weather_info = {}
for item in json_data:
if location == item["市名"]:
city_code = item["编码"]
# 调用天气查询 API 接口
if city_code:
weather_url = "http://t.weather.itboy.net/api/weather/city/" + city_code
response = requests.get(weather_url)
result1 = eval(response.text)
print(result1)
forecast = result1["data"]["forecast"][0]
print(forecast)
weather_info = {
"location": location,
"high_temperature": forecast["high"],
"low_temperature": forecast["low"],
"week": forecast["week"],
"type": forecast["type"],
}
return json.dumps(weather_info, ensure_ascii=False)
if __name__ == '__main__':
print(get_current_weather('昌平'))
[
{
"市名": "北京",
"编码": "101010100"
},
{
"市名": "海淀区",
"编码": "101010200"
},
{
"市名": "朝阳区",
"编码": "101010300"
},
{
"市名": "顺义区",
"编码": "101010400"
},
{
"市名": "怀柔区",
"编码": "101010500"
},
{
"市名": "昌平",
"编码": "101010700"
}
]
第三步:模型应用 Function
Function 应用
目的:1.实现大模型 Function Call 的功能应用
代码路径:./weather/main.py
具体代码:一共包含 2 个函数:调用模型函数和主逻辑函数。如下文:
模型应用 Function Call
主逻辑函数 main:
import json
from langchain_core.messages import HumanMessage, SystemMessage
from langchain_ollama import ChatOllama
from tools import get_current_weather
llm = ChatOllama(model="qwen3:1.7b")
llm_tools = llm.bind_tools([get_current_weather])
messages = [
SystemMessage("""你是一个天气播报小助手,你需要根据用户提供的地址来回答当地的天气情况,
如果用户提供的问题具有不确定性,不要自己编造内容,提示用户明确输入"""),
HumanMessage('今天北京的天气如何')
]
output = llm_tools.invoke(messages)
# 打印工具调用明细
print("工具调用明细:", output)
tool_load = json.dumps(output.tool_calls, indent=4, ensure_ascii=False)
print('调用的工具为:\n', tool_load)
# 创建新的消息列表
messages.append(output)
# 添加可以调用的 function call 信息
available_tools = {"get_current_weather": get_current_weather}
for tool_call in output.tool_calls:
select_tool = available_tools[tool_call["name"]]
tool_message = select_tool.invoke(tool_call)
messages.append(tool_message)
second_output = llm_tools.invoke(messages)
for message in second_output:
print(message)
# print(json.dumps(message.model_dump(), indent=4, ensure_ascii=False))
print(second_output.content)
结果展示:
今天北京的天气晴朗,高温 27℃,低温 17℃,星期四。
思考总结
1、Function Call 单一函数应用流程?
答案:
- 定义函数:函数可以是真实的外部 API 或工具,也可以是模拟函数。
- 提供函数定义给模型:将定义好的函数作为参数 (tools) 提供给模型。
- 模型生成函数调用 JSON:包含要调用的函数名称和参数值。
- 后端系统执行函数:后端系统根据 JSON 中的内容,调用相应的函数结果。
- 将函数结果返回给模型:函数返回结果给模型,作为模型的额外上下文信息。
- 模型生成最终响应:模型综合原始查询、函数调用结果等信息,生成最终输出。
多个函数应用
chat 方式实现
import json
from langchain_core.tools import tool
from langchain.chat_models import init_chat_model
from langchain_core.messages import HumanMessage
from langchain_ollama import ChatOllama
@tool
def add(a: int, b: int) -> int:
"""Adds two numbers together."""
return a + b
@tool
def subtract(a: int, b: int) -> int:
"""Subtracts two numbers."""
return a - b
llm = ChatOllama(model='qwen3:1.7b')
llm_tools = llm.bind_tools([add, subtract])
query = "12 和 15 相差多少?"
messages = [
HumanMessage(query)
]
output = llm_tools.invoke(messages)
# 打印工具调用明细
print("工具调用明细:", output)
tool_load = json.dumps(output.tool_calls, indent=4)
print('调用的工具为:\n', tool_load)
# 创建新的消息列表
messages.append(output)
# 添加可以调用的 function call 信息
available_tools = {"add": add, "subtract": subtract}
for tool_call in output.tool_calls:
select_tool = available_tools[tool_call["name"]]
tool_message = select_tool.invoke(tool_call)
messages.append(tool_message)
second_output = llm_tools.invoke(messages)
for message in second_output:
print(message)
# print(json.dumps(message.model_dump(), indent=4, ensure_ascii=False))
print(second_output.content)
agent 方式实现
from langchain.agents import AgentType, initialize_agent
from langchain_ollama import ChatOllama
from langchain_openai import ChatOpenAI
from langchain.tools import Tool, StructuredTool
from typing import Optional
from langchain.chat_models import init_chat_model
# 定义工具函数
def search_api(query: str) -> str:
"""模拟 API 调用"""
return f"结果:{query}"
def add_two_numbers(a: int, b: int) -> int:
"""模拟两个数字相加"""
return a + b
# 创建工具实例
tools = [
Tool(
name="SearchAPI",
func=search_api,
description="用于查询实时信息"
),
# StructuredTool 来处理多参数工具:
StructuredTool.from_function(
func=add_two_numbers,
name="add_two_numbers",
description="用于计算两个数的和",
)
]
llm = ChatOllama(model='qwen3:1.7b')
agent = initialize_agent(
tools=tools,
llm=llm,
agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION,
verbose=True
)
# 执行查询
response = agent.invoke("123 和 456 相加是多少?")
print(response)
Function Call 实现数据库查询
第一步:构建脚本 db.py
- 定义查询数据库的函数;
- 描述函数功能 tools;
- 解析模型参数调用函数
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
from sqlalchemy.orm import sessionmaker, declarative_base
# 数据库连接配置
DATABASE_URI = "mysql+pymysql://windows:Zhengxin...123456@localhost:3306/llm_sql"
# 创建数据库引擎
engine = create_engine(DATABASE_URI)
# 创建会话
Session = sessionmaker(bind=engine)
session = Session()
# 定义基类
Base = declarative_base()
# 定义用户表
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(50))
gender = Column(String(10))
age = Column(Integer)
department_id = Column(Integer, ForeignKey('departments.id'))
# 定义部门表
class Department(Base):
__tablename__ = 'departments'
id = Column(Integer, primary_key=True)
fid = Column(Integer)
name = Column(String(50))
if __name__ == '__main__':
# 创建表
Base.metadata.create_all(engine)
# 插入一些测试数据
session.add_all([
Department(id=1, fid=None, name="HR"),
Department(id=2, fid=1, name="Recruitment"),
User(id=1, name="Alice", gender="Female", age=28, department_id=1),
User(id=2, name="Bob", gender="Male", age=32, department_id=2),
])
session.commit()
第二步:实现查询
from langchain_deepseek import ChatDeepSeek
from langchain_community.agent_toolkits.sql.base import create_sql_agent
from langchain_community.agent_toolkits.sql.toolkit import SQLDatabaseToolkit
from langchain_community.utilities import SQLDatabase
from langchain.agents.agent_types import AgentType
from db import DATABASE_URI
# 创建数据库对象
db = SQLDatabase.from_uri(DATABASE_URI)
llm = ChatDeepSeek(model='deepseek-chat')
# 创建 SQL 工具套件
toolkit = SQLDatabaseToolkit(db=db, llm=llm)
# 创建 SQL 代理执行器
agent_executor = create_sql_agent(
llm=llm,
toolkit=toolkit,
verbose=True,
agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
)
# 执行查询
query = "SELECT * FROM users WHERE age > 30"
ret = agent_executor.invoke(query)
print(ret)
# 更复杂的问答
question = "列出所有年龄大于 30 岁的员工及其所在部门名称"
ret = agent_executor.invoke(question)
print(ret)