Files
PolyGateway/research-wiki/migrations/video-tree-trm5.md
T
iomgaa e09362dcd1 docs: sync M4 outcomes into roadmap, architecture, and migration docs
VT migration abandoned (v1.0 scope becomes two projects), Q1 resolved
to Gitea PyPI, Q6 resolved as judge exemption (unwired zero-consumer
eval scaffolding), migration docs annotated with implementation errata,
and the reference/ read-only rule clarified for the worktree workflow.
2026-07-22 10:57:00 -04:00

24 KiB
Raw Permalink Blame History

Video-Tree-TRM5 迁移文档(迁移即验收)

Important

本迁移已放弃(2026-07-22 用户拍板: VT 项目本体已放弃,不再迁移)。 全文保留作历史记录与能力倒推依据——VT 倒推的库能力(R1-R12,含多逻辑角色/cache salt/多模态摘要/OcrTextPort/trust_env/check_health)均已在 M1-M3 交付,不因放弃而回收。v1.0 验收标准改为 GovDoc + CHS 两项目(见 ROADMAP §5)。

定位: 本文是 ARCHITECTURE.md §11.2 的展开——库建成后如何合并进 Video-Tree-TRM5、替换其哪些内部组件。它既是 M4 迁移的操作指南,也是 M1-M3 设计的反向约束(库公共 API 必须让本文描述的迁移成立)。与 ARCHITECTURE.md 冲突时以 ARCHITECTURE.md 为准。 全部结论基于 2026-07-20 对 reference/Video-Tree-TRM5/ 的代码实测(file:line 均为实测证据)。


1. 迁移目标与验收定义

验收公式: 删除清单文件全删 → import 替换为 from polygateway import ... → 项目原业务测试全绿(治理层自身单测随文件一并删除,由库的测试继任)。凡替换不掉的能力 = 库的边界缺口,回补后重验。

阶段 范围 验收
最小接入冒烟M1 后) 独立分支上,用 GatewayClient.from_env() 装配 SEARCH 角色单 client,替换 tools/build_trees.py_build_clients() 跑通一个小批量建树(LLM+VLM 路径、缓存、遥测落库) 冒烟脚本成功 + telemetry 落库可查 + 缓存命中率非零(重跑同视频)
全量迁移M4,需 M3 完成 OCR 删除清单全删、8 处装配点统一 from_env、OCR 换 OcrTextPort、AgentLoop 异常集合改造 make test 业务测试全绿 + 一次完整 train run 对照旧遥测指标无回归

2. 现状盘点

行数为 wc -l 实测。治理相关约 2555 行,其中可删 1296 行

文件 行数 职责一句话 迁移后命运
adapters/llm.py 595 GovernedLLMClient:熔断→缓存→重试+SSE 流式→写缓存→遥测五层内联于一个 chat 方法 删除(库 client+middleware 继任)
adapters/breaker.py 85 进程内熔断器(时钟注入、半开单探针、force_open) 删除(库 backends/memory,本身即移植蓝本)
adapters/streaming.py 131 三层活性看门狗纯函数 删除(库 streaming.py,近原样移植)
adapters/redis_cache.py 128 sha256 内容寻址响应缓存,TTL 校验、静默降级 删除(库 backends/redis 缓存继任)
adapters/telemetry.py 229 SQLite 遥测(单连接+锁+WAL+幂等+to_thread+降级) 删除(库 telemetry/sqlite.py 继任)
adapters/ocr.py 128 MonkeyOCR /ocr/text 裸调:同步 requests、线程轮询双端点、单帧失败跳过 删除(换库 OcrTextPort,升级为全治理;行过滤/拼接逻辑上移业务侧,见 §4)
adapters/vlm.py 131 base64 编码图片并注入最后一条 user message,委托 LLM client 保留改写(业务侧封装:_inject_images 保留,委托对象换成库 client
adapters/embedding.py 184 local(sentence-transformers)/remote(OpenAI SDK) 嵌入 remote 路径删除,换 polygateway.EmbeddingClient(Q3 已拍板纳入 M2,2026-07-20;库已交付);local(sentence-transformers)保留。迁移要点: 库为 async embed(list[str]) -> EmbeddingResponse(list[list[float]])——VT 同步调用点需自包同步壳(asyncio.run 或事件循环内 await),ndarray/tensor 转换自带 adapter(np.asarray(resp.vectors, dtype=np.float32));装配传 EMBED__NORMALIZE=true 保 L2 归一化语义
adapters/baseline_diagnosis_store.py 183 基线诊断结果 SQLite 存储(业务数据) 保留(业务侧)
core/protocols.py 69 LLMProvider/VLMProvider/TelemetryRecorder 三 Protocol 改写LLMProvider 由库满足;VLMProvider 指向改写后的 vlm.pyTelemetryRecorder 删除,见 §3
core/types.py 182 LLMResponse(11 字段) + 业务类型 改写LLMResponse 改为 re-export 库类型;其余保留)
main.py _build_adapters() 337(全文件) Composition Root:手写装配 breaker/cache/telemetry/llm×2/vlm/embed/ocr 改写(按角色 from_env
app/ports.py 173 应用层端口,含 OCRProvider.transcribe_frames 改写OCRProvider 保留但实现改为包装库 OcrTextPort 的业务适配器)
tools/{build_trees,repair_trees,generate_questions}.pyapp/harness/video_split_cli.py 368/492/1462/824 各自复制一份手写装配(共 6 处 GovernedLLMClient(...) 构造) 改写(装配段换 from_env,业务编排保留)
治理层单测 tests/unit/test_{governed_llm,streaming,vlm_adapter,breaker,ocr_adapter,redis_cache,telemetry,infra_settings}.py 治理栈自身测试 删除(库测试继任);业务测试(假 LLMProvider 注入)保留为验收基准

3. 组件替换映射表(签名实测对比)

项目组件 库对应物 签名兼容性(实测) shim 形态
LLMProvider.chat(messages, *, session_id=None, parent_call_id=None, cache_salt=None) (core/protocols.py:22-29) GatewayClient.chat() ARCHITECTURE §5.2/§7.8/§7.5 含这三个语义(链路 id 调用方传入、salt 进 key),但 §5.1 未固化 chat() 便捷方法的 kwargs 形态 库若原生支持同名 kwargs 则零 shim(首选,见 §9-R1);否则 3 行包装函数
VLMProvider.chat_with_images(messages, images: list[str|Path], ...) (core/protocols.py:36-44) 无库端口VLM 封装属业务侧,ARCHITECTURE §11.2 chat() 须原生接受多模态 content partsimage_url data URL 数组,adapters/vlm.py:112-130 组装格式) vlm.py 改写为包装库 client:保留 _encode_image/_inject_imagesself._llm.chat(...) 换成库调用,对 33 处业务调用点零改动
TelemetryRecorder.record_llm_call(15 个关键字参数) (core/protocols.py:51-69) 库内部遥测(单一 helper 铁律) 业务侧无人调用 record_llm_callgrep 实测仅 Protocol 定义与 adapter 实现);Runner 注入 telemetry 后从未使用(runner.py:738 赋值即终点,死注入) 无需 shim:删 Protocol、删 Runner 参数
LLMResponse(11 字段) (core/types.py:19-29) LLMResponse(§5.1 超集) 字段逐一比对完全一致content/thinking/model/provider/prompt_tokens/completion_tokens/latency_ms/ttft_ms/max_inter_token_ms/cache_hit/call_id);库新增 source_name/cost/usage_source 只增不删 core/types.py 改 re-exportfrom polygateway import LLMResponse
CircuitOpenError (adapters/llm.py:36) CircuitOpenError(§6.1 业务侧无 except 该异常(grep 实测),仅治理层内部 无需 shim
MonkeyOCRClient.transcribe_frames(frame_paths) -> str (adapters/ocr.py:88) OcrTextPort.recognize_text(bytes)(§7.10 不兼容:项目端口收路径列表、返回拼接文本、单帧失败跳过;库端口收单帧 bytes、失败抛异常 业务适配器(约 30 行):读文件→逐帧 recognize_text→行过滤去重→"帧N: ..." 拼接→单帧异常捕获跳过;实现 app/ports.py:OCRProvider 不变,vision.py:105 调用点零改动
EmbeddingProvider(同步 embed()) (app/ports.py:17-36) polygateway.EmbeddingClient.embed(async,M2 已交付) 同步→异步适配 + list[list[float]]→ndarray 转换留业务侧 adapter;normalize 走库开关 M4 执行

4. 调用点清单(grep 实测,33 处 await

业务调用点全部经 Protocol迁移后形态不变(前提是 §3 的 shim 策略成立);需要改动的只有装配点与两个特殊点。

分组 调用点 (file:line) 迁移后形态
llm.chat (16 处) core/agent/loop.py:336core/evolution/evolve.py:566,881,1074,1162core/evolution/diagnose.py:389,982,1917app/tree/video_builder.py:1117app/search/summarizer.py:236app/tree/repair/{regenerator.py:436,480, supplement.py:460}app/harness/momentum.py:163app/question_gen/{gates.py:354,389,423, pipeline_v2.py:753} 不变(库 client 直接满足签名)
vlm.chat_with_images (14 处) app/tree/video_builder.py:940,1047,1084app/search/vision.py:126,148app/tree/repair/regenerator.py:390app/question_gen/{adversarial_filter.py:393, distractor_selector.py:150,185, gates.py:314,322, synthesizer.py:720, generator_v2.py:424} 不变(改写后的 vlm.py 继续满足 VLMProvider
ocr.transcribe_frames (1 处) app/search/vision.py:105(外层已有降级边界 105-107:失败 warning 不注入) 不变(业务适配器满足 OCRProvider);底层升级为多源+重试+熔断
装配点 (8 处构造) main.py:105(经 _make_llm 实例化于 122,130)、app/harness/video_split_cli.py:328tools/build_trees.py:216,232tools/repair_trees.py:154,172tools/generate_questions.py:265,988,1007 全部换 from_env 按角色装配(§5

三个必须专门论述的点

  1. 四角色装配与 evolve_llm = llm 别名main.py:128):.env 定义了 SEARCH/JUDGE/VL/EVOLVE 四组配置(.env.example:6-23),但实测 InfraSettings 只读 search/vl/evolve 三组(main.py:24-34)且 EVOLVE_LLM_* 读入后从未使用——_build_adapters 直接 evolve_llm = llm 静默共享(配置面看似独立实则死配置);JUDGE 组不在 InfraSettings 里,仅 tools/generate_questions.py:1008-1010 直接 os.environ 裸读。迁移后按 §7.7 逻辑角色装配,共享必须显式:EVOLVE 要么显式声明共享 SEARCH client,要么启用独立配置——需人类拍板(行为变化见 §8)。
  2. tools/build_trees.py 跨视频共享 semaphoreapi_sem = asyncio.Semaphore(api_concurrency)build_trees.py:294TREE_BUILD_API_CONCURRENCY=16)注入 VideoTreeBuilder(api_semaphore=),包裹 LLM 与 VLM 两个 client 的每次调用video_builder.py:365-366)。迁移后由库限流承接而非 gather_bounded——gather_bounded 限的是任务列表并发,这里限的是"跨两个 client 的全局在途调用数",语义对应库的全局并发闸。前提:SEARCH 与 VL 两个 client 共享同一 limiter 后端实例(⚠️ 见 §9-R5);配额满行为配 wait 才与 semaphore 等价。
  3. AgentLoop 双层重试core/agent/loop.py:84-101,295-315):步级重试 step_retries=2, delays=(20,40),捕获 (TimeoutError, OSError)——即"穿透治理层的瞬时异常"。库单层重试原则(§7.2)下,transport 会把这些异常翻译为领域错误,TimeoutError/OSError 将不再穿出,原配置下步级重试静默失效TransientError 不是 OSError 子类)。去留论述:这层的语义实为"任务步兜底"(治理层重试预算耗尽后再给整步一次机会),属业务侧任务级重试,库允许在库外包。建议保留但必须改造:利用 AgentLoop 已参数化的 retryable_exceptions 注入库的 (TransientError, AllSourcesExhausted);若判定治理层预算已足够则删除该层——二选一,禁止保留原异常集合(静默失效 = 隐性行为删除)。

