Recipes · agents
Planner / Executor
Patrón de dos etapas: un LLM planifica los pasos, otro los ejecuta. Reduce alucinaciones en tareas complejas al separar el razonamiento de la acción.
claude-opus-4-5agentmulti-stepplanningtypescriptActualizado 2026-04-23
Concepto
En lugar de pedir a un solo modelo que razone y actúe al mismo tiempo, separamos:
- Planner — toma el objetivo y produce un plan estructurado (JSON o lista numerada).
- Executor — toma cada paso del plan y lo ejecuta con herramientas.
Esto reduce las alucinaciones porque el modelo planificador no tiene acceso a herramientas y no puede "impacientar" ejecutando pasos precipitados.
System Prompt — Planner
You are a planning agent. Your job is to take a high-level goal and break it
down into a precise, ordered list of steps that a separate executor agent will
carry out.
## Output format
Always respond with valid JSON matching this schema:
{
"goal": "<restate the goal clearly>",
"steps": [
{
"id": 1,
"action": "<imperative verb phrase>",
"depends_on": [],
"notes": "<optional context for the executor>"
}
]
}
## Rules
- Each step must be atomic — one action, one outcome.
- Never include steps you are uncertain about. If the goal is ambiguous, ask
one clarifying question before producing the plan.
- Keep steps under 10 unless truly necessary.
- Do not suggest tools by name — the executor decides how to implement each step.
System Prompt — Executor
You are an executor agent. You will be given one step from a plan and must
carry it out using the available tools.
## Input format
You will receive:
- The overall goal (for context)
- The current step: { id, action, notes }
- Results of previous steps (if any)
## Rules
- Execute exactly the step described — do not improvise or skip ahead.
- If a step is impossible to execute, report why clearly and stop.
- Return a structured result:
{ "step_id": N, "status": "success" | "failed", "output": "..." }
Implementación (TypeScript)
typescript
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
interface Step {
id: number;
action: string;
depends_on: number[];
notes?: string;
}
interface Plan {
goal: string;
steps: Step[];
}
interface StepResult {
step_id: number;
status: "success" | "failed";
output: string;
}
async function plan(goal: string): Promise<Plan> {
const response = await client.messages.create({
model: "claude-opus-4-5",
max_tokens: 2048,
system: PLANNER_SYSTEM_PROMPT,
messages: [{ role: "user", content: goal }],
});
const text = response.content
.filter((b): b is Anthropic.TextBlock => b.type === "text")
.map((b) => b.text)
.join("");
return JSON.parse(text) as Plan;
}
async function executeStep(
plan: Plan,
step: Step,
previousResults: StepResult[],
tools: Anthropic.Tool[],
executeTool: (name: string, input: unknown) => Promise<string>,
): Promise<StepResult> {
const messages: Anthropic.MessageParam[] = [
{
role: "user",
content: JSON.stringify({
goal: plan.goal,
current_step: step,
previous_results: previousResults,
}),
},
];
const response = await client.messages.create({
model: "claude-opus-4-5",
max_tokens: 4096,
system: EXECUTOR_SYSTEM_PROMPT,
tools,
messages,
});
// Handle tool calls (simplified — use full agentic loop for complex steps)
for (const block of response.content) {
if (block.type === "tool_use") {
await executeTool(block.name, block.input);
}
}
const text = response.content
.filter((b): b is Anthropic.TextBlock => b.type === "text")
.map((b) => b.text)
.join("");
try {
return JSON.parse(text) as StepResult;
} catch {
return { step_id: step.id, status: "success", output: text };
}
}
// Orchestrator
async function runPlannerExecutor(
goal: string,
tools: Anthropic.Tool[],
executeTool: (name: string, input: unknown) => Promise<string>,
) {
const thePlan = await plan(goal);
console.log("Plan:", JSON.stringify(thePlan, null, 2));
const results: StepResult[] = [];
for (const step of thePlan.steps) {
const result = await executeStep(thePlan, step, results, tools, executeTool);
results.push(result);
if (result.status === "failed") {
console.error(`Step ${step.id} failed:`, result.output);
break;
}
}
return results;
}Ventajas vs. loop simple
| Aspecto | Agentic Loop simple | Planner / Executor |
|---|---|---|
| Coste | Menor (un modelo) | Mayor (dos pasadas) |
| Transparencia | El plan emerge implícitamente | El plan es explícito y auditable |
| Corrección humana | Difícil de interrumpir | Se puede revisar el plan antes de ejecutar |
| Tareas largas | Se puede perder en el contexto | Cada paso tiene contexto fresco |
Antes de ejecutar el plan, muéstralo al usuario para que lo apruebe. Esto evita ejecutar pasos costosos o destructivos basados en un malentendido del objetivo.