RAG

يدعم Microsoft Agent Framework استرداد الجيل المعزز (RAG) من خلال موفري السياق الذين يضيفون المحتوى الذي تم استرداده قبل استدعاء النموذج وأدوات البحث التي تسمح للنموذج باسترداد بيانات الأساس عند الطلب.

للحصول على أنماط المحادثة/الجلسة إلى جانب الاسترداد، راجع نظرة عامة على المحادثات والذاكرة. للإعداد الخاص بالخدمة، راجع البحث باستخدام الذكاء الاصطناعي في AzureMicrosoft 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 أو محرك بحث ويب.

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 الفئة.

خيار Type Description Default
وقت البحث TextSearchProviderOptions.TextSearchBehavior يشير إلى متى يجب تنفيذ البحث. هناك خياران، في كل مرة يتم فيها تشغيل العامل، أو عند الطلب عبر استدعاء الوظيفة. TextSearchProviderOptions.TextSearchBehavior.BeforeAIInvoke
FunctionToolName string اسم أداة البحث المكشوفة عند العمل في وضع عند الطلب. "بحث"
FunctionToolDescription string وصف أداة البحث المكشوفة عند العمل في وضع عند الطلب. "يسمح بالبحث عن معلومات إضافية للمساعدة في الإجابة على سؤال المستخدم."
ContextPrompt string موجه السياق مسبوق بالنتائج. "## سياق إضافي\nضع في اعتبارك المعلومات التالية من مستندات المصدر عند الاستجابة للمستخدم:"
CitationsPrompt string التعليمات الملحقة بعد النتائج لطلب الاقتباسات. "قم بتضمين الاقتباسات إلى المستند المصدر مع اسم المستند والارتباط إذا كان اسم المستند والارتباط متوفرين."
ContextFormatter Func<IList<TextSearchProvider.TextSearchResult>, string> تفويض اختياري لتخصيص تنسيق قائمة النتائج بشكل كامل. إذا تم توفيرها، ContextPromptCitationsPrompt ويتم تجاهلها. null
RecentMessageMemoryLimit 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() باستخدام الخيارات التالية:

خيار الغرض
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 وقيودا رقمية للاحتفاظ بالقيم التي يوفرها النموذج ضمن النطاق الذي يقبله التطبيق الخاص بك.

يمكنك إنشاء أدوات متعددة للمجموعات أو أوضاع البحث المختلفة. امنح كل أداة أداة مميزة namedescription حتى يتمكن النموذج من تحديد مصدر المعرفة المناسب.

اختيار مخزن متجه أصلي

تتوفر تطبيقات Python الأصلية للبحث في الذاكرة، البحث باستخدام الذكاء الاصطناعي في Azure، وPostgreSQL مع pgvector، وQdrant، وRedis. تختلف أوضاع البحث ودورة حياة الحزمة والأوامر والقيود الخاصة بهم. راجع تكاملات مخزن المتجهات لتحديد التنفيذ وتكوينه. تحدد هذه الصفحة أيضا قواعد البيانات التي تحتوي حاليا على موصل نواة دلالية منفصل فقط.

Note

سيتوفر الدعم لهذه الميزة قريبا. راجع مستودع Agent Framework Go للحصول على أحدث حالة.

الرسم البياني RAG

بالنسبة إلى GraphRAG باستخدام البحث المثري باجتياز الرسم البياني باستخدام استعلامات Cypher، راجع موفر Neo4j GraphRAG.

الخطوات التالية