5. 配置迁移

5.1 .env 键名映射

旧键 (.env.example 实测) 库键(形态待 M1 定稿,按 §9 约定) 语义差异
SEARCH_LLM_{MODEL,BASE_URL,API_KEY} SEARCH__{PROVIDER}__1__{MODEL,BASE_URL,API_KEY} 单源→源列表长度 1 的特例;provider 由键名显式给出,消灭 model.split("-")[0] 猜测(main.py:109
JUDGE_LLM_* JUDGE__... 现状仅被 generate_questions.py 裸读 os.environ;迁移后归入统一装配
VL_LLM_* VL__... 同 SEARCH
EVOLVE_LLM_* EVOLVE__... 或删除 现状为死配置(§4 点 1);显式共享则删键,独立则启用——人类拍板
LLM_TIMEOUT / LLM_MAX_RETRIES / LLM_RETRY_BASE_DELAY / LLM_RETRY_MAX_DELAY / LLM_CIRCUIT_BREAKER_{THRESHOLD,COOLDOWN} / LLM_TTFT_TIMEOUT / LLM_INTER_TOKEN_TIMEOUT 同名沿用(§9 承诺) 熔断阈值 max(cfg, concurrency*2) 从 .env 注释手动约定(.env.example:44)变为库内自动计算(§7.4)
REDIS_URL / REDIS_CACHE_TTL 库缓存后端配置(TTL>0 校验继承,redis_cache.py:27-31 语义同
(无) 缓存 namespace(新增必填) §7.5 key 公式新增字段,建议 video-tree-trm5
MONKEY_OCR_URLS(逗号列表) OCR__MONKEY__{1,2}__BASE_URL 逗号列表→多源配置;轮询升级为选源策略
TREE_BUILD_API_CONCURRENCY 库全局并发限额键 语义:跨 SEARCH+VL 两 client 的全局在途上限(⚠️ §9-R5
ASR_*Groq whisper 删除 死配置零实现(D10 已确认不作需求证据)
EMBED_API_KEY/URL 保留业务侧 Q3 未决
no_proxy/NO_PROXY 保留环境级;OCR 的 trust_env=False 需库支持 ⚠️ §9-R9

5.2 装配代码 before/after

Beforemain.py:_build_adapters,手写约 110 行,节选骨架):

breaker = CircuitBreaker(fail_threshold=..., cooldown_s=...)
cache = RedisResponseCache(redis=aioredis.from_url(...), ttl_s=ttl) if settings.redis_url else None
telemetry = SQLiteTelemetryRecorder(Path("logs/telemetry.db"))
def _make_llm(model, base_url, api_key, *, thinking):
    return GovernedLLMClient(model=..., provider=model.split("-")[0], breaker=breaker,
                             cache=cache, telemetry=telemetry, ...)  # 15 个参数
llm = _make_llm(settings.search_llm_model, ..., thinking=True)
evolve_llm = llm                       # 静默别名,EVOLVE_LLM_* 配置被忽略
vlm = GovernedVLMClient(_make_llm(settings.vl_llm_model, ..., thinking=False))
ocr = MonkeyOCRClient(urls=settings.monkey_ocr_urls.split(","))

After(伪代码,具体 API 以 M1 设计定稿为准):

from polygateway import GatewayClient

llm = GatewayClient.from_env(role="SEARCH")
evolve_llm = llm                              # 共享必须显式:或 from_env(role="EVOLVE")
vlm = GovernedVLMClient(GatewayClient.from_env(role="VL"))   # 业务侧 base64 封装保留
ocr = FrameOcrAdapter(OcrTextPort_from_env()) # 业务适配器包装库 OCR 端口
# breaker/cache/telemetry/limiter 全部由 from_env 按配置内建,共享后端见 §9-R5

6. 迁移步骤(每步一个 commit 作回滚点)

# 步骤 验证方式 回滚
0 M1 后最小接入冒烟(§1,独立分支) 冒烟脚本 + 遥测/缓存实测 丢弃分支
1 feature 分支;.env 增库键(旧键暂双存) from_env 装配冒烟 git revert
2 core/types.py LLMResponse 改 re-exportcore/protocols.py 删 TelemetryRecorder、LLMProvider 指库 make test(类型层面无行为变化) 单 commit revert
3 adapters/vlm.py 改写为包装库 clientmain.py:_build_adapters 换 from_envEVOLVE 决策落地);Runner 删 telemetry 死注入参数 make test + --mode infer 小样本跑通 单 commit revert
4 AgentLoop retryable_exceptions 注入库异常(或删除步级重试,按 §4 点 3 决策) 断网/假 transport 注错的集成测试证明步级重试可触发 单 commit revert
5 删除 adapters/{llm,breaker,streaming,redis_cache,telemetry}.py 及其单测 make test 全绿;grep 确认无残留 import 单 commit revert
6 四个工具/CLI 装配点换 from_envbuild_trees 删 semaphore 改库全局并发闸;generate_questions 删 JUDGE 裸读) 每个工具 --limit 1 级小跑 逐工具 commit
7 M3 后)adapters/ocr.py 删除,业务适配器接 OcrTextPort vision.py 路径集成测试 + OCR 注入率遥测对照 单 commit revert
8 一次完整 train run 对照旧遥测(准确率/成本/缓存命中率);删旧 .env 键 指标无回归 保留分支不合并

