Что значит «агент» и почему это важно
Слово «агент» превратилось в маркетинговый термин: агентом называют и простую цепочку промптов, и сложную мультиагентную систему. Из-за этого возникает путаница — непонятно, что строить, где граница между «умным пайплайном» и «настоящим агентом», и почему одно сложнее другого.
Чёткое определение: AI-агент — это программа, которая в цикле воспринимает состояние среды, рассуждает о нём с помощью LLM и предпринимает действия для достижения цели. Три ключевых слова: цикл, рассуждение, действие.
Отличие от простого LLM-вызова: агент не получает один ответ и не останавливается. Он продолжает итерироваться — вызывать инструменты, анализировать результаты, корректировать план — до тех пор, пока цель не достигнута или не превышен лимит итераций.
Chatbot — LLM отвечает на вопросы. Нет инструментов, нет памяти между сессиями, нет целей.
Pipeline — фиксированная цепочка шагов: ввод → шаг 1 → шаг 2 → вывод. Логика жёстко задана разработчиком.
Agent — LLM сам решает, какие инструменты вызывать, в каком порядке и когда остановиться. Логика гибкая, определяется задачей.
Четыре компонента любого агента
Разобрать агента «по запчастям» полезно по той же причине, по которой хирург должен знать анатомию до операции. Каждый компонент отвечает за свою часть работы, имеет свои точки отказа и свои способы оптимизации.
Каждый компонент независим и может быть заменён. Другой LLM, другая память, другие инструменты — цикл управления остаётся тем же. Именно поэтому архитектура важнее выбора конкретного провайдера.
LLM как движок рассуждений
LLM в агенте — это не просто «вызов API». Это единственный компонент, который принимает решения: что делать дальше, какой инструмент вызвать, достаточно ли информации для ответа.
Модель получает на вход весь накопленный контекст — system prompt с инструкциями, историю сообщений, результаты предыдущих инструментов — и возвращает либо финальный ответ (stop_reason: "end_turn"), либо запрос на вызов инструмента (stop_reason: "tool_use").
max_iterations, иначе агент может зациклиться.Качество рассуждений напрямую зависит от system prompt. Именно там задаётся: какова цель агента, какие инструменты доступны и когда их использовать, как форматировать ответы, какие ограничения и границы поведения.
При одном и том же вводе модель может принять разные решения о порядке вызова инструментов. Агент должен корректно работать при любом разумном порядке действий — не рассчитывай на фиксированную последовательность шагов.
Инструменты: как агент действует
Инструменты — это мост между LLM и реальным миром. Сам LLM ничего не «делает»: он только решает, какую функцию вызвать и с какими аргументами. Реальное действие происходит в Python-функции, которую ты пишешь сам.
Каждый инструмент — это пара: JSON Schema (описание для LLM) + Python-функция (реализация). Подробнее о JSON Schema — в уроке «Описание инструментов».
Хорошее правило: один инструмент — одна ответственность. Не делай «универсальный инструмент на все случаи» — LLM хуже справляется с выбором аргументов для перегруженных инструментов.
Память агента: четыре уровня
Без памяти агент «слеп» — каждый запрос начинается с нуля. Именно память превращает набор вызовов API в систему, которая знает пользователя, помнит контекст задачи и учится на результатах.
messages, передаваемый в каждый запрос к LLM. Быстрая, но ограничена контекстным окном. Исчезает после сессии.Для большинства production-агентов достаточно L1 + L2: история в контексте плюс векторный поиск по долгосрочной памяти через pgvector. L3 добавляют, когда агент должен «знать» конкретного пользователя. L4 — для сложных задач с многошаговым планированием.
In-context память растёт с каждым сообщением. При длинных сессиях контекстное окно переполняется. Типичные решения: суммаризация старой истории через LLM, скользящее окно последних N сообщений, или вынос истории в external memory с retrieval по релевантности.
Реактивный цикл управления
Цикл управления — это код, который связывает все четыре компонента. Это обычный while-loop, который работает до тех пор, пока агент не решит остановиться или не превысит лимит итераций.
Одна итерация цикла — это один запрос к LLM плюс все инструменты, которые он запросил в этом ответе. Число итераций = число «раундов» рассуждения. Типичный агент делает от 2 до 10 итераций; больше — повод оптимизировать промпт или декомпозировать задачу.
Минимальный агент на Python
Абстракции понятны — время написать код. Ниже — полный рабочий агент с двумя инструментами, без фреймворков, ~60 строк. Именно так работают LangGraph, AutoGen и другие фреймворки под капотом:
import anthropic
import json
client = anthropic.Anthropic()
# ── Инструменты ──────────────────────────────────────────────
def get_weather(city: str) -> str:
"""Заглушка: в реальности — вызов API."""
return f"В {city} сейчас +18°C, облачно."
def calculate(expression: str) -> str:
"""Безопасный eval для простых арифметических выражений."""
try:
result = eval(expression, {"__builtins__": {}})
return str(result)
except Exception as e:
return f"Ошибка вычисления: {e}"
TOOLS = [
{
"name": "get_weather",
"description": "Получить текущую погоду в городе. Используй когда пользователь спрашивает о погоде.",
"input_schema": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "Название города на русском или английском"}
},
"required": ["city"]
}
},
{
"name": "calculate",
"description": "Вычислить математическое выражение: сложение, умножение, степени и т.д.",
"input_schema": {
"type": "object",
"properties": {
"expression": {"type": "string", "description": "Математическое выражение, например '2 ** 10 + 5'"}
},
"required": ["expression"]
}
}
]
TOOL_FUNCTIONS = {
"get_weather": get_weather,
"calculate": calculate,
}
# ── Цикл управления ──────────────────────────────────────────
def run_agent(user_message: str, max_iterations: int = 10) -> str:
messages = [{"role": "user", "content": user_message}]
for iteration in range(max_iterations):
# THINK: отправляем контекст в LLM
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=1024,
system="Ты полезный ассистент. Используй инструменты когда нужны актуальные данные.",
tools=TOOLS,
messages=messages,
)
# Добавляем ответ модели в историю
messages.append({"role": "assistant", "content": response.content})
# ACT: если модель закончила — возвращаем ответ
if response.stop_reason == "end_turn":
for block in response.content:
if hasattr(block, "text"):
return block.text
return ""
# ACT: выполняем все запрошенные инструменты
tool_results = []
for block in response.content:
if block.type == "tool_use":
fn = TOOL_FUNCTIONS.get(block.name)
result = fn(**block.input) if fn else f"Инструмент {block.name!r} не найден"
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": result,
})
# OBSERVE: добавляем результаты инструментов в контекст
messages.append({"role": "user", "content": tool_results})
return "Достигнут лимит итераций."
# ── Запуск ───────────────────────────────────────────────────
if __name__ == "__main__":
answer = run_agent("Какая погода в Москве? И сколько будет 2 в степени 16?")
print(answer)
Обрати внимание на структуру: цикл for iteration in range(max_iterations), два условия выхода (end_turn и лимит итераций), и то, что результаты инструментов добавляются в messages как сообщение роли user — именно такой формат ожидает Anthropic API.
LangGraph, AutoGen, OpenAI Agents SDK — всё это надстройки над этим же циклом. Они добавляют: граф состояний вместо простого while, checkpointing, параллельные ветки, human-in-the-loop. Но ядро — тот же while: think → act → observe.
Когда нужен агент, когда хватит пайплайна
Агент — не всегда правильный выбор. Он сложнее в отладке, дороже в токенах, менее предсказуем. Вот критерий выбора: если шаги решения можно определить заранее — используй пайплайн. Если нет — нужен агент.
Оборачивать в агента каждый LLM-вызов — антипаттерн. Если задача решается одним промптом — это пайплайн. Агент добавляет сложность, стоимость и непредсказуемость. Используй его только там, где гибкость цикла действительно нужна.
Шпаргалка
Анатомия AI-агента — коротко LLM мозг агента; получает весь контекст; решает что делать; stop_reason = "end_turn" | "tool_use" | "max_tokens" Инструменты Python-функции + JSON Schema; один инструмент = одна задача; типы: информационные / исполнительные / вычислительные / агентские Память L1 in-context (messages list) — быстро, ограничено окном L2 external (pgvector, Redis) — медленно, неограниченно L3 entity facts — структурированные знания L4 scratchpad (CoT) — промежуточные рассуждения Цикл while not done and iterations < MAX: perceive → think (LLM) → act (tools) → observe → repeat Agent vs Pipeline Pipeline — шаги фиксированы, маршрут известен заранее Agent — шаги определяются LLM на основе промежуточных результатов Защита от зацикливания Всегда: max_iterations (обычно 10–20) Всегда: обработка stop_reason != "end_turn" && != "tool_use" Опцион.: timeout на весь цикл агента
Практическое задание
-
Расширь минимального агента. Добавь третий инструмент —
search_memory(query: str), который ищет по заранее заполненному словарю фактов о пользователе (имя, город, предпочтения). Убедись, что агент использует его когда нужен персональный контекст. - Визуализируй итерации. Добавь в цикл вывод в консоль: номер итерации, название вызванного инструмента и его аргументы. Запусти агента с вопросом, который требует 2–3 итерации, и проследи за циклом.
-
Сломай цикл намеренно. Убери ограничение
max_iterationsи создай ситуацию, в которой агент никогда не получит удовлетворительный результат от инструмента (инструмент всегда возвращает «данные недоступны»). Что происходит? Добавь обработку этого случая.