背景:我为什么要搭这个

我是个做教育信息化的开发者,跟学校教研组打交道多了,发现一个很反直觉的事:一次集体备课,最累的不是备课本身,是备课之后的"记纪要"。记录人要花一节课把讨论整理成纪要,而最关键的"意见分歧"——比如这节课到底该用数轴直观还是口诀提速——经常被记录人"和稀泥"带过,最后纪要里只剩共识,分歧丢了。两周后没人记得当时为什么吵。

我想试试用大模型把这件事自动化,但通用大模型直接跑"会议纪要"有两个硬伤:① 输出格式飘,没法直接落库;② 为了显得"全面",经常把分歧写成共识。所以我搭了一个教研协同 Agent,强约束它输出结构化 JSON,并且明确要求"不得将未达成共识的内容写成最终结论"。

最终效果

先放结果。下面这张图是一次真实的七年级数学集体备课(有理数运算薄弱环节对策)跑出来的纪要——几秒出,七段结构齐全,两种对立意见都原样记下来了,没被和稀泥

放大看关键部分:

  • 七段结构一次成型:会议目标 / 核心观点 / 已达成共识 / 尚未解决的问题 / 行动项(带负责人和截止时间)/ 需要补充的资料 / 意见分歧记录
  • 分歧被如实归集:刘一鸣说"口诀对基础薄弱学生可能变成机械记忆,应保留数轴操作至少两周",张淑贤说"先并行两周用数据说话"——两种观点都在 disagreements 字段里,没被合并成"经讨论一致同意"。
  • 行动项到人:李文静负责口诀材料(下周三前)、刘一鸣负责数轴练习包(下周五前)、赵敏负责归档——owner 全部来自讨论记录里的真实姓名,没有幻觉。
  • 状态是"待教师确认":AI 永远不替老师拍板,纪要生成后状态是 pending_confirm,教师点"教师确认"才算定稿。

这东西能跑,而且跑得稳。

搭建过程

技术选型

选型

为什么

模型

Qwen3.8-MAX(OpenAI 兼容协议)

强 JSON 纪律 + 中文教学语义自然,术语(通分/移项/异号相加)零翻译腔

后端

Spring Boot 3.3 + Java 17 + Spring Data JPA + PostgreSQL(jsonb)

jsonb 存七段纪要结构,JPA 省去手写 SQL

前端

Vue 3.5 + TypeScript + Element Plus + ECharts

教研详情页要渲染七段+表格+引用,组件库省事

网关接入

OpenAI 兼容 /v1/chat/completions,Bearer Token

关键决策:用兼容协议意味着我随时能切 Qwen/DeepSeek/其它,不被锁死,改 3 个环境变量就行

知识库

PostgreSQL + 关键词匹配(二期 pgvector)

纪要底部的"生成依据"靠它注入引用

整条链路:前端点"生成会议纪要" → POST /api/research/activities/{id}/minutes/generate → 后端组装 Prompt → 调 Qwen3.8-MAX → 解析 JSON → 内容审核 → 审计留痕 → jsonb 落库。

核心 Prompt / Agent 编排

这是整个 Agent 的灵魂。我用了一个"系统提示词 + JSON 输出规则 + 任务模板"三层结构

① 系统提示词(所有 Agent 共用,定基调):

你是"AI智慧教学中枢 Agent",服务于学校教学管理、教师教研协作……
你的任务不是替代教师,而是帮助教师和学校更快获得有依据、可编辑、可追溯的教学建议。
工作要求:
1. 优先使用用户提供的教材、课程标准、校本资料和业务数据。
2. 所有事实性内容尽量给出来源;无法确认时标记"待确认"。
3. 严格区分数据事实、模型推断和行动建议。
4. 不编造教材页码、政策条款、成绩数据、研究结论或学生信息。
5. 不对学生进行心理诊断、人格评价或长期能力定性。
6. 不直接替教师或学校作出升学、处分、绩效和其他高风险决定。
7. 涉及隐私时使用学生编号或脱敏信息,不输出真实敏感数据。
9. 语言自然、克制、专业,避免夸张的AI营销表达。

注意第 2、3、4 条——这是反幻觉和反"和稀泥"的根。

② JSON 输出规则(追加在任务模板前,强制结构化):

【本次任务的特别要求】本次任务要求输出结构化 JSON:
1. 只输出一个合法 JSON 对象,不要输出任何 JSON 之外的文字、解释或 Markdown 代码块标记。
2. 不得输出上述八段式文本结构,严格按任务给定的 JSON 结构输出。
3. 数组字段没有内容时输出空数组 [],不要省略字段。

