dsh-ocr1-memory 测试报告

August 30, 2026 · View on GitHub

[简体中文] | English

dsh-ocr1-memory 测试报告

目标:在隔离临时环境中持续测试与修复,直到插件稳定实现 DeepSeek-OCR1(Contexts Optical Compression)的记忆系统效果。 本文档持续更新,所有测试均使用隔离临时目录,不污染 ~/.dsh/ocr1-memory

测试环境

项目
插件目录<Agent_Extensions>\dsh-plugins\dsh-ocr1-memory
真实 OCR 后端http://127.0.0.1:18080/v1(llama-server + DeepSeek-OCR Q4_K_M + mmproj q8_0)
真实 Embedding 后端与 OCR 共用 http://127.0.0.1:18080/v1(combined --embeddings --pooling mean
采样参数temperature=0repeat_penalty=1.2no_repeat_ngram_size=30
渲染Python + Pillow + CJK 字体(微软雅黑/黑体)
隔离方式每个测试 mkdtemp 独立目录,测试结束自动删除

当前通过状态(2026-08-30)

套件结果
npm test(健康真实后端在线)88/88 通过,0 fail,0 skip
核心 store 测试12/12 通过
context 测试7/7 通过
复杂隔离测试(T1–T24)24/24 通过
OCR HTTP2/2 通过
OCR server 生命周期4/4 通过
Embedding 测试(E1–E5)5/5 通过
定位器测试(L1–L8)8/8 通过
治理层与取消信号测试13/13 通过
集成接线与自动治理测试2/2 通过
渲染几何测试(RG1–RG2)2/2 通过
Robustness 测试(M1–M9)9/9 通过
真实 OCR / Embedding 用例PASS(T6/T15/T16/T21/T23/T24/E4;无后端时共 8 个 live-backend 用例跳过)

当前 Web 运行验证

  • profile 使用 ocrBaseUrl=http://127.0.0.1:18080/v1requireOcr=trueautoStartOcrServer=true;OCR 与 embedding 共用 CPU-only llama-server
  • ocr1_mem_statusocr1_mem_calibrate 和真实图像 embedding 均成功;校准基线为 prompt_tokens=5,独立 embedding probe 为 1280 维、prompt_tokens=785、直接视觉 token=784。
  • 连续 memory_maintain 每批最多刷新 8 条并返回 remaining/complete;重复 namespace 维护不会并发执行,取消和卸载会等待已拥有的任务。
  • 上述是本机运行证据;更换模型、量化、后端或服务参数时应重新验收。

单元测试覆盖

  • splitSegments:空行分段、连续 id、超长段落切分
  • scoreSegment:命中、未命中、空文本
  • tierIndexFor:vivid/normal/fuzzy 年龄边界
  • 动态衰减:默认关闭、近期频率、平滑过期、倍率上限和注入时钟
  • context 快照:热度排序、字符上限、空/损坏 manifest 容错
  • store + retrieve:verbatim 返回、OCR 文本写入
  • active recall:fuzzy → vivid
  • OCR 驱动召回:原始文本未命中但 OCR 命中时仍召回
  • OCR HTTP 客户端:OpenAI 兼容 /v1/chat/completions 集成
  • 渲染缓存:相同分段集合 + 分辨率复用图像

复杂隔离测试覆盖

ID场景结果
T1时间旅行:fuzzy → 命中 → vividPASS
T230 条模糊记忆中只升级命中的 1 条PASS
T3多主题记忆检索互不串扰PASS
T450 段大文本中准确命中目标段PASS(修复后)
T5中文/英文/日文/Emoji/特殊符号PASS
T6真实 DeepSeek-OCR 连续 3 次读图稳定PASS
T7OCR 后端不可用:严格模式报错/宽松模式降级PASS
T820 个并发 store 后 JSON 完整PASS

已发现并修复的问题

1. 检索打分污染(T4 暴露)

现象:查询 unique-key-37 时,所有包含 unique/key 的无关片段被整条记忆的聚合分抬到 topK,目标段 37 被挤出。

原因retrieveSegments 给每个字面命中片段使用了 Math.max(segScore, est.score * 0.5),其中 est.score 是整条记忆的聚合分,导致泛化词片段集体虚高。

修复

  • 字面命中片段直接使用片段级得分 segScore
  • OCR 聚合分只用于“原始文本无命中时的 OCR 兜底召回”,不再污染普通片段得分。

回归:T4 通过;当前 core/context 单元测试共 19/19 通过。

2. 分辨率层级未对齐 OCR1 官方模式

修改DEFAULT_TIERS1024/768/512 调整为:

vivid  1280 → 400 tokens(对应 OCR1 Large)
normal 1024 → 256 tokens(对应 OCR1 Base)
fuzzy  640  → 100 tokens(对应 OCR1 Small)

