助手文件搜索
试用版

文件搜索使用来自其模型外部的知识(例如专有产品信息或用户提供的文档)来扩充 Assistant。OpenAI 会自动解析和分块您的文档,创建和存储嵌入,并使用矢量和关键字搜索来检索相关内容以回答用户查询。source

快速入门

在此示例中,我们将创建一个助手,帮助回答有关公司财务报表的问题。source

第 1 步:创建启用了文件搜索的新助手

使用file_searchenabled 在tools参数。source

1
2
3
4
5
6
7
8
9
10
from openai import OpenAI
 
client = OpenAI()
 
assistant = client.beta.assistants.create(
  name="Financial Analyst Assistant",
  instructions="You are an expert financial analyst. Use you knowledge base to answer questions about audited financial statements.",
  model="gpt-4o",
  tools=[{"type": "file_search"}],
)

一旦file_search工具,则模型会根据用户消息决定何时检索内容。source

第 2 步:上传文件并将其添加到 Vector Store

要访问您的文件,file_search工具使用 Vector Store 对象。 上传您的文件并创建一个 Vector Store 来包含它们。 创建 Vector Store 后,您应该轮询其状态,直到所有文件都超出in_progressstate 设置为 确保所有内容都已完成处理。SDK 提供了一次性上传和轮询的帮助程序。source

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Create a vector store caled "Financial Statements"
vector_store = client.beta.vector_stores.create(name="Financial Statements")
 
# Ready the files for upload to OpenAI
file_paths = ["edgar/goog-10k.pdf", "edgar/brka-10k.txt"]
file_streams = [open(path, "rb") for path in file_paths]
 
# Use the upload and poll SDK helper to upload the files, add them to the vector store,
# and poll the status of the file batch for completion.
file_batch = client.beta.vector_stores.file_batches.upload_and_poll(
  vector_store_id=vector_store.id, files=file_streams
)
 
# You can print the status and the file counts of the batch to see the result of this operation.
print(file_batch.status)
print(file_batch.file_counts)

第 3 步:更新助手以使用新的 Vector Store

要使 Assistant 可以访问这些文件,请更新 Assistant 的tool_resources使用新的vector_store同上。source

1
2
3
4
assistant = client.beta.assistants.update(
  assistant_id=assistant.id,
  tool_resources={"file_search": {"vector_store_ids": [vector_store.id]}},
)

步骤 4:创建线程

您还可以在线程上将文件作为消息附件附加。这样做将创建另一个vector_store与线程关联,或者,如果已将向量存储附加到此线程,则将新文件附加到现有线程向量存储。当您在此线程上创建 Run 时,文件搜索工具将查询vector_store从您的助手和vector_store在线程上。source

在此示例中,用户附加了 Apple 最新 10-K 文件的副本。source

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Upload the user provided file to OpenAI
message_file = client.files.create(
  file=open("edgar/aapl-10k.pdf", "rb"), purpose="assistants"
)
 
# Create a thread and attach the file to the message
thread = client.beta.threads.create(
  messages=[
    {
      "role": "user",
      "content": "How many shares of AAPL were outstanding at the end of of October 2023?",
      # Attach the new file to the message.
      "attachments": [
        { "file_id": message_file.id, "tools": [{"type": "file_search"}] }
      ],
    }
  ]
)
 
# The thread now has a vector store with that file in its tool resources.
print(thread.tool_resources.file_search)

使用消息附件创建的矢量存储的默认过期策略为上次活动后 7 天(定义为矢量存储上次运行的一部分)。此默认值的存在是为了帮助您管理矢量存储成本。您可以随时覆盖这些过期策略。在此处了解更多信息。source

步骤 5:创建运行并检查输出

现在,创建一个 Run 并观察模型是否使用 File Search (文件搜索) 工具来回答用户的问题。source

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
from typing_extensions import override
from openai import AssistantEventHandler, OpenAI
 
client = OpenAI()
 
