KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA

03. 一条记忆怎样才算完整? — keel 龙骨

现在你已经知道什么可能值得保存,但“用户偏好中文”还不是一条完整的工程记录。只保存正文,未来会出现三个无法回答的问题:它属于谁?为什么相信它?什么时候应该停止使用?

现在你已经知道什么可能值得保存,但“用户偏好中文”还不是一条完整的工程记录。只保存正文,未来会出现三个无法回答的问题:它属于谁?为什么相信它?什么时候应该停止使用?

这一章建立一个数据契约。数据契约不是为了让结构看起来复杂,而是为了让不同模块对同一条记忆有一致理解。

1. 先从一条不完整的记录开始

{
  "content": "用户希望故障报告使用中文"
}

它缺少很多关键信息:

所以一条可治理的记忆至少需要下面几组字段。

2. 记忆记录的五组字段

内容:系统究竟要记住什么

content 应该是一条清楚、短小、可以独立理解的事实,而不是整段聊天记录。把“用户说以后都用中文”压缩为“用户偏好中文回答”后,未来检索和上下文装配都更稳定。

作用域:谁拥有、谁可以读取

作用域(scope)是访问边界,不是模型生成的内容。最小实践通常包括:

tenant_id = acme
owner_id  = user-123

查询时先按作用域过滤,再计算相似度。不能先在全库找到最相似结果,然后才想起检查用户身份。

来源:为什么系统相信它

来源(provenance)至少要说明来源类型和来源 ID:

source_type = user_message
source_ref  = conversation-456/message-7

“用户确认过”“工单系统提供”“模型从对话中推断”是不同可信等级。来源还让你能够解释和撤回一条记忆。

生命周期:它现在是什么状态

至少需要:

过期不是数据库故障,而是信息本身的有效性结束。比如服务负责人可能每季度变化,情景记忆可能只在事故复盘期间有用。

质量和保护:怎样使用它

confidence 表示抽取系统对候选的把握,不能被解释成事实为真的概率;importance 表示未来可能的用途;sensitivity 表示需要怎样保护。它们都应该由策略层重新检查,不能把模型填的数字当作事实。

3. 用一个表查看完整记录

字段 示例 由谁提供
memory_id mem_123 存储层
tenant_id acme 认证后的 Harness
owner_id user-123 认证后的 Harness
kind semantic 模型候选 + 策略复核
content 用户偏好中文回答 抽取器,随后校验
source_type user_message 运行时
source_ref message-7 运行时
confidence 0.92 抽取器,不能单独授权
status active 存储层
version 1 存储层
expires_at null 或时间 策略/业务规则
embedding 向量索引 embedding provider

最后一行尤其重要:embedding 是从正文派生出来的索引,不是真相本身。模型变化、索引损坏或删除时,向量都应该能够重建或清理。

4. 候选和记录不是同一个对象

你可以把它们理解为“申请表”和“正式档案”:

MemoryCandidate  = 模型提出的申请
MemoryRecord     = 通过策略、带有可信元数据的正式记录

候选可以包含 reason,但它不能决定 owner_id、审计操作者、状态或真实来源。返回一个候选只表示“值得进入策略评估”;返回空列表表示没有合适候选。正式记录由应用代码把候选和可信运行上下文合并后生成。

5. 练习:检查一条记录是否足够

下面两条记录哪一条更适合进入生产存储?为什么?

{"content": "用户喜欢中文"}
{
  "memory_id": "mem_123",
  "owner_id": "user-123",
  "kind": "semantic",
  "content": "用户偏好中文故障报告",
  "source_type": "user_message",
  "source_ref": "msg-7",
  "status": "active",
  "version": 1,
  "updated_at": "2026-08-21T10:00:00Z",
  "expires_at": null
}

第二条仍然不一定可以直接使用:它还需要租户、敏感度、确认状态和权限策略。但它已经具备了可追踪、可更新和可隔离的基础。

下一章会暂时把模型放在一边,使用这个契约完成真正的保存、读取、修改和删除。只有亲手看过生命周期,后面接入 Ollama 才不会变成“把 JSON 塞进数据库”。

下一章:先不用模型,手动完成记忆生命周期

进入 keel 阅读