原因:更贴近 DeepSeek-OCR 论文中的原生分辨率模式。

Embedding 测试覆盖

ID场景结果
E1measureImageEmbedding 通过 media marker 请求,返回 embedding / 直接视觉 token 数PASS
E2记忆 store 存储真实 multimodal embedding 与 visualTokensDirectPASS
E3embedding 后端失败时降级为像素 embedding 并记录 embeddingErrorPASS
E4真实 DeepSeek-OCR embeddings 后端生成 1280 维视觉 embeddingPASS
E5启用 embedding 检索时:向量更近的记忆排在前面PASS

真实 E4 在当前健康 CPU-only llama-server 上通过;当前 ocr1_mem_embed_test 记录 prompt_tokens=785、空文本基线 prompt_tokens=1、直接视觉 token=784、embedding 维度=1280。该数值随图像、prompt 和服务配置变化,不能当作论文内部 token 数。

真实 OCR 隔离测试记录

ISOLATED_REAL_TEST_PASS
storeDir=临时目录(已删除)

输入文本:
Orbit API 需要登录并携带 token。

OCR 回读(节选):
"### 题目内容
**Orbit API 需要登录并携带 token。**
..."

检索结果:
[entryId=..., segmentId=1, score=1.00, tier=vivid]
content: "Orbit API 需要登录并携带 token。"

第二轮复杂隔离测试

ID场景结果
T9路径穿越安全:source 注入 ../、绝对路径PASS
T10memories.json 损坏后安全重建为空库PASS
T11500 轮 store/retrieve/forget 长稳PASS
T1210 路并发 active recall 命中同一目标PASS(修复后)
T13分辨率模式对齐 OCR1:1280/1024/640PASS
T14压缩比指标:textTokens / visualTokensPASS
T15真实 OCR 记录 usage.prompt_tokensPASS
T16真实 OCR 近似视觉 token 数 / 近似压缩比PASS
T17update 冲突消解:旧值被新值覆盖PASS
T18选择性遗忘:删除后检索不到PASS
T19跨会话持久化:重建 store 后仍可检索PASS
T20实测视觉 token 使用文本-only baseline 校准PASS
T21文本-only prompt_tokens 校准请求PASS
T22相同 source 的 store 自动更新为最新值PASS
T23optical memory 存储 visual token 元数据PASS
T24渲染图像生成并存储视觉 embedding(无 embeddings 后端时为 64 维像素 embedding)PASS

Robustness 测试覆盖(M1–M9)

ID场景结果
M1多 Agent 共享 store:两个 store 实例通过 reload 互相看到新增记忆PASS
M2原子保存:多次写入后无 .tmp 残留PASS
M3图像文件丢失后自动重新渲染恢复PASS
M4渲染缓存损坏(缓存路径被替换为目录)时回退到全新渲染PASS
M5超长多段落输入(>200KB)分段存储并检索命中目标PASS
M6超长单段落(约 250KB)切分后无数据丢失PASS
M7list 为纯查询,不隐式修复或重渲染PASS
M8tier refresh 受 maintenanceBatchSize 限制并报告剩余工作PASS
M9tier refresh 在 renderer 内观察取消信号PASS

已发现并修复的问题(第二轮)

并发 active recall 渲染竞争(T12 暴露)

现象:多个并发 retrieve 同时命中同一条 fuzzy 记忆时,渲染缓存写入报 EBUSY: resource busy or locked

原因:同一输出路径被多个异步渲染同时写入/复制。

修复

  • createMemoryStore 内增加 renderLocks,同一 outputPath 的并发渲染只执行一次;
  • 缓存写入改为 best-effort,失败不阻断主流程。

回归:T12 通过;相关核心/context 回归以及并发锁测试均通过。

已发现并修复的问题(第三轮:DSH 级 R5/R6 验证)

DSH 工具输出 schema 严格性(R5 暴露)

现象:headless Agent 调用 ocr1_mem_store / ocr1_mem_list 时提示 "invalid output",因为返回对象包含 schema 未声明字段(updated / ocrText / visualMemory)。

修复

  • ocr1_mem_store 输出 schema 增加 updated: boolean
  • ocr1_mem_list 在 execute 中只返回 schema 声明字段;
  • ocr1_mem_metrics 去掉 null 可选字段,避免严格 schema 拒绝。

回归:DSH 级 R5 再次执行无 invalid output,结果 PASS。

OCR 服务生命周期验证

验证结果

  1. ocr-server.test.mjs 覆盖健康检查、URL 显式端口、同 endpoint 并发启动去重;4/4 通过;
  2. autoStartOcrServer 直接 detached spawn llama-server,不会通过 PowerShell wrapper 管理子进程;
  3. 启动取消或健康检查超时会回收本次 spawn 的进程;插件 dispose 会取消 pending startup、等待 startup task,并停止记录过的自启动 PID;
  4. 已运行的外部服务只返回 already-up,不会被插件卸载。

