#!/usr/bin/env python3 """ CLI для исследовательского агента с web search через Tavily Строит бриф: план → пошаговый сбор данных → финальная сводка """ import argparse import sys from dotenv import load_dotenv from graph import build_research_graph from state import BriefState # Загружаем переменные окружения (.env) load_dotenv() # Демо-тема по умолчанию DEMO_TOPIC = "Как студенту безопасно подключать MCP к LangChain" def run_researcher(topic: str, verbose: bool = True): """Запускает исследовательского агента""" if verbose: print("\n" + "="*80) print(f"🔬 ИССЛЕДОВАТЕЛЬСКИЙ АГЕНТ") 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) return final_state def save_brief_to_file(brief: str, filename: str = "research_brief.md"): """Сохраняет бриф в Markdown файл""" 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="Исследовательский агент для создания брифа с web search", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" Примеры: python cli.py --demo # Демо-тема про MCP и LangChain python cli.py -t "Экологичные технологии 2024" # Своя тема python cli.py -t "..." --save report.md # Сохранить в файл python cli.py --interactive # Интерактивный режим """ ) parser.add_argument("-t", "--topic", help="Тема исследования") parser.add_argument("--demo", action="store_true", help="Запустить на демо-теме") parser.add_argument("-i", "--interactive", action="store_true", help="Интерактивный режим") parser.add_argument("-s", "--save", metavar="FILE", help="Сохранить бриф в файл") parser.add_argument("--quiet", action="store_true", help="Тихий режим (только итоговый бриф)") args = parser.parse_args() # Определяем тему topic = None if args.interactive: print("\n🎓 ИНТЕРАКТИВНЫЙ РЕЖИМ") topic = input("Введите тему исследования: ").strip() if not topic: print("❌ Тема не может быть пустой") sys.exit(1) elif args.demo or not args.topic: topic = DEMO_TOPIC if not args.quiet: print(f"\n🎯 Запуск на демо-теме: {topic}") else: topic = args.topic # Запуск исследования try: result = run_researcher(topic, verbose=not args.quiet) # Вывод брифа if args.quiet: print(result["final_brief"]) else: print("\n" + result["final_brief"]) # Сохранение в файл if args.save: save_brief_to_file(result["final_brief"], args.save) elif not args.quiet and not args.save: # Предлагаем сохранить save_option = input("\n💾 Сохранить бриф в файл? (y/n): ").strip().lower() if save_option == 'y': filename = input("Имя файла (по умолч. research_brief.md): ").strip() if not filename: filename = "research_brief.md" save_brief_to_file(result["final_brief"], filename) except KeyboardInterrupt: print("\n\n⚠️ Исследование прервано пользователем") sys.exit(0) except Exception as e: print(f"\n❌ Ошибка: {e}") print("\nУбедитесь, что:") print("1. Установлен TAVILY_API_KEY в .env файле") print("2. Установлен OPENAI_API_KEY в .env файле") print("3. Установлены зависимости: pip install -r requirements.txt") sys.exit(1) if __name__ "__main__": main()