Home › Interviews › EPAM
EPAM Gen AI interview questions & answers
Real EPAM interview experience for the Senior AI / LLM Engineer role. Process: a phone screening, a system design round, a hands-on coding round, and a final managerial discussion.
Part 1 — Technical Round 1 (System Design, Async Agents, LangGraph, MCP)
You have a lot of incident data in a database. How will you manage it so that execution is fast and RAG retrieval has low latency?
Sure. First, I will partition the incident table — by time window, like monthly or weekly, and by severity, like critical, high and low. So heavy reads and writes are isolated and we avoid full table scans. Second, indexing — I will create a composite B-tree index on the columns we filter most, like incident ID, timestamp and severity. Third, hybrid storage for RAG. Structured data like status, assigned team and timestamps stays in PostgreSQL with partitions. The raw incident logs and post-mortem documents go into a vector database, or pgvector, with metadata like incident ID and created date. So during RAG analysis, we can filter first and then do a fast, targeted semantic search.
How will you run them in parallel? And if one agent crashes, how will you make sure the other two are not affected?
I will use Python asyncio. I can use asyncio.gather or a TaskGroup to run all three agents together on the event loop, so total time is much less than calling them one by one. For failure isolation, I wrap each agent's logic in its own try-except. And the important part is return_exceptions equal to True in asyncio.gather. With that, if agent B throws an exception or a timeout, gather does not cancel agent A and agent C. It just returns the exception object for B, and normal results for A and C. Then I loop over the results — if it is an exception, I log it and add a fallback response; otherwise I use the result.
How will you design a retry mechanism for agent execution?
I will keep a retry counter with exponential backoff and jitter. If the agent fails because of a 429 rate limit or a 5xx server error, I wait and retry. The delay doubles every time — 1 second, 2 seconds, 4 seconds — and I add a small random jitter so all retries don't hit at the same time. Once max retries is reached, I stop and return a structured fallback response, or move the workflow to an error state.
What is the main difference between a chain and an agent?
A chain is hardcoded. The steps are fixed — step A, then step B, then step C. The LLM is used only for some transformation or extraction at specific steps. An agent is dynamic. The LLM acts like a reasoning engine — it looks at the input, decides which tool to call, checks the tool output, and decides the next step by itself, until the goal is complete.
How is state managed in LangGraph?
In LangGraph we define one central state schema, using a TypedDict or a Pydantic model. All nodes in the graph can read this state. Each node gets the current state, does its work, and returns a dictionary with only the fields it wants to update. And we can use reducers on some fields — for example, operator.add on the messages list, so new messages are appended and not overwritten. So the state moves forward in a controlled way as the graph goes from node to node.
Why is FastAPI preferred for Gen AI agent backends? And where does Pydantic fit?
FastAPI has native async and await support, built on Starlette. So it handles non-blocking I/O very well, which we need for token streaming and long-running LLM or tool calls. Pydantic is used by FastAPI to validate the incoming JSON request and the response schema automatically. And in LLM backends, we also use Pydantic to enforce structured outputs — like tool schemas and function calling signatures.
What is MCP, and how does the integration work?
MCP is Model Context Protocol, an open standard from Anthropic. It standardizes how LLM clients connect to tools and data sources, like databases, search tools and enterprise apps. It is a client-server architecture. The MCP server exposes tools, prompts and resources using JSON-RPC, over standard input-output or server-sent events. The client, like Claude Desktop or our own agent, connects to the server, discovers what is available, and calls it. So we don't need to write a custom wrapper for every data source.
Explain temperature, top-p and top-k.
Temperature scales the logits before softmax. Near zero, it is greedy — always the highest probability token, so output is deterministic. High temperature flattens the distribution, so more variety and creativity. Top-K keeps only the top K most likely tokens and removes the rest. Top-P, nucleus sampling, keeps the smallest set of tokens whose total probability reaches P, like 0.9. So the pool becomes bigger or smaller depending on how confident the model is.
How does an LLM understand a word with multiple meanings? Like "bank" of a river and a money "bank."
Because of self-attention. Older methods like Word2Vec gave one fixed embedding for "bank." But in a transformer, every token looks at every other token in the sentence. Using query, key and value, the representation of "bank" changes based on the words around it. If nearby words are river, water, mud — it means river bank. If nearby words are money, deposit, interest — it means the financial bank.
How do you detect and handle hallucinations in an agentic system?
Four ways. One, grounding check — verify the generated claims against the retrieved documents using an entailment model or an evaluation tool like RAGAS or DeepEval. Two, a verification node in LangGraph — a separate step that checks the tool outputs against the generated text before the final answer. Three, strict system prompt — if the fact is not in the context, the model must say "I don't know." Four, self-correction — if a hallucination is detected in a middle step, we send the error back to the agent and ask it to regenerate with strict constraints.
Part 2 — Technical Round 2 (Live Coding)
Given an integer as a string, n, find the nearest palindrome number, but not n itself. Nearest means smallest absolute difference. If there is a tie, return the smaller number.
Okay. Checking every number up and down will be too slow for big numbers, so I will generate a small set of candidates. First, two boundary candidates for when the number of digits changes. For example, for 100 the answer can be 99, and for 99 the answer can be 101. So I add 10 to the power length-minus-one, minus 1 — that is like 99 — and 10 to the power length, plus 1 — that is like 101.
Follow-up: And the main candidates?
I take the first half of the number as the prefix. Then I try prefix minus 1, prefix, and prefix plus 1. For each, I mirror it to make a palindrome. If the length is even, I mirror the full prefix. If the length is odd, I mirror it without the middle digit. That gives me three more candidates.
Follow-up: Test it with some cases.
For 123, the answer is 121. For 1, the answer is 0. For 10, the answer is 9. For 88, the answer is 77 — because 77 and 99 are both 11 away, and in a tie we return the smaller one. For 1001, the answer is 999. The time is very fast, because we only check around five candidates.
Part 3 — Managerial & Offer Discussion
At EPAM, a senior engineer also works closely with clients. How do you prepare for that?
Sir, I always try to connect system design with the client's business need. In my answers I talk about trade-offs — cost, latency and reliability — and I explain the full SDLC, from requirement to design, development, testing, deployment and monitoring. I am comfortable explaining architecture to both technical people and business people.
Preparation tips
- Master async concurrency — asyncio.gather, return_exceptions, retries with backoff — they asked it live in system design.
- Know exactly how state works in LangGraph — TypedDict, state channels and reducers.
- Be ready to switch from system design to classic coding — the nearest palindrome question came in the coding round.