chatgpt tools调用

dwy 2024-06-14 08:13:00 阅读 79

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 集合中

这里有几点需要注意:

  1. 如果第一次运行 tool 时返回的是错误信息,openai 可能会让重新运行 tool,但是返回的 tool_call_id 是不变的,这时不能把错误的结果与正确的结果都返回给 openai,不然会出现错误
  2. 需要 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的调用很别扭



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。