class EventHandler(AssistantEventHandler):
    @override
    def on_text_created(self, text) -> None:
        print(f"\nassistant > ", end="", flush=True)

    @override
    def on_tool_call_created(self, tool_call):
        print(f"\nassistant > {tool_call.type}\n", flush=True)

    @override
    def on_message_done(self, message) -> None:
        # print a citation to the file searched
        message_content = message.content[0].text
        annotations = message_content.annotations
        citations = []
        for index, annotation in enumerate(annotations):
            message_content.value = message_content.value.replace(
                annotation.text, f"[{index}]"
            )
            if file_citation := getattr(annotation, "file_citation", None):
                cited_file = client.files.retrieve(file_citation.file_id)
                citations.append(f"[{index}] {cited_file.filename}")

        print(message_content.value)
        print("\n".join(citations))


# Then, we use the stream SDK helper
# with the EventHandler class to create the Run
# and stream the response.

with client.beta.threads.runs.stream(
    thread_id=thread.id,
    assistant_id=assistant.id,
    instructions="Please address the user as Jane Doe. The user has a premium account.",
    event_handler=EventHandler(),
) as stream:
    stream.until_done()

您的新助手将查询两个附加的向量存储(一个包含goog-10k.pdfbrka-10k.txt,另一个包含aapl-10k.pdf) 并从aapl-10k.pdf.source

要检索模型使用的文件搜索结果的内容,请使用includequery 参数并提供值step_details.tool_calls[*].file_search.results[*].content在格式?include[]=step_details.tool_calls[*].file_search.results[*].content.source


运作方式

file_search工具实施了几个开箱即用的检索最佳实践,以帮助您从文件中提取正确的数据并增强模型的响应。这file_search工具:source

  • 重写用户查询以优化它们以进行搜索。
  • 将复杂的用户查询分解为可以并行运行的多个搜索。
  • 跨 Assistant 和 Thread Vector 存储运行关键字和语义搜索。
  • 在生成最终响应之前,对搜索结果进行重新排序以选择最相关的结果。

默认情况下,file_search工具使用以下设置,但可以根据需要配置这些设置:source

  • 区块大小:800 个代币
  • 区块重叠:400 个代币
  • 嵌入模型:text-embedding-3-large在 256 个维度
  • 添加到上下文的最大块数:20(可能会更少)
  • 排名器:auto(OpenAI 将选择使用哪个排名器)
  • 分数阈值:最低排名分数 0

已知限制source

我们有一些已知的限制,正在努力在未来几个月内添加支持:source

  1. 支持使用自定义元数据进行确定性搜索前筛选。
  2. 支持解析文档中的图像(包括图表、图形、表格等的图像)
  3. 支持对结构化文件格式(如csvjsonl).
  4. 更好地支持摘要 — 该工具目前针对搜索查询进行了优化。

矢量存储

Vector Store 对象使 File Search 工具能够搜索您的文件。将文件添加到vector_store自动解析、分块、嵌入和存储文件在能够进行关键字和语义搜索的矢量数据库中。每vector_store最多可容纳 10,000 个文件。向量存储可以附加到 Assistant 和 Threads。现在,您最多可以将一个向量存储附加到助手,最多可以将一个向量存储附加到线程。source

创建矢量存储和添加文件

您可以在单个 API 调用中创建矢量存储并向其添加文件:source

1
2
3
4
vector_store = client.beta.vector_stores.create(
  name="Product Documentation",
  file_ids=['file_1', 'file_2', 'file_3', 'file_4', 'file_5']
)

将文件添加到向量存储是一个异步作。为确保作完成,我们建议您使用我们官方 SDK 中的“create and poll”帮助程序。如果您未使用 SDK,则可以检索vector_store对象并监控它的file_counts属性以查看文件摄取作的结果。source

文件也可以在创建矢量存储后通过创建矢量存储文件添加到矢量存储中。source

