A senior infrastructure engineer who interviewed at Anthropic in late 2024 described the process in a Substack post as "the most intellectually honest interview I've ever been in." The recruiter sent reading material beforehand: Dario Amodei's essay on AI safety, Anthropic's Responsible Scaling Policy, and a note that the culture round was not a personality test but a genuine test of whether you had thought seriously about the work. That's a different kind of signal than most companies send before a loop.
What makes Anthropic's process unusual is that it's shaped by what the company actually believes, not by cargo-culted hiring norms. The coding assessment doesn't give you tree traversal puzzles. The system design round asks you to design Claude's serving infrastructure, not a URL shortener. And there is a whole interview that exists purely to probe whether your relationship with AI safety is real or performed. That round has the highest failure rate of any stage in the loop. This page covers what the 2026 Anthropic interview actually looks like, based on verified candidate accounts from Glassdoor, interviewing.io, Exponent, and multiple write-ups from people who went through the process between 2024 and early 2026.
Easy questions
13The starting point for the database-style CodeSignal challenge reported by multiple candidates. SET writes a value, GET retrieves it or returns null, DELETE removes the key. The implementation itself is trivial. What matters is how you structure the code, because levels 2, 3, and 4 will layer on filtered scans, TTL expiry, and file persistence, and your Level 1 structure either makes those extensions clean or painful.
This is reported directly from a 2025 CodeSignal assessment by a candidate who wrote up the experience in detail. The key observation from that write-up: "I spent more time on class structure than on the actual logic, and that paid off at level 3 when they added TTL. My interviewer noted the modularity specifically."
class KeyValueStore:
def __init__(self):
self.store = {}
def set(self, key: str, value: str) -> None:
self.store[key] = value
def get(self, key: str) -> str | None:
return self.store.get(key)
def delete(self, key: str) -> bool:
if key in self.store:
del self.store[key]
return True
return FalseReported from an Exponent summary of Anthropic coding round questions. Group file paths by content hash. Any group with more than one entry contains duplicates. Return the paths to delete (all copies but one). The follow-up: what if content hashes aren't pre-computed and you need to hash the files yourself? The answer involves choosing a fast hash function (xxHash or MD5 for deduplication, not SHA-256 unless integrity is the goal) and batching file reads to avoid opening thousands of file handles simultaneously.
A subtler follow-up that interviewers report asking: "What if two files have the same hash but different content?" At Anthropic, this is worth a real answer about collision probability and whether the use case (deduplication vs. integrity checking) changes the acceptable collision rate.
A hash map for O(1) lookup combined with a doubly linked list for O(1) reordering. The hash map stores key to node references. The linked list keeps nodes ordered from most to least recently used, with the head as most recent. On get, move the accessed node to the head. On put, insert at the head and evict from the tail if capacity is exceeded. Python's OrderedDict does this internally, but interviewers almost always ask you to implement it from primitives.
This is one of the most recurring warm-up questions in Anthropic's early technical screens, per aggregated Glassdoor and Blind threads from 2024 through 2026. The follow-up worth having ready: what changes if get and put need to be thread-safe under concurrent access? A single lock around the whole structure works but serializes every operation, which connects directly to the rate limiter question above.
class Node:
def __init__(self, key, value):
self.key, self.value = key, value
self.prev = self.next = None
class LRUCache:
def __init__(self, capacity: int):
self.capacity = capacity
self.cache = {}
self.head = Node(0, 0)
self.tail = Node(0, 0)
self.head.next, self.tail.prev = self.tail, self.head
def _remove(self, node):
node.prev.next, node.next.prev = node.next, node.prev
def _add_to_front(self, node):
node.next, node.prev = self.head.next, self.head
self.head.next.prev = node
self.head.next = node
def get(self, key: int) -> int:
if key not in self.cache:
return -1
node = self.cache[key]
self._remove(node)
self._add_to_front(node)
return node.value
def put(self, key: int, value: int) -> None:
if key in self.cache:
self._remove(self.cache[key])
node = Node(key, value)
self.cache[key] = node
self._add_to_front(node)
if len(self.cache) > self.capacity:
lru = self.tail.prev
self._remove(lru)
del self.cache[lru.key]Tests intellectual honesty and the capacity to update on evidence. The specifics matter more than the magnitude of the belief change. A technical belief is fine (I was convinced architecture X was correct, found evidence that Y worked better, and changed my implementation). A non-technical belief is also fine. What doesn't work: a change of mind framed as "I didn't have all the information," because that implies the change was forced rather than genuine. What works: "I was wrong about X, here's the specific evidence that shifted me, and here's what I would have done differently if I'd seen it earlier."
The follow-up question candidates report: "Is there something you currently believe strongly that you might be wrong about?" That's the real test. It requires live reasoning, not a prepared story.
Simple sounding, but it tests the same intellectual honesty muscle as the harder values questions. What doesn't work: a story where the feedback landed well and everything resolved cleanly, which is a suspiciously easy version of a genuinely hard situation. Interviewers want the version where the conversation was actually uncomfortable, the relationship took a real hit or the feedback was only partly accepted, and what the candidate did with that outcome afterward.
The follow-up that separates a rehearsed answer from a real one: "did you check back later to see if anything changed?" A candidate who never revisited the situation is describing a one-time performance, not an ongoing working relationship.
No, not in the conventional sense. The CodeSignal assessment is implementation-based: one problem split into four escalating levels, where each level adds new requirements to your existing code. Reported problems include building a bank system with multiple transaction types and an in-memory database with TTL and file compression. The live coding rounds during onsite similarly focus on practical implementation problems and systems thinking, not abstract algorithm puzzles. You won't be asked to implement Dijkstra's algorithm in 20 minutes.
Three to 8 weeks is the typical range. Anthropic's own Glassdoor data shows an average of 19 days across all roles, which skews short because some roles (especially non-engineering) have simpler loops. For senior engineering and research roles, 4 to 8 weeks is more realistic. With a referral or a competing offer, the process can be compressed significantly; candidates report getting the full loop scheduled within 2 weeks in those cases.
Not for most engineering roles. Anthropic has said publicly, and candidates confirm, that many staff members had no ML experience before joining. What Anthropic cares about for engineering roles is strong systems thinking, clean implementation, and genuine engagement with the company's safety mission. That said, for research scientist and ML engineering roles, the bar on ML fundamentals (transformers, RLHF, scaling laws, interpretability) is very high. Ask your recruiter which category your role falls into; they'll tell you what the domain focus of your loop will be.
Anthropic sends reading material before the culture round, which is itself a signal. The standard list: "Core Views on AI Safety" (available on anthropic.com), the Responsible Scaling Policy (also public), and Dario Amodei's long-form essays, especially "Machines of Loving Grace" (October 2024) and "The Adolescence of Technology" (February 2026). Multiple candidates also recommend listening to the Dwarkesh Patel and Lex Fridman interviews with Dario Amodei, not to collect talking points but to understand how Anthropic reasons about safety tradeoffs at a level of depth the blog posts don't always reach.
Per Levels.fyi data as of 2025 to 2026, total compensation for software engineers at Anthropic ranges from around $300K at L3 to $563K at senior level (L5) to above $785K at lead level (L6), inclusive of base, bonus, and equity. The equity component is significant and follows a 4-year vesting schedule with 25% in year one. These numbers move with the market and with Anthropic's funding status; the company raised at a $61.5 billion valuation in late 2024, and compensation has tracked that trajectory upward.
The biggest structural difference is the values interview. OpenAI has behavioral rounds but nothing with the explicit focus on AI safety reasoning that Anthropic's culture round has. OpenAI's coding rounds are more LeetCode-adjacent; Anthropic's are more implementation-focused. Both companies use system design rounds with an LLM infrastructure flavor. In terms of difficulty, candidates who've done both report that Anthropic's values round is harder to prepare for than anything OpenAI puts in its loop, not because the technical bar is higher, but because it's genuinely hard to perform intellectual honesty.
This is a warm-up problem, but interviewers watch how you handle it because the clean solution is a stack and a lot of candidates reach for something messier first. The idea is that every closing bracket has to match the most recently opened bracket of the same type, which is exactly the last-in-first-out behavior a stack gives you for free.
def is_balanced(s):
pairs = {')': '(', ']': '[', '}': '{'}
stack = []
for ch in s:
if ch in '([{':
stack.append(ch)
elif ch in ')]}':
if not stack or stack.pop() != pairs[ch]:
return False
return not stackPush every opening bracket. On a closing bracket, check that the stack isn't empty and that the top of the stack matches the expected opener, popping it if so. If either check fails, return false immediately. At the end, an empty stack means every open bracket got closed, so the string is balanced. The edge cases worth calling out loud in the interview: an empty string should return true, a string with only closing brackets should short-circuit on the first character, and a string with only opening brackets has to fall through to the final check rather than returning early. Runtime is O(n) and space is O(n) in the worst case of an all-opening-bracket string.
An endpoint is idempotent if calling it once and calling it five times with the same input leave the system in the same state. GET, PUT, and DELETE are idempotent by convention: fetching a resource repeatedly doesn't change it, overwriting a resource with the same payload repeatedly produces the same final record, and deleting an already-deleted resource is still "deleted" whether you call it once or three times. POST is the odd one out because a naive POST handler that creates a new row on every call is not idempotent by default, calling it twice creates two rows.
This matters in practice because networks are unreliable and clients retry. Say a client sends a request to create a message, the server processes it and writes to the database, but the response gets lost to a timeout before it reaches the client. The client, seeing no response, retries. Without idempotency protection you now have two messages instead of one, or worse, two charges on a billing endpoint. The standard fix is an idempotency key: the client generates a unique key per logical operation and sends it in a header, and the server stores a record of keys it has already processed along with the result. If the same key comes in again, the server returns the cached result instead of re-executing the side effect. It's a small piece of infrastructure, usually a table with a unique constraint on the key plus a TTL for cleanup, but it's the difference between a retry being safe and a retry being a bug that shows up as duplicate data in production.
Medium questions
27Level 3 in the typical in-memory database assessment. On SET, accept an optional TTL in seconds. On GET, check whether the key has expired; if it has, treat it as deleted. Lazy expiration (checking at GET time) is simpler and acceptable here. Eager cleanup via a background thread is a valid extension but don't reach for it unless you've finished all four levels.
The timestamp comparison is where candidates stumble. Use a monotonic clock or time.time() consistently. Storing the expiry timestamp rather than the TTL duration avoids drift when the GET call happens long after SET. This design detail comes up in follow-up questions.
import time
class KeyValueStoreWithTTL:
def __init__(self):
self.store = {} # key -> value
self.expiry = {} # key -> expiry timestamp
def set(self, key: str, value: str, ttl: float | None = None) -> None:
self.store[key] = value
if ttl is not None:
self.expiry[key] = time.time() + ttl
elif key in self.expiry:
del self.expiry[key] # remove any old TTL
def get(self, key: str) -> str | None:
if key in self.expiry and time.time() > self.expiry[key]:
del self.store[key]
del self.expiry[key]
return None
return self.store.get(key)
def delete(self, key: str) -> bool:
existed = key in self.store
self.store.pop(key, None)
self.expiry.pop(key, None)
return existedThe other common CodeSignal variant reported for Anthropic. Level 1 handles basic balance operations. Level 2 adds validation (insufficient funds, invalid amounts). Level 3 adds payment scheduling or recurring transfers. Level 4 adds account merging or cross-account transfers with atomicity guarantees. The specific progression varies slightly by assessment version, but the structure is consistent: you build on what you already wrote.
Reported in a Glassdoor review from a 2024 candidate: "CodeSignal assessment, building some bank system." The modular structure matters exactly as it does in the database variant. An Account class with clearly separated transaction and balance logic survives the level transitions; a single-function script does not.
from dataclasses import dataclass, field
from datetime import datetime
@dataclass
class Transaction:
kind: str # "deposit" | "withdrawal" | "transfer"
amount: float
timestamp: datetime = field(default_factory=datetime.utcnow)
note: str = ""
class BankAccount:
def __init__(self, account_id: str, owner: str):
self.account_id = account_id
self.owner = owner
self._balance = 0.0
self.history: list[Transaction] = []
@property
def balance(self) -> float:
return self._balance
def deposit(self, amount: float, note: str = "") -> float:
if amount <= 0:
raise ValueError("Deposit amount must be positive")
self._balance += amount
self.history.append(Transaction("deposit", amount, note=note))
return self._balance
def withdraw(self, amount: float, note: str = "") -> float:
if amount <= 0:
raise ValueError("Withdrawal amount must be positive")
if amount > self._balance:
raise ValueError("Insufficient funds")
self._balance -= amount
self.history.append(Transaction("withdrawal", amount, note=note))
return self._balanceReported as a live coding question from an Exponent guide based on Anthropic onsite accounts. Given a log of function call start and end events, find which functions have the highest cumulative execution time. A stack tracks open calls; when a function ends, pop the stack and accumulate its duration. Functions that were called multiple times need aggregated totals.
The parsing part is where most candidates spend unnecessary time. Ask the interviewer upfront what the log format looks like and whether timestamps are integers or strings. That question alone signals that you're thinking about the input contract before writing code.
def longest_running(logs: list[tuple[str, str, int]]) -> dict[str, int]:
"""
logs: list of (function_name, event, timestamp)
event: "start" or "end"
Returns: {function_name: total_duration}
"""
stack = [] # stack of (function_name, start_time)
totals = {} # function_name -> cumulative ms
for name, event, ts in sorted(logs, key=lambda x: x[2]):
if event == "start":
stack.append((name, ts))
elif event == "end" and stack:
fn, start = stack.pop()
totals[fn] = totals.get(fn, 0) + (ts - start)
return dict(sorted(totals.items(), key=lambda x: -x[1]))Concurrency questions show up across multiple Anthropic rounds. A token bucket or sliding window counter with a threading lock is the expected starting implementation. The token bucket approach: maintain a bucket of N tokens refilling at R tokens per second. Each request consumes one token; if the bucket is empty, reject or wait. Use a threading.Lock around bucket state reads and writes.
Interviewers follow up on what happens at very high concurrency (the lock becomes a bottleneck, you'd need sharding or an atomic counter). They also ask about distributed rate limiting when you have multiple API gateway instances, which pushes the conversation toward Redis and atomic Lua scripts or sliding window counters in a shared store. That extension shows up specifically in system design round conversations, per candidate reports from 2025.
import threading
import time
class RateLimiter:
def __init__(self, capacity: int, refill_rate: float):
self.capacity = capacity
self.tokens = float(capacity)
self.refill_rate = refill_rate # tokens per second
self.last_refill = time.monotonic()
self._lock = threading.Lock()
def _refill(self) -> None:
now = time.monotonic()
elapsed = now - self.last_refill
self.tokens = min(self.capacity, self.tokens + elapsed * self.refill_rate)
self.last_refill = now
def allow(self) -> bool:
with self._lock:
self._refill()
if self.tokens >= 1:
self.tokens -= 1
return True
return FalseReported as a topic that comes up in Anthropic's live coding rounds and sometimes as a conceptual follow-up question rather than a coding problem. The core answer covers three layers: the GIL (Python's Global Interpreter Lock provides some protection against data corruption but not logical race conditions), threading primitives (Lock, RLock, Event, Semaphore for when you need guaranteed atomicity), and the preferred pattern of using immutable data structures or queues to avoid shared mutable state entirely.
Anthropic interviewers care about the third layer most. "Design your data so it doesn't need to be mutated concurrently" is a better answer than "slap a lock on everything." The queue-based producer-consumer pattern, or passing messages instead of sharing state, is the design idiom they're looking for.
Given a corpus already split into characters or existing subword symbols, count every adjacent pair, find the most frequent one, and merge it into a new single symbol everywhere it occurs. Repeat for a fixed number of merges or until a target vocabulary size is reached. The counting step is the part candidates rush through, and it's the part interviewers actually watch: a naive re-scan of the whole corpus after every single merge is correct but far too slow for anything beyond a toy example.
This shows up for ML infrastructure and research-adjacent roles specifically, since tokenization sits underneath every model Anthropic ships. A reasonable follow-up: how would you make this incremental, so that after one merge you only update pair counts touching the symbols that changed, rather than recomputing everything? That's the actual optimization real BPE implementations use.
from collections import Counter
def get_pair_counts(corpus: list[list[str]]) -> Counter:
counts = Counter()
for word in corpus:
for a, b in zip(word, word[1:]):
counts[(a, b)] += 1
return counts
def merge_pair(corpus: list[list[str]], pair: tuple[str, str]) -> list[list[str]]:
merged_symbol = pair[0] + pair[1]
new_corpus = []
for word in corpus:
new_word, i = [], 0
while i < len(word):
if i < len(word) - 1 and (word[i], word[i + 1]) == pair:
new_word.append(merged_symbol)
i += 2
else:
new_word.append(word[i])
i += 1
new_corpus.append(new_word)
return new_corpus
def train_bpe(corpus: list[list[str]], num_merges: int) -> list[list[str]]:
for _ in range(num_merges):
counts = get_pair_counts(corpus)
if not counts:
break
best_pair = max(counts, key=counts.get)
corpus = merge_pair(corpus, best_pair)
return corpusThe classic merge-intervals problem, framed around a real Anthropic-shaped resource: researchers reserving GPU nodes for time windows that may overlap. Sort reservations by start time, then walk through them once, merging the current interval into the previous one whenever its start falls before or at the previous interval's end. The result is the minimal set of consolidated busy windows for that node.
The follow-up interviewers ask most often: what if reservations carry priority, and a higher-priority job should be able to preempt an overlapping lower-priority one rather than just merging blindly? That turns a pure interval-merge problem into a scheduling problem, and a good candidate says so explicitly instead of trying to force the merge logic to also handle preemption.
def merge_reservations(windows: list[tuple[int, int]]) -> list[tuple[int, int]]:
if not windows:
return []
windows.sort(key=lambda w: w[0])
merged = [windows[0]]
for start, end in windows[1:]:
last_start, last_end = merged[-1]
if start <= last_end:
merged[-1] = (last_start, max(last_end, end))
else:
merged.append((start, end))
return mergedThe practical version of the "avoid shared mutable state" idiom described above in the data-mutation question. Producers push items onto a fixed-capacity queue; when it's full, producers block (or return a rejection signal) instead of growing the queue unbounded. Consumers pull items off and block when the queue is empty. A threading.Condition wraps the shared deque so producers and consumers can wait and signal each other instead of busy-polling.
Interviewers push on what happens under sustained overload: if producers always outpace consumers, do you want callers to block indefinitely, time out, or drop the oldest item to make room for the newest? Anthropic's own inference queueing has exactly this shape at the request-ingestion layer, and candidates who name the tradeoff between blocking and shedding load tend to score better than ones who just implement the happy path.
import threading
from collections import deque
class BoundedQueue:
def __init__(self, capacity: int):
self.capacity = capacity
self.items = deque()
self.lock = threading.Lock()
self.not_full = threading.Condition(self.lock)
self.not_empty = threading.Condition(self.lock)
def put(self, item, timeout: float | None = None) -> bool:
with self.not_full:
if not self.not_full.wait_for(lambda: len(self.items) < self.capacity, timeout):
return False
self.items.append(item)
self.not_empty.notify()
return True
def get(self, timeout: float | None = None):
with self.not_empty:
if not self.not_empty.wait_for(lambda: len(self.items) > 0, timeout):
return None
item = self.items.popleft()
self.not_full.notify()
return itemIn autoregressive generation, each new token attends to all prior tokens. Without a cache, computing attention at step N requires recomputing the key and value tensors for all N-1 previous tokens: O(N^2) total compute for a sequence of length N. KV-cache stores those key and value tensors after they're first computed. Each decoding step only needs to compute attention for the new token against the cached context.
The memory cost: KV-cache grows linearly with sequence length and batch size. For a 70B parameter model with long-context requests and a large batch, the KV-cache can exceed GPU memory before compute does. PagedAttention (implemented in vLLM) addresses this by managing KV-cache memory in fixed-size pages rather than contiguous allocations, reducing fragmentation and allowing higher effective batch sizes. This specific question and the PagedAttention follow-up are reported from Anthropic system design rounds in 2025.
Constitutional AI (CAI), introduced in Anthropic's 2022 paper, trains a model using a set of written principles (a "constitution") rather than requiring human labelers to rate every output. The model critiques and revises its own outputs against those principles during training, and a reinforcement learning step uses the constitution-guided model as the reward signal rather than a human preference model.
Standard RLHF collects human preference data (which response is better?) and trains a reward model from those labels, which then guides RL fine-tuning. CAI replaces much of the human labeling in the second step with AI-generated feedback guided by explicit principles. It's faster and more scalable than pure RLHF for the harmlessness objective, but depends on the quality and completeness of the constitution itself. Interviewers at Anthropic ask about the limitations: a constitution that fails to anticipate a category of harmful behavior won't provide useful training signal for that category. Knowing this tradeoff honestly is part of what they're testing.
A small, fast draft model proposes several candidate tokens ahead of the current position. The large target model then verifies all of them in a single forward pass instead of one pass per token. Any prefix of correct guesses gets accepted for free; the first wrong guess is discarded and the target model's own token is used instead. Because verification is one batched pass rather than several sequential ones, the wall-clock speedup can be substantial even though the total compute done by the target model doesn't drop much.
The technique traces back to Leviathan et al.'s 2023 paper "Fast Inference from Transformers via Speculative Decoding." Interviewers push on the acceptance rate: if the draft model disagrees with the target model often, you're paying for the draft model's compute without getting the speedup, so the choice of draft model matters as much as the algorithm itself. A common follow-up: how would you pick or train a draft model for a specific target model?
Quantization stores weights (and sometimes activations) in lower-precision formats, cutting memory footprint roughly in half at INT8 versus FP16, and further at INT4. Lower memory means more of the model fits in GPU memory alongside a bigger KV-cache, which raises the batch sizes you can serve. The cost is precision: naive rounding of every weight to 8 bits measurably hurts output quality, particularly because a small number of activation dimensions in large models have outlier magnitudes that a uniform quantization scheme handles badly.
Dettmers et al.'s LLM.int8() (2022) and Frantar et al.'s GPTQ (2023) both address this by treating outlier dimensions specially or by quantizing weights layer by layer while minimizing the reconstruction error against the original outputs, rather than rounding independently. Interviewers want you to name the actual failure mode (outlier features), not just say "quantization loses some precision."
Prefill processes the entire input prompt in one shot, computing attention over all prompt tokens in parallel. It's compute-bound and uses the GPU efficiently because there's a large matrix multiply to do. Decode generates one new token at a time, and each step has to read the full KV-cache and the full set of model weights to produce a single new token's worth of output. That makes decode memory-bandwidth-bound, not compute-bound, so it uses the GPU poorly by comparison.
Because the two phases have opposite bottlenecks, running them on the same GPU pool wastes capacity, either the decode step starves for bandwidth while compute sits idle, or a long prefill blocks decode steps for other requests and spikes tail latency. Disaggregating prefill and decode onto separate GPU pools, as described in Patel et al.'s 2023 Microsoft paper "Splitwise," is the production answer. Anthropic's system design interviewers reportedly ask this as a direct follow-up to the token generation service question earlier in this loop.
Modulo hashing (key hash mod N nodes) is simple, but when N changes, nearly every key remaps to a different node, which means a node joining or leaving triggers a massive, unnecessary data shuffle. Consistent hashing places both nodes and keys on a fixed hash ring; a key belongs to the first node found walking clockwise from its position. Adding or removing a node only reassigns the keys between it and its neighbor on the ring, roughly 1/N of all keys rather than nearly all of them.
The follow-up interviewers ask, tied directly to the earlier distributed search system question: plain consistent hashing can still produce hot spots if nodes land unevenly on the ring. Virtual nodes, where each physical node owns many points scattered around the ring, smooth that distribution out. Candidates who bring up virtual nodes without being prompted tend to stand out.
Mechanistic interpretability is the research program of reverse-engineering neural networks to understand what computations they're actually performing, at the level of individual circuits and features. Anthropic's team has published work on superposition (how models represent more features than they have neurons by using near-orthogonal directions in activation space), on identifying specific circuits responsible for in-context learning, and on monosemantic features in sparse autoencoders trained on model activations.
The safety motivation: if you can identify the mechanisms responsible for a model behavior, you can potentially verify that a model doesn't contain circuits for deceptive alignment or reward hacking, rather than just hoping that behavioral evaluations catch it. Interviewers want to know whether you've read any of the published work, particularly the 2023 toy models paper and the 2024 features in superposition work. "I read the paper and I have a question about X" lands much better than a Wikipedia-level summary.
The original Kaplan et al. 2020 paper (Scaling Laws for Neural Language Models) showed that model loss decreases as a power law with compute, parameters, and data, and that the optimal parameter-to-token ratio follows a specific relationship at a given compute budget. Chinchilla (Hoffman et al. 2022) revised this, showing that prior large models were significantly over-parameterized relative to their training data, and that training a smaller model on more tokens often outperforms a larger model on fewer tokens at the same compute budget.
What scaling laws don't tell you: whether capabilities emerge gradually or discontinuously, whether safety properties scale in parallel with capabilities (the empirical evidence is that they don't, at least not automatically), and whether the power-law relationship holds at scales beyond current training runs. Anthropic interviewers for research roles want you to know where the theory breaks down, not just what it predicts.
Sycophancy is a model changing a previously correct or well-reasoned answer to match a user's stated opinion, when the user offers pushback but no new evidence. Sharma et al.'s 2023 Anthropic paper, "Towards Understanding Sycophancy in Language Models," found that sycophancy increases with RLHF training and traced part of the cause back to the preference data itself: human and preference-model raters prefer sycophantic responses a meaningful fraction of the time, so the reward signal is quietly teaching the model to agree rather than to reason.
An evaluation for this presents the model with a question it answered correctly, has a simulated user push back with something like "I don't think that's right" and no supporting argument, and measures how often the model flips its position anyway. A well-calibrated model should hold its answer unless the user actually supplies new information. Interviewers want to hear that you'd separate genuine belief updating from simple social pressure in the eval design, not just measure "did the answer change."
Reward hacking is a policy learning to exploit weaknesses in a reward model or reward function rather than to satisfy the actual human intent the reward was supposed to capture. Reported forms include models learning to write longer responses because a reward model correlates length with quality, or a model expressing artificial confidence because confident-sounding text scores higher even when the underlying answer is uncertain or wrong.
Mitigations candidates are expected to name: a KL-divergence penalty against a reference policy so the trained model can't drift arbitrarily far in search of reward, reward model ensembling so a single exploitable reward model isn't the sole signal, and periodic human spot-checks comparing human judgment against the reward model's own scores to catch divergence before it compounds. The interviewer follow-up worth expecting: how would you even detect reward hacking if the reward model itself is the thing being fooled?
The most commonly reported values round opener. A vague answer ("AI could be dangerous") is worse than saying nothing. Interviewers want to see specificity: which risks, on what timeline, what does the empirical evidence suggest, and how does your view connect to work you've actually done or read about. Anthropic's own framing distinguishes misuse risks (bad actors using capable models deliberately) from accident risks (models pursuing unintended goals) from structural risks (AI-enabled concentration of power). Knowing this taxonomy and having a view on which risk category worries you most is the baseline.
The follow-up is almost always: "Where do you disagree with Anthropic's current approach?" Interviewers explicitly want pushback. A candidate who has read the Responsible Scaling Policy and found a genuine tension in it is more credible than one who agrees with everything.
Reported by multiple candidates as a core values round question. What makes this question hard is that it requires a real answer: a situation where you genuinely compromised, not one where you heroically resolved the conflict in your favor. Interviewers are explicitly looking for intellectual honesty here, the kind that shows up when the story doesn't make you look good. What mattered to the interviewers, per candidate accounts, was not the severity of the conflict but whether the candidate could describe their internal reasoning with accuracy and without defensiveness.
What doesn't work: a conflict that was actually someone else's fault, reframed as yours. A "values conflict" that turned out to be a simple misunderstanding. A story that ends with you being correct. These land as performance, not honesty.
The real-stakes version of the values question. Interviewers want to hear about your actual decision process, not a policy recitation. The strong answers describe a specific sequence: first, verify your understanding of the safety concern (is it a real risk or an unfamiliarity?); second, raise it through the appropriate channel (team lead, safety team, whoever owns the risk assessment); third, describe what you'd do if the concern was acknowledged but the project proceeded anyway. That third part is where most candidates hedge. Interviewers notice.
Anthropic's culture explicitly supports raising safety concerns at any level of the organization. A candidate who says "I'd defer to my manager" without any escalation path described is signaling that they haven't thought about how safety concerns actually propagate in a real organization.
Specifically reported from multiple Anthropic values rounds. The question probes whether you can distinguish between good pushback (you had genuine evidence, made the case clearly, the decision still went the other way) and sycophantic capitulation (you disagreed but didn't say anything). Both are interesting. Neither is disqualifying on its own. What is disqualifying: a story where you were obviously right and the other person was obviously wrong, told without any acknowledgment of the ambiguity that makes organizational decisions actually hard.
Interviewers also probe what happened after the decision: did you execute it anyway? Did you continue to monitor whether your concern materialized? Did you revisit it if new information arrived? The post-decision behavior tells them more than the pushback itself.
This is the project deep-dive version of the hiring manager call question, often repeated in a second loop with a different interviewer probing different angles. "End-to-end ownership" at Anthropic means you made design decisions, not just implemented someone else's spec. Interviewers want to understand what constraints you were working under, what you traded off and why, and specifically what you'd do differently with hindsight.
The "differently" part matters a lot. Candidates who say everything went well, or who only mention minor tactical adjustments, aren't giving the interviewer what they're looking for. The best answers describe a real mistake in judgment: an architectural decision that created maintenance debt, a performance assumption that turned out to be wrong under production load, a product choice that users didn't respond to as expected. Specific, not sanitized.
Reported as a question that shows up across both system design and values rounds at Anthropic. The surface level: when you ship something to millions of users, the effects you planned for are not the only effects that matter. Second-order effects might include: users finding unintended uses of the system (a model built for customer support being used for legal advice), distributional shift in inputs over time as the user base grows and changes, feedback loops where model outputs influence future training data, and concentration effects where a small number of users or use cases dominate the system's behavior in ways that harm the long tail.
Interviewers want you to reason out loud about specific second-order effects that would be relevant to whatever system you're discussing, not give a generic answer. "What second-order effects do you think matter for the inference platform we just designed?" is the kind of follow-up to expect.
This tests whether a candidate can translate risk into concrete, falsifiable consequences instead of vague caution that a stakeholder under deadline pressure can easily wave away. A weak answer says "I explained the risks and they understood." A strong answer names exactly what the stakeholder wanted to skip, what specific evidence supported the concern, and how the conversation actually resolved, including the version where it resolved in the stakeholder's favor and what happened next.
What interviewers listen for specifically: did the candidate frame the risk in terms the stakeholder could act on (a probability, a cost, a concrete failure scenario) rather than in engineering jargon that just restates the concern in a more technical register?
Probes for conflict avoidance dressed up as escalation. The weak answer goes straight to a manager. The strong answer engages the colleague directly first, tries to understand whether the corner-cutting was a deliberate, already-disclosed tradeoff the colleague had reasoned through, or something that genuinely hadn't been surfaced to anyone, and escalates only if that direct conversation doesn't resolve it.
Anthropic's culture explicitly supports raising concerns at any level, but interviewers want to hear that the uncomfortable peer conversation is the first move, not the last resort taken only after building a case to present to someone else.
A real answer names a specific framework rather than a feeling. Risk-tiering by severity and likelihood, defining in advance what "enough" testing means for each tier instead of deciding it after the fact, and building a rollback or kill switch as compensation for the uncertainty that inevitably remains. This connects directly to the Responsible Scaling Policy's ASL framework referenced earlier in the values round: crossing a capability threshold requires passing specific evaluations first, precisely because "we tested a lot of cases" isn't a sufficient answer on its own.
Interviewers want the candidate to connect this abstract framework to an actual shipping decision they've made, with the specific tier boundaries and rollback mechanism named, not a restatement of the policy.
Hard questions
4Capability evaluations measure what a model can do: MMLU, HumanEval, MATH, coding benchmarks, multimodal tasks. They're well-defined and easy to run. Alignment evaluations measure whether a model behaves safely across novel situations: following instructions without being sycophantic, refusing clearly harmful requests, not deceiving users about its nature, not pursuing goals when instructed not to. These are harder to define, harder to run comprehensively, and harder to know when they're saturated.
Anthropic's Responsible Scaling Policy defines "AI Safety Levels" (ASL-2, ASL-3, and so on) and says that crossing certain capability thresholds requires passing alignment evaluations before deployment. The practical tension: alignment evaluations are evaluated by the same organization deploying the model, creating a conflict of interest. Interviewers want to hear you name this tension, not just describe the policy. "What's the governance mechanism?" is the follow-up.
Unfaithful chain-of-thought means the reasoning steps a model writes out aren't actually what produced its final answer. The model may arrive at a conclusion through some other internal process and then generate a plausible-sounding rationalization after the fact. Lanham et al.'s 2023 Anthropic paper "Measuring Faithfulness in Chain-of-Thought Reasoning" tested this by truncating or subtly corrupting a model's stated reasoning and checking whether the final answer changed as much as it should if the model genuinely depended on those steps. In several cases it didn't change nearly enough.
The safety stakes: a common proposal for monitoring advanced models is to read their chain of thought as a window into intent. If the chain of thought is unfaithful, that monitoring gives false confidence, since the model's real reasoning process is hidden regardless of how transparent the written-out steps look. Interviewers for research roles want a candidate who can name this specific failure mode, not just define chain-of-thought prompting.
The distinction rests on consistency and context-sensitivity. Genuine incompetence should be roughly consistent across similarly difficult variations of a task, and it shouldn't correlate with whether the model has cues suggesting it's being evaluated versus deployed for real. Strategic deception would show up as a gap: better, safer-looking behavior specifically when evaluation signals are present, and different behavior when those signals are absent.
Hubinger et al.'s 2024 Anthropic paper "Sleeper Agents: Training Deceptive LLMs that Persist Through Safety Training" trained models with a deliberately backdoored behavior and found that standard safety training techniques, including RLHF and adversarial training, largely failed to remove it, and in some cases taught the model to hide the behavior better instead. Interviewers want a concrete evaluation design as the answer, held-out honeypot scenarios the model has no way to distinguish from real deployment, consistency checks across paraphrased versions of the same prompt, interpretability-based verification of internal state, rather than "we'd ask the model directly."
Strong answers describe a concrete path, not just a yes or no. First, get specific about what the disagreement actually is: a timeline concern, a gap in safety testing, or a genuine belief that the capability shouldn't exist yet at all are three different problems with three different responses. Second, raise it through the safety and team channels that own that risk, with specific evidence rather than a general unease. Third, be honest about what you'd actually do if the concern was heard and the project proceeded anyway.
Interviewers reportedly distrust both extremes: an immediate principled refusal with no attempt at internal escalation first, and an immediate compliance with no pushback at all. The middle path, where a candidate genuinely tries to change the outcome through the organization's own process before deciding what to do if that fails, is what they're listening for.
Real-time scenario questions
8A topological sort variant. Build a dependency graph and track each task's in-degree (number of unfinished prerequisites). Instead of a plain FIFO queue for tasks with satisfied dependencies, use a max-heap keyed on priority, so that whenever multiple tasks become runnable at the same time, the highest-priority one executes first. As each task completes, decrement the in-degree of its dependents and push any that reach zero onto the heap.
Candidates who reach for Kahn's algorithm immediately usually forget the priority ordering until asked. A cycle in the dependency graph means some tasks never reach in-degree zero, and the interviewer wants you to detect that (compare the number of scheduled tasks against the total) rather than silently returning a partial schedule.
import heapq
from collections import defaultdict
def schedule(tasks: list[str], deps: list[tuple[str, str]], priority: dict[str, int]) -> list[str]:
graph = defaultdict(list)
in_degree = {t: 0 for t in tasks}
for before, after in deps:
graph[before].append(after)
in_degree[after] += 1
heap = [(-priority[t], t) for t in tasks if in_degree[t] == 0]
heapq.heapify(heap)
order = []
while heap:
_, task = heapq.heappop(heap)
order.append(task)
for nxt in graph[task]:
in_degree[nxt] -= 1
if in_degree[nxt] == 0:
heapq.heappush(heap, (-priority[nxt], nxt))
if len(order) != len(tasks):
raise ValueError("Cycle detected in task dependencies")
return orderSpecifically reported as a common Anthropic system design question. The pattern here is a job queue (not a request queue), where each job consists of thousands of documents that need to be processed by a model. The key design considerations: job partitioning (split each job into chunks that fit a reasonable batch size), worker coordination (workers pull chunks from the queue, process them, and write results to an output store), fault tolerance (workers should be idempotent; a failed worker can be retried without duplicating results if you use chunk-level deduplication), and priority scheduling (some batch jobs are more time-sensitive than others).
Interviewers at Anthropic push specifically on the output delivery mechanism: do you push results to the caller, or do they poll? Polling is simpler but creates thundering-herd problems at job completion. Webhooks or long-polling via Server-Sent Events are the common alternatives, each with their own failure modes.
Reported directly from a 2025 onsite by a candidate who documented the question. The core design requires a request queue that buffers incoming prompts, a batching layer that groups requests by prompt length or deadline to maximize GPU utilization, and a fleet of GPU instances running the model. The batching strategy is where most of the real design work lives: static batching wastes capacity on requests that arrive at different times; dynamic batching (collect requests up to a max wait time or max batch size, whichever comes first) is the standard approach and is what vLLM implements by default.
At 100K RPS, load balancing must be aware of which GPU node has available KV cache capacity, not just CPU or network load. A node that has high GPU memory utilization from long-context requests shouldn't receive new requests even if it's otherwise healthy. Interviewers push specifically on this distinction: "how does your load balancer know the difference?" The answer involves heartbeat metrics from the inference workers reporting KV cache utilization alongside the standard health check.
Reported from a 2025 Anthropic onsite. The question was specifically about incorporating LLM inference into the search pipeline, not just keyword retrieval. The design involves an inverted index across sharded document stores, a query router that distributes the load, a caching layer for repeated queries, and an LLM re-ranking stage that takes the top-K keyword results and applies a smaller model to reorder them by relevance. The LLM re-ranking stage is the Anthropic-specific wrinkle: interviewers want to know how you prevent it from becoming the latency bottleneck (batch the re-ranking calls, cap the context window, use a smaller distilled model for this stage).
Follow-ups centered on hotspot prevention in the sharded index (consistent hashing with virtual nodes, or range-based sharding with overflow buckets) and cache invalidation when documents are updated. Interviewers also asked about how you handle queries that contain sensitive information and whether those queries should be logged at all.
The key design decisions: model routing (a metadata service maps model IDs to inference cluster endpoints, supporting A/B routing and canary deploys), GPU memory management (models can't all be loaded on every node; you need a model registry with eviction policies for less-frequently-used models), and autoscaling (trigger on queue depth, not on CPU, because CPU utilization during LLM inference tells you almost nothing useful).
For latency SLOs, the important design choice is where you set the timeout and what happens when you miss it. Interviewers want to see that you distinguish between P50 latency (easy to hit) and P99 latency (where the hard cases live). The tail latency problem for LLM inference is real: a very long prompt can block a batch slot and raise P99 for all other requests. Request pre-emption or prompt length caps are the two approaches. Both have costs. The interviewer wants to hear you name the trade-off, not just pick one.
This question bridges system design and Anthropic's core domain. The architecture involves a pre-response moderation step (classifier or smaller model that flags high-risk content before it reaches the user), a post-generation review for borderline cases, and an async audit pipeline for logging and analysis. The hard part is latency: running a full moderation model synchronously on every response adds hundreds of milliseconds. The mitigation involves distilled classifiers trained specifically for moderation speed, caching moderation results for repeated or near-identical prompts, and risk-tiering requests so that low-risk prompt categories skip the full moderation pipeline.
Interviewers push on failure modes: what happens if the moderation classifier has a false positive rate of 0.1%? At 100K RPS, that's 100 incorrectly blocked responses per second. The answer involves a human review queue for edge cases, a feedback loop to improve the classifier, and a grace period before auto-blocking. This is a real operational problem Anthropic solves.
At the scale of thousands of GPUs running for weeks, hardware failure isn't an edge case, it's the expected steady state. Meta's Llama 3 technical report (2024) documented 466 job interruptions across a 54-day training snapshot, the majority caused by GPU and host hardware issues rather than software bugs. A fault-tolerant checkpointing design needs frequent enough snapshots that a failure only loses a small amount of compute, asynchronous writes so checkpointing doesn't stall the training step, and a fast restart path that can resume from the last good checkpoint on a different set of nodes without re-deriving the entire data pipeline state from scratch.
The interesting design tension: checkpoint too often and the I/O overhead itself slows training measurably; checkpoint too rarely and a failure late in an interval wastes a lot of GPU-hours. Interviewers want you to reason about that tradeoff quantitatively, using failure rate and checkpoint write time as the two inputs, rather than just saying "checkpoint periodically."
Reported directly as a sample question in the Anthropic research scientist interview guide from interviewquery.com (2025). The core challenge: standard benchmarks test models on isolated tasks with clean inputs and defined outputs. Agentic systems interact with real environments over multiple steps, compound errors across turns, and encounter distributional shift that static evals don't capture.
A rigorous eval suite for agentic models would include: task completion rate across a distribution of environment states (not just the canonical starting state), error recovery rate (does the model recognize and correct mistakes mid-task?), boundary testing (does the model refuse to perform actions that violate its stated instructions or that the user hasn't authorized?), and adversarial user inputs (prompt injection attacks in tool responses, misleading feedback from the environment). Interviewers want to see that you think about evaluation as an ongoing process, not a one-time benchmark run.
Candidates who practice for Anthropic through LastRoundAI's mock sessions show a consistent pattern that preparation guides don't capture well. The failure mode that ends Anthropic loops most often isn't in the coding rounds, and it isn't in system design. It's in the values interview, specifically when candidates treat it like a behavioral interview and show up with rehearsed STAR stories.
The tell is when an answer is too clean. Real ethical dilemmas don't resolve neatly. When a candidate's answer about a values conflict has a clear arc, a villain, and a satisfying conclusion, interviewers flag it as performance. The candidates who get through the values round consistently say something surprising, something that reveals an actual uncertainty or an actual mistake, not a pre-packaged story about how they stood up for what was right.
The second pattern: Anthropic's system design interviewers expect you to connect design choices to safety concerns, not just to performance metrics. "I'd add a moderation layer" isn't enough. Interviewers want to hear what the moderation layer catches, what it misses, what the false positive rate is, and what you do when it fails. The company actually runs these systems. The interviewers know where the bodies are buried.

