DeepSeekハーネス(dsh):インストール、ヘッドレス実行、3モデルベンチマーク
- カテゴリ
- AIとローカルLLM
- 公開日
- 2026年8月18日
- 更新日
- 2026年9月16日
- 著者
- Jacob Lloyd — プロジェクト完了後、AIの支援を受けて執筆
- 読了時間
- 約23分で読めます
かんたんに言うと: DeepSeekは無料のオープンソース「コーディングエージェント」をリリースしました。これはClaude Codeのように、プロジェクトを読み取り、ファイルを編集し、コマンドを実行してくれるプログラムです。この記事では、私がLinux PCにそれをインストールし、自動起動するように設定し、DeepSeekのクラウドモデルと自分のハードウェア上のモデルの両方を指定し、5つの小さな実際のコーディング作業でテストした方法を紹介します。15回の実行はすべて成功し、クラウドでの実行費用は数セントで済み、いくつか鋭いエッジもあります。
6秒でファイルが作成され、プログラムが実行され、答えが出力され、終了コードは0。これが、私が最初に与えたタスクに対してDeepSeek Harness(dsh)が行ったことです。DeepSeekは2026年8月13日にこれをリリースしました。MITライセンスのコーディングエージェントで、「すべてはプラグインである」という一つの考え方に基づいて作られており、モデルアダプター、ツール、サンドボックス、エージェントループ自体も含まれます。私は同じ週にインストールし、DeepSeekのクラウドモデルと自分のGPUマシン上のモデルを指定して、小さなタスクスイートを実行しました。ここでは、それに何が必要で、いくらかかり、どこでつまずいたかを紹介します。
要約
- 概要: Claude Code級のエージェント(ファイルの読み書き、シェルコマンドの実行、計画の維持、サブエージェントの生成)で、npmパッケージとして提供されています。
127.0.0.1:3080でWeb UIが利用でき、答えを1回出力して終了するヘッドレスモードも備えており、これがスクリプト向けに作られた部分です。 - コスト: ソフトウェアは無料です。私の5タスクのベンチマークは、ピーク時の料金でV4-Flashでは約3セント、V4-Proでは約7セントかかり、ローカルモデルでは無料でした。
- 結果: バージョン0.1.0-rc.7で、V4-Flash、V4-Pro、ローカルのGemma-4-26Bの3つすべてで15回中15回合格し、スイート全体で43秒から56秒でした。実際の雑用(290ページのウェブサイトのビルドとリンクチェック)では、頼まれてもいないのに私のランブックが古くなっていることも指摘しました。
- 必要なもの: Node.js、およびDeepSeek APIキーまたは任意のOpenAI互換サーバー。私は両方を使いました。
- 注意点: これは開発者向けプレビュー版です。READMEにはバージョン間で動作が壊れると警告されているため、バージョンを固定し、アップグレード後に再テストしてください。
2026年9月16日更新: ここに記載したテストは8月時点で0.1.0-rc.7を使用して実施されました。その後私の環境では0.1.5-rc.1へとアップデートされており、こちらのREADMEにはSDKやACPプロファイルに関する記述も含まれています。また2026年9月9日付で、本記事で比較対象として用いていた別のコーディングエージェントであるReasonixも私の環境から撤去しました。そのため現在では、かつての比較結果は文末にある簡単な歴史的補足情報としてのみ残っています。
利用方法:基本から上級まで
手順1から3を行うことで、約10分程度で実際に動作するエージェントが完成します。手順4および5を実施すると、他のソフトウェアからも呼び出せるようになります。
最終的に得られるもの
私が実際に使っているのはヘッドレスモードです。プロジェクトフォルダーの中から利用します。
$ cd ~/scratch/dsh-demo
$ dsh --profile headless "Create fizz.py that prints FizzBuzz for 1..15 and run it; reply with the program output only."
1
2
Fizz
4
Buzz
…
FizzBuzz
$ echo $?
0
3重のバッククォートはdsh独自の仕様で、返答内容をMarkdownのコードブロック内に記述しています。また、起動したフォルダー外には一切書き込みを行いません(デフォルトの権限モードは workspace-write です)。標準出力には最終的なメッセージのみを表示し、各実行内容は保存されるため、後でWeb UIを開いてツール呼び出しの履歴やトークン数などを確認することも可能です。
最も良い証拠となったのは、単なるお遊びではなく実際の作業でした。このウェブサイトのソースフォルダーを対象に、プロジェクトの運用マニュアルを読み取り、ビルドやリンクチェックを実行し、何の編集や公開もせずに結果を報告するよう指示しました。53秒後にはマニュアルを読み取り、適切なコマンドを実行した上で、290ページ・1,752枚の画像があり、壊れたリンクは存在せず、ビルドに要した時間も正確に報告してくれました。さらに、マニュアルには「288ページ」と記載されている点にも気付き、その差異を指摘してくれたのです。こうした些細な作業こそ、今では何の迷いもなくdshに任せられるのです。
ブラウザUIは2026年時点の標準的なレイアウトとなっており、左側にセッション一覧、中央にチャット画面、モデル設定用のページも用意されています。良い習慣としては、APIキーを設定ファイルではなくこの設定ページに貼り付けることです。
手順1:インストール(2分程度)
これは1つのnpmパッケージにすぎません。私はエージェント用ツール用に専用のNodeのプレフィックスを設定しており、そうすることでシステムツリーに何も追加されなくなっています。私のように不変性が保たれているFedoraデスクトップ環境では、これが唯一適切な方法です。通常のグローバルインストールでも同じコマンドを使用します。
npm install -g @deepseek-ai/dsh
dsh --version # 0.1.0-rc.7 when I benchmarked it
dsh web # starts the UI, prints http://127.0.0.1:3080
指定されたURLにアクセスし、設定 → モデルへ進んでDeepSeekのキーを貼り付けて保存してください。そうすると ~/.dsh/.credentials.yaml が作成され(パーミッションは0600)、再起動せずにすぐにモデルが利用可能になります。スクリプトで処理したい場合でも、このファイルは単なるYAML形式のマッピングとなっています(DEEPSEEK_API_KEY: sk-…)。私は既存のサービスが読み込んでいる環境変数ファイルから情報を取り出して設定したため、キーがシェルの履歴やユニットファイルに一切残らないようにしています。
先に進む前に知っておくべき点が2つあります:
- テレメトリはデフォルトで無効です。
DSH_TELEMETRY_MODEが設定されていない場合、テレメトリ機能はオフになります。公式のマーケティング文面ではなく、実際に同梱されている設定内容を確認したところ、OTLPエクスポーター自体は存在しますが有効化されていませんでした。 - サンドボックス機能は実装されていますが制限付きです。 デフォルトモードでは書き込み操作が起動元のフォルダ内に限定されます。読み取り操作には制限がありませんし、ドキュメントにもその点が明記されています。本格的な作業を行う際はホームフォルダから起動しないようにし、また機密情報が含まれるフォルダを指定することも避けてください。
手順2:サービスとして実行する
ウェブUIは長時間実行されるNodeプロセスです。ログイン時に自動的に起動し、ターミナルを必要とせず、ループバックインターフェースのみにバインドされるようにしたかったのです。systemdの--userオプション付きユニットを使えば、それが実現できます。
# ~/.config/systemd/user/dsh-web.service
[Unit]
Description=DeepSeek Harness web UI (dsh web) on 127.0.0.1:3080
After=network.target
[Service]
WorkingDirectory=%h
Environment=DSH_HOME=%h/.dsh
# Use the path from `which dsh`. systemd does not allow comments at the end of a line.
ExecStart=/usr/local/bin/dsh web --host 127.0.0.1 --port 3080
Restart=on-failure
RestartSec=3
[Install]
WantedBy=default.target
systemctl --user daemon-reload
systemctl --user enable --now dsh-web.service
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:3080/ # 200
WorkingDirectoryという設定項目でUIのデフォルトのワークスペースのルートディレクトリを指定できますが、それでも実際に入力する前にユーザー自身がワークスペースを選択する必要があります。これは良いデフォルト設定だと思います。また、CLIでは--host 0.0.0.0の指定も受け付けてくれません。開発者側によると、すべてのインターフェースにバインドすることは「意図的にまだサポートしていない」とのことです。このUIにはログイン機能自体が存在しないため、私もその判断に賛同します。他のマシンから利用したい場合は、認証機能付きのリバースプロキシを設置するか、私が行っているようにリモートデスクトップ経由でホスト側のブラウザを使うのが良いでしょう。
ステップ3:YAMLファイル1つでモデルを管理し、ホットリロードも可能
~/.dsh/settings.yamlにはデフォルトのモデルや追加のプロバイダー情報が記載されています。dshは次回のリクエストの前にこのファイルを再読み込みするため、再起動や再ログインの必要はありません。私の設定例は以下の通りです:
agent-default-model:
provider: deepseek-official
model: deepseek-v4-flash # or deepseek-v4-pro
llm-deepseek:
reasoningEffort: high # off | low | high | max
# A local OpenAI-compatible server (mine is llama.cpp-based on a GPU rig).
llm-pi-ai:
providers:
local-rig:
displayName: Local GPU rig
apiKeyEnv: LOCAL_RIG_PLACEHOLDER_KEY # a reference, not a value
api: openai-completions
baseURL: http://my-gpu-rig:1234/v1 # your server's address
defaultContextWindow: 65536
models:
- id: unsloth/gemma-4-26B-A4B-it-qat-GGUF/gemma-4-26B-A4B-it-qat-UD-Q4_K_XL
name: Gemma 4 26B-A4B (rig)
2つの点でそれぞれ10分ほど手間取りました:
apiKeyEnvには実際の値を記載せず、参照名のみを指定します。 dshは.credentials.yamlまたは環境変数から該当する値を取得します。キーの不要なローカルサーバーでも、OpenAI互換のクライアントがビーアートークンを要求するため、何らかの認証情報を参照させる必要があります。そのため.credentials.yaml内に任意のダミー値を指定しておきます。- プロバイダーID(上記の
local-rig)は、一度セッションで使用されれば変更不可となります。名前を変更したい場合は新しいプロバイダーを追加する必要があります。
このファイルがすべての設定インターフェースとなるため、「dshをローカルモデル用に切り替える」という操作もわずか2行の編集で済み、どんなスクリプトや他のエージェントでも実行可能です。私はこれを利用して、簡単なタスクは無料のローカルモデルに、難易度の高い問題はV4-Proに割り当てています。
手順4:ご自身のソフトウェアから呼び出す
公式パッケージにはターミナルベースのUI(TUI)は存在しません。npm上にはサードパーティ製のTUIプラグインもありましたが、8月時点では作成から4日しか経っておらず、workspace:*に関する依存関係に不具合がありました。家族用サーバー上で、未検証かつシェルアクセス権を持つパッケージを実行するつもりはありません。そこで私は自身のチャットアプリにdshを組み込む際、公式パッケージが提供している機能のみを利用しました。
- 固定された引数リストを用いてヘッドレスモードでジョブを実行する。私のサーバーでは
dsh --profile headless "…"という形でタスクが単一の引数として渡され、シェルは使用されません。そのため、; rm -rf /を含むような内容も単なるテキストに過ぎません。一度に1つのジョブのみ実行され、最終的な結果の履歴も少しだけ保持されます。 settings.yaml内のagent-default-modelを書き換えることでモデルを切り替えられる。再起動の必要はありません。- 必要に応じてWeb UIをiframe内に埋め込める。フレームをブロックするようなヘッダーは一切送信されません。
真似しておくべき唯一のルールとしては、これらすべてをご自身のアプリケーションの管理者ログイン機能の背後に隠しておくことです。ヘッドレスモードでのジョブ実行とはつまり任意のコードを実行することに他ならないため、「タスクを実行する」という操作を、シェル利用時と全く同じように扱うべきなのです。
ベンチマーク:5つのタスク、3つのモデル、15/15
これは科学的な検証というわけではありません。実際にコーディングエージェントに任せたいと思うような小さなタスクを5つ用意し、それぞれを新しい空のフォルダー内で実行させ、スクリプトによって以下の点を確認しました:ファイルが存在して正常に実行できるか、テストファイルを一切触らずにテストが通るか、名前変更後に古い名前への参照が一切残っていないか。実際にかかった時間には、約7,500トークン分のシステムプロンプトも含まれています。トークン数はdshのセッションログから得た数値です。
| タスク | V4-Flash | V4-Pro | Gemma-4-26B(ローカル、RTX 5090搭載マシン) |
|---|---|---|---|
| 「PONG」と返答する(起動+1回の呼び出し) | ✅ 2.1秒 | ✅ 2.8秒 | ✅ 13.2秒* |
| FizzBuzzを記述して実行する | ✅ 5.3秒・ツール2回使用 | ✅ 8.4秒・ツール2回使用 | ✅ 4.9秒・ツール2回使用 |
| ユニットテストが通るようにバグを2つ修正(テストファイルは触らず) | ✅ 11.7秒・ツール8回使用 | ✅ 15.8秒・ツール7回使用 | ✅ 10.4秒・ツール8回使用 |
| 6つのモジュールからなるコードベースを要約する(150語未満) | ✅ 8.9秒・ツール9回使用 | ✅ 10.9秒・ツール7回使用 | ✅ 12.1秒・ツール7回使用 |
| 3つのファイルおよびテスト内の関数名を変更し、問題なく動作することを確認する | ✅ 15.1秒・ツール14回使用 | ✅ 18.2秒・ツール12回使用 | ✅ 12.2秒・ツール11回使用 |
| 合計経過時間 | 43秒 | 56秒 | 53秒 |
| トークン数(入力ミス/キャッシュヒット/出力) | 42.6k / 136k / 4.5k | 41.4k / 107k / 3.2k | 40.5k / 237k / 5.6k |
| ピーク時の料金(オフピーク時は半額) | 約0.027ドル | 約0.072ドル | 0ドル(電気代のみ) |
*マシン上でモデルが初めて読み込まれた直後の呼び出しです。その後のタスクでは高速な反応が見られました。バージョンは0.1.0-rc.7、日付は2026年8月18日です。料金は同日付のDeepSeekの料金ページに基づいています:Flashモデルはキャッシュヒット時0.014ドル、ミス時0.44ドル、出力時1.32ドル/100万トークン、Proモデルはそれぞれ0.044ドル、1.32ドル、3.96ドルとなります。ベンチマーク用のスクリプトは一度きりで使用した後削除されたため、要約内容が正しく単語数をカウントしていたかどうかは確認できません。
この表から読み取れる点は以下の通りです:
- プロンプトキャッシュがコストを抑えています。各タスクにおいて約7,500トークン分のシステムプロンプトが必要となりますが、最初の処理以降はほとんどがキャッシュヒットとして計算され、その料金はミス時の約3%程度に抑えられています。複数ステップからなるタスクでもコストが低く抑えられるのは、この仕組みのおかげです。
- V4-Proでは同じ結果を得るためにより少ないツール呼び出しで済みました。例えば関数名変更時には12回に対しFlashは14回でした。今回のテスト群においてはFlashの方が速く、かつコストも約3分の1だったため、私のデフォルト選択肢となりました。
- ローカルモデルも十分な性能を示しました。Gemma-4-26Bはミックスド・オブ・エキスパーツ型モデルで、実際に使用されるパラメータ数は4B、Q4量子化版であり、llama.cppを介して2台のRTX 5090上で動作します。すべてのタスクを無事にこなしました。キャッシュされたコンテキスト量はFlashより多い(237kトークン対136kトークン)ものの、経過時間は十分に競争力がありました。これまで単なる試し用だったローカルモデルが、実用的な選択肢となった最初の例と言えるでしょう。ただし5つの小さなタスクだけでは40ファイル規模のリファクタリングの可否を判断するには不十分です。
最終的に私が定めた判断基準は以下の通りです:単純な作業やスクリプト化可能なタスクにはFlash、より少ないステップで適切な結果が求められる場合にはV4-Pro、再実行コストが低く社内環境だけで完結できる作業であればローカルモデルを利用することにしています。
面白いテスト:私のためにおもちゃを作ってみてください
また、自由形式の創造的課題に対してどのような反応を示すかも確認したかったのです。課題内容は「このサイトのロゴをインタラクティブなピクセルアート版に作り直してください。バニラJSを使用し、どこにでも埋め込める形にすること。マウスオーバー時には何らかの物理的な反応が起き、クリック時には面白い動作が現れること。外部ライブラリは一切不要。自分でテストしてみてください」というものです。実際に生成された結果はこちらで、現在公開されています(その後、ピクセルアート・ウィジェット対決において他の2つのKimiによる生成物と競い合いました)。
prefers-reduced-motionの設定にも対応しています。
実際の経緯は以下の通りです:
- 第1回試行(V4-Flash):10分間ループし続け、ファイルは一切生成されませんでした。 課題では手描きまたはプロシージャル生成によるビットマップのどちらでも構いませんでした。しかしモデルは40×40サイズのビットマップを手描きで作成しようとし、無限ループに陥ってしまいました。セッションログには何百行にもわたって
################や....が並び、私の設定したタイムアウトで処理が中断されました。費用は約2セント程度でした。教訓として:モデルに頭の中でピクセルを手描きさせてはいけません。 - 第2回試行(V4-Flash、課題内容を「幾何学的形状からラスター化せよ、ビットマップは不可」に変更):25分かかり、すべてが完成しました。 モデルは100回のステップ、201回のツール呼び出し、172,000個の出力トークン(そのうち123,000個は推論用)および16.3百万個のキャッシュ読み取りトークンを使用し、ピーク時レートで約49セントの費用がかかりました。399行からなる
ll-pixel-logo.jsファイルや、グローバルAPIおよびdata-属性を備えた設定項目、デモページ、README、ラスター化処理用のNode単体テスト、さらには要望されていなかったものの3種類のサイズでデモ画面をスクリーンショット撮影するPlaywrightスクリプトまで作成してくれました。READMEの仕上げ中に25分の制限時間に達したため、実際は作業が完了していたにもかかわらずタイムアウトという終了コードが返されました。終了コードは場合によって正しくないこともあります。 - 出来上がったデザインについて: 輪と2つの斜めのL字型からなるロゴは一見すると元のロゴに見えますが、実物よりも少し太く、よりZ字型に近い印象です。実際に使用する前にはそのシアー定数を10分ほど調整する必要があるでしょう。私はそうしませんでしたので、現在公開されているのは未調整の状態です。
- 本サイトへの埋め込みも1行だけで済みました。 サイトのCSP設定が
script-src 'self'となっており、このウィジェットはネットワークリクエストを一切行わないためです。課題でもその点が求められており、モデルはそれに従いました。 - 追加のコストとして: dshは生成したファイルの権限を0600に設定していました。私のデプロイ処理でもそのままウェブホストへ反映されたため、本番サイトでは
chmod 644を実行するまで403エラーが発生していました。dshワークスペースからコピーしたファイルの権限は必ず修正する必要があります。
注意点
- これは開発者向けプレビュー版であり、READMEにもその旨が記載されています。 rc.6の3日後に
0.1.0-rc.7をインストールしました。プロファイルや設定キー、プラグインの構造などは今後変更される可能性があります。自動化処理ではバージョンを固定しておき、アップグレードのたびにスモークテストを再実行することをお勧めします。 - ヘッドレスモードでは処理が終了するまで何も出力されません。 stdoutに一切データが流れないため、長時間かかるタスクが「フリーズしている」ように見えることがあります。セッションログ(
~/.dsh/sessions/…/session.jsonl.zstd、zstdで圧縮されたJSONL形式)を確認するか、Web UIで状況を確認してください。終了コード0は「処理が完了した」ことを意味するだけで「タスクが成功した」わけではないので、実際の結果も確認する必要があります。 - ヘッドレスモードには
--modelフラグがありません。 使用されるモデルはsettings.yamlで指定されており、そこを編集するかWeb UIから変更できます(設定はホットリロードされます)。 - キー不要のローカルサーバーには仮の認証情報が必要です。 またプロバイダーIDは一度設定すると変更できません。手順3をご参照ください。
- Web UIでは絶対パスが使用されています(
/assets/…、/api)。そのため、独自のリバースプロキシの下でサブパスとしてマウントする場合はパスを書き換える必要があります。代わりにUIを埋め込むか、別のホスト名を割り当てる方が良いでしょう。 - UIの言語設定はブラウザに従います。 同梱されている index.html には
lang="zh-CN"と記載されており、最初に表示されるのは「内部テスト通知」ダイアログです。「続行」をクリックすると、その後は英語で表示されました。 - インストール時には postinstall スクリプトが実行されます(node-pty、koffi、protobufjsなど)。npmからもその旨の警告が出ます。悪意のある処理は見受けられませんでしたが、ネイティブコードがインストール先ディレクトリ内でコンパイルされるため、システム標準のパスではなく専用のプライベートなパスを利用することをお勧めします。
- Nodeのバージョンについて: rc.7ではNode 22.19以降または24が必要で、古いLTSリリースでは実行できませんでした。インストールするバージョンのREADMEもご確認ください。
歴史的な経緯:dshとReasonixの関係
8月の頃、私は第三者が開発したターミナルエージェントであるReasonixと並行してdshも利用していました。使い分け方は単純で、Reasonixはエージェントと対話したい時に起動するTUI版のツールであり、一方dshは他のソフトウェアから呼び出される際に用いるツールでした。私は2026年9月9日に自分の環境からReasonixを撤去し、現在ではdshが私のメインのコーディングエージェントとなっています。両者から選ぶ場合、大きな違いとしては、dshにはスクリプト作成が容易な「1コマンドで1回答・1終了コードを返すヘッドレスモード」があるのに対し、TUI版であるReasonixはキーボードの前に人間がいることを前提としています。
これにより私が得られるもの
ヘッドレスモードは、他のソフトウェアから呼び出されるコーディングエージェントにふさわしい形態です。つまり、1回のコマンドで1つの応答が返され、終了コードも得られ、監査可能なログも残ります。モデルをYAMLで指定することで、呼び出し側のスクリプトがそのタスクに最適なモデルを選ぶことができます。すでにローカルのモデルサーバーを運用している場合は、同じ5つのタスクを試してみてください。API利用料として10セント分のクレジットと、一時的な作業用フォルダーさえあれば、それだけで準備は整います。
関連記事:DeepSeek Everywhere(DeepSeekをClaude Codeやエージェントスタックに組み込む方法)、Kimi K3をコーディングエージェントとして利用する(同じ5つのタスクを9月にdshで再実行した事例)、bench-llmおよびその後継であるCrucibleForge(私がここで行った以上に本格的にローカルモデルのベンチマークを行うツール)、そしてReasonix(dshを使う前に私が利用していたターミナルエージェントで、現在は使用していません)。