Chapter 16 · 10 Topics

Architectures, Extensions & Practical Deployment

From sparse expert routing to deployment governance — the decisions that separate a solid prototype from a durable production system.

By the time a team reaches production, the discussion is no longer only about prompts and base models. Teams must decide whether sparse expert routing is worth the operational complexity, whether structured knowledge should complement retrieval, how to tune hyperparameters responsibly, and how to manage bias, privacy, interpretability, and cost under real workloads. These topics distinguish a solid prototype from a durable system and frequently appear in senior interviews because they force candidates to connect model architecture to product governance.

Architecture & Scaling

Sparse scaling, efficient output layers, and the architectural patterns that let models grow without proportional compute cost.

1

Mixture of Experts (MoE)

A Mixture of Experts model contains multiple expert subnetworks and a routing mechanism that activates only a subset for each token. This creates sparse architecture: total parameter count can be very large, but compute per token stays small.
🧠Think of a hospital with many specialists. Each patient sees only the relevant doctors, not the entire staff. The hospital has enormous total expertise, but the cost of treating one patient stays manageable because routing directs them to the right experts.

How MoE Works

In a standard (dense) transformer, every token passes through every feed-forward network (FFN) layer. In an MoE transformer, each FFN layer is replaced with N expert FFNs and a lightweight gating network (router) that decides which experts to use for each token. Typically, only the top-k experts (often k=1 or k=2) are activated per token.

Why MoE Is Attractive

PropertyDense ModelMoE Model
Total parametersAll active every stepMany params, few active per token
Compute per tokenProportional to param countProportional to active expert count
Scaling efficiencyLinear compute growthSublinear compute growth
Memory footprintMust load all paramsMust load all params (serving concern)
Training stabilityGenerally stableRequires load balancing losses

Switch Transformers and Beyond

Switch Transformers (Fedus et al., 2022) simplified MoE by routing each token to exactly one expert (top-1), demonstrating that sparse scaling can work efficiently at trillion-parameter scale. Later work explored top-2 routing, expert parallelism across GPUs, and more sophisticated load-balancing strategies.

Interview frame: MoE captures a core scaling idea: you can increase capacity without paying the full dense-compute cost on every step. But this trades dense simplicity for conditional capacity, which introduces new failure modes (see Topic 2: MoE Failure Modes).
Key Takeaway: MoE models decouple parameter count from per-token compute cost. This makes them attractive for scaling, but they require careful routing, load balancing, and serving infrastructure. The total model must still fit in memory even though only a fraction is active.
Python — Simplified MoE routing layer
# Simplified Mixture of Experts routing layer.
# The router (gating network) assigns each token to top-k experts.
# Only selected experts process each token, keeping compute sparse.
import torch
import torch.nn as nn

class MoELayer(nn.Module):
    def __init__(self, d_model, n_experts, top_k=2):
        super().__init__()
        self.n_experts = n_experts
        self.top_k = top_k

        # Each expert is an independent FFN
        self.experts = nn.ModuleList([
            nn.Sequential(
                nn.Linear(d_model, d_model * 4),  # Expand
                nn.GELU(),
                nn.Linear(d_model * 4, d_model)   # Project back
            ) for _ in range(n_experts)
        ])

        # Router: lightweight linear layer that scores experts
        self.router = nn.Linear(d_model, n_experts, bias=False)

    def forward(self, x):
        # x shape: (batch, seq_len, d_model)
        gate_scores = self.router(x)                        # (batch, seq, n_experts)
        top_vals, top_idx = gate_scores.topk(self.top_k)    # Select top-k experts
        weights = torch.softmax(top_vals, dim=-1)            # Normalize gate weights

        # Dispatch tokens to selected experts (simplified)
        output = torch.zeros_like(x)
        for k in range(self.top_k):
            for e in range(self.n_experts):
                mask = (top_idx[..., k] == e)                # Tokens routed to expert e
                if mask.any():
                    expert_out = self.experts[e](x[mask])    # Run expert on its tokens
                    output[mask] += weights[mask, k:k+1] * expert_out
        return output
Follow-up Questions
How does expert parallelism work across GPUs?
In expert parallelism, different experts are placed on different GPUs. The router sends tokens to the correct GPU via all-to-all communication. This distributes memory (each GPU holds fewer experts) but introduces network overhead for token routing. It is often combined with data and tensor parallelism for maximum efficiency.
Why does MoE memory footprint remain high despite sparse compute?
All expert parameters must be loaded into memory even though only a subset activates per token. A model with 8 experts has ~8x the FFN parameters of a dense model. During inference, you cannot predict which experts will be needed, so all must be resident. This is why MoE models require more GPUs for serving despite lower per-token FLOPs.
What is the load-balancing loss in MoE training?
Without intervention, the router can collapse to routing most tokens to a few dominant experts, leaving others undertrained. The load-balancing loss adds a penalty term that encourages even distribution of tokens across experts. Switch Transformers use an auxiliary loss proportional to the fraction of tokens assigned to each expert times the average gate probability for that expert.
2

MoE Failure Modes

Sparse routing adds its own risks: expert overload, router collapse, training instability, and debugging complexity. MoE models trade dense simplicity for conditional capacity, requiring careful load balancing, routing diagnostics, and serving-aware infrastructure.
🧠Imagine a call center where the routing system keeps sending all calls to the same two agents while the rest sit idle. Those two agents become overwhelmed, callers get bad service, and the idle agents never develop expertise. That is router collapse.

Key Failure Modes

Failure ModeWhat HappensRoot CauseMitigation
Router collapseMost tokens go to 1-2 expertsRich-get-richer dynamicsLoad-balancing auxiliary loss
Expert overloadPopular experts cannot handle volumeUneven token distributionExpert capacity factors, overflow buffers
Training instabilityLoss spikes, divergenceDiscrete routing decisionsJitter, temperature-scaled gating
Quality regression opacityHard to attribute errors to specific expertsRouting hides which expert produced outputPer-expert logging, routing diagnostics
Serving complexityUneven GPU utilizationSome experts receive more trafficDynamic expert placement, caching

Router Collapse in Detail

Router collapse occurs when a positive feedback loop causes the router to favor a small subset of experts. Those experts get more training signal, become more capable, and attract even more tokens. Without a load-balancing loss, this can happen early in training and is difficult to reverse.

Debugging MoE Systems

Quality regressions in MoE systems may reflect routing behavior rather than base-model quality. Debugging requires:

  • Per-expert utilization metrics: Monitor which experts are being used and how often
  • Routing entropy: Low entropy means the router is not spreading tokens across experts
  • Expert-level quality metrics: Compare output quality when specific experts are active
  • Token-expert assignment logs: Trace which expert produced which part of a problematic output
Key Takeaway: MoE models trade dense simplicity for conditional capacity. The new failure modes (router collapse, expert overload, debugging opacity) require load-balancing losses, routing diagnostics, and per-expert monitoring that dense models do not need.
Python — Load-balancing loss for MoE training
# Load-balancing auxiliary loss to prevent router collapse.
# Encourages even distribution of tokens across experts
# by penalizing both over- and under-utilization.
import torch

def load_balancing_loss(gate_probs, top_indices, n_experts):
    """
    Compute the Switch Transformer load-balancing loss.

    gate_probs: (batch*seq, n_experts) - softmax router probabilities
    top_indices: (batch*seq,) - index of the selected expert per token
    n_experts: int - total number of experts
    """
    # f_i = fraction of tokens assigned to expert i
    one_hot = torch.nn.functional.one_hot(top_indices, n_experts).float()
    f = one_hot.mean(dim=0)  # (n_experts,)

    # p_i = average gate probability for expert i across all tokens
    p = gate_probs.mean(dim=0)  # (n_experts,)

    # Loss = n_experts * sum(f_i * p_i)
    # Minimized when f and p are uniform (1/n_experts each)
    loss = n_experts * (f * p).sum()

    return loss  # Add to main loss with a small coefficient (e.g., 0.01)
Follow-up Questions
How do you detect router collapse during training?
Monitor routing entropy and per-expert token counts. If entropy drops sharply or a few experts receive >50% of tokens while others receive near zero, the router is collapsing. Many frameworks log these metrics as training curves alongside loss. Early detection allows increasing the load-balancing coefficient before the collapse becomes irreversible.
Can expert overload cause serving latency spikes?
Yes. In expert-parallel serving, if one expert receives disproportionate traffic, the GPU hosting it becomes a bottleneck while other GPUs idle. This manifests as tail latency spikes (high P99) even when average throughput looks healthy. Dynamic expert replication (placing popular experts on multiple GPUs) can help.
3

Adaptive Softmax

Adaptive softmax speeds training and inference for very large vocabularies by spending less computation on rare words than on frequent words. It organizes the vocabulary into clusters so common tokens are evaluated cheaply while still supporting a very large overall vocabulary.
🧠Imagine a dictionary where the 1,000 most-used words are in the front section (quick lookup), and the remaining 50,000 rare words are organized by topic in the back. You check the front section first and only go to the back when needed. That is adaptive softmax.

The Problem: Output Bottleneck

The final softmax layer in a language model computes a probability distribution over the entire vocabulary. For a vocabulary of 100K+ tokens, this means a matrix multiplication of (hidden_dim x vocab_size) at every decoding step. This can become a significant compute and memory bottleneck.

How Adaptive Softmax Works

Adaptive softmax partitions the vocabulary into frequency-based clusters:

  • Head cluster: The most frequent tokens (e.g., top 2,000) get a full-dimension projection. These cover ~80-90% of token occurrences.
  • Tail clusters: Progressively rarer tokens are grouped into clusters with reduced-dimension projections. Since they are rarely needed, the smaller projection saves compute on most steps.

When predicting, the model first scores the head cluster and cluster-level probabilities. If a tail cluster has high probability, its internal scores are computed. On most steps, only the head computation runs.

When to Use Adaptive Softmax

ScenarioBenefitNotes
Very large vocabularies (100K+)Major compute savingsMost relevant for character or multilingual models
Resource-constrained trainingFaster training per stepReduces output layer from dominant to minor cost
Standard BPE vocab (~32K-50K)Marginal benefitVocab is small enough that full softmax is fast
Interview frame: Adaptive softmax is a good example of how systems efficiency and model math are deeply connected. It is less visible in interview prep than attention or LoRA, but it demonstrates understanding of the full compute pipeline beyond the attention mechanism.
Key Takeaway: Adaptive softmax trades uniform vocabulary treatment for frequency-aware efficiency. It matters most for large-vocabulary settings where the output layer becomes a bottleneck, and demonstrates the connection between model architecture and systems efficiency.
Python — Using PyTorch AdaptiveLogSoftmaxWithLoss
# PyTorch provides AdaptiveLogSoftmaxWithLoss for efficient large-vocabulary models.
# It partitions the vocabulary into clusters by frequency,
# using smaller projections for rare tokens.
import torch
import torch.nn as nn

# Configuration
d_model = 512       # Hidden dimension
vocab_size = 100000  # Large vocabulary (e.g., multilingual)

# Define cluster cutoffs: [2000, 10000, 100000]
# - Head: tokens 0-1999 (most frequent, full-dim projection)
# - Tail 1: tokens 2000-9999 (reduced-dim projection)
# - Tail 2: tokens 10000-99999 (smallest projection)
adaptive_softmax = nn.AdaptiveLogSoftmaxWithLoss(
    in_features=d_model,
    n_classes=vocab_size,
    cutoffs=[2000, 10000],  # Frequency-based cluster boundaries
    div_value=4.0             # Dimension reduction factor for tail clusters
)

# Forward pass: computes log-probabilities and loss efficiently
hidden = torch.randn(32, d_model)   # Batch of hidden states
targets = torch.randint(0, vocab_size, (32,))  # Target token ids

output = adaptive_softmax(hidden, targets)
print(f"Loss: {output.loss.item():.4f}")

# For inference: get full log-probabilities (when needed)
log_probs = adaptive_softmax.log_prob(hidden)  # (batch, vocab_size)
Follow-up Questions
How does adaptive softmax compare to sampled softmax?
Sampled softmax approximates the full softmax by only computing scores for a random subset of negative classes. Adaptive softmax is exact for the classes it evaluates — it just organizes computation hierarchically. Adaptive softmax gives better gradient quality because it does not approximate, but sampled softmax is simpler to implement and does not require frequency-based vocabulary ordering.
Is adaptive softmax still relevant with modern BPE vocabularies?
For standard BPE vocabularies (32K-50K tokens), the output layer is typically not the bottleneck — attention and FFN dominate. Adaptive softmax becomes relevant again for character-level models, multilingual models with 200K+ tokens, or specialized vocabularies (e.g., genomics, chemical notation) where vocabulary size is very large.
Knowledge & Ecosystems

How structured knowledge augments retrieval, and how to think about comparing model ecosystems without hard-coding assumptions that change by release.

4

Knowledge Graphs + LLMs

Knowledge graphs represent entities and their relations in structured form. They complement LLMs by providing explicit factual constraints, cleaner entity linking, and multi-hop relational reasoning that is sometimes harder to recover from unstructured text alone.
🧠An LLM is like a well-read person who knows a lot but sometimes confuses details. A knowledge graph is like a verified reference database. Combining them is like giving that person access to a fact-checked encyclopedia they can consult before answering.

What Knowledge Graphs Provide

Unlike unstructured text, knowledge graphs represent facts as triples: (subject, relation, object). For example: (Aspirin, treats, Headache), (Aspirin, manufactured_by, Bayer). This structured representation enables:

  • Entity disambiguation: "Apple" the company vs "apple" the fruit is explicit in the graph
  • Multi-hop reasoning: Follow chains of relations (Who manufactures drugs that treat X?)
  • Factual grounding: Facts are explicit and verifiable, not implicit in model weights
  • Traceability: Answers can cite specific graph paths, not just "the model said so"

Integration Patterns

PatternHow It WorksBest For
KG as contextQuery the graph, inject triples into the promptFactual Q&A, entity-rich tasks
KG for validationCheck LLM output against graph constraintsReducing hallucination on known entities
KG-guided retrievalUse graph structure to expand or filter retrievalMulti-hop questions, structured domains
LLM for KG constructionUse LLM to extract triples from textBuilding graphs from unstructured data

When KGs Help Most

Knowledge graphs help most when the product depends on stable entities and relationships: products, people, regulations, scientific concepts, or enterprise assets. They are especially valuable when traceability matters as much as fluency. See Topic 5: KG vs Vector Retrieval for a detailed comparison.

Key Takeaway: Knowledge graphs complement LLMs by providing structured, verifiable facts with explicit relations. They are most valuable in domains where entity accuracy, multi-hop reasoning, and traceability are critical requirements.
Python — Querying a knowledge graph to augment LLM context
# Query a knowledge graph and inject structured facts into an LLM prompt.
# This pattern grounds the model in verified entities and relations,
# reducing hallucination on factual questions.
from neo4j import GraphDatabase

class KGAugmenter:
    def __init__(self, uri, auth):
        self.driver = GraphDatabase.driver(uri, auth=auth)

    def get_entity_context(self, entity_name: str, max_hops: int = 2) -> str:
        """Retrieve structured facts about an entity from the knowledge graph."""
        query = """
        MATCH (e {name: $name})-[r*1..%d]-(related)
        RETURN e.name, type(r[0]), related.name
        LIMIT 20
        """ % max_hops

        with self.driver.session() as session:
            results = session.run(query, name=entity_name)
            # Format triples as structured context for the LLM
            facts = []
            for record in results:
                facts.append(
                    f"({record[0]}) --[{record[1]}]--> ({record[2]})"
                )
        return "\n".join(facts)

    def build_augmented_prompt(self, question: str, entity: str) -> str:
        """Combine KG facts with the user question."""
        facts = self.get_entity_context(entity)
        return f"""Known facts from our knowledge graph:
{facts}

Based on these verified facts, answer: {question}"""
Follow-up Questions
How do you handle knowledge graph staleness?
Knowledge graphs require maintenance workflows: automated extraction pipelines, human validation for critical facts, versioning, and freshness scores on edges. Stale facts are worse than missing facts because they create confident but wrong answers. Good systems timestamp triples and deprecate facts that have not been validated within a freshness window.
Can LLMs build knowledge graphs automatically?
Yes, LLMs can extract (subject, relation, object) triples from unstructured text with reasonable accuracy. However, automated extraction produces noisy graphs that require deduplication, entity resolution, and human validation for high-stakes use cases. The best approach is LLM extraction with human-in-the-loop curation for critical entities.
What are the limitations of knowledge graphs?
KGs are expensive to build and maintain, struggle with implicit or nuanced knowledge (sarcasm, context-dependent facts), have limited coverage (only contain what has been explicitly encoded), and require schema design that may not fit evolving domains. They work best as a complement to retrieval, not a replacement.
5

