patch_deepseek_v4_effort.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #!/usr/bin/env python3
  2. """Minimal patch to the eugr image's vendored deepseek_v4 tokenizer to add the
  3. updated reasoning_effort (low/high/max) support WITHOUT rewriting the whole file.
  4. We deliberately do NOT replace the files with the full 0731 model-card variant.
  5. Instead this applies the smallest possible edits on top of whatever eugr ships:
  6. deepseek_v4.py (API layer):
  7. - let "low"/"high"/"max" pass through; unknown/garbage -> None (reverts to
  8. engine default) instead of coercing everything to "high".
  9. deepseek_v4_encoding.py:
  10. - replace the single REASONING_EFFORT_MAX constant with the per-level
  11. REASONING_EFFORT_PROMPTS dict + DEFAULT_REASONING_EFFORT="low"
  12. ("high" text == the old "max" text; a stronger "max" added; "low" = "").
  13. - in render_message: default None->"low", assert against the dict, and emit
  14. the per-level prompt at index 0 in thinking mode.
  15. Everything else in eugr's files (tool handling, `reasoning` key, structure) is
  16. left intact, so no independent updates are lost.
  17. Usage: python3 patch_deepseek_v4_effort.py [--check]
  18. --check : verify each file is in a CONSISTENT state (either pristine-old or
  19. already-patched) and exit 0 if so. Both before and after apply.
  20. (apply) : replace old anchors with new (requires exact old-anchor match).
  21. """
  22. import os
  23. import sys
  24. import vllm
  25. BASE = os.path.join(vllm.__path__[0], "tokenizers")
  26. F_ENC = os.path.join(BASE, "deepseek_v4_encoding.py")
  27. F_API = os.path.join(BASE, "deepseek_v4.py")
  28. # --- deepseek_v4.py: let low/high/max through; unknown -> None ---
  29. OLD_API = (
  30. " elif reasoning_effort in (\"max\", \"xhigh\"):\n"
  31. " reasoning_effort = \"max\"\n"
  32. " else:\n"
  33. " reasoning_effort = \"high\""
  34. )
  35. NEW_API = (
  36. " elif reasoning_effort in (\"max\", \"xhigh\"):\n"
  37. " reasoning_effort = \"max\"\n"
  38. " elif reasoning_effort not in (\"low\", \"high\", \"max\"):\n"
  39. " reasoning_effort = None"
  40. )
  41. # --- deepseek_v4_encoding.py: constant -> dict + default ---
  42. OLD_EFF_CONST = (
  43. "REASONING_EFFORT_MAX = (\n"
  44. " \"Reasoning Effort: Absolute maximum with no shortcuts permitted.\\n\"\n"
  45. ' "You MUST be very thorough in your thinking and comprehensively decompose the problem to resolve the root cause, rigorously stress-testing your logic against all potential paths, edge cases, and adversarial scenarios.\\n"\n'
  46. ' "Explicitly write out your entire deliberation process, documenting every intermediate step, considered alternative, and rejected hypothesis to ensure absolutely no assumption is left unchecked.\\n\\n"\n'
  47. ")"
  48. )
  49. NEW_EFF_CONST = (
  50. "REASONING_EFFORT_PROMPTS = {\n"
  51. " \"low\": \"\",\n"
  52. " \"high\": (\n"
  53. " \"Reasoning Effort: Absolute maximum with no shortcuts permitted.\\n\"\n"
  54. " \"You MUST be very thorough in your thinking and comprehensively decompose the problem to resolve the root cause, rigorously stress-testing your logic against all potential paths, edge cases, and adversarial scenarios.\\n\"\n"
  55. " \"Explicitly write out your entire deliberation process, documenting every intermediate step, considered alternative, and rejected hypothesis to ensure absolutely no assumption is left unchecked.\\n\\n\"\n"
  56. " ),\n"
  57. " \"max\": (\n"
  58. " \"Reasoning Effort: Beyond maximum \\u2014 exhaustive, relentless, and uncompromising.\\n\"\n"
  59. " \"You MUST reason with the utmost depth and rigor, leaving absolutely nothing to chance: exhaustively decompose the problem into its most fundamental components, trace every causal chain to its root, and resolve the underlying cause rather than any surface symptom.\\n\"\n"
  60. " \"Do not stop reasoning until you have independently verified the solution from multiple angles and are certain that no assumption remains unchecked and no error remains undiscovered.\\n\\n\"\n"
  61. " ),\n"
  62. "}\n"
  63. 'DEFAULT_REASONING_EFFORT = "low"'
  64. )
  65. # --- deepseek_v4_encoding.py: render_message effort hunk ---
  66. OLD_EFF_HUNK = (
  67. " # Reasoning effort prefix (only at index 0 in thinking mode with max effort)\n"
  68. " assert reasoning_effort in ['max', None, 'high'], f\"Invalid reasoning effort: {reasoning_effort}\"\n"
  69. " if index == 0 and thinking_mode == \"thinking\" and reasoning_effort == 'max':\n"
  70. " prompt += REASONING_EFFORT_MAX"
  71. )
  72. NEW_EFF_HUNK = (
  73. " # Reasoning effort prefix (only at index 0 in thinking mode; \"low\" adds nothing)\n"
  74. " reasoning_effort = reasoning_effort or DEFAULT_REASONING_EFFORT\n"
  75. " assert reasoning_effort in REASONING_EFFORT_PROMPTS, \\\n"
  76. " f\"Invalid reasoning effort: {reasoning_effort}, expected one of {list(REASONING_EFFORT_PROMPTS)}\"\n"
  77. " if index == 0 and thinking_mode == \"thinking\":\n"
  78. " prompt += REASONING_EFFORT_PROMPTS[reasoning_effort]"
  79. )
  80. # Each entry: (path, [(old_anchor, new_anchor), ...])
  81. TARGETS = [
  82. (F_API, [(OLD_API, NEW_API)]),
  83. (F_ENC, [(OLD_EFF_CONST, NEW_EFF_CONST), (OLD_EFF_HUNK, NEW_EFF_HUNK)]),
  84. ]
  85. def _consistent(src, old, new):
  86. """True if the file holds exactly one of old|new (pristine or patched).
  87. Handles overlapping edits where NEW embeds OLD (e.g. an inserted import
  88. block that starts with the original lines)."""
  89. co, cn = src.count(old), src.count(new)
  90. if cn >= 1:
  91. # patched: new present once, and old does not appear beyond the copy
  92. # embedded inside new itself.
  93. return cn == 1 and co <= new.count(old)
  94. return co == 1
  95. def main() -> None:
  96. check = "--check" in sys.argv
  97. states = [(path, open(path).read()) for path, _ in TARGETS]
  98. if check:
  99. for path, src in states:
  100. for old, new in dict(TARGETS)[path]:
  101. if not _consistent(src, old, new):
  102. raise SystemExit(
  103. f"CHECK FAIL: {path} — file is neither pristine-old nor "
  104. "already-patched for an anchor"
  105. )
  106. print("check OK: deepseek_v4 reasoning_effort state is consistent")
  107. return
  108. # Apply: require exact old anchors, then replace and verify new.
  109. for path, src in states:
  110. for old, new in dict(TARGETS)[path]:
  111. if src.count(old) != 1:
  112. raise SystemExit(
  113. f"refusing: {path} old anchor matched {src.count(old)}x "
  114. "(expected 1); source changed, re-sync patch"
  115. )
  116. for old, new in dict(TARGETS)[path]:
  117. src = src.replace(old, new)
  118. for old, new in dict(TARGETS)[path]:
  119. if src.count(new) != 1:
  120. raise SystemExit(
  121. f"refusing: {path} new anchor present {src.count(new)}x "
  122. "after apply (internal error)"
  123. )
  124. with open(path, "w") as f:
  125. f.write(src)
  126. print(f"patched {path}")
  127. if __name__ == "__main__":
  128. main()