🔴 Breaking Analysis: The Secret Traitor / Red Cloak Explained → Read Now

Part IV: Computational Modelling

Chapter 9: RAG Architecture for The Traitors Simulation

~5,000 words

Abstract

This chapter presents the technical architecture for simulating The Traitors using a Retrieval-Augmented Generation (RAG) system. I describe the V5 pipeline architecture, expert-based knowledge organization, citation-grounded response generation, and the integration of query classification, graph enrichment, and hierarchical summarization. The system enables AI agents to embody distinct characters with personality, knowledge boundaries, and strategic capabilities: the foundation for emergent gameplay. For an introduction to the AI approach, see the article on AI Architecture.

9.1 Introduction: The RAG Approach to Social Simulation

Simulating The Traitors requires AI agents that can:

  1. Maintain consistent personalities across extended gameplay (see Strategic Archetypes)
  2. Access relevant knowledge while respecting information boundaries
  3. Generate authentic dialogue reflecting character voice
  4. Make strategic decisions based on game state
  5. Manage deception, secrets, and emotional states

Traditional approaches (rule-based systems, finite state machines, simple chatbots) fail to capture the nuanced social dynamics the format requires. RAG-based systems offer a solution by grounding generation in retrieved knowledge while enabling contextual response synthesis.

9.2 System Architecture Overview

9.2.1 Core Components

┌────────────────────────────────────────────────────────────┐
│                    TRAITORS SIMULATION ENGINE              │
├────────────────────────────────────────────────────────────┤
│                                                            │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐     │
│  │   PLAYER    │    │    GAME     │    │   VIEWER    │     │
│  │   AGENTS    │    │   ENGINE    │    │  INTERFACE  │     │
│  └──────┬──────┘    └──────┬──────┘    └──────┬──────┘     │
│         │                  │                  │            │
│         ▼                  ▼                  ▼            │
│  ┌──────────────────────────────────────────────────────┐  │
│  │                   RAG PIPELINE (V5)                  │  │
│  ├──────────────────────────────────────────────────────┤  │
│  │  Query          Vector        Graph        Prompt    │  │
│  │  Classifier  →  Search   →   Enrichment → Builder    │  │
│  │       │            │             │            │      │  │
│  │       ▼            ▼             ▼            ▼      │  │
│  │  ┌────────┐  ┌──────────┐  ┌─────────┐  ┌─────────┐  │  │
│  │  │ 7 Type │  │ pgvector │  │ Dgraph  │  │ Modular │  │  │
│  │  │ Routes │  │   k-NN   │  │ Client  │  │ Prompts │  │  │
│  │  └────────┘  └──────────┘  └─────────┘  └─────────┘  │  │
│  └──────────────────────────────────────────────────────┘  │
│                            │                               │
│                            ▼                               │
│  ┌──────────────────────────────────────────────────────┐  │
│  │                  KNOWLEDGE STORES                    │  │
│  ├──────────────────────────────────────────────────────┤  │
│  │  PostgreSQL     │    Dgraph      │    RAPTOR         │  │
│  │  (Sections,     │  (Entities,    │  (Hierarchical    │  │
│  │   Embeddings)   │  Relationships)│   Summaries)      │  │
│  └──────────────────────────────────────────────────────┘  │
│                                                            │
└────────────────────────────────────────────────────────────┘
        

9.2.2 Technology Stack

Component Technology Purpose
Language Go 1.21+ Core implementation
Database PostgreSQL 15+ with pgvector Vector storage, sections, metadata
Knowledge Graph Dgraph v23.1.0 Entity relationships
LLM OpenAI GPT-4o-mini Response generation
Embeddings text-embedding-3-small Vector representations
Communication MCP (Model Context Protocol) Agent integration

9.3 The V5 RAG Pipeline

9.3.1 Pipeline Stages

The V5 pipeline processes queries through seven stages:

Query → Classification → Embedding → Vector Search →
        Temporal Filter → Graph Enrichment →
        RAPTOR Context → Prompt Building → LLM Generation
        

9.3.2 Query Classification

The classifier routes queries to appropriate processing paths:

Classification Types:

Type Description Example Query
factual Direct information request "What is [character]'s occupation?"
temporal Time-bound questions "What happened in Episode 3?"
relationship Entity connections "How does [X] know [Y]?"
synthesis Requires inference "Why might [X] suspect [Y]?"
comparison Evaluating alternatives "Who is more trustworthy?"
narrative Story-based "Describe the events of the murder"
entity_list Enumeration "Who are the remaining players?"

