RAG2026-5일17차시 · LangGraph 입문12 / 20← 이전목차다음 →MetaContents

17차시. LangGraph 입문

Graph를 그림으로 보기

출처: 원본 PDF 17차시_LangGraph입문.pdf 11~12쪽 · 쪽 그림 11쪽 12쪽

우리가 만든 Graph가 정말로 어떻게 생겼는지 확인할 수 있습니다.

Python
import matplotlib.pyplot as plt
from PIL import Image
import io

# Graph를 이미지로 변환
image_data = graph.get_graph().draw_mermaid_png()

# 이미지 표시
image = Image.open(io.BytesIO(image_data))
plt.imshow(image)
plt.show()

생성되는 이미지 — 조건부 분기가 있는 Graph의 모습
start → search
↕ (조건)
↙ ↘
좋음 나쁨
↓ ↓
answer search (다시)
↓
end
→ 이렇게 시각화됩니다! 훨씬 더 이해하기 쉽습니다!

실습 코드 · 17/visual_graph.py

실습 코드: 실습/src/17/visual_graph.py · 위의 원본 PDF 17차시 11~12쪽 「Graph를 그림으로 보기」과 이어집니다.

Python
# ============================================================
# 17차시 | LangGraph 입문
# 교안: 17차시_LangGraph입문.pptx
# 역할: 조건부 그래프를 실행하지 않고, 연결 그림만 화면에 띄운다.
# 입력: 그래프 정의(State 키 query, results, answer). invoke 는 하지 않는다.
# 출력: matplotlib 창의 그래프 그림. 이 파일은 png 파일을 저장하지 않는다.
#
#   State  = 공유 노트. 이 파일의 노드는 그림용으로만 등록된다.
#   Node   = search, answer 함수.
#   Edge   = START → search, answer → END.
#   조건부 엣지 = search 다음 good 이면 answer, bad 이면 search.
#   compile = 그림을 그리려면 먼저 앱으로 확정해야 한다.
#   get_graph().draw_mermaid_png() = 확정된 연결을 그림 바이트로 만든다.
#
# 흐름 (그림에 나오는 연결)
#   START
#     |
#     v
#   search ---- bad ----+
#     |                  |
#     | good             v
#     v               search
#   answer
#     |
#     v
#    END
# ============================================================

from typing import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.errors import GraphRecursionError

import io
import matplotlib.pyplot as plt
from PIL import Image

class SimpleRAGState(TypedDict):
    query: str      # 사용자의 질문
    results: list   # 검색 결과 목록
    answer: str     # 최종 답변

# 노드 search
#   읽기: query
#   쓰기: results
def search_node(state: SimpleRAGState):
    query = state["query"]
    # 현재 State에서 질문을 읽습니다.
    print("[검색 노드] 질문:", state["query"])

    # 실제 검색 대신 고정된 문서 목록을 준비합니다.
    if "가격" in query:
        results = [
            "문서1: 제품 가격은 10,000원입니다.",
            "문서2: 배송비는 무료입니다.",
            "문서3: 현재 할인 행사가 진행 중입니다."
        ]
    else:
        results = []

    print("[검색] 결과:", results)

    # LangGraph가 results 항목을 갱신하도록 반환합니다.
    return {"results": results}

# 노드 answer
#   읽기: results
#   쓰기: answer
def answer_node(state: SimpleRAGState):
    # 앞의 검색 노드가 반환한 결과를 읽습니다.
    print("[답변 노드] 검색 결과:", state["results"])

    # 실제 LLM 대신 고정된 답변을 준비합니다.
    answer = "검색 결과를 바탕으로 만든 답변입니다."

    # LangGraph가 answer 항목을 갱신하도록 반환합니다.
    return {"answer": answer}

# 조건부 엣지 함수. 노드가 아니다.
#   읽기: results
#   쓰기: 없음
#   "good" → answer, "bad" → search
def check_search_quality(state: SimpleRAGState):
    # 검색 결과가 하나 이상이면 답변 경로를 선택합니다.
    if len(state["results"]) > 0:
        print("[판단] 검색 성공 → 답변")
        return "good"

    # 검색 결과가 없으면 재검색 경로를 선택합니다.
    print("[판단] 검색 실패 → 다시 검색")
    return "bad"

graph = StateGraph(SimpleRAGState)

graph.add_node("search", search_node)
graph.add_node("answer", answer_node)

graph.add_edge(START, "search")

graph.add_conditional_edges(
    "search",
    check_search_quality,
    {
        "good": "answer",  # 성공하면 답변 노드로 이동
        "bad": "search"    # 실패하면 검색 노드로 돌아감
    }
)

graph.add_edge("answer", END)

# compile 한 뒤에야 연결 그림을 뽑을 수 있다. 이 파일은 invoke 하지 않는다.
app = graph.compile()

print("Graph 이미지를 생성합니다...")

image_data = app.get_graph().draw_mermaid_png()

# PNG 바이트 데이터를 메모리상의 파일처럼 다룹니다.
image_file = io.BytesIO(image_data)

# 메모리상의 PNG 데이터를 PIL 이미지 객체로 엽니다.
image = Image.open(image_file)

# 8. 그래프 이미지를 화면에 표시합니다.
plt.figure(figsize=(8, 6))  # 그림의 가로·세로 크기를 지정합니다.
plt.imshow(image)          # PIL 이미지를 표시합니다.
plt.axis("off")            # 좌표축과 눈금을 숨깁니다.
plt.title("LangGraph - Conditional RAG Graph")
plt.show()                 # 그림 창을 화면에 띄웁니다.

실행 결과 샘플 (교안 기록. API 키가 필요한 코드는 키 없이 맞춘 예시이고, 모델의 답은 실행할 때마다 달라집니다)

출력
===== 실행 결과 샘플 =====
실행: cd 실습/src/17
      python visual_graph.py
예시 출력 (그림 창을 띄우므로 실행하지 않음)
Graph 이미지를 생성합니다...
(이어서 matplotlib 창에 조건부 그래프 그림이 뜬다. 파일로 저장하지는 않는다.)
경로: search → answer → END

코드 해설

조건부 그래프를 실행하지 않고, 연결 그림만 화면에 띄운다. 입력은 그래프 정의(State 키 query, results, answer). invoke 는 하지 않는다.이고, 출력은 matplotlib 창의 그래프 그림. 이 파일은 png 파일을 저장하지 않는다.

주석에 적힌 흐름입니다.

출력
흐름 (그림에 나오는 연결)
START
|
v
search ---- bad ----+
|                  |
| good             v
v               search
answer
|
v
END

코드 앞에서 고정해 두는 말입니다.

  • 17차시 | LangGraph 입문
  • 교안: 17차시_LangGraph입문.pptx
  • State = 공유 노트. 이 파일의 노드는 그림용으로만 등록된다.
  • Node = search, answer 함수.
  • Edge = START → search, answer → END.
  • 조건부 엣지 = search 다음 good 이면 answer, bad 이면 search.
  • compile = 그림을 그리려면 먼저 앱으로 확정해야 한다.
  • get_graph().draw_mermaid_png() = 확정된 연결을 그림 바이트로 만든다.

함수와 클래스로 나누어 읽습니다.

  • SimpleRAGState: 이름 그대로 한 가지 일만 합니다. 본문 주석을 같이 읽습니다.
  • search_node: 노드 search 읽기: query 쓰기: results
  • answer_node: 노드 answer 읽기: results 쓰기: answer
  • check_search_quality: 조건부 엣지 함수. 노드가 아니다. 읽기: results 쓰기: 없음 "good" → answer, "bad" → search

파일 맨 아래 실행 결과 샘플 주석은 실행되지 않습니다. 화면 출력은 다음 절에 다시 적어 두었습니다.

← 이전 절17차시 · LangGraph 설치하기다음 절 →17차시 · 정리: 1부와의 차이점