From 93712268acf189f9ffb3033727e192d5421cafb8 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:43:55 +0000 Subject: [PATCH] add --- graph.py | 84 +++++++++++++++++++++++++------------------------------- 1 file changed, 38 insertions(+), 46 deletions(-) diff --git a/graph.py b/graph.py index 51c4839..64c4f6f 100644 --- a/graph.py +++ b/graph.py @@ -1,68 +1,64 @@ from langgraph.graph import StateGraph, START, END -from state import ReflectState -from nodes import generate_answer +from state import BriefState +from nodes import outline_node, research_step_node, synthesize_node -def should_retry(state: ReflectState) -> str: +def should_continue_research(state: BriefState) -> str: """ - Условие: продолжать попытки или завершить - Проверяет наличие ошибки и количество попыток + Условие: продолжать исследование или переходить к синтезу """ - # Если ошибки нет - успех - if state["error"] is None: - print(f"✅ Ответ успешно сгенерирован за {state['round']} попыт(ок/ки)") - return "end" - - # Если есть ошибка и не превышен лимит - повторяем - if state["round"] < state["max_rounds"]: - print(f"🔄 Повторная попытка ({state['round'] + 1}/{state['max_rounds']})...") - return "retry" - - # Превышен лимит - завершаем с ошибкой - print(f"⚠️ Достигнут лимит попыток ({state['max_rounds']}). Последняя ошибка: {state['error']}") - return "end" + if state["step_index"] < len(state["outline"]): + return "continue" + else: + return "synthesize" -def build_retry_graph(max_rounds: int = 3): +def build_research_graph(): """ - Строит граф с retry-логикой через try/except + Строит граф исследовательского агента Структура: - START → generate_answer → should_retry - → (если error None) → END - → (если error и round < max_rounds) → generate_answer (с увеличенным round) - → иначе → END + START → outline → research_step → (пока есть пункты) → research_step → synthesize → END """ - graph = StateGraph(ReflectState) + graph = StateGraph(BriefState) - # Добавляем единственный узел (он же будет вызываться повторно) - graph.add_node("generate_answer", generate_answer) + # Добавляем узлы + graph.add_node("outline", outline_node) + graph.add_node("research_step", research_step_node) + graph.add_node("synthesize", synthesize_node) # Добавляем рёбра - graph.add_edge(START, "generate_answer") + graph.add_edge(START, "outline") + graph.add_edge("outline", "research_step") - # Условное ребро после генерации + # Условное ребро после research_step graph.add_conditional_edges( - "generate_answer", - should_retry, + "research_step", + should_continue_research, { - "retry": "generate_answer", # Петля для повторной попытки - "end": END + "continue": "research_step", # Берём следующий пункт + "synthesize": "synthesize" # Завершаем исследование } ) + # После синтеза завершаем + graph.add_edge("synthesize", END) + return graph.compile() # Пример использования if __name__ == "__main__": + from dotenv import load_dotenv + load_dotenv() + # Создаём граф - app = build_retry_graph(max_rounds=3) + app = build_research_graph() # Входное состояние initial_state = { - "question": "Объясни студенту разницу между tool и resource в MCP", - "draft": "", - "error": None, - "round": 1, - "max_rounds": 3 + "topic": "Как студенту безопасно подключать MCP к LangChain", + "outline": None, + "step_index": 0, + "notes": [], + "final_brief": None } # Запуск @@ -70,10 +66,6 @@ if __name__ == "__main__": # Вывод результата print("\n" + "="*80) - if final_state["error"] is None: - print("✅ ФИНАЛЬНЫЙ ОТВЕТ:") - print("="*80) - print(final_state["draft"]) - else: - print("❌ НЕ УДАЛОСЬ СГЕНЕРИРОВАТЬ КАЧЕСТВЕННЫЙ ОТВЕТ") - print(f"Ошибка: {final_state['error']}") \ No newline at end of file + print("ИТОГОВЫЙ ИССЛЕДОВАТЕЛЬСКИЙ БРИФ") + print("="*80) + print(final_state["final_brief"]) \ No newline at end of file