Repository navigation
Project Overview
dev
a9974a0(2026-10-12) 기준
AI 손해사정 플랫폼(팀 윤동주)의 AI 엔진 저장소다. 사용자가 사고 정보와 진단서·보험증권을 올리면 이 엔진이 문서를 읽고(OCR), 개인정보를 가리고, 약관·판례·분쟁조정사례를 검색해 보험금 리포트 초안을 만든다. 초안은 사용자에게 바로 가지 않고 등록 손해사정사의 검수를 거친다. 서비스 전체의 문제 정의와 B2B2C 구조는 Backend 위키의 프로젝트 개요에 있다.

서비스 흐름. 이 저장소가 맡는 곳은 2~3단계(문서 처리·초안 생성)다. 사람이 손대지 않는 구간이라, 틀린 값이 사람에게 닿기 전에 걸러지도록 단계마다 게이트를 둔다
| 컴포넌트 | 방식 | 하는 일 | 위치 |
|---|---|---|---|
| OCR 워커 | SQS 워커 (ocr-job-queue 소비) |
GPU OCR, 문서 분류·추출, PII 마스킹(텍스트+이미지), 하이브리드 VLM, 청구 단위 fan-in, report-job 발행 |
src/ocr_worker · 구성
|
| 리포트 워커 | SQS 워커 (report-job 소비) |
LangGraph 멀티에이전트로 진단 분류·약관 대조·판례·후유장해·보험금 범위·리포트 초안 |
src/report_worker · 구성
|
| 챗봇 | FastAPI WebSocket 직결, 비스트리밍 | 입력 가드레일 → RAG → LLM → 출력 가드레일, 완성 응답 1회 | src/chatbot |
| RAG | 공용 모듈 | 키워드(tsvector + trigram) + 벡터(pgvector HNSW) → RRF |
src/rag · 파이프라인
|
| 가드레일 | 공용 모듈 | 입력(PII·도메인 차단) / 생성(단정 금액 치환·인용 강제) / 출력(고지문·LLM Judge) | src/guardrail |
| corpus 워커 | 상시 폴링 데몬 | Notion의 약관 PDF를 PG에 미러링하고 우선순위대로 S3에 스테이징 | src/corpus_worker |
AI 모델은 모두 자체 GPU 인스턴스의 Ollama로 서빙한다. 사용자 문서의 개인정보가 외부 API로 나가지 않게 하려는 것이고, 약관처럼 반복 처리량이 큰 작업에서 외부 LLM API 비용을 피하려는 것이기도 하다.
| 용도 | 모델 |
|---|---|
| OCR | surya-ocr 0.17.x (in-process, GPU) |
| 이름 NER | KoELECTRA-small 계열 한국어 NER (CPU) |
| VLM 표 전사 | qwen3.6:35b-a3b |
| VLM PII 좌표 | qwen3-vl:8b-instruct |
| 리포트·챗봇 LLM | Ollama 서빙 LLM (설정값 LLM_MODEL) |
| 임베딩 | qwen3:embedding 1024d (폴백 BGE-M3) |

