DeepSeek V4 をローカルでロードでき、長い回答も返る。それでも coding agent がファイルを読まず、terminal command を実行しないことがあります。このとき「モデルのtool能力が低い」と決めるのは早すぎます。
tool loop には少なくとも、モデルの生テキスト、DSML parser、OpenAI-compatible response、client adapter、tool dispatcher、次ターンのhistoryという境界があります。同じ最小リクエストを一周させ、構造が最初に失われる場所を探すのが最短です。
会話成功では確認できない四つのこと
ローカル推論の smoke test で確認できるのは、主に「モデルをロードでき、textを生成できる」ことです。次の四点は別に確認する必要があります。
- モデルは宣言済みtoolを選び、正しいDSMLを出したか。
- server parserはDSMLを
tool_callsへ変換したか。 - clientは構造化eventを保持し、許可されたtoolへdispatchしたか。
- tool resultとassistant stateは次のrequestへ正しく戻ったか。
一つのUIメッセージ「ツールを呼び出せません」だけでは、このどれも特定できません。副作用のない単純なtoolを一つ宣言し、parser前のraw completion、server JSON、client event、実行記録、tool result、次requestを保存してください。共有する場合はtoken、実path、argument、repository contentを削除します。
| 最初の異常 | 読めるシグナル | 次の一手 |
|---|---|---|
| モデル出力 | invokeがない、wrapperやnameが壊れている | context短縮、required、同条件のartifact比較 |
| parser | 完全なinvokeがrawにあるのにtool_callsがない | vLLM versionとV4 parser/tokenizerを確認 |
| quant/runtime | 特定artifactだけload失敗、またはraw構造が変わる | 他条件固定でartifact/featureを一つ変更 |
| harness | server responseは正常だがtoolが動かない | adapter、permission、schema、call IDを追跡 |
| history | 1回目は成功し次ターンで400または反復 | assistant messageと再送historyを比較 |
DSMLが教えるのは「どこまで届いたか」
DeepSeek のV4公式model cardでは、通常のJinja chat templateではなく、専用のencoding実装でOpenAI形式のmessageをmodel inputへ変換し、completion textを解析すると説明されています。tool intentはraw output内で次のようなDSMLになります。
text<|DSML|tool_calls> <|DSML|invoke name="read_file"> <|DSML|parameter name="path" string="true">src/app.ts</|DSML|parameter> </|DSML|invoke> </|DSML|tool_calls>
coding agentがこのmarkupを直接処理するのではなく、serving layerが通常は構造化tool_callsへ変換します。したがって、raw outputに完全なinvokeがあるのに通常のcontentへDSMLが出た場合、parser境界を先に調べます。raw自体にstart wrapperがなければ、モデル生成またはprompt renderingと、parserのrecovery方針を分けて考えます。
vLLM #48931にはGPU不要のparser-level reproductionがあります。外側のstart markerがないinvokeは、対象pathで普通のcontentとして返り、tool_callsになりません。このtestはquant weightをロードしないため、その特定現象をquantだけで説明できません。
一方、#51914はV4-Flash-0731、vLLM 0.27.1、DSpark利用時にstart wrapperが誤った形になったという報告です。報告者はDSparkが原因とは断定していません。ON/OFFで同じrequest setを比較し、raw token列が変わるかを確認するのが妥当です。
Agentを外してparserを試す
まずstream=falseでserver responseを保存し、その後だけstreamingを有効にします。同じtool-required taskでtool_choice="required"と"auto"も比較します。vLLM #40801では、ある環境のauto + streamでDSML断片がcontentへ漏れ、requiredまたはnon-streamingで減る挙動が報告されました。issueはclosedで現行versionと同じとは限らないため、これは原因を絞るtoggleであり、恒久的な推奨設定ではありません。
container内部の実versionも取得します。現在のvLLM mainはDeepSeek V4 reasoningとDSMLを専用state machineで扱います。過去にはparameterの型、arguments wrapper、stream終端bufferなどの修正があり、#41240に条件が記録されています。新しいcommand lineを古いimageへコピーしてもparser実装は更新されません。
大きなclientを介さない観測gateは次の程度で十分です。
pythondef locate(raw, message): invoke = "<|DSML|invoke" in raw calls = message.get("tool_calls") or [] if invoke and not calls: return "parser boundary" if calls: return "client dispatch or replay" return "generation or prompt rendering"
これはDSMLを修復するparserではありません。誤ったmarkupを寛容に実行するのは危険です。

量子化を疑う条件を狭くする
公式V4-Flash artifact自体が、MoE expertにFP4、多くの他parameterにFP8を使うmixed precisionです。「quantizedだからtool callが壊れる」という分類は成立しません。artifact、encoding/tokenizer revision、runtimeが一致しているかが問題です。
vLLM #41604は、non-canonical V4 quantizationに期待されるscale_fmt metadataがなく、initializationで失敗するケースを報告しています。これは明確なruntime compatibility問題ですが、tool responseを解析する段階より前です。
生成品質を比較するなら、model revision、encoding/tokenizer、runtime build、parser flag、sampling、context、tool schema、prompt、可能ならseedを固定し、artifactだけを変更します。比較対象が同じvalid DSMLを出したのに、片方だけparsed responseを失うなら、最初の障害はquant bit数ではありません。
Harnessは2ターン目まで観測する
serverがtool_callsを返したら、client adapterが受け取ったnameとarguments、permission判定、dispatch、call ID、tool resultを確認します。finish reasonの扱い、tool alias、argumentsの二重wrapper、IDの付け替えだけでも実行は止まります。
1回目のtool実行後にHTTP 400になる場合、hosted APIの条件とlocal serverを混同しないことも重要です。DeepSeekのhosted thinking mode documentationでは、tool callを行ったassistant turnのreasoning_contentを後続requestへ完全に戻す必要があり、欠落すると400になり得ます。local OpenAI-compatible implementationが同じvalidationを行うとは限りません。返却messageとharnessが再構築したmessageをfield単位で比較します。
最小SDK loopでは2ターン完了し、同じendpointを使うcoding agentだけが失敗するなら、調査対象はclient normalization、permission、dispatch、historyです。quantを交換しても、この差分は説明できません。

再現matrixは一変数ずつ
順番に、non-streaming/streaming、required/auto、短い/長いcontext、concurrency 1/実運用負荷、公式artifact/候補quant、最小loop/完全なagentを比較します。vLLM #48089は、0.24.0の一環境でsequential baselineは正常、concurrency下で構造破損が増え、non-streamingにも残ったと報告しています。このrateを一般化せず、まずconcurrency 1で再現する理由として使います。
issueにはmodel repositoryとrevision、quant filenameとhash、encoding/tokenizer revision、runtime version、launch flags、secretを除いたrequest、raw completion、parsed response、次requestを含めます。これでmaintainerはmodel、parser、runtime、harnessのどこから確認すべきか判断できます。
モデルIDやhosted APIのthinking contractはDeepSeek V4 Proガイド、限られたhardwareでのlocal model選定はローカルagentic codingモデルのガイドが隣接taskです。ここでの合格条件は一つです。tool callの構造がraw outputから実行、そして次ターンまで維持されることです。



