通过


你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

在 Foundry 代理服务中创建和使用内存(预览版)

重要

在 Foundry 代理服务和内存存储 API(预览版)中,内存(预览版)作为您 Azure 订阅的一部分获得许可,并且受到 Microsoft 产品条款Microsoft 产品和服务数据保护附录中有关“预览版”的适用条款的约束,还需遵守 Microsoft Azure 预览版的补充使用条款中的 Microsoft 生成 AI 服务预览版条款。

Foundry 代理服务中的内存是托管的长期内存解决方案。 它支持跨会话、设备和工作流的代理连续性。 通过创建和管理内存存储,可以生成代理来保留用户首选项、维护聊天历史记录并提供个性化体验。

内存存储充当持久性存储,定义与每个代理相关的信息类型。 使用 scope 参数控制访问,该参数将内存分段到各个用户,以确保安全且隔离的体验。

本文介绍如何创建、管理和使用内存存储。 有关概念信息,请参阅 Foundry 代理服务中的内存

使用支持

能力 Python SDK C# SDK JavaScript SDK REST API
创建、更新、列出和删除内存存储 ✔️ ✔️ ✔️ ✔️
更新和搜索存储器 ✔️ ✔️ ✔️ ✔️
将内存附加到提示代理器 ✔️ ✔️ ✔️ ✔️

先决条件

授权和权限

建议对生产部署 使用基于角色的访问控制 。 如果角色不可行,请跳过本部分,改用基于密钥的身份验证。

若要配置基于角色的访问权限,请执行以下操作:

  1. 登录到 Azure 门户

  2. 在您的项目中:

    1. 在左窗格中,选择 “资源管理>标识”。
    2. 使用开关启用系统分配的托管标识。
  3. 在包含您项目的资源中:

    1. 在左窗格中,选择“访问控制”(IAM)。
    2. 选择添加>添加角色分配
    3. Azure AI 用户分配给项目的托管标识。

配置您的环境

安装所需的包:

pip install "azure-ai-projects>=2.0.0" azure-identity

安装所需的包:

dotnet add package Azure.AI.Projects
dotnet add package Azure.AI.Projects.Agents
dotnet add package Azure.AI.Extensions.OpenAI
dotnet add package Azure.Identity

安装所需的包:

npm install @azure/ai-projects@2 @azure/identity

为项目终结点和模型部署名称设置环境变量:

export FOUNDRY_PROJECT_ENDPOINT="https://{your-ai-services-account}.services.ai.azure.com/api/projects/{project-name}"
export MEMORY_STORE_CHAT_MODEL_DEPLOYMENT_NAME="<chat-model-deployment-name>"
export MEMORY_STORE_EMBEDDING_MODEL_DEPLOYMENT_NAME="<embedding-model-deployment-name>"

为项目终结点、模型部署、API 版本和访问令牌设置环境变量:

FOUNDRY_PROJECT_ENDPOINT="https://{your-ai-services-account}.services.ai.azure.com/api/projects/{project-name}"
MEMORY_STORE_CHAT_MODEL_DEPLOYMENT_NAME="<chat-model-deployment-name>" # For example, gpt-5.2
MEMORY_STORE_EMBEDDING_MODEL_DEPLOYMENT_NAME="<embedding-model-deployment-name>" # For example, text-embedding-3-small
API_VERSION="2025-11-15-preview"

# Get a short-lived access token using Azure CLI
ACCESS_TOKEN="$(az account get-access-token --resource https://ai.azure.com/ --query accessToken -o tsv)"

了解范围

参数 scope 控制内存的分区方式。 内存存储中的每个范围都保留一个独立内存项集合。 例如,如果创建具有内存的客户支持代理,则每个客户都应有自己的单个内存。

作为开发人员,可以选择用于存储和检索内存项的密钥。 正确的方法取决于访问内存的方式。

通过内存搜索工具

内存搜索工具附加到代理时,设置为scope{{$userId}}启用每用户内存隔离,而无需硬编码标识符。 系统会自动解析来自以下两个源之一的每个响应调用的最终用户标识:

  • x-memory-user-id 请求标头: 如果存在,标头值将用作用户 ID。 在代理或后端方案中使用此方案,服务代表最终用户调用 API。

  • Microsoft Entra 身份验证令牌:如果未设置标头,系统会回退到调用方的租户 ID 和对象 ID。 这是前端方案中的默认方案,即用户直接使用 Microsoft Entra 进行身份验证。

