Documentation Index Fetch the complete documentation index at: https://docs.runflow.ai/llms.txt
Use this file to discover all available pages before exploring further.
An automated feedback processing pipeline that analyzes sentiment with AI, categorizes issues, and creates tickets for negative feedback. This example shows how to combine workflows with agents and connectors for a hands-off analysis system.
Project Structure
feedback-analysis/
├── main.ts
├── workflows/
│ └── analyze-feedback.ts
├── agents/
│ ├── sentiment.ts
│ └── action-recommender.ts
├── config/
│ └── settings.ts
├── .runflow/
│ └── rf.json
├── package.json
└── tsconfig.json
Step 1: Configuration
export const FEEDBACK_CATEGORIES = [
'product_bug' ,
'feature_request' ,
'ux_issue' ,
'performance' ,
'documentation' ,
'pricing' ,
'support_quality' ,
'praise' ,
'other' ,
] as const ;
export type FeedbackCategory = ( typeof FEEDBACK_CATEGORIES )[ number ];
export const SENTIMENT_THRESHOLDS = {
negative: - 0.3 , // Below this = negative
positive: 0.3 , // Above this = positive
};
Step 2: Analysis Agents
Sentiment Analyzer
Cheap, fast model for classification:
import { Agent , openai } from '@runflow-ai/sdk' ;
export const sentimentAgent = new Agent ({
name: 'Sentiment Analyzer' ,
instructions: `You analyze customer feedback for sentiment and categorization.
## Task
Analyze the feedback and return a structured analysis.
## Response Format
Respond with valid JSON only:
{
"sentiment": "positive" | "neutral" | "negative",
"score": <number between -1.0 and 1.0>,
"category": "<one of: product_bug, feature_request, ux_issue, performance, documentation, pricing, support_quality, praise, other>",
"themes": ["<key theme 1>", "<key theme 2>"],
"summary": "<one sentence summary of the feedback>"
}` ,
model: openai ( 'gpt-4o-mini' ),
modelConfig: { temperature: 0 },
});
Action Recommender
Better model for nuanced recommendations:
agents/action-recommender.ts
import { Agent , openai } from '@runflow-ai/sdk' ;
export const actionAgent = new Agent ({
name: 'Action Recommender' ,
instructions: `You recommend specific actions based on customer feedback analysis.
## Task
Given the original feedback and sentiment analysis, recommend concrete actions.
## Response Format
Respond with valid JSON:
{
"priority": "critical" | "high" | "medium" | "low",
"actions": [
{ "action": "<what to do>", "owner": "<team: product | engineering | support | marketing>" }
],
"shouldFollowUp": <boolean>,
"followUpMessage": "<suggested response to the customer, if applicable>"
}` ,
model: openai ( 'gpt-4o' ),
modelConfig: { temperature: 0.3 },
});
Step 3: Workflow
The workflow chains analysis steps and conditionally creates tickets:
workflows/analyze-feedback.ts
import { createWorkflow } from '@runflow-ai/sdk' ;
import { z } from 'zod' ;
import { sentimentAgent } from '../agents/sentiment' ;
import { actionAgent } from '../agents/action-recommender' ;
export const analyzeFeedbackWorkflow = createWorkflow ({
id: 'analyze-feedback' ,
inputSchema: z . object ({
feedback: z . string (),
customerEmail: z . string (),
customerName: z . string (),
source: z . string (),
}),
outputSchema: z . any (),
})
// Step 1: Analyze sentiment
. agent ( 'analyze' , sentimentAgent , {
promptTemplate: `Analyze this customer feedback:
"{{input.feedback}}"
Customer: {{input.customerName}} ({{input.customerEmail}})
Source: {{input.source}}` ,
})
// Step 2: Recommend actions
. agent ( 'recommend' , actionAgent , {
promptTemplate: `Original feedback: "{{input.feedback}}"
Customer: {{input.customerName}}
Sentiment analysis:
{{analyze.text}}
What actions should we take?` ,
})
// Step 3: Create ticket if negative
. condition (
'check-negative' ,
( ctx ) => {
try {
const analysis = JSON . parse ( ctx . stepResults . get ( 'analyze' ). text );
return analysis . sentiment === 'negative' ;
} catch {
return false ;
}
},
// Negative path: create ticket
[
{
id: 'create-ticket' ,
type: 'connector' ,
config: {
connector: 'hubspot' ,
resource: 'tickets' ,
action: 'create' ,
parameters: {
subject: 'Negative Feedback — {{input.customerName}}' ,
content: `Feedback: {{input.feedback}}
Analysis: {{analyze.text}}
Recommended actions: {{recommend.text}}` ,
priority: 'high' ,
category: 'feedback' ,
},
},
},
],
// Positive/neutral path: log only
[
{
id: 'log-feedback' ,
type: 'function' ,
config: {
execute : async ( input , ctx ) => {
return { logged: true , sentiment: 'positive_or_neutral' };
},
},
},
]
)
. build ();
Step 4: Main Entry Point
import { identify , track } from '@runflow-ai/sdk/observability' ;
import { analyzeFeedbackWorkflow } from './workflows/analyze-feedback' ;
export async function main ( input : any ) {
// Validate
if ( ! input ?. feedback ) {
return { error: 'feedback is required' };
}
identify ( input . customerEmail || input . customerId || 'anonymous' );
try {
const result = await analyzeFeedbackWorkflow . execute ({
feedback: input . feedback ,
customerEmail: input . customerEmail || '' ,
customerName: input . customerName || 'Unknown' ,
source: input . source || 'api' ,
});
// Parse results for metrics
let sentiment = 'unknown' ;
let category = 'unknown' ;
try {
const analysis = JSON . parse ( result . stepResults ?. analyze ?. text || '{}' );
sentiment = analysis . sentiment ;
category = analysis . category ;
} catch {}
// Track feedback metrics
track ( 'feedback_analyzed' , {
sentiment ,
category ,
source: input . source || 'api' ,
ticketCreated: sentiment === 'negative' ,
});
return {
message: `Feedback analyzed: ${ sentiment } sentiment, category: ${ category } ` ,
analysis: result . stepResults ?. analyze ?. text ,
actions: result . stepResults ?. recommend ?. text ,
ticketCreated: sentiment === 'negative' ,
};
} catch ( error ) {
console . error ( '[feedback-analysis] Error:' , error );
return { error: 'Failed to analyze feedback' };
}
}
Triggering the Pipeline
This workflow is typically triggered by external events, not user conversations:
# From a webhook (NPS survey, support form, review platform)
curl -X POST https://your-agent.runflow.ai/api \
-H "Content-Type: application/json" \
-d '{
"feedback": "The product crashes every time I try to export. Very frustrated.",
"customerEmail": "jane@example.com",
"customerName": "Jane Doe",
"source": "nps_survey"
}'
How It Works
Feedback arrives (webhook, form, API)
↓
┌────────────────────┐
│ Sentiment Agent │ gpt-4o-mini → sentiment, category, themes
└──────┬─────────────┘
↓
┌────────────────────┐
│ Action Agent │ gpt-4o → priority, actions, follow-up
└──────┬─────────────┘
↓
Negative?
╱ ╲
Yes No
↓ ↓
Create Log for
HubSpot analytics
ticket
↓
Track metrics
Key Patterns
Pipeline vs Conversation
This is a workflow (pipeline), not an agent (conversation). Data flows in, gets processed, and comes out — no back-and-forth with a user. Workflows are ideal for batch processing and event-driven automations.
Cheap Classification, Quality Recommendations
The sentiment agent uses gpt-4o-mini (fast, cheap). The action recommender uses gpt-4o (better reasoning). Match model cost to task complexity.
Structured JSON for Reliable Branching
Both agents return structured JSON so the workflow can reliably branch on results:
// Agent returns: { "sentiment": "negative", ... }
// Workflow condition parses and branches:
. condition ( 'check' , ( ctx ) => {
const analysis = JSON . parse ( ctx . stepResults . get ( 'analyze' ). text );
return analysis . sentiment === 'negative' ;
})
Next Steps
Workflows Learn more about workflows
Connectors HubSpot, Slack integrations
Multi-Agent System Supervisor pattern
Observability Track business metrics