Academy

Tracing a request through a multi-agent system

The best way to understand a multi-agent architecture is to follow a real request from start to finish. Let's trace a vague message, step by step, into a structured action.

The Felesh team 5 min

Architecture theory becomes clear when you trace a real request through it. Here, we follow an illustrative example step by step: a vague message from a user that must become a clear, structured action. The example is hypothetical, but it demonstrates a pattern that recurs in many multi-agent systems.

The request: a free-form message

Suppose a user sends a message: “The order I placed last week still hasn’t arrived and nobody is answering.” This message is clear to a human, but to a system, it is free, unstructured text. The system’s job is to extract the user’s intent, the necessary details, and the correct action from this single sentence.

One sentence, four things to findThe message “The order I placed last week still hasn’t arrived and nobody is answering.” sits on the left as one string. On the right are the four things the system must extract: the intent is a delivery complaint, it was placed last week, the customer is waiting with no reply yet, and the order number is not in the message.the messagewhat it must findThe order I placedlast weekstill hasn’t arrivedandnobody is answering.to the system: one stringintentdelivery complaintplacedlast weekwaitingno reply yetorder no.not in the message
A person reads the complaint at a glance; the system has to pull the intent, the timing and the waiting out of one string, and notice that the order number is missing.

Step 1: the foreground layer understands the intent

The first component to meet the message is a conversation specialist in the foreground layer. Its job is to process natural language and guide the interaction: it determines that this is a complaint about a delayed order. If a detail is missing — like the order number — it asks the user for it. This layer avoids deep domain logic; it simply clarifies intent and gathers context.

Asking for the missing order numberThe customer message sits at the top of a short conversation. The specialist asks “What is the order number?”, the customer answers ORD-3306, and the answer travels into the collected context on the right, replacing the question mark next to order. The context now reads: intent delivery complaint, order ORD-3306, ready to hand off. A footer notes that the foreground layer does no domain logic.customerspecialistcustomerThe order I placed last weekstill hasn’t arrived…What is the order number?ORD-3306collected so farintentdelivery complaintorder?ORD-3306ready to hand offforeground layer: no domain logic
When a detail is missing, the conversation specialist asks for it and writes the answer into the context it hands on, and it does no domain work.

Step 2: handing off to the domain service

Once the intent is clear, the conversation specialist passes the work to a specialised domain service in the background layer. This handoff is not direct. It follows an event-driven pattern: an event is published signalling that a delay complaint is ready, carrying only an identifier. The domain service receives this event and reads the full state from shared memory — never from the event payload itself.

An event with an id, state in memoryThe conversation specialist first writes the state of the complaint to shared memory under c-5521: intent delivery_delay, order ORD-3306, the full message. It then publishes the event complaint.ready carrying only the id c-5521. The domain service receives the event and reads the state from shared memory by that id.conversationspecialistdomainservice2 eventcomplaint.readycarries only id c-5521the event never carries the state1 writes3 readsby idshared memoryc-5521: intent delivery_delayorder ORD-3306, full message
The handoff event carries only an identifier; the domain service takes the full state from shared memory, never from the event.

Step 3: the heavy cognitive work

Now the domain service executes the core work: transforming the message into a clear structure. It determines the issue type (delivery delay), infers the priority, and selects the right action — for example, creating a follow-up ticket populated with the required fields. This is where depth of expertise is necessary, and precisely why it is kept separate from the conversation layer.

Three decisions become ticket fieldsThree decisions on the left feed the ticket on the right. Issue type: delivery delay, written to the type field as delivery_delay. Priority: high, because there is no reply yet, written to the priority field. Action: create a follow-up ticket, so the status field reads open. The ticket TK-7712 is created for order ORD-3306.the domain service decidesfollow-up ticket1 issue typedelivery delay2 priorityhigh: no reply yet3 actioncreate follow-up tickettypedelivery_delaypriorityhighstatusopenTK-7712 created for ORD-3306
The domain service turns the message into three decisions, and each one lands in a field of the follow-up ticket.

Step 4: the monitor makes the next decision

When the domain service finishes, it publishes a completion event. The completion monitor receives it, reads the state from memory, and decides deterministically: is there more work to route, or is it time to reply to the user? In this example, the ticket is created and no further tasks remain, so the monitor instructs the conversation layer to prepare the reply.

A plain rule decides the next stepThe event ticket.created with id c-5521 reaches the completion monitor. The monitor reads c-5521 from memory, counts pending tasks, finds zero, and applies its rule: none left, so reply. The route to the next service stays dashed because it only applies when tasks are pending. The chosen branch leads to reply to the user. The monitor uses a rule, not a model.eventticket.createdid c-5521completionmonitor1 read c-55212 pending tasks: 03 none left: replya plain ruleroute tonext servicemorereply tothe usernone
The completion monitor reads the state and applies a plain rule: nothing pending means reply to the user, otherwise route the next service.

Step 5: back to the user

Finally, the conversation specialist closes the loop. It provides the user with a clear, human reply: “Your complaint is logged, the reference number is such-and-such, and it will be handled by such a time.” The user experiences a simple conversation, but behind the scenes, their vague message passed through several specialised layers to become a structured action.

What this trace tells us

This path reveals three architectural principles. First, separation of layers: conversation in the foreground, heavy cognitive work in the background. Second, the event as a trigger: components connect through identifiers rather than heavy data payloads, and truth is always read from memory. Third, deterministic decision-making at the key routing points, so coordination does not become fragile. These principles are the difference between a system that resolves a vague message with confidence and one that stalls at the first unexpected case.