Knowledge Graphs vs Vector Retrieval

Vector retrieval excels at semantic similarity over text but struggles with explicit graph structure: hierarchies, ownership chains, typed relations, and multi-hop constraints. The strongest systems use both — vector retrieval for broad evidence discovery and graph reasoning for entity-grounded logic.
🧠Vector search is like searching by "vibes" — it finds documents that feel similar. Graph search is like following a map — it navigates explicit connections. You need vibes to discover relevant territory, but you need the map to navigate it precisely.

Head-to-Head Comparison

DimensionVector RetrievalKnowledge Graph
Query typeSemantic similarity ("find related text")Structured traversal ("follow this relation")
Multi-hop reasoningWeak (each hop is a separate query)Native (graph traversal)
Entity disambiguationRelies on embedding proximityExplicit entity identity
CoverageAny indexed textOnly what has been explicitly encoded
Setup costLow (embed + index)High (schema design + curation)
MaintenanceRe-embed when docs changeContinuous curation and validation
TraceabilityCan cite source chunksCan cite specific fact paths

When to Use Which

  • Vector retrieval alone: Broad Q&A over document collections, semantic search, content recommendation
  • Knowledge graph alone: Strict entity queries, compliance checks, structured data navigation
  • Both together: Vector retrieval discovers relevant passages; KG validates entities and relations mentioned in those passages. This is the strongest pattern for production systems that need both coverage and accuracy.
Interview frame: The strongest answer is comparative rather than ideological. Many strong systems use both: vector retrieval for broad evidence discovery and graph-based reasoning for entity-grounded logic. Avoid declaring one universally better than the other. See Topic 4: Knowledge Graphs + LLMs for integration patterns.
Key Takeaway: Vector retrieval and knowledge graphs solve different problems. Vector search finds semantically similar content; graphs navigate explicit entity relationships. The best systems combine both for coverage plus precision.
Python — Hybrid retrieval combining vector search and KG lookup
# Hybrid retrieval: vector search finds relevant passages,
# then knowledge graph validates and enriches entity references.
# This gives you broad coverage + entity precision.

class HybridRetriever:
    def __init__(self, vector_store, kg_client, entity_extractor):
        self.vectors = vector_store       # e.g., Pinecone, Weaviate, pgvector
        self.kg = kg_client               # e.g., Neo4j, Amazon Neptune
        self.extractor = entity_extractor  # NER model for entity detection

    def retrieve(self, query: str, top_k: int = 5) -> dict:
        """Two-stage retrieval: vector search + KG enrichment."""

        # Stage 1: Vector retrieval for broad evidence discovery
        passages = self.vectors.search(query, top_k=top_k)

        # Stage 2: Extract entities mentioned in query and passages
        entities = self.extractor.extract(query)
        for p in passages:
            entities.extend(self.extractor.extract(p.text))
        entities = list(set(entities))  # Deduplicate

        # Stage 3: KG lookup for structured facts about those entities
        kg_facts = []
        for entity in entities:
            facts = self.kg.get_relations(entity, max_hops=2)
            kg_facts.extend(facts)

        return {
            "passages": passages,     # Semantic evidence (from vectors)
            "facts": kg_facts,         # Structured facts (from KG)
            "entities": entities       # Detected entities
        }
Follow-up Questions
How do you handle entities that exist in the KG but not in retrieved passages?
This gap means the vector retrieval missed relevant content, or the entity is only represented structurally. Solutions include KG-guided retrieval expansion (use graph neighbors to generate additional search queries) and including KG facts directly in the prompt even without supporting passages. The model then reasons over both evidence types.
What is the latency impact of adding KG lookups to retrieval?
KG lookups typically add 10-50ms for shallow queries (1-2 hops) against indexed graph databases. This is negligible compared to LLM generation time (hundreds of milliseconds to seconds). The bigger latency concern is entity extraction from passages, which may require an NER model inference step. Pipeline design should parallelize where possible.
6

Model Ecosystem Comparison

Frontier model ecosystems (Claude, GPT, Gemini, open-weight models) differ in packaging, product defaults, tool interfaces, context windows, and platform ergonomics. The right comparison is empirical: benchmark candidate models on your workload, your prompts, and your latency budget.
🧠Choosing a model ecosystem is like choosing a programming language for a project. Each has strengths, trade-offs, and community effects. The answer is always "it depends on the workload" — never "this one is universally best."

Comparison Dimensions

Developers compare model ecosystems less by brand identity and more by task fit. The relevant dimensions include:

DimensionWhat to EvaluateWhy It Matters
Reasoning qualityComplex multi-step tasks, code, mathDetermines which tasks the model can handle
Tool use / function callingReliability of structured output, tool invocationCritical for agentic and structured workflows
Context windowMaximum tokens, quality at various lengthsAffects RAG design and long-document tasks
LatencyTTFT, ITL at different input/output sizesUser experience in interactive applications
PricingCost per input/output token, caching discountsUnit economics at scale
Safety controlsContent filtering, refusal behavior, customizationDetermines fitness for regulated industries
Deployment optionsAPI only, self-hosted, fine-tunable, on-premiseData residency, compliance, customization

Avoiding Common Interview Mistakes

