Prechádzať zdrojové kódy

Rebase deepseek-v4-flash :fixed overlay onto production-3.76.1

aidendle94 published production-3.76.1 (2026-08-20), same lineage as
3.75 — 56/56 base layers byte-identical, plus a 7-layer source overlay.
Drop our vendored deepseek_v4.py: 3.76.1 names thinking/enable_thinking/
reasoning_effort/drop_thinking as explicit signature params, fixing the
serving-path kwarg filter (supports_kw, allow_var_kwargs=False) at the
root cause; our copy read the same kwargs from **kwargs and was equally
dropped. Keep the deepseek_v4_encoding.py patch — 3.76.1 does not touch
the stale bundled encoding (single REASONING_EFFORT_MAX wording, max used
high text, deprecated reasoning key).

Image checksum changes, so the next serve/build rebuilds :fixed.
Alexander Korolev 2 mesiacov pred
rodič
commit
5a9795c612

+ 21 - 21
docker-images/deepseek-v4-flash-dspark/Dockerfile

@@ -1,34 +1,34 @@
 # syntax=docker/dockerfile:1.7
 # DeepSeek-V4-Flash-DSpark — instanttensor on top of
-# aidendle94/sparkrun-vllm-ds4-gb10:production-3.75
+# aidendle94/sparkrun-vllm-ds4-gb10:production-3.76.1
 #
-# production-3.75 already ships the patched NCCL 2.30.4 ABI (its base layers
-# are byte-identical to production-3.2, which is labeled "patched NCCL
-# 2.30.4"), so no NCCL re-alignment is needed. This overlay adds instanttensor
-# for faster model loading (load-format instanttensor) plus the deepseek_v4
-# encoder reasoning-effort fix (see patch COPY below).
+# production-3.76.1 (same lineage as 3.75) ships the patched NCCL 2.30.4 ABI
+# (the base layers are byte-identical to production-3.2, which is labeled
+# "patched NCCL 2.30.4"), so no NCCL re-alignment is needed. This overlay adds
+# instanttensor for faster model loading (load-format instanttensor) plus the
+# deepseek_v4 encoder reasoning-effort fix (see patch COPY below).
 #
 # Build: cd docker-images/deepseek-v4-flash-dspark && docker build -t sparkrun-vllm-ds4-gb10:fixed .
-# Tag:   docker tag sparkrun-vllm-ds4-gb10:fixed aidendle94/sparkrun-vllm-ds4-gb10:production-3.75
+# Tag:   docker tag sparkrun-vllm-ds4-gb10:fixed aidendle94/sparkrun-vllm-ds4-gb10:production-3.76.1
 
-FROM aidendle94/sparkrun-vllm-ds4-gb10:production-3.75
+FROM aidendle94/sparkrun-vllm-ds4-gb10:production-3.76.1
 
 RUN pip install --no-cache-dir --no-deps --force-reinstall instanttensor==0.1.9
 
-# Fix reasoning_effort handling in the vendored deepseek_v4 tokenizer:
-# - high was accepted but silently injected nothing (only max triggered text)
-# - low / unknown values were coerced to high (unreachable low, silent escalation)
-# - the bundled deepseek_v4_encoding.py was an OLD revision (single REASONING_EFFORT_MAX
-#   wording, max used the high text, read the deprecated `reasoning` key)
-# deepseek_v4_encoding.py is replaced with the canonical model-card reference
+# production-3.76.1 itself ships a fixed deepseek_v4.py (layer LABEL
+# "org.375.overlay=3.76.1"): it names thinking/enable_thinking/reasoning_effort/
+# drop_thinking as explicit signature params so the vllm serving path
+# (supports_kw, allow_var_kwargs=False) no longer drops them — the root-cause
+# fix. So our vendored deepseek_v4.py is NOT needed on this base (it read the
+# same kwargs via **kwargs and was equally dropped).
+#
+# The bundled deepseek_v4_encoding.py is still the stale revision (single
+# REASONING_EFFORT_MAX wording, max used the high text, read the deprecated
+# `reasoning` key) — 3.76.1's overlay layers do not touch it. deepseek_v4_encoding.py
+# is therefore still replaced with the canonical model-card reference
 # (deepseek-ai/DeepSeek-V4-Flash-0731 encoding/encoding_dsv4.py): full low/high/max
 # prompt dict, correct gate for both high and max, and reasoning_content key.
-# deepseek_v4.py carries the normalization fix so low is reachable and unknown
-# values map to None. See deepseek_v4.py / deepseek_v4_encoding.py in patches/.
 # Mirrors the encoder fix 0rand bundled into his local
-# production-3.75-reffix-0731 image (forums…/372268/708): we keep it as a
-# source overlay on our own :fixed image instead of adopting the private
-# -reffix tag.
-COPY patches/deepseek_v4.py \
-     patches/deepseek_v4_encoding.py \
+# production-3.75-reffix-0731 image (forums…/372268/708).
+COPY patches/deepseek_v4_encoding.py \
      /opt/venv/lib/python3.12/site-packages/vllm/tokenizers/

+ 0 - 99
docker-images/deepseek-v4-flash-dspark/patches/deepseek_v4.py

