OPENAI Assistants API学习笔记

OPENAI Assistants API学习笔记

📅 2024-12-05 | 🖱️
🔖 agent

1.OPENAI Assistants API概述 #

OPENAI Assistants API概述:构建AI助手,并提供工具和集成功能

OPENAI的Assistants API允许我们在自己的应用程序中构建AI助手。助手包含指令(instructions),并可以利用模型(models)、工具(tools)和文件(files)来响应用户查询。Assistants API 当前支持三种类型的工具:代码解释器、文件搜索和函数调用。

您可以使用 Assistants Playground 来探索 Assistants API 的功能,或者通过 Assistants API 快速入门中概述的逐步集成进行构建。

可以使用Assistants Playground了解Assistants API的功能,或者按照Assistants API快速入门中概述的逐步集成步骤进行构建。

1.1 Assistants的工作原理 #

Assistants API旨在帮助开发者构建功能强大的AI助手,支持执行多种任务。

Assistants API目前处于Beta测试阶段
  1. 助手可以向 OpenAI 的模型发送特定指令,从而调整其个性和能力。
  2. 助手可以同时访问多个工具,这些工具既可以是 OpenAI 托管的工具(如code_interpreterfile_search),也可以是我们自行构建或托管的工具(通过函数调用function calling实现)。
  3. 助手支持访问具有持久性的thread。thread通过存储消息历史记录并在对话超出模型上下文长度时进行截断,从而简化了AI应用程序的开发。只需创建一次thread,并在用户回复时不断向其中追加消息即可。
  4. 助手可以访问多种格式的文件——这些文件既可以在助手创建时提供,也可以作为助手与用户之间thread的一部分提供。在使用工具时,助手还可以创建文件(例如图像、电子表格等),并在其生成的消息中引用所使用的文件。

1.2 对象 #

diagram-assistant.webp

ObjectWhat it represents
Assistant为特定目的构建的AI,使用OpenAI的模型并调用工具。
Thread助手与用户之间的会话。Thread存储消息,并自动处理截断以将内容适配到模型的上下文中。
Message由助手或用户创建的消息。消息可以包含文本、图片和其他文件,并作为Thread上的列表存储。
Run在Thread上调用助手的一次运行。助手利用其配置和Thread的消息,通过调用模型和工具来执行任务。作为Run的一部分,助手会将消息附加到Thread中。
Run Step助手在一次Run中执行的详细步骤列表。助手可以在运行过程中调用工具或创建消息。检查运行步骤可深入了解助手如何得出最终结果。

2.Assistants API快速入门 #

Assistants API的典型集成流程如下:

  1. 通过定义自定义指令并选择模型来创建Assistant。如果需要,可以添加文件并启用诸如代码解释器、文件搜索和函数调用等工具。
  2. 当用户开始对话时,创建一个Thread。
  3. 用户提问时,将Message添加到该Thread。
  4. 在该Thread上运行Assistant,通过调用模型和工具生成响应。

本入门指南将逐步讲解如何创建和运行一个启用了代码解释器的Assistant。在本示例中,我们将创建一个个人数学辅导助手,并启用代码解释器工具。

提示

调用Assistants API时需要传递一个测试版HTTP头。如果你使用的是OpenAI官方的Python或Node.js SDK,这一操作会自动处理。

2.1 步骤1:创建一个Assistant #

Assistant代表一个实体,可以通过配置多个参数(如模型mode、指令instructions和工具tools)来响应用户的消息。

1from openai import OpenAI
2client = OpenAI()
3
4assistant = client.beta.assistants.create(
5  name="Math Tutor",
6  instructions="You are a personal math tutor. Write and run code to answer math questions.",
7  tools=[{"type": "code_interpreter"}],
8  model="gpt-4o",
9)

2.2 步骤2:创建一个Thread #

Thread代表用户与一个或多个助理之间的交流。当用户(或你的AI应用)开始与Assistant交流时,可以创建一个Thread。

