Добавлен agent.py
This commit is contained in:
@@ -1,116 +1,80 @@
|
|||||||
# agent.py
|
# agent.py
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Простой LangChain‑агент с поддержкой потокового вывода через `agent.stream()`.
|
Простой пример агента на LangChain с поддержкой потокового вывода.
|
||||||
Внутри используется один инструмент – get_price, который вызывает под‑агента,
|
Используем только указанный стек:
|
||||||
обрабатывающего запросы к «базе цен».
|
- create_agent из langchain.agents
|
||||||
|
- @tool из langchain.tools
|
||||||
|
- rich.print как rprint
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from langchain.agents import create_agent
|
from langchain.agents import create_agent
|
||||||
from langchain.tools import tool
|
from langchain.tools import tool
|
||||||
from rich import print as rprint
|
from rich import print as rprint
|
||||||
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
# 1. Определяем LLM (Ollama) – это единственный доступный LLM в задании.
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
try:
|
|
||||||
from langchain_ollama import ChatOllama
|
|
||||||
except ImportError: # если Ollama недоступен, используем простой Mock‑LLM
|
|
||||||
class DummyLLM:
|
|
||||||
def __call__(self, *args, **kwargs):
|
|
||||||
return "Mock response"
|
|
||||||
|
|
||||||
llm = DummyLLM()
|
# ------------------------------
|
||||||
else:
|
# Определяем инструменты (tools)
|
||||||
llm = ChatOllama(model="llama3.1") # пример модели
|
# ------------------------------
|
||||||
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
# 2. Создаём инструмент get_price.
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
|
|
||||||
@tool
|
@tool
|
||||||
def get_price(product: str, city: str) -> str:
|
def echo(text: str) -> str:
|
||||||
"""
|
"""
|
||||||
Возвращает таблицу цен на указанный продукт в заданном городе.
|
Простейший инструмент, который просто возвращает переданный текст.
|
||||||
Для демонстрации используется под‑агент, который формирует ответ.
|
|
||||||
"""
|
"""
|
||||||
# Под‑агент – простая функция, которая возвращает строку
|
return f"Echo: {text}"
|
||||||
sub_agent = create_agent(
|
|
||||||
llm=llm,
|
|
||||||
tools=[],
|
|
||||||
verbose=False,
|
|
||||||
agent_type="openai-tools",
|
|
||||||
)
|
|
||||||
|
|
||||||
# Запускаем под‑агента в режиме invoke (т.к. он короткий)
|
|
||||||
result = sub_agent.invoke({
|
|
||||||
"messages": [
|
|
||||||
{"role": "human", "content": f"Сколько стоит {product} в городе {city}?"}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
return result["output"]
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------- #
|
@tool
|
||||||
# 3. Создаём главный агент с инструментом get_price.
|
def add(a: int, b: int) -> int:
|
||||||
# --------------------------------------------------------------------------- #
|
"""
|
||||||
|
Возвращает сумму двух целых чисел.
|
||||||
|
"""
|
||||||
|
return a + b
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------
|
||||||
|
# Создаём агента с инструментами
|
||||||
|
# ------------------------------
|
||||||
|
|
||||||
agent = create_agent(
|
agent = create_agent(
|
||||||
llm=llm,
|
tools=[echo, add],
|
||||||
tools=[get_price],
|
# Можно задать любой шаблон диалога; здесь используем простой
|
||||||
verbose=False,
|
system_message="Ты помощник, который может отвечать и выполнять инструменты.",
|
||||||
agent_type="openai-tools",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# --------------------------------------------------------------------------- #
|
# ------------------------------------
|
||||||
# 4. Функции для форматирования и вывода чанков.
|
# Функция запуска агента в stream‑режиме
|
||||||
# --------------------------------------------------------------------------- #
|
# ------------------------------------
|
||||||
|
|
||||||
step = 1
|
def run_agent(prompt: str):
|
||||||
|
|
||||||
def format_chunk_message(chunk):
|
|
||||||
"""
|
"""
|
||||||
Выводит токен текста без перевода строки.
|
Запускает агента с заданным запросом и выводит результат токен за токеном.
|
||||||
При смене шага печатает разделитель.
|
|
||||||
"""
|
"""
|
||||||
global step
|
# Стартуем потоковый вызов
|
||||||
message, meta = chunk
|
|
||||||
if meta["langgraph_step"] != step:
|
|
||||||
step = meta["langgraph_step"]
|
|
||||||
rprint("\n--- --- ---\n")
|
|
||||||
if message.content:
|
|
||||||
print(message.content, end="", flush=True)
|
|
||||||
|
|
||||||
def format_message(message):
|
|
||||||
"""
|
|
||||||
Форматирует сообщение для вывода в режиме invoke.
|
|
||||||
"""
|
|
||||||
if message.content:
|
|
||||||
return message.content
|
|
||||||
# Если нет content – это вызов инструмента
|
|
||||||
tool_call = message.tool_calls[0]
|
|
||||||
return f"{tool_call['name']}({tool_call['args']})"
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
# 5. Запускаем потоковый вывод.
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
# Пример запроса к агенту
|
|
||||||
stream = agent.stream(
|
stream = agent.stream(
|
||||||
{
|
{"messages": [{"role": "human", "content": prompt}]},
|
||||||
"messages": [
|
|
||||||
{"role": "human", "content": "Покажи мне цены на молоко и хлеб в Казани."}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
stream_mode=["messages", "updates"],
|
stream_mode=["messages", "updates"],
|
||||||
)
|
)
|
||||||
|
|
||||||
for chunk in stream:
|
# Перебираем события из потока и печатаем их в реальном времени
|
||||||
chunk_type, chunk_data = chunk
|
for event in stream:
|
||||||
if chunk_type == "messages":
|
if isinstance(event, dict):
|
||||||
format_chunk_message(chunk_data)
|
# В режиме 'updates' событие может быть словарём с информацией о шаге
|
||||||
elif chunk_type == "updates":
|
rprint(f"[bold cyan]Update:[/bold cyan] {event}")
|
||||||
# При завершении шага выводим итоговое сообщение
|
else:
|
||||||
if chunk_data.get("model"):
|
# В режиме 'messages' это строка‑токен
|
||||||
last_msg = chunk_data["model"]["messages"][-1]
|
rprint(event, end="", flush=True)
|
||||||
rprint("\n" + format_message(last_msg) + "\n")
|
|
||||||
|
rprint("\n[green]--- Конец ответа ---[/green]")
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------
|
||||||
|
# Пример использования (можно удалить)
|
||||||
|
# ------------------------------
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sample_prompt = (
|
||||||
|
"Привет! Скажи мне сумму 7 и 5, а потом эхо 'Hello World'."
|
||||||
|
)
|
||||||
|
run_agent(sample_prompt)
|
||||||
Reference in New Issue
Block a user