ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Friend 记忆向量水合 Fail-Closed 不变式(INV-MEM-2):从候选 ID 到权威 memory_items 的安全检索架构解析

Friend 记忆向量水合 Fail-Closed 不变式(INV-MEM-2):从候选 ID 到权威 memory_items 的安全检索架构解析 Friend 记忆向量水合 Fail-Closed 不变式INV-MEM-2从候选 ID 到权威 memory_items 的安全检索架构解析【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/FriendFriend 是一款AI 能看见你的屏幕、听见你的对话并告诉你该做什么的端侧智能记忆产品其核心能力是让用户在检索自己过往对话与记忆时获得及时、可信的结果。本文围绕仓库不变式文档 memory-vector-hydration.md编号 INV-MEM-2展开完整讲解向量检索命中只是候选内存 ID、必须回源权威memory_items记录做投影新鲜度与访问权限校验后才能进入用户可见结果的 fail-closed 设计并结合 memory_search_gateway.py、vector_search_service.py 与向量修复 outbox 系列源码给出可复现的行为契约与实现细节。读完本文你将掌握为什么向量库只能当作候选源、一次检索请求如何被水合并过滤、每种拒绝决策如何转化为修复/清除候选以及如何用 guard 测试守住这条不变式。一、不变式背景为什么向量命中不能直接返回在 Friend 的架构中Pinecone 等向量数据库承载的是语义检索的候选索引而users/{uid}/memory_items集合才是产品记忆内容的权威来源。二者之间存在必然的时间差与不一致风险投影projection尚未提交、账号代数account generation已推进、条目被归档或删除、内容被修订——这些都会让向量索引中的 metadata 滞后甚至失配。INV-MEM-2 以locked状态锁定以下陈述向量检索命中只是候选内存 ID。每次命中必须回源权威memory_items记录进行水合hydrate并通过投影新鲜度与访问权限检查后才允许出现在用户可见结果中。缺失或过期时必须 fail-closed返回空结果或被过滤的结果同时产出修复候选绝不返回原始向量 ID。与之配套的 MUST NOT 约束包括不得在未做权威水合的情况下直接返回向量命中不得把 Pinecone/向量 metadata 当作产品记忆内容的 truth source不得在 water合拒绝某条命中时 fail-open只有访问策略拒绝而非条目缺失或过期时才允许静默丢弃且不产生修复遥测。这条不变式与 INV-MEM-1memory-tiers.md产品记忆只有short_term/long_term/archive三个层级默认访问策略为短期长期和 INV-MEM-3memory-canonical-fail-closed.md所有认证账户必须使用统一记忆权威规范状态检查失败必须 fail-closed构成记忆子系统三位一体的防御主线。二、不变式覆盖面Surface、路径 glob 与 PR 规则按文档约定INV-MEM-2 治理以下三块实现面SurfacesSurface职责仓库路径水合网关定义决策模型、命中模型与核心纯函数hydrate_and_filter_vector_hitsbackend/models/memory_search_gateway.py向量检索编排过取overfetch→ 按 ID 水合 → 刷新 → 输出结果与修复候选backend/utils/memory/vector_search_service.py向量修复 outbox 与 metadata 适配将修复候选落为可租约、可重试、可死信的清理/重建任务backend/database/memory_vector_repair_outbox.py、backend/database/memory_vector_repair_outbox_worker.py、backend/database/memory_vector_metadata.py路径 glob 为backend/models/memory_search_gateway.py、backend/utils/memory/vector_search_service.py以及backend/database/memory_vector_*.py。文档同时规定 PR 规则凡是触及上述路径的改动必须在 PR body 中署名INV-MEM-2以便评审者与 CI 挂钩。三、水合网关的数据模型决策、命中与结果memory_search_gateway.py 用 Pydantic 模型把候选命中 → 决策 → 结果全链路结构化SearchModedefault与archive_explicit两种检索模式。默认模式不返回归档内容归档检索必须显式进行。SearchDecision单条命中的裁决结果共 6 种取值——allowed、missing_authoritative_item权威条目缺失、stale_projection投影过期、stale_vector向量陈旧、access_denied访问被拒。VectorRepairPurgeReason修复/清除的原因枚举共 9 种几乎一一对应每个 freshness 检查点。SearchVectorHit向量库返回的原始命中携带memory_id、score以及用于新鲜度比对的元数据字段projection_commit_id、vector_updated_at、uid、account_generation、item_revision、source_commit_id、content_hash。HydratedSearchResult通过全部检查后的水合结果包含权威MemoryItem、score 与投影 commit ID。SearchGatewayResult最终返回结构由results用户可见结果、decisions每条命中的裁决与repair_purge_candidates修复/清除候选组成。MemoryItem权威模型定义在 backend/models/product_memory.py其中ledger_commit_id、account_generation、item_revision、source_commit_id、content_hash、updated_at等字段正是水合比对所需的真值锚点。四、核心裁决函数hydrate_and_filter_vector_hits 的检查流水线纯函数 hydrate_and_filter_vector_hits 是整条不变式的心脏。它按 score 降序遍历所有命中对每一条依次执行如下检查链任何一环失败即拒绝该命中权威条目存在性authoritative_items.get(hit.memory_id)为 None →missing_authoritative_item产出修复候选。投影 commit 新鲜度命中携带的projection_commit_id必须等于权威条目的ledger_commit_id条目未携带 ledger commit 时以调用方传入的required_projection_commit_id为准不等 →stale_projection修复原因为stale_projection_commit。向量 freshness metadata 完备性uid、account_generation、item_revision任一缺失 →stale_vector原因missing_vector_freshness_metadata权威条目有source_commit_id而命中缺失、或权威条目有content_hash而命中缺失同样判为陈旧。账号代数一致性权威条目的account_generation不等于调用方要求的required_account_generation或命中与权威条目的account_generation不一致 →stale_vector原因stale_account_generation。跨用户校验命中uid不等于权威条目uid→stale_vector原因cross_user_vector_metadata——这是防止向量索引跨用户串数据的兜底。条目修订一致性命中item_revision与权威不一致 →stale_vector原因stale_item_revision。来源 commit 一致性命中source_commit_id与权威不一致 →stale_vector原因stale_source_commit。内容哈希一致性命中content_hash与权威不一致 →stale_vector原因stale_content_hash。向量时间戳新鲜度命中vector_updated_at早于权威updated_at→stale_vector原因stale_vector_updated_at。访问策略裁决按模式选择 is_archive_access_eligible 或 is_default_access_eligible。拒绝 →access_denied不产生修复候选这是文档明确允许的唯一静默丢弃场景。只有通过全部检查的命中才进入allowed决策并生成HydratedSearchResult。每个修复候选由 _repair_purge_candidate 组装包含vector_id、memory_id、reason、decision、required/observed_projection_commit_id、required/observed_account_generation、authoritative/observed_item_revision、authoritative/observed_source_commit_id、authoritative/observed_content_hash等字段为下游 worker 提供完整的事故现场。五、检索编排过取、水合与刷新的有界循环vector_search_service.py 中的fetch_default_vector_memory_search把水合逻辑编织进真实检索流程核心策略是有界过取 失败刷新参数校验与预算封顶limit默认 10上限 100、overfetch_factor默认 3上限 10、max_candidates默认 50、max_vector_queries默认 3上限 10、可选的timeout_seconds。初次请求向量库的候选数为min(max(limit * overfetch_factor, limit), candidate_budget)。所有参数均有 对应校验函数 保证取值合法。新鲜度栅栏调用方必须提供required_projection_commit_id非空字符串与required_account_generation非负整数缺失即抛ValueError从源头保证每次检索都带有明确的投影与账号代数基线。按 ID 水合_hydrate_vector_candidate_items_by_id 对每个候选 ID 直接读取users/{uid}/memory_items/{memory_id}文档受max_candidate_hydration_reads与 deadline 双重约束读到空 payload 记入missing_authoritative_memory_ids读到则用MemoryItem.model_validate反序列化并校验item.uid uid发现跨用户即抛错。水合后裁决仅对已成功水合或确认缺失的命中调用hydrate_and_filter_vector_hits见_filter_read_candidate_hits避免对未读取条目做无效裁决。刷新循环若结果不足limit且候选预算/查询次数/超时均未耗尽则按max(候选上限 limit, 候选上限 * 2)扩容候选窗口继续查询直到满足以下任一终止条件结果达标、候选窗口达预算、向量查询次数耗尽、水合读取预算耗尽或超时。产出与遥测最终响应包含items、scores_by_memory_id、projection_commit_ids_by_memory_id、逐条decisions、五类拒绝计数缺失/投影过期/向量陈旧/访问拒绝/向量库自身拒绝、repair_purge_candidate_count与候选列表、search_statusok/timeout_exhausted/hydration_read_budget_exhausted/vector_query_budget_exhausted/candidate_budget_exhausted以及legacy_fallback_used: False——明确声明此路径永不回退到旧读取器。修复候选通过回调与 outbox writer 两条通道分别投递并挂接 向量检索遥测。六、修复闭环outbox、租约、重试与死信被裁决为陈旧但可修复的向量 ID 不会自愈而是进入持久化 outbox由独立 worker 异步收敛build_vector_repair_purge_outbox_records 把repair_purge_candidates转成 outbox 记录携带idempotency_key、event_typevector_repair_purge、reason等write_vector_repair_purge_outbox_records 将其写入users/{uid}/memory_outbox。lease_vector_repair_purge_outbox_records 通过两条查询pending且available_at now或in_progress且租约已过期选取待处理记录以worker_id加租约元数据lease_owner、leased_at、lease_expires_at抢占避免并发重复处理。process_vector_repair_purge_outbox_records 对每条记录做幂等处理先判断是否可直接删除缺失权威条目场景否则加载权威条目后用_decide_delete_or_repair决策——权威条目不存在、处于 tombstone/delete 状态或原因为missing_authoritative_item时执行delete否则执行repair通过注入的vector_repairer重建向量。失败时按 durable_queue 的QueuePolicy(max_attempts3, base_backoff_seconds1, max_backoff_seconds1800)重试超限转dead_letter。整个 worker 由 run_vector_repair_outbox_worker_tick 驱动其VectorRepairOutboxWorkerTickConfig默认enabledFalse——即默认 fail-closed不自行注册任何生产调度器必须由 Cloud Run/Tasks 或显式调度器以服务端配置注入执行并挂接 outbox worker 遥测。七、Guard 测试如何守住这条不变式文档指定的行为级 guard 测试位于 backend/tests/unit/test_inv_mem_1_guard.py其中TestInvMem2VectorHydrationFailClosed三个用例精确刻画了 fail-closed 语义缺失权威条目被排除并产出修复候选构造mem_present长期记忆与只有memory_id的mem_missing两条命中传入只含mem_present的权威字典。断言结果只含mem_presentmem_missing的决策为missing_authoritative_item且修复候选包含该 ID。投影过期时结果为空把命中的projection_commit_id改成过期值断言results []、决策为stale_projection、且产出修复候选。默认模式下归档命中被拒绝且无修复候选归档层级命中在SearchMode.default下决策为access_deniedrepair_purge_candidates []——这正是文档访问策略拒绝允许静默丢弃条款的测试固化。同文件的TestInvMemSourceRatchet还通过 AST 扫描对database/memory_*.py、utils/memory/**等路径做源码棘轮source ratchet禁止新增非规范 tier 字面量、禁止MemoryCollections出现未列入白名单的集合属性、禁止默认读路径在无显式 archive 上下文时出现归档层级——从行为与静态结构两个层面阻止未来回归。扩展的网关用例见 backend/tests/unit/test_memory_search_gateway.py。八、实践要点与阅读路径检索方必须提供新鲜度栅栏调用fetch_default_vector_memory_search时required_projection_commit_id与required_account_generation不可省略否则抛错——这是调用者无法绕过 fail-closed的强制点。归档检索是显式能力默认模式与归档模式走不同的访问判定函数归档命中在默认模式下只产生access_denied、不触发修复符合 INV-MEM-1归档不进入默认访问的层级语义。修复与访问拒绝要区分对待缺失/陈旧条目必须留痕并进入 outbox 修复管线访问拒绝则允许静默丢弃两者在决策模型与测试中都有明确分野。深入源码的推荐顺序memory_search_gateway.py决策模型与裁决函数→ vector_search_service.py检索编排→ memory_vector_metadata.py向量 metadata 构建与解析→ memory_vector_repair_outbox.py 与 memory_vector_repair_outbox_worker.py修复闭环→ test_inv_mem_1_guard.py行为契约。层级与权威语义可对照 memory_tiers 不变式 与 universal fail-closed 不变式 一起阅读。对产品记忆的任何一次向量检索Friend 都坚持以权威memory_items为唯一真值来源、以 fail-closed 为默认行为、以修复 outbox 为收敛手段——这正是AI 记住你的过去这一承诺背后的工程保障。【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表