函数调用
概述
大模型中的函数调用又称function call
。函数调用指的是用户通过描述函数和目标任务,让大模型尝试去调用某个函数。
需要注意的是,大模型本身没有能力自行执行函数,大模型根据用户输入和函数定义,向你提供:是否需要调用、调用什么函数、函数参数。得到这些信息后,客户端再自行执行函数,再把执行结果给到大模型,进行下一轮的任务。
一些框架 比如 LangGraph、LlamaIndex 可以简化这一过程。GiteeAI 提供了开箱即用的大模型函数调用能力,下文将讲述如何使用。
“function call” 与 “tool call” 是类似概念,“tool call” 是升级版,已替代 “function call”。工具列表需要传入 tools。
案例一:让AI知道今天的天气,直接解析函数调用结果
本案例的方法为最直接的方法,用于理解 function call 流程和原理。结合Langchain的更简便的方法实现参考案例二。
步骤一:组合tools参数
首先组合tools参数,下面向大模型描述了一个名为get_current_weather
的函数,函数传入参数为city,x,y,函数能力是通过城市名和经纬度获取地点的天气情况:
tools = [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "根据经纬度城市名,获取指定地点的天气情况",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "根据用户提到的地点推测城市",
},
"x": {
"type": "float",
"description": "城市的经度,根据你的知识推测",
},
"y": {
"type": "float",
"description": "城市的纬度,根据你的知识推测",
},
},
"required": ["city", "x", "y"],
},
}
}
]
tools 是一个列表,可定义多个,参数说明:
- type:定义参数对象的类型,通常是 object,表示参数结构为一个包含多个属性的 JSON 对象。
- properties:这是核心部分,列出每个参数的具体定义。JSON Schema 格式。
- name:每个属性的名称,对应函数的参数名。
- type:参数的数据类型,比如 string、float、integer 等。
- description:描述每个参数的用途,帮助模型理解如何填充参数值。
- required:指定哪些参数是必填的,如果参数在 required 列表中,那么模型在生成调 用时必须填充这些参数。
步骤二:调用大模型
将上文拼凑好的tools参数传入客户端中,解析响应的请求,并根据请求调用定义好的get_current_weather函数。
completion_tool = client.chat.completions.create(
model=model_name,
stream=False,
tools=tools,
temperature=0.1,
top_p=0.95,
tool_choice="auto",
messages=[
{"role": "system", "content": "你是聪明的助手,在合适的时候会调用工具。"},
{"role": "user", "content": "中国首都的天气情况"}
]
)
print(completion_tool, end="\n\n")
def get_current_weather(city: str, x: float, y: float) -> str:
print(f"执行 get_current_weather, 获得的参数是: city: {city},x: {x}, y: {y}")
# 执行一些爬虫、调用 API...
return """北京当前温度:12°C
天气状 况:雾霾
体感温度:12°C
今天天气:大部分地区多云,最低气温9°C
空气质量:轻度污染 (51-100),主要污染物 PM2.5 75 μg/m³
风速:轻风 (2 - 5 公里/小时),西南风 1级
湿度:78%
能见度:能见度差 (1 - 2 公里),2 公里
气压:1018 hPa
露点:8°C"""
function_res = completion_tool.choices[0].message.tool_calls[0].function
arguments_res = function_res.arguments
print("即将调用的函数是: ", function_res.name)
json_arguments = json.loads(
completion_tool.choices[0].message.tool_calls[0].function.arguments)
print(f"tool call 参数:",
json_arguments["city"], json_arguments["x"], json_arguments["y"])
# 执行函数
eval(f'{function_res.name}(**{arguments_res})')
至此函数已成功调用!你可以将函数响应的结果处理为:
{'role': 'tool', 'name': 'get_current_weather', 'content': '抓取的数据: 北京当前温度:12°C天气状况:雾霾...', tool_call_id:'xxxx'}
添加到 messages 消息列表末尾,再次请求 Gitee AI Serverless API,让 AI 整理答案。
案例二:配合Langchain 让AI总结汇报今日新闻
步 骤一:安装必要的库
langchain 等库提供了更多简便的工具和写法,首先安装必要的库:
pip install langchain==0.3.3 langgraph==0.2.38 langchain_core langchain_community==0.3.2 langchain_openai -i https://mirrors.cloud.tencent.com/pypi/simple
你也可以使用 langchain javascript 版本
使用 langchain @tool
装饰器,会自动帮你转换为符合规范的 tools 参数,包括首行的 """xxx""" 注释和 Annotated 注释都会成为 tools 参数中的 "description"。
使用 langgraph create_react_agent
创建 agent, 将会自动生成函数调用、执行工具、回传工具消息等,极大简化流程。
步骤二:获取新闻信息
下面实现让 AI “获取新闻,编写并执行 Python 代码,将新闻写入到 ./news.txt 文件中”:
from langchain_openai import ChatOpenAI
from langchain.tools import tool
from langchain_community.document_loaders import WebBaseLoader
from typing import AsyncIterator, Iterator, List, Optional, Annotated
from langgraph.prebuilt import create_react_agent
from langchain_core.messages import HumanMessage, AIMessage, AIMessageChunk, ToolMessage
# 仅用于个人学习演示:
@tool
def get_news(query: str):
"""获取最新新闻列表、今日新闻。此工具提供热门新闻摘要、链接,有图片的信息还提供了封面"""
try:
news_load = WebBaseLoader(
# 忽略 2019/07,实际上是最新的
'https://news.cctv.com/2019/07/gaiban/cmsdatainterface/page/news_1.jsonp?cb=news').load()
news = news_load[0].page_content
print('get_news 长度', len(news))
# 截取字符, 防止过长、加快 AI 速度。
return news[:4000]
except Exception as e:
print("get_news 失败", e)
# 此函数存在安全隐患,仅用于演示,请勿用于生产环境:
@tool
def python_code_exec(code: Annotated[str, '安全的 python 代码、表达式,将结果赋值到变量 result 中。字符串是多行字符串']) -> dict:
"""执行 python 代码、根据输入的表达式进行数学计算。可利用 python 编程解决问题,你可以自由编写安全的、完整、可执行的 python 代码,然后获取执行结果"""
local_vars = {}
try:
exec(code, {}, local_vars)
return f"结果是: {str(local_vars)}"
except Exception as e:
return f"执行失败: {str(e)}"
tools_list = [get_news, python_code_exec]
model_name = "Qwen2.5-72B-Instruct"
base_url = "https://ai.gitee.com/v1"
# https://ai.gitee.com/dashboard/settings/tokens 获取你的访问令牌
GITEE_AI_API_KEY = ""
llm = ChatOpenAI(model=model_name, api_key=GITEE_AI_API_KEY, base_url=base_url, streaming=True, temperature=0.1, presence_penalty=1.05, top_p=0.9,
extra_body={
"tool_choice": "auto",
})
system_message = """你是聪明的助手,在调用工具之前简单汇报"""
# 使用 langgraph 创建 agent,自带调用、执行工具、回传工具消息等
agent_executor = create_react_agent(
llm, tools=tools_list, debug=False)
ai_res_msg = ''
first = True
config = {"configurable": {"thread_id": "xxx", "recursion_limit": 10}}
for ai_msg, metadata in agent_executor.stream(
{"messages": [system_message, HumanMessage(content="获取今日前三条新闻标题,然后编写 python 代码写入到 ./news.txt 中, 编码使用 utf-8")]}, config, stream_mode="messages"
):
if ai_msg.content and isinstance(ai_msg, AIMessage):
# 实时输出
print(ai_msg.content, end="")
ai_res_msg += ai_msg.content
if isinstance(ai_msg, AIMessageChunk):
if first:
gathered = ai_msg
first = False
else:
gathered = gathered + ai_msg
if ai_msg.tool_call_chunks:
print("调用的函数:", gathered.tool_calls)
if isinstance(ai_msg, ToolMessage):
print("工具调用结果:", ai_msg.content)
# 汇总输出
print(ai_res_msg)
你将会看到模型实时调用的过程和最新新闻结果,然后 AI 将自行编写代码,将新闻标题保存到 news.txt 文件中!