AIFreeAPI Logo

DeepSeek V4のローカルcoding agentでツールが動かない:DSML・parser・量子化・harnessの切り分け

A
8 min read開発者ガイド

モデルが文章を返すのにtoolを実行しない場合、同じturnのraw output、構造化response、client event、次requestを並べると最初の破損点が分かります。

DeepSeek V4のtool callがモデル、parser、runtime、agent harnessを通る診断境界

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を一つ変更
harnessserver responseは正常だがtoolが動かないadapter、permission、schema、call IDを追跡
history1回目は成功し次ターンで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は次の程度で十分です。

python
def 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を寛容に実行するのは危険です。

raw DSMLからstructured tool_callsまで最初の破損境界を確認するチェック表
raw DSMLからstructured tool_callsまで最初の破損境界を確認するチェック表

量子化を疑う条件を狭くする

公式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を交換しても、この差分は説明できません。

モデル入力からtool実行と次requestまでを一周する制御済みtool loop
モデル入力からtool実行と次requestまでを一周する制御済みtool loop

再現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から実行、そして次ターンまで維持されることです。