Agentic · Human-in-the-loop

Interview Agent

A stateful interviewer that pauses for each answer, scores it and gives feedback.

Last commit
Apr 2025
Stack
  • LangGraph
  • Gemini 2.0 Flash
  • SQLite checkpointer
  • MongoDB
  • FastAPI
  • React
  • MUI

Problem

Mock interviews need someone to choose suitable questions, judge answers and give constructive feedback. The agent does that for a chosen role, holding a multi-turn session that waits for a human between steps and adapts the next question to recent performance.

Architecture

start interviewselect questionask questionawait answeranalyze + scoregenerate feedbackprovide feedbackupdate state
start interviewselect questionask questionawait answeranalyze + scoregenerate feedbackprovide feedbackupdate state

Each turn pauses at “await answer”; the API resumes the graph with the candidate’s reply, and the loop continues until the planned number of questions is reached or the bank runs out.

  • POST /interview/start and POST /interview/{session_id}/submit_answer; the session id is the graph thread id.

  • Checkpointerapi.py:64-67

    AsyncSqliteSaver persists graph state between requests.

  • Question bankdatabase.py

    Role-specific questions with topic and difficulty, loaded from MongoDB.

  • React + MUI clientInterview.js

    Pick a role, answer each question, see feedback alongside.

Key decisions

  • Human-in-the-loop with interrupt()

    The graph pauses with interrupt() at each question and resumes with Command(resume=answer) on the same thread, with state saved in SQLite between HTTP calls.

    nodes.py:110-123
  • LLM picks from a bank, and its choice is validated

    Given recent turns and the remaining pool, the LLM returns a question id or decides to end; the id is checked against the pool and removed once asked.

    llm_helpers.py:97-120
  • One call for analysis and scoring

    A single prompt returns relevance, clarity, technical accuracy and sentiment plus a score out of 10, strengths and improvements; required keys are checked.

    llm_helpers.py:130-215
  • Explicit terminal states and caps

    Status is a typed literal; a failed LLM step terminates cleanly, and the router enforces the planned question count regardless of the LLM.

    nodes.py:249-273

In action

From the repo: a short run through the interview UI.

Run it

APIuvicorn agent.api:api
Clientcd frontend && npm start