Planner-Executor AI Workflow: Using Opus for Planning and Budget Models for Execution
My Claude API bill hit $300 last month. Most of that spend went to routine coding tasks — code reviews, documentation generation, test case creation. Tasks that didn’t need Opus-level reasoning.
I had two options: cut back on AI usage or find a cheaper way to handle the routine work. I chose the second option and tested a planner-executor workflow for five days.
The results: 60-80% cost reduction with minimal quality loss.
The Core Idea
The planner-executor pattern separates high-level reasoning from task execution. Instead of sending every request to Opus, I use it only for planning. Then I hand those plans to budget models for execution.
Task -> Opus Planning -> Detailed Plan -> Budget Execution -> Implementation -> ReviewOpus creates detailed, step-by-step instructions. Budget models follow those instructions. A review step catches errors.
Why This Works
I tested three models over five days: GLM-5.1, MiniMax-2.7, and Claude Haiku. Each had different strengths:
+------------------+----------------------+----------------------+| Model | Strength | Best Use Case |+------------------+----------------------+----------------------+| Claude Opus | Deep reasoning | Planning phase || Claude Sonnet | Balanced | Review phase || Claude Haiku | Fast, cheap | Simple execution || GLM-5.1 | Strong logic | Complex execution || MiniMax-2.7 | Fast execution | Rapid iteration |+------------------+----------------------+----------------------+The key insight from my testing: plan quality determines execution success. When Opus creates a plan that a “junior developer” can follow, MiniMax performs well. When the plan is vague or ambiguous, execution fails.
Setting Up the Workflow
Phase 1: Planning with Opus
Opus analyzes the task and breaks it into atomic steps. The prompt needs to emphasize creating instructions for a less capable model:
def create_plan(self, task: str, context: str) -> dict: """Use Opus to create detailed implementation plan""" prompt = f"""You are creating a detailed implementation plan for a junior developer.
Task: {task}Context: {context}
Create a step-by-step plan that:1. Breaks down the task into atomic operations2. Specifies exact file paths and function names3. Includes error handling considerations4. Provides test cases to validate each step
Format as JSON with keys: steps, files_to_modify, tests_needed, edge_cases""" response = self.client.messages.create( model="claude-3-opus", max_tokens=4096, messages=[{"role": "user", "content": prompt}] ) return self._parse_plan(response.content[0].text)I learned to make plans more explicit after several failures. When I wrote “implement authentication”, MiniMax created a basic login form. When I wrote “create JWT-based authentication with refresh tokens, rate limiting, and session management”, MiniMax delivered a complete system.
Phase 2: Execution with Budget Models
The executor receives the plan and implements it step by step:
def execute_plan(self, plan: dict) -> dict: """Execute plan with budget model""" prompt = f"""Follow this plan exactly. If you encounter ambiguity, note it for review.
Plan:{plan['steps']}
Implement step by step, providing code for each step.Format output as JSON with keys: implemented_steps, code_changes, issues_found""" response = self.client.messages.create( model="minimax-2.7", # or glm-5.1 or haiku max_tokens=8192, messages=[{"role": "user", "content": prompt}] ) return self._parse_execution(response.content[0].text)The “follow exactly” instruction matters. Without it, budget models sometimes improvise. Improvisation leads to drift from the original plan.
Phase 3: Review with Sonnet
Review catches what budget models miss:
def review_implementation(self, plan: dict, implementation: dict) -> dict: """Review implementation against original plan""" prompt = f"""Review this implementation against the original plan:
Original Plan:{plan}
Implementation:{implementation}
Check for:1. Plan adherence (each step completed correctly)2. Edge cases missed3. Code quality issues4. Security concerns
Provide: approval_status, issues, suggested_fixes""" response = self.client.messages.create( model="claude-3.5-sonnet", max_tokens=2048, messages=[{"role": "user", "content": prompt}] ) return self._parse_review(response.content[0].text)I skip review for trivial tasks. For anything touching production code or security, review is mandatory.
The Cost Math
Here’s what the numbers look like for a typical feature development cycle:
MODEL_COSTS = { # Input cost per 1M tokens "claude-3-opus": 15.00, "claude-3.5-sonnet": 3.00, "claude-3-haiku": 0.25, "minimax-2.7": 0.10, # estimated "glm-5.1": 0.50, # estimated}
def calculate_workflow_cost( planning_tokens: int, execution_tokens: int, review_tokens: int, executor_model: str = "minimax-2.7") -> dict: """Calculate cost comparison for different workflows"""
# Traditional: All Opus traditional_cost = ( (planning_tokens + execution_tokens + review_tokens) / 1_000_000 * MODEL_COSTS["claude-3-opus"] )
# Planner-Executor: Opus + Budget + Sonnet pe_cost = ( planning_tokens / 1_000_000 * MODEL_COSTS["claude-3-opus"] + execution_tokens / 1_000_000 * MODEL_COSTS[executor_model] + review_tokens / 1_000_000 * MODEL_COSTS["claude-3.5-sonnet"] )
savings = traditional_cost - pe_cost savings_percent = (savings / traditional_cost) * 100
return { "traditional_cost": traditional_cost, "planner_executor_cost": pe_cost, "savings": savings, "savings_percent": savings_percent }Running the numbers for a typical feature:
Traditional (all Opus): $0.915Planner-Executor: $0.225Savings: $0.69 (75%)The execution phase consumes most tokens. That’s where the savings come from.
Model Selection Guide
I choose executors based on task characteristics:
+------------------------+------------+------------------+| Task Characteristic | Executor | Reason |+------------------------+------------+------------------+| Speed critical | MiniMax | Fastest response || Logic complex | GLM-5.1 | Better reasoning || Routine/boilerplate | Haiku | Cheapest || High-stakes production | Sonnet | Safer fallback |+------------------------+------------+------------------+GLM-5.1 has better logic but runs slower. MiniMax is fast but sometimes misses subtle edge cases. Haiku is cheap but struggles with complex tasks.
Mistakes I Made
Vague Plans
My first attempts failed because plans lacked specificity. “Add error handling” produced inconsistent results across executors. “Add try-catch blocks to database operations with specific error messages for connection failures, query timeouts, and constraint violations” produced consistent output.
Skipping Review
I skipped review on a database migration. The executor missed a cascade delete that wiped related records. Review would have caught it.
Wrong Executor Choice
I sent a complex refactoring task to Haiku. It produced syntactically correct code that broke the application logic. GLM-5.1 handled the same task correctly.
No Fallback
When MiniMax failed on a task, I had no fallback mechanism. Now I route failed executions to Sonnet automatically.
Practical Template
Here’s the prompt template I use for different task types:
PLANNING_PROMPTS = { "feature_development": """Task: Implement {feature_name}Requirements: {requirements}Existing Code Context: {context}
Create a plan covering:1. New files/components needed2. Modifications to existing code3. API changes4. Database schema changes (if any)5. Testing strategy6. Rollback plan""",
"bug_fix": """Task: Fix bug {bug_description}Error Context: {error_context}Affected Files: {files}
Create a plan that:1. Identifies root cause2. Proposes fix approach3. Lists affected components4. Defines test cases5. Considers side effects""",}The key is structure. Each prompt forces Opus to think through implementation details, not just high-level concepts.
When I Still Use Opus Directly
Some tasks don’t benefit from this workflow:
- Architectural decisions — Need deep reasoning throughout
- Novel problems — No clear plan structure exists yet
- Security analysis — Risk outweighs cost savings
- Complex debugging — Execution phase would fail
For these, I send the full task to Opus without the executor step.
Claude Code Configuration
I configured Claude Code with model roles:
{ "env": { "ANTHROPIC_AUTH_TOKEN": "your-token", "ANTHROPIC_BASE_URL": "https://api.anthropic.com" }, "defaultModel": "claude-3-opus", "fallbackModel": "claude-3.5-sonnet", "maxBudgetUsd": 10.00, "modelRoles": { "planning": "claude-3-opus", "execution": "minimax-2.7", "review": "claude-3.5-sonnet" }}This lets me switch roles based on task phase without manual configuration changes.
Summary
The planner-executor workflow changed how I use AI for development. Opus handles the thinking. Budget models handle the doing. Sonnet handles the checking.
The tradeoff is clear: I spend slightly more time crafting detailed plans, but I save 60-80% on API costs. For routine tasks, that tradeoff works.
Three principles matter most:
- Plan specificity — Vague plans fail. Detailed plans succeed.
- Review discipline — Skip review only for trivial tasks.
- Executor matching — Match executor to task characteristics.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments