PostgreSQL 实现 CMDC.Memory behaviour — 与 cmdc 主库
CMDC.Plugin.Builtin.EpisodicMemory Plugin 直接对接。
让 EpisodicMemory Plugin 在生产场景可用(默认 CMDC.Memory.ETS 进程退出数据丢失)。
v0.1 范围
实现 5 个 CMDC.Memory callback:
| callback | 行为 |
|---|---|
store/3 | 写入 cmdc_episodic_memories 表(按 :user_id filter 隔离) |
search/3 | 文本 ILIKE 匹配(v0.1 不含 pgvector) |
similarity_search/3 | 同上(降级为关键词搜索,行为与 ETS 一致) |
list/1 | 全表按插入时间倒序 |
delete/2 | 按 id 删除 |
多租户隔离
EpisodicMemory Plugin 通过 filters: [user_id: uid] 在 search/3 时按
ctx.user_data[:user_id] 过滤。本 backend 在 store/3 时把 data[:user_id]
落到 cmdc_episodic_memories.user_id 列,search/3 按 filters 注入 WHERE 子句。
使用
# config/runtime.exs
config :cmdc, :memory_backend, CMDCMemoryPg.EpisodicMemoryBackend
# Plugin 配置
plugins: [
{CMDC.Plugin.Builtin.EpisodicMemory,
memory_store: :cmdc_episodic, # store 参数(这里被忽略,因为 PG 不需要)
memory_module: CMDCMemoryPg.EpisodicMemoryBackend,
top_k: 3}
]多租户保护(v0.1.1+)
search/3 / similarity_search/3 在 filters 中未传 :user_id 时的行为,
由调用方通过 :on_missing_tenant opt 控制:
| opt 值 | 行为 |
|---|---|
:return_empty(默认) | 返回 {:ok, []},强制空结果防泄漏 |
:return_error | 返回 {:error, :missing_tenant_filter},严格模式 |
v0.1.0 → v0.1.1 行为变化提示:v0.1.0 注释声称"返回空列表"但代码实际 不过滤,存在跨租户读出全部记录的安全风险。v0.1.1 修复为真返空(默认)或 报错(严格)。多租户集成方升级 0.1.0 → 0.1.1 时强烈建议显式传
opts[:on_missing_tenant] = :return_error让调用栈尽早暴露漏传 user_id 的代码。
list/1(无 query 的全表枚举)保持原行为不变(用于运维 / 调试), 多租户场景应改用search/3带 user_id filter。
v0.1 明示不含
- ❌ pgvector 真语义检索 —
similarity_search/3降级为 ILIKE(v0.2 加) - ❌ Ecto Sandbox 之外的并发性能优化(v0.2 加 batch insert)
Summary
Functions
返回当前 backend 的 entry schema 版本(v0.1.2 起)。
Functions
@spec schema_version() :: pos_integer()
返回当前 backend 的 entry schema 版本(v0.1.2 起)。
0.1.2 引入 :tags :: [String.t()] 字段,但 SQL 列 default [],老数据零 ETL,
schema 版本号保持 1。tags 不算"破坏老 entry 的字段变更"。