> ## Documentation Index
> Fetch the complete documentation index at: https://praison.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# praisonai-train Package

> Train agents or fine-tune LLMs without installing the full PraisonAI wrapper

Train agents or fine-tune LLMs without installing the full PraisonAI wrapper.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    subgraph "praisonai-train"
        Agent[🤖 Agent] --> Train[⚙️ praisonai-train agents]
        Train --> Grade[⭐ Grader / Human]
        Grade --> Better[✅ Improved Agent]
        Trials[🧪 trials.json] --> FromTrials[♻️ data from-trials]
        FromTrials --> Data[📋 Dataset]
        Data --> LLM["⚙️ praisonai-train llm<br/>⚙️ Multi-GPU"]
        LLM --> Model[✅ LoRA Model]
        Model --> Export[🚀 export]
        Export --> Dest[HF / GGUF / Ollama]
    end

    classDef input fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef process fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef grade fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef output fill:#10B981,stroke:#7C90A0,color:#fff

    class Agent,Trials input
    class Train,LLM,Export,FromTrials process
    class Grade grade
    class Better,Data,Model,Dest output
```

The `praisonai-train` PyPI package (import: `praisonai_train`) is Tier 2c — it sits on top of `praisonaiagents` and gives you the `train` CLI group and a standalone `praisonai-train` console script.

<Card title="Prefer a UI? See Desktop → Training" icon="display" href="/docs/features/desktop/training">
  The PraisonAI Desktop app wraps `praisonai-train llm` in a Train tab — live loss chart, log, and reconnect-safe progress.
</Card>

## Quick Start

<Steps>
  <Step title="Agent Training">
    Improve an agent iteratively — no ML dependencies required.

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    from praisonaiagents import Agent

    agent = Agent(instructions="You are a helpful assistant.")
    ```

    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    pip install praisonai-train

    praisonai-train agents --input "What is Python?"
    ```
  </Step>

  <Step title="LLM Fine-tuning">
    Add the `[llm]` extra to pull the modern Unsloth/torch stack (`unsloth>=2025.9.1`, `trl>=0.18.2`, `transformers>=4.51.3`, `torch>=2.6.0`). The trainer uses each model's own chat template, so `chat_template` is optional.

    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    pip install "praisonai-train[llm]"
    ```

    <Tabs>
      <Tab title="Llama">
        ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
        praisonai-train llm dataset.json \
            --model unsloth/Meta-Llama-3.1-8B-Instruct-bnb-4bit
        ```

        <Note>
          The base install now uses the modern TRL API (`SFTConfig` + `SFTTrainer`) and pulls the current Unsloth / TRL / torch 2.6+ stack. On old pins, upgrade with `pip install -U "praisonai-train[llm]"`.
        </Note>

        <Note>
          `praisonai-train llm <dataset>` correctly trains on the dataset you pass. On PraisonAI releases before [PR #4239](https://github.com/MervinPraison/PraisonAI/pull/4239) the dataset argument was silently dropped and the run fell back to `yahma/alpaca-cleaned`; upgrade if `praisonai-train show <session>` reports a model trained on a corpus you didn't provide.
        </Note>

        <Note>
          As of [PR #4317](https://github.com/MervinPraison/PraisonAI/pull/4317), `praisonai train llm` (the wrapper route) also actually launches the trainer. On earlier releases the legacy dispatcher had no `train` case and silently forwarded the literal word `"train"` to an LLM as a chat prompt, exited `0`, and never invoked the trainer. Direct use of the `praisonai-train llm` console script was unaffected.
        </Note>
      </Tab>

      <Tab title="Gemma">
        ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
        praisonai-train llm dataset.json \
            --model unsloth/gemma-2-2b-it-bnb-4bit
        ```
      </Tab>

      <Tab title="Qwen">
        ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
        praisonai-train llm dataset.json \
            --model unsloth/Qwen2.5-0.5B-Instruct-bnb-4bit
        ```
      </Tab>

      <Tab title="From a config file">
        Preview a run before you spend GPU time — `--dry-run` prints the resolved config and exits without loading the trainer. The tuning flags override the file (file first, flags on top).

        ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
        # Preview the resolved config before spending GPU time
        praisonai-train llm -c config.yaml --lora-r 32 --epochs 2 --dry-run

        # Then run it — flags override the file
        praisonai-train llm -c config.yaml --lora-r 32 --epochs 2
        ```
      </Tab>

      <Tab title="Send it to a remote GPU box">
        No GPU on this machine? Add `--remote-host` and the run happens on another box over SSH — the same as a `remote:` block in YAML or the desktop "Run on" dropdown. Set up key auth once with `ssh-copy-id gpubox`.

        ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
        praisonai-train llm dataset.json \
            --model unsloth/gemma-2-2b-it-bnb-4bit \
            --remote-host gpubox
        ```

        The log streams while training; Ctrl-C stops the remote run. See [Remote in one step](/docs/features/praisonai-train-inline-remote).
      </Tab>
    </Tabs>
  </Step>

  <Step title="Serve a trained model">
    Serve a fine-tuned GGUF over an OpenAI-compatible endpoint — Gemma-4 auto-fetches its MTP drafter for lossless fast inference.

    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    praisonai-train serve --gguf model.gguf
    ```

    See [Serve & MTP Fast-Inference](/docs/features/praisonai-train-serve) for the full walkthrough.
  </Step>
