chatgpt tools 调用
1. 引入 openai, 创建 client
import json
import os
import subprocess
from openai import OpenAI
# api_key 可以填入自己的key
# base_url 可以使用国内的代理,海外可以使用官方地址
client = OpenAI(api_key="", base_url="https://api.openai-proxy.com/v1")
2. 创建一个 tool 的实现
这里定义的是一个执行系统命令的方法, 接受传入的命令,返回运行结果与运行错误
def do_command(command: str):
process = subprocess.Popen(command, shell=True, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, encoding="utf-8")
stdout, stderr = process.communicate()
return {"stdout": stdout, "stderr": stderr}
3. 创建一个提供给 openai 的 tools 定义集合
在提供给 openai 时会有 schema 的校验,校验不通过时会报错,参数的类型没有 list
或者 array
tools = [{
"type": "function",
"function": {
"name": "do_command",
"description": "执行linux / windows命令",
"parameters": {
"type": "object",
"properties": {
"command": {"type": "string", "description": "输入的命令"}
},
"required": ["command"]
}
}
}]
4. 创建一个运行 tool 的方法
接收参数为 chatgpt 返回的 response 与 message 集合, 将运行完成的结果写入到集合中
如果不需要执行 tool,则将 response 的 message 添加到 message 集合中
这里有几点需要注意:
- 如果第一次运行 tool 时返回的是错误信息,openai 可能会让重新运行 tool,但是返回的 tool_call_id 是不变的,这时不能把错误的结果与正确的结果都返回给 openai,不然会出现错误
- 需要 tool_call 的场景下,不代表 content 是空的;可能一边有结果返回,一边让你再次运行;方法中没有处理运行 tool 的 message,也没有处理并行 tool 的场景(因为只有一个方法)
def parse_function_call(model_response, messages):
_messages = messages.copy()
_messages.append(model_response.choices[0].message.model_dump())
if model_response.choices[0].message.tool_calls:
tool_call = model_response.choices[0].message.tool_calls[0]
model = model_response.model
args = tool_call.function.arguments
function_result = {}
if tool_call.function.name == "do_command":
function_result = do_command(**json.loads(args))
_messages.append({
"role": "tool",
"content": f"{json.dumps(function_result)}",
"tool_call_id": tool_call.id
})
print(_messages)
response = client.chat.completions.create(
model=model, # 填写需要调用的模型名称
messages=_messages,
tools=tools,
)
if response.choices[0].message.tool_calls:
parse_function_call(response, messages)
else:
messages.append(response.choices[0].message.model_dump())
else:
messages.append(model_response.choices[0].message.model_dump())
5. 运行 chatgpt,并将工具的定义作为参数传入
messages = []
messages.append({"role": "system", "content": "当前的运行环境是{}".format(os.name)})
messages.append({"role": "user", "content": "查询python的版本"})
resp = client.chat.completions.create(messages=messages, model="gpt-4o-2024-05-13", tools=tools)
parse_function_call(resp, messages)
print(messages)
运行tool的message 记录
[{'role': 'system', 'content': '当前的运行环境是nt'}, {'role': 'user', 'content': '查询python的版本'}, {'content': None, 'role': 'assistant', 'function_call': None, 'tool_calls': [{'id': 'call_f3OaTCDet0p73o2fPvTRBFIs', 'function': {'arguments': '{"command":"python --version"}', 'name': 'do_command'}, 'type': 'function'}]}, {'role': 'tool', 'content': '{"stdout": "Python 3.11.6\\n", "stderr": ""}', 'tool_call_id': 'call_f3OaTCDet0p73o2fPvTRBFIs'}]
返回结果
[{'role': 'system', 'content': '当前的运行环境是nt'}, {'role': 'user', 'content': '查询python的版本'}, {'content': '当前的Python版本是:**Python 3.11.6**。', 'role': 'assistant', 'function_call': None, 'tool_calls': None}]
6. 总结
tool 确实让chatgpt 的使用变得更加灵活,后续应该扩展为系统命令创建一个稳定的运行环境,现在是单命令的场景;message可以添加一个缓存机制,使读取与写入更加灵活一些
用openai原生的api与langchain的体验不太一样,原生的可以很明显的感受的到是基于一个message的流来进行交流
langchian的LECL也有比较方便的地方,但是对于tool的调用很别扭
标签:function,调用,tool,messages,message,call,chatgpt,tools,model From: https://www.cnblogs.com/daiwyang/p/18246277