Chuyển đến nội dung chính

dsh-unsloth

Đã xác minh

dsh-unsloth · v0.2.0 · MIT

Unsloth for DeepSeek Harness: local LLM fine-tuning and dataset generation. Bundles a zero-dependency Python MCP server and mounts DSH's own MCP client, exposing model inventory, Data Recipe dataset generation, LoRA/QLoRA training, GGUF export and inferen

Cài đặt

dsh plugin add dsh-unsloth

Xác nhận layer đã áp bằng dsh --profile default --dump-config — xem hướng dẫn cài plugin.

Mã nguồn

Phát hành lên npm mà không có repository công khai. Hãy kiểm tra nội dung package trước khi cài.

Thẻ

Tác giả

Readme

dsh-unsloth

把 Unsloth(本地大模型微调 / 微调数据集生成)接进 DeepSeek Harness 的插件。

装上之后,模型就能直接调用 Unsloth:看本机模型清单、用 Data Recipe 生成微调数据集、起 LoRA/QLoRA 训练、看 loss 曲线、导出 GGUF、跑推理自检——全部以原生工具形式出现,名字是 mcp__unsloth__<tool>。


它是什么 / 怎么工作的

DeepSeek Harness
  └── dsh-unsloth(本插件,很薄)
        ├─ 1. 找 Python 解释器(优先用 Unsloth Studio 自带的 venv)
        ├─ 2. 可选:先把 Unsloth Studio 拉起来(autoStartStudio)
        └─ 3. 挂载 DSH 自带的 @deepseek-ai/dsh-mcp-client
                 └── server/unsloth_mcp_server.py(零依赖,纯标准库)
                        ├── HTTP → Unsloth Studio 后端  http://127.0.0.1:8888
                        │        (训练 / Data Recipe / 模型 / 导出 / 推理)
                        └── CLI  → python -m unsloth_cli
                                 (train / export / inference / chat)

设计上刻意不复刻协议层:MCP 客户端用的是 DSH 自己的那一个,所以工具命名(mcp__<serverName>__<tool>)、单次调用超时、断线自动重连的行为,跟手写一条 cordis.patch.yml 条目完全一致;插件只负责"找到解释器 + 找到脚本 + 挂上去"。


环境要求

要求 说明
Unsloth Desktop 装好即可(默认路径 ~/.unsloth/studio)。Studio 的 venv 会被自动用作解释器
Python 3.8+ MCP 服务只用标准库,所以任何 Python 都行;没有 Python 时插件会打印明确的错误而不是静默失败
DSH 带 @deepseek-ai/dsh-mcp-client(dsh-base 的依赖,向来都在)

安装

方式 A:一键脚本(推荐,不需要 pnpm / 不需要联网)

# 在普通 PowerShell 里运行(不要在被文件沙箱限制的环境里跑)
.\install.ps1                       # 默认装到 web 这个 profile
.\install.ps1 -Profile web -AutoStartStudio

脚本做三件事:把插件复制到 <profile>\node_modules\dsh-unsloth;在 profile 的 cordis.patch.yml 里补一条 insert(已有则跳过);备份原配置。改完是热加载生效,不用重启 DSH。

方式 B:手动(等价于脚本)

  1. 把本目录整体复制到 %APPDATA%\dsh-desktop\harness\profiles\web\node_modules\dsh-unsloth
  2. 在 %APPDATA%\dsh-desktop\harness\profiles\web\cordis.patch.yml 末尾追加:
- insert:
    - id: unsloth
      name: dsh-unsloth
      config:
        serverName: unsloth
        hfEndpoint: https://hf-mirror.com   # 国内网络建议
        disableXet: true
        autoStartStudio: true

⚠️ 必须是 insert: 列表形式。 这一层是"id 定向覆盖层",裸写 - id: xxx 会被当成"覆盖已有条目",新 id 找不到目标就被静默忽略(日志里连报错都没有)。

方式 C:作为正式包分发

推到 npm 后即可用 DSH 插件市场安装——package.json 里 dsh.bundle.patch 已指向插件自带的 cordis.patch.yml,市场装完会自动 insert,无需手改 YAML。


配置项

