본문 바로가기
개발 가이드/AI 개발

[AI 개발] 7. LI LlamaIndex 완전 가이드

by 플로거 2026. 7. 19.

RAG · AI Agent 데이터 파이프라인 가이드

LlamaIndex 완전 가이드

LlamaIndex로 고급 RAG 파이프라인, ReAct Agent, 서브쿼리 분해와 하이브리드 검색을 구축합니다. ChromaDB·Pinecone 연동, RAGAS 평가와 프로덕션 운영까지 정리합니다.

  • 고급 RAG
  • ReAct Agent
  • Sub-question
  • Hybrid Search
  • Vector DB
  • RAGAS
설치 없이 LlamaIndex 예제를 실행해 보세요 브라우저에서 단계별 코드를 실행하고 결과를 확인할 수 있는 AI DevOps Learn LlamaIndex 웹 IDE를 제공합니다.
LlamaIndex 웹 IDE 열기 →
이 글의 핵심
LlamaIndex는 문서 수집과 파싱, 인덱싱, 검색, 응답 생성을 연결하는 데이터 중심 LLM 프레임워크입니다. 검색 품질은 모델 크기보다 chunking, metadata, retriever, reranker와 평가 데이터셋의 영향을 크게 받습니다.

1. 핵심 아키텍처

LlamaIndex는 데이터 수집 → 인덱싱 → 검색 → 생성의 전 과정을 추상화합니다. VectorStoreIndex는 임베딩 기반 의미 검색에, SummaryIndex는 문서 전체 요약에 적합합니다. Settings로 LLM과 임베딩 모델, chunk 설정을 공통 관리할 수 있습니다.

데이터 수집
Document
노드 변환
Chunking
인덱스·검색
Retriever
응답 생성
Query Engine
인덱스 유형 특징 적합한 용도
VectorStoreIndex 임베딩 유사도 기반 검색 의미 검색, FAQ, 지식베이스
SummaryIndex 전체 노드를 순차적으로 처리 문서 전체 요약, 긴 리포트
KeywordTableIndex 키워드 중심 문서 탐색 정확한 용어 검색, 전문 문서
KnowledgeGraphIndex 엔티티와 관계를 기반으로 탐색 다중 홉 질문, 관계형 지식 탐색
Python
from llama_index.core import Settings
from llama_index.llms.openai import OpenAI
from llama_index.embeddings.openai import OpenAIEmbedding

# 전역 설정
Settings.llm = OpenAI(
    model="gpt-4o",
    temperature=0.1,
)

Settings.embed_model = OpenAIEmbedding(
    model="text-embedding-3-small",
)

Settings.chunk_size = 512
Settings.chunk_overlap = 50

2. 고급 인덱싱 전략

고정 크기 chunking은 문장을 중간에서 끊어 검색 품질을 떨어뜨릴 수 있습니다. Sentence Window 전략은 문장을 검색 단위로 사용하면서 주변 문장을 함께 보존합니다. Hierarchical 또는 Auto-Merging 전략은 작은 노드를 검색한 뒤 상위 문맥을 반환해 세부 정보와 전체 흐름을 함께 제공합니다.

Sentence Window 인덱싱
from llama_index.core import VectorStoreIndex
from llama_index.core.indices.postprocessor import (
    MetadataReplacementPostProcessor,
    SentenceTransformerRerank,
)
from llama_index.core.node_parser import (
    SentenceWindowNodeParser,
)

window_parser = SentenceWindowNodeParser.from_defaults(
    window_size=3,
    window_metadata_key="window",
    original_text_metadata_key="original_text",
)

nodes = window_parser.get_nodes_from_documents(
    documents
)

window_index = VectorStoreIndex(nodes)

window_query_engine = window_index.as_query_engine(
    node_postprocessors=[
        MetadataReplacementPostProcessor(
            target_metadata_key="window",
        ),
        SentenceTransformerRerank(
            top_n=3,
            model="BAAI/bge-reranker-base",
        ),
    ]
)
인덱싱 전략은 문서 유형에 따라 달라집니다. FAQ, 계약서, 기술 문서와 보고서에 같은 chunk 크기를 일괄 적용하기보다 실제 평가 질문으로 검색 품질을 비교하세요.

3. 하이브리드 검색과 리랭킹

의미 검색은 표현이 다른 유사 문서를 잘 찾지만 정확한 코드나 전문 용어를 놓칠 수 있습니다. BM25 검색은 정확한 키워드에 강하지만 유사 의미 표현에는 약합니다. 두 결과를 RRF로 결합하고 cross-encoder reranker를 추가하면 검색 재현율과 상위 결과의 정밀도를 함께 개선할 수 있습니다.

Python
from llama_index.core.query_engine import (
    RetrieverQueryEngine,
)
from llama_index.core.retrievers import (
    QueryFusionRetriever,
)
from llama_index.postprocessor.cohere_rerank import (
    CohereRerank,
)
from llama_index.retrievers.bm25 import (
    BM25Retriever,
)

vector_retriever = index.as_retriever(
    similarity_top_k=10,
)

bm25_retriever = BM25Retriever.from_defaults(
    nodes=nodes,
    similarity_top_k=10,
)

hybrid_retriever = QueryFusionRetriever(
    [vector_retriever, bm25_retriever],
    similarity_top_k=10,
    num_queries=4,
    mode="reciprocal_rerank",
)

reranker = CohereRerank(
    api_key="co_your_api_key",
    top_n=3,
)

query_engine = RetrieverQueryEngine(
    retriever=hybrid_retriever,
    node_postprocessors=[reranker],
)
API Key 보안
Cohere, OpenAI와 벡터 DB API Key를 코드에 직접 입력하지 마세요. 로컬에서는 환경 변수, 운영에서는 Secret Manager 또는 Kubernetes Secret으로 관리하세요.

4. ReAct Agent

ReAct Agent는 생각, 행동, 관찰 과정을 반복해 복잡한 질문을 해결합니다. 여러 Query Engine을 도구로 등록하면 Agent가 질문에 적합한 데이터 소스를 선택할 수 있습니다. 무한 반복과 과도한 모델 호출을 막기 위해 최대 실행 횟수를 제한해야 합니다.

Python
from llama_index.core.agent import ReActAgent
from llama_index.core.tools import (
    QueryEngineTool,
    ToolMetadata,
)

knowledge_tool = QueryEngineTool(
    query_engine=query_engine,
    metadata=ToolMetadata(
        name="knowledge_base",
        description=(
            "회사 내부 문서, 정책과 절차를 검색합니다. "
            "구체적인 질문을 입력하세요."
        ),
    ),
)

agent = ReActAgent.from_tools(
    [knowledge_tool],
    verbose=True,
    max_iterations=10,
)

response = agent.chat(
    "분기별 매출 트렌드를 분석하고 이상치를 찾아줘"
)

print(response)
Agent 권한 주의
검색 외에 파일 변경, 이메일 발송, 데이터베이스 수정과 같은 Tool을 연결할 때는 최소 권한, 입력 검증, 사용자 승인과 실행 기록을 적용하세요.

5. 이벤트 기반 워크플로우

Workflow는 비동기 이벤트 그래프로 복잡한 RAG 파이프라인을 명시적으로 표현합니다. 각 step은 입력 이벤트를 받아 새로운 이벤트 또는 종료 이벤트를 반환합니다. 조건 분기와 병렬 처리, 단계별 테스트가 필요한 흐름에 적합합니다.

Python
from llama_index.core import Settings
from llama_index.core.workflow import (
    Event,
    StartEvent,
    StopEvent,
    Workflow,
    step,
)


class RetrievalEvent(Event):
    nodes: list
    query: str


class RAGWorkflow(Workflow):
    @step
    async def retrieve(
        self,
        ev: StartEvent,
    ) -> RetrievalEvent:
        retriever = index.as_retriever(
            similarity_top_k=5,
        )

        nodes = await retriever.aretrieve(
            ev.query
        )

        return RetrievalEvent(
            nodes=nodes,
            query=ev.query,
        )

    @step
    async def generate(
        self,
        ev: RetrievalEvent,
    ) -> StopEvent:
        context = "\n".join(
            node.get_content()
            for node in ev.nodes
        )

        response = await Settings.llm.acomplete(
            f"컨텍스트:\n{context}\n\n"
            f"질문: {ev.query}"
        )

        return StopEvent(
            result=str(response),
        )


workflow = RAGWorkflow(timeout=60)

result = await workflow.run(
    query="핵심 내용을 요약해줘"
)

6. Sub-question 분해

