加入会话与语义记忆
持久化只追加 Transcript、限制上下文、安全摘要,并跨会话检索经过整理的记忆。
三类状态
Runifold 会刻意分开:
| 状态 | 作用 | 模型是否可见 |
|---|---|---|
| Transcript | 不可变的用户、助手与工具消息 | 只看到有界窗口 |
| Summary | 旧 Transcript 前缀的有损派生视图 | 作为带标签的上下文可见 |
| Semantic memory | 在 Namespace 中显式整理的事实 | 只有被检索时可见 |
执行 Journal 是第四种记录,但它不是会话状态。它描述 Runtime 做了什么,而不是模型 说了什么。
运行多轮会话
为每段会话指定稳定 ID,为每个租户或隔离域指定经过校验的 Namespace。Context Policy 控制最近消息窗口。
use runifold::{
ConversationContextPolicy, ConversationId, ConversationWindow,
InMemoryConversationStore, MemoryNamespace,
};
let store = InMemoryConversationStore::new();
let conversation_id = ConversationId::new();
let namespace = MemoryNamespace::parse("tenant-42")?;
let policy = ConversationContextPolicy::new(ConversationWindow::new(16)?);
let result = agent
.run_conversation(
"What did we decide?",
&run,
&store,
conversation_id,
namespace,
policy,
)
.await?;一次 Turn 通过乐观并发原子提交。调用方需要诊断并发更新时,应保留
result.conversation_version。
限制上下文
即使 Transcript 超过模型窗口,它仍保持只追加。ConversationWindow 选择最近后缀,
更旧条目进入有界 Summary Batch,不会被静默删除或改写。
run_conversation 返回 SummaryRequired 时,可以运行显式摘要工作流,或向
run_conversation_with_summary 提供可信 ConversationSummarizer。摘要生成消耗同一
Run Budget,并遵守同一取消与 Deadline。
Summary 是派生数据。更新、更长的 Summary 可以替换旧 Summary,但源 Transcript 始终是审计记录。
语义记忆
Semantic Memory 不应该保存用户说过的每句话。只整理真正需要跨会话使用的事实,附上
源 Sequence 范围,并存入相同 MemoryNamespace。
使用 policy.with_semantic_memory(limit)? 开启有界检索。命中的记忆会作为显式不可信
上下文进入请求,永远不会变成系统指令。保留、纠正与删除策略应在 Memory Store 边界
执行。
并发与存储
内存 Store 适合测试与单进程。持久化、多进程访问和语义向量记忆使用 PostgreSQL Conversation Store。
两个 Writer 可以从同一 Version 执行,但只有一个 Append 能提交。失败方会收到冲突, 同时保留已经完成的 Agent Outcome。不要自动重新调用模型:第一次执行已经消耗预算, 也可能调用过工具。
生产检查清单:
- Namespace 必须由已认证的应用身份派生;
- Window、Summary Batch 与 Memory Limit 都应有界;
- 持久 Transcript 中不能出现 System Instruction;
- 导出可观测数据前移除敏感正文;
- 测试并发 Append、Store 故障与 Summary Backlog 恢复。