如果不需要每个用户隔离,请改用静态 scope 值。

通过低级别内存 API

直接调用 内存 API 时,请在每个请求中显式指定 scope 。 可以从系统传递静态值,例如通用唯一标识符(UUID)或其他稳定标识符。 这些操作不支持自动标识提取。

创建内存存储

为每个代理创建专用内存存储,为内存访问和优化建立明确的边界。 创建内存存储时,请指定处理内存内容的聊天模型和嵌入模型的部署。

import os
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import MemoryStoreDefaultDefinition, MemoryStoreDefaultOptions
from azure.identity import DefaultAzureCredential

project_client = AIProjectClient(
    endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
    credential=DefaultAzureCredential(),
)

memory_store_name = "my_memory_store"

# Specify memory store options
options = MemoryStoreDefaultOptions(
    chat_summary_enabled=True,
    user_profile_enabled=True,
    user_profile_details="Avoid irrelevant or sensitive data, such as age, financials, precise location, and credentials"
)

# Create memory store
chat_model = os.environ["MEMORY_STORE_CHAT_MODEL_DEPLOYMENT_NAME"]
embedding_model = os.environ["MEMORY_STORE_EMBEDDING_MODEL_DEPLOYMENT_NAME"]

definition = MemoryStoreDefaultDefinition(
    chat_model=chat_model,
    embedding_model=embedding_model,
    options=options
)

memory_store = project_client.beta.memory_stores.create(
    name=memory_store_name,
    definition=definition,
    description="Memory store for customer support agent",
)

print(f"Created memory store: {memory_store.name}")
using System;
using Azure.AI.Projects;
using Azure.AI.Projects.Memory;
using Azure.Identity;

#pragma warning disable AAIP001

var projectEndpoint = Environment.GetEnvironmentVariable(
    "FOUNDRY_PROJECT_ENDPOINT");
var chatModel = Environment.GetEnvironmentVariable(
    "MEMORY_STORE_CHAT_MODEL_DEPLOYMENT_NAME");
var embeddingModel = Environment.GetEnvironmentVariable(
    "MEMORY_STORE_EMBEDDING_MODEL_DEPLOYMENT_NAME");

AIProjectClient projectClient = new(
    new Uri(projectEndpoint),
    new DefaultAzureCredential());

var memoryStoreName = "my_memory_store";

// Specify memory store options
MemoryStoreDefaultDefinition memoryStoreDefinition = new(
    chatModel: chatModel,
    embeddingModel: embeddingModel
);
memoryStoreDefinition.Options = new(
    isUserProfileEnabled: true,
    isChatSummaryEnabled: true);
memoryStoreDefinition.Options.UserProfileDetails =
    "Avoid irrelevant or sensitive data, such as age, "
    + "financials, precise location, and credentials";

// Create memory store
MemoryStore memoryStore = projectClient.MemoryStores.CreateMemoryStore(
    name: memoryStoreName,
    definition: memoryStoreDefinition,
    description: "Memory store for customer support agent"
);

Console.WriteLine($"Created memory store: {memoryStore.Name}");
import { DefaultAzureCredential } from "@azure/identity";
import type {
  MemoryStoreDefaultDefinition,
  MemoryStoreDefaultOptions,
} from "@azure/ai-projects";
import { AIProjectClient } from "@azure/ai-projects";

const projectEndpoint =
  process.env["FOUNDRY_PROJECT_ENDPOINT"] ||
  "<project endpoint>";
const chatModelDeployment =
  process.env["MEMORY_STORE_CHAT_MODEL_DEPLOYMENT_NAME"] ||
  "<chat model deployment name>";
const embeddingModelDeployment =
  process.env["MEMORY_STORE_EMBEDDING_MODEL_DEPLOYMENT_NAME"] ||
  "<embedding model deployment name>";

const memoryStoreName = "my_memory_store";

const project = new AIProjectClient(
  projectEndpoint,
  new DefaultAzureCredential(),
);

const memoryOptions: MemoryStoreDefaultOptions = {
  user_profile_enabled: true,
  chat_summary_enabled: true,
  user_profile_details:
    "Avoid irrelevant or sensitive data, such as age, " +
    "financials, precise location, and credentials",
};

const definition: MemoryStoreDefaultDefinition = {
  kind: "default",
  chat_model: chatModelDeployment,
  embedding_model: embeddingModelDeployment,
  options: memoryOptions,
};