1thread = client.beta.threads.create()

2.3 步骤3:添加Message到Thread中 #

用户或应用程序创建的消息会作为Message对象添加Thread中。消息可以包含文本和文件。每个Thread最多可以容纳100,000 条消息,对于超出模型上下文窗口限制的部分,会自动智能截取超出的消息内容。

1message = client.beta.threads.messages.create(
2  thread_id=thread.id,
3  role="user",
4  content="I need to solve the equation `3x + 11 = 14`. Can you help me?"
5)

2.4 步骤4:创建Run #

可以使用Python和Node SDK中的“创建和流式传输”助手来创建Run并流式传输响应。

 1from typing_extensions import override
 2from openai import AssistantEventHandler
 3 
 4# First, we create a EventHandler class to define
 5# how we want to handle the events in the response stream.
 6 
 7class EventHandler(AssistantEventHandler):    
 8  @override
 9  def on_text_created(self, text) -> None:
10    print(f"\nassistant > ", end="", flush=True)
11      
12  @override
13  def on_text_delta(self, delta, snapshot):
14    print(delta.value, end="", flush=True)
15      
16  def on_tool_call_created(self, tool_call):
17    print(f"\nassistant > {tool_call.type}\n", flush=True)
18  
19  def on_tool_call_delta(self, delta, snapshot):
20    if delta.type == 'code_interpreter':
21      if delta.code_interpreter.input:
22        print(delta.code_interpreter.input, end="", flush=True)
23      if delta.code_interpreter.outputs:
24        print(f"\n\noutput >", flush=True)
25        for output in delta.code_interpreter.outputs:
26          if output.type == "logs":
27            print(f"\n{output.logs}", flush=True)
28 
29# Then, we use the `stream` SDK helper 
30# with the `EventHandler` class to create the Run 
31# and stream the response.
32 
33with client.beta.threads.runs.stream(
34  thread_id=thread.id,
35  assistant_id=assistant.id,
36  instructions="Please address the user as Jane Doe. The user has a premium account.",
37  event_handler=EventHandler(),
38) as stream:
39  stream.until_done()

在API参考文档中可以查看完整的Assistants流式事件列表。还可以在PythonNode仓库文档中查看这些事件的SDK事件监听器列表。

Run是异步的,这意味着需要通过轮询Run对象来监控其状态status,直到达到终止状态。为了方便,‘创建和轮询’(‘create and poll’)SDK助手可以帮助您创建Run并轮询其完成状态。

1run = client.beta.threads.runs.create_and_poll(
2  thread_id=thread.id,
3  assistant_id=assistant.id,
4  instructions="Please address the user as Jane Doe. The user has a premium account."
5)

一旦Run完成,就可以列出Assistant添加到Thread中的Messages。

1if run.status == 'completed': 
2  messages = client.beta.threads.messages.list(
3    thread_id=thread.id
4  )
5  print(messages)
6else:
7  print(run.status)

如果想查看在此运行期间所做的任何工具调用,还可以列出此运行(Run)的步骤(Run Steps)。

3.深入Assistants API #

创建和管理Assistants的深入指南。

3.1 Creating Assistants #

为了获得最佳效果和与工具的最大兼容性,建议使用OpenAI的最新模型与Assistants API。

要开始使用,创建Assistant只需指定要使用的模型。但是,还可以进一步自定义助手的行为:

  1. 使用instructions参数来引导助手的个性并定义其目标。instructions类似于Chat Completions API中的系统消息。
  2. 使用tools参数为助手提供最多128个工具的访问权限。可以为助手提供对OpenAI托管工具(如code_interpreterfile_searc)的访问权限,或者通过函数调用调用(function calling)第三方工具。
  3. 使用tool_resources参数为工具(如code_interpreterfile_search)提供对文件的访问权限。文件通过文件上传端点进行上传,必须将其用途设置为assistants才能与此API一起使用。

