Large Language Models (LLMs) have transformed how we tackle complex tasks, enabling the creation of agents that operate autonomously. Unlike AI agents that function without a predefined sequence of steps, agentic workflows leverage LLMs within structured, task-oriented processes. To design effective LLM workflows, it's crucial to understand key patterns. In this tutorial, we'll explore four essential workflow patterns: Prompt Chaining, Orchestrator-Workers, Evaluator-Optimizer, and Parallelization.
Each of these patterns addresses unique challenges in building AI-powered applications. Let's explore their implementation and best practices. The following diagram illustrates the common agentic workflow patterns.
Common Agentic Workflow Pattern: Prompt Chaining, Orchestrator-Workers, Evaluator-Optimizer, and Parallelization.
In Prompt chaining, complex tasks are broken into smaller steps. Similar to a sequential workflow each step's output serve as the input for the next prompt. This approach simplifies complex tasks by breaking them into smaller subtasks. It is commonly used when LLM calls depend on each other and when tasks can be easily decomposed into smaller steps. It offers many benefits, such as:
How to Implement Prompt Chaining?
To implement Prompt Chaining, you should follow these steps:
The following code snippet illustrate how to implement the prompt chaining pattern using two calls to OpenAI LLM.
1from openai import OpenAI23client = OpenAI()45def get_key_topics(text):6 response = client.chat.completions.create(model="gpt-4o",7 messages=[{"role": "user", "content": f"Extract key topics from this text: {text}"}])8 return response.choices[0].message.content910def summarize_topics(topics):11 response = client.chat.completions.create(model="gpt-4o",12 messages=[{"role": "user", "content": f"Summarize these topics: {topics}"}])13 return response.choices[0].message.content1415text = "Your document text here."16topics = get_key_topics(text)17summary = summarize_topics(topics)18print(summary)
The Evaluator-Optimizer Pattern introduces a feedback loop where an evaluator assesses the quality of an LLM's response, and an optimizer refines it iteratively. LLM outputs are not always optimal on the first attempt. By introducing an evaluator, we ensure that outputs meet predefined standards.
How to Implement Evaluator-Optimizer?
The following code snippet illustrate how to implement the Evaluator-Optimizer pattern using an iteration between code generation and security checks.
1from openai import OpenAI23client = OpenAI()45def evaluate_code(code_snippet):6 response = client.chat.completions.create(7 model="gpt-4o",8 messages=[9 {"role": "user", "content": f"Check code security and CVEs in this code: {code_snippet}"}10 ]11 )12 return response.choices[0].message.content1314def generate_code(feature, feedback | None = None):15 content = f"Generate code for : {feature}"16 if feedback:17 content = f"Generate code for : {feature} make sure that the code is secure and does not contains these issues {feedback}"1819 response = client.chat.completions.create(20 model="gpt-4o",21 messages=[22 {23 "role": "user",24 "content": content25 }26 ])27 return response.choices[0].message.content2829feature = "My new feature"3031generated_code = generate_code(feature)32feedback = evaluate_code(generated_code)33# if no feedback, end workflow, else we move to the next iteration34generated_code = generate_code(feature, feedback)
The Parallelization Pattern divides large tasks into smaller, independent units that can be processed simultaneously. This approach is used to reduce latency by processing tasks concurrently and handles large workloads by distributing tasks across multiple agents. It can also be used to compare and get the best results from different prompts or models.
How to Implement Parallelization?
The following code snippet illustrate how to implement the Parallelization pattern using Python ThreadPoolExecutor.
1from concurrent.futures import ThreadPoolExecutor23def translate_text(segment):4 response = openai.ChatCompletion.create(5 model="gpt-4o",6 messages=[{"role": "user", "content": f"Translate this to French: {segment}"}]7 )8 return response["choices"][0]["message"]["content"]910document_segments = ["Hello, how are you?", "This is an AI tutorial.", "LLMs are powerful tools."]11with ThreadPoolExecutor() as executor:12 translations = list(executor.map(translate_text, document_segments))1314print(translations)
As shown in the diagram above, the Orchestrator-Workers Pattern has three components: the orchestrator, which is responsible for dividing tasks into multiple subtasks and assigning them to workers; the workers, which are essentially LLM calls; and the synthesizer, which collects the workers' outputs and synthesizes the final result. This pattern is useful when tasks are not easily decomposable.
How to Implement Orchestrator-Workers?
Below is a code snippet that demonstrates a minimal implementation of this workflow pattern using Celery.
12from fastapi import FastAPI3from celery import Celery45app = FastAPI()6celery = Celery('tasks', broker='redis://localhost:6379/0')78@celery.task9def orchestrator(message):10 # Simulated LLM call11 return {12 "search": "internet"13 }1415@celery.task16def synthesizer(message):17 return "synthesized output content"1819@celery.task20def internet_search(query):21 return {22 "iPhone16": "1000$"23 }2425@celery.task26def document_search(query):27 return {28 "iPhone16": "1100$"29 }3031@app.post("/chat")32def chat(message: str):33 task_assignments = orchestrator.delay(message).get()34 # based on task_assignments call the appropriate search35 output = synthesizer.delay(outputs).get()36 return output37
In this tutorial, we explored four essential workflow patterns: Prompt Chaining, Orchestrator-Workers, Evaluator-Optimizer, and Parallelization. This tutorial demonstrates that you don't always need complex workflows or frameworks to build agentic systems. Instead, you can rely on basic LLM features to implement your desired functionality. If you need to create an agentic system, start with small iterations, refine frequently, and don't hesitate to combine patterns for even greater results.