# 基于 HTML 知识库的多模态问答集生成方案 **知识库特征:** - 格式:Sphinx 生成的 HTML 文档(209 个 HTML 文件) - 图片:1142 张图片(PNG/JPG),存放在 `_images/` 目录 - 结构:层级目录组织,包含大量配置界面截图、架构图、流程图等 **目标:** 生成高质量的多模态问答集,充分利用文本和图像信息 --- ## 一、核心挑战 ### 1.1 当前问题 | 问题 | 影响 | |------|------| | **图像信息丢失** | 现有 MD 问答集只有文本,配置界面截图、架构图等关键信息缺失 | | **图文关联弱** | 图片与文本分离,无法生成"如图所示"类问题 | | **问题质量受限** | 纯文本问题无法覆盖"界面在哪里点击"、"架构图中的模块关系"等场景 | ### 1.2 图像类型分析 根据采样分析,知识库中的图像主要分为以下类型: | 图像类型 | 占比估算 | 示例 | 问答价值 | |---------|---------|------|---------| | **配置界面截图** | ~40% | menuconfig 界面、参数配置页面 | ⭐⭐⭐⭐⭐ 高价值,可生成操作类问题 | | **架构图/流程图** | ~30% | 系统架构、数据流向、模块关系 | ⭐⭐⭐⭐⭐ 高价值,可生成理解类问题 | | **代码截图** | ~15% | 代码片段、配置文件示例 | ⭐⭐⭐ 中等价值,文本已包含 | | **硬件接口图** | ~10% | 引脚定义、电路连接 | ⭐⭐⭐⭐ 高价值,纯文本难以描述 | | **其他** | ~5% | Logo、装饰性图片 | ⭐ 低价值 | --- ## 二、方案设计 ### 2.1 整体流程 ``` HTML 知识库 ↓ ┌─────────────────────────────────────┐ │ 阶段 1:HTML → 结构化 Markdown │ │ - 提取文本内容 │ │ - 保留图片占位符 [IMAGE: xxx.png] │ │ - 保留章节层级结构 │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 阶段 2:图像分类与描述生成 │ │ - 多模态 LLM 识别图像类型 │ │ - 生成图像描述(caption) │ │ - 提取图像中的关键信息 │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 阶段 3:多模态问答生成 │ │ - 纯文本问题(基于文本内容) │ │ - 图文结合问题(基于图像+上下文) │ │ - 图像理解问题(基于图像描述) │ └─────────────────────────────────────┘ ↓ ┌─────────────────────────────────────┐ │ 阶段 4:问答集审核与优化 │ │ - 查重(文本 + 图像相似度) │ │ - 质量评分 │ │ - 人工审核 │ └─────────────────────────────────────┘ ↓ 多模态问答集(MD + 图像引用) ``` --- ## 三、技术实现 ### 3.1 阶段 1:HTML → 结构化 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-5(5=高价值)", "suggested_questions": ["基于此图像可以生成的问题示例"] }} **图像类型定义:** - config_ui: 配置界面截图(menuconfig、参数设置页面等) - architecture: 架构图、系统框图 - flowchart: 流程图、时序图 - code: 代码截图 - hardware: 硬件接口图、引脚定义 - other: 其他类型 **评分标准:** - 5分:包含关键操作步骤或架构信息,必须通过图像才能理解 - 4分:补充说明性图像,有助于理解但非必需 - 3分:代码或配置示例,文本已包含但图像更直观 - 2分:装饰性图像,价值较低 - 1分:无实质内容 """ # 调用多模态 LLM(GPT-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. 先筛选高价值图像
2. 使用 Claude 3.5 Sonnet 降低成本
3. 缓存分析结果 | | 图像描述不准确 | 问答质量下降 | 1. 人工抽查 10% 样本
2. 低置信度图像跳过
3. 提供图像让审核人员验证 | | 多模态召回测试复杂 | 实施困难 | 1. Phase 1 先生成问答集
2. Phase 2 再适配召回测试
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. **预算审批**:全量方案约 $20,MVP 约 $1 --- **总结:** 多模态方案能显著提升问答集质量和覆盖度,建议先用 MVP 验证效果,再决定是否全量实施。