1
2
3
4
file = client.beta.vector_stores.files.create_and_poll(
  vector_store_id="vs_abc123",
  file_id="file-abc123"
)

或者,您可以通过创建最多 500 个文件的批次来将多个文件添加到向量存储中。source

1
2
3
4
batch = client.beta.vector_stores.file_batches.create_and_poll(
  vector_store_id="vs_abc123",
  file_ids=['file_1', 'file_2', 'file_3', 'file_4', 'file_5']
)

同样,可以通过以下方式从向量存储中删除这些文件:source

最大文件大小为 512 MB。每个文件包含的令牌不应超过 5,000,000 个(在附加文件时自动计算)。source

文件搜索支持多种文件格式,包括.pdf,.md.docx.有关支持的文件扩展名(及其相应的 MIME 类型)的更多详细信息,请参阅下面的 Supported files 部分。source

附加向量存储

您可以使用tool_resources参数。source

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
assistant = client.beta.assistants.create(
  instructions="You are a helpful product support assistant and you answer questions based on the files provided to you.",
  model="gpt-4o",
  tools=[{"type": "file_search"}],
  tool_resources={
    "file_search": {
      "vector_store_ids": ["vs_1"]
    }
  }
)

thread = client.beta.threads.create(
  messages=[ { "role": "user", "content": "How do I cancel my subscription?"} ],
  tool_resources={
    "file_search": {
      "vector_store_ids": ["vs_2"]
    }
  }
)

您还可以在创建 Threads 或 Assistant 后将向量存储附加到它们,方法是使用 right 更新tool_resources.source

在创建运行之前确保 vector store 准备就绪

我们强烈建议您确保vector_store在创建运行之前完全处理。这将确保您的vector_store是可搜索的。您可以检查vector_store就绪性,或者通过手动轮询vector_storeobject 来确保statuscompleted.source

作为后备,当线程的向量存储包含仍在处理的文件时,我们在 Run 对象中构建了最长 60 秒的等待时间。这是为了确保在运行继续之前,用户在线程中上传的任何文件都是完全可搜索的。此回退等待不适用于助手的 vector store。source

自定义文件搜索设置

您可以自定义file_search工具对数据进行分块,以及它返回到模型上下文的块数。source

分块配置source

默认情况下,max_chunk_size_tokens设置为800chunk_overlap_tokens设置为400,这意味着每个文件都通过拆分为 800 个令牌的块来编制索引,连续的块之间有 400 个令牌的重叠。source

您可以通过设置chunking_strategy将文件添加到 Vector Store 时。存在一定的限制chunking_strategy:source

  • max_chunk_size_tokens必须介于 100 和 4096 之间(包括 100 和 4096)。
  • chunk_overlap_tokens必须为非负值且不应超过max_chunk_size_tokens / 2.

块数source

默认情况下,file_search工具最多可输出 20 个数据块,用于gpt-4*models 和最多 5 个数据块gpt-3.5-turbo.您可以通过设置file_search.max_num_results在工具中创建 Assistant 或 Run.source

请注意,file_search工具输出的量可能会少于此数字,原因有很多:source

  • 块总数小于max_num_results.
  • 所有检索到的 chunk 的总 token 大小超过分配给file_search工具。这file_search工具当前具有以下令牌 bugdet:
    • 4,000 个代币gpt-3.5-turbo
    • 16,000 个代币gpt-4*模型

通过块排名提高文件搜索结果的相关性

默认情况下,文件搜索工具会将所有搜索结果返回给它认为在生成响应时具有任何相关级别的模型。但是,如果响应是使用相关性较低的内容生成的,则可能会导致响应质量较低。您可以通过检查生成响应时返回的文件搜索结果,然后优化文件搜索工具的排名程序的行为来调整此行为,以更改结果在用于生成响应之前必须的相关程度。source

检查文件搜索块source

