DeepSeek-V4-Flash-Vision-ExpとV4.1-FlashをDeepSeek Harnessで使う
DeepSeek-V4-Flash-Vision-ExpとDeepSeek-V4.1-FlashをRTX PRO 6000 Max-Q 2枚のvLLMで動かし、DeepSeek HarnessをコンテナPodの中でフル権限で使った記録。自作agentを外してfamiliar-daemon、agent-gateway、ancestorの構成に作り直した経緯と、Vision-ExpでDjangoのドメイン層を実装させた実行の設定とengineログの数値をまとめる。
はじめに
familiarのagentの作り方を大きく変えた。
これまではgateway、agent、infraをすべて内包したモノリシックなfamiliarとして自作してきた。今回、agent部分をまるごと外した。代わりにDeepSeek Harness(以下dsh)をコンテナPodの中に置いて、フル権限で自由に動かす。
familiarはfamiliar-daemonとagent-gatewayの2つに分けた。推論バックエンドを管理するancestorは前からあったので、そのまま使っている。この3つでPodの中のdshを動かす仕組みになっている。
移植は、Codex Astraがリリースされたあと、性能チェックも兼ねて1週間ほどでやった。
familiarを作り始めた経緯と初期設計は、前回の記事にまとめている。この記事はその続きになる。
動画
dshをPodの中でフル権限で動かし、compute上のvLLMで推論させているところを動画にした。
1本目は、deepseek-ai/DeepSeek-V4-Flash-Vision-Expを公式のcheckpointのまま動かし、Djangoのドメイン層を実装させたもの。設定と数値は後半の「Vision-Expでの実行内容」にまとめている。
動画リンク: https://www.youtube.com/watch?v=KD-4jm46izk
2本目は、最近リリースされたDeepSeek-V4.1-FlashのEXL3 2.0bpwで別に撮ったもの。モデルはdiffbotが公開している量子化モデルを使っている。
動画リンク: https://www.youtube.com/watch?v=CBkIkCtIxJI
これまでのfamiliar
前回の記事の時点では、familiarはgateway、agent、infraをすべて内包したモノリシックな作りだった。中には、かなりいろいろなものを持たせていた。
- コンパクション
- メモリー
- サマライズ
- ロールごとのメモリー管理
- knowledge基盤の操作
- 独自ツール
- MCP。Goで書いていたので、
embedでMCPのソースを丸ごと埋め込んだりもしていた - OpenTelemetry、Vector、Prometheus、Grafanaへのobservability
- GrafanaとGraphQLで作ったwhat-ifやreplay
- Dagster assetsのpipeline
- shell実行を検証するコンテナの仕組み
- ツールのリカバリー
前回の記事で「本体より、ツールを作っていた」と書いたとおり、ローカルLLMが苦手なところを周りの仕組みで補う作業が中心だった。
DeepSeek Harnessに乗り換えた
きっかけはdshのpluggableな設計だった。これがすごく良かった。
プラグインもどんどん追加されている。最近は、何か実装する前に検索すると、欲しいものが見つかることも出てきた。

GrafanaとGraphQLで自作していたwhat-ifやreplayも、プラグインで解決できた。たとえばThoughtDAGは、LLMに渡るcontextをグラフで見て編集でき、分岐させて別の流れを試せる。dsh向けのプラグインとしても提供されていて、desktop側のdshではChatの隣のDAGタブで使っている。


