Drei weitere Kandidaten geprueft, alle drei abgelehnt

Ministral-3-3B: Architektur mistral3 steht nicht in der Liste des
rkllm-Toolkits, dazu FP8-Gewichte -- nie konvertiert. Config auf Llama
umbiegen waere moeglich gewesen, aber ein falsch eingelesenes Modell
haette plausiblen Unsinn produziert.

Phi-4-mini: konvertiert (5,06 GB), laedt aber nicht auf der NPU.
partial_rotary_factor 0.75 ergibt 48 LongRoPE-Faktoren, die Runtime
erwartet starr head_dim/2 = 64. Rockchips "Phi3" meint Phi-3-mini.

SmolLM3-3B: laeuft, in 2 von 3 Faellen schneller als Qwen3, scheitert
aber inhaltlich -- 13 statt 61 Todos, JSON-Schluessel als
Listeneintraege, Englisch-Drift im deutschen Text.

rkllm_server.cpp: Chat-Template kommt jetzt aus der Umgebung
(RKLLM_TMPL_SYSTEM / _USER_PRE / _USER_POST), Defaults = bisheriges
ChatML-Verhalten, mit Qwen3 gegengeprueft. Damit ist der naechste
Kandidat eine Drop-in-Zeile statt einer Neuuebersetzung.

Doku: Changelog 2026-09-29 (4) mit Messwerten und allen Fallstricken,
Kapitel 05 um Architektur-Vorpruefung und Template-Konfiguration
erweitert. Messstrecke: Zeitlimit 45 -> 90 Minuten.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017A91sWU5aWrqZ2DWNTLVph
This commit is contained in:
2026-09-29 19:59:04 +02:00
co-authored by Claude Opus 5
parent 9e9958fb01
commit 3a2e8144f7
4 changed files with 176 additions and 11 deletions
+1 -1
View File
@@ -22,7 +22,7 @@ import { pool } from '../db.js';
const OUT = '/opt/callrec/lab/ab-llm';
const API = 'http://127.0.0.1';
const POLL_MS = 5000;
const TIMEOUT_MS = 45 * 60 * 1000; // eine Analyse darf lange dauern (Whole-Pass)
const TIMEOUT_MS = 90 * 60 * 1000; // 45 min war zu knapp: #114 brauchte 60,8 min
fs.mkdirSync(OUT, { recursive: true });
+32 -10
View File
@@ -14,6 +14,24 @@
#include <string>
#include <iostream>
// Liest einen Umgebungswert und wandelt die Zwei-Zeichen-Folgen \n und \t in
// echte Steuerzeichen. systemd-Environment-Zeilen koennen keine Zeilenumbrueche
// enthalten, die Chat-Marker brauchen aber welche.
static std::string env_or(const char* name, const char* fallback) {
const char* v = getenv(name);
std::string s = (v && *v) ? v : fallback;
std::string out;
for (size_t i = 0; i < s.size(); ++i) {
if (s[i] == '\\' && i + 1 < s.size()) {
if (s[i+1] == 'n') { out += '\n'; ++i; continue; }
else if (s[i+1] == 't') { out += '\t'; ++i; continue; }
else if (s[i+1] == '\\') { out += '\\'; ++i; continue; }
}
out += s[i];
}
return out;
}
static std::string g_out;
static bool g_error = false;
@@ -75,17 +93,21 @@ int main(int argc, char** argv) {
// without this the model gets the raw prompt with no turn markers and just
// rambles generic filler. prefix/postfix wrap each user prompt; <bos> is
// added by the runtime (add_bos_token=True at conversion).
// Qwen3.5 denkt per Default und ignoriert dabei die JSON-Vorgabe -- es
// antwortet mit Gedankengang ("Wait, looking at line ..."), und der
// JSON-Parser in llm.js sieht nichts Brauchbares. RKLLMInput.enable_thinking
// allein schaltet das NICHT ab; das Modell-Template tut es, indem es den
// Assistenten-Zug mit einem LEEREN Denkblock vorbefuellt. Genau den haengen
// wir hier an, wenn RKLLM_SUPPRESS_THINK=1 gesetzt ist (Qwen3, Gemma3 und
// Qwen2.5 brauchen es nicht und bekommen unveraendert das alte Template).
std::string assist = "<|im_end|>\n<|im_start|>assistant\n";
// Das Chat-Template kommt aus der Umgebung, weil rkllm das HF-Template NICHT
// selbst anwendet: ohne passende Marker bekommt das Modell den nackten Prompt
// und faselt generisches Fuellmaterial. Defaults = ChatML (Qwen, Gemma3).
// Phi-4-mini und SmolLM3 setzen eigene Werte per Drop-in.
// RKLLM_SUPPRESS_THINK=1 haengt einen LEEREN Denkblock an: Denk-Modelle wie
// Qwen3.5 antworten sonst mit Gedankengang statt JSON, und
// RKLLMInput.enable_thinking allein genuegt dafuer nicht.
std::string sys_pre = env_or("RKLLM_TMPL_SYSTEM", "");
std::string user_pre = env_or("RKLLM_TMPL_USER_PRE", "<|im_start|>user\n");
std::string user_post = env_or("RKLLM_TMPL_USER_POST", "<|im_end|>\n<|im_start|>assistant\n");
const char* sup = getenv("RKLLM_SUPPRESS_THINK");
if (sup && *sup == '1') assist += "<think>\n\n</think>\n\n";
rkllm_set_chat_template(h, "", "<|im_start|>user\n", assist.c_str());
if (sup && *sup == '1') user_post += "<think>\n\n</think>\n\n";
fprintf(stderr, "chat template: sys=%zu user_pre=%zu user_post=%zu bytes\n",
sys_pre.size(), user_pre.size(), user_post.size());
rkllm_set_chat_template(h, sys_pre.c_str(), user_pre.c_str(), user_post.c_str());
printf("READY\n"); fflush(stdout);
fprintf(stderr, "rkllm model loaded\n"); fflush(stderr);