활용 사례로 돌아가기
지식 기반

RAG 챗봇 API — 프로덕션에서 Claude로 구동하는 지식 기반 어시스턴트

대부분의 내부 지식 기반은 죽은 문서에 불과합니다 — 아무도 원하는 정보를 찾지 못합니다. Claude 기반 RAG 챗봇은 이를 출처를 인용하고 모르는 내용은 거부하는 실제 어시스턴트로 바꿉니다. 여기에서 프로덕션 패턴을 확인하세요.

마지막 검토일: .

기본적인 최신 KB 챗봇 아키텍처

기존 KB 검색은 링크를 반환하고 사용자가 이를 읽습니다. RAG는 이를 인용이 포함된 단 한 번의 대화형 답변으로 바꿉니다. 잘 구현하면 사용자는 5개의 문서를 뒤지는 대신 2초 만에 답을 얻습니다. 잘못 구현하면 챗봇이 환각을 일으키고 CTO가 프로젝트를 1년간 금지합니다. 이 페이지는 그 차이를 설명합니다.

운영에 필요한 최소 스택

  1. 벡터 저장소: 이미 Postgres를 사용 중이라면 pgvector, 관리형 서비스를 원한다면 Pinecone 또는 Qdrant
  2. 임베딩: text-embedding-3-large를 OpenAI에 직접 호출 — Kunavo는 임베딩을 제공하지 않으며, 어느 경우든 임베딩 호출은 생성 호출과 별도의 요청입니다
  3. 검색: 하이브리드(벡터 + 상호 순위 융합을 적용한 BM25)
  4. 생성: 시스템 프롬프트에 cache_control을 적용한 Claude Sonnet 5
  5. UI: 스트리밍 응답, 인용 렌더링, "모르겠습니다" 대체 응답
rag_chat.py
from openai import OpenAI
client = OpenAI(api_key="sk-kn-...", base_url="https://api.kunavo.com/v1")

def chat(question: str, history: list[dict]) -> dict:
    chunks = hybrid_retrieve(question, k=5)  # vector + BM25
    context = "\n\n---\n\n".join(
        f"[doc:{c['id']}] {c['text']}" for c in chunks
    )
    resp = client.chat.completions.create(
        model="claude-sonnet-5",
        messages=[
            {"role": "system", "content": [{
                "type": "text",
                "text": (
                    "Answer only from Context. Cite [doc:N] for each claim. "
                    "If Context doesn't answer, say 'I don't have that.' "
                    "Be concise, no throat-clearing."
                ),
                "cache_control": {"type": "ephemeral"},
            }]},
            *history,
            {"role": "user", "content": f"# Context\n{context}\n\n# Q\n{question}"},
        ],
        max_tokens=600,
    )
    answer = resp.choices[0].message.content
    cited_ids = parse_citations(answer)  # extract [doc:N] references
    return {"answer": answer, "sources": [c for c in chunks if c["id"] in cited_ids]}

프로덕션 규모에서의 비용

  • 초기 인덱싱: 토큰 500개인 문서 5,000개 기준 약 $0.25
  • 하루 1,000개 쿼리: 캐싱 적용 시 약 $210/월
  • 하루 10,000개 쿼리: 약 $2,100/월
  • Sonnet 대신 Haiku 4.5를 사용하는 경우: 약 4배 저렴, 답변 품질은 약 85%

전체 아키텍처 분석은 RAG 구현 가이드를 참조하세요. 언어별 튜닝 노트는 일본어 RAG 심층 분석과 스페인어 RAG 가이드에 있습니다.

환각을 실제로 방지하는 세 가지 패턴

  • 모든 주장에 인용 추가: 모델 출력의 [doc:42] 태그. 인용된 id가 검색된 집합에 없으면 환각이므로 차단하고 기록합니다
  • 시스템 프롬프트에 명시적인 거부 지침 추가: "Context가 답하지 못하면 '해당 정보를 알지 못합니다.'라고 말하세요." 이 지침이 없으면 모델은 세계 지식으로 빈칸을 채웁니다
  • 출력을 600토큰으로 제한: 짧은 답변은 대체로 정확한 답변입니다. 길어진 출력에서 추가적인 날조가 끼어들기 쉽습니다

1주 차에 출시할 것과 4주 차에 출시할 것

주차마일스톤
1문서 100개, 단일 청킹 전략, 기본 벡터 검색, 10개 질문 평가 세트, recall@5 약 70%
2전체 코퍼스, 하이브리드 검색, 100개 질문 평가 세트, 인용 강제, 내부 베타
3실패한 질문을 바탕으로 청킹을 조정하고, 내부 사용자에게 출시하며, CSAT를 측정합니다
4모니터링 + 비용 대시보드, 일일 지출 한도, 공개 베타 또는 프로덕션 출시

/app/signup에서 시작하세요

$10 충전으로 약 100K개 문서의 초기 인덱싱과 1,500개의 테스트 쿼리를 처리할 수 있습니다. 기능성 프로토타입에는 충분하며 잔액은 만료되지 않습니다. 그런 다음 프로덕션 패턴은 전체 RAG 가이드에서 확인하세요.

자주 묻는 질문

How much does one RAG chatbot query cost?

About $0.007 per query on Claude Sonnet 4.6 with prompt caching active, or about $0.001 on Claude Haiku 4.5 — which returns roughly 85% of the quality at one-seventh of the cost.

How do I stop a RAG chatbot from hallucinating?

Three patterns do most of the work: require the model to cite a [doc:N] id for every claim, put an explicit refusal instruction in the system prompt, and cap the answer with max_tokens=600. Then verify every cited id appears in the retrieved set before rendering the answer.

What chunk size should a RAG index use?

1,000–1,500 characters per chunk with 100–200 characters of overlap, split with RecursiveCharacterTextSplitter and embedded with text-embedding-3-large.

Is vector search alone enough for RAG retrieval?

No. Hybrid retrieval combines vector similarity with BM25 keyword search and merges the two with reciprocal rank fusion, taking the top 5 chunks.