Most agent failures trace back to sloppy planning, not weak models. This AI agent planning tool use guide lays out an ordered path for shipping agents that decompose tasks, call tools reliably, and recover from partial failures. We focus on concrete code and the tradeoffs you’ll hit in production.
1. Pin down the task boundary
Write a spec before touching model code. Define the input the agent receives, the final output shape, and which tools are allowed. Ambiguous goals produce agents that loop or hallucinate steps.
{
"task": "Book a flight and reserve a rental car for the dates",
"inputs": {
"origin": "SFO",
"destination": "JFK",
"depart_date": "2025-06-01",
"return_date": "2025-06-08"
},
"output_schema": {
"flight_confirmation": "string",
"car_confirmation": "string",
"total_cost_usd": "number"
},
"allowed_tools": ["search_flights", "book_flight", "search_cars", "book_car"]
}
If you skip this, the planner will invent tools or emit free-form text that your executor can’t parse.
2. Pick a planning representation
Use a structured step list, not a prose narrative. Each step should name a tool, its arguments, and a success criterion. This keeps the execution loop dumb and testable.
interface PlanStep {
step_id: number;
tool: string;
args: Record<string, unknown>;
expects: string; // human-readable success condition
}
interface Plan {
steps: PlanStep[];
final_answer_key: string;
}
The AI agent planning tool use guide recommends JSON over natural language because you can validate it with a schema and feed it directly to a loop. The tradeoff: the model must support JSON mode or function calling reliably.
Why plain text fails
Free-text plans like “First, search flights. Then book the cheapest.” require a second LLM pass to extract intent. That adds latency and a failure surface. Reserve natural language for the planner’s internal reasoning, not the contract.
3. Build a strict tool registry
Each tool is a function with a JSON schema and a timeout. The registry is the only thing the executor can call.
from dataclasses import dataclass
import asyncio
@dataclass
class Tool:
name: str
schema: dict
fn: callable
timeout: float = 5.0
registry = {}
def register_tool(name, schema, timeout=5.0):
def deco(fn):
registry[name] = Tool(name, schema, fn, timeout)
return fn
return deco
@register_tool("search_flights", {
"type": "object",
"properties": {"origin": {"type": "string"}, "dest": {"type": "string"}},
"required": ["origin", "dest"]
})
async def search_flights(origin: str, dest: str):
# call external API
return [{"id": "FL123", "price": 300}]
If a tool isn’t in the registry, the executor must reject the step before calling anything. That prevents prompt-injection from spawning arbitrary code.
4. Generate the plan in one shot
Call a strong model with the task spec, tool schemas, and a system prompt demanding a Plan object. Use an OpenAI-compatible client.
from openai import OpenAI
client = OpenAI(base_url="https://api.n4n.ai/v1", api_key="KEY")
# n4n.ai exposes one OpenAI-compatible endpoint covering 240+ models,
# with automatic fallback when a provider is rate-limited or degraded.
resp = client.chat.completions.create(
model="anthropic/claude-3.5-sonnet",
messages=[
{"role": "system", "content": "Produce a Plan JSON per the schema. No extra text."},
{"role": "user", "content": task_spec_json}
],
response_format={"type": "json_object"}
)
plan = Plan.parse_raw(resp.choices[0].message.content)
This AI agent planning tool use guide assumes you validate plan against your Pydantic/JSON schema immediately. Invalid plans should trigger a replan with a stricter prompt, not a guess.
5. Execute step-by-step with checks
The executor walks plan.steps in order. It calls the tool, enforces the timeout, and stores the result keyed by step_id.
async def execute_plan(plan: Plan):
results = {}
for step in plan.steps:
tool = registry.get(step.tool)
if not tool:
raise ValueError(f"Unknown tool {step.tool}")
try:
res = await asyncio.wait_for(
tool.fn(**step.args), timeout=tool.timeout
)
results[step.step_id] = res
except asyncio.TimeoutError:
results[step.step_id] = {"error": "timeout"}
return results
Pitfall: swallowing errors and continuing. If a step that later steps depend on fails, you must halt or replan. Track dependencies explicitly if your graph isn’t strictly linear.
6. Replan on tool failure
When a step returns an error, don’t blindly retry. Send the failed step, its error, and prior results back to the planner with a constraint to avoid the same bad args.
replan_prompt = f"Step {failed_id} failed: {err}. Prior results: {results}. Produce a revised Plan."
# same client call as section 4, different model maybe
Tradeoff: replanning costs another model call and adds latency. For transient errors (timeout, 429), one retry with backoff is cheaper. Use replanning for semantic failures—invalid arguments, missing data.
7. Control context growth
Tool outputs can be huge. Truncate or summarize before feeding back to the model. Keep only fields the next steps need.
def trim(result: dict, keep_keys: list[str]):
return {k: result[k] for k in keep_keys if k in result}
If you skip this, you’ll blow the context window and silently drop earlier steps. The AI agent planning tool use guide treats context as a budget: log token counts per loop iteration.
8. Validate with offline simulations
Replace real tools with fakes that return canned data. Assert the planner produces valid steps and the executor handles happy path and a forced failure.
@register_tool("search_flights", {"type": "object", "properties": {}}, timeout=1)
async def fake_search(**kwargs):
return [{"id": "TEST", "price": 1}]
Run this in CI. If the model provider changes, your tests catch schema drift before users do.
Common pitfalls and tradeoffs
- Over-decomposition. Ten tiny steps mean ten model-adjacent calls and more latency. Group independent calls.
- Strict schema vs flexibility. JSON mode is reliable but the model may refuse impossible tasks instead of explaining. Provide an
errorstep type. - Provider downtime. Even with fallback, a planner call can fail. Cache the last good plan for read-only tasks.
- Cost. A replan per failure multiplies tokens. Set a max replan count (e.g., 2) and surface a clear error.
Building agents is mostly systems engineering around the model, not model tuning. This AI agent planning tool use guide gives you the skeleton; adapt the schemas to your domain and you’ll have something that survives real traffic.