提高文件搜索结果质量的第一步是检查 Assistant 的当前行为。大多数情况下,这将涉及调查您的助理表现不佳的回复。您可以使用 REST API 获取有关过去运行步骤的精细信息,特别是使用includequery 参数获取用于生成结果的文件块。source

创建运行时在响应中包含文件搜索结果
1
2
3
4
5
6
7
8
9
10
11
from openai import OpenAI
client = OpenAI()

run_step = client.beta.threads.runs.steps.retrieve(
    thread_id="thread_abc123",
    run_id="run_abc123",
    step_id="step_abc123",
    include=["step_details.tool_calls[*].file_search.results[*].content"]
)

print(run_step)

然后,您可以记录和检查在运行步骤中使用的搜索结果,并确定它们是否始终与您的助手应生成的响应相关。source

配置排名选项source

如果您已确定文件搜索结果的相关性不足以生成高质量的响应,则可以调整结果排名程序的设置,以选择应使用哪些搜索结果来生成响应。您可以调整此设置file_search.ranking_options工具中创建 Assistant创建运行时。source

您可以配置的设置包括:source

  • ranker- 在确定要使用的 chunk 时使用哪个排名器。可用值为auto,它使用最新的可用排名程序,以及default_2024_08_21.
  • score_threshold- 排名介于 0.0 和 1.0 之间,其中 1.0 是最高排名。较大的数字会将用于生成结果的文件块限制为仅具有更高相关性的块,但代价是可能会遗漏相关块。

使用过期策略管理成本

file_search工具使用vector_stores对象作为其资源,您将根据vector_store对象已创建。vector store 对象的大小是文件中所有已解析的块及其相应嵌入的总和。source

您的前 GB 是免费的,超出此范围后,矢量存储的使用费为 0.10 USD/GB/天。没有与载体存储作相关的其他成本。source

为了帮助您管理与这些相关的成本vector_store对象中,我们在vector_store对象。您可以在创建或更新vector_store对象。source

1
2
3
4
5
6
7
8
vector_store = client.beta.vector_stores.create_and_poll(
  name="Product Documentation",
  file_ids=['file_1', 'file_2', 'file_3', 'file_4', 'file_5'],
  expires_after={
	  "anchor": "last_active_at",
	  "days": 7
  }
)

线程向量存储具有默认过期策略source

使用线程帮助程序(如tool_resources.file_search.vector_storesMessages) 的默认过期策略为上次活动后 7 天(定义为向量存储最后一次运行的一部分)。source

当 vector store 过期时,该线程上的运行将失败。要解决此问题,您只需重新创建一个新的vector_store替换为相同的文件,然后将其重新附加到线程。source

1
2
3
4
5
6
7
8
9
10
11
12
all_files = list(client.beta.vector_stores.files.list("vs_expired"))

vector_store = client.beta.vector_stores.create(name="rag-store")
client.beta.threads.update(
    "thread_abc123",
    tool_resources={"file_search": {"vector_store_ids": [vector_store.id]}},
)

for file_batch in chunked(all_files, 100):
    client.beta.vector_stores.file_batches.create_and_poll(
        vector_store_id=vector_store.id, file_ids=[file.id for file in file_batch]
    )

支持的文件

text/MIME 类型,则编码必须是以下utf-8,utf-16ascii.source

文件格式MIME 类型
.ctext/x-c
.cpptext/x-c++
.cstext/x-csharp
.csstext/css
.docapplication/msword
.docxapplication/vnd.openxmlformats-officedocument.wordprocessingml.document
.gotext/x-golang
.htmltext/html
.javatext/x-java
.jstext/javascript
.jsonapplication/json
.mdtext/markdown
.pdfapplication/pdf
.phptext/x-php
.pptxapplication/vnd.openxmlformats-officedocument.presentationml.presentation
.pytext/x-python
.pytext/x-script.python
.rbtext/x-ruby
.shapplication/x-sh
.textext/x-tex
.tsapplication/typescript
.txttext/plain