Assistants API
Assistants API 允许你在自己的应用程序内构建 AI 助手。助手拥有指令,并能利用模型、工具和知识来响应用户查询。Assistants API 目前支持三种工具:代码解释器、检索和函数调用。将来,OpenAI 计划发布更多由 OpenAI 构建的工具,并允许你在 OpenAI 的平台上提供自己的工具。
你可以使用 Assistants playground 或按照本指南逐步构建来探索 Assistants API 的功能。
Assistants API 的典型集成流程如下:
- 在 API 中创建一个助手,通过定义自定义指令和选择一个模型。如果有帮助的话,启用如代码解释器、检索和函数调用等工具。
- 当用户开始对话时,创建一个线程。
- 随着用户提问,向线程添加消息。
- 在线程上运行助手以触发响应。这将自动调用相关工具。
Assistants API 目前处于测试阶段。
关键步骤
创建一个助手
助手代表一个实体,可以被配置为使用多个参数来响应用户的消息,如:
- 指令:说明助手和模型应如何行为或响应
- 模型:你可以指定任何 GPT-3.5 或 GPT-4 模型,包括调优后的模型。检索工具需要 gpt-3.5-turbo-1106 和 gpt-4-1106-preview 模型。
- 工具:API 支持由 OpenAI 构建和托管的代码解释器和检索。
- 函数:API 允许你定义自定义函数签名,与 OpenAI 的函数调用功能类似。
在此示例中,OpenAI 创建的助手是一个个人数学导师,并启用了代码解释器工具:
assistant = client.beta.assistants.create(
name="Math Tutor",
instructions="You are a personal math tutor. Write and run code to answer math questions.",
tools=[{"type": "code_interpreter"}],
model="gpt-4-1106-preview"
)
NOTE: 调用 Assistants API 需要你传递一个 beta HTTP 头部。如果你使用的是 OpenAI 官方的 Python 和 Node.js SDK,则此操作会自动处理。
OpenAI-Beta: assistants=v1
步骤 2:创建一个线程
线程代表一场对话。OpenAI 建议在用户开始对话时立即为每个用户创建一个线程。通过创建消息,将任何特定于用户的上下文和文件传递到这个线程。
thread = client.beta.threads.create()
线程没有大小限制。你可以向线程传递任意多的消息。API 将确保对模型的请求适合最大上下文窗口,并使用相关优化技术,如截断。
步骤 3:向线程添加消息
消息包含用户的文本,以及用户上传的任何文件。现在不支持图片文件,但 OpenAI 计划在未来几个月内添加对它们的支持。
message = client.beta.threads.messages.create(
thread_id=thread.id,
role="user",
content="I need to solve the equation `3x + 11 = 14`. Can you help me?"
)
打印消息对象会获得:
{
"object": "list",
"data": [
{
"created_at": 1696995451,
"id": "msg_4rb1Skx3XgQZEe4PHVRFQhr0",
"object": "thread.message",
"thread_id": "thread_34p0sfdas0823smfv",
"role": "user",
"content": [{
"type": "text",
"text": {
"value": "I need to solve the equation `3x + 11 = 14`. Can you help me?",
"annotations": []
}
}],
...
步骤 4:运行助手
为了让助手响应用户消息,你需要创建一个运行。这使得助手读取线程并决定是否调用工具或仅使用模型来最佳回答用户查询。随着运行的进展,助手将以 "role =" assistant "" 的角色将消息附加到线程上。
你还可以在创建运行时向助手传递额外的指令:
run = client.beta.threads.runs.create(
thread_id=thread.id,
assistant_id=assistant.id,
instructions="Please address the user as Jane Doe. The user has a premium account."
)
步骤 5:显示助手的响应
这会创建一个排队状态的运行。你可以定期检索运行的状态,以查看它是否已完成。
run = client.beta.threads.runs.retrieve(
thread_id=thread.id,
run_id=run.id
)
一旦运行完成,你可以检索助手添加到线程的消息。
messages = client.beta.threads.messages.list(
thread_id=thread.id
)
最后,向用户显示它们!在此运行期间,助手向线程添加了两条新消息。
你还可以检索此运行的运行步骤,如果你想探索或显示助手及其工具的内部工作。
助手 API 是如何工作的?
助手 API 旨在帮助开发者构建能够执行多种任务的强大 AI 助手。
-
助手可以调用 OpenAI 的模型,并给出具体指示以调整其个性和能力。
-
助手能够同时访问多种工具。这些工具既可以是 OpenAI 托管的——比如代码解释器和知识检索——也可以是你构建/托管的工具(通过函数调用)。
-
助手可以访问持久的线程。线程通过存储消息历史并在对话对于模型的上下文长度太长时进行截断,简化了 AI 应用开发。你只需创建一次线程,然后随着用户的回复,简单地向其中追加消息即可。
-
助手可以在不同时机访问文件——无论是作为创建助手的时候,还是助手与用户交互的时候。使用工具时,助手也可以创建文件(例如,图片、电子表格等)并在它们创建的消息中引用这些文件。
对象 (Objects)
!(助手对象架构图)[https://cdn.openai.com/API/docs/images/diagram-assistant.webp (opens in a new tab)]
对象标识符 | 它代表什么 |
Assistant | 使用 OpenAI 模型并调用工具的专为特定目的构建的 AI| Thread | 助手与用户之间的会话会话。线程存储消息,并自动处理内容截断,以适应模型的上下文| Message| 由助手或用户创建的消息。消息可以包含文本、图片和其他文件。消息存储为线程上的一个列表| Run | 在线程上调用助手的行为。助手使用它的配置和线程的消息执行任务,通过调用模型和工具。作为运行的一部分,助手将消息追加到线程中 | Run Step | 助手在运行过程中所采取的详细步骤列表。一个助手可以在其运行过程中调用工具或创建消息。检查运行步骤可以让你内省助手如何得出最终结果|
创建助手
OpenAI 推荐使用 OpenAI 的最新模型搭配助手 API,以获得最佳结果和与工具的最大兼容性。 要开始创建助手,只需指定要使用的模型。但你可以进一步自定义助手的行为:
-
使用 instructions 参数来指导助手的个性和定义其目标。instructions 类似于聊天完成 API 中的系统消息。
-
使用 tools 参数授予助手访问多达 128 个工具的权限。你可以让它访问 OpenAI 托管的工具,如 code_interpreter 和 retrieval,或者通过函数调用第三方工具。
-
使用 file_ids 参数授予像 code_interpreter 和 retrieval 这样的工具访问文件的权限。文件通过文件上传端点上传,并且必须将用途设置为 assistants,才能与此 API 一起使用。
例如,要创建一个能够根据.csv 文件创建数据可视化的助手,请先上传一个文件。
file = client.files.create(
file=open("speech.py", "rb"),
purpose='assistants'
)
然后用上传的文件创建助手。
assistant = client.beta.assistants.create(
name="Data visualizer",
description="You are great at creating beautiful data visualizations. You analyze data present in .csv files, understand trends, and come up with data visualizations relevant to those trends. You also share a brief text summary of the trends observed.",
model="gpt-4-1106-preview",
tools=[{"type": "code_interpreter"}],
file_ids=[file.id]
)
你可以为每个助手附加最多 20 个文件,每个文件最大为 512MB。此外,你组织上传的所有文件的大小不应超过 100GB。你可以通过 OpenAI 的帮助中心申请增加这个存储限制。
你还可以使用 AssistantFile 对象来创建、删除或查看助手和文件对象之间的关联。请注意,删除 AssistantFile 并不会删除原始文件对象,它仅仅删除该文件与助手之间的关联。要删除文件,请使用文件删除端点。
管理 Threads 和 Messages
线程和消息代表助手与用户之间的会话会话。你可以在线程中存储无限数量的消息。一旦消息的大小超过模型的上下文窗口,线程会自动地截断它们以适应。你可以像这样创建一个包含初始消息列表的线程:
thread = client.beta.threads.create(
messages=[
{
"role": "user",
"content": "Create 3 data visualizations based on the trends in this file.",
"file_ids": [file.id]
}
]
)
消息可以包含文本、图片或文件。目前,用户创建的消息不能包含图片文件,但 OpenAI 计划在未来添加支持。
消息注释
助手创建的消息可能在对象的 content 数组中包含注释。注释提供了有关如何在消息中注释文本的信息。
注释有两种类型:
-
文件引用
file_citation
:文件引用是由检索工具创建的,被助手上传或者用来生成响应的这些文件,被检索工具操作后,在这些文件中定义了很多引用块。 -
文件路径
file_path
:文件路径注释是由代码解释器创建的,指定了在助手运行时,如何访问和操作一组文件的路径。
当消息对象中存在注释时,你会在文本中看到由模型生成的不可读子字符串,你应该用注释替换这些字符串。这些字符串可能看起来像【13†source】或者 sandbox:/mnt/data/file.csv。以下是一个 python 代码片段的示例,它将这些字符串替换为注释中存在的信息。
# Retrieve the message object
message = client.beta.threads.messages.retrieve(
thread_id="...",
message_id="..."
)
# Extract the message content
message_content = message.content[0].text
annotations = message_content.annotations
citations = []
# Iterate over the annotations and add footnotes
for index, annotation in enumerate(annotations):
# Replace the text with a footnote
message_content.value = message_content.value.replace(annotation.text, f' [{index}]')
# Gather citations based on annotation attributes
if (file_citation := getattr(annotation, 'file_citation', None)):
cited_file = client.files.retrieve(file_citation.file_id)
citations.append(f'[{index}] {file_citation.quote} from {cited_file.filename}')
elif (file_path := getattr(annotation, 'file_path', None)):
cited_file = client.files.retrieve(file_path.file_id)
citations.append(f'[{index}] Click <here> to download {cited_file.filename}')
# Note: File download functionality not implemented above for brevity
# Add footnotes to the end of the message before displaying to user
message_content.value += '\n' + '\n'.join(citations)
运行和运行步骤
当你从线程中获得了用户的所有上下文后,你可以选择一个助手来运行线程。
run = client.beta.threads.runs.create(
thread_id=thread.id,
assistant_id=assistant.id
)
默认情况下,运行会使用在助手对象中指定的模型和工具配置,但在创建运行时,你可以重写其中的大多数设置,以增加灵活性:
run = client.beta.threads.runs.create(
thread_id=thread.id,
assistant_id=assistant.id,
model="gpt-4-1106-preview",
instructions="additional instructions",
tools=[{"type": "code_interpreter"}, {"type": "retrieval"}]
)
注意:与助手关联的 file_ids 在运行创建期间不能被重写。你必须使用修改助手端点来做这件事。
运行生命周期
运行对象可以有多个状态。
状态 |定义|
queued | 当运行首次创建或完成 required_action 时,它们会移动到 queued 状态。它们应该几乎立即转移到 in_progress 状态。|
in_progress | 在 in_progress 状态时,助手使用模型和工具执行步骤。你可以通过检查运行步骤来查看运行的进展。|
completed | 运行成功完成!现在你可以查看助手添加到线程中的所有消息,以及运行采取的所有步骤。你还可以通过向线程添加更多用户消息并创建另一个运行来继续对话。|
requires_action | 在使用函数调用工具时,一旦模型确定了要调用的函数的名称和参数,运行会移动到 requires_action 状态。然后,你必须运行这些函数并提交输出,之后运行才会继续。如果在 expires_at 时间戳过去(大约创建后 10 分钟)之前未提供输出,运行将移动到过期状态。|
expired | 这发生在函数调用输出未在 expires_at 之前提交,运行过期的情况下。此外,如果运行执行的时间太长,超出了 expires_at 中规定的时间,OpenAI 的系统将使运行过期。|
cancelling | 你可以尝试使用取消运行端点来取消 in_progress 中的运行。一旦取消尝试成功,运行的状态就会转变为 cancelled。尝试取消是有可能的但不保证。| cancelled | 运行成功取消。| failed | 你可以通过查看运行中的 last_error 对象来了解失败的原因。失败的时间戳将记录在 failed_at 下。|
轮询更新
为了保持运行状态的更新,你将不得不定期检索运行对象。每次检索对象时,你都可以检查运行的状态,以确定你的应用接下来应该做什么。OpenAI 计划在不久的将来添加对流式传输的支持,以简化此过程。
线程锁定
当运行正在进行中并且不处于终端状态时,线程被锁定。这意味着:
- 无法向线程添加新消息。
- 无法在线程上创建新的运行。
运行步骤
运行步骤的状态含义与运行状态相同。
运行步骤对象中的大部分有趣细节都存在于 step_details 字段中。可以有两种类型的步骤细节:
message_creation
:当助手在线程上创建消息时,会创建这个运行步骤。
tool_calls
:当助手调用工具时,会创建这个运行步骤。围绕此的详细信息在工具指南的相关部分有覆盖。
数据访问权限指导
目前,通过 API 创建的助手、线程、消息和文件都限定于整个组织。因此,任何拥有组织 API 密钥访问权限的人都能读取或写入组织中的助手、线程、消息和文件。
OpenAI 强烈推荐以下数据访问控制措施:
-
实施授权。在对助手、线程、消息和文件执行读写操作之前,请确保终端用户有权这样做。例如,在你的数据库中存储终端用户可以访问的对象 ID,并在使用 API 获取对象 ID 之前检查它。
-
限制 API 密钥访问。仔细考虑你的组织中谁应该拥有 API 密钥,并定期审计此列表。API 密钥启用了包括读取和修改敏感信息在内的广泛操作,如消息和文件。
-
创建独立账户。考虑为不同的应用创建独立账户/组织,以便在多个应用程序中隔离数据。
API 限制
在此 beta 版中,OpenAI 正在努力解决未来几周和几个月中的几个已知限制。当 OpenAI 增加对额外功能的支持时,OpenAI 会在这个页面上发布更新日志。以下功能,API 并不支持:
- 对流式输出的支持(包括消息和运行步骤)。
- 对通知的支持,以便在无需轮询的情况下共享对象状态更新。
- 对 DALL · E 工具的支持。
- 支持带有图像的用户消息创建。