🔌 第7章 MCP开发进阶
📄 一句话概括

记忆不是上下文。上下文随对话结束消失,记忆存在库里,换模型、换宿主都还在。 把记忆做成 Server 之后,两个客户端读到的是同一份东西——共享的是存储,不是会话。 共享之后立刻出现三个问题:谁写的、谁能读、怎么删。

📝 本章和前面几章的关系

这一节是第 7 章的收尾,也是全书从「协议」转向「应用」的过渡。 教材这一节讲的是 OpenMemory 这个开源项目:部署一个服务,把记忆集中存起来。 这台机器上跑不了它的完整部署(要 Docker、要容器),但它的机制可以在纯 Python 里真跑。

一、记忆不是上下文

上下文是这一次对话的请求里带的东西。对话结束,它就没有了。 记忆在一个能持久存的库里。你不删它,它就一直在。 差别不只是「活多久」。上下文有上限、还要算 token;记忆只受存储限制。上下文只有这一轮看得见; 记忆所有连上来的客户端都看得见。

把记忆做成 Server 之后,换一个宿主、换一个模型,记忆还在。 这是它和「把对话历史塞回提示词」最本质的区别:前者是外存,后者是每次重新搬一遍。

二、两个客户端,共享的是存储

演示里客户端 A 连上、客户端 B 连上,两个都连同一个 Server。 A 写两条:「用户偏好答复要短」「项目代号叫朱雀」。 B 完全不知道 A 说过什么,直接问「朱雀」,拿到了 A 写的那条;再列全部,两条都在。

B 拿到的是 A 写的内容。【因为记忆不在连接里,在文件里】。 这一句就是「共享记忆」的全部机制:共享的是存储,不是会话。 会话还是各自独立的。

三、共享之后,三个问题立刻出现

第一,谁写的。两条记忆打架时信谁?所以每条要带来源和时间。 第二,谁能读。换个用户连上来也能看全量——这一条最容易被忽略。 第三,怎么删。记错了要能撤,所以每条要给一个 id,支持删除。

第二个问题的严重性:一个团队共用一个记忆 Server,等于所有人都能读到所有人的笔记。 所以要共享就得先想清楚粒度:按人、按项目、还是按组织。 写权限和读权限要分开给,这是第 3 章那道闸在这里的复用。

四、部署要做的三件事

数据放哪:挂一个卷,别放在容器里。不然重启一次记忆全丢。 备份:定时拷走那个 json 或者那个库。删错一条就找不回来。 并发:多客户端同时写要加锁。后写的会覆盖先写的。

第三条在这个演示里没暴露,因为两个客户端是先后写的。真并发了,读写同一个 json 一定会丢数据。 所以上线前换成正经数据库。json 文件适合验证机制,不适合装真数据。

五、教材里的 OpenMemory 是什么

它是一个开源项目,把记忆做成一个独立的服务:有存储、有接口、有多个客户端接进来。 部署方式照教材是跑容器(本沙箱不执行,这里没有 Docker):拉镜像、配一个存储路径、起服务、 拿到一个地址,然后在宿主里把这个地址配成 MCP Server。 判据是三步:服务起来之后能访问健康检查、宿主里能看到它的几个工具、在一个客户端里写一条、 换另一个客户端能读到。

第三步才是它存在的意义。 前两步只是「装上了」。 这一章到这儿结束。下一章开始全是案例:先在 IDE 里用别人的 Server,再自己搭智能体。

六、动手 Demo:把记忆做成一个 Server

先分清上下文和记忆,再把记忆做成一个最小的 Server:一个 json 文件、三个工具。 然后让两个客户端连上去,A 写、B 读,看「共享的是存储不是会话」。 最后说清真并发下会发生什么——这一段这个演示里没暴露,得单独讲。

# 一、记忆就是一个 json 文件加三个工具
def add(a):
    db = load()
    db.append({'id': len(db) + 1, 'text': a['text']})
    save(db)
    return {'total': len(db)}


# 二、两个客户端连同一个 Server
a = Stdio('mem.py')      # 客户端 A
b = Stdio('mem.py')      # 客户端 B,另一个进程、另一条连接
a.call('mem.add', {'text': '用户偏好:答复要短'})
a.call('mem.add', {'text': '项目代号叫朱雀'})
print(b.call('mem.search', {'keyword': '朱雀'}))   # B 读到了 A 写的

# 三、两个进程同时写同一个文件,后写的覆盖先写的
print('并发写同一个 json 会丢数据,上线要换成数据库')

实跑输出:

--------------------------------------------------------------------
把记忆做成一个 Server
--------------------------------------------------------------------


  ① 记忆不是上下文
  --------------------------------------------------------------------

