LLM的挑战
大语言模型(Large Language Model,简称 LLM)是一类基于深度学习技术、具备大规模参数的语言处理模型,其核心能力在于理解和生成自然语言,并通过海量数据训练获得泛化性极强的语言理解与生成能力。这使LLM过于依赖训练数据,从而带来以下问题和挑战:
- 幻觉(Hallucination) :有时候会不懂装懂,生成与事实不符的内容。
- 知识时效性:训练数据截止后无法自动更新。
解决方法-- FunctionCall
Function Call(函数调用) 提供了连接大语言模型(LLM)与外部工具的关键机制,它使LLM能够突破纯文本生成的限制,通过调用外部函数(如 API、工具、数据库等)来执行实际操作,实现更复杂的任务闭环。
函数调用的核心流程
- 注册工具:定义函数签名并提供实现。
- 首次调用:将用户问题和工具列表发送给模型。
- 工具执行:解析模型返回的工具调用请求,执行对应函数。
- 结果整合:将函数结果作为新输入再次调用模型,生成最终回答。
案例演示
以下是LLM使用Function Call获取实时股价的过程演示
一、环境准备与客户端初始化
load_dotenv('.env.local') # 从环境文件加载 API 密钥
client = OpenAI(
api_key=os.getenv('DEEPSEEK_API_KEY'),
base_url="https://api.deepseek.com/v1", # 指向 DeepSeek 接口
)
- 关键点:通过
base_url参数将 OpenAI 客户端指向第三方模型(DeepSeek)的 API 端点。
二、工具定义与注册
tools = [
{
"type": "function",
"function": {
"name": "get_closing_price",
"description": "获取指定股票的收盘价",
"parameters": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "股票名称",
},
},
"required": ["name"],
}
}
}
]
-
关键点:
- 使用 JSON Schema 格式定义函数签名。
- 通过
description字段向模型解释函数用途。
三、函数实现
def get_closing_price(name):
if name == '青岛啤酒':
return '67.92'
elif name == '贵州茅台':
return '1488.21'
else:
return '未找到该股票'
- 模拟实现:实际应用中应调用真实股票 API(如 Alpha Vantage、东方财富等)。
四、主流程:消息发送与函数调用
1. 首次请求用户问题
messages = [{"role": "user", "content": "青岛啤酒的收盘价是多少?"}]
response = send_message(messages)
- 模型决策:DeepSeek 模型分析问题后,决定调用
get_closing_price函数。
2. 解析工具调用请求
message = response.choices[0].message
if message.tool_calls: # 检查是否有工具调用
tool_call = message.tool_calls[0]
if tool_call.function.name == "get_closing_price":
# 解析参数并执行函数
arguments_dict = json.loads(tool_call.function.arguments)
price = get_closing_price(arguments_dict['name'])
# 将函数执行结果添加到对话历史
messages.append({
"role": "tool",
"content": price,
"tool_call_id": tool_call.id
})
-
关键点:
- 通过
tool_calls字段获取模型选择的工具。 - 将函数执行结果作为
tool角色的消息加入对话。
- 通过
3. 二次请求生成最终回答
response = send_message(messages) # 带着函数结果再次调用模型
print(response.choices[0].message.content) # 输出:"青岛啤酒的收盘价是67.92元"
- 模型行为:模型结合函数返回的价格数据,生成自然语言回答。
五、完整代码与运行结果
import json
from email import message
from openai import OpenAI
import os
from dotenv import load_dotenv
load_dotenv('.env.local')
client = OpenAI(
api_key=os.getenv('DEEPSEEK_API_KEY'),
base_url="https://api.deepseek.com/v1",
)
def send_message(messages):
response = client.chat.completions.create(
model='deepseek-reasoner',
messages=messages,
tools=tools,
tool_choice='auto'
)
return response
# 打造一个函数调用的工具
tools = [
{
"type": "function",
"function": {
"name": "get_closing_price",
"description": "获取指定股票的收盘价",
"parameters": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "股票名称",
},
},
"required": ["name"],
}
}
}
]
# 定义函数
def get_closing_price(name):
if name == '青岛啤酒':
return '67.92'
elif name == '贵州茅台':
return '1488.21'
else:
return '未找到该股票'
if __name__ == '__main__':
messages = [{"role": "user", "content": "青岛啤酒的收盘价是多少?"}]
response = send_message(messages)
message = response.choices[0].message
messages.append({
"role": message.role,
"content": message.content,
"tool_calls": message.tool_calls
})
# print("回复:")
# print(response.choices[0].message.content)
# print("工具选择:")
# print(response.choices[0].message.tool_calls)
# LLM 已经确定了它要用的函数
if response.choices[0].message.tool_calls != None:
tool_call = response.choices[0].message.tool_calls[0]
if tool_call.function.name == "get_closing_price":
arguments_dict = json.loads(tool_call.function.arguments) # {"name": "青岛啤酒"}
price = get_closing_price(arguments_dict['name'])
messages.append({
"role": "tool",
"content": price,
"tool_call_id": tool_call.id
})
# print("messages:", messages)
response = send_message(messages)
print("回复:")
print(response.choices[0].message.content)