这一段是踩坑后才加的,后面会说。

③ 教研纪要任务模板(本 Agent 专用):

请根据以下教研会议材料生成结构化会议纪要。
会议主题:%s / 参与人员:%s / 会议议程:%s / 讨论记录:%s
请输出 JSON:
{ "objectives":["会议目标"],
  "keyPoints":["核心观点"],
  "consensus":["已达成共识"],
  "unresolved":["尚未解决的问题"],
  "actionItems":[{"content":"行动项内容","owner":"负责人姓名","deadline":"截止时间"}],
  "neededMaterials":["需要补充的资料"],
  "disagreements":["可能存在的意见分歧"] }
要求:不得将未达成共识的内容写成最终结论;
负责人必须来自讨论记录中出现的真实姓名;无法确定的截止时间填写"待确认"。

最后一句"不得将未达成共识的内容写成最终共识"是分歧归集的关键约束。

后端编排伪代码AiStructuredService.generateMinutes):

public Map<String,Object> generateMinutes(AppUser user, ResearchActivity activity, List<Citation> citations) {
    String prompt = MINUTES_JSON_TEMPLATE.formatted(title, members, agenda, discussion);
    String raw = aiGateway.chat(SYSTEM_PROMPT + JSON_OUTPUT_RULE, prompt);  // 调 Qwen3.8-MAX
    List<String> issues = reviewService.review(raw);                         // 规则审核
    JsonNode root = parseJsonOrThrow(user, raw, title);                      // JSON 解析(带兜底)
    Map<String,Object> minutes = buildMinutes(root, citations);              // 组装七段
    minutes.put("status", "pending_confirm");                                // 关键:待教师确认
    auditService.recordAi(...);                                              // 审计留痕
    return minutes;
}

踩坑记录(这部分最真实)

坑 1:模型偶尔用 ```markdown 代码块包 JSON,后端解析直接炸

第一版我没加 JSON 输出规则,直接把任务模板发给模型。十次里大概一两次,模型会"贴心地"返回:

```json
{ "objectives": [...] }
```

后端 objectMapper.readTree(raw) 直接抛 JsonProcessingException,前端收到 502。

解法:① 在系统提示词后追加 JSON_OUTPUT_RULE,明确"不要输出 Markdown 代码块标记";② 后端 parseJsonOrThrow 加兜底——先剥 包裹,再截首尾大括号:

private JsonNode parseJsonOrThrow(AppUser user, String raw, String target) {
    String text = raw.strip();
    if (text.startsWith("```")) {
        text = text.replaceFirst("^```[a-zA-Z]*\\s*", "").replaceFirst("\\s*```$", "");
    }
    int start = text.indexOf('{'), end = text.lastIndexOf('}');
    if (start >= 0 && end > start) text = text.substring(start, end + 1);
    try { return objectMapper.readTree(text); }
    catch (JsonProcessingException ex) { throw new BusinessException(BAD_GATEWAY, "AI输出格式异常,请重试"); }
}

加了之后解析失败率趋近 0。教训:永远不要信任模型的格式承诺,后端必须有兜底解析。

坑 2:分歧被写成共识(这是最隐蔽的坑)

最早的任务模板里没有"不得将未达成共识写成共识"这句。结果我发现,模型为了显得"讨论有成果",会把两种对立观点柔和成"经讨论,决定采用 XX 方案"——分歧消失了。

这在教研场景是致命的:分歧恰恰是两周后回溯决策依据的关键。丢了分歧,等于丢了"当时为什么没选另一条路"。

解法:在任务模板末尾硬约束"不得将未达成共识的内容写成最终共识",并单独设 disagreements 字段要求模型显式归集。改完之后,前文刘一鸣 vs 张淑贤的分歧就被准确记录了。

坑 3:owner 字段偶尔是空的

讨论记录里如果某人说"这件事我来跟进吧"但没报名字,模型有时会把 owner 填空。

解法:任务模板加"负责人必须来自讨论记录中出现的真实姓名",模型基本能对上号;实在对不上的,后端兜底填"待确认",不报错。

坑 4:调了几轮?

诚实说,Prompt 大概调了 3 轮就稳定了:第 1 轮加 JSON 规则(解坑 1),第 2 轮加分歧约束(解坑 2),第 3 轮加 owner 约束(解坑 3)。Qwen3.8-MAX 对结构化约束的理解力不错,没有反复拉扯。提示词版本从 v2.0 走到 v2.2 定稿,之后没再动过。

效果对比

vs 人工记录(教研组真实情况):

指标

之前(人工记录)

现在(Qwen3.8-MAX Agent)

