Add model recommendation guides and Hauhau GGUF support

This commit is contained in:
Marcel Hofer
2026-05-29 19:05:29 +02:00
parent 6faa6bade2
commit 90df6de975
8 changed files with 557 additions and 9 deletions
+4 -1
View File
@@ -64,7 +64,10 @@ try:
sageattn_qk_int8_pv_fp8_cuda_sm90,
)
SAGE_ATTENTION_AVAILABLE = True
except ImportError:
except Exception:
sageattn_qk_int8_pv_fp16_cuda = None
sageattn_qk_int8_pv_fp8_cuda = None
sageattn_qk_int8_pv_fp8_cuda_sm90 = None
SAGE_ATTENTION_AVAILABLE = False
# Global cache for generated prompts
+1 -1
View File
@@ -3,7 +3,7 @@
"name": "ComfyUI-ThinkingLLM",
"description": "A multimodal ComfyUI AI node with Qwen3.5, Qwen3-VL, Qwen2.5-VL, Qwen3, and Gemma 4 integrations. Features live thinking in the terminal to see what the LLM is doing in real time.",
"author": "goodguy1963",
"version": "2.3.3",
"version": "2.3.4",
"url": "https://github.com/goodguy1963/ComfyUI-ThinkingLLM",
"category": "image"
}
+1 -1
View File
@@ -9,5 +9,5 @@
"description": "A multimodal ComfyUI AI node with Qwen3.5, Qwen3-VL, Qwen2.5-VL, Qwen3, and Gemma 4 integrations. Features live thinking in the terminal to see what the LLM is doing in real time.",
"category": "image",
"tags": ["vision", "language", "multimodal", "thinkingllm", "qwen", "gguf", "flash_attention", "performance", "wan2.2", "video", "i2v", "t2v", "storyboard", "caching", "fork", "gpl-3.0"],
"version": "2.3.3"
"version": "2.3.4"
}
+48
View File
@@ -189,6 +189,27 @@
"context_length": 131072
}
},
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-GGUF [Q2:11GB|Q3:15GB|Q4:20GB|Q5:28GB|Q6:31GB|Q8:44GB|VRAM:~24GB+]": {
"author": "HauhauCS",
"repo_name": "Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive",
"repo_id": "HauhauCS/Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive",
"model_files": [
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-Q8_K_P.gguf",
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-Q6_K_P.gguf",
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-Q5_K_P.gguf",
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-Q4_K_P.gguf",
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-Q4_K_M.gguf",
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-IQ4_NL.gguf",
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-IQ4_XS.gguf",
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-Q3_K_P.gguf",
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-IQ3_M.gguf",
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-Q2_K_P.gguf",
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-IQ2_M.gguf"
],
"defaults": {
"context_length": 131072
}
},
"Gemma-4-E2B-it-GGUF [Q4:2GB|Q8:3.5GB|VRAM:~3GB]": {
"author": "ggml-org",
"repo_name": "gemma-4-E2B-it-GGUF",
@@ -333,6 +354,33 @@
"pool_size": 4194304
}
},
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive [Q2:11GB|Q3:15GB|Q4:20GB|Q5:28GB|Q6:31GB|Q8:44GB|VRAM:~24GB+]": {
"author": "HauhauCS",
"repo_name": "Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive",
"repo_id": "HauhauCS/Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive",
"mmproj_file": "mmproj-Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-f16.gguf",
"model_files": [
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-Q8_K_P.gguf",
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-Q6_K_P.gguf",
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-Q5_K_P.gguf",
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-Q4_K_P.gguf",
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-Q4_K_M.gguf",
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-IQ4_NL.gguf",
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-IQ4_XS.gguf",
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-Q3_K_P.gguf",
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-IQ3_M.gguf",
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-Q2_K_P.gguf",
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-IQ2_M.gguf"
],
"defaults": {
"context_length": 131072,
"image_max_tokens": 4096,
"n_batch": 512,
"gpu_layers": -1,
"top_k": 20,
"pool_size": 4194304
}
},
"Qwen3.5-4B [Q4:2.4GB|Q6:3.2GB|Q8:4.2GB|BF16:8GB|VRAM:~4GB]": {
"author": "unsloth",
"repo_name": "Qwen3.5-4B-GGUF",
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "ComfyUI-ThinkingLLM"
description = "A multimodal ComfyUI AI node with Qwen3.5, Qwen3-VL, Qwen2.5-VL, Qwen3, and Gemma 4 integrations. Features live thinking in the terminal to see what the LLM is doing in real time."
version = "2.3.3"
version = "2.3.4"
license = {file = "LICENSE"}
dependencies = ["transformers>=5.2.0", "torch", "huggingface-hub", "hf_xet", "psutil", "numpy", "Pillow", "opencv-python", "bitsandbytes", "accelerate", "sentencepiece", "tiktoken", "llama-cpp-python"]
+69 -1
View File
@@ -272,6 +272,38 @@ def iter_workflow_types(path: Path) -> list[str]:
]
def load_model_recommendations() -> dict:
return json.loads((PKG / "web" / "model_recommendations.json").read_text(encoding="utf-8"))
def matches_recommendation_rule(model_name: str, rules: list[dict]) -> bool:
lowered = model_name.lower()
ordered = sorted(rules, key=lambda rule: rule.get("priority", 0), reverse=True)
for rule in ordered:
include = [token.lower() for token in rule.get("match_any", [])]
exclude = [token.lower() for token in rule.get("exclude_any", [])]
if any(token in lowered for token in include) and not any(token in lowered for token in exclude):
return True
return False
def iter_catalog_display_names() -> list[str]:
names: list[str] = []
hf_payload = json.loads((PKG / "hf_models.json").read_text(encoding="utf-8"))
for section in ("hf_vl_models", "hf_text_models"):
names.extend(list((hf_payload.get(section) or {}).keys()))
gguf_payload = json.loads((PKG / "gguf_models.json").read_text(encoding="utf-8"))
for section in ("Qwen_model", "qwenVL_model"):
entries = gguf_payload.get(section) or {}
for repo_key, repo in entries.items():
if not isinstance(repo, dict):
continue
for model_file in repo.get("model_files") or []:
names.append(str(Path(model_file).name))
return names
class TestTerminalDisplayHelper(unittest.TestCase):
def test_helper_file_exists(self):
self.assertTrue((PKG / "AILab_StreamDisplay.py").exists())
@@ -318,8 +350,44 @@ class TestBufferedStreamingIntegration(unittest.TestCase):
def test_gguf_prompt_enhancer_has_no_off_toggle_text_stream_fallback(self):
source = read_source("AILab_QwenVL_GGUF_PromptEnhancer.py")
self.assertNotIn("_maybe_emit_prompt_compact_progress", source)
class TestModelRecommendations(unittest.TestCase):
def test_recommendation_rules_have_sources(self):
payload = load_model_recommendations()
rules = payload.get("rules") or []
self.assertTrue(rules, "model_recommendations.json should define at least one rule")
for rule in rules:
with self.subTest(rule=rule.get("id")):
self.assertTrue(rule.get("sources"), "each recommendation rule should record its research source")
def test_recommendations_cover_all_catalog_models(self):
payload = load_model_recommendations()
rules = payload.get("rules") or []
uncovered = [name for name in iter_catalog_display_names() if not matches_recommendation_rule(name, rules)]
self.assertEqual([], uncovered)
def test_qwen36_hauhau_exists_in_text_and_vision_catalogs(self):
payload = json.loads((PKG / "gguf_models.json").read_text(encoding="utf-8"))
text_catalog = payload.get("Qwen_model") or {}
vision_catalog = payload.get("qwenVL_model") or {}
text_key = next((key for key in text_catalog if "Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive" in key), None)
vision_key = next((key for key in vision_catalog if "Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive" in key), None)
self.assertIsNotNone(text_key)
self.assertIsNotNone(vision_key)
self.assertIn("mmproj-Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-f16.gguf", vision_catalog[vision_key]["mmproj_file"])
self.assertGreaterEqual(len(text_catalog[text_key].get("model_files") or []), 11)
self.assertGreaterEqual(len(vision_catalog[vision_key].get("model_files") or []), 11)
def test_appearance_js_loads_recommendation_widget(self):
source = read_source("web/js/appearance.js")
self.assertIn("model_recommendations.json", source)
self.assertIn("ComfyWidgets", source)
self.assertIn("recommended_settings", source)
self.assertNotIn("Prompt enhancer compact terminal progress is active", source)
self.assertIn("_maybe_emit_prompt_background_heartbeat", source)
self.assertIn("queueRecommendationRefresh", source)
def test_gguf_prompt_enhancer_caps_context_and_safe_constructs_llama(self):
source = read_source("AILab_QwenVL_GGUF_PromptEnhancer.py")
+234 -4
View File
@@ -1,4 +1,5 @@
import { app } from "/scripts/app.js";
import { ComfyWidgets } from "/scripts/widgets.js";
const COLOR_THEMES = {
QwenVL: { nodeColor: "#28403f", nodeBgColor: "#374539", width: 340 },
@@ -8,15 +9,12 @@ const COLOR_THEMES = {
};
const NODE_COLORS = {
// QwenVL nodes
"AILab_QwenVL": "QwenVL",
"AILab_QwenVL_Advanced": "QwenVL",
"AILab_QwenVL_PromptEnhancer": "Enhancer",
"AILab_QwenVL_GGUF": "QwenVLGGUF",
"AILab_QwenVL_GGUF_Advanced": "QwenVLGGUF",
"AILab_QwenVL_GGUF_PromptEnhancer": "Enhancer",
// Tools
"AILab_QwenVL_PromptLibrary": "Tools",
};
@@ -46,6 +44,31 @@ const GGUF_ADVANCED_INTERNAL_WIDGETS = new Set([
"ctx_checkpoints",
]);
const RECOMMENDATIONS_URL = new URL("../model_recommendations.json", import.meta.url);
const RECOMMENDATION_WIDGET_NAME = "recommended_settings";
const RECOMMENDATION_PLACEHOLDER = "Select a model to see provider/community recommended settings. This note never changes your saved widget values.";
const RECOMMENDATION_FIELDS = ["temperature", "top_p", "top_k", "max_tokens", "ctx_min", "n_batch", "image_max_tokens"];
let recommendationsPromise = null;
function loadRecommendations() {
if (!recommendationsPromise) {
recommendationsPromise = fetch(RECOMMENDATIONS_URL)
.then((response) => {
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
})
.then((payload) => Array.isArray(payload?.rules) ? payload.rules : [])
.catch((error) => {
console.warn("[ThinkingLLM] Failed to load model recommendations", error);
return [];
});
}
return recommendationsPromise;
}
function setNodeColors(node, theme) {
if (!theme) { return; }
if (theme.nodeColor) {
@@ -103,17 +126,224 @@ function clearHfTokenAfterExecution(node) {
};
}
function recommendationScope(node) {
if ([
"AILab_QwenVL_GGUF",
"AILab_QwenVL_GGUF_Advanced",
"ThinkingLLM_QwenVL_GGUF",
"ThinkingLLM_QwenVL_GGUF_Advanced",
"AILab_QwenVL_GGUF_PromptEnhancer",
"ThinkingLLM_QwenVL_GGUF_PromptEnhancer",
].includes(node.comfyClass)) {
return "gguf";
}
return "hf";
}
function matchRecommendationRule(modelName, rules) {
const lowered = String(modelName || "").toLowerCase();
if (!lowered) {
return null;
}
const ordered = [...(rules || [])].sort((left, right) => (right.priority || 0) - (left.priority || 0));
for (const rule of ordered) {
const include = Array.isArray(rule?.match_any) ? rule.match_any : [];
const exclude = Array.isArray(rule?.exclude_any) ? rule.exclude_any : [];
const matches = include.some((token) => lowered.includes(String(token).toLowerCase()));
const blocked = exclude.some((token) => lowered.includes(String(token).toLowerCase()));
if (matches && !blocked) {
return rule;
}
}
return null;
}
function hasWidget(node, widgetName) {
return Boolean(findWidget(node, widgetName));
}
function formatSetting(fieldName, value) {
if (typeof value !== "number") {
return null;
}
if (fieldName === "ctx_min") {
return `ctx>=${value}`;
}
return `${fieldName}=${value}`;
}
function buildModeSummary(node, settings) {
const parts = [];
for (const fieldName of RECOMMENDATION_FIELDS) {
if (!(fieldName in (settings || {}))) {
continue;
}
if (fieldName === "ctx_min") {
if (!hasWidget(node, "ctx")) {
continue;
}
} else if (fieldName === "top_k") {
if (!hasWidget(node, "top_k")) {
continue;
}
} else if (!hasWidget(node, fieldName)) {
continue;
}
const formatted = formatSetting(fieldName, settings[fieldName]);
if (formatted) {
parts.push(formatted);
}
}
return parts;
}
function buildRecommendationText(node, rules) {
const modelName = String(findWidget(node, "model_name")?.value || "").trim();
if (!modelName || modelName.startsWith("(no ")) {
return RECOMMENDATION_PLACEHOLDER;
}
const rule = matchRecommendationRule(modelName, rules);
if (!rule) {
return [
"Manual settings guide",
`No curated recommendation is bundled yet for ${modelName}.`,
"Your current widget values stay exactly as you set them.",
].join("\n");
}
const thinkingEnabled = Boolean(findWidget(node, "enable_thinking")?.value);
const activeSettings = thinkingEnabled ? rule.thinking_on : rule.thinking_off;
const alternateSettings = thinkingEnabled ? rule.thinking_off : rule.thinking_on;
const activeSummary = buildModeSummary(node, activeSettings);
const alternateSummary = buildModeSummary(node, alternateSettings);
const scope = recommendationScope(node);
const lines = [
rule.family_label || "Manual settings guide",
`Current toggle: ${thinkingEnabled ? "thinking ON" : "thinking OFF"}`,
];
const supportNote = rule.support_notes?.[scope];
if (supportNote) {
lines.push(`Toggle: ${supportNote}`);
}
lines.push(`Thinking ON: ${(thinkingEnabled ? activeSummary : alternateSummary).join(" | ") || "use the provider defaults"}`);
lines.push(`Thinking OFF: ${(thinkingEnabled ? alternateSummary : activeSummary).join(" | ") || "use the provider defaults"}`);
const softSwitch = rule.support_notes?.soft_switch;
if (softSwitch) {
lines.push(`Note: ${softSwitch}`);
}
if (Array.isArray(rule.notes) && rule.notes.length) {
lines.push(`Extra: ${rule.notes[0]}`);
}
if (Array.isArray(rule.sources) && rule.sources.length) {
lines.push(`Sources: ${rule.sources.join(" + ")}`);
}
return lines.join("\n");
}
function ensureRecommendationWidget(node) {
if (!THINKINGLLM_NODE_NAMES.has(node.comfyClass)) {
return null;
}
let widget = findWidget(node, RECOMMENDATION_WIDGET_NAME);
if (widget) {
return widget;
}
widget = ComfyWidgets.STRING(node, RECOMMENDATION_WIDGET_NAME, ["STRING", { multiline: true }], app).widget;
if (widget?.inputEl) {
widget.inputEl.readOnly = true;
widget.inputEl.style.opacity = 0.78;
widget.inputEl.style.fontSize = "12px";
widget.inputEl.style.lineHeight = "1.35";
widget.inputEl.rows = 6;
}
widget.options = { ...(widget.options || {}), serialize: false };
widget.serializeValue = async () => undefined;
widget.value = RECOMMENDATION_PLACEHOLDER;
return widget;
}
function resizeNode(node) {
requestAnimationFrame(() => {
const size = node.computeSize();
if (size[0] < node.size[0]) {
size[0] = node.size[0];
}
if (size[1] < node.size[1]) {
size[1] = node.size[1];
}
node.setSize(size);
app.graph?.setDirtyCanvas?.(true, false);
});
}
function updateRecommendationWidget(node) {
const widget = ensureRecommendationWidget(node);
if (!widget) {
return;
}
loadRecommendations().then((rules) => {
widget.value = buildRecommendationText(node, rules);
resizeNode(node);
});
}
function queueRecommendationRefresh(node) {
if (!node || node._thinkingllmRecommendationQueued) {
return;
}
node._thinkingllmRecommendationQueued = true;
requestAnimationFrame(() => {
node._thinkingllmRecommendationQueued = false;
updateRecommendationWidget(node);
});
}
function hookRecommendationUpdates(node) {
if (!THINKINGLLM_NODE_NAMES.has(node.comfyClass) || node._thinkingllmRecommendationHooked) {
return;
}
node._thinkingllmRecommendationHooked = true;
ensureRecommendationWidget(node);
for (const widgetName of ["model_name", "enable_thinking"]) {
const target = findWidget(node, widgetName);
if (!target || target._thinkingllmRecommendationCallbackHooked) {
continue;
}
target._thinkingllmRecommendationCallbackHooked = true;
const originalCallback = target.callback;
target.callback = function (...args) {
const result = originalCallback?.apply(this, args);
queueRecommendationRefresh(node);
return result;
};
}
const originalConfigure = node.onConfigure;
node.onConfigure = function (...args) {
const result = originalConfigure?.apply(this, args);
queueRecommendationRefresh(this);
return result;
};
queueRecommendationRefresh(node);
}
const ext = {
name: "QwenVL.appearance",
nodeCreated(node) {
const nclass = node.comfyClass;
if (NODE_COLORS.hasOwnProperty(nclass)) {
let colorKey = NODE_COLORS[nclass];
const colorKey = NODE_COLORS[nclass];
const theme = COLOR_THEMES[colorKey];
setNodeColors(node, theme);
}
hideGgufAdvancedInternals(node);
hookRecommendationUpdates(node);
clearHfTokenAfterExecution(node);
}
};
+199
View File
@@ -0,0 +1,199 @@
{
"version": 1,
"rules": [
{
"id": "qwen36_hauhau_multimodal",
"priority": 100,
"match_any": [
"Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive"
],
"family_label": "Qwen3.6 35B A3B HauhauCS aggressive",
"sources": [
"HauhauCS model card",
"Qwen3.5 official model card"
],
"support_notes": {
"hf": "Not in the HF lineup here. Use the GGUF nodes for this model.",
"gguf": "Hard toggle via enable_thinking. Pair the vision node with the matching mmproj file.",
"soft_switch": "No official /think or /no_think soft switch for this family."
},
"thinking_on": {
"temperature": 1.0,
"top_p": 0.95,
"top_k": 20,
"max_tokens": 32768,
"ctx_min": 131072
},
"thinking_off": {
"temperature": 0.7,
"top_p": 0.8,
"top_k": 20,
"max_tokens": 32768,
"ctx_min": 131072
},
"notes": [
"Provider says keep at least 128K context to preserve thinking quality.",
"Q4_K_P is the best quality-size starting point; move to Q6_K_P or Q8_K_P when VRAM allows.",
"IQ quants are fallback options when you cannot fit Q4_K_M or Q4_K_P."
]
},
{
"id": "qwen35_family",
"priority": 80,
"match_any": [
"Qwen3.5",
"qwen3.5"
],
"family_label": "Qwen3.5 family",
"sources": [
"Qwen3.5 official model card"
],
"support_notes": {
"hf": "Hard toggle via enable_thinking when the backend honors the chat template.",
"gguf": "Hard toggle via enable_thinking in the Qwen chat template.",
"soft_switch": "No official /think or /no_think soft switch for Qwen3.5."
},
"thinking_on": {
"temperature": 1.0,
"top_p": 0.95,
"top_k": 20,
"max_tokens": 32768,
"ctx_min": 131072
},
"thinking_off": {
"temperature": 0.7,
"top_p": 0.8,
"top_k": 20,
"max_tokens": 32768,
"ctx_min": 131072
},
"notes": [
"For precise coding, Qwen recommends temperature 0.6 with thinking still enabled.",
"For hard non-thinking reasoning tasks, Qwen recommends top_p 1.0 and top_k 40 when the backend exposes them.",
"Provider says keep at least 128K context to preserve thinking capability and use 32K+ output budget when possible."
]
},
{
"id": "qwen3_family",
"priority": 70,
"match_any": [
"Qwen3VL-",
"qwen3vl-",
"Qwen3-VL",
"Qwen3-",
"qwen3-"
],
"exclude_any": [
"Qwen3.5",
"qwen3.5",
"Qwen3.6",
"qwen3.6"
],
"family_label": "Qwen3 family",
"sources": [
"Qwen3 official model card",
"Qwen Transformers docs"
],
"support_notes": {
"hf": "Hard toggle via enable_thinking, with /think and /no_think available as soft switches.",
"gguf": "Hard toggle via enable_thinking. /think and /no_think are available only on Qwen3 chat-template builds.",
"soft_switch": "Qwen3 officially supports /think and /no_think when thinking is enabled."
},
"thinking_on": {
"temperature": 0.6,
"top_p": 0.95,
"top_k": 20,
"max_tokens": 32768,
"ctx_min": 32768
},
"thinking_off": {
"temperature": 0.7,
"top_p": 0.8,
"top_k": 20,
"max_tokens": 32768,
"ctx_min": 32768
},
"notes": [
"Qwen warns against greedy decoding for thinking mode because it can repeat or degrade quality.",
"Provider recommends 32K output budget for most tasks and only enabling YaRN when you really need longer than the native 32K context.",
"For harder reasoning benchmarks, Qwen suggests stretching output budget beyond 32K if your backend allows it."
]
},
{
"id": "gemma4_large_family",
"priority": 60,
"match_any": [
"Gemma-4-26B",
"gemma-4-26B",
"Gemma-4-31B",
"gemma-4-31B"
],
"family_label": "Gemma 4 large family",
"sources": [
"Gemma 4 official model card"
],
"support_notes": {
"hf": "Gemma 4 supports configurable thinking, but current repo behavior can vary by backend.",
"gguf": "Use the settings manually and verify behavior in RAW_TRACE because GGUF support varies by backend.",
"soft_switch": "Gemma uses chat-template thinking controls instead of /think or /no_think."
},
"thinking_on": {
"temperature": 1.0,
"top_p": 0.95,
"top_k": 64,
"max_tokens": 1024,
"ctx_min": 262144
},
"thinking_off": {
"temperature": 1.0,
"top_p": 0.95,
"top_k": 64,
"max_tokens": 1024,
"ctx_min": 262144
},
"notes": [
"Gemma 4 uses one standardized sampler for both thinking and non-thinking modes.",
"Official context target is 256K on 26B A4B and 31B variants.",
"If the backend does not expose top_k, keep temperature and top_p at the official defaults."
]
},
{
"id": "gemma4_small_family",
"priority": 50,
"match_any": [
"Gemma-4-E2B",
"gemma-4-E2B",
"Gemma-4-E4B",
"gemma-4-E4B"
],
"family_label": "Gemma 4 small family",
"sources": [
"Gemma 4 official model card"
],
"support_notes": {
"hf": "Gemma 4 supports configurable thinking, but current repo behavior can vary by backend.",
"gguf": "Use the settings manually and verify behavior in RAW_TRACE because GGUF support varies by backend.",
"soft_switch": "Gemma uses chat-template thinking controls instead of /think or /no_think."
},
"thinking_on": {
"temperature": 1.0,
"top_p": 0.95,
"top_k": 64,
"max_tokens": 1024,
"ctx_min": 131072
},
"thinking_off": {
"temperature": 1.0,
"top_p": 0.95,
"top_k": 64,
"max_tokens": 1024,
"ctx_min": 131072
},
"notes": [
"Gemma 4 uses one standardized sampler for both thinking and non-thinking modes.",
"Official context target is 128K on E2B and E4B variants.",
"Gemma recommends higher visual token budgets only for OCR or fine detail tasks; lower budgets are faster for captioning or video summaries."
]
}
]
}