> ## Documentation Index
> Fetch the complete documentation index at: https://arkor-92aeef0e-eng-615.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# スターターテンプレートのカスタマイズ

> 生成されたテンプレートを起点として扱う。データセット、ハイパーパラメーター、コールバック、ベースモデルを変える。

# スターターテンプレートのカスタマイズ

プロジェクト生成ツールは動くトレーナーを `src/arkor/trainer.ts` に書き出します。テンプレートは出発点で、どのフィールドも変更してよく、多くのプロジェクトは最初の数回の学習でデフォルトを卒業します。このレシピは最初に出てくる 4 つのカスタマイズを順に見ます。

出発点のトレーナー（`--template triage` 直後）はこんな形:

```ts theme={null}
// src/arkor/trainer.ts (scaffolded)
import { createTrainer } from "arkor";

export const trainer = createTrainer({
  name: "triage-run",
  model: "unsloth/gemma-4-E4B-it",
  dataset: { type: "huggingface", name: "arkorlab/triage-demo" },
  datasetFormat: { type: "chatml" },
  maxSteps: 100,
  evalSteps: 25,
  lora: { r: 16, alpha: 16, loadIn4bit: false },
  callbacks: {
    onLog: ({ step, loss, evalLoss }) => {
      const lossPart =
        typeof loss === "number" && Number.isFinite(loss)
          ? ` loss=${loss.toFixed(4)}`
          : "";
      const evalPart =
        typeof evalLoss === "number" && Number.isFinite(evalLoss)
          ? ` evalLoss=${evalLoss.toFixed(4)}`
          : "";
      console.log(`step=${step}${lossPart}${evalPart}`);
    },
  },
});
```

`evalSteps: 25` がデフォルトで導入されているので、学習 loss と並んで eval loss の系列も出力されます。Studio の loss チャートは `evalLoss` を自動で拾い、上の `onLog` コールバックも eval が走ったステップだけターミナル行末に ` evalLoss=…` を追記します（`maxSteps: 100` で 25 ごと、つまり 1 run あたり 4 回）。各 `field=…` セグメントは `Number.isFinite` でガードされているので、eval-only ステップで `loss=null` が出たり、training-only ステップで `evalLoss=null` が出ることはありません（SDK は欠損値を `null` に正規化し、`evalLoss` の型は `number | null` です）。 eval が不要なら `evalSteps` を外し、`onLog` の `evalLoss` 関連も合わせて削ってください。

## 1. データセットを差し替える

データセットはモデルが実際に学ぶものです。一番よくある変更は、デモデータセットから自分のデータセットへの切り替えです。

**別の HuggingFace データセットを使う。** `name` を渡し、必要なら `split` と `subset` を固定:

```ts theme={null}
dataset: {
  type: "huggingface",
  name: "your-org/your-private-dataset",
  split: "train",        // 任意。データセットのデフォルト split
  subset: "v3",          // 任意。複数 subset を持つデータセット用
},
```

**Blob URL を使う**（バックエンドが取得できる任意の HTTPS URL）。Hub に置けないデータに便利:

```ts theme={null}
dataset: {
  type: "blob",
  url: "https://internal.example.com/data/2026-04.jsonl",
  token: process.env.DATASET_TOKEN,    // バックエンドの blob 取得時に転送（ワイヤーフォーマットはバックエンド側で定義）
},
```

今のところ `{ type: "file" }` オプションはありません。ローカルファイルはバックエンドが到達できる場所にホストしてください。[SDK § DatasetSource](/ja/sdk/dataset) を参照。

## 2. ハイパーパラメーターを調整する

`TrainerInput` 上の型付きオプションは安全に調整できるツマミです。省略すれば、それぞれクラウド API のデフォルト値が使われます:

```ts theme={null}
createTrainer({
  // ...
  lora: {
    r: 32,                 // ランクが高いほどよく学べるがコストも上がる
    alpha: 64,             // しばしば 2 × r
    maxLength: 2048,       // 長いサンプルをこのトークン数で切り詰める
    loadIn4bit: true,      // QLoRA、約 4 倍のメモリ節約、わずかな品質コスト
  },
  maxSteps: 500,
  learningRate: 2e-4,
  batchSize: 8,
  weightDecay: 0.01,
  lrSchedulerType: "cosine",
});
```

トレーナーファイル自体を高速に反復して試したいときは `dryRun` を立てます:

```ts theme={null}
createTrainer({
  // ...
  dryRun: true,
});
```

`dryRun: true` はデータセットを切り詰め、ステップ数を制限してフルパイプラインを走らせます。GPU 時間は使います（スモークテストであり、何もしないわけではありません）が、学習は数分で終わるので、長い学習にコミットする前に設定とコールバックの挙動を確認できます。[SDK § createTrainer](/ja/sdk/create-trainer) を参照。

上級者向けフィールド（`warmupSteps`、`loggingSteps`、`saveSteps`、`evalSteps`、`trainOnResponsesOnly`、`datasetFormat`、`datasetSplit`）は `unknown` として型付けされ、クラウド API にそのまま転送されます。バックエンドの想定形を既に知っている場合のみ使ってください。SDK は渡す値を型チェックしません。

