
DeepChat Agent Memory 质量门禁与可观测性架构原生 SQLite CI 门禁、确定性检索评估与有界诊断指标全解【免费下载链接】deepchatDeepChat - A smart assistant that connects powerful AI to your personal world项目地址: https://gitcode.com/GitHub_Trending/dee/deepchat本篇技术指南深入剖析 DeepChat 中 Agent MemoryAgent 记忆子系统的三层质量保证体系CI 层不可跳过的 Native SQLite 门禁、基于版本化 fixture 的确定性检索评估、以及暴露在既有 Health 契约与 UI 中的有界、内容无关的运行时诊断。读完本文你将掌握test:memory:scope/test:memory/test:memory:eval等稳定命令的用途与执行顺序、Recall5 / MRR10 / nDCG10 的精确语义、MemoryDiagnosticsCollector的容量与淘汰策略、以及全部运行时指标的归属与隐私边界并可直接对照仓库源码验证每一项实现。1. 背景为什么单元测试不够Agent Memory 依赖四类在生产环境才暴露问题的能力SQLite 全文检索FTS与向量检索异步文本抽取extraction与向量化embedding定时维护任务maintenance与预算控制进程自有的原生资源Native SQLite 绑定、向量存储句柄。传统宽而浅的单元测试存在三个盲区见 spec.md 第 1 节原生绑定可能静默跳过binding silently skip、检索基准可能只跑玩具行为toy behavior、运行时劣化在产品既有的诊断面上不可见。为此架构提供了三个互补的证据层对应 plan.md 第 1 节的四层依赖顺序CI 所有权的 Native SQLite 门禁——无法静默回退或跳过确定性、带版本的检索评估——运行真实 SQLite FTS 与生产融合逻辑有界、内容无关的运行时诊断——通过既有 Memory Health 契约与 UI 暴露。三层在正确性依赖生产行为的地方复用生产代码而测试专用的向量生成与指标计算则与凭据、Provider、外部网络完全隔离。2. 目标与边界2.1 目标清单规范在第 2 节明确了八条目标它们是全部验收标准的源头让 Native SQLite、FTS、JSON、迁移与存储故障直接让 Memory CI 任务失败提供稳定命令覆盖可移植行为、确定性检索评估与性能边界防止 Memory 所属测试悄悄脱离聚焦的质量门禁用版本化 fixture 与固定指标语义度量检索质量暴露检索、抽取、向量化、维护、向量与 Provider 的内容无关诊断让每个诊断数据结构有界并在 Agent 被淘汰eviction后仍然正确保持主进程到渲染进程的类型化契约不引入新事件或遗留 IPC 通道用服务级测试套件与显式 harness 能力替换门面facade级测试预言。2.2 约束Constraints第 4 节列出的硬性约束同样重要不引入外部分析 SDK、指标守护进程、遥测端点、数据库表或版本化迁移不做真实 Provider 评估、不读凭据、不出现 API Key、Provider URL 或网络请求不改动检索打分、维护预算、Provider 重试策略与 Memory 决策语义不以绝对墙钟延迟作为共享 CI 阈值不创建第二个 Native CI 任务、smoke 实现或测试清单。2.3 非目标Non-Goals第 5 节明确排除产品分析/崩溃上报/云遥测、持久化运行时指标历史、真实 embedding 模型质量对比、新的 Health 轮询或更新事件、新的本地 Native 测试命令、数据库状态模型规范化或遗留状态移除。3. 第一层CI 原生 SQLite 门禁AC-13.1 门禁职责test-native-memoryCI 任务早期名为memory-native-validation承担不可跳过的职责使用仓库锁定的Node 24与 pnpm 工具链安装独立依赖树并为 Node ABI重建 SQLite 绑定smoke 步骤加载绑定 → 打开加密 SQLite → 建表 → 写入 → 读取 → 关闭原生测试以DEEPCHAT_REQUIRE_NATIVE_SQLITE1运行缺少绑定、FTS、JSON、迁移 harness 或任何意外 skip 都必须产生非零退出码。3.2 工作流顺序任务执行顺序被严格固定plan.md 第 2.2 节Node 24 仓库锁定 pnpm 安装依赖先跑 scope 守卫与可移植 Memory 行为此时未改动任何原生绑定为 Node ABI 重建 SQLite 绑定跑加密 SQLite smoke 检查以DEEPCHAT_REQUIRE_NATIVE_SQLITE1跑 Native 配置在同一 required-Native 环境下跑确定性检索评估跑专用 Memory 性能配置以if: always()上传test-results/memory/retrieval-v1.json。关键设计没有test:memory:native本地包脚本——Native 调用完全由 CI 工作流拥有避免本地开发误把 Electron ABI 绑定替换掉。这也解释了为什么package.json中只有可移植命令。该上传步骤是当前唯一标注待办的外部门禁tasks.md 第 18-19 行PR #1952 已在评估期间生成报告但 CI 工件上传警告test-results/memory/retrieval-v1.json缺失本地验证不能替代 CI 自有证据。4. 第二层确定性检索评估AC-3、AC-44.1 版本化 Fixturetest/fixtures/memory/retrieval-v1.json是版本化的合成语料实测包含301 个id字段超过 200 行语料要求并在queries段存放 60 查询。fixture 结构前 80 行可验证顶层声明version: 1与vectorProfile{ id: deterministic-lexicon-v1, dimensions: 128, normalized: true }corpus每行含id、agentId、kind如semantic/episodic/reflection、content、importance覆盖精确匹配、CJK、路径、代码、语义、混合检索并内置跨 Agent 干扰项如exact-01-cross-agent属于agent-beta与多相关 IDexact-01-relevant与exact-01-secondary-relevant同属agent-alphafixture 只存文本与相关性数据不存向量。4.2 确定性 Embedder语料与查询向量由同一个测试本地deterministic-lexicon-v1配置生成NFKC 规范化、ASCII 小写化、代码/路径 token、CJK 三元组trigram、版本化同义词表、稳定特征哈希到 128 维、L2 归一化。Gating 的 CJK 查询在规范化后至少包含三个连续 CJK 码点。实现只接受文本与配置查询 ID、子集标签、相关性数据对 embedding 函数不可见从机制上杜绝答案泄漏answer leakage。4.3 评估数据流与指标语义对每个查询runner 执行plan.md 第 3.2 节将合成语料行载入真实AgentMemoryTable通过生产仓储路径执行真实 SQLite FTS用同一 profile 生成确定性语料与查询向量用生产相似度助手把向量距离转换为相似度剔除低于生产similarityThreshold的候选实现见 scoring.ts 与 retrievalService.ts使用生产关键词抽取、权威行投影、稳定排序与fuse生成混合结果计算 FTS-only / vector-only / hybrid 三档指标在断言之前写入完整 JSON 报告确保门禁失败也保留诊断证据。指标语义AC-4非常明确指标定义Recall5前 5 条结果中去重后的相关 ID 数 ÷ 相关 ID 总数MRR10前 10 条中首个相关结果的倒数排名nDCG10二元相关性多个相关 ID 时使用正确的理想 DCG配套规则重复结果 ID 只计首次出现位置无相关 ID 的查询被拒绝生产距离-相似度转换、相似度阈值、关键词抽取、融合与稳定排序全部被评估器复用固定阈值只门禁 hybrid 结果FTS-only 与 vector-only 仅作诊断基线语义消融semantic ablation测试证明去掉同义词概念信号会降低语义检索质量。源码证据在 memoryRetrieval.eval.test.tsexpect(summary.recallAt5).toBe(1)、expect(summary.mrrAt10).toBe(0.5)、expect(summary.ndcgAt10).toBeGreaterThan(0.6)以及概念消融段断言ablation.recallAt5 0去掉概念信号后召回归零并验证混合门禁hybrid.recallAt5 0.95与词法子集回归约束hybrid fts - 0.02。gating 查询的开关相关/不相关同样有断言覆盖。5. 第三层有界内容无关诊断AC-5、AC-65.1 收集器状态管理核心实现是 memoryDiagnosticsCollector.ts 中的MemoryDiagnosticsCollector类Agent 与进程状态严格分离Agent 状态最多64 个 AgentDEFAULT_MAX_AGENTS 64、24 小时 TTLDEFAULT_AGENT_TTL_MS、LRU 淘汰。已有条目通过删除后重插Map条目实现 O(1) touchagent()方法agents.delete(agentId); agents.set(agentId, existing)。TTL 扫描只在容量满时新建 Agent / 读取快照 / 显式清理三个时机执行从记录热路径移除全量 TTL 扫描对应 tasks 中的Remove full TTL sweeps from record hot paths进程状态抽取队列、embedding 积压、向量资源、Provider 准入数据不随 Agent 被淘汰仅在 presenter 销毁时清除每个分布保留最多256 个样本由 boundedNumberRing.ts 的BoundedNumberRing固定容量环形缓冲实现push拒绝非有限或负数snapshot()返回有序快照百分位在快照时用 nearest-rank 计算 p50/p95/max记录热路径绝不排序所有 recorder 都经safely()包装收集器异常被吞掉诊断失败绝不能改变业务结果Diagnostics must never affect memory behavior.。createCompositeMemoryPerfObserver将多个可选观察者合成为最佳努力best-effort通道每个观察者调用都单独 try/catch——这印证了 plan 中仓库 Proxy 仅当存在外部性能观察者时才启用诊断本身不给生产热路径加 Proxy的设计。5.2 隐私边界诊断数据结构只接受数字、布尔、时间戳与共享闭包枚举。绝不保留查询文本、记忆内容、prompt、向量、Provider 响应、API Key、SQL、堆栈、异常消息或任何自由文本。查询 embedding 熔断circuit诊断只保留 closed/open/half-open 状态与聚合的 failure / open / skip 计数Provider/模型身份保留在熔断器所有者内部。5.3 检索操作语义每个检索入口创建一个执行上下文包含purpose意图、开始时间、来源计数、终止结果terminal outcome、退化原因集合由单个finally保证恰好结算一次。共享闭包枚举定义在 agent-memory.ts延迟阶段MEMORY_RECALL_LATENCY_STAGESkeyword、queryEmbedding、vector、authoritativeRevalidation、assembly、total意图MEMORY_RETRIEVAL_PURPOSESrecall、decision、search、injection终止结果MEMORY_RETRIEVAL_OUTCOMEScompleted、disabled、emptyQuery、cancelled、failed退化原因MEMORY_RETRIEVAL_DEGRADATION_CAUSESvectorCold、embeddingTimeout、embeddingError、embeddingCircuitOpen、storeUnusable、storeTimeout、storeError、revisionChanged、ftsUnavailable、candidateBudgetExhausted、unknown维护预算步骤MEMORY_MAINTENANCE_BUDGET_STEPSchallenge、merge、reflection、persona。终止结果与退化原因刻意相互独立disabled/emptyQuery是正常终止结果FTS 不可用、向量冷启动、embedding 超时/错误、store 不可用/超时/错误、版本变更、未知失败才是退化原因一次操作可保留多个退化原因源码中recordRecall用new Set(sample.degradations)去重后逐项累加。5.4 后台操作语义抽取记录进程绝对队列深度与最旧排队时间戳会话销毁时移除记账条目chunk 结果区分 completed / cancelled / failedCAS 重试只在真实第二次 apply 前递增不产生虚假终止计数Embedding使用必需的全局限定 pending 计数仓储查询与幂等的部分 SQLite 索引派生基础设施无需版本化迁移drain 结果携带控制结果、批次大小、实际仓储状态转移的 ID/计数embedded / error / ftsOnly维护报告 cheap/heavy 阶段时长与结果、调用次数、输入 token以及每个被拒绝的预算步骤的计数budgetDeniedByStep在结算 pass 时记录每次被拒的MaintenanceBudget.reserve缺失模型选择产生 heavy skipped 样本向量复用现有资源观察者一次绝对观测同时更新当前值与 high-water 值observeVectorResources里Math.max更新openStoresHighWater/activeLeasesHighWaterwarmup 区分 succeeded / deferred / failedProvider 准入真实等待中的准入 gauge 与 admitted / rateLimited / capacityRejected / deadline / aborted / lateSettled 计数严格分离admitted只在远程准入与本地容量预留都成功后记录查询 embedding 熔断的 skip 使用闭包检索退化原因而取消与本地控制面拒绝不计入 Provider 健康失败数。6. 运行时指标字典metrics.md 全量metrics.md 是维护中的指标字典Version 1记录每条指标的 DTO 路径、单位、采样点、容量与清理策略、隐私分类。6.1 Agent 作用域DTO 路径单位采样点容量与清理隐私分类agent.retrieval.{recall,decision,search,injection}.latencyMs.*毫秒分布对应检索操作结算每 Agent 每序列 256 样本64-Agent LRU24h TTLAgent 清理时移除无内容计时agent.retrieval.*.{ftsCandidates,vectorCandidates,selected}计数权威复核与融合完成每 Agent 计数器同 Agent 清理聚合计数agent.retrieval.*.outcomeCounts.*按闭包结果计数操作finally每 Agent 计数器同 Agent 清理闭包枚举agent.retrieval.*.degradationCounts.*按闭包原因计数操作finally一次操作可记多个原因每 Agent 计数器同 Agent 清理闭包枚举agent.queryEmbeddingCircuit.state闭包状态closed/open/halfOpen熔断状态迁移仅当前 Provider/模型配置变更与 Agent 清理时重置闭包枚举agent.queryEmbeddingCircuit.{failures,openCount,skipped}计数合格 Provider 失败、打开迁移或跳过每 Agent 计数器同配置与 Agent 清理聚合计数agent.extraction.{chunksCompleted,chunksCancelled,chunksFailed,llmCalls,casRetries}计数chunk 结算或真实第二次 CAS apply每 Agent 计数器同 Agent 清理聚合计数agent.embedding.batchSize行分布embedding drain 批次结算256 样本同 Agent 清理聚合计数agent.embedding.drainDurationMs毫秒分布embedding drain 批次结算256 样本同 Agent 清理无内容计时agent.embedding.{succeeded,failed,ftsOnly}计数实际仓储终止态转移每 Agent 计数器同 Agent 清理聚合计数agent.maintenance.{cheapDurationMs,heavyDurationMs}毫秒分布维护阶段结算256 样本同 Agent 清理无内容计时agent.maintenance.{completed,skipped,failed,llmCalls,llmTokens}计数维护阶段结算每 Agent 计数器同 Agent 清理聚合计数agent.maintenance.budgetDeniedByStep.*按闭包步骤计数每次被拒的MaintenanceBudget.reservepass 结算时记录每 Agent 计数器同 Agent 清理闭包枚举快照语义百分位在快照时通过复制并排序 ring 后计算 nearest-rank p50、p95、max记录热路径永不排序样本。注意queryEmbeddingCircuit的failures/openCount在配置变更时被resetQueryEmbeddingCircuit重置为全零 closed 状态。6.2 进程作用域DTO 路径单位所有者与采样点容量与清理隐私分类process.extractionQueue.{depth,oldestQueuedAgeMs}任务/毫秒Agent 运行时入队、出队、会话销毁绝对值不受 Agent LRU/TTL 约束presenter 销毁时清除无内容队列状态process.embeddingBacklog.{pending,activeAgents}行/Agent仓储绝对计数与 embedding drain 所有者进程单例销毁时清除聚合计数process.vector.{openStores,activeLeases}资源资源所有者经复合MemoryPerfObserver的绝对观测进程单例销毁时清除资源 gaugeprocess.vector.{openStoresHighWater,activeLeasesHighWater}资源同一绝对观测更新进程生命周期销毁时清除资源 high-waterprocess.vector.{evictions,warmupSucceeded,warmupDeferred,warmupFailed}计数向量收敛与 warmup 结算进程生命周期销毁时清除闭包结果process.providerAdmission.queued请求限流准入前后等待中的绝对 gauge进程单例销毁时清除资源 gaugeprocess.providerAdmission.admissionDecisions.{admitted,rateLimited,capacityRejected}计数准入决策每请求至多一次进程生命周期销毁时清除闭包枚举process.providerAdmission.raceEvents.{deadline,aborted,lateSettled}计数外层请求竞态事件进程生命周期销毁时清除闭包枚举进程 gauges 由资源所有者写入绝对值收集器绝不从保留的 Agent 状态推导活跃进程资源——因此 Agent TTL/LRU 淘汰不会让活跃 gauge 漂移。Health UI 将所有进程字段明确标注为 process-wide。7. 稳定测试作用域与命令AC-27.1 单一权威清单test/memory-test-scope.json是 Memory 测试唯一的归属清单将具体路径分类为behavior、native、eval、perf四类并允许带强制理由的显式豁免当前 3 条豁免均属跨域回归套件留在全量 main 门禁型理由。实测清单包含 56 个 behavior 路径、13 个 native 路径、1 个 eval 路径与 6 个 perf 路径。7.2 稳定命令package.json中对应的包脚本第 18-22 行mise exec -- pnpm run test:memory:scope # node scripts/check-memory-test-scope.mjs mise exec -- pnpm run test:memory:type # node scripts/typecheck-memory-tests.mjs mise exec -- pnpm run test:memory # scope type vitest --config vitest.config.memory.ts --run mise exec -- pnpm run test:memory:eval # vitest --config vitest.config.memory-eval.ts --run mise exec -- pnpm run test:main:memory-perf # vitest --config vitest.config.memory-perf.ts --run语义严格对应 AC-2test:memory:scope校验单一版本化清单test:memory只跑可移植 Memory 行为test:memory:eval跑确定性检索评估test:main:memory-perf沿用专用性能配置Native 测试保持工作流所有没有本地包脚本改写 Electron 绑定。scope 校验器check-memory-test-scope.mjs会拒绝缺失路径、重复归属、未分类 Memory 测试、可移植集合中的 Native 测试、以及没有非空理由的豁免。发现机制使用显式归属路径、文件名与直接 Memory import而非宽泛内容标记避免误分类无关应用套件文件内容访问可注入测试永不落回真实文件系统。8. 类型化 Health 契约与 UIAC-7MemoryHealthDto.runtime为必填字段memory.routes.ts 的MemoryHealthSchema第 520 行runtime: MemoryRuntimeDiagnosticsSchema包含独立的agent与process快照agent按检索意图分段的延迟分布与计数器、抽取结果、embedding 转移、维护结果process抽取队列、embedding 积压、向量当前/high-water 资源、warmup 结果、Provider 准入与竞态数据。规则要点每个按闭包枚举键控的Record在有数据与空快照中都是全键完整的createEmptyMemoryRuntimeDiagnostics提供零值默认未托管或未采样的 Agent 获得空 Agent 快照 真实进程快照源码snapshot()中if (!state) return { agent: empty.agent, process }。Diagnostics 面板复用既有 Health 刷新路径不发布新的 Memory 更新事件缺失延迟样本渲染为em dash—而非0 msProvider gauges 与累计计数器分开显示任何内容、SQL、堆栈、Provider 错误细节都不进入渲染进程。新增 UI 文案对全部支持语言完成本地化。9. 测试架构演进AC-8服务套件与基础设施套件分别拥有检索、写入、embedding、维护、冲突、persona、工作记忆、向量、Provider 与仓储行为门面套件只保留组合、公共委托、跨服务工作流、清理、销毁与少量回归 smoke。共享测试支撑仅提供可复用能力基于能力的仓储片段读/写/embedding/生命周期/健康/事务、受控 promise 与条件等待器、向量/Provider/时钟/诊断探针、公共合成 fixture 构建器。配套结构守卫不允许集中式register*套件注册表、生产可变测试访问器、或只为了测试自己而存在的 harness 构建器每个保留的 harness 构建器必须有真实服务套件消费者。迁移后生命周期、生成、冷却、清理与竞态覆盖保持行为等价。这些断言被test:memory:scope中的结构测试持续守护。10. 兼容性、回滚与验证兼容性plan.md 第 7 节不改变任何持久化用户数据格式或公开 Memory 决策行为SQLite 部分索引是幂等的派生基础设施、无需版本化迁移runtimeHealth 字段为必填但由空工厂与类型化路由提供完整默认值CI 新增可独立回滚但会移除 Native 存储与检索质量所需证据由于所有 recorder 端口是观测性的诊断可在组合层禁用而不影响业务行为。验证策略第 8 节本地验证覆盖 typecheck、全量 main 套件、聚焦 Memory scope 与行为、确定性 eval 原语、性能边界、渲染进程套件、格式化、本地化一致性、linttasks.md 的 Local Validation 清单全部勾选最终外部门禁是更新的test-native-memory工作流任务——必须证明必需 Native 存储、FTS、检索评估与性能路径在提交后无跳过、无回退地通过。当前唯一待办是检索 JSON 工件的 CI 上传PR #1952 已验证 Native 存储、检索评估与性能路径通过但上传步骤曾警告工件缺失。11. 结语这套三层架构回答了Agent Memory 凭什么可信CI 层的 Native 门禁把绑定静默跳过从可能性中排除确定性评估用真实 FTS 生产融合逻辑 固定指标语义度量检索质量并用概念消融证明语义信号真实存在有界的内容无关诊断把运行时劣化映射为 Health UI 上可读的 p50/p95、退化计数、队列深度与 Provider 压力同时守住隐私与内存边界。三条证据链共享生产行为、隔离测试杂质正是 DeepChat 记忆子系统可观测、可回归、可审计的设计样板。继续深入可阅读 spec.md、plan.md、tasks.md 与 metrics.md 四件套并对照 memoryDiagnosticsCollector.ts、boundedNumberRing.ts、agent-memory.ts、memory-test-scope.json 与 retrieval-v1.json 验证每处细节。【免费下载链接】deepchatDeepChat - A smart assistant that connects powerful AI to your personal world项目地址: https://gitcode.com/GitHub_Trending/dee/deepchat创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考