# 从拟合到训练 · 路线图

<p align="center">
  <a href="./TRAINING.md"><img alt="中文" src="https://img.shields.io/badge/%E4%B8%AD%E6%96%87-%E5%BD%93%E5%89%8D-blue?style=for-the-badge"></a>
  <a href="./TRAINING_EN.md"><img alt="English" src="https://img.shields.io/badge/English-switch-lightgrey?style=for-the-badge"></a>
</p>

<p align="center"><a href="../README.md">← 返回 README</a> · <a href="../USER-GUIDE.md">用户手册</a></p>

---

> **这份文档回答一个问题**：将来端侧模型可以训练了，怎么用它把「拟合」变成「真的懂你」？

## 0. 先说清楚：现在的拟合是权宜之计

三种「让模型贴近某个用户」的手段，成本结构完全不同：

| | 进得去权重吗 | 每轮成本 | 生效范围 | 现在能做吗 |
|---|---|---|---|---|
| **A. 微调 / LoRA** | 进得去 | **零**（已内化） | 该模型的所有会话 | 做不到：统一 API |
| **B. 上下文注入** | 进不去 | **每轮都付** token 租金 | 当前会话 | 现在唯一的办法 |
| **C. 外置状态 + 检索** | 进不去 | 按需付 | 可跨会话 | 现在可做 |

本插件现在的定位是 **B + C**。B 有三个结构性缺陷：

1. **租金随轮数线性增长** —— 100 轮就付 100 次
2. **和用户真正的内容抢上下文位置**
3. **最重要**：同一条提示词注入 50 轮之后，**模型对它的注意力是衰减的**；而权重里的东西不会衰减

所以真正的问题不是「怎么注入得更多」，而是**「怎么注入得始终有分量」**。

**A 才是终点。** 而 A 需要一样东西：**数据**。这正是本插件从第一天就在采集的。

---

## 1. 今天已经在采集什么

每次拟合结束，fit/feedback 帧记录一个四元组：

~~~jsonc
{
  "type": "fit/feedback",
  "context":   "当时的情况（触发语 + 工作区 + 轮次）",
  "modelDid":  "模型这一轮做了什么（提了哪些问题 / 给出了什么方向）",
  "userSaid":  "用户的回答或纠正",
  "verdict":   "accepted | corrected | rejected",
  "preference":"从中能提炼出的偏好规则"
}
~~~

**这就是一份现成的偏好训练集（preference pairs）。** 它天然是「同一个 context 下，模型做了 X，用户接受了/纠正成了 Y」的形式——正是 DPO / ORPO 这类偏好优化最想要的形状。

### 为什么现在就要按这个形状采

因为**将来不用重新采**。等端侧模型能训练时，你手里已经有一年的数据了；重新采意味着再从零攒起。

**权宜之计和最终方案不是两件事，是同一件事的两个阶段。**

---

## 2. 数据够了吗：够与不够的分界

| 目标 | 大致需要 | 说明 |
|---|---|---|
| **风格画像**（先结论后理由类） | ~100 条 | 很快能到。这层适合上下文注入或轻量 system prompt |
| **偏好对齐**（该顺着还是该顶着） | 1k–10k 条 | 需要真实的"纠正"事件，不是点赞 |
| **领域直觉**（像本领域的人那样权衡） | 10k+ 条，且要**难负例** | 这层才真正需要训练 |

**关键不是条数，是"纠正率"。** 如果 90% 的拟合都以「用户直接接受」结束，那这些样本几乎不含信息——模型本来就猜对了。

**含金量最高的是 verdict = corrected 的样本**：模型猜错了，用户给出了正确答案。这是偏好对的天然来源。

> **设计含义**：本插件应当在提案被拒绝时**明确记录"错在哪"**（用户是选了另一个方向，还是说"都不对"）。这两种信号强度不同，值得分开存。

---

## 3. 三个阶段的路线

### 阶段 1 · 现在（数据采集期）

**目标**：把数据采干净、采成训练就绪的形状。

