feat(personas): deep OCEAN semantics, missing fields, extraversion + baseline
- Add techSavviness, hasPurchasingPower, hasChildren, description to _format_persona_details() — previously ignored despite being in persona model - Rewrite OCEAN block: each trait now includes its psychological definition, full name, and [LOW/MODERATE/HIGH] label so LLM understands the scoring scale (e.g. "Agreeableness (cooperation, empathy, conflict avoidance): 25/100 [LOW]") - Add extraversion behavioral constraint to _generate_behavioral_instructions() (was used for response length only, never for personality guidance) - Add LOW conscientiousness constraint (spontaneous, gut-feel) - Add BALANCED PERSONALITY baseline for personas with all-moderate OCEAN scores — previously these got zero behavioral constraints, behaving generically - Add optimist/enthusiast personality keyword mapping - Add OCEAN archetype legend to conversation-decision-engine.md so decision engine understands what high/low scores mean when selecting next speaker - Add +15% Diversity Boost modifier: prefer speakers whose archetype differs from the last 2 participants (reduces echo-chamber dynamics) - Add OCEAN model explanation header to focus-group-response.md prompt Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
64568b6164
commit
e23e52f77d
3 changed files with 92 additions and 23 deletions
|
|
@ -245,24 +245,44 @@ def _format_persona_details(persona: Dict[str, Any]) -> str:
|
|||
if env_concern:
|
||||
details.append(f"Environmental concern: {env_concern}")
|
||||
|
||||
# OCEAN traits if available
|
||||
tech_savviness = persona.get('techSavviness')
|
||||
if tech_savviness:
|
||||
details.append(f"Tech savviness: {tech_savviness}")
|
||||
|
||||
has_purchasing_power = persona.get('hasPurchasingPower')
|
||||
if has_purchasing_power is not None:
|
||||
details.append(f"Has purchasing decision authority: {'Yes' if has_purchasing_power else 'No'}")
|
||||
|
||||
has_children = persona.get('hasChildren')
|
||||
if has_children is not None:
|
||||
details.append(f"Has children: {'Yes' if has_children else 'No'}")
|
||||
|
||||
description = persona.get('description')
|
||||
if description and isinstance(description, str) and description.strip():
|
||||
details.append(f"Additional description: {description}")
|
||||
|
||||
# OCEAN traits — Big Five psychological model with full semantic context
|
||||
ocean = persona.get('oceanTraits', {})
|
||||
if ocean:
|
||||
ocean_traits = []
|
||||
if 'openness' in ocean:
|
||||
ocean_traits.append(f"Openness: {ocean['openness']}/100")
|
||||
if 'conscientiousness' in ocean:
|
||||
ocean_traits.append(f"Conscientiousness: {ocean['conscientiousness']}/100")
|
||||
if 'extraversion' in ocean:
|
||||
ocean_traits.append(f"Extraversion: {ocean['extraversion']}/100")
|
||||
if 'agreeableness' in ocean:
|
||||
ocean_traits.append(f"Agreeableness: {ocean['agreeableness']}/100")
|
||||
if 'neuroticism' in ocean:
|
||||
ocean_traits.append(f"Neuroticism: {ocean['neuroticism']}/100")
|
||||
|
||||
if ocean_traits:
|
||||
details.append("OCEAN Traits:")
|
||||
details.extend([f"- {trait}" for trait in ocean_traits])
|
||||
trait_meta = {
|
||||
'openness': ("Openness to Experience", "curiosity, creativity, preference for novelty vs. routine"),
|
||||
'conscientiousness': ("Conscientiousness", "organization, dependability, self-discipline, detail focus"),
|
||||
'extraversion': ("Extraversion", "sociability, assertiveness, talkativeness, energy in social situations"),
|
||||
'agreeableness': ("Agreeableness", "cooperation, empathy, trust, tendency to avoid conflict"),
|
||||
'neuroticism': ("Neuroticism / Emotional Instability", "anxiety, moodiness, worry, emotional reactivity"),
|
||||
}
|
||||
ocean_lines = []
|
||||
for key, (label, desc) in trait_meta.items():
|
||||
if key in ocean:
|
||||
score = ocean[key]
|
||||
level = "LOW" if score < 35 else ("HIGH" if score > 65 else "MODERATE")
|
||||
ocean_lines.append(f"- {label} ({desc}): {score}/100 [{level}]")
|
||||
if ocean_lines:
|
||||
details.append(
|
||||
"OCEAN Personality Traits (Big Five model — 0=very low, 100=very high; "
|
||||
"LOW/HIGH labels show how strongly each trait shapes behaviour):"
|
||||
)
|
||||
details.extend(ocean_lines)
|
||||
|
||||
# Goals, frustrations, motivations
|
||||
if persona.get('goals'):
|
||||
|
|
@ -310,7 +330,9 @@ def _generate_behavioral_instructions(persona: Dict[str, Any]) -> str:
|
|||
neuroticism = ocean.get('neuroticism', 50)
|
||||
openness = ocean.get('openness', 50)
|
||||
conscientiousness = ocean.get('conscientiousness', 50)
|
||||
extraversion = ocean.get('extraversion', 50)
|
||||
|
||||
# Agreeableness — cooperation vs. challenge
|
||||
if agreeableness < 35:
|
||||
instructions.append(
|
||||
"LOW AGREEABLENESS: Challenge ideas directly. Express disagreement when you see flaws. "
|
||||
|
|
@ -322,16 +344,19 @@ def _generate_behavioral_instructions(persona: Dict[str, Any]) -> str:
|
|||
"don't just echo what others said without adding something new."
|
||||
)
|
||||
|
||||
# Neuroticism — emotional stability vs. anxiety
|
||||
if neuroticism > 65:
|
||||
instructions.append(
|
||||
"HIGH ANXIETY/NEUROTICISM: Focus on risks, downsides, and worst-case scenarios. "
|
||||
"HIGH NEUROTICISM/ANXIETY: Focus on risks, downsides, and worst-case scenarios. "
|
||||
"Express hesitation and concerns openly. Be the voice of doubt in the group."
|
||||
)
|
||||
elif neuroticism < 25:
|
||||
instructions.append(
|
||||
"LOW NEUROTICISM: Respond with calm confidence. Don't dwell on risks unless they're obvious."
|
||||
"LOW NEUROTICISM: Respond with calm, grounded confidence. "
|
||||
"Don't catastrophise or dwell on risks unless they are very obvious."
|
||||
)
|
||||
|
||||
# Openness — curiosity vs. conventionality
|
||||
if openness > 75:
|
||||
instructions.append(
|
||||
"HIGH OPENNESS: Welcome unconventional angles. Connect ideas to broader trends. "
|
||||
|
|
@ -343,17 +368,36 @@ def _generate_behavioral_instructions(persona: Dict[str, Any]) -> str:
|
|||
"Prefer familiar, proven solutions over novelty."
|
||||
)
|
||||
|
||||
# Conscientiousness — discipline and detail focus
|
||||
if conscientiousness > 75:
|
||||
instructions.append(
|
||||
"HIGH CONSCIENTIOUSNESS: Demand specifics, evidence, and reliability. "
|
||||
"Challenge vague claims. Focus on quality, detail, and whether promises can actually be kept."
|
||||
)
|
||||
elif conscientiousness < 30:
|
||||
instructions.append(
|
||||
"LOW CONSCIENTIOUSNESS: You are spontaneous and flexible. "
|
||||
"Don't over-analyse — respond from gut feeling and first impressions."
|
||||
)
|
||||
|
||||
# Personality keyword mapping
|
||||
# Extraversion — social energy and assertiveness
|
||||
if extraversion > 70:
|
||||
instructions.append(
|
||||
"HIGH EXTRAVERSION: Be vocal and enthusiastic. Drive the conversation forward. "
|
||||
"Express your opinions energetically and naturally invite others to react."
|
||||
)
|
||||
elif extraversion < 30:
|
||||
instructions.append(
|
||||
"LOW EXTRAVERSION/INTROVERTED: Speak thoughtfully, not impulsively. "
|
||||
"Your contributions are deliberate and considered — quality over quantity."
|
||||
)
|
||||
|
||||
# Personality keyword mapping (covers descriptive labels users assign)
|
||||
personality_lower = personality.lower()
|
||||
skeptic_words = ['skeptic', 'sceptic', 'critical', 'doubtful', 'скептик', 'критик', 'сварлив', 'критичн']
|
||||
anxious_words = ['anxious', 'worried', 'nervous', 'тревожн', 'беспокойн', 'тревог']
|
||||
pragmatic_words = ['pragmatic', 'practical', 'реалист', 'прагматич']
|
||||
optimist_words = ['optimist', 'оптимист', 'enthusiast', 'энтузиаст', 'positive', 'позитивн']
|
||||
|
||||
if any(w in personality_lower for w in skeptic_words):
|
||||
instructions.append(
|
||||
|
|
@ -371,9 +415,19 @@ def _generate_behavioral_instructions(persona: Dict[str, Any]) -> str:
|
|||
"PRAGMATIC PERSONALITY: Focus on practical, real-world applicability. "
|
||||
"Challenge idealistic claims with 'but will this actually work in my daily life?'"
|
||||
)
|
||||
if any(w in personality_lower for w in optimist_words):
|
||||
instructions.append(
|
||||
"OPTIMIST/ENTHUSIAST PERSONALITY: Lead with excitement and possibility. "
|
||||
"Highlight what excites you — but make sure your enthusiasm is grounded in your personal experience."
|
||||
)
|
||||
|
||||
if not instructions:
|
||||
return ""
|
||||
# Baseline guidance so even moderate personas have some direction
|
||||
instructions.append(
|
||||
"BALANCED PERSONALITY: Your traits are moderate across the board. "
|
||||
"Don't just agree with everything — add your unique perspective, lived experience, or personal angle. "
|
||||
"Balance validation with thoughtful questions or a different point of view."
|
||||
)
|
||||
|
||||
header = "## BEHAVIORAL CONSTRAINTS (these define your personality — follow them strictly):"
|
||||
return header + "\n" + "\n".join(f"- {i}" for i in instructions)
|
||||
|
|
|
|||
|
|
@ -27,15 +27,29 @@ Use these guidelines to determine who should speak next:
|
|||
- **@Mentions override ALL other selection criteria - ignore probability calculations, fatigue, recency penalties, etc.**
|
||||
- **Only use the probability system below if NO participant is @mentioned in the recent message**
|
||||
|
||||
**OCEAN ARCHETYPES — use these to understand each participant's role in the group:**
|
||||
- HIGH Agreeableness (>65): consensus-seeker — builds bridges, validates, harmonises
|
||||
- LOW Agreeableness (<35): challenger — pushes back, questions, disrupts consensus
|
||||
- HIGH Neuroticism (>65): risk-focused voice — raises concerns, doubts, worst-cases
|
||||
- LOW Neuroticism (<35): stabiliser — calm, grounded, doesn't catastrophise
|
||||
- HIGH Conscientiousness (>65): detail skeptic — demands evidence, challenges vague claims
|
||||
- HIGH Openness (>65): innovator — welcomes new angles, connects ideas across contexts
|
||||
- LOW Openness (<35): traditionalist — prefers proven approaches, skeptical of novelty
|
||||
- HIGH Extraversion (>65): conversation driver — speaks freely, energises the group
|
||||
- LOW Extraversion (<35): deliberate contributor — speaks less but adds considered insights
|
||||
|
||||
**When selecting the next speaker, actively seek DIVERSITY OF ARCHETYPES — not just the next person by probability. If the last 2 speakers were both consensus-seekers (high agreeableness), deliberately select a challenger or risk-focused voice next.**
|
||||
|
||||
**Base Participation Probability (only when no @mentions detected):**
|
||||
- High Extraversion (70-100): 35-40% base chance
|
||||
- Medium Extraversion (30-70): 25-30% base chance
|
||||
- Medium Extraversion (30-70): 25-30% base chance
|
||||
- Low Extraversion (0-30): 20-25% base chance
|
||||
|
||||
**Modifiers (only when no @mentions detected):**
|
||||
- **Participation Fatigue**: Reduce probability by 5% for each previous response in this session (max 50% reduction)
|
||||
- **Recency Penalty**: If participant spoke in the last turn, reduce probability by 50%
|
||||
- **Topic Relevance**: If current topic matches participant's interests/expertise, increase by 50%
|
||||
- **Diversity Boost**: +15% if this participant's OCEAN archetype differs from the last 2 speakers
|
||||
- **Agreeableness Boost**: +5% if discussion is consensus-oriented and participant has high agreeableness
|
||||
- **Neuroticism Penalty**: -5% if topic is emotionally sensitive and participant has high neuroticism
|
||||
- **Openness Boost**: +8% when novel ideas are emerging and participant has high openness
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
You are acting as a synthetic persona in a focus group discussion. Your goal is to provide a realistic,
|
||||
thoughtful response that reflects your persona's characteristics, values, and communication style.
|
||||
You are acting as a synthetic persona in a focus group discussion. Your goal is to provide a realistic, thoughtful response that reflects your persona's characteristics, values, and communication style.
|
||||
|
||||
**HOW TO READ THE PERSONA BELOW**: The persona uses the Big Five (OCEAN) personality model — a widely validated psychological framework. Each trait is scored 0–100. Scores marked [LOW] (<35) mean the trait is weak and should actively shape behaviour in that direction. Scores marked [HIGH] (>65) mean the trait dominates. Scores marked [MODERATE] are average. The BEHAVIORAL CONSTRAINTS section translates these scores into concrete instructions — follow them strictly, they are the core of this persona's personality.
|
||||
|
||||
## PERSONA DETAILS:
|
||||
{persona_details}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue