91 lines
4.2 KiB
Python
91 lines
4.2 KiB
Python
Я проанализировал решение и нашел несколько проблем:
|
|
|
|
1. **Главный баг**: Узел `interrupt_node` будет вызывать `interrupt()` снова после возобновления, что создаст бесконечный цикл. Узел должен проверять, является ли это возобновлением (по наличию `human_value` в состоянии).
|
|
|
|
2. **Отсутствие обновления состояния при возобновлении**: При вызове `graph.stream(Command(resume=...))` нужно также обновить состояние через `update`, чтобы `human_value` был сохранен.
|
|
|
|
3. **Команда при возобновлении**: Нужно использовать `Command(resume=..., update=...)` вместо только `Command(resume=...)`.
|
|
|
|
Вот исправленное решение:
|
|
|
|
from typing import TypedDict
|
|
from langgraph.graph import StateGraph, START, END
|
|
from langgraph.types import interrupt, Command
|
|
from langgraph.checkpoint.memory import InMemorySaver
|
|
import questionary
|
|
|
|
# 1. Состояние графа
|
|
class GraphState(TypedDict):
|
|
human_value: str
|
|
foo: str
|
|
|
|
# 2. Узел с прерыванием
|
|
def interrupt_node(state: GraphState) -> Command:
|
|
# Если human_value уже заполнен - это возобновление, возвращаем состояние
|
|
if state.get("human_value"):
|
|
return state
|
|
|
|
# Первое прерывание - запрашиваем подтверждение
|
|
payload = {
|
|
"type": "confirm",
|
|
"question": "Уверены, что хотите продолжить?",
|
|
"allow_responds": ["approve", "reject"]
|
|
}
|
|
return interrupt(payload)
|
|
|
|
# 3. Сборка графа
|
|
def build_graph():
|
|
workflow = StateGraph(GraphState)
|
|
workflow.add_node("interrupt_node", interrupt_node)
|
|
workflow.add_edge(START, "interrupt_node")
|
|
workflow.add_edge("interrupt_node", END)
|
|
return workflow.compile(checkpointer=InMemorySaver())
|
|
|
|
# 4. Запуск с обработкой прерывания
|
|
def run():
|
|
graph = build_graph()
|
|
config = {"configurable": {"thread_id": "1"}}
|
|
|
|
# Начальное состояние
|
|
initial_state = {"human_value": "", "foo": "начальное значение"}
|
|
|
|
# Запускаем граф
|
|
for chunk in graph.stream(initial_state, config):
|
|
if "__interrupt__" in chunk:
|
|
# Обработка прерывания
|
|
interrupt_value = chunk["__interrupt__"][0].value
|
|
print(f"!!! Прерывание !!!")
|
|
print(f"Вопрос: {interrupt_value['question']}")
|
|
print(f"Варианты: {interrupt_value['allow_responds']}")
|
|
|
|
# Получаем ответ пользователя
|
|
answer = questionary.select(
|
|
interrupt_value["question"],
|
|
choices=interrupt_value["allow_responds"],
|
|
qmark=">"
|
|
).ask()
|
|
|
|
print(f"> Получен ответ: {answer}")
|
|
|
|
# Возобновляем выполнение с обновлением состояния
|
|
for chunk in graph.stream(
|
|
Command(resume=interrupt_value, update={"human_value": answer}),
|
|
config
|
|
):
|
|
print(chunk)
|
|
else:
|
|
print(chunk)
|
|
|
|
# Итоговое состояние
|
|
final_state = graph.get_state(config).values
|
|
print("\nИтоговое состояние:", final_state)
|
|
|
|
if __name__ == "__main__":
|
|
run()
|
|
|
|
**Что исправлено**:
|
|
1. Узел `interrupt_node` теперь проверяет, заполнено ли `human_value`. Если да — это возобновление, возвращаем состояние без нового прерывания.
|
|
2. При возобновлении используется `Command(resume=interrupt_value, update={"human_value": answer})` для обновления состояния.
|
|
3. Добавлен вывод ответа для лучшей видимости.
|
|
|
|
**APPROVED** |