الخطوة 4: الذاكرة والمثابرة

أضف سياقا إلى وكيلك حتى يتمكن من تذكر تفضيلات المستخدم أو التفاعلات السابقة أو المعرفة الخارجية.

بشكل افتراضي، سيقوم الوكلاء بتخزين محفوظات الدردشة InMemoryChatHistoryProvider في أو في خدمة الذكاء الاصطناعي الأساسية، اعتمادا على ما تتطلبه الخدمة الأساسية.

يستخدم العامل التالي OpenAI Chat Completion، والذي لا يدعم ولا يتطلب تخزين محفوظات الدردشة في الخدمة لذلك يقوم تلقائيا بإنشاء واستخدام InMemoryChatHistoryProvider.

using System;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;

var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")
    ?? throw new InvalidOperationException("Set AZURE_OPENAI_ENDPOINT");
var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";

AIAgent agent = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential())
    .AsAIAgent(
        model: deploymentName,
        instructions: "You are a friendly assistant. Keep your answers brief.",
        name: "MemoryAgent");

تحذير

DefaultAzureCredential مناسب للتنمية ولكنه يتطلب دراسة متأنية في الإنتاج. في الإنتاج، ضع في اعتبارك استخدام بيانات اعتماد محددة (على سبيل المثال، ManagedIdentityCredential) لتجنب مشكلات زمن الانتقال، وبحث بيانات الاعتماد غير المقصودة، والمخاطر الأمنية المحتملة من الآليات الاحتياطية.

لاستخدام مخصص ChatHistoryProvider ، يمكنك تمرير واحد إلى خيارات العامل:

using System;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;

var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")
    ?? throw new InvalidOperationException("Set AZURE_OPENAI_ENDPOINT");
var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";

AIAgent agent = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential())
    .AsAIAgent(model: deploymentName, options: new ChatClientAgentOptions()
    {
        ChatOptions = new() { Instructions = "You are a helpful assistant." },
        ChatHistoryProvider = new CustomChatHistoryProvider()
    });

استخدم جلسة عمل لمشاركة السياق عبر عمليات التشغيل:

AgentSession session = await agent.CreateSessionAsync();

Console.WriteLine(await agent.RunAsync("Hello! What's the square root of 9?", session));
Console.WriteLine(await agent.RunAsync("My name is Alice", session));
Console.WriteLine(await agent.RunAsync("What is my name?", session));

Tip

انظر هنا للحصول على نموذج تطبيق كامل قابل للتشغيل.

تحدد العينة الكاملة موفر السياق، وتضيفه إلى عامل، وتستخدم جلسة واحدة للحفاظ على حالة التخصيص:

import asyncio
from typing import Any

from agent_framework import Agent, AgentSession, ContextProvider, SessionContext
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential


class UserMemoryProvider(ContextProvider):
    def __init__(self) -> None:
        super().__init__("user_memory")

    async def before_run(
        self,
        *,
        agent: Any,
        session: AgentSession | None,
        context: SessionContext,
        state: dict[str, Any],
    ) -> None:
        user_name = state.get("user_name")
        instructions = (
            f"The user's name is {user_name}. Address them by name." if user_name else "Ask for the user's name."
        )
        context.extend_instructions(self.source_id, instructions)

    async def after_run(
        self,
        *,
        agent: Any,
        session: AgentSession | None,
        context: SessionContext,
        state: dict[str, Any],
    ) -> None:
        for message in context.input_messages:
            text = message.text
            if not isinstance(text, str):
                continue
            _, marker, name = text.lower().partition("my name is")
            if marker and name.strip():
                state["user_name"] = name.split()[0].capitalize()


async def main() -> None:
    agent = Agent(
        client=FoundryChatClient(
            project_endpoint="https://your-account.services.ai.azure.com/api/projects/your-project",
            model="gpt-6-luna",
            credential=AzureCliCredential(),
        ),
        instructions="You are a friendly assistant.",
        context_providers=[UserMemoryProvider()],
    )
    session = agent.create_session()

    print(await agent.run("Hello! What's the square root of 9?", session=session))
    print(await agent.run("My name is Alice", session=session))
    print(await agent.run("What is 2 + 2?", session=session))


if __name__ == "__main__":
    asyncio.run(main())

Tip

راجع النموذج الكامل للملف الكامل القابل للتشغيل.

Note

في Python، تتم معالجة الثبات/الذاكرة بواسطة ContextProvider عمليات التنفيذ.HistoryProvider InMemoryHistoryProvider هو موفر المحفوظات المحلية المضمنة في الذاكرة. RawAgent قد يضيف InMemoryHistoryProvider() تلقائيا في حالات معينة (على سبيل المثال، عند استخدام جلسة عمل مع عدم وجود موفري سياق مكونين ولا مؤشرات تخزين من جانب الخدمة)، ولكن هذا غير مضمون في جميع السيناريوهات. إذا كنت تريد دائما الاستمرارية المحلية، أضف InMemoryHistoryProvider بشكل صريح. تأكد أيضا من أن موفر محفوظات واحدا فقط لديه load_messages=True، لذلك لا تقوم بإعادة تشغيل متاجر متعددة في نفس استدعاء .

إنشاء عميل مشروع ومخزن ذاكرة باتباع Microsoft الذاكرة الدلالية المدارة من Foundry. ثم اجمع بين محفوظات النسخ المحلية والذاكرة المدارة ومخزن التدقيق:

