ai-interview-caller / src /interview_agent.py
ranjithkumar111's picture
Upload 8 files
b253d7e verified
Raw
History Blame Contribute Delete
5.01 kB
# File: src/interview_agent.py
# Purpose: Stateful LLM interview agent using Groq (llama-3.3-70b-versatile)
from typing import List, Dict, Optional
from groq import Groq
from config import (
GROQ_API_KEY, GROQ_LLM_MODEL, LLM_TEMPERATURE, LLM_MAX_TOKENS,
MAX_QUESTIONS, INTRO_MESSAGE
)
from src.resume_rag import retrieve_resume_context
_groq = Groq(api_key=GROQ_API_KEY)
SYSTEM_PROMPT = """You are an expert AI technical recruiter conducting a structured phone interview.
Your job is to:
1. Ask one clear question at a time — never ask multiple questions together.
2. Listen carefully to the candidate's answer, identify skills and technical depth.
3. Ask a natural follow-up if the answer is vague or incomplete.
4. Move to the next planned question when the current topic is sufficiently explored.
5. Keep a professional, warm, and encouraging tone.
Rules:
- Never reveal you are evaluating the candidate.
- Do not provide hints or correct the candidate.
- Keep responses under 3 sentences.
- If the candidate is off-topic, gently redirect.
"""
BASE_QUESTIONS = [
"Can you start by giving me a brief overview of your background and what you've been working on recently?",
"What is the most technically challenging project you have worked on, and what was your specific contribution?",
"How do you approach debugging a model that is underperforming on a validation set?",
"Describe your experience with deploying machine learning models to production.",
"How do you handle class imbalance in a classification problem?",
"What is your experience with version control and collaborative development?",
"Where do you see yourself growing technically in the next year?",
]
class InterviewAgent:
def __init__(
self,
session_id: int,
candidate_name: str,
resume_skills: List[str],
use_rag: bool = True,
):
self.session_id = session_id
self.candidate_name = candidate_name
self.resume_skills = resume_skills
self.use_rag = use_rag
self.history: List[Dict[str, str]] = []
self.question_index = 0
self.turn_count = 0
self.is_complete = False
self._build_question_plan()
def _build_question_plan(self):
personalised = []
for skill in self.resume_skills[:3]:
personalised.append(
f"I noticed your experience with {skill}. Can you walk me through a specific project where you used it?"
)
self.questions = (personalised + BASE_QUESTIONS)[:MAX_QUESTIONS]
def _get_resume_context(self, last_answer: str) -> str:
if not self.use_rag:
return ""
return retrieve_resume_context(self.session_id, last_answer)
def get_next_ai_message(self, candidate_answer: Optional[str] = None) -> str:
if candidate_answer is not None:
self.history.append({"role": "user", "content": candidate_answer})
self.turn_count += 1
if self.question_index >= len(self.questions):
self.is_complete = True
closing = (
f"Thank you so much, {self.candidate_name}. That concludes our screening interview. "
"The hiring team will review your responses and reach out with next steps. "
"Have a great day!"
)
self.history.append({"role": "assistant", "content": closing})
return closing
resume_ctx = ""
if candidate_answer:
resume_ctx = self._get_resume_context(candidate_answer)
next_question = self.questions[self.question_index]
system_with_context = SYSTEM_PROMPT
if resume_ctx:
system_with_context += f"\n\nRelevant resume context:\n{resume_ctx}"
system_with_context += f"\n\nNext planned question: {next_question}"
system_with_context += (
"\n\nIf the last answer was incomplete, ask a short follow-up first. "
"Otherwise transition naturally and ask the next planned question."
)
messages = [{"role": "system", "content": system_with_context}] + self.history
response = _groq.chat.completions.create(
model=GROQ_LLM_MODEL,
messages=messages,
temperature=LLM_TEMPERATURE,
max_tokens=LLM_MAX_TOKENS,
)
ai_text = response.choices[0].message.content.strip()
if candidate_answer is not None:
self.question_index += 1
self.history.append({"role": "assistant", "content": ai_text})
return ai_text
def get_full_transcript(self) -> List[Dict[str, str]]:
transcript = []
for msg in self.history:
speaker = "AI" if msg["role"] == "assistant" else "Candidate"
transcript.append({"speaker": speaker, "text": msg["content"]})
return transcript