도구 호출, 사람 승인, 실행 제한을 적용한 LangGraph 고객 지원 에이전트 구축
고객 지원 분류를 위한 실용적인 LangGraph 패턴을 살펴봅니다. 요청을 라우팅하고 조회 도구를 호출하며, 환불을 사람의 승인 대기 상태로 일시 중지하고 그래프 실행 범위를 제한하는 방법을 다룹니다.
목차
설계 결정: 에이전트가 환불을 찾을 수는 있지만 최종 처리할 수는 없게 하기
고객 지원 에이전트는 구매 세부 정보와 일치하는 기록을 조회할 수 있어야 하지만, 스스로 환불을 처리할 수 있어서는 안 됩니다. LangGraph에서는 이 구분을 워크플로에 표현할 수 있습니다. 요청을 라우팅하고, 필요한 경우 읽기 전용 조회 도구를 호출한 다음, 환불 작업 전에 일시 중지하여 사람이 승인하거나 거부하도록 하는 방식입니다.
이 튜토리얼은 고객 지원 분류를 중심으로 이러한 패턴을 구축합니다. 오케스트레이션에는 LangGraph를 사용하고, 조회에는 도구 호출을 지원하는 채팅 모델을 사용하며, 중요한 노드 전에 사람의 확인 단계를 두고, 그래프 실행 범위를 제한하기 위해 재귀 제한을 적용합니다. 아래 코드는 적용을 위한 패턴이며, 테스트된 OneMux 통합이 아닙니다.
이 글에 제공된 LangSmith 튜토리얼은 조회 서브그래프와 환불 서브그래프를 분리한 디지털 음악 스토어 지원 봇을 구축합니다. 고객 및 구매 세부 정보 추출, 누락된 정보 요청, 최종 응답·도구 경로·개별 단계 평가를 설명합니다. 환불 예제는 데이터베이스 삭제를 사용하며 인증 및 기타 프로덕션 보안 조치를 명시적으로 생략합니다. 해당 데모의 파괴적 동작을 실제 고객 지원 시스템에 복사하지 마세요. LangSmith 복합 에이전트 평가 튜토리얼 읽기.
사전 요구 사항과 경계
LangGraph와 선택한 모델 제공업체에 적합한 LangChain 통합을 설치합니다. 원본 튜토리얼은 langgraph와 langchain[openai]를 사용하지만, 아래 예제에서는 의도적으로 모델 초기화를 제공업체별 구현으로 남겨 둡니다. 또한 읽기 전용 구매 조회와 애플리케이션이 제어하는 환불 작업을 제공하는 데이터베이스 또는 서비스가 필요합니다.
모델을 연결하기 전에 각 도구가 수행할 수 있는 작업을 정의하세요.
- 조회: 인증된 고객이 확인할 권한이 있는 기록만 반환합니다.
- 환불 준비: 정확한 거래와 금액을 식별하며, 기록은 변경하지 않습니다.
- 환불 실행: 인증 및 감사 로깅을 적용한 애플리케이션 코드에서 승인된 작업을 수행합니다.
고객 인증, 권한 부여, 멱등성, 환불 정책은 모델의 판단에 맡기지 마세요. 모델이 생성한 고객 이름이나 청구서 ID는 신원 증명이 아닙니다.
사람의 확인 단계를 포함한 그래프 구축
이 예제는 도구 호출을 지원하는 모델, 조회 도구, 별도의 환불 노드를 사용합니다. 표시된 애플리케이션 함수를 자체적으로 권한이 부여된 서비스 호출로 대체하세요. 모델과 도구 스키마는 구성한 엔드포인트에서 지원되어야 하며, 호환성은 문서화된 엔드포인트 및 매개변수 지원 여부에 따라 달라집니다. 이 스니펫은 특정 모델이나 OneMux 구성이 테스트되었다는 근거를 제공하지 않습니다.
from typing import Annotated, Literal
from langchain.tools import tool
from langchain_core.messages import AnyMessage
from langgraph.graph import END, START, StateGraph
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode, tools_condition
from langgraph.checkpoint.memory import MemorySaver
from langgraph.types import interrupt
from typing_extensions import TypedDict
# Replace with your provider's documented LangChain model setup.
# Confirm that the chosen endpoint supports tool calling and the parameters used.
model = make_your_chat_model().bind_tools([]) # bind the tools below in your application
class State(TypedDict):
messages: Annotated[list[AnyMessage], add_messages]
refund_request: dict | None
approval: str | None
@tool
def find_purchases(customer_reference: str) -> list[dict]:
"""Find purchases for an already authenticated customer."""
return authorized_purchase_lookup(customer_reference)
tools = [find_purchases]
model = make_your_chat_model().bind_tools(tools)
def assistant(state: State):
return {"messages": [model.invoke(state["messages"])]}
def prepare_refund(state: State):
# Build this from validated application data, not model-invented values.
request = build_validated_refund_request(state["messages"])
decision = interrupt({
"type": "refund_approval",
"request": request,
"instruction": "Approve or reject this exact refund request.",
})
if decision != "approve":
return {"approval": "rejected", "refund_request": request}
return {"approval": "approved", "refund_request": request}
def execute_refund(state: State):
if state.get("approval") != "approved":
return {"messages": [{"role": "assistant", "content": "The refund was not approved."}]}
result = issue_refund_safely(state["refund_request"])
return {"messages": [{"role": "assistant", "content": format_refund_result(result)}]}
builder = StateGraph(State)
builder.add_node("assistant", assistant)
builder.add_node("tools", ToolNode(tools))
builder.add_node("prepare_refund", prepare_refund)
builder.add_node("execute_refund", execute_refund)
builder.add_edge(START, "assistant")
builder.add_conditional_edges("assistant", tools_condition)
builder.add_edge("tools", "assistant")
builder.add_edge("prepare_refund", "execute_refund")
builder.add_edge("execute_refund", END)
graph = builder.compile(checkpointer=MemorySaver())
이는 완전한 라우팅 그래프가 아닌 구조 예제입니다. 애플리케이션은 검증된 환불 의도를 prepare_refund로 라우팅하고, 일반적인 질문은 어시스턴트/조회 경로로 라우팅해야 합니다. interrupt() 호출은 그래프를 일시 중지하고 승인 페이로드를 호출자에게 반환합니다. 사람의 검토 인터페이스에는 결정을 보내기 전에 고객, 거래, 금액, 정책 컨텍스트가 표시되어야 합니다. LangGraph의 Command(resume=...) 메커니즘과 동일한 스레드 식별자를 사용해 같은 스레드를 재개합니다. 체크포인트는 적절히 영속화하세요. 인메모리 체크포인트는 개발용이며, 내구성이 필요한 프로덕션 워크플로용이 아닙니다.
중요한 제어 흐름 세부 사항은 다음과 같습니다. 인터럽트는 일시 중지일 뿐 권한 시스템이 아닙니다. 환불 실행 노드에서 승인 값을 다시 검증하고, 환불 서비스 자체에서도 권한, 거래 자격, 중복 요청을 확인해야 합니다.
실행 범위를 제한하고 오류를 명확히 드러내기
그래프를 호출할 때 재귀 제한을 전달합니다. 재귀 제한은 그래프 슈퍼스텝을 제한하지만 모델 토큰, 도구 실행 시간, 데이터베이스 쿼리 비용, 사용자 요청 횟수를 제한하지는 않습니다. 모델 호출과 도구에는 별도의 타임아웃 및 리소스 제한을 설정하세요.
from langgraph.errors import GraphRecursionError
config = {
"configurable": {"thread_id": "support-case-123"},
"recursion_limit": 12,
}
try:
result = graph.invoke(
{"messages": [{"role": "user", "content": "I need help with a purchase."}]},
config=config,
)
except GraphRecursionError:
# Return a safe handoff or ask for clarification; log the trace for review.
result = {"status": "needs_human_review"}
예상되는 워크플로를 기준으로 제한을 정한 다음, 정상적으로 완료되는 입력과 루프가 발생하기 쉬운 입력을 모두 테스트합니다. 소진된 그래프를 조용히 재시도하지 마세요. 도구가 멱등적이지 않다면 재시도로 인해 도구 호출이 반복될 수 있습니다. 읽기 전용 조회 도구는 부작용이 있는 작업보다 재시도에 안전합니다.
답변뿐 아니라 경로를 평가하기
제공된 LangSmith 튜토리얼은 세 가지 유용한 평가 대상을 제시합니다. 최종 응답은 고객에게 적절한 답변을 했는지, 경로는 에이전트가 예상된 도구 호출 경로를 따랐는지, 단일 단계는 특정 결정에 적합한 도구를 선택했는지를 평가합니다. 환불 분류를 위해 신원 정보 누락, 일치하는 구매가 여러 개인 경우, 조회 결과가 없는 경우, 승인 거부, 환불 승인 사례를 만드세요.
에이전트가 필요한 정보를 지어내지 않고 요청하는지, 조회가 환불을 실행하지 않는지, 승인 없이는 실행할 수 없는지 확인합니다. 테스트가 실제 고객 기록을 변경하지 않도록 평가에는 모의 서비스 또는 테스트 서비스를 사용하세요. 원본 튜토리얼은 데이터베이스 작업에 모의 모드를 사용하지만, 자체 데모 설정을 설명하는 것이며 프로덕션 안전성을 보장하지는 않습니다.
모델 액세스에 OneMux 사용하기
OneMux는 하나의 OpenAI 호환 API를 통해 주요 AI 모델에 액세스할 수 있도록 제공합니다. 모델 액세스에 단일 API 표면을 사용하려면 OneMux 빠른 시작, API 문서, 사용 가능한 모델을 확인하세요. 이 워크플로의 호환성은 선택한 모델 엔드포인트가 문서화된 도구 호출 지원 및 허용 매개변수를 제공하는지에 따라 달라집니다. 배포 전에 해당 세부 정보를 확인하세요. 이 글은 LangGraph 예제가 OneMux에서 테스트되었다고 주장하지 않습니다.
제한 사항 및 문제 해결
- 모델이 도구를 호출하지 않음: 선택한 엔드포인트가 도구 호출을 지원하는지, 도구 스키마가 해당 엔드포인트가 문서화한 형식으로 전달되는지 확인합니다.
- 그래프가 반복됨: 어시스턴트와 도구 사이의 전환을 검사하고, 그래프 단계 수를 제한하며, 완료된 도구 결과가 다음 결정에 변화를 주는지 확인합니다.
- 승인 후 잘못된 사례가 재개됨: 지원 사례에 연결된 안정적인 스레드 식별자를 사용하고, 재개하기 전에 체크포인트를 검증합니다.
- 환불이 두 번 실행됨: 서비스 경계에 멱등성을 추가하고 승인된 요청과 결과를 기록합니다.
- 에이전트가 다른 고객의 기록을 노출함: 조회 서비스의 권한 부여를 수정합니다. 프롬프트 지침은 접근 제어가 아닙니다.
결론
LangGraph를 사용하면 단일 모델 응답이 판단과 실행을 모두 맡도록 신뢰하는 대신, 고객 지원 분류를 명시적인 워크플로 단계로 표현할 수 있습니다. 조회는 읽기 전용으로 유지하고, 환불 전에 일시 중지하며, 실행 시 승인을 검증하고, 그래프 단계를 제한하세요. 그런 다음 답변과 에이전트가 거친 경로를 평가합니다. 이러한 제어 기능은 워크플로를 더 쉽게 검사할 수 있게 하지만, 프로덕션 보안과 정책 집행은 여전히 애플리케이션의 책임입니다.
출처
- LangSmith: 복합 에이전트 평가 — 음악 스토어 지원 예제, 조회/환불 구조, 모의 모드, 세 가지 평가 대상의 출처입니다.
FAQ
LangGraph 에이전트가 환불을 처리하기 전에 사람의 승인을 요구하려면 어떻게 해야 하나요?
환불 실행 노드 전에 LangGraph 인터럽트로 그래프를 일시 중지하고, 검증된 요청을 검토자에게 제시한 다음, 명시적인 결정이 내려진 경우에만 같은 체크포인트를 재개합니다. 또한 실행 노드 내부에서 승인을 다시 확인하고 환불 서비스에서 정책을 집행해야 합니다.
LangGraph 재귀 제한이 도구 실행 시간이나 모델 토큰을 제한하나요?
아니요. 재귀 제한은 그래프 슈퍼스텝을 제한할 뿐 모델 토큰 사용량, 도구 실행 시간, 데이터베이스 비용, 들어오는 요청량은 제한하지 않습니다. 별도의 타임아웃과 리소스 제한을 추가하세요.
고객이 환불 권한이 있는지 모델이 결정하도록 할 수 있나요?
아니요. 모델 출력을 신뢰할 수 없는 입력으로 취급하세요. 애플리케이션 및 서비스 코드에서 고객을 인증하고 거래 접근 권한과 환불 자격을 검증해야 합니다.
고객 지원 에이전트에서 무엇을 평가해야 하나요?
최종 응답, 도구 호출 순서, 개별 도구 선택 단계를 평가하세요. 정보 누락, 모호한 구매, 승인 거부, 환불 승인 사례를 포함하고, 부작용이 발생하는 작업에는 테스트 서비스를 사용합니다.
관련 글
Guides
스키마 검증 추출을 위한 실행 제한 LangGraph 에이전트 만들기
필요할 때 도구를 호출하고, 정해진 실행 예산 안에서 멈추며, Pydantic 스키마로 검증한 구조화 데이터를 반환하는 LangGraph 워크플로를 만들어 봅니다.
Guides
LangGraph Agentic RAG: 도구 호출, 출처 명시, 실행 횟수 제한
검색이 필요한 시점을 판단하고, 컨텍스트의 관련성을 평가하며, 검색 결과가 부실할 때 재시도하고, 무한 실행 없이 출처를 명시한 답변을 반환하는 LangGraph 문서 질의응답 에이전트를 구축합니다.
Guides
사람의 승인과 테스트 검증을 포함한 n8n 코드 변경 워크플로 구축
저장소 변경안을 제안하고, 사람이 쓰기 작업을 승인한 뒤, 결과 커밋을 테스트로 검증하는 n8n 워크플로를 설계합니다.
Guides
사람의 승인을 거치는 지원 티켓 분류를 위한 OpenAI 호환 Provider와 Cline 연동
OpenAI 호환 Provider와 OneMux를 사용하도록 Cline을 구성해 고객 지원 티켓을 분류하되, 고객에게 전달되는 모든 작업은 사람의 승인 뒤에 실행되도록 설정하는 방법을 알아봅니다.