Memory tool


Memory tool 使 Claude 能够通过记忆文件目录跨对话存储和检索信息。Claude 可以创建、读取、更新和删除在会话之间持久化的文件,使其能够随时间构建知识,而无需将所有内容保留在上下文窗口中。

这是即时上下文检索的关键原语:agent 不是预先加载所有相关信息,而是将学到的内容存储在记忆中,按需拉回。这使活动上下文专注于当前相关的内容,对于一次性加载所有内容会使上下文窗口过载的长时间运行工作流至关重要。参见有效的上下文工程了解更广泛的模式。

Memory tool 在客户端运行:你通过自己的基础设施控制数据的存储位置和方式。

Note

请通过反馈表分享你对此功能的反馈。

Note

此功能符合零数据留存 (ZDR) 条件。当你的组织有 ZDR 安排时,通过此功能发送的数据在 API 响应返回后不会被存储。

使用场景

  • 跨多次 agent 执行维护项目上下文
  • 从过去的交互、决策和反馈中学习
  • 随时间构建知识库
  • 实现跨对话学习,使 Claude 在重复工作流中不断改进

工作原理

启用后,Claude 在开始任务前自动检查其记忆目录。Claude 可以在 /memories 目录中创建、读取、更新和删除文件,以存储工作中学到的内容,然后在未来的对话中引用这些记忆,以更有效地处理类似任务或从中断处继续。

由于这是客户端工具,Claude 发出工具调用以执行记忆操作,你的应用程序在本地执行这些操作。这使你完全控制记忆的存储位置和方式。为安全起见,应将所有记忆操作限制在 /memories 目录中。

示例:记忆工具调用如何工作

当你请求 Claude 帮助完成任务时,Claude 会自动先检查其记忆目录。以下是典型交互的样子:

1. 用户请求:

"Help me respond to this customer service ticket."

2. Claude 检查记忆目录:

"I'll help you respond to the customer service ticket. Let me check my memory for any previous context."

Claude 调用 memory tool:

{
  "type": "tool_use",
  "id": "toolu_01C4D5E6F7G8H9I0J1K2L3M4",
  "name": "memory",
  "input": {
    "command": "view",
    "path": "/memories"
  }
}

3. 你的应用程序返回目录内容:

{
  "type": "tool_result",
  "tool_use_id": "toolu_01C4D5E6F7G8H9I0J1K2L3M4",
  "content": "Here're the files and directories up to 2 levels deep in /memories, excluding hidden items and node_modules:\n4.0K\t/memories\n1.5K\t/memories/customer_service_guidelines.xml\n2.0K\t/memories/refund_policies.xml"
}

4. Claude 读取相关文件:

{
  "type": "tool_use",
  "id": "toolu_01D5E6F7G8H9I0J1K2L3M4N5",
  "name": "memory",
  "input": {
    "command": "view",
    "path": "/memories/customer_service_guidelines.xml"
  }
}

5. 你的应用程序返回文件内容:

{
  "type": "tool_result",
  "tool_use_id": "toolu_01D5E6F7G8H9I0J1K2L3M4N5",
  "content": "Here's the content of /memories/customer_service_guidelines.xml with line numbers:\n     1\t<guidelines>\n     2\t<addressing_customers>\n     3\t- Always address customers by their first name\n     4\t- Use empathetic language\n..."
}

6. Claude 使用记忆提供帮助:

"Based on your customer service guidelines, I can help you craft a response. Please share the ticket details..."

模型支持参见工具参考

开始使用

要使用 memory tool:

  1. 将 memory tool 添加到你的请求中
  2. 为记忆操作实现客户端处理程序
Note

要在你的应用程序中处理 memory tool 操作,你需要为每个记忆命令实现处理程序。SDK 提供了处理工具接口的 memory tool 辅助工具。你可以子类化 BetaAbstractMemoryTool(Python)或使用 betaMemoryTool(TypeScript)来实现你自己的记忆后端(基于文件、数据库、云存储、加密文件等)。

工作示例参见:

基本用法

curl https://api.anthropic.com/v1/messages \
    --header "x-api-key: $ANTHROPIC_API_KEY" \
    --header "anthropic-version: 2023-06-01" \
    --header "content-type: application/json" \
    --data '{
        "model": "claude-opus-4-7",
        "max_tokens": 2048,
        "messages": [
            {
                "role": "user",
                "content": "I'\''m working on a Python web scraper that keeps crashing with a timeout error. Here'\''s the problematic function:\n\n```python\ndef fetch_page(url, retries=3):\n    for i in range(retries):\n        try:\n            response = requests.get(url, timeout=5)\n            return response.text\n        except requests.exceptions.Timeout:\n            if i == retries - 1:\n                raise\n            time.sleep(1)\n```\n\nPlease help me debug this."
            }
        ],
        "tools": [{
            "type": "memory_20250818",
            "name": "memory"
        }]
    }'
ant messages create <<'YAML'
model: claude-opus-4-7
max_tokens: 2048
tools:
  - type: memory_20250818
    name: memory
messages:
  - role: user
    content: |
      I'm working on a Python web scraper that keeps crashing with a
      timeout error. Here's the problematic function:

      ```python
      def fetch_page(url, retries=3):
          for i in range(retries):
              try:
                  response = requests.get(url, timeout=5)
                  return response.text
              except requests.exceptions.Timeout:
                  if i == retries - 1:
                      raise
                  time.sleep(1)
      ```

      Please help me debug this.
YAML
import anthropic

client = anthropic.Anthropic()

message = client.messages.create(
    model="claude-opus-4-7",
    max_tokens=2048,
    messages=[
        {
            "role": "user",
            "content": "I'm working on a Python web scraper that keeps crashing with a timeout error. Here's the problematic function:\n\n```python\ndef fetch_page(url, retries=3):\n    for i in range(retries):\n        try:\n            response = requests.get(url, timeout=5)\n            return response.text\n        except requests.exceptions.Timeout:\n            if i == retries - 1:\n                raise\n            time.sleep(1)\n```\n\nPlease help me debug this.",
        }
    ],
    tools=[{"type": "memory_20250818", "name": "memory"}],
)

print(message)
import Anthropic from "@anthropic-ai/sdk";

const anthropic = new Anthropic({
  apiKey: process.env.ANTHROPIC_API_KEY
});

const message = await anthropic.messages.create({
  model: "claude-opus-4-7",
  max_tokens: 2048,
  messages: [
    {
      role: "user",
      content:
        "I'm working on a Python web scraper that keeps crashing with a timeout error. Here's the problematic function:\n\n```python\ndef fetch_page(url, retries=3):\n    for i in range(retries):\n        try:\n            response = requests.get(url, timeout=5)\n            return response.text\n        except requests.exceptions.Timeout:\n            if i == retries - 1:\n                raise\n            time.sleep(1)\n```\n\nPlease help me debug this."
    }
  ],
  tools: [{ type: "memory_20250818", name: "memory" }]
});

console.log(message);
using System;
using System.Threading.Tasks;
using Anthropic;
using Anthropic.Models.Messages;

public class Program
{
    public static async Task Main(string[] args)
    {
        AnthropicClient client = new()
        {
            ApiKey = Environment.GetEnvironmentVariable("ANTHROPIC_API_KEY")
        };

        var parameters = new MessageCreateParams
        {
            Model = Model.ClaudeOpus4_7,
            MaxTokens = 2048,
            Messages = [
                new()
                {
                    Role = Role.User,
                    Content = "I'm working on a Python web scraper that keeps crashing with a timeout error. Here's the problematic function:\n\n```python\ndef fetch_page(url, retries=3):\n    for i in range(retries):\n        try:\n            response = requests.get(url, timeout=5)\n            return response.text\n        except requests.exceptions.Timeout:\n            if i == retries - 1:\n                raise\n            time.sleep(1)\n```\n\nPlease help me debug this."
                }
            ],
            Tools = [new ToolUnion(new MemoryTool20250818())]
        };

        var message = await client.Messages.Create(parameters);
        Console.WriteLine(message);
    }
}
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/anthropics/anthropic-sdk-go"
)

