Claude API Memory Tool:让你的 AI Agent 终于不再失忆

用不到 100 行 Python,打造一个有记忆的 AI 编程助手。从「重启就失忆」的聊天机器人,到能跨天接续专案、自动更新记忆、防 path traversal 攻击的真正 AI 同事。

一、问题展示:Claude 的失忆现场

先感受一下问题有多烦。做一个最简单的聊天机器人——你打字、Claude 回你:

先建一个虚拟环境,Mac 现在不让你直接 pip install 了:

Bash
python3 -m venv .venv
source .venv/bin/activate
pip install anthropic

设定 API key。如果你还没有,去官网注册,在 API Keys 那边建一把就好:

Bash
export ANTHROPIC_API_KEY=你的key

建立 chatbot.py

Python
import anthropic

client = anthropic.Anthropic()
messages = []

print("跟Claude聊天(输入quit退出)")
while True:
    msg = input("\n> ")
    if msg.lower() == "quit":
        break
    messages.append({"role": "user", "content": msg})
    res = client.messages.create(
        model="claude-opus-4-6",
        max_tokens=512,
        messages=messages,
    )
    reply = res.content[0].text
    print(f"Claude: {reply}")
    messages.append({"role": "assistant", "content": reply})

执行 python chatbot.py,跟它聊聊:

  • 输入「我叫 Matt,我在做一个电商平台的后端,用 Python 加 FastAPI」—— Claude 正确回覆。
  • 输入「我叫什么名字?我用什么框架?」—— Claude 也答得出来。

到这边都没问题,它记得你是谁。但假设你下班了,程式关掉,明天回来重开:

  • 输入 quit 退出程式
  • 重新执行 python chatbot.py
  • 输入「我叫什么名字?我用什么框架?」—— Claude 回覆「抱歉,我无法知道你的名字...」

完全不记得了。昨天聊的所有东西全部消失。因为 messages 这个阵列是存在内存里的,程式一关就没了。这就是你用 Claude API 做任何 Agent 都会遇到的问题:重启就失忆

二、加上 Memory Tool,让 Claude 有记忆

新建一个有记忆的版本 memory_agent.py。先写最上面的设定:

Python
import anthropic
import os

client = anthropic.Anthropic()
os.makedirs("./memories", exist_ok=True)

就是 import 跟建一个 memories 资料夹,Claude 的记忆会存在这里面。

记忆 Handler

Claude 会发指令跟你说「帮我看这个档案」或「帮我建一个档案」,你的程式要接住这些指令。先处理「看」跟「建」两个最基本的:

Python
def handle_memory(command, **kwargs):
    path = kwargs.get("path", "")
    local_path = "." + path  # /memories/note.txt -> ./memories/note.txt

    if command == "view":
        if os.path.isdir(local_path):
            entries = []
            for root, dirs, files in os.walk(local_path):
                for f in files:
                    fp = os.path.join(root, f)
                    entries.append(f"{os.path.getsize(fp)}\t{fp}")
            return "Files in " + path + ":\n" + "\n".join(entries) if entries else "Empty directory"
        elif os.path.isfile(local_path):
            with open(local_path, "r") as f:
                return f"Content of {path}:\n{f.read()}"
        return f"Error: {path} does not exist"

    elif command == "create":
        os.makedirs(os.path.dirname(local_path), exist_ok=True)
        with open(local_path, "w") as f:
            f.write(kwargs.get("file_text", ""))
        return f"File created at {path}"

    return f"Unknown command: {command}"

这个函数做的事很单纯。Claude 传一个 command 过来,如果是 view 就去读资料夹或档案,如果是 create 就建一个新档案。**kwargs 就是「把剩下的参数全部收进来」的意思,因为不同指令需要的参数不一样。

Agent Loop:让 Claude 来回操作记忆

最关键的部分。我们要写一个循环让 Claude 可以跟你的程式来回对话。为什么需要循环?因为 Claude 用记忆的时候,一次对话里面可能会连续操作好几次——先看目录有什么档案、再读某个档案、最后建一个新档案。每次操作都是一个 tool call,你的程式要一个一个接住,做完再把结果送回去,直到 Claude 说「我做完了」为止。