纪要耗时

记录人花 40-60 分钟课后整理

点一下,3-5 秒出初稿

Token 消耗

单次输入≈2500、输出≈1500 token,成本可忽略

七段结构完整度

凭记录人经验,常缺"分歧"或"待补资料"段

七段齐全,字段命中率稳定

分歧保留率

经常被"和稀泥",共识为主

两种对立观点原样归集,不合并

行动项到人

模糊("数学组负责")

明确到个人+截止时间

教师确认门槛

无(记录人定稿即发)

AI 出初稿状态 pending_confirm,教师确认才定稿

一句话:快是真的快(40 分钟 → 5 秒),但更值钱的是"分歧不被和稀泥"——这是人工记录最容易丢、而恰恰最该留的东西。

效果对比(vs 通用对话模型)

也对比了一下不加约束、直接让通用对话模型写纪要:

指标

通用对话模型(裸跑)

Qwen3.8-MAX(+ Prompt 工程)

JSON 一次成型率

常需 1-2 次重试去掉 Markdown 包裹

首次跑通即合法 JSON

单次生成时长

纠错后 ≈ 8-12s

≈ 3-5s(无纠错)

分歧保留

倾向写成共识

显式归集到 disagreements

后处理

需手动清洗格式

直接落库

诚实说:这里的提升不只是模型的功劳,更多来自 Prompt 工程(JSON 规则 + 分歧约束 + 后端兜底)。但 Qwen3.8-MAX 对这些硬约束的理解力和遵从度,是这套方案能稳定跑通的前提——换成 JSON 纪律弱的模型,同样的 Prompt 会出现字段缺失,需要更多重试。

总结:Qwen3.8-MAX 在这个场景下的表现

优点:强 JSON 纪律(七段结构一次成型、字段完整)、中文教学语义自然(术语零翻译腔)、对"不得和稀泥"这类硬约束遵从度高、单次生成 3-5 秒。在"结构化教研内容生成"这个场景下,是能稳定落地的。

缺点/注意:① 模型本身不产引用来源——纪要底部的"生成依据"靠后端知识库检索注入,检索没命中时引用为空,得老师手动补;② 偶发用 Markdown 包裹 JSON(已用后端兜底解决,但不能完全依赖模型自律);③ 反幻觉能力强依赖 Prompt 约束 + RAG,裸跑会退化。

一句话:Qwen3.8-MAX 不是"自己就能搞定一切"的魔法,而是"你把约束讲清楚,它就能稳定执行"的可靠搭档——这在需要可审计、可追溯的教育场景里,比"聪明但不可控"重要得多。

复现指南

环境配置

# 1. 起 PostgreSQL + Redis
cd ai-teaching-hub
docker compose up -d
# 2. 配置 Qwen3.8-MAX 网关(仅环境变量,不落源码)
export AI_GATEWAY_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
export AI_GATEWAY_API_KEY=<你的 key>
export AI_GATEWAY_MODEL=qwen3.8-max
# 3. 启动后端(首次自动建表+种子数据,统一密码 ChangeMe@2026)
cd backend && mvn spring-boot:run      # http://localhost:8080
# 4. 启动前端
cd ../frontend && npm install && npm run dev   # http://localhost:5173

演示账号

账号

角色

用途

T010

教研组长(张淑贤)

生成/审核纪要、审核资源

T001

教师(李文静)

生成纪要/学情/作业

A001

管理员(王海东)

审计日志、看板

统一密码 ChangeMe@2026,登录页可一键填充。

完整 Prompt(可直接复制)

系统提示词 + JSON 输出规则 + 纪要任务模板三段,见上文「核心 Prompt / Agent 编排」小节,逐字可用。版本号 v2.2。

注意事项

  1. 后端编译需带 -parameters:Spring 的 @PathVariable 反射依赖参数名,mvn 默认带这个 flag,但如果你手动 javac 会报 IllegalArgumentException: Name for argument not specified。用 mvn spring-boot:run 不会有这问题。
  2. 知识库当前是关键词匹配:纪要的"生成依据"引用质量受此限制,二期升级 pgvector 向量检索后会有质的提升。
  3. 不要把 API Key 写进源码:demo 的 application.yml 里为了方便写了默认值,生产必须只走环境变量并定期轮换。
  4. 纪要状态默认 pending_confirm:必须教师点"教师确认"才定稿,这是设计——AI 出建议,教师拍板。

搭这个 Agent 的完整代码在 ai-teaching-hub 仓库,教研纪要的核心逻辑在 AiStructuredService.generateMinutes()。有问题欢迎评论区交流。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