diff --git a/journey/plans/260315_companyx_rag_답변합성_시나리오동시종결_계획.md b/journey/plans/260315_companyx_rag_답변합성_시나리오동시종결_계획.md index db7aaf3..663027d 100644 --- a/journey/plans/260315_companyx_rag_답변합성_시나리오동시종결_계획.md +++ b/journey/plans/260315_companyx_rag_답변합성_시나리오동시종결_계획.md @@ -247,14 +247,14 @@ tags: [plans, companyx, rag, answer-composition, scenario, troubleshooting] | 저장 경로 (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와 완전 분리됨. 긴급하지 않으나 정리 대상. | **레거시 격리** | -| 인덱싱 파이프라인 | 현재 모든 파일을 텍스트 변환 후 청킹. Gemini Embedding 2의 멀티모달(PDF, 이미지, docx 등 직접 임베딩) 능력을 미활용. 원본 파일 직접 임베딩으로 전환. Phase 5A에서 닫음. | **미완료** | -| NAS 동기화 경로 | NAS → skill-rag-file 반영 경로/시점 미확인. **Phase 5A 선행 조건** — 임베딩 실행 전에 NAS 파일이 skill-rag-file에 어떻게 들어오는지(수동 upload vs 자동 동기화) 확인 필요. | **미완료 (5A 선행)** | +| 인덱싱 파이프라인 | 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 실응답 재현 미실시 | **미완료** | - 현재 상태: - 임베딩/저장 전제는 확정됨. - - 인덱싱 파이프라인 전환과 Company X 문서 임베딩은 Phase 5A에서 닫음. - - **NAS 동기화 경로는 Phase 5A 선행 조건** — 5A에서 임베딩을 실행하려면 NAS 파일 투입 방식이 먼저 확인돼야 합니다. + - 인덱싱 파이프라인 코드 전환 완료, 배포 대기. + - NAS 동기화 경로 확인 완료. NAS 원본 53,249개 중 114개만 인덱싱. **대량 투입 배치 스크립트가 Phase 5A 남은 핵심 작업**. - 재오픈 질문 20개 재현은 Phase 5B에서 검증. ### Phase 1. 구조 분리 — **구현 완료** @@ -357,9 +357,10 @@ tags: [plans, companyx, rag, answer-composition, scenario, troubleshooting] - 임베딩 완료 후 Phase 0 표의 인덱싱 파이프라인 항목을 **완료**로 갱신합니다. - 현재 상태: **코드 전환 완료, 배포 미완료** - 남은 작업: - - skill-embedding + skill-rag-file 배포/재기동 - - NAS 동기화 경로 확인 (선행 조건) - - 1순위/2순위 폴더 실제 임베딩 실행 + 1. skill-embedding + skill-rag-file 배포/재기동 + 2. ~~NAS 동기화 경로 확인~~ → **확인 완료**. NAS 원본 경로: `/mnt/nas/workspace/6.Company X/`. 인덱싱 저장: `/mnt/hdd/data/documents/`. 자동 동기화 없음 — 수동 upload API만 가능. + 3. **NAS 일괄 투입 배치 스크립트 작성** — `/mnt/nas/workspace/6.Company X/` 하위 1순위 폴더 파일을 순회하며 upload API를 호출하는 스크립트. 현재 114/53,249개만 인덱싱된 상태. + 4. 1순위/2순위 폴더 실제 임베딩 실행 - pdftotext/OCR 경로는 텍스트 미리보기 생성용으로 잔존 — PDF 직접 임베딩과 병행. 별도 제거 계획 불필요. ### Phase 5B. 테스트 고정 및 검증 diff --git a/journey/research/260315_companyx_rag_답변합성_시나리오동시종결_리서치.md b/journey/research/260315_companyx_rag_답변합성_시나리오동시종결_리서치.md index 72eedbe..9413a62 100644 --- a/journey/research/260315_companyx_rag_답변합성_시나리오동시종결_리서치.md +++ b/journey/research/260315_companyx_rag_답변합성_시나리오동시종결_리서치.md @@ -248,7 +248,7 @@ tags: [research, companyx, rag, answer-composition, scenario, troubleshooting] ### 여전히 미확정 3. `재정리형 질문`은 이전 응답 재사용 없이 재검색함 (세션 연결 없음). 현재 스코프에서는 재검색 허용으로 운영. 4. Company X 전용 규칙은 현재 독립 모듈(`companyx_grounding_service.py`)로 유지. 범용화는 이 문제 세트 밖. -6. NAS 최신 문서 동기화본이 Company X RAG 검색 컬렉션에 언제, 어떤 방식으로 반영되는지는 아직 미확정. +~~6. NAS 최신 문서 동기화본이 Company X RAG 검색 컬렉션에 언제, 어떤 방식으로 반영되는지는 아직 미확정.~~ → **확인 완료 (2026-03-17)**: NAS 마운트 `/mnt/nas` (CIFS). Company X 원본: `/mnt/nas/workspace/6.Company X/` (53,249개). 외부→내부 NAS는 cron(30분 계층형 + 하루 1회 전수조사)으로 동기화. 단, NAS → skill-rag-file 인덱싱은 자동화 없음 — 수동 upload API 호출만 가능. 현재 114개만 인덱싱. 대량 투입 배치 스크립트 필요. ~~7. 한국어 과소 청킹 리스크 및 `Gemini 2 PDF 직접 임베딩` 미구현은 **본 문제 세트에서 즉시 전환** 대상으로 결정할지 미확정.~~ → **확정 (2026-03-17)**: 계획 Phase 5A에서 문자 단위 청킹 제거 + PDF 직접 임베딩 전환으로 결정됨. 이 계획에서 닫음. ## 결론 diff --git a/journey/worklog/260317_companyx_rag_phase4_5a_구현완료_및_504_라우팅_수정.md b/journey/worklog/260317_companyx_rag_phase4_5a_구현완료_및_504_라우팅_수정.md new file mode 100644 index 0000000..4621291 --- /dev/null +++ b/journey/worklog/260317_companyx_rag_phase4_5a_구현완료_및_504_라우팅_수정.md @@ -0,0 +1,193 @@ +--- +tags: [worklog, companyx, rag, phase4, phase5a, gateway, routing, troubleshooting] +--- + +# Company X RAG Phase 4·5A 구현 완료 및 Gateway 504 라우팅 버그 수정 + +**작성일**: 2026-03-17 +**작업자**: Claude Code + +## 관련 문서 +- [Company X RAG 답변합성 시나리오·트러블 동시종결 계획](../plans/260315_companyx_rag_답변합성_시나리오동시종결_계획.md) +- [Company X RAG 답변합성 시나리오·트러블 동시종결 리서치](../research/260315_companyx_rag_답변합성_시나리오동시종결_리서치.md) + +--- + +## 1. Phase 4 완료 확인 (트랙 B) + +계획 문서 Phase 4 요구사항 8개와 실제 코드 대조 결과 전부 충족 확인. + +### 핵심 구현 내용 (`rb8001/app/services/companyx_grounding_service.py`) +- `CompanyXRAGOutput(direct_answer, evidence_docs, failure_reason)` Pydantic 모델 도입 +- `_call_llm_companyx_grounding()` — 선별된 청크를 컨텍스트로 LLM 호출 +- `_build_grounded_response()` — LLM 답변 우선, 실패 시 규칙 기반 fallback +- LLM 모델: `settings.DEFAULT_LLM_MODEL` SSOT 참조 (gpt-5-mini, 하드코딩 없음) + +### 경미한 미비점 (Phase 5B에서 확인) +- 질문 유형별 분기 프롬프트 없이 `question_type` 문자열을 LLM에 위임. 품질 검증 필요. + +--- + +## 2. Phase 5A 완료 확인 및 보완 (트랙 A) + +### 이미 구현된 내용 +- `IndexingPipelineService` 도입 — PDF 6페이지 단위 바이너리 Base64 → `embed_items()` +- `chunk_text`는 검색 호환용 미리보기 텍스트로 유지 +- 비PDF fallback: 텍스트 추출 → 청킹 → `embed_items(text=chunk)` + +### 이번 세션에서 추가 구현 + +**`task_type` 전달 (RETRIEVAL_DOCUMENT / RETRIEVAL_QUERY 구분)** + +| 파일 | 변경 내용 | +|------|---------| +| `skill-embedding-repo/main.py` | `EmbedRequest.task_type` 필드 추가, `EmbedItem.metadata` pass-through 추가, `EmbedResponse.item_metadata` 반환 | +| `skill-embedding-repo/embedder.py` | `encode(task_type=...)` → `EmbedContentConfig(task_type=...)` Gemini API 전달 | +| `skill-rag-file/app/services/embedding.py` | `embed_texts()`, `embed_text()`, `embed_items()` 모두 `task_type` 파라미터 추가 | +| `skill-rag-file/app/api/upload.py` | `embed_items(task_type="RETRIEVAL_DOCUMENT")` | +| `skill-rag-file/app/api/reindex.py` | `embed_items(task_type="RETRIEVAL_DOCUMENT")` | +| `skill-rag-file/app/api/search.py` | `embed_text(task_type="RETRIEVAL_QUERY")` | + +### NAS 동기화 경로 확인 결과 +- 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만 가능 +- 현재 인덱싱 완료: 114개 (`/mnt/hdd/data/documents/79441171.../`) +- **남은 핵심**: 1순위 폴더(2,957개) 일괄 투입 배치 스크립트 필요 + +--- + +## 3. Gateway 504 라우팅 버그 수정 + +### 증상 +- `ro-being.com/api/chat` 및 `localhost:8100/api/chat` 호출 시 약 60초 후 504 +- 3개 테스트 질문 모두 실패 + +### 원인 추적 과정 + +1. **초기 오진**: 타임아웃 문제로 판단 → Gateway httpx 30s→60s 상향, 병렬 검색 도입 +2. **재발**: 60초에도 동일하게 504 발생 +3. **로그 확인**: `docker logs robeing-gateway`에서 실제 라우팅 주소 확인 + ``` + Proxying to: http://192.168.219.52:8001/api/message ← 구 IP! + ``` +4. **DB 확인**: `robeing.robeing_container_url = 'http://192.168.219.52:8001'` + - 서버 IP가 `192.168.219.52` → `192.168.0.106`으로 변경됐으나 DB 미갱신 + - AGENTS.md 기록: "2026-03-09 이후 `192.168.0.106`이 SSOT" + +### 수정 내용 + +**DB 업데이트** (Docker exec, gateway 컨테이너에서 직접 실행): +```sql +UPDATE robeing +SET robeing_container_url = 'http://192.168.0.106:8001' +WHERE robeing_container_url = 'http://192.168.219.52:8001' +-- Updated 1 rows +``` + +**Gateway 재기동** (캐시 초기화): +```bash +docker restart robeing-gateway +``` + +### 함께 적용된 개선 (이번 기회에) + +**1. RAG 다중 쿼리 순차→병렬 실행** (`rb8001/app/services/companyx_grounding_service.py`) +```python +# Before: for loop 순차 실행 (최대 9쿼리 × 2-3초 = ~22초) +for query in _build_query_candidates(message, question_type): + for result in await _search_once(query): ... + +# After: asyncio.gather 병렬 실행 (~3초) +queries = _build_query_candidates(message, question_type) +all_results = await asyncio.gather(*[_search_once(q) for q in queries]) +``` + +**2. Gateway httpx timeout 상향** (`robeing-gateway/app/main.py`) +- `timeout=30.0` → `timeout=60.0` + +### 접근 방법 (51124 서버 SSH) +```bash +# 51124 서버 SSH 포트: 51124 (기본 22 아님) +ssh -i ~/.ssh/id_rsa_51123_to_51124 -p 51124 admin@192.168.0.106 +``` + +--- + +## 4. 커밋 이력 + +| 레포 | 커밋 해시 | 내용 | +|------|---------|------| +| rb8001 | `1756983` | perf: RAG 다중 쿼리 순차→병렬 실행으로 응답 지연 해소 | +| robeing-gateway | `d835fe4` | fix: Gateway httpx timeout 30s→60s 상향 | +| skill-embedding-repo | (push 필요) | feat: task_type + metadata pass-through 추가 | +| skill-rag-file | (push 필요) | feat: embed_items task_type RETRIEVAL_DOCUMENT/QUERY 전달 | + +--- + +## 5. 남은 작업 (Phase 5A) + +1. skill-embedding + skill-rag-file 배포/재기동 +2. NAS 일괄 투입 배치 스크립트 작성 (1순위 폴더 → upload API 호출) +3. 1순위 2,957개 → 2순위 15,976개 순서로 임베딩 실행 +4. Phase 5B 테스트/검증 + +--- + +## 워크플로우 — 다음에 같은 작업 시 참고 + +### Company X RAG E2E 테스트 순서 + +``` +1. skill-rag-file 검색 직접 확인 + curl http://192.168.0.106:8508/api/search -X POST \ + -H 'Content-Type: application/json' -H 'X-User-Id: system' \ + -d '{"query":"...", "team_id":"79441171-3951-4870-beb8-916d07fe8be5", "limit":3, "threshold":0.35}' + +2. rb8001 헬스 확인 + curl http://192.168.0.106:8001/health + +3. Gateway 라우팅 확인 + docker logs robeing-gateway --tail 20 | grep Proxying + → 주소가 192.168.0.106인지 확인 (구 IP 192.168.219.52 아님) + +4. Gateway 504 발생 시 체크리스트 + a. docker logs에서 "Proxying to:" 주소 확인 + b. 구 IP면 DB 수정: + docker exec robeing-gateway python3 -u -c " + import asyncio + from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession + from sqlalchemy.orm import sessionmaker + from sqlalchemy import text + async def main(): + engine = create_async_engine('postgresql+asyncpg://robeings:robeings@192.168.0.100:5432/main_db') + Session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False) + async with Session() as s: + r = await s.execute(text('SELECT id, robeing_container_url FROM robeing')) + for row in r.fetchall(): print(row[0], row[1]) + await engine.dispose() + asyncio.run(main()) + " + c. 잘못된 URL 확인 후 UPDATE 실행 + d. docker restart robeing-gateway (캐시 초기화) + +5. rb8001 코드 변경 후 반영 확인 + ssh -i ~/.ssh/id_rsa_51123_to_51124 -p 51124 admin@192.168.0.106 + cd ~/robeing/rb8001 && git log --oneline -3 + → 최신 커밋 확인 후 프로세스 재기동 여부 판단 +``` + +### 서버 구조 요약 + +| 항목 | 값 | +|------|---| +| 51123 (이 서버) | nginx, Gateway(Docker:8100), auth, DB | +| 51124 | rb8001(:8001), skill-rag-file(:8508), skill-embedding(:포트확인필요) | +| 51124 SSH | `ssh -i ~/.ssh/id_rsa_51123_to_51124 -p 51124 admin@192.168.0.106` | +| rb8001 경로 (51124) | `~/robeing/rb8001/` | +| DB | `postgresql://robeings:robeings@192.168.0.100:5432/main_db` | +| NAS | `/mnt/nas` (CIFS, `//192.168.0.101/home`) | +| Company X 원본 문서 | `/mnt/nas/workspace/6.Company X/` | +| Company X 인덱싱 저장 | `/mnt/hdd/data/documents/79441171-3951-4870-beb8-916d07fe8be5/` (51123) | +| Company X team_id | `79441171-3951-4870-beb8-916d07fe8be5` |