## 3. ライフサイクルコールバックを追加する

このセクションの他のレシピは、いずれもコールバックで噛み合います。生成済みのトレーナーでも、コールバックを 1 つずつ足していけます:

```ts theme={null}
import { createTrainer } from "arkor";

export const trainer = createTrainer({
  name: "support-bot-v1",
  model: "unsloth/gemma-4-E4B-it",
  dataset: { type: "huggingface", name: "arkorlab/triage-demo" },
  lora: { r: 16, alpha: 16 },
  maxSteps: 100,
  callbacks: {
    onLog: ({ step, loss, evalLoss }) => {
      const lossPart =
        typeof loss === "number" && Number.isFinite(loss)
          ? ` loss=${loss.toFixed(4)}`
          : "";
      const evalPart =
        typeof evalLoss === "number" && Number.isFinite(evalLoss)
          ? ` evalLoss=${evalLoss.toFixed(4)}`
          : "";
      console.log(`step=${step}${lossPart}${evalPart}`);
    },
    onCheckpoint: async ({ step, infer }) => {
      // /ja/cookbook/mid-run-eval を参照
      // 型付きフィールドの抽出は /ja/cookbook/structured-outputs を参照
    },
    onCompleted: async ({ job, artifacts }) => {
      // /ja/cookbook/notifications を参照
    },
    onFailed: async ({ job, error }) => {
      // /ja/cookbook/notifications を参照
    },
  },
});
```

このセクションのレシピは、最もよくある組み合わせです:

* [学習中の評価](/ja/cookbook/mid-run-eval) は `onCheckpoint` に組み込みます。
* [Early Stopping](/ja/cookbook/early-stopping) は `onLog` とトレーナーの `abortSignal` に組み込みます。
* [Slack / Discord 通知](/ja/cookbook/notifications) は `onCompleted` と `onFailed` に組み込みます。

学習に合うものを選んでください。トレーナーファイルはただの TypeScript なので、自由に組み合わせられます。

## 4. ベースモデルを変える

`model` フィールドはクラウド API に文字列としてそのまま転送されます。現在対応しているのは `gemma-4-E4B-it`（すべてのスターターテンプレートに同梱）です。クラウド API がそれ以外のどの ID を受け付けるかを決めます。サポートされない値を送ると上流から 4xx が返り、`training.failed` イベントにバックエンドのエラーメッセージが乗ります。

```ts theme={null}
model: "unsloth/gemma-4-E4B-it",   // 現在サポートされている値
```

別のベースを試すことは[ロードマップ](/ja/roadmap) に明示的に挙がっています。それが実現するまでは、`model` フィールドを選択肢のあるメニューではなく、サポートされる単一の値として扱ってください。

## 全部まとめる

上記すべてのカスタマイズを使ったトレーナーはこんな形:

```ts theme={null}
// src/arkor/trainer.ts
import { createTrainer } from "arkor";

const SLACK_WEBHOOK = process.env.SLACK_WEBHOOK_URL;

async function postSlack(text: string): Promise<void> {
  if (!SLACK_WEBHOOK) return;
  try {
    await fetch(SLACK_WEBHOOK, {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ text }),
    });
  } catch (err) {
    console.warn("slack post failed:", err);
  }
}

export const trainer = createTrainer({
  name: "support-bot-v2",
  model: "unsloth/gemma-4-E4B-it",
  dataset: { type: "huggingface", name: "arkorlab/triage-demo" },
  lora: { r: 32, alpha: 64, maxLength: 2048, loadIn4bit: true },
  maxSteps: 500,
  learningRate: 2e-4,
  callbacks: {
    onLog: ({ step, loss, evalLoss }) => {
      const lossPart =
        typeof loss === "number" && Number.isFinite(loss)
          ? ` loss=${loss.toFixed(4)}`
          : "";
      const evalPart =
        typeof evalLoss === "number" && Number.isFinite(evalLoss)
          ? ` evalLoss=${evalLoss.toFixed(4)}`
          : "";
      console.log(`step=${step}${lossPart}${evalPart}`);
    },
    onCompleted: async ({ job, artifacts }) => {
      await postSlack(`✓ ${job.name} done (${artifacts.length} artifact(s))`);
    },
    onFailed: async ({ job, error }) => {
      await postSlack(`✗ ${job.name} failed: ${error}`);
    },
  },
});
```

これでもまだ 30 行のファイルで、上から下まで一読できます。テンプレートの要点は、生成される具体的なコードそのものではなく、すでに学習が配線済みの状態を出発点として与えてくれることにあります。上のカスタマイズは、エディターを開いた 1 セッションのうちに到達できます。

Early Stopping を上に重ねるなら、[Early Stopping](/ja/cookbook/early-stopping) を参照してください。Abort された学習がバックエンドの GPU を回し続けないようにする `AbortController` + `trainer.cancel()` のペアを示しています。
