Skip to content

2023 年 11 月 6 日,OpenAI 举办了首届开发者大会——OpenAI DevDay。您可以在 OpenAI DevDay, Opening Keynote 观看大会相关视频。

在这次大会上,OpenAI 发布了 Assistant API(视频 1:02:47 处),旨在简化构建定制化 AI 助手的流程。

Assistant API 允许开发者在自己的应用中轻松集成 AI 助手。一个助手主要由以下几个部分组成:

  • name:助手的名称,用于标识助手。
  • instructions:助手的指令,用于设定助手的个性和目标,类似于 system message
  • tools:助手可以使用的工具。每个助手最多可以配置 128 个工具,可以是 OpenAI 提供的工具,也可以通过 函数调用 集成第三方工具。目前,OpenAI 提供了三种工具:代码解释器、检索和函数调用。

助手能够根据指令并利用工具来响应用户的请求。实际上,OpenAI Assistant 的概念与 @sec-agent 中介绍的 Agent 非常相似。在 LangChain 的官方文档中,OpenAI Assistant 也被归类为一种 Agent 类型。这表明,从 LangChain 的角度来看,OpenAI Assistant 本质上也是一种 Agent。Assistant API 的发布,大大提升了我们开发 OpenAI Assistant 的效率。

OpenAI 的技术论坛上,有用户提出了这样的疑问:Assistant API 和 LangChain 之间有什么区别?。正如该帖子下方的回复所说,Assistant API 和 LangChain Agent 做的是同一件事,只是 Assistant API 在某些方面更易于使用。

Assistant API and LangChain are basically doing the same thing. Both require programming. The only advantage of Assistant API is that memory and context window are automatically managed where in LangChain you have explicitly set those things up.

Assisant API 架构

OpenAI Assistant API 的架构图如 @fig-d_assistant 所示。

OpenAI Assistant API 的架构示意图

Assistant Overview 已经对这张图进行了详细的解释。其中,最吸引人的特性之一是访问持久化线程的能力。

INFO

助手可以访问持久化线程。线程通过存储消息历史记录来简化 AI 应用的开发,并在对话过长而超出模型的上下文长度时自动截断。

使用 Assistant API,我们只需要创建一次线程,就可以在该线程内进行连续的多轮对话。多轮对话所需的 记忆 功能由 OpenAI 自动管理(而如果使用 LangChain 或其他框架,则需要我们自己实现)。这使得我们可以轻松实现类似下面的多轮会话:

  • 1 + 1 =?
  • 那么,再加上 10 的结果是多少?
  • ……

Assistant 运行状态

与进程类似,Assistant API 创建的线程在响应用户提问时(对应 @fig-d_assistant 中的 Run 阶段),也会经历不同的状态转换。每次运行的具体状态转换过程如 @fig-openai_ass_status 所示。

Assistant API 线程每次运行的生命周期示意图

状态状态含义
queued首次创建助理并执行或从 required_action 状态恢复时,线程会进入 queued 状态。queued 状态会立即转换为 in_progress 状态。
in_progressin_progress 状态下,助理使用模型和工具执行相关操作。可以通过检查 Run Step 来获取本次运行的具体进度。
completed当本次运行成功完成时,线程会进入该状态。此时,可以查看助理返回的所有消息,也可以在该线程中继续进行下一轮对话。
requires_action当使用 函数调用 工具时,一旦模型确定了要调用的函数名称和参数,线程会转换为 required_action 状态。然后,我们需要运行这些函数并提交函数响应,才能继续运行。如果在 expires_at 时间戳(创建后约 10 分钟)到达时仍未提交函数运行结果,则本次运行将进入 expired 状态。
expired函数调用 的输出未在 expires_at 之前提交时,会发生这种情况。此外,如果本次运行时间过长,超过 expires_at 规定的时间,也会转换到该状态。
cancelling可以使用 Cancel Run API 取消 in_progress 状态的某次运行。一旦取消成功,本次运行的状态将变为 cancelled。需要注意的是,Assistant API 只是尝试取消,并不能保证取消一定成功。
cancelled如果某次运行已成功取消,则进入该状态。
failed执行失败时,进入该状态。可以通过 last_error 查看失败原因。

: Assistant API 中不同状态的含义

由于 Assistant API 提供的线程是持久线程,因此,每次使用该线程处理用户请求时,最好及时查询线程的当前状态,以避免出现非预期的结果。

Assistant API 示例

from langchain.agents.openai_assistant import OpenAIAssistantRunnable

interpreter_assistant = OpenAIAssistantRunnable.create_assistant(
    name="langchain assistant",
    instructions="你是一个私人数学导师。编写并运行代码来回答数学问题。", # You are a personal math tutor. Write and run code to answer math questions.
    tools=[{"type": "code_interpreter"}],
    model="gpt-4-1106-preview",
) # <1>

output = interpreter_assistant.invoke({"content": "10 - 4 的 2.7 次方是多少?"}) # What's 10 - 4 raised to the 2.7
print(output)

"""
[ThreadMessage(id='msg_6Gj48OdMV8dQrFUPTh17UvG4', assistant_id='asst_19av1lcBjSCQ5cEk4pWqugEU', content=[MessageContentText(text=Text(annotations=[], value='The result of the expression \\(10 - 4^{2.7}\\) is approximately \\(-32.224\\).'), type='text')], created_at=1700038489, file_ids=[], metadata={}, object='thread.message', role='assistant', run_id='run_4wK9GIK2W0iiJlLB86DKoMQQ', thread_id='thread_Ie874bQrsaakLMpOMZe2KUav')]
""" #<3>

output_2 = interpreter_assistant.invoke({"content": "然后,将结果加上 10", "thread_id": "thread_Ie874bQrsaakLMpOMZe2KUav"}) # Then, Add 10 to the result
print(output_2)

"""
[ThreadMessage(id='msg_xRoHzvCdtqW9NRWxmE36VMZG', assistant_id='asst_mEAcerOkTv1IyggYoU3jTNMn', content=[MessageContentText(text=Text(annotations=[], value='After adding 10 to the previous result, the new result is approximately -22.224.'), type='text')], created_at=1700038760, file_ids=[], metadata={}, object='thread.message', role='assistant', run_id='run_ubrOtRXh6ITIRQ4BbPMk5juV', thread_id='thread_Ie874bQrsaakLMpOMZe2KUav')]
""" #<5>
  1. 创建一个 Assistant 线程
  2. 计算 $10-4^{2.7}$
  3. 获得结果 -32.224,同时返回线程 id 等其他信息
  4. 在当前结果基础上,继续用同一个线程执行 $res + 10$
  5. 获得结果 -22.224