Shaping behaviour
Prompts, budgets, and deciding what needs a human.
In short: three dials control how your agent acts. What you tell it to do (the prompt), how far it's allowed to go (budgets), and what it must ask permission for (risk). Most of the behaviour you want comes from these, not from code.
The prompt
Your agent's instructions live in the template you scaffolded — for the support agent, in
templates/support/langgraph/prompt.py. It's a plain string. Edit it.
What belongs in it:
SYSTEM_PROMPT = """You are a support agent for Northwind, a B2B logistics company.
Always search the knowledge base before answering a policy question. Never
guess at a policy — if the knowledge base doesn't cover it, say so and escalate.
Refunds under $200 for damaged goods are standard. Anything larger, or anything
where the customer has already been refunded this quarter, needs a human.
Be brief. Customers are operations staff who are busy — three sentences beats
three paragraphs.
"""
Most prompt effort goes into tone and produces very little. The lines that change outcomes are the ones that tell the agent when to use which tool and when to stop and ask. "Be friendly" changes almost nothing; "always search the KB before answering a policy question" changes everything.
Behaviour belongs in the prompt, not in if statements. agentFast's templates deliberately contain
no intent-matching regexes — routing a request by keyword is brittle in a way that instructions
aren't, and it's the first thing that breaks when a customer phrases something unexpectedly.
Budgets
Budgets are what stop a stuck agent becoming an invoice. Checked before every model call:
budget:
max_iterations: 50 # how many times it can think
max_tokens: 150000 # total input + output for the run
max_duration_ms: 300000 # wall clock — five minutes
Rough guidance:
| Kind of agent | iterations | tokens | duration | |---|---|---|---| | Support ticket | 20–50 | 150k | 5 min | | Research task | 60–100 | 400k | 20 min | | Code change | 80–150 | 500k | 30 min |
Hitting a limit ends the run as error with a readable reason — not a silent loop, and not a
half-finished job that looks finished.
Letting the agent size itself
Rather than picking one budget for every request, the pre-flight classifier reads the incoming task and adjusts:
complexity_classifier: heuristic # off | heuristic | llm
heuristic is free and works on task shape. llm uses a cheap model call for a better read, worth
it when your workload varies a lot. off pins every run to the configured budget.
The decision shows up in the trace as a planning step, so you can see what it decided and why.
What needs a human
The most consequential configuration in the file:
tool_overrides:
refund_request:
risk: high
hitl_mode: suspend # stop and wait
send_customer_email:
risk: high
hitl_mode: defer # queue it, keep working
order_lookup:
risk: low # just do it
A useful test for each tool: if the agent did this a hundred times by mistake overnight, would you be fine in the morning? If yes, low risk. If you'd be on the phone to your bank, high.
suspend when the agent can't sensibly continue without an answer. defer when it can get on with
something else and this can happen later.
Choosing a model
model: claude-sonnet-4-5
Any LangChain model id works — openai:gpt-4o, anthropic:claude-haiku-4-5, and so on. A cheaper
model on a well-instructed agent with good tools usually beats an expensive one with vague
instructions, so try tightening the prompt before reaching for a bigger model.
scripted-support runs the whole harness deterministically with no API key — useful in tests and
in CI.
Check you didn't break it
Every behaviour change should be followed by:
agentfast eval
This is the point of evals. Prompt edits are the single most common way an agent silently regresses — you improve one case and quietly break three others, and nothing errors. The eval gate is what turns that into a failed build instead of a support ticket.