블로그

​​LangGraph와 Elasticsearch를 사용하여 RAG 워크플로우 구축하기

효율적인 데이터 검색과 AI 기반 응답을 위한 RAG 워크플로우를 구축하기 위해 Elasticsearch로 LangGraph 검색 에이전트 템플릿을 구성하고 사용자 정의하는 방법을 알아보세요.

LangGraph 검색 에이전트 템플릿은 LangGraph Studio에서 LangGraph를 사용하여 검색 기반 질문 답변 시스템을 쉽게 만들 수 있도록 LangChain에서 개발한 스타터 프로젝트입니다. 이 템플릿은 Elasticsearch와 원활하게 통합되도록 미리 구성되어 있어 개발자가 문서를 효율적으로 색인하고 검색할 수 있는 에이전트를 신속하게 구축할 수 있습니다.

이 블로그는 LangGraph Studio와 LangGraph CLI를 사용하여 LangChain 검색 에이전트 템플릿을 실행하고 커스터마이징하는 방법에 중점을 두고 있습니다. 이 템플릿은 Elasticsearch와 같은 다양한 검색 백엔드를 활용하여 검색 증강 생성(RAG) 애플리케이션을 구축하기 위한 프레임워크를 제공합니다.

에이전트 흐름을 사용자 정의하면서 Elastic으로 환경을 설정하고, 구성하고, 템플릿을 효율적으로 실행하는 방법을 안내해드립니다.

필수 구성 요소

계속 진행하기 전에 다음이 설치되어 있는지 확인하세요:

  • Elasticsearch Cloud 배포 또는 온프레미스 Elasticsearch 배포(또는 Elastic Cloud에서 14일 무료 체험판 생성) - 버전 8.0.0 이상

  • Python 3.9+

  • Cohere (이 가이드에서 사용됨), OpenAI 또는 Anthropic/Claude와같은 LLM 제공업체에 대한 액세스

LangGraph 앱 만들기

1. LangGraph CLI 설치

pip install --upgrade "langgraph-cli[inmem]"

2. 검색 에이전트 템플릿에서 LangGraph 앱 만들기

mkdir lg-agent-demo
cd lg-agent-demo
langgraph new lg-agent-demo

사용 가능한 템플릿 목록에서 선택할 수 있는 대화형 메뉴가 표시됩니다. 아래와 같이 검색 에이전트에는 4개를, 파이썬에는 1개를 선택합니다:

대화형 검색 템플릿.
  • 문제 해결: 오류 발생 시: "urllib.error.URLError: <urlopen 오류 [SSL: CERTIFICATE_VERIFY_FAILED] 인증서 확인 실패: 로컬 발급자 인증서(_ssl.c:1000)를 얻을 수 없음> "

아래와 같이 파이썬의 인증서 설치 명령을 실행하여 문제를 해결하세요.

Python 인증서 설치 명령을 실행합니다.

3. 설치 종속성

새 LangGraph 앱의 루트에서 가상 환경을 만들고 edit 모드에서 종속성을 설치하여 로컬 변경 사항이 서버에서 사용되도록 합니다:

#For Mac
python3 -m venv lg-demo
source lg-demo/bin/activate 
pip install -e .

#For Windows
python3 -m venv lg-demo
lg-demo\Scripts\activate 
pip install -e .

환경 설정

1. .environment 만들기 파일

.env 파일에는 앱이 선택한 LLM 및 검색 제공업체에 연결할 수 있도록 API 키와 구성이 저장되어 있습니다. 예제 구성을 복제하여 새 .env 파일을 생성합니다:

cp .env.example .env

2. .env 파일

.env 파일은 기본 구성 세트와 함께 제공됩니다. 설정에 따라 필요한 API 키와 값을 추가하여 업데이트할 수 있습니다. 사용 사례와 관련이 없는 키는 변경하지 않거나 제거할 수 있습니다.

