跳到主要内容

函数调用

概述

大模型中的函数调用又称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 文件中!