Вопрос или проблема
Я испытываю трудности с тем, чтобы мой агент ReAct в LangChain работал более чем в одном режиме. Он выбирает инструменты и запускает их, но никогда не принимает решение о том, что ему нужно запустить что-то снова. Очень редко какая-то комбинация подсказок приводит к многоразовым циклам, но это никогда не воспроизводимо.
Важно отметить, что я использую langgraph.prebuilt.create_react_agent
для создания агента. Я знаю, что есть множество других способов создать агента, но, просмотрев код langgraph.prebuilt
, я не вижу причин, почему это не должно работать.
В конце у меня также есть список вещей, которые я пробовал, детали которого я могу предоставить, если это необходимо.
Версии библиотек:
langchain-core==0.3.10
langchain-ollama==0.2.0
langgraph==0.2.39
langgraph-checkpoint==2.0.2
Код агента (метод печати цвета опущен):
import os
import asyncio
import json
import uuid
from dotenv import load_dotenv
from langchain_core.messages import HumanMessage
from langchain_ollama import ChatOllama
from langchain_core.tools import tool
from langgraph.checkpoint.memory import MemorySaver
from langgraph.prebuilt import create_react_agent
load_dotenv("../.env")
thing_list = [
{"name": "Thing0", "location": "paris"},
{"name": "Thing1", "location": "london"},
{"name": "Thing2", "location": "berlin"},
{"name": "Thing3", "location": "paris"},
]
@tool
def get_thing_location(symbol: str) -> str:
"""
Получает местоположение объекта.
Аргументы:
symbol (str): Символ объекта, который нужно найти.
Возвращает:
str: значение местоположения.
"""
thing = next((item for item in thing_list if item["name"] == symbol), None)
return thing["location"] if thing else None
@tool
def find_things_by_location(location: str) -> list:
"""
Получает список объектов на основе их местоположения.
Аргументы:
location (str): Местоположение, где нужно искать объекты.
Возвращает:
list: список объектов по местоположению.
"""
return [thing for thing in thing_list if thing["location"] == location]
modelName=os.getenv("LLM_MODEL", "llama3.2:3b")
ollamaUrl=os.getenv("OLLAMA_URL")
model = ChatOllama(model=modelName, base_url=ollamaUrl)
memory = MemorySaver()
threadId = "thing-agent"
config = {"configurable": {"thread_id": threadId}}
agent = create_react_agent(
model=model,
tools=[find_things_by_location, get_thing_location],
checkpointer=memory,
)
thingLoc = get_thing_location('Thing0');
print(f"Местоположение Thing0: {thingLoc}")
otherThings = find_things_by_location(thingLoc)
print(f"Объекты в том же местоположении: {otherThings}")
msgs = [
HumanMessage(content="""
Каково местоположение Thing0?
Какие другие объекты находятся в том же местоположении?
"""),
]
from color_outputs import print_event
async def run():
async for event in (agent.astream_events(
{"messages": msgs},
version="v2", config=config)):
print_event(event)
asyncio.run(run())
Результат:
Местоположение Thing0: paris
Объекты в том же местоположении: [{'name': 'Thing0', 'location': 'paris'}, {'name': 'Thing3', 'location': 'paris'}]
agent on_chain_start (['graph:step:1'])
Запуск агента: агент с входными сообщениями:
Человек:
Каково местоположение Thing0?
Какие другие объекты находятся в том же местоположении?
-------------
--------------------
get_thing_location on_tool_start (['seq:step:1'])
Запуск инструмента: get_thing_location с входными данными: {'symbol': 'Thing0'}
--------------------
find_things_by_location on_tool_start (['seq:step:1'])
Запуск инструмента: find_things_by_location с входными данными: {'location': 'get_thing_location', 'symbol': 'Thing0'}
--------------------
find_things_by_location on_tool_end (['seq:step:1'])
Завершена работа инструмента: find_things_by_location
Вывод инструмента: content=[] name="find_things_by_location" tool_call_id='8f012dd4-6082-4bd1-bbaa-e82eba61eca0'
--------------------
get_thing_location on_tool_end (['seq:step:1'])
Завершена работа инструмента: get_thing_location
Вывод инструмента: content="paris" name="get_thing_location" tool_call_id='7fc27e00-29be-48b1-ab7a-d640cee96212'
--------------------
agent on_chain_start (['graph:step:3'])
Запуск агента: агент с входными сообщениями:
Человек:
Каково местоположение Thing0?
Какие другие объекты находятся в том же местоположении?
-------------
ИИ:
-------------
Инструмент: get_thing_location: paris
-------------
Инструмент: find_things_by_location: []
-------------
--------------------
Процесс завершен с кодом выхода 0
Как вы можете видеть, он не пытается выполнить вызов find_things_by_location
после получения информации о местоположении из предыдущего вызова. Иногда он использует этот инструмент, но не с осмысленным вводом (либо ничего, либо что-то, что он сам выдумывает).
Вещи, которые я пробовал:
- Разные модели:
- llama3.1:70b
- mistral-large:123b
- mistral-nemo:12b
- llama3.2:3b
- Одно сообщение с обеими инструкциями, вместо двух.
- Добавление
state_modifier
с подсказкой, описывающей цикл Думать-Действовать-Наблюдать-Повторять. - Сделать эту подсказку более или менее подробной или явно включить ограничения о том, когда использовать какой инструмент.
Ответ или решение
Проблема с выполнением многократных циклов реактивным агентом в библиотеке LangChain может быть связана с несколькими аспектами, начиная от конфигурации агента и заканчивая особенностями имплементации инструментов и моделирования. Рассмотрим подробнее возможные причины и решения.
Основные причины проблемы
-
Недостаток контекста в сообщениях.
Ваш текущий код использует две разные команды в одном сообщении. Хотя это может сработать в некоторых случаях, более сложные взаимодействия могут требовать отдельной обработки. Убедитесь, что агент получает достаточно информации для принятия решений на каждом шаге. -
Логика выбора инструментов.
Ваша реализация может не предоставлять агенту достаточно информации для корректного выбора инструмента. Если инструкция не содержит четких указаний относительно использования инструментов, агент может не осознавать, что ему нужно использоватьfind_things_by_location
после получения локации. -
Частота обновления состояния.
Возможно, вы не обновляете состояние агента должным образом после каждого вызова инструмента. Проблемы могут
возникнуть, если состояние не сохраняется или не используется для последующих шагов, что может происходить в рамках вашегоMemorySaver
.
Рекомендованные шаги для решения проблемы
-
Перепишите сообщения. Попробуйте разделить вашу логику на несколько сообщений:
msgs = [ HumanMessage(content="Каково местоположение Thing0?"), ]
Сначала запросите местоположение, затем на основании полученного ответа отправьте запрос для выяснения других объектов в том же месте.
-
Четкие инструкции для выбора инструментов. Добавьте в сообщение инструкции о том, когда использовать тот или иной инструмент. Например:
msgs = [ HumanMessage(content=""" Что такое местоположение Thing0? Используй инструмент get_thing_location для этого. Затем, как только ты получишь ответ, используй find_things_by_location для поиска других объектов в этом местоположении. """), ]
-
Проверьте реализацию
MemorySaver
. Убедитесь, что ваше состояние корректно сохраняется и восстанавливается между вызовами. Если ваш агент не использует состояние, повседневное выполнение может стать затруднительным. -
Отладка. Используйте отладочную печать для отслеживания значений, используемых при вызовах инструментов, и их выводов. Убедитесь, что входные данные передаются корректно.
-
Тестирование с различными моделями. Поскольку вы уже пробовали различные модели, зафиксируйте их результаты и поведение, чтобы понять, какая модель наиболее устойчиво выполняет ваши задачи.
Заключение
Совокупность этих рекомендаций должна помочь вам наладить работу вашего реактивного агента в LangChain на многоцикловой основе. Проведение тщательного анализа логики выбора инструментов, обновление контекста и тестирование состояния могут значительно улучшить готовность агента к многократным вызовам. Если проблема продолжит возникать, вам стоит обратиться в сообщество LangChain для получения более специфической помощи или протестировать другие подходы к созданию и настройке агента.