Implementation:

type QueryClassifier struct {
    llmClient *llm.Client
    patterns  []ClassificationPattern
}

func (c *QueryClassifier) Classify(ctx context.Context, query string) (QueryType, float64) {
    // LLM-based classification with confidence score
    // Falls back to pattern matching for efficiency
}
        

9.3.3 Vector Search with pgvector

Embedding Process:

  1. Query text vectorized using text-embedding-3-small
  2. Similarity search against section embeddings
  3. k-NN retrieval with configurable k

SQL Query Pattern:

SELECT section_id, body_text,
       1 - (embedding <=> $1::vector) as similarity
FROM content_section_definition cs
JOIN section_embeddings se ON cs.section_id = se.section_id
WHERE expert_id = $2
ORDER BY embedding <=> $1::vector
LIMIT $3
        

9.3.4 Temporal Filtering

For game-state-aware retrieval:

type QueryOptions struct {
    TemporalCutoff *time.Time  // Only retrieve content before this point
    GamePhase      GamePhase   // Current game phase
    EpisodeNumber  int         // Episode context
}
        

This enables queries that respect player knowledge boundaries; a character should only "know" events that have occurred in their timeline.

9.3.5 Graph Enrichment

Dgraph provides relationship context:

Entity Query:

query GetEntityWithRelationships($id: string) {
    entity(func: eq(entity_id, $id)) {
        name
        type
        properties
        relationships @facets {
            target {
                name
                type
            }
            relationship_type
            strength
        }
    }
}
        

Enrichment Process:

  1. Identify entities mentioned in query
  2. Retrieve entity details and relationships
  3. Inject relationship context into prompt

9.3.6 RAPTOR Hierarchical Summarization

RAPTOR (Recursive Abstractive Processing for Tree-Organized Retrieval) provides multi-scale context:

Tree Structure:

Level 0: Base sections (942 for main expert)
Level 1: Cluster summaries (~100 nodes)
Level 2: Super-cluster summaries (~10 nodes)
Level 3: Root summary (1 node)
        

Retrieval Logic:

func (r *RAPTORService) GetContextForQuery(ctx context.Context,
    query string, chunkIDs []int, maxDepth int) (*RAPTORContext, error) {

    // Traverse tree from base chunks upward
    // Gather summaries that contextualize retrieved content
    // Return hierarchical context for prompt inclusion
}
        

9.4 Expert-Based Knowledge Organization

9.4.1 The Expert Concept

Each AI agent is backed by an "expert", a knowledge domain with:

  • Defined personality and voice
  • Knowledge boundaries (what they can know)
  • Citation sources
  • Relationship to other experts

Expert Schema:

CREATE TABLE expert_definition (
    expert_id UUID PRIMARY KEY,
    expert_name TEXT NOT NULL,
    description TEXT,
    personality JSONB,
    knowledge_scope TEXT[],
    voice_configuration JSONB,
    created_at TIMESTAMP
);
        

9.4.2 Traitors-Specific Expert Configuration

For game simulation, each player requires an expert configuration based on player archetypes:

{
    "expert_id": "player_1_uuid",
    "expert_name": "Sarah",
    "personality": {
        "archetype": "detective",
        "traits": ["analytical", "cautious", "observant"],
        "speaking_style": "precise_questioning",
        "risk_tolerance": 0.3
    },
    "role": "faithful",
    "knowledge_scope": ["public_events", "personal_observations", "alliance_info"],
    "secret_knowledge": ["own_role"]
}
        

9.4.3 Knowledge Boundaries

Critical for game integrity:

Faithful Knowledge:

  • Own role (Faithful)
  • Public events (murders revealed, banishments)
  • Personal observations (who they've talked to)
  • Alliance information (shared within trusted group)

Traitor Knowledge:

  • Own role (Traitor)
  • Fellow Traitor identities
  • Murder decisions and rationale
  • Public events
  • Recruitment plans (see Secret Traitor analysis)

Forbidden Knowledge:

  • Other players' private thoughts (confessionals, as explored in Audience Psychology)
  • Future events
  • Production information

9.4.4 Multi-Expert Interaction

When players converse, the system:

  1. Maintains separate expert contexts
  2. Routes queries to appropriate expert
  3. Ensures no cross-contamination of private knowledge
  4. Generates contextually appropriate responses

9.5 The PromptBuilder System

9.5.1 Modular Architecture

The PromptBuilder assembles prompts from components based on context:

type PromptBuilder struct {
    modes    PromptModes
    identity IdentityConfig
    voice    VoiceConfig
    context  RetrievedContext
}

type PromptModes struct {
    StrictKnowledgeBoundary bool  // Only speak from retrieved context
    AllowSynthesis         bool  // Can speculate beyond context
    CiteSynthesis          CitationStyle
    IncludeCitations       bool
    HasLowConfidence       bool  // Retrieved context is weak
}
        

9.5.2 Component Assembly

Standard Assembly Order:

  1. Identity (always) - "You are [Name], a [role]"
  2. Voice (if configured) - Personality, expertise, language variant
  3. Knowledge Boundary (if strict mode) - What you can/cannot know
  4. Synthesis Permission (if allowed and not strict) - How to handle gaps
  5. Context (always) - Numbered chunks from retrieval
  6. Citation Instructions (if enabled) - How to cite sources
  7. Query (always) - The actual question/prompt

9.5.3 Mode-Based Behavior

Strict Knowledge Boundary Mode:

  • Expert speaks ONLY from retrieved context
  • No speculation or synthesis
  • "I don't know" for gaps
  • Maximum citation compliance

Synthesis Allowed Mode:

  • Can speculate from character perspective
  • Must mark synthesized content
  • Maintains voice while extending

Game Context Mode (Traitors-specific):

  • Integrates game state (who's alive, current phase)
  • Respects role-based knowledge
  • Enables strategic reasoning

9.5.4 Prompt Efficiency

V5 prompts are approximately 80% smaller than legacy approaches:

Old Approach (V4):

You are an AI assistant playing the role of...
[500 words of instructions]
[100 words of personality]
[200 words of constraints]
[Retrieved context]
[Query]
        

New Approach (V5):

You are Sarah, analytical and cautious.
Your knowledge: [Retrieved context with citations]
Question: [Query]
        

9.6 Citation System

9.6.1 Citation Types

Type Description Use Case
canonical Direct quote from source Stating known facts
synthesized Generated from character knowledge Opinions, inferences
background Timeless character facts Personality, history

9.6.2 Citation Generation

Citations are extracted post-generation:

type Citation struct {
    SourceID     string
    SourceName   string
    ChunkID      int
    Quote        string
    Confidence   float64
    MatchType    MatchType  // direct, paraphrased, synthesized
    Position     TextRange
}

func (p *CitationProcessor) ExtractCitations(
    response string,
    context *RetrievedContext,
) ([]Citation, error) {
    // Match response segments to source chunks
    // Score confidence based on overlap
    // Return structured citations
}
        

9.6.3 Citation Workflow

  1. LLM generates response with inline citation markers
  2. Post-processor extracts citation positions
  3. Validator confirms citations match source material
  4. Formatter creates final output with proper attribution

9.7 Sections vs. Chunks

9.7.1 Design Decision

The system uses sections (not chunks) for RAG retrieval:

Sections:

  • Preserve semantic boundaries (~1,500 words average)
  • Natural content divisions (chapters, scenes, dialogues)
  • Context-rich units that stand alone

Chunks (traditional approach):

  • Fixed-size segments (512-1024 tokens)
  • May break mid-sentence or mid-thought
  • Require overlap for coherence

9.7.2 Rationale

For Traitors simulation, section-based retrieval provides:

  • Complete conversations (not fragments)
  • Full strategic context (not partial)
  • Character voice preservation
  • Natural citation boundaries

9.7.3 Chunk Usage

Chunks are still used for:

  • Fine-grained citation attribution
  • Detailed similarity scoring
  • RAPTOR tree building (clustering)

9.8 Game State Integration

9.8.1 State Management

The system maintains comprehensive game state:

type GameState struct {
    Episode      int
    Phase        GamePhase
    PrizePool    int

    Players      []PlayerState
    Traitors     []PlayerID  // Known to system, not all players

    Murders      []MurderEvent
    Banishments  []BanishmentEvent
    Votes        []VoteRecord

    Alliances    []Alliance
    Conversations []ConversationRecord
}

type PlayerState struct {
    ID           PlayerID
    Name         string
    Role         Role
    Status       PlayerStatus  // alive, murdered, banished
    EmotionState EmotionState
    Knowledge    KnowledgeState
    Relationships map[PlayerID]RelationshipState
}
        

9.8.2 Query Context Enhancement

Before RAG query, game state provides context:

func (e *GameEngine) EnhanceQuery(
    playerID PlayerID,
    baseQuery string,
) *EnhancedQuery {

    player := e.State.GetPlayer(playerID)

    return &EnhancedQuery{
        Query:           baseQuery,
        AskerRole:       player.Role,
        KnownPlayers:    player.Knowledge.KnownPlayers,
        CurrentPhase:    e.State.Phase,
        RecentEvents:    e.getRecentEventsFor(playerID),
        AllowedKnowledge: e.getKnowledgeBoundary(playerID),
    }
}
        

9.8.3 Response Validation

Generated responses are validated against game state:

func (v *ResponseValidator) Validate(
    response string,
    playerID PlayerID,
    gameState *GameState,
) *ValidationResult {

    // Check for forbidden knowledge leaks
    // Verify mentioned players exist
    // Confirm events referenced have occurred
    // Ensure role-appropriate content
}
        

9.9 Integration Points

9.9.1 Expert Adapter Layer

Translates between game concepts and RAG queries:

type ExpertAdapter struct {
    ragService *RAGService
    gameEngine *GameEngine
}

func (a *ExpertAdapter) GetPlayerResponse(
    ctx context.Context,
    playerID PlayerID,
    situation Situation,
) (*PlayerResponse, error) {

    // Translate situation to query
    // Apply player-specific filters
    // Call RAG pipeline
    // Post-process for game context
}
        

9.9.2 Conversation Handler

Manages multi-turn interactions:

type ConversationHandler struct {
    adapter     *ExpertAdapter
    history     *ConversationHistory
    turnManager *TurnManager
}

func (h *ConversationHandler) HandleTurn(
    ctx context.Context,
    speaker PlayerID,
    listeners []PlayerID,
    content string,
) (*TurnResult, error) {

    // Generate speaker's contribution
    // Update all listeners' knowledge
    // Record for history
    // Trigger follow-up if needed
}
        

9.9.3 Event Processing

Game events trigger RAG queries:

func (e *GameEngine) ProcessMurderReveal(murder MurderEvent) {
    // Update game state
    e.State.RecordMurder(murder)

    // Generate reactions from each living player
    for _, player := range e.State.LivingPlayers() {
        reaction := e.adapter.GetReaction(player, murder)
        e.recordReaction(player, reaction)
    }

    // Update relationship states
    e.updateRelationshipsAfterMurder(murder)
}
        

9.10 Performance Considerations

9.10.1 Caching Strategy

Query Cache:

  • Cache frequent queries (player descriptions, common situations)
  • TTL-based expiration
  • Game-state-aware invalidation

Embedding Cache:

  • Pre-computed embeddings for all sections
  • Query embedding cached per session
  • Reduces API calls significantly

9.10.2 Parallel Processing

func (e *GameEngine) GenerateAllReactions(event Event) {
    var wg sync.WaitGroup
    reactions := make(chan PlayerReaction, len(e.State.LivingPlayers()))

    for _, player := range e.State.LivingPlayers() {
        wg.Add(1)
        go func(p PlayerID) {
            defer wg.Done()
            reaction := e.adapter.GetReaction(p, event)
            reactions <- reaction
        }(player)
    }

    wg.Wait()
    close(reactions)

    // Collect and process reactions
}
        

9.10.3 Token Budget Management

type TokenBudget struct {
    MaxTotal     int
    ContextLimit int
    ResponseLimit int
}

func (b *PromptBuilder) BuildWithBudget(budget TokenBudget) (string, error) {
    // Prioritize essential components
    // Truncate context if needed
    // Reserve response space
}
        

9.11 Conclusion: Foundation for Social Simulation

The RAG architecture provides the foundation for authentic Traitors simulation:

  1. Knowledge Grounding: Responses rooted in retrieved content
  2. Personality Consistency: Expert configuration maintains character voice
  3. Information Boundaries: Role-appropriate knowledge access
  4. Game Integration: State-aware query and response processing
  5. Scalability: Parallel processing and caching for performance

Chapter 10 extends this foundation with the emotional and deception modelling that transforms factual retrieval into believable social behaviour. For advanced memory management techniques, see the Cognitive Memory Architecture chapter.

Thesis Contents