给大语言模型插上翅膀
1.引言
有人说,智慧是 知识
+ 运用知识的能力
。从这个角度来看,大语言模型(如ChatGPT)
在某种程度上可以被认为具有一定形式的智慧。然而现在针对大语言模型的使用有一个问题,
就是模型所具有的知识无法保持实时更新。比如某个API文档发生变化,大语言模型仍然只能基于历史知识进行回答。
有没有办法让大语言模型获取最新的知识,而不至于stale
。
显然如果它能够调用搜索引擎,获取最新知识,就可以解决这个问题。
事实上,现在kimi的联网搜索和ChatGPT的搜索网页都是为了解决这个问题。
下面让我们看看如何利用function calling
来实现大语言模型从搜索引擎获取数据,继而回答用户的提问。
2. 大语言模型通过搜索引擎获取数据
首先,我们来看一个问题:“今天武汉和上海的气温,哪一个更高?”
对于人类而言,我们要解决这个问题,必须经过以下步骤
- 1)获取武汉和上海的气温数据
- 2)比较武汉和上海的最高气温,得出结论
下面萌叔提供一个完整的Python程序,看看如何使用function calling
来回答这个提问
import json
from email.policy import strict
from openai import OpenAI
import requests
from openai._utils import maybe_transform
from openai.types.chat import ChatCompletion
base_url = "{此处请自行替换}"
api_key = "{此处请自行替换}"
google_search_key = "{此处请自行替换}"
google_search_engine = "{此处请自行替换}"
# 定义 google_search 函数(示例)
def google_search(query: str) -> str:
url = "https://www.googleapis.com/customsearch/v1"
query_params = {
"key": google_search_key,
"cx": google_search_engine,
"q": query,
"num": 5,
}
response = requests.get(url, params=query_params)
print(response.url)
return response.text
# 调用大模型
def send_messages(messages):
# 函数信息,用于 Function Calling
tools = [
{
"type": "function",
"function": {
"name": "google_search",
"description": "通过 Google 搜索获取信息",
"parameters": {
# 参数类型必须是object
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "需要搜索的关键词或短语",
}
},
"required": ["query"],
"additionalProperties": False,
},
"strict": True
}
},
]
client = OpenAI(api_key=api_key, base_url=base_url)
response = client.chat.completions.create(
model="gpt-4o-mini", # 确保使用支持 Function Calling 的模型
messages=messages,
tools=tools,
max_tokens=4096,
parallel_tool_calls=True,
)
dd = maybe_transform(response, ChatCompletion)
data = json.dumps(dd, ensure_ascii=False)
print(data)
return response.choices[0].message
if __name__ == "__main__":
# 示例对话
# input_text = input("请输入您的问题:")
messages = [
{"role": "system",
"content": "你是一个智能搜索机器人。你根据用户提出的问题,利用google_search函数,获取额外信息,然后回答用户的提问"},
{"role": "user", "content": "今天武汉和上海的气温,哪一个更高?"},
]
# 1. **第1次调用AI接口**
message = send_messages(messages)
call_cout = len(message.tool_calls)
print(f"将会发起{call_cout}次调用...")
# 2. **在client端调用google_search()**
messages.append(message)
for tool in message.tool_calls:
if tool.function.name == "google_search":
parsed_arguments = json.loads(tool.function.arguments)
query = parsed_arguments.get("query", None) # 获取 query 值
print("query:", query)
content = google_search(query)
messages.append({"role": "tool", "tool_call_id": tool.id, "content": content})
# 3. **第2次调用AI接口**
message = send_messages(messages)
print(f"Model>\t {message.content}")
0) 函数说明
这里我们给出了函数google_search()说明, 并把它传递给大模型,
告诉它在处理问题的时候,可以考虑使用上我们提供的函数。
tools = [
{
"type": "function",
"function": {
"name": "google_search",
"description": "通过 Google 搜索获取信息",
"parameters": {
# 参数类型必须是object
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "需要搜索的关键词或短语",
}
},
"required": ["query"],
"additionalProperties": False,
},
"strict": True
}
},
]
提示: tools中可以包含多个函数,大模型会自主选择使用哪些函数
1) 第1次调用AI接口
{
"id": "chatcmpl-ApD9VJN3P1lo65kq2ZX7XKQ7hDpwa",
"choices": [{
"finish_reason": "tool_calls",
"index": 0,
"logprobs": null,
"message": {
"content": null,
"refusal": null,
"role": "assistant",
"tool_calls": [{
"id": "call_jZ3hzsJVFaqMiz0UF2BxDdm8",
"function": {
"arguments": "{\"query\": \"武汉今天气温\"}",
"name": "google_search"
},
"type": "function"
}, {
"id": "call_cKwbFiAxGdUuCf2dgsUpG3Qn",
"function": {
"arguments": "{\"query\": \"上海今天气温\"}",
"name": "google_search"
},
"type": "function"
}]
}
}],
...
}
如果模型确定应该调用某个函数,它将在响应中返回一个tool_calls字段,您可以使用该字段来确定模型是否生成了函数调用以及参数是什么。
2) 在client端调用google_search()
for tool in message.tool_calls:
if tool.function.name == "google_search":
parsed_arguments = json.loads(tool.function.arguments)
query = parsed_arguments.get("query", None) # 获取 query 值
content = google_search(query)
messages.append({"role": "tool", "tool_call_id": tool.id, "content": content})
When you use the OpenAI API with function calling, the model never actually executes functions itself - instead,
it simply generates parameters that can be used to call your function.
You are then responsible for handling how the function is executed in your code.
注意: 当您使用 OpenAI API 进行函数调用时,模型实际上并不会自己执行函数——它只是生成可以用于调用您函数的参数。然后,您需要负责处理在代码中如何执行该函数。
3) 第2次调用AI接口
message = send_messages(messages)
print(f"Model>\t {message.content}")
下面是第2次调用AI接口,提交的messages信息,从搜索引擎获得的内容萌叔做了简化
[{
"role": "system",
"content": "你是一个智能搜索机器人。你根据用户提出的问题,利用google_search函数,获取额外信息,然后回答用户的提问"
}, {
"role": "user",
"content": "今天武汉和上海的气温,哪一个更高?"
}, {
"content": "",
"role": "assistant",
"tool_calls": [{
"id": "call_0_b1edafcc-f274-4a3f-b350-5c879c5a6095",
"function": {
"arguments": "{\"query\":\"武汉今天气温\"}",
"name": "google_search"
},
"type": "function",
"index": 0
}, {
"id": "call_1_e02f2dac-1c89-4363-894f-050831f89060",
"function": {
"arguments": "{\"query\":\"上海今天气温\"}",
"name": "google_search"
},
"type": "function",
"index": 1
}]
}, {
"role": "tool",
"tool_call_id": "call_0_b1edafcc-f274-4a3f-b350-5c879c5a6095",
"content": "武汉今天的最高气温是17°C"
}, {
"role": "tool",
"tool_call_id": "call_1_e02f2dac-1c89-4363-894f-050831f89060",
"content": "上海今天的最高气温是12°C"
}]
可以看到从搜索引擎获得的数据也和指令、提问等数据一起作为上下文发给了大模型。
这里似乎是因为搜索引擎不能正确理解"今天"导致最终返回结果有错误。
3. 延伸
其实大语言模型本身就很擅长从非结构化数据中提取结构化数据,所以我们可以以类似下面的方式提问,也可以获得函数的使用建议。
提示: Function Calling
的返回结果与大模型的智商有一定关系,openAI早期模型并不支持Function Calling
后记
2024年01月14日,懒得申请注册google搜索API的,也可以用mock函数替代
# 定义 google_search 函数(示例)
def google_search(query: str) -> str:
if query.__contains__("武汉"):
return "15摄氏度"
elif query.__contains__("上海"):
return "12摄氏度"
参考资料
1.Function calling
2.google custom search申请注册
3.Assistants 5:Function calling
作者: vearne
文章标题: 给大语言模型插上翅膀
发表时间: 2025年01月14日
文章链接: https://vearne.cc/archives/40245
版权说明: CC BY-NC-ND 4.0 DEED