关于 add-agent-memory
为现有 Agent 添加 Redis Agent Memory 的技能,涵盖代码检查、服务配置与创建,并指导在模型调用前召回记忆、回合结束后写回对话。
主要功能
- 01检查 Agent 回合、标识符和现有记忆
- 02配置记忆类型、有效期与排除项
- 03创建并检查记忆服务
- 04接入记忆召回和对话写回
- 05支持异步 Agent 方法
适用场景
- 01为 Agent 添加跨会话用户记忆
- 02替换现有记忆存储的读写逻辑
- 03设置共享上下文或按需删除用户数据
- 04使用 iris CLI 创建 Redis Agent Memory
MCP 相关
技能建议在编码前通过可用的 MCP 查询框架和 Redis 文档,也将通过 MCP 客户端向模型提供记忆工具列为一种接入方式。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ redis/ agent-skills --skill add-agent-memory安装后在 Claude Code 中输入/add-agent-memory确认已加载。
详细介绍
添加 Agent Memory
调用模型之前:回忆已知的用户信息。本轮交互结束后:写回本次对话。该服务会从会话中提取长期记忆。它记住、共享、排除和保留哪些内容,属于服务设置,而非 SDK 参数:先询问,再配置,最后接入。
1. 探查
阅读项目:
- 找到调用模型的轮次,以及该处涉及的用户 ID 和会话或线程 ID。
- 根据导入内容识别框架。
- 找出现有的记忆代码(
BaseStore、InMemoryStore、自定义字典或数据库)。你要替换的是它的读写操作,而不是图。 - 已经通过专用客户端使用 Redis Agent Memory?修改前先盘点:基于生成的
redis_agent_memory客户端构建的适配器、向模型暴露记忆工具的 MCP 客户端、每条记录都写入的namespace字符串,以及任何会写入同一存储的第二个运行时或框架插件。参见第 4 步中的“已在使用 Redis Agent Memory”。 - Agent 是异步的吗?使用带
a前缀的方法。
然后只向开发者询问以下五个问题,不要多问。对方若不确定,则采用默认值。
| 询问 | 如果回答是 | 配置 |
|---|---|---|
| Agent 应该在不同会话间记住用户的哪些信息? | 自由格式的事实和偏好(默认) | 无需配置:内置的 semantic 和 episodic 类型足以覆盖 |
| 结构化业务数据:行程要求、订单限制、账户偏好 | 添加一个带命名 fields 和提取用 prompt 的 memory_types 条目 | |
| 是否有每次对话都应获取的知识? | 事件、临时政策、团队备注 | 使用 memory.shared_namespace("<name>");由运维负责人通过 remember(..., namespace_id=...) 写入;Agent 通过 recall(shared=[...]) 读取 |
| 没有(默认) | 跳过命名空间 | |
| 哪些内容绝不能保留? | 密码、令牌、卡号、确认码、健康数据 | 在 exclusions.prompt 中逐项列出。这只是指导,并非保证:会话内容仍会发送给模型提供商,而且直接调用 remember() 写入时会跳过此项 |
| 记忆应保留多久? | 会话 TTL、长期 TTL(默认值为 30d / 365d) | short_term_ttl、long_term_ttl |
| 用户是否需要能够按请求被遗忘? | 是 | 在数据擦除流程中调用 memory.forget(owner) |
长会话(支持工单、多小时聊天):保持启用 summarization,并设置 after_messages: 20、keep_recent: 10。
2. 从 MCP 获取当前事实
编写代码前先完成此操作。切勿凭记忆猜测框架 API。
- 框架文档:查询可用的文档 MCP(Context7,或框架自带的文档 MCP,例如 LangChain 的 MCP),了解已安装版本的动态系统提示词或指令、模型调用前后的回调,以及运行上下文(工具或回调如何读取用户 ID)。
- Redis 文档:如果已连接 Redis 文档 MCP,请使用
search/fetch/ask查询 Agent Memory 概念(会话、长期记忆、命名空间、自定义记忆类型、排除项)。 - 没有可用的 MCP:阅读虚拟环境中已安装的软件包源码,并在报告中说明。
3. 配置
根据答案编写 service.yaml。将其提交:这是可供审查的服务记录。
name: support-memory
# database: "1" # the default on-prem; the registered database id the store lives in
short_term_ttl: 30d
long_term_ttl: 365d
# extraction_cadence: 60s # the default (60s to 600s); raise it to spend less on extraction
summarization: {enabled: true, after_messages: 20, keep_recent: 10}
exclusions: {prompt: "Do not keep passwords, access tokens, recovery codes, payment card information, or booking confirmation codes in long-term memory."}
memory_types: # only when question 1 named structured data
- name: trip_preference
description: Structured requirements for a planned trip
prompt: Extract trip requirements only when the user states a destination or travel plan.
enabled: true
fields: {destinations: "list[str]", travel_period: str, dietary_requirements: "list[str]"}
在终端中进行配置:
iris --json --no-input agent-memory service create --from service.yaml --dry-run
iris --json --no-input agent-memory service create --from service.yaml --write-env .env
iris --json --no-input agent-memory service check <storeId from the result> --env-file .env
| 技术栈 | 运行前的准备 |
|---|---|
本地自托管(Agent Memory 服务 http://127.0.0.1:9100,Agent Memory URL http://127.0.0.1:9000) | 添加 --local |
| 自行管理的套件 | 由操作人员导出 IRIS_AGENT_MEMORY_SERVICE_TOKEN、IRIS_IDENTITY_TOKEN,以及在多租户 Identity Service 上使用的 IRIS_IDENTITY_TENANT;URL 来自 IRIS_AGENT_MEMORY_SERVICE_URL、IRIS_AGENT_MEMORY_URL 和 IRIS_IDENTITY_URL,也可以来自配置文件。请参阅下文的“Identity 令牌” |
| Redis Cloud | 服务命令会返回 cloud_unsupported;请参阅下文的控制台说明 |
Identity 令牌。 每个产品图表都可以运行自己的 Identity Service。此时请设置该产品自己的 IRIS_AGENT_MEMORY_IDENTITY_TOKEN(以及 IRIS_AGENT_MEMORY_IDENTITY_URL,或配置文件中的 identity_url),并将 IRIS_IDENTITY_URL 留空:它会覆盖配置文件中所有产品的 identity_url。在共用一个 Identity Service 的套件中,IRIS_IDENTITY_TOKEN 和 IRIS_IDENTITY_URL 适用于所有产品。CLI 按照 --identity-token、IRIS_AGENT_MEMORY_IDENTITY_TOKEN、IRIS_IDENTITY_TOKEN、产品服务令牌的顺序获取令牌;最后一种仅在两个令牌是同一密钥时才可用。试运行会在 warnings 中列出此回退情况。
启动项目的 iris.toml。只有 iris CLI 会读取 iris.toml;应用会读取环境变量。该文件仅保存 URL:如果在 TOML 中设置令牌,CLI 会以状态码 2 退出。使用 IRIS_CONFIG=./iris.toml 和 IRIS_PROFILE=cloud 或 IRIS_PROFILE=suite 选择配置文件。
Redis Cloud。由操作人员根据控制台内容填写 .env:IRIS_AGENT_MEMORY_URL、IRIS_AGENT_MEMORY_STORE_ID 和 IRIS_AGENT_MEMORY_API_KEY。
[profiles.cloud]
kind = "cloud"
console_url = "https://cloud.redis.io"
[profiles.cloud.agent_memory]
url = "https://gcp-us-east4.memory.redis.io" # the data-plane URL from the console
自行管理的套件。操作人员的令牌应放在 .env.admin 中,绝不能放在应用的 .env 中;service create --write-env .env 会写入应用的 .env。
[profiles.suite]
kind = "self-managed"
[profiles.suite.agent_memory]
service_url = "https://memory-admin.example.com" # control plane: the CLI calls it for service create and check
url = "https://memory.example.com" # data plane: what the agent calls
identity_url = "https://memory-identity.example.com" # Identity Service that mints the agent's keys
共用一个 Identity Service 的套件应在 [profiles.suite.identity] 中设置一次 url,而不是为每项产品分别设置 identity_url。IRIS_<PRODUCT>_SERVICE_URL、IRIS_<PRODUCT>_URL 和 IRIS_<PRODUCT>_IDENTITY_URL 会覆盖配置文件中的值。
以 Agent 身份运行 CLI
每次调用 iris 都要遵循相同的流程:
- 始终将
--json --no-input放在产品名称之前。stdout 会输出一个 JSON 值,stderr 会输出一个 JSON 格式的错误值,并且不会显示提示。 - 先进行试运行:
service create ... --dry-run不会发送任何内容,并会在missing中列出真实运行所需的所有凭据或 URL。如果missing不为空,请停止,并在进行任何写入前移交处理(步骤 4)。在真实运行前,将warnings中的内容(例如授权没有租户,或使用服务令牌代替 Identity Service 令牌)告知操作人员。 - 始终使用
--write-env PATH交付密钥(key命令使用--write PATH)。绝不要在没有文件参数的情况下使用--json运行create或key:这样会将密钥输出到 stdout 和操作记录中。 - 遇到
credential_required时,立即停止。告知操作人员需要设置哪个变量(details.env),以及对应的产品和配置文件,并提供details.obtain链接。遇到unauthenticated或forbidden时,说明哪个值被拒绝(details.source)。绝不要在聊天中索要密钥、在命令行中传递密钥,或回显、cat或grep环境文件。 - 配置完成后,运行
service check ID --env-file .env(即create写入的文件;密钥不会进入 shell),并报告每个步骤。若失败,报告失败的环节(details.hop、details.step、details.cause),不要猜测原因。 - 遇到
resource_exists时,询问操作人员是要通过--reuse重用details.id,还是选择其他名称。绝不要为了重试而删除资源。如果create失败且details.created: true,说明资源已存在,但尚无密钥:请使用--reuse --write-env重新运行。
每个错误都是 stderr 上的一个 JSON 值,包含 error.code;凭据错误还包含 details.env 和 details.obtain,绝不包含实际值。首次失败时立即停止并转达错误:
error.code | 执行方 | 操作 |
|---|---|---|
credential_required | 人员 | 在 Agent 的 shell 中设置 details.env 里的变量。参见上文“身份令牌”。 |
unauthenticated | 人员 | details.source 中的令牌被拒绝:它已过期,或属于另一个部署。请签发新令牌。 |
forbidden | 人员 | 令牌有效,但缺少相应角色或租户。请使用具有该产品所需角色的令牌。 |
configuration_error | 人员或 Agent | 缺少 URL,例如 url。请将其添加到配置文件中。 |
invalid_request | Agent | HTTP 400。请修正消息中指出的请求。 |
resource_exists | 人员 | 决定如何处理:使用 --reuse 重新运行以接管 details.id,或选择其他名称。 |
unavailable | 人员 | 无法连接该链路。请检查 URL、入口和服务的 Pod。 |
check_failed | 人员 | details.hop 和 details.cause 指明了故障链路。请修复问题并重新运行检查。 |
cloud_unsupported | 人员 | 配置文件为 kind = "cloud"。请按照控制台中的 details.steps 操作。 |
input_error、usage_error | Agent | 请修正命令。在 --no-input 下执行破坏性命令时,需要由人员提供 --yes。 |
--write-env .env 会写入 IRIS_AGENT_MEMORY_URL、IRIS_AGENT_MEMORY_STORE_ID、IRIS_AGENT_MEMORY_API_KEY。请在 .env.example 中添加相同的三个名称,并将值留空。切勿提交 .env。后续可使用:iris agent-memory service list | show STORE_ID | env STORE_ID [--write PATH](对于本地堆栈,请添加 --local)。
无法访问 Agent Memory 服务,或正在使用 Redis Cloud?人员需在 Redis Cloud 控制台中创建服务:Iris → Agent Memory → New service。输入服务名称并选择数据库;Customize settings 可设置 TTL、提取频率、摘要、自定义记忆类型和排除项。然后,从存储的 Configuration 选项卡中的 URL List 复制 Store ID 和一个 URL,并在 Iris → Access & Identity 中创建可访问该存储的 API 密钥。API 密钥只会显示一次。
| 控制台 | 环境变量 | 必需 |
|---|---|---|
| URL List | IRIS_AGENT_MEMORY_URL | 是 |
| Store ID | IRIS_AGENT_MEMORY_STORE_ID | 是 |
| API key | IRIS_AGENT_MEMORY_API_KEY | 是 |
IRIS_AGENT_MEMORY_TIMEOUT | 否,单位为秒,默认值为 30 |
在启动时创建一次:
from redis_iris import AgentMemory
memory = AgentMemory.from_env(assistant_id="<agent-name>")
floor = memory.shared_namespace("<team-namespace>") # question 2: memories every user may read
4. 接好两个接口
模型调用前(读入上下文):
known = memory.recall(question, owner=user_id, shared=[floor]) # await memory.arecall(...)
system_prompt = f"{system_prompt}\n\n{known.as_prompt()}"
本轮结束后(写回):
convo = memory.conversation(owner=user_id, session_id=thread_id) # session_id optional
convo.user(question) # await convo.auser(...)
convo.assistant(answer) # await convo.aassistant(...)
明确的事实:memory.remember(text, owner=user_id, topics=[...])。删除记忆(问题 5):memory.forget(user_id) 会返回 Forgotten(owner, sessions, memories)。其他操作:memory.client。
每种框架都只需相同的两个调用,不涉及框架特定逻辑:hooks = memory.hooks(shared=[...]),然后将 hooks.before(message, owner=user_id) 的结果放入系统提示词,并在回复后调用 hooks.after(message, answer, owner=user_id, session=thread_id)(异步代码中为 abefore / aafter)。调用位置如下(请在步骤 2 中确认名称):
| 框架 | 模型调用前 | 本轮结束后 | 工具(可选的 remember) |
|---|---|---|---|
| LangGraph (StateGraph) | 从 redis_iris.integrations.langgraph 导入的 attach(memory, graph)(额外安装 redis-iris[langgraph])会在 compile() 前接好两个接口;owner 和 thread 分别来自 configurable.user_id / thread_id。手动接线的替代方案:在模型调用前添加一个节点 | 已包含在 attach 中;否则在模型调用后添加一个节点 | @tool / StructuredTool |
| OpenAI Agents SDK | 动态 instructions callable | Runner.run 返回后,或使用 run hooks | @function_tool / FunctionTool |
Google ADK (LlmAgent) | 从 redis_iris.integrations.adk 导入的 attach(memory, agent)(无需额外安装)会在 Agent 自身的回调前添加两个模型回调;owner 和 session 分别来自调用中的 user_id 和 session.id | 已包含在 attach 中:只在最终回复时记录一次 | FunctionTool |
| Pydantic AI | 动态 @agent.system_prompt,在 deps 中传入用户 ID | agent.run 返回后 | Tool / @agent.tool |
| CrewAI | 在 kickoff 前注入任务或 Agent 的输入 | kickoff 返回后,或使用 task_callback | @tool / BaseTool |
| 普通循环 | 模型调用前 | 模型调用后 | 请求中的函数定义 |
移除已替换的记忆代码。如果图使用 checkpointer 保存线程状态,则保留它。
已在使用 Redis Agent Memory
存储保持不变;只需更换客户端。沿用项目已有的 owner ID 和 session ID 推导方式,以便现有会话继续使用。
- 将此前轮次作为消息。 如果 Agent 会用当前会话内容初始化模型,
memory.conversation(owner=user_id, session_id=thread_id).transcript()会返回turns(格式为(role, text))和summary;将摘要放在最前面,作为系统消息。如果只需要事实,使用recall即可。 - 两个写入方合并为一个。 面向模型的记忆工具(
create、search、edit、delete)和服务自身的提取逻辑都会写入长期记忆。默认移除这些工具:调用前检索,调用后记录,由服务负责提取。只有在评估证明显式写入很重要时,才保留remember工具。 - 记录上的
namespace字符串字段已弃用。 读取会按 owner 限定范围;共享使用通过shared_namespace创建的命名空间。在删除该常量前,先确认recall(owner=...)会返回现有记录;切勿在同一环境中同时运行旧路径和新路径:按该字符串过滤的客户端看不到新路径写入的内容。 - Agent 需要值时,直接获取值而非字符串。
hooks()会渲染提示词区块。若 Agent 需要根据记忆验证缓存答案,或统计检索到的内容,应直接调用recall()和transcript()。 - 故障策略。 SDK 会抛出异常;如果 Agent 在记忆服务中断时仍必须作答,应在每次调用时捕获异常,并使用空区块继续执行。
5. 验证
iris agent-memory service show $IRIS_AGENT_MEMORY_STORE_ID会输出service.yaml中的 TTL、摘要、排除项和记忆类型。- 写入一条记忆:
memory.remember("Prefers email.", owner="<test-user>")。 - 以
<test-user>身份运行一次 Agent。 - 展示
memory.recall("contact", owner="<test-user>").as_prompt()列出了该记忆,并且该记忆已进入模型的提示词。 - 展示会话:
memory.conversation(owner="<test-user>", session_id=...).transcript().turns不为空。 - 问题 5 的答案为是:
memory.forget("<test-user>")会报告写入的计数,第二次recall则不返回任何内容。 - 取消设置一个变量,并确认
ConfigurationError会指出该变量(在首次调用时引发)。 - 从现有客户端转换而来:
memory.recall(<a known topic>, owner=<an existing user>)会返回变更前写入的记忆。
提取的记忆会在提取窗口结束后出现;写入的记忆则会立即出现。
6. 报告
列出五个问题的答案以及各自生成的 service.yaml、变更的文件、新增的环境变量、每个接入点的去向、验证输出,以及无法通过 MCP 确认的事项。