---
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` |
