你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

Azure AI 代理服务文件搜索工具

文件搜索利用其模型外部的知识(如专有产品信息或用户提供的文档)提升代理功能。

注意

使用标准代理设置,改进的文件搜索工具可确保你的文件保留在你自己的存储中,并且你的 Azure AI 搜索资源用于引入这些文件,确保你保持对数据的完全控制。

文件源

  • 上传本地文件
  • Azure Blob 存储

依赖于代理设置

基本代理设置

文件搜索工具的功能与 Azure OpenAI 助手相同。 会使用 Microsoft 托管搜索和存储资源。

  • 上传的文件存储在 Microsoft 托管存储中
  • 会使用 Microsoft 托管搜索资源创建矢量存储

标准代理设置

文件搜索工具使用在代理设置过程中连接的 Azure AI 搜索和 Azure Blob 存储资源。

  • 上传的文件存储在连接的 Azure Blob 存储帐户中
  • 会使用连接的 Azure AI 搜索资源创建矢量存储

对于这两种代理设置,Azure OpenAI 将处理整个引入过程,其中包括:

  • 自动分析文档并将文档分块
  • 生成并存储嵌入
  • 利用矢量和关键字搜索来检索用户查询的相关内容。

两种设置之间没有代码方面的区别;唯一的区别在于你的文件和创建的矢量存储的存储位置。

工作原理

文件搜索工具现身实现多个检索最佳做法,以帮助你从文件中提取正确的数据,并增强模型响应。 文件搜索工具:

  • 重写用户查询以优化其搜索。
  • 将复杂的用户查询分解为可以并行运行的多个搜索。
  • 在代理和线程矢量存储上运行关键字和语义搜索。
  • 在生成最终响应之前,请重新调整搜索结果以选取最相关的搜索结果。
  • 默认情况下,文件搜索工具使用以下设置:
    • 区块大小:800 个令牌
    • 区块重叠:400 个令牌
    • 嵌入模型:text-embedding-3-large,尺寸为 256
    • 添加到上下文的最大区块数:20

矢量存储

矢量存储对象使文件搜索工具能够搜索文件。 将文件添加到矢量存储会自动分析、分块、嵌入文件并将其存储在能够进行关键字和语义搜索的矢量数据库中。 每个矢量存储最多可以容纳 10,000 个文件。 矢量存储可以附加到代理和线程。 目前,最多可以将一个矢量存储附加到一个代理,并且最多可以将一个矢量存储附加到一个线程。

同样,可以通过以下任一方法从矢量存储中删除这些文件:

  • 删除矢量存储文件对象或
  • 删除基础文件对象,这会将文件从组织中所有代理和线程的所有 vector_store 和 code_interpreter 配置中删除

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

在创建运行之前确保矢量存储就绪情况

强烈建议在创建运行之前确保已完全处理 vector_store 中的所有文件。 这可以确保矢量存储中的所有数据都可搜索。 可以使用 SDK 中的轮询帮助程序,或者手动轮询矢量存储对象来确保状态为“已完成”,来检查矢量存储就绪情况。

作为回退,当线程的矢量存储包含仍在处理的文件时,最多在 Run 对象中等待 60 秒。 这是为了确保用户在运行继续之前完全可搜索的线程中上传的任何文件。 此回退等待不适用于代理的矢量存储。

在此示例中,我们使用 Azure AI 代理服务创建一个代理,以帮助回答有关从本地文件上传的信息的问题。

先决条件

  1. 完成代理设置

  2. 确保你在项目的存储帐户上具有“存储 Blob 数据参与者”角色。

  3. 确保你在项目上具有“Azure AI 开发人员”角色。

步骤 1:创建项目客户端

创建一个客户端对象,其中包含用于连接到 AI 项目和其他资源的连接字符串。

import os
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import FileSearchTool, MessageAttachment, FilePurpose
from azure.identity import DefaultAzureCredential


