PhysicsCorrection/AGENTS.md

826 lines
32 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.

## 项目概述
- **名称**: 初中数学作业批改工作流
- **功能**: 上传多学生的作业图片和Word答案文件自动识别学生答案、提取标准答案、精准批改并返回每个学生的批改结果JSON
### 数据结构(重要变更)
**输入参数**
```json
{
"student_homework": [
{
"student_id": 0,
"student_name": "张三",
"homework_images": [
"图片URL1",
"图片URL2"
]
},
{
"student_id": 1,
"student_name": "李四",
"homework_images": [
"图片URL3",
"图片URL4"
]
}
],
"answer_doc_url": "答案文档URL可选",
"comment_max_length": 100,
"max_concurrent": 10
}
```
**输出结果**
```json
{
"student_results": [
{
"student_id": 0,
"student_name": "张三",
"total_images": 2,
"image_results": [...],
"overall_comment": "优秀5题全部正确",
"total_score": 15,
"full_score": 15,
"grade": "A+"
}
]
}
```
### 节点清单
| 节点名 | 文件位置 | 类型 | 功能描述 | 分支逻辑 | 配置文件 |
|-------|---------|------|---------|---------|---------|
| 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 文档
- **缓存优化**:使用 `utils/cache_manager.py` 缓存解析结果有效期30天
## 缓存机制(优化版 v2026-03-28
- **缓存管理器**`src/utils/cache_manager.py`
- **双层架构**
- 内存缓存LRU淘汰最大数量1000快速访问
- 文件缓存:持久化存储,进程重启后仍可用
- **缓存有效期**30天自动清理过期缓存
- **缓存内容**AI解析后的结构化数据CorrectAnswer列表
- **缓存键**answer_doc_urlMD5哈希
- **线程安全**:使用锁保护并发访问
- **异常安全**:文件缓存失败时自动降级为纯内存模式
- **统计功能**`get_stats()` 返回缓存统计信息
### 性能优化与超时控制
- **图片下载超时**30秒单次总时间不超过60秒
- **重试机制**图片获取失败最多重试2次
- **单图片处理超时**120秒含LLM调用
- **总任务超时**120秒 × 图片数量
- **降级处理**:超时任务返回空结果,不影响其他任务
- **并发安全**:使用 `ThreadPoolExecutor` + 超时保护
## 等级标准配置(核心规则)
- **参数名**`grade_standards`
- **核心规则****A+ 和 A 的首要条件是"全对",与得分率无关**
### 等级判定逻辑(简化版)
| 等级 | 条件 | 说明 |
|------|------|------|
| A+ | 全对(错误数=0 | 所有题目都正确,与得分率无关 |
| A | 预留全对时返回A+ | 答案全对 |
| B | 有错误得分率≥80% | 有少量错误 |
| C | 有错误得分率≥70% | 错误较多 |
| D | 有错误,得分率<70% | 错误很多 |
### 关键说明
- **全对 = A+**只要所有题目都正确incorrect_count == 0就是A+
- **有错 = B/C/D**:有错误时,按得分率判断具体等级
### 示例
- 得分80分错误0题 A+全对得分率不重要
- 得分95分错误0题 A+全对
- 得分95分错误1题 B有错误按得分率判断
- 得分90分错误2题 B有错误按得分率判断
### 配置示例
```json
{
"grade_standards": {
"A+": {"min_percentage": 95, "description": "优秀"},
"A": {"min_percentage": 85, "description": "良好"},
"B": {"min_percentage": 70, "description": "中等"}
}
}
```
## 工作流程(多图片批改架构)
```
┌─────────────────────┐
│ doc_extract │
│ (Word答案解析) │
└──────────┬──────────┘
┌─────────────────────┐
│ process_images │
│ (多图片循环处理) │
│ 生成最终批改结果 │
└─────────────────────┘
```
### 子图内部流程(处理单张图片 - 优化版)
```
┌─────────────────────┐
│ image_preprocess │
│ (图像预处理) │
└──────────┬──────────┘
┌─────────────────────┐
│recognize_and_correct│ ← 合并节点:识别+批改一次完成
│ (一体化识别批改) │
└──────────┬──────────┘
┌─────────────────────┐
│ result_merge │
│ (结果整合) │
└──────────┬──────────┘
┌─────────────────────┐
│ wrap_result │
│ (包装输出) │
└─────────────────────┘
```
## 核心功能:多学生多图片批改机制
### 输入参数
- `student_homework`: 学生作业列表List[StudentHomework]支持多个学生
- 每个学生包含
- `student_id`: 学生IDint
- `student_name`: 学生姓名str可选
- `homework_images`: 该学生的作业图片URL列表List[str]纯字符串数组
- `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": "大面积错误核心知识点未掌握大量空白敷衍抄袭未达到基本完成要求"}
}
```
### 输出结果
- `student_results`: 各学生的批改结果列表List[StudentResult]
- 每个学生包含
- `student_id`: 学生IDint
- `student_name`: 学生姓名str
- `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-27 最终图片处理方案(重要)
**问题**如何在不上传图片的前提下保证AI识别准确
**方案对比**
| 方案 | 旋转缩放 | 上传 | AI访问 | 请求体积 | 选择 |
|------|---------|------|--------|---------|------|
| 方案1 | | base64编码 | Data URL | | |
| 方案2 | | | 原始URL | | |
**选择方案2的原因**
1. **AI模型足够强大**`doubao-seed-2-0-pro-260215` 可以处理各种尺寸和方向的图片
2. **坐标系统统一**使用相对坐标0-1000自动适配任意尺寸
3. **最简单高效**不需要base64编码不需要上传处理速度最快
**最终逻辑**
```python
# 获取原始图片URL和尺寸
original_url = state.homework_image.url
width, height, dpi = get_image_info(original_url)
# 直接返回原始URL不上传
return ImagePreprocessOutput(
image_url=original_url,
image_info=ImageInfo(width=width, height=height, dpi=dpi)
)
```
**效果**
- 不上传新图片到Coze
- 返回原始图片URL
- 坐标自动适配原始尺寸
- 处理速度最快
### 2026-03-27 移除图片上传功能(重要)
**问题**系统自动上传处理后的图片到Coze对象存储用户不需要这个功能
**原逻辑**
1. 下载原始图片
2. 自动旋转横向纵向
3. 缩放到固定宽度1000px
4. **上传到Coze对象存储**
5. 返回上传后的URL
**新逻辑**
1. 获取原始图片URL
2. 获取图片尺寸信息
3. **直接返回原始URL和尺寸**不上传
**优化内容**
- 移除图片旋转功能
- 移除图片缩放功能
- 移除图片上传功能
- 直接使用原始图片URL
- 坐标系统仍然使用相对坐标0-1000自动适配原始图片尺寸
**代码对比**
```python
# 优化前
img = download_and_rotate(image_url)
img = resize_to_1000px(img)
new_url = upload_to_coze(img) # 上传新图片
return ImagePreprocessOutput(image_url=new_url)
# 优化后
width, height, dpi = get_image_info(image_url)
return ImagePreprocessOutput(
image_url=original_url, # 直接返回原始URL
image_info=ImageInfo(width=width, height=height, dpi=dpi)
)
```
**效果**
- 不再上传新图片到Coze
- 返回原始图片URL
- 减少存储空间占用
- 提升处理速度
### 2026-03-27 坐标偏移量优化(重要)
**问题**批改标记离学生答案太远定位不够精准
**原因分析**
- 原偏移量设置过大30px20px
- 导致标记与答案视觉距离过远
- 影响批改结果的精准度
**优化方案**
减小所有偏移量让标记更贴近答案
| 策略 | 原偏移 | 新偏移 | 说明 |
|------|--------|--------|------|
| 策略1右侧空间>80px | +30px | **+10px** | 紧贴答案框右侧 |
| 策略2右侧空间40-80px | -20px | **-10px** | 答案框右上角内部 |
| 策略3右侧空间<40px | +20px | **+10px** | 答案框左上角 |
| Y轴偏移 | 15px | **10px** | 顶部位置 |
**代码对比**
```python
# 优化前
mark_x = answer_bbox[2] + 30 # 偏移过大
# 优化后
mark_x = answer_bbox[2] + 10 # 紧贴答案框
```
**效果**
- 批改标记更贴近学生答案
- 视觉定位更精准
- 避免标记离答案太远的问题
### 2026-03-27 坐标边界严格限制(重要)
**问题**标记坐标可能超过图片宽度导致定位错误
**修复内容**
1. **严格边界检查**
```python
# 确保x轴不超过图片宽度y轴不超过图片高度
mark_x = max(10, min(mark_x, image_info.width - 10))
mark_y = max(10, min(mark_y, image_info.height - 10))
```
2. **边界优化**
- 边距从20px减少到10px确保标记更接近边缘
- 绝对不会超过图片宽度和高度
- 保证批改标记始终在图片可视范围内
**效果**标记坐标始终在图片范围内不会出现越界问题
### 2026-03-27 空答案判定优化(重要)
**问题**学生没有作答空白判定不够明确
**修复内容**
在Prompt中新增"空答案处理"规则
```
# ⚠️ 重要:空答案处理
- 如果学生没有作答(空白),必须判定为**incorrect**
- status字段填写"incorrect"
- score字段填写0
- comment字段填写"未作答"或"空白,无答案"
```
**示例**
- 正确`"status": "correct", "score": 10, "comment": "计算正确"`
- 错误`"status": "incorrect", "score": 5, "comment": "单位错误"`
- 空答案`"status": "incorrect", "score": 0, "comment": "未作答"`
**效果**空答案统一判定为错误得分0分评语明确
### 2026-03-27 坐标定位精准度优化(重要)
**问题**个别批改标记过于偏右超出答题区域甚至与相邻题目重叠
**原因分析**
- 原逻辑固定在答案框右侧30px未考虑右侧空间是否充足
- 当答案框本身靠右时标记会超出合理范围
**优化方案**三级策略
1. **策略1**右侧空间充足>100px→ 标记在右侧(原有逻辑)
```python
mark_x = answer_bbox[2] + 30
mark_y = answer_bbox[1] + height * 0.5
```
2. **策略2**右侧空间不足50-100px→ 标记在答案框右上角内部
```python
mark_x = answer_bbox[2] - 20 # 内部
mark_y = answer_bbox[1] + 15
```
3. **策略3**:右侧空间很小(<50px)→ 标记在答案框左上角
```python
mark_x = answer_bbox[0] + 20 # 左侧
mark_y = answer_bbox[1] + 15
```
**效果**
- 批改标记始终在合理范围内
- 不会超出答题区域
- 不会与相邻题目重叠
- 视觉效果更精准
### 2026-03-27 完全并行架构优化(重要)
**问题**原架构外层串行处理学生内层并行处理图片效率不高且可能有数据混乱风险
**修复内容**
1. **完全并行架构**
- 所有学生的所有图片同时提交到线程池
- 学生间+图片间完全并行最大化效率
- 使用 `(student_id, image_index, image_result)` 元组确保数据关联
2. **数据隔离机制**
- 结果按 `student_id` 分组存储
- 每个学生的 `total_score`、`full_score`、`overall_comment`、`grade` 完全独立
- 只使用该学生自己的 `image_results` 计算分数
3. **核心代码**
```python
# 返回元组(student_id, image_index, image_result)
return (student_id, idx, image_result)
# 按student_id分组存储
student_image_results[student_id][image_index] = image_result
# 为每个学生独立计算结果
for student in state.student_homework:
image_results = student_image_results[student_id]
# 只使用该学生的数据计算...
```
**效果**
- 完全并行效率最大化
- 数据严格隔离不会混淆
- 学生A的数据绝不会出现在学生B的结果中
### 2026-03-27 输入参数格式优化(重要)
**问题**`homework_images` 使用 `List[File]` 格式用户输入不够简洁
**修复内容**
1. **简化输入格式**
- `homework_images: List[File]` `homework_images: List[str]`
- 直接传入URL字符串数组无需构造File对象
- 代码内部自动将URL转换为File对象
2. **输入示例**
```json
{
"student_homework": [
{
"student_id": 0,
"homework_images": ["url1", "url2"]
}
]
}
```
**效果**
- 用户输入更简洁
- 减少构造对象的复杂度
- 符合用户习惯
### 2026-03-27 多学生支持(重要变更)
**问题**原架构只支持单个学生的多图片批改无法区分不同学生
**修复内容**
1. **数据结构重构**
- 输入参数`homework_images` `student_homework`List[StudentHomework]
- 输出结果`final_result` `student_results`List[StudentResult]
- 新增 `StudentHomework` 类型包含 student_id homework_images
- 新增 `StudentResult` 类型包含 student_id 和批改结果
2. **处理逻辑优化**
- 外层循环遍历每个学生
- 内层循环并行处理该学生的所有图片
- 每个学生独立计算分数评语和等级
3. **返回结果独立**
- 每个学生有自己的 overall_commenttotal_scorefull_scoregrade
- 各学生的批改结果互不影响
**效果**
- 支持批量批改多个学生的作业
- 每个学生的结果独立清晰
- 符合实际教学场景需求
### 2026-03-27 Comment评语优化重要
**问题**comment字段输出过于简单"正确"/"错误"或输出思考过程不符合"精练评语"要求
**修复内容**
1. **明确comment定义**
- **正确时**简短说明为什么正确"根据称重法F浮=G-F示计算正确"
- **错误时**指出错误原因并给出正确答案"应为1.2N注意单位换算"
- **字数限制**不超过comment_max_length字默认100字
- **禁止**不输出思考过程不输出详细解析
2. **提供comment示例**
```
正确根据称重法F浮=G-F示计算正确
正确浮力产生原因理解正确
错误应为1.2N根据F浮=ρ液gV排计算
错误应选ACE控制变量法应用错误
错误正确过于简单
错误根据...思考过程...所以正确包含思考过程
```
3. **参数传递优化**
- comment_max_length正确传递到Jinja2模板
- LLM根据该参数生成符合长度要求的评语
**效果**
- comment既简洁又有意义
- 正确时说明原因错误时指出问题
- 符合comment_max_length限制
- 无思考过程无详细解析
### 2026-03-27 JSON解析健壮性优化重要
**问题**
- LLM输出JSON包含思考过程导致格式错误
- JSON太长11946字符解析失败
- annotations为空无法识别题目
**修复内容**
1. **新增extract_complete_objects函数**
- 从包含思考过程的JSON中提取完整对象
- 按对象边界逐个提取不受思考过程干扰
- 即使JSON格式错误也能提取出有效数据
2. **新增clean_comment函数**
- 检测思考过程特征词"不对"、"重新看"、"可能我"
- 在思考过程开始处截断comment
- 保留完整句子确保结论清晰
3. **增加max_completion_tokens**
- 从8192增加到16384避免JSON被截断
- 确保完整输出所有题目
4. **优化Prompt**
- 明确要求"禁止输出思考过程"
- comment只写结论"正确""错误应为X"
- 强调不要输出推理过程
**效果**
- JSON解析成功率大幅提升
- 即使包含思考过程也能提取有效数据
- annotations不再为空
- comment简洁无思考过程
### 2026-03-26 填空题拆分优化(重要)
**问题**一道题有多个填空时被合并成一个答案批改标记无法精准定位
**修复内容**
1. **优化Prompt**
- 明确要求一道题有多个填空时**每个空单独识别为一个题目**
- 题号格式\"3(1)第一空\"\"3(1)第二空\"\"4(2)第一空\"\"4(2)第二空\"
- 每个空单独批改单独打分
2. **示例说明**
```
错误3(1) "41"合并
正确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优化**
- 明确禁止标注实验装置图示意图电路图
- 明确禁止标注图中标注的字母如ABCDEFG
- 强调只标注学生手写答案
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. **识别指导**
- 题号识别如123、(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_recognizecorrection_judge
- 新增recognize_and_correct合并节点
- 保留image_preprocessresult_mergewrap_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和96和01和7等相似字符
3. 效果第7题正确识别为"8+√78-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格式答案文档