プラグインはライブラリのような感覚で使えて、自分で作らなくても誰かが開発とメンテナンスをしてくれるのがありがたい。
3つのコンポーネント
agent部分以外を抜き出して、インフラ基盤の部分だけを移植した。役割はこう分けている。
| コンポーネント | 実装 | 役割 | 旧familiarとの関係 |
|---|---|---|---|
| familiar-daemon(famd) | Go | dshへの依頼(delegation)の受付、隔離したworkspace、状態の永続化、復旧、結果の回収、Podの管理 | familiarから分けた |
| agent-gateway | Go | dshやOpenAI互換クライアント向けの推論gateway。起動中のAncestorインスタンスを見つけて、公開モデルIDでルーティングする | familiarから分けた |
| ancestor | Rust | compute hostの推論サーバーの管理。presetから構成を作り、Podman Quadletとsystemdのuser serviceで起動、停止する | 前からある。そのまま使った |
famdが持つのは、agentの実行と、自分の運用イベントをNATSへ出すところまで。OpenAI互換の推論エンドポイントや、prompt、tool call、responseのcaptureは持たない。そこはagent-gatewayの担当で、captureは非同期でNATSに流す。OpenTelemetryなどのobservabilityも、agent-gatewayのeventを流用して実装した。
推論サーバーの起動と停止はancestorの担当で、famdに依頼を投げても推論サーバーが勝手に起動したり止まったりはしない。
今の構成
flowchart LR
subgraph desktop["desktop.home.arpa"]
CLI["famdctl"]
UI["dsh Web UI"]
end
subgraph compute["compute.home.arpa"]
FAMD["familiar-daemon<br/>control / launcher / finalizer"]
GW["agent-gateway"]
ANC["ancestor"]
VLLM["vLLM"]
RELAY["famd-egress<br/>inference relay"]
subgraph pod["runtime Pod"]
DSH["DeepSeek Harness<br/>Full access"]
WEB["Web relay"]
end
end
NATS[("NATS")]
CLI --> FAMD
CLI --> GW
CLI --> ANC
FAMD --> pod
ANC --> VLLM
DSH --> RELAY --> GW --> VLLM
GW -. discover .-> ANC
FAMD -. events .-> NATS
GW -. capture .-> NATS
UI -. "SSH tunnel<br/>pod forward" .-> WEB
compute.home.arpaでは、famdのcontrol、launcher、finalizerなどと、agent-gatewayがネイティブのサービスとして動いている。
famd-egressは、Podから見える推論の入口。Podの中のdshはhttp://famd-egress:8080/v1に推論を投げ、famd-egressがそれをagent-gatewayへ中継する。Quadletのコンテナで、root filesystemはread-only、capabilityもすべて落としている。
操作はdesktopのfamdctlから行う。依頼はdelegationとして投げ、受け付けられるとruntime Podができてdshが動き出す。Podの中身はdshのコンテナとWeb relayの2つで、dshはPodの中ではフル権限で自由に動かしている。フル権限にしている理由と注意点は、後半の「フル権限について」に書いた。
famdctlでの操作
famdctlはこういうコマンド構成になっている。
ksh3@desktop.home.arpa ~ % famdctl
famdctl [--json] [--config path] [--idempotency-key key] <command>
ancestor List, inspect, plan, ensure or stop Ancestor services
delegation List, submit, inspect, wait for, retrieve or cancel a delegation
session List, start, recover, observe or close a DSH session
events Stream lifecycle events, resuming with --after
artifact Inspect or download a verified artifact
pod List, start, stop, remove, drain or forward runtime Pods
dsh-local Prepare, sync and open the local DSH Web UI
workbench Alias for dsh-local open
workspace Initialize or locate the local work records and DSH mirror
gateway List public models
config Initialize or inspect saved settings
doctor Check configuration; --online probes supported service APIs
completion Print a bash or zsh completion script
Use famdctl <command> --help for details. Output is formatted for reading.
Add --json anywhere before -- for raw JSON responses and JSONL events.
Exit status: 0 success/waiting, 1 service/local/terminal failure, 2 usage error.
Root submit/run, status, wait, result and cancel are delegation shortcuts.
Save endpoints once with config init, then use alias fam=famdctl.
ancestorがancestor、gatewayがagent-gateway、delegation、session、events、artifact、podがfamdへの操作になっている。3つのサービスは接続先と認証情報を別々に持たせている。
Djangoのドメイン実装タスクを投げたときの操作の例。--detachで投げると受付だけ返ってくる。
ksh3@desktop.home.arpa ~/familiar-workspace % famdctl delegation submit --workflow django --detach /Users/ksh3/familiar-workspace/task/task.json
Work record: /Users/ksh3/familiar-workspace/workflow/django/2026-09-15/18-03-25
STATUS DELEGATION SESSION ACCEPTED
accepted del_W9hVQjDgA2zzXQ ags_NPoXgKU5IGYmAg 2026-09-15 18:04:17
Receipt only; execution is not confirmed.
Next: famdctl delegation wait del_W9hVQjDgA2zzXQ
Podの中のdshの様子は、pod forwardでcompute.home.arpa経由のトンネルを張ってブラウザで見る。
ksh3@desktop.home.arpa ~/familiar-workspace % famdctl pod forward del_W9hVQjDgA2zzXQ
http://127.0.0.1:13080/?token=<redacted>
Pod pod_EaTd58jSdfE2kA is forwarded through compute.home.arpa; press Ctrl-C to close the tunnel.
Web UIにはChatとTrajectoryのタブがあり、To-dosの作業計画や、Pod内の/workspaceのファイルを見られる。Podで動いたセッションはdesktopの~/familiar-workspace/dsh-local/Remote/にも同期されて、desktop側のdshからRemote / artifact_…として開ける。


