docs(wiki): 赛题生成工具设计 + 实现计划

design: synthesizer + factory + CLI 三模块架构
plan: 9 个 Task(前置修复 + synthesizer 4 步 + factory + CLI generate/calibrate + re-export)
calibrate: Fisher exact test 组合判定替代固定阈值

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-09 05:05:57 -04:00
parent 8c383354c5
commit 0b48b889e0
7 changed files with 1706 additions and 3 deletions
@@ -0,0 +1,477 @@
---
id: question-gen-synth
title: 赛题生成工具设计(Question Generation Synthesis
type: design
created: 2026-07-09
status: draft
---
# 赛题生成工具设计
## 1. 目标与动机
让视频树自行生成与 Video-MME 原始赛题风格、难度近似的四选一选择题,用于自进化训练循环的 DataLoader。原始 900 道 benchmark 题保留为 held-out 最终评测集,避免"直接拿答案调"的审稿质疑。
**角色定位**:生成题 = 训练集,原始题 = 测试集。进化循环的改进效果最终由原始 benchmark 验证泛化能力。
**训练 vs 论文评测的区分**:训练循环全程使用生成题(三池切分——诊断池/验证池/test 池——均来自生成题),论文报告的 held-out 泛化指标是训练结束后,用最终 best 版本对原始 benchmark 全量 900 题单独跑推理得到的结果。两步分离,Runner 代码无需改动。
## 2. 模块结构与职责边界
### 2.1 文件布局
```
app/question_gen/
├── __init__.py ← 已有:re-export loader API
├── loader.py ← 已有:load_benchmark + stratified_sample
└── synthesizer.py ← 新增①:出题核心逻辑
app/harness/
└── factory.py ← 新增②:推理依赖组装(wiring)
tools/generate_questions.py ← 新增③:CLI 壳(generate + calibrate
```
### 2.2 职责切分
| 模块 | 职责 | 消费者 |
|------|------|--------|
| `synthesizer.py` | 题型-层级映射、锚节点采样、prompt 构造(few-shot)、embedding 去重、单题生成编排 | `tools/generate_questions.py` |
| `factory.py` | 给定 store 路径 + config → 组装 LLM/VLM/Embedding/SearchToolDispatcher/PromptManager 全套推理依赖 | `tools/generate_questions.py`(校准)、未来 `main.py`、Runner |
| `tools/generate_questions.py` | CLI 参数解析、并发编排(Semaphore)、进度日志、JSON 输出 | 用户直接运行 |
### 2.3 依赖方向
```mermaid
flowchart LR
TOOLS["tools/generate_questions.py"] --> SYN["app/question_gen/synthesizer"]
TOOLS --> FAC["app/harness/factory"]
TOOLS --> ADP["adapters/*"]
FAC --> SEARCH["app/search/*"]
FAC --> ENV["app/tree/environment"]
FAC --> ADP
SYN --> PROTO["core/protocols (VLMProvider, EmbeddingProvider via DI)"]
SYN --> TYPES["core/types (GeneratedQuestion)"]
SYN --> IDX["app/tree/index (TreeIndex)"]
```
全部合规——外层→内层,`core/` 不依赖任何外层。
### 2.4 与 QuestionGenerator Protocol 的关系
`app/ports.py` 已预留 `QuestionGenerator` Protocol。本设计**不实现该 Protocol**——出题是一次性离线工具而非运行时能力,Runner 不需要运行时出题。`synthesizer.py` 的函数式接口(`generate_one` 等纯函数 + async 编排)比 Protocol class 更适合工具脚本场景。`QuestionGenerator` Protocol 保留但标记为"预留,当前无实现",不删除——若未来需要运行时出题可基于 synthesizer 的纯函数包装实现。
### 2.5 方案选择与否决
| 方案 | 否决理由 |
|------|---------|
| A: 单体脚本(全部逻辑放 `tools/`) | 业务逻辑(题型映射、采样、prompt、去重)混在 CLI 编排中,不可独立测试;不匹配 repair 管线的 app/ + tools/ 分层惯例 |
| B: Protocol 实现 + 脚本编排(`adapters/` 实现 `QuestionGenerator`) | adapter 层语义是外部服务接口,出题逻辑是应用层业务规则,放 adapter 层语义不匹配 |
| **C: app/ 业务逻辑 + tools/ CLI 壳(采用)** | 与 repair 管线结构一致,Clean Architecture 依赖方向合规,业务逻辑可独立测试 |
## 3. synthesizer.py 核心设计
### 3.1 题型-层级映射
模块级常量,沿用 TRM4 设计文档的映射表:
| 锚定层级 | 题型 | 帧图 | 文本上下文 | 帧数 |
|---------|------|------|-----------|------|
| L3 | Object Recognition | 必须 | frame_summary | 1 |
| L3 | Attribute Perception | 必须 | frame_summary | 1 |
| L3 | OCR Problems | 必须 | frame_summary | 1 |
| L3 | Spatial Reasoning | 必须 | frame_summary + spatial_layout | 1 |
| L3 | Spatial Perception | 必须 | frame_summary | 1 |
| L2 | Action Recognition | 必须 | 事件 card | 2-3(子帧均匀采样) |
| L2 | Action Reasoning | 必须 | 事件 card | 2-3 |
| L2 | Counting Problem | 必须 | 事件 card | 2-3 |
| L2 | Temporal Perception | 可选 | 事件 card + time_range | 0-1 |
| L1 | Temporal Reasoning | 必须 | 根 card + 多个 L2 card(≥3 | 每 L2 取 1 张代表帧 |
| L1 | Information Synopsis | 必须 | 根 card + 全部 L2 card | 每 L2 取 1 张代表帧 |
| L1-L2 | Object Reasoning | 必须 | 2-3 个 L2 card | 每 L2 取 1 张代表帧 |
节点采样:每道题从全部视频树中随机选一棵,在对应层级随机选一个锚节点。同视频同题型不重复。L1 题型使用多个 L2 子节点联合输入时,按时间顺序组织节点,保持叙事连贯性。
### 3.2 AnchorContext 数据结构
```python
@dataclass(frozen=True)
class AnchorContext:
"""锚节点上下文——生成单道题所需的全部素材。"""
node_id: str # 锚节点 ID
card_text: str # 锚节点 card 序列化文本
frame_paths: list[str] # 帧图片路径
subtitle: str # 对应字幕(可空)
distractor_texts: list[str] # 同视频其他节点摘要(供 VLM 生成干扰项)
```
### 3.3 核心函数签名
```python
# 纯函数:从树中采样锚节点 + 帧 + 上下文
def sample_anchor(
tree: TreeIndex,
task_type: str,
used_node_ids: set[str],
rng: random.Random,
) -> AnchorContext
# 纯函数:组装 VLM promptsystem + user,含 few-shot exemplar
def build_generation_prompt(
task_type: str,
anchor: AnchorContext,
exemplars: list[GeneratedQuestion],
) -> tuple[list[dict], list[str]]
# 返回:(messages, image_paths) — 直接喂给 VLMProvider
# 纯函数:解析 VLM 返回的 JSON → 部分字段字典
# source_nodes 和 difficulty 由 generate_one 在 parse 后用 anchor 信息补齐
def parse_vlm_response(
raw: str,
video_id: str,
task_type: str,
seq: int,
) -> dict
# 返回:{"question_id", "question", "options", "answer"} 字典
# 调用方补齐 source_nodes/difficulty 后构造 GeneratedQuestion
# 纯函数:embedding 去重判定
def is_duplicate(
question_text: str,
pool_embeddings: np.ndarray,
embed_fn: Callable[[str | list[str]], np.ndarray],
threshold: float,
) -> bool
# 异步编排:生成单道题(含重试 + 去重循环)
async def generate_one(
vlm: VLMProvider,
embed_fn: Callable[[str | list[str]], np.ndarray],
tree: TreeIndex,
video_id: str,
task_type: str,
seq: int,
*,
exemplars: list[GeneratedQuestion],
pool_embeddings: np.ndarray,
used_node_ids: set[str],
max_retries: int,
similarity_threshold: float,
rng: random.Random,
session_id: str,
) -> GeneratedQuestion | None
```
**设计要点**
- 纯函数(sample_anchor、build_generation_prompt、parse_vlm_response、is_duplicate)可独立单测,不需要 VLM
- `generate_one` 是唯一异步函数,接收 `VLMProvider` 通过 DI
- 干扰项来自 `AnchorContext.distractor_texts`——同视频其他节点的真实信息
### 3.4 few-shot exemplar 选择
生成 prompt 包含 2-3 道同题型的原始 benchmark 题作示例,对齐风格和难度。
选择策略:
- 每题型取 `min(3, 该题型 benchmark 总量)`
- 按 seed 随机采样 + 跨视频去重(避免 exemplar 全来自同一视频)
- exemplar 是只读引用,不从 benchmark 评测集中移除
### 3.5 prompt 结构
```
System: 视频理解题目生成器,根据视频树节点内容和帧图生成 {task_type} 四选一题。
[2-3 道该题型原始 benchmark 题作示例]
约束:
- 问题必须基于给定节点内容,不能靠常识推断
- 干扰项来自同视频其他节点的真实信息(非凭空捏造)
- 难度和问法风格与示例一致
User: [锚节点 card + 字幕 + 帧图] + [同视频其他节点摘要,供干扰项素材]
```
### 3.6 去重机制
`EmbeddingProvider`nomic-embed-text-v1.5)对 question 文本做 embedding,余弦相似度检查:
| 检查对 | 阈值 | 处理 |
|--------|------|------|
| 生成题 vs 原始 benchmark 同题型题 | ≥ similarity_threshold | 丢弃,换节点重试 |
| 生成题 vs 已生成的同题型题 | ≥ similarity_threshold | 丢弃,换节点重试 |
维护 embedding 池(原始题 + 已通过的生成题),每生成一道新题即时查重。单题最多重试 `max_retries` 次。某题型连续耗尽重试配额时,脚本报错退出并输出已完成/未完成的题型统计,不静默少题。
**并发去重安全**embedding 池的"检查 + 添加"必须是原子操作。并发 `generate_one` 任务成功后,通过单线程汇总点(asyncio.Queue 或 await 后顺序提交)更新 embedding 池 + 写 JSON + 更新 progress,避免竞态导致相似题同时通过。
## 4. factory.py 推理依赖组装
### 4.1 解决的问题
目前 `Runner._make_tool_dispatch_fn()``_make_prompt_builder()` 都是 `raise NotImplementedError`,设计为"由 main.py 注入"。组装逻辑涉及 adapter 实例化 + app 组件串联,应提取为可复用的 factory 函数,避免在每个调用方(tools/ 脚本、未来 main.py)重复 wiring。
### 4.2 核心接口
```python
@dataclass(frozen=True)
class InferenceDeps:
"""跑一次推理所需的全套依赖(不含 HarnessLog,其生命周期由调用方管理)。"""
llm: LLMProvider
tool_dispatch_fn: Callable # SearchToolDispatcher.dispatch
prompt_builder: Callable # PromptManager 的偏函数
def build_inference_deps(
*,
store_dir: Path,
video_id: str,
prompts_dir: Path,
skills_dir: Path | None,
skill_mode: str,
embed_provider: EmbeddingProvider,
llm: LLMProvider,
vlm: VLMProvider,
ocr: OCRProvider | None,
verify_vision: bool,
anchor: bool,
assemble_mode: str,
) -> InferenceDeps
```
### 4.3 内部流程
```
build_inference_deps()
├── 加载 TreeIndexstore_dir/videos/{video_id}/tree.json
├── 构建 TreeEnvironmentindex=tree, frames_dir=videos/{video_id}/frames
├── 构建 SkillRegistryskills_dir,可选)
├── 构建 SearchToolDispatcherenv, tool_llm, vlm, ocr, prompts_dir,
│ skills, embed_fn, verify_vision, anchor, assemble_mode
├── 构建 PromptManagerprompts_dir)→ 偏函数化 prompt_builder(绑定 skill_mode
└── 返回 InferenceDeps
```
注意:`HarnessLog` 不放入 `InferenceDeps`——其生命周期由调用方通过 `with HarnessLog(...) as log` 管理,作为参数传给 `run_inference`
### 4.4 消费者
| 消费者 | 用法 |
|--------|------|
| `tools/generate_questions.py` calibrate | 按 video_id 分组题目,对每组调 `build_inference_deps` 构建对应视频树的依赖 → 分组 `run_inference` |
| 未来 `main.py --mode infer` | CLI 参数映射到 factory 参数 |
| `Runner` | `_make_tool_dispatch_fn` / `_make_prompt_builder` 改为委托 factory |
### 4.5 设计约束
- factory 只做**组装**,不持有状态——每次调用返回独立的 `InferenceDeps`
- adapter 实例(LLM/VLM/Embedding)由调用方创建并传入,factory 不管 adapter 生命周期
- 调用方自由决定 adapter 的复用策略(共享 vs 按需创建)
## 5. tools/generate_questions.py CLI 设计
### 5.1 子命令
```bash
# 生成
python tools/generate_questions.py generate \
--store-dir store \
--output-dir store/questions/generated/Video-MME \
--per-type 20 \
--similarity-threshold 0.85 \
--max-retries 3 \
--concurrency 8 \
--seed 42
# 校准(生成题 vs benchmark 基线对比)
python tools/generate_questions.py calibrate \
--generated-dir store/questions/generated/Video-MME \
--benchmark-dir store/questions/benchmarks/Video-MME \
--store-dir store \
--db-path results/calibrate.db \
--prompts-dir store/prompts \
--concurrency 4 \
--max-steps 15 \
--skill-mode auto \
--tolerance 0.10 \
--alpha 0.05 \
--baseline-db <可选,已有基线 DB 路径> \
--baseline-run-id <可选,已有基线 run_id>
```
除 baseline 复用参数外均必传,无默认值(CLAUDE.md §4.5)。`--baseline-db` + `--baseline-run-id` 可选但必须成对出现:有则从 DB 读 benchmark 基线,无则自动跑一次 benchmark 推理。
### 5.2 generate 流程
```
1. 加载 300 棵树的 video_id 列表
2. 加载 benchmark 题目(作为 few-shot exemplar 来源)
3. 初始化 embedding 池(benchmark 题 question text → embedding
4. 实例化 GovernedVLMClient + EmbeddingProvider
5. 检查断点续跑文件(progress.json
6. 对 12 题型 × per_type
├── 跳过已完成的(断点续跑)
├── 随机选视频 + 锚节点(同视频同题型不重复)
├── asyncio.Semaphore(concurrency) 并发调 generate_one
├── 成功 → 加入 embedding 池 + 追加到结果 + 更新 progress
└── 连续耗尽重试 → 报错退出,输出已完成/未完成统计
7. 按 video_id 分组写入 JSON
8. 全部完成后删除 progress.json
```
### 5.3 calibrate 流程
```
1. load_benchmark 加载生成题和 benchmark 题
2. 获取 benchmark 基线:
├── 有 --baseline-db + --baseline-run-id → 从 DB 读 per_task_type accuracy
└── 没有 → 按 video_id 分组 benchmark 题 → 每组 build_inference_deps
→ 分组 run_inference → 汇总存 DB
3. 按 video_id 分组生成题 → 每组 build_inference_deps → 分组 run_inference
(每组使用对应视频的 TreeEnvironment,避免跨视频树错用)
4. 汇总两组 per_task_type accuracy,对比(Fisher exact test
5. 输出对比表 + 判定结果
6. 存在 FAIL → 退出码 1
```
### 5.4 tools/ 脚本职责边界
脚本**只做**argparse、adapter 实例化(读 `.env`)、Semaphore 并发、进度日志(loguru)、JSON 写入、calibrate 时调 factory + run_inference。
脚本**不做**:prompt 构造、节点采样、去重判定(synthesizer.py)、依赖组装逻辑(factory.py)。
## 6. 校准统计方法
### 6.1 问题
benchmark 题型分布极不均匀(Spatial Perception 仅 3 道 vs Object Reasoning 240 道),固定 10% 阈值对小样本题型会产生误判——单题翻转即 33% 波动。
### 6.2 组合判定:Fisher exact test + effect size
`scipy.stats.fisher_exact` 对每个题型构造 2×2 列联表:
| | 答对 | 答错 |
|--|------|------|
| Benchmark | a | b |
| Generated | c | d |
判定规则:
| \|Δ\| > tolerance | p < α | 判定 | 含义 |
|---|---|---|---|
| ✗ | — | **PASS** | 差异在容忍范围内 |
| ✓ | ✓ | **FAIL** | 差异大且统计显著——生成题难度确实偏了 |
| ✓ | ✗ | **WARN** | 差异大但样本不足以确认——可能是噪声 |
### 6.3 优势
- 不需要 ad-hoc 的 `min_calibrate_size` 参数
- 小样本题型自动降级为 WARN——Fisher test 的 p-value 天然反映样本量不足
- CLI 只需两个语义清晰的统计参数:`--tolerance 0.10` + `--alpha 0.05`
- 退出码只看是否存在 FAIL(WARN 不阻塞)
### 6.4 检测灵敏度与 per_type 的关系
| per_type | 可检出的最小差异(大样本 benchmark 侧) |
|----------|---------------------------------------|
| 20 | ~30%(仅极大差异) |
| 50 | ~15%(中等差异) |
用户可根据需要的检测灵敏度选择 `--per-type`
### 6.5 输出格式
```
题型 | bench | gen | Δ | p-value | 判定
-------------------|--------|--------|---------|---------|--------
Spatial Perception | 66.7% | 40.0% | -26.7% | 0.590 | ⚠ WARN
Action Reasoning | 72.2% | 68.0% | -4.2% | 0.712 | ✓ PASS
Object Reasoning | 60.0% | 30.0% | -30.0% | 0.016 | ✗ FAIL
```
## 7. 断点续跑
生成 240 道题可能中断(VLM 故障、手动 Ctrl-C),沿用项目已有的 progress.json 模式:
```json
{
"completed": {
"Action Reasoning": ["gen-xyz-001", "gen-xyz-002"],
"Object Recognition": ["gen-abc-001"]
},
"output_dir": "store/questions/generated/Video-MME"
}
```
- 启动时检查 `{output_dir}/progress.json`,跳过已完成的题
- **恢复 embedding 池**:从已写出的 `{output_dir}/*.json` 重建已生成题的 embedding + `used_node_ids`,避免续跑后产生重复题
- 每道题写入 JSON 后立即更新 progress
- 全部完成后删除 progress.json
## 8. 输出格式
输出路径:`store/questions/generated/Video-MME/{video_id}.json`
```json
[
{
"question_id": "gen-{video_id}-{seq}",
"task_type": "Action Reasoning",
"question": "...",
"options": ["A. ...", "B. ...", "C. ...", "D. ..."],
"answer": "B",
"source_nodes": ["L1_000_L2_003"],
"difficulty": "medium"
}
]
```
与 loader schema 兼容(额外 `source_nodes`/`difficulty` 字段用于溯源),`load_benchmark` 零改动直接加载。
**训练集成**`--questions generated/Video-MME`
## 9. 受影响的既有接口
| 接口 | 影响 | 适配 |
|------|------|------|
| `load_benchmark` | 无 | 输出与 loader schema 兼容(额外 source_nodes/difficulty 字段用于溯源) |
| `RunConfig.questions` | 无 | 传 `generated/Video-MME` |
| `build_or_load_pools` | 无 | 三池均来自生成题 |
| `Runner._make_tool_dispatch_fn` | 改造 | 委托 factory.py |
| `Runner._make_prompt_builder` | 改造 | 委托 factory.py |
| `_VIDEO_MME_TASK_TYPE_COUNT` | **前置修复** | 从 11 改为 12`app/harness/config.py:24`),影响验证池保底下限 |
## 10. 测试策略
### 10.1 synthesizer.py
| 测试 | 覆盖点 |
|------|--------|
| `test_sample_anchor` | 各层级题型正确采锚、同视频同题型不重复、树节点不足时报错 |
| `test_build_generation_prompt` | messages 结构正确、exemplar 注入、图片路径列表、干扰项素材包含 |
| `test_parse_vlm_response` | 正常解析、格式异常(缺字段/非法 JSON)报错 |
| `test_is_duplicate` | 相似度 ≥ 阈值判重、< 阈值通过、空池不判重 |
| `test_generate_one` | mock VLMProvider,验证重试+去重循环、耗尽重试返回 None |
### 10.2 factory.py
| 测试 | 覆盖点 |
|------|--------|
| `test_build_inference_deps` | fake LLM/VLM/Embedding 验证返回各字段非 None、类型正确 |
| `test_missing_tree_file` | tree.json 不存在时报错 |
### 10.3 tools/generate_questions.py(集成级)
| 测试 | 覆盖点 |
|------|--------|
| `test_generate_smoke` | mock VLM + 1 棵真实树 + per_type=1,验证 JSON 输出格式 |
| `test_progress_resume` | 中断后重启,跳过已完成题 |
| `test_calibrate_pass_fail` | mock 两组 accuracy,验证 Fisher + tolerance 组合判定 |
真实 VLM 调用的 integration test 不在此次范围——依赖外部服务,不适合 CI。
## 11. 实现约束
- 完整类型注解 + 中文 DocstringCLAUDE.md §4.2
- 禁用 `print()`,使用 loguruCLAUDE.md §4.2
- 脚本放 `tools/`,不被其他模块 importCLAUDE.md §5
- 并发模式:`asyncio.Semaphore`CLI `--concurrency` 指定(沿用项目既有模式)
- 所有 VLM 调用经过 `GovernedLLMClient` 治理栈(CLAUDE.md §4.9
@@ -0,0 +1,9 @@
---
type: design
node_id: design:question-gen-synth
title: 赛题生成工具设计
date: 2026-07-09
---
# 赛题生成工具设计
+17
View File
@@ -60,6 +60,16 @@
"id": "design:paper-main-figure",
"label": "论文主图:Self-Evolving Search Agent 推理训练闭环",
"type": "design"
},
{
"id": "design:question-gen-synth",
"label": "赛题生成工具设计",
"type": "design"
},
{
"id": "plan:question-gen-synth",
"label": "赛题生成工具实现计划",
"type": "plan"
}
],
"links": [
@@ -104,6 +114,13 @@
"relation": "implements",
"evidence": "实现设计文档的三项改造:遥测加固+断点续跑+并发",
"added": "2026-07-09T04:08:15.312470+00:00"
},
{
"source": "plan:question-gen-synth",
"target": "design:question-gen-synth",
"relation": "implements",
"evidence": "计划实现设计文档中定义的 synthesizer + factory + CLI 三模块",
"added": "2026-07-09T09:05:43.697644+00:00"
}
]
}
+7 -3
View File
@@ -1,8 +1,8 @@
# Research Wiki 索引
> 自动生成,更新时间:2026-07-09 04:38 UTC
> 自动生成,更新时间:2026-07-09 09:05 UTC
## design (11)
## design (13)
- [2026-07-06-core-agent-adapters-llm-design](designs/2026-07-06-core-agent-adapters-llm-design.md) `design:2026-07-06-core-agent-adapters-llm-design`
- [2026-07-07-app-harness-design](designs/2026-07-07-app-harness-design.md) `design:2026-07-07-app-harness-design`
- [2026-07-07-core-evolution-design](designs/2026-07-07-core-evolution-design.md) `design:2026-07-07-core-evolution-design`
@@ -14,13 +14,16 @@
- [建树模块竖切设计:数据结构 + 建树 + 修复 + 迁移](designs/tree-module-vertical-slice.md) `design:tree-module-vertical-slice`
- [搜索 Agent 装配层设计(app/search/](designs/2026-07-07-search-module-design.md) `design:2026-07-07-search-module-design`
- [论文主图:Self-Evolving Search Agent 推理训练闭环](designs/paper-main-figure.md) `design:paper-main-figure`
- [赛题生成工具设计](designs/question-gen-synth.md) `design:question-gen-synth`
- [赛题生成工具设计(Question Generation Synthesis](designs/2026-07-09-question-gen-synth-design.md) `design:2026-07-09-question-gen-synth-design`
## plan (13)
## plan (15)
- [2026-07-06-core-agent-adapters-llm](plans/2026-07-06-core-agent-adapters-llm.md) `plan:2026-07-06-core-agent-adapters-llm`
- [2026-07-07-app-harness](plans/2026-07-07-app-harness.md) `plan:2026-07-07-app-harness`
- [2026-07-07-core-evolution](plans/2026-07-07-core-evolution.md) `plan:2026-07-07-core-evolution`
- [2026-07-07-question-gen](plans/2026-07-07-question-gen.md) `plan:2026-07-07-question-gen`
- [2026-07-07-tree-module-vertical-slice](plans/2026-07-07-tree-module-vertical-slice.md) `plan:2026-07-07-tree-module-vertical-slice`
- [2026-07-09-question-gen-synth](plans/2026-07-09-question-gen-synth.md) `plan:2026-07-09-question-gen-synth`
- [2026-07-09-tree-repair-resilience](plans/2026-07-09-tree-repair-resilience.md) `plan:2026-07-09-tree-repair-resilience`
- [app/harness/ 训练循环编排层实现计划](plans/app-harness.md) `plan:app-harness`
- [app/search/ 搜索 Agent 装配层实现计划](plans/2026-07-07-search-module.md) `plan:2026-07-07-search-module`
@@ -28,4 +31,5 @@
- [question_gen 模块实现计划](plans/question-gen.md) `plan:question-gen`
- [建树修复管线三项改造实现计划](plans/tree-repair-resilience.md) `plan:tree-repair-resilience`
- [建树模块竖切实现计划](plans/tree-module-vertical-slice.md) `plan:tree-module-vertical-slice`
- [赛题生成工具实现计划](plans/question-gen-synth.md) `plan:question-gen-synth`
- [项目基础设施初始化计划](plans/infrastructure-setup.md) `plan:infrastructure-setup`
+4
View File
@@ -29,3 +29,7 @@
- [2026-07-09 04:08 UTC] 重建索引: 22 篇页面
- [2026-07-09 04:38 UTC] 新增 design: 论文主图:Self-Evolving Search Agent 推理训练闭环 (design:paper-main-figure)
- [2026-07-09 04:38 UTC] 重建索引: 24 篇页面
- [2026-07-09 09:05 UTC] 新增 design: 赛题生成工具设计 (design:question-gen-synth)
- [2026-07-09 09:05 UTC] 新增 plan: 赛题生成工具实现计划 (plan:question-gen-synth)
- [2026-07-09 09:05 UTC] 新增边: plan:question-gen-synth --implements--> design:question-gen-synth
- [2026-07-09 09:05 UTC] 重建索引: 28 篇页面
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,9 @@
---
type: plan
node_id: plan:question-gen-synth
title: 赛题生成工具实现计划
date: 2026-07-09
---
# 赛题生成工具实现计划