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。 它們的搜尋模式、套件生命週期、安裝指令及限制各不相同。 請參閱 向量儲存整合以 選擇並配置實作。 該頁面也標示目前僅有獨立 語意核心 連接器的資料庫。

圍棋中的 RAG

該 agent/textsearch 套件透過 . 來加入檢索的知識 agent.ContextProvider。 提供一個搜尋功能,回傳 []textsearch.Result,包括文字及可選的來源名稱與連結,然後在 中註冊提供者。agent.Config.ContextProviders

維護的自訂資料來源範例使用模擬搜尋功能及 Foundry 模型部署:

import (
    "context"
    "fmt"
    "strings"

    "github.com/microsoft/agent-framework-go/agent"
    "github.com/microsoft/agent-framework-go/agent/textsearch"
    "github.com/microsoft/agent-framework-go/examples/internal/demo"
    "github.com/microsoft/agent-framework-go/provider/foundryprovider"
)
    searchProvider := textsearch.NewContextProvider(mockSearch, textsearch.Config{
        SearchTime:               textsearch.BeforeInvoke,
        RecentMessageMemoryLimit: 6,
    })

    a := foundryprovider.NewAgent(demo.FoundryProjectEndpoint, token, foundryprovider.ModelDeployment(demo.FoundryModel),
        foundryprovider.AgentConfig{
            Instructions: "You are a helpful support specialist for Contoso Outdoors. Answer questions using the provided context and cite the source document when available.",
            Config: agent.Config{
                ContextProviders: []agent.ContextProvider{searchProvider},
                Middlewares:      []agent.Middleware{logger},
            },
            DisableStoreOutput: true,
        })

選擇取回運行時間:

  • textsearch.BeforeInvoke 每次執行前搜尋,並將格式化結果注入模型上下文中。 此為預設值。
  • textsearch.OnDemandFunctionCalling 它會暴露搜尋工具,讓模型能請求額外的上下文。 使用啟用自動功能工具調用的提供者。

RecentMessageMemoryLimit 可選擇性地保留會話中的個別訊息,以豐富自動搜尋查詢。 重複使用明確的會話以保留這個查詢上下文。 它不是長期的對話儲存。

設定 textsearch.Config.Logger 為表層自動搜尋診斷。 在搜尋功能中強制執行存取控制,並將檢索的文字與模型產生的搜尋查詢視為不可信的輸入。

請參閱 Go RAG 範例 ,涵蓋記憶體內向量搜尋、Qdrant、自訂檢索、Foundry 檔案搜尋及 Neo4j GraphRAG。 關於內建儲存及其限制,請參見 向量儲存整合。

圖形擷取增強生成 (RAG)

關於使用 Cypher 查詢進行圖遍歷豐富搜尋的 GraphRAG,請參見 Neo4j GraphRAG 提供者。

下一步