Use Template

Opens this plan in Hirezen, where one click makes it a position.

AI Engineer interview questionsCoding — the call that has to degrade round

A 60 min interview plan with a time-boxed script, what each question is for, and the signals to score against. Key skills: Whether the candidate can write the code around a model call rather than the prompt inside it: validating output that is well-formed and still wrong, choosing a timeout against a request budget they did not set, keeping a page alive while the provider is down, and telling a finished answer from an interrupted one..

Setup and the first failure

16 min
What this section is for

Purpose

Runs in an editor against a stub, not on a whiteboard. Before the round, prepare a repository the candidate can run in the language they are strongest in: one function that takes a support ticket and returns a three-field summary by calling a model, a test that passes, and a local stub server standing in for the provider whose behaviour you control from a config file or a query parameter. The stub matters more than the starter code — you need to be able to make it return malformed JSON, a schema-valid refusal, a 503, a 429 with a Retry-After header, and a stream that stops mid-sentence, without editing the candidate's code or restarting anything. Send the repository 24 hours ahead with instructions to get it running and nothing else; a candidate spending the first ten minutes on their environment is a wasted round and tells you nothing. If they cannot run it, pair on your machine and say so in the debrief rather than scoring setup as engineering. The four sections are ordered by how much of the previous one they assume, so run them in order and stop where you stop — an honest three sections beats four rushed ones.

I'm [YOUR_NAME] and I build the model-backed features at [COMPANY_NAME]. The repository you have is real in shape and tiny in size. We are not going to write a prompt today. We are going to write everything around one.

What this section is for

Purpose

Sets the subject, and closes off prompt engineering as a place a candidate can spend the hour.

Talk while you work, run things whenever you want, and look anything up — I care about what you write, not what you remember. I will be changing the stub's behaviour underneath you as we go, and I will tell you when I do.

What this section is for

Purpose

Makes the tooling and the lookups explicitly allowed, and warns that the environment will change so a candidate does not spend minutes doubting their own code.

The function works against the happy path. Make it safe to put in front of a customer. Start wherever you think the biggest hole is, and tell me why that one.

What this question is for, and what to listen for

Purpose

Deliberately open. What they reach for first is the read — a candidate who starts by validating the model's output has the right instinct; one who starts by adding a try/catch around everything has a different one. Once they have something, switch the stub to return the fenced JSON, then the schema-valid refusal, in that order.

Signals to score

  • Validates the model's output against a schema at the boundary rather than trusting its shape
  • Treats a parse failure as an expected outcome with a policy, not as an exception to log
  • Handles the response that is wrapped in a code fence without reaching for a regular expression that assumes one
  • Notices the schema-valid refusal — every field present, the content an apology — and says schema validation cannot catch it
  • Proposes a check on the content itself for that case, and keeps it cheap
  • Does not retry with a byte-identical prompt at temperature 0 and expect a different result
  • If it re-asks, appends what was wrong to the next attempt, and bounds the number of attempts
  • Keeps the failure path returning the same type as the success path, rather than null or a thrown error the caller must know about
  • Puts the model call behind a boundary the rest of the code does not see through
  • Writes or extends a test for each failure as it appears, rather than testing by re-running by hand

Follow-up questions

  • Run it against the stub now. What does your code do with that?
  • Every field is there and the summary says the model cannot help. Which of your checks catches that?
  • You are retrying. What is different about the second attempt?
  • What does the caller of this function have to know about how it can fail?
  • If I changed the model tomorrow, which of these checks would I have to revisit?

The budget you did not set

14 min
What this section is for

Purpose

Give the numbers on the whiteboard or in a comment so they stay visible: this endpoint has a 10 second budget from the gateway, and the provider's own latency is p50 1.8s, p95 6.5s, p99 14s. The question is not what number they pick, it is whether they notice the budget is not theirs to spend all of and whether they know what a client-side timeout does and does not stop.

This function is called inside an HTTP handler. The gateway gives that handler 10 seconds, total, and the model call is not the only thing in it. Here is the provider's latency profile.

What this section is for

Purpose

Introduces a constraint from outside the code, which is where most production timeout mistakes come from.

Set the timeout. Then tell me what happens to the request that hits it, and what happens to the one after that.

What this question is for, and what to listen for

Purpose

Three separate reads in one question: the number, what a timeout actually cancels, and whether their retry policy makes the tail worse. The second is the one most candidates have never thought about.

Signals to score

  • Leaves room in the budget for everything else in the handler rather than setting the timeout at 10 seconds
  • Says what fraction of calls the chosen timeout kills, using the profile rather than guessing
  • Knows that abandoning the request does not stop the generation, and that the tokens are still billed
  • Distinguishes which errors are worth retrying — a 429 or a 503 — from which are not, and never retries a 400
  • Reads Retry-After when the stub sends one instead of using its own backoff
  • Notices that retrying a timeout inside the same request budget makes the tail worse, not better
  • Adds jitter, or explains why synchronised retries across instances are the failure they are avoiding
  • Raises idempotency if the surrounding code writes anything, or asks whether it does
  • Reaches for streaming as a way to change what the user experiences rather than what the p99 is
  • Separates the timeout on first token from the timeout on the whole response, if streaming

Follow-up questions

  • Your handler has 10 seconds. How much of it is this call allowed to have, and what has the rest?
  • You time out at 8 seconds. What is the provider doing at second 9?
  • The stub returns 429 with Retry-After: 30. What does your code do?
  • You retry once on timeout. What just happened to your p99?
  • Does this function write anything? Does the retry write it twice?

While it is down

16 min
What this section is for

Purpose

Switch the stub to 503 on every call before asking, and leave it there for the whole section. If the repository has a page or an endpoint that renders the summary, have it open so the candidate can see what the failure does to the surface a user is on — this section is much stronger when the breakage is visible rather than described.

The provider is returning 503 to everything. This is not a blip; assume it lasts eight minutes, and assume it will happen again next quarter.

What this section is for

Purpose

Rules out waiting it out, and rules out treating it as an incident rather than as a condition the code is expected to have an answer for.

A customer is on the page that shows this summary, right now, while it is down. What do they see, and what does your code have to do for them to see it?

What this question is for, and what to listen for

Purpose

The section the round exists for. A model call is the one dependency in most products that is expected to fail regularly, and the difference between a candidate who has run one and a candidate who has not is entirely in what they think the page does meanwhile.

Signals to score

  • The page still renders — the failure is scoped to the part of it that needed the model
  • Names the isolation mechanism concretely, rather than saying the error is handled
  • Puts something useful in the space: the raw ticket, the previous summary with the time it was made, or an honest empty state
  • Labels a stale value as stale rather than presenting it as current
  • Never surfaces a provider error string, a status code or a stack trace to a customer
  • Stops calling after a run of failures instead of sending every request into a dead provider
  • Says what the breaker costs when it is wrong, and how it closes again
  • Knows the queue of waiting requests is its own outage — their own latency dies before the provider comes back
  • Separates what the customer sees from what is logged and alerted on, and says who is paged
  • Distinguishes a feature that may degrade from one that may not, and asks which this is

Follow-up questions

  • Which part of the page is allowed to fail, and how does the rest of it not?
  • Show me what is in that space. What does the customer read?
  • You have 40,000 of these a day. How many requests do you send to a provider you know is down?
  • Your breaker opens by mistake on a slow afternoon. What did that cost?
  • What do you want to be told about this, and when — a page at 3am or a number in the morning?

The answer that stopped

14 min
What this section is for

Purpose

Set the stub to stream normally and then cut the connection mid-sentence, after enough tokens that the partial output reads like a real answer. If the candidate has not implemented streaming, describe it precisely instead of skipping the section — the question is about what a consumer can know, and it can be answered against code that does not exist yet. This section pairs with the caching round in the loop, and a candidate who connects them without prompting is worth noting in the debrief.

Streaming now. Six hundred tokens have reached the browser, the user is reading them, and the connection drops.

What this section is for

Purpose

Puts the partial output in front of a user before asking anything, so the answer cannot be purely server-side.

How does anything downstream know that is not the whole answer?

What this question is for, and what to listen for

Purpose

The question is epistemic rather than mechanical, and it catches an assumption almost everyone carries: that a stream ending means the response finished.

Signals to score

  • Says plainly that a closed connection and a finished response are indistinguishable without something that says which
  • Requires a terminal event or a finish reason from the stream, and treats its absence as a failure
  • Does not persist or cache a truncated answer as a completed one
  • Marks the partial result as partial wherever it is stored, if it is stored at all
  • Distinguishes the stream ending from the model stopping at a length limit, which is a different problem with the same symptom
  • Tells the user the answer was cut off rather than letting it trail away
  • Prefers re-asking over resuming, or justifies resumption with what it would cost to build
  • Notices that this interacts with anything that reuses answers, and says so
  • Asks what the consumer is — a browser, a queue, another service — before deciding what it needs to know
  • Keeps the completed-or-not decision in one place rather than in every consumer

Follow-up questions

  • The connection closed. Does that mean the answer finished?
  • Where does those six hundred tokens end up, and is it marked as anything?
  • The model stopped because it hit its length limit instead. Same symptom — how would you tell?
  • Would you resume it or ask again? What does resuming cost you to build?
  • Does anything else in this system reuse stored answers?

AI Engineer interviews — common questions

Who is this AI Engineer interview plan for?
It is written for the interviewer, not the candidate: the hiring manager, engineer or panel member running the Coding — the call that has to degrade round for a AI Engineer role. It gives you a 60 min script to follow in the conversation — 4 questions with what each one is for and the signals to score against — so you are not writing the round from scratch the night before.
What does the Coding — the call that has to degrade round assess?
This round is focused on: Whether the candidate can write the code around a model call rather than the prompt inside it: validating output that is well-formed and still wrong, choosing a timeout against a request budget they did not set, keeping a page alive while the provider is down, and telling a finished answer from an interrupted one.. It works through Setup and the first failure, The budget you did not set, While it is down and The answer that stopped, scoring against 40 observable signals, with follow-up prompts on all 4 questions for going deeper where an answer is thin.
How is the 60 min split up?
Setup and the first failure (16 min), The budget you did not set (14 min), While it is down (16 min), The answer that stopped (14 min). The timings are there so the round stays on schedule and every candidate gets the same shape of interview — which is what makes two candidates comparable afterwards.
What other rounds should I run for a AI Engineer?

A single round does not cover a whole role. The other rounds in this library for a AI Engineer: