0

0

掌握OpenAI Assistant函数调用:正确提交工具输出的Python指南

心靈之曲

心靈之曲

发布时间:2025-12-13 14:22:30

|

814人浏览过

|

来源于php中文网

原创

掌握openai assistant函数调用:正确提交工具输出的python指南

本文详细阐述了在OpenAI Assistant API中处理函数调用并正确提交工具输出的方法。针对常见的`BadRequestError`问题,文章深入分析了错误原因,并提供了使用`client.beta.threads.runs.submit_tool_outputs`的正确解决方案。通过完整的Python代码示例和注意事项,旨在帮助开发者高效、准确地实现Assistant的函数调用功能,确保API交互的顺畅与可靠。

理解OpenAI Assistant的函数调用机制

OpenAI Assistant API提供了一个强大的功能,允许助手在对话过程中调用外部工具或函数来获取信息或执行操作。当助手需要调用某个函数时,它会将对话状态从“in_progress”转换为“requires_action”,并在run.required_action.submit_tool_outputs.tool_calls中提供需要调用的函数信息,包括函数名和参数。开发者的任务是执行这些函数,并将结果反馈给助手,以便其继续生成响应。

常见的错误与原因分析

许多开发者在首次尝试向Assistant提交函数执行结果时,可能会遇到类似于以下代码片段所示的错误:

# 错误的尝试
message = client.beta.threads.messages.create(
    thread_id=thread.id,
    role="tool", # 错误:此角色不适用于创建新消息来提交工具输出
    content=ret,
)

当尝试使用client.beta.threads.messages.create方法并指定role="tool"来提交函数执行结果时,API会返回openai.BadRequestError: Error code: 400 - {'error': {'message': "1 validation error for Request\nbody -> role\n value is not a valid enumeration member; permitted: 'user' (type=type_error.enum; enum_values=[])", ...}}。

立即学习Python免费学习笔记(深入)”;

这个错误清晰地表明,client.beta.threads.messages.create方法中的role参数仅接受"user"(用户消息)或"assistant"(助手消息)。它并不是用来提交工具函数执行结果的接口。工具函数的结果需要通过专门的机制来通知Assistant,而不是作为普通对话消息的一部分。

AI Room Planner
AI Room Planner

AI 室内设计工具,免费为您的房间提供上百种设计方案

下载

正确的函数结果提交方法

OpenAI Assistant API为提交工具函数执行结果提供了专用的方法:client.beta.threads.runs.submit_tool_outputs。这个方法允许你将一个或多个工具调用的输出结果与特定的运行(Run)关联起来,从而让Assistant能够获取这些结果并继续处理。

其基本用法如下:

run = client.beta.threads.runs.submit_tool_outputs(
  thread_id=thread.id,
  run_id=run.id,
  tool_outputs=[
      {
        "tool_call_id": tool_call_id,
        "output": "your_function_output_string_here",
      },
      # 如果有多个工具调用,可以在这里添加更多字典
    ]
)
  • thread_id: 当前会话的线程ID。
  • run_id: 当前处于requires_action状态的运行ID。
  • tool_outputs: 一个列表,包含所有需要提交的工具输出。每个输出是一个字典,必须包含:
    • tool_call_id: 助手在run.required_action.submit_tool_outputs.tool_calls中提供的具体工具调用的ID。这个ID用于将输出与助手请求的特定函数调用进行匹配。
    • output: 对应工具函数执行后的结果字符串。

完整的示例代码

下面是一个完整的Python示例,演示了如何正确地处理Assistant的函数调用并提交结果:

from openai import OpenAI
import time
import os
import json # 导入json库,用于处理函数参数

# 初始化OpenAI客户端
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY")) # 建议从环境变量获取API_KEY

# 假设你已经创建并配置了一个Assistant,其ID存储在环境变量中
# 并添加了名为 'funnyfunc' 的工具
# 例如:assistant = client.beta.assistants.create(
#     name="Function Caller Assistant",
#     instructions="You are a helpful assistant that can call the funnyfunc.",
#     model="gpt-4-turbo",
#     tools=[{"type": "function", "function": {"name": "funnyfunc", "description": "Returns a funny value."}}]
# )
# 然后将 assistant.id 存储到环境变量 ALEXA_ASSISTANT_ID_OPENAI 中

assistant_id = os.environ.get("ALEXA_ASSISTANT_ID_OPENAI")
if not assistant_id:
    raise ValueError("请设置环境变量 ALEXA_ASSISTANT_ID_OPENAI 为您的Assistant ID")

# 创建一个新的线程
thread = client.beta.threads.create()

# 辅助函数:等待Run完成
def wait_on_run(run_obj, thread_obj):
    """
    等待Run对象完成执行,并返回最新的Run状态。
    """
    while run_obj.status in ["queued", "in_progress", "cancelling"]:
        time.sleep(0.5) # 适当增加等待时间以减少API调用频率
        run_obj = client.beta.threads.runs.retrieve(
            thread_id=thread_obj.id,
            run_id=run_obj.id,
        )
    return run_obj

# 模拟自定义函数
def funnyfunc():
    """一个简单的模拟函数,返回一个字符串。"""
    print("Executing funnyfunc...")
    return "The funniest number is five!"