例如,要创建一个可以基于.csv文件生成数据可视化的助手,首先上传一个文件。

1file = client.files.create(
2  file=open("revenue-forecast.csv", "rb"),
3  purpose='assistants'
4)

然后,创建启用了code_interpreter工具的助手,并将该文件作为工具的资源提供。

 1assistant = client.beta.assistants.create(
 2  name="Data visualizer",
 3  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.",
 4  model="gpt-4o",
 5  tools=[{"type": "code_interpreter"}],
 6  tool_resources={
 7    "code_interpreter": {
 8      "file_ids": [file.id]
 9    }
10  }
11)

可以在 code_interpreter 中附加最多 20 个文件,在 file_search(使用 vector_store 对象)中附加最多10000个文件。 每个文件最大可以是512MB,并且最多有5000000 个token。默认情况下,项目中上传的所有文件的总大小不能超过100GB。

3.2 管理Threads和Messages #

Thread和Messsage表示助手和用户之间的对话会话。每个Thread的消息数限制为100000条。当消息的大小超过模型的上下文窗口时,Thread将尝试智能地截断消息,然后删除它认为最不重要的消息。

可以像这样创建一个带有初始消息列表的Thread:

 1thread = client.beta.threads.create(
 2  messages=[
 3    {
 4      "role": "user",
 5      "content": "Create 3 data visualizations based on the trends in this file.",
 6      "attachments": [
 7        {
 8          "file_id": file.id,
 9          "tools": [{"type": "code_interpreter"}]
10        }
11      ]
12    }
13  ]
14)

消息可以包含文本、图像或文件附件。消息的attachments是帮助方法,用于向Thread的 tool_resources 添加文件。也可以直接将文件添加到thread.tool_resources

创建图像输入内容 #

消息内容可以包含外部图像URL或通过文件API上传的文件ID。只有支持视觉的模型才能接受图像输入。支持的图像内容类型包括png、jpg、gif 和webp。创建图像文件时,传递 purpose="vision" 以允许你稍后下载和显示输入内容。目前,每个项目有100GB的限制。

工具除非指定,否则无法访问图像内容。要将图像文件传递给代码解释器,请在消息 attachments 列表中添加文件 ID,以允许工具读取和分析输入。目前,代码解释器无法下载图像URL。

 1file = client.files.create(
 2  file=open("myimage.png", "rb"),
 3  purpose="vision"
 4)
 5thread = client.beta.threads.create(
 6  messages=[
 7    {
 8      "role": "user",
 9      "content": [
10        {
11          "type": "text",
12          "text": "What is the difference between these images?"
13        },
14        {
15          "type": "image_url",
16          "image_url": {"url": "https://example.com/image.png"}
17        },
18        {
19          "type": "image_file",
20          "image_file": {"file_id": file.id}
21        },
22      ],
23    }
24  ]
25)

低保真度或高保真度图像理解

通过控制 detail 参数,它有三个选项:lowhighauto,可以控制模型处理图像并生成文本理解的方式。

  • low 将启用"低分辨率"模式。模型将接收一个低分辨率的 512px x 512px 版本的图像,并用85个token来表示图像。这使API能够更快地返回响应,并为不需要高细节的用例消耗较少的输入标记。
  • high 将启用"高分辨率"模式,它首先允许模型查看低分辨率图像,然后根据输入图像的大小创建详细的图像裁剪。使用价格计算器可以查看不同图像大小的token数量。
 1thread = client.beta.threads.create(
 2  messages=[
 3    {
 4      "role": "user",
 5      "content": [
 6        {
 7          "type": "text",
 8          "text": "What is this an image of?"
 9        },
10        {
11          "type": "image_url",
12          "image_url": {
13            "url": "https://example.com/image.png",
14            "detail": "high"
15          }
16        },
17      ],
18    }
19  ]
20)

上下文窗口管理 #

