企业内部AI系统的PDCA
这个场景其实是把「模型 + Agent + 知识库」当成一套可观测、可反馈、可持续进化的闭环系统来做 PDCA,而不是简单的"攒语料—微调"。核心判断原则先说清楚:
知识本身尽量不进模型参数,微调只做"行为对齐",不做"知识记忆"。 这是最容易踩坑的地方——把大量业务知识硬塞进微调数据,短期内看起来"模型懂了",但会带来幻觉率上升、知识过期后无法及时纠正、维护成本指数级增长的问题。凡是"会变"的知识(业务规则、API 版本、术语表)应该走 Skills/文档/知识图谱;只有"高频出现、难以用规则显式描述、具有稳定隐性模式"的东西(代码风格偏好、review 习惯、语气规范)才值得微调。
整体架构如下:

一、PDCA 怎么套在这个系统上
| 阶段 | 对应动作 |
|---|---|
| Plan | 从日志(accept/reject、diff、对话)里挖掘问题域,圈定本轮要改进的目标:某类代码规范违规率高、某业务知识点频繁被追问、图谱里某类实体关联缺失 |
| Do | 三选一或组合执行改进:更新 Skills/文档、补全知识图谱、构造微调数据训练 LoRA |
| Check | 离线 regression eval + 灰度发布,看 accept rate、reject 原因分布是否改善 |
| Act | 达标则固化并全量推广,不达标则回滚,问题记录进下一轮 Plan |
这套下来关键不是"有没有 PDCA",而是每一轮改进要走哪条产出路径——这是整个方案里最容易出问题的决策点,展开说一下。
二、决策准则:Skills/文档 vs 知识图谱 vs 微调
用几条可执行的判断标准,而不是拍脑袋:
- 变化频率/半衰期:这周决定这月就可能改的东西(API 版本、当前 sprint 的业务规则)→ Skills/文档。微调数据从采集到训练到上线有延迟,追不上高频变化,还会把过时知识焊死在参数里。
- 可解释性/可审计要求:涉及合规审查、需要能对着某条规则说"这是谁写的、什么时候改的"→ 必须是文档形态,微调后的行为不可追溯到具体条款。
- 是否可显式描述为规则:能写成"遇到 X 场景,应该 Y"的条件语句 → Skills;只能靠大量示例隐式表达的"感觉"(代码风格的微妙偏好、某种 review 语气)→ 微调更合适,写成规则反而啰嗦且覆盖不全。
- 重复量级:某类 reject 原因在日志里反复出现(比如 500+ 样本里都是同一种隐性风格问题,且规则描述不清)→ 进入微调候选池;偶发的一次性问题 → 记一条 Skill 就够了。
- 上下文成本:如果某个知识点几乎每次对话都要塞进 context,占 token 又拖慢推理 → 考虑"蒸馏"进参数(微调),而不是永远挂在 prompt 里。
- 知识 vs 关联推理:单点事实 → RAG 检索;多实体间的关系、"这个模块依赖那个模块、这个业务和那个团队相关"这类结构性知识 → 图谱,图谱的价值在于关联推理,向量检索做不到。
一句话原则:Skills/文档解决"知道什么",知识图谱解决"怎么关联",微调只解决"怎么做(行为/风格)"。
三、微调 pipeline 的几个关键点
- 数据来源:从 accept/reject 日志构造 (prompt, chosen, rejected) 偏好对,做 DPO;或者用人工最终采纳的代码版本做 SFT target。你已经在做的 accept 情况收集正好是这个数据源。
- LoRA 为主,不做全量微调:每个业务域一个 adapter(这就是你说的"多头"的具体落地——每个 adapter 是一个可插拔的"头"),成本低、灾难性遗忘风险小,坏了直接卸载回滚。
- 持续预训练慎用:只有当某个领域的稳定知识量已经大到 RAG+图谱撑不住语义密度时才考虑,绝大多数场景不需要。
- 训练节奏:不要追热点式地天天微调,建议双周或月度一批,凑够质量样本再训练,每批必须过离线 eval 集才能进灰度。
四、MoE 化的路由怎么做
不是真的从头训练 MoE 大模型,而是在推理时做 adapter 路由:一个轻量分类器(甚至可以是规则+小 LLM 判断)识别当前任务属于哪个业务域,动态挂载对应的 LoRA adapter 组合。业务线越多,"头"越多,路由层决定当前请求该激活哪几个头——这跟 attention 里 query 决定关注哪些 key 是同一个逻辑,只是这里的"头"是可插拔的领域专家而不是固定权重。
五、Skills/文档 与 知识图谱 的部署回路
- 复用你已有的 Router+Leaf 结构(confluence2skills 那套思路),Git 作为唯一事实源,PR 走人审
- 可以做一个"日志→建议 PR"的机器人:检测到某规范被反复违反,自动生成一条 Skill 草稿丢进 PR 队列,人工确认后合并
- 知识图谱走"LLM 辅助抽取 + 人工审核队列 + 定期去重合并",作为 RAG 之外的一层结构化补充
- Agent Runtime 每次任务启动时拉取最新 Skills index,做到"改完当天/当周生效",比模型迭代快得多
六、周期节奏建议
- 每日:日志采集、异常监控、accept rate 看板
- 每周:Skills/文档增量更新(低风险高频)、知识图谱增量合并
- 双周/每月:LoRA 微调批次训练 → 离线 eval → 灰度发布
- 每季度:全量回归评估、adapter 路由结构调整、是否升级 base model 的评审
七、治理与风险控制
- 离线 eval set 防 regression,每次改动(无论 Skills、图谱还是微调)都要跑一遍
- Human-in-the-loop:微调数据和 Skills 草稿都要过人审,不能全自动合并
- 灰度/金丝雀发布 + 可回滚的版本注册中心(模型 adapter 和 Skills 都要有版本号,能一键回退)
- 闭源部署下数据不出内网,这个前提你已经在做
统一部署和灰度发布的具体机制是什么?
部署和灰度发布这块是整个闭环里风险最集中的地方——Skills、知识图谱、LoRA adapter 三条产出路径最终都要经过同一套发布机制,不能各玩各的,否则出问题时都不知道是哪个变量导致的。具体机制画个图:

逐段展开每个环节的具体做法:
1. 版本注册中心(统一 Registry)
三类产出物必须纳入同一套版本体系,哪怕它们的物理形态完全不同:
| 产出物 | 版本化对象 | 存储形态 |
|---|---|---|
| Skills/文档 | Git commit hash / tag | Git repo,Router+Leaf 结构不变,只是每次发布打 tag |
| 知识图谱 | 图谱快照版本号 | 图数据库定期 snapshot,或增量 changelog |
| LoRA adapter | 权重文件 + 训练元数据 | 对象存储(S3/内部存储)+ 元数据表(base model 版本、训练数据批次、eval 分数) |
关键是三者都要能回答同一个问题:"当前 Agent Runtime 正在用的是哪个组合版本?" 建议做一张"版本清单表",记录 (Skills版本, 图谱版本, adapter版本) 的组合快照,每次发布是对这个组合打一个新标签,而不是三者各自独立发布——否则出问题时无法定位是哪个变量导致的回归。
2. 灰度选择器:分流维度怎么选
不要用"随机抽 5% 流量"这种粗放方式,按你们的场景更合适的分流维度:
- 按业务域/Tenant:新的领域 adapter 先只在对应业务线的任务上生效,不影响其他域
- 按 Agent 类型:如果是某个 Skill 只影响特定 agent(比如代码规范类),只对涉及代码生成的 agent 灰度
- 按任务风险等级:低风险任务(内部工具、非生产代码)先放开,高风险任务(涉及生产发布的 agent)后灰度
这样出问题时影响面天然可控,不需要等指标恶化才发现。
3. 双轨路由运行:怎么做到"新旧并行不干扰"
- 旧版本(当前基线)和新版本(候选)同时在线,路由层根据灰度选择器的结果把请求分到对应版本,而不是先下线旧版本再上线新版本
- Skills/文档层面:Agent Runtime 拉取配置时带上"实验组"标记,去对应版本的 index
- adapter 层面:推理服务同时加载新旧两个 adapter,路由层决定用哪个(这也是为什么坚持用 LoRA 而不是全参数微调——两个版本同时常驻的显存成本低很多)
- 知识图谱:如果改动是增量式的,通常可以直接热更新;如果是结构性变更(大规模合并去重),才需要走双轨对比
4. 指标采集对比:具体看什么
分两层:
自动化门禁指标(触发阈值即可自动拦截,不需要等人工)
- accept rate 环比是否下降超过阈值(比如超过 3-5 个百分点)
- reject 原因分布是否出现新的高频类别
- 延迟 P95 是否显著劣化(尤其是加载了新 adapter 后的推理耗时)
需要人工判断的信号
- accept rate 没降但 reject 的"性质"变了(比如从"格式问题"变成"逻辑错误",这种即使总量没恶化也要人工介入)
- 用户在对话里的显式负反馈(吐槽、纠正)
5. 决策环节:自动 + 人工怎么分工
- 自动门禁:硬指标不达标直接自动回滚,不等人。这一步的意义是把"响应时间"从人工审核的小时级压缩到分钟级
- 人工复核:自动门禁通过后,进入观察期(比如 24-48 小时),由负责人抽查典型 case,尤其是那些"指标好看但直觉上不对"的场景——这一步是防止过拟合到评估集本身
- 只有两层都过了才能进入全量发布
6. 全量发布 / 自动回滚
- 全量发布:把这次的版本组合设为新基线,写回 Registry,旧版本进入"保留期"(不是立刻删除,留一个可以快速回退的窗口,通常一到两周)
- 自动回滚:一旦触发,立刻把流量切回上一个已知稳定的基线版本组合,同时把这次失败的改动(不管是哪条路径产生的)打上"已知问题"标签,反馈进下一轮 Plan 阶段去分析失败原因,而不是简单丢弃
这套机制的核心价值在于:Skills、图谱、微调三条路径共用同一套"灰度—对比—门禁—回滚"的骨架,团队不需要为每条路径单独造一套发布流程,也不会出现"Skills 更新了但没人知道对应哪个 adapter 版本"这种版本错配问题。
LoRA微调数据集怎么从日志里构造?
构造微调数据集是整条链路里质量把关最重要的环节——喂进去的数据质量直接决定 adapter 出来是"真的学到了行为偏好"还是"学到了噪声"。流程图先给个骨架:

1. 原始日志需要埋哪些字段
每条 accept/reject 事件至少要能还原出这些信息,否则后面没法构造有效样本:
json
{
"task_id": "task_2026xxxx",
"agent_id": "agent_codegen_01",
"skill_version": "skills@v42",
"context": {
"instruction": "用户原始指令/需求描述",
"file_path": "src/service/xxx.py",
"code_before": "改动前代码片段",
"retrieved_skills": ["skill_id_1", "skill_id_2"],
"retrieved_kg_entities": ["entity_id_1"]
},
"model_output": "模型生成的代码/回复",
"human_action": "accept | reject | edit_then_accept",
"final_version": "用户最终采纳的版本(如果是edit_then_accept)",
"reject_reason": "可选,人工标注的拒绝原因分类",
"timestamp": "..."
}
关键点:edit_then_accept 这个状态非常重要,很多团队只记 accept/reject 两态,丢了"模型生成的和用户最终用的之间差了什么"这个信息——而这恰恰是质量最高的训练信号。
2. 清洗与脱敏:先于一切
- 密钥/凭证/内部域名/员工信息:用规则+正则先过一遍(API key 格式、内网 IP、邮箱),有条件的话再过一次 LLM 做二次检测,因为正则漏检率不低
- 去除无意义样本:纯粹"没改动就 accept"的(比如模型只是复述了已有代码)、以及"reject 但没有后续修改"的悬空样本(不知道用户到底想要什么,无法构造 target)
- 去除过短/过长样本:单行改动信息量太低,超长 diff 又会稀释训练信号,建议按 token 长度设一个合理区间过滤
3. SFT 数据怎么构造
用 edit_then_accept 和纯 accept 的日志:
json
{
"messages": [
{"role": "system", "content": "对应当时生效的skill/图谱context"},
{"role": "user", "content": "instruction + retrieved context"},
{"role": "assistant", "content": "final_version(用户最终采纳的版本,不是模型原始输出)"}
]
}
注意:target 一定是"用户最终采纳的版本",不是"模型原始生成的版本"——如果模型输出被用户改过才 accept,说明模型原始输出是有偏差的,拿它当 target 等于把偏差也学进去了。这一点很容易被忽略。
4. DPO 数据怎么构造(更适合你的场景)
因为你已经天然有 accept/reject 的对比信号,DPO 比纯 SFT 更贴合数据形态:
json
{
"prompt": "同一个instruction + context",
"chosen": "被accept的版本,或edit_then_accept的最终版本",
"rejected": "被reject的模型原始输出"
}
构造 chosen/rejected pair 时,prompt 必须完全一致——同一个 instruction、同一个 context,只有输出不同。如果两次请求的 context 不同(比如检索到的 skill 版本不一样),这个 pair 就不成立,训练出来的偏好信号是错的。这是最常见的踩坑点。
对于同一个 reject,如果同一个 task 后来被人工修正过,可以构造多对:(原始输出, 修正版本) 和 (修正前的中间版本, 最终版本),能提高样本利用率。
5. 质量打分与去重
- LLM-judge 打分:用一个独立模型(不是要被微调的那个)对每条样本打分,过滤掉"reject 原因其实是需求理解错误而非代码质量问题"这类不该进训练集的样本——这类应该反馈给 Skills/图谱去修需求理解,而不是喂给微调
- 语义去重:同一类 reject 原因可能反复出现几百次几乎一样的 pattern,全部塞进去会导致过拟合到高频 pattern、稀释稀有但重要的信号。用 embedding 相似度做聚类,每个 cluster 保留一定配额(比如每类最多保留 N 条代表性样本)
6. 配比与切分
- 按业务域配比:不能让样本量大的业务线(比如某个高频使用的 agent)淹没其他业务域,按域设定采样上限,防止 adapter 训出来只对一个业务线有效
- train/eval 按时间切分,不要随机切分:eval 集用比 train 更晚时间段的数据,模拟"用这批数据训出来的模型,能不能应对之后出现的新场景",随机切分会让 eval 分数虚高(train 和 eval 里可能混进了同一个 task 的不同版本,造成信息泄漏)
- 独立维护的 golden eval set:这个集合不进入任何一轮训练数据池,专门用来做跨版本对比,否则每次都用"当期最新日志切一部分当 eval",评估基准会随着数据分布一起漂移,看不出真实的进步或退步
7. 什么时候算"攒够了可以训一批"
不是按时间硬性触发,按有效样本量和分布触发更合理:单个业务域的高质量 pair 数达到几百到上千量级(LoRA 对数据量要求不算高,几百条高质量 pair 往往比几千条噪声数据效果好),且业务域配比不严重失衡,再启动一轮训练。凑不够宁可推迟到下一个周期,也不要为了赶节奏塞低质量样本进去。
更多推荐



所有评论(0)