dev.to

I Built My Friend a Mock Interviewer That Read His Rust Code

친구의 Rust 코드를 읽고 질문하는 모의 면접 도구를 만들었습니다

grill은 저장소에서 면접 질문거리를 찾아 로컬 모델로 질문하고 답변을 채점하는 터미널 도구입니다. 정규식 기반 코드 스캐너와 Gemma, Ollama를 조합해 코드와 취약한 답변을 노트북 안에 보관합니다.

AI 요약

grill은 친구 Akash의 Rust와 TypeScript 코드에서 면접 질문거리를 찾아 실제 코드 맥락을 짚으며 질문하는 터미널 도구입니다. 일반적인 면접 준비 도구가 클로저나 소유권 같은 교과서 질문을 내는 데 그친다면, grill은 프로젝트를 설명하는 과정에서 특정 코드 줄을 지목하는 기술 면접을 연습하도록 설계했습니다. 공개 저장소뿐 아니라 로컬 경로도 가져올 수 있어, 외부에 올릴 수 없는 코드도 대상으로 삼습니다.

코드에서 질문거리 찾기

스캐너는 Rust 패턴 17개와 JavaScript·TypeScript 패턴 21개, 총 38개를 정규식으로 검사합니다. Rust의 잠금과 수명, unsafe 블록, JavaScript의 비동기 루프와 useEffect, 빈 catch 블록 등이 대상입니다. 패턴마다 주제와 가중치, 면접관이 살펴볼 관점을 지정합니다. 예를 들어 잠금 패턴에는 guard가 얼마나 오래 살아 있는지, await를 건너 잠금을 쥐고 있는지, 잠금 경합이나 poisoning을 어떻게 다루는지 묻도록 설정합니다.

정규식이 걸린 한 줄만 질문에 넘기지는 않습니다. 스캐너가 바깥 함수의 시작과 끝을 찾아 함수 전체를 질문 맥락으로 잡습니다. 점수를 함수별로 합산하고 겹치는 범위는 더 강한 항목을 남깁니다. 저장소마다 점수가 높은 지점 40개를 고르되 주제를 돌아가며 뽑아, unwrap()이 많은 코드가 오류 처리 질문으로만 채워지지 않게 합니다. 다만 이 방식은 파서가 아니라 정규식과 중괄호 계산에 의존합니다. 흥미로운 코드를 찾을 뿐, 코드의 의미를 이해하지는 않습니다.

작은 모델에 일을 나눠 맡기기

실행 흐름은 TypeScript 코드가 관리합니다. 4B 모델에 면접 전체를 계획하거나 여러 차례 대화를 기억하라고 요구하지 않습니다. 모델은 질문 작성, 후속 질문 작성, 답변 채점이라는 작은 작업만 맡습니다. 매번 관련 코드 조각을 다시 전달해 모델이 코드를 기억하는 과정에서 내용을 지어낼 여지를 줄입니다.

면접관과 채점자는 Mastra의 별도 에이전트로 구성합니다. 면접관은 질문을 하나만 하고 코드 조각 안의 식별자를 언급하며, 답을 알려주거나 힌트를 주지 않도록 지시받습니다. 채점자는 질문을 만든 에이전트와 분리해 답변을 점수 0~4, 한 문장 평가, 놓친 지점, 더 나은 답변이 담긴 JSON으로 평가합니다. 작은 모델이 JSON 바깥에 설명이나 코드 펜스를 붙이는 경우를 고려해 첫 번째 균형 괄호 객체를 추출하고 Zod로 검증합니다. 검증에 실패하면 잘못된 응답을 모델에 보여준 뒤 한 번 더 요청합니다.

기본 모델은 Ollama로 로컬에서 실행하는 Gemma입니다. Mastra는 OpenAI 호환 엔드포인트에 연결하므로 별도 제공업체 SDK나 API 키가 필요하지 않습니다. 선택 기능인 read_source 도구를 켜면 면접관이 호출 위치나 타입 정의 같은 주변 코드를 읽습니다. 저장소 바깥으로 벗어나는 경로는 거부하며, 도구 호출을 지원하는 모델이 필요해 기본 설정에서는 꺼져 있습니다.

취약한 주제를 다음 세션에 반영

각 라운드는 ~/.grill/sessions 아래 JSON으로 저장합니다. 다음 세션은 주제별 평균 점수를 바탕으로 약한 항목을 더 자주 고릅니다. 우선순위는 코드 지점 점수의 제곱에 취약도 가중치를 곱하고, 이미 질문한 항목에는 낮은 반복 계수를 적용하는 방식입니다. 점수 1을 받은 수명 주제는 다시 등장할 가능성이 커지고, 점수 4를 받은 unsafe 주제는 빈도가 줄어듭니다. 이미 질문한 항목도 완전히 제외하지 않습니다. 같은 질문을 다시 받아야 학습 여부를 확인할 수 있기 때문입니다.

로컬 실행과 테스트

프로젝트는 테스트를 포함해 TypeScript 약 1,300줄이며, 실행 의존성은 세 개이고 MIT 라이선스를 사용합니다. 사용자는 Ollama에서 gemma3:4b를 받은 뒤 저장소를 빌드하고, grill ingest로 저장소를 등록합니다. grill start는 기본 다섯 문항을 진행하며, 옵션으로 질문 수와 언어를 지정합니다. grill report는 취약한 주제를 보여줍니다.

테스트는 GPU나 실제 모델을 요구하지 않습니다. 임의의 로컬 포트에서 가짜 OpenAI 호환 서버를 띄우고 실제 Mastra 에이전트를 연결해 한 라운드, JSON 재시도, 건너뛰기와 종료, 경로 탈출을 막는 도구 호출을 확인합니다. 전체 테스트 18개는 몇 초 안에 끝납니다.

로컬 모델을 택한 이유와 한계

저자는 오픈 모델을 로컬에서 돌리는 선택이 Akash에게 세 가지 실용적 이점과 모델 변경의 자유를 준다고 설명합니다. 틀린 답변 기록은 사용자 컴퓨터에 남고, NDA 코드나 아직 공개하지 않은 저장소도 외부로 보내지 않고 연습할 수 있습니다. 질문마다 모델 호출이 세 번 필요하고 세션마다 다섯 질문을 진행하므로, 과금형 API를 쓰면 연습량에 따라 비용도 늘어납니다. 면접 기준은 프롬프트를 수정해 바꿀 수 있으며, 환경 변수로 더 큰 모델이나 다른 로컬 엔드포인트를 지정할 수 있습니다.

저자는 스캐너가 의도적인 unwrap()과 부주의한 unwrap()을 구별하지 못하고, 질문 품질은 모델에 달렸다고 밝힙니다. 채점 결과도 판정이 아니라 학습 보조 자료이므로 숫자보다 missed 목록을 읽으라고 안내합니다. 프로젝트 소개에는 Gemma와 Mastra를 활용한 사례로 Hacktoberfest Weekend Challenge 제출작이라는 점도 담겼습니다.

원문: dev.to / 번역·요약: Trawling