Multi-Step Chain Example
Build a complete customer support automation workflow with sentiment analysis, conditional routing, and personalized responses.
Overview
This example demonstrates a real-world customer support automation chain that:
- Analyzes customer message sentiment
- Fetches customer profile and history from an API
- Routes to different response strategies based on sentiment and customer tier
- Generates personalized responses
- Creates support tickets for negative feedback
- Logs all interactions for analysis
Architecture
The workflow has 8 steps with conditional branching:
Step 0: Analyze sentiment
Step 1: Fetch customer profile
Step 2: Check if negative sentiment
├─ TRUE (negative):
│ Step 3: Create urgent support ticket
│ Step 4: Generate empathetic response
│
└─ FALSE (neutral/positive):
Step 5: Check if premium customer
├─ TRUE (premium):
│ Step 6: Generate VIP response
│
└─ FALSE (standard):
Step 7: Generate friendly response
Step 8: Log interaction (always runs)Step 1: Create Required Prompts
First, create three prompts that will be used in the chain:
Sentiment Analysis Prompt
mutation CreateSentimentPrompt {
createPrompt(input: {
name: "support-sentiment-analyzer"
description: "Analyzes customer support messages for sentiment"
category: ANALYSIS
}) {
id
}
}
mutation CreateSentimentVersion {
createPromptVersion(input: {
promptId: "prompt_sentiment_123"
content: """
Analyze the sentiment of this customer support message.
Message: {{message}}
Return JSON:
{
"sentiment": "Positive" | "Negative" | "Neutral",
"confidence": 0.0 to 1.0,
"urgency": "low" | "medium" | "high"
}
"""
params: {
model: "claude-3-5-sonnet-20241022"
temperature: 0.2
max_tokens: 200
}
inputSchema: {
type: "object"
properties: {
message: { type: "string" }
}
required: ["message"]
}
}) {
id
}
}Empathetic Response Prompt
mutation CreateEmpatheticPrompt {
createPrompt(input: {
name: "empathetic-support-response"
description: "Generates empathetic responses for upset customers"
category: GENERATION
}) {
id
}
}
mutation CreateEmpatheticVersion {
createPromptVersion(input: {
promptId: "prompt_empathetic_456"
content: """
Generate a highly empathetic customer support response.
Customer: {{customerName}} ({{customerTier}} tier)
Original Message: {{message}}
Sentiment: {{sentiment}}
Ticket ID: {{ticketId}}
Write a compassionate response that:
1. Acknowledges their frustration
2. Takes ownership of the issue
3. References the ticket number
4. Provides next steps
5. Assures urgent resolution
"""
params: {
model: "claude-3-5-sonnet-20241022"
temperature: 0.7
max_tokens: 400
}
inputSchema: {
type: "object"
properties: {
customerName: { type: "string" }
customerTier: { type: "string" }
message: { type: "string" }
sentiment: { type: "string" }
ticketId: { type: "string" }
}
required: ["customerName", "message"]
}
}) {
id
}
}VIP Response Prompt
mutation CreateVIPPrompt {
createPrompt(input: {
name: "vip-support-response"
description: "Generates personalized responses for VIP customers"
category: GENERATION
}) {
id
}
}
mutation CreateVIPVersion {
createPromptVersion(input: {
promptId: "prompt_vip_789"
content: """
Generate a personalized VIP customer support response.
Customer: {{customerName}} (Premium Member since {{memberSince}})
Message: {{message}}
Purchase History: {{purchaseCount}} orders
Write a warm, personalized response that:
1. Thanks them for their loyalty
2. Addresses their message directly
3. Offers priority assistance
4. Mentions their membership benefits
"""
params: {
model: "claude-3-5-sonnet-20241022"
temperature: 0.6
max_tokens: 350
}
inputSchema: {
type: "object"
properties: {
customerName: { type: "string" }
memberSince: { type: "string" }
message: { type: "string" }
purchaseCount: { type: "number" }
}
required: ["customerName", "message"]
}
}) {
id
}
}Step 2: Create the Chain
Create Chain
graphql
mutation CreateChain {
createChain(input: {
name: "customer-support-automation"
description: "Automated customer support with sentiment routing"
isActive: true
requiredInputs: {
type: "object"
properties: {
message: {
type: "string"
description: "Customer support message"
}
customerId: {
type: "string"
description: "Customer ID"
}
}
required: ["message", "customerId"]
}
intentTags: ["support", "customer-service", "help", "assistance"]
}) {
id
}
}Save the chain ID - we'll use it to add steps in the next section.
Step 3: Add Chain Steps
Step 0: Sentiment Analysis
mutation AddSentimentStep {
addChainStep(input: {
chainId: "chain_abc123"
order: 0
type: PROMPT
promptId: "prompt_sentiment_123"
inputMapping: {
message: "{{message}}"
}
outputKey: "sentiment"
}) {
id
}
}Step 1: Fetch Customer Profile
mutation AddCustomerFetchStep {
addChainStep(input: {
chainId: "chain_abc123"
order: 1
type: API_CALL
config: {
url: "https://api.yourcompany.com/customers/{{customerId}}"
method: "GET"
headers: {
Authorization: "Bearer YOUR_API_KEY"
}
}
outputKey: "customer"
}) {
id
}
}Step 2: Check Sentiment
mutation AddSentimentCondition {
addChainStep(input: {
chainId: "chain_abc123"
order: 2
type: CONDITION
config: {
condition: "{{sentiment.sentiment}} == 'Negative'"
trueTag: "negative_path"
falseTag: "positive_neutral_path"
}
}) {
id
}
}Step 3: Create Support Ticket (Negative Path)
mutation AddTicketCreation {
addChainStep(input: {
chainId: "chain_abc123"
order: 3
type: API_CALL
tags: ["negative_path"]
config: {
url: "https://api.yourcompany.com/tickets"
method: "POST"
headers: {
Authorization: "Bearer YOUR_API_KEY"
"Content-Type": "application/json"
}
body: {
customerId: "{{customerId}}"
subject: "Urgent: Negative feedback from {{customer.name}}"
message: "{{message}}"
sentiment: "{{sentiment.sentiment}}"
urgency: "{{sentiment.urgency}}"
priority: "high"
}
}
outputKey: "ticket"
}) {
id
}
}Step 4: Generate Empathetic Response (Negative Path)
mutation AddEmpatheticResponse {
addChainStep(input: {
chainId: "chain_abc123"
order: 4
type: PROMPT
tags: ["negative_path"]
promptId: "prompt_empathetic_456"
inputMapping: {
customerName: "{{customer.name}}"
customerTier: "{{customer.tier}}"
message: "{{message}}"
sentiment: "{{sentiment.sentiment}}"
ticketId: "{{ticket.id}}"
}
outputKey: "response"
}) {
id
}
}Step 5: Check Customer Tier (Positive/Neutral Path)
mutation AddTierCondition {
addChainStep(input: {
chainId: "chain_abc123"
order: 5
type: CONDITION
tags: ["positive_neutral_path"]
config: {
condition: "{{customer.tier}} == 'premium'"
trueTag: "premium_path"
falseTag: "standard_path"
}
}) {
id
}
}Step 6: VIP Response (Premium Path)
mutation AddVIPResponse {
addChainStep(input: {
chainId: "chain_abc123"
order: 6
type: PROMPT
tags: ["premium_path"]
promptId: "prompt_vip_789"
inputMapping: {
customerName: "{{customer.name}}"
memberSince: "{{customer.memberSince}}"
message: "{{message}}"
purchaseCount: "{{customer.purchaseCount}}"
}
outputKey: "response"
}) {
id
}
}Step 7: Friendly Response (Standard Path)
mutation AddStandardResponse {
addChainStep(input: {
chainId: "chain_abc123"
order: 7
type: PROMPT
tags: ["standard_path"]
promptId: "prompt_friendly_123"
inputMapping: {
customerName: "{{customer.name}}"
message: "{{message}}"
}
outputKey: "response"
}) {
id
}
}Step 8: Log Interaction (Always Runs)
mutation AddLogging {
addChainStep(input: {
chainId: "chain_abc123"
order: 8
type: API_CALL
config: {
url: "https://api.yourcompany.com/analytics/log"
method: "POST"
headers: {
Authorization: "Bearer YOUR_API_KEY"
"Content-Type": "application/json"
}
body: {
customerId: "{{customerId}}"
sentiment: "{{sentiment.sentiment}}"
customerTier: "{{customer.tier}}"
responseGenerated: true
timestamp: "{{now}}"
}
}
outputKey: "log_result"
}) {
id
}
}Step 4: Execute the Chain
Example 1: Negative Feedback
Execute Chain
graphql
mutation ExecuteChain {
executeChain(
chainId: "chain_abc123"
input: {
message: "I'm extremely disappointed. My order arrived damaged and I've been trying to get a refund for 2 weeks with no response!"
customerId: "cust_456"
}
) {
output
steps {
order
type
status
latency
cost
}
totalLatency
totalCost
}
}Response
json
{
"data": {
"executeChain": {
"output": "Dear Sarah, I sincerely apologize for this extremely frustrating experience. You absolutely should not have had to wait 2 weeks for a refund, and I take full ownership of this failure on our part.\n\nI've immediately escalated your case to our senior support team under ticket #TKT-45678. Your refund will be processed within the next 24 hours, and you'll receive a confirmation email directly from our finance team.\n\nAdditionally, I'm applying a 20% discount to your next order as a gesture of our commitment to making this right. Your trust matters deeply to us, and we're implementing process improvements to ensure this never happens again.\n\nYou should expect an update within 4 hours. Thank you for bringing this to our attention.",
"steps": [
{
"order": 0,
"type": "PROMPT",
"status": "success",
"latency": 1200,
"cost": 0.0015
},
{
"order": 1,
"type": "API_CALL",
"status": "success",
"latency": 450,
"cost": 0
},
{
"order": 2,
"type": "CONDITION",
"status": "success",
"latency": 5,
"cost": 0
},
{
"order": 3,
"type": "API_CALL",
"status": "success",
"latency": 380,
"cost": 0
},
{
"order": 4,
"type": "PROMPT",
"status": "success",
"latency": 2100,
"cost": 0.0025
},
{
"order": 5,
"type": "CONDITION",
"status": "skipped",
"latency": 0,
"cost": 0
},
{
"order": 6,
"type": "PROMPT",
"status": "skipped",
"latency": 0,
"cost": 0
},
{
"order": 7,
"type": "PROMPT",
"status": "skipped",
"latency": 0,
"cost": 0
},
{
"order": 8,
"type": "API_CALL",
"status": "success",
"latency": 200,
"cost": 0
}
],
"totalLatency": 4335,
"totalCost": 0.0040
}
}
}Steps 5, 6, and 7 were skipped because the negative path was taken. A support ticket was created and an empathetic response was generated.
Example 2: Premium Customer Query
Execute Chain
graphql
mutation ExecuteChain {
executeChain(
chainId: "chain_abc123"
input: {
message: "Hi! I'm interested in upgrading my subscription. What options do you have?"
customerId: "cust_premium_789"
}
) {
output
totalLatency
totalCost
}
}Response
json
{
"data": {
"executeChain": {
"output": "Hi Michael! It's wonderful to hear from you, and thank you for being a valued Premium member since 2022. We truly appreciate your continued loyalty!\n\nI'm excited to help you explore upgrade options. As a Premium member, you already enjoy priority support and exclusive features, but our Enterprise plan offers even more:\n\n• Dedicated account manager\n• Custom integrations\n• Advanced analytics dashboard\n• 24/7 white-glove support\n• Volume discounts (perfect given your 47 orders with us!)\n\nI'd love to schedule a personalized demo to show you exactly how these features could benefit your use case. Would you prefer a call this week or next?\n\nAs always, you have priority access to our team - feel free to reach out anytime!",
"totalLatency": 3890,
"totalCost": 0.0035
}
}
}In this execution, the chain took the positive/neutral path, then the premium path, generating a personalized VIP response.
Step 5: Monitor and Optimize
Query Chain Statistics
graphql
query GetChainStats {
chain(id: "chain_abc123") {
name
executions {
id
status
totalLatency
totalCost
createdAt
steps {
type
status
latency
cost
}
}
}
}Analyze execution patterns to optimize:
// Calculate path distribution
const executions = data.chain.executions
const pathCounts = {
negative: 0,
premium: 0,
standard: 0,
}
executions.forEach(exec => {
const steps = exec.steps
// Check which response step executed
if (steps.find(s => s.order === 4 && s.status === 'success')) {
pathCounts.negative++
} else if (steps.find(s => s.order === 6 && s.status === 'success')) {
pathCounts.premium++
} else if (steps.find(s => s.order === 7 && s.status === 'success')) {
pathCounts.standard++
}
})
console.log('Path Distribution:')
console.log(`Negative path: ${pathCounts.negative} (${(pathCounts.negative / executions.length * 100).toFixed(1)}%)`)
console.log(`Premium path: ${pathCounts.premium} (${(pathCounts.premium / executions.length * 100).toFixed(1)}%)`)
console.log(`Standard path: ${pathCounts.standard} (${(pathCounts.standard / executions.length * 100).toFixed(1)}%)`)Key Patterns
- Conditional Routing - Use CONDITION steps to route execution based on data
- Shared Output Keys - Multiple conditional branches can write to the same output key
- API Integration - Fetch external data and create records via API calls
- Always-Run Steps - Steps without tags execute regardless of conditions
- Nested Conditions - Tag CONDITION steps to create multi-level decision trees
Production Considerations
Error Handling - Add error handling for API calls with fallback responses
Timeout Configuration - Set appropriate timeouts for external API calls
Rate Limiting - Monitor execution volume and implement rate limiting
Cost Monitoring - This workflow costs ~$0.004 per execution. Monitor daily volumes to control spending.