const memoryStore = await project.beta.memoryStores.create(
  memoryStoreName,
  definition,
  {
    description: "Memory store for customer support agent",
  },
);

console.log(
  `Created memory store: ${memoryStore.name} (${memoryStore.id})`,
);
curl -X POST "${FOUNDRY_PROJECT_ENDPOINT}/memory_stores?api-version=${API_VERSION}" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my_memory_store",
    "description": "Memory store for customer support agent",
    "definition": {
      "kind": "default",
      "chat_model": "'"${MEMORY_STORE_CHAT_MODEL_DEPLOYMENT_NAME}"'",
      "embedding_model": "'"${MEMORY_STORE_EMBEDDING_MODEL_DEPLOYMENT_NAME}"'",
      "options": {
        "chat_summary_enabled": true,
        "user_profile_enabled": true,
        "user_profile_details": "Avoid irrelevant or sensitive data, such as age, financials, precise location, and credentials"
      }
    }
  }'

小窍门

  • 其余 Python、C# 和 TypeScript 代码片段基于 创建内存存储中定义的客户端和变量生成。 如果独立运行这些代码片段,请包含本节中的导入代码和客户端初始化代码。
  • 本文中的 C# 代码片段使用同步方法。 有关异步用法,请参阅内存搜索工具和内存存储示例。

自定义内存

自定义智能体存储的信息,以保持内存高效、相关性强,并尊重隐私。 使用 user_profile_details 参数指定对代理函数至关重要的数据类型。

例如,设置 user_profile_details 以优先考虑旅行社的“航班承运人偏好和饮食限制”。 这种重点方法帮助记忆系统明确提取、总结以及存储到长期记忆中的详细信息。

还可以使用此参数排除某些类型的数据,使内存保持精简且符合隐私要求。 例如,设置为 user_profile_details “避免不相关或敏感数据,例如年龄、财务、精确位置和凭据”。

更新内存存储

更新内存存储属性(例如 descriptionmetadata)以更好地管理内存存储。

# Update memory store properties
updated_store = project_client.beta.memory_stores.update(
    name=memory_store_name,
    description="Updated description"
)

print(f"Updated: {updated_store.description}")
// Update memory store properties
MemoryStore updatedStore = projectClient.MemoryStores.UpdateMemoryStore(
    name: memoryStoreName,
    description: "Updated description"
);

Console.WriteLine($"Updated: {updatedStore.Description}");
const updatedStore = await project.beta.memoryStores.update(
  memoryStoreName,
  {
    description: "Updated description",
  },
);

console.log(`Updated: ${updatedStore.description}`);
MEMORY_STORE_NAME="my_memory_store"

curl -X POST "${FOUNDRY_PROJECT_ENDPOINT}/memory_stores/${MEMORY_STORE_NAME}?api-version=${API_VERSION}" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "description": "Updated description"
  }'

列出内存空间

检索项目中内存存储的列表,以管理和监视内存基础结构。

# List all memory stores
stores_list = list(project_client.beta.memory_stores.list())

print(f"Found {len(stores_list)} memory stores")
for store in stores_list:
    print(f"- {store.name} ({store.description})")
// List all memory stores
foreach (MemoryStore store in projectClient.MemoryStores.GetMemoryStores())
{
    Console.WriteLine(
        $"Memory store: {store.Name} ({store.Description})");
}
const storeList = project.beta.memoryStores.list();

console.log("Listing all memory stores...");
for await (const store of storeList) {
  console.log(`  - Memory Store: ${store.name} (${store.id})`);
}
curl -X GET "${FOUNDRY_PROJECT_ENDPOINT}/memory_stores?api-version=${API_VERSION}" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}"

通过代理工具使用记忆

创建内存存储后,可以将内存搜索工具附加到提示代理。 此工具使代理能够在会话期间读取和写入内存存储。 使用合适的 scopeupdate_delay 来配置该工具,以控制内存更新的方式和时间。

小窍门

若要将内存范围限定为单个最终用户,请将其设置为scope"{{$userId}}"工具定义中,并在每个响应调用中作为标头传递x-memory-user-id: <user-id>。 系统将作用域解析为该用户的身份。 如果没有标头,范围将回退到调用方Microsoft Entra 标识(TID 和 OID)。 有关详细信息,请参阅了解范围

from azure.ai.projects.models import MemorySearchPreviewTool, PromptAgentDefinition

# Set scope to associate the memories with
scope = "user_123"

openai_client = project_client.get_openai_client()

# Create memory search tool
tool = MemorySearchPreviewTool(
    memory_store_name=memory_store_name,
    scope=scope,
    update_delay=1, # Wait 1 second of inactivity before updating memories
    # In a real application, set this to a higher value like 300 (5 minutes, default)
)

# Create a prompt agent with memory search tool
agent = project_client.agents.create_version(
    agent_name="MyAgent",
    definition=PromptAgentDefinition(
        model=os.environ["MEMORY_STORE_CHAT_MODEL_DEPLOYMENT_NAME"],
        instructions="You are a helpful assistant that answers general questions",
        tools=[tool],
    )
)

print(f"Agent created (id: {agent.id}, name: {agent.name}, version: {agent.version})")
using Azure.AI.Projects.Agents;
using Azure.AI.Extensions.OpenAI;
using OpenAI.Responses;

#pragma warning disable OPENAI001

// Set scope to associate the memories with
string scope = "user_123";

// Create a prompt agent with memory search tool
DeclarativeAgentDefinition agentDefinition = new(model: chatModel)
{
    Instructions = "You are a helpful assistant that answers "
        + "general questions",
};
agentDefinition.Tools.Add(new MemorySearchPreviewTool(
    memoryStoreName: memoryStore.Name,
    scope: scope)
{
    UpdateDelayInSecs = 1, // Wait 1 second of inactivity before updating memories
    // In a real application, set this to a higher value
    // like 300 (5 minutes, default)
});

ProjectsAgentVersion agent =
    projectClient.AgentAdministrationClient.CreateAgentVersion(
        agentName: "MyAgent",
        options: new(agentDefinition));

Console.WriteLine(
    $"Agent created (id: {agent.Id}, name: {agent.Name}, "
    + $"version: {agent.Version})");
// Set scope to associate the memories with
const scope = "user_123";

const agent = await project.agents.createVersion(
  "memory-search-agent",
  {
    kind: "prompt",
    model: chatModelDeployment,
    instructions:
      "You are a helpful assistant that retrieves relevant " +
      "information from the user's memory store to answer their questions.",
    tools: [
      {
        type: "memory_search_preview",
        memory_store_name: memoryStoreName,
        scope: scope,
        update_delay: 1,
      },
    ],
  },
);

console.log(
  `Created agent with memory search tool, agent ID: ${agent.id}, ` +
    `name: ${agent.name}, version: ${agent.version}`,
);
# The agents API uses api-version=v1, which differs from the memory store API version
curl -X POST "${FOUNDRY_PROJECT_ENDPOINT}/agents?api-version=v1" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "MyAgent",
    "definition": {
        "kind": "prompt",
        "model": "gpt-5.2",
        "instructions": "You are a helpful assistant that answers general questions",
        "tools": [
            {
              "type": "memory_search_preview",
              "memory_store_name": "my_memory_store",
              "scope": "user_123",
              "update_delay": 1
            }
        ]
    }
}'

创建对话

现在可以创建对话和请求代理响应。 在每个会话开始时,将注入静态内存,以便代理具有即时的持久上下文。 上下文记忆会在每一轮根据最新消息进行检索,以辅助生成每个响应。

每次代理响应后,服务都会在内部调用 update_memories。 但是,对长期记忆的实际写入会受到 update_delay 设置的去抖控制。 更新是计划执行的,只有在配置的非活动时间段结束后才会完成。

import time

# Create a conversation with the agent with memory tool enabled
conversation = openai_client.conversations.create()
print(f"Created conversation (id: {conversation.id})")

# Create an agent response to initial user message
response = openai_client.responses.create(
    input="I prefer dark roast coffee",
    conversation=conversation.id,
    extra_body={"agent_reference": {"name": agent.name, "type": "agent_reference"}},
    # To scope memories to an end user, uncomment:
    # extra_headers={"x-memory-user-id": "<user-id>"},
)

print(f"Response output: {response.output_text}")

# After an inactivity in the conversation, memories will be extracted from the conversation and stored
print("Waiting for memories to be stored...")
time.sleep(65)

# Create a new conversation
new_conversation = openai_client.conversations.create()
print(f"Created new conversation (id: {new_conversation.id})")

# Create an agent response with stored memories
new_response = openai_client.responses.create(
    input="Please order my usual coffee",
    conversation=new_conversation.id,
    extra_body={"agent_reference": {"name": agent.name, "type": "agent_reference"}},
)

