Добавить solutions/69a474cdc46fd26feae69896_Практическое_задание__3__Память_и_подтве/agent_with_memory_and_human_in_the_loop.py
This commit is contained in:
+112
@@ -0,0 +1,112 @@
|
||||
|
||||
"""
|
||||
Практическое задание №3:
|
||||
Память и подтверждение действий
|
||||
|
||||
Сценарий:
|
||||
- Агент использует LangChain + HumanInTheLoopMiddleware.
|
||||
- При каждом вызове инструмента агент останавливается,
|
||||
выводит запрос пользователю (approve/reject) через консоль.
|
||||
- История сохраняется в MemorySaver, чтобы при повторном запуске
|
||||
агент «помнил» предыдущие сообщения и решения.
|
||||
|
||||
Требования:
|
||||
1. Подключение к LLM (ChatOpenAI).
|
||||
2. Создание простого инструмента – get_weather(city: str) -> str.
|
||||
3. Middleware‑подтверждение с выводом в консоль.
|
||||
4. Хранение истории в MemorySaver.
|
||||
5. Чат‑цикл: пользователь вводит запрос, агент отвечает,
|
||||
при необходимости запрашивает подтверждение.
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
from typing import Dict, Any
|
||||
|
||||
# ---------- 1. Подключаем LLM ----------
|
||||
from langchain_openai import ChatOpenAI
|
||||
from langchain.agents import create_agent
|
||||
from langchain.tools import tool
|
||||
from langchain.schema import HumanMessage, AIMessage, SystemMessage
|
||||
from langgraph.checkpoint.memory import MemorySaver
|
||||
from langchain.agents.middleware import HumanInTheLoopMiddleware
|
||||
|
||||
# Для примера используем локальный LLM (замените на свой)
|
||||
os.environ["OPENAI_API_KEY"] = "fake" # нужен только для совместимости
|
||||
llm = ChatOpenAI(
|
||||
model="gpt-4o-mini",
|
||||
base_url="https://api.openai.com/v1", # замените, если используете локальный сервер
|
||||
temperature=0.7,
|
||||
)
|
||||
|
||||
# ---------- 2. Инструмент ----------
|
||||
@tool
|
||||
def get_weather(city: str) -> str:
|
||||
"""
|
||||
Возвращает погоду в указанном городе.
|
||||
(В реальном проекте подключитесь к API погоды)
|
||||
"""
|
||||
# Здесь просто пример – возвращаем фиктивный ответ
|
||||
return f"Погода в {city}: ☀️ 25°C, ясное небо."
|
||||
|
||||
# ---------- 3. Создаём агент ----------
|
||||
memory = MemorySaver() # хранит историю
|
||||
|
||||
agent = create_agent(
|
||||
model=llm,
|
||||
tools=[get_weather],
|
||||
system_prompt="Ты полезный ассистент, отвечай на вопросы и при вызове инструментов спрашивай подтверждение.",
|
||||
middleware=[
|
||||
HumanInTheLoopMiddleware(
|
||||
interrupt_on={"get_weather": True}, # останавливаемся перед каждым вызовом
|
||||
description_prefix="Подтвердите вызов инструмента",
|
||||
)
|
||||
],
|
||||
checkpointer=memory, # сохраняем историю в памяти
|
||||
)
|
||||
|
||||
# ---------- 4. Чат‑цикл ----------
|
||||
def main():
|
||||
print("🤖 Агент готов! Введите запрос (или 'exit' для выхода).")
|
||||
while True:
|
||||
user_input = input("\nВы: ")
|
||||
if user_input.lower() in {"exit", "quit"}:
|
||||
break
|
||||
|
||||
# Запускаем потоковый ответ
|
||||
for chunk in agent.stream(
|
||||
{"messages": [{"role": "human", "content": user_input}]},
|
||||
stream_mode=["messages", "updates"],
|
||||
):
|
||||
chunk_type, data = chunk
|
||||
|
||||
if chunk_type == "messages":
|
||||
msg: AIMessage | HumanMessage | SystemMessage = data
|
||||
# выводим только текст (без tool_calls)
|
||||
if hasattr(msg, "content") and msg.content:
|
||||
print(msg.content, end="", flush=True)
|
||||
|
||||
elif chunk_type == "updates":
|
||||
# Обрабатываем вызовы инструментов и подтверждения
|
||||
for update in data:
|
||||
if "tool_calls" in update:
|
||||
# Выводим запрос к пользователю о подтверждении
|
||||
tool_name = update["tool_calls"][0]["name"]
|
||||
args = update["tool_calls"][0]["args"]
|
||||
print(f"\n\n⚠️ Нужно вызвать инструмент: {tool_name}({args})")
|
||||
decision = input("Разрешить? (y/n): ").strip().lower()
|
||||
if decision == "y":
|
||||
# Продолжаем выполнение, передавая решение
|
||||
agent.invoke(
|
||||
{"messages": [{"role": "human", "content": user_input}]},
|
||||
config={"configurable": {"thread_id": "chat-1"}},
|
||||
)
|
||||
else:
|
||||
print("⚠️ Вызов инструмента отклонён.")
|
||||
# Можно завершить цикл, если не нужно продолжать
|
||||
break
|
||||
|
||||
print("\n\n--- Конец ответа ---")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user