ChatGPT应用:函数调用(function_calling)配合流式输出示例代码

文章讲述了如何使用OpenAI的GPT-4进行流式对话,涉及函数调用和参数传递,以及一个具体使用场景的代码实现。
摘要由CSDN通过智能技术生成

function_call + 流式输出

pip install openai==1.9.0

# -*- coding: utf-8 -*-
# Author: 薄荷你玩
# Date: 2024/01/26

from openai import OpenAI
import json

api_key = "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
client = OpenAI(api_key=api_key)


def get_user_name(user_id: int):
    """
    根据用户id获取用户名(模拟)
    :param user_id: 用户ID
    :return:
    """
    if user_id == 1001:
        return "张三"
    elif user_id == 1002:
        return "李四"
    else:
        return "-"


def get_weather(city: str, date: str = None):
    """
    获取城市当天天气信息(模拟)
    :param city: 城市名
    :param date: 日期(暂时不使用)
    :return:
    """
    data = {}
    if city == "杭州":
        data['weather'] = "晴天"
        data['temperature'] = "20℃"
    elif city == "北京":
        data['weather'] = "中雨"
        data['temperature'] = "15℃"

    return json.dumps(data)


def gpt_ask_with_stream(messages: list[dict], tools: list[dict]):
    response = client.chat.completions.create(
        model="gpt-4",
        messages=messages,
        tools=tools,
        tool_choice="auto",
        stream=True
    )
    tool_calls = []
    for chunk in response:
        if chunk.choices:
            choice = chunk.choices[0]
            if choice.delta.tool_calls:  # function_calling
                for idx, tool_call in enumerate(choice.delta.tool_calls):
                    tool = choice.delta.tool_calls[idx]
                    if len(tool_calls) <= idx:
                        tool_calls.append(tool)
                        continue
                    if tool.function.arguments:
                        # function参数为流式响应,需要拼接
                        tool_calls[idx].function.arguments += tool.function.arguments
            elif choice.finish_reason:
                # print(f"choice.finish_reason: {choice.finish_reason}")
                break
            else:  # 普通回答
                yield ""  # 第一条返回无意义,便于后续检测回复消息类型
                yield choice.delta.content

    # 如果是function_call请求,返回数据
    if tool_calls:
        yield tool_calls


def run_conversation(content: str):
    messages = [{"role": "user", "content": content}]
    tools = [
        {
            "type": "function",
            "function": {
                "name": "get_weather",
                "description": "获取城市今天的天气信息",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "city": {
                            "type": "string",
                            "enum": ["杭州", "北京"],
                            "description": "城市名",
                        },
                        "date": {
                            "type": "string",
                            "description": "查询的日期,格式:%Y-%m-%d。默认为当天日期",
                        }
                    },
                    "required": ["city"],
                },
            },
        },
        {
            "type": "function",
            "function": {
                "name": "get_user_name",
                "description": "根据用户id获取用户名",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "user_id": {
                            "type": "integer",
                            "description": "用户id",
                        }
                    },
                    "required": ["user_id"],
                },
            },
        }
    ]

    response = gpt_ask_with_stream(messages, tools)
    tool_calls = []
    for res in response:
        # 如果响应数据第一条是list则表明是function_call,如果是str就是普通回答
        if type(res) == list:
            tool_calls = res
        break
    # 判断是否是 function_call 请求
    while tool_calls:
        available_functions = {
            "get_weather": get_weather,
            "get_user_name": get_user_name
        }
        # 手动构建gpt返回消息,tool_calls暂时置空,后面循环调用function的时候再赋值
        assistant_message = {
            "role": "assistant",
            "tool_calls": [],
            "content": None
        }
        messages.append(assistant_message)
        # send the info for each function call and function response to the model
        for tool_call in tool_calls:
            print("tool_calls:", tool_call)
            assistant_message['tool_calls'].append({
                "id": tool_call.id,
                "type": tool_call.type,
                "function": {
                    "name": tool_call.function.name,
                    "arguments": tool_call.function.arguments
                }
            })
            function_name = tool_call.function.name
            function_to_call = available_functions[function_name]
            function_args = json.loads(tool_call.function.arguments)
            if function_name == 'get_weather':
                function_response = function_to_call(
                    city=function_args.get("city"),
                    date=None,
                )
            else:
                function_response = function_to_call(
                    user_id=function_args.get("user_id"),
                )
            messages.append({
                "tool_call_id": tool_call.id,
                "role": "tool",
                "name": function_name,
                "content": function_response,
            })
        # 携带 function 返回的结果再请求一次GPT
        response = gpt_ask_with_stream(messages, tools)
        # 和 while 前面写法一样,支持多轮tools调用
        tool_calls = []
        for res in response:
            if type(res) == list:
                tool_calls = res
            break
    # 返回普通回答的流式响应
    return response


if __name__ == '__main__':
    for chunk in run_conversation("杭州今天天气怎么样? ID 1002的用户名?"):
        print(chunk, end='')
    # 输出:
    # tool_calls: ChoiceDeltaToolCall(index=0, id='call_5jSbeoAcUqDmZRXS70iVKbrL', function=ChoiceDeltaToolCallFunction(arguments='{\n  "city": "杭州"\n}', name='get_weather'), type='function')
    # tool_calls: ChoiceDeltaToolCall(index=0, id='call_ppgzqcbHAeDnfklMznrOG7lh', function=ChoiceDeltaToolCallFunction(arguments='{\n  "user_id": 1002\n}', name='get_user_name'), type='function')
    # 杭州今天是晴天,温度为20℃。ID 1002的用户名是李四。

更多示例代码:https://github.com/yaokui2018/chatgpt_example

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
根据引用中的信息,您遇到的错误是"RuntimeError: CUDA error: CUBLAS_STATUS_NOT_SUPPORTED when calling `cublasSgemm`"。这个错误通常是由于CUDA库的不兼容性或配置问题引起的。 其中有一种可能的解决方法是检查您的CUDA版本和CUDA相关库的版本是否匹配。请确保您使用的CUDA版本与您的GPU驱动程序和其他CUDA相关库的版本兼容。 另外,引用提到过的一个解决方法是确保在使用CUDA之前先调用`torch.cuda.set_device(device)`来设置GPU设备。这可能会帮助解决一些CUDA相关的问题。 此外,引用中提到的另一个情况是内存不足的问题。您可以检查您的系统内存是否足够支持您的计算任务。 综上所述,您可以按照以下步骤尝试解决这个问题: 1. 检查CUDA版本和相关库的兼容性。 2. 在使用CUDA之前调用`torch.cuda.set_device(device)`来设置GPU设备。 3. 检查系统内存是否足够支持计算任务。 希望这些信息能对您有所帮助!<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [bug记录:RuntimeError: CUDA error: CUBLAS_STATUS_NOT_INITIALIZED when calling `cublasCreate(handle)`](https://blog.csdn.net/MarsandOcean/article/details/130237565)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [Python RuntimeError: thread.__init__() not called解决方法](https://download.csdn.net/download/weixin_38630358/12877726)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [RuntimeError: CUDA error: CUBLAS_STATUS_NOT_INITIALIZED when calling `cublas](https://blog.csdn.net/Yonggie/article/details/130931694)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薄荷你玩_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值