By Gari Ciodaro, Co-Founder and CTO of Recall Space GmbH
Agentic flows are valuable because they can adapt. Architectural patterns help us put that flexibility where it belongs, so we can improve an agent without redesigning everything around it. LangChain and LangGraph make this approach practical.
A customer asks for a refund. An agent reads the message, the application checks the order, and a decision comes back. The demo works.
Then the model changes. A new tool is added. The refund policy moves from thirty days to sixty. Suddenly, changes to how the application understands language are tangled up with changes to what the business allows.
AI makes the first version easy. It also makes change constant: models are swapped, prompts are tuned, tools are added, and each revision shifts behavior nobody wrote by hand. The faster the parts change, the more the boundaries between them are worth. That is why AI makes architectural patterns more important, not obsolete. The useful question is how much of the system has to move when one part changes.
Start with what the business needs
Consider a simple refund-triage application. It has two different jobs:
- Understand the request. Is the customer asking for a full refund, something else, or something unclear? Which words support that interpretation?
- Apply the policy. Using trusted order data, does the request qualify? In this example, a paid order up to thirty days old is eligible.
The first job benefits from an agent. Customers express the same thing in different ways, and the agent may need a terminology lookup before it can interpret the message. The second job has a rule the business owns. Ambiguous requests go to review; issuing a payment is a separate responsibility.
That separation gives us a domain boundary before we choose a framework.
Give the agent a boundary
Hexagonal architecture gives this boundary a concrete form. The application defines a port: “interpret this request and return an intent with supporting evidence, or tell me you could not.” An adapter implements it using an agentic flow.
The adapter translates the agent’s output into the application’s own terms. Prompts, tool calls and model responses stay inside that capability. The refund policy receives an interpretation it understands.
from typing import Protocol
class RequestInterpreter(Protocol):
async def interpret(
self, message: str
) -> Request | InterpretationFailure: ...
Request carries intent and a supporting quote; InterpretationFailure makes failure explicit. These Python excerpts omit supporting types and setup to focus on the boundaries.

This is a useful way to think about high cohesion and low coupling: keep the work of interpretation together, and keep its implementation details out of the policy. The agentic flow becomes a unit that absorbs variability.
The tempting alternative is to skip the architecture and vibe code it: wire steps together, accept what works, iterate. But a graph of connected steps does not, by itself, decide who owns the business rules. Hexagonal architecture addresses dependencies; the graph expresses execution. They work together.
It also helps to name what we are trading. Richards and Ford’s first law of software architecture says that everything in software architecture is a trade-off. Adaptability is an architecture characteristic like testability or auditability, and it is not free: an agentic flow buys it and pays in predictability. The boundary does not remove that trade-off; it decides where each side is paid. Adaptability lives in the adapter, where it creates value. Determinism stays in the policy, where the business depends on it.
Where LangChain and LangGraph fit
LangChain provides the adaptive capability. Its create_agent API supplies the model-and-tool loop. In this example, the agent can consult a read-only support glossary when useful. Structured output gives the adapter an intent and a supporting quote to validate, while middleware can limit model and tool calls. We can build on those capabilities without writing another agent runtime.
agent = create_agent(
model=model,
tools=[support_glossary],
response_format=IntentOutput,
)
class LangChainRequestInterpreter:
def __init__(self, agent):
self.agent = agent
async def interpret(self, message):
result = await self.agent.ainvoke({
"messages": [
{"role": "user", "content": message}
]
})
output = result["structured_response"]
return to_domain(output, message)
IntentOutput is the agent’s output schema. The adapter’s to_domain helper validates the quote and returns the application’s types. Prompt configuration, error handling and call limits are omitted here.
LangGraph composes it with the business process. A StateGraph connects interpretation, policy and review. If the interpretation is unclear, an interrupt, backed by a checkpointer, lets the workflow pause for a person and resume with their correction. The same policy then runs again.
graph = StateGraph(TriageState)
graph.add_node("interpret", interpret_request)
graph.add_node("policy", apply_policy)
graph.add_node("review", review_request)
graph.add_edge(START, "interpret")
graph.add_edge("interpret", "policy")
graph.add_conditional_edges("policy", next_step)
graph.add_edge("review", "policy")
workflow = graph.compile(checkpointer=checkpointer)

The nodes call the interpreter, apply the policy, or pause for review. next_step sends an unresolved case to review once; after the reviewer’s correction the policy decides again, and that decision is final. A case that is still unresolved leaves the workflow for manual handling.
LangChain agents themselves run on LangGraph. That shared foundation lets us place a dynamic agent inside a more explicit workflow, choosing the right amount of flexibility for each responsibility.
The boundary still needs engineering judgment. A valid output shape does not prove that an interpretation is correct. Here, the adapter checks the supporting quote, failures go to review, and the agent has no payment tool.
The useful test is what happens when something changes
Now extend the refund window to sixty days. That change belongs in the policy and its tests. Try a new model or improve the glossary tool: that work belongs in the interpretation capability and its evaluations. The rest of the application can keep using the same contract.
Some changes cross the boundary. Supporting partial refunds introduces a new business concept, so both the contract and policy may need to evolve. A good boundary makes that impact visible.
This is the practical value of architectural patterns in AI systems: a contained blast radius for change, clearer ownership, and room to improve the agent independently. The more often the AI parts change, the more often those boundaries pay for themselves. The same approach applies when interpreting a supplier confirmation or classifying a support case.
Give agentic flows room to adapt. Use architecture to make that adaptability useful to the whole system.
Architecture glossary
- Domain: The business concepts and rules the software models: here, customer requests, orders and refund eligibility.
- Hexagonal architecture: An approach that keeps business logic independent of technology choices by connecting it to implementations through ports and adapters.
- Port / contract: An interface owned by the application that defines a capability and its expected inputs and outcomes, including failure.
- Adapter: An implementation of a port that translates between the application’s concepts and a particular technology, such as a LangChain agent.
- Cohesion: How closely a component’s responsibilities belong together. High cohesion keeps the work of interpreting a request in one capability.
- Coupling: How much components depend on each other’s details. Low coupling lets the agent change while the policy keeps using the same contract.
- Architecture characteristic: A quality the system must support, such as adaptability, testability or auditability. Improving one usually costs another, so the trade-offs are chosen, not avoided.
- Blast radius: How far the effects of a change or failure can spread. Clear boundaries help contain those effects.
Sources
- Hexagonal architecture, Alistair Cockburn
- Structured design, W. P. Stevens, G. J. Myers and L. L. Constantine, IBM Systems Journal, 1974
- Fundamentals of Software Architecture: A Modern Engineering Approach, Mark Richards and Neal Ford, O’Reilly Media
- Agents, LangChain documentation
- Structured output, LangChain documentation
- Built-in middleware, LangChain documentation
- Workflows and agents, LangGraph documentation
- Interrupts, LangGraph documentation

.png)