AI 답변의 신뢰성은 모델 성능보다 데이터 상태에서 갈렸다. 뉴스가 오래됐든 임베딩이 빠졌든 서비스가 막혔든 답변은 자연스럽게 나오니까, 답변 이전에 데이터 상태를 먼저 보여주는 쪽으로 설계했다.

diagram-rag.png


무엇이 답변 품질을 무너뜨리나

문제 운영 리스크
오래된 뉴스 지난 근거로 현재 판단을 만든다
임베딩 누락 검색 품질이 떨어져도 알 수 없다
대체 문서 임시 문서가 RAG 근거에 섞인다
서비스 호출 제한 호출 실패가 분석 누락이 된다
뉴스 소스 상태 불명확 어떤 소스가 죽었는지 모른다

설계 기준

AI 답변보다 RAG 품질을 먼저 드러낸다. 원문 메타데이터와 검색용 청크는 따로 저장하고, 검색은 kNN 벡터와 BM25 키워드를 함께 쓴다. 서비스 라우터가 Gemini와 OpenAI 후보의 차단 상태를 계산해 한 서비스 장애가 전체를 멈추지 않게 하고, 오래된 데이터와 임베딩 누락, 서비스 실패는 화면과 API에 경고로 띄운다.

2026.07에는 목적별 제한 시간이 붙었다. 분석·매수 사전 점검·채팅·리포트·임베딩·번역마다 제한 시간을 두고 SDK 자체 재시도는 억제했다. 분석이 제한 시간을 넘기면 현재 주기를 HOLD로 저장하고, 매수 사전 점검이 넘기면 주문 0회로 끝낸다.


실제 코드 근거

서비스 대체 전환

for candidate in candidates:
    try:
        value = await operation(candidate)
    except AIProviderRateLimitError as exc:
        await self.mark_rate_limited(candidate.provider, exc)
        continue
    except Exception as exc:
        if is_provider_rate_limit_error(candidate.provider, exc):
            await self.mark_rate_limited(candidate.provider, exc)
        else:
            await self.mark_error(candidate.provider, exc)
        continue

    await self.mark_success(candidate.provider)
    return AIProviderExecutionResult(
        value=value,
        provider=candidate.provider,
        model=candidate.model,
    )

한 서비스가 할당량이나 호출 제한으로 막혀도 AI 기능 전체가 멈추지 않는다. 차단된 서비스는 후보에서 빠지고 대체 서비스가 실제로 쓰이는지를 테스트로 고정했다.

RAG 품질 경고

if real_documents <= 0:
    warnings.append(_rag_warning("no_real_documents", "critical", {...}))

if fallback_documents > 0:
    warnings.append(_rag_warning("fallback_documents_present", "warning", {...}))

if embedding_total > 0:
    missing_ratio = missing_embedding_documents / embedding_total
    if missing_ratio >= 0.5:
        warnings.append(_rag_warning("missing_embedding_high", "warning", {...}))

실제 문서 부재, 대체 문서, 임베딩 누락을 등급이 있는 경고로 올린다. 대체 뉴스가 긍정 신호로 과대평가되지 않는지도 검증했다.