Архитектура агента: Восприятие, Планирование, Действие

50 минут Урок 26

Архитектура агента: Восприятие, Планирование, Действие

Добро пожаловать в шестой модуль курса по Gemini 3 API. До этого момента мы рассматривали модель как мощный, но реактивный инструмент: вы задаете вопрос — получаете ответ. Сегодня мы переходим к созданию автономных агентов.

В отличие от чат-бота, агент не просто генерирует текст. Он взаимодействует с миром. Он способен ставить промежуточные цели, использовать инструменты и корректировать свое поведение на основе полученных результатов. Чтобы построить такую систему, нам нужен надежный архитектурный каркас.

В инженерном сообществе этот каркас часто называют циклом PPA (Perception, Planning, Action) или «Восприятие — Планирование — Действие». Давайте разберем, как реализовать этот цикл, используя возможности Gemini 3.

1. Восприятие (Perception): От сырых данных к состоянию

Первый этап работы любого агента — понять, что происходит вокруг. Для LLM «окружающая среда» — это контекст. Но в случае с Gemini 3, благодаря мультимодальности, понятие контекста значительно расширяется.

Что включает в себя восприятие?

  • Входные данные пользователя: Текст задачи или запроса.
  • История диалога: Что мы уже сделали и обсудили (краткосрочная память).
  • Состояние среды: Результаты выполнения предыдущих функций, содержимое файлов, текущее время или данные с сенсоров (если мы говорим о робототехнике).

Ключевая задача фазы восприятия — Grounding (Заземление). Нам нужно превратить неструктурированный поток данных (лог ошибок, длинный PDF-документ, скриншот интерфейса) в структурированное описание текущего состояния, понятное для планировщика.

Совет эксперта: Не пытайтесь просто «скормить» модели все данные подряд. Используйте системный промпт для структурирования восприятия. Попросите модель явно перечислить, что она «видит» перед тем, как начнет думать.

python
import google.generativeai as genai

# Пример функции восприятия, формирующей контекст
def build_perception_context(user_input, chat_history, tool_outputs):
    """
    Собирает сырые данные в единый промпт для фазы восприятия.
    """
    context = "Current System State:\n"
    
    # Добавляем результаты предыдущих действий (наблюдения)
    if tool_outputs:
        context += "Last Tool Outputs:\n"
        for output in tool_outputs:
            context += f"- {output}\n"
    else:
        context += "No actions taken yet.\n"
        
    # Добавляем историю (Memory)
    context += "\nConversation History:\n"
    for msg in chat_history[-5:]: # Берем последние 5 сообщений для фокуса
        context += f"{msg['role']}: {msg['content']}\n"
        
    # Текущая задача
    context += f"\nUser Request: {user_input}\n"
    
    return context

# Демонстрация
current_state = build_perception_context(
    user_input="Найди ошибки в логах и исправь код.",
    chat_history=[{"role": "user", "content": "Привет"}, {"role": "model", "content": "Привет! Чем помочь?"}],
    tool_outputs=["Error: File 'main.py' not found."]
)

print(current_state)

2. Планирование (Planning): Мозг агента

После того как агент «увидел» ситуацию, он должен решить, что делать. Это самый сложный этап. Если мы просто попросим модель дать ответ, она может начать галлюцинировать. Нам нужно заставить её думать.

Паттерн ReAct (Reason + Act)

Это золотой стандарт в архитектуре агентов. Мы требуем от модели следовать строгому формату:

  1. Thought (Мысль): Модель анализирует текущее состояние и рассуждает о том, что нужно сделать.
  2. Plan (План): Формирование последовательности шагов.
  3. Action (Действие): Выбор конкретного инструмента для выполнения первого шага плана.

Gemini 3 отлично справляется с этим благодаря увеличенному окну контекста и улучшенным способностям к логическим рассуждениям (reasoning). Мы можем использовать Chain of Thought (CoT), чтобы агент явно прописывал свои рассуждения перед вызовом функции.

Важный нюанс: Планирование — это не статичный процесс. Агент должен уметь пересматривать свой план, если действие не принесло ожидаемого результата (например, API вернул ошибку).

python
# Системный промпт, задающий архитектуру ReAct для Gemini
REACT_SYSTEM_PROMPT = """
Ты — автономный агент. Для решения задач ты должен использовать цикл THOUGHT-ACTION-OBSERVATION.

Доступные инструменты:
- search_web(query): Поиск информации в интернете.
- read_file(path): Чтение содержимого файла.
- write_file(path, content): Запись в файл.

ФОРМАТ ОТВЕТА (строго соблюдай):
Thought: Здесь ты рассуждаешь о текущей ситуации и следующем шаге.
Action: {"function_name": "имя_функции", "parameters": {arguments}}

После того как ты получишь результат действия (Observation), повтори цикл.
Если задача решена, выведи:
Final Answer: Твой итоговый ответ.
"""

model = genai.GenerativeModel('gemini-1.5-pro', system_instruction=REACT_SYSTEM_PROMPT)

# Пример того, как модель могла бы сгенерировать план (симуляция)
response_simulation = """
Thought: Пользователь просит найти ошибки в логах. Я вижу в предыдущем наблюдении, что файл 'main.py' не найден. 
Это странно, возможно, я ищу не в той директории. Мне нужно сначала посмотреть список файлов в текущей папке.
Action: {"function_name": "list_directory", "parameters": {"path": "."}}
"""

3. Действие (Action): Использование инструментов

Действие — это момент, когда агент влияет на внешний мир. В экосистеме Gemini это реализуется через механизм Function Calling (Вызов функций).

Агент не выполняет код сам (обычно). Он генерирует структурированный запрос (JSON), который ваше приложение перехватывает, выполняет и возвращает результат.

Жизненный цикл действия:

  1. Выбор: На этапе планирования модель выбирает функцию.
  2. Генерация аргументов: Модель заполняет параметры функции на основе контекста.
  3. Исполнение (Client-side): Ваш Python-скрипт парсит ответ модели, находит нужную Python-функцию и запускает её.
  4. Наблюдение (Observation): Результат выполнения (return value) возвращается обратно в модель как новый кусок контекста.

В Gemini 3 определение инструментов стало нативным. Вы можете передавать список функций прямо в конструктор модели, и она автоматически поймет их сигнатуры и docstrings.

python
# 1. Определение реальных функций (инструментов)
def get_stock_price(ticker: str):
    """Получает текущую цену акции по тикеру."""
    # Имитация API запроса
    return {"price": 150.25, "currency": "USD"} if ticker == "GOOGL" else {"error": "Not found"}

# 2. Регистрация инструментов в Gemini
tools = [get_stock_price]
model = genai.GenerativeModel('gemini-1.5-pro', tools=tools)

# 3. Запуск агента (Цикл Action)
chat = model.start_chat(enable_automatic_function_execution=True)

# В этом режиме библиотека сама выполнит вызов функции и вернет результат модели
response = chat.send_message("Сколько сейчас стоят акции Google? И хватит ли мне 100 долларов, чтобы купить одну?")

# Модель пройдет цикл: 
# Thought -> Call get_stock_price('GOOGL') -> Observation (150.25) -> Thought (150 > 100) -> Final Answer
print(response.text)

Сборка цикла: Main Loop

Теперь объединим все три компонента. Автономный агент — это по сути бесконечный цикл while, который крутится до тех пор, пока не будет достигнуто условие остановки (Final Answer) или не сработает предохранитель (максимальное число шагов).

Типичные проблемы архитектуры:

  • Зацикливание: Агент пытается выполнить одно и то же действие, получая одну и ту же ошибку. Решение: Добавлять ошибки в контекст и просить модель предложить другой путь.
  • Потеря цели: В длинных цепочках агент может забыть изначальный запрос пользователя. Решение: Всегда держать исходный `user_query` в системном промпте или начале контекстного окна.
  • Галлюцинации инструментов: Вызов несуществующих функций. Решение: Строгая типизация и валидация JSON перед исполнением.

Упражнение

Спроектируйте архитектуру 'Исследовательского Агента'.<br><br>1. Определите список из 3-х функций (tools), которые понадобятся агенту для написания краткой биографии исторической личности (например, поиск, чтение Википедии, сохранение текста).<br>2. Напишите Системный Промпт, который заставит агента сначала составить план исследования из 3 пунктов, а затем выполнять их последовательно.

Вопрос

В архитектуре ReAct, что происходит на этапе 'Observation' (Наблюдение)?