05-embabel-agent-orchestration

GOAP: Why Embabel Plans Instead of Prompts

Why the fintech team's hand-rolled Plan-and-Execute refund flow turned into an unmaintainable if/else tree, and how Goal-Oriented Action Planning replaces hand-written branching with a real planner.

August 13, 2026
spring-aiembabelgoapblackboardoodaagent-planning

The If/Else Tree That Ate the Refund Flow

The Plan-and-Execute pattern from the previous phase served the fintech team well for a while: ask the model for a plan up front, execute each step, done. Then the business rules kept arriving. Premium-tier customers get a longer eligibility window. Joint accounts need a second lookup. Anything over $500 needs the reflection/review pass from the agentic-patterns guide. Anything flagged fraud-adjacent skips straight to escalation, bypassing the refund calculation entirely. Six months in, the code choosing which steps to run for a given request is a deeply nested if/else tree that nobody enjoys touching, and every new business rule risks breaking a path nobody was testing.

This is precisely the failure mode the last guide's closing section predicted: the branching logic itself outgrew hand-written control flow. Embabel exists for exactly this moment. Its core idea is almost architecturally simple, but changes everything about how the flow above gets built: don't write the branching logic. Describe the pieces, and let a planner compute the branching for you, fresh, for every request.


1. GOAP: A Planner, Not a Prompt

Goal-Oriented Action Planning (GOAP) is not an LLM technique — it's a non-LLM AI algorithm borrowed from video game AI (used for decades to let game NPCs decide what to do next). Embabel repurposes it as the orchestration layer sitting above your LLM calls:

The difference isn't cosmetic. In the hand-rolled version, you are the planner — every new business rule is a line you add to an if/else tree, and the tree's correctness depends entirely on you tracing every path by hand. In the GOAP version, the planner is a piece of deterministic search code inside the framework: give it a goal and a set of available actions, and it computes which sequence of actions gets there, based on what each action declares it needs and produces. Add a new action, and it becomes available to the planner automatically — you're extending a set of building blocks, not editing a decision tree.

"Deterministic" here describes the planner, not the LLM calls inside individual actions. GOAP always finds the same plan for the same blackboard state and the same set of available actions — the non-determinism from token sampling still lives inside whichever actions actually call a model, exactly as it does everywhere else in this roadmap.


2. The Blackboard: Preconditions and Postconditions You Never Write

Every hand-rolled pattern from the last guide needed you to track state explicitly — a List<AgentStep> trace, a Plan record, a scratchpad in ChatMemory. Embabel's equivalent is the Blackboard: a shared, typed space that every action reads from and writes to, managed entirely by the framework.

The mechanism is almost deceptively simple: an action's method parameters are its preconditions, and its return type is its postcondition. There's no separate configuration file or graph you wire up by hand:

java
// This method's signature alone tells the planner everything it needs:
// - Precondition: a RefundEligibility must already be on the blackboard
// - Postcondition: running this action adds a RefundAmount to the blackboard
@Action
public RefundAmount calculateAmount(RefundEligibility eligibility) {
    // ...
}

The planner reads every @Action method's parameter types and return type across your whole agent, and works out which actions can run given what's currently on the blackboard, and which combination of actions reaches the goal type. You never call blackboard.put(...) or blackboard.get(...) yourself — returning a value adds it; declaring a parameter type retrieves it. Guide two in this phase builds a real one of these; this guide is about the idea before the syntax.


3. Replanning: An OODA Loop After Every Action

Plan-and-Execute (last guide) commits to a full plan before anything runs. GOAP replans after every single action — Observe the new blackboard state, Orient against the goal, Decide the next action, Act — the OODA loop military strategists use for exactly this kind of fast, repeated re-evaluation under changing conditions.

This is what actually replaces the fraud-adjacent-skip-to-escalation rule from the top of this guide. In the hand-rolled version, that's an explicit if checked before the refund calculation even starts. In Embabel, it's just another available action with a fraud-related precondition — if the blackboard ends up in a state where that action's preconditions are satisfied, the planner can route there instead of continuing toward the refund-calculation path, without anyone having encoded "check for this special case before that other one."

⚠️

This gives you explainability the hand-rolled if/else tree never had for free — you can log the plan the framework actually computed for a given request, which is a genuine audit trail (like the one Legal asked for in the agentic-patterns guide), generated by the framework rather than assembled by hand in a List<AgentStep>. It does not give you a plan that's correct by construction; a poorly described @Action or an under-specified @Goal produces a bad plan just as easily as bad hand-written logic does. The planning is automatic; the responsibility for good building blocks isn't.


What's Next

You now know why Embabel plans instead of prompting an LLM to orchestrate itself, and the two ideas — the Blackboard and OODA replanning — that make it possible. The next guide builds a real agent: @Agent, @Action, @Condition, and @AchievesGoal, rebuilding this exact refund scenario so the planner handles the branching this guide described in the abstract.

Frequently asked questions

Is GOAP specific to Embabel, or a general concept?

General — GOAP predates LLM agent frameworks entirely and comes from game AI, where NPCs use it to decide actions like "take cover" or "reload" based on the game state. Embabel is one of the first frameworks to apply it to LLM-based agents specifically; the algorithm itself isn't proprietary to Embabel.

Does replanning after every action mean every action re-calls the LLM to decide what's next?

No — that's precisely the distinction from a hand-rolled ReAct loop. The planning step itself is non-LLM search code operating over your @Action method signatures. Only the individual actions that are actually LLM calls (marked as such by using Ai inside them) hit a model; deciding which action to run next is free of any model call.

What happens if the planner can't find a path to the goal at all?

The framework surfaces this as a planning failure rather than silently doing nothing or guessing — a goal the current set of actions genuinely can't reach given the blackboard's state is a configuration problem (a missing action, an under-specified precondition) worth fixing, not something to route around at runtime.

Is the Blackboard the same thing as ChatMemory from earlier in this roadmap?

No, though they solve superficially similar-sounding problems. ChatMemory persists conversation turns for a single ongoing chat across separate requests. The Blackboard is scoped to one agent run and holds typed domain objects — a RefundEligibility, a RefundAmount — not chat messages, and exists specifically so the planner can compute preconditions and postconditions from what's on it.