지난 글은 “다음 글에는 무엇을 더 붙였는지보다, 써보니 무엇이 도움이 됐고 무엇이 필요 없었는지를 적고 싶다”로 끝났다. 이번 글이 그 글이다.

장면은 미리 정해 둔 대로다. 프로필 하나와 공고 세 개를 넣고, 결과를 본 사람이 지원 우선순위를 정할 수 있는지 본다. 확인할 것은 세 가지다.

  1. 왜 지원할 만한지, 넘길 만한지 근거를 따라갈 수 있는가?
  2. 읽기 전에는 몰랐던 차이나 확인할 질문이 생겼는가?
  3. 같은 자료를 일반 채팅에 붙였을 때보다 편한가?

프로필은 측정용으로 만들어 둔 합성 이력서다. 공고는 한 국내 이커머스 기업의 채용 페이지에서 세 개를 골랐다. 이 페이지는 앱이 URL로 읽을 수 있는 채용 보드가 아니라서 본문을 텍스트 파일로 옮겼고, 지원 절차 같은 상용구는 잘랐다. 엔지니어링 매니저, 플랫폼 아키텍처, 머신러닝 엔지니어 공고 하나씩이다. 두 번째는 제목이 백엔드 엔지니어인데 본문은 웹·모바일 클라이언트 아키텍처 역할이라, 이 글에서는 플랫폼 아키텍처 공고라고 부른다. 현재 프론트엔드 제목의 공고가 없어서, 그럴듯한 후보 하나와 범위가 다른 후보 둘을 섞은 셈이 됐다.

모델은 OpenRouter의 무료 모델을 썼다. 실행은 PR #18의 실행기로 했다. 승인 플래그 없이 한 번 돌려 어디로 무엇이 전송되는지 확인하고, 키를 넣고, 승인 플래그를 붙여 돌렸다. 전송된 것은 합성 이력서와 공개 공고뿐이다. 이 글은 병합 직전에 쓴 기록이고, 구현은 Claude Code가, 리뷰는 Codex가 맡았다.

첫 실행은 판정이 아니라 도구에서 멈췄다

첫 실행은 프로필 추출 단계에서 끝났다. 모델이 아니라 실행기가 문제였다. 실행기는 실제 MCP 도구를 MCP TypeScript SDK의 클라이언트로 호출하는데, 그 클라이언트의 기본 요청 제한이 60초다. 첫 실행에 쓴 무료 모델의 추출 한 번이 그보다 오래 걸렸고, 클라이언트는 포기했다. 호출은 클라이언트와 상관없이 계속되므로 결과가 오더라도 버려진다. 실행기 로그에는 그 뒤에 무엇이 왔는지 남지 않았지만, 제공자 대시보드의 호출 기록에는 그 요청이 출력 618토큰으로 완료된 것으로 적혀 있었다.

지난 글들에서 만든 측정 도구는 추천 배치의 90초 예산을 재는 것이었다. 도구 호출 하나가 클라이언트 쪽 제한에 걸리는 경우는 재지 않았다. ChatGPT 호스트에도 자체 제한이 있을 텐데, 그 값은 아직 모른다.

실행기의 호출 제한을 5분으로 넓히고, 호출마다 걸린 시간과 모델 응답의 종료 상태·토큰 수·실제 처리 엔드포인트를 기록하게 고쳤다. 추가한 텔레메트리 로그에는 입력·응답 본문을 넣지 않았다. 결과 파일에는 구조화된 프로필과 공고, 판정이 저장된다. 그다음부터는 실패해도 왜 실패했는지 읽을 수 있었다.

무료 모델 네 개 중 하나가 답했다

OpenRouter의 공개 모델 메타데이터로 보면 무료 모델 22개 중 구조화 출력을 지원한다고 표시된 것이 6개였다. 그중 네 개를 같은 입력으로 돌렸다.

모델 결과
nemotron-3-super 125초 뒤 상위 엔드포인트가 오류로 종료. 제공자가 보고한 추론 토큰 116개, 본문 없음
nex-n2.5-pro 5분이 지나도 응답 없음. 제공자 대시보드에는 그 뒤 출력 31,045토큰으로 완료된 기록이 있었다
lfm-2.5-2.6b 응답은 오지만 출력 상한 8천 토큰에 추출과 판정이 잘림. 판정 0건
dots-3-note-preview 세 공고 중 두 개 판정 완료

오류나 잘린 응답은 판정 결과로 받아들이지 않았다. 지난 PR에서 응답을 다시 검증하고 형식에 맞지 않으면 닫히게 만든 것이 여기서 일을 했다. 하지만 형식을 통과한 결과에도 요건 오독과 사실 오류는 남았다. “무료 모델을 쓸 수 있다”와 “무료 모델로 이 앱을 쓸 수 있다”가 다른 문장이라는 것도 같이 확인됐다.

동작한 모델에서 걸린 시간은 이랬다. 프로필 추출 28초, 공고당 추출 29~60초에 판정 67~81초. 공고 하나에 2분 안팎이다. 엔지니어링 매니저 공고는 추출이 5분 안에 끝나지 않았다. 응답은 요청 시작 약 515초 뒤, 잘린 상태로 도착했고, 제공자가 보고한 토큰 수는 출력 65,536(이 엔드포인트의 출력 상한), 추론 93,504였다. 추론 토큰이 출력 토큰보다 크게 기록돼 있어 이 값을 합산하거나 실제 사용량으로 확정하지는 않았다(추론 토큰 안내). 시간과 토큰 모두 이 엔드포인트의 값이고, 다른 제공자에 대해서는 아무것도 말해 주지 않는다. 실행기가 기록한 입력·출력 토큰 수는 제공자 대시보드의 호출별 기록과 건마다 일치했고, 비용 항목은 모두 0으로 표시됐다.

앱이 내놓은 것

플랫폼 아키텍처 공고는 PASS, 확신 high였다. 화면에 표시된 근거 세 개는 이력서 문장을 그대로 옮겼고, 정책 검사도 통과했다. 그런데 PASS의 이유가 된 차단 사유는 “데이터 모델, API, 이벤트 계약, 캐시, 분산 시스템의 기본 원리를 이해하고 서버 엔지니어와 함께 클라이언트와 서버의 책임 및 시스템 경계를 설계하실 수 있는 분”이라는 요건이었다. 모델은 이것을 백엔드 엔지니어링과 분산 시스템의 직접 경험 요구로 읽고 결격으로 올렸다. 요건이 말하는 것은 기본 원리의 이해와 협업 설계이지 직접 경험이 아니라고 나는 읽었고, 제목이 백엔드 엔지니어였던 것에 끌려간 것으로 보였다. 다만 이 부분은 내 해석이다.

추천 문장은 “stretch” 한 단어였다. 점수는 0.65였다. 스키마는 0에서 100 사이를 받으니 형식은 통과했지만, 100점 기준의 낮은 점수인지 0에서 1 척도로 답한 것인지 결과만으로는 구분하기 어려웠다.

머신러닝 엔지니어 공고는 PASS, 확신 high였고, 이건 타당해 보인다. 경력 서사 위험이 high로 나왔고, 확인 질문은 영어 한 문장이었는데 줄여 옮기면 “프론트엔드 배경에서 왜 이 역할에 지원하는지, 개인 프로젝트 경험이 5년의 전문 경험 요구를 어떻게 대신하는지”였다. 채용 담당자가 물을 법한 질문이다.

서류 검토 맥락에서 역할 수준 비교는 두 공고 모두 uncertain이었다. 지난 M4-B2에서 근거 위치를 검증하는 층을 두었는데, 이 모델이 인용한 위치가 그 검증을 통과하지 못해 검증기가 설계대로 판단을 낮췄다. 경력 서사에서는 플랫폼 아키텍처 공고가 uncertain으로 내려간 반면, 머신러닝 공고에는 위험 설명과 확인 질문이 검증을 지나 화면에 남았다.

가장 눈에 띈 것은 따로 있었다. 플랫폼 아키텍처 공고의 본문에는 고용주 이름이 없는데, 추출 결과에는 실제로 존재하는 다른 기업의 이름이 들어 있었다. 모델이 본문에 없는 고용주 이름을 만들었고, 현재 스키마는 이를 막지 못했다. 프롬프트는 “고용주를 지어내지 말라”고 하고 스키마는 고용주 이름을 필수 문자열로 요구하는데, 그 조합이 원인인지는 따로 확인해야 한다. 머신러닝 공고에서는 같은 모델이 “본문에 명시되지 않음”이라고 답했으니, 매번 그러는 것도 아니다. ‘정보 없음’을 명시적으로 표현할 수 있도록 바꿔 보려 한다.

세 질문에 답하면

아래는 결과 화면과 저장된 결과 파일을 읽고 적은 잠정 평가다. 라운드를 더 돌린 뒤의 사용 소감과는 구분해서 읽어야 한다.

근거를 따라갈 수 있는가. 절반은 그렇다. 근거 문장과 결격 사유가 요건 ID와 함께 나오니, 왜 PASS인지는 읽을 수 있었다. 그리고 근거를 읽으니 내가 동의하기 어려운 요건 해석이 어디서 나왔는지 확인할 수 있었다. 일반 채팅과 같은 입력으로 직접 비교하지는 않았다. 다만 근거와 요건을 나란히 보여줘 판정 이유를 되짚기 쉬웠고, 동의하기 어려운 판정을 어디서 따져 봐야 하는지 알아볼 수 있게 해 주는 것이 이 구조의 쓸모였다.

몰랐던 차이나 질문이 생겼는가. 하나는 생겼다. 제목이 백엔드인 공고가 실제로는 클라이언트 아키텍처 역할이라는 것을, 앱이 올린 결격 사유를 따져 보려고 본문을 다시 읽으면서 알았다. 머신러닝 공고의 확인 질문도 그대로 쓸 수 있는 질문이었다. 반면 역할 수준 비교는 두 공고 모두 uncertain이라 새로 알려 준 것이 없었고, 경력 서사는 머신러닝 공고에서만 내용이 남았다.

일반 채팅보다 편한가. 아직 그렇다고 말할 수 없다. 같은 입력을 채팅에 넣어 나란히 비교하지 않았으니 우열을 말할 근거가 없다. 비교 없이도 남는 사실은 있다. 공고 하나에 2분이 걸렸고, 셋 중 하나는 실패했고, 실행기를 만들어야 했고, 없는 값을 지어냈다. 이 앱이 가진 것은 세 공고에 같은 항목이 같은 자리에 나오고, 근거가 인용되고, 모르는 것이 목록으로 남는다는 구조다.

다음에 손댈 것과 손대지 않을 것

이번에 드러난 것 가운데 앱 쪽에서 고칠 만한 것은 셋이다. 고용주 이름을 필수가 아니라 없을 수 있는 값으로 바꾸는 것, 점수의 단위를 프롬프트와 스키마에서 같이 못 박는 것, 그리고 OpenRouter 경로에서 추론 토큰 예산을 제한하는 것이다. 셋 다 이 앱을 써 보지 않았다면 우선순위에 오르지 않았을 항목이다.

손대지 않을 것도 정했다. 무료 모델을 더 찾아다니는 일, 실행기를 더 키우는 일이다. 이 정도면 장면을 돌릴 수 있고, 돌려 보니 무엇을 고쳐야 하는지 나왔다.

세 공고로 추천 정확도를 말할 수는 없다. 다만 앱이 하려던 일을 돕는지는 조금 보였다. 판정 자체보다, 판정의 이유를 드러내서 그 이유를 따져 볼 수 있게 하는 쪽이 도움이 됐다. 본인 이력서로 하는 두 번째 라운드는 이 세 가지를 고친 뒤에, 전송 범위와 보관 정책을 다시 확인하고 정하려 한다.