인공지능팩토리는 한국항공우주연구원·한국전력·원자력통제기술원 같은 공공기관에 어시웍스(노코드 AI 에이전트 빌더)를 온프레미스로 납품하는 회사입니다. 모호한 공공 요구사항을 작동하는 기술로 풀어내는 FDE 자리라, 기관 내부 문서를 연동해 근거 조항으로 답하고 근거가 약하면 담당자에게 넘기는 이 도구는 어시웍스가 실제로 부딪히는 문제(내부 문서 연동·폐쇄망·근거 없는 답 금지)와 같은 골조입니다. 다만 이 포트폴리오가 입증하는 것은 Spring Boot 상태머신 플로우·RAG 인용 근거 채점·pgvector 검색·컨테이너 배포 기술이지, 공공 SI 사업 수행 경험이나 국정원 보안 인증 통과를 주장하지 않습니다. 실제 기관 규정의 잦은 개정과 별표·서식 참조의 복잡함은 실무에서 배워야 하고, 모르는 깊이는 면접에서 모른다고 말하는 편이 낫습니다.
FDE 는 발주처의 모호한 요구사항을 분석해 기술로 해결 가능한 구조로 정의하고 실제 구동 가능한 솔루션으로 구현하는 자리입니다. 규정 질의를 조항 인용 답변으로 푸는 이 도구가 그 최소 단위입니다.
온프레미스(폐쇄망) 구축과 국정원 가이드 등 공공 보안 규정 준수가 핵심입니다. 데이터가 외부로 나가지 않는 구조에서 답변이 근거 조항에 묶여 있어야 신뢰가 생깁니다.
어시웍스는 내부 API·DB·문서 시스템을 연동하고 RAG 벡터스토어로 기관 전용 에이전트를 조립합니다. 문서를 근거로 답하고 근거가 없으면 멈추는 것이 이 제품군의 뼈대입니다.
공공기관 규정·지침 문서를 올리면, 민원·업무 질문에 근거 조항을 인용해 답하고, 근거가 약하면 자동으로 담당자에게 넘기는 질의응답 에이전트입니다. 어시웍스처럼 도구를 등록하고 에이전트를 구성해 플로우로 잇는 3단계로 조립하며, 폐쇄망 가정으로 Docker 컨테이너에서 그대로 구동합니다. 인용한 조항이 실제 문서에 있는지, 답변 근거와 맞는지를 규칙으로 채점합니다. 근거는 채용공고 정렬이고, 데이터는 작성자가 만든 더미입니다.
인공지능팩토리 FDE. 발주처의 모호한 규정 질의에 매번 사람이 규정집을 뒤져 답하던 상황을 끝내고, AI 답변이 실제 조항에 근거했는지까지 확인하고 싶은 사람입니다.
규정 문서를 조항 단위로 나눠 pgvector 로 검색하고 답변마다 인용 조항 id 를 강제하면, 질문에 맞는 조항을 인용해 답하고, 그 인용이 실제 문서에 있는지와 정답 근거와 겹치는지를 규칙으로 채점할 수 있으며, 근거가 약한 질문은 답을 지어내지 않고 담당자에게 넘길 수 있습니다.
규정 문서를 올리면 질문에 근거 조항을 인용해 답하고 근거가 약한 질문은 담당자 확인으로 표시하는, Docker compose 로 폐쇄망을 가정해 로컬에서 도는 도구입니다. 문서 임베딩은 외부 임베딩 API 를 가정해 시작하고, 온프레미스 오픈웨이트 모델 교체는 3주차로 분리합니다.
질의 접수에서 검색·근거 판정·답변 또는 담당자 에스컬레이션까지를 Spring Boot 상태머신으로 잇고, 인용한 조항이 실제 문서에 있는지와 정답 근거와 겹치는지를 규칙으로 채점하며, 공무원 검수자 2명의 라벨 일치도를 보여주는 단계입니다.
폐쇄망을 가정해 임베딩·생성 모델을 오픈웨이트로 교체하고 Kubernetes/Helm 으로 배포하며, 대용량 규정 문서의 조항 검색을 pgvector 인덱스로 튜닝하고 질의·감사 이벤트를 Kafka 로 남기는 단계입니다.
규정 질의 시나리오 20개를 넣으면, 각 답변이 근거 조항을 인용하고 근거가 약한 질의는 담당자 에스컬레이션으로 라우팅되는 걸 시연합니다
인용한 조항이 실제 문서에 존재하고 답변 근거 span 과 겹치는지 규칙으로 채점합니다. 정답 40건 중 인용이 정확히 근거된 게 34건. 단, 정답과 규정 문서를 모두 작성자가 만든 합성 기준이라 '성능 검증'이 아니라 '데모 조건 동작'임을 명시합니다
일부러 만든 폐지 조항·조항 표기 흔들림·근거 없는 질문 30종을 넣어도 출력 형식(스키마)이 한 번도 안 깨지고, 근거 없는 질문은 답을 지어내지 않고 에스컬레이션합니다
위 수치는 전부 작성자가 만든 더미 규정 문서 자가채점이며, 실제 인용 정확도와 에스컬레이션 적정성은 인공지능팩토리가 다루는 실 공공기관 규정과 실무 담당자 검수가 있어야 측정 가능합니다. 이 도구는 그 검증을 바로 돌릴 수 있는 상태까지 만듭니다
이건 고객·실데이터 없이 혼자 만든 포트폴리오입니다. 모든 수치는 합성 규정 문서 자가채점이라 '성능 증명'이 아닙니다. 면접에서 솔직히 '데모 조건 동작 + 실검증 준비 상태'로 설명하는 게 오히려 신뢰를 줍니다
정답을 내가 만들었으니 잘 맞는 게 당연합니다. 그래서 일부러 폐지 조항·표기 흔들림·근거 없는 질문 같은 경계 케이스를 더미에 섞어, 쉬운 문제만 푸는 게 아님을 보여줘야 합니다
인용이 조항을 정확히 짚어도 그 해석이 질문에 맞는지는 별개 문제입니다. 인용 존재와 근거 겹침은 규칙으로 채점하지만 '해석의 타당성'은 실무 담당자 판단이 필요해 사람 검수 표본으로만 확인합니다
이 포트폴리오가 입증하는 것은 Spring Boot 상태머신 플로우·RAG 인용 근거 채점·pgvector 검색·컨테이너 배포 기술이지 공공 SI 도메인 전문성이나 국정원 보안 인증 통과가 아닙니다. 모르는 깊이는 면접에서 모른다고 말하는 편이 낫습니다
실제 도입 시 달라지는 것을 명시합니다. 실 규정은 개정이 잦고 별표·서식 참조가 복잡하며, 폐쇄망 오픈웨이트 모델의 답변 품질은 데모용 상용 모델과 다르므로 임계값과 검색 파라미터를 다시 맞춰야 합니다(도입 단계 과제로 분리)
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
공공기관 규정·지침을 조항 단위로 나눈 청크. RAG 검색과 인용 채점의 근거 원본입니다. 운영 현실대로 시행일 미기재·개정 폐지 조항·존재하지 않는 별표 참조·조항 표기 흔들림을 일부러 섞어, 쉬운 문서만 다루는 게 아님을 보여줍니다.
| doc_id | clause_id | title | chunk_text | effective_date | superseded_by | refers_to |
|---|---|---|---|---|---|---|
| reg_forest_2024 | 제5조 | 보전산지 입목벌채 허가 | 보전산지에서 입목을 벌채하려는 자는 관할 시장·군수의 허가를 받아야 … | 2024-03-01 | — | 별표2 |
| reg_forest_2024 | 제6조 | 벌채 제한 면적 | 한 필지에서 허가 없이 벌채할 수 있는 면적은 500제곱미터를 초과할… | — | — | — |
| reg_forest_2024 | 제7조 | 벌채 후 조림 의무(구) | 벌채한 자는 벌채 완료일부터 1년 이내에 조림을 완료하여야 합니다. | 2022-01-01 | 제7조의2 | — |
| reg_forest_2024 | 제7조의2 | 벌채 후 조림 의무 | 벌채한 자는 벌채 완료일이 속한 해의 다음 해 5월 31일까지 조림을… | 2024-03-01 | — | — |
| reg_forest_2024 | 제12조 | 벌칙 | 제5조를 위반하여 허가 없이 벌채한 자는 500만원 이하의 벌금에 처… | 2024-03-01 | — | 제5조 |
아래 JSON Schema 에 맞는 한국 공공기관 규정 조항 청크 40행을 JSON 배열로 생성. 문서 2~3종(산림·재난안전·연구지원 등), 조항 제1조~제20조 및 조의2 신설 조항 포함.
{"type":"object","properties":{"doc_id":{"type":"string"},"clause_id":{"type":"string"},"title":{"type":"string"},"chunk_text":{"type":"string"},"effective_date":{"type":["string","null"]},"superseded_by":{"type":["string","null"]},"refers_to":{"type":["string","null"]}},"required":["doc_id","clause_id","title","chunk_text"]}
쉬운 데이터만 만들지 말 것. 다음 하드 케이스를 의도적으로 섞어라(쉬운 문제만 푸는 함정 회피): (1) effective_date=null 인 시행일 미기재 조항 2~3건, (2) superseded_by 가 다른 조항 id 를 가리키는 개정 폐지 조항 2건과 그에 대응하는 조의2 신설 조항, (3) refers_to 가 존재하지 않는 별표(예: 별표9)를 가리키는 orphan 참조 1~2건, (4) chunk_text 안 조항 표기가 clause_id 와 다른 표기 흔들림('제3조' vs '3조') 1~2건, (5) 아주 짧은 목적 조항(경계값) 1건. JSON 배열만.{"type":"object","properties":{"doc_id":{"type":"string"},"clause_id":{"type":"string"},"title":{"type":"string"},"chunk_text":{"type":"string"},"effective_date":{"type":["string","null"]},"superseded_by":{"type":["string","null"]},"refers_to":{"type":["string","null"]}},"required":["doc_id","clause_id","title","chunk_text"]}규정 질의와 그에 대한 정답 근거 조항·에스컬레이션 여부. 인용 근거 결정론 채점의 정답지입니다. 근거 없는 질문(정답=에스컬레이션)·폐지 조항 함정·표기 흔들림을 섞어, 답을 지어내지 않는지와 개정 조항을 짚는지를 검증합니다.
| qid | question | gold_clause_ids | should_escalate | note |
|---|---|---|---|---|
| q01 | 보전산지에서 나무를 베려면 누구의 허가를 받아야 하나요? | ["제5조"] | false | — |
| q02 | 허가 없이 벌채할 수 있는 면적 한도는 얼마인가요? | ["제6조"] | false | 시행일 미기재 조항이지만 조문 내용으로 답변 가능 |
| q03 | 벌채 후 조림은 언제까지 끝내야 하나요? | ["제7조의2"] | false | 폐지된 제7조가 아니라 개정 제7조의2 가 정답. 폐지 조항 인용 시… |
| q04 | 기초생활수급자의 재난지원금 가산은 얼마인가요? | ["제3조의2"] | false | '3조'/'제3조' 표기 흔들림 정규화 필요 |
| q05 | 재난지원금 이의신청 기한은 며칠인가요? | ["제9조"] | false | 조항이 별표9를 참조하나 별표9 미첨부. 조문만으로 답변 가능 |
아래 JSON Schema 에 맞는 규정 질의응답 정답지 40행을 JSON 배열로 생성. regulation_chunks 의 clause_id 와 매칭되도록.
{"type":"object","properties":{"qid":{"type":"string"},"question":{"type":"string"},"gold_clause_ids":{"type":"array","items":{"type":"string"}},"should_escalate":{"type":"boolean"},"note":{"type":["string","null"]}},"required":["qid","question","gold_clause_ids","should_escalate"]}
쉬운 데이터만 만들지 말 것. 하드 케이스 의도적 혼입: (1) gold_clause_ids=[] 이고 should_escalate=true 인 근거 없는 질문 6~8건(지어내면 안 되는 질의), (2) 폐지된 조항이 아니라 개정 조항이 정답인 함정 질의 2건(note 에 폐지 조항 인용 시 오답 명시), (3) '3조'/'제3조' 같은 표기 흔들림 정규화가 필요한 질의 2건, (4) 여러 조항을 조합해야 답이 되는 질의 2건. 그 외 단일 조항 정답 질의. JSON 배열만.{"type":"object","properties":{"qid":{"type":"string"},"question":{"type":"string"},"gold_clause_ids":{"type":"array","items":{"type":"string"}},"should_escalate":{"type":"boolean"},"note":{"type":["string","null"]}},"required":["qid","question","gold_clause_ids","should_escalate"]}| Python | 규정 문서 청킹·임베딩 ingest 파이프라인과, 인용 근거가 맞는지 채점하는 평가 스크립트 |
| Spring Boot | Java 기반 질의응답 API 와 상태머신 플로우 오케스트레이션(접수 → 검색 → 근거 판정 → 답변 또는 에스컬레이션), 감사 로그 |
| PostgreSQL | 규정 조항 청크와 pgvector 임베딩·인용 추적을 담는 단일 진실원, 대용량 조항 검색 인덱스 튜닝 |
| Redis | 검색 결과·세션 캐시와 담당자 에스컬레이션 큐 상태 보관 |
| Kafka | 질의·감사 이벤트 비동기 스트림(누가 무엇을 언제 물었고 어떤 조항으로 답했는지) |
| Docker | 폐쇄망을 가정해 전체 스택을 compose 로 로컬 구동 |
| Kubernetes | 온프레미스 배포용 Helm 차트로 3주차 폐쇄망 구동 |
| NGINX | 사내망 리버스 프록시 겸 게이트웨이 |
| AWS CodeDeploy | 2주차부터 AWS 로 CI/CD 배포·운영 |
| GitHub | 소스 관리와 GitHub Actions CI(테스트·컨테이너 이미지 빌드) |
✓ pass → 그대로 멈춰도 완결입니다. 더 키우고 싶으면 2주차(상태머신 플로우 + 인용 근거 결정론 채점)로 진행합니다.
✓ pass → 여기서 멈춰도 완결입니다. 더 키우면 3주차(온프레미스 배포 + 대용량 조항 검색·감사 로그)로 진행합니다.
규정 질의에 대해 근거 조항을 인용한 답변을 생성하고, 근거가 실제 조항에 있는지 추적 가능하게 담습니다. 근거가 부족하면 답을 지어내지 않고 담당자 에스컬레이션으로 결정합니다.
{"type":"object","properties":{"query":{"type":"string"},"answer":{"type":"string"},"citations":{"type":"array","items":{"type":"object","properties":{"doc_id":{"type":"string"},"clause_id":{"type":"string"},"quoted_span":{"type":"string"},"char_start":{"type":"integer"},"char_end":{"type":"integer"}},"required":["doc_id","clause_id","quoted_span"]}},"grounding":{"type":"object","properties":{"supported":{"type":"boolean"},"matched_clause_ids":{"type":"array","items":{"type":"string"}}},"required":["supported","matched_clause_ids"]},"decision":{"type":"string","enum":["answer","escalate"]},"escalation_reason":{"type":["string","null"]},"confidence":{"type":"number"}},"required":["query","answer","citations","grounding","decision"]}[
{
"input_ref": "q01 · 보전산지 벌채 허가 질의",
"output": {
"query": "보전산지에서 나무를 베려면 누구의 허가를 받아야 하나요?",
"answer": "보전산지에서 입목을 벌채하려면 관할 시장·군수의 허가를 받아야 합니다. 신청 시 벌채구역도와 사업계획서를 첨부합니다.",
"citations": [
{
"doc_id": "reg_forest_2024",
"clause_id": "제5조",
"quoted_span": "관할 시장·군수의 허가를 받아야 하며",
"char_start": 24,
"char_end": 41
}
],
"grounding": {
"supported": true,
"matched_clause_ids": [
"제5조"
]
},
"decision": "answer",
"escalation_reason": null,
"confidence": 0.9
}
},
{
"input_ref": "q03 · 벌채 후 조림 기한(폐지 조항 함정)",
"output": {
"query": "벌채 후 조림은 언제까지 끝내야 하나요?",
"answer": "벌채한 자는 벌채 완료일이 속한 해의 다음 해 5월 31일까지 조림을 완료하여야 합니다.",
"citations": [
{
"doc_id": "reg_forest_2024",
"clause_id": "제7조의2",
"quoted_span": "다음 해 5월 31일까지 조림을 완료하여야 합니다",
"char_start": 18,
"char_end": 40
}
],
"grounding": {
"supported": true,
"matched_clause_ids": [
"제7조의2"
]
},
"decision": "answer",
"escalation_reason": null,
"confidence": 0.82
}
},
{
"input_ref": "q06 · 근거 없는 질의(에스컬레이션)",
"output": {
"query": "산불 진화 헬기 임차 비용은 누가 부담하나요?",
"answer": "이 질문에 답할 근거 조항을 규정집에서 찾지 못했습니다. 담당자 확인이 필요합니다.",
"citations": [],
"grounding": {
"supported": false,
"matched_clause_ids": []
},
"decision": "escalate",
"escalation_reason": "검색된 조항 중 산불 진화 헬기 임차 비용을 규정한 조문이 없어 답을 생성하지 않았습니다.",
"confidence": 0.2
}
}
][자동 검증(규칙·결정론으로 채점)] 1) 스키마 통과: 출력이 위 JSON Schema 형식을 지키는지(citations·grounding·decision 필드 존재와 타입 확인). 2) 인용 존재: 각 citation 의 doc_id·clause_id 가 regulation_chunks 에 실제 있고, quoted_span 이 해당 조항 chunk_text 의 substring 인지(지어낸 인용 차단). 3) 근거 겹침: 인용한 clause_id 가 qa_gold 의 gold_clause_ids 와 겹치는지(정답 조항을 짚었는지). 4) 에스컬레이션 정합: gold 의 should_escalate=true 질의에서 decision 이 'escalate' 이고 citations 가 비어 있는지(근거 없는 질문에 답을 지어내지 않는지). 5) 폐지 조항 차단: superseded_by 가 있는 조항을 인용하면 오답 처리(개정 조항으로 유도). [수동 검증(사람이 봐야 하는 것)] 6) 공무원 민원 담당 페르소나 2명이 답변 해석이 타당한지 비동기 라벨 → 일치도 Cohen's κ(두 사람 판단이 우연 이상으로 일치하는 정도, 0~1) 하한 0.6 이상. 7) 에스컬레이션 사유가 실무적으로 납득되는지 5% 표본 사람 점검.