여러 데이터 소스에 걸친 질문은 하나의 검색기로 답하기 어렵습니다. SubQuestionQueryEngine은 복합 질문을 여러 하위 질문으로 분해하고, 각 질문에 적합한 Query Engine을 호출한 뒤 결과를 통합합니다.

Python
from llama_index.core.query_engine import (
    SubQuestionQueryEngine,
)
from llama_index.core.tools import (
    QueryEngineTool,
    ToolMetadata,
)

tools = [
    QueryEngineTool(
        query_engine=sales_engine,
        metadata=ToolMetadata(
            name="sales_2024",
            description=(
                "2024년 월별·분기별 매출 데이터. "
                "금액, 수량과 지역 정보를 포함합니다."
            ),
        ),
    ),
    QueryEngineTool(
        query_engine=hr_engine,
        metadata=ToolMetadata(
            name="hr_data",
            description=(
                "인사 데이터. 입사일, 부서, 직급과 "
                "성과 평가 정보를 포함합니다."
            ),
        ),
    ),
]

engine = SubQuestionQueryEngine.from_defaults(
    query_engine_tools=tools,
    verbose=True,
)

response = engine.query(
    "2024년 신규 직원의 성과와 매출 기여도는?"
)

print(response)

7. 벡터 DB 통합

메모리 기반 인덱스는 서버가 재시작되면 사라질 수 있습니다. 운영에서는 ChromaDB, Pinecone, PostgreSQL pgvector 등 영구 벡터 저장소를 사용하고 인덱스 재사용과 갱신 정책을 관리해야 합니다.

ChromaDB 영구 저장
import chromadb

from llama_index.core import (
    StorageContext,
    VectorStoreIndex,
)
from llama_index.vector_stores.chroma import (
    ChromaVectorStore,
)

chroma_client = chromadb.PersistentClient(
    path="./chroma_db"
)

collection = chroma_client.get_or_create_collection(
    name="company_docs",
    metadata={
        "hnsw:space": "cosine",
    },
)

vector_store = ChromaVectorStore(
    chroma_collection=collection,
)

storage_context = StorageContext.from_defaults(
    vector_store=vector_store,
)

# 최초 인덱싱
index = VectorStoreIndex.from_documents(
    documents,
    storage_context=storage_context,
    show_progress=True,
)

# 기존 컬렉션을 다시 사용할 때
index = VectorStoreIndex.from_vector_store(
    vector_store
)

벡터 저장소 운영 시 확인할 항목

  • 문서 ID와 chunk ID를 재현 가능하게 생성합니다.
  • 문서 변경 및 삭제 시 기존 vector를 함께 정리합니다.
  • embedding 모델이 바뀌면 기존 index와 혼합하지 않습니다.
  • collection, namespace 또는 tenant 단위로 접근 권한을 분리합니다.
  • 검색 latency와 vector DB 장애에 대한 timeout과 fallback을 설정합니다.

8. RAGAS 평가

RAG 시스템의 품질은 느낌이 아니라 고정된 평가셋으로 측정해야 합니다. Faithfulness는 답변이 검색 문서에 근거하는지, Answer Relevancy는 질문과 답변의 관련성을, Context Recall은 정답에 필요한 정보가 검색되었는지 평가합니다.

Python
from datasets import Dataset
from ragas import evaluate
from ragas.metrics import (
    answer_relevancy,
    context_recall,
    faithfulness,
)

eval_dataset = Dataset.from_dict({
    "question": questions,
    "answer": answers,
    "contexts": contexts,
    "ground_truth": ground_truths,
})

result = evaluate(
    eval_dataset,
    metrics=[
        faithfulness,
        answer_relevancy,
        context_recall,
    ],
)

dataframe = result.to_pandas()

print(
    dataframe[
        [
            "question",
            "faithfulness",
            "answer_relevancy",
            "context_recall",
        ]
    ]
)
faithfulness가 낮다면 chunk 크기, prompt와 reranker를 점검하고, context recall이 낮다면 top-k, query 변형과 하이브리드 검색을 비교하세요. 지표 목표값은 서비스와 평가 데이터 특성에 맞게 정해야 합니다.

9. LlamaIndex 실무 설계

ingestion 파이프라인과 query 파이프라인을 분리하면 문서 재색인과 검색 전략 튜닝을 독립적으로 수행할 수 있습니다. 문서 파싱, metadata, embedding과 index 버전을 함께 추적해야 검색 결과와 장애 원인을 재현할 수 있습니다.

