From a8dea48a5d538f078af7e7a570c8a5d34c67aa6c 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:26:20 +0000 Subject: [PATCH] add nodes.py --- nodes.py | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 nodes.py diff --git a/nodes.py b/nodes.py new file mode 100644 index 0000000..b861be6 --- /dev/null +++ b/nodes.py @@ -0,0 +1,102 @@ +from langchain_openai import ChatOpenAI +from langchain_core.messages import HumanMessage, SystemMessage +from state import ReflectState + +# Инициализация LLM +llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.7) + +# Промпты для узлов +DRAFT_PROMPT = """Ты — эксперт, который дает краткие, но содержательные ответы. +Ответь на вопрос пользователя в 5-10 предложений. +Будь конкретным, избегай общих фраз и "воды". + +Вопрос: {question}""" + +REFLECT_PROMPT = """Ты — строгий критик, оценивающий качество ответа. +Критерии оценки: +1. Полнота: ответ покрывает все аспекты вопроса +2. Конкретика: есть примеры, детали, точные формулировки +3. Отсутствие воды: нет общих фраз, повторений, лишних слов + +Ответ для оценки: {draft} + +Твой ответ должен быть в формате: +VERDICT: [ok/needs_revision] +CRITIQUE: [2-3 конкретных пункта замечаний или похвала] + +Примеры: +VERDICT: ok +CRITIQUE: Ответ полный, есть примеры, нет воды. + +VERDICT: needs_revision +CRITIQUE: 1. Нет конкретных примеров. 2. Слишком много общих фраз. 3. Не раскрыта разница в контексте MCP.""" + +REWRITE_PROMPT = """Улучши ответ на вопрос, учитывая замечания критика. +Вопрос: {question} +Предыдущая версия: {draft} +Замечания критика: {critique} + +Дай исправленную версию (5-10 предложений), которая: +- Учитывает все замечания +- Становится более полной и конкретной +- Убирает воду +- Сохраняет краткость (5-10 предложений)""" + +def draft_answer(state: ReflectState) -> ReflectState: + """Узел: первичная генерация ответа""" + print(f"\n📝 [Раунд {state['round']}] Генерация черновика...") + + prompt = DRAFT_PROMPT.format(question=state["question"]) + response = llm.invoke([HumanMessage(content=prompt)]) + + new_state = state.copy() + new_state["draft"] = response.content + return new_state + +def reflect(state: ReflectState) -> ReflectState: + """Узел: критическая оценка ответа""" + print(f"🔍 [Раунд {state['round']}] Рефлексия критика...") + + prompt = REFLECT_PROMPT.format(draft=state["draft"]) + response = llm.invoke([HumanMessage(content=prompt)]) + + # Парсим ответ критика + lines = response.content.strip().split('\n') + verdict = "needs_revision" # по умолчанию + critique = response.content + + for line in lines: + if line.startswith("VERDICT:"): + verdict = line.replace("VERDICT:", "").strip().lower() + elif line.startswith("CRITIQUE:"): + critique = line.replace("CRITIQUE:", "").strip() + + # Нормализация вердикта + if verdict not in ["ok", "needs_revision"]: + verdict = "needs_revision" + + new_state = state.copy() + new_state["verdict"] = verdict + new_state["critique"] = critique + + print(f" Вердикт: {verdict.upper()}") + if verdict == "needs_revision": + print(f" Замечания: {critique[:100]}...") + + return new_state + +def rewrite(state: ReflectState) -> ReflectState: + """Узел: переписывание ответа с учетом замечаний""" + print(f"✏️ [Раунд {state['round']}] Переписывание с учетом критики...") + + prompt = REWRITE_PROMPT.format( + question=state["question"], + draft=state["draft"], + critique=state["critique"] + ) + response = llm.invoke([HumanMessage(content=prompt)]) + + new_state = state.copy() + new_state["draft"] = response.content + new_state["round"] = state["round"] + 1 + return new_state \ No newline at end of file