Исправление инъекции ToolRuntime в LangGraph StateGraph
Узнайте, как исправлять ошибки инъекции ToolRuntime в агентах StateGraph LangGraph. Узнайте, почему поле tool_runtime исчезает и реализуйте рабочие решения с примерами кода.
Я сталкиваюсь с ошибкой времени выполнения при вызове инструмента, требующего tool_runtime, внутри агента LangGraph StateGraph. Сообщение об ошибке указывает, что обязательное поле tool_runtime отсутствует при вызове инструмента.
Вот моя настройка:
- Версия LangGraph: 1.0.3
- Версия LangChain: 1.0.0
- Версия LangChain OpenAI: 1.0.0
Инструмент определен следующим образом:
@tool("foo_tool", description="Please call this tool so that I can try how it's working")
def foo_tool(tool_runtime: ToolRuntime) -> Command:
msg = tool_runtime.state.messages # I need to access the state
...
return Command(update={"called_tool": True})
При вызове инструмента я получаю следующую ошибку:
Error invoking tool 'foo_tool' with kwargs {} with error:
tool_runtime: Field required
Please fix the error and try again.
Я ожидал, что tool_runtime будет автоматически внедрен LangGraph, так как это аргумент, который не должен быть виден LLM. Это ошибка в LangGraph, или я что-то упустил в своей реализации?
Проблема, с которой вы столкнулись, является известным ограничением в LangGraph, где внедрение ToolRuntime не работает при использовании обертки ToolNode, несмотря на то, что оно должно происходить автоматически. Это не ошибка в вашей реализации, а скорее ограничение того, как LangGraph обрабатывает внедрение во время выполнения в разных контекстах.
Содержание
- Понимание проблемы внедрения ToolRuntime
- Основные причины ошибки отсутствия tool_runtime
- Рабочие решения и обходные пути
- Лучшие практики для внедрения во время выполнения
- Будущие улучшения и статус
Понимание проблемы внедрения ToolRuntime
Параметр ToolRuntime в инструментах LangGraph предназначен для автоматического внедрения фреймворком, предоставляя доступ к данным во время выполнения, таким как runtime.state.messages, которые вы пытаетесь использовать. Однако, как вы обнаружили, это внедрение не работает последовательно во всех шаблонах использования.
Согласно документации LangChain, “Просто добавьте runtime: ToolRuntime в сигнатуру вашего инструмента, и он будет автоматически внедрен без раскрытия его LLM”. Это предполагает, что функциональность должна работать, но реализация имеет ограничения.
Основная проблема заключается в том, как LangGraph обрабатывает контексты выполнения инструментов. Когда вы используете ToolNode для обертки ваших инструментов, механизм внедрения во время выполнения обходит стандартный путь внедрения, который работает для напрямую добавленных узлов.
Основные причины ошибки отсутствия tool_runtime
1. Ограничение обертки ToolNode
Из обсуждения на Stack Overflow, параметр ToolRuntime должен автоматически внедряться, но “в настоящее время это работает только при добавлении инструмента напрямую как узла или при использовании create_agent — не через обертку ToolNode”.
Это означает:
- ✅ Работает при прямом добавлении инструментов:
agent_builder.add_node("tools", foo_tool) - ❌ Не работает с ToolNode:
ToolNode([foo_tool])
2. Вмешательство валидации Pydantic
В GitHub issue #6431 указано, что ToolNode не может выполнять инструменты с параметрами ToolRuntime из-за ошибок валидации Pydantic. Валидация схемы инструмента происходит до внедрения во время выполнения, вызывая ошибку “Обязательное поле”.
3. Проблема раскрытия схемы
Как отмечено в issue #31688, “InjectedState и InjectedToolCallId должны быть включены в args_schema” для работы внедрения. Без правильной настройки схемы эти параметры рассматриваются как обязательные пользовательские входы, а не как внедренные значения во время выполнения.
Рабочие решения и обходные пути
Решение 1: Добавление инструментов напрямую как узлов (Рекомендуется)
Самый надежный обходной путь — добавить ваш инструмент напрямую как узел, а не обертывать его в ToolNode:
from langchain.tools import tool, ToolRuntime
from langgraph.types import Command
@tool("foo_tool", description="Пожалуйста, вызовите этот инструмент, чтобы я мог проверить, как он работает")
def foo_tool(runtime: ToolRuntime) -> Command:
msg = runtime.state.messages # Успешный доступ к состоянию
print(f"Доступ к сообщениям: {msg}")
return Command(update={"called_tool": True})
# Добавляем инструмент напрямую как узел
agent_builder.add_node("tools", foo_tool)
Этот подход работает, потому что он обходит обертку ToolNode, которая вызывает сбой внедрения.
Решение 2: Использование альтернативы InjectedState
Если вам нужен доступ к состоянию, но не требуется полная функциональность ToolRuntime, вы можете использовать InjectedState вместо него:
from langgraph.prebuilt import InjectedState
from langgraph.types import Command
@tool("foo_tool", description="Пожалуйста, вызовите этот инструмент, чтобы я мог проверить, как он работает")
def foo_tool(state: Annotated[dict, InjectedState]) -> Command:
msg = state.get("messages", []) # Доступ к сообщениям состояния
return Command(update={"called_tool": True})
Решение 3: Использование create_agent вместо ручного добавления узлов
Как указано в ответе на Stack Overflow, использование create_agent также может решить проблемы внедрения:
# Этот подход может лучше работать с внедрением ToolRuntime
agent = create_agent(
llm,
tools=[foo_tool], # Прямая ссылка на инструмент
prompt=prompt_template
)
Решение 4: Обновление LangGraph до последней версии
В GitHub issues указано, что поддержка внедрения во время выполнения была улучшена в последних версиях. Рассмотрите возможность обновления до последней версии LangGraph, где класс InjectedRuntime был правильно раскрыт в публичном API.
Лучшие практики для внедрения во время выполнения
1. Выбор правильного метода внедрения
| Метод | Случай использования | Ограничения |
|---|---|---|
ToolRuntime |
Полный доступ во время выполнения (состояние, хранилище и т.д.) | Не работает с оберткой ToolNode |
InjectedState |
Только доступ к состоянию | Более ограниченная функциональность |
InjectedStore |
Только доступ к хранилищу | Только специфические случаи использования |
2. Настройка схемы
Убедитесь, что ваша схема инструмента правильно исключает параметры времени выполнения из раскрытия LLM:
from langchain_core.tools import tool
from pydantic import Field
@tool("foo_tool")
def foo_tool(
runtime: ToolRuntime = Field(default_factory=ToolRuntime), # Скрыто от LLM
user_input: str # Это будет раскрыто LLM
) -> Command:
# Реализация инструмента
pass
3. Обработка ошибок
Всегда включайте правильную обработку ошибок для сценариев внедрения во время выполнения:
@tool("foo_tool")
def foo_tool(runtime: ToolRuntime = None) -> Command:
try:
if runtime:
msg = runtime.state.messages
# Обработка сообщений
else:
# Резервное поведение
msg = []
except Exception as e:
# Обработка сбоев внедрения
return Command(update={"error": str(e)})
return Command(update={"called_tool": True})
Будущие улучшения и статус
Команда LangGraph активно работает над улучшением внедрения во время выполнения. Согласно обсуждениям на GitHub, поддержка обновления состояния графа из инструментов была добавлена с использованием нового типа Command.
Ключевые улучшения в разработке:
- Лучшая интеграция между
ToolNodeи внедрением во время выполнения - Улучшенная обработка ошибок для сбоев внедрения
- Более последовательное поведение внедрения в разных шаблонах использования инструментов
- Раскрытие класса
InjectedRuntimeв публичном API (как видно в issue #5990)
Для получения самой актуальной информации и исправлений следите за GitHub issues LangGraph и рассмотрите возможность участия в обсуждениях сообщества для помощи в приоритизации этих улучшений.
Источники
- ToolRuntime error: Required fields tool_runtime missing when invoking tool in LangGraph - Stack Overflow
- LangGraph CLI treats InjectedState as required tool parameter and fails the validation · Issue #6241
- Inject Runtime into tools · Issue #5990
- state is not being injected when using custom input schema on tool · Issue #31688
- ToolNode fails to execute tools with ToolRuntime parameter due to Pydantic validation error · Issue #6431
- Difference between InjectedStore, InjectedState, ToolRuntime, Runtime Context - LangChain Forum
- How to access the langraph state inside the langraph tool - Stack Overflow
- Tools - Docs by LangChain
- Tool calling in LangGraph and how to update the Graph-State with Tools output · Discussion #1616
- Runtime context is not being passed to the subgraph · Issue #5700
Заключение
Ошибка отсутствия tool_runtime в LangGraph является известным ограничением, а не ошибкой в вашей реализации. Ключевые выводы:
- Используйте прямое добавление узлов вместо обертки
ToolNodeдля инструментов, требующихToolRuntime - Рассмотрите альтернативные методы внедрения, такие как
InjectedStateдля простого доступа к состоянию - Держите зависимости обновленными, чтобы воспользоваться текущими улучшениями внедрения во время выполнения
- Следите за GitHub issues для последних исправлений и улучшений этой функциональности
Для вашего конкретного случая я рекомендую реализовать Решение 1 — добавление вашего инструмента напрямую как узла, а не использование ToolNode. Этот подход обеспечит надежный доступ к состоянию во время выполнения, избегая проблем с внедрением, которые вы сейчас испытываете.