Assistants API会自动管理截断,以确保保持在模型的最大上下文长度内。可以通过指定希望运行使用的最大token数和/或希望在运行中包含的最近消息的最大数量来自定义此行为。

Max Completion and Max Prompt Tokens

要控制单个Run中的token使用量,在创建Run时设置max_prompt_tokensmax_completion_tokens。这些限制适用于Run生命周期内所有completion过程中使用的token总数。

例如,启动一个Run时将max_prompt_tokens设置为500,max_completion_tokens 设置为 1000,意味着第一次completion将Thread截断至500个token,并将输出上限设为1000个token。如果第一次completion仅使用了200个提示token和300个completion token,那么第二次completion将有300个可用的提示token和700个可用的completion标记。

如果completion过程达到max_completion_tokens限制,Run将 incomplete 状态终止,并在Run对象的incomplete_details字段中提供详细信息。

提示

在使用文件搜索工具时,建议将max_prompt_tokens设置为不少于20,000。对于较长的对话或与文件搜索的多次交互,请考虑将此限制提高到50000,或者最理想的是完全取消max_prompt_tokens限制,以获得最高质量的结果。

截断策略

还可以指定截断策略来控制Thread如何渲染到模型的上下文窗口中。使用类型为auto的截断策略将使用OpenAI的默认截断策略。使用类型为last_messages的截断策略将允许指定要包含在上下文窗口中的最新消息的数量。

Message annotations #

