Skeleton-of-Thought: parallel redeneren via prompts
De generatiesnelheid van grote taalmodellen wordt fundamenteel begrensd door het autoregressieve decoderingsproces: elk nieuw token vereist een voorwaartse berekening over alle voorgaande tokens. Wanneer een applicatie een uitgebreide analyse, een technisch rapport of een meerstappenplan moet genereren, resulteert dit lineaire proces onvermijdelijk in een merkbare vertraging voor de eindgebruiker. Skeleton-of-Thought (SoT) doorbreekt deze lineaire keten door het generatieproces op te splitsen in twee fasen: eerst schetst het model een beknopt antwoordskelet, waarna een orchestrator de afzonderlijke punten parallel laat uitwerken door gelijktijdige API-aanroepen.
Waar sequentiële methoden de latentie laten oplopen naarmate de gewenste uitvoer langer wordt, schaalt de wachttijd bij Skeleton-of-Thought voornamelijk mee met de lengte van het langste individuele deelpunt. Dit levert aanzienlijke snelheidswinsten op bij gestructureerde prompts, maar introduceert tegelijkertijd specifieke uitdagingen rondom coherentie, tokenconsumptie en redundantie. In dit artikel behandelen we de wiskundige onderbouwing, de exacte prompt-sjablonen, een complete implementatie en de architecturale afwegingen van deze techniek.
De mechanica van autoregressieve latentie versus parallellisme
Moderne transformermodellen genereren tekst token voor token. Voor een antwoord van $N$ tokens bedraagt de totale inferentietijd grofweg $T_{totaal} = T_{prefill} + N \times T_{decode}$, waarbij $T_{prefill}$ de tijd is om de invoerprompt te verwerken en $T_{decode}$ de tijd per gegenereerd token. Omdat $T_{decode}$ gedomineerd wordt door geheugenbandbreedte op de grafische processor, blijft de wachttijd lineair evenredig aan de lengte van het antwoord. Wie 1200 tokens genereert bij een snelheid van 40 tokens per seconde, moet 30 seconden wachten op voltooiing.
Skeleton-of-Thought verandert deze dynamiek fundamenteel door gebruik te maken van de inherente onafhankelijkheid van deelsecties in veel informatieve antwoorden. In plaats van één lange generatie aan te roepen, splitst het systeem de taak in twee afzonderlijke processtappen:
- Skeletgeneratie (Skeleton Stage): Het model ontvangt de hoofdinstructie en genereert uitsluitend een genummerde lijst met kernpunten of deelonderwerpen, meestal beperkt tot 30 tot 80 tokens.
- Puntuitwerking (Expansion Stage): Voor elk punt uit het skelet wordt een afzonderlijke, parallelle API-aanroep gestart. Elke aanroep krijgt de originele gebruikersvraag, het volledige skelet en het specifieke punt dat uitgewerkt moet worden mee als context.
De totale latentie wordt hierdoor teruggebracht tot $T_{totaal} = T_{skelet} + \max(T_{punt_1}, T_{punt_2}, \dots, T_{punt_k}) + T_{samenvoeging}$. In plaats van de som van alle uitwerkingen, betaalt de applicatie enkel de latentie van het langste individuele deelpunt, vermeerderd met de verwaarloosbare tijd voor het samenvoegen van de tekstblokken.
Het verschil met sequentiële redeneerketens
Om te begrijpen wanneer Skeleton-of-Thought ingezet moet worden, is een vergelijking met traditionele promptstrategieën essentieel. Raadpleeg de beslisgids voor prompttechnieken om te bepalen of een taak baat heeft bij zero-shot, few-shot of meerstaps-redeneren. Waar klassieke technieken zoals Chain-of-Thought redeneerstappen bewust achter elkaar plaatsen, gaat Skeleton-of-Thought uit van breedte-exploratie.
Bij een strikt sequentiële redeneerketen bouwt stap $B$ direct voort op de uitkomst van stap $A$. Als we bijvoorbeeld wiskundige afleidingen maken of logische deducties uitvoeren, is het niet mogelijk om stap 3 uit te rekenen voordat stap 2 voltooid is. Zie ook de diepere theoretische achtergrond over hoe een model stapsgewijs tot een conclusie komt in het artikel over redeneren via Chain-of-Thought. Skeleton-of-Thought is daarentegen ontworpen voor taken met een orthogonale informatiestructuur: onderwerpen waarbij de deelsecties parallel kunnen worden uitgediept zonder dat ze elkaars tussenresultaten direct nodig hebben.
| Eigenschap | Standaard Zero-Shot / CoT | Prompt Chaining | Skeleton-of-Thought (SoT) |
|---|---|---|---|
| Executiemodel | Enkelvoudig sequentieel | Meervoudig sequentieel (pipeline) | Hybride: 1 sequentieel + $K$ parallel |
| Latentieschaling | Lineair ($O(\sum L_i)$) | Lineair ($O(\sum L_i)$) | Sub-lineair ($O(L_{skelet} + \max L_i)$) |
| Afhankelijkheid tussen stappen | Hoog (volledige autoregressieve context) | Zeer hoog (output $n$ is input $n+1$) | Laag (punten zijn conceptueel orthogonaal) |
| API-aanroepen | 1 | $K$ opeenvolgend | $1 + K$ gelijktijdig |
| Tokenkosten | Laagst (geen context-duplicatie) | Gemiddeld | Hoger (originele prompt wordt $K$ keer herhaald) |
Prompt-ontwerp: De skeletfase en de expansiefase
De effectiviteit van Skeleton-of-Thought hangt volledig af van de precisie van de prompts. Als de skeletprompt te breed formuleert, worden de deelpunten overlappend. Als de expansieprompt te weinig context bevat, verliest het model de overkoepelende verhaallijn.
1. De skeletprompt (Skeleton Prompt)
Deze prompt dwingt het model om een compacte, genummerde lijst te produceren zonder inleidende beleefdheidsvormen of diepere toelichtingen. Hoe korter het skelet, des te sneller de eerste fase klaar is.
[SYSTEEM]
Je bent een gespecialiseerde planner. Jouw enige taak is om een beknopt antwoordskelet
te ontwerpen voor de vraag van de gebruiker.
Regels:
1. Geef uitsluitend een genummerde lijst van 3 tot maximaal 6 kernpunten.
2. Elk punt mag maximaal 3 tot 7 woorden bevatten.
3. Geen inleiding, geen conclusie, geen toelichting per punt.
4. Zorg dat de punten elkaar niet inhoudelijk overlappen.
[GEBRUIKER]
Vraag: Welke architecturale maatregelen zijn noodzakelijk om een RAG-systeem te beveiligen tegen data-lekken?
[ASSISTENT]
1. Strikte document-level autorisatie bij retrieval
2. Encryptie van vector-indices en embeddings
3. Input-sanitisatie tegen indirect prompt injection
4. Context-filtering vóór generatie
5. Output-validatie en datalek-monitoring
2. De expansieprompt (Point-Expansion Prompt)
Vervolgens vuurt het orchestratiesysteem gelijktijdig $K$ requests af naar de model-API. Elke worker ontvangt de volledige context, maar krijgt de expliciete instructie om uitsluitend zijn toegewezen deelpunt uit te werken.
[SYSTEEM]
Je bent een technische schrijver die meewerkt aan een parallel gegenereerd rapport.
Je werkt aan één specifiek onderdeel van een vooraf vastgesteld skelet.
Context van het totale document:
Oorspronkelijke vraag: Welke architecturale maatregelen zijn noodzakelijk om een RAG-systeem te beveiligen tegen data-lekken?
Volledig skelet:
1. Strikte document-level autorisatie bij retrieval
2. Encryptie van vector-indices en embeddings
3. Input-sanitisatie tegen indirect prompt injection
4. Context-filtering vóór generatie
5. Output-validatie en datalek-monitoring
Jouw taak:
Werk uitsluitend punt 3 uit: "Input-sanitisatie tegen indirect prompt injection".
Instructies voor jouw uitvoer:
- Schrijf direct de inhoudelijke alinea's voor dit specifieke punt.
- Begin NIET met een titel, nummering of herhaling van het punt.
- Schrijf geen inleiding of afsluiting voor het hele document.
- Houd de toon zakelijk, feitelijk en diepgaand technisch.
Een werkende Python-implementatie met asyncio
De onderstaande code demonstreert hoe je een Skeleton-of-Thought pipeline bouwt met behulp van Python's asyncio en een generieke OpenAI-compatibele API client. In plaats van lineaire ketens die wachten op opeenvolgende stappen — zoals beschreven in de handleiding over complexe taken opknippen via prompt-chaining — toont dit script hoe gelijktijdige coroutines de totale wachttijd drastisch minimaliseren.
import asyncio
import re
import time
from openai import AsyncOpenAI
client = AsyncOpenAI()
async def generate_skeleton(query: str) -> list[str]:
system_prompt = (
"Je bent een planner. Geef uitsluitend een genummerde lijst van 3 tot 5 "
"korte kernpunten (max 7 woorden per punt) als antwoordskelet. "
"Geen introductie of extra tekst."
)
response = await client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": query}
],
temperature=0.2,
max_tokens=150
)
raw_text = response.choices[0].message.content.strip()
# Parse genummerde regels: "1. Punt" -> "Punt"
points = []
for line in raw_text.split("\n"):
match = re.match(r"^\d+[\.\)]\s*(.+)$", line.strip())
if match:
points.append(match.group(1).strip())
return points
async def expand_point(query: str, skeleton: list[str], point_idx: int, point_title: str) -> str:
skeleton_formatted = "\n".join(f"{i+1}. {p}" for i, p in enumerate(skeleton))
system_prompt = (
"Je bent een technisch expert. Werk uitsluitend het aangewezen punt uit "
"van het onderstaande skelet. Schrijf direct de inhoudelijke tekst. "
"Herhaal de titel of het nummer niet."
)
user_prompt = (
f"Originele vraag: {query}\n\n"
f"Volledig skelet:\n{skeleton_formatted}\n\n"
f"Werk nu punt {point_idx + 1} uit: '{point_title}'."
)
response = await client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
],
temperature=0.5,
max_tokens=400
)
return response.choices[0].message.content.strip()
async def skeleton_of_thought_pipeline(query: str) -> str:
t0 = time.perf_counter()
# Stap 1: Genereer het skelet
skeleton = await generate_skeleton(query)
t_skeleton = time.perf_counter()
print(f"Skelet gereed ({len(skeleton)} punten) in {t_skeleton - t0:.2f}s")
# Stap 2: Parallel uitwerken via asyncio.gather
tasks = [
expand_point(query, skeleton, idx, point)
for idx, point in enumerate(skeleton)
]
expansions = await asyncio.gather(*tasks)
t_expanded = time.perf_counter()
print(f"Alle deelpunten parallel uitgewerkt in {t_expanded - t_skeleton:.2f}s")
# Stap 3: Assemblage
assembled_document = [f"# Analyse: {query}\n"]
for idx, (point, content) in enumerate(zip(skeleton, expansions)):
assembled_document.append(f"## {idx + 1}. {point}\n{content}\n")
final_output = "\n".join(assembled_document)
print(f"Totale verwerkingstijd: {t_expanded - t0:.2f}s")
return final_output
# Voorbeeld-aanroep
# asyncio.run(skeleton_of_thought_pipeline("Hoe schaal je een multi-tenant vector database?"))
Kwaliteit en consistentie: Het ontbreken van cross-point context
De belangrijkste architecturale concessie van Skeleton-of-Thought is het verlies van autoregressieve conditionerende context tussen de deelpunten. Bij een standaard modelaanroep "weet" alinea 4 precies wat er in alinea 2 en 3 is geschreven; het model stemt formuleringen af, bouwt argumenten op en voorkomt dat dezelfde voorbeelden worden herhaald.
Omdat bij SoT alle expansies gelijktijdig plaatsvinden in geïsoleerde contextvensters, kunnen er specifieke kwaliteitsdefecten optreden:
- Stijlbreuken en toongestotter: Worker 1 hanteert een formele academische stijl met passieve zinsconstructies, terwijl Worker 3 overschakelt op een actieve, directe instructietoon.
- Interne redundantie: Verschillende workers definiëren onafhankelijk van elkaar hetzelfde acroniem of lichten hetzelfde basisconcept opnieuw toe in hun inleidende zinnen.
- Tegenstrijdigheden: Bij open vraagstukken kan Worker 2 een technologie aanbevelen die door Worker 4 als onveilig of verouderd wordt bestempeld, zonder dat het document deze nuance expliciteert.
Wanneer consistentie en betrouwbaarheid van redeneringen absolute prioriteit hebben, kan het noodzakelijk zijn om parallelle uitwerkingen te combineren met meervoudige steekproeven, zoals gedocumenteerd in het artikel over self-consistency prompting voor redeneerstappen. Hierbij worden meerdere parallelle paden geëvalueerd om de meest coherente uitkomst te selecteren.
Assemblagestrategieën: Van concatenatie tot recombinatie
Na het voltooien van de parallelle expansie-aanroepen moeten de fragmenten worden samengevoegd tot een coherent eindresultaat. Er zijn drie gangbare methoden om deze aggregatie vorm te geven:
1. Directe concatenatie (Deterministic Stitching)
Dit is de snelste en goedkoopste methode: de orchestrator plakt de titels uit het skelet en de uitgewerkte alinea's achter elkaar in een Markdown- of HTML-structuur. Dit kost 0 extra tokens en 0 milliseconden inferentietijd, maar lost eventuele stijlverschillen of dubbele definities niet op. Dit patroon is uitstekend geschikt voor naslagwerken, modulaire documentatie en gestructureerde checklists.
2. Lichtgewicht reconciliatie (Smoothing Pass)
De samengestelde tekst wordt door een snel, klein taalmodel gehaald met de opdracht om uitsluitend overgangen tussen alinea's te versoepelen en dubbele inleidingen te schrappen, zonder de inhoudelijke feiten te wijzigen. Dit voegt een kleine sequentiële latentie toe (ca. 1 tot 2 seconden), maar verhoogt de redactionele leesbaarheid aanzienlijk.
3. Hiërarchische recombinatie
Voor zeer omvangrijke rapporten kan het skelet zelf recursief zijn: een hoofd-skelet definieert hoofdstukken, waarna sub-skeletten parallel worden gegenereerd en uitgewerkt. De aggregatie verloopt dan boomstructuur-gewijs, waarbij per sectie een samenvattende conclusie wordt gegenereerd.
Wanneer gebruik je Skeleton-of-Thought wel en niet?
Skeleton-of-Thought is geen universele vervanging voor traditionele prompting. Het is een gespecialiseerd patroon dat excelleert onder specifieke randvoorwaarden en faalt onder andere.
Vuistregel: Gebruik Skeleton-of-Thought wanneer de uitvoer lang moet zijn (>800 tokens), de structuur zich leent voor opsomming of sectie-indeling, en de tijd tot het volledige antwoord (Time-to-Last-Token) bedrijfskritisch is.
Uitstekende use-cases:
- Uitgebreide overzichtsrapporten: Vergelijkingen van marktsegmenten, analyses van wetgeving of overzichten van best practices.
- Systeemarchitectuur-documenten: Waarbij frontend, backend, database, beveiliging en deployment parallel kunnen worden beschreven.
- Educatieve handleidingen en curricula: Waarbij elk hoofdstuk een afgebakend onderwerp behandelt.
- Brainstorming en optie-analyses: Het parallel genereren van vijf verschillende scenario's met hun voor- en nadelen.
Ongeschikte use-cases:
- Wiskundige bewijsvoering en logische deductie: Waarbij elke stap mathematisch afhangt van de vorige.
- Complexe software-codebases: Waarbij functies in bestand $B$ afhankelijk zijn van de exacte types en declaraties die zojuist in bestand $A$ zijn gegenereerd.
- Creatieve verhaallijnen en proza: Waarbij narratieve spanningsopbouw en subtiele foreshadowing een doorlopende contextuele stroom vereisen.
Kosten, rate limits en token-overhead in productie
De tijdswinst van Skeleton-of-Thought komt met een duidelijke financiële en infrastructurele prijs. In plaats van één prompt-context sturen we de initiële vraag en het skelet $K$ keer mee naar de LLM-aanbieder. Bij een skelet van 5 punten wordt de basiscontext vijf keer gedupliceerd in de input-tokens.
Bovendien zorgt een plotselinge burst van 5 tot 10 gelijktijdige requests per eindgebruiker voor een zware belasting van de API rate limits (zowel Requests-Per-Minute als Tokens-Per-Minute). Wanneer meerdere gebruikers gelijktijdig een SoT-pipeline triggeren, moet de orchestratielaag voorzien zijn van robuuste concurrency limits, semaforen en retry-mechanismen met exponentiële backoff om HTTP 429-fouten te voorkomen.
Tot slot speelt prompt-caching een cruciale rol in moderne infrastructuren. Omdat de $K$ parallelle expansie-aanroepen grotendeels identieke systeemprompts en documentcontexten delen, kunnen API-gateways met automatische prefix-caching de kosten en de verwerkingstijd van deze redundante invoer aanzienlijk verlagen. Door de statische context consistent vooraan in het promptvenster te plaatsen, wordt het financiële nadeel van Skeleton-of-Thought in productieomgevingen grotendeels geneutraliseerd.


