DDD + AI Agent 怎么设计一套智能教育题库系统?从知识库、搜题到智能组卷完整拆解
DDD + AI Agent 怎么设计一套智能教育题库系统?从知识库、搜题到智能组卷完整拆解
很多人第一次设计“AI 教育平台”,很容易把重点放在大模型上:接一个模型 API,给它一段 Prompt,让它生成教案、解析题目、自动组卷,看起来很快就能做出一套“智能系统”。
但真做过复杂业务系统的人都知道,问题往往不在“AI 能不能生成”,而在于:生成出来的东西是不是受业务规则约束,题目数据能不能长期维护,知识点体系会不会越做越乱,组卷能不能稳定可控,AI 出错之后谁来兜底。
如果系统只是做 Demo,Prompt 驱动当然够用。但如果目标是建设一套真正能落地、能持续演进、能服务教师和学生的教育平台,那么架构核心就不能是“调用大模型”,而应该是:
先用 DDD 把教育业务领域拆清楚,再把 AI Agent 作为领域能力增强层接进去。
本文就围绕一套典型的智能教育平台,完整拆一下应该怎么设计。
平台主要包含知识库建设、题目维护、格式模板管理、学生搜题、教师备课、智能出卷等能力,同时还要考虑 AI 预标注、同类题、变式题、分步解析、智能组卷等 AI 场景。
这类系统非常适合用 DDD。
一、先说结论:AI 不是核心领域,教育业务才是
设计这类系统时,我最先确定的一条原则是:
AI 不是领域本身,AI 是能力提供者。
这句话很重要。
很多系统会直接把业务写成:
String result = llm.chat("帮我生成一套高二数学试卷");
如果只是内部工具,这样做问题不大。
但一旦进入正式业务,这种设计很危险。
因为一套试卷到底应该有多少题、选择题几道、难度比例是多少、哪些知识点必须覆盖、总分是多少、是否允许重复题,这些都属于确定性的业务规则。
大模型适合做:
- 理解自然语言要求;
- 推荐候选题;
- 生成变式题;
- 分析题目;
- 辅助补充内容。
但最终的业务决策,不应该交给模型自由发挥。
比如智能组卷,更合理的流程应该是:
教师输入组卷要求
↓
AI 解析自然语言
↓
转换为结构化组卷约束
↓
领域规则校验
↓
题目候选池检索
↓
组卷算法求解
↓
AI 辅助补题 / 调整
↓
试卷领域再次校验
↓
生成最终试卷
换句话说:
AI 负责理解和生成,领域模型负责约束和裁决。
这也是整个系统最重要的架构边界。
二、先用 DDD 划清业务边界
从功能上看,这个平台表面上只有几个模块:
知识库、题库、模板、搜题、备课、组卷。
但如果真的做 DDD,不能只按页面菜单拆模块,而要按照业务能力和变化边界拆限界上下文。
我会至少划分下面几个 Bounded Context:
| 限界上下文 | 主要职责 |
|---|---|
| Knowledge Context | 知识点、课程标准、教材、章节体系 |
| Question Context | 题目创建、审核、发布、版本、标签 |
| Search Context | 关键词搜索、语义检索、相似题 |
| Paper Context | 组卷、试卷、细目表、组卷规则 |
| Lesson Context | 教案、课堂练习、分层作业 |
| Template Context | 教案模板、试卷模板、答题卡模板 |
| AI Context | Agent、Prompt、RAG、模型调用 |
| IAM Context | 用户、教师、学生、权限 |
这里需要特别注意一点:
DDD 不是简单地把目录从:
controller
service
mapper
entity
换成:
question
paper
lesson
真正的 DDD 是先思考:
业务能力
↓
业务边界
↓
领域模型
↓
聚合与行为
也就是说,一个模块存在的原因,不是因为页面上有个菜单,而是因为它拥有一套独立的业务规则和生命周期。
三、知识库建设:不是建几张“知识点表”那么简单
知识库是这个系统的基础。
从需求上看,知识库要维护:
- 知识点体系;
- 考纲;
- 教材;
- 文档库;
- 题库;
- 卷库。
很多系统一开始会设计一张 knowledge_point 表,然后配个 parent_id 做树。
这只能解决“展示树”的问题,却解决不了真正的知识体系问题。
例如高中数学中:
函数
├── 函数概念
├── 定义域
├── 值域
├── 单调性
└── 奇偶性
这里不仅仅存在父子关系。
还可能存在:
函数定义
↓ prerequisite
函数单调性
也就是“前置知识”。
还可能存在:
函数图像
↓ related
函数单调性
或者:
函数最值
↓ examinedBy
选择题 / 填空题 / 解答题
因此,真正的知识点领域不能只有一棵树。
我会把它建模为:
Subject
└── KnowledgeTree
└── KnowledgePoint
├── Parent
├── Children
├── Prerequisite
├── Related
└── CurriculumMapping
Java 领域模型可能类似:
public class KnowledgePoint {
private KnowledgePointId id;
private SubjectId subjectId;
private String name;
private KnowledgePointId parentId;
private Integer level;
private Difficulty difficulty;
private List<KnowledgeRelation> relations;
public void addPrerequisite(KnowledgePoint point) {
// 领域规则校验
}
public void bindCurriculum(CurriculumNode node) {
// 关联课程标准
}
}
知识点和教材之间也不应该写死。
因为同一个知识点,在不同教材版本中的章节位置可能不同。
所以需要有:
Textbook
↓
TextbookVersion
↓
Chapter
↓
KnowledgePoint Mapping
课程标准同理:
Curriculum
↓
CurriculumVersion
↓
CurriculumNode
↓
KnowledgePoint Mapping
这样后面才能支持不同省份、不同版本教材、不同年级,以及知识点体系的版本演进。
四、题目领域才是整个系统真正的核心
从业务价值来看,题库往往是整个平台最重要的数据资产。
因此 Question Context 应该作为核心域来设计。
题目不能只是数据库中的一行数据。
至少应该拥有这些属性:
public class Question {
private QuestionId id;
private QuestionContent content;
private QuestionType type;
private Subject subject;
private Difficulty difficulty;
private List<KnowledgePointRef> knowledgePoints;
private Answer answer;
private Analysis analysis;
private QuestionStatus status;
private QuestionVersion version;
}
更关键的是,它应该有自己的生命周期。
比如:
DRAFT
↓
AI_TAGGED
↓
WAITING_REVIEW
↓
APPROVED
↓
PUBLISHED
↓
ARCHIVED
很多 CRUD 系统会写成:
status = 0
status = 1
status = 2
然后所有业务逻辑堆在 Service 里。
DDD 更推荐让领域对象自己表达业务行为:
question.aiTag();
question.submitReview();
question.approve(reviewer);
question.publish();
question.archive();
例如发布题目时,可以这样:
public void publish() {
if (status != QuestionStatus.APPROVED) {
throw new DomainException("题目未经审核不能发布");
}
if (knowledgePoints.isEmpty()) {
throw new DomainException("题目必须关联知识点");
}
this.status = QuestionStatus.PUBLISHED;
}
这时候“题目能不能发布”这个规则,就真正属于 Question,而不是散落在某个 Service 的 if else 中。
这就是贫血模型和领域模型之间的差别。
五、AI 预标注不能直接污染正式题库
题目批量导入之后,通常会希望 AI 自动完成这些事情:
- 判断学科;
- 判断年级;
- 判断题型;
- 识别知识点;
- 判断难度;
- 补充标签。
比如一道题:
已知函数 f(x)=x²-2x+3,求函数最小值。
AI 可能返回:
{
"subject": "数学",
"grade": "高中",
"knowledgePoints": [
"二次函数",
"函数最值"
],
"difficulty": 2,
"questionType": "解答题"
}
这个结果看起来很好,但有一个架构问题:
AI 返回值不能直接覆盖正式题目。
因为 AI 本质上具有不确定性。
今天模型判断为“函数最值”,明天模型升级后可能又多判断一个“配方法”。
因此中间应该增加一个 AI 建议对象:
AITagSuggestion
流程变成:
导入题目
↓
AI 分析
↓
AITagSuggestion
↓
教师审核
↓
写入正式 Question
领域对象可以类似:
public class AITagSuggestion {
private List<TagSuggestion> knowledgePoints;
private DifficultySuggestion difficulty;
private double confidence;
}
这样有几个明显的好处。
第一,AI 和业务数据彻底解耦。
第二,可以保留 AI 的原始判断,后续做模型评估。
第三,可以统计不同模型的准确率。
第四,未来换 DeepSeek、豆包、OpenAI 或其他模型,都不会影响 Question 领域本身。
六、题目查重不能只靠 MD5
题库系统里,查重一定是高频需求。
但如果只是:
MD5(questionText)
实际上只能发现完全一样的文本。
例如:
题目 A:
若 x²-5x+6=0,求 x。
另外一道:
题目 B:
已知方程 x²−5x+6=0,请求出方程的根。
两道题表达方式不同,但本质上一样。
因此我会把查重分三层。
第一层是标准化文本 Hash。
先把:
- 空格;
- 标点;
- LaTeX 格式;
- 特殊字符;
- 全角半角;
做标准化。
这一层成本最低,可以快速挡掉完全重复题。
第二层使用 Elasticsearch BM25。
通过文本相关度判断高相似题。
第三层再使用 Embedding 向量。
把题目内容向量化,例如:
Question
↓
Embedding Model
↓
Vector
然后做 cosine similarity。
例如:
similarity = 0.96
就可以进入人工确认。
一个比较实用的技术组合是:
PostgreSQL
+
Elasticsearch
+
pgvector
早期规模不是特别大时,pgvector 完全够用。
等题库达到千万级甚至更大时,再考虑 Milvus、Qdrant 等独立向量数据库。
七、学生搜题应该独立成 Search Context
学生搜题看起来只是“查询题目”,实际上它和题库后台管理完全不是一回事。
后台题目查询强调:
- 条件准确;
- 权限;
- 状态;
- 管理操作。
学生搜索强调:
- 召回率;
- 语义理解;
- 相似题;
- 搜索体验;
- 排序效果。
所以我不会让学生搜题直接调用:
QuestionRepository
而是独立出 Search Context。
典型搜索链路:
用户输入
↓
Query Understanding
↓
BM25 Search
+
Vector Search
↓
融合排序
↓
Reranker
↓
权限过滤
↓
返回结果
为什么需要混合搜索?
例如用户输入:
函数最大值怎么求
真正相关的内容可能是:
- 函数最值;
- 二次函数;
- 配方法;
- 单调性;
- 函数图像。
如果只用数据库 LIKE:
WHERE content LIKE '%函数最大值%'
很多真正相关的题目根本搜不到。
而 BM25 + 向量搜索可以兼顾关键词准确性和语义召回。
再加一层 Reranker,则可以进一步优化排序。
八、分步解析要做成结构化 Agent,而不是长文本生成
学生搜题之后,平台可能要返回:
- 答案;
- 分步解析;
- 对应知识点;
- 解题思路;
- 易错点。
这里最容易出现的设计就是:
Prompt
↓
LLM
↓
一大段 Markdown
能用,但很难工程化。
更合理的是强制 Agent 返回结构化 JSON:
{
"steps": [
{
"index": 1,
"description": "整理函数表达式",
"formula": "...",
"knowledgePoint": "二次函数"
},
{
"index": 2,
"description": "使用配方法求最值",
"formula": "...",
"knowledgePoint": "函数最值"
}
],
"answer": "...",
"knowledgePoints": [
"二次函数",
"函数最值"
]
}
这样前端才能真正按照业务需求展示。
同时解析过程最好不要只依赖 LLM。
可以走:
Question
↓
标准答案
↓
知识点体系
↓
RAG
↓
Solution Agent
↓
Verifier Agent
↓
最终结果
尤其数学、物理这类题目,建议增加校验 Agent,降低模型生成错误答案的概率。
九、“同类题”和“变式题”必须分开设计
这两个功能看起来差不多,实际上完全是两种能力。
同类题属于搜索。
它的意思是:
从现有题库中找出与当前题目类似的题。
因此属于 Search Context。
链路大概是:
当前题目
↓
提取知识点
↓
文本检索
+
向量召回
↓
相似题排序
而变式题属于生成。
它的意思是:
在保持核心知识点的前提下,生成一道新的题。
所以应该由 AI Context 与 Question Context 协作。
流程:
Original Question
↓
Knowledge Constraint
↓
Variation Strategy
↓
LLM Generate
↓
Answer Agent
↓
Consistency Check
↓
Question Candidate
比如原题:
x²-5x+6=0
可以改变:
- 参数;
- 问法;
- 难度;
- 题型;
- 情景。
但必须保证:
核心知识点 = 一元二次方程
最终生成的也不能直接进入正式题库,而应该先进入候选状态。
十、智能组卷是另一个核心域
如果说 Question 是第一个核心域,那么 Paper 基本就是第二个。
试卷也不应该只是一张表。
可以设计为:
Paper
├── PaperSection
│ └── PaperQuestion
│
├── PaperConstraint
│
└── Blueprint
组卷本质上是一个多约束问题。
例如老师可能要求:
满分:150
考试时间:120 分钟
选择题:12
填空题:4
解答题:6
难度比例:
简单 30%
中等 50%
困难 20%
知识点比例:
函数 30%
数列 20%
概率 20%
其他 30%
这时候可以抽象出:
public class PaperConstraint {
private int totalScore;
private Duration duration;
private Map<QuestionType, Integer> typeDistribution;
private Map<Difficulty, Double> difficultyDistribution;
private Map<KnowledgePointId, Double> knowledgeDistribution;
}
有了这个对象,后面的组卷逻辑就不再依赖某个页面参数,而是真正形成领域语言。
十一、智能组卷绝不能全部交给大模型
这是整个 AI 教育系统里最容易踩坑的地方之一。
假设老师输入:
帮我生成一套高二数学月考试卷,重点考函数和数列,中等偏难。
LLM 很适合把这句话解析成:
{
"grade": "高二",
"difficulty": {
"easy": 0.2,
"medium": 0.5,
"hard": 0.3
},
"knowledge": {
"函数": 0.55,
"数列": 0.45
}
}
但是接下来真正选哪些题,不应该再让 LLM 随机决定。
合理的方案是:
自然语言
↓
Constraint Agent
↓
PaperConstraint
↓
Candidate Search
↓
Constraint Solver
↓
Paper
↓
Paper Evaluation
早期可以使用:
贪心
+
回溯
后续复杂后可以考虑:
- 遗传算法;
- 整数规划;
- Constraint Programming;
- Timefold;
- OptaPlanner。
这样生成出来的试卷才能真正满足:
- 总分;
- 题量;
- 知识点覆盖;
- 难度;
- 题型;
- 时间;
- 重复率。
AI 在这里是辅助者,而不是裁判。
十二、双向细目表应该是试卷领域自身的能力
双向细目表其实就是对试卷结构的一个二维统计。
比如:
| 知识点 | 选择题 | 填空题 | 解答题 |
|---|---|---|---|
| 函数 | 3 | 1 | 2 |
| 数列 | 2 | 1 | 1 |
| 概率 | 2 | 1 | 1 |
也可以从难度维度看:
| 知识点 | 简单 | 中等 | 困难 |
|---|---|---|---|
| 函数 | 1 | 3 | 2 |
| 数列 | 1 | 2 | 1 |
这个能力最好放在 Paper Context 中。
比如:
Blueprint blueprint = paper.generateBlueprint();
而不是让前端临时统计。
因为双向细目表后续可能还会参与组卷反向校验,是重要的领域对象。
十三、教师备课是最适合发挥 Agent 能力的场景
相对于题库和组卷,备课是最适合大模型发挥的地方。
教师可能只输入一句:
帮我准备一节高一函数单调性的课。
如果只是普通 LLM 调用,流程就是:
Prompt
↓
LLM
↓
教案
但真正的 AI Agent 应该能够自动完成多个步骤。
例如:
Lesson Planning Agent
│
┌───────────────┼───────────────┐
↓ ↓ ↓
Curriculum Agent Knowledge Agent Search Agent
│ │ │
└───────────────┼───────────────┘
↓
Lesson Planner
↓
┌─────────────────┼─────────────────┐
↓ ↓ ↓
教案 Agent 课件 Agent 练习 Agent
│ │ │
└─────────────────┼─────────────────┘
↓
Review Agent
整个过程可能包括:
读取课程标准
↓
定位教材章节
↓
识别知识点
↓
寻找对应例题
↓
生成教学目标
↓
生成教学流程
↓
生成课件大纲
↓
生成课堂练习
↓
生成分层作业
这里 Agent 的价值就体现出来了。
因为它不是单次生成,而是:
拆任务、调用工具、读取知识、形成结果、再次校验。
十四、模板管理一定要从 AI 中独立出来
不同学校对教案、试卷、答题卡的格式要求往往完全不一样。
如果把这些格式全部写进 Prompt:
你必须按照 XX 学校的格式……
后面一定会越来越难维护。
因此应该独立设计 Template Context。
例如:
Template
├── LessonTemplate
├── QuestionTemplate
├── PaperTemplate
└── AnswerSheetTemplate
教案模板可以结构化:
{
"sections": [
{
"name": "教学目标",
"required": true
},
{
"name": "教学重点",
"required": true
},
{
"name": "教学难点",
"required": true
},
{
"name": "教学过程",
"required": true
}
]
}
这样以后学校 A、学校 B、学校 C 都可以维护自己的模板。
AI Agent 只负责:
读取模板
↓
按模板生成内容
而不是让模型自己决定格式。
十五、Java 工程目录不要再按 Controller、Service、Mapper 平铺
如果用了 DDD,我不太推荐这种传统项目结构:
controller
service
mapper
entity
因为项目一大,所有领域会混在一起。
更推荐:
education-platform
├── interfaces
│ ├── rest
│ ├── dto
│ └── assembler
│
├── application
│ ├── command
│ ├── query
│ ├── service
│ └── event
│
├── domain
│ ├── question
│ │ ├── model
│ │ ├── repository
│ │ ├── service
│ │ └── event
│ │
│ ├── knowledge
│ ├── paper
│ ├── lesson
│ └── template
│
└── infrastructure
├── persistence
├── redis
├── elasticsearch
├── mq
├── ai
└── oss
依赖关系保持:
Interface
↓
Application
↓
Domain
Infrastructure
↑
implements
↑
Domain Repository
例如 Domain 只定义:
public interface QuestionRepository {
Optional<Question> findById(QuestionId id);
void save(Question question);
}
MyBatis、JPA、数据库表这些实现细节全部放在 Infrastructure。
这样 Domain 就不会知道:
- MyBatis;
- Elasticsearch;
- Redis;
- PostgreSQL。
这也是六边形架构、整洁架构和 DDD 很容易结合的地方。
十六、这个系统非常适合 CQRS
题库平台有一个很明显的特点:
写操作业务规则重,读操作查询复杂。
写侧包括:
创建题目
修改题目
提交审核
审核通过
发布题目
组卷
这些操作应该经过领域模型。
而读侧包括:
题库检索
试卷预览
知识点统计
学生搜题
后台报表
这些查询没必要每次还原领域对象。
所以非常适合 CQRS。
例如:
Command
↓
Application
↓
Domain
↓
PostgreSQL
查询则可以直接:
Query
↓
Elasticsearch
Redis
Read Model
这会比所有请求都走 Repository 更合理。
尤其学生搜题,更不应该写成:
SELECT *
FROM question
WHERE content LIKE '%函数%'
十七、领域事件和 MQ 是非常重要的一环
这个系统存在大量“主流程完成后,异步处理”的任务。
比如一道题发布之后,后面可能需要:
- 写入 Elasticsearch;
- 生成 Embedding;
- 更新知识点统计;
- 更新推荐索引;
- 写审计日志。
所以可以定义:
QuestionPublishedEvent
消费者分别处理:
SearchIndexConsumer
→ 更新 ES
EmbeddingConsumer
→ 生成向量
KnowledgeConsumer
→ 更新知识体系统计
AuditConsumer
→ 写审计日志
整体:
老师发布题目
↓
Question 聚合
↓
数据库事务提交
↓
Domain Event
↓
MQ
↓
ES / Vector / Statistics
这里建议再配合 Outbox Pattern。
因为经典问题是:
数据库提交成功
MQ 发送失败
如果没有 Outbox,很容易出现数据库已经有题目,但搜索索引永远没有更新的情况。
十八、AI 层一定要做自己的 LLM Gateway
业务代码不要到处出现:
openAiClient.chat(...)
或者:
deepSeekClient.chat(...)
更合理的方式是定义统一接口:
public interface LlmClient {
LlmResponse chat(LlmRequest request);
}
具体实现:
OpenAiLlmClient
DoubaoLlmClient
DeepSeekLlmClient
QwenLlmClient
上面再包一层 LLM Gateway。
负责:
- 模型路由;
- 限流;
- 重试;
- 熔断;
- 超时;
- Fallback;
- Token 统计;
- 成本统计;
- Prompt 版本;
- 结构化输出。
例如:
题目分类
→ 低成本模型
复杂数学解析
→ 推理模型
教案生成
→ 长文本模型
Embedding
→ Embedding Model
否则系统越做越大,模型成本一定会失控。
十九、Agent 平台不要只理解成“LangChain”
如果后续 AI 场景越来越多,建议把 AI Context 做成一个相对独立的平台层。
可以抽象:
AI Gateway
│
├── Model Router
├── Prompt Manager
├── Guardrail
└── LLM Client
再往上:
Agent Runtime
├── Tool Registry
├── Context Manager
├── Workflow Engine
├── RAG
├── Memory
└── MCP Client
最后才是具体业务 Agent:
QuestionTagAgent
QuestionExplainAgent
QuestionVariationAgent
LessonPlanAgent
PaperGenerationAgent
PaperEvaluationAgent
这样做最大的好处,就是业务 Agent 不再关心:
到底调用哪个模型
Prompt 放在哪里
Token 怎么统计
超时怎么处理
失败怎么降级
这些全部交给 AI 基础设施层。
二十、第一版到底要不要上微服务?
我的建议反而是:
不要一上来就拆微服务。
很多团队一看到:
Knowledge Context
Question Context
Paper Context
Lesson Context
马上就想做:
knowledge-service
question-service
paper-service
lesson-service
但 DDD 和微服务不是一回事。
如果团队只有五六个人,却拆十几个服务,结果往往是:
Feign 调用满天飞
本地启动困难
链路排查困难
事务更复杂
发布更复杂
业务还没复杂,基础设施先复杂了。
所以第一阶段我更推荐:
Spring Boot
+
Spring Modulith
+
DDD
做模块化单体。
模块之间通过明确接口和领域事件交互。
当后面真正出现这些条件时,再拆:
- Search QPS 很高;
- AI 需要独立 GPU 或弹性扩容;
- 组卷计算越来越重;
- 团队组织独立;
- 模块发布频率明显不同。
这时候再把 Search、AI、Paper 等逐渐拆出来。
这比第一天就搞二三十个微服务务实得多。
二十一、我会采用的第一版技术栈
如果现在真让我落地,我会优先选成熟和可维护的技术,而不是追求“全新”。
后端:
Java 21
Spring Boot 3
Spring Modulith
数据库:
PostgreSQL
缓存:
Redis
全文检索:
Elasticsearch
向量检索:
pgvector
消息队列:
RocketMQ
或
Kafka
对象存储:
MinIO / OSS
AI:
Spring AI
或
LangChain4j
+
自研 Agent Runtime
任务调度:
XXL-JOB
复杂流程如果真的需要再考虑:
Flowable
Temporal
可观测:
Prometheus
Grafana
SkyWalking
部署阶段则:
Docker
+
Kubernetes
但还是那句话:
第一天不一定就需要 Kubernetes。
架构的目标永远不是复杂,而是让复杂业务变得可控制。
二十二、最终架构可以浓缩成这一张逻辑图
智能教育平台
│
┌───────────────────┼───────────────────┐
│ │ │
教师端 学生端 教务端
│ │ │
└───────────────────┼───────────────────┘
↓
API Gateway
↓
Application / BFF
↓
┌──────────────── Core Domain ────────────────┐
│ │
│ Knowledge Question Paper │
│ 知识体系 题库 智能组卷 │
│ │
│ Lesson Search Template │
│ 智能备课 搜题 模板 │
│ │
└─────────────────────────────────────────────┘
│ │
↓ ↓
Domain Event AI Agent
│ │
↓ ┌─────────┼──────────┐
Kafka / MQ RAG Tools LLM
│ │ │
┌──────┼──────┐ │ │
↓ ↓ ↓ ↓ ↓
ES Redis Vector Knowledge DB Model Gateway
整个架构真正稳定的部分,是中间的领域模型。
AI 模型未来一定会变化。
今天可能用一个模型,半年以后可能全部切换。
Embedding 模型也会换,Agent 框架也会换。
但是:
什么是一道题
什么叫题目审核
什么叫试卷
什么叫知识点
什么叫组卷规则
什么叫教材章节
这些核心业务概念不会轻易改变。
这就是为什么要先做 DDD。
写在最后
做 AI 系统这两年,我越来越觉得一个误区特别明显:
很多人觉得 AI 来了之后,传统软件架构就不重要了。
实际恰恰相反。
因为 AI 是不确定的。
传统业务系统追求:
输入 A
一定得到 B
而 AI 可能是:
输入 A
这次得到 B
下次可能得到 C
正因为存在这种不确定性,核心业务才更加需要稳定的边界、确定的规则和可追踪的数据模型。
所以这类教育系统真正合理的架构,不应该是:
页面
↓
Spring Boot
↓
Prompt
↓
LLM
而应该是:
业务需求
↓
DDD 领域模型
↓
确定性业务规则
↓
AI Agent 能力增强
↓
规则验证
↓
最终业务结果
简单来说就是:
确定性的事情交给代码,不确定性的事情交给 AI。
题目是否已经审核通过,由领域模型决定。
一套试卷总分是不是 150 分,由规则引擎决定。
题型比例是否符合要求,由组卷算法决定。
AI 可以帮助理解老师想要什么,可以推荐更合适的题,也可以生成一道变式题,但它不应该成为整个业务系统最终的裁判。
如果把这个原则守住,再结合 DDD 做好 Knowledge、Question、Paper、Lesson、Search、Template 等业务边界,这套系统后面不管是扩展到小学、初高中,还是职业教育、在线教育,甚至继续加入 AI 学情分析、个性化推荐、自动批改,都还有比较充足的演进空间。
真正好的 AI 架构,从来不是“模型调用得有多花”,而是当模型发生变化、业务规模扩大、数据越来越多之后,系统依然能保持清晰。
而这,才是 DDD 在 AI Agent 时代最大的价值。
更多推荐



所有评论(0)