跳到主要内容

函数调用 (Function Calling)

概述

大模型中的函数调用又称 Function Calling 。函数调用指的是用户通过描述函数和目标任务,让大模型尝试去调用某个函数。

需要注意的是,大模型本身没有能力自行执行函数,大模型根据用户输入和函数定义,向您提供:是否需要调用、调用什么函数、函数参数。得到这些信息后,客户端再自行执行函数,再把执行结果给到大模型,进行下一轮的任务。

一些框架比如 LangGraphLlamaIndex 可以简化这一过程。模力方舟提供了开箱即用的大模型函数调用能力,下文将讲述如何使用。

提示

Function Callingtool call 是类似概念,tool call 是升级版,已替代 Function Calling
工具列表需要传入 tools

案例一:让AI知道今天的天气,直接解析函数调用结果

本案例的方法为最直接的方法,用于理解 Function Calling 流程和原理。结合Langchain的更简便的方法实现参考 案例二

步骤一:组合tools参数

首先组合tools参数,下面向大模型描述了一个名为 get_current_weather 的函数,函数传入参数为 city, x , y ,函数能力是通过城市名和经纬度获取地点的天气情况:

python
tools = [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "通过城市名和日期获取地点的天气情况,包括温度、天气状况等信息",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "用户想要查询天气的城市名称",
},
"date": {
"type": "string",
"description": "想要查询的日期,如'今天'、'明天'或具体日期'2023-10-01'",
}
},
"required": ["city", "date"],
},
}
}
]

tools 是一个列表,可定义多个,参数说明:

  • type :定义参数对象的类型,通常是 object,表示参数结构为一个包含多个属性的 JSON 对象。
  • properties :这是核心部分,列出每个参数的具体定义 JSON Schema 格式。
    • name :每个属性的名称,对应函数的参数名。
    • type :参数的数据类型,比如 string、float、integer 等。
    • description :描述每个参数的用途,帮助模型理解如何填充参数值。
    • required :指定哪些参数是必填的,如果参数在 required 列表中,那么模型在生成调用时必须填充这些参数。

步骤二:调用大模型

将上文拼凑好的 tools 参数传入客户端中,解析响应的请求,并根据请求调用定义好的 get_current_weather 函数。

python
import json

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, date: str) -> str:
print(f"执行 get_current_weather, 获得的参数是: city: {city}, date: {date}")
# 模拟天气查询接口返回结果
return f"""北京市{date}天气信息:
天气状况:晴朗
温度:25-32℃
风力:东北风3-4级
湿度:45%
紫外线强度:中等,建议外出涂抹防晒霜"""


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['date']}")

# 执行函数
eval(f'{function_res.name}(**{arguments_res})')

至此函数已成功调用!您可以将函数响应的结果处理为:

{
'role': 'tool',
'name': 'get_current_weather',
'content': '北京市今天天气信息:天气状况:晴朗...',
'tool_call_id': 'xxxx'
}

案例二:配合 Langchain 让 AI 总结汇报今日新闻

步骤一:安装必要的库

Langchain 等库提供了更多简便的工具和写法,首先安装必要的库:

bash
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 文件中”:

python
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://moark.com/v1"

# https://moark.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 文件中!