## 项目概述 - **名称**: 初中物理作业批改工作流 - **功能**: 上传多张作业图片和Word答案文件,自动识别学生答案、提取标准答案、精准批改并返回批改结果JSON ### 节点清单 | 节点名 | 文件位置 | 类型 | 功能描述 | 分支逻辑 | 配置文件 | |-------|---------|------|---------|---------|---------| | doc_extract | `nodes/doc_extract_node.py` | agent | 从Word文件(.docx)提取题干和标准答案;如无URL则返回空列表 | - | `config/doc_extract_llm_cfg.json` | | process_images | `nodes/process_images_node.py` | looparray | 循环调用子图处理每张作业图片,生成最终批改结果 | - | - | **类型说明**: task(普通任务节点) / agent(大模型节点) / condition(条件分支) / looparray(列表循环) / loopcond(条件循环) ## 子图清单 | 子图名 | 文件位置 | 功能描述 | 被调用节点 | |-------|---------|------|---------| | single_image_subgraph | `graphs/loop_graph.py` | 处理单张图片的完整批改流程(预处理→识别批改→整合→包装) | process_images | ### 子图内部节点 | 节点名 | 文件位置 | 类型 | 功能描述 | |-------|---------|------|---------| | image_preprocess | `nodes/image_preprocess_node.py` | task | 下载图片、自动旋转(横向→纵向)、缩放到固定宽度1000px、上传对象存储 | | recognize_and_correct | `nodes/recognize_and_correct_node.py` | agent | **一体化识别批改**:合并识别题目和批改为一次LLM调用 | | result_merge | `nodes/result_merge_node.py` | task | 将识别结果和批改结果合并为最终批注 | | wrap_result | `graphs/loop_graph.py` | task | 包装子图结果为SingleImageResult输出 | ## 技能使用 - 节点 `recognize_and_correct` 使用大语言模型技能(多模态,识别+批改合并) - 模型:`doubao-seed-2-0-pro-260215`(旗舰视觉模型,推理能力强,输出简洁) - 节点 `doc_extract` 使用大语言模型技能 - 模型:`doubao-seed-2-0-pro-260215`(旗舰模型,复杂推理能力强) - 使用 python-docx 解析 Word 文档 ## 工作流程(多图片批改架构) ``` ┌─────────────────────┐ │ doc_extract │ │ (Word答案解析) │ └──────────┬──────────┘ │ ▼ ┌─────────────────────┐ │ process_images │ │ (多图片循环处理) │ │ 生成最终批改结果 │ └─────────────────────┘ ``` ### 子图内部流程(处理单张图片 - 优化版) ``` ┌─────────────────────┐ │ image_preprocess │ │ (图像预处理) │ └──────────┬──────────┘ │ ▼ ┌─────────────────────┐ │recognize_and_correct│ ← 合并节点:识别+批改一次完成 │ (一体化识别批改) │ └──────────┬──────────┘ │ ▼ ┌─────────────────────┐ │ result_merge │ │ (结果整合) │ └──────────┬──────────┘ │ ▼ ┌─────────────────────┐ │ wrap_result │ │ (包装输出) │ └─────────────────────┘ ``` ## 核心功能:多图片批改机制 ### 输入参数 - `homework_images`: 上传的作业图片列表(List[File],支持多张图片) - `answer_doc_url`: 正确答案Word文件的URL(.docx格式,**可选**) - `comment_max_length`: 评语最大字数(默认100字,**可选**) - `max_concurrent`: 并行批改的最大数量(默认10,**可选**) - `grade_standards`: 评价等级标准(**可选**,默认值如下) ```json { "A+": {"min_percentage": 95, "description": "答案全部正确,步骤完整规范,逻辑严谨;书写/格式整洁,无错别字、无遗漏;完成度100%,态度认真,质量上乘"}, "A": {"min_percentage": 90, "description": "答案完全正确,无任何错误;步骤合理、格式规范,无原则性问题;完成度100%,满足全部要求"}, "B": {"min_percentage": 80, "description": "存在少量非关键性错误,或步骤略有缺失;整体思路基本正确,仅细节、格式、计算等小问题;完成大部分内容,整体合格但不够严谨"}, "C": {"min_percentage": 70, "description": "错误较多,部分核心题目作答错误;步骤不完整、逻辑不够清晰;完成度一般,有明显应付、漏答情况"}, "D": {"min_percentage": 0, "description": "大面积错误,核心知识点未掌握;大量空白、敷衍、抄袭;未达到基本完成要求"} } ``` ### 输出结果 - `final_result`: 最终批改结果JSON(包含多图片) - `total_images`: 总图片数 - `image_results`: 各图片的批改结果列表 - `overall_comment`: 整体评价(根据得分率生成) - `total_score`: 总得分 - `full_score`: 总满分 - `grade`: 等级评定 ### 批改优先级(严格按照以下顺序) 1. **最优先**:使用Word文档中的标准答案批改 - 当提供了`answer_doc_url`且在文档中找到对应题目时 - 严格按照标准答案判断学生答案正误 2. **降级方案**:使用专业物理老师批改 - 场景1:未提供`answer_doc_url` - 场景2:提供了URL但文档中未找到对应题目 - 使用专业物理老师的经验自主判断答案正误 ### 功能说明 1. **多图片支持**:可上传多张作业图片,系统会并行处理每张图片(并发数限制为3) 2. **Word答案提取**:从.docx文件中提取题干和标准答案 3. **子图循环处理**:使用子图封装单图片处理流程,主图调用子图处理每张图片 4. **批改结果JSON**:返回包含所有图片批改结果的结构化JSON 5. **智能降级**:无标准答案时自动切换到专业老师模式 ## 优化记录 ### 2026-03-26 填空题拆分优化(重要) **问题**:一道题有多个填空时,被合并成一个答案,批改标记无法精准定位 **修复内容**: 1. **优化Prompt**: - 明确要求:一道题有多个填空时,**每个空单独识别为一个题目** - 题号格式:\"3(1)第一空\"、\"3(1)第二空\"、\"4(2)第一空\"、\"4(2)第二空\" - 每个空单独批改,单独打分 2. **示例说明**: ``` ❌ 错误:3(1) → "4、1"(合并) ✅ 正确:3(1)第一空 → "4" 3(1)第二空 → "1" ``` 3. **参数传递优化**: - comment_max_length参数正确传递到Jinja2模板 - 确保LLM生成符合长度要求的comment **效果**: - 识别数量从9个增加到13个 - 每个填空都有独立的批改标记 - 批改标记精准定位到每个答案位置 ### 2026-03-26 JSON解析优化(重要) **问题**:LLM输出可能不完整(被max_completion_tokens截断),导致JSON解析失败 **修复内容**: 1. **新增fix_incomplete_json函数**: - 自动检测缺失的括号(}和]) - 自动补全缺失的括号,使JSON完整 - 示例:`{"results": [{"id": 1}` → 自动补全为 `{"results": [{"id": 1}]}` 2. **增强JSON解析流程**: - 第一步:尝试直接解析 - 第二步:尝试修复不完整的JSON(补全括号) - 第三步:尝试提取JSON对象 - 第四步:尝试修复提取的JSON 3. **移除错误的截断逻辑**: - 不再在解析后截断comment(可能破坏转义字符) - 完全依赖LLM遵守comment_max_length限制 - 通过Prompt明确要求LLM控制comment长度 4. **参数正确传递**: - comment_max_length参数正确传递到Prompt - LLM根据该参数生成符合长度的comment **效果**: - JSON解析成功率大幅提升 - 能够处理不完整的JSON输出 - comment长度由LLM控制,避免截断破坏格式 ### 2026-03-26 识别优化:禁止标注实验装置图(重要) **问题**: 1. 在实验装置图(如弹簧测力计、烧杯等)上标注了批改气泡 2. 坐标定位不够精准 **修复内容**: 1. **Prompt优化**: - 明确禁止标注实验装置图、示意图、电路图 - 明确禁止标注图中标注的字母(如A、B、C、D、E、F、G) - 强调只标注学生手写答案 2. **工程规范优化**: - 从config文件读取sp和up(符合工程规范) - 使用Jinja2模板渲染Prompt - 代码中只保留动态部分构建(标准答案、图片尺寸等) 3. **识别流程优化**: - 找题号 → 找学生答案 → 框选答案 → 判断正误 - 强调学生答案的特征:手写、填写空白处、计算结果 **效果**:不再误标注实验装置图,只标注学生手写答案 ### 2026-03-26 新增并行数量控制参数 **优化前**:硬编码并发数限制为3,不够灵活 **优化后**:添加max_concurrent参数,默认值10,用户可自定义 **具体优化**: 1. **新增参数**:`max_concurrent`(可选,默认10) 2. **修改位置**: - `GraphInput.max_concurrent: Optional[int] = 10` - `GlobalState.max_concurrent: int = 10` - `ProcessImagesInput.max_concurrent: int` 3. **使用方式**: ```json { "homework_images": [...], "max_concurrent": 5 // 最多同时处理5张图片 } ``` **效果**:用户可根据服务器性能和网络情况灵活调整并发数 ### 2026-03-26 学科变更 **修改**:将所有"数学"改为"物理" - 节点描述:数学作业 → 物理作业 - Prompt中的学科引用:数学 → 物理 - 配置文件说明更新 ### 2026-03-25 多图片并行处理优化 **优化前**:多图片串行处理,总时间 = 单张图片时间 × 图片数量 **优化后**:多图片并行处理(并发数限制为3),总时间大幅缩短 **具体优化**: 1. **并行处理架构**:使用 `ThreadPoolExecutor` 并行调用子图处理每张图片 - 最多同时处理3张图片 - 结果按 `image_index` 正确排序,保证顺序一致性 2. **性能提升**: - 3张图片:时间减少约66%(从3份时间 → 1份时间) - 5张图片:时间减少约80%(从5份时间 → 约2份时间,分两批并行) 3. **质量保证**: - 每张图片独立处理,互不影响 - 识别逻辑、批改逻辑完全相同,质量不受影响 ### 2026-03-26 坐标定位修复(重要) **问题**:坐标定位特别不准,批改标记位置错误 **原因**:Y坐标修正逻辑错误,导致坐标被错误缩放 **修复内容**: 1. **坐标系统重构**:从绝对坐标改为相对坐标(0-1000)系统 - AI返回相对坐标(0-1000),(0,0)为图片左上角,(1000,1000)为右下角 - 代码将相对坐标转换为绝对坐标:`绝对X = 相对X × width / 1000`,`绝对Y = 相对Y × height / 1000` 2. **Prompt优化**: - 明确要求AI返回相对坐标(0-1000) - 添加坐标系统说明和示例 3. **转换逻辑修正**: - 移除错误的Y坐标修正(`Y × height_ratio`) - 实现正确的相对坐标到绝对坐标转换 **效果**:坐标定位准确,批改标记位置正确 ### 2026-03-26 题目和答案识别优化(重要) **问题**: 1. 无法准确区分"题干"和"学生答案" 2. 批改气泡不在学生答案位置 3. 题干位置被误标注为答案 **修复内容**: 1. **Prompt重写**: - 明确定义"题干"和"学生答案"的区别 - 强调只标注学生手写答案,不标注印刷体题干 - 添加识别流程指导 2. **坐标定位优化**: - 自动计算mark_position:答案框右侧30像素,垂直居中 - 添加边界检查,确保不超出图片范围 - 不再依赖AI返回的mark_position(可能不准确) 3. **识别指导**: - 题号识别:如1、2、3、(1)、(2)等 - 答案定位:学生手写内容(不是印刷体) - bbox框选:准确框选学生答案区域 **效果**:更准确地区分题干和答案,批改气泡位置更精准 ### 2026-03-25 批改速度优化 **优化前**:每张图片需要3次LLM调用(识别+批改+整体评价) **优化后**:每张图片只需1次LLM调用 **具体优化**: 1. **合并识别和批改**:将`homework_recognize`和`correction_judge`合并为`recognize_and_correct`节点 - 识别题目、学生答案、坐标的同时进行批改 - 减少一次LLM调用,速度提升约50% 2. **简化整体评价**:不再调用LLM生成整体评价 - 使用规则直接生成评价内容 - 根据得分率和错误数量生成个性化评语 - 减少一次LLM调用 3. **子图节点精简**:从5个节点减少到4个节点 - 移除:homework_recognize、correction_judge - 新增:recognize_and_correct(合并节点) - 保留:image_preprocess、result_merge、wrap_result **效果**: - LLM调用次数:每张图片从3次减少到1次 - 预计批改时间减少约60% ### 2026-03-25 新增输入参数控制 1. **新增 `comment_max_length` 参数**:控制评语最大字数,默认100字 2. **新增 `grade_standards` 参数**:自定义评价等级标准 - 支持自定义各等级的最低得分率百分比 - 支持自定义各等级的描述 - 默认标准:A+(≥95%)、A(≥90%)、B(≥80%)、C(≥70%)、D(<70%) 3. **使用方式**: ```json { "homework_images": [...], "comment_max_length": 50, // 评语最多50字 "grade_standards": { "A+": {"min_percentage": 98, "description": "完美"}, "A": {"min_percentage": 90, "description": "优秀"}, ... } } ``` ### 2026-03-25 评语优化与整体评价 1. **评语具体化**:批改评语要求具体说明对错原因 - 正确时:说明为什么正确 - 错误时:指出错误原因并给出正确答案 - 部分正确时:说明哪些对了哪些错了 - 字数限制:50字以内,最多不超过100字 - 不要显示思考过程,只输出结果 2. **评语示例**: - 选择题正确:答案为B,与标准答案一致,正确。 - 填空题错误:答案应为8+√7和8-√7,学生只写了一个,不完整。 - 解答题正确:解题过程完整,步骤清晰,结果正确。 - 计算题错误:计算过程有误,正确答案是m=2,建议检查移项步骤。 3. **整体评价**:根据所有批改内容自动生成简短的整体评价 - 调用LLM生成个性化评价 - 评价不超过50字 - 包含主要问题或优点 - 给出简短建议 4. **HTML报告优化**:在统计总览后显示整体评价区域 ### 2026-03-25 自动旋转功能 1. **新增横向图片自动旋转**:如果上传的图片宽度大于高度(横向图片),系统会自动旋转-90度使其变为纵向 2. **旋转时机**:在图像预处理阶段,下载图片后、缩放前进行旋转 3. **旋转方向**:逆时针旋转90度(rotate(-90)),确保文字方向正确 4. **日志记录**:添加详细的旋转日志,便于调试 ### 2026-03-25 多图片批改功能 1. **新增多图片支持**:从单图片批改升级为支持多图片批量批改 2. **新增子图架构**:创建 `loop_graph.py` 封装单图片处理流程 3. **新增循环节点**:创建 `process_images_node.py` 循环调用子图处理每张图片 4. **重构状态定义**: - `GraphInput.homework_image` → `homework_images: List[File]` - 新增 `SubgraphState`、`SubgraphInput`、`SubgraphOutput` 子图状态 - 新增 `SingleImageResult` 单图片批改结果 - 新增 `FinalResult.image_results` 多图片结果列表 5. **重构HTML生成**:支持生成包含所有图片批改标注的HTML报告 6. **优化主图编排**:简化为三节点线性流程(doc_extract → process_images → html_generate) ### 2026-03-25 双模式批改机制 1. **新增智能降级逻辑**:优先使用标准答案,无标准答案时自动切换专业老师模式 2. **修改state.py**:`answer_doc_url`改为可选字段,支持不提供答案URL的场景 3. **升级correction_judge_node**:实现题目分离逻辑,有标准答案和无标准答案分别处理 4. **更新Prompt**:批改节点支持两种模式(标准答案模式 + 专业老师模式) 5. **优化doc_extract_node**:无URL时返回空列表,不中断工作流 ### 2026-03-25 Word答案解析功能 1. 新增 `doc_extract_node` 节点:从Word文件(.docx)提取题干和标准答案 2. 使用 python-docx 提取 Word 文档内容 3. 并行处理架构:图像识别与答案解析同时进行 4. 基于 Word 中的标准答案进行精准批改 ### 2026-03-25 OCR识别能力优化 1. 问题:识别节点把学生答案中的"8"错认成"9",导致误判 2. 优化识别节点prompt:增加OCR识别特别提示,强调区分8和9、6和0、1和7等相似字符 3. 效果:第7题正确识别为"8+√7,8-√7",满分通过 ### 2026-03-25 批改能力升级 1. 升级批改节点模型:`doubao-seed-1-6-vision-250815` → `doubao-seed-2-0-pro-260215` 2. 原因:较小模型对选择题判断准确率不足 3. 效果:选择题判断准确率大幅提升,推理过程更严谨 ### 2026-03-24 重构(学习豆包APP方式) 1. 从8个节点简化为5个节点(现调整为子图+主图架构) 2. 采用一体化识别:AI识别answer_bbox,代码计算mark_position 3. 实现精准坐标计算,Y坐标与答案垂直中心完美对齐 ## TODO - 提供真实的多页作业图片进行完整流程测试 - 优化HTML报告的图片展示布局 - 支持PDF格式答案文档