From 1082a43183580d354db27f3994ea7af006c110e6 Mon Sep 17 00:00:00 2001 From: lonpatovaadelina Date: Thu, 28 May 2026 10:37:43 +0000 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20client.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client.py | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 client.py diff --git a/client.py b/client.py new file mode 100644 index 0000000..f4a5bbe --- /dev/null +++ b/client.py @@ -0,0 +1,120 @@ +# client.py + +""" +Интерактивный CLI для LangChain‑агента с потоковым выводом. +Используем только стек из условия: + - langchain.agents.create_agent + - langchain.tools.tool + - langchain_ollama.ChatOllama + - rich.print (rprint) +""" + +from langchain.agents import create_agent +from langchain.tools import tool +from langchain_ollama import ChatOllama +from rich import print as rprint + +# ------------------------------------------------------------------ +# 1. Определяем LLM‑обёртку – Ollama +# ------------------------------------------------------------------ +llm = ChatOllama(model="llama3") # модель, которую можно заменить + +# ------------------------------------------------------------------ +# 2. Создаём инструмент get_price +# В реальном проекте он бы вызывал подагент или API, +# здесь просто возвращаем фиктивную таблицу. +# ------------------------------------------------------------------ +@tool("get_price", "Получить цену товара в указанном городе") +def get_price(product: str, city: str) -> str: + """ + Возвращает таблицу с ценой продукта в заданном городе. + """ + # В реальном коде здесь могла бы быть логика обращения к API + return f"| Продукт | Цена (руб.) | Магазин |\n| {product} | 89 | Магнит |" + +# ------------------------------------------------------------------ +# 3. Создаём агента, который использует LLM и инструмент get_price +# ------------------------------------------------------------------ +agent = create_agent( + llm=llm, + tools=[get_price], + verbose=False, # будем выводить вручную +) + +# ------------------------------------------------------------------ +# 4. Функции форматирования чанков +# ------------------------------------------------------------------ +def format_message(message) -> str: + """ + Форматируем сообщение для вывода. + Если в сообщении есть content – возвращаем его, + иначе (tool call) формируем строку вызова инструмента. + """ + if message.content: + return message.content + # Предполагаем, что tool_calls содержит один элемент + tc = message.tool_calls[0] + name = tc["name"] + args = tc.get("args", {}) + return f"{name}({args})" + +def format_chunk_message(chunk): + """ + Выводим токен текста в режиме stream. + При смене шага выводим разделитель. + """ + global step + message, meta = chunk + if meta["langgraph_step"] != step: + step = meta["langgraph_step"] + rprint("\n--- --- ---\n") + if message.content: + # flush=False – чтобы не добавлять перевод строки после каждого токена + print(message.content, end="", flush=True) + +# ------------------------------------------------------------------ +# 5. Основной цикл CLI +# ------------------------------------------------------------------ +def main(): + """ + Запускаем интерактивный режим: пользователь вводит запрос, + агент отвечает в режиме stream. + """ + rprint("[bold cyan]LangChain Stream‑Agent[/bold cyan]") + rprint("Введите ваш вопрос (Ctrl+C для выхода):") + while True: + try: + user_input = input("\n> ") + except KeyboardInterrupt: + rprint("\n[red]Выход из программы.[/red]") + break + + if not user_input.strip(): + continue + + # Запускаем потоковый вывод + stream = agent.stream( + {"messages": [{"role": "human", "content": user_input}]}, + stream_mode=["messages", "updates"], + ) + + step = 1 # номер текущего шага агента + + for chunk in stream: + chunk_type, chunk_data = chunk + + if chunk_type == "messages": + format_chunk_message(chunk_data) + + elif chunk_type == "updates": + # При завершении шага выводим итоговое сообщение + model_update = chunk_data.get("model") + if model_update: + last_msg = model_update["messages"][-1] + rprint("\n" + format_message(last_msg)) + + # После завершения потока добавляем перевод строки для следующего запроса + print() + +if __name__ == "__main__": + main() \ No newline at end of file