Мультимодельная маршрутизация в LangGraph — это в первую очередь проблема проектирования графа, а во вторую — проблема шлюза. Граф решает, какой тип работы выполняется, клиент модели решает, какой OpenAI-совместимый маршрут вызывать, а шлюз должен проверять, остался ли каждый вызов в рамках правил бюджета, инструментов, повторных попыток, ведения журнала и условий остановки.
Flatkey подходит для этой границы шлюза. Его общедоступный сайт показывает OpenAI-совместимый маршрут чата по адресу https://router.flatkey.ai/v1/chat/completions, с одним ключом, видимостью использования, контролем биллинга и маршрутизацией моделей в одном месте. Это руководство показывает практическую настройку мультимодельной маршрутизации в LangGraph для рабочих процессов агентов, не предполагая, что каждый псевдоним модели, поведение инструмента или резервный маршрут уже проверены в вашей учетной записи.
Краткий ответ по мультимодельной маршрутизации в LangGraph
Безопасная настройка мультимодельной маршрутизации в LangGraph разделяет маршрутизацию на три уровня.
| Уровень | Что он решает | Проверка через шлюз |
|---|---|---|
| Маршрут графа | Должен ли рабочий процесс использовать узел простого ответа, узел сложного рассуждения, узел с интенсивным использованием инструментов или путь остановки | Сохранять имя маршрута и причину с временной меткой запроса. |
| Маршрут модели | Какой OpenAI-совместимый псевдоним модели вызывает каждый узел через Flatkey | Проверить, существует ли псевдоним для ключа и семейства конечных точек. |
| Операционные ограничения | Должен ли запрос продолжаться, повторяться, использовать резервный вариант или остановиться | Проверить бюджет, количество вызовов инструментов, количество повторных попыток, тайм-аут и журналы запросов. |
| Подтверждение | Действительно ли маршрут сработал | Сопоставить ответ приложения с данными об использовании или журналами запросов Flatkey. |
Не скрывайте мультимодельную маршрутизацию в LangGraph внутри одного длинного промпта. Размещайте политику в узлах графа, условных ребрах и проверках шлюза, которые ваша команда может инспектировать.
Почему маршрутизация моделей должна находиться на границах графа
Большинство примеров LangGraph сосредоточены на управлении потоком графа: состоянии, узлах, ребрах, инструментах и персистентности. Это правильная отправная точка, но производственным агентам также нужны границы маршрутов, которые могут анализировать команды платформы и финансов.
Используйте маршруты на уровне графа, когда рабочий процесс имеет явно различные профили затрат, задержек или рисков, связанных с инструментами:
| Тип работы | Пример | Форма маршрута |
|---|---|---|
| Простой ответ | Суммировать короткую заметку поддержки | Быстрый, недорогой псевдоним модели. |
| Сложное рассуждение | Согласовать противоречивый текст политики | Более сильный псевдоним модели с более высоким бюджетом на вызов. |
| Действие с интенсивным использованием инструментов | Запрашивать системы, создавать тикеты, обновлять записи | Псевдоним модели, способный использовать инструменты, с более строгими ограничениями на вызовы. |
| Путь остановки | Бюджет исчерпан, слишком много повторных попыток, небезопасное состояние | Вернуть контролируемое сообщение вместо вызова другой модели. |
Именно на этой границе может помочь Flatkey. Вместо того чтобы разбрасывать отдельные ключи провайдеров по каждому узлу, каждый маршрут может вызывать базовый URL OpenAI-совместимого API, в то время как Flatkey обеспечивает видимость на уровне шлюза. Для смежного проектирования политик см. руководство Flatkey по элементам управления шлюзом для AI-агентов.
Проверки источника перед настройкой маршрута
Используйте актуальную документацию и проверки в реальной учетной записи, прежде чем рассматривать шаблоны как производственный код.
| Проверка | Что проверить |
|---|---|
| Состояние и ребра LangGraph | Ваш граф может выполнять маршрутизацию с помощью StateGraph, функций узлов и условных ребер. |
| Клиент модели LangChain | Ваша установленная версия LangChain поддерживает init_chat_model с провайдером OpenAI, base_url и api_key, или эквивалентный конструктор ChatOpenAI. |
| Вызов инструментов | Выбранный маршрут модели поддерживает схему инструментов и поведение вызова инструментов, необходимое вашему узлу. |
| Конечная точка Flatkey | Ваш ключ может вызывать выбранный псевдоним модели через OpenAI-совместимый базовый URL Flatkey. |
| Бюджет и журналы | Реальный запрос появляется в данных об использовании или журналах запросов Flatkey с ожидаемым ключом, псевдонимом модели и временной меткой. |
Приведенный ниже код является шаблоном. Запустите его с вашими текущими версиями langchain, langchain-openai и langgraph, прежде чем внедрять политику мультимодельной маршрутизации в LangGraph.
Настройка чат-моделей с использованием Flatkey
Установите актуальные пакеты в среде, где выполняется ваш граф.
pip install -U langgraph langchain langchain-openaiДержите корень API отдельно от пути конечной точки. Клиенты LangChain должны получать базовый URL; клиент добавляет путь Chat Completions для OpenAI-совместимых вызовов чата.
FLATKEY_API_KEY=sk-fk-your-key
FLATKEY_BASE_URL=https://router.flatkey.ai/v1
FLATKEY_FAST_MODEL=your-fast-model-alias
FLATKEY_REASONING_MODEL=your-reasoning-model-alias
FLATKEY_TOOL_MODEL=your-tool-capable-model-aliasЗатем создайте явные клиенты моделей для каждого маршрута.
import os
from langchain.chat_models import init_chat_model
BASE_URL = os.getenv("FLATKEY_BASE_URL", "https://router.flatkey.ai/v1")
API_KEY = os.environ["FLATKEY_API_KEY"]
fast_model = init_chat_model(
model=os.environ["FLATKEY_FAST_MODEL"],
model_provider="openai",
base_url=BASE_URL,
api_key=API_KEY,
)
reasoning_model = init_chat_model(
model=os.environ["FLATKEY_REASONING_MODEL"],
model_provider="openai",
base_url=BASE_URL,
api_key=API_KEY,
)
tool_model = init_chat_model(
model=os.environ["FLATKEY_TOOL_MODEL"],
model_provider="openai",
base_url=BASE_URL,
api_key=API_KEY,
)Это самая простая полезная форма для мультимодельной маршрутизации в LangGraph: у каждого маршрута есть именованный клиент модели, но все вызовы используют одну и ту же границу шлюза. Не предполагайте, что псевдоним модели поддерживает потоковую передачу или инструменты только потому, что это делает другой псевдоним. Тестируйте каждый маршрут отдельно.
Создание шаблона маршрутизации LangGraph
Используйте узел-классификатор, чтобы записать маршрут в состояние. Затем позвольте условным рёбрам решать, какой узел будет выполняться следующим.
from typing import Annotated, Literal, TypedDict
from langchain_core.messages import AIMessage, BaseMessage
from langchain_core.tools import tool
from langgraph.graph import END, StateGraph
from langgraph.graph.message import add_messages
class RouteState(TypedDict):
messages: Annotated[list[BaseMessage], add_messages]
route: Literal["simple", "complex", "tools", "stop"]
budget_cents: float
errors: int
tool_calls: int
@tool
def lookup_account_status(account_id: str) -> str:
"""Шаблонный инструмент. Замените его на ваш реальный инструмент для поиска только для чтения."""
return "active"
tool_ready_model = tool_model.bind_tools([lookup_account_status])
def choose_route(state: RouteState) -> dict:
last_message = state["messages"][-1].content.lower()
if state.get("budget_cents", 0) <= 0:
return {"route": "stop"}
if state.get("errors", 0) >= 2:
return {"route": "stop"}
if "lookup" in last_message or "account" in last_message:
return {"route": "tools"}
if len(last_message) > 600:
return {"route": "complex"}
return {"route": "simple"}
def simple_answer(state: RouteState) -> dict:
return {"messages": [fast_model.invoke(state["messages"])]}
def complex_answer(state: RouteState) -> dict:
return {"messages": [reasoning_model.invoke(state["messages"])]}
def tool_answer(state: RouteState) -> dict:
if state.get("tool_calls", 0) >= 3:
return {"messages": [AIMessage(content="Tool-call limit reached.")] }
return {"messages": [tool_ready_model.invoke(state["messages"])]}
workflow = StateGraph(RouteState)
workflow.add_node("choose_route", choose_route)
workflow.add_node("simple_answer", simple_answer)
workflow.add_node("complex_answer", complex_answer)
workflow.add_node("tool_answer", tool_answer)
workflow.set_entry_point("choose_route")
workflow.add_conditional_edges(
"choose_route",
lambda state: state["route"],
{
"simple": "simple_answer",
"complex": "complex_answer",
"tools": "tool_answer",
"stop": END,
},
)
workflow.add_edge("simple_answer", END)
workflow.add_edge("complex_answer", END)
workflow.add_edge("tool_answer", END)
graph = workflow.compile()Этот шаблон делает мультимодельную маршрутизацию в LangGraph наглядной. Рецензент может видеть, почему запрос был направлен в simple_answer, complex_answer, tool_answer или stop, без необходимости реконструировать промпт.
Узел tool_answer выше проверяет маршрут модели, который может предлагать вызовы инструментов. Если ваш граф должен выполнять инструменты, добавьте ToolNode из LangGraph или ваш собственный исполнитель после этого узла модели, а затем направьте результат инструмента обратно в граф с теми же проверками бюджета и условий остановки.
Добавление проверок через шлюз для каждого вызова модели
Маршрут графа не должен быть единственным защитным механизмом. Добавьте небольшую обёртку, которая проверяет бюджеты перед вызовом модели и записывает данные после вызова модели.
from dataclasses import dataclass
from time import time
@dataclass
class GatewayDecision:
route: str
model_alias: str
allowed: bool
reason: str
started_at: float
def preflight(route: str, model_alias: str, state: RouteState) -> GatewayDecision:
if state.get("budget_cents", 0) <= 0:
return GatewayDecision(route, model_alias, False, "budget_exhausted", time())
if route == "tools" and state.get("tool_calls", 0) >= 3:
return GatewayDecision(route, model_alias, False, "tool_limit_reached", time())
if state.get("errors", 0) >= 2:
return GatewayDecision(route, model_alias, False, "retry_limit_reached", time())
return GatewayDecision(route, model_alias, True, "allowed", time())
def record_gateway_result(decision: GatewayDecision, response: BaseMessage) -> None:
# Замените это на структурированное логирование. Включите отредактированную метку ключа,
# имя маршрута, псевдоним модели, временную метку запроса и метаданные ответа.
print(
{
"route": decision.route,
"model_alias": decision.model_alias,
"allowed": decision.allowed,
"reason": decision.reason,
"started_at": decision.started_at,
"response_type": response.type,
}
)
В производственной среде не ограничивайтесь локальными логами. Сопоставляйте временную метку и псевдоним модели с логами использования или запросов Flatkey. Это будет доказательством того, что мультимодельная маршрутизация в LangGraph использовала именно тот маршрут шлюза, который вы предполагали.
Проверяйте инструменты, прежде чем доверять маршруту с их интенсивным использованием
Узлы с интенсивным использованием инструментов заслуживают собственного пакета верификации. Модель может хорошо справляться с обычным чатом, но не соответствовать вашей схеме инструментов, по-другому передавать дельты инструментов или генерировать аргументы инструментов, которые ваш исполнитель отклоняет. Для более глубоких проверок совместимости используйте руководство Flatkey по совместимости вызова инструментов у разных провайдеров.
| Проверка инструмента | Условие прохождения |
|---|---|
| Схема принята | Маршрут модели принимает определение инструмента без ошибки запроса. |
| Инструмент выбран | Ответ содержит ожидаемый вызов инструмента для детерминированного промпта. |
| Аргументы разбираются | Аргументы инструмента проходят валидацию по вашей схеме перед выполнением. |
| Количество инструментов ограничено | Маршрут останавливается после максимального количества вызовов инструментов. |
| Сбой обработан | Ошибки инструментов приводят к контролируемому состоянию графа, а не к бесконечному циклу повторных попыток. |
| Лог виден | Логи Flatkey показывают запрос под ожидаемым ключом и псевдонимом модели. |
Здесь вы также решаете, относится ли маршрут к Chat Completions или Responses. Держите семейства конечных точек раздельно; если вы оцениваете маршруты агентов в стиле Responses, используйте это руководство вместе с совместимым с OpenAI маршрутизатором Responses API от Flatkey.
Политика повторных попыток, резервирования и условий остановки
Повторные попытки могут скрывать ошибки маршрутизации. Строгая политика мультимодельной маршрутизации в LangGraph должна определять, когда повторять попытку, когда переключаться на резервный вариант и когда останавливаться.
| Условие | Рекомендуемое действие | Почему |
|---|---|---|
401 или 403 | Остановиться и исправить ключ | Повторная попытка не исправит аутентификацию. |
404 model not found | Остановиться и проверить псевдоним модели или семейство конечных точек | Маршрут может вызывать не ту модель. |
429 или ошибка емкости | Повторить один раз с экспоненциальной задержкой или переключиться на утвержденный резервный псевдоним | Избегайте неконтролируемого роста затрат и видимых пользователю циклов. |
| Ошибка валидации инструмента | Остановить маршрут инструмента и вернуть контролируемое сообщение | Повторение неверных аргументов инструмента редко бывает полезным. |
| Достигнут порог бюджета | Остановиться перед следующим вызовом модели | Политика шлюза должна защищать расходы до вызова. |
Промежуточное ПО LangChain может помочь с повторными попытками на уровне агента, резервированием и ограничениями вызовов. Для созданных вручную рабочих процессов LangGraph придерживайтесь той же политики рядом с узлом, который вызывает модель, а затем подтверждайте результат в логах Flatkey.
Контрольный список для тестирования перед публикацией
Выполните эти проверки, прежде чем сделать Flatkey маршрутом по умолчанию для агента.
- Отправьте один прямой запрос
curlнаhttps://router.flatkey.ai/v1/chat/completionsс предполагаемым ключом и псевдонимом модели. - Вызовите каждый клиент модели LangChain один раз вне LangGraph.
- Запустите граф с одним промптом для простого маршрута, одним для сложного маршрута и одним для маршрута с интенсивным использованием инструментов.
- Принудительно вызовите путь остановки, установив
budget_centsв0. - Принудительно достигните лимита повторных попыток, установив
errorsна максимальное допустимое значение. - Убедитесь, что каждый запрос появляется в логах Flatkey с ожидаемой временной меткой, меткой ключа, именем маршрута и псевдонимом модели.
- Сравните поля затрат или использования с владельцем, который утверждает бюджет рабочего процесса. Страница цен Flatkey — подходящее публичное место для начала этой проверки.
Результат этого контрольного списка становится приемочным пакетом для мультимодельной маршрутизации в LangGraph. Это полезнее, чем скриншот работающего промпта, потому что это доказывает, что граф, клиент модели и шлюз согласованы между собой.
Устранение неполадок мультимодельной маршрутизации в LangGraph
| Симптом | Вероятная причина | Что проверить |
|---|---|---|
| Каждый запрос использует одну и ту же модель | Условное ребро никогда не меняет состояние | Выведите значение маршрута после узла-классификатора. |
401 или 403 | Неверный, отсутствующий или отозванный ключ Flatkey | Создайте ключ заново и не храните его в системе контроля версий. |
404 | Неверный корень API, дублирование /v1 или недоступный псевдоним модели | Используйте https://router.flatkey.ai/v1 в качестве базового URL и проверьте псевдоним. |
| Маршрут инструмента завершается сбоем | Псевдоним модели не поддерживает вашу схему инструментов | Протестируйте bind_tools с одним детерминированным промптом перед выполнением графа. |
| Повторные попытки увеличивают затраты | Политика повторных попыток находится в слишком многих местах | Выберите одного владельца повторных попыток: узел графа, промежуточное ПО LangChain или политика шлюза. |
| Логи не совпадают | Запрос обошел Flatkey или логи отфильтрованы | Ищите по временной метке, метке ключа, псевдониму модели и маршруту. |
| Финансовый отдел не может утвердить развертывание | Владелец затрат не может сопоставить маршруты с расходами | Помечайте ключи по рабочей нагрузке и держите псевдонимы моделей явными в конфигурации маршрута. |
Если первый маршрут не работает, сведите к минимуму область отладки: ключ, базовый URL, псевдоним модели, один клиент модели, один узел графа и один просмотр лога Flatkey.
Часто задаваемые вопросы
Является ли мультимодельная маршрутизация в LangGraph тем же самым, что и отказоустойчивость провайдера?
Нет. Мультимодельная маршрутизация в LangGraph решает, какой маршрут подходит для задачи, до или во время выполнения графа. Отказоустойчивость провайдера — это то, что происходит, когда выбранный маршрут не может быть завершен. Вы можете использовать и то, и другое, но их следует тестировать отдельно.
Должен ли каждый узел LangGraph использовать свою модель?
Нет. Начните с двух или трех явных маршрутов. Слишком большое количество псевдонимов моделей усложняет проверку логов, бюджетов и откат.
Можно ли использовать Flatkey одновременно с маршрутами Chat Completions и Responses?
Flatkey предоставляет семейства конечных точек, совместимых с OpenAI, но каждый клиентский путь все равно требует отдельного тестирования. Разделяйте проверки для Chat Completions и Responses, особенно для вызовов инструментов, потоковой передачи, полей использования и резервного поведения.
Итоговый чек-лист
Ваша настройка мультимодельной маршрутизации LangGraph готова к выходу за рамки шаблона, когда:
- Маршрут графа виден в состоянии и логах.
- Каждый маршрут сопоставлен с именованным псевдонимом модели.
- Ключ Flatkey может вызывать каждый выбранный псевдоним через базовый URL, совместимый с OpenAI.
- Маршруты с интенсивным использованием инструментов проходят тесты схемы, аргументов, ограничений и ошибок.
- Условия остановки по бюджету и повторным попыткам срабатывают до следующего вызова модели.
- Логи использования или запросов Flatkey подтверждают выбранный маршрут.
- Откат — это изменение одной конфигурации, а не переписывание приложения.
Когда вы будете готовы направить трафик агентов LangGraph через один шлюз, получите ключ Flatkey, начните с одного маршрута графа с низким риском и расширяйте его только после того, как логи подтвердят, что политика работает.