결정 지점 확인 질문 실무 기준
수집 어떤 문서가 언제 들어왔는가? 원본 문서 ID, 버전, 수집 시각과 출처를 기록합니다.
Chunk 검색 결과에서 원문 위치를 확인할 수 있는가? 페이지, 제목, 섹션과 URL을 metadata로 보존합니다.
Index 어떤 embedding 모델로 생성했는가? 모델명, dimension과 index 버전을 함께 관리합니다.
Retriever top-k와 reranker 설정을 재현할 수 있는가? 검색 설정을 코드 밖의 구성으로 분리합니다.
장애 검색이나 LLM이 실패하면 무엇을 반환하는가? timeout, fallback과 error contract를 정의합니다.

권장 프로젝트 구조

Directory
llamaindex-project/
├── app/
│   ├── api/
│   ├── agents/
│   ├── ingestion/
│   ├── indexes/
│   ├── query_engines/
│   ├── retrievers/
│   ├── workflows/
│   └── settings.py
├── evaluations/
│   ├── rag_dataset.jsonl
│   └── regression_cases.jsonl
├── storage/
├── tests/
└── pyproject.toml

10. 운영 기준

운영에서는 embedding 비용, index refresh 주기, vector DB latency, top-k, reranker 비용과 LLM token 사용량을 함께 관리해야 합니다.

운영 전 확인 목록
  • 문서 수집과 재색인 작업을 query API와 분리합니다.
  • 문서·chunk·embedding·index 버전을 연결해 기록합니다.
  • 검색 latency, reranker latency와 LLM latency를 구분해 측정합니다.
  • 검색 결과와 최종 답변의 citation을 검증합니다.
  • 문서 접근 권한을 검색 단계에서 적용합니다.
  • 변경된 문서의 삭제 및 재색인 정책을 마련합니다.
  • 외부 LLM, reranker와 vector DB 장애에 fallback을 준비합니다.
  • 질문, 검색 문서와 답변 로그에서 개인정보를 보호합니다.

11. 검증 전략

검색 품질은 context recall과 precision, citation 정확도와 응답 충실도를 기준으로 평가해야 합니다. 실제 장애나 잘못된 답변 사례는 고정 평가 데이터에 추가해 회귀 테스트로 유지합니다.

품질 축 검증 방법 완료 기준
정확성 정상·경계·실패 질문을 자동화합니다. 핵심 시나리오가 반복 실행되어도 통과합니다.
검색 품질 context recall·precision과 top-k 결과를 평가합니다. 정답에 필요한 문서가 허용 범위 내에 검색됩니다.
근거성 faithfulness와 citation 정확도를 확인합니다. 문서에 없는 내용을 근거 없이 단정하지 않습니다.
회귀 방지 장애 사례를 regression dataset으로 유지합니다. 같은 오류가 다음 배포에서 재발하지 않습니다.
성능 ingestion, 검색, rerank와 응답 시간을 측정합니다. 서비스 지연 시간과 비용 목표를 충족합니다.
운영성 로그, metric, alert와 장애 복구 절차를 검증합니다. 장애 원인과 문서·index 버전을 추적할 수 있습니다.

마무리

LlamaIndex를 잘 활용하려면 VectorStoreIndex를 생성하는 코드보다 문서 수집, chunking, metadata, 검색, reranking과 평가를 하나의 데이터 파이프라인으로 설계해야 합니다. 작은 평가 데이터셋으로 먼저 검색 전략을 비교하고, 품질 지표와 운영 비용을 기준으로 Agent와 고급 워크플로우를 단계적으로 확장하세요.

핵심 정리
  • ingestion과 query 파이프라인을 분리합니다.
  • Sentence Window, 계층형 chunking과 하이브리드 검색을 비교합니다.
  • 복합 질문은 ReAct Agent와 Sub-question 분해를 활용할 수 있습니다.
  • 영구 벡터 DB에서는 문서 변경, 삭제와 index 버전을 관리합니다.
  • RAGAS와 고정 평가셋으로 검색 및 답변 품질 회귀를 검증합니다.

원문: AI DevOps Korea LlamaIndex 가이드  ·  LlamaIndex 웹 IDE

반응형

댓글