DeepSeek-V4-FlashのIQ2XXS版をDwarfStar4の2ノードで起動し、オーケストレーションとコーディングを分けて評価しました。Step-3.7-Flashの単一モデル構成で改善した後の検証です。AIシステム開発で使うローカルエージェントの役割分担を見ています。

TGは31.7-35.8t/sでした。Step-3.7-FlashやQwen3.6-27B-EAGLEに比べ、長いコードを書かせるには待ち時間が大きく感じます。開発初期の1ショットは10-20分でしたが、完走するようになった最近の処理はTG100でも60-70分です。出力は良い印象でもツールが不安定なため、軽量workerのspeculative decodingと組み合わせる案を考えています。

DwarfStar4/DeepSeek-V4-Flashをctx 44kのorchestrator、Qwen3.6-27Bをctx 144kのworkerにした構成は使いやすい印象でした。単体モデルのagent化が進むDwarfStarのcommitが増えたら、再度確認する予定です。

検証の目的

orchestrator/planner/coder/tester/reviewer/integratorの各ロールにモデルを割り当てます。orchestratorがターンごとに次の作業を判断します。

orchestratorでは、長い文脈のprefix cacheとctx windowのローリングを重視します。cache hitを保ちながら意味と構造を維持する役割で、workerほど生成速度だけが支配的ではありません。

構成

項目内容
ModelDeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf
RuntimeDwarfStar4 (ds4-server)
GPUNVIDIA RTX PRO 6000 Blackwell Max-Q 96GB x 2
Node APID 5435 / GPU0 / port 8001
Node BPID 5543 / GPU1 / port 8002
VRAM各 95.3 GiB / 95.6 GiB 使用
Host RAM各 ~83.5 GB
Context98304
Balancingオーケストレーション層で起動した2ノードへ分散

2つのQuadletユニットは、--portとGPU割り当てだけを変えています。

  [Unit]
Description=familiar orchestrator backend (DwarfStar 4 / DeepSeek V4 Flash) node-a
After=network-online.target
Wants=network-online.target

[Container]
ContainerName=ds4-node-a
Image=registry.home.arpa/dwarfstar4:ad0209f
Pull=always
Network=host
AddDevice=nvidia.com/gpu=0
Volume=/mnt/data/models/.../snapshots/<rev>:/model:ro
Volume=/mnt/data/models/.../kv_cache:/kv
Exec=-m /model/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf \
  --ctx 98304 --host 0.0.0.0 --port 8001 \
  --warm-weights --kv-disk-dir /kv/node-a --kv-disk-space-mb 4096 \
  --trace /kv/trace.node-a.log

[Service]
TimeoutStartSec=900
TimeoutStopSec=30
Restart=on-failure
RestartSec=30
  

nvtopで各プロセスが別GPUを使い、それぞれ約96GBのVRAMを確保していると確認しました。

nvtopでGPU0とGPU1にDwarfStar4のds4-serverプロセスが1つずつ載り、各GPUのVRAMをほぼ使い切っている画面
DwarfStar4を2プロセス起動し、GPU0とGPU1に1ノードずつ割り当てた状態。decode中は片側だけが99%まで上がる瞬間もある。

実測結果

生成スループット

decodeは31.7-35.8t/sでした。ツール応答後のTHINKINGと長い再計画では約35.7t/s、prefillは227-241t/sです。

観測時はGPU1が2302MHz/240W/99%でdecodeし、GPU0は180MHz/13Wで待機していました。逐次依存があるターンは片側に寄り、2ノードの効果は並行ターンやworkerがある場合に出ます。暑い時期に交互に使える点は良いと感じました。Broadcomの10GbE NICはlink downでも熱があり、Realtek 8127だったと思うNICは低温ですが、帯域を使い切るとSSHが不安定でした。

GrafanaのDCGM GPU MonitoringでGPU1が100%使用率と300W近くの電力を示し、GPU0は低負荷で待機している画面
DCGMで見たGPU占有。2ノード構成でも、逐次依存が強いターンでは片側GPUだけがdecodeを担当する瞬間がある。

長い実装を出すworkerに使うと、1リクエストの待ち時間が大きくなります。

オーケストレーション結果

1セッション、3ターンの集計です。

指標値
orchestrator 判断回数3
planned worker5
dependency block0
worker failure rate33.3%
recovery2

5workerを計画し、1workerが失敗、再計画が2回ありました。replan-t2はfail、replan-t3はcapacityと依存でblockです。DAG構築、依存解決、再計画は動いていました。

Familiar Orchestrator Decisionsダッシュボードでorchestrator判断3回、planned worker 5、worker failure 33.3%、recovery 2を表示している画面
Familiar Orchestrator Decisions。3ターンで5ワーカーを計画し、failとcapacity blockを再計画として扱えている。

Chat DAGでも、user requestからplanner/coderへ分岐し、結果が戻る流れを確認できました。