compute-server側で、vLLMもPodも動いていないときのpodman psはこうなっている。
ksh3@compute-server:~$ podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
77af06a3024b registry.home.arpa/ml-foundry-mlflow@sha256:e0916a7bce42adc92f5b688e212ece81c0b1ce363e92eaf02b1118161f23cf3b mlflow server --h... 5 hours ago Up 5 hours mlflow
2144fc65532d registry.home.arpa/ml-foundry@sha256:df3d06efff1570a47085c8002d980d66085c01c69b5d07d5afab98c4f482c888 dagster api grpc ... 5 hours ago Up 5 hours dagster-user-code
381a9063ea00 registry.home.arpa/ml-foundry@sha256:df3d06efff1570a47085c8002d980d66085c01c69b5d07d5afab98c4f482c888 dagster-webserver... 5 hours ago Up 5 hours dagster-webserver
9df064d0e85b registry.home.arpa/ml-foundry@sha256:df3d06efff1570a47085c8002d980d66085c01c69b5d07d5afab98c4f482c888 dagster-daemon ru... 5 hours ago Up 5 hours dagster-daemon
c9849a9fd9a5 registry.home.arpa/famd-inference-relay@sha256:702149bdc55611ef25ba40d98c0181d55e9d786507ad5b991e17ccbc96bd4ed4 --upstream http:/... 17 minutes ago Up 17 minutes famd-egress
famd-egressが推論のrelay。famdのcontrolやagent-gatewayはネイティブのサービスなので、ここには出てこない。
DagsterとMLflowはml-foundry。以前のmodel-foundryを、これもagent-gatewayに合わせて作り直したもので、モデルだけでなく、趣味の投資用のML pipelineも追加した。