Python
def run_agent(user_message):
    messages = [{"role": "user", "content": user_message}]
    while True:
        response = client.messages.create(
            model="claude-opus-4-6",
            max_tokens=4096,
            tools=[{"type": "memory_20250818", "name": "memory"}],
            messages=messages,
        )
        # 印出Claude说的话
        for block in response.content:
            if block.type == "text":
                print(f"Claude: {block.text}")
        # Claude不再要求操作记忆 -> 结束
        if response.stop_reason != "tool_use":
            break
        # 处理Claude的记忆操作请求
        tool_results = []
        for block in response.content:
            if block.type == "tool_use":
                print(f"  [记忆操作] {block.input['command']} {block.input.get('path','')}")
                result = handle_memory(**block.input)
                tool_results.append({
                    "type": "tool_result",
                    "tool_use_id": block.id,  # 对应哪个tool call
                    "content": result,
                })
        # 把结果送回去,让Claude继续
        messages.append({"role": "assistant", "content": response.content})
        messages.append({"role": "user", "content": tool_results})

三个重点:

  • while True 让循环一直跑。
  • 每次检查 stop_reason,如果 Claude 不再要求 tool call 就 break 跳出。
  • tool_use_id 要从 block.id 拿,这是让 Claude 知道「这个结果是回覆你哪个请求的」。

小知识:tool result 为什么用 "role": "user" 送回去?这是 Claude API 的规定,tool result 就是要放在 user 的 message 里面,不是因为它是人类说的话,是 API 格式就是这样。

tools 里面的 memory_20250818 是 Anthropic 定义好的内建 tool type,从官方文件查到的。你不需要自己定义 schema,Claude 天生就知道 memory tool 有哪些指令可以用——view、create、str_replace 全部都是内建的。日期是 API 版本号,照写就好。

最后加一个互动循环:

Python
while True:
    msg = input("\n> ")
    if msg.lower() in ("exit", "quit", "q"):
        break
    run_agent(msg)

实际运行效果

执行 python memory_agent.py,输入「我叫 Matt,我在做一个电商平台的后端,用 Python 加 FastAPI」:

  • Claude 第一件事去看记忆资料夹,发现是空的。
  • 回覆完之后,它自己决定建一个记忆档案 user_profile.txt 把你的信息存下来。没有人叫它存,它自己觉得应该记住。

不退出程式,继续输入「帮我 review 一下我的订单 API」:

  • 看到「订单 API」这个关键字,它第一反应是去翻记忆,因为它知道记忆里可能有之前存的进度。
  • 读完记忆发现只有 user_profile,没有订单 API 的代码,就直接问你档案路径。它没有乱猜、没有瞎掰,这就是有记忆的 Agent 该有的行为。

给它档案路径后,Claude 完成 review,还主动把 review 结论存进记忆。没有人叫它存。它知道这种 review 结论之后可能还会用到,所以主动写了一份。这就是 Memory Tool 最强的地方:Agent 自己判断什么该记、什么不该记。

关键点:把程式关掉重开,输入「我们上次 review 到哪了?」—— Claude 先去读记忆,读到 user_profile 跟 review 结论,直接接上。全新的 process,跟失忆版天差地远。

三、Claude 自己会更新记忆

记忆存了,但如果情况有变化呢?比如订单 API 你已经修掉一个 bug 了,记忆里的 review 结论就过期了。

如果只有 viewcreate 两个指令,Claude 想修改记忆只能整个档案重写——浪费 token、资料多的时候效率差、写到一半程式挂了整个档案就没了。正确做法是补上精准修改的指令。在 handle_memorycreate 分支下面加上这些:

Python
    elif command == "str_replace":
        with open(local_path, "r") as f:
            content = f.read()
        old_str = kwargs["old_str"]
        if content.count(old_str) != 1:
            return f"Error: old_str must appear exactly once, found {content.count(old_str)}"
        with open(local_path, "w") as f:
            f.write(content.replace(old_str, kwargs["new_str"]))
        return "Memory file updated"

    elif command == "insert":
        with open(local_path, "r") as f:
            lines = f.readlines()
        lines.insert(kwargs["insert_line"], kwargs["insert_text"])
        with open(local_path, "w") as f:
            f.writelines(lines)
        return "Inserted"

    elif command == "delete":
        import shutil
        if os.path.isdir(local_path):
            shutil.rmtree(local_path)
        else:
            os.remove(local_path)
        return f"Deleted {path}"

    elif command == "rename":
        os.rename("." + kwargs["old_path"], "." + kwargs["new_path"])
        return f"Renamed to {kwargs['new_path']}"
指令 功能 说明
str_replace 精准替换字串 旧字串必须唯一出现一次,否则报错
insert 在指定行插入文字 按行号插入
delete 删除档案或资料夹 资料夹用 shutil.rmtree
rename 重命名档案 os.rename

补上之后,Claude 就能直接用 str_replace 精准改一行,不用再整个档案重写。而且它还会主动帮你整理目前的进度——哪几条修好了、哪几条还没修,一目了然。

四、安全问题:差点被打穿的教训

功能都好了,但这里有一个严重的安全漏洞。第一版上线没做路径检查,Claude 送了一个带「点点斜线」的路径(../),直接跳出 memories 资料夹,读到了 .env 档——API key、数据库密码、JWT 密钥、Stripe 付款金钥全部外泄。如果是线上服务,这波外泄够你上新闻。

修复方法是用 os.path.realpath 加上 prefix check。在 handle_memory 里面,local_path = "." + path 上面加这段:

Python
    # 安全检查:挡掉 path traversal,只允许存取 memories 资料夹底下
    real_path = os.path.realpath("." + path)
    memories_root = os.path.realpath("./memories")
    if not real_path.startswith(memories_root):
        return "Error: 路径不合法"

os.path.realpath 会把 ../ 这种东西解析成真实路径,然后检查它有没有跑出 memories 资料夹。如果跑出去了就直接挡掉。这样连 .env 这种放在专案根目录的敏感档案也读不到。

多人场景注意:如果是多人使用,记得用 user_id 建不同的子资料夹做隔离,不然使用者之间会互相看到记忆。

五、跨天专案:接上昨天的进度

最后一招,也是真正让 Agent 能长期跟你搭档的关键。清空记忆,重新开始:

输入「我要做一个电商平台的后端,用 Python + FastAPI,功能包括:使用者认证、商品管理、订单系统、支付串接。今天我们先讨论使用者认证的设计,做完把这次讨论的重点和下一步要做什么,存到 /memories/progress.md」。

Claude 没有一上来就硬写代码,而是先跟你讨论设计方向——技术选型、数据库模型、API 端点、token 策略、安全性、权限、目录结构,七个面向全讲了,还主动问三个待确认的问题。这才是真正有用的 pair programming——先对齐设计,再开始写。最后它把讨论重点和下一步存进 progress.md

正确的记忆用法:不是把程式码塞进去,是存「为什么这样选、接下来要做什么」这种讨论层的东西。

模拟第二天——关掉程式重开,输入「继续昨天的进度,今天接着做下一步」:

  • Claude 读完记忆,不只知道昨天讨论到哪、下一步该做什么。
  • 连昨天没决定完的事都记得——主动提醒你要先回答三个问题才能继续写代码。

这才是真正有记忆的同事,不是你讲一次它就当过眼云烟。你下班前悬而未决的事,第二天回来它会帮你盯着。第三天、第四天,都能这样接上去。

总结

你现在手上有什么?一个不到 100 行的程式,能记住使用者、能更新记忆、能防攻击、跨天专案也能接上。核心就是四步:

  • 加 Memory Tool:用 memory_20250818 内建 tool type,Claude 天生知道怎么用。
  • 补全指令:view、create、str_replace、insert、delete、rename 六个指令让记忆系统完整。
  • 防 path traversalos.path.realpath + prefix check,一行代码挡住目录穿越攻击。
  • 跨天接续:存讨论决策和下一步计划,不是存代码,让 Agent 能无缝衔接。
Y
YAHA学堂 发布于 2026年4月12日

专注 AI 工具与开发效率的技术频道,用最简单的方式讲最实用的技术。