助手文件搜索试用版
文件搜索使用来自其模型外部的知识(例如专有产品信息或用户提供的文档)来扩充 Assistant。OpenAI 会自动解析和分块您的文档,创建和存储嵌入,并使用矢量和关键字搜索来检索相关内容以回答用户查询。
快速入门
在此示例中,我们将创建一个助手,帮助回答有关公司财务报表的问题。
第 1 步:创建启用了文件搜索的新助手
使用file_search
enabled 在tools
参数。
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
要访问您的文件,file_search
工具使用 Vector Store 对象。
上传您的文件并创建一个 Vector Store 来包含它们。
创建 Vector Store 后,您应该轮询其状态,直到所有文件都超出in_progress
state 设置为
确保所有内容都已完成处理。SDK 提供了一次性上传和轮询的帮助程序。
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
同上。
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
在线程上。
在此示例中,用户附加了 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.pdf
和brka-10k.txt
,另一个包含aapl-10k.pdf
) 并从aapl-10k.pdf
.
要检索模型使用的文件搜索结果的内容,请使用include
query 参数并提供值step_details.tool_calls[*].file_search.results[*].content
在格式?include[]=step_details.tool_calls[*].file_search.results[*].content
.
运作方式
这file_search
工具实施了几个开箱即用的检索最佳实践,以帮助您从文件中提取正确的数据并增强模型的响应。这file_search
工具:
- 重写用户查询以优化它们以进行搜索。
- 将复杂的用户查询分解为可以并行运行的多个搜索。
- 跨 Assistant 和 Thread Vector 存储运行关键字和语义搜索。
- 在生成最终响应之前,对搜索结果进行重新排序以选择最相关的结果。
默认情况下,file_search
工具使用以下设置,但可以根据需要配置这些设置:
- 区块大小:800 个代币
- 区块重叠:400 个代币
- 嵌入模型:
text-embedding-3-large
在 256 个维度 - 添加到上下文的最大块数:20(可能会更少)
- 排名器:
auto
(OpenAI 将选择使用哪个排名器) - 分数阈值:最低排名分数 0
已知限制
我们有一些已知的限制,正在努力在未来几个月内添加支持:
- 支持使用自定义元数据进行确定性搜索前筛选。
- 支持解析文档中的图像(包括图表、图形、表格等的图像)
- 支持对结构化文件格式(如
csv
或jsonl
). - 更好地支持摘要 — 该工具目前针对搜索查询进行了优化。
矢量存储
Vector Store 对象使 File Search 工具能够搜索您的文件。将文件添加到vector_store
自动解析、分块、嵌入和存储文件在能够进行关键字和语义搜索的矢量数据库中。每vector_store
最多可容纳 10,000 个文件。向量存储可以附加到 Assistant 和 Threads。现在,您最多可以将一个向量存储附加到助手,最多可以将一个向量存储附加到线程。
创建矢量存储和添加文件
您可以在单个 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,则可以检索vector_store
对象并监控它的file_counts
属性以查看文件摄取作的结果。
文件也可以在创建矢量存储后通过创建矢量存储文件添加到矢量存储中。
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 文件对象,或者
- 通过删除底层文件对象(这会从所有
vector_store
和code_interpreter
跨组织中所有助手和线程的配置)
最大文件大小为 512 MB。每个文件包含的令牌不应超过 5,000,000 个(在附加文件时自动计算)。
文件搜索支持多种文件格式,包括.pdf
,.md
和.docx
.有关支持的文件扩展名(及其相应的 MIME 类型)的更多详细信息,请参阅下面的 Supported files 部分。
附加向量存储
您可以使用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"]
}
}
)
您还可以在创建 Threads 或 Assistant 后将向量存储附加到它们,方法是使用 right 更新tool_resources
.
在创建运行之前确保 vector store 准备就绪
我们强烈建议您确保vector_store
在创建运行之前完全处理。这将确保您的vector_store
是可搜索的。您可以检查vector_store
就绪性,或者通过手动轮询vector_store
object 来确保status
是completed
.
作为后备,当线程的向量存储包含仍在处理的文件时,我们在 Run 对象中构建了最长 60 秒的等待时间。这是为了确保在运行继续之前,用户在线程中上传的任何文件都是完全可搜索的。此回退等待不适用于助手的 vector store。
自定义文件搜索设置
您可以自定义file_search
工具对数据进行分块,以及它返回到模型上下文的块数。
分块配置
默认情况下,max_chunk_size_tokens
设置为800
和chunk_overlap_tokens
设置为400
,这意味着每个文件都通过拆分为 800 个令牌的块来编制索引,连续的块之间有 400 个令牌的重叠。
您可以通过设置chunking_strategy
将文件添加到 Vector Store 时。存在一定的限制chunking_strategy
:
max_chunk_size_tokens
必须介于 100 和 4096 之间(包括 100 和 4096)。chunk_overlap_tokens
必须为非负值且不应超过max_chunk_size_tokens / 2
.
块数
默认情况下,file_search
工具最多可输出 20 个数据块,用于gpt-4*
models 和最多 5 个数据块gpt-3.5-turbo
.您可以通过设置file_search.max_num_results
在工具中创建 Assistant 或 Run.
请注意,file_search
工具输出的量可能会少于此数字,原因有很多:
- 块总数小于
max_num_results
. - 所有检索到的 chunk 的总 token 大小超过分配给
file_search
工具。这file_search
工具当前具有以下令牌 bugdet:- 4,000 个代币
gpt-3.5-turbo
- 16,000 个代币
gpt-4*
模型
- 4,000 个代币
通过块排名提高文件搜索结果的相关性
默认情况下,文件搜索工具会将所有搜索结果返回给它认为在生成响应时具有任何相关级别的模型。但是,如果响应是使用相关性较低的内容生成的,则可能会导致响应质量较低。您可以通过检查生成响应时返回的文件搜索结果,然后优化文件搜索工具的排名程序的行为来调整此行为,以更改结果在用于生成响应之前必须的相关程度。
检查文件搜索块
提高文件搜索结果质量的第一步是检查 Assistant 的当前行为。大多数情况下,这将涉及调查您的助理表现不佳的回复。您可以使用 REST API 获取有关过去运行步骤的精细信息,特别是使用include
query 参数获取用于生成结果的文件块。
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
在工具中创建 Assistant 或创建运行时。
您可以配置的设置包括:
ranker
- 在确定要使用的 chunk 时使用哪个排名器。可用值为auto
,它使用最新的可用排名程序,以及default_2024_08_21
.score_threshold
- 排名介于 0.0 和 1.0 之间,其中 1.0 是最高排名。较大的数字会将用于生成结果的文件块限制为仅具有更高相关性的块,但代价是可能会遗漏相关块。
使用过期策略管理成本
这file_search
工具使用vector_stores
对象作为其资源,您将根据vector_store
对象已创建。vector store 对象的大小是文件中所有已解析的块及其相应嵌入的总和。
您的前 GB 是免费的,超出此范围后,矢量存储的使用费为 0.10 USD/GB/天。没有与载体存储作相关的其他成本。
为了帮助您管理与这些相关的成本vector_store
对象中,我们在vector_store
对象。您可以在创建或更新vector_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) 的默认过期策略为上次活动后 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]
)
支持的文件
为text/
MIME 类型,则编码必须是以下utf-8
,utf-16
或ascii
.
文件格式 | MIME 类型 |
---|---|
.c | text/x-c |
.cpp | text/x-c++ |
.cs | text/x-csharp |
.css | text/css |
.doc | application/msword |
.docx | application/vnd.openxmlformats-officedocument.wordprocessingml.document |
.go | text/x-golang |
.html | text/html |
.java | text/x-java |
.js | text/javascript |
.json | application/json |
.md | text/markdown |
.pdf | application/pdf |
.php | text/x-php |
.pptx | application/vnd.openxmlformats-officedocument.presentationml.presentation |
.py | text/x-python |
.py | text/x-script.python |
.rb | text/x-ruby |
.sh | application/x-sh |
.tex | text/x-tex |
.ts | application/typescript |
.txt | text/plain |