Vision-Expでの実行では、これに加えてancestorが起動したvLLMのancestor-deepseek-v4-flash-vision-expと、Podのdsh runner、dsh webが動いていた。Podの2つは同じfamd-dsh-runnerイメージで、--managedがdsh本体、--proxy-onlyがWeb relayになる。Podは127.0.0.1のポートを1つだけ公開していて、Web UIへはそこにトンネル越しでつながる。
Vision-Expでの実行内容
1本目の動画では、DeepSeek-V4-Flash-Vision-Expをcompute上のvLLMで動かし、Podman Podの中のdshにフル権限を渡して、Djangoのドメイン層を実装させている。モデルへのリクエストはホストの外に出ない。
構成
MODEL: deepseek-ai/DeepSeek-V4-Flash-Vision-Exp @ 6821d6ad3681a4b137b066b76094fa82ebd0a380
IMAGE: registry.home.arpa/voipmonitor/vllm:ds4-jovian-r9-5bea08859798
HOST: compute.home.arpa:8000 (engine) <- pod forward <- desktop.home.arpa (client)
POD: dsh runner, dsh web
GPU: NVIDIA RTX PRO 6000 Blackwell Max-Q ×2 (GPU 0,1 / 300W cap)
| 項目 | 設定 |
|---|---|
| context | 1M(max-model-len 1048576)、最大出力393,216 tokens |
| 重み | 公式checkpointのまま。FP8(e4m3、128×128 block)、expertはFP4、それ以外はbfloat16。追加の量子化はしていない |
| 並列 | TP2(tensor-parallel-size 2)、NVLinkなし |
| speculative decoding | DSpark fixed-probabilistic K3(3 token) |
| KV cache | GPU KVのみ、LMCacheなし |
| GPU memory | gpu-memory-utilization 0.968 |
| 同時リクエスト | 4(max-num-seqs 4) |
| batch | max-num-batched-tokens 4096 |
| reasoning effort | high |
| その他 | tool calling有効、vision有効、OpenAI互換のchat completions API |
vLLMのserviceのExecStartはこれ。env fileはancestorのactiveディレクトリから読んでいる。
ExecStart=/usr/bin/podman run --name=ancestor-deepseek-v4-flash-vision-exp --cidfile=%t/%N.cid --replace --rm --cgroups=split --network=host --init --sdnotify=conmon -d --ulimit stack=67108864:67108864 --device=nvidia.com/gpu=0 --device=nvidia.com/gpu=1 -v /mnt/data/hf/hub/models--deepseek-ai--DeepSeek-V4-Flash-Vision-Exp:/models:ro -v /mnt/data/hf/jit/ds4-vision-exp-jovian-r9:/cache -v /mnt/data/hf/tmp/ds4-vision-exp-jovian-r9:/container-tmp --env-file /home/ksh3/.local/state/ancestor/active/ancestor-deepseek-v4-flash-vision-exp.env --pull never --entrypoint=/usr/local/bin/lmcache-mp-wrapper.sh --ipc=host registry.home.arpa/voipmonitor/vllm:ds4-jovian-r9-5bea08859798 /usr/local/bin/serve-ds4-flash.sh
serving profileは、local-inference-lab/rtx6kproで公開されているDeepSeek-V4-Flash Jovian Judgement r9のVision向けspecをベースにした。gpu_memory_utilizationだけは、ドキュメントにある値(GPU KVのみなら0.975、LMCacheを使うなら0.970)ではなく0.968にしている。
entrypointはLMCacheのwrapper(lmcache-mp-wrapper.sh)を通るが、LMCACHE_MODEを設定していない。なのでhost側のtierは使われず、GPU KVだけの実行になっている。
同じRTX PRO 6000 2枚で、DeepSeek V4 Flash 0731とDSpark K5を測った記録は別の記事に書いている。モデルも設定も違うので、数字は並べて比べていない。
engineログの数値
約7分のengineログの範囲で、chat completionのリクエストは70件だった。
| 指標 | 値 |
|---|---|
| decode throughput(平均) | 180 tok/s(ピーク257.9 tok/s) |
| prefill throughput(prompt処理中の窓の平均) | 444 tok/s |
| DSpark draftの採択 | 53,246 / 72,615 tokens(73.3%)、depth 3での平均採択長3.20 |
| prefix cache hit rate | 87.5% → 98.0% |
| decodeだけの窓(平均) | 216.6 tok/s |
| prefillが混ざる窓(平均) | 156.3 tok/s |
prefix cache hit rateは、窓の中で87.5%から98.0%まで上がっていった。途中、新しいprefixが入ってきたところで3回下がっている。
decodeだけの窓とprefillが混ざる窓を比べると、同じengineの上でchunked prefillがdecodeを28%くらい削っている計算になる。
動画のdshのステータスバーには201 tok/s、cache hit 93%と出ている。これはクライアント側が別の期間、別の分母で数えている値なので、上のengineのカウンターと一致するものではない。
数字の注意点
数字はどれもengineログの10秒ごとの窓の平均で、TTFT、ITL、リクエストごとのlatencyは取っていない。token数の合計も、正確なカウンターではなく「rate×10秒」からの概算になる。
また、r9の公開値は600WのWorkstationカードで測られている。こちらは300WのMax-Qなので、そのまま比べられる数字ではない。
フル権限について
フル権限にしているのは、以前のfamiliarで一番苦しんだのが過剰なガード機構だったから。ガードのせいで負のスパイラルに陥り、品質がどんどん落ちていった。旧版の時点で、複雑なパイプなどのshellだけはコンテナ側でdry-runしてから実行する仕組みにして、ガードはなくしていた。
今年の3月頃と比べると、OSSモデルの性能はかなり上がっている。ds4、glm5.3-flash、qwen38-flash-nextは普通に作業で使っている。
とはいえ、制限なしで実行させる以上、破壊的な操作のリスクはそのまま残る。試すなら、隔離してスナップショットを取ってからにしてほしい。
所感
6ヶ月位自作agentを合間で作っていたけど、とても楽しかった。 モデル選定や実際に動かしたときの課題などもよくよく分かってMCP開発もずいぶんやってきた。 僕はできるだけOSSからコードを借りてきて、自分ではできるだけ書かないスタイルが好きだったけど、 AIコーディングのおかげでここ半年は車輪の再発明が楽しくて没頭していた。
dshはプラグインに対応していて、コミュニティもできてきている。1から作らなくても継続してメンテナンスされる状態で借りられるようになるのも、そう遠くないと思う。 それに、中国の技術力はすごくて、今もすごい勢いでいろんなツールが公開されている。なんというか場が盛り上がっているので、いろんな技術的恩恵を受けられるという考えもあって、自分で作っていたagentは捨てて、dshに載せ替えた。 ローカル環境でagentを動かすときの参考になればうれしい。
