dagent_eval/docs/LLM自动生成问题方案.md

515 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# LLM 自动生成问题 + 测试 + 审核方案
**版本:** v1.0
**日期:** 2026-04-21
**目标:** 基于知识库 MD 文件,自动生成测试问题,经过查重和质量审核后,直接送入单跳召回测试
---
## 一、整体流程
```
┌──────────────┐
│ 上传 MD 文件 │
└──────┬───────┘
┌──────────────────────────┐
│ LLM 按章节生成 Q&A │
│ - 每个 section 生成 N 个 │
│ - 同时生成参考答案 │
│ - 记录答案来源原文片段 │
└──────┬───────────────────┘
┌─────────────────────────────────┐
│ 审核流程 │
│ ┌─────────────────────────┐ │
│ │ 1. 批次内查重 │ │
│ │ - 精确查重hash │ │
│ │ - 语义查重embedding│ │
│ └─────────────────────────┘ │
│ ┌─────────────────────────┐ │
│ │ 2. 跨历史问题库查重 │ │
│ │ - 与已审核问题对比 │ │
│ └─────────────────────────┘ │
│ ┌─────────────────────────┐ │
│ │ 3. 问题质量自动评分 │ │
│ │ - 可回答性 │ │
│ │ - 问题清晰度 │ │
│ │ - 答案准确性 │ │
│ │ - 独特性 │ │
│ └─────────────────────────┘ │
│ ┌─────────────────────────┐ │
│ │ 4. 人工确认/编辑/删除 │ │
│ │ - 自动通过高质量问题 │ │
│ │ - 标记低质量/重复问题 │ │
│ └─────────────────────────┘ │
└─────────┬───────────────────────┘
┌──────────────────────────┐
│ 导出为标准 MD 格式 │
│ (与现有单跳测试格式一致) │
└──────┬───────────────────┘
┌──────────────────────────┐
│ 直接送入单跳召回测试 │
└──────────────────────────┘
```
---
## 二、模块设计
### 2.1 生成模块(`/api/qa-gen`
#### API 设计
```
POST /api/qa-gen/task # 创建生成任务
GET /api/qa-gen/task/list # 任务列表
GET /api/qa-gen/task/{id} # 任务详情(含进度)
DELETE /api/qa-gen/task/{id} # 删除任务
GET /api/qa-gen/task/{id}/questions # 获取生成的问题列表
POST /api/qa-gen/question/{id}/approve # 通过问题
POST /api/qa-gen/question/{id}/reject # 拒绝问题
PUT /api/qa-gen/question/{id} # 编辑问题
POST /api/qa-gen/task/{id}/export-md # 导出已通过问题为 MD
```
#### 生成策略
**输入:**
- MD 文件(与单跳测试相同格式)
- 配置参数:
- `model`: LLM 模型(默认 gpt-4o-mini
- `questions_per_section`: 每章节生成问题数(默认 5
- `quality_threshold`: 质量阈值(默认 0.6
- `judge_config_id`: 评分模型配置
**处理流程:**
1.`## section` 切分文档
2. 对每个 section
- 提取章节标题和内容
- 调用 LLM 生成 N 个问题
- 每个问题包含:
- 问题文本
- 参考答案
- 答案来源原文片段(用于质量审核)
3. 后台异步执行,支持进度回调
**Prompt 模板:**
```
你是一个专业的技术文档测试问题生成专家。
任务:根据以下技术文档章节内容,生成 {N} 个测试问题。
章节标题:{section_path}
章节内容:
{content}
要求:
1. 问题必须能从该章节内容直接回答(不要生成需要跨文档才能回答的问题)
2. 问题应覆盖章节的关键知识点
3. 问题表述清晰,无歧义
4. 答案准确,与原文一致
5. 标注答案来源的原文片段(用于后续审核)
输出格式JSON
[
{
"question": "问题文本",
"answer": "参考答案",
"source_chunk": "答案来源的原文片段50-200字"
},
...
]
```
---
### 2.2 查重模块
#### 两层查重机制
| 层级 | 方法 | 阈值 | 说明 |
|------|------|------|------|
| **精确查重** | 问题文本 hash | 完全相同 | 快速过滤完全重复 |
| **语义查重** | embedding 余弦相似度 | > 0.92 | 识别语义相似问题 |
#### 查重范围
1. **批次内查重**:当前生成任务内的问题互相查重
2. **跨历史查重**:与 `qa_approved_question` 表中已审核通过的问题查重
#### 实现细节
**Embedding 计算:**
- 使用 `text-embedding-3-small` 或配置的 embedding 模型
- 问题生成后立即计算 embedding 并存储
- embedding 存储为 JSON 字符串1536 维向量)
**查重流程:**
```python
# 1. 精确查重
question_hash = hashlib.md5(question.strip().lower().encode()).hexdigest()
if question_hash in existing_hashes:
mark_as_duplicate()
# 2. 语义查重
question_embedding = get_embedding(question)
similarities = cosine_similarity(question_embedding, all_embeddings)
if max(similarities) > 0.92:
mark_as_similar(most_similar_question_id)
```
---
### 2.3 质量审核模块
#### 自动质量评分
每条生成的问题自动打分0-1综合以下维度
| 维度 | 权重 | 评分方法 |
|------|------|---------|
| **可回答性** | 30% | LLM 判断:答案是否能从 source_chunk 推导出 |
| **问题清晰度** | 25% | LLM 判断:问题是否有歧义、表述是否清晰 |
| **答案准确性** | 30% | LLM 判断:参考答案是否与 source_chunk 一致 |
| **独特性** | 15% | 计算与最相似问题的语义距离1 - max_similarity |
**质量评分 Prompt**
```
评估以下测试问题的质量,从 0-1 打分。
问题:{question}
参考答案:{answer}
答案来源原文:{source_chunk}
评估维度:
1. 可回答性0-1答案是否能从原文推导出
2. 问题清晰度0-1问题是否清晰无歧义
3. 答案准确性0-1参考答案是否与原文一致
输出格式JSON
{
"answerable": 0.9,
"clarity": 0.85,
"accuracy": 0.95,
"reasoning": "简短说明"
}
```
#### 审核状态流转
```
pending待审核
├─→ approved通过→ 进入 qa_approved_question 表
├─→ rejected拒绝→ 不进入测试
└─→ edited编辑后→ 重新计算 embedding 和质量分
```
**自动通过规则:**
- `quality_score >= threshold`(默认 0.6
-`dup_of IS NULL`(非重复)
- 自动标记为 `approved`
**需人工审核:**
- `quality_score < threshold`
-`dup_of IS NOT NULL`(疑似重复)
---
### 2.4 数据库设计
#### 新增表
```sql
-- 生成任务表
CREATE TABLE qa_gen_task (
id TEXT PRIMARY KEY,
name TEXT,
status TEXT NOT NULL DEFAULT 'pending', -- pending/running/done/failed
model TEXT NOT NULL, -- 使用的 LLM 模型
judge_config_id TEXT, -- 评分模型配置
questions_per_section INTEGER DEFAULT 5,
quality_threshold REAL DEFAULT 0.6,
progress INTEGER DEFAULT 0,
total INTEGER DEFAULT 0,
error_message TEXT,
created_at TEXT NOT NULL,
finished_at TEXT
);
-- 生成的问题表(待审核池)
CREATE TABLE qa_gen_question (
id TEXT PRIMARY KEY,
task_id TEXT NOT NULL,
section_path TEXT NOT NULL,
question TEXT NOT NULL,
reference_answer TEXT NOT NULL,
source_chunk TEXT, -- 答案来源原文片段
quality_score REAL, -- 自动质量评分0-1
quality_detail TEXT, -- JSON: {answerable, clarity, accuracy, reasoning}
dup_of TEXT, -- 重复问题的 id如果是重复的
dup_similarity REAL, -- 与重复问题的相似度
status TEXT NOT NULL DEFAULT 'pending', -- pending/approved/rejected/edited
embedding TEXT, -- JSON 向量,用于查重
created_at TEXT NOT NULL,
updated_at TEXT
);
-- 已审核通过的问题库(用于查重基准 + 导出测试)
CREATE TABLE qa_approved_question (
id TEXT PRIMARY KEY,
gen_question_id TEXT NOT NULL, -- 关联 qa_gen_question.id
section_path TEXT NOT NULL,
question TEXT NOT NULL,
reference_answer TEXT NOT NULL,
embedding TEXT NOT NULL, -- 用于后续查重
source_task_id TEXT NOT NULL,
quality_score REAL,
approved_at TEXT NOT NULL,
approved_by TEXT DEFAULT 'auto' -- auto/manual
);
-- 索引
CREATE INDEX idx_qa_gen_question_task_id ON qa_gen_question(task_id);
CREATE INDEX idx_qa_gen_question_status ON qa_gen_question(status);
CREATE INDEX idx_qa_approved_question_section ON qa_approved_question(section_path);
```
---
## 三、前端设计
### 3.1 页面结构
新增"问题生成"一级菜单,包含两个子页面:
```
问题生成
├─ 生成任务
└─ 问题审核
```
---
### 3.2 生成任务页
**布局:** 类似单跳测试的任务列表页
**功能:**
- 上传 MD 文件
- 配置生成参数:
- 模型选择(下拉)
- 每章节问题数(数字输入,默认 5
- 质量阈值滑块0-1默认 0.6
- 评分模型配置(下拉,复用 judge_config
- 任务列表:
- 任务名称、状态、进度、创建时间
- 操作:查看问题、删除任务
**任务状态展示:**
```
┌────────────────────────────────────────────────────┐
│ 任务名称evb_linux_development │
│ 状态:运行中 进度45/107 章节 │
│ 已生成225 个问题 自动通过180 待审核45 │
│ [查看问题] [停止任务] │
└────────────────────────────────────────────────────┘
```
---
### 3.3 问题审核页(核心交互)
**布局:** 左右分栏
```
┌─────────────────────────────────────────────────────────────┐
│ 筛选:[全部] [待审核] [重复] [低质量] [已通过] [已拒绝] │
│ 任务:[下拉选择任务] │
├──────────┬──────────────────────────────────────────────────┤
│ │ 批量操作:[全部通过] [通过高质量(>0.6)] [导出MD] │
│ ├──────────────────────────────────────────────────┤
│ 章节列表 │ 问题列表 │
│ │ ┌────────────────────────────────────────────┐ │
│ □ 全选 │ │ ✅ Q1: 如何配置 DDR 参数? 质量分: 0.85 │ │
│ □ ch1 │ │ A: 通过修改 xxx 配置文件... │ │
│ (12/15) │ │ 来源: linux_development/ddr/config │ │
│ │ │ [通过] [拒绝] [编辑] │ │
│ □ ch2 │ └────────────────────────────────────────────┘ │
│ (8/10) │ ┌────────────────────────────────────────────┐ │
│ │ │ ⚠️ Q2: DDR 配置文件在哪? 质量分: 0.45 │ │
│ □ ch3 │ │ A: 在 /etc/ddr.conf │ │
│ (5/8) │ │ ⚠️ 与"Q1"相似度 0.94(疑似重复) │ │
│ │ │ [通过] [拒绝] [编辑] [查看原问题] │ │
│ │ └────────────────────────────────────────────┘ │
│ │ ┌────────────────────────────────────────────┐ │
│ │ │ ❌ Q3: xxx 质量分: 0.32 │ │
│ │ │ A: xxx │ │
│ │ │ ⚠️ 低质量:问题不清晰 │ │
│ │ │ [通过] [拒绝] [编辑] │ │
│ │ └────────────────────────────────────────────┘ │
└──────────┴──────────────────────────────────────────────────┘
```
**交互细节:**
1. **问题卡片状态标识:**
- ✅ 绿色已通过quality_score >= threshold 且非重复)
- ⚠️ 黄色:待审核(低质量或疑似重复)
- ❌ 红色:已拒绝
2. **批量操作:**
- "全部通过":将当前筛选结果中所有 pending 问题标记为 approved
- "通过高质量":仅通过 quality_score >= threshold 且非重复的问题
- "导出 MD":导出已通过问题为标准 MD 格式
3. **编辑问题:**
- 弹出对话框,可修改问题、答案
- 保存后重新计算 embedding 和质量分
- 状态变为 `edited`
4. **查看原问题:**
- 点击"查看原问题"跳转到重复问题的卡片
- 高亮显示相似部分
---
### 3.4 导出 MD 格式
导出的 MD 文件格式与单跳测试输入格式完全一致:
```markdown
## section_path / doc_name
## Q1: 问题文本
**A1:** 参考答案
## Q2: 问题文本
**A2:** 参考答案
---
## section_path2 / doc_name2
## Q1: 问题文本
**A1:** 参考答案
```
导出后可直接上传到"单跳召回测试"模块进行测试。
---
## 四、实现优先级
### P0核心功能1-2 周)
| 模块 | 功能 | 工作量 |
|------|------|--------|
| 后端 | 生成任务 API上传 MD → LLM 生成 Q&A → 存库) | 1-2 天 |
| 后端 | 问题列表 API + 通过/拒绝/编辑 API | 0.5 天 |
| 后端 | 导出 MD API | 0.5 天 |
| 前端 | 生成任务页(上传 + 配置 + 任务列表) | 1 天 |
| 前端 | 问题审核页(列表 + 基础交互) | 1-2 天 |
| 数据库 | 新增 3 张表 + schema 迁移 | 0.5 天 |
### P1查重 + 质量评分1 周)
| 模块 | 功能 | 工作量 |
|------|------|--------|
| 后端 | 批次内查重hash + embedding | 1 天 |
| 后端 | 质量自动评分LLM 评分) | 1 天 |
| 前端 | 问题卡片状态标识(质量分、重复标记) | 0.5 天 |
| 前端 | 批量操作(全部通过、通过高质量) | 0.5 天 |
### P2跨历史查重 + 优化3-5 天)
| 模块 | 功能 | 工作量 |
|------|------|--------|
| 后端 | 跨历史问题库查重 | 0.5 天 |
| 前端 | 查看原问题跳转 | 0.5 天 |
| 前端 | 编辑问题对话框 | 0.5 天 |
| 优化 | embedding 批量计算优化 | 0.5 天 |
| 优化 | 生成任务并发控制 | 0.5 天 |
---
## 五、技术选型
### LLM 模型
| 用途 | 推荐模型 | 备选 |
|------|---------|------|
| 问题生成 | gpt-4o-mini | gpt-4o, claude-3.5-sonnet |
| 质量评分 | gpt-4o-mini | gpt-4o |
| Embedding | text-embedding-3-small | text-embedding-3-large |
### 依赖库
- **后端:** 复用现有 `judge_config` 表的 OpenAI 配置
- **Embedding** 使用 OpenAI SDK 或 `sentence-transformers`(如果需要本地部署)
- **相似度计算:** `numpy.dot` + `numpy.linalg.norm`(余弦相似度)
---
## 六、风险与注意事项
### 6.1 成本控制
- **问题生成:** 每个 section 约 500-2000 tokens 输入,生成 5 个问题约 500 tokens 输出
- 估算12,000 条问题2,400 sections × 5≈ 3M tokens input + 1M tokens output
- 成本gpt-4o-mini约 $0.6
- **质量评分:** 每个问题约 300 tokens 输入 + 100 tokens 输出
- 估算12,000 条问题 ≈ 3.6M tokens input + 1.2M tokens output
- 成本gpt-4o-mini约 $0.7
- **Embedding** 每个问题约 20 tokens
- 估算12,000 条问题 ≈ 240K tokens
- 成本text-embedding-3-small约 $0.005
**总成本:** 约 $1.3 / 12,000 条问题
### 6.2 性能优化
- **并发控制:** 生成任务使用 `asyncio.Semaphore` 限制并发数(默认 5
- **批量 embedding** 每次最多 100 个问题批量计算 embedding
- **查重优化:** 使用 numpy 向量化计算,避免循环
### 6.3 数据一致性
- **事务保护:** 问题通过/拒绝操作使用数据库事务
- **幂等性:** 重复提交生成任务时检查是否已存在相同任务
---
## 七、后续扩展
### 7.1 高级功能
- **问题难度分级:** 自动标注问题难度(简单/中等/困难)
- **知识点标签:** 自动提取问题涉及的知识点标签
- **多轮对话问题:** 生成需要多轮交互的复杂问题
- **负样本生成:** 生成故意错误的答案,用于测试模型鲁棒性
### 7.2 集成优化
- **与单跳测试联动:** 审核通过后自动创建单跳测试任务
- **测试结果反馈:** 单跳测试失败的问题自动标记为"需优化"
- **持续迭代:** 根据测试结果自动调整生成策略
---
## 八、总结
本方案提供了一个完整的"生成 → 查重 → 审核 → 测试"闭环,核心优势:
1. **自动化程度高:** 90% 的高质量问题可自动通过,人工仅需审核 10%
2. **质量可控:** 多维度质量评分 + 查重机制保证问题质量
3. **无缝集成:** 导出格式与现有单跳测试完全兼容
4. **可扩展性强:** 模块化设计,易于后续扩展
**预期效果:** 将问题生成效率提升 10 倍,从人工编写 1 小时 10 条问题,提升到 LLM 生成 1 小时 1000+ 条问题(含审核)。