Microsoft Agent Framework 支援透過上下文提供者進行檢索增強生成(RAG),這些服務會在模型調用前加入檢索內容,以及讓模型能隨時檢索基礎資料的搜尋工具。
關於對話/會話模式與擷取,請參見 對話與記憶總覽。 關於服務專屬設定,請參見 Azure AI 搜尋服務、Microsoft Foundry 和 Neo4j。
使用 TextSearchProvider
類別 TextSearchProvider 是 RAG 內容提供者的現成實作。
它支援不同的操作模式,例如對每次客服執行進行聊天記錄的搜尋,或是用於搜尋廣告的工具。
它可以輕鬆地附加 ChatClientAgent 到選項 AIContextProviders 上。
// Configure the options for the TextSearchProvider.
TextSearchProviderOptions textSearchOptions = new()
{
SearchTime = TextSearchProviderOptions.TextSearchBehavior.BeforeAIInvoke,
};
// Create the AI agent with the TextSearchProvider.
AIAgent agent = azureOpenAIClient
.GetChatClient(deploymentName)
.AsAIAgent(new ChatClientAgentOptions
{
ChatOptions = new() { Instructions = "You are a helpful support specialist. Answer questions using the provided context and cite the source document when available." },
AIContextProviders = [new TextSearchProvider(SearchAdapter, textSearchOptions)]
});
需要 TextSearchProvider 一個函數,該函數提供給定查詢的搜索結果。 這可以透過任何搜尋技術實作,例如 Azure AI 搜尋服務 或網頁搜尋引擎。
Tip
欲了解更多如何使用向量儲存器搜尋結果的資訊,請參閱 向量儲存整合 。
以下是模擬搜尋函數的範例,該函數根據查詢傳回預先定義的結果。
SourceName 和 SourceLink 是可選的,但如果提供,則代理在回答用戶問題時將使用該信息的來源來引用信息的來源。
static Task<IEnumerable<TextSearchProvider.TextSearchResult>> SearchAdapter(string query, CancellationToken cancellationToken)
{
// The mock search inspects the user's question and returns pre-defined snippets
// that resemble documents stored in an external knowledge source.
List<TextSearchProvider.TextSearchResult> results = new();
if (query.Contains("return", StringComparison.OrdinalIgnoreCase) || query.Contains("refund", StringComparison.OrdinalIgnoreCase))
{
results.Add(new()
{
SourceName = "Contoso Outdoors Return Policy",
SourceLink = "https://contoso.com/policies/returns",
Text = "Customers may return any item within 30 days of delivery. Items should be unused and include original packaging. Refunds are issued to the original payment method within 5 business days of inspection."
});
}
return Task.FromResult<IEnumerable<TextSearchProvider.TextSearchResult>>(results);
}
TextSearchProvider 選項
TextSearchProvider可以通過類自定義TextSearchProviderOptions。 這裡有一個範例,如何在每次模型呼叫前建立選項,讓搜尋前執行搜尋,並保留一個短暫的聊天歷史滾動視窗。
TextSearchProviderOptions textSearchOptions = new()
{
// Run the search prior to every model invocation and keep a short rolling window of chat history for searches.
SearchTime = TextSearchProviderOptions.TextSearchBehavior.BeforeAIInvoke,
RecentMessageMemoryLimit = 6,
};
類別透過 TextSearchProvider 類別支援 TextSearchProviderOptions 下列選項。
| Option | 類型 | 說明 | Default |
|---|---|---|---|
| 搜尋時間 | TextSearchProviderOptions.TextSearchBehavior |
指出何時應執行搜尋。 有兩種選擇:每次執行代理時,或是透過函式呼叫按需執行。 | TextSearchProviderOptions.TextSearchBehavior.BeforeAIInvoke |
| 函數工具名稱 | string |
在隨選模式下操作時公開的搜尋工具的名稱。 | 「搜尋」 |
| 函數工具說明 | string |
在隨選模式下操作時公開的搜尋工具的描述。 | “允許搜索其他信息以幫助回答用戶問題。” |
| ContextPrompt | string |
結果前綴的上下文提示。 | “## 附加上下文\n在回應使用者時,請考慮來源文件中的以下資訊:” |
| 引文提示 | string |
結果後附上的指示是請求引用。 | “如果文檔名稱和鏈接可用,請包含對源文檔的引用以及文檔名稱和鏈接。” |
| ContextFormatter | Func<IList<TextSearchProvider.TextSearchResult>, string> |
可選擇委託以完全自訂結果列表的格式。 如果提供, ContextPrompt 則 CitationsPrompt 會忽略。 |
null |
| RecentMessageMemory限制 | int |
要保留在記憶體中的最近交談訊息 (使用者和助理) 數目,並在建構搜尋的 BeforeAIInvoke 搜尋輸入時包含。 |
0 (禁用) |
| RecentMessageRolesIncluded | List<ChatRole> |
在決定建構搜尋輸入時要包含哪些最近訊息時,要篩選最近訊息的類型清單 ChatRole 。 |
ChatRole.User |
Tip
完整可執行範例請參閱 .NET 範例 。
代理框架提供原生向量存儲合約及 create_vector_search_tool()。 輔助工具將任何 SupportsVectorSearch 實作轉化為函數工具,讓模型能在回答前取得接地資料。
建立原生向量搜尋工具
首先,定義你的向量儲存模型,建立一個集合,並載入其紀錄。 以下範例使用 InMemoryCollection , OpenAIEmbeddingClient但你也可以提供任何實作 SupportsVectorSearch的原生代理框架集合。 接著,它會向模型開放可選的分類與評分篩選器,將每個結果映射到基礎文字,並指示代理人在回答前先搜尋:
import asyncio
import json
import os
from typing import Annotated, Any, Literal
from urllib.request import urlopen
from agent_framework import (
Agent,
Filter,
FilterGroup,
InMemoryCollection,
Param,
VectorStoreField,
create_vector_search_tool,
vectorstoremodel,
)
from agent_framework.openai import OpenAIChatClient, OpenAIEmbeddingClient
from dotenv import load_dotenv
async def main() -> None:
"""Create an in-memory hotel search tool and give it to an agent."""
api_key = os.environ["OPENAI_API_KEY"]
collection: InMemoryCollection[str, Hotel] = InMemoryCollection(
Hotel,
embedding_generator=OpenAIEmbeddingClient(
model="text-embedding-3-small",
api_key=api_key,
),
)
await collection.ensure_collection_exists()
# 1. Load the hotel records.
hotels = await asyncio.to_thread(load_hotels)
await collection.upsert(hotels)
# 2. Param values become optional model-visible filter arguments.
# When the allowed values are known, use Literal so the tool schema exposes
# them as an enum.
category = Param(
"category",
Literal["Boutique", "Budget", "Extended-Stay", "Luxury", "Resort and Spa", "Suite"],
description="Only return hotels in this category.",
)
min_rating = Param(
"min_rating",
float,
description="The minimum guest rating.",
minimum=0,
maximum=5,
)
tool = create_vector_search_tool(
collection,
description="Search the hotel dataset, optionally filtering by category and minimum rating.",
filter=FilterGroup(
"and",
(
Filter("category", "eq", category),
Filter("rating", "gte", min_rating),
),
),
result_mapper=lambda result: (
f"(hotel_id: {result['record'].hotel_id}) {result['record'].hotel_name} "
f"(rating {result['record'].rating}) - {result['record'].description}. "
f"Address: {result['record'].address.city}, {result['record'].address.country}."
),
)
# 3. The agent chooses whether to supply the exposed category and minimum-rating filters.
async with Agent(
client=OpenAIChatClient(
model="gpt-5.4-nano",
api_key=api_key,
),
name="HotelAgent",
instructions=(
"Always use the search tool to answer hotel questions. "
"Use category and minimum rating filters when the request provides them. "
"Include the hotel_id in the answer."
),
tools=[tool],
) as agent:
result = await agent.run("Find a resort and spa with a rating of at least 4.")
print(result)
完整範例定義 Hotel 模型,並在展示的集合設置前載入來源紀錄。 在執行前先設定好 OPENAI_API_KEY 。
自訂搜尋行為
請使用以下選項進行配置 create_vector_search_tool() :
| Option | Purpose |
|---|---|
name |
將暴露給模型的函式名稱設定。 新增多個搜尋工具時,請使用獨特的名稱。 |
description |
說明模型何時以及如何使用該工具。 |
approval_mode |
將工具批准設定為 always_require 或 never_require。 |
search_type |
選擇 vector 或 keyword_hybrid 搜尋。 該收藏必須支援所選模式。 |
top 與 skip |
設定固定分頁值或使用模型提供的類型 Param 值。 |
filter |
套用可攜式 Filter 或 FilterGroup. 過濾器可以包含工具結構中暴露的 Param 類型值。 |
result_mapper |
將每個模型 SearchResponse 轉換成文字或多模態 Content 。 |
產生的工具總是包含一個 query 字串。 過濾器中的值 Param 、 top參數或 skip 設定會成為額外的驗證工具參數。
使用 Literal 數值限制,將模型提供的數值維持在應用程式接受的範圍內。
你可以為不同的收藏或搜尋模式建立多種工具。 為每個工具賦予獨特 name 性,讓 description 模型能選擇適當的知識來源。
選擇原生向量儲存庫
原生 Python 實作可用於記憶體內搜尋、Azure AI 搜尋服務、帶有 pgvector 的 PostgreSQL、Qdrant 及 Redis。 它們的搜尋模式、套件生命週期、安裝指令及限制各不相同。 請參閱 向量儲存整合以 選擇並配置實作。 該頁面也標示目前僅有獨立 語意核心 連接器的資料庫。
備註
Go 對此功能的支援即將推出。 最新狀態請參閱 Agent Framework Go 倉庫 。
圖形擷取增強生成 (RAG)
關於使用 Cypher 查詢進行圖遍歷豐富搜尋的 GraphRAG,請參見 Neo4j GraphRAG 提供者。