A good interview answer stays current-aware and avoids hard-coding assumptions that can change by release. The capabilities of frontier models shift frequently. Instead of memorizing a comparison table, emphasize your evaluation methodology:

  • Benchmark on your actual workload, not public leaderboards alone
  • Test with your actual prompts, not synthetic benchmarks
  • Measure your latency budget and cost constraints
  • Consider the ecosystem: documentation, SDKs, community, support
Key Takeaway: Model ecosystem comparisons should be empirical, not tribal. Benchmark candidate models on your specific workload, prompts, and constraints. Capabilities shift between releases, so evaluation methodology matters more than memorized rankings.
Python — Model comparison evaluation harness
# A simple evaluation harness for comparing models empirically.
# Runs the same test suite against multiple providers and
# reports quality, latency, and cost metrics.
import time
from dataclasses import dataclass

@dataclass
class EvalResult:
    model: str
    task: str
    score: float        # Task-specific quality metric (0-1)
    ttft_ms: float      # Time to first token
    total_ms: float     # Total generation time
    cost_usd: float     # Estimated cost per request

class ModelComparator:
    def __init__(self, models, evaluator, test_suite):
        self.models = models         # Dict of model_name -> client
        self.evaluator = evaluator   # Scores output quality per task
        self.test_suite = test_suite # List of (task_name, prompt, expected)

    def run_comparison(self) -> list:
        """Run all test cases against all models."""
        results = []
        for model_name, client in self.models.items():
            for task, prompt, expected in self.test_suite:
                # Measure timing
                start = time.perf_counter()
                output = client.generate(prompt)
                elapsed = (time.perf_counter() - start) * 1000

                # Score quality
                score = self.evaluator.score(output, expected, task)

                results.append(EvalResult(
                    model=model_name, task=task,
                    score=score, ttft_ms=output.ttft_ms,
                    total_ms=elapsed, cost_usd=output.usage_cost
                ))
        return results
Follow-up Questions
Should you use open-weight models or API-based models?
The choice depends on constraints: API models offer frontier quality with zero infrastructure burden but create vendor dependency and data-residency concerns. Open-weight models (Llama, Mistral, Qwen) offer full control, customization via fine-tuning, and data sovereignty, but require GPU infrastructure and ML ops expertise. Many teams use a hybrid: APIs for prototyping and complex tasks, self-hosted for high-volume or privacy-sensitive workloads.
How often should you re-evaluate model choices?
Re-evaluate at every major model release (typically every 3-6 months for frontier providers) and whenever your workload characteristics change significantly. Maintain an evaluation suite that can be run quickly against new models. The cost of switching should be low if your architecture uses model-agnostic abstractions in the serving layer.
Production Governance

The operational realities that determine whether a deployed LLM system is durable: hyperparameter management, bias detection, privacy architecture, and the bottlenecks teams underestimate.

7

Hyperparameters Beyond the Learning Rate

Hyperparameters control much more than optimization speed. Batch size, weight decay, sequence length, decoding parameters, retrieval settings, reranker depth, and chunk size are all operational hyperparameters in real LLM systems. Good teams treat them as part of the system design, not as afterthoughts.
🧠Hyperparameters are all the knobs on a mixing board. The learning rate is the master volume, but equalization, compression, reverb, and pan all affect the final sound. A good engineer adjusts the whole board, not just the volume.

The Full Hyperparameter Landscape

CategoryHyperparameterWhat It Controls
OptimizationLearning rate, schedule, warmupConvergence speed and stability
OptimizationBatch sizeGradient noise, hardware efficiency, generalization
RegularizationWeight decay, dropoutOverfitting prevention, generalization
ArchitectureSequence lengthMemory pressure, context capacity
DecodingTemperature, top-p, top-kOutput quality, determinism, diversity
RetrievalChunk size, overlap, top-kRetrieval quality, context efficiency
RetrievalReranker depth, score thresholdPrecision vs recall in retrieved context
Fine-tuningLoRA rank, alpha, target modulesAdaptation capacity vs efficiency

Batch Size: More Than Just Speed

Batch size is often treated as a hardware constraint, but it has deep effects on training dynamics:

  • Small batches: More gradient noise, can improve generalization (implicit regularization), but slower wall-clock convergence
  • Large batches: Lower noise, faster convergence, but may generalize worse and require learning rate scaling (linear scaling rule)
  • Practical concern: Batch size determines GPU memory usage, gradient accumulation strategy, and distributed training configuration

Retrieval as Hyperparameters

In RAG systems, chunk size, overlap, top-k, and reranker depth are operational hyperparameters that dramatically affect output quality. A team that carefully tunes the learning rate but uses default chunk sizes is optimizing the wrong knobs.

Interview frame: Show that you think broadly: hyperparameters are any knobs set by the engineer rather than learned by the model. Good teams treat them as part of the system design, running systematic sweeps on the full parameter surface, not just learning rate and batch size.
Key Takeaway: In production LLM systems, hyperparameters extend far beyond learning rate. Retrieval chunk size, reranker depth, decoding temperature, and LoRA rank are all system-design decisions that must be tuned, validated, and versioned alongside the model itself.
Python — Systematic hyperparameter configuration for a RAG system
# Define a complete hyperparameter configuration for a RAG system.
# This shows that production LLM tuning goes far beyond learning rate.
from dataclasses import dataclass

