본문 바로가기
개발/LLM

[AI][Agent] LangChain과 LangGraph 1.0 출시: 새로운 기능·개선 사항 상세 정리

by ▶ Carpe diem ◀ 2025. 10. 27.

요즘 에이전트 프레임워크를 도입하려고 보면 “기능은 많은데 뭐부터 써야 하지?”가 가장 큰 고민이죠. LangChain과 LangGraph 1.0은 바로 그 지점을 겨냥해 안정화된 API와 역할 분리를 내세웠고, 특히 LangChain의 에이전트는 LangGraph 런타임 위에서 돌아가도록 정리돼 처음은 쉽게, 필요해지면 깊이 있게 내려갈 수 있게 했습니다. 즉, 표준 에이전트 패턴은 LangChain으로 빠르게, 장기 실행·감사·중단/재개 같은 프로덕션 제어는 LangGraph로 맡기는 그림입니다.

 
 

LangChain 1.0: 실제로 도움이 되는 기능과 코드 예시

 

 

LangChain 1.0의 핵심은 표준 진입점 create_agent 미들웨어입니다. create_agent로 모델·도구·프롬프트만 지정하면 생산성 높은 에이전트 루프(모델→도구→응답)가 바로 서고, 미들웨어 훅(before/after model, tool call wrapping 등)으로 대화 요약, Human‑in‑the‑Loop(HITL), PII 감지/마스킹 같은 정책을 손쉽게 끼워 넣을 수 있습니다. 또한 구조화 출력(Structured output)은 메인 루프에 통합되어 ToolStrategy/ProviderStrategy로 더 견고해졌고, 메시지의 표준 콘텐츠 블록(.content_blocks)이 도입돼(OpenAI/Anthropic 등) 멀티모달·도구 호출·인용 데이터를 공급자 중립 형식으로 다룰 수 있습니다. (기존 레거시는 langchain‑classic으로 이동, Python 3.10+ 요구)

 

 

예시 1) 가장 기본적인 에이전트 + 요약/HITL 미들웨어

# Python 3.10+
from typing import TypedDict
from langchain.tools import tool
from langchain.agents import create_agent
from langchain.agents.middleware import SummarizationMiddleware, HumanInTheLoopMiddleware
from langchain_openai import ChatOpenAI

@tool
def get_weather(city: str) -> str:
    """Get weather information for a city."""
    return f"{city}: 22°C, Clear"

agent = create_agent(
    model=ChatOpenAI(model="gpt-4o-mini"),  # 또는 문자열 "openai:gpt-4o-mini"
    tools=[get_weather],
    system_prompt="Answer concisely and call tools when helpful.",
    middleware=[
        SummarizationMiddleware(
            model="openai:gpt-4o-mini",
            max_tokens_before_summary=1000
        ),
        HumanInTheLoopMiddleware(
            # get_weather 도구 호출 시 사람 승인 단계 삽입
            interrupt_on={"get_weather": True, "description": "Review weather call before executing"}
        ),
    ],
)

result = agent.invoke({"messages": [{"role": "user", "content": "서울 날씨 알려줘"}]})
print(result["messages"][-1].content)

 

이 패턴은 LangChain의 표준 에이전트 루프와 미들웨어를 활용해, 토큰 한계에 가까워지면 자동 요약을, 민감 도구 호출엔 사용자 승인을 끼워 넣는 구성입니다.

 

 

예시 2) 구조화 출력 — 비용/지연 절약(메인 루프 통합)

from pydantic import BaseModel
from langchain.agents import create_agent
from langchain.agents.structured_output import ToolStrategy, ProviderStrategy

class WeatherReport(BaseModel):
    temperature: float
    condition: str

# (A) 어떤 모델이든 도구 호출로 스키마를 강제: ToolStrategy
agent = create_agent(
    model="openai:gpt-4o-mini",
    tools=[],  # 필요 시 도구 추가
    response_format=ToolStrategy(WeatherReport),
)
out = agent.invoke({"messages": [{"role": "user","content": "서울의 기온과 상태를 숫자/문자로만 알려줘"}]})
print(out["structured_response"])  # WeatherReport(temperature=..., condition="...")

# (B) 공급자 네이티브 구조화 출력: ProviderStrategy (예: OpenAI)
agent_native = create_agent(
    model="openai:gpt-4o",
    response_format=ProviderStrategy(WeatherReport),
)

 

v1에서는 구조화 출력을 별도 노드가 아니라 메인 루프에서 처리해 비용/지연을 줄였고, 사전에 도구가 바인딩된 모델(pre‑bound)은 구조화 출력과 함께 쓸 수 없으니 에이전트 측에서 도구를 넘기세요.

 

 

예시 3) 표준 콘텐츠 블록 접근(멀티모달 포함)

# 마지막 AI 메시지의 표준화된 콘텐츠 블록 순회
ai_msg = result["messages"][-1]
for block in getattr(ai_msg, "content_blocks", []):
    print(block["type"], block)  # text / image / tool_call 등

 

.content_blocks는 공급자별 포맷 차이를 흡수해 추론 추적·인용·도구 호출과 같은 복합 내용을 일관되게 다루게 해줍니다. (LangChain Blog)

 

 

 

LangGraph 1.0: 실제로 도움이 되는 기능과 코드 예시

LangGraph 를 설명하는 그림

 

 

LangGraph 1.0은 내구성 있는 실행(Durable execution)지속성(Persistence)을 기본기처럼 제공합니다. 그래프를 체크포인터(예: MemorySaver/SQLite/Postgres)와 함께 컴파일하면 각 단계의 상태가 체크포인트로 저장되고, 스레드(Thread) 단위로 중단/재개, 타임 트래블 디버깅, 단기/장기 메모리가 가능해집니다. 특히 interrupt()로 노드 중간에 실행을 멈추고 사람 입력을 받아 Command(resume=...)로 이어갈 수 있어, 결재·승인·수정 같은 Human‑in‑the‑Loop 패턴이 간결해집니다.

👉 이전 글: [AI][Agent] LangGraph: 차세대 AI 에이전트 프레임워크의 부상

 

예시 1) 체크포인터 + 스레드 + 중단/재개(HITL)

# Python 3.10+
from typing import TypedDict
from langgraph.graph import START, END, StateGraph
from langgraph.checkpoint.memory import MemorySaver  # 데모용 체크포인터
from langgraph.types import interrupt, Command

class State(TypedDict):
    draft: str
    approved: bool

def write_draft(state: State) -> dict:
    proposal = f"[DRAFT] {state.get('draft','') or '안녕하세요!'}"
    # 사람에게 승인/수정 요청: UI에 proposal을 보여주고 입력을 기다리게 된다
    decision = interrupt({"action": "approve_draft", "proposal": proposal})
    # 사용자가 {"approve": True} 또는 {"approve": False, "edit": "..."}로 응답한다고 가정
    if decision.get("edit"):
        proposal = decision["edit"]
    return {"draft": proposal, "approved": bool(decision.get("approve", False))}

def send_or_cancel(state: State) -> dict:
    return {"draft": f"SENT: {state['draft']}" if state["approved"] else "CANCELLED"}

builder = StateGraph(State)
builder.add_node("write_draft", write_draft)
builder.add_node("send_or_cancel", send_or_cancel)
builder.add_edge(START, "write_draft")
builder.add_edge("write_draft", "send_or_cancel")

graph = builder.compile(checkpointer=MemorySaver())

# 1) 최초 호출: interrupt 발생 → "__interrupt__" 정보가 반환됨
cfg = {"configurable": {"thread_id": "user-123"}}
out = graph.invoke({"draft": "안부 메일 초안"}, cfg)
if "__interrupt__" in out:
    payload = out["__interrupt__"]["value"]  # {"action": "approve_draft", "proposal": "..."}
    # 2) 사람 응답을 받아 재개
    human_answer = {"approve": True}  # or {"approve": False, "edit": "[DRAFT] 수정본 ..."}
    out = graph.invoke(Command(resume=human_answer), cfg)

print(out["draft"])  # SENT: ...  또는  CANCELLED
  • compile(checkpointer=...)로 내구성 활성화, {"configurable": {"thread_id": ...}}로 스레드를 지정합니다.
  • interrupt()가 불리면 실행이 저장·중단되고, Command(resume=...)로 같은 스레드에서 정확히 그 지점부터 이어집니다. 

 

예시 2) 파일 기반 지속성(데모용 SQLite 체크포인터)

# pip install langgraph-checkpoint-sqlite
from sqlite3 import connect
from langgraph.checkpoint.sqlite import SqliteSaver  # 동기용(데모/소규모), 실서비스는 별도 백엔드 권장

conn = connect("state.db")
sqlite_cp = SqliteSaver(conn=conn)

# 위의 builder.compile(checkpointer=sqlite_cp)로 교체하면,
# 프로세스 재시작 후에도 같은 thread_id로 상태를 이어갑니다.

 

SQLite 체크포인터 패키지가 별도로 제공되며, 프로덕션에서는 동시성/확장성을 고려한 백엔드를 선택하세요(예: Postgres 버전, LangGraph 플랫폼).

 

 

 

 

주의사항과 바로 적용 포인트(요약)

처음엔 표준 패턴으로 빨리 결과 내야 하니 LangChain 1.0의 create_agent + 미들웨어(요약/HITL/PII)를 기본으로 삼고, 구조화 출력은 ToolStrategy/ProviderStrategy로 메인 루프에서 처리해 비용·지연을 줄이세요. 워크플로가 길어지고 승인·감사·재시작/재실행이 중요해지면 LangGraph 1.0으로 내려가 체크포인터·스레드·interrupt/Command 조합으로 내구성을 확보하면 됩니다. 마이그레이션 관점에서는 v1에서 레거시 일부가 langchain‑classic으로 분리되고 Python 3.9 지원이 중단되었으니 환경을 3.10+로 정리해 두세요. 지금 바로 LangChain과 LangGraph 1.0을 기준으로 설계하면, 알파/베타 시절의 깨지는 변경보다 훨씬 예측 가능한 개발 경험을 얻을 수 있습니다.

 

 

 


 

참고 출처

  • LangChain Agents: create_agent, 미들웨어, 구조화 출력 전략(메인 루프 통합) 및 사용 예시. (LangChain Docs)
  • LangChain v1 마이그레이션(레거시 분리, Python 3.10+, pre‑bound 모델 제한, 구조화 출력 변경점). (LangChain Docs)
  • 표준 콘텐츠 블록(.content_blocks) 소개(공급자 중립 멀티모달/도구 호출 표현). (LangChain Blog)
  • LangChain Guardrails/PII 감지 미들웨어(개요). (LangChain Docs)
  • LangGraph 내구성/지속성(체크포인터·스레드), 메모리 개념, Interrupt/Command 기반 HITL. (LangChain Docs)

 

👉 다음 글: [AI][Agent] CrewAI vs LangGraph: 협업인가, 상태인가? 당신의 멀티에이전트 프로젝트에 맞는 프레임워크 선택 가이드

 

[AI][Agent] CrewAI vs LangGraph: 협업인가, 상태인가? 당신의 멀티에이전트 프로젝트에 맞는 프레임워크

AI 에이전트 기술은 이제 단순한 업무 자동화를 넘어, 복잡한 비즈니스 문제를 해결하는 핵심 동력으로 자리 잡고 있습니다. 이 기술적 진화의 중심에서 개발자들은 중요한 아키텍처 선택의 기

wide-shallow.tistory.com