@@ -1,99 +0,0 @@
-# SPDX-License-Identifier: Apache-2.0
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
-import copy
-from typing import Any
-
-from transformers import PreTrainedTokenizerFast
-
-from vllm.entrypoints.chat_utils import ChatCompletionMessageParam
-
-from .deepseek_v4_encoding import encode_messages
-from .hf import HfTokenizer, get_cached_tokenizer
-from .protocol import TokenizerLike
-
-
-def get_deepseek_v4_tokenizer(tokenizer: HfTokenizer) -> HfTokenizer:
-    """
-    Wraps a tokenizer to use the custom DeepSeek V4 chat template encoding.
-    """
-    dsv4_tokenizer = copy.copy(tokenizer)
-
-    added_vocab = tokenizer.get_added_vocab()
-    added_vocab_size = len(added_vocab)
-    tokenizer_vocab_size = tokenizer.vocab_size
-
-    class _DeepseekV4Tokenizer(tokenizer.__class__):  # type: ignore
-        def apply_chat_template(
-            self,
-            messages: list["ChatCompletionMessageParam"],
-            tools: list[dict[str, Any]] | None = None,
-            **kwargs,
-        ) -> str | list[int]:
-            thinking = kwargs.get("thinking", False)
-            enable_thinking = kwargs.get("enable_thinking", False)
-            # Honor the model-card API too: callers may pass either `thinking`
-            # (bool) or `thinking_mode` ("thinking"/"chat"). Previously `thinking_mode`
-            # was silently dropped, so a request asking for thinking ran in chat mode.
-            thinking = thinking or enable_thinking or kwargs.get("thinking_mode") == "thinking"
-            thinking_mode = "thinking" if thinking else "chat"
-
-            conversation = kwargs.get("conversation", messages)
-            messages = conversation.copy()
-            if tools is not None and len(tools) > 0:
-                messages.insert(0, {"role": "system"})
-                messages[0]["tools"] = tools  # type: ignore[typeddict-unknown-key]
-
-            reasoning_effort = kwargs.get("reasoning_effort")
-            if not isinstance(reasoning_effort, str):
-                reasoning_effort = None
-            elif reasoning_effort == "none":
-                thinking_mode = "chat"
-                reasoning_effort = None
-            elif reasoning_effort in ("max", "xhigh"):
-                reasoning_effort = "max"
-            elif reasoning_effort not in ("low", "high", "max"):
-                reasoning_effort = None
-
-            encode_config = dict(
-                thinking_mode=thinking_mode,
-                drop_thinking=kwargs.get("drop_thinking", True),
-                reasoning_effort=reasoning_effort,
-            )
-
-            prompt_str = encode_messages(messages, **encode_config)  # type: ignore
-
-            if kwargs.get("tokenize", True):
-                tokenizer_kwargs = {
-                    k: kwargs[k] for k in ("truncation", "max_length") if k in kwargs
-                }
-                return self.encode(
-                    prompt_str,
-                    add_special_tokens=False,
-                    **tokenizer_kwargs,
-                )
-
-            return prompt_str
-
-        def num_special_tokens_to_add(self) -> int:
-            return len(self.encode(""))
-
-        def __len__(self) -> int:
-            return tokenizer_vocab_size + added_vocab_size
-
-        def get_added_vocab(self) -> dict[str, int]:
-            return added_vocab.copy()
-
-        def __reduce__(self):
-            return get_deepseek_v4_tokenizer, (tokenizer,)
-
-    _DeepseekV4Tokenizer.__name__ = f"DSV4{tokenizer.__class__.__name__}"
-
-    dsv4_tokenizer.__class__ = _DeepseekV4Tokenizer
-    return dsv4_tokenizer
-
-
-class DeepseekV4Tokenizer(TokenizerLike):
-    @classmethod
-    def from_pretrained(cls, *args, **kwargs) -> HfTokenizer:
-        tokenizer = PreTrainedTokenizerFast.from_pretrained(*args, **kwargs)
-        return get_cached_tokenizer(get_deepseek_v4_tokenizer(tokenizer))

+ 1 - 1
recipes/deepseek-v4-flash-eugr/recipe.toml

@@ -23,7 +23,7 @@
 # Model: deepseek-ai/DeepSeek-V4-Flash-0731 — official release; native
 # dspark_block_size = 5, so num_speculative_tokens = 5.
 #
-# Differences vs recipes/deepseek-v4-flash (aidendle94 production-3.75 image):
+# Differences vs recipes/deepseek-v4-flash (aidendle94 production-3.76.1 image):
 #   - attention backend B12X_MLA_SPARSE (eugr) vs FLASHINFER_MLA_SPARSE_DSV4
 #   - --linear-backend b12x + --load-format instanttensor (the mod's trigger)
 #   - --reasoning-config pinned to deepseek_v4 parser w/ empty start/end strs

+ 2 - 2
recipes/deepseek-v4-flash/recipe.toml

@@ -1,10 +1,10 @@
 # DeepSeek-V4-Flash-DSpark — 2× GB10 / DGX Spark, TP=2 over RoCE.
 # DSpark speculative decoding on the official DeepSeek-V4-Flash-0731 release
-# via the local :fixed overlay on aidendle94's production-3.75 image (see
+# via the local :fixed overlay on aidendle94's production-3.76.1 image (see
 # docker-images/deepseek-v4-flash-dspark).
 #
 # Image: sparkrun-vllm-ds4-gb10:fixed
-#   production-3.75 base (DSpark, b12x MoE, patched NCCL 2.30.4, multi-node
+#   production-3.76.1 base (DSpark, b12x MoE, patched NCCL 2.30.4, multi-node
 #   fixes) + instanttensor for faster model loading.
 # Model: deepseek-ai/DeepSeek-V4-Flash-0731 — official release.
 #   0731 (and the -DSpark preview) both have dspark_block_size = 5. This image's