TL;DR
이 글은 인도 재무·법률 문서를 자동으로 파싱하기 위해 11개 노드로 구성된 LangGraph 기반 RAG 파이프라인을 구현한 사례로, 입력 전 PII 마스킹과 정규식 기반 차단으로 민감정보와 프롬프트 인젝션을 차단하고 분류기에서 6경로로 라우팅해 맞춤형 노드를 호출하는 설계를 보여준다. 검색 단계는 Jina AI v3 MRL 임베딩을 1024d에서 256d로 트렁크해 Pinecone에 저장하고 부모-자식 해상과 Cohere Rerank로 상위 청크를 선별하는 5단계 워크플로로 구성되며 신뢰도 게이트로 저신뢰 응답을 HITL 또는 완화 모드로 처리한다. 생성 이후 Hallucination Guard는 LLM을 판사로 호출해 근거 여부를 판단하고 비근거 응답에는 면책 문구를 붙여 사용자 판단에 맡기며 장애 격리를 위해 pybreaker 기반 회로 차단기(연속 실패 3회, 30초 재시도)를 적용해 폴백 경로로 안정적으로 전환한다. 전체 스택은 Pinecone·MongoDB·Supabase·Upstash·Langfuse·Gemini Flash Lite 등 무료 티어 조합으로 운영되어 월간 비용을 0으로 유지하면서 실무적 트레이드오프(임베딩 차원 축소 vs 품질, 차단 vs UX)를 명확히 제시하고 추가 실험 결과를 커뮤니티에 요청하고 있다.
커뮤니티 반응
게시물 작성자는 코드 스니펫과 운영 수치(예: graph.py 라인 수, 등록 노드 11개, Pinecone 벡터 14,662 등)를 함께 제시해 기술적 신뢰도를 확보했고 커뮤니티는 구현 세부와 트레이드오프에 대해 높은 관심을 보였다. 많은 댓글이 MRL 트렁크 차원, 재정렬의 효과, Hallucination Guard의 차단 여부 선택, 회로 차단 임계값 등 실무적 파라미터에 대해 경험을 공유하거나 질문을 제기했다. 전반적으로 공유된 구현은 실용적이라는 평가와 함께 특정 설정(예: 트렁크 비율, 신뢰도 임계값)에 대한 추가 실험 결과 요청이 동시에 제기되었다.
주요 논점
분류기와 6경로 라우팅을 통한 노드 분리는 복잡한 금융·법률 문서 처리에서 책임 분리를 명확히 하여 보안과 품질 관리를 용이하게 만든다.
MRL 임베딩을 1024d에서 256d로 트렁크하면 저장 비용을 크게 낮출 수 있지만 품질 저하 가능성이 있으므로 재정렬과 부모-자식 조회로 품질을 보강해야 한다.
검증 노드를 advisory 모드로 두어 면책 문구를 부착하는 방식은 차단으로 인한 UX 저하를 방지하면서 사용자에게 응답 신뢰도를 제공한다.
합의점 vs 논쟁점
합의점
- PII 마스킹과 프롬프트 인젝션 차단은 LLM 기반 시스템에서 전처리 단계로 반드시 적용되어야 한다.
- 검색 파이프라인에서 재정렬(reranking)은 다문서 질의의 응답 품질을 실질적으로 개선하는 핵심 단계로 인정되었다.
- 회로 차단기 같은 장애 격리 메커니즘은 외부 LLM/임베딩 서비스 의존성을 완화하는 데 필수적이다.
논쟁점
- Hallucination Guard를 차단 대신 면책문구 부착 방식으로 운영하는 결정은 UX와 안전성 사이의 트레이드오프를 낳아 일부에서는 차단 필요성을 주장했다.
- MRL 차원 트렁크(1024→256)의 품질/저장 절감 균형이 실무에서 일관되게 재현되는지에 대해 의견이 분열되었다.
실용적 조언
- 민감정보는 LLM 호출 이전 단계에서 정규식 기반 PII 마스크로 제거해 프롬프트 인젝션과 데이터 유출 위험을 동시에 줄일 것.
- 검색 품질 향상을 위해 임베딩 트렁크와 함께 부모-자식 청크 해상 및 신경망 기반 reranker를 결합해 사용하면 소규모 청크의 정밀도와 대규모 문맥의 밀도를 동시에 확보할 수 있다.
- 외부 LLM/임베딩 실패를 대비해 pybreaker 같은 회로 차단기를 적용하고 연속 실패 임계치를 설정해 폴백 경로를 즉시 활성화하도록 구현할 것.
섹션별 상세
graph.add_node("classifier", classifier_node) # 1
graph.add_node("reject", reject_node) # 2
graph.add_node("greet", greet_node) # 3
graph.add_node("cross_question", cross_question_node) # 4
graph.add_node("retriever", retriever_node) # 5
graph.add_node("web_search", web_search_node) # 6
graph.add_node("stock_tool", stock_tool_node) # 7
graph.add_node("generator", generator_node) # 8
graph.add_node("hallucination_guard", hallucination_guard_node) # 9
graph.add_node("post_process", post_process_node) # 10
graph.add_node("fallback", fallback_node) # 11LangGraph에 11개의 처리 노드를 등록하는 구문으로, 각 노드는 분류·차단·인사·질문상보·검색·도구호출·생성·검증·후처리·폴백 등의 책임을 가진다.

graph.add_conditional_edges("classifier", route_after_classify, {
"reject": "reject",
"greet": "greet",
"cross_question": "cross_question",
"web_search": "web_search",
"stock_tool": "stock_tool",
"retriever": "retriever"
})분류기 결과(intent)에 따라 6가지 경로로 라우팅하는 조건부 엣지 매핑으로, 입력 분기 로직을 정의한다.
tools = [{"function_declarations": [{
"name": "get_stock_price",
"description": "Get real-time stock price and financial data",
"parameters": {"type": "object", "properties": {"ticker": {"type": "string", "description": "Stock ticker symbol"}}}
}]}]
response = model.generate_content(prompt, tools=tools)Generator 노드에서 LLM 도구 호출을 선언하는 JSON 구조와 모델로의 요청 예시로, LLM이 도구 호출 시점과 인자를 자율 결정하게 설계되었다.
llm_circuit = pybreaker.CircuitBreaker(fail_max=3, reset_timeout=30, name="LLM_CB")
embed_circuit = pybreaker.CircuitBreaker(fail_max=3, reset_timeout=30, name="Embed_CB")LLM 및 임베딩 API 호출을 보호하기 위한 회로 차단기 설정 코드로, 연속 실패 임계치와 재시도 대기 시간을 지정한다.
용어 해설
- LangGraph 상태 그래프(LangGraph)
- — LangGraph는 노드와 조건부 엣지로 구성된 상태 기반 오케스트레이션 접근법으로, 입력을 노드별 처리 파이프라인으로 라우팅하고 각 노드의 출력을 다음 상태의 입력으로 연결하여 복잡한 멀티스텝 워크플로를 구현한다. 이 글에서는 11개의 등록된 노드와 6경로 분기 로직을 통해 질의 분류, PII 마스킹, 재검색, 재정렬, 생성, 검증, 후처리 등 단계별 처리를 조직화하는 데 LangGraph가 핵심 역할을 한다. LangGraph는 에이전트 유즈케이스에서 기능별 격리와 장애 격리를 제공하여 특정 노드 실패 시 회로 차단이나 폴백 루트를 통해 전체 시스템의 안정성을 유지한다.
- MRL 임베딩(MRL Embeddings)
- — MRL(Multi-Resolution Learning) 임베딩은 원문의 고해상도 표현을 다양한 차원으로 압축하거나 트렁크해서 저장 공간과 검색 비용을 낮추는 기법을 의미한다. 해당 구현에서는 Jina AI v3 MRL을 1024차원에서 256차원으로 트렁크하여 Pinecone 저장량을 약 75% 절감하면서 품질 저하를 최소화하는 트레이드오프를 적용했다. MRL 임베딩은 짧은 청크의 정확도와 긴 문서 컨텍스트의 밀도를 균형 있게 유지하기 위해 부모-자식(chunk parent-child) 조회와 결합되어 사용되었다.
- 부모-자식 청크 연계 해상(Parent-Child Resolution)
- — Parent-Child Resolution은 검색 시 작은 청크(child)를 우선으로 정확도를 확보한 후 해당 청크의 상위 문서(parent)를 다시 불러와 문맥을 보강하는 방식이다. 이 글에서는 작은 청크의 정밀도와 대규모 문서의 컨텍스트 밀도를 동시에 확보하기 위해 Supabase에 저장된 부모 문서를 조회하는 단계로 구현되었다. 이 방식은 멀티문서 질의에서 관련 조각의 정합성을 높이고 이후 재정렬 단계에서 더 긴 문단 단위로 증거를 제공하는 데 기여한다.
- 재정렬(Reranking)(Reranking)
- — Reranking은 최초 검색으로 얻은 후보 집합을 별도의 신경망 기반 모델로 재평가하여 최종 상위 문서들을 선정하는 과정이다. 본 사례에서는 Cohere Rerank v3.0을 통해 15개 후보를 받아 상위 10개 'Golden Chunks'를 선택해 생성기의 컨텍스트로 공급함으로써 다문서 응답 품질을 크게 개선했다. Reranking은 특히 유사도 기반 초기 검색으로는 놓치기 쉬운 문맥적 적합도를 보정하는 데 중요하다.
- 회로 차단기(Circuit Breaker)(Circuit Breaker)
- — Circuit Breaker는 외부 API 장애가 반복될 때 호출을 임시 중단하고 빠른 폴백 경로로 전환해 장애 전파를 방지하는 안정성 패턴이다. 구현에서는 pybreaker를 사용해 LLM과 임베딩 API에 대해 연속 실패 3회 시 회로를 열고 30초 후 재시도하는 정책을 적용하여 요청 지연과 중첩 실패를 회피했다. 이 패턴은 특히 외부 LLM 장애가 시스템 전체 응답성을 저하시킬 위험을 줄이는 데 핵심적이다.
언급된 도구
벡터 저장 및 유사도 검색
MRL 방식의 임베딩 생성
검색 결과 재정렬으로 상위 문서 선정
외부 API 호출에 대한 회로 차단기 구현
생성기(Generator) LLM
언급된 리소스
AI 요약 · 북마크 · 개인 피드 설정 — 무료
출처 · 인용 안내
인용 시 "요약 출처: AI Trends (aitrends.kr)"를 표기하고, 사실 확인은 원문 보기 기준으로 진행해 주세요. 자세한 기준은 운영 정책을 참고해 주세요.