dagent_eval/docs/多模态问答集生成方案.md

622 lines
20 KiB
Markdown
Raw Permalink 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.

# 基于 HTML 知识库的多模态问答集生成方案
**知识库特征:**
- 格式Sphinx 生成的 HTML 文档209 个 HTML 文件)
- 图片1142 张图片PNG/JPG存放在 `_images/` 目录
- 结构:层级目录组织,包含大量配置界面截图、架构图、流程图等
**目标:** 生成高质量的多模态问答集,充分利用文本和图像信息
---
## 一、核心挑战
### 1.1 当前问题
| 问题 | 影响 |
|------|------|
| **图像信息丢失** | 现有 MD 问答集只有文本,配置界面截图、架构图等关键信息缺失 |
| **图文关联弱** | 图片与文本分离,无法生成"如图所示"类问题 |
| **问题质量受限** | 纯文本问题无法覆盖"界面在哪里点击"、"架构图中的模块关系"等场景 |
### 1.2 图像类型分析
根据采样分析,知识库中的图像主要分为以下类型:
| 图像类型 | 占比估算 | 示例 | 问答价值 |
|---------|---------|------|---------|
| **配置界面截图** | ~40% | menuconfig 界面、参数配置页面 | ⭐⭐⭐⭐⭐ 高价值,可生成操作类问题 |
| **架构图/流程图** | ~30% | 系统架构、数据流向、模块关系 | ⭐⭐⭐⭐⭐ 高价值,可生成理解类问题 |
| **代码截图** | ~15% | 代码片段、配置文件示例 | ⭐⭐⭐ 中等价值,文本已包含 |
| **硬件接口图** | ~10% | 引脚定义、电路连接 | ⭐⭐⭐⭐ 高价值,纯文本难以描述 |
| **其他** | ~5% | Logo、装饰性图片 | ⭐ 低价值 |
---
## 二、方案设计
### 2.1 整体流程
```
HTML 知识库
┌─────────────────────────────────────┐
│ 阶段 1HTML → 结构化 Markdown │
│ - 提取文本内容 │
│ - 保留图片占位符 [IMAGE: xxx.png] │
│ - 保留章节层级结构 │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ 阶段 2图像分类与描述生成 │
│ - 多模态 LLM 识别图像类型 │
│ - 生成图像描述caption
│ - 提取图像中的关键信息 │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ 阶段 3多模态问答生成 │
│ - 纯文本问题(基于文本内容) │
│ - 图文结合问题(基于图像+上下文) │
│ - 图像理解问题(基于图像描述) │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ 阶段 4问答集审核与优化 │
│ - 查重(文本 + 图像相似度) │
│ - 质量评分 │
│ - 人工审核 │
└─────────────────────────────────────┘
多模态问答集MD + 图像引用)
```
---
## 三、技术实现
### 3.1 阶段 1HTML → 结构化 Markdown
**目标:** 将 HTML 转换为保留图像占位符的 Markdown
**实现方案:**
```python
from bs4 import BeautifulSoup
from pathlib import Path
def html_to_markdown_with_images(html_path: Path, base_path: Path) -> str:
"""
将 HTML 转换为 Markdown保留图像占位符
返回格式:
## 章节标题
文本内容...
![配置界面](../../_images/image-20220518111319607.png)
*图Uboot menuconfig 配置界面*
继续文本内容...
"""
html = html_path.read_text(encoding='utf-8')
soup = BeautifulSoup(html, 'html.parser')
# 提取主内容区域
main = soup.find('div', role='main') or soup.find('section')
md_lines = []
current_section = []
for elem in main.descendants:
if elem.name in ('h1', 'h2', 'h3', 'h4'):
# 章节标题
level = int(elem.name[1])
title = elem.get_text(strip=True)
md_lines.append(f"{'#' * level} {title}\n")
elif elem.name == 'p':
# 段落(可能包含图片)
if elem.find('img'):
# 处理图片
for img in elem.find_all('img'):
src = img.get('src', '')
alt = img.get('alt', '')
# 转换相对路径为绝对路径
img_path = (html_path.parent / src).resolve()
rel_path = img_path.relative_to(base_path)
md_lines.append(f"![{alt}]({rel_path})")
# 添加图片说明(从上下文推断)
caption = infer_image_caption(elem, img)
if caption:
md_lines.append(f"*图:{caption}*\n")
else:
# 纯文本段落
text = elem.get_text(strip=True)
if text:
md_lines.append(f"{text}\n")
elif elem.name == 'pre':
# 代码块
code = elem.get_text(strip=True)
md_lines.append(f"```\n{code}\n```\n")
elif elem.name == 'li':
# 列表项
text = elem.get_text(strip=True)
if text:
md_lines.append(f"- {text}")
return '\n'.join(md_lines)
def infer_image_caption(parent_elem, img_elem) -> str:
"""从图片周围的上下文推断图片说明"""
# 策略 1查找前一个段落的最后一句
prev = parent_elem.find_previous_sibling('p')
if prev:
text = prev.get_text(strip=True)
if '如图' in text or '如下图' in text or '界面' in text:
return text[-50:] # 取最后 50 字符
# 策略 2使用 alt 属性
alt = img_elem.get('alt', '')
if alt and not alt.startswith('image-'):
return alt
# 策略 3查找后续段落的第一句
next_elem = parent_elem.find_next_sibling('p')
if next_elem:
text = next_elem.get_text(strip=True)
if text:
return text[:50]
return ""
```
**输出示例:**
```markdown
## 4.3.2. 配置 Uboot 和 Kernel 选项参数
在嵌入式系统开发中Uboot 和 Kernel 的功能选项配置...
### 使用 xbuild 命令配置
命令执行成功后,系统会启动一个图形化的配置界面。
![menuconfig界面](linux_development/driver_develop_guide/_images/image-20220518111319607.png)
*图Uboot menuconfig 配置界面,可以选择启用或禁用功能*
完成配置后,选择 Exit 退出...
![保存配置](linux_development/driver_develop_guide/_images/image-20220518111506018.png)
*图:保存配置提示界面*
```
---
### 3.2 阶段 2图像分类与描述生成
**目标:** 使用多模态 LLM 为每张图片生成结构化描述
**实现方案:**
```python
import base64
from pathlib import Path
async def analyze_image_with_llm(
image_path: Path,
context_before: str,
context_after: str,
llm_config: dict,
) -> dict:
"""
使用多模态 LLM 分析图像
返回:
{
"type": "config_ui", # 图像类型
"description": "Uboot menuconfig 配置界面截图,显示了...",
"key_elements": ["File System support", "Network support", ...],
"qa_value": 5, # 问答价值评分 1-5
"suggested_questions": [
"如何进入 Uboot 配置界面?",
"配置界面中如何保存修改?"
]
}
"""
# 读取图像并编码为 base64
img_data = image_path.read_bytes()
img_b64 = base64.b64encode(img_data).decode()
prompt = f"""你是一个技术文档图像分析专家。请分析以下图像并提供结构化信息。
**图像上下文(前):**
{context_before[-500:]}
**图像上下文(后):**
{context_after[:500]}
请分析图像并返回 JSON 格式:
{{
"type": "图像类型config_ui/architecture/flowchart/code/hardware/other",
"description": "详细描述图像内容100-200字",
"key_elements": ["图像中的关键元素列表"],
"qa_value": "问答价值评分 1-55=高价值)",
"suggested_questions": ["基于此图像可以生成的问题示例"]
}}
**图像类型定义:**
- config_ui: 配置界面截图menuconfig、参数设置页面等
- architecture: 架构图、系统框图
- flowchart: 流程图、时序图
- code: 代码截图
- hardware: 硬件接口图、引脚定义
- other: 其他类型
**评分标准:**
- 5分包含关键操作步骤或架构信息必须通过图像才能理解
- 4分补充说明性图像有助于理解但非必需
- 3分代码或配置示例文本已包含但图像更直观
- 2分装饰性图像价值较低
- 1分无实质内容
"""
# 调用多模态 LLMGPT-4V / Claude 3.5 Sonnet
response = await call_multimodal_llm(
prompt=prompt,
image_base64=img_b64,
config=llm_config,
)
return json.loads(response)
```
**批量处理策略:**
```python
async def batch_analyze_images(
md_content: str,
image_paths: list[Path],
llm_config: dict,
concurrency: int = 5,
) -> dict[str, dict]:
"""
批量分析图像,返回 {image_path: analysis_result}
优化策略:
1. 并发调用concurrency=5
2. 缓存已分析的图像(基于文件 hash
3. 低价值图像跳过详细分析(仅记录类型)
"""
results = {}
sem = asyncio.Semaphore(concurrency)
async def analyze_one(img_path: Path):
# 检查缓存
cache_key = hashlib.md5(img_path.read_bytes()).hexdigest()
if cache_key in image_cache:
return image_cache[cache_key]
# 提取上下文
context_before, context_after = extract_image_context(md_content, img_path)
async with sem:
result = await analyze_image_with_llm(
img_path, context_before, context_after, llm_config
)
image_cache[cache_key] = result
return result
tasks = [analyze_one(p) for p in image_paths]
analyses = await asyncio.gather(*tasks)
return dict(zip(image_paths, analyses))
```
---
### 3.3 阶段 3多模态问答生成
**目标:** 生成三类问题:纯文本、图文结合、图像理解
**3.3.1 纯文本问题生成**
复用现有的问题生成逻辑(已实现),基于文本内容生成。
**3.3.2 图文结合问题生成**
```python
async def generate_image_text_questions(
section_path: str,
text_content: str,
images: list[dict], # [{path, analysis, context}]
llm_config: dict,
n: int = 3,
) -> list[dict]:
"""
生成图文结合的问题
示例问题类型:
- "如图所示的配置界面中,如何启用 XXX 功能?"
- "根据架构图XXX 模块与 YYY 模块的关系是什么?"
- "图中显示的错误信息是什么原因导致的?"
"""
# 筛选高价值图像qa_value >= 4
high_value_images = [img for img in images if img['analysis']['qa_value'] >= 4]
if not high_value_images:
return []
prompt = f"""你是一个技术文档问答生成专家。基于以下文本和图像信息,生成 {n} 个图文结合的问题。
**章节路径:** {section_path}
**文本内容:**
{text_content[:2000]}
**图像信息:**
"""
for i, img in enumerate(high_value_images[:3]): # 最多 3 张图
prompt += f"""
{i+1}{img['path'].name}
- 类型:{img['analysis']['type']}
- 描述:{img['analysis']['description']}
- 关键元素:{', '.join(img['analysis']['key_elements'][:5])}
"""
prompt += """
**要求:**
1. 问题必须同时依赖文本和图像才能回答(不能只看文本或只看图)
2. 问题中明确提及"如图所示"、"图中"、"根据架构图"等
3. 答案需要结合图像中的具体元素(按钮位置、模块名称、流程步骤等)
4. 每个问题附带:
- 参考答案
- 关联的图像文件名
- 答案来源(文本片段 + 图像描述)
输出 JSON 数组:
[
{
"question": "如图所示的配置界面中,如何...",
"answer": "在图中可以看到...",
"image_ref": "image-20220518111319607.png",
"source_text": "文本来源片段",
"source_image_desc": "图像描述片段",
"quality_score": 0.9
}
]
"""
response = await call_llm(prompt, llm_config)
return json.loads(response)
```
**3.3.3 图像理解问题生成**
```python
async def generate_image_understanding_questions(
image_path: Path,
image_analysis: dict,
context: str,
llm_config: dict,
n: int = 2,
) -> list[dict]:
"""
生成纯图像理解问题(主要针对架构图、流程图)
示例问题类型:
- "架构图中有哪些主要模块?"
- "数据流向是怎样的?"
- "XXX 模块的输入输出是什么?"
"""
if image_analysis['type'] not in ('architecture', 'flowchart', 'hardware'):
return [] # 只对特定类型图像生成
# 读取图像
img_b64 = base64.b64encode(image_path.read_bytes()).decode()
prompt = f"""基于以下架构图/流程图,生成 {n} 个理解性问题。
**图像类型:** {image_analysis['type']}
**图像描述:** {image_analysis['description']}
**上下文:** {context[:500]}
**要求:**
1. 问题聚焦于图像中的结构、关系、流程
2. 答案必须通过仔细观察图像才能得出
3. 避免过于简单的"有哪些模块"类问题,要问模块间的关系、数据流向等
输出 JSON 数组:
[
{
"question": "架构图中 XXX 模块与 YYY 模块通过什么方式通信?",
"answer": "通过 ZZZ 接口进行通信,数据流向为...",
"image_ref": "{image_path.name}",
"quality_score": 0.85
}
]
"""
response = await call_multimodal_llm(prompt, img_b64, llm_config)
return json.loads(response)
```
---
### 3.4 阶段 4多模态问答集格式
**输出格式:** 扩展现有 MD 格式,支持图像引用
```markdown
## linux_development/driver_develop_guide/uboot_config
## Q1: 如何进入 Uboot 的图形化配置界面?
**A1:** 在 Uboot 目录下执行 `make ARCH=arm menuconfig` 命令,会启动图形化配置界面。
## Q2: 如图所示的配置界面中,如何保存修改后的配置?
**IMAGE:** linux_development/driver_develop_guide/_images/image-20220518111319607.png
**A2:** 在配置界面中选择 Exit 退出,系统会提示是否保存修改,选择 Yes 即可保存配置到 .config 文件中。如图中红框所示,选择 "< Save >" 按钮。
## Q3: 根据架构图BPU 模块与 DDR 之间的数据通路是什么?
**IMAGE:** linux_development/system_architecture/_images/bpu_architecture.png
**A3:** BPU 模块通过 AXI 总线与 DDR 进行数据交互,支持 DMA 方式进行高速数据传输。
---
```
**数据库扩展:**
```sql
-- 扩展 qa_gen_question 表
ALTER TABLE qa_gen_question ADD COLUMN image_ref TEXT; -- 关联的图像路径
ALTER TABLE qa_gen_question ADD COLUMN question_type TEXT; -- text/image_text/image_only
```
---
## 四、实施计划
### 4.1 Phase 1基础设施1-2 天)
| 任务 | 输出 |
|------|------|
| HTML → Markdown 转换器 | Python 脚本,支持图像占位符 |
| 图像分析 API 封装 | 调用 GPT-4V/Claude 3.5 Sonnet |
| 数据库扩展 | 新增 image_ref 字段 |
### 4.2 Phase 2图像分析2-3 天)
| 任务 | 输出 |
|------|------|
| 批量图像分类 | 1142 张图片的类型标注 |
| 高价值图像筛选 | 筛选出 qa_value >= 4 的图像(约 400-500 张) |
| 图像描述生成 | 为高价值图像生成详细描述 |
**成本估算:**
- GPT-4V$0.01/image × 1142 = **$11.42**
- Claude 3.5 Sonnet$0.008/image × 1142 = **$9.14**
### 4.3 Phase 3多模态问答生成3-5 天)
| 任务 | 输出 |
|------|------|
| 纯文本问题生成 | 复用现有逻辑 |
| 图文结合问题生成 | 针对 400-500 张高价值图像 |
| 图像理解问题生成 | 针对架构图/流程图(约 100-150 张) |
| 问答集审核 | 查重、质量评分、人工审核 |
**预期产出:**
- 纯文本问题:~1000 条(与现有方案一致)
- 图文结合问题:~800 条(每张高价值图像 2 条)
- 图像理解问题:~200 条(每张架构图 2 条)
- **总计:~2000 条多模态问答**
### 4.4 Phase 4集成与测试2-3 天)
| 任务 | 输出 |
|------|------|
| 前端支持图像预览 | 审核页显示关联图像 |
| 导出格式扩展 | 支持导出带图像引用的 MD |
| 单跳测试适配 | 支持多模态召回测试 |
---
## 五、技术选型
### 5.1 多模态 LLM 选择
| 模型 | 优势 | 劣势 | 推荐场景 |
|------|------|------|---------|
| **GPT-4V** | 图像理解能力强API 稳定 | 成本较高($0.01/image | 图像分类、架构图理解 |
| **Claude 3.5 Sonnet** | 成本较低($0.008/image中文支持好 | 图像细节识别略弱 | 配置界面截图、流程图 |
| **Qwen-VL** | 开源免费,可本地部署 | 需要 GPU推理速度慢 | 成本敏感场景 |
**推荐组合:**
- 图像分类Claude 3.5 Sonnet成本低速度快
- 架构图理解GPT-4V精度高
- 问答生成Claude 3.5 Sonnet中文生成质量好
### 5.2 HTML 解析库
- **BeautifulSoup4**:简单易用,适合结构化 HTML
- **html2text**:快速转换,但图像处理能力弱
- **推荐BeautifulSoup4 + 自定义逻辑**
---
## 六、预期效果
### 6.1 问答集质量提升
| 维度 | 现有方案(纯文本) | 多模态方案 | 提升 |
|------|------------------|-----------|------|
| 问题数量 | ~1000 条 | ~2000 条 | **+100%** |
| 覆盖场景 | 概念、配置、命令 | + 界面操作、架构理解、硬件接口 | **+3 类** |
| 召回准确率 | 63% | 预期 75%+ | **+12%** |
| 用户体验 | 纯文本问答 | 图文并茂,更直观 | **显著提升** |
### 6.2 Benchmark 价值
- **更全面**:覆盖文本 + 图像两个模态
- **更真实**:贴近用户实际使用场景(看文档 + 看图)
- **更有挑战**:测试 RAG 系统的多模态召回能力
---
## 七、风险与应对
| 风险 | 影响 | 应对措施 |
|------|------|---------|
| 图像分析成本高 | 预算超支 | 1. 先筛选高价值图像<br>2. 使用 Claude 3.5 Sonnet 降低成本<br>3. 缓存分析结果 |
| 图像描述不准确 | 问答质量下降 | 1. 人工抽查 10% 样本<br>2. 低置信度图像跳过<br>3. 提供图像让审核人员验证 |
| 多模态召回测试复杂 | 实施困难 | 1. Phase 1 先生成问答集<br>2. Phase 2 再适配召回测试<br>3. 可先用纯文本测试验证 |
---
## 八、快速启动方案MVP
如果时间紧张,可以先实现 **最小可行方案**
### MVP 范围
1. **只处理配置界面截图**~400 张,占比 40%
2. **只生成图文结合问题**(不做纯图像理解)
3. **手动筛选 50 张高价值图像** 作为 Pilot
### MVP 实施3-5 天)
| Day | 任务 |
|-----|------|
| Day 1 | HTML → MD 转换 + 手动筛选 50 张图 |
| Day 2 | 图像分析50 张) + 描述生成 |
| Day 3 | 图文结合问答生成(~100 条) |
| Day 4 | 审核 + 导出 |
| Day 5 | 单跳测试验证效果 |
### MVP 成本
- 图像分析50 × $0.008 = **$0.4**
- 问答生成100 条 × $0.002 = **$0.2**
- **总计:~$0.6**
---
## 九、下一步行动
1. **确认方案**:是否采用多模态方案?全量还是 MVP
2. **准备环境**
- 申请 GPT-4V 或 Claude 3.5 Sonnet API key
- 准备图像存储(本地 or OSS
3. **开发排期**
- 谁负责 HTML 解析?
- 谁负责图像分析?
- 谁负责问答生成?
4. **预算审批**:全量方案约 $20MVP 约 $1
---
**总结:** 多模态方案能显著提升问答集质量和覆盖度,建议先用 MVP 验证效果,再决定是否全量实施。