# 核心函数:向Assistant提问并处理函数调用
def ask_question_and_handle_tools(question_content):
    """
    向Assistant提问,并处理可能的函数调用。
    """
    # 1. 向线程添加用户消息
    client.beta.threads.messages.create(
        thread_id=thread.id,
        role="user",
        content=question_content,
    )

    # 2. 创建并运行Assistant
    run = client.beta.threads.runs.create(
        thread_id=thread.id,
        assistant_id=assistant_id,
    )

    # 3. 等待Run完成或需要动作
    run = wait_on_run(run, thread)

    # 4. 循环处理 'requires_action' 状态
    while run.status == 'requires_action':
        if run.required_action.type == 'submit_tool_outputs':
            tool_outputs_to_submit = []
            for tool_call in run.required_action.submit_tool_outputs.tool_calls:
                function_name = tool_call.function.name
                tool_call_id = tool_call.id

                # 假设我们只处理 'funnyfunc'
                if function_name == 'funnyfunc':
                    # 在实际应用中,这里会解析 tool_call.function.arguments 并传递给实际函数
                    # 例如:args = json.loads(tool_call.function.arguments)
                    # result = funnyfunc(**args)
                    result = funnyfunc() # 调用模拟函数
                    tool_outputs_to_submit.append({
                        "tool_call_id": tool_call_id,
                        "output": result,
                    })
                else:
                    # 对于未实现的函数,可以返回一个错误或默认值
                    print(f"Warning: Unimplemented function called: {function_name}")
                    tool_outputs_to_submit.append({
                        "tool_call_id": tool_call_id,
                        "output": f"Error: Function '{function_name}' not implemented.",
                    })

            # 提交工具输出
            run = client.beta.threads.runs.submit_tool_outputs(
                thread_id=thread.id,
                run_id=run.id,
                tool_outputs=tool_outputs_to_submit
            )

            # 提交后,需要再次等待Run完成
            run = wait_on_run(run, thread)
        else:
            raise NotImplementedError(f"Unhandled required action type: {run.required_action.type}")

    # 5. Run完成后,获取Assistant的响应
    if run.status == 'completed':
        messages = client.beta.threads.messages.list(
            thread_id=thread.id,
            order="desc", # 获取最新消息
            limit=1 # 只获取一条
        )
        # 查找最新的Assistant消息
        for message in messages.data:
            if message.role == "assistant":
                for content_block in message.content:
                    if content_block.type == "text":
                        return content_block.text.value
        return "No assistant response found."
    else:
        return f"Run finished with status: {run.status}"

# 提问并打印结果
response = ask_question_and_handle_tools("What is funnyfunc() equal to right now?")
print("\nAssistant's final response:")
print(response)

运行前请确保:

  1. 你已设置 OPENAI_API_KEY 环境变量
  2. 你已创建了一个OpenAI Assistant,并为其添加了名为 funnyfunc 的Function Tool。
  3. 将你的Assistant ID赋值给 ALEXA_ASSISTANT_ID_OPENAI 环境变量。

注意事项

  1. 错误处理与重试机制:在生产环境中,wait_on_run函数应包含更健壮的错误处理和指数退避重试机制,以应对API调用失败或暂时性服务问题。
  2. 多工具调用:如果Assistant在一个requires_action状态下请求调用多个工具,run.required_action.submit_tool_outputs.tool_calls将是一个列表。你的代码需要遍历这个列表,为每个工具调用执行相应的函数,并收集所有结果,然后一次性通过submit_tool_outputs提交。
  3. 函数参数解析:当Assistant调用函数时,tool_call.function.arguments会包含函数参数的JSON字符串。你需要使用json.loads()来解析这些参数,并将其传递给你的实际函数。
  4. 状态管理:Assistant API是异步的。每次提交工具输出后,都需要再次等待Run完成或进入下一个requires_action状态。
  5. API版本:请确保你的openai Python库是最新版本,以兼容OpenAI Assistant API的最新功能和行为。

总结

正确处理OpenAI Assistant的函数调用是构建智能对话系统的关键一步。核心在于理解client.beta.threads.messages.create与client.beta.threads.runs.submit_tool_outputs之间的区别。前者用于常规的对话消息,而后者则是专门用于向Assistant反馈外部工具或函数执行结果的接口。通过遵循本文提供的指南和示例代码,开发者可以有效避免常见的BadRequestError,并成功地将外部功能集成到OpenAI Assistant中,从而实现更丰富、更强大的交互体验。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

420

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

536

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

312

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

77

2025.09.10

scripterror怎么解决
scripterror怎么解决

scripterror的解决办法有检查语法、文件路径、检查网络连接、浏览器兼容性、使用try-catch语句、使用开发者工具进行调试、更新浏览器和JavaScript库或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

228

2023.10.18

500error怎么解决
500error怎么解决

500error的解决办法有检查服务器日志、检查代码、检查服务器配置、更新软件版本、重新启动服务、调试代码和寻求帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

297

2023.10.25

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

320

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

212

2023.09.04

C++ 设计模式与软件架构
C++ 设计模式与软件架构

本专题深入讲解 C++ 中的常见设计模式与架构优化,包括单例模式、工厂模式、观察者模式、策略模式、命令模式等,结合实际案例展示如何在 C++ 项目中应用这些模式提升代码可维护性与扩展性。通过案例分析,帮助开发者掌握 如何运用设计模式构建高质量的软件架构,提升系统的灵活性与可扩展性。

14

2026.01.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.4万人学习

Django 教程
Django 教程

共28课时 | 3.7万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号