print(f"Response output: {new_response.output_text}")
using System.Threading;

#pragma warning disable OPENAI001

// Get a response client scoped to the agent
ProjectResponsesClient responseClient =
    projectClient.ProjectOpenAIClient
        .GetProjectResponsesClientForAgent(agent.Name);

// Create an agent response to initial user message
ResponseItem request = ResponseItem.CreateUserMessageItem(
    "I prefer dark roast coffee");
ResponseResult response = responseClient.CreateResponse([request]);
// To scope memories to an end user, uncomment:
// var options = new CreateResponseOptions();
// options.InputItems.Add(request);
// var requestOptions = new RequestOptions();
// requestOptions.AddHeader("x-memory-user-id", "<user-id>");
// ClientResult result = responseClient.CreateResponse(
//     BinaryContent.Create(options), requestOptions);
// ResponseResult response = ModelReaderWriter.Read<ResponseResult>(
//     result.GetRawResponse().Content);

Console.WriteLine($"Response output: {response.GetOutputText()}");

// After inactivity, memories are extracted and stored
Console.WriteLine("Waiting for memories to be stored...");
Thread.Sleep(65_000);

// Create a new response to demonstrate cross-session recall
ResponseItem newRequest = ResponseItem.CreateUserMessageItem(
    "Please order my usual coffee");
ResponseResult newResponse = responseClient.CreateResponse(
    [newRequest]);

Console.WriteLine(
    $"Response output: {newResponse.GetOutputText()}");
import { setTimeout } from "timers/promises";

const openaiClient = project.getOpenAIClient();

// Create a conversation with the agent with memory tool enabled
const conversation = await openaiClient.conversations.create();
console.log(`Created conversation (id: ${conversation.id})`);

// Create an agent response to initial user message
const response = await openaiClient.responses.create(
  {
    conversation: conversation.id,
    input: "I prefer dark roast coffee",
  },
  {
    body: {
      agent: { name: agent.name, type: "agent_reference" },
    },
    // To scope memories to an end user, uncomment:
    // headers: { "x-memory-user-id": "<user-id>" },
  },
);

console.log(`Response output: ${response.output_text}`);

// After inactivity, memories are extracted and stored
console.log("Waiting for memories to be stored...");
await setTimeout(65_000);

// Create a new conversation to demonstrate cross-session recall
const newConversation = await openaiClient.conversations.create();
console.log(`Created new conversation (id: ${newConversation.id})`);

// Create an agent response with stored memories
const newResponse = await openaiClient.responses.create(
  {
    conversation: newConversation.id,
    input: "Please order my usual coffee",
  },
  {
    body: {
      agent: { name: agent.name, type: "agent_reference" },
    },
  },
);

console.log(`Response output: ${newResponse.output_text}`);
curl -X POST "${FOUNDRY_PROJECT_ENDPOINT}/openai/v1/conversations" \
    -H "Authorization: Bearer ${ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -d '{}'

# Copy the "id" field from the previous response
# To scope memories to an end user, add -H "x-memory-user-id: <user-id>" to the following request
curl -X POST "${FOUNDRY_PROJECT_ENDPOINT}/openai/v1/responses" \
    -H "Authorization: Bearer ${ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -d '{
      "input": "I prefer dark roast coffee",
      "conversation": "{conversation-id}",
      "agent_reference": {
        "type": "agent_reference",
        "name": "MyAgent"
      }
    }'

通过 API 使用内存

可以使用内存存储 API 直接与内存存储进行交互。 首先,将对话内容中的记忆添加到内存存储,然后搜索相关记忆,以提供代理交互的上下文。

将信息添加到记忆存储库

通过向内存存储提供对话内容来添加记忆。 系统预处理和后处理数据(包括内存提取和合并)以优化代理的内存。 此长时间运行的操作可能需要大约一分钟。

通过指定 scope 参数来确定如何跨用户分段内存。 可以将内存范围限定为特定的最终用户、团队或其他标识符。

可以使用多个会话轮次的内容更新内存存储,或者使用以前的更新操作 ID 在每个轮次和链更新后更新。

# Set scope to associate the memories with
scope = "user_123"

user_message = {
  "role": "user",
  "content": "I prefer dark roast coffee and usually drink it in the morning",
   "type": "message"
}

update_poller = project_client.beta.memory_stores.begin_update_memories(
    name=memory_store_name,
    scope=scope,
    items=[user_message], # Pass conversation items that you want to add to memory
    update_delay=0, # Trigger update immediately without waiting for inactivity
)

# Wait for the update operation to complete, but can also fire and forget
update_result = update_poller.result()
print(f"Updated with {len(update_result.memory_operations)} memory operations")
for operation in update_result.memory_operations:
    print(
        f"  - Operation: {operation.kind}, Memory ID: {operation.memory_item.memory_id}, Content: {operation.memory_item.content}"
    )

# Extend the previous update with another update and more messages
new_message = {
    "role":"user", 
    "content":"I also like cappuccinos in the afternoon", 
    "type":"message"}

new_update_poller = project_client.beta.memory_stores.begin_update_memories(
    name=memory_store_name,
    scope=scope,
    items=[new_message],
    previous_update_id=update_poller.update_id, # Extend from previous update ID
    update_delay=0, # Trigger update immediately without waiting for inactivity
)
new_update_result = new_update_poller.result()
for operation in new_update_result.memory_operations:
    print(
        f"  - Operation: {operation.kind}, Memory ID: {operation.memory_item.memory_id}, Content: {operation.memory_item.content}"
    )
#pragma warning disable OPENAI001

// Set scope to associate the memories with
string scope = "user_123";

MemoryUpdateOptions memoryOptions = new(scope)
{
    UpdateDelay = 0, // Trigger update immediately without waiting for inactivity
};
memoryOptions.Items.Add(ResponseItem.CreateUserMessageItem(
    "I prefer dark roast coffee and usually drink it "
    + "in the morning"));

// Wait for the update operation to complete
MemoryUpdateResult updateResult =
    projectClient.MemoryStores.WaitForMemoriesUpdate(
        memoryStoreName: memoryStore.Name,
        options: memoryOptions,
        pollingInterval: 500);

if (updateResult.Status == MemoryStoreUpdateStatus.Failed)
{
    throw new InvalidOperationException(
        updateResult.ErrorDetails);
}
Console.WriteLine(
    $"Updated with {updateResult.Details.MemoryOperations.Count} "
    + "memory operations");
foreach (var operation in updateResult.Details.MemoryOperations)
{
    Console.WriteLine(
        $"  - Operation: {operation.Kind}, "
        + $"Memory ID: {operation.MemoryItem.MemoryId}, "
        + $"Content: {operation.MemoryItem.Content}");
}

// Extend the previous update with another message
MemoryUpdateOptions newMemoryOptions = new(scope)
{
    PreviousUpdateId = updateResult.UpdateId,
    UpdateDelay = 0, // Trigger update immediately without waiting for inactivity
};
newMemoryOptions.Items.Add(ResponseItem.CreateUserMessageItem(
    "I also like cappuccinos in the afternoon"));

MemoryUpdateResult newUpdateResult =
    projectClient.MemoryStores.WaitForMemoriesUpdate(
        memoryStoreName: memoryStore.Name,
        options: newMemoryOptions,
        pollingInterval: 500);

if (newUpdateResult.Status == MemoryStoreUpdateStatus.Failed)
{
    throw new InvalidOperationException(
        newUpdateResult.ErrorDetails);
}
foreach (var operation in newUpdateResult.Details.MemoryOperations)
{
    Console.WriteLine(
        $"  - Operation: {operation.Kind}, "
        + $"Memory ID: {operation.MemoryItem.MemoryId}, "
        + $"Content: {operation.MemoryItem.Content}");
}
const scope = "user_123";

const userMessage: Record<string, unknown> = {
  type: "message",
  role: "user",
  content: [
    {
      type: "input_text",
      text: "I prefer dark roast coffee and usually drink it in the morning",
    },
  ],
};

console.log("\nSubmitting memory update request...");
const updatePoller = project.beta.memoryStores.updateMemories(
  memoryStoreName,
  scope,
  {
    items: [userMessage],
    updateDelayInSecs: 0,
  },
);

const updateResult = await updatePoller.pollUntilDone();
console.log(
  `Updated with ${updateResult.memory_operations.length} ` +
    `memory operation(s)`,
);
for (const operation of updateResult.memory_operations) {
  console.log(
    `  - Operation: ${operation.kind}, ` +
      `Memory ID: ${operation.memory_item.memory_id}, ` +
      `Content: ${operation.memory_item.content}`,
  );
}

// Extend the previous update with another message
const newMessage = {
  role: "user",
  content: "I also like cappuccinos in the afternoon",
  type: "message",
};

const newUpdatePoller = project.beta.memoryStores.updateMemories(
  memoryStoreName,
  scope,
  {
    items: [newMessage],
    updateDelayInSecs: 0,
  },
);

const newUpdateResult = await newUpdatePoller.pollUntilDone();
console.log(
  `Updated with ${newUpdateResult.memory_operations.length} ` +
    `memory operation(s)`,
);
for (const operation of newUpdateResult.memory_operations) {
  console.log(
    `  - Operation: ${operation.kind}, ` +
      `Memory ID: ${operation.memory_item.memory_id}, ` +
      `Content: ${operation.memory_item.content}`,
  );
}
curl -X POST "${FOUNDRY_PROJECT_ENDPOINT}/memory_stores/my_memory_store:update_memories?api-version=${API_VERSION}" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "scope": "user_123",
    "items": [
      {
        "type": "message",
        "role": "user",
        "content": [
          {
            "type": "input_text",
            "text": "I prefer dark roast coffee and usually drink it in the morning"
          }
        ]
      }
    ],
    "update_delay": 0
  }'

# Get add memory status by polling the update_id
# Use the "update_id" from previous response
UPDATE_ID=<your_update_id>
curl -X GET "${FOUNDRY_PROJECT_ENDPOINT}/memory_stores/my_memory_store/updates/${UPDATE_ID}?api-version=${API_VERSION}" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}"

在记忆库中搜索记忆

搜索记忆以检索代理交互的相关上下文。 指定内存存储名称和范围以缩小搜索范围。

from azure.ai.projects.models import MemorySearchOptions

# Search memories by a query
query_message = {"role": "user", "content": "What are my coffee preferences?", "type": "message"}

search_response = project_client.beta.memory_stores.search_memories(
    name=memory_store_name,
    scope=scope,
    items=[query_message],
    options=MemorySearchOptions(max_memories=5)
)
print(f"Found {len(search_response.memories)} memories")
for memory in search_response.memories:
    print(f"  - Memory ID: {memory.memory_item.memory_id}, Content: {memory.memory_item.content}")
#pragma warning disable OPENAI001

// Search memories by a query
MemorySearchOptions searchOptions = new(scope)
{
    Items =
    {
        ResponseItem.CreateUserMessageItem(
            "What are my coffee preferences?")
    },
    ResultOptions = new() { MaxMemories = 5 },
};

MemoryStoreSearchResponse searchResponse =
    projectClient.MemoryStores.SearchMemories(
        memoryStoreName: memoryStore.Name,
        options: searchOptions);

Console.WriteLine(
    $"Found {searchResponse.Memories.Count} memories");
foreach (MemorySearchItem item in searchResponse.Memories)
{
    Console.WriteLine(
        $"  - Content: {item.MemoryItem.Content}");
}
const queryMessage: Record<string, unknown> = {
  type: "message",
  role: "user",
  content: [
    { type: "input_text", text: "What are my coffee preferences?" },
  ],
};

console.log("\nSearching memories for stored preferences...");
const searchResponse =
  await project.beta.memoryStores.searchMemories(
    memoryStoreName,
    scope,
    {
      items: [queryMessage],
      options: { max_memories: 5 },
    },
  );

console.log(`Found ${searchResponse.memories.length} memory item(s)`);
for (const memory of searchResponse.memories) {
  console.log(
    `  - Memory ID: ${memory.memory_item.memory_id}, ` +
      `Content: ${memory.memory_item.content}`,
  );
}
curl -X POST "${FOUNDRY_PROJECT_ENDPOINT}/memory_stores/my_memory_store:search_memories?api-version=${API_VERSION}" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "scope": "user_123",
    "items": [
      {
        "type": "message",
        "role": "user",
        "content": [
          {
            "type": "input_text",
            "text": "What are my coffee preferences?"
          }
        ]
      }
    ],
    "options": {
      "max_memories": 5
    }
  }'

检索静态或上下文内存

通常,无法基于与用户消息的语义相似性来检索用户配置文件记忆。 建议将静态记忆注入每个会话的开头,并使用上下文记忆来生成每个代理响应。

  • 若要检索静态内存,请调用search_memories,使用scope但不使用itemsprevious_search_id。 这将返回与特定范围相关联的用户档案数据。

  • 若要检索上下文记忆,请调用 search_memories 并将 items 设置为最新消息。 这可以返回与给定项目最相关的用户配置文件和聊天摘要记忆。

