Повторный экзамен: Граф с рефлексией и доработкой: solution.py

This commit is contained in:
2026-06-02 16:16:53 +00:00
parent a1ce26b016
commit 4fac263a12
+129
View File
@@ -0,0 +1,129 @@
<|channel|>final code<|message|>import os
from typing import TypedDict, Literal
from langgraph.graph import StateGraph, END
from langchain_openai import ChatOpenAI
# ---------- 1. Состояние ----------
class ReflectState(TypedDict):
question: str
draft: str
critique: str
verdict: Literal["ok", "needs_revision"]
round: int
max_rounds: int
# ---------- 2. Узлы ----------
def draft_answer(state: ReflectState) -> dict:
"""Первичный ответ на вопрос."""
llm = ChatOpenAI(model="gpt-4o-mini")
prompt = f"Напиши краткий ответ (5–10 предложений) на следующий вопрос:\n\n{state['question']}"
response = llm.invoke(prompt)
state["draft"] = response.content.strip()
return {"draft": state["draft"]}
def reflect(state: ReflectState) -> dict:
"""LLM‑критик оценивает ответ."""
llm = ChatOpenAI(model="gpt-4o-mini")
prompt = (
f"Оцени следующий ответ на вопрос \"{state['question']}\":\n\n"
f"{state['draft']}\n\n"
"Дай verdict: ok или needs_revision. "
"Если needs_revision, перечисли 2–3 конкретных замечания."
)
response = llm.invoke(prompt)
text = response.content.strip()
# Разделяем verdict и critique
if "needs_revision" in text:
state["verdict"] = "needs_revision"
parts = text.split("needs_revision", 1)[-1].strip()
state["critique"] = parts
else:
state["verdict"] = "ok"
state["critique"] = ""
return {"verdict": state["verdict"], "critique": state["critique"]}
def rewrite(state: ReflectState) -> dict:
"""Учитываем critique и переписываем ответ."""
llm = ChatOpenAI(model="gpt-4o-mini")
prompt = (
f"Перепиши ответ, учитывая следующие замечания:\n\n"
f"{state['critique']}\n\n"
f"Оригинальный ответ:\n{state['draft']}"
)
response = llm.invoke(prompt)
state["draft"] = response.content.strip()
state["round"] += 1
return {"draft": state["draft"], "round": state["round"]}
# ---------- 3. Граф ----------
builder = StateGraph(ReflectState)
builder.add_node("draft_answer", draft_answer)
builder.add_node("reflect", reflect)
builder.add_node("rewrite", rewrite)
builder.set_entry_point("draft_answer")
builder.add_edge("draft_answer", "reflect")
builder.add_conditional_edges(
"reflect",
lambda x: x["verdict"],
{
"ok": END,
"needs_revision": "rewrite",
},
)
builder.add_edge("rewrite", "reflect")
graph = builder.compile()
# ---------- 4. CLI ----------
def main():
import argparse
parser = argparse.ArgumentParser(description="LangGraph рефлексия")
parser.add_argument(
"--question",
type=str,
required=True,
help="Вопрос, на который нужно ответить.",
)
args = parser.parse_args()
# Инициализируем состояние
state: ReflectState = {
"question": args.question,
"draft": "",
"critique": "",
"verdict": "",
"round": 0,
"max_rounds": 2,
}
# Запускаем граф
result = graph.invoke(state)
# Выводим финальный ответ и логи
print("\n=== Финальный ответ ===")
print(result["draft"])
print("\n=== Лог рефлексии ===")
print(f"Round: {result['round']}")
print(f"Verdict: {result['verdict']}")
if result["critique"]:
print("Critique:")
print(result["critique"])
if __name__ == "__main__":
# Проверяем наличие ключа OpenAI
if "OPENAI_API_KEY" not in os.environ:
raise RuntimeError(
"Пожалуйста, установите переменную окружения OPENAI_API_KEY."
)
main()