전체 구조. 무거운 작업(OCR·리포트)은 SQS 뒤의 워커로 가고, 워커와 API는 같은 RDS·S3를 쓴다. 약관은 오프라인 파이프라인이 미리 청킹해 pgvector에 넣어 둔다
- 업로드·JWT·S3 저장·SQS 발행은 Spring Boot 게이트웨이가 맡는다. AI 엔진은 백엔드를 호출하지 않는다.
- 백엔드는 청구의 문서마다 OCR 트리거를 하나씩 보낸다. 메시지에는 식별자만 있고 문서 내용은 없다.
- 결과와 상태는 공유 DB에 쓴다. 그래서 스키마 소유권과 상태값 계약을 양쪽이 같이 지켜야 한다.
sequenceDiagram
participant BE as Spring Boot
participant Q1 as SQS ocr-job-queue
participant OCR as OCR 워커
participant Q2 as SQS report-job
participant RPT as 리포트 워커
participant DB as PostgreSQL
BE->>DB: reports·첨부 shell 행 생성
BE->>Q1: OcrJob × 문서 수 (claim_id, report_id, doc_index, doc_total)
Q1->>OCR: 롱폴링 수신
OCR->>DB: ai.ocr_results 저장 + 종결 카운트 (같은 트랜잭션)
Note over OCR: 청구의 모든 문서가 종결될 때까지 대기 (fan-in)
OCR->>Q2: ReportJob 1건 (ocr_quality = ok / needs_reupload)
Q2->>RPT: 수신
alt ocr_quality = needs_reupload
RPT->>DB: reports.status = NEEDS_REUPLOAD
else 정상
RPT->>DB: 리포트 초안 저장 (report_id 기준 덮어쓰기)
end
BE->>DB: 상태·초안 조회, 실패·재업로드 상태는 스윕으로 알림
| 스키마 | 소유 | 다른 쪽의 권한 |
|---|---|---|
core |
백엔드 | 워커는 필요한 테이블·컬럼만 읽고, reports.status는 정해진 값만 갱신 |
ai |
AI 엔진 (OCR·리포트) | 백엔드는 ocr_job_failures·report_drafts SELECT, ocr_results는 식별·상태 7개 컬럼만 SELECT |
corpus |
corpus 워커·청킹 파이프라인 | 리포트·챗봇은 검색용 SELECT |
워커가 다른 워커의 테이블에 쓰지 않고 메시지로 넘긴다는 규칙은 청구 fan-in 기록에서, 마이그레이션을 워커별로 나눈 이유는 스키마 기록에서 볼 수 있다.

Docker Compose 시기의 AWS 구성. GPU가 필요한 OCR 워커와 Ollama는 별도 GPU 인스턴스, 리포트 워커는 백엔드와 같은 범용 인스턴스에 있었다
| 서비스 | 배포 대상 | 경로 |
|---|---|---|
| OCR 워커 | GPU EC2 (Ollama 동거) | GitHub Actions → ECR → SSM |
| corpus 워커 | 경량 EC2 | GitHub Actions → ECR → SSM |
| 리포트 워커·챗봇 | dev Kubernetes | GitHub Actions가 매니페스트 레포의 image.tag를 커밋 → Argo CD 반영 (PR #69, 2026-10-12) |
- 마이그레이션 경로 필터는 워커별로 나뉘어, 마이그레이션만 바뀌어도 해당 워커가 다시 배포된다(PR #51).
- GPU 인스턴스는 node-exporter·cAdvisor·DCGM exporter·Alloy로 중앙 모니터링에 편입했다(2026-09-03).
- Argo CD 경로에서 CI 성공은 "매니페스트를 커밋했다"는 뜻일 뿐이다. 실제 반영 결과는 Argo CD 알림이 보내고, CI는 실패만 알린다(PR #70).

초기 리포트 그래프 스케치. 지금 그래프([리포트 워커 구성](Report-Worker))에는 입력·출구 가드레일, 장해 분류 감수, 규칙 기반 합산, 보험금 계산이 단계로 더해졌다
-
브로커: Kafka(MSK)에서 SQS로 바뀌었다(PR #53, 2026-08-10). 메시지 계약(
OcrJob·ReportJobJSON)은 그대로 두고 수신 방식만 바꿨다. 경위는 Backend: OCR 트리거 브로커를 Kafka에서 MSK를 거쳐 SQS로 전환에 있다. - OCR 엔진: 기획 단계의 PaddleOCR에서 surya-ocr로 바뀌었고, 표·저화질 문서에는 VLM을 더했다(VLM 하이브리드 기록).
- 업로드 주체: 처음엔 FastAPI가 문서를 받아 동기 OCR로 폼을 채우는 안도 검토했다. GPU 인스턴스가 비싸 API를 같이 올리기 어려웠고, 결국 업로드는 Spring Boot가, OCR은 큐 뒤의 워커가 맡았다.
- 청구 단위 처리: 문서 1건 = 리포트 1건에서, 청구의 모든 문서를 모아 리포트 1건으로 바뀌었다.
구성과 설계 근거
OCR 인식 · VLM 보완
개인정보 보호 · 마스킹
리포트 정확도
배포 · 데이터 파이프라인
레퍼런스