deepseek_v4: wire tool calling via checkpoint-native DSML encoding - #992
deepseek_v4: wire tool calling via checkpoint-native DSML encoding#992gcaponi wants to merge 1 commit into
Conversation
|
This one seems better than my previous #948, so better drop mine or merge this... |
|
Thanks @dcutugno β and congratulations on #948, we independently converged on the exact same design (vendored official DSML encoding, tolerant parse, per-arch dispatch). No point duplicating: I'm happy to close this in favor of the merged work. What this PR still adds on top: a standalone e2e suite (4 tests, DSML-speaking mock engine over the SERVE wire protocol, incl. streamed marker suppression across chunks) and a live validation of the full two-turn tool loop on the real 284B checkpoint served CPU-only on consumer hardware (6-core, 32 GB RAM, greedy) β try_tool_calling.py |
|
What i recommend is keep my 948, but refactor it with your vendor encoder, i'm currently doing it, stay tuned! |
|
Done this PR can be closed! |
What
Tool calling for the DeepSeek V4 engine (
/v1/chat/completionswithtoolsβtool_calls), closing the "tools and grammar are rejected" serving gap for V4.Instead of inventing a prompt format, this vendors the checkpoint's own DSML
encoding (
encoding/encoding_dsv4.pyinsidedeepseek-ai/DeepSeek-V4-Flash-0731)into
c/v4_dsml.py:## ToolsDSML templatetool_callshistory renders as<ο½DSMLο½invoke>blockstoolrole results merge into user turns as<tool_result>blocks(V4 has no standalone tool role β this is the native merge)
\n\n<ο½DSMLο½tool_calls>block and decodesstring="true|false"parameters back to JSON argumentsChanges
c/v4_dsml.py(new): vendored reference encoding. Encode side kept byte-exact(verified against the checkpoint's own fixtures); parse side made fault-tolerant
for gateway use β malformed/truncated DSML degrades to visible content + stderr
log, never raises to the client (same philosophy as GLM salvage-off).
c/openai_server.py(+~90 lines):render_chat_v4_tools(): used whentoolsare declared or the history containstool/tool_callsmessages; plain chat rendering is byte-identical to beforeparse_tool_calls_any(): routes reply parsing per arch (GLM unchanged)(
<ο½DSMLο½tool_calls>for V4)tool_choice:auto/nonesupported;required/forced returns an honest 400c/tests/test_openai_tools_v4_e2e.py(new): mirrorstest_openai_tools_e2e.pyagainst the deepseek_v4 arch with a DSML-speaking mock engine (4 tests).
The Anthropic
/v1/messagesendpoint getstool_useblocks for free, since ittranslates onto the same OpenAI path.
Validation
test_openai_tools_v4_e2e: 4/4 pass (non-stream call,<tool_result>roundtrip, streamed marker suppression across 12 chunks, plain chat unchanged)
test_openai_tools_e2e(GLM regression): 6/6 passtest_openai_server: 122/123 β the single error (resource_plan.physical_cpu_countmock) reproduces identically on unpatched main
tools/try_tool_calling.pyPASS againstDeepSeek-V4-Flash-0731 (284B) served CPU-only on consumer hardware (6-core Ryzen 5,
32 GB RAM,
--ram 22, greedy): turn 1get_weather({"city": "Rome"}), turn 2answer consumes the tool result ("sunny, 31Β°C")
Scope / follow-ups
tool_choice: required/ forced function: 400 for now, prompt-level support is asmall follow-up
response_formaton V4 remains rejected (unchanged)Nota strategica
Questa PR Γ¨ la SPEC-41 (prima PR mergiata) e chiude il cerchio con il commento su #175:
arriviamo al progetto con un dataset pubblico E con codice funzionante misurato sul
modello reale. Se il maintainer chiede modifiche, si itera sul branch β Γ¨ il gioco.