Orchestrating agentic systems

Raunak Jain
7 min readApr 14, 2024

Static and dynamic execution of tasks by agents

Refer to this for a background on Modules and to this for an introduction dynamic state machines.

In NLP or LLM driven pipelines, we are used to the idea of chaining the output of one LLM call with the other in a defined order and sequence. With reasoning and planning capabilities improving in LLMs, this is being challenged. We now let the LLM decide what should be the next node of execution in a dynamically built path based on observation, reasoning and planning. Read the following for an introduction:

Before we dive in, I need to differentiate between Multi-State and Multi-Agent. While executing a specific LLM request, we might enter different goals an LLM is trying to achieve, for e.g. in ReAct, an LLM might be in either of the following states — Thought, Act, Observe. vs the state a system might be in, e.g. Agent 1 executing query. In closed prompt systems like ReAct, we can not control the flow of the states and it always goes from Thought -> Act -> Observe -> Thought.. but in a system where even the process of thought generation, action taking and observation is broken down, we can break this chain down into a multi agent problem.

This article is about the multi-agent systems which can be controlled while execution is happening.

We will first look at orchestration in terms of where the decision is made on the sequence of steps to execute and then look at how to control them using routers and state machines. Even if the decision is made in a decentralized manner, the router can be used to control the flow and close or open certain paths based on the output of each node.

Decision making patterns

Consider a graph, with entities as agents (having the capability to transform the input and apply functions) and edges defining the order of flow from one agent to the other. We start from the beginning with a Message which gets transformed as it is being passed from one Agent to the other in a pre-defined order (because we are sane) and end execution with the final output.

But now, what if the path / edges are not known at the beginning and is dynamically decided by the underlying Agents based on some reasoning or planning? How would you represent this communication topology as a generalized system? How would this system decide when to stop? Frameworks like Langgraph and Autogen attempted to solve this using a router or orchestrator, let’s dig in.

Each agent defined in the system should have the following capabilities:

  1. Profile — a well defined purpose it fulfills in the ecosystem so that other agents can call it when they need help and it does not move away from it’s goals while execution.
  2. Memory — both for the message which is transformed and passed around and for the plan. We can not considering the scratch pad each agent has access to.
  3. Planning — what next step to use based on the current message and the overall goal / user query. This could involve complex reasoning with multiple or single paths. See the sample of static planner below
  4. Action — while executing the plan, the agent needs access to tools and might even take inputs from the user.

With the above qualities, an LLM agent can build plans of execution based on reasoning prompts.

Different reasoning methodologies build different complexity of plans.

In the above diagram, ToT or CoT based reasoning prompts can build different variations of the path which the system can take.

Graph of thoughts is a more advanced technique where the system can build reasoning paths, but also self-reflect, backtrack and refine all based on just the LLM critiquing itself.

source

It is a bit too costly and unpredictable to trust the LLM to make the right reflection and change the path of navigation, we will look at how to control this more reliably using state machines and routers later.

Static execution plan

Use the LLM to generate a plan, using GoT, ToT etc and picking the best one, and then execute it.

A very interesting use-case is provided by Semantic kernel which represents plans as executables using handlebars.

Dynamic execution plan

Define only an entry point in the execution graph, let the next step be dynamically decided based on the output of the LLM.

There are two common patterns I see being used:

  1. Centralized — there exists a supervisory LLM, which dispatches jobs for other agents and tools and is responsible for response handling, analysis, next step planning or end the execution.
  2. Decentralized — Each of the agents involved in the system can decide which agent or function to call next or end the execution.

In both these scenarios, even when the decision is decentralized, the actual execution of the node might still be controlled using a controller / executor.

Centralized pattern

A supervisor LLM decides what to do next. Below is a prompt build by the langgraph team to demo an agent supervisor:

You are a supervisor tasked with managing a conversation between the following workers: {members}. Given the following user request, respond with the worker to act next. Each worker will perform a task and respond with their results and status. When finished, respond with FINISH.

To be able to parse the route predicted by the supervisor agent, it uses function calling to make it easy to extract structured path.

OpenAI function definition which generates the next route in a structured format. See sample below.
Sample of the ‘next’ route generated by the supervisor dynamically using function calling.

The way to invoke this graph is by defining the supervisor as the entry point and letting the supervisor build the next path or finish execution based on the output of the first task execution. There is usually a recursion limit or conditions to check, which stops the generation of the next path by the supervisor if a response has not been found.

For a more advanced example of this pattern, see this — https://github.com/langchain-ai/langgraph/blob/main/examples/multi_agent/hierarchical_agent_teams.ipynb

Decentralized pattern

In a decentralized pattern, each agent is expected to do their job, and then decide which other agent to trigger. The execution of the next agent in the path might still happen from a router, for house-keeping purposes, but the decision making is still done in a decentralised manner and no “Supervisor” exists.

Look at the prompt below for clarity:

You are a helpful AI assistant, collaborating with other assistants. Use the provided tools to progress towards answering the question. If you are unable to fully answer, that’s OK, another assistant with different tools will help where you left off. Execute what you can to make progress. If you or any of the other assistants have the final answer or deliverable, prefix your response with FINAL ANSWER so the team knows to stop. You have access to the following tools: {tool_names}.

Each agent in the system is instructed with this as a system prompt, but has it’s own goals and tools well defined. There is always an entry point, then some limitations being defined by not allowing every agent talk to every other agent which the router can help with.

source

these can be represented as state machines or as mentioned below, State Driven Workflows.

Controlling path generations using states

When we can not rely on advanced techniques like GoT to build a reliable path, and also want to encode some “principles” in the system of execution, for e.g. only return the response if the code suggested successfully executes, we can use agents with profiles and state machines to control the flow based on definitions like below:

Many times, we will also use this type of a router to influence the execution of the graph to act more personalized, based on the state of the user or any other state tracked in the system like Dialogue State. But let’s not confuse that concept here.

In summary

With well defined nodes, dynamic edge generation and a router to house keep, we can build dynamic multi agent systems which coordinate to achieve a goal in an intelligent manner without pre-defining execution strategies.

In the future we will review how Autogen executes this using conversational patterns — https://microsoft.github.io/autogen/docs/tutorial/conversation-patterns

--

--