feat: solution for task-003
This commit is contained in:
@@ -29,7 +29,7 @@ memory = MemorySaver()
|
|||||||
agent = create_agent(
|
agent = create_agent(
|
||||||
model=llm,
|
model=llm,
|
||||||
tools=tools,
|
tools=tools,
|
||||||
system_prompt="Ты полезный помощкиник. Если пользователь спрашивает о погоде, используй инструмент get_price.",
|
system_prompt="Ты полезный помощмущник. Если пользователь спрашивает о погоде, используй инструмент get_price.",
|
||||||
checkpointer=memory,
|
checkpointer=memory,
|
||||||
interrupt_before=['tools'],
|
interrupt_before=['tools'],
|
||||||
)
|
)
|
||||||
@@ -39,39 +39,32 @@ config = {"configurable": {"thread_id": "chat-session-123"}}
|
|||||||
|
|
||||||
def ask_and_run(user_input, config):
|
def ask_and_run(user_input, config):
|
||||||
"""Основная функция обработки сообщений и управления циклом подтверждения."""
|
"""Основная функция обработки сообщений и управления циклом подтверждения."""
|
||||||
|
|
||||||
# Если user_input is None, мы просто продолжаем выполнение (возобновление после паузы)
|
# Если user_input is None, мы просто продолжаем выполнение (возобновление после паузы)
|
||||||
input_payload = {"messages": [{"role": "human", "content": user_input}]} if user_input else None
|
# В LangGraph для возобновления через stream передается None или пустой список сообщений
|
||||||
|
stream_input = user_input if user_input is not None else []
|
||||||
# stream_mode=['messages', 'updates'] позволяет обрабатывать и токены, и изменения состояния
|
|
||||||
stream = agent.stream(input_payload, config=config, stream_mode=['messages', 'updates'])
|
|
||||||
|
|
||||||
|
# Используем stream_mode=['messages', 'updates'] согласно заданию
|
||||||
try:
|
try:
|
||||||
for chunk in stream:
|
for chunk in agent.stream(stream_input, config=config, stream_mode=['messages', 'updates']):
|
||||||
chunk_type, chunk_data = chunk
|
|
||||||
state = agent.get_state(config)
|
state = agent.get_state(config)
|
||||||
|
chunk_type, chunk_data = chunk
|
||||||
|
|
||||||
if chunk_type == 'messages':
|
if chunk_type == 'messages':
|
||||||
# Потоковый вывод текста (токены)
|
# Потоковый вывод токенов (сообщений)
|
||||||
# В новых версиях LangGraph/LangChain чанк сообщения может быть объектом BaseMessage
|
message, metadata = chunk_data
|
||||||
content = ""
|
if hasattr(message, "content") and message.content:
|
||||||
if hasattr(chunk_data, 'content'):
|
print(message.append if hasattr(message, 'append') else message.content, end="", flush=True)
|
||||||
content = chunk_data.content
|
|
||||||
elif isinstance(chunk_data, str):
|
|
||||||
content = chunk_data
|
|
||||||
|
|
||||||
if content:
|
|
||||||
console.print(content, end="", flush=True)
|
|
||||||
|
|
||||||
elif chunk_type == 'updates':
|
elif chunk_type == 'updates':
|
||||||
# Здесь можно обрабатывать обновления узлов, если нужно
|
# Вывод информации об обновлениях (например, вызовы инструментов)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Проверка на прерывание (интеррупт перед инструментом)
|
# Проверка на прерывание перед вызовом инструмента
|
||||||
# В LangGraph при interrupt_before ключ '__interrupt__' появляется в данных чанка
|
|
||||||
if '__interrupt__' in chunk_data and state.next == ('tools',):
|
if '__interrupt__' in chunk_data and state.next == ('tools',):
|
||||||
console.print("\n" + "---" * 10)
|
console.print("\n" + "---" * 15)
|
||||||
|
|
||||||
# Извлекаем информацию о том, какой инструмент вызывается
|
# Извлекаем информацию о том, какой инструмент хочет вызвать агент
|
||||||
last_message = state.values['messages'][-1]
|
last_message = state.values['messages'][-1]
|
||||||
if hasattr(last_message, 'tool_calls') and last_message.tool_calls:
|
if hasattr(last_message, 'tool_calls') and last_message.tool_calls:
|
||||||
tool_call = last_message.tool_calls[0]
|
tool_call = last_message.tool_calls[0]
|
||||||
@@ -81,39 +74,34 @@ def ask_and_run(user_input, config):
|
|||||||
answer = input("Разрешить? (Y/n): ")
|
answer = input("Разрешить? (Y/n): ")
|
||||||
|
|
||||||
if answer.lower().strip() == 'y':
|
if answer.lower().strip() == 'y':
|
||||||
# Рекурсивный вызов с None для продолжения выполнения
|
# Рекурсивный вызов для продолжения без нового сообщения пользователя
|
||||||
ask_and_run(None, config)
|
ask_and_run(None, config)
|
||||||
else:
|
else:
|
||||||
console.print("Отменено")
|
console.print("Отменено")
|
||||||
return # Выход из текущей итерации функции
|
return # Выходим из текущей итерации стрима
|
||||||
|
|
||||||
# Печать переноса строки после завершения стрима (если не было прерывания)
|
|
||||||
if user_input is not None:
|
|
||||||
console.print()
|
|
||||||
|
|
||||||
|
if user_input: # Печать переноса строки только если был новый ввод
|
||||||
|
print()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Обработка ошибок или остановки потока
|
# Если произошла ошибка в процессе стрима (например, при рекурсии), пробрасываем её выше
|
||||||
pass
|
raise e
|
||||||
|
|
||||||
def main():
|
if __name__ == "__main__":
|
||||||
console.print("[bold blue]Чат запущен. Напишите 'exit' для выхода.[/bold blue]")
|
console.print("[bold blue]Чат запущен. Напишите 'exit' для выхода.[/bold blue]")
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
user_text = input("\nВы: ")
|
user_text = input("\nВы: ")
|
||||||
if user_text.lower().strip() == 'exit':
|
if user_text.lower().strip() == 'exit':
|
||||||
console.print("До свидания!")
|
|
||||||
break
|
break
|
||||||
|
|
||||||
# Запуск агента с новым сообщением
|
# Формируем входные данные для агента
|
||||||
ask_and_run(
|
input_payload = {"messages": [{"role": "human", "content": user_text}]}
|
||||||
{"messages": [{"role": "human", "content": user_text}]},
|
|
||||||
config,
|
ask_and_run(input_payload, config)
|
||||||
)
|
|
||||||
except EOFError:
|
except KeyboardInterrupt:
|
||||||
break
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
console.print(f"Ошибка: {e}")
|
console.print(f"[bold red]Ошибка: {e}[/bold red]")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
Reference in New Issue
Block a user