@dataclass
class RAGConfig:
    """Full hyperparameter surface for a RAG-based LLM system."""

    # --- Retrieval hyperparameters ---
    chunk_size: int = 512            # Tokens per chunk (affects granularity)
    chunk_overlap: int = 64          # Overlap between chunks (context continuity)
    retrieval_top_k: int = 10        # Candidates from vector search
    reranker_top_n: int = 3          # Final candidates after reranking
    similarity_threshold: float = 0.7  # Minimum relevance score

    # --- Decoding hyperparameters ---
    temperature: float = 0.3        # Low for factual RAG tasks
    top_p: float = 0.85              # Nucleus sampling threshold
    max_output_tokens: int = 1024   # Output budget (cost + latency)

    # --- Model hyperparameters ---
    model_name: str = "claude-sonnet"   # Model selection
    context_budget: int = 8000       # Max tokens for retrieved context

    # --- Fine-tuning hyperparameters (if applicable) ---
    lora_rank: int = 16              # LoRA rank (adaptation capacity)
    lora_alpha: float = 32.0         # LoRA scaling factor
    weight_decay: float = 0.01       # Regularization

# Example: create configs for different use cases
factual_config = RAGConfig(temperature=0.1, retrieval_top_k=20, reranker_top_n=5)
creative_config = RAGConfig(temperature=0.8, top_p=0.95, retrieval_top_k=5)
Follow-up Questions
How do you decide which hyperparameters to tune first?
Use sensitivity analysis: vary one parameter at a time and measure the effect on your primary metric. In RAG systems, chunk size and retrieval top-k often have the largest impact. In training, learning rate is usually the most sensitive. Start with the highest-impact parameters and fix the rest at reasonable defaults.
Should hyperparameters be version-controlled?
Absolutely. Hyperparameters should be stored as configuration files in version control alongside the code. Changes to hyperparameters should go through the same review process as code changes, with associated evaluation results. This enables reproducibility, rollback, and attribution when quality changes.
8

Bias & Systematically Incorrect Outputs

Start by making the failure concrete: identify which groups, topics, or scenarios show systematic problems. Then improve the stack at the appropriate layer — better data, stronger evaluation sets, retrieval constraints, calibrated refusals, post-generation validation, or targeted fine-tuning.
🧠Bias is like a compass that consistently points slightly off true north. You cannot fix it by looking at just one reading — you need systematic measurement across many directions, and the correction may require adjusting the instrument, the map, or both.

A Systematic Approach

"Fixing bias" must be an engineering process, not a slogan. The approach follows these steps:

  1. Identify: Discover systematic failures through disaggregated evaluation, user reports, and red-teaming
  2. Characterize: Determine the scope — which groups, topics, or scenarios are affected and how
  3. Locate: Determine where in the stack the problem originates (data, model, retrieval, post-processing)
  4. Intervene: Apply the appropriate fix at the right layer
  5. Validate: Measure whether the fix works without introducing new problems
  6. Monitor: Continuously track for regressions

Intervention Layers

LayerInterventionWhen to Use
Training dataBetter curation, deduplication, representationSystematic bias from data distribution
EvaluationDisaggregated metrics, representative edge casesMeasuring and tracking all biases
RetrievalSource diversity constraints, fairness-aware rankingBias from retrieval corpus composition
DecodingCalibrated refusals, constrained generationKnown unsafe or unreliable output patterns
Post-processingOutput validators, bias classifiersLast-resort catch for deployment
Fine-tuningTargeted training on underrepresented scenariosModel-level capability gaps

Disaggregated Evaluation

Aggregate metrics hide bias. A model with 92% accuracy overall may have 75% accuracy on minority demographics and 97% on the majority. Disaggregated evaluation breaks performance down by relevant dimensions (demographics, topics, edge cases) to expose these disparities.

Interview frame: A strong answer includes measurement. Teams need disaggregated evaluation, representative edge cases, and clear escalation policies. Otherwise "fixing bias" becomes a slogan rather than an engineering process.
Key Takeaway: Addressing bias requires systematic identification, layered intervention, and continuous measurement. No single blanket fix solves every bias — the correction must target the right layer of the stack (data, model, retrieval, or post-processing).
Python — Disaggregated evaluation framework
# Disaggregated evaluation: break overall metrics into subgroup metrics
# to expose hidden bias that aggregate numbers mask.
from collections import defaultdict

class DisaggregatedEvaluator:
    def __init__(self, dimensions):
        """
        dimensions: list of metadata keys to disaggregate by
                    e.g., ["demographic", "topic", "language", "complexity"]
        """
        self.dimensions = dimensions
        self.results = defaultdict(lambda: defaultdict(list))

    def record(self, prediction, ground_truth, metadata: dict):
        """Record one evaluation result with its metadata."""
        is_correct = self._score(prediction, ground_truth)

        # Record overall
        self.results["_overall"]["all"].append(is_correct)

        # Record per dimension
        for dim in self.dimensions:
            if dim in metadata:
                self.results[dim][metadata[dim]].append(is_correct)

    def report(self):
        """Generate disaggregated performance report."""
        for dim, groups in self.results.items():
            print(f"\n--- {dim} ---")
            for group, scores in sorted(groups.items()):
                acc = sum(scores) / len(scores)
                print(f"  {group}: {acc:.1%} ({len(scores)} samples)")

                # Flag significant disparities
                overall_acc = sum(self.results["_overall"]["all"]) / \
                              len(self.results["_overall"]["all"])
                if abs(acc - overall_acc) > 0.1:
                    print(f"    WARNING: {abs(acc-overall_acc):.1%} gap vs overall")
