βμ½λμμ νλ¦μΌλ‘, νλ¦μμ μΈν°λμ μΌλ‘.β
LangGraph κ·Έλνλ₯Ό μκ°ννκ³ μ€μκ° μ‘°μ κ°λ₯ν UIλ‘ μ°κ²°νκΈ°.
μ§κΈκΉμ§μ LangGraphλ μ½μ μ€μ¬μΌλ‘ μ€νλμμ£ .
νμ§λ§ μ€μ μμ©μμλ μ¬μ©μ μ
λ ₯, μν νμ, κ·Έλν μκ°ν, λλ²κΉ
λ‘κ·Έκ° νμν©λλ€.
μ΄λ² νΈμμλ λ€μμ λͺ¨λ λ€λ£Ήλλ€.
β
LangGraph + Gradio: κ·Έλν κΈ°λ° μ±ν
μΈν°νμ΄μ€
β
LangGraph + Streamlit: λ
Έλ μν μκ°ν λμ보λ
β
μ€μκ° μν μ
λ°μ΄νΈ (WebSocket / Callback)
π LangGraph + UI ν΅ν© ꡬ쑰:

κ° λ Έλμ μ€ν μνλ₯Ό UIμ νμνκ³ , μ¬μ©μμ μ λ ₯(ν μ€νΈΒ·λ²νΌ λ±)μ΄ κ·Έλν μ€νμ νΈλ¦¬κ±°νλ ꡬ쑰μ λλ€.
LangGraphλ Gradioμ μμ£Ό μ½κ² ν΅ν©λ©λλ€.
LLM νΈμΆ κ²°κ³Όλ₯Ό μ€νΈλ¦¬λ°νκ±°λ, λ
Έλ μ€ν κ²°κ³Όλ₯Ό μ€μκ° νμν μ μμ΅λλ€.
import gradio as gr
from langgraph.graph import StateGraph
from langchain_openai import ChatOpenAI
# μν μ μ
class ChatState:
messages: list[str]
# κ·Έλν μ μ
def chat_node(state: ChatState):
llm = ChatOpenAI(model="gpt-4o-mini")
user_msg = state.messages[-1]
reply = llm.invoke(user_msg)
state.messages.append(reply.content)
return state
graph = StateGraph(ChatState)
graph.add_node("chat", chat_node)
graph.set_entry_point("chat")
graph.set_finish_point("chat")
app = graph.compile()
# Gradio μΈν°νμ΄μ€
def chat_fn(user_input, history):
state = ChatState(messages=history + [user_input])
result = app.invoke(state)
return result.messages, result.messages
ui = gr.ChatInterface(
fn=chat_fn,
title="LangGraph Chatbot",
description="LangGraph λ
Έλ κΈ°λ° LLM λν νλ¦ μμ",
)
ui.launch()
β μ€ν ν:
StateGraphμ μ λ¬λκ³ ,LangGraphλ λ΄λΆ μνλ₯Ό μκ°ννλ κΈ°λ₯μ μ 곡ν©λλ€.
graph.visualize("chat_flow.png")
λλ Gradio UI λ΄λΆμμ μ§μ μνλ₯Ό νμν μλ μμ΅λλ€:
def debug_panel(state):
return f"νμ¬ λ©μμ§ μ: {len(state.messages)}\nμ΅κ·Ό μλ΅: {state.messages[-1]}"
Gradioμμ stateλ₯Ό μΆλ ₯ μμμΌλ‘ μ°κ²°νλ©΄, λνλΏ μλλΌ λ΄λΆ νλ¦μ ν¨κ» λͺ¨λν°λ§ν μ μμ΅λλ€.
Streamlitμ LangGraph μ€ν λ‘κ·Έλ₯Ό μ€μκ° μκ°ννκΈ°μ μ ν©ν©λλ€.
import streamlit as st
from langgraph.graph import StateGraph
from langchain_openai import ChatOpenAI
# μν
class QAState:
query: str
answer: str
# λ
Έλ
def answer_node(state: QAState):
llm = ChatOpenAI(model="gpt-4o-mini")
res = llm.invoke(f"Q: {state.query}\nA:")
state.answer = res.content
return state
graph = StateGraph(QAState)
graph.add_node("answer", answer_node)
graph.set_entry_point("answer")
graph.set_finish_point("answer")
app = graph.compile()
# Streamlit UI
st.title("LangGraph QA Dashboard")
query = st.text_input("μ§λ¬Έμ μ
λ ₯νμΈμ:")
if st.button("μ€ν"):
state = app.invoke({"query": query})
st.subheader("LLM μλ΅")
st.write(state["answer"])
st.image(graph.visualize("graph.png"))
β μ€ν ν:
graph.visualize()λ‘ κ·Έλν μ΄λ―Έμ§ νμLangGraph μ€ν μ€κ°μ κ° λ
Έλμ μνλ₯Ό μ€μκ°μΌλ‘ λΈλ‘λμΊμ€νΈνλ €λ©΄ CallbackManagerλ WebSocketμ μ¬μ©ν μ μμ΅λλ€.
from langgraph.callbacks.base import CallbackManager
def on_node_start(node_name, state):
print(f"[Node Start] {node_name}")
def on_node_end(node_name, state):
print(f"[Node End] {node_name}")
manager = CallbackManager(
on_node_start=on_node_start,
on_node_end=on_node_end
)
app = graph.compile(callbacks=manager)
μ΄ λ°μ΄ν°λ₯Ό WebSocketμΌλ‘ μ€νΈλ¦¬λ°νλ©΄ μ€μκ° κ·Έλν βλ Έλ μ€ν λ‘κ·Έβ UIλ₯Ό λ§λ€ μ μμ΅λλ€.
| λͺ©μ | ꡬν λ°©μ | λΉκ³ |
|---|---|---|
| λνν μ±λ΄ | gr.ChatInterface | μ§κ΄μ μΈν°λμ |
| λμ보λν | Streamlit | μνΒ·λ Έλ μκ°ν |
| μ€μκ° μΆμ | CallbackManager / WS | λλ²κΉ λ° μ΄μμ© |
| λ Έλλ³ λ‘κ·Έ | κ° λ
Έλ λ΄ print λλ state.log.append() | μν κΈ°λ° λ‘κΉ |
| Mermaid μκ°ν | graph.visualize() or μ§μ Mermaid μ½λ μμ± | λ¬Έμ μλν κ°λ₯ |
π 8νΈ: μ€μ μν€ν
μ² μ€κ³ & Best Practice
λ§μ§λ§ νΈμμλ μ§κΈκΉμ§ λ°°μ΄ λ΄μ©μ μ’
ν©νμ¬ λκ·λͺ¨ κ·Έλν μ€κ³, μ±λ₯ μ΅μ ν, μ€λ₯ μ²λ¦¬, λ°°ν¬ μ λ΅μ λͺ¨λ λ€λ£Ήλλ€.
| μ£Όμ | νμ΅ μ΄μ | μΆμ² νμ΅ λ°©ν₯ |
|---|---|---|
| Event-driven UI | μ€μκ° κ·Έλν μ€ν μν λ°μ | WebSocket, async callback |
| Graph Visualization Libraries | κ·Έλνλ₯Ό μΈν°λν°λΈνκ² μκ°ν | D3.js, Cytoscape.js, NetworkX |
| LangGraph Callback System | λ Έλ μ€ν μν λͺ¨λν°λ§ | CallbackManager, custom logger |
| LangServe Integration | UIμ κ·Έλν λ°±μλ λΆλ¦¬ | LangServe REST endpoint |
| Frontend-Graph Sync | μν κ°μ²΄λ₯Ό UIμ μλ°©ν₯ λκΈ°ν | React + FastAPI μ‘°ν© |
| User Feedback Loop (HITL UI) | μ¬μ©μ νΌλλ°±μ κ·Έλνμ μ§μ λ°μ | νκ°μ© λ²νΌ, μμ νΌλλ°± μ΄λ²€νΈ |
- LangGraphλ Gradio/Streamlitκ³Ό κ²°ν©νμ¬ μκ°μ μν¬νλ‘μ° μΈν°νμ΄μ€λ₯Ό λ§λ€ μ μλ€.
- Gradioλ μ€μκ° λνμ©, Streamlitμ λΆμΒ·λλ²κΉ μ©μΌλ‘ μ ν©νλ€.
- Callbackκ³Ό WebSocketμ ν΅ν΄ κ·Έλνμ μ€μκ° μν μΆμ λ κ°λ₯νλ€.
π‘ μ½λλ‘ μ€κ³ν κ·Έλνκ° μ΄μ λμμ βνλ¦βμΌλ‘ 보μ΄κΈ° μμνλ€.