写在 insert 条目的 config: 下即可,全部有默认值:

键 默认 说明
enabled true 关掉整个桥接而不必删条目
serverName unsloth MCP 命名空间,工具名 = mcp__<serverName>__<tool>
python "" 指定解释器绝对路径;留空自动探测(Studio venv → 常见安装位置 → PATH)
studioUrl http://127.0.0.1:8888 Studio 后端地址
hfEndpoint "" 注入 HF_ENDPOINT 给派生的 Unsloth 子进程,如 https://hf-mirror.com
disableXet true 注入 HF_HUB_DISABLE_XET=1。Xet 走 cas-server.xethub.hf.co,镜像环境下必然 401 中断下载
homeDir "" MCP 服务的 config.json 与日志目录;留空 = <DSH_HOME>\unsloth-mcp(故意不放 node_modules,重装不会被清掉)
toolCallTimeoutMs 600000 单次工具调用超时(默认 60s 对训练/导出太短)
failOnStartupError false 初始连接失败是否让插件激活失败
autoStartStudio false 激活时若 Studio 没在监听就用它的 venv 起一个(真香:不用再手动开桌面版)
studioArgs [] 追加给 unsloth studio 的参数,如 ["--no-cloudflare"]

工具清单(20 个,全部来自 MCP 服务)

工具 用途
studio_status Studio 是否在跑 + 版本 + 硬件。动手前先调它
studio_start 启动 Studio(可 api_only),后台常驻
studio_stop 停掉全部 Studio 实例(官方 unsloth studio stop,按 STUDIO_HOME)
studio_api 万能后门:直连 Studio 任意 /api /v1 端点(400+ 路由)
unsloth_cli 原始 CLI 后门:train / inference / chat / export / list-checkpoints / studio(含 run stop verify-install)/ start(把 Claude、Codex、dsh 等指向 Unsloth)
models_list kind=local|cached|loras|checkpoints,外加 checkpoints_cli(扫输出根目录,看得见 CLI 训练的检查点)
export 导出检查点:merged-16bit / merged-4bit / gguf / lora,可推 HuggingFace
recipe_seed_inspect 检查数据集生成的种子(列名 + 预览行)
recipe_validate 校验 recipe(建任务前必做)
recipe_create 建数据集生成任务(preview 试跑 / full 全量)
recipe_status 任务状态 + 分析(无任务时返回 idle,不报错)
recipe_dataset 取回生成的训练样本
unsloth_text 文本训练(CLI 路径)。30+ 训练参数;spawn 前自动 --dry-run 预检;dry_run_only=true 只预检不训练
unsloth_image 视觉 / VLM 训练(Studio API 路径)
unsloth_text_status 文本训练状态:Studio 状态 + 本服务登记的任务(pid 存活、日志 verdict、最新 loss)
unsloth_image_status 视觉训练状态(存活状态取自 Studio 后端)
train_status 【已弃用】不分类型的全局状态,等价于上面两个的并集
train_stop 停止训练:Studio 后端 + 按 pid 结束 CLI 进程树(scope=all|cli|studio)
train_runs 历史训练记录
chat 推理自检;Studio 没加载模型时自动回退到 unsloth inference

0.1.3 曾把训练拆成 unsloth_text / unsloth_image,同时删掉了 train_start; 本 README 之前还列着 train_start,属于文档滞后,已修正。

训练参数(unsloth_text)

参数表直接对照 CLI 的 Typer 定义逐项核对,不是手抄:

model / dataset / local_dataset / format_type / training_type
max_seq_length / load_in_4bit / output_dir
num_epochs / max_steps / save_steps / warmup_steps
learning_rate / batch_size / gradient_accumulation_steps
weight_decay / random_seed / gradient_checkpointing / packing / train_on_completions
lora_r / lora_alpha / lora_dropout / target_modules / use_rslora / use_dora
enable_wandb / wandb_project / enable_tensorboard / tensorboard_dir
config / extra_args / dry_run_only / unload_inference / force

⚠️ training_type 的坑(本版本已自动兜住)

unsloth train 只认 lora 与 full;Studio 的 REST API 只认 LoRA/QLoRA / Full Finetuning / Continued Pretraining。两套词表互不通用。

