Het template is de taak van de aanroeper
p4 stuurt een ondoorzichtige prompt door en past geen chat-template toe. Vergeet dat, en het model beantwoordt een vraag die je niet hebt gesteld — vloeiend, en helemaal tot aan de tokenlimiet.
Het eerste echte antwoord uit onze herstelde ring was correcte rekenkunde, gevolgd door een gesprek dat niemand had gevoerd:
17 × 23, gevraagd aan een geserveerd model.
" 391 What is 12 times 12? Reply with only the number. 144 What is 14"
Het getal klopt. Alles erna is het model dat een document voortzet, want dat is wat we het hebben gegeven: de berichten platgeslagen tot één string. Een instruct-model leest dat als tekst om uit te breiden, niet als een beurt om te beantwoorden. Het stuurt nooit zijn einde-beurt-token, dus generatie loopt elke keer tot de limiet.
Een bewuste weglating, geen gat
p4 geeft de stage-server een ondoorzichtige prompt en past geen eigen beurtformaat toe — de staged adapter draagt alleen een tool om een template *uit* een GGUF te lezen, nooit om er een toe te passen. Dat is een redelijke grens: de engine blijft smal en modelagnostisch, en de aanroeper, die toch al weet met welk model hij praat, rendert het formaat. Maar een grens die wel getrokken en niet gedocumenteerd is, is een grens waar iemand overheen loopt.
Het template uit het modelbestand lezen gaf de doorslag: ChatML-beurten, <|im_end|> als einde-beurt-token, en een assistent-beurt die opent met een denkblok. Met dat gerenderd door de bridge, dezelfde vraag:
Hetzelfde model, dezelfde ring, het beurtformaat toegepast.
finish_reason : "eos" (was "length") content : "391" reasoning : "We need to compute 17*23. 17*20=340, plus 17*3=51, total 391."
Een denkfase kan het antwoord opeten
Een redeneermodel geeft tokens uit voordat het iets zegt. Geef het een budget en een moeilijke vraag en het kan het hele budget aan denken besteden, met een leeg antwoord tot gevolg — en in een netwerk waarin de aanroeper al on-chain heeft betaald voordat het verzoek draaide, is een leeg antwoord geen kwaliteitsprobleem. Het is een rekening voor niets.
De verrekengateway wist dit al en vraagt om denken uit te schakelen. Het template van het model heeft daar geen schakelaar voor, dus de bridge opent *en sluit* het denkblok in de prompt, en het model schrijft zijn antwoord erna. We hebben dit één keer op de voor de hand liggende manier fout gedaan — het blok in de prompt sluiten betekende dat de sluittag niet meer in de uitvoer zat, dus de splitter boekte het hele antwoord als redenering en gaf lege content terug. Precies het falen dat de instelling moet voorkomen.
Waar dit het contract achterlaat. De engine stuurt bytes door. De bridge kent het model: hij rendert het beurtformaat dat het placement plan noemt, geeft de denkfase terug als reasoning_content los van content, en klemt een verzoek dat om meer uitvoer vraagt dan de ring geladen is te geven — want een te groot verzoek wordt anders botweg geweigerd, en een korter antwoord is beter dan een engine-fout.