A sophisticated FastAPI-based orchestration engine that manages multi-step conversational flows through distributed Agent-to-Agent (A2A) microservices. This system coordinates complex customer service call flows by routing intents between specialized agents while maintaining session state and audit trails.
The Orchestrator Flows system is designed to handle 5-stage customer service call workflows where each stage is handled by a specialized agent. The orchestrator acts as a central coordinator that:
- Manages session state across multiple turns of conversation
- Routes intents to appropriate specialized agents
- Tracks conversation history with audit trails
- Maintains flow progression through defined stages
- Provides resumable sessions with Redis-backed persistence
When a customer calls a service center with a complex request (e.g., "I'd like to lodge a complaint and request a refund"), the orchestrator:
- Routes through greeting โ authentication โ intent capture โ fulfillment โ closing
- At each step, different specialized agents handle their domain
- Session state is preserved so clients can reconnect mid-call
- Full audit trail tracks every intent and response
โโโโโโโโโโโโโโโโโโโ
โ Client/User โ
โ (FastAPI Call) โ
โโโโโโโโโโฌโโโโโโโโโ
โ POST /orchestrate
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Orchestrator (main.py) โ
โ โข Session mgmt โ
โ โข Intent validation โ
โ โข Agent routing โ
โ โข Response building โ
โโโโฌโโโโโโโโโโโโโโโฌโโโโโโโโโโโโฌโโโโโโโโโ
โ โ โ
โผ โผ โผ
โโโโโโโโโโโโ โโโโโโโโโโ โโโโโโโโโโโโ
โ Redis โ โ Router โ โ A2A โ
โ Store โ โ(Intent โ โ Client โ
โ(Session) โ โ Maps) โ โ(HTTP) โ
โโโโโโฌโโโโโโ โโโโโโโโโโ โโโโโโฌโโโโโโ
โ โ
โโโโโโโโโโโโฌโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโ
โ Specialized Agents โ
โ (greeting, auth, โ
โ billing, refund, โ
โ booking, closing) โ
โโโโโโโโโโโโโโโโโโโโโโโโ
| File | Purpose |
|---|---|
| main.py | Core orchestrator engine with FastAPI endpoints and flow control logic |
| models.py | Pydantic data models (requests, responses, session state) |
| router.py | Intent-to-agent mapping and flow validation rules |
| redis_store.py | Redis persistence layer for session management |
| a2a_client.py | HTTP client for communicating with downstream agents |
| pyproject.toml | Project dependencies and metadata |
Each call progresses through exactly 5 intent flow stages:
Flow ID 1: GREETING
โโ Intent Examples: greeting, welcome
โโ Agent: greeting-agent:8001
โโ Purpose: Initial contact, call opening
Flow ID 2: AUTHENTICATION
โโ Intent Examples: verify_identity, authenticate, otp_verify
โโ Agent: auth-agent:8002
โโ Purpose: Verify caller identity
Flow ID 3: INTENT_CAPTURE
โโ Intent Examples: refund_request, billing_inquiry, booking_request, etc.
โโ Agents: Specialized domain agents (refund, billing, booking, complaint, account, balance)
โโ Purpose: Understand what customer wants
Flow ID 4: FULFILLMENT
โโ Intent Examples: process_refund, confirm_booking, update_account
โโ Agents: Same specialized agents
โโ Purpose: Execute the action
Flow ID 5: CLOSING
โโ Intent Examples: closing, end_call, feedback
โโ Agent: closing-agent:8009
โโ Purpose: Wrap up, confirmation, survey
Key Rule: Session automatically moves to the next flow ID after each step completes.
Once Flow ID 5 completes, is_complete: true and no further steps are recorded.
- Automatic session creation on first request with
call_identify_id - Resumable sessions - clients can reconnect with same
call_identify_id - TTL-based expiry - sessions auto-expire after 1 hour of inactivity
- Complete state tracking - current flow, completed flows, all steps recorded
- Intent-to-URL mapping - routing rules defined in
INTENT_AGENT_MAP - Flow-aware validation - certain intents only allowed at specific flow stages
- Flexible fallback -
unknownintent handled gracefully at any stage
- Every interaction step is recorded with:
- Intent and input message
- Agent URL called
- Response status and data
- Timestamp
- Full session state snapshots
- JSON-RPC 2.0 protocol for agent communication
- Context passing - agents receive account_id, eci, flow metadata
- Error handling - timeouts, HTTP errors, and unknown exceptions captured gracefully
- Response extraction - parses multi-part agent messages
Input from client:
{
"call_identify_id": "CALL-001", # Unique session ID
"account_id": "ACC-999", # Customer account
"eci": "ECI-7", # E-commerce indicator
"input_message": "I need help", # User utterance
"intent": "greeting" # Classified intent
}Output to client:
{
"call_identify_id": "CALL-001",
"intent_flow_id": 1, # Which flow stage just completed
"intent": "greeting",
"status": "success", # "success" | "error"
"response": {...}, # Agent's response data
"next_flow_id": 2, # Where to send next request (null if complete)
"is_complete": false,
"session_summary": null # Populated only when is_complete: true
}Full session stored in Redis:
{
"call_identify_id": "CALL-001",
"account_id": "ACC-999",
"eci": "ECI-7",
"current_flow_id": 3, # Where we are now
"completed_flows": [1, 2], # What's been done
"is_complete": false,
"steps": [
{
"intent_flow_id": 1,
"intent": "greeting",
"input_message": "Hello",
"a2a_agent_url": "http://greeting-agent:8001",
"response_status": "success",
"response_data": {...},
"timestamp": "2026-02-28T10:00:00Z"
},
...
],
"created_at": "2026-02-28T10:00:00Z",
"updated_at": "2026-02-28T10:01:30Z"
}Main entry point - Process a single interaction step
Request:
curl -X POST http://localhost:8000/orchestrate \
-H "Content-Type: application/json" \
-d '{
"call_identify_id": "CALL-001",
"account_id": "ACC-999",
"eci": "ECI-7",
"input_message": "I need a refund",
"intent": "refund_request"
}'Response: Returns orchestrator response with next flow ID and agent response
Inspect current session state
curl http://localhost:8000/session/CALL-001Returns CallSessionState with current flow ID, completed flows, and all steps
Retrieve full audit trail
curl http://localhost:8000/session/CALL-001/stepsReturns list of all IntentStepRecord entries for the session
End call and clear cache
curl -X DELETE http://localhost:8000/session/CALL-001Removes session from Redis and ends tracking
POST /orchestrate
{
"call_identify_id": "CALL-001",
"account_id": "ACC-999",
"eci": "ECI-7",
"input_message": "Hello, I need help",
"intent": "greeting"
}
Orchestrator Logic:
- Check Redis: No existing session
- Create new session with
current_flow_id = 1 - Validate: "greeting" is allowed at Flow 1 โ
- Route: greeting โ http://greeting-agent:8001
- Call agent with context (account_id, eci, flow_label="GREETING")
- Record step in Redis
- Advance to Flow ID 2
- Return response with
next_flow_id: 2
Response:
{
"call_identify_id": "CALL-001",
"intent_flow_id": 1,
"intent": "greeting",
"status": "success",
"response": {"text": "Welcome to customer service..."},
"next_flow_id": 2,
"is_complete": false,
"session_summary": null
}POST /orchestrate
{
"call_identify_id": "CALL-001",
"account_id": "ACC-999",
"eci": "ECI-7",
"input_message": "My SSN is 123-45-6789",
"intent": "verify_identity"
}
Orchestrator Logic:
- Check Redis: Session exists with
current_flow_id = 2 - Validate: "verify_identity" is allowed at Flow 2 โ
- Route: verify_identity โ http://auth-agent:8002
- Call agent (session knows this is flow 2)
- Record step
- Advance to Flow ID 3
- Return response with
next_flow_id: 3
Flow 3 โ INTENT_CAPTURE (refund_request โ refund-agent:8003)
Flow 4 โ FULFILLMENT (process_refund)
Flow 5 โ CLOSING (closing โ closing-agent:8009)
โโ is_complete: true
session_summary included with full audit trail
- Python 3.13+
- Redis server running on localhost:6379
- FastAPI, Uvicorn, httpx, Pydantic, redis
- Clone and navigate to project:
cd orchestrator_flows
source .venv/bin/activate- Install dependencies:
pip install -e .- Ensure Redis is running:
redis-server
# or with Homebrew on macOS
brew services start redis- Run orchestrator:
uvicorn main:app --reload --port 8000Orchestrator will be available at http://localhost:8000
Edit redis_store.py:
REDIS_URL = "redis://localhost:6379" # Connection string
SESSION_TTL_SEC = 3600 # 1 hour session timeoutEdit router.py INTENT_AGENT_MAP to update agent URLs:
INTENT_AGENT_MAP: dict[str, str] = {
"greeting": "http://your-greeting-agent:8001",
"verify_identity": "http://your-auth-agent:8002",
# ... etc
}Edit a2a_client.py:
self.timeout = 15 # seconds for agent requests# Start a new call flow
curl -X POST http://localhost:8000/orchestrate \
-H "Content-Type: application/json" \
-d '{
"call_identify_id": "TEST-001",
"account_id": "ACC-TEST",
"eci": "ECI-TEST",
"input_message": "Hello",
"intent": "greeting"
}'
# Check session state
curl http://localhost:8000/session/TEST-001
# Get steps for audit trail
curl http://localhost:8000/session/TEST-001/steps
# End the call
curl -X DELETE http://localhost:8000/session/TEST-001| Decision | Rationale |
|---|---|
| Redis for sessions | Fast, expires automatically, perfect for short-lived call sessions |
| JSON-RPC 2.0 for A2A | Standard protocol for agent-to-agent communication |
| 5 fixed flow stages | Ensures structured, consistent call flow across all customers |
| TTL expiry (1 hour) | Balances memory efficiency with reasonable call duration |
| Flexible intent validation | Allows agents to handle unexpected intents gracefully |
| Full audit trail | Enables debugging, compliance, and quality assurance |
The system handles errors gracefully:
- Missing agent โ
unknownintent routes to fallback agent - Agent timeout (15s) โ Returns error response, session continues
- HTTP errors โ Captured and returned to client
- Unknown exception โ Generic error response, session unaffected
- Session not found โ Returns 404 HTTP Exception
Potential improvements:
- Implement agent retry logic with exponential backoff
- Add WebSocket support for real-time streaming responses
- Support for branching flows (conditional next_flow_id based on response)
- Multi-language support with intent classification
- Metrics/logging dashboard (call duration, agent response times, error rates)
- Support for parallel agent calls in certain flow stages
- Agent versioning and A/B testing capabilities
For detailed code walkthroughs:
- See
main.pyfor full orchestration logic - See
router.pyfor intent routing configuration - See
models.pyfor all data structures - See
redis_store.pyfor persistence implementation - See
a2a_client.pyfor agent communication