你有没有遇到过这种情况:你的 AI Agent 今天早上还能准确叫出客户的名字、记得项目偏好,下午换了一个会话窗口,它就像失忆了一样,把所有上下文忘得一干二净。这不是你的 Agent 不够聪明,而是它缺少一个真正属于自己的“长期记忆”。最近我在帮团队搭建一个带记忆能力的 AI Agent,把 Graphiti MCP Server 接进去之后,整个系统才算真正“记住了事”。这篇文章我不打算讲太多空泛的概念,就从一个实际工程问题出发:AI Agent 怎么接上长期记忆,顺便把 MCP、Episode、搜索这些绕不开的名词一次讲透。
先说结论:长期记忆不是把聊天记录存到一个大文本里,也不是简单丢给向量数据库就完事。真正可用的记忆系统,需要有结构、有时间意识、能被检索,还得能按照统一协议暴露给 Agent 调用。Graphiti MCP Server 就是目前我认为最适合直接落地的方案之一。它把记忆做成了标准化的 MCP 工具,Agent 可以像调用普通函数一样写入和搜索记忆。下面我会从为什么需要长期记忆开始,一直讲到环境搭建、配置细节和实战踩坑。
1. 为什么 AI Agent 必须解决长期记忆问题
1.1 上下文窗口不是记忆,只是一张“便签纸”
很多人会把大模型的上下文窗口当成记忆来看待。上下文窗口确实能让模型在单个会话里记住刚才聊过的内容,但这里有一个致命的边界:窗口长度是有限的,而且每次对话结束,这个“临时便签纸”就会被清空。哪怕你今天和 Agent 聊了一个小时,它对你需求的精准理解,明天打开新会话就全部作废。用大白话说,这就像一个同事每次上班都把你重新认识一遍,你上次交代的事情他完全没印象。
我见过不少团队把“上下文”和“记忆”混为一谈,结果做了一个看起来很聪明的对话助手,实际一上线就露馅:用户第二次访问,Agent 又开始问“您之前想解决什么问题来着”。这种体验很差,而且根本原因不是模型能力不行,而是架构上压根没把记忆做进去。长期记忆要解决的就是跨会话、跨时间的信息沉淀问题,让 Agent 不只记住“刚才说了什么”,还能记住“昨天你交代了什么、你的偏好是什么、这个项目的背景是什么”。
1.2 长期记忆不是存文本,是沉淀“结构化的知识”
如果只是把历史消息写进一个 JSON 文件,或者塞进向量数据库,看起来是“记住了”,但检索时很容易翻车。原因很简单:自然语言文本是非结构化的,同一个意思有无数种表达方式,靠向量相似度能找出相关片段,却很难精准回答“这个人上个月关注的三个项目分别处于什么状态”这类问题。长期记忆要发挥作用,必须把零散的对话信息沉淀成结构化的知识:谁、在什么时候、和什么实体、有什么关系。
这里就引入了知识图谱的概念。把事实拆成实体和关系,比如“用户A(青睐) 简洁风格”、“项目B(截止日期) 2025年6月30日”,Agent 才能在做决策时精准抽取,而不是在一堆文本里碰运气。我自己的体会是,文本存储适合做“翻阅档案”,记忆系统需要的是“按图索骥”。这也是为什么我强烈建议做长期记忆时直接考虑知识图谱方案,而不是只有向量库。
1.3 Agent 需要的是时间意识,而不是一锅乱炖
另一个容易忽略的问题是时间维度。好的记忆系统必须能回答两层问题:一件事“什么时候发生的”,这个信息“系统是何时知道的”。尤其是 Agent 的知识会不断被新对话修正,如果没有时间意识,旧的事实和新的事实混在一起,系统就会陷入逻辑混乱。常说的 Episode 就是围绕时间组织起来的记忆事件单元,Graphiti 的设计恰好在这里下了很大功夫。
2. MCP 协议:把记忆做成 Agent 的标准外设
2.1 MCP 到底是什么:一句“给 AI 插 U 盘”就懂了
在你接触 Graphiti 之前,大概率会先碰到 MCP 这个词。MCP 全称是 Model Context Protocol,也就是“模型上下文协议”,由 Anthropic 在 2024 年底开源。它的目标非常明确:统一 AI 应用与外部工具、数据源之间的交互方式。你可以把它理解成 AI 世界的 USB-C 接口——以前各种设备要用不同的线,现在所有设备都用同一个标准接口,插上就能用。
在 MCP 协议里,有几个基础角色。Host 是宿主应用,也就是你正在使用的 AI 客户端,比如 Claude Desktop;Client 在宿主内部负责维护与 Server 的连接;Server 则是提供具体能力的服务端,比如一个“记忆服务”。Agent 需要调用外部能力时,通过 MCP 协议向 Server 发起请求,Server 把结果返回给模型。通过这个标准化通道,Agent 可以读取数据库、操作文件、查询日历,当然也包括读写长期记忆。
2.2 为什么记忆功能特别适合做成 MCP Server
你可能会问:记忆功能为什么不能直接写在 Agent 代码里,非要套一层 MCP?这里有几个实际工程原因,体验过就会明白。第一,记忆服务是典型的基础设施,它和业务 Agent 之间要解耦,单独做成服务方便独立升级和复用。第二,MCP Server 与语言、框架无关,无论你的 Agent 是用 Python、TypeScript 还是别的语言写的,只要支持 MCP 客户端就可以接入同一个记忆服务。第三,记忆过程本身很重,涉及图数据库、实体抽取、向量索引,塞进 Agent 主流程只会拖慢响应,拆出来作为外设服务更合适。
我做项目时最直观的感受是:把记忆暴露成 MCP 工具之后,Agent 的代码变得非常干净。我不需要在业务代码里手动管理 Neo4j 连接、拼接 Cypher 查询、处理向量检索,Agent 只要知道“这个服务器提供了 add_memory、search_memory 这样的工具”,按协议调用就行。这其实就是记忆工具化的价值:把复杂的记忆能力封装成一个一个可被模型直接调用的“函数”,模型通过自然语言就能决定何时写入、何时读取。
2.3 Agent 调用记忆工具的完整链路
一条典型的记忆读写链路大概是这样的:用户和 Agent 对话,Agent 判断这段信息值得长期记住,于是调用记忆 Server 提供的写入工具,把内容传过去。记忆 Server 收到内容后,先调用 LLM 抽取实体和关系,再把结构化的数据写入知识图谱,同时生成用于语义搜索的向量索引。当用户下一次问“我上次让你记的那件事怎么样了”,Agent 先调用搜索工具把相关记忆片段取回来,作为上下文的一部分再交给模型生成回答。整个过程用户无感知,但 Agent 的行为从“每次重新认识你”变成了“老熟人”。
3. Graphiti 记忆引擎拆解:Episode、双时态与图搜索
3.1 Episode:以“事件”为单位的记忆单元
Graphiti 里最核心的概念之一是 Episode。简单理解,Episode 就是一次有边界的记忆事件,可以是一段对话、一条用户反馈、一次任务记录。它强调的是“以事件为单位保存原始信息”,而不是把一大堆历史消息糊在一起。每个 Episode 自带时间信息,这样系统既能保留原始内容,也能对事件做后续的实体抽取和关系构建。
这种设计的优势在于,记忆颗粒度是可控的。我可以在 Episode 里看到“某次对话中用户明确说了预算上限是五万”,后续知识图谱里也会有一个“预算上限是五万”的事实节点。原始事件与结构化知识互为补充:原始事件保证细节不丢,知识图谱保证检索高效。相比之下,很多简单方案只保留向量化后的文本,永远丢失了事件之间的关联。
3.2 双时态知识图谱:同时记住“事实”和“时间”
Graphiti 遵循 bi-temporal 模型,也就是“双时态”建模。这里有两个时间概念要区分:一个是有效时间,即这个事实在真实世界里是什么时候成立或变化的;另一个是摄入时间,即系统在什么时候获知并记录了这条事实。为什么需要区分?因为 Agent 获知信息的时间,和事实发生的时间往往不是同一刻。比如用户今天告诉你“上个月项目已经延期了”,“项目延期”这个事实的有效时间是上个月,但系统记录它的时间是今天。
双时态的价值在实战中非常明显。它能避免记忆被简单覆盖,当一个新信息和旧信息冲突时,系统可以根据摄入时间判断“旧记忆是历史版本,新记忆才是当前状态”,同时保留历史可追溯。这种能力是普通的“键值覆盖式记忆”完全不具备的。如果你的 Agent 需要处理“用户修改过需求”“业务状态发生了变更”这一类场景,双时态图谱基本是必须的。
3.3 搜索机制:向量语义检索加图谱关联拓展
Graphiti 的搜索并不是单一手段,而是把语义检索和图遍历结合起来。用户在提问时,系统先通过向量相似度把相关事实节点捞出来,再沿着知识图谱的关系边做拓展,找到与这些节点相关联的实体和事件。这个组合非常聪明:向量负责“找到线索”,图遍历负责“顺藤摸瓜”。比如检索到“预算五万”这个事实,图遍历会自动把“预算五万”和“方案A”“老板审批”“上季度会议”这些关联实体连接起来,Air Agent 拿到的上下文就不是一个个孤立的片段,而是一张围绕当前需求的完整知识网络。
4. 实操:让 AI Agent 真正“记住”你
4.1 准备环境与启动 Neo4j
先说环境准备。Graphiti 的记忆存储底层用的是 Neo4j 图数据库,所以第一步是把 Neo4j 跑起来。我习惯用 Docker 直接拉镜像,一行命令就能启动一个开发实例:
docker run -d --name neo4j-memory \ -p 7474:7474 -p 7687:7687 \ -e NEO4J_AUTH=neo4j/testpassword123 \ neo4j:5.26端口要解释一下:7474 是 Neo4j 的浏览器管理界面,7687 是 Bolt 协议端口,应用连接用的是 7687。NEO4J_AUTH 里设置的是初始用户名和密码,默认用户名是 neo4j。如果你本地已经装了 Neo4j Desktop 也可以直接用,关键是保证后续配置里连接的地址和密码一致。启动之后,最好先打开浏览器访问一次 7474,确认数据库能正常登录,避免后面排查半天。
4.2 Graphiti MCP Server 的配置与启动
Graphiti 官方维护了一个 graphiti-mcp 项目,提供将 Graphiti 封装成 MCP Server 的实现。获取代码后,建议创建 Python 虚拟环境安装依赖。依赖主要包括 graphiti-core 和 mcp 库。首次运行需要准备几个关键配置:Neo4j 的连接地址、用户名、密码,以及用于实体抽取的 LLM API Key。这里我以 OpenAI 兼容接口为例,实际换成其他兼容服务也行,关键是模型要支持 function calling,因为抽取实体时模型需要按固定结构输出。
uv python install 3.11 uv venv source .venv/bin/activate uv pip install graphiti-mcp启动 MCP Server 之前,需要把环境变量准备好。常见的变量有 NEO4J_URI、NEO4J_USER、NEO4J_PASSWORD,以及 LLM 相关的 API Key 配置。如果你用 zsh 或 bash,可以写进一个.env 文件再 source,或者直接在命令行里 export。这里给你一份我实际用的参考配置:
export NEO4J_URI="bolt://localhost:7687" export NEO4J_USER="neo4j" export NEO4J_PASSWORD="testpassword123" export OPENAI_API_KEY="sk-你的key" export OPENAI_MODEL="gpt-4o-mini"配置完成之后启动服务。这个过程会打印一些启动日志,看到类似 MCP server 已监听 stdio 的提示就说明启动成功。要特别提醒的是,MCP Server 默认走的是 stdio 模式,从终端启动后它会一直占用前台,不需要额外开端口。后续把它交给 Claude Desktop 这类客户端调用时,客户端会按配置里的命令自动拉起子进程,所以不用手动长期挂着终端。
4.3 接入 Claude Desktop 等 MCP 客户端
启动好 Server 只是第一步,真正的“接上”发生在客户端一侧。以 Claude Desktop 为例,它的配置文件是 claude_desktop_config.json,通常在用户目录下的配置文件夹里。在里面加入 mcpServers 节点,指定你刚才启动服务的方式就行。官方维护的 graphiti-mcp 支持用 uvx 一键启动,配置可以写成这样:
{ "mcpServers": { "graphiti-memory": { "command": "uvx", "args": [ "graphiti-mcp" ], "env": { "NEO4J_URI": "bolt://localhost:7687", "NEO4J_USER": "neo4j", "NEO4J_PASSWORD": "testpassword123", "OPENAI_API_KEY": "sk-你的key" } } } }配置保存后重启 Claude Desktop,在对话界面应该能看到多了一个工具集合。我在实测里会先问一句“你现在有哪些记忆相关工具”,模型会自然地告诉你它可以在需要时调用记忆写入和搜索功能。这意味着记忆不再是后台的“隐藏功能”,而是模型主动可用的工具栏。这一步很重要,因为 Agent 是否“想起来去查记忆”,决定了长期记忆系统是否真正生效。
4.4 记忆工具化的调用设计与落地套路
工具接入之后,真正决定成败的是“什么时候写入、什么时候搜索”。我在实践里总结了一套比较稳的规则。写入的时机:用户明确表达偏好、给出关键业务约束、交代任务背景、做出状态变更时,都应该触发写入。搜索的时机:用户提到以前聊过的事、问题中涉及具体实体、需要结合历史信息回答时,必须触发搜索。你可以利用 MCP 的现有工具,把“写入记忆”和“搜索记忆”操作设计成 Agent 可调用的两步动作,让模型在每次回答前自主决定是否查询。
有一个细节很容易踩坑:不要把所有对话都无脑写进记忆。信息噪声会直接拉低后续检索精度,还会浪费 token。我在项目里会在对话链路中加一层“记忆写入意图判断”,只有命中规则的信息才允许调用写入工具。比如说,“我喜欢简洁的回答”值得记,“今天天气不错”就不值得记。这类规则可以通过提示词约束,也可以通过前置的轻量分类模型过滤。从结果看,精选写入比全量写入的检索命中率高出一大截。
5. 踩坑指南与常见问题排查
5.1 连接与启动类问题
最常遇到的是 Neo4j 连接失败。报错信息一般是指向 bolt://localhost:7687 连不上,这时先确认容器是否正常启动,再确认端口映射是否被占用。另一个隐蔽坑是 Neo4j 默认只有本机能访问 Bolt 端口,如果 Agent 跑在容器里,需要把地址改成 host.docker.internal 一类的宿主机地址,这个我在团队联调时踩过。还有一次折腾了半天,最后发现是密码里带了特殊字符,bash 解析时被转义了,导致认证失败。建议密码只使用字母和数字,省去转义麻烦。
5.2 记忆写入质量类问题
实体抽取是影响整个系统质量的核心环节。如果发现图谱里的节点很乱、关系不对,大概率是抽取时模型没有充分理解上下文。我有两个优化方向:一是把写入工具的提示词写细,明确告诉模型要抽取哪些类型的实体和关系;二是更换更擅长结构化输出的模型,比如指令遵循能力更强的模型。还有一个技巧,就是让 Graphiti 在写入前先把原始内容切分成更小的 Episode,一次只处理一个完整事件,抽取准确率明显更高。
5.3 检索效果类问题
检索不到相关内容是第二个高频问题。这里有个容易忽略的点:Graphiti 的搜索是“向量召回加图谱拓展”,如果你写入的内容本身没有形成有效的关系边,后面的图遍历就无图可拓。所以写入质量直接决定搜索质量。如果搜索时发现结果太少,可以先在 Neo4j 的浏览器界面里看看图谱长什么样,是不是实体没有正确连接。如果图谱稀疏,就要回到写入环节,优化抽取而不是调搜索参数。
5.4 成本与性能优化
记忆系统的开支主要集中在 LLM 调用上,尤其是每次写入都要做实体抽取、每次搜索都要做语义嵌入。为了控制成本,我建议在非高峰场景使用更小的模型做抽取,搜索时限制返回实体数量。并发方面,MCP Server 本身是单实例服务,如果 Agent 需要扛大量并发访问,记忆服务应该独立部署并考虑多实例。一个小经验:把记忆相关的 MCP Server 和主对话服务的超时时间区分开,记忆操作宁可慢一点也要避免主链路被拖垮。
最后分享一个我自己的感受:给 AI Agent 接长期记忆这件事,真正难的从来都不是“存进去”,而是“取出来时正好有用”。Graphiti 把双时态、Episode、图搜索这些复杂机制封装进 MCP Server 之后,我从业务代码里解放出来,反而有更多精力去设计“哪些该记、何时该查”。如果你也在做 AI Agent 的长期记忆方案,建议不要上来就自己造轮子,先基于 Graphiti MCP Server 把闭环跑通,再根据实际效果调整写入规则和检索策略。这一套做下来,你的 Agent 才算真正从一个“每次都要重新认识你的陌生人”,变成了一个“越用越懂你的老搭档”。