尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Friend 通用记忆运行时架构解析:canonical Short-term → Long-term 全生命周期与原子准入机制

Friend 通用记忆运行时架构解析:canonical Short-term → Long-term 全生命周期与原子准入机制 Friend 通用记忆运行时架构解析canonical Short-term → Long-term 全生命周期与原子准入机制【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/FriendFriend开源版 omi项目将「记忆Memory」定义为区别于会话与任务工作流的独立产品域。backend/docs/canonical_memory_architecture.md是这一领域的运行时架构权威文档它规定所有已认证账号共用同一套记忆与任务逻辑canonicalmemory_items拥有全部新写入与生命周期迁移的权威而历史users/{uid}/memories行仅通过一个有界、只读的历史适配器原地可读因此通用可用general availability不需要任何账号回填。读完本文你将掌握记忆从「捕获」到「原子准入」再到「统一读取」的完整链路MemoryService统一仓储如何合并双物理格式TTL 审计、consolidation 路由与维护作业的调度机制以及全局运维开关与回滚底线。文中所有关键结论均可在本仓库源码与测试中逐行验证。一、生命周期全景一次捕获、一条终端路由、一次原子准入文档开篇用一张 ASCII 流程图概括了整个记忆运行时。将其翻译为文字即Conversation、显式记忆、导入、API、插件、集成六大来源 │ ▼ canonical Short-term 捕获新摄入一律入层 │ ▼ 必需归一化 → TTL 审计 / 到期裁定 │ ▼ 每个 pending 条目有且仅有一条终端 consolidation 路由 ├── promote提升→ 原子 Long-term 准入回执 图断言 item commit operation 投影/向量 outbox ├── archive / review归档 / 复核 └── reject拒绝→ 默认访问之外 │ ▼ 通用读取 canonical 条目 保留的历史适配器 → 策略 → 稳定 ID 去重三条核心所有权原则值得单独强调原文即如此表述广泛捕获只产生 Short-termConversation 提取、显式首方记忆、导入、API、插件、集成写入全部先落 Short-termconsolidation 拥有唯一的终端路由pending 的 Short-term 只能经由promote / archive / review / reject四选一被裁定原子 apply 事务拥有状态派生 provider关键词索引、向量库、图谱永远不拥有记忆它们只是可重试的投影。二、统一仓储一个权威、两个物理格式所有已发布的 REST、chat、agent、MCP、developer、tool、integration、export 与账号生命周期接口最终都进入MemoryServicebackend/utils/memory/memory_service.py约 4000 行的路由缝实现。服务在返回前合并三路来源canonical 条目—— 权威来源拥有记忆策略历史行—— 经适配器转换为发布响应模型不改写持久化的历史覆盖/墓碑override/tombstone—— 用于抑制已物化或已删除的历史副本。合并规则非常明确same-ID 冲突时 canonical 获胜合并完成后应用单一的可见性、生命周期、设备、锁定记忆、排序与分页策略一个 UID 列表、注册文档、客户端 header 或物理存储永远不能选择不同的产品路径。这意味着某账号走旧逻辑、某账号走新逻辑的按用户分流时代已经结束——这是文档中反复强调的通用存储universal repository语义。领域词汇速查承接 domain model配套的 backend/docs/memory/domain_model.md 是 canonical 词汇的唯一权威WS-A其中的三个层次定义如下术语含义生命周期默认可见Conversationusers/{uid}/conversations的持久会话记录processed transcript、structured、apps_results位于记忆上游in_progress → processing → completed展示在 Conversations 页而非 MemoriesShort-termLayer 1广泛新摄入layershort_term保留来源证据voice 路径evidence[].source_id Conversation idTTL 是裁定截止期限恰有一条 consolidation 路由裁定符合条件的可见仅到 TTL 不会隐藏未裁定条目Long-termLayer 2持久化合成的实事如姓名是 David Zhang、定居西雅图layerlong_term仅promote路由含服务端准入回执 逐条图断言可进入可老化到 Archive可见Archive老化退出的 Long-termlayerarchive或终态保留供回忆终态除非显式重新浮现否仅显式 opt-inWorkflowaction_items、goals不是记忆层它与 Memories 同缝提取但独立存储任务/目标行永远留在 workflow 域。Conversation 与 Memory 的边界由 backend/tests/unit/test_upstream_boundary.py 强制校验。三、捕获与原子 applyquote 接地、pending 回执与单事务落库3.1 捕获规则所有新摄入都是 canonical Short-term。显式写入可以向首方记忆列表返回pending 回执受保护的 chat、agent、MCP、developer 与搜索消费者在必需处理required processing完成前排除 pending 原始文本。Conversation 提取有一条硬性校验每个 quote 引用必须先落在一个 transcript segment 上才能进行来源替换。失败则保留先前状态一次合法但结果为空的替换会完全撤回先前来源所拥有的 cohort。文档还明确了 L1 提示broad L1 prompt的排除项未识别的非主要说话者、自我设限式归因self-hedging attribution、泛化的产品/公司描述——除非它们表达的是主人的决策、偏好、约束、计划或承诺。具名人物与已知关系角色仍保留入选资格。3.2 拒绝反馈的闭环主人的拒绝不是仅抑制而是有界的负反馈。提取阶段会接收来自活跃来源、最近 30 天内、最多8 条最新的非受限 active 或 terminally hidden 拒绝优先级为 user-message位于共享会话缓存断点之后consolidation 在 volatile 批量上下文中收到同一份集合一次不依赖被拒条目的向量邻居——因为被拒条目已从向量投影中移除。prompt-safe 集合在进程内缓存 5 分钟并在任何记忆变更时失效。3.3 原子 apply 事务backend/database/memory_apply_store.py约 2900 行是原子持久化层。它在一个 Firestore 事务内同时推进UID / 账号 / 来源代际栅栏account/source-generation fences幂等性栅栏idempotency fencescontrol/head、item、commit、operation journal、图断言、投影/向量 outbox 状态。事务开头还有一道全局部署栅栏_require_canonical_intake_enabled()读取MemoryRolloutMode仅当模式为write或read时才放行否则抛出CanonicalMemoryIntakePausedErrorcanonical memory intake is globally paused。这与文档全局 incident/readiness 开关的定位完全一致。四、惰性历史迁移不批量回填、逐条确定性物化历史数据不做批量迁移。当一条仅存在于历史存储中的记忆被编辑、复核、重新打标、归档或删除时服务按固定顺序执行四步校验历史行与请求以相同的公开 ID写入 canonical 表示提交一条 active override 或 tombstone尽力清理过时的历史行/向量best-effort。关键设计点在步骤 3 与 4 的顺序上抑制记录先于清理提交因此重试、崩溃或 provider 故障都不会导致重复读取或复活读取。该路径不做任何 LLM 调用、不做通用重嵌入批量操作在第一次变更前预先校验。这是文档与 domain model 中Q2一个权威、两种物理格式与Q4无通用回填两项决定性结论的直接落地。历史行被物理保留、读取是纯的list/fetch/search/export 均不改写行只在被寻址变更时才确定性物化。五、维护作业与 Long-term 准入内存扫描、四路路由与排水5.1 调度与扫描范围专用memory-maintenance-job入口在 backend/modal/memory_maintenance_job.py编排核心在 backend/utils/memory/canonical_short_term_maintenance_cron.py清点有界的 canonical pending 工作——不是从 allowlist 取用户、也不是无界全表扫描。常量可见其有界性MAX_MAINTENANCE_UIDS_PER_RUN 400单次最多 400 个 UIDEXPIRY_ADJUDICATION_LOOKAHEAD DEFAULT_SHORT_TERM_TTL / 2TTL 前半个 TTL 即进入裁定前瞻窗口每次运行 6 步① 通过仅生命周期元数据的查询优先处理 TTL 最后 24 小时的 UID独立于 registry 游标与每用户冷却② 排空先前已提交的 outbox 工作③ 归一化必需提交④ 裁定 TTL 到期⑤ 向canonical_consolidation.py请求按条目寻址的 partitionpromote / archive / review / reject⑥ 经 canonical apply 提交各路由并排空新 outbox 工作。5.2 consolidation 是唯一提升通道backend/utils/memory/canonical_consolidation.py约 2300 行明确写道确定性代码取候选、水合 active memory_items、组装 LLM 上下文单一批量 LLM agent 是 consolidation 结果的唯一裁决者决定经apply_long_term_patch_firestore提交。只有 consolidation 能签发 Short-term → Long-term 转换所需的promotion 回执。无效/部分模型输出不产生任何变更。以下机制共同防止毒行poison-row饥饿与重复 LLM 成本revision-scoped attempts修订作用域的尝试leases租约CONSOLIDATION_ATTEMPT_LEASE_SECONDSbounded retries有界重试review quarantine复核隔离scan cursors扫描游标。到达 TTL 本身不是一条路由只要 canonical apply 尚未记录终态裁定active Short-term 条目仍然默认可读。这防止一次错过的维护执行在到期队列仍在优先处理该条目时静默删除记忆。5.3 Knowledge-ledger 账号切换独立于维护knowledge-ledger-drain-job不属于这条串行维护通道每次小时执行最多读取20 个canonical apply-control 文档使用自己的代际栅栏游标每次账号/行变更前重查共享 JIT rollout 权威缺失权威则 fail-closed只有complete-union proof成功后才会发布切换。因此维护超时不会饿死 writer 模式收敛被 kill 的 drain 执行或任一账号失败不会推进其分页游标。部署通道会在创建/恢复小时触发器前授予调度服务账号对该 job 的run.invoker权限。5.4 文本无关的决策遥测canonical_memory_decision_path.v1日志实现在 backend/utils/memory/decision_path_telemetry.py按 UID 与 memory ID 关联捕获机制与接地归因到后续已应用或已阻止的路由。它只发射分类决策字段与计数——绝不含 transcript、quote、memory 或模型理由文本例如classify_model_about()将模型about字段规约为primary_user/source_speaker/unidentified_non_primary_speaker/named_person_role_or_entity等非 PII 聚合 token。六、搜索、图谱与投影候选永不越权关键词/向量 provider只返回候选每个结果在返回前都要通过统一权威读取器水合hydrate。因此即使 provider 清理滞后restricted、archived、superseded 与 tombstoned 条目依然被排除。用户复核user review保持同一追加式边界恢复一条被 superseded 的knowledge_ledger.v1事实不会重开或改写其历史行。认证 memories API 沿所选事实的有界后继链走到当前事实再追加一条带 retry-stable 显式用户证据的新替换。畸形、跨身份、受限、锁定或不再当前的链fail closed。独立的封闭knowledge_ledger.v1事实无后继链但显式用户重开可通过同一 apply 边界追加一条新的当前尾源行保持封闭不可变。projection_sync与vector_syncoutbox 事件是重试权威消费端见 backend/database/memory_outbox_worker.py事件 payload 只携带栅栏与意图绝不作为记忆内容来源写入前始终重载 canonical Firestore 条目restricted 条目只可删除其内容永不进入关键词/兼容性/嵌入/向量 providermemory_graph_assertions/{memory_id}是图谱权威保留的历史图谱数据只是有界读覆盖层不能准入或变更记忆。七、隐私、导出与删除双格式统一关闭单条 / 批量 / 默认 / 全删delete-all、来源替换、导出与账号删除都通过统一服务同时闭合两种物理格式canonical tombstone 与历史 override tombstone立即使数据从读取中消失外部 provider 清理可异步完成导出对每条存活逻辑条目恰好发出一次账号代际栅栏防止旧租约复活一个被重建的账号。canonical delete-all 使用有界 tombstone 事务 受控重扫循环只有观察到稳定的非 tombstone 空集才算成功并发写入会返回错误而非部分成功。canonical 账号删除由持久化的顶层 wipe 记录围栏围栏激活期间普通投影投递变为只删模式。八、运维边界与回滚底线8.1 全局开关无按用户开关控制项拥有者含义MEMORY_MODEbackend maintenance manifests全局就绪/incident 声明绝不是用户选择器MEMORY_CANONICAL_MAINTENANCE_ENABLEDmemory-maintenance-job专用启用计划 Short-term 归一化、TTL 审计、consolidation 与 outbox 排空MEMORY_CANONICAL_CONSOLIDATION_ENABLEDmaintenance job全局 L2 成本/incident 开关必需处理、TTL 审计与 outbox 所有权保持独立consolidation batch/candidate capsmaintenance job限制单次 L2 调用与单次 passKNOWLEDGE_LEDGER_DRAIN_ENABLEDknowledge-ledger-drain-job显式运维门dev/prod manifest 默认关闭KNOWLEDGE_LEDGER_DRAIN_UID_ALLOWLISTknowledge-ledger-drain-jobdev 保留一名 QA owner 供显式覆盖生产为空。是安全围栏不是产品注册ledger drain page cap/cursorknowledge-ledger-drain-job每次小时运行最多扫描 20 个 apply-control 文档页内账号全部无错完成才推进游标文档明确不存在MEMORY_ENABLED_USERS运行时绑定也不存在产品注册命令MEMORY_ENABLED_USERS与代码内置的按用户记忆清单已被退役运行时校验会拒绝重新引入按用户记忆清单。8.2 回滚底线统一双格式读取器不可回退统一双格式读取器是回滚地板rollback floor。运维可全局停止新的 canonical 处理但不得回退到仅历史读取器——那会隐藏新 canonical 数据物理历史删除需要单独的、有证据支撑的审批部署顺序摘自 backend/docs/runbooks/universal-memory-operations.md先跑 hermetic 管线与兼容性契约 → 在非生产项目用两类合成账号仅历史、仅 canonical、混合验证逻辑 ID/排序/去重/跨 UID 隔离 → 验证维护作业与 Scheduler 身份/节奏 → 验证 drain job 独立性与run.invoker→ 演练全局停止与恢复路径并记录 revision/镜像摘要/计数器 →先部署统一读取器再启用生产 canonical 摄入且不加 canary UID 或注册文档。8.3 内容无关的可观测性记录只计数canonical 行返回数、历史行返回数、canonical-over-historical 抑制数、override/tombstone 抑制数、畸形历史行数、游标失败、pending/terminal 维护行、outbox 滞后/死信、历史清理失败。绝不记录记忆内容、嵌入或 provider payload。低基数字段包括memory_universal_read_origin_total{origincanonical|historical}memory_historical_suppression_total{reasoncanonical_identity|canonical_state}memory_historical_materialization_total{outcomenot_needed|committed}告警聚合时同样不得带 UID、memory ID 或内容标签。九、主缝一览Primary seams文档结尾给出的代码映射是全篇的索引可直接用于深入阅读关注点代码统一服务backend/utils/memory/memory_service.pycanonical 适配器backend/utils/memory/canonical_memory_adapter.py历史覆盖路径backend/database/memory_collections.py原子持久化backend/database/memory_apply_store.py必需处理backend/utils/memory/canonical_required_processing.py终端路由backend/utils/memory/canonical_consolidation.py计划编排backend/utils/memory/canonical_short_term_maintenance_cron.pyOutbox 投递backend/database/memory_outbox_worker.py公开 APIbackend/routers/memories.py补充三处可佐证深度的源码事实合法状态组合校验器is_legal_state_combination()与assert_legal_state()实现在 backend/models/memory_domain.py——short_term允许全部processing_statelong_term/archive仅允许processedarchive永不superseded物理statushidden经physical_status_to_record_status()边界映射为 canonicaltombstoned。归一化必需处理用户/API/MCP/插件create_memory调用立即可读为 Short-term但在 backend/utils/memory/canonical_required_processing.py 归一化断言并附加可审计回执前不具备提升资格。维护幂等性backend/modal/memory_maintenance_job.py 明确 Scheduler 与手工执行可能重叠但 required 归一化、TTL、total L2 routing 与租约投影 outbox 投递均设计为幂等outbox_delivery_failed与cursor_persist:被标记为致命错误fail the job而 Flex stop 不重试该页。十、结语Friend 的通用记忆运行时回答了记忆系统设计中三个最难的问题谁能写只有 canonical apply 事务、历史怎么办只读适配器 惰性物化无回填、回滚怎么办双格式读取器永不离场。如果你要理解这套系统建议按生命周期图 → 统一仓储 → 原子 apply → 维护作业 → 运维开关的顺序阅读若要改代码则以本文第九节的主缝一览为入口逐模块对照 domain_model.md 的词汇表与合法状态矩阵避免重新引入被明确退役的 L1/L2、tier、MEMORY_ENABLED_USERS等旧概念。【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表