AI Interview interview questions
A model can be converted into a browser-friendly format and loaded using a library such as TensorFlow.js, which runs inference directly in JavaScript, optionally accelerated by the device's GPU through WebGL. This avoids a round trip to a server for every prediction and keeps user data on the device, though it is generally limited to smaller models, since browser memory and compute are far more constrained than a dedicated server.
Typically the Node server holds the API key securely and exposes its own endpoint that the front end calls, which then forwards the request to the AI provider's API using a library like fetch or an official SDK, and returns the result back to the client. Keeping the key on the server rather than in front-end code prevents it from being exposed to anyone inspecting the browser's network requests.
Many AI providers support a streaming response format, where the answer arrives in small chunks as it is generated rather than all at once. The Node server can read this stream and forward each chunk to the browser as it arrives, commonly using server-sent events or a chunked HTTP response, letting the front end display words appearing progressively instead of a long silent wait followed by the full answer.
Since JavaScript in the browser runs on a single main thread, a slow request should always be made asynchronously with fetch and await rather than any blocking call, which does not exist for network requests anyway. Showing a loading indicator, disabling the relevant button, and letting the rest of the page remain responsive while the request is in flight keeps the experience usable even when the AI response takes several seconds.
Identical or very similar prompts can be cached, keyed by a hash of the request, using something like an in-memory cache for a single server instance or a shared cache like Redis across multiple servers. Caching is especially effective for AI features where many users ask the same common questions, since it avoids paying for and waiting on a fresh generation every single time.
A rate limiter, either a simple token bucket implemented in memory or a shared one backed by Redis for a multi-server setup, can track how many requests a user or the whole application has made in a given time window and reject or queue requests once a limit is reached. This protects against runaway costs, respects the AI provider's own rate limits, and helps ensure fair usage across all users.
Documents are first converted into vector embeddings using an embedding model and stored in a vector database or a simple in-memory index. When a user asks a question, that question is also embedded, the most similar stored documents are retrieved by comparing vectors, and those retrieved snippets are included alongside the question in the prompt sent to the language model, grounding its answer in the actual source material rather than relying purely on its training data.
A WebSocket keeps a persistent, two-way connection open, which suits scenarios needing frequent back-and-forth updates, such as a live collaborative AI assistant or real-time status updates during a long-running generation. For a single request and a single response, even a streamed one, a plain HTTP request is usually simpler to implement and sufficient, reserving WebSockets for cases where the server also needs to push unsolicited updates to the client.
Running inference on the client, such as in the browser with TensorFlow.js, avoids server costs and keeps data local, but is limited to smaller models and depends on the user's device capability. Running inference on the server allows much larger, more capable models and centralized control over versioning and monitoring, but adds network latency, ongoing infrastructure cost, and requires careful handling of user data sent to the server.
Wrapping calls with a retry strategy that uses backoff between attempts handles transient failures, while a circuit breaker can temporarily stop sending requests to a provider that is clearly failing repeatedly, avoiding piling up more failing requests. A sensible timeout, a fallback response or cached result for when the provider is unavailable, and clear logging of failures all help keep the rest of the application stable even when the AI dependency is not.
If the API supports streaming, chunks of the response can be displayed as they arrive, which is the smoothest experience for something like a chat response. When streaming is not available, a progress indicator, an estimated time remaining, or intermediate status messages such as "analyzing your request" give the user useful feedback and reduce the perceived wait, even though the actual result only appears once the whole operation finishes.
Useful signals include request latency and its distribution rather than just the average, error rates broken down by type such as timeouts versus rate limits, token usage and cost per request, and cache hit rates if caching is in place. Alerting on a sustained spike in errors or latency lets a team catch a struggling AI provider or a runaway cost issue before it becomes a bigger problem.
The endpoint should validate and sanitize the incoming input, apply a reasonable length limit, attach the API key on the server rather than trusting anything from the client, enforce authentication and rate limiting on who can call it, and catch errors from the provider to return a clean, generic error message rather than leaking internal details or the raw provider response back to the caller.
Sensitive fields should ideally be detected and stripped or masked before ever being sent to a third-party AI provider, and the application should clearly disclose what data is sent and how it might be used or retained. Logging on the server should avoid capturing full prompts containing sensitive data, and access to any stored logs or transcripts should be restricted, since a data leak through an AI feature is still a data leak.
The AI API call is typically mocked in automated tests, returning fixed, predictable sample responses so the surrounding logic, such as parsing, error handling and rendering, can be tested reliably without depending on the real network call or its inherent variability. Separately, a smaller set of manual or scheduled integration tests against the real API helps catch cases where the provider's actual behavior has drifted from what the mocks assume.