Agent Architecture Patterns
The core agent architecture patterns explained with Java: ReAct, plan-and-execute, reflection, orchestrator-worker and routing — when to use each, and why simpler is usually better.
On this page
There are a handful of agent architecture patterns worth knowing, and most production agents use the simplest one. This tutorial covers each pattern, the problem shape it fits, and the honest guidance that you should reach for the more elaborate ones far less often than the literature suggests.
Key Takeaways
- ReAct (reason-act-observe) is the default and covers most cases. Start here.
- Plan-and-execute suits long tasks whose shape is knowable — a visible plan you can inspect.
- Reflection raises quality on tasks with a clear "better", at extra cost.
- Orchestrator-worker and routing handle genuinely heterogeneous sub-tasks — use sparingly.
ReAct: the default
Reason, act, observe, repeat. The agent thinks, calls a tool, sees the result, and continues until done. Spring AI and LangChain4j run this loop for you.
// A ReAct agent is just tools plus a bounded loop — the library handles it.
Agent agent = AiServices.builder(Agent.class)
.chatModel(model)
.tools(new InvestigationTools())
.maxSequentialToolsInvocations(8)
.build();Its strength is flexibility: it adapts step by step to what each observation reveals. Its weakness is that on long tasks it can meander, because it never commits to an overall plan.
Plan-and-execute
For longer tasks, make a plan first, then execute it. The plan is inspectable and the execution is more directed.
public Result solve(String task) {
// 1. Plan: the model produces an ordered list of steps.
Plan plan = planner.plan(task); // structured output: List<Step>
// 2. Execute each step, feeding results forward.
List<StepResult> results = new ArrayList<>();
for (Step step : plan.steps()) {
StepResult result = executor.execute(step, results);
results.add(result);
// Optional: re-plan if a step reveals the plan was wrong.
if (result.requiresReplan()) {
plan = planner.replan(task, results);
}
}
return synthesise(results);
}Reflection
Generate, then critique, then revise. Reflection raises quality where there is a clear notion of better:
public String writeWithReflection(String task) {
String draft = writer.write(task);
for (int i = 0; i < MAX_REVISIONS; i++) {
Critique critique = critic.review(draft); // structured: issues + severity
if (critique.isAcceptable()) {
break;
}
draft = writer.revise(draft, critique);
}
return draft;
}It works well for code (does it compile, pass tests, handle edge cases?) and writing (is it clear, complete, on-brief?). It costs extra model calls per revision, so reserve it for tasks where quality outweighs latency and cost.
Orchestrator-worker
An orchestrator decomposes a task and delegates to specialised workers, then combines results. Use it when sub-tasks need genuinely different tools or prompts:
public Report research(String question) {
List<SubQuestion> subs = orchestrator.decompose(question);
// Workers run concurrently — on Java 21, cheap on virtual threads.
List<Finding> findings = subs.parallelStream()
.map(sub -> switch (sub.type()) {
case FILINGS -> filingsWorker.analyse(sub);
case NEWS -> newsWorker.analyse(sub);
case DATA -> dataWorker.analyse(sub);
})
.toList();
return orchestrator.synthesise(question, findings);
}The FinAgentic project is a full worked example of this pattern.
Routing
The simplest multi-path pattern: classify the input and dispatch. It is a chain, not really an agent, because the routing is deterministic — but it belongs in the same mental toolkit.
return switch (router.classify(request)) {
case BILLING -> billingAgent.handle(request);
case TECHNICAL -> technicalAgent.handle(request);
case GENERAL -> generalAgent.handle(request);
};Choosing a pattern
| Pattern | Use when | Cost |
|---|---|---|
| ReAct | Default; exploratory, tool-using tasks | Low |
| Plan-and-execute | Long tasks with a knowable shape | Medium |
| Reflection | Quality matters more than latency | High (revisions) |
| Orchestrator-worker | Heterogeneous sub-tasks | High (many agents) |
| Routing | Distinct handlers by category | Low |
Next
Frequently Asked Questions
What is the most common agent architecture pattern?
When should I use plan-and-execute instead of ReAct?
What is the reflection pattern?
What is the orchestrator-worker pattern?
Related tutorials
- What Is Agentic AI? A Complete GuideA clear, hype-free explanation of agentic AI: how it differs from generative AI, the five components of an agent, when autonomy is worth it, and when a plain workflow is the better engineering choice.
- Tool Use & Function CallingHow agents use tools well: designing tool schemas, dynamic tool selection, composing tools into workflows, error recovery, and keeping the tool set small enough to choose from.
- Planning & Reasoning in AgentsHow agents plan and reason: task decomposition, hierarchical planning, chain-of-thought and tree-of-thought — with Java examples and honest guidance on when planning helps.
- Memory Systems for AgentsHow agent memory works beyond a chat window: working, episodic and semantic memory, vector-based recall, memory consolidation, and implementing persistent agent memory in Java.