> For AI agents: the complete documentation index is available at https://open-spaced-repetition.github.io/ts-fsrs/zh-CN/llms.txt, the full documentation bundle is available at https://open-spaced-repetition.github.io/ts-fsrs/zh-CN/llms-full.txt.

# 训练与评估

训练通过几次 binding 调用把复习历史跑完。输入是一份复习日志 CSV；输出是可直接交给 `DefaultScheduler` 或自定义 `defineScheduler` 的权重数组。

示例导入 `@open-spaced-repetition/binding`。在 Node 中是原生 napi 模块；在浏览器中解析为 WASI Preview 1 的 wasm 构建（多线程说明见[训练器概览](https://open-spaced-repetition.github.io/ts-fsrs/zh-CN/guide/optimizer/index.md)）。

## 把复习日志转成项

`convertCsvToFsrsItems` 读取 CSV 文本，并按卡片把各行归并为 `FSRSItem`。列如下：

| 列                 | 含义                   |
| ----------------- | -------------------- |
| `card_id`         | 卡片稳定标识。              |
| `review_time`     | 复习时间，epoch 毫秒。       |
| `review_rating`   | 评分，1 Again 到 4 Easy。 |
| `review_duration` | 复习耗时，毫秒。             |
| `review_state`    | 复习时的卡片状态。            |

传入 `nextDayStartsAt`（新一天开始的小时）以及 IANA 时区（如 `'UTC'`）或固定的 UTC 分钟偏移。对 `Uint8Array` 输入，该调用同步返回项：

```ts file="../../../snippets/run-code/optimizer-csv.ts"
import { convertCsvToFsrsItems } from '@open-spaced-repetition/binding'

// One card with two reviews: first review today, second the next day.
const csv = [
  'review_time,card_id,review_rating,review_duration,review_state',
  '1704067200000,card-one,3,1000,0',
  '1704153600000,card-one,4,900,2',
].join('\n')

// The day starts at 04:00 local, in the UTC timezone.
const items = convertCsvToFsrsItems(
  new TextEncoder().encode(csv),
  4,
  'UTC',
  'FSRS-7'
)

console.log(
  JSON.stringify(
    {
      itemCount: items.length,
      reviewsPerItem: items.map((item) => item.reviews.length),
      ratings: items.map((item) => item.reviews.map((review) => review.rating)),
    },
    null,
    2
  )
)

```


▶ 运行代码

原来的转换函数仍返回数组。需要一次性归一化任意 CSV 卡片标识时，使用 `convertCsvToFsrsItemsWithCardIds`：它返回 `{ items, cardIds }`，流输入则返回 Promise。数值 ID 按本次转换中保留的卡片生成，与排序后的 items 逐项对齐，不是原始卡片标识。训练和直接评估复用同一组 IDs；不要混用不同转换结果中的 IDs。

`computeParameters` 和 `evaluateWithTimeSeriesSplits` 接受可选的 `options.cardIds`。

```ts file="../../../snippets/run-code/optimizer-card-ids.ts"
import {
  computeParameters,
  convertCsvToFsrsItemsWithCardIds,
  evaluateWithTimeSeriesSplits,
} from '@open-spaced-repetition/binding'

const response = await fetch(`${import.meta.env.BASE_URL}/revlog.csv`, {
  cache: 'force-cache',
})
if (!response.ok) throw new Error(`revlog.csv: ${response.status}`)
if (!response.body) throw new Error('revlog.csv: empty response body')
console.log('Response received. Converting reviews and training…')

const dataset = await convertCsvToFsrsItemsWithCardIds(
  response.body,
  4,
  'UTC',
  'FSRS-7'
)
const optimizedWeights = await computeParameters(dataset.items, {
  modelVersion: 'FSRS-7',
  enableShortTerm: true,
  cardIds: dataset.cardIds,
})
const metrics = await evaluateWithTimeSeriesSplits(dataset.items, {
  modelVersion: 'FSRS-7',
  enableShortTerm: true,
  cardIds: dataset.cardIds,
})

console.log(JSON.stringify({ optimizedWeights, metrics }, null, 2))

```


▶ 运行代码

CSV 转换、训练、评估和调度必须选择相同的 `modelVersion`（默认 `'FSRS-7'`，也可选 `'FSRS-6'`）。将它作为 `convertCsvToFsrsItems` 的第四个参数，并传入训练和评估选项；调度时使用 `DefaultScheduler({ version: modelVersion, weights })`。FSRS-7 产生 34 个权重，按本地学习日的实际时长归一化并保留小数与同日间隔；FSRS-6 产生 21 个权重，使用整数学习日。因此同日的后续复习也可以参与 FSRS-7 训练。

## 训练权重

`computeParameters(items, options)` 是异步的，返回训练好的权重。`enableShortTerm` 必填；`numRelearningSteps` 与 `trainingConfig` 可选，`progress` 在训练期间回报 `(current, total)`：

```ts
const weights = await computeParameters(items, {
  modelVersion: 'FSRS-7',
  enableShortTerm: true,
  enableSchedPenalties: true,
})
```

`enableSchedPenalties` 可选，默认为 `false`。设为 `true` 会在训练损失中加入 FSRS-7 的间隔增长和短间隔惩罚。它也适用于 `evaluateWithTimeSeriesSplits` 内部的训练，FSRS-6 会忽略此选项；它不改变调度公式。

`trainingConfig`（epochs、batch size、seed、最大序列长度、学习率与 L2 权重）可选，缺省时用 binding 的默认值。`computeParameters` 运行真正的训练循环，因此应在 Worker 而非主线程中调用。[Playground](https://open-spaced-repetition.github.io/ts-fsrs/zh-CN/playground.md)页的训练器就在 Web Worker 里跑同一路径并实时回报进度。返回的 `weights` 数组就是传给 `DefaultScheduler({ version: modelVersion, weights })` 或 `defineScheduler` 配置、用于替换模型默认值的东西。

## 评估拟合

`evaluateWithTimeSeriesSplits(items, options)` 按时间切分复习历史，返回带 `logLoss` 与 `rmseBins` 的 `ModelEvaluation`，供你判断训练权重对留出复习的预测质量。`computeOptimalSteps` 更进一步：给定复习与目标保留率，推荐学习与再学习步骤的时长。

安装命令与两种运行时见[训练器概览](https://open-spaced-repetition.github.io/ts-fsrs/zh-CN/guide/optimizer/index.md)。