from agent_framework import InMemoryHistoryProvider
from agent_framework.foundry import FoundryMemoryProvider

history = InMemoryHistoryProvider(load_messages=True)
memory = FoundryMemoryProvider(
    project_client=project_client,
    memory_store_name="user-memory",
    scope="user-123",
)
audit_store = InMemoryHistoryProvider(
    "audit",
    load_messages=False,
    store_context_messages=True,  # include context added by other providers
)

agent = client.as_agent(
    name="MemoryAgent",
    instructions="You are a friendly assistant.",
    context_providers=[history, memory, audit_store],  # audit store last
)

بشكل افتراضي، يستخدم الوكلاء إما المحفوظات المحلية في الذاكرة أو المحفوظات المدارة بواسطة الخدمة اعتمادا على الموفر وجلسة العمل.

يستخدم عامل Foundry التالي نشر نموذج مدعوم من المشروع. أضف موفر سياق عندما تريد ذاكرة خاصة بالتطبيق أو حالة تخصيص خارج محفوظات المحادثات.

a := foundryprovider.NewAgent(
    endpoint,
    token,
    foundryprovider.ModelDeployment(model),
    foundryprovider.AgentConfig{
        Instructions: "You are a friendly assistant. Keep your answers brief.",
        Config: agent.Config{
            Name: "MemoryAgent",
        },
    },
)

حدد موفر سياق يخزن معلومات المستخدم في حالة جلسة العمل ويضخ إرشادات التخصيص:

import (
    "context"
    "fmt"
    "strings"

    "github.com/microsoft/agent-framework-go/agent"
    "github.com/microsoft/agent-framework-go/message"
)

const userMemorySourceID = "user_memory"

type providerState struct {
    UserName string `json:"user_name,omitempty"`
}

func newUserMemoryProvider() agent.ContextProvider {
    return agent.NewContextProvider(agent.ContextProviderConfig{
        SourceID: userMemorySourceID,
        Provide:  provideUserMemory,
        Store:    storeUserMemory,
    })
}

func provideUserMemory(ctx context.Context, invoking agent.InvokingContext) ([]*message.Message, []agent.Option, error) {
    session, _ := agent.GetOption(invoking.Options, agent.WithSession)
    var state providerState
    _, _ = session.Get(userMemorySourceID, &state)

    instructions := "You don't know the user's name yet. Ask for it politely."
    if state.UserName != "" {
        instructions = fmt.Sprintf("The user's name is %s. Always address them by name.", state.UserName)
    }
    return nil, []agent.Option{agent.WithInstructions(instructions)}, nil
}

func storeUserMemory(ctx context.Context, invoked agent.InvokedContext) error {
    session, _ := agent.GetOption(invoked.Options, agent.WithSession)
    var state providerState
    _, _ = session.Get(userMemorySourceID, &state)
    for _, msg := range invoked.RequestMessages {
        text := strings.TrimSpace(msg.Contents.Text())
        lower := strings.ToLower(text)
        if idx := strings.Index(lower, "my name is"); idx >= 0 {
            parts := strings.Fields(text[idx+len("my name is"):])
            if len(parts) == 0 {
                continue
            }
            state.UserName = strings.Trim(parts[0], ".,!?")
            session.Set(userMemorySourceID, state)
            break
        }
    }
    return nil
}

إنشاء عامل مع موفر السياق:

a := foundryprovider.NewAgent(
    endpoint,
    token,
    foundryprovider.ModelDeployment(model),
    foundryprovider.AgentConfig{
        Instructions: "You are a friendly assistant.",
        Config: agent.Config{
            Name:             "MemoryAgent",
            ContextProviders: []agent.ContextProvider{newUserMemoryProvider()},
        },
    },
)

قم بتشغيله — يمكن للعامل الآن الوصول إلى السياق:

ctx := context.Background()
session, err := a.CreateSession(ctx)
if err != nil {
    panic(err)
}

// The provider doesn't know the user yet.
resp, err := a.RunText(ctx, "Hello, what is the square root of 9?", agent.WithSession(session)).Collect()
fmt.Println(resp, err)

// Teach the provider the user's name.
resp, err = a.RunText(ctx, "My name is Alice", agent.WithSession(session)).Collect()
fmt.Println(resp, err)

// Subsequent calls are personalized using session state.
resp, err = a.RunText(ctx, "What is 2 + 2?", agent.WithSession(session)).Collect()
fmt.Println(resp, err)

تنتمي حالة التخصيص إلى جلسة العمل، وليس مثيل الموفر. قم بتسلسل جلسة العمل للحفاظ عليها:

import "encoding/json"

data, err := json.Marshal(session)
if err != nil {
    panic(err)
}

var restored agent.Session
if err := json.Unmarshal(data, &restored); err != nil {
    panic(err)
}

resp, err = a.RunText(
    ctx,
    "What is my name?",
    agent.WithSession(&restored),
).Collect()
if err != nil {
    panic(err)
}
fmt.Println(resp.String())

لا تزال حالة الموفر المستعادة تحتوي على اسم Alice. للنجاة من إعادة تشغيل العملية، قم بتخزين وحدات البايت المتسلسلة في طبقة استمرار التطبيق الخاص بك. هذا المثال ليس مخزنا للذاكرة الدلالية عبر الجلسات.

Tip

راجع النموذج الكامل للملف الكامل القابل للتشغيل.

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

انتقل إلى أبعد من ذلك: