검색
검색 (Retrieval)
대규모 언어 모델(LLM)은 강력하지만 두 가지 뚜렷한 한계가 있어요. 먼저 유한한 컨텍스트 — 전체 문서를 한 번에 집어넣을 수 없고, 다음으로 고정된 지식 — 학습 데이터가 특정 시점에 멈춰 있죠. 검색(Retrieval)은 쿼리 시점에 관련 외부 지식을 가져와서 이 문제를 풀어요. 이게 바로 **RAG(Retrieval-Augmented Generation, 검색 증강 생성)**의 토대이자, LLM의 답변을 상황에 맞는 정보로 다듬어 주는 핵심이에요.
출처: 공식문서
지식 기반 만들기 (Building a knowledge base)
**지식 기반(knowledge base)**은 검색에 사용할 문서나 정형 데이터의 저장소예요.
커스텀 지식 기반이 필요하다면 LangChain의 문서 로더(document loader)와 벡터 스토어(vector store)로 내 데이터를 가공해 만들 수 있어요.
이미 지식 기반이 있다면 (예: SQL 데이터베이스, 문서 데이터베이스, CRM, 사내 문서 시스템) 처음부터 다시 만들 필요가 없어요. 두 가지 방법이 있죠.
- 에이전트의 **툴(tool)**로 연결해서 Agentic RAG에서 활용하기
- 쿼리 후 검색된 내용을 컨텍스트로 LLM에 넘겨주는 (2-Step RAG)
지식 기반을 만들고 최소한의 RAG 워크플로우를 구성하는 방법은 "Semantic search" 튜토리얼에서 자세히 다뤄요. document loader, 임베딩, 벡터 스토어로 PDF 위에 검색 엔진을 올리고, 그 위에 최소 RAG를 얹는 흐름을 보여줘요.
검색에서 RAG로 (From retrieval to RAG)
검색은 LLM이 런타임에 관련 컨텍스트에 접근하게 해줘요. 그런데 실제 애플리케이션은 대부분 한 발 더 나가서, 검색을 생성(generation)과 통합해 근거 있고 상황을 반영한 답변을 만듭니다. 이게 **검색 증강 생성(RAG)**의 핵심 아이디어예요. 검색 파이프라인은 검색과 생성을 결합한 더 큰 시스템의 기반이 되는 거죠.
검색 파이프라인 (Retrieval pipeline)
전형적인 검색 워크플로우는 이렇게 생겼어요.
flowchart TB
subgraph ingest[" "]
direction LR
S(["Sources<br>(Google Drive, Slack, Notion, etc.)"]) --> L[Document Loaders]
L --> A([Documents])
end
A --> B[Split into chunks]
B --> C[Turn into embeddings]
C --> D[(Vector Store)]
Q([User Query]) --> E[Query embedding]
E --> D
D --> F[Retriever]
F --> G[LLM uses retrieved info]
G --> H([Answer])
각 컴포넌트는 모듈형이라, 앱의 로직을 다시 쓰지 않고도 로더, 스플리터, 임베딩, 벡터 스토어를 자유롭게 바꿔 끼울 수 있어요.
구성 요소 (Building blocks)
- Document loaders — Google Drive, Slack, Notion 같은 외부 소스에서 데이터를 읽어 표준화된
Document객체로 반환해요. - Text splitters — 큰 문서를 모델의 컨텍스트 윈도우 안에 들어가고 개별적으로 검색 가능한 작은 청크로 나눠요.
- Embedding models — 텍스트를 숫자 벡터로 바꿔서 의미가 비슷한 텍스트가 벡터 공간에서 가까이 위치하게 해요.
- Vector stores — 임베딩을 저장하고 검색하는 데 특화된 데이터베이스예요.
- Retrievers — 구조화되지 않은 쿼리를 받아 문서를 반환하는 인터페이스예요.
RAG 아키텍처 (RAG architectures)
RAG는 시스템의 요구에 따라 여러 방식으로 구현할 수 있어요. 각 유형을 아래에서 살펴볼게요.
| 아키텍처 | 설명 | 제어 | 유연성 | 지연시간 | 예시 사용 사례 |
|---|---|---|---|---|---|
| 2-Step RAG | 생성 전에 항상 검색이 먼저 일어남. 단순하고 예측 가능 | ✅ 높음 | ❌ 낮음 | ⚡ 빠름 | FAQ, 문서 봇 |
| Agentic RAG | LLM 기반 에이전트가 추론 중 언제, 어떻게 검색할지 결정 | ❌ 낮음 | ✅ 높음 | ⏳ 가변 | 여러 툴에 접근하는 리서치 어시스턴트 |
| Hybrid | 검증 단계와 함께 두 접근의 특성을 결합 | ⚖️ 중간 | ⚖️ 중간 | ⏳ 가변 | 품질 검증이 필요한 도메인 특화 Q&A |
지연시간: 일반적으로 2-Step RAG에서 지연시간이 더 예측 가능해요. LLM 호출 최대 횟수가 정해져 있고 제한돼 있기 때문이죠. 다만 이 예측 가능성은 LLM 추론 시간이 지배적이라는 전제 하에 성립해요. 실제 지연시간은 API 응답 시간, 네트워크 지연, 데이터베이스 쿼리 같은 검색 단계 성능에 따라 달라질 수 있어요.
2-Step RAG
2-Step RAG에서는 검색 단계가 항상 생성 단계보다 먼저 실행돼요. 이 아키텍처는 단순하고 예측 가능해서, 관련 문서 검색이 답변 생성의 명확한 전제 조건인 많은 애플리케이션에 적합해요.
graph TB
A[User Question] --> B["Retrieve Relevant Documents"]
B --> C["Generate Answer"]
C --> D[Return Answer to User]
- 튜토리얼: Semantic search — document loader, 임베딩, 벡터 스토어로 검색 가능한 지식 기반을 만들고 그 위에 retrieve-then-generate RAG 워크플로우를 돌려봐요.
- 튜토리얼: RAG 애플리케이션 평가 — 간단한 retrieve-then-generate RAG 앱을 만들고 LangSmith로 답변 정확성, 관련성, 근거성, 검색 품질을 측정해요.
Agentic RAG
**Agentic RAG(에이전틱 검색 증강 생성)**는 RAG의 강점과 에이전트 기반 추론을 결합해요. 답변 전에 문서를 가져오는 대신, (LLM으로 구동되는) 에이전트가 단계별로 추론하며 상호작용 중 언제, 어떻게 정보를 검색할지 스스로 결정하죠.
Agent에 RAG 동작을 켜는 데 필요한 것은 단 하나예요 — 문서 로더, 웹 API, 데이터베이스 쿼리 같은 외부 지식을 가져올 툴(tool) 하나 이상에 대한 접근이죠.
graph TB
A[User Input / Question] --> B["Agent (LLM)"]
B --> C{Need external info?}
C -- Yes --> D["Search using tool(s)"]
D --> H{Enough to answer?}
H -- No --> B
H -- Yes --> I[Generate final answer]
C -- No --> I
I --> J[Return to user]
에이전트에 검색 툴 하나만 주면 RAG가 되는데, 가장 간단한 형태는 이렇게 생겼어요.
import requests
from langchain.tools import tool
from langchain.chat_models import init_chat_model
from langchain.agents import create_agent
@tool
def fetch_url(url: str) -> str:
"""Fetch text content from a URL"""
response = requests.get(url, timeout=10.0)
response.raise_for_status()
return response.text
system_prompt = """\
Use fetch_url when you need to fetch information from a web-page; quote relevant snippets.
"""
agent = create_agent(
model="claude-sonnet-4-6",
tools=[fetch_url], # A tool for retrieval
system_prompt=system_prompt,
)
확장 예제: LangGraph의 llms.txt를 위한 Agentic RAG — 이 예제는 LangGraph 문서 쿼리를 돕는 Agentic RAG를 구현해요. 에이전트가 먼저 문서 URL 목록을 담은 llms.txt를 로드하고, fetch_documentation 툴을 동적으로 사용해 사용자 질문에 맞는 관련 내용을 가져와 처리해요.
import requests
from langchain.agents import create_agent
from langchain.messages import HumanMessage
from langchain.tools import tool
from markdownify import markdownify
ALLOWED_DOMAINS = ["https://langchain-ai.github.io/"]
LLMS_TXT = 'https://langchain-ai.github.io/langgraph/llms.txt'
@tool
def fetch_documentation(url: str) -> str:
"""Fetch and convert documentation from a URL"""
if not any(url.startswith(domain) for domain in ALLOWED_DOMAINS):
return (
"Error: URL not allowed. "
f"Must start with one of: {', '.join(ALLOWED_DOMAINS)}"
)
response = requests.get(url, timeout=10.0)
response.raise_for_status()
return markdownify(response.text)
# We will fetch the content of llms.txt, so this can
# be done ahead of time without requiring an LLM request.
llms_txt_content = requests.get(LLMS_TXT).text
# System prompt for the agent
system_prompt = f"""
You are an expert Python developer and technical assistant.
Your primary role is to help users with questions about LangGraph and related tools.
Instructions:
1. If a user asks a question you're unsure about—or one that likely involves API usage,
behavior, or configuration—you MUST use the `fetch_documentation` tool to consult the relevant docs.
2. When citing documentation, summarize clearly and include relevant context from the content.
3. Do not use any URLs outside of the allowed domain.
4. If a documentation fetch fails, tell the user and proceed with your best expert understanding.
You can access official documentation from the following approved sources:
{llms_txt_content}
You MUST consult the documentation to get up to date documentation
before answering a user's question about LangGraph.
Your answers should be clear, concise, and technically accurate.
"""
tools = [fetch_documentation]
model = init_chat_model("claude-sonnet-4-6", max_tokens=32_000)
agent = create_agent(
model=model,
tools=tools,
system_prompt=system_prompt,
name="Agentic RAG",
)
response = agent.invoke({
'messages': [
HumanMessage(content=(
"Write a short example of a langgraph agent using the "
"prebuilt create react agent. the agent should be able "
"to look up stock pricing information."
))
]
})
print(response['messages'][-1].content)
- 튜토리얼: RAG with Deep Agents — 쿼리 시점에 관련 청크를 가져와 파일시스템으로 내리고, 분석을 서브에이전트에 위임하는 문서 Q&A 에이전트를 만들어요.
Hybrid RAG
Hybrid RAG는 2-Step RAG와 Agentic RAG의 특성을 결합해요. 쿼리 전처리, 검색 검증, 생성 후 검사 같은 중간 단계를 도입하죠. 고정 파이프라인보다 유연하면서도 실행에 대한 일부 제어를 유지해요.
전형적인 구성 요소는 다음과 같아요.
- 쿼리 향상(Query enhancement): 입력 질문을 바꿔 검색 품질을 높여요. 불명확한 쿼리 재작성, 여러 변형 생성, 추가 컨텍스트로 쿼리 확장 등이 해당돼요.
- 검색 검증(Retrieval validation): 검색된 문서가 관련성 있고 충분한지 평가해요. 부족하면 쿼리를 다듬고 다시 검색할 수 있어요.
- 답변 검증(Answer validation): 생성된 답변의 정확성, 완전성, 원본 콘텐츠 일치 여부를 확인해요. 필요하면 답변을 재생성하거나 수정해요.
이 아키텍처는 보통 여러 단계 사이의 반복을 지원해요.
graph TB
A[User Question] --> B[Query Enhancement]
B --> C[Retrieve Documents]
C --> D{Sufficient Info?}
D -- No --> E[Refine Query]
E --> C
D -- Yes --> F[Generate Answer]
F --> G{Answer Quality OK?}
G -- No --> H{Try Different Approach?}
H -- Yes --> E
H -- No --> I[Return Best Answer]
G -- Yes --> I
I --> J[Return to User]
이 아키텍처는 이런 경우에 잘 맞아요.
-
모호하거나 과소 지정된 쿼리를 다루는 애플리케이션
-
검증이나 품질 관리 단계가 필요한 시스템
-
여러 소스나 반복적 다듬기(refinement)가 필요한 워크플로우
-
튜토리얼: Agentic RAG with Self-Correction — 검색·자가 교정과 에이전틱 추론을 결합한 Hybrid RAG 예제예요.
더 알아보기 (Learn more)
- Document loaders — 외부 소스에서 표준화된
Document로 데이터를 읽는 인터페이스 - Text splitters — 큰 문서를 검색 가능한 청크로 분할
- Embeddings — 텍스트를 의미 벡터로 변환
- Vector stores — 임베딩 저장·검색 전용 DB
- Retrievers — 비정형 쿼리를 문서로 변환하는 인터페이스