有关用户配置文件和聊天摘要记忆的详细信息,请参阅 内存类型

删除内存

警告

在删除内存存储之前,请考虑对依赖代理的影响。 具有附加内存存储的代理可能会失去对历史上下文的访问权限。

内存根据内存库中的范围进行组织。 可以删除特定范围的内存以删除特定于用户的数据,也可以删除整个内存存储,以删除所有范围内的所有内存。

按范围删除内存

在保留内存存储结构的同时,删除与特定用户或组范围关联的所有内存。 使用此作可处理特定用户的用户数据删除请求或重置内存。

# Delete memories for a specific scope
project_client.beta.memory_stores.delete_scope(
    name=memory_store_name,
    scope="user_123"
)

print(f"Deleted memories for scope: user_123")
// Delete memories for a specific scope
MemoryStoreDeleteScopeResponse deleteScopeResponse =
    projectClient.MemoryStores.DeleteScope(
        name: memoryStore.Name,
        scope: "user_123");

Console.WriteLine(
    $"Deleted scope: {deleteScopeResponse.Name}, "
    + $"success: {deleteScopeResponse.IsDeleted}");
console.log("\nDeleting memories for scope...");
await project.beta.memoryStores.deleteScope(memoryStoreName, scope);
curl -X POST "${FOUNDRY_PROJECT_ENDPOINT}/memory_stores/my_memory_store:delete_scope?api-version=${API_VERSION}" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "scope": "user_123"
  }'

删除内存存储

删除所有范围内的整个内存仓库及所有关联的内存。 此操作不可逆。

# Delete the entire memory store
delete_response = project_client.beta.memory_stores.delete(memory_store_name)
print(f"Deleted memory store: {delete_response.deleted}")
// Delete the entire memory store
DeleteMemoryStoreResponse deleteResponse =
    projectClient.MemoryStores.DeleteMemoryStore(
        name: memoryStore.Name);

Console.WriteLine(
    $"Deleted memory store: {deleteResponse.Name}, "
    + $"success: {deleteResponse.IsDeleted}");
console.log("Deleting memory store...");
await project.beta.memoryStores.delete(memoryStoreName);
curl -X DELETE "${FOUNDRY_PROJECT_ENDPOINT}/memory_stores/my_memory_store?api-version=${API_VERSION}" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}"

最佳做法

  • 实现每用户访问控制: 避免向代理授予对所有用户共享的内存的访问权限。 scope使用属性按用户对内存存储进行分区。 在用户之间共享 scope 时,用于 user_profile_details 指示内存系统不存储个人信息。

  • 将范围映射到最终用户:使用内存搜索工具时,请在工具定义中设置为scope{{$userId}}。 系统从 x-memory-user-id 请求标头(如果存在)解析用户标识。 否则,会回退到调用方的 Microsoft Entra 令牌 ({tid}_{oid})。

  • 最小化和保护敏感数据: 仅存储用例所需的内容。 如果必须存储敏感数据(如个人数据、运行状况数据或机密业务输入),请编辑或删除可用于追溯到个人的其他内容。

  • 支持隐私和合规性: 为用户提供透明度,包括访问和删除其数据的选项。 在防篡改审核日志中记录所有删除。 确保系统遵守本地合规性要求和法规标准。

  • 分段数据并隔离内存: 在多代理系统中,以逻辑方式和作方式分段内存。 允许客户定义、隔离、检查和删除其自己的内存占用情况。

  • 监视内存使用情况: 跟踪令牌使用情况和内存作,以了解成本和优化性能。

故障排除

問题 原因 决议
请求失败并出现身份验证或授权错误。 你的标识或项目托管标识没有所需的角色。 验证 授权和权限中的角色。 对于 REST 调用,请生成新的访问令牌并重试。
对话后记忆不会出现。 内存更新已去抖或仍在处理。 增加等待时间,或调用更新 API,并将 update_delay 设置为 0 以立即触发处理。
内存搜索不返回任何结果。 该值 scope 与存储内存时使用的作用域不匹配。 使用相同的范围进行更新和搜索。 如果将范围映射到用户,请使用稳定的用户标识符。
代理响应不使用存储的内存。 代理未使用内存搜索工具进行配置,或者内存存储名称不正确。 确认代理定义包括该工具 memory_search_preview 并引用正确的内存存储名称。