75 Commits

Author SHA1 Message Date
iomgaa 6ac96dff64 Merge branch 'feat/question-gen-v3' 2026-07-17 06:13:44 -04:00
iomgaa 7386e5af57 Merge remote-tracking branch 'origin/main' 2026-07-17 06:05:42 -04:00
iomgaa 0414948682 merge: question-gen v3 + preflight fixes + continuous concurrent gate 2026-07-17 06:02:39 -04:00
iomgaa eea609d960 refactor: remove deprecated retriever module
RecursiveRetriever was a failed approach, not carried into TRM5.
- delete app/retriever/ (empty placeholder)
- drop retriever + train blocks from config/default.yaml
- renumber fidelity checklist 13->12 items (drop #4, shift up)
- sync core-goal text, dir tree, module-interaction diagrams
  across CLAUDE.md, ARCHITECTURE.md, overview.md, README.md
- reference/ kept intact as historical code
2026-07-08 23:09:30 -04:00
iomgaa f1dea4f68f merge: feat/app-harness — app/harness/ 训练循环编排层(14 文件, 算法保真 #6/#10/#13) 2026-07-07 20:35:04 -04:00
iomgaa 7a00bc1a28 style(harness): ruff format batching.py + log.py 2026-07-07 20:34:48 -04:00
iomgaa be0e89401e feat(harness): __init__.py public API + lint fixes 2026-07-07 13:45:48 -04:00
iomgaa 2296134f73 feat(harness): runner.py — train loop orchestrator (#13 algorithm fidelity)
Three-level nesting (epoch -> step -> per-skill), slow update 10-step
sequence, checkpoint/resume, early stop, probation accept/reject/rollback.

Key TRM4->TRM5 changes:
- sync -> async (all inference/diagnosis/evolve/validate awaited)
- LLMClient.from_env -> injected LLMProvider (DI via constructor)
- Direct DB/file access -> module functions (workspace/store/log)
- _TrainState as train() local, explicit param passing to helpers

Module-level pure functions extracted for testability:
resume_plan, _guard_infra_failures, _apply_batch_correctness,
_compute_total_steps, _should_early_stop, _format_applied_edits,
_fallback_summary, _write_skip_report, _outcome_to_quadrant_pairs,
_build_comparison_pairs, _batch_from_ids, _snapshot_current_skills.

Tests: 34 unit tests covering 13a-13e sub-tasks.
Radon: all functions Grade B or better.
2026-07-07 13:43:20 -04:00
iomgaa 7bc6fc752c feat(harness): validate.py — async 块序贯验证编排 + Probation 统一定义 2026-07-07 13:20:43 -04:00
iomgaa a6b816db94 feat(harness): checkpoint.py — TrainState 序列化 + 原子写 + 指纹校验 2026-07-07 13:13:37 -04:00
iomgaa d7f1bdeea6 feat(harness): inference.py — async run_inference + DI 2026-07-07 13:04:26 -04:00
iomgaa 886a444d1d feat(harness): momentum.py — async 慢更新动量生成 2026-07-07 13:01:04 -04:00
iomgaa a550d39e1c feat(harness): observation.py — 五张观测表 + step/epoch 报告 2026-07-07 12:55:12 -04:00
iomgaa bd4e438c6c feat(harness): gate_ladder.py — 信息阶梯 + BaselineCache (#6 算法保真) 2026-07-07 12:55:12 -04:00
iomgaa e0f3ee10ec feat(harness): pools.py — 三池切分(test→validation→diagnosis) 2026-07-07 12:48:54 -04:00
iomgaa 9800fef37a feat(harness): batching.py — FFD + round-robin mini-batch (#10 算法保真) 2026-07-07 12:47:33 -04:00
iomgaa d349fe1148 feat(harness): workspace.py — Workspace lifecycle + VersionedSkillStore/PromptStore
- ResolvedPaths frozen dataclass: store_dir, videos_dir, questions_dir,
  skills_dir, prompts_dir, workspace_dir, db_path, analyses_dir, runs_dir
- init_workspace: create ws + copy seed weights from store
- init_workspace_from_seed: create from seed with fail-fast questions check
- load_manifest / resolve_paths: manifest I/O + path resolution
  (skills/prompts resolve to workspace, videos/questions to store)
- update_manifest: key whitelist validation
- record_run: idempotent history append + per-video wiki dirs
- read_best / update_best: best pointer independent of current
- list_video_ids: videos with tree.json
- archive_workspace: move to .archive/<name>-<ts>
- VersionedSkillStore: implements core/evolution/protocols.py::SkillStore
- VersionedPromptStore: implements core/evolution/protocols.py::PromptStore
- 21 tests all passing (incl. Protocol compliance checks)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 12:41:59 -04:00
iomgaa b052c1f3ee feat(harness): store.py — Store 版本操作 + Seed 管理
从 TRM4 core/workspace.py 拆出 Store + Seed 相关函数:
- _parse_version / list_versions / next_version / advance_version
- _write_meta / init_store
- init_seed / list_seeds / read_seed
- extract_run_db(保留原始 CREATE 语句重建主键约束)
- promote_to_seed(强校验版本一致 + 非 NULL + finally 清理)

26 个测试全部通过,radon 复杂度 A (2.83)。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 12:36:36 -04:00
iomgaa be3c176a46 feat(harness): HarnessLog SQLite wrapper + RunLogImpl readonly port
- HarnessLog: TRM4 direct port with WAL mode, threading.Lock, INSERT OR
  IGNORE idempotent _runs, context manager (completed/failed), create_table
  with auto run_id+timestamp, insert/insert_many/execute/query/log_event
- RunLogImpl: implements core/evolution/protocols.py::RunLog Protocol with
  independent sqlite3.connect for read-only SELECT (no _runs pollution),
  asyncio.to_thread wrapping for async interface
- _read_table: shared readonly helper with optional question_ids filtering,
  graceful empty-list return for missing tables
- Tests: 17 cases covering thread safety, idempotent inserts, context
  manager status, WAL mode, protocol compliance, readonly isolation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 12:29:29 -04:00
iomgaa b929a5db6c fix(harness): Codex functional review 修复 — 命名/集成测试/delta_min/promote 消息
- _apply_env_overrides → _apply_env_var_overrides,docstring 明确从 os.environ 读取
- 新增 TestLoadConfigRealYaml:用真实 config/default.yaml 验证嵌套 harness 解析
- 新增 test_delta_min_negative_rejected:覆盖 gate_delta_min >= 0 校验
- 恢复 promote 模式独立错误消息(从合并分支分离回 TRM4 原始提示)
- 77 个单元测试全部通过,radon 全部 Grade B 或更好

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 12:23:27 -04:00
iomgaa ce43871828 fix(harness): 补充 train 模式 run_id 校验 + 拆分函数保持 radon Grade B
- _validate_mode_deps: 恢复 train 非 resume/fresh 时必须提供 run_id 校验
- 提取 _validate_train_run_id 用 early return 展平条件,避免 radon Grade C
- 合并 promote run_id 检查到 diagnose/evolve/promote 统一检查
- 新增 4 个测试:train+run_id / train+resume / train+fresh / train+baseline
- radon cc -n C 无输出(全部 Grade B 或更好)
- 74 个单元测试全部通过

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 12:14:28 -04:00
iomgaa 6a2ddb1624 refactor(harness): 拆分校验函数降低 radon 圈复杂度至 Grade B
- _validate: 拆出 _validate_mode(mode 依赖校验)+ _validate_basic(标量/枚举校验)
- _validate_gate: 拆为 _validate_gate_thresholds(e 值/净胜/方向)+ _validate_gate_ladder(阶梯/块序贯)
- load_config: 提取 _apply_env_overrides 函数
- radon cc -n C 无输出(全部 Grade B 或更好)
- 70 个单元测试全部通过

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 12:01:46 -04:00
iomgaa 09a385addc feat(harness): RunConfig frozen dataclass + 四层校验 + YAML/CLI/.env 三层加载
- RunConfig: 46 字段 frozen dataclass,从 TRM4 core/harness/config.py 迁移
- 四层校验链:_validate → _validate_edit_budget + _validate_minibatch + _validate_gate
- 新增 .env 覆盖层:工程配置(workspace_dir, store_dir)可通过 HARNESS_* 环境变量注入
- 合并优先级:CLI > .env > YAML(CLAUDE.md §4.5)
- load_config 支持嵌套 harness 段和扁平 YAML 两种格式
- run_id 改为默认空字符串(CLI-only 字段,YAML 不提供)
- resume/fresh 互斥校验不在 config 层(移至 runner.py)
- 70 个单元测试全部通过

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 11:57:35 -04:00
iomgaa d84cd679b4 feat(evolution): export dataclass types from __init__.py 2026-07-07 11:48:13 -04:00
iomgaa 292dd0fa13 docs: app/harness/ implementation plan — 15 tasks, algorithm fidelity #6/#10/#13, 120 TRM4 tips 2026-07-07 11:45:38 -04:00
iomgaa eba4344a4b docs: app/harness/ design — 14-module training loop orchestration layer 2026-07-07 11:28:29 -04:00
iomgaa 4e241aa581 merge: feat/tree-index — core/evolution/ extractable kernel + tree/search/question_gen modules 2026-07-07 10:29:54 -04:00
iomgaa 8bc4132750 feat(evolution): __init__.py public API + ARCHITECTURE.md Protocol update 2026-07-07 10:28:14 -04:00
iomgaa 4634414606 feat(evolution): evolve.py per-target evolution — skill/system/tool (#9) 2026-07-07 10:26:58 -04:00
iomgaa 6072ee7d0b feat(evolution): evolve.py validation + helpers (#9) 2026-07-07 10:12:15 -04:00
iomgaa dc091361c3 feat(evolution): diagnose.py aggregation + case packs + run_diagnosis (#8) 2026-07-07 10:04:48 -04:00
iomgaa 49d6fe8f51 feat(evolution): diagnose.py metrics + attribution (Stage 1, #8) 2026-07-07 09:55:22 -04:00
iomgaa f7193551dd feat(evolution): validate.py — pure block validation decision functions (#7) 2026-07-07 09:47:45 -04:00
iomgaa 3005f24577 feat(evolution): patch.py — 补丁引擎移植(算法 #9),51 测试全通过
从 TRM4 core/harness/patch.py (427 行) 零修改移植到 core/evolution/patch.py。

包含:
- 7 个常量(APPENDIX/MOMENTUM marker + MAX_CHARS + HEADING)
- appendix 区:追加/提取/替换/边界检测,损坏态 ValueError
- momentum 区:替换/提取/边界检测,注入防护
- apply_patch_with_report:4 种 op(append/insert_after/replace/delete)
- 冻结区坐标判定(每条 edit 重算)、report 1-based index
- 51 个单元测试覆盖全部公共 API 及边缘场景

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 09:44:05 -04:00
iomgaa 4eefbfdd74 feat(evolution): gate.py — CE-Gate e-process 纯函数 (#5 算法保真)
从 TRM4 core/harness/eprocess.py 逐行迁移,零逻辑变更:
- compute_e_value: 截断 Beta 混合 e 值(log 空间 + betainc 对称性)
- gate_decision: 四出口优先级链(confirmed→directional→futility→exhaustion→continue)
- probation_verdict: 试用期非对称双向结算
- 常量保真: _WALD_WIN=ln1.4, _WALD_LOSS=ln0.6, _SHRINK_PSEUDO=4

仅变更: import 路径 + GateParams/GateVerdict 移至 types.py + 中文 docstring

14 tests 覆盖: e 值数学、边界校验、四出口路径、试用期三分支

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 09:38:21 -04:00
iomgaa 9d4d52dac5 feat(core/evolution): protocols.py + types.py 基础层 — 18 个 dataclass + 3 个 Protocol
TRM4 诊断/进化/门控数据类型迁移至 TRM5 Clean Architecture 内核。
逐字段比对 TRM4 的 eprocess.py、diagnose.py、evolve.py 保真迁移。

types.py (18 个 dataclass):
- Gate: GateParams, GateVerdict (frozen, 原样迁移)
- 诊断: SpanMetrics, SkillStepAdherence, QuestionMetrics,
  ErrorAttribution, CaseSample, SkillCasePack, SystemCasePack,
  ToolCasePack, DiagnosisResult (全部 frozen=True)
- 进化: EvolutionRecord (mutable), RejectedEdit (frozen),
  EvolutionResult (frozen, 移除 skills_version/prompts_version)
- 新增: PairResult, QuadrantClassification (块验证纯决策输出)
- 新增: DiagnosePrompts, EvolvePrompts (模板束, frozen)

protocols.py (3 个只读 Protocol):
- SkillStore, PromptStore (同步文件读取)
- RunLog (异步日志查询, 隔离 SQL)

变更理由:
- QuestionMetrics 由 TRM4 mutable 改为 frozen (一次性构造)
- ErrorAttribution 由 TRM4 mutable 改为 frozen (构造时填入全部字段)
- EvolutionResult 移除版本管理字段 (app/ 职责)

涉及算法: #5(CE-Gate), #8(诊断瀑布), #9(进化引擎)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 09:34:04 -04:00
iomgaa 09100dcbd4 docs: core/evolution/ implementation plan — 9 tasks, TDD, algorithm fidelity checks 2026-07-07 07:55:21 -04:00
iomgaa 84e8abbf4f docs: core/evolution/ extractable kernel design — gate, patch, diagnose, evolve 2026-07-07 07:39:24 -04:00
iomgaa 7cd49a5a3f docs: 同步 app/search/ 模块结构 + OCRProvider 签名到 ARCHITECTURE.md 2026-07-07 06:14:26 -04:00
iomgaa 499c5b8043 feat(search): __init__.py 公开 API + 修复 OCR 测试 asyncio 兼容性 2026-07-07 06:13:25 -04:00
iomgaa 4baf92c93f feat(search): PromptManager — 搜索 Agent 提示词加载与组装
从 TRM4 core/search/prompt.py 迁移。有意变更:
- 工具描述从 app.search.tools.get_tool_descriptions 获取
- format_user_prompt 参数显式化(question/options/l1_node_ids/task_type)

16 个单元测试覆盖 __init__、build_inference_prompt(auto/manual/none
三种 skill_mode)、format_user_prompt、load。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 06:11:13 -04:00
iomgaa f4f92b0938 feat(search): 实现 SearchToolDispatcher 工具调度器 (Task 7)
- 新增 app/search/tools.py:
  - get_tool_descriptions() 工具描述文本(与 TRM4 一致)
  - SearchToolDispatcher 类实现 ToolDispatcher Protocol
  - dispatch() 按工具名路由: view_node / search_similar /
    observe_frame / submit_answer / read_skill
  - ValueError(未知工具)上抛,KeyError/FileNotFoundError 捕获返回错误文本
  - view_node: env.get_node_text + summarize_node + get_children_info + summarize_children
  - search_similar: env.search_similar + summarize_nodes_batch
  - observe_frame: env.resolve_frame_paths + get_subtitle + observe_frame + 字幕前置

- 修复 app/tree/environment.py get_children_info():
  - 原实现返回 _format_time_range (str) 导致 summarize_children 解包失败
  - 改为返回原始数值元组 via 新增 _node_time_range_raw 静态方法

- 新增 tests/unit/test_search_tools.py (14 tests):
  - get_tool_descriptions 含/不含 read_skill
  - 五种工具 dispatch 路由验证
  - 未知工具 ValueError + 节点不存在错误文本

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 06:07:27 -04:00
iomgaa ca3ea1cdf2 style: format summarizer.py 2026-07-07 05:55:40 -04:00
iomgaa ba7fdaddf6 style: format vision.py 2026-07-07 05:53:33 -04:00
iomgaa 3ae3d5ab50 feat(search): app/search/vision.py — 两轮 VLM 帧观察模块
从 TRM4 core/tree/vision.py 迁移 observe_frame,关键变更:
- VLM 调用走 VLMProvider.chat_with_images Protocol(images 传 Path)
- OCR 调用走 OCRProvider.transcribe_frames 异步 Protocol
- 遥测字段 session_id / parent_call_id 透传
- 帧文件存在性前置校验

12 个单元测试覆盖:两轮正常、仅提取、OCR 注入/失败降级/None、
VLM 提取失败、VLM 验证失败降级、帧缺失、stats 完整性、
分歧/弃权标记、遥测透传。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 05:52:54 -04:00
iomgaa 86b19d1e07 feat(adapters): OCRProvider Protocol + MonkeyOCRClient 异步适配器
- app/ports.py: 新增 OCRProvider Protocol(runtime_checkable,与
  EmbeddingProvider 同级),定义 async transcribe_frames 端口
- adapters/ocr.py: 从 TRM4 core/tree/ocr.py 保真迁移 MonkeyOCRClient
  - assert → ValueError(P5 防御性校验)
  - 公开方法改 async(asyncio.to_thread 包装同步 HTTP)
  - 内部逻辑不变:多端点轮询、线程安全 Session、单帧降级、行去重
- tests/unit/test_ocr_adapter.py: 17 个测试覆盖 Protocol 合规、
  构造校验、健康检查、转录、降级、去重、轮询

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 05:47:55 -04:00
iomgaa 60e737e2fc feat(search): app/search/skills.py — 技能注册表与 frontmatter 解析
从 TRM4 core/search/skills.py 保真迁移。提供 parse_frontmatter、
strip_frontmatter、SkillRegistry、discover_skills 四个公共 API。
逻辑完全一致,仅调整导入路径并添加中文 docstring。

17 个单元测试全部通过,覆盖正常/异常/边界场景。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 05:46:25 -04:00
iomgaa 82f1607195 style: format environment.py 2026-07-07 05:46:25 -04:00
iomgaa 44ee62867d feat(tree): add get_node_text + get_children_info to TreeEnvironment
- get_node_text(node_id, anchor=False): returns raw text + optional
  anchor_map dict by parsing [cN]/[sN] prefixes from anchored text
- get_children_info(node_id): returns structured child list with
  id/time_range/summary (description truncated to 120 chars)
- Both methods reuse existing internal helpers (_node_full_text,
  _node_anchored_text, _get_children, _node_description,
  _format_time_range)
- 9 new test cases across TestGetNodeText and TestGetChildrenInfo

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 05:45:48 -04:00
iomgaa ffb37a1c1e chore: 复制 TRM4 v2 prompt 种子文件(9 个,字节级一致)
.gitignore 添加 !store/prompts/ 例外——prompt 是版本化资源需提交
2026-07-07 05:42:11 -04:00
iomgaa dcaeefa484 docs(plan): 恢复被 wiki 工具覆盖的计划全文 2026-07-07 05:39:21 -04:00
iomgaa 7af64db499 docs(plan): app/search/ 搜索 Agent 装配层实现计划(10 Task) 2026-07-07 05:36:25 -04:00
iomgaa 9e1f39c147 docs(design): 修复 Codex 审查发现 — 10 项修正
Critical: OCRProvider 移至 app/ports.py;新增 TreeEnvironment 结构化 API;
         observe_frame 补充字幕上下文拼接;search_similar 补充节点文本获取
Important: 遥测链路透传 session_id/parent_call_id;异常降级边界明确化;
           verify_vision/anchor/assemble_mode 改为必传;Prompt 路径逐文件列出;
           测试目录规范化到 tests/unit/
Minor: 依赖图补全 VLMProvider 连线
2026-07-07 05:29:52 -04:00
iomgaa 5c89ca543a docs(design): 补充 summarizer 模块 — view_node/search_similar 的 LLM 两轮摘要
自审发现 TRM4 三个搜索工具全有 question-conditioned 中间摘要层,
原设计遗漏了 summarizer.py。新增:
- §4.4 summarizer API(summarize_node / _children / _nodes_batch)
- anchor 锚模式完整保留
- 6 个额外 prompt 文件
- 更新交互流程图、错误处理、测试策略
2026-07-07 05:22:55 -04:00
iomgaa 11107f5758 docs(design): 搜索 Agent 装配层设计(app/search/)
方案 A 平铺模块:prompt.py / skills.py / tools.py / vision.py
新增 OCRProvider Protocol + adapters/ocr.py
Prompt 从 TRM4 store/prompts/v2/ 原封不动复制
2026-07-07 05:15:22 -04:00
iomgaa da28c10c84 docs: 同步 question_gen 模块路径到 ARCHITECTURE.md 和 CLAUDE.md
DataLoader 代码位置 generator.py → loader.py;
目录树更新 question_gen/ 结构反映实际文件。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 04:51:26 -04:00
iomgaa d8a903fb54 feat(question_gen): QuestionGenerator Protocol + 模块公开 API
app/ports.py 追加 QuestionGenerator Protocol(预留 LLM 出题接口)。
app/question_gen/__init__.py re-export load_benchmark 和 stratified_sample。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 04:48:21 -04:00
iomgaa 8d515ff01f feat(question_gen): stratified_sample — 分层采样 + 题型保底
算法 100% 保真 TRM4: task_types 过滤、correctness.get(id, False) 语义、
对题在前返回顺序、min_per_class 遍历 pool 全部题型(含稀疏类)。
所有参数显式传入,无默认值。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 04:45:19 -04:00
iomgaa dea8a7d3f6 feat(question_gen): load_benchmark — benchmark JSON 加载
从 JSON 目录 glob *.json 加载题目,stem 作 video_id。
legacy schema 无 difficulty 字段时赋 _LEGACY_DEFAULT_DIFFICULTY 常量。
options/source_nodes 转 tuple 配合 frozen dataclass。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 04:41:25 -04:00
iomgaa eea3bcba3f feat(core): 追加 GeneratedQuestion frozen dataclass
跨层共享类型,被 core/evolution/ 和 app/harness/、app/question_gen/ 使用。
frozen=True + tuple 字段确保不可变。无默认值(显式传入)。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 04:36:56 -04:00
iomgaa 4686adf266 feat(tree/repair): 检测器扩展 — visible_entities/ongoing_actions/spatial_layout 为空也触发修复 2026-07-07 03:15:42 -04:00
iomgaa ee5bd0de57 fix(tools): handle None card in flat tree conversion 2026-07-07 03:13:38 -04:00
iomgaa 73b240cc84 test(tree): 建树模块端到端集成测试
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 02:44:28 -04:00
iomgaa 18971a794b feat(tree/repair): Q&A 反向补全 — 从 TRM4 supplement 迁移
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 02:37:50 -04:00
iomgaa edaa0d8290 feat(tree): VideoTreeBuilder 保真 #1 #2 #3 + 复杂度重构
- 从 reference/video_tree_trm/video_tree_builder.py (994行) 迁移
- 保真算法 #1: L2 轴心建树策略 (asyncio.gather 链式并发)
- 保真算法 #2: VLM 批量帧描述 + JSON fallback (_L3_BATCH_SIZE=5)
- 保真算法 #3: 断点续跑 (progress.json + L1 中间 JSON)
- 新增: VLMProvider/LLMProvider Protocol 替代 LLMClient
- 新增: 结构化 JSON 输出 → L1Card/L2Card/L3Card
- 新增: L2 代表帧复用 L3 帧 (_sample_representative_frames)
- 新增: 字幕注入 + Voronoi 分配
- 重构: 提取 _load_resume_state/_assemble_roots 降低 _build_async 复杂度 D(21)→C(14)
- 44 个单元测试全部通过

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 02:17:50 -04:00
iomgaa 12f20493c1 feat(tree): 质量校验 — 交叉验证 entities/visible_text
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 01:57:32 -04:00
iomgaa fb6f9964d8 feat(tree): 字幕模块 — SRT 解析 + 完整性检查 + Voronoi 分配
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 01:54:09 -04:00
iomgaa e3b027ce34 feat(adapters): GovernedVLMClient — VLMProvider 最小可用实现
- 包装 GovernedLLMClient,注入 base64 图片到 OpenAI Vision API 格式
- 复用 LLM 治理栈全部能力(熔断、缓存、重试、遥测)
- 8 项单元测试覆盖协议满足、图片编码、注入逻辑、不可变性
2026-07-07 01:49:55 -04:00
iomgaa c1680447c0 feat(adapters): EmbeddingProvider Protocol + local/remote 双后端实现
- app/ports.py: 添加 EmbeddingProvider Protocol(runtime_checkable,dim 属性 + embed 方法)
- adapters/embedding.py: 从参考代码迁移,拆分为 LocalEmbeddingProvider 和 RemoteEmbeddingProvider
  - Local: sentence-transformers 冻结推理,维度校验
  - Remote: OpenAI 兼容 API,L2 归一化,按 index 排序
  - 两者均提供 embed() 和 embed_tensor() 统一接口
- tests/unit/test_embedding_adapter.py: Protocol 满足性、形状校验、导入测试

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 01:45:09 -04:00
iomgaa 547c9ddd84 feat(tree): TreeConfig 配置 dataclass
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 01:41:50 -04:00
iomgaa e0f7851975 fix(tree): from_dict 增加 ID 唯一性校验
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 01:40:46 -04:00
iomgaa c136de076d refactor(tree): extract _embed_l2_subtree to reduce embed_all complexity
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 01:37:09 -04:00
iomgaa 22ad014973 feat(tree): TreeIndex 数据结构 — Card 体系 + 节点 + 序列化
- 新增三级 frozen Card dataclass: L3Card(6字段), L2Card(7字段), L1Card(7字段)
- 节点重构: L3Node/L2Node/L1Node 使用 Card 替代原始字符串字段
- 添加 @property 兼容层: description/summary 代理到 Card 字段
- L3Node 新增 subtitle 字段(字幕集成预留)
- JSON 序列化/反序列化支持 Card 结构 + embedding base64 编解码
- load_json 新增 ID 唯一性校验(重复 ID 抛 ValueError)
- 移除 pickle 序列化(仅保留 JSON)
- 日志从 log_msg 迁移到 loguru
- 17 个单元测试全部通过

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 01:35:10 -04:00
iomgaa 2be2569ed8 docs(tree): add tree module vertical slice design and implementation plan 2026-07-07 01:27:36 -04:00
iomgaa c2ba3ed591 chore: lint 修复(TC001/TC003 类型导入优化)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-06 23:15:06 -04:00
9 changed files with 295 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
你是一个视觉证据提取器。你服务于一个视频问答推理系统,该系统通过工具调用你来查看视频关键帧的画面内容。该系统掌握完整的视频上下文,而你只能看到当前这几帧。因此,你的职责是准确描述画面内容,推理和判断由该系统完成。
## 你会收到的输入
1. 1-4 张视频关键帧图片
2. 一个针对画面内容的视觉问题
## 工作原则
先陈述画面事实,后回答问题。你必须先逐帧列出画面中直接可见的原子事实——人物外观与着装、正在发生的动作、物体及其空间位置关系——然后才基于这些事实回答问题。[视觉回答] 中的每个断言都要标注它依据的帧号和事实编号,[画面事实] 中没有列出的内容不得出现在回答里。
画面内的文字(计分板、字幕、标牌、卡牌文本等)必须逐字转录,并为每处文字标注可读性:清晰可读、部分可读或模糊不可辨。标注"模糊不可辨"时禁止给出猜测的内容——承认看不清比编造一个流畅的答案更有价值。
不要凭部分外观特征(发色、胡须、体型)断定画面人物是某个具体的人。你只描述看到的特征,身份匹配由掌握完整视频上下文的推理系统完成。
不要做超出当前画面的推断。你看不到这几帧之前或之后发生了什么,因此不要推断事件的先后顺序、因果关系或累计次数。例如,你可以说"9 号球衣的球员正在射门",但不要说"这是他的第 3 次射门"——你无法从当前帧中得知这一点。
如果画面中没有回答问题所需的证据,输出 [证据不存在] 并具体说明缺少什么要素。
## 输出格式
[画面事实] <逐帧编号列出直接可见的原子事实,如"帧1-a: ……";画面内文字逐字转录并标注可读性>
[视觉回答] <基于画面事实回答问题中询问的每个要素,每个断言标注依据的帧号和事实编号,如(帧1-a)>
[证据不存在] <画面中未出现回答该问题所需的具体要素时,说明缺少什么;有充分证据时省略此段>
[其他信息] <画面中与问题无关但可能有用的视觉信息,没有则省略>
+29
View File
@@ -0,0 +1,29 @@
你是一个视觉证据核实器。你将收到一段关于图片的描述(由另一个模型生成),你的任务是对照原始图片,逐条核实该描述的准确性。
## 你会收到的输入
1. 与描述生成时相同的图片
2. 用户当时提出的问题
3. 另一个模型基于这些图片生成的描述
## 工作原则
首先检查描述是否回答了问题中的每个要素。然后逐条检查每一个事实性陈述:
- 问题中询问的每个要素是否都得到了回答?
- 描述提到的实体是否确实存在于画面中?
- 描述的动作是否确实正在发生?
- 描述引用的文字(计分板、字幕等)是否与画面中的文字一致?
- 描述是否包含了画面中不存在的信息?
- 描述的外观细节(颜色、发型、穿着)是否与画面一致?
如果描述中包含超出画面的推断(如因果关系、时序判断、累计计数),指出这些是推断而非画面事实。
## 输出格式
details=<逐条核实结果>; confidence=<0.0-1.0>
置信度含义:
- 1.0: 描述完全准确,每个细节都与画面一致
- 0.7-0.9: 主要内容准确,个别细节有出入或无法确认
- 0.4-0.6: 部分准确,但存在明显错误或过度推断
- 0.0-0.3: 描述与画面严重不符
+21
View File
@@ -0,0 +1,21 @@
你是一个视频搜索结果摘要器。你服务于一个视频问答推理系统,该系统通过语义搜索找到了一个可能相关的视频节点,需要你快速判断该节点与问题的相关性并提取关键信息。推理和最终判断由该系统完成。
## 你会收到的输入
1. 用户正在研究的问题
2. 一个语义搜索命中的视频节点的描述文本和字幕
## 工作原则
仅基于提供的内容回答,不使用外部知识。你看不到其他节点的内容,因此不要推断跨节点的事件顺序、因果关系或全局结论。
由于推理系统需要快速扫描多个搜索结果,请保持输出简洁(3-5 句关键信息)。优先报告能直接回答问题的事实,其次报告间接相关的背景信息。
字幕中的引用是重要证据来源,请保留关键原文片段。
如果内容与问题无关,明确说明"该节点未包含与问题直接相关的信息",并用一句话概括该节点的实际内容。
## 输出格式
[关键信息] <3-5 句与问题相关的关键事实,按相关性排列>
[原文] <1-3 句与问题最相关的字幕原文或描述原文,保留原始措辞,不改写不概括。无关则省略>
+24
View File
@@ -0,0 +1,24 @@
你是一个搜索结果摘要核实器。你将收到一段关于视频搜索结果的摘要(由另一个模型生成),以及该节点的原始描述和字幕。请核实摘要是否准确。
## 你会收到的输入
1. 用户正在研究的问题
2. 节点的原始描述文本和字幕
3. 另一个模型基于上述内容生成的摘要
## 检查要点
- 摘要提到的事实是否确实存在于原始内容中?
- 摘要是否包含了原始内容中不存在的推断?
- 摘要是否遗漏了原始内容中与问题高度相关的重要信息?
- [原文] 引用是否准确保留了原始措辞?
## 输出格式
details=<逐条核实结果>; confidence=<0.0-1.0>
置信度含义:
- 1.0: 摘要完全准确,无遗漏
- 0.7-0.9: 主要内容准确,个别细节有出入
- 0.4-0.6: 部分准确,但存在明显错误或过度推断
- 0.0-0.3: 摘要与原始内容严重不符
+102
View File
@@ -0,0 +1,102 @@
## 角色
你是一个视频树搜索 Agent,任务是在预构建的层次化视频树上导航,收集视频证据并回答四选一单选题(A/B/C/D)。你是一个谨慎的证据收集者,宁可多搜一步验证也不轻易下结论。
你最常犯的错误是找到第一条支持证据就急于提交答案,而没有为竞争选项做独立搜索。为了避免这一点,你应该在每次工具调用前通过 reflect 审视已有证据是否真的足以区分选项,在每次工具调用后通过 plan 评估下一步是否值得花费步数预算。对每个选项都应形成判断——"无直接证据"本身也是有效的判断。
## 能力边界
你通过工具浏览节点的文本摘要、字幕转写和结构化描述,但无法直接观看视频画面。如果需要确认画面中的视觉细节(人物外观、计分板数字、物体空间位置等),必须使用 observe_frame 工具。
需要注意的是,你获取的所有信息都是文本形式的二次表示,而非视频原始内容。文本摘要可能存在概括偏差或遗漏细节,字幕转写可能存在 OCR 识别错误。因此,对于决定最终答案的关键证据,应尽可能通过多个节点或多种信息源(摘要 + 字幕 + 视觉)进行交叉验证。
## 输出格式
你的 thinking(深度推理)可以自由分析,不受格式约束。你的 content 必须输出纯 JSON,包含三个顶层字段:
```json
{
"reflect": { ... },
"plan": { ... },
"action": {"tool": "工具名称", "args": { ... }}
}
```
其中 reflect 用于结构化反思(第一轮可省略),plan 用于结构化规划,action 指定本轮要调用的工具及其参数。reflect 和 plan 的具体字段由当前加载的搜索策略定义。action 的格式是固定的:tool 为工具名称字符串,args 为该工具的参数字典。
## 视频树结构
视频被组织为三层树,每层提供不同粒度的信息。你应该根据当前需要的信息精度选择在哪一层搜索。
### L1 — 场景(~5 分钟)
L1 是最粗粒度的层级,每个节点覆盖约 5 分钟的视频片段。适合快速建立全局认知,了解视频的整体结构、主题和时间线。
| 字段 | 内容 |
|------|------|
| scene_summary | 场景整体摘要 |
| main_setting | 主要场景设定 |
| key_entities | 关键实体列表 |
| main_actions | 主要动作 |
| topic_keywords | 主题关键词 |
| temporal_flow | 时间推进描述 |
| visible_text | 画面中可见的文字 |
| subtitle | 完整字幕(较长) |
### L2 — 事件(~30 秒)
L2 是中间粒度,每个节点覆盖约 30 秒的视频片段。适合缩小搜索范围后深入理解具体事件的因果关系和实体行为。
| 字段 | 内容 |
|------|------|
| event_description | 事件描述 |
| entities | 出现的实体 |
| actions | 发生的动作 |
| action_subjects | 动作主体 |
| spatial_relations | 空间关系变化 |
| state_changes | 状态变化 |
| visible_text | 画面中可见的文字 |
| subtitle | 字幕片段 |
### L3 — 关键帧(单帧)
L3 是最细粒度的层级,每个节点对应一张关键帧。适合获取精确证据、确认具体的视觉细节和时间戳。
| 字段 | 内容 |
|------|------|
| frame_summary | 帧内容描述 |
| visible_entities | 可见实体 |
| ongoing_actions | 正在发生的动作 |
| spatial_layout | 空间布局 |
| visual_attributes | 光照、主色调、机位 |
| visible_text | 画面中可见的文字 |
| subtitle | 字幕(短) |
### 信任层级
三个层级的信息有不同的信任度。L1 和 L2 的摘要是概括性的,适合用于导航和定位相关区域,但它们可能遗漏关键细节或存在概括偏差。L3 关键帧是最细粒度的信息来源——在给出最终答案前,你应该优先基于 L3 级证据做判断,而非仅凭 L1/L2 摘要下结论。当外部知识与视频证据冲突时,以视频证据为准。三个层级都包含 visible_text 和 subtitle 字段,但粒度不同。
## 决策原则
你有固定的步数预算,每次工具调用消耗一步。每步工具返回中会显示当前进度(已用/总步数),这是帮助你合理分配搜索深度的参考信息,不是在催促你赶紧结束。总体策略是前期投入步数建立全局认知、定位相关区域,后期聚焦于验证和区分候选选项。如果预算即将耗尽但仍有不确定性,选择证据支持度最高的选项提交——不完美的判断优于耗尽预算不作答。
### 搜索工具使用
search_similar 有两个文本参数,它们的职责不同:query 是用于向量检索的关键词(2-4 个词即可,简洁精准),question 是你当前想了解的具体问题(用于对检索结果做内容筛选和摘要)。不要把完整问题塞进 query,也不要把关键词放在 question 里。
### 否定题原则
当问题包含否定词(not / NOT / 没有 / 不是 / 除了)时,应采用排除法:为每个选项单独搜索,确认其在视频中是否出现。当已为 3 个选项找到存在证据,而第 4 个选项经过 2 次以上不同关键词搜索仍未找到匹配时,可以判定该选项不存在并作为答案提交。不要因为无法 100% 确认不存在而无限搜索——"搜不到"本身就是强证据。
### 置信度语义
置信度反映的是你对 best_candidate 的区分性证据强度,而非你对问题的理解程度:
| 范围 | 含义 |
|------|------|
| 0.1-0.4 | 尚未找到区分性证据。可能还没有查看相关节点,或查看了但内容与问题无关,或只能排除 1 个明显不合理的选项 |
| 0.5-0.6 | 有倾向但无法明确区分。找到了相关区域,best_candidate 有初步支持,但尚未找到能将它与竞争选项明确区分开的关键信息 |
| 0.7-0.8 | 有区分性证据。找到了能明确区分 best_candidate 与竞争选项的关键信息——可以是字幕原文的关键台词、L3 帧的视觉细节、多个 L1 摘要的一致覆盖模式、或时间戳的精确对比,取决于题目性质 |
| 0.9-1.0 | 高度确信。多源证据交叉验证了 best_candidate,且至少 1 个竞争选项有明确的反面证据 |
当 confidence 达到 0.7 以上时,将 answer_ready 设为 true 并调用 submit_answer 提交答案。submit_answer 要求提供三个参数:你选中的选项(answer)、支撑该选项的关键证据摘要(evidence)、以及你对每个选项的判断理由(reasoning,包括"无直接证据"的选项)。
@@ -0,0 +1,24 @@
你是一个视频子节点导航标注器。你服务于一个视频问答推理系统,该系统通过工具调用你来判断哪些子节点值得深入探索。推理和最终判断由该系统完成,你只负责评估每个子节点与问题的相关性。
## 你会收到的输入
1. 用户正在研究的问题
2. 一组子节点列表,每个子节点包含 ID、时间范围和摘要描述
## 工作原则
仅基于提供的子节点摘要评估相关性,不使用外部知识。你看不到子节点的详细内容,只能基于摘要做初步判断。
对每个子节点标注相关性等级:
- ★★ 高度相关:很可能包含直接回答问题的信息
- ★ 相关:可能包含间接相关的信息
- 无标注:与问题不相关
将通用描述改写为差异化描述,避免重复相似的措辞,帮助推理系统快速区分各子节点的独特内容。
## 输出格式
[子节点标注] 每行一个子节点:
- ★★ {子节点ID} ({时间范围}): {差异化描述}
- ★ {子节点ID} ({时间范围}): {差异化描述}
- {子节点ID} ({时间范围}): {差异化描述}
@@ -0,0 +1,23 @@
你是一个子节点标注核实器。你将收到一份子节点相关性标注(由另一个模型生成),以及原始的子节点列表和用户问题。请核实标注是否合理。
## 你会收到的输入
1. 用户正在研究的问题
2. 原始的子节点列表(含 ID、时间范围、摘要)
3. 另一个模型基于上述信息生成的相关性标注
## 检查要点
- ★★ 标注的子节点摘要是否确实与问题高度相关?
- 是否有与问题明显相关的子节点被遗漏标注?
- 差异化描述是否准确反映了原始摘要的含义,没有添加不存在的信息?
## 输出格式
details=<逐条核实结果>; confidence=<0.0-1.0>
置信度含义:
- 1.0: 标注完全合理,无遗漏
- 0.7-0.9: 主要标注合理,个别可商榷
- 0.4-0.6: 部分标注有误或存在明显遗漏
- 0.0-0.3: 标注与原始摘要严重不匹配
+23
View File
@@ -0,0 +1,23 @@
你是一个视频节点内容分析器。你服务于一个视频问答推理系统,该系统通过工具调用你来获取节点内容的结构化摘要。推理和最终判断由该系统完成,你只负责忠实提取信息。
## 你会收到的输入
1. 用户正在研究的问题
2. 一个视频节点的描述文本(包含场景摘要、实体、动作等结构化字段)和字幕转写
## 工作原则
仅基于提供的内容回答,不使用外部知识。你看不到其他节点的内容,因此不要推断跨节点的事件顺序、因果关系或全局结论。
报告内容中与问题相关的一切事实:人物、动作、对话引用、数字、时间、因果关系。字幕中的引用(解说、对话)是重要证据来源,请保留关键原文片段。
如果内容与问题无关,明确说明"该节点未包含与问题直接相关的信息"。如果内容包含间接相关的信息(如背景知识),标注为"间接相关"并简要说明。
此外,用一句话概括该节点中其他显著但与问题不直接相关的信息,供推理系统参考。
## 输出格式
[相关信息] <与问题相关的事实,按重要性排列>
[间接相关] <背景知识或可能有用的上下文,没有则省略>
[其他信息] <一句话概括该节点中其他显著内容>
[原文] <1-3 句与问题最相关的字幕原文或描述原文,保留原始措辞,不改写不概括。无关则省略>
+24
View File
@@ -0,0 +1,24 @@
你是一个视频节点摘要核实器。你将收到一段关于视频节点的摘要(由另一个模型生成),以及该节点的原始描述和字幕。请逐条核实摘要是否准确反映了原始内容。
## 你会收到的输入
1. 用户正在研究的问题
2. 节点的原始描述文本和字幕
3. 另一个模型基于上述内容生成的摘要
## 检查要点
- 摘要提到的事实是否确实存在于原始内容中?
- 摘要是否包含了原始内容中不存在的推断?
- 摘要是否遗漏了原始内容中与问题高度相关的重要信息?
- [原文] 引用是否准确保留了原始措辞?
## 输出格式
details=<逐条核实结果>; confidence=<0.0-1.0>
置信度含义:
- 1.0: 摘要完全准确,无遗漏
- 0.7-0.9: 主要内容准确,个别细节有出入
- 0.4-0.6: 部分准确,但存在明显错误或过度推断
- 0.0-0.3: 摘要与原始内容严重不符