add graph.py

This commit is contained in:
2026-06-04 16:38:24 +00:00
parent e7ea727947
commit 9d7d80b61a
+54 -41
View File
@@ -1,59 +1,68 @@
from langgraph.graph import StateGraph, START, END from langgraph.graph import StateGraph, START, END
from state import BriefState from state import ReflectState
from nodes import outline_node, research_step_node, synthesize_node from nodes import generate_answer
def should_continue_research(state: BriefState) -> str: def should_retry(state: ReflectState) -> str:
"""Условие: продолжать исследование или переходить к синтезу""" """
if state["step_index"] < len(state["outline"]): Условие: продолжать попытки или завершить
return "continue_research" Проверяет наличие ошибки и количество попыток
else: """
return "synthesize" # Если ошибки нет - успех
if state["error"] is None:
print(f"✅ Ответ успешно сгенерирован за {state['round']} попыт(ок/ки)")
return "end"
def build_research_graph(): # Если есть ошибка и не превышен лимит - повторяем
"""Строит граф исследовательского агента""" if state["round"] < state["max_rounds"]:
# Инициализация графа с состоянием print(f"🔄 Повторная попытка ({state['round'] + 1}/{state['max_rounds']})...")
graph = StateGraph(BriefState) return "retry"
# Добавляем узлы # Превышен лимит - завершаем с ошибкой
graph.add_node("outline", outline_node) print(f"⚠️ Достигнут лимит попыток ({state['max_rounds']}). Последняя ошибка: {state['error']}")
graph.add_node("research_step", research_step_node) return "end"
graph.add_node("synthesize", synthesize_node)
def build_retry_graph(max_rounds: int = 3):
"""
Строит граф с retry-логикой через try/except
Структура:
START → generate_answer → should_retry
→ (если error None) → END
→ (если error и round < max_rounds) → generate_answer (с увеличенным round)
→ иначе → END
"""
graph = StateGraph(ReflectState)
# Добавляем единственный узел (он же будет вызываться повторно)
graph.add_node("generate_answer", generate_answer)
# Добавляем рёбра # Добавляем рёбра
graph.add_edge(START, "outline") graph.add_edge(START, "generate_answer")
graph.add_edge("outline", "research_step")
# Условное ребро после research_step # Условное ребро после генерации
graph.add_conditional_edges( graph.add_conditional_edges(
"research_step", "generate_answer",
should_continue_research, should_retry,
{ {
"continue_research": "research_step", # Цикл по шагам "retry": "generate_answer", # Петля для повторной попытки
"synthesize": "synthesize" "end": END
} }
) )
# После синтеза завершаем
graph.add_edge("synthesize", END)
# Компилируем граф
return graph.compile() return graph.compile()
# Пример использования (для тестирования) # Пример использования
if __name__ == "__main__": if __name__ == "__main__":
from dotenv import load_dotenv
load_dotenv()
# Создаём граф # Создаём граф
app = build_research_graph() app = build_retry_graph(max_rounds=3)
# Входное состояние # Входное состояние
initial_state: BriefState = { initial_state = {
"topic": "Как студенту безопасно подключать MCP к LangChain", "question": "Объясни студенту разницу между tool и resource в MCP",
"outline": None, "draft": "",
"step_index": 0, "error": None,
"notes": [], "round": 1,
"final_brief": None "max_rounds": 3
} }
# Запуск # Запуск
@@ -61,6 +70,10 @@ if __name__ == "__main__":
# Вывод результата # Вывод результата
print("\n" + "="*80) print("\n" + "="*80)
print("ИТОГОВЫЙ ИССЛЕДОВАТЕЛЬСКИЙ БРИФ") if final_state["error"] is None:
print("="*80) print("✅ ФИНАЛЬНЫЙ ОТВЕТ:")
print(final_state["final_brief"]) print("="*80)
print(final_state["draft"])
else:
print("❌ НЕ УДАЛОСЬ СГЕНЕРИРОВАТЬ КАЧЕСТВЕННЫЙ ОТВЕТ")
print(f"Ошибка: {final_state['error']}")