Follow-up Questions
How do you red-team for bias?
Red-teaming for bias involves diverse adversarial testers who systematically probe the system with inputs designed to trigger biased outputs. This includes varying demographic attributes in otherwise identical prompts, testing edge cases for underrepresented groups, and checking whether the model makes different assumptions based on names, locations, or cultural references. Automated red-teaming can scale this with template-based prompt generation.
What is the difference between bias and hallucination?
Bias is a systematic skew in outputs that affects certain groups or topics disproportionately. Hallucination is generating confident but factually incorrect content. They can overlap (biased hallucinations about certain groups) but are distinct problems requiring different mitigations. Bias needs fairness-aware evaluation; hallucination needs factual grounding and retrieval.
Should you fix bias in the model or in the pipeline?
Both. Model-level fixes (better training data, targeted fine-tuning) address root causes but are expensive and slow. Pipeline-level fixes (retrieval constraints, output validators, prompt engineering) are faster to deploy but are band-aids. A mature approach layers both: fix what you can in the model, and add pipeline guardrails for the rest.
9

Interpretability & Privacy

Interpretability is hard because large neural networks do not expose simple rules for why a response emerged. Privacy is hard because the model may process sensitive data, retrieve confidential documents, or call tools on protected systems. Together they create a governance challenge: visibility without exposure.
🧠Imagine auditing a decision-maker who speaks a language you do not fully understand, while also ensuring they never reveal any confidential information they were given. That is the dual challenge of interpretability and privacy in LLM deployment.

Interpretability Challenges

LLMs are not inherently interpretable. Current approaches provide partial visibility:

TechniqueWhat It RevealsLimitation
Attention visualizationWhich tokens the model attends toAttention is not always causal attribution
Probing classifiersWhat information is encoded in representationsDoes not show how information is used
Chain-of-thoughtModel's stated reasoning stepsMay not reflect actual computation (post-hoc rationalization)
Mechanistic interpretabilitySpecific circuits and features in the networkScales poorly to large models
Feature attribution (SHAP/LIME)Input token importance scoresApproximations; can be misleading for seq2seq

Privacy Architecture

Privacy in LLM systems is an architecture problem, not just a policy problem:

  • Access control: Who can query which data through the model, and what the model can retrieve
  • Data minimization: Only include necessary context; do not dump entire databases into prompts
  • Logging policy: What gets logged, how long it is retained, and who can access logs
  • Redaction: PII detection and removal before logging and in model outputs
  • Retention: How long prompts, responses, and intermediate data are stored
  • Data residency: Where data is processed and stored (on-premise, cloud region, provider)

The Governance Tension

Organizations need visibility into model behavior (for debugging, compliance, quality assurance) while simultaneously limiting exposure of sensitive data. This tension requires careful architectural choices:

  • Log metadata (latency, token counts, safety scores) without logging content (prompts, responses)
  • Use aggregate analytics instead of individual request inspection where possible
  • Implement role-based access to debugging tools and logs
Key Takeaway: Interpretability and privacy are intertwined governance challenges. You need visibility without exposure. Connect privacy to architecture: access control, data minimization, logging policy, retention, and redaction are product decisions as much as model decisions.
Python — Privacy-aware logging middleware
# Privacy-aware logging middleware that captures metrics
# without storing sensitive content. This balances
# observability needs with data protection requirements.
import hashlib
import time
from dataclasses import dataclass

@dataclass
class PrivacySafeLog:
    """Log entry that captures operational metrics without PII."""
    request_hash: str     # One-way hash for deduplication, not content
    timestamp: float
    model: str
    input_tokens: int      # Count only, not content
    output_tokens: int
    ttft_ms: float
    total_ms: float
    safety_score: float    # Safety classifier output
    pii_detected: bool     # Whether PII was found (not what it was)
    user_tier: str          # Anonymized user group, not user ID

class PrivacyLogger:
    def __init__(self, pii_detector, log_store):
        self.pii_det = pii_detector
        self.store = log_store

    def log_request(self, prompt, response, metadata):
        """Log metrics about a request without storing content."""
        # Hash the prompt for deduplication (cannot be reversed)
        prompt_hash = hashlib.sha256(prompt.encode()).hexdigest()[:16]

        # Check for PII without logging what was found
        has_pii = self.pii_det.contains_pii(response)

        # Store only safe metadata
        entry = PrivacySafeLog(
            request_hash=prompt_hash,
            timestamp=time.time(),
            model=metadata["model"],
            input_tokens=metadata["input_tokens"],
            output_tokens=metadata["output_tokens"],
            ttft_ms=metadata["ttft_ms"],
            total_ms=metadata["total_ms"],
            safety_score=metadata["safety_score"],
            pii_detected=has_pii,
            user_tier=metadata.get("user_tier", "unknown")
        )
        self.store.write(entry)
        # Content (prompt, response) is NEVER stored
Follow-up Questions
Can chain-of-thought be trusted as interpretability?
Chain-of-thought shows the model's stated reasoning, but research shows this can be post-hoc rationalization rather than a faithful representation of the computation. The model may reach a conclusion through internal patterns and then generate a plausible-sounding justification. CoT is useful for debugging and user transparency but should not be treated as ground-truth interpretability.
How do you handle GDPR right-to-deletion for LLM systems?
For data in prompts and logs, implement retention policies and deletion workflows. For data in model weights (training data memorization), this is harder — you cannot easily "unlearn" specific training examples. Mitigations include not fine-tuning on PII, using differential privacy during training, and ensuring retrieval systems (not model weights) are the source of personal data so deletion is straightforward.
What is differential privacy in the context of LLM training?
Differential privacy (DP) adds calibrated noise during training to provide mathematical guarantees that individual training examples cannot be extracted from the model. DP-SGD (differentially private stochastic gradient descent) clips gradients and adds noise. The trade-off is significant quality degradation at strong privacy budgets, making it impractical for many LLM applications. It is most useful for specific fine-tuning on sensitive datasets.
10

Deployment Bottlenecks

Teams often underestimate evaluation maintenance, prompt and model version drift, access-control complexity, long-tail latency, and the human cost of debugging failures that span retrieval, tools, and model behavior. Compute cost matters, but operational ambiguity is often the more painful bottleneck.
🧠Deploying an LLM is like opening a restaurant. Everyone worries about the kitchen equipment (compute), but the real bottlenecks are often supply chain management (data freshness), health inspections (compliance), staff training (prompt management), and customer complaints (debugging failures).

Commonly Underestimated Bottlenecks

BottleneckWhy It HurtsMitigation
Evaluation maintenanceEval suites go stale as the product evolvesVersion evals alongside prompts; automate refresh
Prompt/model version driftPrompts break when models changePin model versions; test prompts on new versions before switching
Access control complexityPer-user, per-document permissions interact with retrievalDesign access control into the retrieval layer from day one
Long-tail latencyP99 spikes from long prompts, cache misses, queue buildupLoad shedding, priority queues, SLO budgets
Cross-component debuggingFailures span retrieval + tools + model + post-processingEnd-to-end tracing, structured logging, replay tools
Cost attributionCannot assign spend to features/teams for budgetingTag requests with feature/team metadata; per-request cost tracking

The Deployment Governance Matrix

Production readiness requires explicit controls across four areas:

AreaExample ControlWhy It Matters
PrivacyRedaction, access control, data minimizationLimits leakage risk with sensitive data
QualityRegression sets and scenario testingDetects drift before users absorb the failure
SafetyModeration, refusal paths, human escalationReduces harm from unsafe behavior
OperationsLogging, tracing, rollback, versioningMakes failures diagnosable instead of mysterious

The Notebook-to-Production Gap

Production LLM work is difficult because quality depends on the whole pipeline. A model that looks excellent in a notebook can still fail once real documents, real permissions, and real users enter the loop. The hardest deployment problems are usually cross-layer problems, where retrieval, permissions, evaluation, and model behavior fail together rather than one at a time.

Interview frame: "The hardest deployment problems are usually cross-layer problems, where retrieval, permissions, evaluation, and model behavior fail together rather than one at a time." This sentence demonstrates senior-level systems thinking. See Topic 9: Interpretability & Privacy for the privacy dimension of this challenge.
Key Takeaway: Compute cost gets the attention, but operational ambiguity is often the worse bottleneck. Evaluation maintenance, version drift, access control, debugging across components, and cost attribution are the problems that actually slow production teams down.
Python — Deployment readiness checklist
# Deployment readiness checklist that codifies the governance matrix.
# Run this before any production deployment to ensure all areas are covered.
from dataclasses import dataclass, field

@dataclass
class DeploymentCheck:
    name: str
    area: str         # privacy | quality | safety | operations
    passed: bool = False
    notes: str = ""

class DeploymentReadiness:
    def __init__(self):
        self.checks = [
            # Privacy controls
            DeploymentCheck("PII detection enabled", "privacy"),
            DeploymentCheck("Access control integrated with retrieval", "privacy"),
            DeploymentCheck("Logging policy reviewed (no content in logs)", "privacy"),
            DeploymentCheck("Data retention policy configured", "privacy"),

            # Quality controls
            DeploymentCheck("Regression test suite passes", "quality"),
            DeploymentCheck("Eval suite versioned with prompts", "quality"),
            DeploymentCheck("A/B test plan defined", "quality"),
            DeploymentCheck("Prompt pinned to model version", "quality"),

            # Safety controls
            DeploymentCheck("Input safety classifier deployed", "safety"),
            DeploymentCheck("Output moderation enabled", "safety"),
            DeploymentCheck("Human escalation path configured", "safety"),
            DeploymentCheck("Red-team results reviewed", "safety"),

            # Operations controls
            DeploymentCheck("Tracing enabled (end-to-end request IDs)", "operations"),
            DeploymentCheck("Rollback procedure tested", "operations"),
            DeploymentCheck("SLO dashboards configured", "operations"),
            DeploymentCheck("Cost attribution tags in place", "operations"),
        ]

    def report(self):
        """Print deployment readiness status."""
        for area in ["privacy", "quality", "safety", "operations"]:
            area_checks = [c for c in self.checks if c.area == area]
            passed = sum(1 for c in area_checks if c.passed)
            print(f"\n{area.upper()}: {passed}/{len(area_checks)}")
            for c in area_checks:
                status = "PASS" if c.passed else "FAIL"
                print(f"  [{status}] {c.name}")
Follow-up Questions
How do you handle prompt-model version drift?
Pin model versions in your configuration, and test all prompts against new model versions in a staging environment before switching. Maintain a prompt regression suite that runs automatically when the model version changes. Version your prompts in source control alongside the model version they were tested against.
What makes cross-component debugging so hard?
A single user-visible failure may involve: retrieval returning wrong chunks, the model misinterpreting context, a tool returning stale data, and post-processing truncating the answer. Each component works fine in isolation. End-to-end tracing with request IDs that propagate across all components is essential. Without it, debugging requires reconstructing the full request path manually.
How should teams handle evaluation suite staleness?
Treat evaluation suites as living test suites, not static artifacts. Schedule regular reviews (monthly or per release) to add new failure cases, remove outdated tests, and update expected behaviors. Automate eval freshness alerts: if the eval suite has not been updated in N releases, flag it. Include production failure cases in the eval suite as they are discovered.