보살핌
경력근거: 커리어 스쿼드는 그 일자리를 찾는 경험을 만드는 팀이고
※ 실제 산출물이 아닌 AI 예측 시안입니다.
보살핌은 평균 연령 61세, 60만 개인 회원과 월 10만 신규 고객이 쌓이는 중장년 직무교육·일자리 매칭 1위 플랫폼이고, 커리어 스쿼드는 그 '일자리를 찾는 경험'을 만드는 팀입니다. 중장년 구직자의 자격증·통근 지역·근무 시간이라는 요건을 61세 눈높이의 쉬운 말 근거로 이어주는 이 매칭 사슬은, 보살핌의 중장년 사용자 프로필과 일자리 공고 풀이 있어야 의미가 있습니다. 다만 이 포트폴리오는 풀스택 구현·규칙 기반 결정론 매칭·실험 설계 기술을 보여주며, 중장년 채용 시장의 도메인 전문성은 주장하지 않습니다. 모르는 깊이는 면접에서 모른다고 말하는 편이 낫습니다.
커리어 스쿼드가 개선할 퍼널을 정하고 거기 붙일 실험을 논의부터 구현·배포·QA까지 책임지는 자리입니다. 그래서 이 도구도 추천 하나로 끝나지 않고, 공고 열람에서 지원까지의 전환을 실험으로 밀어 올리는 데까지 이어집니다.
쓰는 분들의 평균 연령이 61세라, 추천 근거는 전문 용어 없이 한 번에 읽히는 쉬운 말이어야 합니다. LLM 은 매칭 결과를 그 눈높이의 문장으로 바꾸는 일만 맡고, 적합 판정 자체는 규칙이 합니다.
화면부터 데이터베이스까지 직접 이어 붙여 배포까지 끌고 가고, REST API·PostgreSQL·모니터링·AWS 운영에 손이 닿아 있어야 하는 자리입니다. Next.js 프론트와 NestJS API, AWS 배포·모니터링이 이 도구의 골조입니다.
중장년 구직자 프로필(자격증·통근 가능 지역·근무 가능 시간·신체 조건)과 일자리 공고 요건을 한 스키마로 묶어, 필수요건이 맞는지 규칙으로 판정합니다. 적합한 공고만 남겨 적합도 순으로 세우고, 각 공고가 왜 맞는지와 무엇이 막는지를 61세 눈높이의 쉬운 말로 LLM 이 설명해 추천 리스트를 보여줍니다. 1주차만으로 완성품이고, AWS 이관과 상담사 검토(2주차)·추천 문구 A/B 실험(3주차)으로 단계적으로 키웁니다. (근거는 채용공고 정렬이고, 데이터는 작성자가 만든 더미입니다.)
보살핌 커리어 스쿼드의 제품 엔지니어입니다. 중장년 구직자에게 '이 일자리가 왜 당신에게 맞는지'를 매번 손으로 설명해 주던 상황을 끝내고, 그 추천이 실제로 지원까지 이어지는지 실험으로 확인하고 싶은 사람입니다.
구직자 프로필과 공고 요건을 한 스키마로 묶고 필수요건(자격증·지역·시간·신체·연령) 매칭을 규칙으로 계산하면, (a) 적합/부적합이 매번 같은 결과로 갈리고, (b) LLM 이 그 매칭 결과만 인용해 '왜 맞는지'를 61세 눈높이 문장으로 바꾸며, (c) 없는 자격을 근거로 지어내는 경우를 자동으로 걸러낼 수 있습니다.
구직자 프로필과 공고를 넣으면 자격증·지역·시간·신체·연령 필수요건을 규칙으로 판정해 적합한 공고만 남기고, 각 공고가 왜 맞는지를 쉬운 말 근거와 함께 보여주는 동작하는 웹앱입니다. Next.js 프론트 + NestJS API + PostgreSQL, Vercel 기본 배포합니다.
서비스를 AWS(Docker·CloudWatch)로 옮겨 운영하고, 상담사 페르소나 2명이 추천 근거가 타당한지 라벨링해 신뢰도를 보여주며, 데이터에 없는 자격을 근거로 지어내는 경우를 자동으로 차단하는 대시보드입니다.
추천을 구직 퍼널의 '공고 열람 → 지원' 단계로 놓고, 근거 문구 변형을 피처 플래그로 나눠 지원 전환을 비교하는 실험 대시보드입니다.
구직자 프로필 1명과 공고 30건을 넣으면, 필수요건이 맞는 공고만 골라 '왜 맞는지'와 '무엇이 막는지'를 쉬운 말 근거와 함께 세운 추천 리스트가 몇 초 안에 나오는 걸 시연합니다
적합/부적합 판정은 LLM 이 아니라 규칙으로 계산하므로 같은 입력에 매번 같은 결과가 나오고, 별도로 짠 규칙 재계산과 100% 일치합니다. LLM 을 바꿔도 판정은 흔들리지 않습니다
일부러 만든 결측(자격증 없음·통근 지역 미입력)·미등록 직무·표기 흔들림 입력 30종을 넣어도 출력 형식이 한 번도 안 깨지고, 데이터에 없는 자격을 근거로 지어내면 자동으로 차단됩니다
위 수치는 전부 작성자가 만든 더미데이터 자가채점이며, 실제 추천 만족도·지원 전환은 보살핌 실 구직자 데이터 + 실 상담사 검수 + 실제 A/B 실험이 있어야 측정 가능합니다. 이 페이지는 그 검증을 바로 돌릴 수 있는 상태까지 만듭니다
이건 고객·실데이터 없이 혼자 만든 포트폴리오입니다. 모든 수치는 합성 데이터 자가채점이라 '성능 증명'이 아닙니다. 면접에서는 '데모 조건 동작 + 실검증 준비 상태'로 솔직히 설명합니다
정답을 제가 만들었으니 잘 맞는 게 당연합니다. 일부러 자격증 결측·미등록 직무·통근 지역 미입력·표기 흔들림·연령 경계값을 더미에 섞어, 쉬운 문제만 푸는 게 아님을 보여줍니다
규칙 매칭이 '필수요건 충족 = 적합'까지만 판정할 뿐, 실제 채용 적합성(면접·근속 의지·현장 태도)까지 보장하지 않습니다. 61세 눈높이 문구도 실제 사용자 테스트 없이는 '쉬운지'를 단정할 수 없습니다. 이 포트폴리오는 풀스택 구현·규칙 기반 결정론 매칭·실험 설계 기술을 보여주며, 중장년 채용 도메인 전문성은 주장하지 않습니다. 모르는 깊이는 면접에서 모른다고 말하는 편이 낫습니다
실제 도입 시 달라지는 것을 분리해 둡니다. 실 공고 요건 표기와 구직자 프로필은 더미보다 훨씬 지저분해 별칭 사전·정규화 규칙을 다시 맞춰야 하고, 상담사 검수도 실제 인력으로 교체하며, A/B 실험은 실제 트래픽에서 표본·기간을 다시 설계해야 합니다
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
중장년 구직자 프로필. 매칭 엔진이 필수요건을 맞추는 기준. 운영 현실대로 자격증 결측·통근 지역 미입력·신체 조건 결측·희망 직무 미등록(orphan)·연령 경계값을 일부러 섞어, 쉬운 데이터만 푸는 게 아님을 보여줍니다.
| seeker_id | age | certs | commutable_regions | available_time | physical_level | career_tags | desired_job_raw | desired_job_id |
|---|---|---|---|---|---|---|---|---|
| s001 | 61 | ["요양보호사"] | ["서울 강서","서울 양천"] | weekday_day | moderate | ["간병","가사"] | 요양보호사 | j_care |
| s002 | 58 | [] | ["경기 성남"] | weekday_day | light | ["사무","경리"] | 사무보조 | j_office |
| s003 | 65 | ["경비지도사"] | ["서울 마포"] | weekday_night | moderate | ["보안"] | 아파트경비 | j_security |
| s004 | 63 | ["운전면허 1종"] | ["인천 남동"] | anytime | moderate | ["운수","배송"] | 마을버스 운전 | — |
| s005 | 70 | ["조리기능사"] | [] | weekend | light | ["급식","조리"] | 급식조리 | j_cooking |
아래 JSON Schema 에 맞는 한국 중장년 구직자 프로필 40행 JSON 배열로 생성.
{"type":"object","properties":{"seeker_id":{"type":"string"},"age":{"type":"integer"},"certs":{"type":"array","items":{"type":"string"}},"commutable_regions":{"type":"array","items":{"type":"string"}},"available_time":{"type":"string","enum":["weekday_day","weekday_night","weekend","anytime"]},"physical_level":{"type":["string","null"],"enum":["light","moderate","heavy",null]},"career_tags":{"type":"array","items":{"type":"string"}},"desired_job_raw":{"type":"string"},"desired_job_id":{"type":["string","null"]}},"required":["seeker_id","age","commutable_regions","available_time"]}
쉬운 데이터만 만들지 말 것. 다음 하드 케이스를 의도적으로 섞어라(쉬운 문제만 푸는 함정 회피): (1) 결측: certs 가 빈 배열(자격증 없음) 3~5건, physical_level 이 null 인 행 1~2건, (2) 통근 지역 미입력: commutable_regions 가 빈 배열 1~2건(경계값), (3) 미등록 희망 직무: desired_job_id 가 null 인 행 2~3건(job_master 에 없는 직무 표기), (4) orphan: job_master 에 없는 desired_job_id(예: j_facility) 1건, (5) 연령 경계값: age 70 이상(일부 공고 age_limit 초과) 2건. age 는 50~75 범위, 나머지 필드는 한국 중장년 직무(요양·경비·미화·조리·운전·사무·판매)에 맞게. JSON 배열만.{"type":"object","properties":{"seeker_id":{"type":"string"},"age":{"type":"integer"},"certs":{"type":"array","items":{"type":"string"}},"commutable_regions":{"type":"array","items":{"type":"string"}},"available_time":{"type":"string","enum":["weekday_day","weekday_night","weekend","anytime"]},"physical_level":{"type":["string","null"],"enum":["light","moderate","heavy",null]},"career_tags":{"type":"array","items":{"type":"string"}},"desired_job_raw":{"type":"string"},"desired_job_id":{"type":["string","null"]}},"required":["seeker_id","age","commutable_regions","available_time"]}일자리 공고 요건. 매칭 엔진이 구직자 프로필과 맞춰보는 상대. 공고 제목 별칭(같은 직무가 '돌봄 요양사/방문요양보호사'로 들어옴)·요건 결측·미등록 직무코드(orphan)·연령 제한 경계를 일부러 섞습니다.
| posting_id | title_raw | job_id | region | required_certs | required_physical | work_time | wage_krw | age_limit |
|---|---|---|---|---|---|---|---|---|
| p001 | 요양보호사(주간보호센터) | j_care | 서울 강서 | ["요양보호사"] | moderate | weekday_day | 2,100,000 | — |
| p002 | 아파트 경비원 | j_security | 서울 마포 | [] | moderate | weekday_night | 2,050,000 | 68 |
| p003 | 급식실 조리원 | j_cooking | 서울 강서 | ["조리기능사"] | moderate | weekday_day | — | — |
| p004 | 마을버스 운전원 | j_driving | 인천 남동 | ["운전면허 1종"] | moderate | weekday_day | 2,600,000 | 65 |
| p005 | 빌딩 미화원 | j_cleaning | 대전 유성 | [] | light | weekday_day | 1,950,000 | — |
아래 JSON Schema 에 맞는 한국 중장년 일자리 공고 40행 JSON 배열로 생성.
{"type":"object","properties":{"posting_id":{"type":"string"},"title_raw":{"type":"string"},"job_id":{"type":["string","null"]},"region":{"type":"string"},"required_certs":{"type":"array","items":{"type":"string"}},"required_physical":{"type":"string","enum":["light","moderate","heavy"]},"work_time":{"type":"string","enum":["weekday_day","weekday_night","weekend","anytime"]},"wage_krw":{"type":["integer","null"]},"age_limit":{"type":["integer","null"]}},"required":["posting_id","title_raw","region","required_physical","work_time"]}
쉬운 데이터만 만들지 말 것. 하드 케이스 의도적 혼입: (1) 표기 흔들림: 같은 직무를 title_raw 로 '돌봄 요양사'·'방문요양보호사'처럼 다르게 쓰되 job_id 는 job_master 로 정규화되게(예: 둘 다 j_care) 2~3건, (2) 요건 결측: wage_krw 가 null 인 공고 2~3건, (3) orphan: job_id 가 null 인 미등록 직무 공고 1~2건(직무 사전에 없어 '분류 보류'로 알려야 함), (4) 연령 경계: age_limit 60·65·70 인 공고 각 1건 이상. region 은 한국 시·구, wage_krw 1800000~2900000. JSON 배열만.{"type":"object","properties":{"posting_id":{"type":"string"},"title_raw":{"type":"string"},"job_id":{"type":["string","null"]},"region":{"type":"string"},"required_certs":{"type":"array","items":{"type":"string"}},"required_physical":{"type":"string","enum":["light","moderate","heavy"]},"work_time":{"type":"string","enum":["weekday_day","weekday_night","weekend","anytime"]},"wage_krw":{"type":["integer","null"]},"age_limit":{"type":["integer","null"]}},"required":["posting_id","title_raw","region","required_physical","work_time"]}직무 표준 ID + 별칭(같은 직무가 '요양보호사/돌봄요양사/케어파트너'로 들어옴). 구직자 희망 직무와 공고 제목이 별칭 차이로 어긋나는 걸 정규화합니다.
| job_id | canonical_name | aliases | category |
|---|---|---|---|
| j_care | 요양보호사 | ["돌봄요양사","방문요양보호사","케어파트너","요양보호"] | care |
| j_security | 경비원 | ["아파트경비","보안요원","경비"] | security |
| j_cleaning | 환경미화원 | ["미화원","건물청소","빌딩미화원"] | cleaning |
| j_cooking | 조리원 | ["급식조리","급식실조리원","조리기능"] | cooking |
| j_driving | 운전원 | ["마을버스운전","지게차","배송기사"] | driving |
아래 JSON Schema 에 맞는 한국 중장년 직무 표준 사전 30행 JSON 배열로 생성. 같은 직무가 별칭 2~4개를 가지도록.
{"type":"object","properties":{"job_id":{"type":"string"},"canonical_name":{"type":"string"},"aliases":{"type":"array","items":{"type":"string"}},"category":{"type":"string","enum":["care","security","cleaning","cooking","driving","office","sales"]}},"required":["job_id","canonical_name","aliases","category"]}
조건: category 분포 자연스럽게, 별칭에 실제 채용 공고에서 쓰이는 구어체 표기를 포함(예: 요양보호사 → 돌봄요양사·케어파트너). 단, job_master 에 일부러 넣지 않는 orphan 직무코드(예: j_facility)는 여기 만들지 말 것. JSON 배열만.{"type":"object","properties":{"job_id":{"type":"string"},"canonical_name":{"type":"string"},"aliases":{"type":"array","items":{"type":"string"}},"category":{"type":"string","enum":["care","security","cleaning","cooking","driving","office","sales"]}},"required":["job_id","canonical_name","aliases","category"]}상담사 페르소나(LLM 시뮬 외부 평가자) 2명이 추천 근거에 부여한 라벨. Cohen's κ 와 근거 지어내기(fabrication) 검출의 입력.
| match_id | evaluator | reason_valid | eligibility_correct | fabricated_evidence | note |
|---|---|---|---|---|---|
| m_s001_p001 | counselor_p1 | true | true | false | — |
| m_s001_p001 | counselor_p2 | true | true | false | 자격증·지역 근거 명확 |
| m_s001_p001 | self | true | true | false | — |
| m_s001_p012 | counselor_p1 | true | true | false | 야간·신체 부적합 사유 정확 |
| m_s001_p012 | counselor_p2 | true | true | false | — |
아래 JSON Schema 에 맞는 match_labels 40 매칭 × 평가자 3(counselor_p1/counselor_p2/self) = 120 행 JSON 배열로 생성.
{"type":"object","properties":{"match_id":{"type":"string"},"evaluator":{"type":"string","enum":["counselor_p1","counselor_p2","self"]},"reason_valid":{"type":"boolean"},"eligibility_correct":{"type":"boolean"},"fabricated_evidence":{"type":"boolean"},"note":{"type":["string","null"]}},"required":["match_id","evaluator","reason_valid","eligibility_correct","fabricated_evidence"]}
조건: 평가자 간 reason_valid 일치 70% 내외, 불일치 시 note 에 도메인 사유(지역 미입력 보류·자격 요건 해석 등), fabricated_evidence=true 인 케이스 10% 내외(프로필에 없는 자격·경력을 근거로 인용), eligibility_correct=false 인 판정 오류 케이스 10% 내외. JSON 배열만.{"type":"object","properties":{"match_id":{"type":"string"},"evaluator":{"type":"string","enum":["counselor_p1","counselor_p2","self"]},"reason_valid":{"type":"boolean"},"eligibility_correct":{"type":"boolean"},"fabricated_evidence":{"type":"boolean"},"note":{"type":["string","null"]}},"required":["match_id","evaluator","reason_valid","eligibility_correct","fabricated_evidence"]}| TypeScript | 프론트(Next.js)와 백엔드(NestJS)를 한 언어로 잇는 대표 언어. 매칭 결과 타입을 프론트·백엔드가 공유합니다. |
| Next.js | 추천 리스트·근거 카드 프론트. 61세 눈높이의 큰 글씨·고대비 화면을 렌더링합니다. |
| React | 근거 카드·부적합 사유 컴포넌트 렌더링과 입력 폼 상태 관리. |
| TailwindCSS | 접근성 큰 글씨·고대비 스타일. 중장년 가독성 기준(최소 글자 크기·대비비)을 유틸리티로 강제합니다. |
| NestJS | 매칭 엔진 API(`POST /match`. 구직자 1명 + 후보 공고 배열 입력 → output_schema 반환). 필수요건 규칙 판정과 LLM 근거 생성을 이 서버가 조율합니다. |
| Prisma | PostgreSQL 스키마·마이그레이션 관리. job_seekers·job_postings·job_master 테이블 정의와 쿼리. |
| PostgreSQL | job_seekers / job_postings / job_master / match_labels 단일 진실원 + 적합도 집계 뷰(`v_eligible_matches`). |
| AWS | 2주차부터 배포·운영. ECS(Docker 컨테이너) 배포 + CloudWatch 로 매칭 API 지표·오류를 모니터링합니다. |
| Docker | 매칭 API·프론트 컨테이너화. 로컬과 AWS 에서 같은 이미지로 구동합니다. |
| Redis | 공고 풀이 커질 때 구직자별 후보 매칭 결과를 캐시해 재계산을 줄입니다. |
| GitHub Actions | 테스트(규칙 판정 단위 테스트) + AWS 배포 CI 파이프라인. |
| Sentry | 프론트·API 예외 수집. 매칭 실패·LLM 응답 파싱 오류를 추적합니다. |
| CloudWatch | AWS 운영 지표·로그. 매칭 지연·오류율 알람. |
✓ pass → 그대로 멈춰도 완결입니다. 더 키우고 싶으면 2주차(AWS 이관 + 상담사 검토 + 근거 지어내기 차단)로 진행합니다.
✓ pass → 여기서 멈춰도 완결입니다. 더 키우면 3주차(추천 문구 A/B 실험으로 지원 전환 개선)로 진행합니다.
구직자 1명 + 후보 공고 배열을 받아, 각 공고에 대해 1) 필수요건 충족 여부(eligible, 규칙 결정론), 2) 우대요건 기반 적합도 점수, 3) 어느 요건이 맞았는지 추적하는 evidence 배열, 4) 왜 맞는지·무엇이 막는지를 쉬운 말로 푼 근거를 담습니다. 3주차에는 추천 문구 A/B 실험 결과(verification)까지 한 스키마에 담습니다.
{"type":"object","properties":{"seeker_id":{"type":"string"},"recommendations":{"type":"array","minItems":1,"items":{"type":"object","properties":{"posting_id":{"type":"string"},"eligible":{"type":"boolean"},"fit_score":{"type":"number"},"evidence":{"type":"array","minItems":1,"items":{"type":"object","properties":{"axis":{"type":"string","enum":["cert","region","time","physical","age","career_tag"]},"matched":{"type":"boolean"},"detail":{"type":"string"}},"required":["axis","matched","detail"]}},"plain_reason":{"type":"string","minLength":15},"blockers":{"type":"array","items":{"type":"string"}},"confidence":{"type":"string","enum":["low","mid","high"]}},"required":["posting_id","eligible","fit_score","evidence","plain_reason","blockers"]}},"verification":{"type":["object","null"],"properties":{"experiment":{"type":"string"},"variant_a_label":{"type":"string"},"variant_b_label":{"type":"string"},"apply_rate_a":{"type":"number"},"apply_rate_b":{"type":"number"},"sample_n":{"type":"integer"}}}},"required":["seeker_id","recommendations"]}[
{
"input_ref": "s001 (61세, 요양보호사 자격, 강서/양천 통근, 주간 근무, 신체 moderate) + 후보 공고 p001·p012·p006",
"output": {
"seeker_id": "s001",
"recommendations": [
{
"posting_id": "p001",
"eligible": true,
"fit_score": 0.92,
"evidence": [
{
"axis": "cert",
"matched": true,
"detail": "요양보호사 자격 보유 = 공고 필수 자격 '요양보호사' 충족"
},
{
"axis": "region",
"matched": true,
"detail": "통근 가능 지역 '서울 강서'에 공고 지역 포함"
},
{
"axis": "time",
"matched": true,
"detail": "희망 근무 '주간'과 공고 'weekday_day' 일치"
},
{
"axis": "physical",
"matched": true,
"detail": "신체 조건 moderate = 공고 요구 moderate"
}
],
"plain_reason": "요양보호사 자격증이 있으시고 강서구에서 다니실 수 있어서, 이 주간보호센터 자리에 바로 지원하실 수 있습니다. 근무도 원하시는 낮 시간입니다.",
"blockers": [],
"confidence": "high"
},
{
"posting_id": "p012",
"eligible": false,
"fit_score": 0.4,
"evidence": [
{
"axis": "cert",
"matched": true,
"detail": "요양보호사 자격 충족"
},
{
"axis": "region",
"matched": true,
"detail": "공고 지역 '서울 강서' 통근 가능"
},
{
"axis": "time",
"matched": false,
"detail": "공고 근무 'weekday_night'(야간) vs 희망 '주간' 불일치"
},
{
"axis": "physical",
"matched": false,
"detail": "공고 요구 heavy vs 프로필 moderate"
}
],
"plain_reason": "자격증과 지역은 맞지만 이 자리는 밤에 일하고 힘을 많이 쓰는 일이라, 원하시는 낮 근무·보통 강도와는 맞지 않습니다.",
"blockers": [
"근무 시간이 야간이라 원하시는 주간과 다릅니다",
"힘을 많이 쓰는 일이라 신체 조건과 맞지 않습니다"
],
"confidence": "high"
},
{
"posting_id": "p006",
"eligible": false,
"fit_score": 0.35,
"evidence": [
{
"axis": "cert",
"matched": true,
"detail": "요양보호사 자격 충족"
},
{
"axis": "region",
"matched": false,
"detail": "공고 지역 '서울 노원'이 통근 가능 지역(강서·양천)에 없음"
}
],
"plain_reason": "자격증은 맞지만 노원구는 다니시기 어려운 지역이라, 이 방문요양 자리는 통근이 부담스러울 수 있습니다.",
"blockers": [
"노원구는 통근 가능 지역에 없습니다"
],
"confidence": "high"
}
],
"verification": null
}
},
{
"input_ref": "s002 (58세, 자격증 없음, 성남 통근, 주간, 신체 light) + 공고 p008: 무자격 요건 공고에서 적합 판정",
"output": {
"seeker_id": "s002",
"recommendations": [
{
"posting_id": "p008",
"eligible": true,
"fit_score": 0.78,
"evidence": [
{
"axis": "cert",
"matched": true,
"detail": "공고 필수 자격 없음(빈 배열) = 자격 요건 통과"
},
{
"axis": "region",
"matched": true,
"detail": "통근 가능 '경기 성남'에 공고 지역 포함"
},
{
"axis": "time",
"matched": true,
"detail": "희망 주간과 공고 weekday_day 일치"
},
{
"axis": "career_tag",
"matched": true,
"detail": "경력 태그 '사무·경리'가 사무보조 직무와 인접"
}
],
"plain_reason": "이 사무 보조 자리는 자격증이 필요 없고 성남에서 다니실 수 있어서 바로 지원하실 수 있습니다. 예전에 하시던 사무·경리 경험도 도움이 됩니다.",
"blockers": [],
"confidence": "mid"
}
],
"verification": null
}
},
{
"input_ref": "3주차 · s001 대상 추천 문구 A/B 실험 결과(공고 열람 → 지원 전환)",
"output": {
"seeker_id": "s001",
"recommendations": [
{
"posting_id": "p001",
"eligible": true,
"fit_score": 0.92,
"evidence": [
{
"axis": "cert",
"matched": true,
"detail": "요양보호사 자격 충족"
}
],
"plain_reason": "요양보호사 자격증이 있으시고 강서구에서 다니실 수 있어 바로 지원하실 수 있습니다.",
"blockers": [],
"confidence": "high"
}
],
"verification": {
"experiment": "추천 문구 A/B (요건만 vs 쉬운 말 근거 포함)",
"variant_a_label": "요건만 노출(자격·지역·시간)",
"variant_b_label": "쉬운 말 근거 포함('왜 맞는지' 설명)",
"apply_rate_a": 0.18,
"apply_rate_b": 0.27,
"sample_n": 240
}
}
}
][자동 검증] 1. 형식 검증: 출력이 JSON Schema 를 통과하는지 parse(타입·필수 필드·enum 위반이면 즉시 실패). 2. 판정 일치: eligible 이 별도로 짠 필수요건 규칙 재계산(자격·지역·시간·신체·연령 게이트)과 100% 일치하는지 대조: LLM 판정을 신뢰하지 않고 규칙 결과를 정답으로 둡니다. 3. 근거 지어내기 차단: evidence[].detail 과 plain_reason 이 인용한 자격·경력이 입력 job_seekers 에 실제로 있는지 검사: 프로필에 없는 자격을 근거로 쓰면(fabricated_evidence) 차단합니다. 4. 눈높이 검사: plain_reason 에 전문 용어·영어 약어가 없는지 토큰 검사(61세 눈높이 유지). [수동 검증] 1. 상담사 페르소나 2명이 근거 타당성(reason_valid)을 비동기 라벨링 → bootstrap Cohen's κ(두 사람 답이 우연 이상으로 일치하는 정도, 0~1) 하한 ≥ 0.6. 2. judge 가 놓친 fabrication 을 사람 5% spot check 로 재확인. 3. verification(A/B)은 실제 트래픽이 아니라 합성 시연 값이므로, 실 도입 시 표본·기간을 다시 설계.
포트폴리오가 “무엇을 만들지”라면, 시나리오 테스트는 “현장에서 어떻게 판단·소통할지” 입니다. 실제 이 채용공고 맥락의 대본을 읽고 무엇을 물어야 할지 직접 써봅니다.