링크알파는 기관투자자의 리서치를 돕는 AI 제품을 만들고, 에이전트의 프롬프트·도구·모델·라우팅을 코드 배포 없이 DB 설정으로 조립·버저닝하는 시스템으로 이미 구현해 두었습니다. 이 포트폴리오는 바로 그 ‘에이전트의 행동은 하드코딩이 아니라 버전 관리되는 설정/데이터’라는 관점을 그대로 재현합니다. 마켓 브리핑·DD 리포트·문서 인용·정형 데이터 질의(TTSQL)를 한 에이전트가 설정에 따라 라우팅하고, 금융 답변의 필수 요건인 출처 귀속을 규칙으로 검증하는 이 사슬은 링크알파의 워크플로우 구성과 출처 귀속 품질 기준이 있어야 의미가 있어, 다른 회사 데이터로는 그대로 만들 수 없습니다. 다만 이 포트폴리오가 입증하는 것은 설정 기반 에이전트 조립·라우팅·인용 grounding·회귀 평가라는 기술이며, buy/sell-side 리서치의 도메인 전문성은 주장하지 않습니다. 모르는 금융 깊이는 면접에서 모른다고 말하는 편이 낫습니다.
프롬프트·도구·모델·라우팅을 코드 배포 없이 DB 설정으로 조립·버저닝하고 feature flag·조건 규칙으로 분기한다는 관점이 링크알파 제품의 골조입니다. 하드코딩이 아니라 설정/데이터로 사고하는 사람을 찾습니다.
한 고객에서 배운 것을 일반화해 코어 에이전트 행동으로 환원할 것과, 도메인 특화 워크플로우로 깎아낼 것을 구분합니다. 마켓 브리핑·DD 리포트·문서 인용·정형 데이터 질의(TTSQL)를 한 에이전트가 호출·조율하도록 라우팅합니다.
‘좋아 보인다’가 아니라 고정된 데이터 분포 위에서 변경 효과를 증명하는 것이 기준입니다. 금융 답변은 출처 귀속이 품질의 필수 요건이라 LLM-as-judge와 인용 grounding 검증을 함께 씁니다.
기관투자자 리서치용 금융 에이전트입니다. 애널리스트가 던진 질문을 설정에 담긴 라우팅 규칙으로 마켓 브리핑·DD 리포트·문서 인용 검색·정형 데이터 질의(TTSQL) 중 알맞은 워크플로우로 보냅니다. 에이전트의 프롬프트·도구·모델·라우팅은 코드 배포 없이 버전 관리되는 설정(agent_configs)으로 조립되고, feature flag와 조건 규칙으로 고객사별로 분기합니다. 답변은 어닝콜·공시·broker note 청크를 인용해 만들고, 인용한 청크가 실제 원문에 존재하며 인용 문구가 원문 안에 있는지 규칙으로 검증해 근거 없는 주장은 ‘미근거’로 표시합니다. 부분 답은 SSE로 실시간 스트리밍하고, 한 요청을 비즈니스 계층(설정)과 런타임 계층(세션·트레이스) 두 저장소를 가로질러 끝까지 추적합니다. 근거는 채용공고 정렬이고, 데이터는 작성자가 만든 더미입니다.
링크알파 FDE. 고객사(헤지펀드·운용사)마다 리서치 방식이 달라 에이전트 동작을 매번 코드로 고쳐 배포하던 상황을 끝내고, 설정만 바꿔 고객별로 분기하며 그 변경이 답 품질을 실제로 올렸는지 배포 전에 고정 질문셋으로 확인하고 싶은 사람입니다.
에이전트 행동을 버전 관리되는 설정으로 분리하면, (a) 질문의 유형에 따라 알맞은 워크플로우로 보내는 라우팅을 설정만으로 결정론적으로 바꿀 수 있고, (b) 답의 각 문장이 인용한 청크가 원문에 존재하는지 규칙으로 검증해 근거 없는 주장을 걸러내며, (c) 설정 버전 A/B를 고정 질문셋에 다시 돌려 인용 정확도와 충실도가 실제로 올랐는지 배포 전에 확인할 수 있습니다.
질문을 설정 기반으로 알맞은 워크플로우로 라우팅하고, 근거 청크가 인용된 답을 SSE로 스트리밍하며, 인용이 원문과 맞는지 규칙으로 검증해 미근거 주장을 걸러내는 동작하는 에이전트입니다. 실 MCP 도구 계층과 세션 격리 런타임은 단일 프로세스·메타 API 가정으로 시작하고, 문서는 합성 코퍼스로 시작합니다.
고정 질문셋 위에서 설정 버전 A/B를 회귀 평가해(결정론적 인용 정확도 + LLM-as-judge 충실도) 새 설정이 답 품질을 실제로 올렸는지 배포 전에 확인하는 draft→시뮬레이션→배포 게이트와, 한 요청을 비즈니스·런타임 두 계층 저장소를 가로질러 추적하는 트레이스 뷰입니다.
feature flag·조건 규칙으로 고객사별 설정을 분기하고, 회귀 평가를 CI 게이트로 걸어 통과분만 배포하며, 에이전트 런타임을 K8s(Helm/ArgoCD)로 올려 세션 격리·오토스케일 가정과 연결하는 단계입니다.
고정 질문 20개를 넣으면 각 질문이 설정 규칙대로 알맞은 워크플로우로 라우팅되고, 답의 문장마다 근거 청크가 인용된 결과가 SSE로 스트리밍되는 걸 시연합니다.
일부러 만든 결측·별칭·orphan·상충 수치 30종을 섞어도 출력 형식(JSON Schema)이 한 번도 안 깨지고, 근거가 없는 주장은 unresolved(미근거)로 빠져 환각이 답에 섞이지 않습니다.
내가 만든 정답 인용 40건을 규칙으로 검증해(인용 청크가 원문에 존재하고 인용 문구가 원문 안에 있는지) 36건(90%)이 일치합니다. 단, 정답·문서·질문을 모두 작성자가 만든 합성 기준이라 ‘성능 검증’이 아니라 ‘데모 조건 동작’입니다.
설정 버전을 바꿔 고정 질문셋에 다시 돌리면, 결정론적 인용 정확도와 LLM-as-judge 충실도 점수(답이 근거에만 기대는 정도, 0~1)가 버전별로 어떻게 달라지는지 배포 전에 비교해 보여줍니다.
위 수치는 전부 작성자가 만든 합성 문서·질문·정답 위 자가채점이며, 실제 인용 정확도·충실도는 링크알파의 실 금융 문서와 실 애널리스트 검수가 있어야 측정 가능합니다. 이 도구는 그 검증을 바로 돌릴 수 있는 상태까지 만듭니다.
이건 고객·실데이터 없이 혼자 만든 포트폴리오입니다. 모든 수치는 합성 데이터 자가채점이라 ‘성능 증명’이 아닙니다. 면접에서 ‘데모 조건 동작 + 실검증 준비 상태’로 솔직히 설명하는 편이 오히려 신뢰를 줍니다.
정답을 내가 만들었으니 잘 맞는 게 당연합니다. 그래서 일부러 헷갈리는 결측(ticker·날짜 null)·별칭 표기·orphan 청크·상충 수치를 더미에 섞어, 쉬운 문제만 푸는 게 아님을 보여줍니다.
금융 답변은 출처 귀속이 품질의 필수 요건이지만, 인용 청크가 원문에 존재한다고 해서 그 근거가 질문에 ‘맞는’ 근거인지(관련성)까지 규칙으로 다 잡지는 못합니다. 상충하는 수치(가이던스 vs 컨센서스) 중 무엇이 맞는지는 도메인 판단이 필요하므로, 인용 존재와 해석 정확은 분리해서 봅니다.
이 포트폴리오가 입증하는 것은 설정 기반 에이전트 조립·라우팅·결정론적 인용 검증·회귀 평가라는 기술이며, buy/sell-side 리서치의 도메인 전문성은 주장하지 않습니다. 모르는 금융 깊이는 면접에서 모른다고 말하는 편이 낫습니다.
실제 도입 시 달라지는 것을 분리해 둡니다. 합성 코퍼스는 실 어닝콜·공시 분포와 다르므로 검색·grounding 임계값을 다시 맞춰야 하고, 단일 프로세스 런타임은 세션 격리 K8s 런타임으로, 시뮬 judge 는 실 애널리스트 검수로, MCP 도구는 실 연동으로 교체해야 합니다(도입 단계 과제로 분리).
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
에이전트 행동을 코드 배포 없이 담는 버전 관리 설정. 라우팅 규칙·프롬프트 블록·도구 정책·모델·feature flag·고객 조건을 한 행에 담습니다. 라우팅 결정이 이 설정으로 결정론적으로 정해지는지 검증하는 입력입니다. 운영 현실대로 결측·orphan·비활성·버전 충돌을 일부러 섞어, 쉬운 데이터만 푸는 게 아님을 보여줍니다.
| config_id | version | customer_id | route_key | model | prompt_block_id | tool_policy | enabled | condition |
|---|---|---|---|---|---|---|---|---|
| cfg_doc_citation | 3 | — | doc_citation | claude-sonnet-4.5 | pb_cite_v3 | ["doc_search","chunk_fetch"] | true | — |
| cfg_doc_citation | 2 | — | doc_citation | claude-sonnet-4.5 | pb_cite_v2 | ["doc_search"] | false | — |
| cfg_market_briefing | 1 | — | market_briefing | claude-sonnet-4.5 | pb_brief_v1 | ["doc_search","news_fetch"] | true | — |
| cfg_dd_report | 2 | cust_hedge_a | dd_report | claude-sonnet-4.5 | pb_dd_v2 | ["doc_search","chunk_fetch","ttsql_run"] | true | asset_class == 'equity' |
| cfg_ttsql | 1 | — | ttsql | claude-haiku-4.5 | pb_ttsql_v1 | ["ttsql_run"] | true | — |
아래 JSON Schema 에 맞는 agent_configs 40행 JSON 배열로 생성. 라우팅·프롬프트·도구·모델·feature flag·고객 조건을 담은 버전 관리 설정.
{"type":"object","properties":{"config_id":{"type":"string"},"version":{"type":"integer"},"customer_id":{"type":["string","null"]},"route_key":{"type":"string","enum":["market_briefing","dd_report","doc_citation","ttsql"]},"model":{"type":"string"},"prompt_block_id":{"type":["string","null"]},"tool_policy":{"type":"array","items":{"type":"string"}},"enabled":{"type":"boolean"},"condition":{"type":["string","null"]}},"required":["config_id","version","route_key","model","tool_policy","enabled"]}
쉬운 데이터만 만들지 말 것. 다음 하드 케이스를 의도적으로 섞어라(쉬운 문제만 푸는 함정 회피): (1) 같은 config_id 에 version 여러 개(하나만 enabled=true 여야 라우팅이 정해지는 버전 충돌 후보), (2) customer_id=null 인 전역 기본 설정과 특정 고객 설정 혼재, (3) prompt_block_id=null(프롬프트 블록 미지정) 1~2건, (4) prompt_block_id 가 프롬프트 마스터에 없는 orphan 1건, (5) enabled=false(feature flag 꺼짐)와 tool_policy=[](도구 없음) 경계값 각 1건, (6) condition 이 채워진 조건 분기 행 몇 개. JSON 배열만.{"type":"object","properties":{"config_id":{"type":"string"},"version":{"type":"integer"},"customer_id":{"type":["string","null"]},"route_key":{"type":"string","enum":["market_briefing","dd_report","doc_citation","ttsql"]},"model":{"type":"string"},"prompt_block_id":{"type":["string","null"]},"tool_policy":{"type":"array","items":{"type":"string"}},"enabled":{"type":"boolean"},"condition":{"type":["string","null"]}},"required":["config_id","version","route_key","model","tool_policy","enabled"]}에이전트가 검색·인용하는 금융 문서 코퍼스(청크 단위). 어닝콜·공시·broker note·뉴스. 인용 grounding 검증(인용 청크가 존재하고 문구가 원문 안에 있는지)의 대상입니다. 결측·별칭 표기·orphan doc·상충 수치·초단문 경계값을 일부러 섞어, 인용 검증이 하드 케이스에서도 안 깨지는지 보여줍니다.
| chunk_id | doc_id | doc_type | ticker | ticker_raw | published_at | section | text |
|---|---|---|---|---|---|---|---|
| ch_0001 | doc_smsn_q1_call | earnings_call | 005930 | 삼성전자 | 2026-04-24 | guidance | 경영진은 2분기 DS 부문 영업이익 가이던스를 전분기 대비 15% 상… |
| ch_0002 | doc_smsn_broker | broker_note | 005930 | Samsung Electronics | 2026-04-25 | estimate | 컨센서스는 2분기 DS 영업이익을 전분기 대비 9% 증가로 보고 있어… |
| ch_0003 | doc_smsn_q1_call | earnings_call | 005930 | 삼전 | 2026-04-24 | capex | 연간 설비투자 계획은 전년과 유사한 수준을 유지한다고 언급했습니다. |
| ch_0004 | doc_hynix_filing | filing | 000660 | SK하이닉스 | 2026-04-22 | risk_factors | 공시는 메모리 가격 변동성과 고객사 재고 조정을 주요 위험으로 적시했… |
| ch_0005 | doc_hynix_filing | filing | — | 하이닉스 | — | unknown | 출처 페이지 메타데이터가 유실되어 발행일과 종목 코드가 확인되지 않는… |
아래 JSON Schema 에 맞는 금융 문서 청크 코퍼스 40행 JSON 배열로 생성. 어닝콜·공시·broker note·뉴스 혼합, 국내 종목 위주.
{"type":"object","properties":{"chunk_id":{"type":"string"},"doc_id":{"type":"string"},"doc_type":{"type":"string","enum":["earnings_call","filing","broker_note","news"]},"ticker":{"type":["string","null"]},"ticker_raw":{"type":"string"},"published_at":{"type":["string","null"]},"section":{"type":"string"},"text":{"type":"string"}},"required":["chunk_id","doc_id","doc_type","ticker_raw","text"]}
쉬운 데이터만 만들지 말 것. 다음 하드 케이스를 의도적으로 섞어라(쉬운 문제만 푸는 함정 회피): (1) ticker_raw 별칭 표기(같은 종목이 '삼성전자/Samsung Electronics/삼전' 처럼 들어와 ticker 로 정규화돼야 함) 3~4종, (2) ticker=null + published_at=null(출처 메타 유실) 1~2건, (3) 문서 마스터에 없는 orphan doc_id 1건(인용 추적 끊김), (4) 같은 종목·같은 지표를 다른 수치로 말하는 상충 청크 2건(회사 가이던스 vs 컨센서스 갭), (5) 초단문(text 10자 내외) 경계값 1건. text 는 한국어 금융 문장, JSON 배열만.{"type":"object","properties":{"chunk_id":{"type":"string"},"doc_id":{"type":"string"},"doc_type":{"type":"string","enum":["earnings_call","filing","broker_note","news"]},"ticker":{"type":["string","null"]},"ticker_raw":{"type":"string"},"published_at":{"type":["string","null"]},"section":{"type":"string"},"text":{"type":"string"}},"required":["chunk_id","doc_id","doc_type","ticker_raw","text"]}| Python | 에이전트 런타임·설정 로더(agent_configs → 프롬프트/도구/모델/라우팅 조립), 결정론적 인용 검증기, 회귀 평가 하니스 |
| TypeScript | Next.js 콘솔(설정 편집기 + SSE 스트림 뷰어 + 회귀 평가 대시보드) 프런트 로직과 런타임 스키마 검증 |
| LangGraph | 라우팅 → 검색 → 생성 → 근거 검증 노드를 잇는 워크플로우 그래프 + stateful 세션 상태 |
| Claude Code SDK | 에이전트 오케스트레이션 골격(도구 호출·부분 결과 스트리밍) 구현 수단 |
| FastAPI | 에이전트 런타임을 노출하는 백엔드 + SSE 스트리밍 엔드포인트 |
| PostgreSQL | 두 계층 저장소로 나눕니다. 비즈니스 계층(agent_configs 버전 관리) vs 런타임 계층(sessions·traces) |
| Redis | 런타임 세션 상태 + 백그라운드 태스크 부분 결과 스트림 버퍼 |
| MCP | 에이전트가 호출하는 도구 계층(문서 검색·TTSQL 실행) 인터페이스 |
| SSE | 백그라운드 검색을 돌리면서 먼저 나온 조각부터 실시간 스트리밍해 레이턴시 최소화 |
| Kubernetes | 3주차에 세션 격리 에이전트 런타임을 Helm/ArgoCD(GitOps)로 배포하고 오토스케일 가정을 연결합니다 |
| Terraform | 3주차에 런타임 인프라를 코드로 정의(IaC)해 회귀 평가 통과분과 함께 배포합니다 |
✓ pass → 그대로 멈춰도 완결입니다. 더 키우고 싶으면 2주차(설정 버전 A/B 회귀 평가와 배포 전 게이트)로 진행합니다.
✓ pass → 여기서 멈춰도 완결입니다. 더 키우면 3주차(고객사별 설정 분기와 CI 배포 게이트, K8s 런타임 배포)로 진행합니다.
1) 질문을 어느 워크플로우로 보냈는지(route)와 어떤 설정 버전을 썼는지, 2) 답을 문장(claim) 단위로 쪼개 각 문장이 인용한 청크와 그 인용이 원문에 존재하는지(grounded), 3) 근거를 못 찾은 문장은 unresolved 로 격리, 4) 모든 문장이 근거를 가졌는지(source_attribution_complete)와 judge 충실도. 라우팅·인용·검증 한 사이클을 한 스키마에 담습니다.
{"type":"object","properties":{"question":{"type":"string"},"route":{"type":"string","enum":["market_briefing","dd_report","doc_citation","ttsql"]},"config_version":{"type":"integer"},"claims":{"type":"array","minItems":1,"items":{"type":"object","properties":{"claim":{"type":"string"},"citations":{"type":"array","items":{"type":"string"}},"grounded":{"type":"boolean"}},"required":["claim","citations","grounded"]}},"unresolved":{"type":"array","items":{"type":"string"}},"source_attribution_complete":{"type":"boolean"},"judge":{"type":"object","properties":{"faithfulness":{"type":"number"},"note":{"type":["string","null"]}}},"hedge":{"type":["string","null"]}},"required":["question","route","config_version","claims","source_attribution_complete"]}[
{
"input_ref": "질문: ‘삼성전자 2분기 DS 가이던스와 컨센서스 갭 정리해줘’ (설정 cfg_doc_citation v3, enabled)",
"output": {
"question": "삼성전자 2분기 DS 가이던스와 컨센서스 갭 정리해줘",
"route": "doc_citation",
"config_version": 3,
"claims": [
{
"claim": "회사는 2분기 DS 영업이익 가이던스를 전분기 대비 15% 상향한다고 밝혔습니다.",
"citations": [
"ch_0001"
],
"grounded": true
},
{
"claim": "컨센서스는 같은 기간 9% 증가로 보고 있어 회사 가이던스와 6%p 갭이 있습니다.",
"citations": [
"ch_0002"
],
"grounded": true
}
],
"unresolved": [
"동일 문서에 5% 상향이라는 상충 조각(ch_0010)이 있어 두 수치 중 무엇이 최종인지는 도메인 확인이 필요합니다."
],
"source_attribution_complete": true,
"judge": {
"faithfulness": 0.92,
"note": "두 인용 모두 원문 문구 일치. 상충 수치를 답에 단정하지 않고 unresolved 로 뺀 점 양호."
},
"hedge": "가이던스와 컨센서스는 서로 다른 문서 출처이며, 동일 지표에 상충 조각이 존재합니다."
}
},
{
"input_ref": "질문: ‘하이닉스 최근 위험요인 근거 문서로 알려줘’ (설정 cfg_doc_citation v3). 근거 청크 일부가 출처 메타 유실",
"output": {
"question": "하이닉스 최근 위험요인 근거 문서로 알려줘",
"route": "doc_citation",
"config_version": 3,
"claims": [
{
"claim": "공시는 메모리 가격 변동성과 고객사 재고 조정을 주요 위험으로 적시했습니다.",
"citations": [
"ch_0004"
],
"grounded": true
}
],
"unresolved": [
"관련 조각 ch_0005 는 발행일과 종목 코드가 유실(null)돼 출처를 특정할 수 없어 답에 포함하지 않았습니다.",
"orphan 청크 ch_0008 은 문서 마스터에 없어 원문 추적이 끊겨 인용에서 제외했습니다."
],
"source_attribution_complete": true,
"judge": {
"faithfulness": 0.88,
"note": "출처 불명 조각을 근거로 쓰지 않고 격리한 점 적절."
},
"hedge": "출처 메타가 유실된 조각은 인용에서 제외했으므로 위험요인 목록이 전부가 아닐 수 있습니다."
}
},
{
"input_ref": "질문: ‘네이버 클라우드 흑자 전환 시점 매출로 계산해줘’. 문서엔 시점만 있고 정형 매출 데이터가 없어 라우팅/근거 경계",
"output": {
"question": "네이버 클라우드 흑자 전환 시점 매출로 계산해줘",
"route": "doc_citation",
"config_version": 3,
"claims": [
{
"claim": "경영진은 질의응답에서 클라우드 부문 흑자 전환 시점을 하반기로 제시했습니다.",
"citations": [
"ch_0007"
],
"grounded": true
}
],
"unresolved": [
"‘매출로 계산’ 부분은 코퍼스에 정형 매출 수치가 없어 근거를 찾지 못했습니다. 정형 질의(ttsql)로 재라우팅하거나 데이터 연결이 필요합니다."
],
"source_attribution_complete": true,
"judge": {
"faithfulness": 0.9,
"note": "근거 없는 수치를 지어내지 않고 미근거로 명시. 재라우팅 제안 적절."
},
"hedge": "질문의 계산 요구는 현재 코퍼스만으로 답할 수 없어 데이터 경계를 벗어납니다."
}
}
][자동 검증: 규칙·결정론으로 객관 채점] 1. JSON Schema parse 통과(출력 형식이 안 깨지는지). 2. route 가 해당 질문에 대해 agent_configs 의 enabled=true 인 설정 라우팅 규칙과 일치하는지(라우팅은 설정으로 결정론적). 3. 각 claim 의 citations 청크가 doc_chunks 에 실제로 존재하고, claim 문구의 핵심 수치·표현이 그 청크 text 안에 있는지(인용 grounding = 청크 존재 + 문구 일치). 4. source_attribution_complete = 모든 claim 이 grounded=true 인 인용을 하나 이상 가졌는지. 근거 못 찾은 문장은 claim 이 아니라 unresolved 로 빠졌는지. 5. orphan doc_id·출처 유실(null) 청크가 인용에 쓰이지 않았는지. [수동 검증: 사람·LLM 보조] 1. LLM-as-judge 충실도(faithfulness, 답이 인용 근거에만 기대는 정도 0~1)를 고정 질문셋에 재서 bootstrap 신뢰구간 하한을 봅니다. 2. 인용이 ‘존재’할 뿐 아니라 질문에 ‘맞는’ 근거인지(관련성)와 상충 수치 판단은 실 애널리스트 spot check 5%로 확인합니다.