RAG

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 提供者。

下一步