7. 旧版行为审计(逐条:保留/替换/修复/有意放弃)

# 现有行为(含非功能行为,file:line) 迁移后
1 VLM 响应也走缓存,且 base64 data URL 整段进 sha256 keyvlm→llm 委托 + redis_cache.py:69-73 全量 messages 进 hash 替换:多模态 part 先摘要再 hash(§7.5)——key 全变,见 §8 风险 1
2 cache_salt 仅非 None 才进 key payload(保证旧键不失效,redis_cache.py:63-71 有意放弃:库 key 公式重构,无旧键兼容义务
3 SSE 流耗尽未收 [DONE]_SseAnomaly("truncated_no_done") 判瞬时、不写缓存(llm.py:584-586 保留(归 TransientErrorD2 明确此信号是选手写 transport 的理由)
4 qwen <think> 剥离 + deepseek reasoning_contentthinking 注入靠 "qwen" in provider 字符串猜(llm.py:130-164,357 替换D11 provider 注册表,行为等价、机制显式
5 熔断按 provider 字符串计数;main.py 中 SEARCH 与 VL 共享同一 breaker 实例main.py:80,111),provider 不同故计数分开 替换:按 source_name 计数(§7.4),语义更细
6 半开只放一个探针防惊群(breaker.py:44-48);401/403 force_open 一击即熔(llm.py:410-411 保留(库蓝本即此实现)
7 429 一律判瞬时重试,不细分 insufficient_quota;无 Retry-After 解析(llm.py:169,185-189 修复429+insufficient_quota → SourceDeadErrorRetry-After 取大者(§6.2
8 缓存命中:独立 call_id、latency_ms=0、遥测必录 cache_hit=Truellm.py:309-341 保留(§4.4 同款)
9 遥测降级不冒泡(初始化失败 conn=None、写失败 warning 丢弃,telemetry.py:77-98,126-153);INSERT OR IGNORE 幂等 保留(降级方向铁律同向)
10 装配时 Redis 不可用 → 降级无缓存(main.py:91-97);TTL≤0 拒绝启动(redis_cache.py:27-31 保留
11 重试全部落在同一源退避等待(单源无换源) 替换:退避与换源结合(§4.4 步 3),单源配置下行为退化为等价
12 遥测 messages 字段全量 JSON 落 SQLite——VLM 调用的 base64 图片整段进 telemetry.dbllm.py:330,391 json.dumps(messages) 修复建议:库遥测对多模态 part 摘要(⚠️ §9-R12ARCHITECTURE 未覆盖)
13 OCR:同步 requests + 线程局部 Session + trust_env=False 绕代理(ocr.py:41-47);双端点加锁轮询(ocr.py:108-109);单帧失败跳过返回空(ocr.py:117-119);行级过滤(len≤1)与帧内去重、"帧N: " 拼接(ocr.py:120-128);check_health 启动预检(ocr.py:64-70 传输/轮询/重试替换(库多源全治理);过滤/拼接/单帧跳过保留业务侧(§3 适配器);trust_env(per-source 键)与 health(逐源 dict,resp.ok 收紧为 2xx)已按 M3 设计 §10.1 落地,R9/R10 已闭
14 tools/build_trees.py 实测 cache=Nonebuild_trees.py:223,239)——建树不走缓存,断点续跑靠 progress.json+完整性双重跳过(build_trees.py:273-279 断点续跑纯业务保留;迁移后建树可统一开启缓存(行为增强,重跑段内调用免费)
15 三处写死 stream=True,短请求也走 SSE+看门狗(llm.py:508 替换可选:库放开非流式快路径(§7.1),默认行为不变
16 Runner 注入 telemetry 从未使用(runner.py:738 死注入);EVOLVE_LLM_* 死配置(§4 点 1 修复(顺带清理,属迁移必要改动非 gold-plating
17 AgentLoop 步级重试捕 (TimeoutError, OSError)loop.py:92 改造或删除(§4 点 3;保留原样 = 静默失效,禁止)
18 CancelledError 全栈穿透(loop.py:280-282 明确不捕获;治理层无 except BaseException 保留(库铁律同向)

8. 行为差异与风险

# 差异/风险 影响与缓解
1 缓存 key 全量变化key 前缀、namespace、多模态摘要、salt 进 payload 方式均变)→ 迁移瞬间全量缓存失效 一次性重付费;TTL 本为 7 天(REDIS_CACHE_TTL=604800)自然滚动。缓解:迁移窗口选在训练间隙,首个 run 按无缓存成本预算
2 OCR 从裸调升级全治理:失败行为从"静默跳过"变"重试→换源→熔断→最终抛异常" 延迟分布变化(重试引入等待);vision.py:105-107 降级边界保留,最终失败仍不中断推理。收益:双端点一台挂掉不再损失 50% 帧证据
3 429 语义变化:insufficient_quota 从"白烧重试预算"变"立即熔断换源" 行为更优;单源配置下表现为快速失败——排查配额问题更快但对"等配额恢复"场景需配 wait
4 semaphore→限流闸:等待语义需显式配 wait,且依赖跨 client 共享后端(§9-R5 未闭合前 build_trees 迁移被阻塞) M1 设计必须先解决 R5,否则该工具只能临时保留 semaphore
5 遥测 schema 变化:表结构/字段名(model_name→model)与新增字段 grep 实测项目内无 telemetry.db 读取方(仅写入),风险低;旧 db 留档即可
6 熔断阈值改库内自动 max(cfg, concurrency*2) 与 .env 注释的手动约定等价,风险低
7 EVOLVE 角色决策(共享或独立)可能改变进化步的模型/配额行为 迁移前人类拍板并写进配置注释

9. 对库的反向约束清单(本文档最重要产出)

# 约束 里程碑 状态
R1 chat() 便捷方法必须接受 session_id / parent_call_id / cache_salt 关键字参数(33 处调用点零改动的前提) M1 语义已覆盖(§7.5/§7.8),签名形态需 M1 设计固化
R2 chat() 原生接受多模态 content parts 数组(image_url data URL),VLM 封装才能留业务侧 M1 已覆盖(§2.3/§11.2
R3 LLMResponse 11 字段只增不删不改名 M1 已覆盖(§5.1,实测一致)
R4 逻辑角色 from_env(role=...) 须支持 SEARCH/JUDGE/VL/EVOLVE 四角色 + 显式共享声明 M1 已覆盖(§7.7
R5 ⚠️ 架构缺口:多角色 client 须能共享同一限流/熔断状态后端TREE_BUILD_API_CONCURRENCY 的全局并发闸横跨 SEARCH+VL 两 clientmain.py 现状 breaker 也跨 client 共享)。from_env 按角色装配多个 client 时的后端共享语义 ARCHITECTURE 未定义 M1 缺口
R6 非流式快路径、cache salt、gather_bounded M1 已覆盖(§7.1/§7.5/D5
R7 库错误类型公共导出且可被业务 exceptAgentLoop retryable_exceptions 注入 TransientError/AllSourcesExhausted M1 基本覆盖(§6),导出面需 M1 确认
R8 缓存 namespace 必填对单项目是新增负担 M1 已覆盖(§7.5);建议 from_env 支持项目名默认
R9 已闭(M3): SourceConfig.trust_env + {SCOPE}__{PROVIDER}__{N}__TRUST_ENV 键 M1 已落地,MonkeyOcrTransport 与 openai_compat 同款尊重;LAN 直连配 OCR__MONKEY__N__TRUST_ENV=false M3 已闭
R10 已闭(M3): OcrClient.check_health() -> dict[str, bool] 逐源并发预检(2xx=True,取消穿透);启动门语义 = all(值),业务可逐源定位坏端点打日志 M3 已闭
R11 ⚠️ 架构缺口/勘误embedding 去向(Q3)——实测 RemoteEmbeddingProvider 无任何重试embedding.py:146-172,同步 OpenAI SDK 裸调),ARCHITECTURE §13-Q3"各有一套独立重试实现"对 Video-Tree 不成立(无治理反而更需要进库);且现端口为同步 embed(),库若 M2 纳入必为异步端口,业务调用点需适配 M2 缺口Q3 决策输入)
R12 ⚠️ 架构缺口:遥测 messages 字段对多模态 part 应摘要——现状 base64 整段进 SQLitellm.py:330),§7.8 未规定,照搬会让库遥测继承 db 膨胀问题 M1 缺口

不确定项声明: 库侧 from_env(role=...)、OCR 装配工厂的具体 API 名称以 M1/M3 设计文档定稿为准,本文 §5.2/§6 中相应伪代码届时同步修订;telemetry.db 是否存在项目外的离线分析脚本消费方未能实测(项目内 grep 无读取方)。