From f32aa6825c0dcc65176892c269f6a635846bf40a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=B4=D0=B5=D0=BB=D0=B8=D0=BD=D0=B0=20=D0=A1=D0=B0?= =?UTF-8?q?=D1=82=D1=82=D0=B0=D1=80=D0=BE=D0=B2=D0=B0?= Date: Thu, 4 Jun 2026 16:27:10 +0000 Subject: [PATCH] add cli.py --- cli.py | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 cli.py diff --git a/cli.py b/cli.py new file mode 100644 index 0000000..03504e0 --- /dev/null +++ b/cli.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +""" +CLI для агента с рефлексией на LangGraph +Демонстрирует цикл: draft → reflect → (rewrite → reflect) → END +""" + +import argparse +import sys +from graph import build_reflection_graph +from state import ReflectState + +DEMO_QUESTION = "Объясни студенту разницу между tool и resource в MCP" + +def run_agent(question: str, max_rounds: int = 2, verbose: bool = True): + """Запускает агента с рефлексией""" + if verbose: + print("\n" + "="*80) + print(f"🤖 ЗАПУСК АГЕНТА С РЕФЛЕКСИЕЙ") + print(f"📋 Вопрос: {question}") + print(f"🔄 Макс. раундов: {max_rounds}") + print("="*80) + + # Создаём граф + app = build_reflection_graph(max_rounds=max_rounds) + + # Состояние + initial_state: ReflectState = { + "question": question, + "draft": "", + "critique": "", + "verdict": "needs_revision", # Начальное значение + "round": 1, + "max_rounds": max_rounds + } + + # Запуск + final_state = app.invoke(initial_state) + + # Вывод + if verbose: + print("\n" + "="*80) + print("✅ ФИНАЛЬНЫЙ РЕЗУЛЬТАТ") + print("="*80) + print(f"📝 Итоговый ответ (раунд {final_state['round']}):") + print("-"*80) + print(final_state["draft"]) + print("-"*80) + + if final_state["verdict"] == "ok": + print("🎉 Ответ одобрен критиком!") + else: + print(f"⚠️ Достигнут лимит раундов ({max_rounds}), но вердикт: {final_state['verdict']}") + + return final_state + +def interactive_mode(): + """Интерактивный режим""" + print("\n🎮 Интерактивный режим агента с рефлексией") + print("Введите 'exit' для выхода\n") + + while True: + question = input("Ваш вопрос: ").strip() + if question.lower() == 'exit': + break + if not question: + continue + + max_rounds = input("Макс. раундов (по умолч. 2): ").strip() + max_rounds = int(max_rounds) if max_rounds.isdigit() else 2 + + run_agent(question, max_rounds, verbose=True) + print("\n" + "─"*80 + "\n") + +def main(): + parser = argparse.ArgumentParser( + description="LangGraph агент с рефлексией и доработкой ответов", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Примеры: + python cli.py --demo # Запуск на демо-вопросе + python cli.py -q "Что такое AI?" # Свой вопрос + python cli.py -q "..." --max-rounds 3 # 3 раунда доработки + python cli.py --interactive # Интерактивный режим + """ + ) + + parser.add_argument("-q", "--question", help="Вопрос для агента") + parser.add_argument("--max-rounds", type=int, default=2, help="Макс. раундов доработки (по умолч. 2)") + parser.add_argument("--demo", action="store_true", help="Запустить демо-вопрос") + parser.add_argument("-i", "--interactive", action="store_true", help="Интерактивный режим") + parser.add_argument("--quiet", action="store_true", help="Тихий режим (только ответ)") + + args = parser.parse_args() + + if args.interactive: + interactive_mode() + elif args.demo or (not args.question): + # Демо-режим + run_agent(DEMO_QUESTION, args.max_rounds, verbose=not args.quiet) + elif args.question: + run_agent(args.question, args.max_rounds, verbose=not args.quiet) + else: + parser.print_help() + +if __name__ == "__main__": + main() \ No newline at end of file