본문으로 건너뛰기
Kreath Archive
TechProjectsBooksAbout
TechProjectsBooksAbout

내비게이션

  • Tech
  • Projects
  • Books
  • About
  • Tags

카테고리

  • AI / ML
  • 웹 개발
  • 프로그래밍
  • 개발 도구

연결

  • GitHub
  • Email
  • RSS
© 2026 Kreath Archive. All rights reserved.Built with Next.js + MDX
홈TechProjectsBooksAbout
//
  1. 홈
  2. 테크
  3. 4장: LlamaIndex -- 데이터 프레임워크와 워크플로우
2026년 2월 8일·AI / ML·

4장: LlamaIndex -- 데이터 프레임워크와 워크플로우

LlamaIndex의 데이터 커넥터, 인덱스 유형, 쿼리 엔진, 그리고 이벤트 드리븐 Workflows 1.0을 실전 예제와 함께 분석합니다.

15분754자11개 섹션
orchestrationai-frameworkaillm
공유
ai-orchestration4 / 11
1234567891011
이전3장: LangGraph -- 그래프 기반 에이전트 오케스트레이션다음5장: Semantic Kernel -- 엔터프라이즈 AI 오케스트레이션

이 장에서 배우는 것

  • LlamaIndex의 설계 철학과 데이터 중심 접근 방식
  • 데이터 커넥터(Data Connector)와 노드 파서(Node Parser)의 역할
  • 인덱스 유형별 특성: Vector, List, Tree, Keyword, Graph
  • 쿼리 엔진의 작동 원리와 커스터마이징
  • Workflows 1.0: 이벤트 드리븐, 비동기 우선 오케스트레이션
  • Agent Workflows와 Agent Client Protocol

데이터가 먼저다

LangChain이 "체인"을 중심으로 설계되었다면, LlamaIndex는 "데이터"를 중심으로 설계되었습니다. "당신의 데이터를 LLM에 연결하라"는 슬로건 그대로, 다양한 데이터 소스에서 정보를 수집하고, 구조화하고, LLM이 효과적으로 활용할 수 있게 만드는 것이 핵심 미션입니다.

이 접근 방식의 장점은 명확합니다. 데이터 수집부터 인덱싱, 검색, 응답 생성까지의 전체 파이프라인을 하나의 프레임워크 안에서 일관되게 관리할 수 있습니다.


데이터 커넥터

데이터 커넥터는 외부 데이터 소스에서 Document 객체를 생성하는 역할을 합니다. LlamaIndex는 LlamaHub을 통해 수백 개의 커넥터를 제공합니다.

data_connectors.py
python
from llama_index.core import SimpleDirectoryReader
from llama_index.readers.web import SimpleWebPageReader
from llama_index.readers.database import DatabaseReader
 
# 로컬 파일 (PDF, DOCX, TXT 등 자동 감지)
documents = SimpleDirectoryReader(
    input_dir="./data",
    recursive=True,
    required_exts=[".pdf", ".md", ".txt"],
).load_data()
 
# 웹 페이지
web_docs = SimpleWebPageReader(html_to_text=True).load_data(
    urls=["https://docs.example.com/guide"]
)
 
# 데이터베이스
db_docs = DatabaseReader(
    sql_database=sql_db,
).load_data(
    query="SELECT title, content FROM articles WHERE published = true"
)
Tip

SimpleDirectoryReader는 파일 확장자를 자동으로 감지하여 적절한 파서를 선택합니다. PDF에는 PyPDF, DOCX에는 python-docx를 사용하며, 커스텀 파서를 등록할 수도 있습니다.


노드 파서

Document는 보통 긴 텍스트를 담고 있습니다. 노드 파서는 이를 LLM의 컨텍스트 윈도우에 맞는 크기의 노드(Node)로 분할합니다.

node_parsers.py
python
from llama_index.core.node_parser import (
    SentenceSplitter,
    SemanticSplitterNodeParser,
    HierarchicalNodeParser,
)
from llama_index.core.ingestion import IngestionPipeline
 
# 문장 기반 분할 (가장 기본적)
sentence_splitter = SentenceSplitter(
    chunk_size=1024,
    chunk_overlap=200,
)
 
# 의미 기반 분할 (임베딩 유사도로 경계 결정)
semantic_splitter = SemanticSplitterNodeParser(
    buffer_size=1,
    breakpoint_percentile_threshold=95,
    embed_model=embed_model,
)
 
# 계층적 분할 (부모-자식 관계 유지)
hierarchical_splitter = HierarchicalNodeParser.from_defaults(
    chunk_sizes=[2048, 512, 128],
)
 
# 인제스천 파이프라인으로 조합
pipeline = IngestionPipeline(
    transformations=[
        sentence_splitter,
        embed_model,
    ]
)
nodes = pipeline.run(documents=documents)

분할 전략 비교

전략장점단점적합한 경우
SentenceSplitter빠르고 예측 가능의미 경계 무시일반 문서
SemanticSplitter의미 단위 보존임베딩 비용 발생기술 문서, 논문
HierarchicalNodeParser다중 해상도 검색복잡한 구조긴 문서, 보고서

인덱스 유형

LlamaIndex는 다양한 인덱스 유형을 제공하며, 각각 다른 검색 패턴에 최적화되어 있습니다.

VectorStoreIndex

가장 널리 사용되는 인덱스 유형입니다. 노드를 벡터로 변환하여 유사도 검색을 수행합니다.

vector_index.py
python
from llama_index.core import VectorStoreIndex, StorageContext
from llama_index.vector_stores.chroma import ChromaVectorStore
import chromadb
 
# Chroma 벡터 스토어 연결
chroma_client = chromadb.PersistentClient(path="./chroma_db")
chroma_collection = chroma_client.get_or_create_collection("docs")
vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
 
storage_context = StorageContext.from_defaults(
    vector_store=vector_store
)
 
# 인덱스 생성
index = VectorStoreIndex.from_documents(
    documents,
    storage_context=storage_context,
    show_progress=True,
)

TreeIndex

문서를 트리 구조로 요약하여 인덱싱합니다. 전체 문서에 대한 요약 질문에 효과적입니다.

tree_index.py
python
from llama_index.core import TreeIndex
 
tree_index = TreeIndex.from_documents(
    documents,
    num_children=10,  # 각 노드의 자식 수
    build_tree_from_text=True,
)

KeywordTableIndex

키워드 기반 검색에 특화된 인덱스입니다. 각 노드에서 키워드를 추출하여 역인덱스를 구축합니다.

keyword_index.py
python
from llama_index.core import KeywordTableIndex
 
keyword_index = KeywordTableIndex.from_documents(
    documents,
    max_keywords_per_node=10,
)

KnowledgeGraphIndex

엔티티와 관계를 추출하여 지식 그래프를 구축합니다.

knowledge_graph_index.py
python
from llama_index.core import KnowledgeGraphIndex
 
kg_index = KnowledgeGraphIndex.from_documents(
    documents,
    max_triplets_per_chunk=10,
    include_embeddings=True,
)
Info

인덱스 유형 선택은 질문의 특성에 따라 달라집니다. "X에 대해 설명해줘"처럼 특정 정보를 찾는 질문에는 VectorStoreIndex가, "이 문서의 핵심 내용은?"처럼 전체 맥락이 필요한 질문에는 TreeIndex가 적합합니다.


쿼리 엔진

인덱스 위에 쿼리 엔진을 구성하여 사용자 질문에 응답합니다.

기본 쿼리 엔진

query_engine.py
python
# 기본 쿼리 엔진
query_engine = index.as_query_engine(
    similarity_top_k=5,
    response_mode="compact",
)
 
response = query_engine.query("LlamaIndex의 핵심 개념은 무엇인가요?")
print(response.response)
print(f"소스 노드: {len(response.source_nodes)}")

응답 모드

모드동작적합한 경우
refine각 노드로 순차적 응답 개선정확한 응답이 필요할 때
compact노드를 압축 후 한 번에 처리기본 추천
tree_summarize트리 구조로 요약긴 컨텍스트 요약
simple_summarize모든 노드를 한 번에 요약빠른 응답

라우터 쿼리 엔진

여러 인덱스를 조합하여 질문 유형에 따라 적절한 인덱스를 선택합니다.

router_query_engine.py
python
from llama_index.core.query_engine import RouterQueryEngine
from llama_index.core.selectors import LLMSingleSelector
from llama_index.core.tools import QueryEngineTool
 
# 각 인덱스를 도구로 래핑
vector_tool = QueryEngineTool.from_defaults(
    query_engine=vector_index.as_query_engine(),
    description="특정 기술 세부사항을 찾을 때 사용",
)
summary_tool = QueryEngineTool.from_defaults(
    query_engine=tree_index.as_query_engine(),
    description="전체적인 내용 요약이 필요할 때 사용",
)
 
# 라우터로 조합
router_engine = RouterQueryEngine(
    selector=LLMSingleSelector.from_defaults(),
    query_engine_tools=[vector_tool, summary_tool],
)
 
response = router_engine.query("이 프로젝트의 전반적인 아키텍처를 설명해줘")

Workflows 1.0

LlamaIndex의 Workflows는 이벤트 드리븐, 비동기 우선의 오케스트레이션 시스템입니다. 데이터 인제스천, 쿼리 처리, 에이전트 워크플로우를 유연하게 구성할 수 있습니다.

기본 개념

Workflows는 이벤트(Event) 를 중심으로 동작합니다. 각 스텝(Step)은 특정 이벤트를 수신하고, 처리 후 새로운 이벤트를 발행합니다.

Workflow 구현

workflow_basic.py
python
from llama_index.core.workflow import (
    Workflow,
    Event,
    StartEvent,
    StopEvent,
    step,
)
 
# 커스텀 이벤트 정의
class RetrievalEvent(Event):
    nodes: list
    query: str
 
class SynthesisEvent(Event):
    response: str
 
# 워크플로우 정의
class RAGWorkflow(Workflow):
    @step
    async def retrieve(self, ev: StartEvent) -> RetrievalEvent:
        """문서 검색 단계"""
        query = ev.query
        nodes = await self.index.aretrieve(query)
        return RetrievalEvent(nodes=nodes, query=query)
 
    @step
    async def synthesize(self, ev: RetrievalEvent) -> StopEvent:
        """응답 합성 단계"""
        context = "\n".join(n.text for n in ev.nodes)
        response = await self.llm.acomplete(
            f"컨텍스트: {context}\n\n질문: {ev.query}"
        )
        return StopEvent(result=str(response))
 
# 실행
workflow = RAGWorkflow()
result = await workflow.run(query="LlamaIndex Workflows란?")

브랜치와 조인

복잡한 워크플로우에서 여러 경로를 병렬로 실행하고 결과를 합치는 패턴입니다.

workflow_branch.py
python
class ParallelRAGWorkflow(Workflow):
    @step
    async def route(self, ev: StartEvent) -> RetrievalEvent:
        """질문을 여러 검색 경로로 분기"""
        # 동시에 두 이벤트 발행
        self.send_event(
            RetrievalEvent(source="vector", query=ev.query)
        )
        self.send_event(
            RetrievalEvent(source="keyword", query=ev.query)
        )
        return None  # 이 스텝은 StopEvent를 반환하지 않음
 
    @step
    async def retrieve(self, ev: RetrievalEvent) -> ResultEvent:
        """각 소스에서 검색"""
        if ev.source == "vector":
            nodes = await self.vector_index.aretrieve(ev.query)
        else:
            nodes = await self.keyword_index.aretrieve(ev.query)
        return ResultEvent(nodes=nodes, source=ev.source)
 
    @step(num_workers=2)  # 2개의 결과를 모두 수집
    async def combine(self, ev: ResultEvent) -> StopEvent:
        """결과 합성"""
        results = self.collect_events(ev, [ResultEvent, ResultEvent])
        if results is None:
            return None  # 아직 모든 결과가 도착하지 않음
 
        all_nodes = []
        for r in results:
            all_nodes.extend(r.nodes)
 
        response = await self.synthesize(all_nodes)
        return StopEvent(result=response)
Warning

collect_events를 사용할 때 기대하는 이벤트 수가 정확해야 합니다. 하나의 이벤트가 누락되면 워크플로우가 영구적으로 대기 상태에 빠질 수 있으므로, 타임아웃 설정을 함께 적용하세요.


Agent Workflows

Workflows 위에 구축된 에이전트 시스템으로, 도구 호출과 추론을 이벤트 기반으로 처리합니다.

agent_workflow.py
python
from llama_index.core.agent.workflow import AgentWorkflow
from llama_index.core.tools import FunctionTool
 
# 도구 정의
def search_web(query: str) -> str:
    """웹 검색을 수행합니다."""
    return f"검색 결과: {query}에 대한 정보..."
 
def calculate(expression: str) -> str:
    """수학 계산을 수행합니다."""
    return str(eval(expression))
 