</Steps>

***

## Beginner-safe defaults

A minimal fine-tuning config trains locally and pushes nowhere unless you opt in.

```yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
model_name: "unsloth/gemma-2-2b-it-bnb-4bit"
max_seq_length: 2048
dataset:
  - name: "yahma/alpaca-cleaned"
    num_samples: 20   # subset for a fast smoke test
```

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Trains locally, saves LoRA to lora_model/, no push.
praisonai-train llm dataset.yaml
```

Four headline safety guarantees (PraisonAI [#3279](https://github.com/MervinPraison/PraisonAI/pull/3279)):

* **A minimal config trains locally** — publishing to Hugging Face or Ollama is opt-in (set the flag **and** its target).
* **`assistant_only_loss: auto` never crashes** on a stock Gemma / Qwen / Llama template — it now masks via Unsloth turn markers when the template lacks `{% generation %}`, and falls back to full-sequence SFT only when neither route is available.
* **Unknown / misnamed keys warn instead of crashing** — a typo logs `WARNING: ignoring unknown config key '...'` and training continues.
* **Environment preflight** — missing or out-of-date training deps are now caught before the first heavy import; the CLI prints one `pip install -U ...` line that fixes them all.
* **An unknown `model_name` warns, it doesn't fail** — the trainer prints one line pointing at `praisonai-train models` (with a "did you mean?" suggestion when there's a close match) and continues, because unsloth also loads models it doesn't map.

<Note>
  Beyond SFT, `praisonai-train llm` also supports preference tuning — **DPO**, **ORPO**, and **KTO** — via the `method` config key. See [Preference Training](/docs/features/train-preference-tuning).
</Note>

Just before training, the trainer prints a run-summary block confirming the resolved model, example count, loss mask, steps, and output dir — see [Train → Run summary](/docs/docs/train#run-summary).

***

## When to Use `praisonai-train` vs `praisonai train`

Install the standalone package when you only need training; use the wrapper's `praisonai train` when you already run the full stack.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph TB
    Q1{What do I need?}
    Q1 -->|Already have the<br/>full wrapper| P1[praisonai train ...]
    Q1 -->|Just agent training| P2[pip install praisonai-train]
    Q1 -->|Agent training +<br/>LLM fine-tuning| P3["pip install praisonai-train[llm]"]
    Q1 -->|Fine-tune on<br/>multiple GPUs| P5[torchrun --nproc_per_node=N ...]
    Q1 -->|Full stack +<br/>fine-tuning deps| P4["pip install praisonai[train]"]

    classDef question fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef wrapper fill:#10B981,stroke:#7C90A0,color:#fff
    classDef runtime fill:#189AB4,stroke:#7C90A0,color:#fff

    class Q1 question
    class P1,P4 wrapper
    class P2,P3,P5 runtime
```