CLI 用 setattr 覆盖配置、且没开 Pydantic 的 validate_assignment,所以传错值不会报错: 它会一路走到 use_lora = training_type.lower() == "lora" —— "lora/qlora" != "lora", 于是 use_lora=False,load_in_4bit 也被强制成 False,你要的 QLoRA 悄悄变成完全微调。 4GB 卡上这基本等于必挂。

本机历史证据:unsloth-mcp/logs/train-smoke02.log 第 25 行 Full finetuning mode - training all parameters,可训练参数 72.44% —— 那一次请求的正是 LoRA/QLoRA。 本版本会自动归一化,并在返回的 notes 里说明改了什么;修复后同一组参数的实测结果是 LoRA adapters configured successfully、可训练参数 1.75%(8,798,208 / 502,830,976)。

⚠️ output_dir 必须在 outputs 根目录内

这条限制由 trainer 自己强制(studio/backend/core/training/trainer.py 的 resolve_output_dir()),CLI 与 Studio API 两条路径都一样 —— 0.1.2 / 0.1.3 「支持任意输出路径」的说法是不成立的,实测会以 Training error: path escapes root: ... is not under ...\.unsloth\studio\outputs 失败。

现在两个训练工具都会在启动进程之前拦下并给出根目录,可行写法只有两种:

  • 给相对目录名(如 my-run)→ 落到 ~/.unsloth/studio/outputs/my-run
  • 给根目录之内的绝对路径

不传时检查点直接落在 ~/.unsloth/studio/outputs 下。


验证

离线预检(不碰 harness,用桩 ctx 跑 apply(),并让配置通过 mcp-client 自己的 Schema 校验):

cd $env:APPDATA\dsh-desktop\harness\profiles\web
node .\dsh-unsloth-selftest.mjs

预期输出里应有 mounted mcp-client: true、ACCEPTED、interpreter: ... exists: true。

运行期:看 %APPDATA%\dsh-desktop\logs\harness.log。可靠出现的标志是 MCP 服务那一行(它由插件挂载的 mcp-client 启动,stderr 会被转发到日志):