func main() {
	client := anthropic.NewClient()

	response, err := client.Beta.Messages.New(context.TODO(), anthropic.BetaMessageNewParams{
		Model:     anthropic.ModelClaudeOpus4_7,
		MaxTokens: 2048,
		Messages: []anthropic.BetaMessageParam{
			anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("I'm working on a Python web scraper that keeps crashing with a timeout error. Here's the problematic function:\n\n```python\ndef fetch_page(url, retries=3):\n    for i in range(retries):\n        try:\n            response = requests.get(url, timeout=5)\n            return response.text\n        except requests.exceptions.Timeout:\n            if i == retries - 1:\n                raise\n            time.sleep(1)\n```\n\nPlease help me debug this.")),
		},
		Tools: []anthropic.BetaToolUnionParam{
			{OfMemoryTool20250818: &anthropic.BetaMemoryTool20250818Param{}},
		},
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(response)
}
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.messages.MemoryTool20250818;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;

public class MemoryToolExample {
    public static void main(String[] args) {
        AnthropicClient client = AnthropicOkHttpClient.fromEnv();

        MessageCreateParams params = MessageCreateParams.builder()
            .model(Model.CLAUDE_OPUS_4_7)
            .maxTokens(2048L)
            .addUserMessage("I'm working on a Python web scraper that keeps crashing with a timeout error. Here's the problematic function:\n\n```python\ndef fetch_page(url, retries=3):\n    for i in range(retries):\n        try:\n            response = requests.get(url, timeout=5)\n            return response.text\n        except requests.exceptions.Timeout:\n            if i == retries - 1:\n                raise\n            time.sleep(1)\n```\n\nPlease help me debug this.")
            .addTool(MemoryTool20250818.builder().build())
            .build();

        Message response = client.messages().create(params);
        System.out.println(response);
    }
}
<?php

use Anthropic\Client;

$client = new Client(apiKey: getenv("ANTHROPIC_API_KEY"));

$message = $client->messages->create(
    maxTokens: 2048,
    messages: [
        [
            'role' => 'user',
            'content' => "I'm working on a Python web scraper that keeps crashing with a timeout error. Here's the problematic function:\n\n```python\ndef fetch_page(url, retries=3):\n    for i in range(retries):\n        try:\n            response = requests.get(url, timeout=5)\n            return response.text\n        except requests.exceptions.Timeout:\n            if i == retries - 1:\n                raise\n            time.sleep(1)\n```\n\nPlease help me debug this.",
        ],
    ],
    model: 'claude-opus-4-7',
    tools: [
        [
            'type' => 'memory_20250818',
            'name' => 'memory',
        ],
    ],
);
require "anthropic"

client = Anthropic::Client.new

message = client.messages.create(
  model: "claude-opus-4-7",
  max_tokens: 2048,
  messages: [
    {
      role: "user",
      content: "I'm working on a Python web scraper that keeps crashing with a timeout error. Here's the problematic function:\n\n```python\ndef fetch_page(url, retries=3):\n    for i in range(retries):\n        try:\n            response = requests.get(url, timeout=5)\n            return response.text\n        except requests.exceptions.Timeout:\n            if i == retries - 1:\n                raise\n            time.sleep(1)\n```\n\nPlease help me debug this."
    }
  ],
  tools: [
    {
      type: "memory_20250818",
      name: "memory"
    }
  ]
)
puts message

工具命令

你的客户端实现需要处理这些 memory tool 命令。虽然这些规范描述了 Claude 最熟悉的推荐行为,但你可以根据你的用例修改实现并返回所需的字符串。

view

显示目录内容或文件内容,支持可选的行范围:

{
  "command": "view",
  "path": "/memories",
  "view_range": [1, 10] // 可选:查看特定行
}

返回值

对于目录: 返回显示文件和目录及其大小的列表:

Here're the files and directories up to 2 levels deep in {path}, excluding hidden items and node_modules:
{size}    {path}
{size}    {path}/{filename1}
{size}    {path}/{filename2}
  • 列出最多 2 层深的文件
  • 显示人类可读的大小(例如 5.5K1.2M
  • 排除隐藏项(以 . 开头的文件)和 node_modules
  • 大小和路径之间使用制表符

对于文件: 返回带标题和行号的文件内容:

Here's the content of {path} with line numbers:
{line_numbers}{tab}{content}

行号格式:

  • 宽度: 6 个字符,右对齐,空格填充
  • 分隔符: 行号和内容之间使用制表符
  • 索引: 从 1 开始(第一行为第 1 行)
  • 行数限制: 超过 999,999 行的文件应返回错误:"File {path} exceeds maximum line limit of 999,999 lines."

示例输出:

Here's the content of /memories/notes.txt with line numbers:
     1	Hello World
     2	This is line two
    10	Line ten
   100	Line one hundred

错误处理

  • 文件/目录不存在: "The path {path} does not exist. Please provide a valid path."

create

创建新文件:

{
  "command": "create",
  "path": "/memories/notes.txt",
  "file_text": "Meeting notes:\n- Discussed project timeline\n- Next steps defined\n"
}

返回值

  • 成功: "File created successfully at: {path}"

错误处理

  • 文件已存在: "Error: File {path} already exists"

str_replace

替换文件中的文本:

{
  "command": "str_replace",
  "path": "/memories/preferences.txt",
  "old_str": "Favorite color: blue",
  "new_str": "Favorite color: green"
}

返回值

  • 成功: "The memory file has been edited." 后跟带行号的已编辑文件片段

错误处理

  • 文件不存在: "Error: The path {path} does not exist. Please provide a valid path."
  • 文本未找到: "No replacement was performed, old_str `{old_str}` did not appear verbatim in \{path\}."
  • 重复文本:old_str 出现多次时,返回:"No replacement was performed. Multiple occurrences of old_str `{old_str}` in lines: \{line_numbers\}. Please ensure it is unique"

目录处理

如果路径是目录,返回"文件不存在"错误。

insert

在特定行插入文本:

{
  "command": "insert",
  "path": "/memories/todo.txt",
  "insert_line": 2,
  "insert_text": "- Review memory tool documentation\n"
}

返回值

  • 成功: "The file {path} has been edited."

错误处理

  • 文件不存在: "Error: The path {path} does not exist"
  • 无效行号: "Error: Invalid `insert_line` parameter: \{insert_line\}. It should be within the range of lines of the file: [0, \{n_lines\}]"

目录处理

如果路径是目录,返回"文件不存在"错误。

delete

删除文件或目录:

{
  "command": "delete",
  "path": "/memories/old_file.txt"
}

返回值

  • 成功: "Successfully deleted {path}"

错误处理

  • 文件/目录不存在: "Error: The path {path} does not exist"

目录处理

递归删除目录及其所有内容。

rename

重命名或移动文件/目录:

{
  "command": "rename",
  "old_path": "/memories/draft.txt",
  "new_path": "/memories/final.txt"
}

返回值

  • 成功: "Successfully renamed {old_path} to {new_path}"

错误处理

  • 源不存在: "Error: The path {old_path} does not exist"
  • 目标已存在: 返回错误(不覆盖):"Error: The destination {new_path} already exists"

目录处理

重命名目录。

提示指导

启用 memory tool 时,此指令会自动包含在系统提示中:

IMPORTANT: ALWAYS VIEW YOUR MEMORY DIRECTORY BEFORE DOING ANYTHING ELSE.
MEMORY PROTOCOL:
1. Use the `view` command of your `memory` tool to check for earlier progress.
2. ... (work on the task) ...
     - As you make progress, record status / progress / thoughts etc in your memory.
ASSUME INTERRUPTION: Your context window might be reset at any moment, so you risk losing any progress that is not recorded in your memory directory.

如果你观察到 Claude 创建杂乱的记忆文件,可以包含此指令:

Note: when editing your memory folder, always try to keep its content up-to-date, coherent and organized. You can rename or delete files that are no longer relevant. Do not create new files unless necessary.

你还可以引导 Claude 写入记忆的内容。例如:"Only write down information relevant to <topic> in your memory system."

安全注意事项

以下是实现记忆存储时的重要安全问题:

敏感信息

Claude 通常会拒绝在记忆文件中写下敏感信息。但是,你可能希望实施更严格的验证来剥离潜在的敏感信息。

文件存储大小

考虑跟踪记忆文件大小并防止文件变得过大。考虑添加记忆读取命令可以返回的最大字符数,并让 Claude 分页浏览内容。

记忆过期

考虑定期清除长时间未访问的记忆文件。

路径遍历保护

Warning

恶意路径输入可能尝试访问 /memories 目录外的文件。你的实现必须验证所有路径以防止目录遍历攻击。

考虑以下安全措施:

  • 验证所有路径以 /memories 开头
  • 将路径解析为规范形式并验证它们保持在记忆目录内
  • 拒绝包含 ../..\\ 或其他遍历模式的路径
  • 注意 URL 编码的遍历序列(%2e%2e%2f
  • 使用你语言的内置路径安全工具(例如 Python 的 pathlib.Path.resolve()relative_to()

错误处理

Memory tool 使用与文本编辑器工具类似的错误处理模式。有关详细的错误消息和行为,请参见上面的各个工具命令部分。常见错误包括文件未找到、权限错误、无效路径和重复文本匹配。

上下文编辑集成

Memory tool 与上下文编辑配合使用,管理长时间运行的对话。详情参见上下文编辑

与 Compaction 一起使用

Memory tool 还可以与 compaction 配合使用,后者提供旧对话上下文的服务端摘要。上下文编辑在客户端清除特定工具结果,而 compaction 在对话接近上下文窗口限制时自动在服务端摘要整个对话。

对于长时间运行的 agent 工作流,考虑同时使用两者:compaction 保持活动上下文可管理,无需客户端记账;memory 跨 compaction 边界持久化重要信息,确保摘要中不会丢失关键内容。

多会话软件开发模式

对于跨多个 agent 会话的长时间运行软件项目,记忆文件需要被刻意引导,而不仅仅是在工作进展时临时编写。下面的模式将记忆转变为结构化的恢复机制,使每个新会话都能准确地从上一个会话中断的地方继续。

工作原理

  1. 初始化会话: 第一个会话在任何实质性工作开始之前设置记忆产物。这包括进度日志(跟踪已完成和接下来的工作)、功能清单(定义工作范围)以及项目所需的任何启动或初始化脚本的引用。

  2. 后续会话: 每个新会话通过读取这些记忆产物开始。这在几秒钟内恢复项目的完整状态,无需重新探索代码库或追溯早期决策。

  3. 会话结束更新: 在会话结束前,更新进度日志,记录已完成和剩余的工作。这确保下一个会话有准确的起点。

关键原则

一次只做一个功能。只有在端到端验证确认功能正常后才标记为完成,而不仅仅是在代码编写后。这使进度日志保持可信,防止范围蔓延在会话间累积。

Tip

有关此模式在实践中的详细案例研究,包括初始化脚本、进度文件结构和基于 git 的恢复,请参见长时间运行 agent 的有效工具

下一步