Both entry points expose the same commands: every `praisonai train <sub>` also runs as `praisonai-train <sub>`.

***

## CLI Subcommands

Eleven subcommands cover dataset tooling, benchmarking, fine-tuning, model discovery, serving, export, and agent training.

| Subcommand                                        | Purpose                                                                                                                                                                                                                       |
| ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `praisonai-train generate [--config FILE]`        | Synthesize an instruction dataset from a teacher LLM                                                                                                                                                                          |
| `praisonai-train validate DATASET [--out FILE]`   | Quality-check / filter an instruction dataset                                                                                                                                                                                 |
| `praisonai-train data from-trials REPORT`         | Export passing trial attempts to a trainer-ready SFT dataset                                                                                                                                                                  |
| `praisonai-train benchmark -d DEPLOYMENT ...`     | Rank deployments by generation speed                                                                                                                                                                                          |
| `praisonai-train llm DATASET`                     | Fine-tune an LLM via Unsloth (as of [PR #4317](https://github.com/MervinPraison/PraisonAI/pull/4317), the wrapper route `praisonai train llm` also actually launches the trainer instead of falling through to a chat prompt) |
| `praisonai-train models [SEARCH]`                 | List the models the trainer knows how to load — with `--json` / `-n` and `*` starting-point markers                                                                                                                           |
| `praisonai-train export {ollama\|gguf\|hf}`       | Publish an already-trained model without re-running training                                                                                                                                                                  |
| `praisonai-train agents [AGENT_FILE]`             | Iteratively train an agent                                                                                                                                                                                                    |
| `praisonai-train serve --gguf FILE [--benchmark]` | Serve a fine-tuned GGUF over an OpenAI-compatible endpoint (auto-fetches the MTP drafter on Gemma-4)                                                                                                                          |
| `praisonai-train list`                            | List training sessions                                                                                                                                                                                                        |
| `praisonai-train show SESSION_ID`                 | Show a session's iterations and best score                                                                                                                                                                                    |
| `praisonai-train apply SESSION_ID`                | Apply learned suggestions to an agent                                                                                                                                                                                         |

See [Train CLI](/docs/cli/train) for full flags.

***

## Supported models

`praisonai-train llm` fine-tunes any Unsloth-supported model. The full list — \~246 repos on a recent unsloth release, including every 4-bit key **and** its 16-bit mirror — is discoverable from the CLI itself:

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai-train models              # everything, capped at 40
praisonai-train models gemma        # filter by family
praisonai-train models 7b           # or by size
praisonai-train models --json       # machine-readable
praisonai-train models -n 0         # the full list
```

Rows marked `*` are the **curated starting set** — one current base per major family, sized to fit a single 24 GB GPU in 4-bit. Pick one of these if you haven't chosen yet:

| Model family  | Curated `--model`                             | Optional `chat_template` |
| ------------- | --------------------------------------------- | ------------------------ |
| Llama         | `unsloth/Meta-Llama-3.1-8B-Instruct-bnb-4bit` | `llama-3.1` / `llama-3`  |
| Qwen          | `unsloth/Qwen2.5-7B-Instruct-bnb-4bit`        | `qwen-2.5` / `qwen-3`    |
| Gemma         | `unsloth/gemma-2-9b-it-bnb-4bit`              | `gemma` / `gemma-2`      |
| Mistral       | `unsloth/mistral-7b-instruct-v0.3-bnb-4bit`   | `mistral`                |
| Phi           | `unsloth/Phi-3.5-mini-instruct-bnb-4bit`      | `phi-3`                  |
| Qwen (small)  | `unsloth/Qwen2.5-3B-Instruct-bnb-4bit`        | `qwen-2.5`               |
| Gemma (small) | `unsloth/gemma-2-2b-it-bnb-4bit`              | `gemma` / `gemma-2`      |

The trainer uses each model's own chat template, so `chat_template` is optional — set it only to override.

<Note>
  **Unknown `model_name` warns, it doesn't refuse.** A `model_name` not in the unsloth catalog prints one line at validation time — e.g. `WARNING: 'unsloth/Meta-Llama-3.1-8B-Instrct-bnb-4bit' is not in unsloth's model list, so it may not load. Did you mean: unsloth/Meta-Llama-3.1-8B-Instruct-bnb-4bit? Run \`praisonai-train models\` to see the full list.`— and training proceeds. unsloth's loader falls through to a generic path for models it doesn't map, so refusing would block working configurations; but a typo no longer costs a Hugging Face download to discover. Suggestions match the repo name, not the full id, so a right model under the wrong org (e.g.`meta-llama/…`) surfaces the `unsloth/…\` mirror.
</Note>

<Note>
  When `unsloth` isn't installed (`pip install praisonai-train` without `[llm]`), the same command still works — it falls back to the 7-entry curated set so `models` is useful in a lightweight agent-training env too.
</Note>

<Note>
  PraisonAI PR #3274 validated `unsloth/Qwen2.5-0.5B-Instruct-bnb-4bit` and `unsloth/gemma-2-2b-it-bnb-4bit` end-to-end. See [Train → Model & template keys](/docs/docs/train#model--template-keys) for the full `chat_template` reference.
</Note>

***

## Common Patterns

### Fine-tune a non-Llama base (Gemma / Qwen)

Point `--model` at any Gemma or Qwen base — the trainer uses each model's own chat template automatically.

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
pip install "praisonai-train[llm]"

# Gemma 2 (uses the model's own template automatically)
praisonai-train llm dataset.json \
    --model unsloth/gemma-2-2b-it-bnb-4bit

# Qwen 2.5
praisonai-train llm dataset.json \
    --model unsloth/Qwen2.5-0.5B-Instruct-bnb-4bit
```

<Note>
  The trainer previously force-applied the Llama-3.1 template to every model, corrupting Gemma / Qwen runs. Fixed as of PraisonAI PR #3274 — set `chat_template` in `config.yaml` only when a base model has no built-in template.
</Note>

### Fine-tune on 2 GPUs with checkpointing

Launch under `torchrun` and add a handful of checkpoint keys — an interrupted run resumes from the latest. See [Multi-GPU](/docs/features/praisonai-train-multigpu).

```yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# config.yaml
model_name: "unsloth/gemma-2-2b-it-bnb-4bit"
max_seq_length: 2048
dataset:
  - name: "yahma/alpaca-cleaned"
save_strategy: "steps"
save_steps: 50
resume_from_checkpoint: true
```

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
torchrun --nproc_per_node=2 -m praisonai_train.train.llm.trainer train --config config.yaml
```

### Train, review, apply

Run a training session, inspect the iterations, then bake the best one into your agent.

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# --iterations N is a max — training stops early on a score >= 9.5 in LLM mode
praisonai-train agents --input "Explain AI" --human
praisonai-train list
praisonai-train show train-abc123 --iterations
praisonai-train apply train-abc123 --run "Explain AI"
```

### Apply in Python

Apply a session's suggestions to an agent directly.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent
from praisonai_train.train.agents import apply_training

agent = Agent(instructions="You are a helpful assistant.")
apply_training(agent, session_id="train-abc123")
```

### Train on any console

The same commands run identically on macOS, Linux, and Windows — no encoding configuration needed.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Works identically on macOS/Linux/Windows — no encoding config needed
from praisonaiagents import Agent

agent = Agent(instructions="You are a helpful assistant.")
```

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# On a Windows cp1252 console, the summary renders as plain ASCII
# and the session is still persisted for later review.
praisonai-train agents --input "What is Python?"
praisonai-train show train-abc123
```

### Force all iterations

Benchmarks, regression tests, and demos that need to observe the feedback loop across every iteration should pass `--no-early-stop` (CLI) or `no_early_stop=True` (Python) so the 9.5 threshold is bypassed.

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# CLI — always runs all 3 iterations
praisonai-train agents --input "What is Python?" --iterations 3 --no-early-stop
```

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent
from praisonai_train.train.agents import AgentTrainer, TrainingScenario

agent = Agent(instructions="You are a helpful assistant.")
trainer = AgentTrainer(agent=agent, iterations=3, no_early_stop=True)
trainer.scenarios.append(TrainingScenario(input_text="What is Python?"))
report = trainer.run()
```

Without this flag, `--iterations` behaves as a **maximum** in LLM-as-Judge mode — training stops as soon as any iteration scores ≥ 9.5.

***

## Exporting an already-trained model

Publish a `lora_model/` you trained earlier — no dataset, no re-training.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    Model[✅ lora_model] --> Export[🚀 praisonai-train export]
    Export --> HF[Hugging Face]
    Export --> GGUF[GGUF]
    Export --> Ollama[Ollama]

    classDef source fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef cli fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef dest fill:#10B981,stroke:#7C90A0,color:#fff

    class Model source
    class Export cli
    class HF,GGUF,Ollama dest
```

<Steps>
  <Step title="Push to Hugging Face">
    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    praisonai-train export hf --model-dir lora_model --hf me/my-model
    ```
  </Step>

  <Step title="Export a GGUF">
    Writes a local `.gguf`; add `--hf` to also push it to the Hub.

    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    praisonai-train export gguf --model-dir lora_model --hf me/my-model --quant q4_k_m
    ```
  </Step>

  <Step title="Push to Ollama">
    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    praisonai-train export ollama --model-dir lora_model --ollama me/my-model --quant q4_k_m
    ```
  </Step>
</Steps>

<AccordionGroup>
  <Accordion title="Export doesn't need a dataset">
    `for_export()` skips the training-only validation, so an export-only run needs no `dataset:` — and no config file at all.
  </Accordion>

  <Accordion title="Chat template is inferred">
    The base model (for chat-template selection) is read from `<model-dir>/config.json:_name_or_path`, falling back to the directory name. Override it with `--base-model`.
  </Accordion>

  <Accordion title="Quantization is validated up front">
    `--quant` accepts the same values as the LLM training path (`q4_k_m`, `q5_k_m`, `q8_0`, `q4_0`, `q4_1`, `q5_0`, `q5_1`, `q3_k_m`, `q6_k`, `f16`, `bf16`, `q2_k`). A typo fails fast, listing every valid choice.
  </Accordion>

  <Accordion title="Ollama needs a namespaced model + registered key">
    The model must be namespaced `<username>/<name>`, and your public key must be registered at [https://ollama.com/settings/keys](https://ollama.com/settings/keys). An unauthorized push tells you exactly where to click and prints your local `~/.ollama/id_ed25519.pub`.
  </Accordion>
</AccordionGroup>

### Python API

Export-only, straight from a config dict — no dataset required.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonai_train import TrainModel

trainer = TrainModel.for_export({
    "model_name": "unsloth/gemma-2-2b-it-bnb-4bit",
    "final_model_dir": "lora_model",
    "hf_model_name": "me/my-model",
    "quantization_method": "q4_k_m",
})
model, tokenizer = trainer.load_model()
trainer.model, trainer.hf_tokenizer = model, tokenizer
trainer.save_model_merged()            # merged HF push
# or  trainer.push_model_gguf()        # GGUF-to-HF push
# or  trainer.create_and_push_ollama_model()   # Ollama push
```

<Note>
  `for_export()` accepts either `model_name` or its alias `model` (matching the `--model` CLI flag), and validates `quantization_method` up front — a typo like `q4km` raises `ValueError` with the full valid-methods list.
</Note>

See [`praisonai train export`](/docs/docs/cli/train#praisonai-train-export) for every flag and exit code.

***

## Windows & non-UTF-8 Consoles

`praisonai-train agents` renders its summary table with emoji (`✅ PASSED`, `❌ NEEDS WORK`, `★` best-iteration marker) when stdout supports UTF-8, and automatically falls back to ASCII (`PASSED`, `NEEDS WORK`, `*`) when it doesn't. It detects the console's encoding at runtime.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph TB
    Start[praisonai-train agents] --> Detect{stdout<br/>encoding?}
    Detect -->|UTF-8| Rich[Rich table + emoji<br/>PASSED tick / star marker]
    Detect -->|cp1252 / ASCII| Safe[Rich table + ASCII labels<br/>PASSED / * marker]
    Safe --> Fallback{Rich still<br/>UnicodeEncodeError?}
    Fallback -->|No| Safe
    Fallback -->|Yes| Plain[Plain-text summary<br/>Key: value lines]

    classDef input fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef decision fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef success fill:#10B981,stroke:#7C90A0,color:#fff
    classDef fallback fill:#189AB4,stroke:#7C90A0,color:#fff

    class Start input
    class Detect,Fallback decision
    class Rich success
    class Safe,Plain fallback
```

<Note>
  The ASCII summary is the correct output on a cp1252 Windows console — not a truncation. The session is saved either way; `praisonai-train show <session-id>` re-renders it in whichever encoding your current console supports.
</Note>

***

## Exit Codes

`praisonai-train agents` reports three distinct outcomes.

| Exit  | Meaning                                                                                                                                                           |
| ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `0`   | Training completed and the report was persisted (`praisonai-train list` will show it). A warning is printed if only the console display failed to encode.         |
| `1`   | Training itself failed — the run raised an exception (including encoding errors that hit before `save_report`) or arguments were invalid. No report is persisted. |
| `130` | Interrupted by `Ctrl-C`.                                                                                                                                          |

<Tip>
  A genuine agent failure (LLM provider unreachable, bad credentials, request timeout) now also surfaces as exit `1`. Previously these errors were captured as an "output" string, graded, persisted, and reported as a successful training run — discard any `train apply` guidance derived from an `"Error: ..."` output. Fixed in [PraisonAI PR #4239](https://github.com/MervinPraison/PraisonAI/pull/4239).
</Tip>

<Tip>
  On a cp1252 Windows console, a completed training session now exits `0` even if Rich cannot render the summary emoji — you'll see `Training complete but summary could not be displayed: 'charmap' codec can't encode ...`. Run `praisonai-train show <session-id>` to inspect the persisted result. If you want the full emoji summary, run `chcp 65001` first or set `PYTHONIOENCODING=utf-8`.
</Tip>

***

## Best Practices

<AccordionGroup>
  <Accordion title="Install the base package for agent training">
    `pip install praisonai-train` pulls `praisonaiagents` plus `litellm` (needed for LLM-as-Judge grading) — enough for `agents`, `list`, `show`, and `apply`. Add `[llm]` only when you need Unsloth fine-tuning.
  </Accordion>

  <Accordion title="Use the standalone script when you don't want the wrapper">
    The `praisonai-train` console script exposes the full `train` group without installing `praisonai`. Ideal for lightweight training-only environments.
  </Accordion>

  <Accordion title="Old imports keep working">
    Existing `praisonai.train.*`, `praisonai.train_vision`, and `praisonai.upload_vision` imports still resolve to the same module objects in `praisonai_train`. Nothing to migrate.
  </Accordion>

  <Accordion title="Let the tokenizer's native template win">
    For LLM fine-tuning, only set `chat_template` for models without one, or to force a specific one. Forcing `llama-3.1` on Gemma/Qwen was the old default and silently corrupted training — the trainer now uses each model's own template by default. See [Train → Chat Template](/docs/docs/train#chat-template).
  </Accordion>

  <Accordion title="Update to the modern Unsloth stack">
    The `[llm]` extra now requires `unsloth>=2025.9.1`, `trl>=0.18.2`, `transformers>=4.51.3`, and `torch>=2.6.0`. If you had pinned `trl<0.9.0`, upgrade — the pre-0.9 TRL API is no longer supported. As of PraisonAI PR #4365, the trainer refuses to import a stale stack at all and tells you the exact `pip install -U ...` to run.
  </Accordion>

  <Accordion title="Fix a GPU out-of-memory run in order">
    When a fine-tuning run stops with "The GPU ran out of memory", lower `max_seq_length` first (biggest lever), then enable `use_gradient_checkpointing: unsloth`, then halve `per_device_train_batch_size` while doubling `gradient_accumulation_steps`, and switch to a 4-bit base model only as a last resort. See [Train → GPU out of memory](/docs/docs/train#gpu-out-of-memory) for the full walkthrough.
  </Accordion>
</AccordionGroup>

<Note>
  Backward-compatible: if you already have the wrapper installed, `praisonai.train.*` imports and the `setup-conda-env` entry point continue to work unchanged.
</Note>

***

## Related

<CardGroup cols={2}>
  <Card title="Train" icon="graduation-cap" href="/docs/train">
    Training overview and fine-tuning setup.
  </Card>

  <Card title="Desktop → Training" icon="display" href="/docs/features/desktop/training">
    Prefer a UI? Run a fine-tune from the Desktop app's Train tab.
  </Card>

  <Card title="Train CLI" icon="terminal" href="/docs/cli/train">
    Full flag reference for every subcommand.
  </Card>

  <Card title="Preference Training" icon="scale-balanced" href="/docs/features/train-preference-tuning">
    Fine-tune on preferences with DPO, ORPO, and KTO.
  </Card>

  <Card title="Serve & MTP Fast-Inference" icon="rocket" href="/docs/features/praisonai-train-serve">
    Serve a GGUF over OpenAI HTTP with lossless MTP speculative decoding.
  </Card>

  <Card title="Ollama" icon="cloud" href="/docs/models/ollama">
    Publish and run fine-tuned models locally with Ollama.
  </Card>

  <Card title="Dataset Tooling" icon="database" href="/docs/features/praisonai-train-dataset-tooling">
    Generate and quality-check instruction datasets.
  </Card>

  <Card title="Speed Benchmark" icon="gauge" href="/docs/features/praisonai-train-benchmark">
    Rank deployments by generation speed before you fine-tune.
  </Card>

  <Card title="Multi-GPU Training" icon="microchip" href="/docs/features/praisonai-train-multigpu">
    Fine-tune across multiple GPUs with torchrun.
  </Card>

  <Card title="Remote in One Step" icon="server" href="/docs/features/praisonai-train-inline-remote">
    Send a run to a remote GPU box with `--remote-host`, `remote:` YAML, or the desktop dropdown.
  </Card>

  <Card title="Checkpointing" icon="database" href="/docs/features/praisonai-train-checkpointing">
    Save, resume, and keep the best checkpoint.
  </Card>

  <Card title="Installation Extras" icon="puzzle-piece" href="/docs/features/installation-extras">
    The train install matrix.
  </Card>

  <Card title="Package Tiers" icon="layer-group" href="/docs/features/architecture-tiers">
    How the six packages stack.
  </Card>

  <Card title="Windows Terminal Encoding" icon="terminal" href="/docs/features/windows-terminal-encoding">
    Fix Rich crashes and ASCII rendering on legacy Windows consoles.
  </Card>
</CardGroup>