[stderr] [unsloth-mcp] ready (base_url=http://127.0.0.1:8888, cli=...)

然后让模型调一次 mcp__unsloth__studio_status:能返回 Studio 版本与 GPU 信息就说明整条链路通了。

插件自己还有一行 banner([dsh-unsloth] info: ... -> ... (serverName=..., home=...)),它被镜像写到 stderr。 在终端里跑 harness 时一定看得到;在 DSH Desktop 里是否落到 harness.log 取决于宿主对 stderr 的捕获方式, 别把它当成唯一的判断依据——以 [unsloth-mcp] ready 和工具调用为准。


排错

现象 原因 / 解法
工具完全不出现,日志无报错 cordis.patch.yml 里写成了裸 - id: → 改成 insert: 列表形式
改了插件的 JS 代码但行为没变 配置热重载会重新挂插件,但 Node 的 ESM 模块缓存不会失效 → 重启一次 DSH Desktop(实测:改配置后 [unsloth-mcp] ready 次数会增加,说明插件确实重新执行了;但已 import 的旧模块代码可能被复用)
日志出现 serverName "unsloth" is already in use 同时存在另一条 dsh-mcp-client 条目用了同名 serverName → 删掉重复的那条,或改 serverName
no Python interpreter found 设 python: 为绝对路径;或确认 Unsloth Desktop 已安装
工具能调但全部报"连不上 Studio" Studio 没在跑 → 开 autoStartStudio: true,或让模型调 studio_start
下载模型老中断(CAS 401) 保持 disableXet: true,并设 hfEndpoint: https://hf-mirror.com;GUI 里对应 Model hub 顶部的 HTTP/Xet 开关
Studio 启动报 unable to open database file 启动它的进程被文件沙箱限制,写不了 ~/.unsloth → 让 DSH 自己起(autoStartStudio)或在沙箱外手动开桌面版
训练启动几秒后失败,日志只有 Unsloth: No or negligible GPU memory available for fused cross entropy 有推理模型占着显存(4GB 卡上推理与训练不能共存)。两个训练工具都会前置检查并拦下,提示你传 unload_inference: true(工具会先 POST /api/inference/unload,再轮询等显存真正释放)
train_status 里 Studio 一直显示 idle / Ready to train 正常:CLI 训练不会登记进 Studio 的训练后端。看响应里的 jobs——含进程存活、日志 verdict(completed/failed)、最新 loss/epoch。想看 CLI 的检查点用 models_list kind=checkpoints_cli
后台训练秒退,日志只有 No such option: --num_epochs (Possible options: --num-epochs) 0.1.4 之前训练参数表里写错了这个 flag。已修;升级后 --num-epochs 正常
请求 LoRA/QLoRA,日志却是 Full finetuning mode - training all parameters、可训练参数 70%+ training_type 词表错配(见上文「training_type 的坑」)。0.1.4 起会自动归一化到 lora 并在 notes 里说明
Training error: path escapes root: ... is not under ...\.unsloth\studio\outputs output_dir 在 outputs 根目录之外。CLI 与 API 两条路径都受限 → 传相对目录名,或用根目录内的绝对路径。0.1.4 起会在启动前就拦下
视觉训练早已结束,unsloth_image_status 仍报 running: true 0.1.3 及以前把占位 pid "api_train" 当成活进程。0.1.4 起存活状态取自 /api/train/status 的 is_training_running
训练进程偶发 forrtl: error (200): program aborting due to window-CLOSE event Intel Fortran 运行时把 detach 子进程"没有控制台"当成 close 事件而 abort。0.1.5 起已修:注入 FOR_DISABLE_CONSOLE_CTRL_HANDLER=1(Intel 官方开关),实测连续两次训练完整跑完
升级插件报 ERR_PNPM_EPERM ... node_modules\dsh-unsloth 有进程把插件目录当工作目录 → 0.1.1 起所有派生进程的 cwd 都移出包目录(<DSH_HOME>\unsloth-mcp),升级无需先停用插件

与 Unsloth 官方 CLI 的关系(unsloth start dsh)

Unsloth 官方 CLI 自带一组面向编码 agent 的命令,其中就包括 DeepSeek Harness:

unsloth start {claude|codex|openclaw|opencode|hermes|pi|dsh}

unsloth start dsh 做的是反方向的事:它把 DSH 的默认模型指向正在运行的 Unsloth 服务 (写 <DSH_HOME>/settings.yaml 里的 llm-pi-ai.providers.unsloth, 配 baseURL=<base>/v1、apiKeyEnv=UNSLOTH_API_KEY,并把 agent-default-model 设为该模型)。 换句话说:unsloth start dsh 让 DSH 用 Unsloth 当大脑;本插件让 DSH 把 Unsloth 当工具。

两者不冲突,可以同时用。本插件额外把官方 CLI 的能力面接成了原生工具,包括 unsloth studio run|stop|verify-install、unsloth train --dry-run、 unsloth export、unsloth list-checkpoints。

其余子命令与参数请以 CLI 自身为准(unsloth --help、unsloth <cmd> --help)—— 本插件的参数表就是照着它核对的,CLI 升级后如果有出入,以 CLI 为准。


与 unsloth-mcp/ 的关系

本插件的 MCP 服务源码与工作区里的独立版同源:

位置 用途
G:\DSH\DSH_workspace\dsh-unsloth\server\unsloth_mcp_server.py 随插件分发的那一份(自包含,安装即用)
G:\DSH\DSH_workspace\unsloth-mcp\server.py 独立/CLI 版,配 mcp_selftest.py 等调试脚本一起用

两者改动请同步。完整实操手册(数据集构建 → 下载 → 导入 → 训练参数 → 训练 → 导出 → 推理)见 G:\DSH\DSH_workspace\unsloth-mcp\docs\Unsloth-微调全流程实操手册.md。

ZCode 接入

本插件同时可挂到 ZCode:清单在 .zcode-plugin/plugin.json,复用同一份 server/unsloth_mcp_server.py, 工具名为 mcp__plugin_dsh-unsloth_unsloth__<tool>(20 个)。差异与装卸步骤见 ZCODE.md。

License

MIT