简介面向高中语文教师、教育研究者和LLM应用开发者的高中作文自动批改工具源码包。项目将大语言模型引入作文批改场景通过深层语义分析识别语法错误、逻辑矛盾与表达不当并依据高中作文评分标准在结构、逻辑、文采等维度自动评分同时给出建设性修改意见能有效减轻人工批改负担。压缩包共18个文件以Python源码、编译缓存pyc、工程配置、依赖清单与说明文档为主整体仅21KB适合快速阅读和二次开发。已有94人学习下载。main.py作为程序入口llm_func.py封装模型交互与提示词逻辑utils.py和tasks.py提供工具函数与批改任务调度test_article.py用于验证效果README与requirements.txt说明运行环境和依赖便于复现流程、替换或微调语言模型并进一步扩展个性化反馈与学情数据分析能力。1. 用LLM批改高中作文这不是给作文打分是给老师的深夜留一条退路深夜十一点语文老师刚改完当天的五十四篇周记圆珠笔油还没干。批改一篇作文熟练工也要七八分钟越改到后面越不敢下分数——手抖了评语糊了。基于LLM的高中语文作文自动批改应用就是把“先看立意、再看结构、再抠语言、最后给发展等级”这套阅卷人打法搬进一个zip包解压、装依赖、启动把作文贴进去五分钟内拿回一份带分项得分、扣分依据、升格建议的批阅单。它解决的不是“作文能不能被机器看懂”的哲学问题而是“老师今晚能不能睡上一觉”的现实问题。这篇笔记写给想自己搭一套的老师、教育产品工程师以及受够了规则评分“只查错别字不评好坏”的开发者。2. 落地前先看清全貌模型怎么选批改流水线怎么排2.1 为什么不建议直接用通用问答提示词批作文很多人拿到LLM第一反应是写一句“请批改下面这篇作文给出评价和分数”把作文粘贴在提示词后面。这样确实能出结果但结果基本不可用。通用问答模型默认“顺着用户说”你敢贴作文它就敢夸“结构完整、语言优美、是一篇佳作”然后给你一个 90 分——这个分数没法给家长交代因为评语里没有任何一处对应到作文的具体句子。批改和生成是两种任务。生成要多样性批改要一致性和可解释性。一个稳定的批改应用提示词里必须有评分量表rubric、扣分规则、输出格式约束还得告诉模型“不要改稿、不要夸、只评”。规则式批改引擎关键词匹配、字数统计、句式识别能抓病句和错字但判断不了“论证是否深入、材料是否贴切、立意是否新颖”——这些只能靠语义理解。LLM的价值正好在这它能把多维评分标准装进上下文给出接近人阅卷分项评分的判断。2.2 推荐流水线架构三阶段串联与每阶段的模型选型我建议把整个应用拆成三个独立阶段而不是让一次大模型调用干完所有事。预处理阶段清洗文本、去空行、分段、识别标题和结尾统计字数。这部分用正则和字符串处理就够了不占大模型资源。核心评阅阶段把作文正文 评分量表 评分要求一起发给LLM要求逐项打分并给出扣分依据。这是唯一必须用大模型的地方。结果规整阶段模型输出JSON做schema校验字段缺失就自动触发一次“补充评阅”调用而不是直接让程序崩溃。模型选型上线上API优先考虑Qwen、GLM这类中文语料扎实的商用模型离线部署优先考虑7B~14B量级的开源模型。批改不是“单点能力最强就好”而是“判断稳定”最重要。你不需要一个文采飞扬的模型你需要一个每次打分都差不多的模型——这一点在第4章展开。2.3 用Gradio还是FastAPIzip应用的两个入口形态zip交付时入口形态决定用户怎么启动这个应用。两种我都试过给你一张对比表。入口形态适用场景启动方式界面复杂度注意点Gradio老师本机试用、教研组小范围跑python app.py打开浏览器极低自带页面并发弱不适合同时十几个老师用FastAPI 前端页面学校机房/服务器部署uvicorn main:app启动较高需要配静态页接口清晰好对接教务系统新手验收阶段我强烈建议先用Gradio跑通批量实测三五篇再换FastAPI。Gradio拖慢了批改速度是正常的它把渲染和推理挤在同一个进程里别在这阶段怀疑模型能力。3. 把“好作文”翻译成让LLM听话的判分维度内容、结构、语言、发展等级3.1 高考作文评分的四个维度如何映射为大模型指令高考作文评分标准可以分成内容、结构、语言、发展等级四个维度。直接把这些中文术语丢给LLM不够模型对“内容”的理解可能是一段抽象赞美。你要把它们翻译成可判别的评分行为。我在项目里是这样映射的内容论点是否集中、论据是否贴切、论证是否有层次。落到prompt里就是“找出中心论点检查每段材料是否支撑中心论点判断论证是单纯罗列还是层层推进”。结构段落推进、过渡衔接、首尾呼应。落到prompt里就是“为每段写一句话概括检查段间过渡句是否存在判断结尾是否只重复开头”。语言句式变化、用词准确度、语病密度。落到prompt里就是“标出高频词指出句式单一的位置列出疑似病句并说明为什么”。发展等级见解深刻、材料丰富、表达有创意。落到prompt里就是“是否提出超出常规套路的观点是否使用跨越学科的材料是否有比喻或意象上的新意”。映射完成后的指令模型才知道自己该做什么动作而不是凭语感打一个总分。你可以先把这份映射存成JSON配置后面调参只改配置不改代码。3.2 分项量表prompt骨架与温度系数设置以下是我常用的评分指令骨架你看完可以直接改成自己的。# prompt_builder.py import json rubric { 内容: 论点是否集中、论据是否贴切、论证是否有层次, 结构: 段落推进、过渡衔接、首尾呼应, 语言: 句式变化、用词准确度、语病密度, 发展等级: 见解深度、材料丰富度、表达创新性 } system_prompt ( 你是高考语文阅卷组组长。请根据评分量表对输入作文逐项评分。 不要重写作文不要整体赞美。\n 评分量表\n json.dumps(rubric, ensure_asciiFalse) \n 输出格式\n {\内容\: {\得分\: 0, \扣分依据\: \\}, \结构\: {\得分\: 0, \扣分依据\: \\}, \语言\: {\得分\: 0, \扣分依据\: \\}, \发展等级\: {\得分\: 0, \扣分依据\: \\}} ) def build_prompt(essay: str) - str: return f请批改以下作文\n{essay}这里的逻辑是把评分量表放到system层让模型在“阅卷组长”角色下工作。输出格式限定为JSON且要求给出扣分依据——这既方便后端解析又逼着模型做“有依据的判断”。temperature系数我固定设在0.1top_p设0.7这两个参数保证每次打分不会因为采样波动差出分数档。如果你用的是第三方API还要把随机种子固定下来否则同样的作文每次调用结果都可能不一样。3.3 分段长文处理的窗口策略拼接、切片与要点保留高中作文一般800到1000字主流模型的上下文窗口装下没问题。但“装得下”不等于“处理得好”作文越长答辩越容易开小差。超过1200字的作文我会先切段再评。一种常见做法是对半切片第一遍评上半部分开头、论点提出、前两个分论点第二遍评下半部分后两个分论点、结尾最后让模型输出整合结果。这比一次性把全文丢进去更能抓住论证结构。还有一种做法是“要点保留”先用一次调用提取作文的论点、论据、过渡句等骨架信息再做第二遍评分把骨架信息附在原文后面作为注意力锚点。两种方法都是为了一个目的防止模型读到最后忘了开头。窗口策略要配合输出格式约束。分段评阅时每个分段都按同样的JSON结构输出最后在应用层做加权汇总而不是让模型自己“合并记忆”。4. 让每次打分一视同仁也让它能装进zip一致性设计、自校验与目录交付4.1 评分漂移的根源位置偏差、措辞敏感与样例锚定大模型评分漂移是个真实存在的“玄学”它不是模型坏了而是你的指令不够稳定。三个最常见的偏差源位置偏差、措辞敏感、样例锚定。位置偏差指模型更容易重点关注开头和结尾中间段落的优缺点容易被忽略。措辞敏感指prompt里一个字的调整比如“请批改”和“请审阅”都可能让分数波动。样例锚定则更隐蔽如果你在prompt里给了“这是一篇48分范文”模型会把这篇作文向48分靠拢给60分范文它就可能往高档走。应对办法是不把范文写进评分提示词而是把评分的判别标准写成“正例描述/反例描述”。我的做法是构造“评分锚点表”对应每个分数档位写清楚该档作文长什么样。给模型看“描述性锚点”而不是“完整范文”能大幅减少锚定效应。4.2 RAG参考作文库与回归校验让大模型当自己的改卷组长要让每次打分“一视同仁”我还建议加一层参考作文库RAG知识库。做法是整理三五十篇历年考场高分作文和典型低分作文按“内容”“结构”“语言”“发展等级”四个维度做分档标注向量化后存到本地库里。批改时先按作文内容检索最相近的3到5个参考案例把它们的分档标注作为上下文一起送进prompt。这相当于让模型先看看“这类作文往年怎么给分”再动笔打分。这一层同时兼顾了“LLM as Judge”的思路让大模型在参考样例的辅助下做裁判而不是拍脑袋评分。额外还有一层自校验评分结果出来后用独立的一次调用让模型复核“你的扣分依据是否匹配所给分数档位”如果模型自己都说“过低”或“过高”就把这次调用标记为低置信度并转入人工复核队列。回归校验是整个应用质量的守门员。我固定三篇不同风格的文章作为基线每次改prompt或换模型版本都先跑一遍这三篇对比前后分数差。这个思路和“基于LLM的单元测试”类似——大模型应用也得有回归测试否则一个提示词改动可能让全班成绩整体往上浮。4.3 zip目录布局与两条部署路径含模型挂载zip包里的目录布局直接决定用户能不能顺利跑起来。这是我现在用的目录结构llm_essay_grader/ ├── app.py # Gradio 入口 ├── main.py # FastAPI 入口 ├── requirements.txt ├── graders/ │ ├── prompt_builder.py # 评分指令构建 │ ├── rubric.json # 评分量表配置 │ └── validator.py # JSON 输出校验 ├── eval/ │ ├── regression_cases/ # 回归基线作文 │ └── anchors/ # 分档锚点描述 ├── storage/ │ ├── ref_vectors/ # 参考作文向量库 │ └── review_history/ # 批改记录存档 └── README.md # 启动说明这里需要注意两件事。第一模型权重不要和代码打在同一层压缩包里。如果用户要离线部署我会在README里写清楚“把量化GGUF模型放到models/目录”图上标注的一个7B量化模型动辄4到5个GB代码zip只有几十KB合并打成一个zip解压出问题用户分不清是代码错还是模型错。第二requirements.txt务必锁版本。Gradio和FastAPI的大版本更新经常破坏兼容性不锁版本半年后用户解压zip装依赖容易直接报错。不给模型文件的zip本质上交付的是“应用外壳 使用说明”。它的落地路径有两类一是纯API模式用户自带大模型API Key改一个环境变量就能用二是离线模式我把量产级别的GGUF模型也放进去整个包会非常大但好处是作文数据不出机房学校更愿意用。部署路径模型来源隐私强度跑通难度适用对象API模式用户自备Key中作文上云低教研组试用、个人老师离线模式包内置GGUF高数据不出本机中学校机房、有合规要求5. 自动批改应用的5个避坑记录从漏判“发展等级”到幻觉泛滥5.1 现象一特征分给得出发展等级永远打不满上线第一周我最常收到的反馈是“内容、结构、语言分得都挺准发展等级怎么永远只有一半分”。不是那批学生真的缺乏创意是提示词出了问题——我在评分量表里把“发展等级”排在最后一个模型给前面三个维度用完注意力后“发展等级”成了它的注意力盲区。原因模型对“列表末尾项”的关注度天然低于开头项且“发展等级”本身缺乏可操作的判别动作。解决把发展等级拆成“创意点识别、素材丰富度、逻辑纵深”三个子问题单独定义一个函数调用并配正反例锚点而不是让模型统一评分。# grader.py 中新增的一个独立评阅调用 def grade_development(essay: str) - dict: prompt ( 只评发展等级忽略其他维度。\n 检查三个子项\n 1. 是否提出超出常规套路的观点\n 2. 素材是否跨学科、非陈词滥调\n 3. 论证是否有递进深度\n 对每个子项给出是/否及示例原文。 ) # 调用模型返回结构化评分 return llm_call(prompt, essay)5.2 现象二同一篇作文换台机器分数差了4分教研组里有人用Mac有人用Windows同一篇作文分数能差出一个档位。我一开始以为是模型版本不一致后来查出来是量化模型文件精度不同、推理时的随机种子没固定。原因离线部署的GGUF模型量化等级不一致加上采样参数不固定导致结果漂移。解决在README里规定统一用q4_k_m量化版本并在代码里固定seed、temperature、top_p。更稳妥的做法是在系统启动时校验模型文件的SHA256不一致就报错提示而不是让用户“凑合跑”。5.3 现象三长作文批到一半输出变成“观点总结”超过1400字的作文输出经常在三分之一处从“评分”变成“内容摘要”然后就没了。这不是模型真的“累了”是上下文过长导致模型把任务理解偏移了。原因模型的有效注意力窗口小于标称输入窗口长文本末尾语义权重过高模型把整段输入当成“总结任务”。解决切成两段评分然后合并。合并时应用层负责加权平均不让模型自己记忆前文。实测这样做之后长作文的评分稳定性明显回升。5.4 现象四参考范文一多LLM开始照着范文“借分”加入RAG参考库后出现了一个新问题系统对某些作文明显“手松”给的评语像在描述参考范文而不是眼前这篇作文。原因检索回来的参考案例是完整范文模型读了范文全文后会把其中高分特征“套”到当前作文上形成幻觉。解决向量库里存的不再是范文全文而是“分档锚点描述”——即“该档作文典型特征”的抽象文本。检索时只给模型看这些描述不给范文本体避免模型抄袭范文打分。5.5 现象五离线部署的模型幻觉严重线上API又怕隐私试用阶段大家都不敢把学生作文传第三方API怕数据合规上有问题而本地跑7B模型又发现它经常编造作文里不存在的句子作为“扣分依据”。原因小参数量模型的指令遵循能力和上下文约束力都弱于大参数模型。解决我现在的折中方案是本地7B模型做初筛和分项打分对低置信度样本比如模型自己觉得“把握不准”的才走云端API复核。成本不高隐私影响面也小。更省事的做法是离线部署也改用14B量化模型牺牲一部分性能换判断质量。6. 进阶用历史作文微调批改口径以及三分钟回归验证如果你打算把应用用在期中、期末这种正式阅卷场景建议你总有一天要走到微调这一步。不是训练模型学会写作而是训练它默认你所在学校的评分口径——不同学校的语文组对“深刻”的理解和宽容度并不一致。常见的做法是整理300到500篇带教研组集体定档分的老作文拆成训练集和验证集用LoRA的方式在不改动基础模型全部参数的前提下做低秩微调。我在项目里只微调过一版效果最明显的变化不是分数更准而是评语的“口径”更贴近本校老师习惯——原来模型只会说“论证不够深入”微调后能说出“本文对‘快与慢’只讨论了个人层面没有上升到时代背景”这就是阅卷组长的口吻。这个效果靠改prompt很难做到。微调之外更通用的进阶能力是回归验证。改任何一条提示词、换任何一版模型、动任何向量库之前先跑三篇固定作文对比评分是否仍在预设范围内。我的回归基线文件名叫regression_cases/内容覆盖三类一篇48分议论文、一篇40分偏题记叙文、一篇55分有创意的散文。每次改完跑一遍看分数档位和评语基调解体性有没有变化。回归样例期望得分区间重点关注48分议论文46~50论点集中论据偏常规40分偏题记叙文38~42语言不错内容跑偏55分创意散文52~57结构松散但表达有亮点这三分钟的时间千万别省。我吃过一次亏改了一条“请重视语言表达的多样性”的prompt主观上觉得加强了语言维度结果回归测试三篇作文的“内容”得分全部掉档。原因是新指令让模型把注意力优先放在了句式上挤占了内容和论点的判断权重。从那以后我养成了习惯任何改动先跑回归不跑就不上生产。如果你要把这个应用真正推给自己的同事或客户我最后一条建议是先拿10篇旧作文跑通全流程打印出评分单给语文教研组长看让他挑毛病。你不需要让机器替代老师的判断你只需要让机器替老师把“每篇作文都改完”这件事做完。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?