|  | 上下文 | 记忆 |
|---|---|---|
| 存在哪 | 这一次对话的请求里 | 一个能持久存的库 |
| 活多久 | 对话结束就没了 | 你不删它就在 |
| 谁能看 | 只有这一轮 | 所有连上来的客户端 |
| 多大 | 有上限,还得算 token | 只受存储限制 |

  把记忆做成 Server 之后,【换一个宿主、换一个模型,记忆还在】。
  这是它和「把对话历史塞回提示词」最本质的区别。

  ② 两个客户端连同一个 Server
  --------------------------------------------------------------------
  客户端 A 连上:mem-mcp
  客户端 B 连上:mem-mcp

A 写两条:
  用户偏好:答复要短              -> {"total": 1}
  项目代号叫朱雀                -> {"total": 2}

B 完全不知道 A 说过什么,直接问:
  mem.search(朱雀) -> ["项目代号叫朱雀"]
  mem.all         -> ["用户偏好:答复要短", "项目代号叫朱雀"]
  B 拿到的是 A 写的内容。【因为记忆不在连接里,在文件里】。
  这一句就是「共享记忆」的全部机制——【共享的是存储,不是会话】。

  ③ 共享之后,三个问题立刻出现
  --------------------------------------------------------------------

| 问题 | 具体表现 | 怎么办 |
|---|---|---|
| 谁写的 | 两条记忆打架时信谁 | 每条带来源和时间 |
| 谁能读 | 换个用户连上来也能看全量 | 加用户标识,读写都过滤 |
| 怎么删 | 记错了要能撤 | 给每条一个 id,支持删 |

  第二个最容易被忽略:【一个团队共用一个记忆 Server,等于所有人都能读到所有人的笔记】。
  要共享就得先想清楚粒度:按人、按项目、还是按组织。
  ! 第 3 章讲的最小权限,在这里同样适用——写权限和读权限要分开给。

  ④ 部署要做的三件事
  --------------------------------------------------------------------

| 事 | 做什么 | 漏了会怎样 |
|---|---|---|
| 数据放哪 | 挂一个卷,别放在容器里 | 重启一次记忆全丢 |
| 备份 | 定时拷走那个 json 或库 | 删错一条就找不回来 |
| 并发 | 多客户端同时写要加锁 | 后写的覆盖先写的 |

  第三行在这个演示里没暴露,是因为两个客户端是先后写的。
  【真并发了,读写同一个 json 一定会丢数据】——上线前换成正经数据库。

①第一张表四行,讲的是上下文和记忆的四条差别。 最实用的是最后一行:上下文有上限还要算 token,记忆只受存储限制。 ②第二段是本节的核心证据:B 完全不知道 A 说过什么,却读到了 A 写的内容。 因为两个进程读的是同一个文件。 ③第三段那三个问题里,第二个最容易被忽略。 一个团队共用一个记忆 Server,等于所有人都能读到所有人的笔记。 ④第四段三件事,第三件在这个演示里没暴露。 没暴露不等于不存在——两个客户端先后写当然不冲突,同时写就丢数据。 ⑤最后一句是这一节的落点:json 适合验证机制,不适合装真数据。

30 秒实验

  1. 把演示里的两个客户端改成同时写,看会不会丢数据。想清楚为什么会丢。
  2. 给每条记忆加一个来源字段,再想一个「两条打架时信谁」的规则。
  3. 列出你希望 AI 长期记住的三件事。想一下它们该按人存、按项目存、还是按组织存。

常见误区

  1. 「记忆就是把聊天记录留着。」聊天记录是上下文的一部分,会算 token、有上限。 记忆是外存,按需检索。
  2. 「共享记忆等于共享会话。」共享的是存储,会话还是各自独立的。 B 读得到 A 写的内容,但看不到 A 的对话。
  3. 「存在一个 json 里就够用了。」验证机制够用,装真数据不行。多客户端并发写必然丢数据。
自测三问(点开对答案) 1. 记忆和上下文最本质的差别是什么? —— 上下文随对话消失、有上限、要算 token;记忆存在库里,换宿主换模型都还在。 2. 两个客户端共享记忆,共享的到底是什么? —— 存储,不是会话。它们读同一个文件,但各自的对话历史互不可见。 3. 为什么说「团队共用一个记忆 Server」有风险? —— 所有人能读到所有人的笔记。共享之前要先定粒度,读写权限分开给。

原理和开发两部分到此结束。下一章开始全是用例:在 Cline 和 Trae 里,用别人写好的 Server 干真活。

相关笔记