# To separate your traces from other applications
LANGSMITH_PROJECT=retrieval-agent

# LLM choice (set the API key for your selected provider):
ANTHROPIC_API_KEY=your_anthropic_api_key
FIREWORKS_API_KEY=your_fireworks_api_key
OPENAI_API_KEY=your_openai_api_key

# Retrieval provider (configure based on your chosen service):

## Elastic Cloud:
ELASTICSEARCH_URL=https://your_elastic_cloud_url
ELASTICSEARCH_API_KEY=your_elastic_api_key

## Elastic Local:
ELASTICSEARCH_URL=http://host.docker.internal:9200
ELASTICSEARCH_USER=elastic
ELASTICSEARCH_PASSWORD=changeme

## Pinecone:
PINECONE_API_KEY=your_pinecone_api_key
PINECONE_INDEX_NAME=your_pinecone_index_name

## MongoDB Atlas:
MONGODB_URI=your_mongodb_connection_string

# Cohere API key:
COHERE_API_KEY=your_cohere_api_key
  • 예시 .env 파일(Elastic Cloud 및 Cohere 사용)

아래는 이 블로그에서 설명한 대로 Elastic Cloud를 검색 공급자로, Cohere를 LLM으로 사용하는 샘플 .env 구성입니다:

# To separate your traces from other applications
LANGSMITH_PROJECT=retrieval-agent
#Retrieval Provider
# Elasticsearch configuration
ELASTICSEARCH_URL=elastic-url:443
ELASTICSEARCH_API_KEY=elastic_api_key
# Cohere API key
COHERE_API_KEY=cohere_api_key

참고: 이 가이드에서는 응답 생성과 임베딩 모두에 Cohere를 사용하지만 , 사용 사례에 따라OpenAI, Claude 또는 로컬 LLM 모델과 같은 다른 LLM 제공업체를 자유롭게 사용할 수 있습니다. 사용하려는 각 키가.env파일에 존재하고 올바르게 설정되어 있는지 확인하세요.

3. 구성 파일 -configuration.py 업데이트

적절한 API 키로 .env 파일을 설정한 후 다음 단계는 애플리케이션의 기본 모델 구성을 업데이트하는 것입니다. 구성을 업데이트하면 시스템에서 .env 파일에 지정한 서비스 및 모델을 사용하도록 합니다.

구성 파일로 이동합니다:

 cd src/retrieval_graph

configuration.py 파일에는 검색 에이전트가 세 가지 주요 작업에 사용하는 기본 모델 설정이 포함되어 있습니다:

  • 임베딩 모델 - 문서를 벡터 표현으로 변환합니다.

  • 쿼리 모델 - 사용자의 쿼리를 벡터로 처리합니다.

  • 응답 모델 - 최종 응답 생성

기본적으로 이 코드는 OpenAI (예: openai/text-embedding-3-small) 및 Anthropic (예: anthropic/claude-3-5-sonnet-20240620 and anthropic/claude-3-haiku-20240307)의 모델을 사용합니다. 이 블로그에서는 Cohere 모델을 사용하도록 전환합니다. 이미 OpenAI 또는 Anthropic을 사용 중인 경우 변경할 필요가 없습니다.

변경 예시(Cohere 사용):

configuration.py 을 열고 아래와 같이 모델 기본값을 수정합니다:

…
 embedding_model: Annotated[
       str,
       {"__template_metadata__": {"kind": "embeddings"}},
   ] = field(
       default="cohere/embed-english-v3.0",
…
response_model: Annotated[str, {"__template_metadata__": {"kind": "llm"}}] = field(
       default="cohere/command-r-08-2024",
…
query_model: Annotated[str, {"__template_metadata__": {"kind": "llm"}}] = field(
       default="cohere/command-r-08-2024",
       metadata={

LangGraph CLI로 검색 에이전트 실행하기

1. LangGraph 서버를 시작합니다.

cd lg-agent-demo
langgraph dev

이렇게 하면 LangGraph API 서버가 로컬에서 시작됩니다. 성공적으로 실행되면 다음과 같은 내용이 표시됩니다:

 LangGraph API 서버가 성공적으로 실행 중입니다.

Open Studio UI URL.

두 가지 그래프를 사용할 수 있습니다:

  • 검색 그래프: Elasticsearch에서 데이터를 검색하고 LLM을 사용하여 쿼리에 응답합니다.

  • 인덱서 그래프: 문서를 Elasticsearch로 색인하고 LLM을 사용하여 임베딩을 생성합니다.

2. 인덱서 그래프 구성

  • 인덱서 그래프를 엽니다.

  • 어시스턴트 관리를 클릭합니다.

    • '새 어시스턴트 추가'를 클릭하고 지정된 대로 사용자 세부 정보를 입력한 다음 창을 닫습니다.

{"user_id": "101"}

3. 샘플 문서 색인 생성

  • 다음 샘플 문서는 가상의 분기별 보고서인 NoveTech 조직에 대한 색인입니다:

[
  {    "page_content": "NoveTech Solutions Q1 2025 Report - Revenue: $120.5M, Net Profit: $18.2M, EPS: $2.15. Strong AI software launch and $50M government contract secured."
  },
  {
    "page_content": "NoveTech Solutions Business Highlights - AI-driven analytics software gained 15% market share. Expansion into Southeast Asia with two new offices. Cloud security contract secured."
  },
  {
    "page_content": "NoveTech Solutions Financial Overview - Operating expenses at $85.3M, Gross Margin 29.3%. Stock price rose from $72.5 to $78.3. Market Cap reached $5.2B."
  },
  {
    "page_content": "NoveTech Solutions Challenges - Rising supply chain costs impacting hardware production. Regulatory delays slowing European expansion. Competitive pressure in cybersecurity sector."
  },
  {
    "page_content": "NoveTech Solutions Future Outlook - Expected revenue for Q2 2025: $135M. New AI chatbot and blockchain security platform launch planned. Expansion into Latin America."
  },
  {
    "page_content": "NoveTech Solutions Market Performance - Year-over-Year growth at 12.7%. Stock price increase reflects investor confidence. Cybersecurity and AI sectors remain competitive."
  },
  {
    "page_content": "NoveTech Solutions Strategic Moves - Investing in R&D to enhance AI-driven automation. Strengthening partnerships with enterprise cloud providers. Focusing on data privacy solutions."
  },
  {
    "page_content": "NoveTech Solutions CEO Statement - 'NoveTech Solutions continues to innovate in AI and cybersecurity. Our growth strategy remains strong, and we foresee steady expansion in the coming quarters.'"
  }
]

문서가 색인되면 아래와 같이 토론글에 삭제 메시지가 표시됩니다.

LangGraph 및 Elasticsearch RAG 워크플로우 문서 색인.

4. 검색 그래프 실행

  • 검색 그래프로 전환합니다.

  • 다음 검색어를 입력합니다:

What was NovaTech Solutions total revenue in Q1 2025?
LangGraph 및 Elasticsearch 검색 그래프 실행하기

시스템은 관련 문서를 반환하고 색인된 데이터를 기반으로 정확한 답변을 제공합니다.

검색 에이전트 사용자 지정

사용자 경험을 개선하기 위해 검색 그래프에 사용자 지정 단계를 도입하여 사용자가 다음 세 가지 질문을 예측할 수 있도록 했습니다. 이 예측은 다음을 기반으로 합니다:

  • 검색된 문서의 컨텍스트

  • 이전 사용자 상호 작용

  • 마지막 사용자 쿼리

쿼리 예측 기능을 구현하려면 다음과 같은 코드 변경이 필요합니다:

1. 그래프.py 업데이트

  • predict_query 기능을 추가합니다:

async def predict_query(
   state: State, *, config: RunnableConfig
) -> dict[str, list[BaseMessage]]:
   logger.info(f"predict_query predict_querypredict_query predict_query predict_query predict_query")  # Log the query

   configuration = Configuration.from_runnable_config(config)
   prompt = ChatPromptTemplate.from_messages(
       [
           ("system", configuration.predict_next_question_prompt),
           ("placeholder", "{messages}"),
       ]
   )
   model = load_chat_model(configuration.response_model)
   user_query = state.queries[-1] if state.queries else "No prior query available"
   logger.info(f"user_query: {user_query}")
   logger.info(f"statemessage: {state.messages}")
   #human_messages = [msg for msg in state.message if isinstance(msg, HumanMessage)]

   message_value = await prompt.ainvoke(
       {
           "messages": state.messages,
           "user_query": user_query,  # Use the most recent query as primary input
           "system_time": datetime.now(tz=timezone.utc).isoformat(),
       },
       config,
   )

   next_question = await model.ainvoke(message_value, config)
   return {"next_question": [next_question]}
  • respond 함수를 수정하여 메시지 대신 response 객체 를 반환하도록 합니다:

async def respond(
   state: State, *, config: RunnableConfig
) -> dict[str, list[BaseMessage]]:
   """Call the LLM powering our "agent"."""
   configuration = Configuration.from_runnable_config(config)
   # Feel free to customize the prompt, model, and other logic!
   prompt = ChatPromptTemplate.from_messages(
       [
           ("system", configuration.response_system_prompt),
           ("placeholder", "{messages}"),
       ]
   )
   model = load_chat_model(configuration.response_model)

   retrieved_docs = format_docs(state.retrieved_docs)
   message_value = await prompt.ainvoke(
       {
           "messages": state.messages,
           "retrieved_docs": retrieved_docs,
           "system_time": datetime.now(tz=timezone.utc).isoformat(),
       },
       config,
   )
   response = await model.ainvoke(message_value, config)
   # We return a list, because this will get added to the existing list
   return {"response": [response]}
  • 그래프 구조를 업데이트하여 predict_query에 대한 새 노드와 에지를 추가합니다:

builder.add_node(generate_query)
builder.add_node(retrieve)
builder.add_node(respond)
builder.add_node(predict_query)
builder.add_edge("__start__", "generate_query")
builder.add_edge("generate_query", "retrieve")
builder.add_edge("retrieve", "respond")
builder.add_edge("respond", "predict_query")

2. prompts.py 업데이트

  • prompts.py 에서 게리 예측을 위한 프롬프트를 작성합니다:

PREDICT_NEXT_QUESTION_PROMPT = """Given the user query and the retrieved documents, suggest the most likely next question the user might ask.

**Context:**
- Previous Queries:
{previous_queries}

- Latest User Query: {user_query}

- Retrieved Documents:
{retrieved_docs}

**Guidelines:**
1. Do not suggest a question that has already been asked in previous queries.
2. Consider the retrieved documents when predicting the next logical question.
3. If the user's query is already fully answered, suggest a relevant follow-up question.
4. Keep the suggested question natural and conversational.
5. Suggest at least 3 question

System time: {system_time}"""

3. configuration.py 업데이트

  • predict_next_question_prompt 을 추가합니다:

predict_next_question_prompt: str = field(
       default=prompts.PREDICT_NEXT_QUESTION_PROMPT,
       metadata={"description": "The system prompt used for generating responses."},
   )

4. state.py 업데이트

  • 다음 속성을 추가합니다:

response: Annotated[Sequence[AnyMessage], add_messages]
next_question : Annotated[Sequence[AnyMessage], add_messages]

5. 검색 그래프 다시 실행

  • 다음 검색어를 다시 입력합니다:

What was NovaTech Solutions total revenue in Q1 2025?

시스템은 입력을 처리하고 아래와 같이 사용자가 질문할 수 있는 세 가지 관련 질문을 예측합니다.

LangGraph와 Elasticsearch를 사용하여 3개의 사용자 질문으로 검색 그래프 실행하기

결론

LangGraph Studio와 CLI에 검색 에이전트 템플릿을 통합하면 몇 가지 주요 이점이 있습니다:

  • 개발 가속화: 템플릿 및 시각화 도구는 검색 워크플로우의 생성 및 디버깅을 간소화하여 개발 시간을 단축합니다.

  • 원활한 배포: API 및 자동 확장에 대한 기본 지원으로 여러 환경에 걸쳐 원활한 배포를 보장합니다.

  • 간편한 업데이트: 워크플로우 수정, 새로운 기능 추가, 추가 노드 통합이 간단해 검색 프로세스를 쉽게 확장하고 개선할 수 있습니다.

  • 영구 메모리: 시스템이 상담원 상태와 지식을 유지하여 일관성과 안정성을 향상시킵니다.

  • 유연한 워크플로 모델링: 개발자는 특정 사용 사례에 맞게 검색 로직과 커뮤니케이션 규칙을 사용자 지정할 수 있습니다.

  • 실시간 상호작용 및 디버깅: 실행 중인 에이전트와 상호 작용하는 기능으로 효율적인 테스트 및 문제 해결이 가능합니다.

이러한 기능을 활용하여 조직은 데이터 접근성과 사용자 경험을 향상시키는 강력하고 효율적이며 확장 가능한 검색 시스템을 구축할 수 있습니다.

이 프로젝트의 전체 소스 코드는 GitHub에서 확인할 수 있습니다.

자주 묻는 질문

RAG 워크플로란 무엇인가요?

RAG(검색 증강 세대) 워크플로우는 AI 모델에 개인 데이터에 대한 액세스 권한을 부여하여 "환각 대신 사실에 기반한 정확한 답변을 제공할 수 있도록 하는 방식입니다."

LangGraph 에이전트의 데이터베이스로 Elasticsearch를 사용하는 이유는 무엇인가요?

Elasticsearch는 에이전트의 "장기 메모리" 역할을 합니다. 표준 데이터베이스와 달리, 벡터 검색(의미 파악)과 키워드 검색(정확한 용어 찾기)을 결합한 하이브리드 검색을 위해 구축되었습니다. 이렇게 하면 "1분기 매출" 또는 "재무 성장," Elasticsearch가 LangGraph가 처리할 수 있는 가장 관련성 높은 문서를 제공할 수 있습니다.

LangGraph 검색 에이전트 템플릿으로 다중 사용자 시스템을 구축할 수 있나요?

예. 이 문서에서는 user_id(예: "101")를 사용한 인덱서 그래프 구성을 통해 이를 보여줍니다. 이렇게 하면 특정 소유자가 있는 문서에 태그를 지정하여 검색 에이전트가 특정 사용자가 볼 수 있는 권한이 있는 정보만 찾을 수 있도록 할 수 있습니다.

관련 콘텐츠

고급 RAG 기술 2부: 쿼리 및 테스트

Han Xiang Choong

Elasticsearch를 통한 엔티티 해석, 4부: 최종 과제

Jessica Moszkowicz

ML을 활용하여 Streams에서 로그 구문 분석 자동화하기

Nastia Havriushenko

Elastic 에이전트 빌더와 GPT-OSS로 HR용 AI 에이전트 구축하기

Tomás Murúa

고급 RAG 기술 1부: 데이터 처리

Han Xiang Choong

최첨단 검색 환경을 구축할 준비가 되셨나요?

충분히 고급화된 검색은 한 사람의 노력만으로는 달성할 수 없습니다. Elasticsearch는 여러분과 마찬가지로 검색에 대한 열정을 가진 데이터 과학자, ML 운영팀, 엔지니어 등 많은 사람들이 지원합니다. 서로 연결하고 협력하여 원하는 결과를 얻을 수 있는 마법 같은 검색 환경을 구축해 보세요.

직접 사용해 보세요