面向教育 Agent 的 Harness 学习进度持久化
面向教育 Agent 的 Harness 学习进度持久化落地全指南
作者:老周 | 资深AI教育产品技术负责人 | 深耕教育Agent落地2年
本文字数:14800+字 | 建议收藏后分段阅读,配套代码可直接用于生产环境
引言
痛点引入
我相信所有做过教育Agent落地的开发者都踩过「学习进度持久化」的坑:
- 测试用户反馈用手机刷了2天初二数学题,换电脑登录之后进度全丢,排查发现是之前用内存存会话状态,服务重启数据全部清零,被老板骂了整整一下午;
- 多端同时学习时进度冲突,用户在平板上做了一套测评掌握度升到0.7,手机上做了一道题进度回退到0.5,用户投诉说自己的学习成果被「吃了」;
- 迭代知识点图谱时存量进度不兼容,我们把初中数学的「一元一次方程」拆成了3个子知识点,老用户的进度全部失效,不得不连夜写迁移脚本,还赔了用户1个月的会员;
- 合规检查不过关,教育数据属于敏感个人信息,我们之前把用户学习记录存在境外的云服务上,被监管警告,差点停服整改。
这些问题本质上不是业务逻辑的问题,而是教育Agent的持久化基础设施没有适配场景特性:普通的CRUD存储解决不了多端冲突、版本兼容、合规审计、高可用扩展这些教育场景的刚性需求。
解决方案概述
我们团队花了2个月时间,基于Harness软件交付平台重构了整个教育Agent的持久化层,上线3个月以来,进度同步成功率达到99.998%,没有出现过一次进度丢失、冲突的问题,开发成本比自研降低了70%,运维成本降低了90%,还一次性通过了等保2.0三级认证。
这套方案的核心优势:
- 开箱即用的基础设施:不需要自己从零实现缓存、多存储适配、灰度发布、合规校验等能力,Harness已经全部封装好了;
- 冲突-free的多端同步:内置CRDT算法,支持无锁的多端进度合并,不会丢失任何学习行为数据;
- 版本兼容保证:基于Harness Schema注册中心,知识点图谱迭代时自动兼容存量进度数据,不需要手动写迁移脚本;
- 合规强制生效:基于Harness Policy as Code,所有数据操作都符合《个人信息保护法》《教育数据安全规范》的要求,不需要担心合规风险;
- 弹性扩缩容:用户量从10万涨到100万不需要改一行代码,Harness自动调整存储资源配额。
最终效果展示
我们的K12数学教育Agent上线这套方案之后的数据表现:
- 多端进度同步延迟<1s;
- 进度数据准确率100%,没有出现过一次冲突或丢失;
- 知识点迭代上线时间从3天缩短到2小时,不需要做数据迁移;
- 合规审计100%通过,不需要额外投入合规研发资源。
准备工作
环境/工具要求
| 工具/环境 | 版本要求 | 用途说明 |
|---|---|---|
| Harness Platform | SaaS版 / 本地部署版≥v0.25 | 提供持久化抽象、策略管理、版本管理、灰度发布能力 |
| Python | ≥3.10 | 教育Agent业务逻辑开发 |
| LangChain | ≥0.1.0 | Agent编排框架,配套回调实现自动持久化 |
| PostgreSQL | ≥14 | 结构化学习进度数据存储 |
| Redis | ≥7.0 | 热学习进度缓存,降低延迟 |
| Pinecone / Milvus | ≥2.0 | 用户交互历史向量存储,支持学习行为溯源 |
| 阿里云OSS / 腾讯云COS | 不限 | 冷数据归档、用户作业等大文件存储 |
前置知识要求
阅读本文需要你具备以下基础知识:
- 教育Agent的基本架构,了解LangChain的基本使用;
- 基本的数据库操作知识,了解关系型数据库、缓存、向量数据库的适用场景;
- 基本的分布式系统概念,了解最终一致性、冲突解决的基本原理;
- 对Harness平台有基本了解,不需要精通,跟着本文步骤操作即可。
相关学习资源:
- Harness官方入门文档
- LangChain官方教程
- CRDT入门论文《Conflict-free Replicated Data Types》
核心概念与问题背景
核心概念定义
1. 教育Agent
教育Agent是基于大语言模型构建的、能够为用户提供个性化学习服务的智能体,核心能力包括知识点讲解、错题分析、自适应刷题、测评诊断、学习路径规划等,核心特点是和用户的交互是会话式的、连续的,需要基于用户的历史学习状态提供个性化服务。
2. 学习进度的核心要素
教育场景的学习进度不是一个简单的「学到第几章」的字段,而是包含多维度数据的结构化对象,核心要素如下:
| 要素 | 类型 | 说明 |
|---|---|---|
| 主体标识 | 字符串 | 用户唯一ID、会话ID、客户端标识 |
| 知识点关联 | 字符串 | 对应的知识点ID、知识点版本、所属学科和年级 |
| 掌握状态 | 浮点数 | 知识点掌握度(0-1)、累计学习时长、做题数、正确率 |
| 历史链路 | 结构化对象 | 交互历史、错题记录、测评得分、停留时长 |
| 版本信息 | 整数 | 数据模型版本、知识点图谱版本 |
3. Harness平台核心组件
本文用到的Harness核心组件如下:
- Harness Persistence Layer:统一的持久化抽象层,支持对接各类存储源,屏蔽底层存储的复杂度;
- Harness Schema Registry:数据模型注册中心,自动校验Schema变更的兼容性,避免Breaking Change;
- Harness Policy as Code:策略即代码引擎,可自定义合规规则,所有数据操作都要经过规则校验才能执行;
- Harness Feature Flags:特性开关,支持灰度发布新的持久化逻辑,出问题可一键回滚;
- Harness Event Bus:事件总线,支持进度更新的实时推送,实现多端同步。
4. 教育场景持久化的核心要求
和普通的业务数据持久化不同,教育场景的持久化有以下刚性要求:
- 不可丢失性:任何学习行为数据都不能丢失,否则会影响用户的学习体验和信任;
- 多端一致性:三端(Web/APP/小程序)的进度必须保持一致,同步延迟<1s;
- 可溯源性:支持查询用户任意时间段的学习历史,用于学习分析和错题溯源;
- 版本兼容性:知识点图谱迭代时,存量进度数据必须自动兼容,不能失效;
- 合规性:符合《个人信息保护法》《教育数据安全规范》的要求,数据必须存在境内,用户有权删除所有个人数据;
- 高可用性:持久化服务的可用性必须≥99.99%,不能因为存储故障影响Agent服务。
行业发展历史与现存痛点
我们整理了近15年教育产品持久化技术的演变历史,如下表所示:
| 时间 | 教育产品形态 | 持久化技术栈 | 核心痛点 | 主流解决方案 |
|---|---|---|---|---|
| 2010年及以前 | 单机教育软件、光盘课程 | 本地文件、Access数据库 | 换设备进度丢失,数据容易损坏 | 手动导出导入进度文件 |
| 2015-2019年 | 在线教育平台、直播课 | MySQL、云服务器存储 | 同步延迟高,扩展困难,运维成本高 | 读写分离、分库分表 |
| 2020-2022年 | AI助教、自适应学习系统 | MySQL+Redis+MongoDB | 多端冲突,合规性差,迭代兼容性差 | 分布式事务、最后写入获胜策略 |
| 2023年至今 | 生成式教育Agent | 自研持久化层+多模存储 | 学习行为数据溯源难,跨场景进度复用难 | 手动实现冲突解决、版本管理 |
| 2025年(预测) | 全域教育Agent网络 | 联邦学习+分布式身份+跨链存储 | 数据孤岛,用户对数据没有控制权 | 学习进度跨平台互通、用户自主掌控数据 |
当前教育Agent持久化的普遍痛点:
- 临时存储导致数据丢失:很多团队为了快速上线,用内存或本地文件存会话状态,服务重启、设备切换就会丢失进度;
- 冲突解决策略不合理:大多采用「最后写入获胜(LWW)」的策略,会丢失更早的学习行为数据,比如用户在两个端同时学习,只会保留最后一个端的进度;
- 版本兼容能力缺失:知识点图谱迭代时,存量进度数据不兼容,需要手动写迁移脚本,容易出问题;
- 合规能力不足:教育数据属于敏感信息,很多团队没有完善的合规机制,容易违反监管要求;
- 运维成本高:需要自己维护多套存储、缓存、同步服务,用户量上涨时还要手动扩缩容,运维成本极高。
整体架构设计
系统架构总览
我们的整体架构分为4层,如下图所示:
渲染错误:Mermaid 渲染失败: Parsing failed: Lexer error on line 2, column 15: unexpected character: ->(<- at offset: 32, skipped 11 characters. Lexer error on line 3, column 20: unexpected character: ->(<- at offset: 63, skipped 1 characters. Lexer error on line 3, column 24: unexpected character: ->端<- at offset: 67, skipped 2 characters. Lexer error on line 4, column 20: unexpected character: ->(<- at offset: 97, skipped 1 characters. Lexer error on line 4, column 24: unexpected character: ->端<- at offset: 101, skipped 2 characters. Lexer error on line 5, column 24: unexpected character: ->(<- at offset: 135, skipped 6 characters. Lexer error on line 7, column 16: unexpected character: ->(<- at offset: 170, skipped 3 characters. Lexer error on line 7, column 24: unexpected character: ->层<- at offset: 178, skipped 3 characters. Lexer error on line 7, column 29: unexpected character: ->教<- at offset: 183, skipped 2 characters. Lexer error on line 7, column 36: unexpected character: ->]<- at offset: 190, skipped 1 characters. Lexer error on line 8, column 24: unexpected character: ->(<- at offset: 215, skipped 1 characters. Lexer error on line 8, column 28: unexpected character: ->网<- at offset: 219, skipped 3 characters. Lexer error on line 9, column 30: unexpected character: ->(<- at offset: 261, skipped 1 characters. Lexer error on line 9, column 40: unexpected character: ->编<- at offset: 271, skipped 3 characters. Lexer error on line 10, column 20: unexpected character: ->(<- at offset: 303, skipped 7 characters. Lexer error on line 11, column 25: unexpected character: ->(<- at offset: 344, skipped 9 characters. Lexer error on line 13, column 18: unexpected character: ->(<- at offset: 385, skipped 1 characters. Lexer error on line 13, column 26: unexpected character: ->中<- at offset: 393, skipped 5 characters. Lexer error on line 13, column 38: unexpected character: ->平<- at offset: 405, skipped 4 characters. Lexer error on line 14, column 24: unexpected character: ->(<- at offset: 433, skipped 8 characters. Lexer error on line 15, column 23: unexpected character: ->(<- at offset: 475, skipped 1 characters. Lexer error on line 15, column 30: unexpected character: ->注<- at offset: 482, skipped 5 characters. Lexer error on line 16, column 23: unexpected character: ->(<- at offset: 521, skipped 9 characters. Lexer error on line 17, column 19: unexpected character: ->(<- at offset: 560, skipped 1 characters. Lexer error on line 17, column 32: unexpected character: ->)<- at offset: 573, skipped 1 characters. Lexer error on line 18, column 25: unexpected character: ->(<- at offset: 610, skipped 6 characters. Lexer error on line 19, column 19: unexpected character: ->(<- at offset: 646, skipped 6 characters. Lexer error on line 21, column 18: unexpected character: ->(<- at offset: 686, skipped 13 characters. Lexer error on line 22, column 22: unexpected character: ->(<- at offset: 721, skipped 1 characters. Lexer error on line 22, column 29: unexpected character: ->热<- at offset: 728, skipped 6 characters. Lexer error on line 23, column 19: unexpected character: ->(<- at offset: 764, skipped 1 characters. Lexer error on line 23, column 31: unexpected character: ->结<- at offset: 776, skipped 6 characters. Lexer error on line 24, column 25: unexpected character: ->(<- at offset: 818, skipped 1 characters. Lexer error on line 24, column 35: unexpected character: ->向<- at offset: 828, skipped 5 characters. Lexer error on line 25, column 20: unexpected character: ->(<- at offset: 864, skipped 1 characters. Lexer error on line 25, column 25: unexpected character: ->冷<- at offset: 869, skipped 6 characters. Parse error on line 3, column 21: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: 'Web' Parse error on line 3, column 27: Expecting token of type ':' but found `in`. Parse error on line 4, column 21: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: 'APP' Parse error on line 4, column 27: Expecting token of type ':' but found `in`. Parse error on line 7, column 19: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: 'Agent' Parse error on line 7, column 27: Expecting token of type ':' but found `AI`. Parse error on line 7, column 31: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: 'Agent' Parse error on line 7, column 37: Expecting token of type ':' but found ` `. Parse error on line 8, column 25: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: 'API' Parse error on line 8, column 32: Expecting token of type ':' but found `in`. Parse error on line 9, column 31: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: 'L' Parse error on line 9, column 44: Expecting token of type ':' but found `in`. Parse error on line 13, column 19: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: 'Harness' Parse error on line 13, column 31: Expecting token of type ':' but found `Harness`. Parse error on line 15, column 24: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: 'Schema' Parse error on line 15, column 36: Expecting token of type ':' but found `in`. Parse error on line 17, column 20: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: 'Feature' Parse error on line 17, column 28: Expecting token of type ':' but found `Flag`. Parse error on line 17, column 34: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: 'in' Parse error on line 17, column 44: Expecting token of type ':' but found ` `. Parse error on line 22, column 23: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: 'R' Parse error on line 22, column 36: Expecting token of type ':' but found `in`. Parse error on line 23, column 20: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: 'PostgreSQL' Parse error on line 23, column 38: Expecting token of type ':' but found `in`. Parse error on line 24, column 26: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: 'Pinecone' Parse error on line 24, column 41: Expecting token of type ':' but found `in`. Parse error on line 25, column 21: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: 'OSS' Parse error on line 25, column 32: Expecting token of type ':' but found `in`. Parse error on line 27, column 9: Expecting token of type 'ARROW_DIRECTION' but found `80`. Parse error on line 27, column 12: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: '--' Parse error on line 27, column 23: Expecting token of type ':' but found ` `. Parse error on line 28, column 9: Expecting token of type 'ARROW_DIRECTION' but found `80`. Parse error on line 28, column 12: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: '--' Parse error on line 28, column 23: Expecting token of type ':' but found ` `. Parse error on line 29, column 13: Expecting token of type 'ARROW_DIRECTION' but found `80`. Parse error on line 29, column 16: Expecting: one of these possible Token sequences: 1. [NEWLINE] 2. [EOF] but found: '--' Parse error on line 29, column 27: Expecting token of type ':' but found ` `. Parse error on line 30, column 13: Expecting token of type ':' but found `--`. Parse error on line 30, column 17: Expecting token of type 'ARROW_DIRECTION' but found `orchestration`. Parse error on line 31, column 19: Expecting token of type ':' but found `--`. Parse error on line 31, column 23: Expecting token of type 'ARROW_DIRECTION' but found `llm`. Parse error on line 32, column 19: Expecting token of type ':' but found `--`. Parse error on line 32, column 23: Expecting token of type 'ARROW_DIRECTION' but found `callback`. Parse error on line 33, column 14: Expecting token of type ':' but found `--`. Parse error on line 33, column 18: Expecting token of type 'ARROW_DIRECTION' but found `adapter`. Parse error on line 34, column 13: Expecting token of type ':' but found `--`. Parse error on line 34, column 17: Expecting token of type 'ARROW_DIRECTION' but found `schema`. Parse error on line 35, column 13: Expecting token of type ':' but found `--`. Parse error on line 35, column 17: Expecting token of type 'ARROW_DIRECTION' but found `policy`. Parse error on line 36, column 13: Expecting token of type ':' but found `--`. Parse error on line 36, column 17: Expecting token of type 'ARROW_DIRECTION' but found `ff`. Parse error on line 37, column 13: Expecting token of type ':' but found `--`. Parse error on line 37, column 17: Expecting token of type 'ARROW_DIRECTION' but found `redis`. Parse error on line 38, column 13: Expecting token of type ':' but found `--`. Parse error on line 38, column 17: Expecting token of type 'ARROW_DIRECTION' but found `pg`. Parse error on line 39, column 13: Expecting token of type ':' but found `--`. Parse error on line 39, column 17: Expecting token of type 'ARROW_DIRECTION' but found `pinecone`. Parse error on line 40, column 13: Expecting token of type ':' but found `--`. Parse error on line 40, column 17: Expecting token of type 'ARROW_DIRECTION' but found `oss`. Parse error on line 41, column 14: Expecting token of type ':' but found `--`. Parse error on line 41, column 18: Expecting token of type 'ARROW_DIRECTION' but found `web`. Parse error on line 42, column 14: Expecting token of type ':' but found `--`. Parse error on line 42, column 18: Expecting token of type 'ARROW_DIRECTION' but found `app`. Parse error on line 43, column 14: Expecting token of type ':' but found `--`. Parse error on line 43, column 18: Expecting token of type 'ARROW_DIRECTION' but found `miniapp`. Parse error on line 44, column 8: Expecting token of type ':' but found `--`. Parse error on line 44, column 12: Expecting token of type 'ARROW_DIRECTION' but found `adapter`.
各层的职责:
- 用户端层:提供多端入口,支持进度的实时展示和同步;
- 教育Agent层:负责业务逻辑编排、大模型推理,通过回调触发进度持久化;
- Harness中间层:核心层,负责存储适配、合规校验、Schema管理、灰度发布、实时同步;
- 存储层:多模存储,适配不同类型数据的存储需求。
核心数据模型ER图
学习进度的核心数据模型如下:
