Building a Multi Agent Customer Support Workflow
A complete example that demonstrates how to create an automated customer support pipeline using multiple agents, tools, memory, structured outputs and TaskFlow orchestration.
This example demonstrates how to build a real world customer support pipeline using Chainless.
The workflow includes three agents working together:
- A classifier agent that identifies the category of the user issue
- A solution agent that uses real tools to fetch system and account information
- A report agent that generates a final user friendly support report
The example also shows how to use Memory, structured responses and TaskFlow orchestration.
Project Structure Overview
This workflow uses these key components:
- Tools for checking system status and retrieving account information
- Agents for classification, solution generation and reporting
- Structured output models using Pydantic
- TaskFlow to orchestrate multi agent execution
- Memory for generating consistent reports
Full Example Code
Below is the complete annotated version of the workflow.
from chainless import Agent, TaskFlow, Tool
from chainless.memory import Memory
from pydantic import BaseModel
import random
import asyncio
from enum import Enum
import anyio
# ----------------------------
# Tools
# ----------------------------
# We define available system names
class SystemName(str, Enum):
MAIL_SERVER = "mail_server"
PAYMENT_GATEWAY = "payment_gateway"
DATABASE = "database"
# A simple tool function that returns system status text
def check_system_status(system_name: SystemName):
statuses = {
SystemName.MAIL_SERVER: "The mail server is running smoothly, last check was performed 3 days ago.",
SystemName.PAYMENT_GATEWAY: "The payment gateway is operating with 99.9% uptime and is stable.",
SystemName.DATABASE: "The database is responding, performance is at 85 percent, no critical alerts.",
}
return statuses.get(
system_name, f"No information found about the '{system_name}' system."
)
# A simulated async tool that returns user account status
async def get_user_account_info(user_id: str):
"""Returns the user's current status and plan information."""
plans = ["Free Plan", "Premium Plan", "Enterprise Plan"]
status = random.choice(["active", "suspended", "frozen"])
plan = random.choice(plans)
await asyncio.sleep(0.1)
return f"User {user_id}: Status: {status}, Plan: {plan}"
# We wrap the functions above as Chainless tools
status_tool = Tool(
"SystemStatusTool",
"Checks whether the specified system is operational and reports its current status.",
check_system_status,
)
account_tool = Tool(
"UserAccountTool",
"Retrieves the status and plan information of the specified user account.",
get_user_account_info,
)
# ----------------------------
# Structured Output Models
# ----------------------------
# Classifier response schema
class ClassifierOutput(BaseModel):
category: str
reason: str
# Solution agent response schema
class SolutionOutput(BaseModel):
solution: str
# ----------------------------
# Agents
# ----------------------------
# The classifier determines whether the issue is billing, technical or other
classifier_agent = Agent(
name="IssueClassifier",
system_prompt=(
"Task: Classify the user's complaint into the correct category.\n"
"Categories: 'billing', 'technical', 'account', 'other'.\n"
"Provide a clear explanation of the reasoning."
),
response_format=ClassifierOutput,
)
# The solution agent can call tools to check system or account data
solution_agent = Agent(
name="SolutionGenerator",
tools=[status_tool, account_tool],
system_prompt=(
"Task: Generate a solution appropriate to the user's request.\n"
"Use SystemStatusTool or UserAccountTool if necessary.\n"
"Present the solution clearly and understandably."
),
response_format=SolutionOutput,
)
# The report agent takes the outputs and creates a user friendly summary
report_agent = Agent(
name="SupportReportAgent",
system_prompt=(
"Task: Using the category and solution from the previous steps, create a comprehensive support report.\n"
"Provide a clear and understandable report to the user without unnecessary technical details."
),
)
# ----------------------------
# TaskFlow Orchestration
# ----------------------------
# We register the three agents
support_flow = TaskFlow("SupportFlow", verbose=True)
support_flow.add_agent("Classifier", classifier_agent)
support_flow.add_agent("Solution", solution_agent)
support_flow.add_agent("Report", report_agent)
# Step 1: classify
support_flow.step("Classifier", input_map={"input": "{{input}}"})
# Step 2: generate a solution using tools when needed
support_flow.step(
"Solution",
step_name="SolutionStep1",
input_map={"category": "{{Classifier.output.category}}", "details": "{{input}}"},
prompt_template="""
We received a support request categorized as {{category}}.
Details: {{details}}
Please provide an appropriate solution suggestion. If necessary, use the following tools:
1. SystemStatusTool: Provides system status and performance information.
2. UserAccountTool: Retrieves user account information.
""",
)
# Step 3: generate the final user facing report
support_flow.step(
"Report",
input_map={
"category": "{{Classifier.output.category}}",
"solution": "{{SolutionStep1.output.solution}}",
},
prompt_template="""
Support Request Report:
Category: {{category}}
Solution: {{solution}}
Please use this information to present a comprehensive report to the user.
""",
)
# ----------------------------
# Running the Example
# ----------------------------
async def main():
memory = Memory()
# In a loop, we accept user input and run the workflow
while True:
user_input = input("Describe your issue (type 'exit' to quit): ")
if user_input.lower() == "exit":
break
memory.add_user(content=user_input)
# Load memory into the report step if needed
support_flow.ctx._get_step_by_name("Report").message_history = memory.get()
# Run the multi agent workflow
result = await support_flow.run_async(user_input)
print("\n--- Final Report ---")
output = result.output
memory.add_assistant(content=output)
print(output)
print(memory.get())
if __name__ == "__main__":
anyio.run(main)Explanation of Key Concepts
Why use multiple agents
Each agent performs a single responsibility. This makes the workflow easier to maintain and expand.
Why use structured output
Structured output enforces predictable responses from agents. This is important when chaining multiple steps.
Why use tools
Tools allow the model to fetch external data. In this example, system status and account details are retrieved dynamically.
Why use TaskFlow
TaskFlow connects agents together in a reproducible workflow. It also handles context and data mapping between steps.
FlowServer
Build and run LLM agents with tools, hooks, and structured outputs.
Payment Issue Resolution Workflow with FlowServer
A complete example showing how to serve a multi agent payment support pipeline using FlowServer. This example demonstrates tool usage, structured outputs and TaskFlow orchestration in a production ready setup.