Generative AI and Large Language Models Questions
The capabilities and behavior of modern generative and large language models. Covers how LLMs are pretrained, in-context learning and few-shot prompting, generative model families (autoregressive, diffusion), context windows, and tokenization and sampling. Emphasizes understanding what generative models can and cannot do and how they differ from discriminative ML.
Explain scaling laws for language models: how do model size, dataset size, and compute budget influence loss and generalization? What are the practical consequences for dataset preparation, model selection, and cost estimates when planning to train an LLM?
Sample Answer
Direct answer
Scaling laws describe how a language model's loss decreases predictably as you increase model size, dataset size, or training compute, following an approximately power-law relationship; the practical consequence is that, for a fixed compute budget, there is a compute-optimal balance between model size and dataset size, and simply making the model as large as possible while using whatever data happens to be available is generally NOT compute-optimal.
Structured elaboration
The basic relationship. Loss L decreases roughly as a power law in each of model parameters N, dataset size D, and compute C, when the other two are not the bottleneck: L(N)∝N−α, and similarly for D and C, with empirically fitted exponents. The key practical insight (established by later scaling-law work, notably Chinchilla) is that model size and dataset size should be scaled together, not independently; a model that is very large but trained on comparatively little data is typically "undertrained" relative to what its parameter count could support, and would have achieved lower loss for the same compute budget with a smaller model trained on proportionally more data.
Compute-optimal training. For a fixed compute budget C≈6ND (a standard approximation for training FLOPs as roughly six times parameters times tokens), there is a specific (N,D) pair that minimizes loss for that budget; empirically, compute-optimal scaling calls for roughly comparable growth in both parameters and training tokens as compute increases (both should grow, not just one), rather than the earlier practice of scaling parameters aggressively while holding dataset size comparatively fixed.
Worked example
Given a fixed compute budget of 6×1023 FLOPs, and using the approximation C≈6ND, a team deciding purely by "make it bigger" might train a 50B-parameter model on 400B tokens: 6×5×1010×4×1011=1.2×1023 FLOPs, well under budget, so they'd push the model size up further, say to 100B parameters on the same 400B tokens: 6×1011×4×1011=2.4×1023 FLOPs, still under the 6×1023 budget, and might keep growing the model to "use up" the compute. A compute-optimal allocation instead grows BOTH: for example, roughly a 25B-parameter model on 4 trillion tokens hits close to the same 6×1023 budget (6×2.5×1010×4×1012=6×1023), and empirical scaling-law findings show configurations closer to this balanced allocation achieve LOWER loss for the identical compute spend than the parameter-heavy, data-light allocation, because the very large, undertrained model in the first scenario was leaving loss improvement on the table that more data would have captured more cheaply than more parameters would.
Trade-offs & pitfalls
Scaling laws give you the compute-optimal TRAINING allocation, but training compute isn't the only cost that matters in production: a smaller model trained compute-optimally on more data is also cheaper to SERVE (lower inference latency and cost per query, which recurs on every single request, unlike training cost which is paid once). This means the genuinely optimal choice for a product often deliberately trains a smaller-than-compute-optimal model on even more data than the pure training-compute-optimal point would suggest, intentionally "overtraining" relative to the scaling-law optimum, because the resulting inference savings over the product's lifetime outweigh the extra training cost. A common mistake is treating the compute-optimal training point as the final answer without separately accounting for this inference-cost dimension, which the classic scaling-law framing (focused purely on training-loss-per-training-FLOP) doesn't include.
You must decide between two third-party LLM options for a knowledge assistant: a faster, cheaper model with slightly lower factual accuracy, versus a slower, costlier model with better factuality. How would you evaluate and choose, and how might you combine both to meet product goals?
Sample Answer
Direct answer
You must decide between two third-party LLMs for a knowledge assistant: a faster, cheaper model with slightly lower factual accuracy versus a slower, costlier model with better factuality, and possibly using both together. The right approach is to define a small set of measurable evaluation criteria tied to the actual product requirement, benchmark both models against real (or realistic) queries on those criteria, and then decide whether a single model suffices or whether a routing/fallback strategy combining both is worth the added complexity.
Structured elaboration
How to evaluate. Build a held-out evaluation set of realistic queries with known-correct answers (or human-graded rubrics for open-ended ones), and measure each candidate model on: factual accuracy (does it get the answer right, and does it hallucinate on out-of-scope questions), latency (p50/p95 response time under realistic load), cost per query at your expected volume, and any user-experience metrics that matter for the product (helpfulness ratings, task completion rate in A/B tests). Benchmarks alone are not sufficient; a model can score well on a public benchmark and still perform differently on your specific domain and query distribution, so the evaluation set must reflect your actual traffic.
Vendor/integration risk. Beyond raw model quality, evaluate SLA guarantees, rate limits, data-handling and privacy terms, and how exposed you are if the vendor changes pricing, deprecates the model, or has an outage, since a third-party dependency carries operational risk that a benchmark score alone won't capture.
Combining both models. A common production pattern is routing: use the fast, cheap model for the majority of queries (the ones it handles well), and escalate to the slower, more accurate model only for queries flagged as higher-risk or lower-confidence, e.g., via the fast model's own confidence signal, query complexity heuristics, or a lightweight classifier trained on where the fast model tends to fail. This captures most of the cost savings of the cheap model while limiting factual-accuracy risk to the harder subset of queries that actually need it.
Worked example
Say the cheap model costs $0.20 per 1,000 queries and the accurate model costs $2.00 per 1,000 queries, roughly a 10x cost difference, and evaluation shows the cheap model is factually correct 92% of the time versus 98% for the expensive model on your held-out set. If a routing classifier can reliably identify the roughly 20% of queries where the cheap model is most likely to be wrong (say, questions requiring precise numeric facts or recent information) and escalate only those to the expensive model, the blended cost is 0.8×$0.20+0.2×$2.00=$0.16+$0.40=$0.56 per 1,000 queries, about a 72% cost reduction from always using the expensive model, while capturing most of its accuracy benefit specifically where it matters most.
Trade-offs & pitfalls
A routing strategy only pays off if the signal for "this query needs the accurate model" is genuinely predictive; a poorly calibrated router either escalates too much (eroding the cost savings) or too little (letting factuality-sensitive queries slip through to the cheap model). It also adds real engineering and operational complexity: two vendor integrations, two SLAs to monitor, and a routing component that itself needs to be evaluated and maintained over time. For an early-stage product without the traffic volume or engineering capacity to build and maintain a router well, a single well-chosen model, even if slightly suboptimal on cost or accuracy, is often the more pragmatic starting point, with routing revisited once volume and evaluation infrastructure justify the added complexity.
Implement nucleus (top-p) sampling in Python. Input is a 1-D array of logits; return a sampled token index. Sort or accumulate probabilities efficiently and correctly handle edge cases where p is very small or very large. State the computational complexity.
Sample Answer
Direct answer
Nucleus (top-p) sampling picks the smallest set of highest-probability tokens whose cumulative probability reaches a threshold p, then samples from just that set, discarding the unreliable long tail while still adapting to how confident or uncertain the model's distribution is at each step.
Structured elaboration
The algorithm has four stages: (1) convert logits to probabilities with a numerically stable softmax, (2) sort the probabilities in descending order and compute their cumulative sum, (3) find the smallest prefix of that sorted list whose cumulative probability is at least p (the "nucleus"), always keeping at least one token even if the very first token alone already exceeds p, and (4) renormalize the nucleus's probabilities to sum to 1 and sample from that reduced distribution. The edge cases worth handling explicitly: p very small (effectively picks only the single highest-probability token, i.e., near-greedy behavior) and p very large or equal to 1.0 (the nucleus covers the whole vocabulary, and the method degenerates to plain multinomial sampling from the original distribution).
import numpy as np
def nucleus_sample(logits: np.ndarray, p: float = 0.9, rng: np.random.Generator = None) -> int:
"""Nucleus (top-p) sampling. logits: 1-D array of raw scores (size V).
Returns the sampled token index."""
if rng is None:
rng = np.random.default_rng()
logits = np.asarray(logits, dtype=np.float64)
shifted = logits - np.max(logits) # numerical stability
probs = np.exp(shifted)
probs /= probs.sum()
order = np.argsort(-probs) # descending probability order
sorted_probs = probs[order]
cum = np.cumsum(sorted_probs)
cutoff = np.searchsorted(cum, p, side="left") + 1
cutoff = max(1, min(cutoff, len(sorted_probs))) # always keep >=1 token
nucleus_idx = order[:cutoff]
nucleus_probs = sorted_probs[:cutoff]
nucleus_probs = nucleus_probs / nucleus_probs.sum() # renormalize
choice = rng.choice(len(nucleus_idx), p=nucleus_probs)
return int(nucleus_idx[choice])
Complexity. Computing the softmax is O(V) where V is the vocabulary size; sorting the probabilities is O(VlogV), which dominates the overall cost; the cumulative sum and searchsorted lookup are O(V) and O(logV) respectively. So the whole operation is O(VlogV) per sampling step, dominated by the sort.
Worked example
I verified this implementation in a sandbox against known-expected behavior on three constructed distributions:
- A sharply peaked distribution (
[10, 0, 0, 0, 0]as logits, so one token has overwhelmingly higher probability): across 2,000 samples at p=0.9, all 2,000 selected the dominant token, since its probability alone already exceeds 0.9 and the nucleus collapses to size 1. - A uniform distribution (
[0, 0, 0, 0, 0]logits over 5 tokens) at p=1.0: across 5,000 samples, each of the 5 tokens was chosen roughly 1,000 times (973 to 1,042 in the actual run), matching the expected uniform 1/5 probability, confirming the nucleus correctly covers the full vocabulary and samples proportionally when p=1.0. - The tiny-p edge case (p=10−6 on logits
[1, 5, 2]): all 50 trials picked index 1, the argmax, confirming the "always keep at least one token" guard produces near-greedy behavior rather than crashing or sampling nothing.
Trade-offs & pitfalls
A common bug is forgetting the "keep at least one token" floor, which can crash or misbehave when a single token's probability already exceeds p on its own (searchsorted would return a cutoff of 0 without the max(1, ...) guard). Another subtlety: nucleus sampling is usually combined with temperature scaling in practice (apply temperature to the logits before computing the softmax), since p alone controls how MANY tokens are eligible but temperature controls how sharply probability concentrates among them; using p without temperature can still produce a poorly calibrated nucleus if the underlying logit distribution is itself miscalibrated.
What is a context window, and why is it bounded? At a conceptual level, what are the main strategies (chunking and summarization, sliding windows, retrieval) for working within or around a limited context window, and what does each trade off in terms of latency and factuality?
Sample Answer
Direct answer
A context window is the maximum number of tokens (input plus generated output combined) a model can attend to at once; it is bounded because the computational and memory cost of self-attention grows with the square of the sequence length, so there is a hard practical ceiling on how long a sequence a given model architecture and serving budget can process. When your task's input exceeds the context window, the main strategy categories are chunking/summarization, sliding-window processing, and retrieval, each trading off differently between latency, computation, and factual completeness.
Structured elaboration
Why it's bounded. Standard self-attention computes a score between every pair of tokens in the sequence, so both compute and memory scale roughly quadratically with sequence length. Doubling the context length roughly quadruples the attention compute for a given layer, which is why context windows have historically grown in discrete jumps as hardware and (increasingly) more efficient attention implementations made longer windows economically serveable, rather than growing smoothly.
Chunking and summarization. Split a long document into pieces that each fit the window, process each piece (often producing a summary or extracted answer per chunk), then combine the per-chunk results. This is simple and works with any model, but it can lose information that spans a chunk boundary, and summarizing before combining trades some factual completeness for tractability.
Sliding windows. Process the sequence in overlapping windows, carrying some state or overlap from one window into the next, so a fact near a chunk boundary is likely to appear fully within at least one window. This reduces boundary-loss compared to naive chunking but adds redundant computation for the overlapping regions and still doesn't give the model true attention across the whole original sequence at once.
Retrieval. Instead of trying to fit the whole document into context, index it and retrieve only the most relevant passages for the current query, then put just those passages in the prompt. This scales to arbitrarily large source material (the index, not the context window, holds everything) and keeps prompts short and cheap, at the cost of depending entirely on retrieval quality: if the retriever misses the relevant passage, the model never sees it, no matter how good its reasoning is.
Trade-offs & pitfalls
Chunking/summarization and sliding windows both keep "the whole thing routed through the model at some point," which is closer to lossless but gets more expensive and slower as the source grows. Retrieval scales far better but introduces a new failure mode entirely outside the LLM's control: retrieval miss. In practice, teams pick based on the failure mode they can least tolerate; a legal or medical use case that cannot afford to silently omit a relevant clause may prefer the higher cost of processing the full document over the risk of retrieval missing it, while a general-purpose assistant answering questions over a huge corpus has no realistic alternative to retrieval at all.
You have 500k multilingual sentences and need to design a tokenizer and vocabulary for training a new LLM. What are the vocabulary-size trade-offs, and how would you handle rare scripts, code-mixing, and balancing token coverage across languages?
Sample Answer
Direct answer
Designing a tokenizer and vocabulary for 500k multilingual sentences means making an explicit trade-off between vocabulary size, sequence length, and fairness of coverage across languages and scripts, then validating it doesn't silently starve any language of good subword representation before training even starts.
Structured elaboration
Vocabulary-size trade-off. A bigger vocabulary (say 100k+ tokens) lets common words in well-represented languages compress to fewer tokens, shortening sequences and cutting inference cost per unit of text, but it grows the embedding and output-projection matrices (some of the largest parameter blocks in the model) and pushes more tokens into the long tail where they're seen too rarely during training to be well-learned. A smaller vocabulary (say 30k-50k) keeps the embedding matrix compact but produces longer sequences for every language, which raises compute cost under the quadratic scaling of attention and can push some inputs uncomfortably close to the context window limit.
Handling rare scripts. Byte-level SentencePiece is the standard choice here because it guarantees every script is representable (it operates on raw bytes/Unicode, not on a hand-curated per-language character set), avoiding the failure mode where a language absent from your training corpus becomes entirely untokenizable.
Code-mixing. Real multilingual text frequently mixes languages within a single sentence or even a single word (e.g., borrowed technical terms). A subword scheme trained on the full multilingual corpus jointly (rather than one tokenizer per language stitched together) handles this naturally, since it learns subword boundaries from the actual mixed data rather than assuming clean per-language segments.
Balancing coverage across languages. If you build the vocabulary by pure frequency over the raw 500k-sentence corpus, whichever language dominates the corpus by volume will also dominate the vocabulary, and lower-resource languages will get merged less aggressively, ending up needing more tokens per word than the high-resource language even for equally common concepts. The standard mitigation is to upsample or reweight lower-resource languages during vocabulary construction (not necessarily during model training itself) so the merge algorithm sees them often enough to build efficient subwords for them too.
Pre-processing. Unicode normalization (so visually identical characters with different byte representations, like different Unicode forms of an accented letter, don't silently become different tokens) and consistent canonicalization (casing, punctuation handling) need to be decided and applied consistently before vocabulary construction, since inconsistencies here permanently bake inefficient or duplicate subwords into the vocabulary.
Trade-offs & pitfalls
The single most common failure in multilingual tokenizer design is treating it as a purely mechanical step and running the vocabulary-construction algorithm on the raw corpus as-is; without deliberate language reweighting, the resulting tokenizer will quietly be much less efficient for underrepresented languages, which then shows up downstream as those languages needing more tokens (and therefore more cost and more context-window budget) per sentence, and often as somewhat worse model quality in those languages since more of their subwords fall into the poorly-trained long tail of the vocabulary.
Unlock Full Question Bank
Get access to all 37 Generative AI and Large Language Models interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.