4단계: 메모리 및 지속성

사용자 기본 설정, 과거 상호 작용 또는 외부 지식을 기억할 수 있도록 에이전트에 컨텍스트를 추가합니다.

기본적으로 에이전트는 시스템 요구 사항에 따라 채팅 기록을 InMemoryChatHistoryProvider에 저장하거나 기본 AI 서비스에 저장합니다.

다음 에이전트는 OpenAI 채팅 완료를 사용하여 서비스 내 채팅 기록 스토리지를 지원하거나 요구하지 않기 때문에 자동으로 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");

Warning

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

전체 실행 가능한 파일에 대한 전체 샘플을 참조하세요.

비고

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)

Tip

전체 실행 가능한 파일에 대한 전체 샘플을 참조하세요.

다음 단계

더 자세히 살펴보기: