신한투자증권
경력근거: AI PB(AI Private Banker) 서비스 개발 및 운영
※ 실제 산출물이 아닌 AI 예측 시안입니다.
신한투자증권 AI솔루션부는 고객 보유 자산으로 AI PB(AI Private Banker) 서비스를 만듭니다. 답변의 모든 수치가 어느 보유 내역에서 나왔는지 근거를 강제하고 어긋난 인용을 차단하는 이 콘솔은, 고객 계좌라는 신한투자증권 고유의 보유 데이터가 있어야 의미가 있습니다. 다만 이 포트폴리오는 답변을 데이터에 근거 짓는 grounding 과 Frontend·Backend·API·DB 풀스택 구현 기술을 보여주며, 금융투자자문·투자권유 도메인 전문성은 주장하지 않습니다. 투자권유·수익률 예측 같은 규제·전문 영역은 제품 골조에서 제외하고 refusal 로 되돌리며, 정답은 인용한 값이 원본과 같은지의 규칙·결정론으로 채점하고 LLM 은 요약·문구만 맡습니다. 모르는 깊이는 면접에서 모른다고 말하는 편이 낫습니다.
AI PB(AI Private Banker) 는 고객 돈이 걸린 답을 냅니다. 그래서 요약·답변의 모든 수치가 고객 보유 내역의 어느 행에서 왔는지 추적돼야 하고, 이 인용 대조가 제품의 뼈대가 됩니다.
특정 영역이 아니라 제품 전체를 구현합니다. 화면(요약 카드·인용 하이라이트), REST API, RDBMS/NoSQL 저장까지 한 사람이 관통해 만드는 걸 보여주는 게 이 직무의 자격요건입니다.
기획을 기다리기보다 문제를 발견해 해결하고, 빠르게 만들고 검증하며 개선하는 방식을 찾습니다. 1주차 완결품에서 grounding 정확도 검증으로 키우는 단계 구조가 이 일하는 방식과 맞습니다.
고객의 보유 자산 내역과 문의를 입력받아, 포트폴리오 요약 카드와 질문 답변을 생성하는 관리자 페이지입니다. 답변에 등장하는 모든 수치·종목은 실제 보유 내역의 어느 행에서 왔는지 인용 근거(source_row_id + 원본값)를 함께 붙이고, 인용한 값이 원본과 다르면 규칙으로 자동 차단합니다. 종목 별칭은 종목 마스터로 정규화하고, 마스터에 없는 종목은 추측하지 않고 '미매핑' 으로 알립니다. 근거는 채용공고 정렬이고, 데이터는 작성자가 만든 더미입니다.
PB 상담 초안을 만들 때마다 고객 계좌를 열어 보유 종목·평가액·손익을 손으로 확인하고, 'AI 가 요약해 줬는데 이 숫자가 실제 계좌랑 맞는지' 를 매번 눈으로 재검하던 상황을 끝내고, 답변의 모든 수치에 어느 보유 내역에서 나왔는지 근거가 자동으로 붙길 바라는 사람입니다.
보유 자산(holdings)과 종목 마스터(instrument_master)를 한 스키마로 묶고, LLM 답변이 인용한 수치마다 source_row_id 를 강제해 원본값과 규칙으로 대조하면, (a) 포트폴리오 요약 카드와 (b) 문의 답변을 몇 초 안에 만들면서 (c) 원본과 어긋난 인용·환각 종목을 자동으로 걸러낼 수 있습니다.
보유 자산 스냅샷(실계좌·실시세 연동 대신 더미 holdings 스냅샷과 사내 조회 API 를 가정)을 받아, 자산 요약 카드와 문의 답변을 만들고, 답변의 모든 수치에 source_row_id 를 붙여 원본값과 대조하며, 어긋난 인용은 규칙으로 차단하는 동작하는 콘솔입니다.
일부러 원본에 없는 종목·수치를 물어보는 환각 유도 질문 세트를 넣어, 인용 대조가 어긋난 답변을 얼마나 잡아내는지(차단율)와 정상 답변을 얼마나 통과시키는지를 재고, PB 검수자 2명이 답변 문구의 오해 소지를 라벨링하는 대시보드입니다.
들어온 문의를 유형(잔고·손익·비중·규제범위 밖)으로 자동 분류해 답변 초안 생성 경로로 라우팅하고, 답변·인용 로그를 NoSQL 에 쌓아 재검토 가능하게 만드는 업무 자동화 단계입니다.
고객 문의 세트를 넣으면 자산 요약 카드와 인용 근거가 붙은 답변이 몇 초 안에 나오는 걸 시연합니다
일부러 만든 환각 유도·결측·미등록(orphan) 종목 입력 30종을 넣어도 출력 형식(JSON Schema)이 한 번도 안 깨지고, 원본과 어긋난 인용은 규칙으로 자동 차단되는 걸 보여줍니다
내가 만든 정답 40건 중 인용 대조 판정(원본값 일치·불일치)이 규칙과 맞은 건수를 재고, 단 정답·데이터를 모두 작성자가 만든 합성 기준이라 '성능 검증' 이 아니라 '데모 조건에서의 동작' 임을 명시합니다
위 수치는 전부 작성자가 만든 더미데이터 자가채점이며, 실제 인용 정확도·차단율은 신한투자증권 실계좌 데이터와 실 PB 검수가 있어야 측정 가능합니다. 이 콘솔은 그 검증을 바로 돌릴 수 있는 상태까지 만듭니다
이건 고객·실데이터 없이 혼자 만든 포트폴리오입니다. 모든 수치는 합성 데이터 자가채점이라 '성능 증명' 이 아니므로, 면접에서 '데모 조건 동작 + 실검증 준비 상태' 로 솔직히 설명합니다
정답을 제가 만들었으니 잘 맞는 게 당연합니다. 원본에 없는 종목·어긋난 수치·결측·미등록(orphan) 같은 경계 케이스를 더미와 질문 세트에 일부러 섞어, 쉬운 문제만 푸는 게 아님을 보여줍니다
이 포트폴리오는 답변을 보유 데이터에 강제로 근거 짓는 grounding 과 Frontend·Backend·API·DB 풀스택 구현 기술을 보여주며, 금융투자자문·투자권유 도메인 전문성은 주장하지 않습니다. 종목 별칭 표기가 제각각인 함정은 유사도 매칭 + 마스터 정규화로 묶고, 못 묶은 건 추측하지 않고 '미매핑' 으로 알립니다. 모르는 깊이는 면접에서 모른다고 말하는 편이 낫습니다
투자권유·수익률 예측 같은 규제·전문 영역은 제품 골조에서 제외하고 refusal 로 되돌립니다. 요약은 자문이 아니며, 실제 도입 시에는 더미 스냅샷 대신 실계좌·실시세 연동이 붙고 자산군 enum·정규화 규칙과 검수자도 실제 인력으로 다시 맞춰야 합니다(도입 단계 과제로 분리)
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
고객 계좌별 보유 자산 내역. 요약 카드와 답변 인용이 대조하는 원본의 단일 진실원입니다. 운영 현실대로 평가액 결측(장중 미반영)·미등록 종목(instrument_id=null)·종목 별칭 표기·경계값(수량 0 청산, 평가손익 0)을 일부러 섞어, 쉬운 데이터만 푸는 게 아님을 보여줍니다.
| row_id | account_id | as_of | instrument_raw | instrument_id | asset_class | quantity | avg_buy_krw | eval_krw | pl_pct |
|---|---|---|---|---|---|---|---|---|---|
| h_001 | c_1001 | 2026-07-20 | 삼성전자 | eq_samsung | equity | 120 | 71,000 | 9,360,000 | 5.1 |
| h_002 | c_1001 | 2026-07-20 | 삼성전자보통주 | eq_samsung | equity | 30 | 80,000 | 2,340,000 | -2.5 |
| h_003 | c_1001 | 2026-07-20 | KODEX 200 | etf_kodex200 | etf | 200 | 38,000 | 8,200,000 | 7.9 |
| h_004 | c_1001 | 2026-07-20 | 국고채권 03500-2609 | bond_ktb2609 | bond | 50 | 10,200 | 510,000 | 0 |
| h_005 | c_1001 | 2026-07-20 | 달러 예수금 | cash_usd | cash | 1 | — | 1,400,000 | — |
아래 JSON Schema 에 맞는 한국 증권 계좌 보유 내역 40행 JSON 배열로 생성하세요. 계좌 3~4개(c_1001~c_1004), 자산군(equity·bond·fund·etf·cash·derivative) 분포를 자연스럽게 섞으세요.
{"type":"object","properties":{"row_id":{"type":"string"},"account_id":{"type":"string"},"as_of":{"type":"string"},"instrument_raw":{"type":"string"},"instrument_id":{"type":["string","null"]},"asset_class":{"type":"string","enum":["equity","bond","fund","etf","cash","derivative"]},"quantity":{"type":"number"},"avg_buy_krw":{"type":["number","null"]},"eval_krw":{"type":["number","null"]},"pl_pct":{"type":["number","null"]}},"required":["row_id","account_id","as_of","instrument_raw","asset_class","quantity"]}
쉬운 데이터만 만들지 말 것. 다음 하드 케이스를 의도적으로 섞으세요(쉬운 문제만 푸는 함정 회피): (1) 같은 종목의 별칭 표기 혼입(instrument_raw '삼성전자'/'삼성전자보통주'/'삼전' 이 모두 instrument_id eq_samsung 으로 정규화돼야 함), (2) 미등록 종목(instrument_id=null) 2~3건(사모펀드·신규 상품 등 마스터 미매핑), (3) 결측. eval_krw/pl_pct 가 null 인 행 각 2~3건(장중 미반영·현금성 손익 없음), (4) 경계값 수량 0(청산 종목, eval_krw=0)과 평가손익 0.0 각 1건 + 대규모 손실 이상치(pl_pct < -30) 1건(파생), (5) 자산군 cash 는 avg_buy_krw/pl_pct 를 null 로. JSON 배열만 출력하세요.{"type":"object","properties":{"row_id":{"type":"string"},"account_id":{"type":"string"},"as_of":{"type":"string"},"instrument_raw":{"type":"string"},"instrument_id":{"type":["string","null"]},"asset_class":{"type":"string","enum":["equity","bond","fund","etf","cash","derivative"]},"quantity":{"type":"number"},"avg_buy_krw":{"type":["number","null"]},"eval_krw":{"type":["number","null"]},"pl_pct":{"type":["number","null"]}},"required":["row_id","account_id","as_of","instrument_raw","asset_class","quantity"]}종목 표준 id + 별칭(같은 종목이 '삼성전자/삼성전자보통주/삼전' 으로 들어옴). 보유 내역의 별칭 표기를 하나로 묶어 인용·집계가 분산되지 않게 합니다. 마스터에 없는 종목은 orphan 으로 남겨 답변이 '미매핑' 을 알리게 합니다.
| instrument_id | canonical_name | aliases | asset_class | ticker | risk_grade |
|---|---|---|---|---|---|
| eq_samsung | 삼성전자 | ["삼성전자보통주","삼전"] | equity | 005930 | 3 |
| eq_skhynix | SK하이닉스 | ["에스케이하이닉스","하이닉스"] | equity | 000660 | 3 |
| eq_naver | NAVER | ["네이버"] | equity | 035420 | 3 |
| etf_kodex200 | KODEX 200 | ["코덱스200","KODEX200"] | etf | 069500 | 2 |
| etf_tiger_sp500 | TIGER 미국S&P500 | ["타이거 미국S&P500","TIGER S&P500"] | etf | 360750 | 3 |
아래 JSON Schema 에 맞는 한국 증권 종목 마스터 40행 JSON 배열로 생성하세요. 같은 종목이 별칭 1~3개(원문·약칭·영문표기)를 가지도록 하세요.
{"type":"object","properties":{"instrument_id":{"type":"string"},"canonical_name":{"type":"string"},"aliases":{"type":"array","items":{"type":"string"}},"asset_class":{"type":"string","enum":["equity","bond","fund","etf","cash","derivative"]},"ticker":{"type":["string","null"]},"risk_grade":{"type":["integer","null"]}},"required":["instrument_id","canonical_name","aliases","asset_class"]}
조건: asset_class 분포 자연스럽게, 상장 주식·ETF 는 ticker 를 채우고 채권·현금·파생·펀드는 ticker=null 로 두세요. risk_grade 는 1(안전)~5(고위험). 별칭에는 띄어쓰기·영문·약칭 변형을 섞어 정규화 난이도를 주세요. JSON 배열만 출력하세요.{"type":"object","properties":{"instrument_id":{"type":"string"},"canonical_name":{"type":"string"},"aliases":{"type":"array","items":{"type":"string"}},"asset_class":{"type":"string","enum":["equity","bond","fund","etf","cash","derivative"]},"ticker":{"type":["string","null"]},"risk_grade":{"type":["integer","null"]}},"required":["instrument_id","canonical_name","aliases","asset_class"]}| React | AI PB 콘솔 프론트. 요약 카드, 답변 화면, 각 수치에 걸린 인용 근거(어느 보유 내역 행인지)를 클릭하면 원본이 펼쳐지는 하이라이트 UI |
| Vue | PB 검수자용 사내 어드민. 답변별 인용 대조 결과와 오해 소지 라벨을 검토하는 화면 |
| Kotlin | Spring Boot 인용 검증 백엔드. 보유 내역 조회 + 답변이 인용한 값과 원본값을 대조해 matches_source 를 판정하는 grounding 검사 서비스 |
| Python | LLM 요약·답변 생성 파이프라인 + grounding 채점 스크립트(인용 일치율·차단율 계산) |
| Node.js | BFF 게이트웨이. 콘솔과 백엔드 사이에서 답변 스트리밍과 문의 라우팅을 중계 |
| REST API | 콘솔과 백엔드의 계약. POST /answer(문의 → 근거 붙은 답변), GET /holdings/{account}(보유 내역 조회), POST /verify(인용 대조) |
| PostgreSQL | holdings / instrument_master 정규화 저장. 인용 대조의 기준이 되는 원본값의 단일 진실원 |
| MongoDB | 답변·인용 로그·문의 이력 저장(NoSQL). 스키마가 유동적인 답변 payload 를 그대로 적재해 재검토 |
| Redis | 세션·보유 스냅샷 캐시(NoSQL). 같은 계좌 반복 조회 시 원본 스냅샷을 재사용 |
✓ pass → 그대로 멈춰도 완결입니다. 더 키우고 싶으면 2주차(환각 유도 질문 세트로 grounding 정확도 검증)로 진행합니다.
✓ pass → 여기서 멈춰도 완결입니다. 더 키우면 3주차(문의 자동 분류·라우팅 + 답변 이력 적재)로 진행합니다.
1) 보유 자산 요약 카드(총 평가액·자산군 비중, 각 수치에 근거 행), 2) 문의 답변(모든 수치에 인용 근거 + 원본값 일치 여부), 3) grounding 판정(미인용 수치·미매핑 종목 표시), 4) 투자권유·수익률 예측 등 범위 밖 질문의 refusal. 요약과 근거 붙은 답변 한 번을 한 스키마에 담습니다.
{"type":"object","properties":{"customer_id":{"type":"string"},"as_of":{"type":"string"},"portfolio_summary":{"type":"object","properties":{"headline":{"type":"string"},"total_eval_krw":{"type":"number"},"asset_mix":{"type":"array","items":{"type":"object","properties":{"asset_class":{"type":"string"},"weight_pct":{"type":"number"},"source_row_ids":{"type":"array","items":{"type":"string"}}},"required":["asset_class","weight_pct","source_row_ids"]}}},"required":["headline","total_eval_krw","asset_mix"]},"answer":{"type":"object","properties":{"question":{"type":"string"},"answer_text":{"type":"string"},"citations":{"type":"array","items":{"type":"object","properties":{"claim":{"type":"string"},"cited_value":{"type":["number","string"]},"source_table":{"type":"string"},"source_row_id":{"type":"string"},"matches_source":{"type":"boolean"}},"required":["claim","cited_value","source_table","source_row_id","matches_source"]}}},"required":["question","answer_text","citations"]},"grounding":{"type":"object","properties":{"all_numbers_cited":{"type":"boolean"},"unmatched_claims":{"type":"array","items":{"type":"string"}},"unmapped_instruments":{"type":"array","items":{"type":"string"}}},"required":["all_numbers_cited","unmatched_claims"]},"refusal":{"type":["string","null"]}},"required":["customer_id","as_of","portfolio_summary","answer","grounding"]}[
{
"input_ref": "c_1001, 문의: '제 계좌에서 주식 비중이 얼마나 되나요?' (정상 답변, 모든 수치가 원본과 일치)",
"output": {
"customer_id": "c_1001",
"as_of": "2026-07-20",
"portfolio_summary": {
"headline": "총 평가액 2,159만원, 주식·ETF 중심 구성입니다",
"total_eval_krw": 21590000,
"asset_mix": [
{
"asset_class": "equity",
"weight_pct": 58.7,
"source_row_ids": [
"h_001",
"h_002",
"h_012"
]
},
{
"asset_class": "etf",
"weight_pct": 38,
"source_row_ids": [
"h_003"
]
},
{
"asset_class": "bond",
"weight_pct": 2.4,
"source_row_ids": [
"h_004"
]
},
{
"asset_class": "cash",
"weight_pct": 6.5,
"source_row_ids": [
"h_005"
]
}
]
},
"answer": {
"question": "제 계좌에서 주식 비중이 얼마나 되나요?",
"answer_text": "보유하신 주식(삼성전자 3건 합산)은 평가액 1,248만원으로 총 평가액의 약 58.7% 입니다. 이 수치는 요약이며 투자권유가 아닙니다.",
"citations": [
{
"claim": "삼성전자 평가액 936만원",
"cited_value": 9360000,
"source_table": "holdings",
"source_row_id": "h_001",
"matches_source": true
},
{
"claim": "삼성전자보통주 평가액 234만원",
"cited_value": 2340000,
"source_table": "holdings",
"source_row_id": "h_002",
"matches_source": true
},
{
"claim": "삼전 평가액 78만원",
"cited_value": 780000,
"source_table": "holdings",
"source_row_id": "h_012",
"matches_source": true
}
]
},
"grounding": {
"all_numbers_cited": true,
"unmatched_claims": [],
"unmapped_instruments": []
},
"refusal": null
}
},
{
"input_ref": "c_1001, 문의: '삼성전자 수익률이 지금 얼마죠?' (LLM 이 +8.2% 로 잘못 인용 → 원본 +5.1% 와 불일치, 규칙이 차단)",
"output": {
"customer_id": "c_1001",
"as_of": "2026-07-20",
"portfolio_summary": {
"headline": "총 평가액 2,159만원, 주식·ETF 중심 구성입니다",
"total_eval_krw": 21590000,
"asset_mix": [
{
"asset_class": "equity",
"weight_pct": 58.7,
"source_row_ids": [
"h_001",
"h_002",
"h_012"
]
}
]
},
"answer": {
"question": "삼성전자 수익률이 지금 얼마죠?",
"answer_text": "[답변 보류] 인용한 수익률이 보유 내역 원본과 일치하지 않아 전달을 차단했습니다. 재생성 후 다시 답변합니다.",
"citations": [
{
"claim": "삼성전자 평가손익 +8.2%",
"cited_value": 8.2,
"source_table": "holdings",
"source_row_id": "h_001",
"matches_source": false
}
]
},
"grounding": {
"all_numbers_cited": true,
"unmatched_claims": [
"h_001 의 pl_pct 원본값은 5.1 인데 답변은 8.2 로 인용해 불일치. 이 계좌의 삼성전자는 매입가가 다른 h_001·h_002·h_012 세 건이라 단일 수익률로 답하려면 어느 건인지 특정 필요"
],
"unmapped_instruments": []
},
"refusal": null
}
},
{
"input_ref": "c_1002, 문의: '성장주식형 사모펀드 지금 사면 더 오를까요?' (미매핑 종목 + 투자권유·수익률 예측 범위 밖 → refusal)",
"output": {
"customer_id": "c_1002",
"as_of": "2026-07-20",
"portfolio_summary": {
"headline": "총 평가액 1,942만원, 주식·ETF·펀드 분산 구성입니다",
"total_eval_krw": 19420000,
"asset_mix": [
{
"asset_class": "fund",
"weight_pct": 23.8,
"source_row_ids": [
"h_008"
]
}
]
},
"answer": {
"question": "성장주식형 사모펀드 지금 사면 더 오를까요?",
"answer_text": "이 콘솔은 보유하신 자산 내역의 요약과 설명만 제공하며, 특정 상품의 매수 권유나 수익률 예측은 하지 않습니다. 보유 중인 '성장주식형 사모펀드 7호' 는 현재 평가액 462만원(평가손익 -7.6%)으로 확인되며, 이 종목은 종목 마스터에 등록되지 않아 상세 정보가 미매핑 상태입니다.",
"citations": [
{
"claim": "성장주식형 사모펀드 7호 평가액 462만원",
"cited_value": 4620000,
"source_table": "holdings",
"source_row_id": "h_008",
"matches_source": true
},
{
"claim": "성장주식형 사모펀드 7호 평가손익 -7.6%",
"cited_value": -7.6,
"source_table": "holdings",
"source_row_id": "h_008",
"matches_source": true
}
]
},
"grounding": {
"all_numbers_cited": true,
"unmatched_claims": [],
"unmapped_instruments": [
"h_008 (instrument_id=null, 종목 마스터 미등록)"
]
},
"refusal": "투자권유·수익률 예측 범위 밖 질문입니다. 보유 내역 요약만 제공했습니다."
}
}
][자동 검증] 1. 출력이 위 JSON Schema 를 통과하는지(형식·필수 필드). 2. answer.citations 의 모든 cited_value 가 source_row_id 로 지목한 holdings 원본 행의 실제 값과 같은지 대조해 matches_source 를 규칙으로 재판정(LLM 이 스스로 매긴 값을 신뢰하지 않고 백엔드가 다시 계산). 3. answer_text 에 등장하는 모든 수치가 citations 로 커버되는지(all_numbers_cited). 미인용 수치가 있으면 차단. 4. instrument_id=null 인 보유 종목을 답변이 임의로 단정하지 않고 unmapped_instruments 로 표시했는지. 5. 투자권유·수익률 예측 의도(매수/매도 권유·'오를까요' 등)가 감지되면 refusal 이 채워졌는지. [수동 검증] 1. PB 검수자 2명이 답변 문구의 오해 소지(요약을 자문으로 읽힐 여지)를 비동기 라벨링하고, 두 사람 판정의 일치도를 bootstrap Cohen's κ(두 검수자 판정이 우연 이상으로 일치하는 정도, 0~1) 하한 0.6 이상으로 확인. 2. 자동 통과분의 5% 를 사람이 spot check 로 원본 대조.
근거: AI PB(AI Private Banker) 서비스 개발 및 운영