# Create an Azure AI Client from a connection string, copied from your Azure AI Foundry project.
# At the moment, it should be in the format "<HostName>;<AzureSubscriptionId>;<ResourceGroup>;<ProjectName>"
# Customer needs to login to Azure subscription via Azure CLI and set the environment variables

credential = DefaultAzureCredential()
project_client = AIProjectClient.from_connection_string(
    credential=credential, conn_str=os.environ["PROJECT_CONNECTION_STRING"] 
)

步骤 2:上传文件并将其添加到矢量存储

为了访问文件,文件搜索工具会使用矢量存储对象。 上传文件并创建矢量存储。 创建矢量存储后,轮询其状态,直到所有文件都退出 in_progress 状态,以确保所有内容都得到充分处理。 SDK 提供用于上传和轮询的帮助程序。

# We will upload the local file and will use it for vector store creation.

#upload a file
file = project_client.agents.upload_file_and_poll(file_path='./data/product_catelog.md', purpose=FilePurpose.AGENTS)
print(f"Uploaded file, file ID: {file.id}")

# create a vector store with the file you uploaded
vector_store = project_client.agents.create_vector_store_and_poll(file_ids=[file.id], name="my_vectorstore")
print(f"Created vector store, vector store ID: {vector_store.id}")

若要使文件可供代理访问,请创建一个具有 vector_store ID 的 FileSearchTool 对象,并将 toolstool_resources 附加到代理。


# create a file search tool
file_search_tool = FileSearchTool(vector_store_ids=[vector_store.id])

# notices that FileSearchTool as tool and tool_resources must be added or the agent will be unable to search the file
agent = project_client.agents.create_agent(
    model="gpt-4o-mini",
    name="my-agent",
    instructions="You are a helpful agent",
    tools=file_search_tool.definitions,
    tool_resources=file_search_tool.resources,
)
print(f"Created agent, agent ID: {agent.id}")

步骤 4:创建线程

还可以将文件作为邮件附件附加到线程上。 这样做会创建另一个与线程关联的 vector_store,或者如果已有一个附加到此线程的矢量存储,则会将新文件附加到现有的线程矢量存储。 在此线程上创建“运行”时,文件搜索工具将从代理的 vector_store 和线程上的 vector_store 进行查询。

# Create a thread
thread = project_client.agents.create_thread()
print(f"Created thread, thread ID: {thread.id}")

# Upload the user provided file as a messsage attachment
message_file = project_client.agents.upload_file_and_poll(file_path='product_info_1.md', purpose=FilePurpose.AGENTS)
print(f"Uploaded file, file ID: {message_file.id}")

# Create a message with the file search attachment
# Notice that vector store is created temporarily when using attachments with a default expiration policy of seven days.
attachment = MessageAttachment(file_id=message_file.id, tools=FileSearchTool().definitions)
message = project_client.agents.create_message(
    thread_id=thread.id, role="user", content="What feature does Smart Eyewear offer?", attachments=[attachment]
)
print(f"Created message, message ID: {message.id}")

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

创建运行并观察模型是否使用文件搜索工具来响应用户的问题。

run = project_client.agents.create_and_process_run(thread_id=thread.id, assistant_id=agent.id)
print(f"Created run, run ID: {run.id}")

project_client.agents.delete_vector_store(vector_store.id)
print("Deleted vector store")

project_client.agents.delete_agent(agent.id)
print("Deleted agent")

messages = project_client.agents.list_messages(thread_id=thread.id)
print(f"Messages: {messages}")

在此示例中,我们使用 Azure AI 代理服务创建一个代理,以帮助回答有关来自 Azure Blob 存储中文件的信息的问题。

先决条件

  1. 完成标准代理设置

  2. 确保你在项目的存储帐户上具有“存储 Blob 数据参与者”角色。

  3. 确保你在项目上具有“Azure AI 开发人员”角色。

重要

使用 Blob 存储进行文件搜索仅受标准代理设置支持。

步骤 1:创建项目客户端

import os
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import FileSearchTool, VectorStoreDataSource, VectorStoreDataSourceAssetType
from azure.identity import DefaultAzureCredential


# Create an Azure AI Client from a connection string, copied from your Azure AI Foundry project.
# At the moment, it should be in the format "<HostName>;<AzureSubscriptionId>;<ResourceGroup>;<ProjectName>"
# Customer needs to login to Azure subscription via Azure CLI and set the environment variables

credential = DefaultAzureCredential()
project_client = AIProjectClient.from_connection_string(
    credential=credential, conn_str=os.environ["PROJECT_CONNECTION_STRING"]
)

步骤 2:将本地文件上传到项目 Azure Blob 存储容器

将本地文件上传到项目的 Azure Blob 存储容器。 这是在设置过程中连接到代理的同一存储帐户。 在同一项目中创建其他代理时,可以重复使用这些代理需要的任何以前上传的文件的资产 URI。 这意味着无需重复上传同一文件,因为资产 URI 允许直接引用文件。

然后,使用 asset_uri(这是项目数据存储中你的文件的位置)创建矢量存储。

# We'll upload the local file to your project Azure Blob Storage container and will use it for vector store creation.
_, asset_uri = project_client.upload_file("sample_file_for_upload.md")
print(f"Uploaded file, asset URI: {asset_uri}")

# create a vector store with a file in blob storage and wait for it to be processed
ds = VectorStoreDataSource(asset_identifier=asset_uri, asset_type=VectorStoreDataSourceAssetType.URI_ASSET)
vector_store = project_client.agents.create_vector_store_and_poll(data_sources=[ds], name="sample_vector_store")
print(f"Created vector store, vector store ID: {vector_store.id}")

步骤 3:创建有权访问文件搜索工具的代理

# create a file search tool
file_search_tool = FileSearchTool(vector_store_ids=[vector_store.id])

# notices that FileSearchTool as tool and tool_resources must be added or the assistant unable to search the file
agent_1 = project_client.agents.create_agent(
    model="gpt-4o-mini",
    name="my-assistant",
    instructions="You are helpful assistant",
    tools=file_search_tool.definitions,
    tool_resources=file_search_tool.resources,
)
# [END upload_file_and_create_agent_with_file_search]
print(f"Created agent_1, agent_1 ID: {agent_1.id}")

thread = project_client.agents.create_thread()
print(f"Created thread, thread ID: {thread.id}")

message = project_client.agents.create_message(
    thread_id=thread.id, role="user", content="What feature does Smart Eyewear offer?"
)
print(f"Created message, message ID: {message.id}")

run = project_client.agents.create_and_process_run(thread_id=thread.id, assistant_id=agent_1.id)

project_client.agents.delete_vector_store(vector_store.id)
print("Deleted vector store")

project_client.agents.delete_agent(agent.id)
print("Deleted agent")

messages = project_client.agents.list_messages(thread_id=thread.id)
print(f"Messages: {messages}")

步骤 4:使用以前上传的文件创建第二个矢量存储

现在,使用以前上传的文件创建第二个矢量存储。 如果有多个代理需要访问相同的文件,则使用 Azure Blob 存储中已有文件的 asset_uri 非常有用,因为这样就无需多次上传相同的文件。


# create a vector store with a previously uploaded file and wait for it to be processed
ds_2 = VectorStoreDataSource(asset_identifier=asset_uri, asset_type=VectorStoreDataSourceAssetType.URI_ASSET)
vector_store_2 = project_client.agents.create_vector_store_and_poll(data_sources=[ds_2], name="sample_vector_store_2")
print(f"Created vector store, vector store ID: {vector_store.id}")

步骤 5:创建第二个有权访问文件搜索工具的代理

file_search_tool_2 = FileSearchTool(vector_store_ids=[vector_store_2.id])
# notices that FileSearchTool as tool and tool_resources must be added or the assistant unable to search the file
agent_2 = project_client.agents.create_agent(
    model="gpt-4o-mini",
    name="my-assistant-2",
    instructions="You are helpful assistant",
    tools=file_search_tool_2.definitions,
    tool_resources=file_search_tool_2.resources,
)
# [END upload_file_and_create_agent_with_file_search]
print(f"Created agent, agent ID: {agent_2.id}")

支持的文件类型

注意

对于文本/MIME 类型,编码必须是 utf-8、utf-16 或 ASCII。

文件格式 MIME 类型
.c text/x-c
.cs text/x-csharp
.cpp text/x-c++
.doc application/msword
.docx application/vnd.openxmlformats-officedocument.wordprocessingml.document
.html text/html
.java text/x-java
.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
.tex text/x-tex
.txt text/plain
.css text/css
.js text/javascript
.sh application/x-sh
.ts application/typescript

创建矢量存储并添加文件

将文件添加到矢量存储是一项异步操作。 为了确保操作完成,我们建议在官方 SDK 中使用“创建和轮询”帮助程序。 如果不使用 SDK,则可以检索 vector_store 对象并监视其 file_counts 属性以查看文件引入操作的结果。

创建矢量存储文件后,还可以将文件添加到矢量存储中。


# create a vector store with no file and wait for it to be processed
vector_store = project_client.agents.create_vector_store_and_poll(data_sources=[], name="sample_vector_store")
print(f"Created vector store, vector store ID: {vector_store.id}")

# add the file to the vector store or you can supply file ids in the vector store creation
vector_store_file_batch = project_client.agents.create_vector_store_file_batch_and_poll(
    vector_store_id=vector_store.id, file_ids=[file.id]
)
print(f"Created vector store file batch, vector store file batch ID: {vector_store_file_batch.id}")

或者,可以通过创建最多 500 个文件的批处理,将多个文件添加到矢量存储中。

batch = project_client.agents.create_vector_store_file_batch_and_poll(
  vector_store_id=vector_store.id,
  file_ids=[file_1.id, file_2.id, file_3.id, file_4.id, file_5.id]
)

基本代理设置:从矢量存储中删除文件

可以通过以下任一方法从矢量存储中删除文件:

  • 删除矢量存储文件对象或
  • 删除基础文件对象,这会将文件从组织中所有代理和线程的所有 vector_store 和 code_interpreter 配置中删除

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

删除矢量存储

可以从文件搜索工具中删除矢量存储。

file_search_tool.remove_vector_store(vector_store.id)
print(f"Removed vector store from file search, vector store ID: {vector_store.id}")

project_client.agents.update_agent(
    assistant_id=agent.id, tools=file_search_tool.definitions, tool_resources=file_search_tool.resources
)
print(f"Updated agent, agent ID: {agent.id}")

删除矢量存储

project_client.agents.delete_vector_store(vector_store.id)
print("Deleted vector store")

使用过期策略管理成本

对于基本代理设置,file_search 工具使用 vector_stores 对象作为其资源,系统将根据创建的 vector_store 对象的大小计费。 矢量存储对象的大小是文件及其相应嵌入的所有已分析区块的总和。

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

vector_store = project_client.agents.create_vector_store_and_poll(
  name="Product Documentation",
  file_ids=[file_1.id],
  expires_after={
      "anchor": "last_active_at",
      "days": 7
  }
)

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

使用线程帮助程序(如 tool_resources.file_search.vector_stores 线程或 message.attachments 消息中创建的矢量存储)的默认过期策略在上次处于活动状态后七天(定义为最后一次矢量存储是运行的一部分)。

当矢量存储过期时,该线程上的运行将失败。 若要解决此问题,可以使用相同的文件重新创建一个新的 vector_store,并将其重新附加到线程。