跳到主要内容

函数调用

Open In Colab

函数调用使 Mistral 模型能够连接到外部工具。通过将 Mistral 模型与用户定义的函数或 API 等外部工具集成,用户可以轻松构建适用于特定用例和实际问题的应用程序。例如,在本指南中,我们编写了两个函数用于跟踪支付状态和支付日期。我们可以使用这两个工具来提供与支付相关的查询的答案。

可用模型

目前,以下模型支持函数调用

  • Mistral Large
  • Mistral Medium
  • Mistral Small
  • Codestral
  • Ministral 8B
  • Ministral 3B
  • Pixtral 12B
  • Pixtral Large
  • Mistral Nemo

四个步骤

概述来说,函数调用有四个步骤

  • 用户:指定工具和查询
  • 模型:生成函数参数(如适用)
  • 用户:执行函数以获取工具结果
  • 模型:生成最终答案
drawing

在本指南中,我们将通过一个简单的例子来演示函数调用如何在 Mistral 模型中通过这四个步骤工作。

在开始之前,我们假设有一个包含支付交易的数据帧(dataframe)。当用户询问有关此数据帧的问题时,他们可以使用某些工具来回答有关此数据的问题。这只是一个模拟 LLM 无法直接访问的外部数据库的示例。

import pandas as pd

# Assuming we have the following data
data = {
'transaction_id': ['T1001', 'T1002', 'T1003', 'T1004', 'T1005'],
'customer_id': ['C001', 'C002', 'C003', 'C002', 'C001'],
'payment_amount': [125.50, 89.99, 120.00, 54.30, 210.20],
'payment_date': ['2021-10-05', '2021-10-06', '2021-10-07', '2021-10-05', '2021-10-08'],
'payment_status': ['Paid', 'Unpaid', 'Paid', 'Paid', 'Pending']
}

# Create DataFrame
df = pd.DataFrame(data)

步骤 1. 用户:指定工具和查询

drawing

工具

用户可以为他们的用例定义所有必要的工具。

  • 在许多情况下,我们可能有多个工具可供使用。例如,假设我们有两个函数作为工具:retrieve_payment_status 用于获取支付状态,retrieve_payment_date 用于获取给定交易 ID 的支付日期。
def retrieve_payment_status(df: data, transaction_id: str) -> str:
if transaction_id in df.transaction_id.values:
return json.dumps({'status': df[df.transaction_id == transaction_id].payment_status.item()})
return json.dumps({'error': 'transaction id not found.'})

def retrieve_payment_date(df: data, transaction_id: str) -> str:
if transaction_id in df.transaction_id.values:
return json.dumps({'date': df[df.transaction_id == transaction_id].payment_date.item()})
return json.dumps({'error': 'transaction id not found.'})
  • 为了让 Mistral 模型理解这些函数,我们需要使用 JSON schema 来定义函数规范。具体来说,我们需要描述函数的类型、函数名、函数描述、函数参数以及函数所需的参数。由于这里有两个函数,我们将列出两个函数的规范。
tools = [
{
"type": "function",
"function": {
"name": "retrieve_payment_status",
"description": "Get payment status of a transaction",
"parameters": {
"type": "object",
"properties": {
"transaction_id": {
"type": "string",
"description": "The transaction id.",
}
},
"required": ["transaction_id"],
},
},
},
{
"type": "function",
"function": {
"name": "retrieve_payment_date",
"description": "Get payment date of a transaction",
"parameters": {
"type": "object",
"properties": {
"transaction_id": {
"type": "string",
"description": "The transaction id.",
}
},
"required": ["transaction_id"],
},
},
}
]
  • 然后我们将这两个函数组织到一个字典中,其中键表示函数名,值是定义了 df 的函数。这使得我们可以根据函数名调用每个函数。
import functools

names_to_functions = {
'retrieve_payment_status': functools.partial(retrieve_payment_status, df=df),
'retrieve_payment_date': functools.partial(retrieve_payment_date, df=df)
}

用户查询

假设用户提出以下问题:“我的交易状态是什么?” 一个独立的 LLM 无法回答这个问题,因为它需要查询业务逻辑后端来访问必要的数据。但如果我们有一个可以用来回答这个问题的工具呢?我们就有可能提供一个答案!

messages = [{"role": "user", "content": "What's the status of my transaction T1001?"}]

步骤 2. 模型:生成函数参数

drawing

Mistral 模型如何知道这些函数以及使用哪个函数?我们将用户查询和工具规范都提供给 Mistral 模型。这一步骤的目标不是让 Mistral 模型直接运行函数。而是 1) 确定要使用的适当函数,2) 识别函数是否缺少任何必要信息,以及 3) 为所选函数生成必要的参数。

tool_choice

用户可以使用 tool_choice 来指定如何使用工具

  • "auto":默认模式。模型决定是否使用该工具。
  • "any":强制使用工具。
  • "none":阻止使用工具。

parallel_tool_calls

用户可以使用 parallel_tool_calls 来指定是否允许并行工具调用。

  • true:默认模式。模型决定是否使用并行工具调用。
  • false:强制模型使用单个工具调用。
import os
from mistralai import Mistral

api_key = os.environ["MISTRAL_API_KEY"]
model = "mistral-large-latest"

client = Mistral(api_key=api_key)
response = client.chat.complete(
model = model,
messages = messages,
tools = tools,
tool_choice = "any",
parallel_tool_calls = False,
)
response

我们得到包含 tool_calls 的响应,其中包含选定的函数名 retrieve_payment_status 和该函数的参数。

输出

ChatCompletionResponse(id='7cbd8962041442459eb3636e1e3cbf10', object='chat.completion', model='mistral-large-latest', usage=Usage(prompt_tokens=94, completion_tokens=30, total_tokens=124), created=1721403550, choices=[Choices(index=0, finish_reason='tool_calls', message=AssistantMessage(content='', tool_calls=[ToolCall(function=FunctionCall(name='retrieve_payment_status', arguments='{"transaction_id": "T1001"}'), id='D681PevKs', type='function')], prefix=False, role='assistant'))])

我们将响应消息添加到 messages 列表中。

messages.append(response.choices[0].message)

步骤 3. 用户:执行函数以获取工具结果

drawing

我们如何执行函数?目前,执行这些函数是用户的责任,并且函数执行发生在用户端。将来,我们可能会引入一些可以在服务器端执行的有用函数。

让我们从模型响应中提取一些有用的函数信息,包括 function_namefunction_params。这里清楚地表明,我们的 Mistral 模型选择了使用函数 retrieve_payment_status,并将参数 transaction_id 设置为 T1001。

import json

tool_call = response.choices[0].message.tool_calls[0]
function_name = tool_call.function.name
function_params = json.loads(tool_call.function.arguments)
print("\nfunction_name: ", function_name, "\nfunction_params: ", function_params)

输出

function_name:  retrieve_payment_status 
function_params: {'transaction_id': 'T1001'}

现在我们可以执行函数并获得函数输出 '{"status": "Paid"}'

function_result = names_to_functions[function_name](**function_params)
function_result

输出

'{"status": "Paid"}'

步骤 4. 模型:生成最终答案

drawing

现在我们可以将工具的输出提供给 Mistral 模型,作为回报,Mistral 模型可以为特定用户生成定制的最终响应。

messages.append({
"role":"tool",
"name":function_name,
"content":function_result,
"tool_call_id":tool_call.id
})

response = client.chat.complete(
model = model,
messages = messages
)
response.choices[0].message.content

输出

The status of your transaction with ID T1001 is "Paid". Is there anything else I can assist you with?