☰
如何编写Raven插件:MemoryBackend契约与四源发现机制开发者完全指南
2026/9/26 4:00:34 网站建设 项目流程

如何编写Raven插件:MemoryBackend契约与四源发现机制开发者完全指南

【免费下载链接】RavenThe Harness of Harnesses: a trusted, persistent, self-evolving multi-agent ecosystem for all-domain collaboration.项目地址: https://gitcode.com/gh_mirrors/raven35/Raven

Raven 是一个可信、持久、自我进化的多智能体生态系统,而它的插件体系是扩展能力的关键:你不需要修改任何宿主代码,只要实现一套 MemoryBackend 契约、写一份插件清单,就能把自己的记忆后端接入 Raven。本文是一份面向新手的完整指南,带你快速吃透编写 Raven 插件的两把钥匙——MemoryBackend 契约与四源发现机制,并给出一份可直接落地的开发清单 🧭


🗺️ 30 秒看懂:契约 + 发现 = 免改动接入

Raven 的插件框架只有两个核心部件:

部件位置作用
MemoryBackend 契约raven/contracts/memory.py定义所有记忆插件必须实现的 8 个方法
四源发现机制raven/plugins/discover.py从 4 个来源扫描插件清单,按优先级去重

理解这两个部件,你就理解了整套插件架构。官方架构文档在 docs/memory-plugin-architecture.md,建议作为进阶读物。


📜 第一步:读懂 MemoryBackend 契约

契约是一个@runtime_checkable的 Protocol(见 raven/contracts/memory.py#L142-L332),共8 个方法,按"热路径"优先级排列:

方法何时被调用可以偷懒吗?
recall每一轮对话组装上下文时❌ 核心方法
store每轮对话结束后持久化❌ 核心方法
feedback技能被注入后回收信号✅ 允许空实现
start/stop启动 / 关闭生命周期需幂等
healthraven doctor诊断时可返回None
delete用户删除某条记忆时可返回False
recall_session子代理运行后回读其记忆可返回[]

规则一:recall的"双轨 XOR"

recall要求user_id与agent_id恰好设置一个(raven/contracts/memory.py#L166-L191):

  • 双轨后端(如 EverOS):把设置的那个 id 路由到对应存储——用户侧存"情节/画像",代理侧存"案例/技能";
  • 扁平后端(如 mem0):用user_id正常工作,收到agent_id调用时直接返回[]。

两个都没传、或都传了?那是调用方的 bug,你返回[]即可。

规则二:store只认"显式 False"

store返回bool表示这次写入是否落地。只有显式返回False才算写入失败——宿主会据此带退避重试;而返回None等假值会被当作"已落地"。所以请谨慎处理返回值。另外,metadata中有两个值得尊重的约定键:

  • flush: True:对话已结束,立即从切片中提取,别等自己的提取周期;
  • user_id/agent_id:仅代表本次调用为谁写入(子代理场景),不要当成默认身份。

规则三:失败契约——宿主会替你兜底,但别依赖它

宿主(AgentLoop、TUI、网关、raven serve)会把每次调用的异常当作"丢失这一次调用":recall计为无命中、store计为未落地、start失败则本会话没有长期记忆。能识别的失败(超时、连接被拒)应尽量自己捕获并降级,返回空结果比抛异常更优雅。


📦 第二步:写好raven-plugin.toml清单

清单是发现机制唯一的"入口",解析规则在 raven/plugins/manifest.py。最小可用的记忆后端清单长这样:

[plugin] id = "my-memory" version = "1.0.0" [[plugin.contributes.memory_backends]] name = "mybackend" factory = "my_package.backend:make_backend"

三个容易踩的坑 ⚠️:

  1. factory必须是module.path:callable格式,写错会在启动时立刻报错(这是好事,好过激活时才炸);
  2. 后端name会成为技能命名空间(技能 id 形如<name>/<id>),所以不能含斜杠,且local、hub两个名字被保留,不能占用;
  3. 插件__init__.py必须保持空或极轻——entry-points 发现会通过资源解析导入它,重依赖放这里会违背"只读清单"的承诺。

参考一个真实成品:plugins-dist/everos-memory/raven_everos/raven-plugin.toml,它还展示了onboard(引导向导步骤)、tools(注册代理工具)和config_schema(对plugins.config配置切片做入门类型校验)三类可选贡献点。


🔍 第三步:四源发现机制如何找到你

PluginDiscovery.discover()会扫描4 个来源并按插件 id 去重(raven/plugins/discover.py#L86-L108)。来源即优先级,数字大者胜出:

优先级来源位置适用人群
4BUNDLED随 Raven 分发的内置目录第一方插件
3USER~/.raven/plugins/<id>/本地放一个目录即用
2PROJECT./.raven/plugins/<id>/及plugins.dirs配置的目录随项目提交
1ENTRY_POINTSpip 包,entry-points 组名raven.plugins第三方分发(推荐)

两条关键设计:

  • 内置遮蔽规则:bundled > user > project > entry_points,内置插件永远不会被同名的本地/pip 副本悄悄盖掉;不同 id 的插件则和平共处,由配置项memory.backend决定激活哪一个;
  • 只读清单,永不导入:发现阶段只解析 TOML,绝不 import 后端代码。所以某个后端缺了重量级依赖(lancedb、mem0ai)也拖不垮其他后端;工厂模块只有在你选中该后端时才被导入——"默认自带"不等于"默认付出启动成本"。

选中的插件会收到一个 PluginContext(配置切片 +ServiceLocator+ 带插件前缀的 logger),你的make_backend(ctx)工厂函数只需基于它返回一个结构上符合MemoryBackend的对象。身份 id(user_id/agent_id)统一由宿主经ctx.services下发,不要从自己的plugins.config切片里另读一份——两处存同一个值,就是"改了一边、读写永久分裂"事故的根源。


✅ 第四步:上线前检查清单

  • 8 个方法齐全,recall/recall_session遵守 XOR 规则,neither/both 时返回[]
  • store仅在明确失败时返回False,传输/鉴权错误不抛异常
  • start幂等,且recall/store能容忍在start未完成时被调用(答"无命中/未落地"即可)
  • stop可在start失败后安全调用
  • health如实报告:只有真故障才是missing,"按需启动、尚未运行"应报ok加提示
  • 清单 id/version 齐全,name不含斜杠、不占用保留名
  • 包__init__.py保持空/轻

跑通测试再发布:

uv run pytest tests/test_memory_backend_protocol.py tests/test_memory_backend_contract.py -q

契约测试与发现测试分别在 tests/test_memory_backend_contract.py 和 tests/test_everos_plugin_discovery.py,可作为编写自家后端的活模板。


📚 延伸阅读

资料说明
raven/contracts/memory.py契约全文,注释即最佳实践
raven/plugins/discover.py四源扫描与冲突消解实现
raven/plugins/bootstrap.py发现 → 激活的一站式装配
docs/memory-plugin-architecture.md完整架构设计与 mem0 接入示例

掌握了契约与发现机制,你离"给 Raven 装上一个自己设计的记忆"只差一个make_backend的距离 🚀

【免费下载链接】RavenThe Harness of Harnesses: a trusted, persistent, self-evolving multi-agent ecosystem for all-domain collaboration.项目地址: https://gitcode.com/gh_mirrors/raven35/Raven

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询