端到端本机配置使用 http://127.0.0.1:18080/v1,OCR 与 embedding 可共用一个 CPU-only 服务。

对比基准:dsh-ocr1-memory vs dsh-memory

  • 设计文档:BENCHMARK.md
  • 执行脚本:scripts/compare-memory.mjs
  • 隔离环境:两个临时 store + --patch 互斥禁用插件
  • 结果:已用修正后的 scripts/compare-memory.mjs 完整重跑 R1–R6;dsh-ocr1-memory 全部 PASS,dsh-memory 本次也全部 PASS(R5 此前手动验证曾 FAIL,行为不稳定)。dsh-ocr1-memory 未出现落后于 dsh-memory 的情况。

后续计划

  • 固化复杂测试脚本为 test/complex.test.mjs 并纳入 npm test
  • 自动拉起 OCR 服务(lib/ocr-server.js + autoStartOcrServer
  • 对比基准脚本 scripts/compare-memory.mjs
  • 多 Agent 共享 store(sharedStore + reload + 原子保存)
  • 图像缺失/缓存损坏恢复测试
  • 超长输入边界测试(>200KB 多段落 + 超长单段落)
  • list 纯查询、bounded tier refresh 与 renderer 取消传播(M7–M9)
  • namespace single-flight 维护与 disposer drain
  • 超长输入(10MB)与内存压力
  • LoRA 定位器训练/评估脚本与合并部署链:详见 docs/DEPLOYMENT.md
  • 直接视觉 token 数:通过 embeddings 端点 marker-only 请求测量(visualMemory.visualTokensDirect
  • 命中频率动态衰减(默认关闭,保留旧库行为)
  • 可选 systemPrompt.context() 记忆摘要注入(L1/光学元数据默认开启;snapshot 正文快照需显式开启)
  • 论文规模训练与完整主表评测
  • DeepEncoder 内部逐层 token/embedding 导出

测试结论与适用范围

1. 结论

在本机当前运行条件下,记忆系统的核心闭环可以正常工作:

store → SoM 图像与原文持久化 → tier 刷新 → 检索 → segment Fetch → verbatim 返回

证据范围如下:

能力结论证据
文本存储、分段、持久化、更新、遗忘已确认核心测试、T8/T10/T17–T19/T22、M1–M2
SoM 渲染、分辨率 tier、老化和 active recall已确认T1/T2/T13/T14、RG1–RG2、M3–M4
真实 OCR 读图当前配置已确认T6/T15/T16/T21;严格模式覆盖 T7
视觉 embedding当前配置已确认E1–E5,E4 使用真实后端返回 1280 维向量
光学定位协议与 verbatim Fetch已确认L1–L8;此前 DSH 隔离闭环 R1–R6 通过
动态衰减与 context 快照已确认核心/context 测试;动态衰减默认关闭,index context 默认开启
维护 batch、single-flight 与取消已确认治理取消测试、M7–M9、自动治理 disposer 测试
DSH 插件加载已确认host 注入通过,运行时状态返回 OK

npm test 当前为 88/88 通过(健康真实后端在线);无后端时 80 项通过、8 项 live-backend 用例跳过。另有 npm run buildnpm run test:smoke 和 Markdown 链接检查通过。测试使用隔离临时 store,不代表任意模型、量化格式、后端或生产数据都无需额外验收。

2. 无独立显卡运行结论

记忆系统本身不要求本机独显:

  • DSH 插件的 Node.js 逻辑、JSON 持久化、tier 管理、context 快照和 Python/Pillow 渲染都可由 CPU 完成;
  • OCR、Locate 和视觉 embedding 是外部服务,当前已验证的运行方案是 Windows CPU-only llama.cpp,OCR 与 embedding 共用一个 CPU 服务,不依赖 RX 7800 XT 独显;
  • 如果不配置 OCR 后端且 requireOcr=false,文本记忆路径仍可工作;需要 OCR、Locate 或视觉 embedding 时才需要对应服务;
  • LoRA 训练是独立的开发流程,本机训练时使用过独显,但普通运行不需要重新训练,因此不构成运行时依赖。

核显不是必需条件。若采用带 Vulkan 后端的 llama.cpp,可以把核显作为可选加速设备,但本报告的真实运行证据是 CPU-only 路径,尚未把当前插件的全部 OCR/embedding/定位链在核显上单独验收。要保证不使用独显,应将 OCR_SERVER_PATH/ocrServerPath 指向 CPU-only 的 llama-server;通用 PATH 解析本身不会替你选择 GPU 或核显。

这只说明 OCR1 记忆服务 不依赖独显;DSH 使用的其他主模型是否占用独显,是另一条与本插件无关的链路。