Naar inhoud
lightbulb Welkom op de nieuwe kennisbank | We hebben de docs volledig vernieuwd met meer dan 160 features. Bekijk wat nieuw isarrow_forward

AI-agent architecturen: ReAct, Plan-and-Execute en Reflexion

Overzicht van de belangrijkste AI-agent architecturen (ReAct, Plan-and-Execute, Reflexion en LATS) en hoe je de juiste kiest voor jouw use case.

Wat is een AI-agent?

Een AI-agent is een systeem waarbij een taalmodel autonoom beslissingen neemt over welke acties het uitvoert om een doel te bereiken. Het verschil met een gewone LLM-aanroep is de loop: het model krijgt het resultaat van zijn actie terug als nieuwe input en kan op basis daarvan nieuwe acties kiezen.

Doel -> Model -> Actie -> Resultaat -> Model -> Actie -> ... -> Einddoel

Drie dingen maken een systeem een echte agent:

  1. Autonomie: het model beslist zelf welke stappen te nemen.
  2. Toolgebruik: het model kan acties uitvoeren in de wereld (API-aanroepen, berekeningen, bestandsoperaties).
  3. Iteratief redeneren: het model verwerkt resultaten en past zijn plan aan.
info

Agent of workflow?

Anthropic maakt een nuttig onderscheid: een workflow orkestreert modellen en tools via vaste, vooraf geschreven codepaden, terwijl een agent het model zelf de volgorde en het toolgebruik laat bepalen. Begin altijd met de eenvoudigste oplossing. Soms is dat geen agent maar een vaste workflow, die voorspelbaarder en goedkoper is.

ReAct: de meestgebruikte architectuur

ReAct (Reasoning + Acting) combineert chain-of-thought redeneren met toolgebruik. Het model genereert afwisselend:

  • Thought: het model denkt na over de situatie en wat te doen.
  • Action: het model kiest een tool en parameters.
  • Observation: het resultaat van de tool-aanroep.
info

Oorsprong

ReAct werd gepubliceerd door Yao et al. (arXiv 2022, gepresenteerd op ICLR 2023) bij Google Research. Het is sindsdien de basis voor de meeste agent-frameworks, waaronder LangChain, LlamaIndex en CrewAI.

ReAct in code

async function reactAgent(goal: string, tools: Tool[]): Promise<string> {
  const messages: Message[] = [
    { role: "system", content: REACT_SYSTEM_PROMPT },
    { role: "user", content: goal },
  ];

  for (let step = 0; step < MAX_STEPS; step++) {
    const response = await llm.complete(messages, { tools });

    if (response.stop_reason === "end_turn") {
      return extractFinalAnswer(response);
    }

    if (response.stop_reason === "tool_use") {
      const toolCall = extractToolCall(response);
      const result = await executeTool(toolCall, tools);

      messages.push({ role: "assistant", content: response.content });
      messages.push({
        role: "user",
        content: [{ type: "tool_result", tool_use_id: toolCall.id, content: result }],
      });
    }
  }
  throw new Error(`Agent bereikte maximumaantal stappen (${MAX_STEPS})`);
}

Plan-and-Execute

Voor taken die meerdere onafhankelijke stappen vereisen, splitst Plan-and-Execute het werk in twee fasen:

  1. Planner: genereert een gestructureerd plan met stappen.
  2. Executor: voert elke stap uit, eventueel parallel.
interface Plan {
  steps: { id: string; description: string; depends_on: string[] }[];
}

