From 95957da305725f4cde03993fc25ff1c12348e9dc Mon Sep 17 00:00:00 2001 From: lonpatovaadelina Date: Tue, 2 Jun 2026 06:07:23 +0000 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=BE=D0=B2=D1=82=D0=BE=D1=80=D0=BD?= =?UTF-8?q?=D1=8B=D0=B9=20=D1=8D=D0=BA=D0=B7=D0=B0=D0=BC=D0=B5=D0=BD:=20?= =?UTF-8?q?=D0=98=D1=81=D1=81=D0=BB=D0=B5=D0=B4=D0=BE=D0=B2=D0=B0=D1=82?= =?UTF-8?q?=D0=B5=D0=BB=D1=8C=D1=81=D0=BA=D0=B8=D0=B9=20=D0=B1=D1=80=D0=B8?= =?UTF-8?q?=D1=84=20(=D0=BF=D0=BB=D0=B0=D0=BD=20=E2=86=92=20=D1=88=D0=B0?= =?UTF-8?q?=D0=B3=D0=B8=20=E2=86=92=20=D1=81=D0=B2=D0=BE=D0=B4=D0=BA=D0=B0?= =?UTF-8?q?):=20solution.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- solution.py | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 solution.py diff --git a/solution.py b/solution.py new file mode 100644 index 0000000..8f6aeb9 --- /dev/null +++ b/solution.py @@ -0,0 +1,106 @@ +import os +from typing import TypedDict, List, Optional, Dict, Any + +from langchain_openai import ChatOpenAI +from langchain_tavily import TavilySearchResults +from langgraph.graph import StateGraph, START, END +from langgraph.prebuilt import ToolNode +from langgraph.prebuilt import create_react_agent +from dotenv import load_dotenv + +load_dotenv() + +# ---------- 1. Состояние ---------- +class BriefState(TypedDict): + topic: str + outline: List[str] | None + step_index: int + notes: List[str] + final_brief: str | None + +# ---------- 2. Инструменты ---------- +search_tool = TavilySearchResults() + +# ---------- 3. Узлы ---------- +def outline_node(state: BriefState) -> Dict[str, Any]: + """Создаёт план из 4–5 пунктов по теме.""" + llm = ChatOpenAI(model="gpt-4o-mini") + prompt = ( + f"Составь план исследования по теме: {state['topic']}. " + "План должен содержать 4–5 пунктов, каждый пункт – заголовок без описания." + ) + plan = llm.invoke(prompt).content.strip() + outline = [line.strip("- ").strip() for line in plan.splitlines() if line.strip()] + return {"outline": outline, "step_index": 0, "notes": []} + +def research_step_node(state: BriefState) -> Dict[str, Any]: + """Для текущего пункта плана делает поиск и формирует заметку.""" + llm = ChatOpenAI(model="gpt-4o-mini") + current_index = state["step_index"] + if state["outline"] is None or current_index >= len(state["outline"]): + return {"step_index": current_index, "notes": state["notes"]} + + topic = state["outline"][current_index] + # Поиск + search_query = f"{state['topic']} - {topic}" + results = search_tool.invoke({"query": search_query}) + # Сводка + summary_prompt = ( + f"Сделай краткую заметку (5–8 предложений) по теме '{topic}'. " + f"Используй найденные источники: {results}" + ) + note = llm.invoke(summary_prompt).content.strip() + notes = state["notes"] + [f"**{topic}**\n{note}"] + return {"step_index": current_index + 1, "notes": notes} + +def synthesize_node(state: BriefState) -> Dict[str, Any]: + """Объединяет все заметки в связный бриф.""" + llm = ChatOpenAI(model="gpt-4o-mini") + combined = "\n\n".join(state["notes"]) + prompt = ( + f"Собери из следующих заметок связный исследовательский бриф (½–1 страница):\n{combined}" + ) + brief = llm.invoke(prompt).content.strip() + return {"final_brief": brief} + +# ---------- 4. Граф ---------- +def build_graph() -> StateGraph[BriefState]: + graph = StateGraph(BriefState) + + # Добавляем узлы + graph.add_node("outline", outline_node) + graph.add_node("research_step", research_step_node) + graph.add_node("synthesize", synthesize_node) + + # Переходы + graph.set_entry_point("outline") + graph.add_edge("outline", "research_step") + graph.add_conditional_edges( + "research_step", + lambda state: "synthesize" if state["step_index"] >= len(state["outline"] or []) else "research_step", + { + "synthesize": "synthesize", + "research_step": "research_step", + }, + ) + graph.add_edge("synthesize", END) + + return graph + +# ---------- 5. Запуск ---------- +if __name__ == "__main__": + topic = input("Введите тему исследования: ").strip() + initial_state: BriefState = { + "topic": topic, + "outline": None, + "step_index": 0, + "notes": [], + "final_brief": None, + } + + graph = build_graph() + chain = graph.compile() + + result = chain.invoke(initial_state) + print("\n=== Итоговый исследовательский бриф ===\n") + print(result["final_brief"]) \ No newline at end of file