aichatのマルチエージェント実行ログ、生成されたDjangoモデルファイル、git commit一覧、GrafanaのFamiliar Chat DAGを横に並べて確認している画面
作業画面全体。左でfamiliarの会話と生成コミットを見ながら、右のFamiliar Chat DAGでorchestratorからworkerへ分岐する流れを確認している。

ツール呼び出し

指標値
tool call 総数65
failed6
failure rate9.20%
distinct tool13

read_fileは30回、write_fileは11回、directory_treeとshell_execは各5回でした。失敗記録はwrite_fileが2回、directory_treeが2回、shell_execが1回、その他が1回です。読み取りは書き込みの約3倍でした。

失敗には独自ガードや論理判定の偽陽性も含みます。ツール自体の失敗率としては使わず、呼び出し量の参考にします。

Familiar Tool Callsダッシュボードでtool call総数65、失敗6、failure rate 9.20%、distinct tool 13を表示している画面
Familiar Tool Calls。read_fileが30回で支配的で、write_file、directory_tree、shell_execに失敗が出ている。

実際に生成された成果物

課題はDjangoの25ドメインモデルを、スキャフォールドからapps/core/models.pyへ実装するものでした。コミットa38864bの1ファイル、差分+861 -0です。

最初のRestaurantGroupを抜粋します。

  from django.db import models
from django.utils.translation import gettext_lazy as _


# ──────────────────────────────────────
# 1. RestaurantGroup
# ──────────────────────────────────────

class RestaurantGroup(models.Model):
    name = models.CharField(max_length=200, verbose_name=_("name"))
    slug = models.SlugField(max_length=200, unique=True, verbose_name=_("slug"))
    description = models.TextField(blank=True, default="", verbose_name=_("description"))
    website_url = models.URLField(blank=True, default="", verbose_name=_("website URL"))
    contact_email = models.EmailField(blank=True, default="", verbose_name=_("contact email"))
    contact_phone = models.CharField(max_length=50, blank=True, default="", verbose_name=_("contact phone"))
    is_active = models.BooleanField(default=True, verbose_name=_("active"))
    created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("created at"))
    updated_at = models.DateTimeField(auto_now=True, verbose_name=_("updated at"))

    class Meta:
        verbose_name = _("restaurant group")
        verbose_name_plural = _("restaurant groups")
        ordering = ("name",)

    def __str__(self):
        return self.name
  

gettext_lazy、blank=Trueとdefault=""、Metaのverbose_name/ordering、__str__が揃い、25モデルで大きなぶれはありませんでした。Qwen3.6でも近い出力は得られるため、TG100超と30台の待ち時間も含めて選ぶ必要があります。

生成されたDjangoのapps/core/models.pyでRestaurantGroupモデルのフィールド、Meta、__str__を確認しているエディタ画面
生成された`RestaurantGroup`モデル。25モデルのうち1つ目で、Django modelとしての基本要素は揃っていた。

観測された失敗モード

再計画のplannerで、速度とは別に次の失敗がありました。

  invalid tool call returned as assistant text finish=stop
  [text_len=1864 saw_start=1 saw_end=1]
  

plannerは新しい成果物を宣言しないと判断し、write_fileのcontent内にwire protocolのXML宣言を入れました。saw_start=1 saw_end=1を検出しても、tool callではなくassistant textに戻っています。

  <...DSML...tool_calls>
<...DSML...invoke name="write_file">
<...DSML...parameter name="content" string="true"><familiar wire=....
    <thought>Re-planning pass: ... No deviations requiring corrective scope. ...</thought>
  

本来トップレベルに置く文書が引数内へ入り、パーサーが文脈を確定できなかったと考えています。

考えられる要因です。

  • モデル挙動: 再計画時に成果物宣言とツール呼び出しの境界を取り違える
  • パーサ厳格性: 入れ子の構造化マーカーを安全側にテキスト扱いする

DeepSeekの検証はまだ少なく、XMLへの影響は未確定です。Qwen系ではXMLのwire protocolで誤りが増え、TOMLにすると減った一方、XMLを学習した利点も失う印象でした。HTML方式も、学習データに多い構造として今後の候補です。

現時点の評価

約34t/sは長い実装を書くworkerには遅く感じます。短い判断を出すorchestrator、または緩いライセンスを活かす蒸留データ元として使う案です。

今回のDAG、依存解決、再計画と生成物は良好でした。IQ2XXSでも動いており、以前はGLM-5.1のsmol-IQ2KSも長く使いました。経験上、100B以下のQ4/5で崩れる場面もあります。量子化の評価はcalibrationとPPLにも依存します。

再計画のtool-call-as-textは、パーサーとモデルの組み合わせの課題として残ります。XMLへ引かれる可能性があります。

最近のcommitでも再検証しましたが、今回のfamiliarのorchestratorにはStep-3.7-Flashの方が使いやすい印象でした。