Assistants创建的消息可能包含在对象的内容(content)数组中的annotations(即message.content[0].text.annotations。annotations提供有关如何注解消息中的文本的信息。

有两种类型的Annotations:

  1. file_citation:文件引文由file_search工具创建,并定义对Assistant上传并用于生成响应的特定文件的引用。
  2. file_path:文件路径注释由code_interpreter工具创建,并包含对工具生成的文件的引用。

当消息对象中存在annotations时,将在文本中看到不可读的模型生成的子字符串,应该用annotations中的信息替换这些子字符串。这些字符串可能看起来像【13†source】sandbox:/mnt/data/file.csv。下面是一个示例 python 代码片段,它用annotations中的信息替换这些字符串。

 1# Retrieve the message object
 2message = client.beta.threads.messages.retrieve(
 3  thread_id="...",
 4  message_id="..."
 5)
 6# Extract the message content
 7message_content = message.content[0].text
 8annotations = message_content.annotations
 9citations = []
10# Iterate over the annotations and add footnotes
11for index, annotation in enumerate(annotations):
12    # Replace the text with a footnote
13    message_content.value = message_content.value.replace(annotation.text, f' [{index}]')
14    # Gather citations based on annotation attributes
15    if (file_citation := getattr(annotation, 'file_citation', None)):
16        cited_file = client.files.retrieve(file_citation.file_id)
17        citations.append(f'[{index}] {file_citation.quote} from {cited_file.filename}')
18    elif (file_path := getattr(annotation, 'file_path', None)):
19        cited_file = client.files.retrieve(file_path.file_id)
20        citations.append(f'[{index}] Click <here> to download {cited_file.filename}')
21        # Note: File download functionality not implemented above for brevity
22# Add footnotes to the end of the message before displaying to user
23message_content.value += '\n' + '\n'.join(citations)

3.3 Runs and Run Steps #

当从Thread中获得所需的所有上下文后,可以使用选择的Assistant运行该Thread。

1run = client.beta.threads.runs.create(
2  thread_id=thread.id,
3  assistant_id=assistant.id
4)

默认情况下,Run将使用Assistant对象中指定的模型和工具配置,但可以在创建Run时覆盖其中大部分配置,以增加灵活性:

1run = client.beta.threads.runs.create(
2  thread_id=thread.id,
3  assistant_id=assistant.id,
4  model="gpt-4o",
5  instructions="New instructions that override the Assistant instructions",
6  tools=[{"type": "code_interpreter"}, {"type": "file_search"}]
7)
注意: 与Assistant关联的tool_resources不能在Run创建期间被覆盖。必须使用modify Assistant端点来执行此操作。

Run的生命周期 #

Run对象可以有多种状态。

diagram-run-statuses-v2.png

状态描述
queuedRun刚创建或完成required_action后,会被移至queued状态。它们应该几乎立即移至in_progress
in_progressin_progress状态,Assistant使用模型和工具执行步骤。可以通过检查Run Steps来查看Run的进度。
completedRun成功完成!现在可以查看Assistant添加到Thread的所有消息,以及Run采取的所有步骤。还可以通过向Thread添加更多用户消息并创建另一个Run来继续对话。
requires_action使用函数调用工具时,一旦模型确定要调用的函数的名称和参数,运行将移至required_action状态。然后,必须运行这些函数并提交输出,然后Run才能继续。如果没有在expires_at时间戳之前提供输出(大约创建后10分钟),Run将移至过期状态。
expired当函数调用输出在expires_at之前未提交且Run过期时,会发生这种情况。此外,如果运行执行时间过长,超过expires_at中指定的时间,系统将使Run过期。
cancelling可以使用Cancel Run端点尝试取消正在进行的Run。一旦取消尝试成功,Run的状态将变为cancelled。取消是尝试的,但不保证成功。
cancelledRun已成功取消。
failed可以通过查看Run中的last_error对象来查看失败的原因。失败的时间戳将在failed_at下记录。
incomplete运行由于达到max_prompt_tokensmax_completion_tokens而结束。可以通过查看Run中的incomplete_details对象来查看具体原因。

轮询更新 #

如果未使用流式传输,为了保持Run状态的最新,将必须定期检索Run对象。可以每次检索对象时检查Run的状态,以确定应用程序接下来应该做什么。 可以选择使用Node和Python SDK中的轮询助手。这些助手将自动轮询Run对象,并在其处于terminal状态时返回Run对象。

Thread locks #

当一个Run处于进行中且未处于terminal状态时,Thread被锁定。这意味着:

  • 无法向Thread添加新消息。
  • 无法在该Thread上创建新的Run。

Run steps #

diagram-2.png

Run steps的状态与Run状态具有相同的含义。

Run Step对象中的大部分有趣细节都位于step_details字段中。可能有两种类型的步骤详细信息:

  1. message_creation:当Assistant在Thread上创建消息时,将创建此Run Step。
  2. tool_calls:当助手调用工具时,将创建此Run Step。

3.4 数据访问指南 #

目前,通过API创建的Assistants, Threads, Messages和向量存储Vector Stores都属于创建它们的项目范围。因此,任何拥有该项目API 密钥访问权限的人都可以读取或写入项目中的Assistants, Threads, Messages和Runs。

强烈建议采取以下数据访问控制措施:

  • 实施授权。在读取或写入Assistants, Threads, Messages和向量存储之前,请确保终端用户有权这样做。例如,在数据库中存储终端用户有权访问的对象ID,并在使用API获取对象ID之前进行检查。
  • 限制API密钥访问。仔细考虑组织中哪些人应该拥有API密钥并成为项目的一部分。定期审核此列表。API密钥支持广泛的操作,包括读取和修改敏感信息,例如消息和文件。
  • 创建单独的帐户。考虑为不同的应用程序创建单独的项目,以便隔离多个应用程序中的数据。

4.Assistants API tools #

探索文件搜索、代码和函数调用工具。

使用Assistants API创建的助手可以配备工具,使它们能够执行更复杂的任务或与你的应用程序交互。Assistants API为助手提供了内置工具,但也可以使用函数调用定义自己的工具来扩展其功能。 Assistants API当前支持以下工具:

  • 文件搜索: 内置的RAG工具,用于处理和搜索文件。
  • 代码解释器: 编写和运行Python代码,处理文件和各种数据。
  • 函数调用: 使用自己的自定义函数与应用程序交互。

参考 #

© 2025 青蛙小白 | 总访问量 | 总访客数