先搞清楚三者的关系

LLM 是大脑,pi-mono 是身体,OpenViking 是海马体。

LLM 负责推理和决策,但天生无记忆——每次对话都是失忆状态。pi-mono 是 AI Agent 框架,给 LLM 装上工具调用、任务执行等能力,让它能真正干活。OpenViking 专门解决记忆问题,负责跨 session 的持久化存储与语义检索。三者组合,才构成一个"用过就记住、下次还认识你"的完整 Agent。

核心设计:工具优先,记忆为辅

这句话背后有一个值得注意的设计取舍。

主流做法是 RAG——每次对话开始前,系统自动检索历史记忆塞进上下文,LLM 被动接收。听起来省事,但问题很明显:LLM 不知道这些记忆从哪来、是否可信、当前场景是否真用得上。记忆变成噪音,上下文窗口被无效信息占满,反而干扰推理。

pi-mono 的选择刚好相反——记忆以工具形式存在,召回这个动作本身交给 LLM 来决策。Agent 在推理过程中自己判断:"我现在需要回忆什么吗?这件事值得记下来吗?"记忆从被动注入变成主动行为,和搜索网页、执行代码在逻辑上完全对等。

这样做的好处是:召回有明确意图,保存有明确判断,记忆的质量和相关性都更高。代价是 Agent 需要足够"聪明"才能知道什么时候该用记忆工具——但这正是现代 LLM 擅长的事。这个设计很实用,把复杂的记忆管理问题转化成了 LLM 本身就擅长的工具调用问题。

架构分两层

主动工具(Agent 自行决策调用):

  • recall_memory → 语义搜索历史记忆
  • save_memory → 显式保存关键信息
  • explore_memory → 浏览记忆文件系统
  • add_knowledge → 索引本地文件/目录

被动钩子(透明自动执行,LLM 无感知):

  • before_agent_start → 建立 OpenViking session
  • session_compact / shutdown → 增量同步消息 + 触发记忆提取

底层是跑在 localhost:1933 的独立 Python 进程,通过 HTTP API 通信。

三层存储,各司其职

  • 消息自动同步:钩子在 compact/shutdown 时静默追加对话内容
  • 记忆提取:OpenViking 内部 LLM pipeline 在 commit 时自动抽取 preferences / entities / cases
  • 主动召回/保存:Agent 自己调用工具决定存取

实际效果

Session 1:用户说"我喜欢用 anyhow 做 Rust 错误处理" → Agent 调用 save_memory 保存 → 关闭 pi-mono,OpenViking 自动提取写入 viking://user/memories/preferences/

Session 2(全新进程,零上下文):用户说"帮我写个 Rust 工具" → Agent 调用 recall_memory("Rust preferences") → 搜到上次的偏好,自动用 anyhow,不过度抽象

跨 session 的偏好记忆真正生效了,不需要用户重复说明。

容错设计:记忆是增强,不是依赖

这一点容易被忽略但非常关键——OpenViking 挂了,pi-mono 照跑:

  • health() 检测失败 → 静默跳过,不注入系统提示
  • 工具调用失败 → 返回描述性文本,不抛异常
  • 所有钩子 → try/catch 吞错误,主流程不受影响

记忆层的故障不会拖垮整个 Agent,这才是生产级的设计思路。

对于想给自己的 Agent 加上长期记忆的开发者来说,这套方案的核心启发在于:与其让系统自动往上下文里塞历史信息,不如把记忆做成工具,让 LLM 自己决定何时存、何时取。项目代码在 GitHub 的 pi-mono 仓库 feat/pi-viking-memory 分支下,感兴趣可以直接看实现。