Files

115 lines
4.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# solution.py
from langchain.agents import create_agent
from langchain.agents.middleware import HumanInTheLoopMiddleware
from langchain.tools import tool
from langchain_ollama import ChatOllama
from langgraph.checkpoint.memory import MemorySaver
from langgraph.types import Command
from rich import print as rprint
# ------------------------------------------------------------------
# 1. Определяем инструмент get_weather
# ------------------------------------------------------------------
@tool("get_weather")
def get_weather(city: str, date: str) -> str:
"""
Возвращает погоду в указанном городе и дате.
Для демонстрации возвращаем фиктивный ответ.
"""
return f"Погода в {city} на {date}: солнечно, 25°C."
# ------------------------------------------------------------------
# 2. Создаём LLM (Ollama) и агент с HumanInTheLoopMiddleware
# ------------------------------------------------------------------
llm = ChatOllama(model="llama3") # используем Ollama
memory = MemorySaver() # память для сохранения пауз
agent = create_agent(
model=llm,
tools=[get_weather],
system_prompt="Ты полезный ассистент, помогающий пользователю.",
middleware=[
HumanInTheLoopMiddleware(
interrupt_on={
"get_weather": True # все решения: approve, edit, reject
},
description_prefix="Подтвердите вызов инструмента",
),
],
checkpointer=memory,
)
# ------------------------------------------------------------------
# 3. Функция для запроса решений у пользователя
# ------------------------------------------------------------------
def ask_decisions(action_requests):
"""
action_requests – список словарей с полями name, args и опционально description.
Возвращает список решений в том же порядке: approve/reject.
"""
decisions = []
for idx, act in enumerate(action_requests, start=1):
rprint(f"\n--- Подтверждение #{idx} ---")
rprint(f"[bold]Инструмент:[/bold] {act['name']}")
rprint(f"[bold]Аргументы:[/bold] {act['args']}")
if "description" in act:
rprint(f"[bold]Описание:[/bold] {act['description']}")
while True:
choice = input("a = approve, r = reject: ").strip().lower()
if choice == "a":
decisions.append({"type": "approve"})
break
elif choice == "r":
msg = input("Сообщение для агента (причина отказа): ")
decisions.append({"type": "reject", "message": msg})
break
else:
rprint("[red]Неверный ввод. Пожалуйста, введите 'a' или 'r'.[/red]")
return decisions
# ------------------------------------------------------------------
# 4. Основной цикл взаимодействия с агентом
# ------------------------------------------------------------------
def main():
thread_id = "сессия-1"
config = {"configurable": {"thread_id": thread_id}}
while True:
user_msg = input("\nВы: ")
if not user_msg.strip():
continue
# первый вызов агента
result = agent.invoke(
{"messages": [{"role": "human", "content": user_msg}]},
config=config,
)
# цикл обработки пауз
while "__interrupt__" in result:
interrupt_value = result["__interrupt__"][0].value
action_requests = interrupt_value.get("action_requests", [])
if not action_requests:
rprint("[yellow]Пауза без действий. Продолжаем...[/yellow]")
break
decisions = ask_decisions(action_requests)
# возобновляем выполнение
result = agent.invoke(
Command(resume={"decisions": decisions}),
config=config,
)
# вывод финального ответа агента
if "messages" in result and result["messages"]:
last_msg = result["messages"][-1]
rprint(f"\n[bold]Агент:[/bold] {last_msg['content']}")
else:
rprint("[red]Ответ не получен.[/red]")
if __name__ == "__main__":
main()