- 已有：fit/feedback 四元组在采集
- **待补**：提案被拒时记录"错在哪"（字段 rejectedReason）
- **待补**：给样本加**质量分层**（用户是深思熟虑还是随手一点）
- **待补**：导出脚本（JSONL → 训练框架能吃的格式）

### 阶段 2 · 端侧可行时（画像注入期）

**目标**：让画像**跨会话**生效，且**只在该用的时候**注入。

技术落点：ctx.on(system-prompt/assemble)（可每轮参与提示词组装）。

**核心设计：注入"风格与已知盲区"，不注入"结论"。**

~~~
✅ 该注入的（影响模型怎么做事）：
   · 此用户偏好先给结论
   · 此用户在该项目的三次决策里都选了保守方案
   · 此用户在配置类问题上反复低估迁移成本 —— 相关判断请先核实再给估计

❌ 不该注入的（会变成回声室）：
   · 此用户认为该库不需要配置     ← 事实性陈述，即使他说过也不能当偏好存
   · 此用户上次的结论是 X         ← 上次的结论不等于这次成立
~~~

**判据一句话：能被证据推翻的，不进画像。**（"我讨厌长表格"推翻不了 → 进；"这个库不需要配置"一查就知道 → 不进）

### 阶段 3 · 端侧训练可行时（权重内化期）

**目标**：把画像从"每轮付租金"变成"一次性买断"。

**技术路线（由轻到重）**：

| 手段 | 需要的数据 | 适合什么 | 风险 |
|---|---|---|---|
| **LoRA / QLoRA** | 1k–10k 偏好对 | 风格、偏好、领域语气 | 低。可插拔，坏了能卸 |
| **DPO / ORPO** | 偏好对（本插件采的就是） | "该顺着还是该顶着" | 中。需要难负例 |
| **全量微调** | 10k+ 且高质量 | 领域直觉 | 高。会遗忘通用能力 |
| **持续学习** | 长期数据流 | 越用越准 | 最高。需要防灾难性遗忘 |

**建议从 LoRA 起步**：便宜、可回滚、不动基座。

---

## 4. 一个必须提前想清楚的问题：边界

训练会让模型**更像你**。但「像你」不等于「对你好」。

本插件在设计上已经埋了一条分界线：

| 层 | 内容 | 谁是权威 | 该不该拟合 |
|---|---|---|---|
| **意图层** | 你**想要什么**（目标、偏好、口味、边界） | **你** | ✅ **完全拟合** |
| **事实层** | 这事**该怎么办**（事实、约束、可行性） | **证据 / 专业标准** | ❌ **绝不拟合** |

**训练时必须保住这条线。** 如果训练数据里混进了"用户的事实性错误被当成偏好"，模型就会学会**顺着用户的错误说**——那不是"懂你"，那是谄媚。

**技术上怎么保**：

- 样本带 scope 字段，训练时**只取 scope = intent**
- scope = fact 的样本单独走另一条路（训练"如何纠正"而不是"纠正成什么"）
- 定期做**反向评估**：给模型一个用户明显说错的场景，看它是否还敢纠正

**这条过滤是整个训练路线能否成立的分水岭。**

---

## 5. 现在就能做的三件事

如果你认同上面的路线，**不用等端侧模型**，今天就能推进：

1. **把 fit/feedback 的字段补全** —— 尤其是 rejectedReason 与质量分层
2. **写导出脚本** —— JSONL → 偏好对格式（prompt / chosen / rejected）
3. **做一次小规模验证** —— 攒够 100 条后，先训一个最小的 LoRA，看风格像不像，**先验证数据有没有用**

第 3 条最重要：**它会告诉你采的数据到底有没有信息量。** 如果 100 条训出来的东西毫无变化，说明样本几乎都是"模型本来就猜对了"，需要调整采集策略（比如主动制造更多分歧）。

---

## 6. 参考文献

- 偏好优化：DPO（Rafailov et al., 2023）、ORPO（Hong et al., 2024）
- 参数高效微调：LoRA（Hu et al., 2021）、QLoRA（Dettmers et al., 2023）
- 灾难性遗忘与持续学习：见各 LLM continual-learning 综述

> 本路线图是该项目的**设计意图**，不是已实现功能。当前版本只做数据采集。