# 에이전트 워크플로우 생성
agent = AgentWorkflow.from_tools_or_functions(
    tools_or_functions=[
        FunctionTool.from_defaults(fn=search_web),
        FunctionTool.from_defaults(fn=calculate),
    ],
    llm=llm,
    system_prompt="당신은 유능한 연구 어시스턴트입니다.",
)
 
# 실행
response = await agent.run("서울의 인구와 면적을 검색하고, 인구밀도를 계산해줘")

성능 특성

LlamaIndex는 프레임워크 오버헤드 측면에서 효율적인 성능을 보입니다.

  • 프레임워크 오버헤드: 약 6ms
  • 토큰 사용량: 약 1.60k (검색 증강 응답 기준)
  • 메모리 사용: 인덱스 크기에 비례하며, 외부 벡터 스토어 사용 시 메모리 영향 최소화
Tip

LlamaIndex의 강점은 데이터 처리에 있습니다. 복잡한 에이전트 오케스트레이션이 필요하다면 LangGraph와 조합하는 하이브리드 접근을 고려하세요. LlamaIndex가 데이터 레이어를, LangGraph가 오케스트레이션 레이어를 담당하는 구조입니다. 이 패턴은 11장에서 자세히 다룹니다.


핵심 요약

  • LlamaIndex는 데이터 중심 프레임워크로, 데이터 수집부터 인덱싱, 검색, 응답 생성까지의 전체 파이프라인을 관리합니다.
  • 데이터 커넥터로 다양한 소스에서 데이터를 수집하고, 노드 파서로 적절한 크기로 분할합니다.
  • Vector, Tree, Keyword, KnowledgeGraph 등 다양한 인덱스 유형이 있으며, 질문 특성에 따라 선택합니다.
  • 쿼리 엔진은 인덱스 위에서 동작하며, 라우터로 여러 인덱스를 조합할 수 있습니다.
  • Workflows 1.0은 이벤트 드리븐, 비동기 우선의 오케스트레이션으로 유연한 워크플로우를 구성합니다.
  • 프레임워크 오버헤드 약 6ms로 효율적이며, 데이터 처리 특화 영역에서 강점을 발휘합니다.

다음 장 예고

5장에서는 Microsoft의 Semantic Kernel을 분석합니다. C#, Python, Java를 지원하는 멀티 언어 아키텍처, 플러그인 시스템과 플래너, Azure 통합, 그리고 엔터프라이즈 환경에서의 보안과 거버넌스 기능을 살펴보겠습니다.

이 글이 도움이 되셨나요?

관련 주제 더 보기

#orchestration#ai-framework#ai#llm

관련 글

AI / ML

5장: Semantic Kernel -- 엔터프라이즈 AI 오케스트레이션

Microsoft Semantic Kernel의 멀티 언어 아키텍처, 플러그인 시스템, 플래너, Azure 통합, 엔터프라이즈 보안과 거버넌스를 분석합니다.

2026년 2월 10일·14분
AI / ML

3장: LangGraph -- 그래프 기반 에이전트 오케스트레이션

LangGraph 1.0/1.1의 StateGraph, 듀러블 상태, 조건부 엣지, 휴먼인더루프, type-safe 스트리밍을 실전 예제와 함께 분석합니다.

2026년 2월 6일·14분
AI / ML

6장: Haystack -- 모듈러 파이프라인 아키텍처

deepset Haystack 2.x의 컴포넌트와 파이프라인 개념, 방향성 멀티그래프, AsyncPipeline, 라우터, 문서 스토어를 분석합니다.

2026년 2월 12일·14분
이전 글3장: LangGraph -- 그래프 기반 에이전트 오케스트레이션
다음 글5장: Semantic Kernel -- 엔터프라이즈 AI 오케스트레이션

댓글

목차

약 15분 남음
  • 이 장에서 배우는 것
  • 데이터가 먼저다
  • 데이터 커넥터
  • 노드 파서
    • 분할 전략 비교
  • 인덱스 유형
    • VectorStoreIndex
    • TreeIndex
    • KeywordTableIndex
    • KnowledgeGraphIndex
  • 쿼리 엔진
    • 기본 쿼리 엔진
    • 응답 모드
    • 라우터 쿼리 엔진
  • Workflows 1.0
    • 기본 개념
    • Workflow 구현
    • 브랜치와 조인
  • Agent Workflows
  • 성능 특성
  • 핵심 요약
  • 다음 장 예고