async function planAndExecute(goal: string): Promise<string> {
  const plan: Plan = await planner.createPlan(goal);

  const results = new Map<string, string>();
  const queue = [...plan.steps];

  while (queue.length > 0) {
    const ready = queue.filter(step =>
      step.depends_on.every(dep => results.has(dep))
    );

    const executed = await Promise.all(
      ready.map(async (step) => {
        const context = step.depends_on.map(dep => results.get(dep)).join("
");
        const result = await executor.execute(step.description, context);
        return { id: step.id, result };
      })
    );

    executed.forEach(({ id, result }) => results.set(id, result));
    queue.splice(0, queue.length, ...queue.filter(s => !ready.includes(s)));
  }

  return await synthesizer.combine(goal, results);
}

Reflexion

Reflexion voegt een zelfevaluatie-stap toe: na elke poging evalueert het model zijn eigen output en leert van fouten.

async function reflexionAgent(goal: string): Promise<string> {
  let draft = await agent.attempt(goal);

  for (let i = 0; i < MAX_REFLECTIONS; i++) {
    const reflection = await evaluator.critique(goal, draft);
    if (reflection.satisfied) break;
    draft = await agent.revise(draft, reflection.feedback);
  }
  return draft;
}

LATS

LATS (Language Agent Tree Search) combineert ReAct, planning en reflectie met Monte Carlo Tree Search. Het model bemonstert meerdere ReAct-trajecten, vormt daar een zoekboom mee en laat een LLM elke toestand beoordelen om het beste pad te kiezen. Dat levert sterke resultaten bij complexe taken (bijvoorbeeld programmeren en webnavigatie), maar tegen flink hogere kosten. Het is gepubliceerd op ICML 2024.

Architectuurkeuze

Kies de architectuur op basis van het soort taak:

  • Eenvoudige taak: ReAct. Voor sequentiële stappen zonder dat je vooraf een plan hoeft te kennen. Voorbeelden: klantenservice, datasearches, eenvoudige automatisering.
  • Complexe taak: Plan-and-Execute. Voor taken met duidelijke deeldoelen die parallel uitgevoerd kunnen worden. Voorbeelden: rapport genereren, codebase analyseren, multi-stap research.
  • Kwaliteitskritisch: Reflexion. Wanneer de output aan hoge kwaliteitseisen moet voldoen. Voorbeelden: juridische documenten, code reviews, technische specificaties.
  • Maximale kwaliteit, kosten secundair: LATS. Wanneer je het beste pad wilt vinden en de extra LLM-aanroepen acceptabel zijn. Voorbeelden: research en lastige decision-making.

Vergelijking

Architectuur Sterkte Zwakte Gebruik
ReAct Eenvoudig, flexibel Inefficient bij parallelliseerbare stappen Algemeen
Plan-and-Execute Parallel, reproduceerbaar Rigide plan als doel onduidelijk is Gestructureerde taken
Reflexion Hoge kwaliteit output Duur door meerdere LLM-aanroepen Kwaliteitskritisch
LATS Beste pad zoeken Zeer hoge kosten Research
warning

Houd je tokens in de gaten

Agentische systemen ruilen latency en kosten in voor betere taakprestaties. Volgens Anthropic verbruiken agents al snel een veelvoud van de tokens van een gewone chat-aanroep, en multi-agent opstellingen nog meer. Zet alleen een agent in als die flexibiliteit echt waarde toevoegt, en bewaak je tokenbudget actief.

Token-gebruik beheersen

Agents kunnen snel grote hoeveelheden tokens consumeren door de groeiende message-history. Een eenvoudige strategie is het oudere midden van de geschiedenis samenvatten en de laatste berichten ongewijzigd laten:

function compressHistory(messages: Message[], maxTokens: number): Message[] {
  const systemMessage = messages[0];
  const lastN = messages.slice(-6);
  const summary = summarizeMiddleMessages(messages.slice(1, -6));
  return [systemMessage, { role: "user", content: summary }, ...lastN];
}
lightbulb

Begin klein, voeg pas complexiteit toe als het loont

Bouw eerst een ReAct-agent met een harde stappenlimiet en goede logging. Stap pas over op Plan-and-Execute, Reflexion of LATS als je in de praktijk ziet dat je het echt nodig hebt. Elke extra laag kost tokens, latency en debug-tijd.

Hoeveel stappen mag een ReAct-agent nemen?

Stel een limiet in van ongeveer 10 tot 20 stappen, afhankelijk van de taak. Zonder limiet kan een agent in een oneindige loop raken. Log het aantal stappen en monitor op terugkerende patronen.

Wanneer gebruik ik agents in plaats van gewone LLM-aanroepen?

Gebruik agents als de taak meerdere tool-aanroepen vereist waarbij het resultaat van de ene de invoer van de volgende bepaalt. Voor enkelvoudige lookups is een directe tool-aanroep efficienter.

Hoe betrouwbaar zijn agents?

Minder betrouwbaar dan deterministische code. Zet agents in voor taken waarbij flexibiliteit en redeneren meer waard zijn dan voorspelbaarheid, en voeg validatiestappen toe voor kritieke acties.

Wat is het verschil met een workflow?

Een workflow is deterministisch: stap A leidt altijd naar stap B. Een agent is non-deterministisch: het model beslist zelf de volgorde. Gebruik een workflow als je vooraf weet hoe het pad eruitziet.

Welke frameworks ondersteunen deze architecturen?

LangChain, LlamaIndex en CrewAI ondersteunen ReAct out of the box en bieden bouwstenen voor plannen en reflectie. Voor LATS bestaan losse implementaties die je bovenop een ReAct-laag zet.

Kan ik architecturen combineren?

Ja. In de praktijk combineer je vaak een planner met ReAct-uitvoerders, of voeg je een Reflexion-stap toe aan een ReAct-loop. LATS is feitelijk al zo'n combinatie van plannen, handelen en reflecteren.