Building AI Workflow Personas: When Your Code Needs an Expert Team
How we implemented workflow personas and multi-provider A/B testing in nyxCore, turning single AI responses into expert team collaborations with side-by-side comparisons.
Building AI Workflow Personas: When Your Code Needs an Expert Team
Ever wished you could inject domain expertise directly into your AI workflows? What if instead of getting one generic response, you could have a team of specialists—a senior architect, a security expert, and a UX designer—all weighing in on your problem simultaneously?
That's exactly what we built into nyxCore this week: workflow personas and multi-provider A/B comparison. Here's the story of turning a single-threaded AI workflow into a collaborative expert system.
The Vision: From Solo AI to Expert Teams
The original nyxCore workflow engine was straightforward—one step, one prompt, one response. But real-world problems need diverse perspectives. When you're designing a new feature, you don't just want "an AI response"—you want input from someone who thinks like a security engineer, another who approaches problems like a product manager, and maybe a third with deep technical architecture experience.
Our solution: workflow personas—pre-defined expert identities that get injected into step system prompts, combined with multi-provider comparison that runs the same prompt across different LLM providers side-by-side.
The Architecture: Database to UI
Database Schema Changes
We started with the data layer, adding two key fields to our Prisma schema:
model Workflow {
// ... existing fields
personaIds String[] @db.Uuid // Links to expert personas
}
model WorkflowStep {
// ... existing fields
compareProviders String[] @default([]) // ["anthropic", "openai", "google"]
}
The beauty of Prisma's String[] type meant we could store multiple personas per workflow and multiple providers per step without complex junction tables.
Backend: The Expert Injection System
The real magic happens in the workflow engine. We built a loadPersonaSystemPrompts() function that fetches persona data and formats it for injection:
// Before: Single system prompt
systemPrompt = step.systemPrompt
// After: Expert team + step prompt
const personaPrompts = await loadPersonaSystemPrompts(workflow.personaIds);
systemPrompt = `${personaPrompts}\n\n${step.systemPrompt}`;
Each persona gets formatted as:
## Expert: Senior Security Engineer
You are a security-focused engineer with 10+ years experience...
## Expert: UX Design Lead
You approach problems from a user-centered design perspective...
Multi-Provider Execution
When a step has compareProviders configured, instead of generating one response, we fork execution:
if (step.compareProviders.length > 1) {
// Generate one alternative per provider
for (const provider of step.compareProviders) {
alternatives.push(
await executeStep(context, step, { providerOverride: provider })
);
}
} else {
// Traditional single/multi-generation
// ...
}
This gives you side-by-side comparisons: the same expert-enhanced prompt run through GPT-4, Claude, and Gemini simultaneously.
Frontend: Intuitive Configuration
The UI needed to make this powerful feature approachable. We added:
Persona Selection: A multi-select checklist that appears after you choose your consolidation strategy:
{selectedPersonas.map(persona => (
<div key={persona.id} className="flex items-center space-x-2">
<Users className="h-4 w-4" />
<Badge variant="secondary">{persona.name}</Badge>
</div>
))}
Provider Comparison Toggle: Each step card now has provider selection that auto-syncs with generation count:
// When you enable multi-provider, generateCount updates automatically
const handleProviderToggle = (providers: string[]) => {
updateStep(step.id, {
compareProviders: providers,
generateCount: Math.max(1, providers.length)
});
};
Visual Feedback: Alternative cards now show which provider and model generated each response, plus step headers display "N providers" badges when comparison is active.
Lessons Learned: The TypeScript Tango
Building this feature taught us some valuable lessons about TypeScript and complex state management:
The Zod Enum Challenge
Our first attempt used simple string[] types for provider arrays, but TypeScript wasn't having it:
// ❌ This failed
compareProviders: string[] // Not assignable to ("anthropic"|"openai"|"google")[]
// ✅ This worked
compareProviders: ("anthropic" | "openai" | "google" | "ollama")[]
Lesson: When working with Zod schemas and strict enums, match your TypeScript types exactly to the schema constraints. The extra verbosity prevents runtime errors.
Default Configuration Gotchas
Adding new required fields to existing schemas created ripple effects:
// ❌ TS2741: Property 'compareProviders' is missing
const defaultStepConfig = {
systemPrompt: "",
generateCount: 1
// compareProviders missing!
};
// ✅ Always provide defaults for new fields
const defaultStepConfig = {
systemPrompt: "",
generateCount: 1,
compareProviders: []
};
Lesson: When extending existing types, audit all the places that create default instances. TypeScript will catch most of them, but it's better to be proactive.
Development Server Conflicts
Running multiple development servers while testing led to mysterious style conflicts and cached responses.
Lesson: When making significant changes, kill all processes on your dev port (lsof -ti:3000 | xargs kill), clear your .next cache, and start fresh. The few extra seconds save hours of debugging phantom issues.
The Results: Workflows That Think Like Teams
The final implementation supports powerful new workflow patterns:
- Expert Team Workflows: Select multiple personas (Security Expert, Product Manager, Technical Architect) and every step gets their combined perspective
- Provider A/B Testing: Enable comparison mode and see how GPT-4, Claude, and Gemini each interpret the same expert-enhanced prompt
- Cost-Aware Planning: The system automatically calculates costs across all providers and personas before execution
- Seamless Selection: Pick the best alternative from any provider and the workflow continues with that choice
What's Next?
This foundation opens up exciting possibilities:
- Dynamic persona creation from natural language descriptions
- Persona marketplace where teams can share expert configurations
- Automated provider selection based on step type and performance history
- Consensus mechanisms that automatically merge insights from multiple expert perspectives
The code is live, tested, and ready for teams who want their AI workflows to think more like diverse, expert human teams. Because sometimes the best AI response isn't from one model—it's from the right combination of expertise and intelligence working together.
Want to see this in action? The complete implementation is available in nyxCore commit aa37799 with full TypeScript types, tRPC procedures, and React components.