109 lines
4.0 KiB
Python
109 lines
4.0 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
CLI для исследовательского агента с Tavily поиском
|
|
Демонстрирует: план → пошаговый сбор информации → итоговый бриф
|
|
"""
|
|
|
|
import argparse
|
|
import sys
|
|
from dotenv import load_dotenv
|
|
from graph import build_research_graph
|
|
from state import BriefState
|
|
|
|
# Загружаем переменные окружения
|
|
load_dotenv()
|
|
|
|
DEMO_TOPIC = "Как студенту безопасно подключать MCP к LangChain"
|
|
|
|
def run_researcher(topic: str, verbose: bool = True):
|
|
"""Запускает исследовательского агента"""
|
|
if verbose:
|
|
print("\n" + "="*80)
|
|
print(f"🔬 ИССЛЕДОВАТЕЛЬСКИЙ АГЕНТ (с Tavily поиском)")
|
|
print(f"📚 Тема: {topic}")
|
|
print("="*80)
|
|
|
|
# Создаём граф
|
|
app = build_research_graph()
|
|
|
|
# Состояние
|
|
initial_state: BriefState = {
|
|
"topic": topic,
|
|
"outline": None,
|
|
"step_index": 0,
|
|
"notes": [],
|
|
"final_brief": None
|
|
}
|
|
|
|
# Запуск (с потоковым выводом)
|
|
if verbose:
|
|
print("\n🔄 Ход выполнения:")
|
|
|
|
final_state = app.invoke(initial_state)
|
|
|
|
# Вывод результата
|
|
if verbose:
|
|
print("\n" + "="*80)
|
|
print("📄 РЕЗУЛЬТАТ ИССЛЕДОВАНИЯ")
|
|
print("="*80)
|
|
print(final_state["final_brief"])
|
|
print("\n" + "="*80)
|
|
print(f"✅ Исследование завершено! Собрано {len(final_state['notes'])} заметок.")
|
|
|
|
return final_state
|
|
|
|
def save_brief_to_file(brief: str, filename: str = "research_brief.md"):
|
|
"""Сохраняет бриф в файл"""
|
|
try:
|
|
with open(filename, 'w', encoding='utf-8') as f:
|
|
f.write(brief)
|
|
print(f"📁 Бриф сохранён в файл: {filename}")
|
|
except Exception as e:
|
|
print(f"⚠️ Ошибка сохранения: {e}")
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="LangGraph исследовательский агент с Tavily поиском",
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
epilog="""
|
|
Примеры:
|
|
python cli.py --demo # Запуск на демо-теме
|
|
python cli.py -t "Использование Docker" # Своя тема
|
|
python cli.py -t "..." --save brief.md # Сохранить бриф в файл
|
|
"""
|
|
)
|
|
|
|
parser.add_argument("-t", "--topic", help="Тема исследования")
|
|
parser.add_argument("--demo", action="store_true", help="Запустить демо-тему")
|
|
parser.add_argument("--save", metavar="FILENAME", help="Сохранить бриф в файл")
|
|
parser.add_argument("--quiet", action="store_true", help="Тихий режим (только бриф)")
|
|
|
|
args = parser.parse_args()
|
|
|
|
# Выбираем тему
|
|
if args.demo or (not args.topic):
|
|
topic = DEMO_TOPIC
|
|
else:
|
|
topic = args.topic
|
|
|
|
# Запускаем исследование
|
|
try:
|
|
result = run_researcher(topic, verbose=not args.quiet)
|
|
|
|
# Сохраняем если нужно
|
|
if args.save and result["final_brief"]:
|
|
save_brief_to_file(result["final_brief"], args.save)
|
|
|
|
except KeyboardInterrupt:
|
|
print("\n\n⚠️ Исследование прервано пользователем")
|
|
sys.exit(1)
|
|
except Exception as e:
|
|
print(f"\n❌ Критическая ошибка: {e}")
|
|
print("Убедитесь, что:")
|
|
print("1. Установлены все зависимости (pip install -r requirements.txt)")
|
|
print("2. Задан TAVILY_API_KEY в .env файле")
|
|
print("3. Задан OPENAI_API_KEY в .env файле")
|
|
sys.exit(1)
|
|
|
|
if __name__ "__main__":
|
|
main() |