助手文件搜索
试用版

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

快速入门

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

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

在 Assistant 的参数中创建一个启用了 enabled 的新助手。file_searchtools

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

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

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

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

要使您的助手可以访问这些文件,请使用新 ID 更新助手的 ID。tool_resourcesvector_store

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_storevector_storevector_store

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

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 天(定义为矢量存储上次运行的一部分)。此默认值的存在是为了帮助您管理矢量存储成本。您可以随时覆盖这些过期策略。在此处了解更多信息。

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

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

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.txtaapl-10k.pdfaapl-10k.pdf

要检索模型使用的文件搜索结果的内容,请使用 query 参数并以 format 提供值 。includestep_details.tool_calls[*].file_search.results[*].content?include[]=step_details.tool_calls[*].file_search.results[*].content


运作方式

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

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

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

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

已知限制

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

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

矢量存储

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

创建矢量存储和添加文件

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

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,则可以检索对象并监控其 file_counts 属性,以查看文件摄取操作的结果。vector_store

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

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

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

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']
)

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

  • 删除 vector store 文件对象,或者
  • 通过删除基础文件对象 (从组织中所有助手和线程的所有 和 configurations 中删除文件)vector_storecode_interpreter

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

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

附加向量存储

您可以使用该参数将矢量存储附加到 Assistant 或 Thread。tool_resources

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"]
    }
  }
)

您还可以在创建线程或助手后将矢量存储附加到线程或助手,方法是使用 right .tool_resources

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

我们强烈建议您在创建运行之前确保 中的所有文件都已完全处理。这将确保 your 中的所有数据都是可搜索的。您可以使用我们 SDK 中的轮询帮助程序检查就绪情况,也可以通过手动轮询对象来确保状态为 .vector_storevector_storevector_storevector_storecompleted

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

自定义文件搜索设置

您可以自定义该工具对数据进行分块的方式以及返回给模型上下文的块数。file_search

分块配置

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

您可以通过在将文件添加到向量存储时设置 chunking_strategy 来调整此设置。存在一定的限制:chunking_strategy

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

块数

默认情况下,该工具最多为 models 输出 20 个数据块,为 .您可以通过在创建辅助尺或梯段时在工具中设置 file_search.max_num_results 来调整此设置。file_searchgpt-4*gpt-3.5-turbo

请注意,由于多种原因,该工具输出的输出可能会少于此数字:file_search

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

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

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

检查文件搜索块

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

创建运行时在响应中包含文件搜索结果
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)

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

配置排名选项

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

您可以配置的设置包括:

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

使用过期策略管理成本

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

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

为了帮助您管理与这些对象相关的成本,我们在对象中添加了对过期策略的支持。您可以在创建或更新对象时设置这些策略。vector_storevector_storevector_store

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
  }
)

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

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

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

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]
    )

支持的文件

对于文本/MIME 类型,编码必须是 utf-8utf-16ascii 之一。

文件格式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