- 260312/260315/260316 계열 트러블/리서치/계획/시나리오/워크로그 - 본문에만 닫힘 표기되어 있던 문서에 status: closed 프론트메타 추가 - 열린 문서는 260320 다형식문서 RAG 체인 10개만 남음 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
30 KiB
status, closed_date, closed_reason, tags
| status | closed_date | closed_reason | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|
| closed | 2026-03-21 | 260320 다형식문서 RAG 계획으로 흡수 또는 구현 완료 |
|
status: closed closed_date: 2026-03-21 closed_reason: 260320 다형식문서 RAG 계획으로 흡수 또는 구현 완료
Company X RAG 답변합성 시나리오·트러블 동시종결 계획
작성일: 2026-03-15
상태: 닫힘 — 미완료 항목은 260320 계획으로 흡수
검토일: 2026-03-17
갱신일: 2026-03-20
종결 사유: 260320 다형식문서 RAG 계획이 범위를 확장(벡터+키워드+Apache AGE 3중 검색)하여 본 계획의 미완료 항목(5A 배포, 5B 검증)을 흡수. 워크로그 참조.
후속 계획: 260320 로빙 다형식문서 RAG 적용1 계획
목표: Company X 내부문서 근거응답 경로를 대표 질문 특례 처리에서 공통 계약 기반 답변합성 구조로 바꾸되, 구현 전에 현재 NAS 문서 운영 상태 + 현재 임베딩 전제를 다시 닫고 대응 troubleshooting 문서와 scenario 문서를 함께 닫습니다.
2026-03-17 코드 검토 결과 (갱신):
- Phase 1~3(구조 분리, 질문 유형 계약, 근거 채택 판정): 구현 완료
- Phase 4(LLM 전환 + Pydantic 출력 검증): 구현 완료 —
_call_llm_companyx_grounding()+CompanyXRAGOutputPydantic 검증.settings.DEFAULT_LLM_MODEL(gpt-5-mini) SSOT 참조.- Phase 5A(인덱싱 파이프라인 전환): 코드 전환 완료, 배포 미완료 — PDF 6페이지 분할 → Base64 →
embed_items(),task_type(RETRIEVAL_DOCUMENT/QUERY) 전달,metadatapass-through 구현. skill-embedding + skill-rag-file 양쪽 반영.- Phase 5B: 미완료 — A 배포 후 진행. 상세 내용: 260317_companyx_grounding_코드검토_및_문서현행화
관련 문서
- Company X RAG 답변 합성 회귀
- Company X 내부 문서 RAG 응답 아이디어
- Company X 내부 문서 근거응답 사용자 시나리오
- Company X RAG 답변합성 시나리오·트러블 동시종결 리서치
- Company X RAG 스킬 문서
연결 구조
- 같은 레벨 입력:
ideas/260312_companyx_내부문서_rag_응답_아이디어.md,scenarios/260312_companyx_내부문서_근거응답_사용자시나리오.md - 단일 리서치:
research/260315_companyx_rag_답변합성_시나리오동시종결_리서치.md - 단일 플랜: 본 문서 1개
- 닫힘 흐름: 본 플랜 완료 기준 충족 시 시나리오/리서치/트러블 동시 닫힘 (아이디어 문서는 종결 상태 유지)
1. 이번 계획의 결정
- 현재 코드 기준으로 Phase 1~3(구조 분리, 질문 유형 계약, 근거 채택 판정)은 구현 완료 상태입니다.
- Phase 4(LLM 전환 + Pydantic 출력 검증)는 구현 완료입니다.
_call_llm_companyx_grounding()+CompanyXRAGOutputPydantic 검증 도입. - 남은 핵심은
Phase 5A 배포+Phase 5B 테스트/검증입니다. - 저장 전제 (SSOT): PostgreSQL
team_document_chunk가skill-rag-file문서 청크의 Single Source of Truth입니다.upload.py,reindex.py,search.py모두PostgresDocumentVectorStore를 사용하며, ChromaDB는 레거시 실험 스크립트(rebuild_chroma_collection.py)에서만 쓰이고 운영 API와 분리됩니다. 이 계획에서 "DB 전환" 작업은 없으며, 대신 스키마 최적화 및 인덱스 재생성 관점에서 관리합니다. - 임베딩 전제 갱신: 컬렉션 차원
384는 더 이상 사용하지 않으며,768도 Gemini 2 기준으로 전량 재임베딩해야 합니다. - Go 전환 근거: 내부 NAS Go 동기화 리서치의 1분 벤치마크는 Go가 Python 대비 총 사이클 +5~6% 수준이며, “무조건 큰 폭의 시간 단축”을 보장하지 않습니다.
- 인덱싱 파이프라인 전환:
skill-rag-file의 텍스트 변환 후 청킹 방식(pdftotext/PyPDF2/OCR/문자단위 분할)을 Gemini Embedding 2 원본 파일 직접 임베딩으로 전환합니다. 이 계획에서 닫습니다. 텍스트 변환 방식으로 임베딩한 뒤 전환하면 전량 재임베딩이 두 번 발생하므로, 파이프라인 전환이 임베딩보다 반드시 선행합니다. - 임베딩 전담 원칙: 임베딩 관련 로직은
skill-embedding이 전담합니다.skill-rag-file에서 Gemini API를 직접 호출하면 모델 관리와 비용 트래킹이 파편화되므로, PDF/이미지 바이트 입력 엔드포인트를skill-embedding에 추가하는 방향으로 확장합니다. - 이 문제는
검색 인프라 확장보다답변 합성 계약 부재문제로 다룹니다. - 질문별
if분기, 질문별 direct answer, 질문별 프롬프트 추가로 닫지 않습니다. Company X grounding경로에 공통 계약 3개를 먼저 고정합니다.- 질문 유형 계약
- 근거 채택 계약
- 근거 부족 시 실패 계약
- 성공 기준은
검색 hit 존재가 아니라직접 답 + 질문 적합 근거 또는 명시적 부족 안내로 바꿉니다.
2. 범위
- 포함:
skill-rag-file인덱싱 파이프라인 → Gemini Embedding 2 원본 파일 직접 임베딩 전환- Company X RAG의 현재 임베딩 경로/차원 재검증
- NAS 최신 문서 동기화본과 검색 컬렉션 반영 상태 확인
rb8001/app/services/companyx_grounding_service.py- Company X 재오픈 기준 질문 20개의 응답 계약
SKILL.md와 코드 계약 정합화- 테스트 보강
- 제외:
- Company X 전체 문서셋 대규모 확대
- 다른 RAG 경로 공통화
- Prompt DB 전면화
skill-rag-file자체 리팩토링 (인덱싱 파이프라인 전환 외)
3. 공통 계약 고정안
A. 질문 유형 계약
- 최소 유형은 아래 4개로 고정합니다.
- 설명형
- 사실 확인형
- 수치 확인형
- 재정리형
- 판단 결과는 코드 내부 enum 또는 동등한 상수로 다룹니다.
- 질문별 문자열 특례가 아니라 유형별 처리로 묶습니다.
B. 근거 채택 계약
- 검색 결과가 있다고 바로 근거로 채택하지 않습니다.
- 채택 기준:
- 질문의 핵심 엔티티와 직접 관련이 있어야 합니다.
- 질문 유형에 맞는 문서여야 합니다.
- 상위 결과라도 질문과 무관하면 버립니다.
relevance_score는 후보 신호일 뿐, 최종 성공 판정 기준이 아닙니다.
C. 실패 계약
- 아래 경우는 성공처럼 반환하지 않습니다.
- 검색 결과 0개
- 검색 결과는 있으나 질문과 무관
- 수치/규정 질문인데 단정 가능한 근거가 없음
- 실패 응답은 아래 셋 중 하나로 고정합니다.
문서 없음질문과 맞는 문서 미확인내부 문서만으로는 단정 불가
4. 구현 원칙
- 인덱싱 파이프라인 전환: 텍스트 변환 후 청킹하는 현재 방식을 Gemini Embedding 2의 멀티모달 직접 임베딩으로 전환합니다.
- 대상: PDF, 이미지, docx 등 모든 파일 형식 — 텍스트 추출 없이 원본 파일 직접 임베딩
- 제한: 텍스트 8,192 토큰, PDF 6페이지 단위, 영상 120초, 오디오 80초
- 기존 텍스트 추출 파이프라인(pdftotext, PyPDF2, OCR)은 제거 대상
- RAG 구조 전환: 현재 규칙 기반 문자열 조합은 RAG가 아닙니다. 검색된 청크를 컨텍스트로 LLM에 전달해 답변을 생성하는 구조로 전환합니다.
- 플로우: 질문 임베딩 → pgvector 유사도 검색 → 적합 청크 선별 → LLM 컨텍스트 전달 → 답변 생성
- LLM: 현재 rb8001 기준 모델 사용 (gpt-4o-mini 계열)
- 근거 부족 시 LLM에게 "문서 없음"을 명시적으로 지시하는 시스템 프롬프트 포함
- LLM 출력 형식 강제: LLM 응답을 프롬프트 지시만으로 믿지 않습니다.
Pydantictyped validation으로 출력 형식을 검증합니다.- 근거: Pydantic AI 도입 기반 LLM 출력 안정화 방향확정 리서치 — 프롬프트만으로 형식 일탈을 막지 못함이 실측 확인됨
- 방식:
Pydantic-only우선 (Pydantic AI는 의존성 부담으로 2차) - 핵심: 텍스트를 생성하는 것이 아니라
evidence_docs와failure_reason을 구조화된 JSON으로 받는 것이 목적입니다. Slack UI나 다른 채널로 전달 시 파싱 에러를 원천 차단합니다. - 출력 스키마:
direct_answer(str),evidence_docs(List[str]),failure_reason(Optional[str])필드 고정 - 검증 실패 시 성공처럼 반환하지 않습니다. 명시적 실패 응답으로 처리합니다.
SKILL.md의 답변 순서(direct answer -> evidence documents -> short evidence summary)를 LLM 프롬프트 계약으로 내립니다.- 질문별 direct answer 하드코딩을 더 늘리지 않습니다.
- 질문 유형 판정과 근거 채택 판정은 별도 함수로 분리합니다.
검색됨과답할 수 있음을 같은 상태로 취급하지 않습니다.- 메타 대화(
어떤 부분이 더 필요하신지...)는 실패 기본 경로로 사용하지 않습니다.
5. 구현 단계
병렬 실행 구조 — 트랙 A / B / C
간섭 없이 3개 트랙으로 분리됩니다.
트랙 담당 Phase 건드리는 서비스 상태 A — 인덱싱 파이프라인 Phase 5A skill-embedding+skill-rag-file인덱싱 경로 (upload.py,reindex.py)코드 완료, 배포 대기 B — LLM 답변 합성 Phase 4 (Phase 1~3 구현 완료) rb8001/companyx_grounding_service전용구현 완료 C — 테스트·검증 Phase 5B A + B 결과물 A 배포 후 진행 A와 B가 간섭 없는 이유: A는
skill-embeddingAPI 확장 +skill-rag-file인덱싱 경로(upload/reindex) 수정. B는rb8001/companyx_grounding_service에서 LLM 호출 + Pydantic 검증 추가. 공유 파일 없음.A·B 시작 전 1회 합의 필요: 아래 멀티모달 임베딩 API 규격. 이것만 고정하면 A·B 독립 진행 가능합니다.
C는 A·B 완료 후: 선행 의존이 명확하므로 병렬 불가.
트랙 A·B 공유 인터페이스 계약: skill-embedding 멀티모달 엔드포인트
이 규격은 트랙 A(skill-embedding 구현측)와 트랙 B(rb8001 소비측)가 독립 개발을 착수하기 위한 합의 기준입니다.
현재 상태 (2026-03-17 코드 확인)
기존 POST /embed 엔드포인트가 이미 멀티모달 입력 구조를 갖고 있습니다.
- 활성 서비스:
skill-embedding-repo/(Gemini Embedding 2 기반,GeminiEmbedder) - 레거시 서비스:
skill-embedding/(ONNX 기반) — 배포 이미지 불일치 의심은 해소됨 - 기존
EmbedItem모델에mime_type+data_base64필드가 이미 존재:class EmbedItem(BaseModel): text: Optional[str] = None mime_type: Optional[str] = None # application/pdf, image/jpeg 등 data_base64: Optional[str] = None # Base64 인코딩 바이너리 dimensions: 환경변수EMBEDDING_DIM=768고정. 요청별 지정 불가이나 768 고정이므로 문제 없음.MAX_BATCH_SIZE: 100 (환경변수로 조정 가능)
따라서 신규 엔드포인트(/v1/embed/multimodal)를 만들지 않고, 기존 POST /embed를 확장합니다.
기존 엔드포인트 확장 — 구현 완료
| 항목 | 구현 내용 |
|---|---|
task_type |
EmbedRequest.task_type 필드 추가 → GeminiEmbedder.encode(task_type=...) → EmbedContentConfig(task_type=...) 전달. skill-rag-file: 인덱싱 시 RETRIEVAL_DOCUMENT, 검색 시 RETRIEVAL_QUERY 전달. |
metadata pass-through |
EmbedItem.metadata 필드(dict) 추가 → 임베딩 처리에서 제외 → EmbedResponse.item_metadata로 그대로 반환. |
확장 후 Request Payload
{
"items": [
{
"mime_type": "application/pdf",
"data_base64": "BASE64_ENCODED_STRING",
"metadata": {
"file_path": "/mnt/nas/6.Company X/...",
"page_range": [1, 6],
"chunk_index": 0
}
},
{
"mime_type": "image/jpeg",
"data_base64": "BASE64_ENCODED_STRING",
"metadata": {
"file_path": "/mnt/nas/6.Company X/...",
"chunk_index": 0
}
}
],
"task_type": "RETRIEVAL_DOCUMENT"
}
| 필드 | 설명 |
|---|---|
data_base64 |
파일 바이너리의 Base64 인코딩 문자열. PDF는 6페이지 단위로 분할된 바이너리. |
mime_type |
application/pdf, image/png, image/jpeg 등 Gemini가 직접 처리할 수 있는 형식. |
metadata |
skill-embedding은 처리하지 않고 결과에 그대로 반환(pass-through). 클라이언트가 결과 매핑에 사용. |
task_type |
RETRIEVAL_DOCUMENT(인덱싱) 또는 RETRIEVAL_QUERY(검색). Gemini Embedding API 최적화 힌트. |
확장 후 Response Payload
기존 EmbedResponse에 metadata 리스트를 추가합니다:
{
"embeddings": [[0.123, -0.456, ...]],
"item_metadata": [
{
"file_path": "/mnt/nas/6.Company X/...",
"page_range": [1, 6],
"chunk_index": 0
}
],
"model": "gemini-embedding-2-preview",
"backend": "gemini",
"dimensions": 768,
"processing_time": 1.23
}
에러 처리
기존 FastAPI 에러 응답 구조를 유지하되, batch 부분 실패 시:
{
"error": {
"code": "UNSUPPORTED_MIME_TYPE | PAYLOAD_TOO_LARGE | EMBEDDING_API_FAILURE",
"message": "상세 사유",
"failed_indices": [0, 2]
}
}
failed_indices: batch 중 실패한 input의 인덱스. 성공한 항목은 정상 반환하고 실패 항목만 별도 표시.
역할 분리 원칙
- PDF를 6페이지 단위로 나누는 로직은
skill-rag-file이 담당 (파일 시스템 접근 권한 보유) skill-embedding은 순수하게 '바이너리 → 벡터' 변환만 수행- 검색 시 질문(텍스트) 임베딩은 기존
POST /embed의texts필드 그대로 사용 (768d 고정,task_type=RETRIEVAL_QUERY추가)
확인 완료 항목
기존→ 환경변수/embed엔드포인트가dimensions=768을 지원하는지EMBEDDING_DIM=768고정. 확인 완료.skill-embedding 레포 코드(ONNX)와 배포 이미지(Gemini 2) 불일치→skill-embedding-repo가 Gemini 2 기반 활성 서비스. 해소.- Base64 인코딩 시 6페이지 PDF 바이트 크기 → nginx/gunicorn HTTP payload 크기 제한과 맞춰야 함 (구현 시 확인)
Phase 0. 운영 전제 재검증
- 확인 항목과 결과:
| 항목 | 결과 | 상태 |
|---|---|---|
| Company X RAG 임베딩 차원 | 384d 폐기, Gemini Embedding 2 / 768d 확정 (0_VALUE 정책) |
확정 |
| SKILL.md 전제 | 384d → Gemini Embedding 2 / 768d 갱신 완료 (2026-03-17) |
확정 |
| 저장 경로 (rb8001 메모리) | PostgreSQL memory_vectors 등 중심 전환 확인 |
확정 |
| 저장 경로 (skill-rag-file 문서 청크) SSOT | PostgreSQL team_document_chunk. upload.py, reindex.py, search.py 모두 PostgresDocumentVectorStore 사용 확인. "DB 전환" 아님 — 스키마 최적화 및 인덱스 재생성 관점으로 관리. |
확정 |
| ChromaDB 레거시 격리 | rebuild_chroma_collection.py — 실험용/레거시. 운영 API와 완전 분리됨. 긴급하지 않으나 정리 대상. |
레거시 격리 |
| 인덱싱 파이프라인 | PDF 6페이지 단위 바이너리 직접 임베딩으로 전환 완료 (IndexingPipelineService). 비PDF는 텍스트 추출 fallback 유지. task_type 구분(RETRIEVAL_DOCUMENT/QUERY) 적용. |
코드 완료, 배포 대기 |
| NAS 동기화 경로 | 확인 완료 (2026-03-17). NAS 마운트: /mnt/nas (CIFS //192.168.0.101/home). Company X 원본: /mnt/nas/workspace/6.Company X/ (53,249개). 외부→내부 NAS 동기화: cron 2건 (30분 주기 계층형 + 하루 1회 전수조사, Go 바이너리). 단, NAS → skill-rag-file 인덱싱은 자동화 없음 — 현재 수동 upload API 호출만 가능. 업로드 저장소(/mnt/hdd/data/documents/)에 114개만 인덱싱된 상태. 1순위 2,957개 투입에는 NAS 경로에서 직접 읽어 upload API를 일괄 호출하는 배치 스크립트 필요. |
확인 완료 (배치 투입 수단 미구현) |
| 재오픈 질문 20개 재현 | Slack 실응답 재현 미실시 | 미완료 |
- 현재 상태:
- 임베딩/저장 전제는 확정됨.
- 인덱싱 파이프라인 코드 전환 완료, 배포 대기.
- NAS 동기화 경로 확인 완료. NAS 원본 53,249개 중 114개만 인덱싱. 대량 투입 배치 스크립트가 Phase 5A 남은 핵심 작업.
- 재오픈 질문 20개 재현은 Phase 5B에서 검증.
Phase 1. 구조 분리 — 구현 완료
companyx_grounding_service에서 아래 책임을 분리합니다.- 질문 유형 판정
- query candidate 생성
- retrieval 결과 수집
- 근거 채택 판정
- direct answer 생성
- failure answer 생성
- 목표:
- 현재 질문별 특례 분기와 generic fallback이 어디서 작동하는지 코드상 경계를 명확히 나눕니다.
Phase 2. 질문 유형 계약 도입 — 구현 완료
- 최소 4개 유형 분류 함수를 추가합니다.
- 재오픈 기준 질문 20개는 각 유형에 명시 매핑돼야 합니다.
- 아래 3개는 대표 매핑 예시입니다.
컴퍼니엑스의 투자사는 몇개야?-> 수치 확인형그럼 컴퍼니엑스 내부 규정 상 휴가는 얼마나 쓸 수 있어?-> 사실 확인형 또는 규정 확인형 성격오늘전통 프로그램을 Company X가 옐로펀치랑 같이 운영한다는 근거 있어?-> 사실 확인형
Phase 3. 근거 채택 판정 — LLM 위임으로 전환
- 검색 결과를 그대로 상위 3개 노출하지 않습니다.
- 키워드 기반 룰 필터링은 룰베이스 절제 원칙(global-principles.md §B.6)에 따라 제거했습니다.
- 벡터 유사도 상위 결과를 문서 다양성 기준으로 선택한 뒤, LLM에 컨텍스트로 전달합니다.
- LLM이 컨텍스트를 보고 질문 적합도를 재판단하며, 무관한 청크는 LLM이
failure_reason으로 처리합니다. 휴가질문에todaytradition청크가 잡히는 경우는 LLM이질문과 맞는 문서 미확인으로 답해야 합니다.
Phase 4. LLM 기반 답변 생성 + Pydantic 출력 검증 — 구현 완료
- 현재
_build_direct_answer()규칙 문자열 조합을 LLM 호출로 대체합니다. - 전체 흐름 (이 Phase가 책임지는 경계):
- Phase 3에서 선별된 청크 원문(질문과 무관한 청크는 이미 탈락)을 컨텍스트로 조합
- 질문 유형별 시스템 프롬프트 + 컨텍스트 + 사용자 질문을 LLM에 전달
- LLM은 컨텍스트를 보고 질문에 답할 수 있는지 재판단 — 컨텍스트가 있어도 질문에 답하기 부족하면
failure_reason을 채움 - LLM 응답을 Pydantic 모델로 검증 (
direct_answer,evidence_docs,failure_reason) - 검증 통과 시 구조체를 파싱해 답변 조합 (직접 답 + 근거 문서 목록), Slack/프론트 출력
- 검증 실패 시 성공처럼 반환하지 않고 명시적 실패 처리
- 역할 경계:
- Phase 3(RAG): 벡터 유사도 기반 질문 적합도 판정 → 무관한 청크 탈락
- Phase 4(LLM): 컨텍스트 기반 답변 가능 여부 재판단 → 형식 보장
- 둘은 다른 판정이며 둘 다 필요합니다. Phase 3을 통과했다고 LLM이 무조건 답할 수 있는 것이 아닙니다.
- Pydantic 출력 스키마:
class CompanyXRAGOutput(BaseModel): direct_answer: str evidence_docs: List[str] failure_reason: Optional[str] = Nonefailure_reason이 None이 아니면 성공처럼 반환하지 않습니다.- 값은
문서 없음 / 문서 미확인 / 단정 불가중 하나로 고정합니다. - 검증 실패 시에도 성공처럼 반환하지 않습니다.
- 시스템 프롬프트 골격:
- 질문 유형별로 다른 지시를 포함합니다.
- 근거 부족 시:
"문서에서 직접 답할 수 없으면 failure_reason 필드에 이유를 명시하고 direct_answer는 빈 문자열로 두세요." - 무관한 청크 주의:
"제공된 컨텍스트가 질문과 직접 관련이 없다면 근거로 채택하지 마세요." - 하드코딩 문장 금지: 질문별 특례 문구 삽입 없이 공통 구조로 답변합니다.
- LLM 호출 위치:
companyx_grounding_service내부에서 호출합니다.rb8001의 기존 gpt-4o-mini 호출 경로(LLM 클라이언트)를 재사용합니다. 별도 서비스로 분리하지 않습니다. - 프롬프트 지시만으로 형식을 믿지 않습니다. Pydantic typed validation이 출력 형식의 최종 보장입니다.
- 질문별 하드코딩 문장을 추가하지 않습니다.
Phase 5A. 인덱싱 파이프라인 전환 및 Company X 문서 임베딩
- 전환 후 파이프라인 흐름 (
upload.py/reindex.py기준):text_extractor.extract() → indexing_pipeline.build_index_payloads() → [PDF: PyPDF2 6페이지 분할 → Base64 | 비PDF: chunk_text fallback] → embedding_service.embed_items(task_type="RETRIEVAL_DOCUMENT") → vector_store.replace_document_chunks()- PDF: 6페이지 단위 바이너리 Base64 →
embed_items()(멀티모달 직접 임베딩).chunk_text는 검색 호환용 미리보기 텍스트로 유지. - 비PDF: 기존 텍스트 추출 → 청킹 →
embed_items(text=chunk)fallback. - 검색:
embed_text(task_type="RETRIEVAL_QUERY")— RETRIEVAL_QUERY/DOCUMENT 구분 적용. task_type+metadatapass-through: skill-embedding API에 구현 완료.
- PDF: 6페이지 단위 바이너리 Base64 →
skill-rag-file인덱싱 파이프라인에서 아래를 제거하고 Gemini Embedding 2 직접 임베딩으로 교체합니다.- pdftotext / PyPDF2 텍스트 추출 경로 제거
- OCR 경로 제거
- 문자 단위 청킹(
chunk_text) 제거 - 대체: PDF 6페이지 단위 직접 임베딩, 이미지 직접 임베딩
- 구현 선택 (확정):
- 임베딩 전담 원칙 유지: 임베딩 관련 로직은
skill-embedding이 전담합니다.skill-rag-file에서 Gemini API를 직접 호출하지 않습니다. - API: 기존
POST /embed를 확장 (task_type+metadatapass-through 추가). 신규 엔드포인트 불필요. 상세는 위 "트랙 A·B 공유 인터페이스 계약" 참조. skill-rag-file측 구현:EmbeddingService에embed_file(file_path, file_type)메서드를 신설합니다. 내부적으로 파일을 읽어 Base64 인코딩 후POST /embed의items필드로 전달합니다.- 파일 형식별 처리 분기 (
skill-rag-file이 담당):- PDF: 6페이지 단위로 분할 후 각 분할 바이너리를 Base64 인코딩하여 batch 요청
- 이미지(PNG/JPEG): 바이트를 Base64 인코딩하여 요청
- docx 등 Gemini 미지원 형식: 텍스트 추출 유지 → 기존
POST /embed의texts필드 사용
- 임베딩 전담 원칙 유지: 임베딩 관련 로직은
- chunk_by_tokens 정리:
chunk_by_tokens()가 다른 경로에서 사용되는지 확인 후 미사용이면 제거합니다. 사용처가 있으면 문서에 반영합니다. - 임베딩 대상 (1·2순위): 전체 53,249개 중 시나리오 질문 커버리지가 높은 폴더만 우선 임베딩합니다.
| 순위 | 폴더 | 파일 수 | 대상 질문 |
|---|---|---|---|
| 1 | 6.Company X/10. MOU&인증 |
91개 | 옐로펀치 공동운영 근거 |
| 1 | 6.Company X/12. 컴퍼니엑스 소개자료 |
1개 | X-COURSE 정의, 슬로건/미션 |
| 1 | 6.Company X/3. 배치프로그램(X-COURSE, X-HISSTORY 등) |
2,865개 | X-COURSE, 오늘전통, 프로그램 운영 흐름 |
| 2 | 6.Company X/6. 투자 |
13,018개 | 투자사 수, 투자 건수 수치형 질문 |
- 1순위 합계: 2,957개 (전체의 5.5%). 2순위 포함 시 15,976개 (전체의 30%).
- 파이프라인 전환 완료 후 1순위 → 2순위 순서로 임베딩을 실행합니다.
- 임베딩 완료 후 Phase 0 표의 인덱싱 파이프라인 항목을 완료로 갱신합니다.
- 현재 상태: 코드 전환 완료, 배포 미완료
- 남은 작업:
- skill-embedding + skill-rag-file 배포/재기동
NAS 동기화 경로 확인→ 확인 완료. NAS 원본 경로:/mnt/nas/workspace/6.Company X/. 인덱싱 저장:/mnt/hdd/data/documents/. 자동 동기화 없음 — 수동 upload API만 가능.- NAS 일괄 투입 배치 스크립트 작성 —
/mnt/nas/workspace/6.Company X/하위 1순위 폴더 파일을 순회하며 upload API를 호출하는 스크립트. 현재 114/53,249개만 인덱싱된 상태. - 1순위/2순위 폴더 실제 임베딩 실행
- pdftotext/OCR 경로는 텍스트 미리보기 생성용으로 잔존 — PDF 직접 임베딩과 병행. 별도 제거 계획 불필요.
Phase 5B. 테스트 고정 및 검증
- Phase 5A 완료 후 진행합니다.
- 자동화 테스트 (코드):
- 질문 유형 분류 정확성: 20개 질문 → 4유형 매핑 검증
- 근거 채택 판정: 무관한 청크 반환 시
grounding_present=false확인 - 실패 응답 형식: generic 문장(
관련 근거를 찾았습니다) 금지 확인 - 성공 응답 형식:
직접 답 + 근거 문서명 + 요약구조 확인 - Pydantic 검증:
CompanyXRAGOutput파싱 성공 여부,failure_reason유무에 따른 분기 확인 - 저장 경로: 임베딩 결과가
team_document_chunk(PostgreSQL)에 저장됨을 확인
- Slack 실응답 검증 (수동, 대표 5개):
오늘전통 프로그램을 Company X가 옐로펀치랑 같이 운영한다는 근거 있어?→ 직접 답 + MOU 근거컴퍼니엑스의 투자사는 몇개야?→ 수치 답 또는단정 불가내부 규정 상 휴가는 얼마나 쓸 수 있어?→ 규정 문서 확인 또는문서 미확인X-COURSE가 뭐야?→ 설명 + 근거 문서근거 문서명만 다시 정리해줘→ 직전 근거 목록 재정리
- Phase 0 갱신: NAS 동기화 경로/시점 검증을 끝내면 Phase 0 표에 반영
- 종결 worklog: 테스트 통과 + Slack 5개 검증 완료 시 종결 worklog 작성
- 테스트는 질문별 예외 성공이 아니라 공통 계약 준수 여부를 검증합니다.
- 현재 상태: 미완료
6. 검증 기준
- Phase 0에서 아래가 먼저 확인돼야 합니다.
- Company X RAG의 실제 임베딩 경로와 차원이 문서/런타임 기준으로 식별된다.
- NAS 최신 문서 동기화본과 검색 컬렉션 반영 경로가 설명 가능해진다.
- 재오픈 기준 질문 20개의 현재 실패 양상이 다시 재현된다.
- 재오픈 기준 질문 20개에서 아래가 확인돼야 합니다.
- 직접 답이 먼저 나온다.
- 질문과 맞는 근거만 붙는다.
- 근거가 부족하면 명시적으로 부족하다고 답한다.
검색 hit 있음 = success경로가 제거돼야 합니다.- 질문별 특례 추가 없이도 재오픈 질문셋이 통과해야 합니다.
SKILL.md요구사항과 실제 응답 형식이 일치해야 합니다.
7. 완료 판정 기준
skill-rag-file인덱싱 파이프라인이 Gemini Embedding 2 원본 파일 직접 임베딩으로 전환됩니다. (pdftotext/PyPDF2/OCR/문자단위 청킹 제거,EmbeddingService.embed_file()구현,skill-embeddingAPI 확장 확인)- Company X NAS 문서가 전환된 파이프라인으로 임베딩됩니다.
- 260312_companyx_rag_answer_composition_regression.md에서 정의한 재현 질문셋이 더 이상 회귀하지 않습니다.
- 260312_companyx_내부문서_근거응답_사용자시나리오.md의 재오픈 기준 질문 20개가 기대 결과를 만족합니다.
- Company X RAG의 현재 임베딩 경로/차원과 NAS 문서 반영 경로가
research에 최신 기준으로 반영됩니다. companyx_grounding_service에 질문별 direct answer 특례를 추가하지 않고 공통 계약 구조로 바뀝니다.- LLM 응답이 Pydantic 모델(
direct_answer,evidence_docs,failure_reason)로 검증됩니다. 검증 실패 시 성공처럼 반환하는 경로가 없습니다. - 테스트가 추가되고 통과합니다.
- 실행 결과는
worklog 1건으로 마감하고, 시나리오/트러블 문서와 양방향 링크를 연결합니다.
8. 후속 경계
- 이 계획이 닫혀도 Company X 전체 문서군 확대나 범용 RAG 정책 공통화는 별도 계획으로 다룹니다.
Prompt DB나 전역 오케스트레이션 구조 변경은 이번 계획 범위 밖입니다.
한 줄 결론
- 이번 계획은
대표 질문 특례 처리 제거자체가 아니라, 현재 NAS 문서 운영 상태와 임베딩 전제를 다시 닫은 뒤 Company X 근거응답을질문 유형 계약 + 근거 채택 계약 + 실패 계약으로 재구성해 시나리오와 트러블을 함께 닫는 작업입니다.