GuidesOneMux

Создание агента поддержки клиентов на LangGraph: вызов инструментов, одобрение человеком и ограничения выполнения

Практический шаблон LangGraph для маршрутизации обращений в поддержку: классификация запросов, вызов инструментов поиска, приостановка возвратов для одобрения человеком и ограничение выполнения графа.

В этой статье

Архитектурное решение: пусть агент ищет данные, но не завершает возврат самостоятельно

Агент поддержки должен иметь возможность собирать сведения о покупке и находить соответствующие записи, но не должен самостоятельно оформлять возврат. В LangGraph это различие можно выразить в самом рабочем процессе: маршрутизировать запрос, при необходимости вызывать инструменты поиска только для чтения, а затем приостанавливать выполнение перед операцией возврата, чтобы человек мог одобрить или отклонить её.

В этом руководстве описан такой подход к маршрутизации обращений в поддержку. Для оркестрации используется LangGraph, для поиска — чат-модель с поддержкой вызова инструментов, перед узлом, выполняющим действие с последствиями, — контрольная точка с участием человека, а для ограничения выполнения графа — лимит рекурсии. Код представляет собой шаблон для адаптации, а не протестированную интеграцию OneMux.

В руководстве LangSmith, использованном для этой статьи, создаётся бот поддержки цифрового музыкального магазина с отдельными подграфами поиска и возврата. В нём описаны извлечение данных клиента и покупки, запрос недостающей информации, а также оценка итоговых ответов, траекторий вызовов инструментов и отдельных шагов. В примере возврата используются удаление данных из базы и явный отказ от аутентификации и других мер безопасности production-уровня. Не переносите деструктивное поведение этой демонстрации в работающую систему поддержки. Ознакомьтесь с руководством 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, а обычные вопросы — в путь assistant/lookup. Вызов interrupt() приостанавливает граф и возвращает вызывающей стороне данные для одобрения. Интерфейс проверки человеком должен показывать клиента, транзакцию, сумму и контекст политики перед отправкой решения. Возобновляйте тот же поток с помощью механизма LangGraph Command(resume=...) и того же идентификатора потока. Настройте соответствующее сохранение контрольных точек; хранение в памяти подходит для разработки, но не для устойчивых production-процессов.

Важная деталь управления потоком: interrupt — это пауза, а не система разрешений. Повторно проверяйте значение одобрения в узле выполнения возврата и убедитесь, что сам сервис возвратов проверяет права, допустимость транзакции и повторные запросы.

Ограничение выполнения и прозрачная обработка сбоев

Передавайте лимит рекурсии при вызове графа. Он ограничивает супершага графа, но не ограничивает количество токенов модели, время работы инструмента, стоимость запросов к базе данных или число пользовательских запросов. Для вызовов модели и инструментов устанавливайте отдельные тайм-ауты и ограничения ресурсов.

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 выделены три полезных объекта оценки: итоговый ответ (был ли ответ клиенту уместным?), траектория (прошёл ли агент ожидаемый путь вызовов инструментов?) и отдельный шаг (выбрал ли он правильный инструмент для конкретного решения?). Для маршрутизации возвратов создайте сценарии с недостающими данными о личности, несколькими совпадающими покупками, поиском без результатов, отклонённым одобрением и одобренным возвратом.

Проверьте, что агент запрашивает необходимую информацию, а не выдумывает её; что поиск не запускает возврат; и что выполнение невозможно без одобрения. Используйте имитационные или тестовые сервисы, чтобы проверки не изменяли реальные записи клиентов. В исходном руководстве для операций с базой данных используется тестовый режим, но описывается собственная демонстрационная конфигурация, а не гарантия безопасности production-системы.

Использование OneMux для доступа к моделям

OneMux предоставляет доступ к ведущим моделям ИИ через единый API, совместимый с OpenAI. Если вам нужен единый интерфейс API для доступа к моделям, ознакомьтесь с кратким руководством OneMux, документацией API и доступными моделями. Совместимость этого сценария зависит от документированной поддержки вызова инструментов и принимаемых параметров выбранной конечной точкой модели. Подтвердите эти сведения до развёртывания; в статье не утверждается, что пример LangGraph тестировался с OneMux.

Ограничения и устранение неполадок

  • Модель не вызывает инструмент: проверьте, поддерживает ли выбранная конечная точка вызов инструментов и передаётся ли схема инструмента в задокументированном формате.
  • Граф зацикливается: изучите переходы между assistant и tools, ограничьте число шагов графа и убедитесь, что завершённый результат инструмента меняет следующее решение.
  • После одобрения возобновляется не тот случай: используйте стабильный идентификатор потока, связанный с обращением в поддержку, и проверяйте контрольную точку перед возобновлением.
  • Возврат выполняется дважды: добавьте идемпотентность на границе сервиса и записывайте одобренный запрос и его результат.
  • Агент раскрывает записи другого клиента: исправьте авторизацию в сервисе поиска; инструкция в промпте не является контролем доступа.

Заключение

LangGraph позволяет представить маршрутизацию обращений в поддержку как последовательность явных шагов рабочего процесса, а не полагаться на один ответ модели при принятии решения и выполнении действия. Оставляйте поиск операцией только для чтения, приостанавливайте процесс перед возвратом, проверяйте одобрение во время выполнения и ограничивайте число шагов графа. Затем оценивайте и ответ, и путь, по которому прошёл агент. Эти меры упрощают проверку рабочего процесса, но безопасность production-уровня и применение политик остаются ответственностью приложения.

Источники

  • LangSmith: Evaluate a complex agent — источник примера поддержки музыкального магазина, его структуры поиска/возврата, тестового режима и трёх объектов оценки.

Вопросы

Как потребовать одобрение человека перед тем, как агент LangGraph оформит возврат?

Приостановите граф перед узлом выполнения возврата с помощью interrupt в LangGraph, покажите проверенный запрос рецензенту и возобновите ту же контрольную точку только после явного решения. Также повторно проверяйте одобрение внутри узла выполнения и применяйте политику в сервисе возвратов.

Ограничивает ли лимит рекурсии LangGraph время работы инструментов или количество токенов модели?

Нет. Он ограничивает супершага графа, но не использование токенов модели, длительность работы инструмента, стоимость запросов к базе данных или объём входящих запросов. Добавьте независимые тайм-ауты и ограничения ресурсов.

Может ли модель определить, имеет ли клиент право на возврат?

Нет. Считайте вывод модели недоверенным вводом. Аутентифицируйте клиента и проверяйте доступ к транзакции и право на возврат в коде приложения и сервисов.

Что следует оценивать в агенте поддержки клиентов?

Оценивайте итоговый ответ, последовательность вызовов инструментов и отдельные шаги выбора инструментов. Включите сценарии с недостающей информацией, неоднозначной покупкой, отклонённым одобрением и одобренным возвратом, используя тестовые сервисы для операций с побочными эффектами.

Похожие статьи

Guides

Создайте ограниченного агента LangGraph для извлечения данных с проверкой по схеме

Создайте рабочий процесс LangGraph, который при необходимости вызывает инструмент, укладывается в заданный лимит выполнения и возвращает структурированные данные, проверенные по схеме Pydantic.

Guides

Agentic RAG с LangGraph: вызов инструментов, указание источников и ограничение выполнения

Создайте агента LangGraph для ответов на вопросы по документам, который решает, когда нужен поиск, оценивает контекст, повторяет неудачный поиск и указывает источники без бесконтрольного выполнения.

Guides

Создайте в n8n процесс изменения кода с согласованием человеком и проверкой тестами

Настройте процесс в n8n, который предлагает изменения в репозитории, запрашивает согласие человека на запись и проверяет полученный коммит с помощью тестов.

Guides

Cline с OpenAI-совместимым провайдером для поддержки с подтверждением человеком

Настройте Cline с OpenAI-совместимым провайдером и OneMux для сортировки обращений в службу поддержки, сохранив подтверждение человеком для каждого действия, видимого клиенту.