Оценка агентов с помощью ADK

1. Разрыв доверия

Момент вдохновения

Вы создали агента службы поддержки клиентов . Он работает на вашем компьютере. Но вчера он сообщил клиенту, что умные часы, которых нет в наличии, доступны, или, что ещё хуже, привиделся ему вариант с политикой возврата. Как вы можете спать по ночам, зная, что ваш агент работает?

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

обслуживание клиентов

Что мы на самом деле оцениваем?

Оценка агента сложнее, чем стандартная оценка LLM. Вы оцениваете не только эссе (окончательный ответ), но и математику (логику/инструменты, использованные для достижения результата).

диаграмма оценки

  1. Траектория (процесс): Использовал ли агент нужный инструмент в нужное время? Вызвал ли он check_inventory перед place_order ?
  2. Окончательный ответ (выход): является ли ответ правильным, вежливым и основанным на данных?

Жизненный цикл разработки

В этой лабораторной работе мы рассмотрим профессиональный жизненный цикл тестирования агентов:

  1. Локальный визуальный осмотр (веб-интерфейс ADK): ручное общение и проверка логики (шаг 1).
  2. Модульное/регрессионное тестирование (ADK CLI): локальный запуск определенных тестовых случаев для быстрого выявления ошибок (шаги 3 и 4).
  3. Отладка (устранение неполадок): анализ сбоев и исправление логики подсказок (шаг 5).
  4. Интеграция CI/CD (Pytest): автоматизация тестов в конвейере сборки (шаг 6).

2. Настройка

Для обеспечения работы наших агентов ИИ нам нужны две вещи: проект Google Cloud, который станет основой.

Шаг 1: Включите платежную учетную запись

  • Активируйте свой платёжный аккаунт с 5 долларами на балансе, которые понадобятся вам для развёртывания. Убедитесь, что он связан с вашим аккаунтом Gmail .

Шаг 2: Открытая среда

👉 Нажмите «Активировать Cloud Shell» в верхней части консоли Google Cloud (это значок в форме терминала в верхней части панели Cloud Shell),

альтернативный текст

👉 Нажмите кнопку «Открыть редактор» (она выглядит как открытая папка с карандашом). В окне откроется редактор кода Cloud Shell. Слева вы увидите проводник. альтернативный текст

👉Откройте терминал в облачной IDE, альтернативный текст

👉💻 В терминале убедитесь, что вы уже аутентифицированы и что проекту присвоен ваш идентификатор проекта, с помощью следующей команды:

gcloud auth list

👉💻 Клонируйте bootstrap-проект с GitHub:

git clone https://github.com/cuppibla/adk_eval_starter

👉💻 Запустите скрипт установки из каталога проекта.

⚠️ Примечание по идентификатору проекта: скрипт предложит случайно сгенерированный идентификатор проекта по умолчанию. Нажмите Enter , чтобы принять это значение по умолчанию.

Однако, если вы предпочитаете создать конкретный новый проект , вы можете ввести желаемый идентификатор проекта, когда скрипт предложит это сделать.

cd ~/adk_eval_starter
./init.sh

Скрипт автоматически выполнит остальную часть процесса настройки.

👉 Важный шаг после завершения: после завершения скрипта необходимо убедиться, что ваша Google Cloud Console отображает правильный проект:

  1. Перейдите на console.cloud.google.com .
  2. Нажмите на раскрывающийся список выбора проекта в верхней части страницы.
  3. Нажмите вкладку «Все» (так как новый проект может еще не появиться в разделе «Недавние»).
  4. Выберите идентификатор проекта, который вы только что настроили на шаге init.sh

03-05-project-all.png

👉💻 Установите необходимый идентификатор проекта:

gcloud config set project $(cat ~/project_id.txt) --quiet

Настройка разрешения

👉💻 Включите необходимые API с помощью следующей команды. Это может занять несколько минут.

gcloud services enable \
    cloudresourcemanager.googleapis.com \
    servicenetworking.googleapis.com \
    run.googleapis.com \
    cloudbuild.googleapis.com \
    artifactregistry.googleapis.com \
    aiplatform.googleapis.com \
    compute.googleapis.com

👉💻 Предоставьте необходимые разрешения, выполнив следующие команды в терминале:

. ~/adk_eval_starter/set_env.sh

Обратите внимание, что для вас создан файл .env , содержащий информацию о вашем проекте.

3. Создание золотого набора данных (adk web)

золотой

Прежде чем оценивать агента, нам нужен ключ с ответами. В ADK мы называем это «золотым набором данных ». Этот набор данных содержит «идеальные» взаимодействия, которые служат эталоном для оценки.

Что такое золотой набор данных?

Золотой набор данных — это моментальный снимок корректной работы вашего агента. Это не просто список пар «вопрос-ответ». Он фиксирует:

  • Запрос пользователя («Я хочу вернуть деньги»)
  • Траектория (точная последовательность вызовов инструмента: check_order -> verify_eligibility -> refund_transaction ).
  • Окончательный ответ («идеальный» текстовый ответ).

Мы используем это для обнаружения регрессий . Если вы обновите запрос, и агент внезапно перестанет проверять право на возврат средств, тест Golden Dataset завершится неудачей, поскольку траектория перестанет совпадать.

Откройте веб-интерфейс

Веб-интерфейс ADK обеспечивает интерактивный способ создания этих «золотых» наборов данных путем фиксации реальных взаимодействий с вашим агентом.

👉 В терминале выполните:

cd ~/adk_eval_starter
uv run adk web

👉 Откройте предварительный просмотр веб-интерфейса (обычно по адресу http://127.0.0.1:8000 ).

👉 В интерфейсе чата введите

Hi, I'm customer CUST001. Can you check my orders? I need a refund for order ORD-102. It arrived damaged.

результат оценки adk

Вы увидите ответ вроде:

I've processed your refund for order ORD-102 due to the items arriving damaged. A full refund of $35.0 has been processed, and the status of order ORD-102 is now updated to "refunded".

Is there anything else I can assist you with today, CUST001? 🛍️

Захватите золотые взаимодействия

Перейдите на вкладку «Сеансы» . Здесь вы можете просмотреть историю разговоров с вашим агентом, нажав на нужный сеанс.

  1. Взаимодействуйте со своим агентом, чтобы создать идеальный ход беседы, например, для проверки истории покупок или запроса возврата средств.
  2. Пересмотрите разговор, чтобы убедиться, что он соответствует ожидаемому поведению.

трассировка оценки

4. Экспортируйте золотой набор данных

Проверить с помощью Trace View

Перед экспортом необходимо убедиться, что агент не получил правильный ответ случайно. Необходимо проверить внутреннюю логику.

  1. Откройте вкладку «Трассировка» в веб-интерфейсе.
  2. Треки автоматически группируются по сообщениям пользователя. Наведите курсор на строку трека, чтобы выделить соответствующее сообщение в чате.
  3. Проверьте синие строки : они отображают события, возникшие в результате взаимодействия. Щелкните синюю строку, чтобы открыть панель проверки.
  4. Проверьте следующие вкладки для проверки логики:
    • График : Визуальное представление вызовов инструментов и логической последовательности. Верный ли путь?
    • Запрос/Ответ : Просмотрите, что именно было отправлено модели и что было возвращено.
    • Проверка : Если агент угадал сумму возврата, не вызывая инструмент базы данных, это «счастливая галлюцинация». оценка проверить

Добавить сеанс в EvalSet

Если вы удовлетворены беседой и трассировкой: 👉 Нажмите вкладку Eval , затем нажмите кнопку Create Evaluation Set , а затем введите имя оценки:

evalset1

набор оценок

👉 В этом наборе оценок нажмите Add current session to evalset1 и во всплывающем окне введите имя сеанса:

eval1

eval создать

Запустить Eval в ADK Web

👉 В веб-интерфейсе ADK нажмите Run Evaluation , во всплывающем окне настройте метрики и нажмите Start :

запустить оценку

Проверьте набор данных в вашем репозитории

Вы увидите подтверждение того, что файл набора данных (например, evalset1.evalset.json ) сохранён в вашем репозитории. Этот файл содержит необработанную, автоматически сгенерированную трассировку вашего разговора.

сохранить набор eval

5. Оценочные файлы

файл оценки

Хотя веб-интерфейс генерирует сложный файл .evalset.json , нам часто требуется создать более чистый и структурированный тестовый файл для автоматизированного тестирования.

ADK Eval использует два основных компонента:

  1. Тестовые файлы : могут быть автоматически сгенерированным золотым набором данных (например, customer_service_agent/evalset1.evalset.json ) или вручную подобранным набором (например, customer_service_agent/eval.test.json ).
  2. Файлы конфигурации (например, customer_service_agent/test_config.json ): определяют метрики и пороговые значения для прохождения.

Настройте тестовый конфигурационный файл

👉 Откройте customer_service_agent/test_config.json в вашем редакторе.

Введите следующий код:

{
  "criteria": {
    "tool_trajectory_avg_score": 0.8,
    "response_match_score": 0.5
  }
}

Расшифровка метрик

  1. tool_trajectory_avg_score (Процесс) Этот параметр измеряет, правильно ли агент использовал инструменты.
  • 0.8 : Мы требуем 80% соответствия.
  1. response_match_score (Выходные данные) Здесь используется ROUGE-1 (совпадение слов) для сравнения ответа с золотым эталоном.
  • Плюсы : Быстро, детерминировано, бесплатно.
  • Минусы : не срабатывает, если агент формулирует одну и ту же идею по-разному (например, «Возврат денег» вместо «Деньги возвращены»).

Расширенные показатели (когда вам нужна большая мощность)

6. Выполнить оценку для золотого набора данных (adk eval)

внутренний цикл

Этот шаг представляет собой «внутренний цикл» разработки. Вы — разработчик, вносящий изменения, и вам нужно быстро проверить результаты.

Запустить золотой набор данных

Давайте запустим набор данных, созданный вами на шаге 1. Это обеспечит надежность вашей базовой линии.

👉 В терминале выполните:

cd ~/adk_eval_starter
uv run adk eval customer_service_agent customer_service_agent/evalset1.evalset.json --config_file_path=customer_service_agent/test_config.json --print_detailed_results

Что происходит?

ADK сейчас:

  1. Загрузка вашего агента из customer_service_agent .
  2. Выполнение входных запросов из evalset1.evalset.json .
  3. Сравнение фактической траектории движения агента и его реакций с ожидаемыми.
  4. Оценка результатов на основе критериев, указанных в test_config.json .

Проанализируйте результаты

Посмотрите на вывод терминала. Вы увидите сводку пройденных и проваленных тестов.

Eval Run Summary
evalset1:
  Tests passed: 1
  Tests failed: 0
********************************************************************
Eval Set Id: evalset1
Eval Id: eval1
Overall Eval Status: PASSED
---------------------------------------------------------------------
Metric: tool_trajectory_avg_score, Status: PASSED, Score: 1.0, Threshold: 0.8
---------------------------------------------------------------------
Metric: response_match_score, Status: PASSED, Score: 0.5581395348837208, Threshold: 0.5
---------------------------------------------------------------------
Invocation Details:
+----+---------------------------+---------------------------+--------------------------+---------------------------+---------------------------+-----------------------------+------------------------+
|    | prompt                    | expected_response         | actual_response          | expected_tool_calls       | actual_tool_calls         | tool_trajectory_avg_score   | response_match_score   |
+====+===========================+===========================+==========================+===========================+===========================+=============================+========================+
|  0 | Hi, I'm customer CUST001. | Great news! Your refund   | Great news, CUST001! 🎉   | id='adk-051409fe-c230-43f | id='adk-4e9aa570-1cc6-4c3 | Status: PASSED, Score:      | Status: PASSED, Score: |
|    | Can you check my orders?  | for order **ORD-102** has | I've successfully        | 4-a7f1- 5747280fd878'     | c-aa3e- 91dbe113dd4b'     | 1.0                         | 0.5581395348837208     |
|    | I need a refund for order | been successfully         | processed a full refund  | args={'customer_id':      | args={'customer_id':      |                             |                        |
|    | ORD-102. It arrived       | processed due to the item | of $35.0 for your order  | 'CUST001'} name='get_purc | 'CUST001'} name='get_purc |                             |                        |
|    | damaged.                  | arriving damaged. You     | ORD-102 because it       | hase_history'             | hase_history'             |                             |                        |
|    |                           | should see a full refund  | arrived damaged. The     | partial_args=None         | partial_args=None         |                             |                        |
|    |                           | of $35.0 back to your     | status of that order has | will_continue=None id= 'a | will_continue=None        |                             |                        |
|    |                           | original payment method   | been updated to          | dk-8a194cb8-5a82-47ce-a3a | id='adk- dad1b376-9bcc-48 |                             |                        |
|    |                           | shortly. The status of    | "refunded."  Is there    | 7- 3d24551f8c90'          | bb-996f-a30f6ef5b70b'     |                             |                        |
|    |                           | this order has been       | anything else I can      | args={'reason':           | args={'reason':           |                             |                        |
|    |                           | updated to "refunded".    | assist you with today?   | 'damaged', 'order_id':    | 'damaged', 'order_id':    |                             |                        |
|    |                           | Here's your updated       |                          | 'ORD-102'}                | 'ORD-102'}                |                             |                        |
|    |                           | purchase history for      |                          | name='issue_refund'       | name='issue_refund'       |                             |                        |
|    |                           | CUST001: *   **ORD-101**: |                          | partial_args=None         | partial_args=None         |                             |                        |
|    |                           | Wireless Headphones,      |                          | will_continue=None        | will_continue=None        |                             |                        |
|    |                           | delivered on 2023-10-15   |                          |                           |                           |                             |                        |
|    |                           | (Total: $120) *           |                          |                           |                           |                             |                        |
|    |                           | **ORD-102**: USB-C Cable, |                          |                           |                           |                             |                        |
|    |                           | Phone Case, refunded on   |                          |                           |                           |                             |                        |
|    |                           | 2023-11-01 (Total: $35)   |                          |                           |                           |                             |                        |
|    |                           | Is there anything else I  |                          |                           |                           |                             |                        |
|    |                           | can help you with today?  |                          |                           |                           |                             |                        |
|    |                           | 😊                         |                          |                           |                           |                             |                        |
+----+---------------------------+---------------------------+--------------------------+---------------------------+---------------------------+-----------------------------+------------------------+

Примечание: поскольку вы только что сгенерировали это из самого агента, тест должен пройти на 100%. Если тест не пройден, ваш агент недетерминированный (случайный).

7. Создайте свой собственный индивидуальный тест

Хотя автоматически сгенерированные наборы данных — это хорошо, иногда приходится вручную создавать пограничные случаи (например, для состязательных атак или обработки определённых ошибок). Давайте рассмотрим, как eval.test.json позволяет определить «корректность».

Давайте создадим комплексный набор тестов.

Структура тестирования

При написании тестового случая в ADK следуйте этой формуле из трех частей:

  • Настройка ( session_input ) : кто пользователь? (например, user_id , state ). Это изолирует тест.
  • Подсказка ( user_content ) : Что является триггером?

С утверждениями (ожиданиями) :

  • Траектория ( tool_uses ) : Правильно ли он рассчитал? (Логика)
  • Ответ ( final_response ) : Правильный ли ответ? (Качество)
  • Промежуточный уровень ( intermediate_responses ) : Правильно ли говорили субагенты? (Оркестровка)

Напишите набор тестов

👉 Откройте customer_service_agent/eval.test.json в вашем редакторе.

Введите следующий код:

{
  "eval_set_id": "customer_service_eval",
  "name": "Customer Service Agent Evaluation",
  "description": "Evaluation suite for the customer service agent covering product info, purchase history, and refunds.",
  "eval_cases": [
    {
      "eval_id": "product_info_check",
      "session_input": {
        "app_name": "customer_service_agent",
        "user_id": "eval_user_1",
        "state": {}
      },
      "conversation": [
        {
          "invocation_id": "turn_1_product_info",
          "user_content": {
            "role": "user",
            "parts": [
              {
                "text": "Do you have wireless headphones in stock?"
              }
            ]
          },
          "final_response": {
            "role": "model",
            "parts": [
              {
                "text": "Yes, we have wireless headphones in stock! They are priced at $120.00 and feature noise-canceling with a 20-hour battery life. 🎧"
              }
            ]
          },
          "intermediate_data": {
            "tool_uses": [
              {
                "name": "lookup_product_info",
                "args": {
                  "product_name": "wireless headphones"
                }
              }
            ],
            "intermediate_responses": []
          }
        }
      ]
    },
    {
      "eval_id": "purchase_history_check",
      "session_input": {
        "app_name": "customer_service_agent",
        "user_id": "eval_user_2",
        "state": {}
      },
      "conversation": [
        {
          "invocation_id": "turn_1_purchase_history",
          "user_content": {
            "role": "user",
            "parts": [
              {
                "text": "What did I buy recently? My customer ID is CUST001."
              }
            ]
          },
          "final_response": {
            "role": "model",
            "parts": [
              {
                "text": "Here's your recent purchase history for Customer ID CUST001:\n\n*   **Order ORD-101** (October 15, 2023): Wireless Headphones, Status: delivered, Total: $120\n*   **Order ORD-102** (November 1, 2023): USB-C Cable, Phone Case, Status: refunded, Total: $35\n\nLet me know if you have any other questions or need further assistance! 🛍️"
              }
            ]
          },
          "intermediate_data": {
            "tool_uses": [
              {
                "name": "get_purchase_history",
                "args": {
                  "customer_id": "CUST001"
                }
              }
            ],
            "intermediate_responses": []
          }
        }
      ]
    },
    {
      "eval_id": "refund_request",
      "session_input": {
        "app_name": "customer_service_agent",
        "user_id": "eval_user_3",
        "state": {}
      },
      "conversation": [
        {
          "invocation_id": "turn_1_refund",
          "user_content": {
            "role": "user",
            "parts": [
              {
                "text": "I want a refund for order ORD-102 because it was damaged."
              }
            ]
          },
          "final_response": {
            "role": "model",
            "parts": [
              {
                "text": "Your refund for order **ORD-102** due to \"damaged\" has been successfully processed!  Refund amount: **$35.0**. Your order status has been updated to **refunded**. \nIs there anything else I can help you with today? 🛍️"
              }
            ]
          },
          "intermediate_data": {
            "tool_uses": [
              {
                "name": "issue_refund",
                "args": {
                  "order_id": "ORD-102",
                  "reason": "damaged"
                }
              }
            ],
            "intermediate_responses": []
          }
        }
      ]
    }
  ]
}

Деконструкция типов тестов

Мы создали три различных типа тестов. Давайте разберёмся, что оценивает каждый из них и почему.

  1. Тест одного инструмента ( product_info_check )
  • Цель : Проверка базового поиска информации.
  • Ключевое утверждение : Мы проверяем intermediate_data.tool_uses . Мы утверждаем, что вызывается lookup_product_info . Мы утверждаем, что аргумент product_name — это именно «wireless headphones».
  • Почему : Если модель галлюцинирует цену, не вызывая инструмент, тест считается проваленным. Это гарантирует заземление.
  1. Тест на извлечение контекста ( purchase_history_check )
  • Цель : убедиться, что агент может извлекать сущности (CUST001) из пользовательского запроса и передавать их инструменту.
  • Ключевое утверждение : Мы проверяем, что get_purchase_history вызывается с customer_id: "CUST001" .
  • Причина : Распространённый тип сбоя — агент вызывает правильный инструмент, но с нулевым идентификатором. Это обеспечивает точность параметров.
  1. Тест «Действие/Траектория» ( refund_request )
  • Цель : проверка критической операции записи.
  • Ключевое утверждение : Траектория. В более сложном сценарии этот список будет содержать несколько шагов: [verify_order, calculate_refund, issue_refund] . ADK проверяет этот список по порядку .
  • Почему : Для действий, связанных с переводом денег или изменением данных, последовательность так же важна, как и результат. Не стоит возвращать средства без подтверждения.

8. Запуск оценки для пользовательских тестов (adk eval)

внутренний цикл

👉 В терминале выполните:

cd ~/adk_eval_starter
uv run adk eval customer_service_agent customer_service_agent/eval.test.json --config_file_path=customer_service_agent/test_config.json --print_detailed_results

Понимание вывода

Вы должны увидеть результат PASS, подобный этому:

Eval Run Summary
customer_service_eval:
  Tests passed: 3
  Tests failed: 0
********************************************************************
Eval Set Id: customer_service_eval
Eval Id: purchase_history_check
Overall Eval Status: PASSED
---------------------------------------------------------------------
Metric: tool_trajectory_avg_score, Status: PASSED, Score: 1.0, Threshold: 0.8
---------------------------------------------------------------------
Metric: response_match_score, Status: PASSED, Score: 0.5473684210526315, Threshold: 0.5
---------------------------------------------------------------------
Invocation Details:
+----+--------------------------+---------------------------+---------------------------+---------------------------+---------------------------+-----------------------------+------------------------+
|    | prompt                   | expected_response         | actual_response           | expected_tool_calls       | actual_tool_calls         | tool_trajectory_avg_score   | response_match_score   |
+====+==========================+===========================+===========================+===========================+===========================+=============================+========================+
|  0 | What did I buy recently? | Here's your recent        | Looks like your recent    | id=None                   | id='adk-8960eb53-2933-459 | Status: PASSED, Score:      | Status: PASSED, Score: |
|    | My customer ID is        | purchase history for      | orders include: *         | args={'customer_id':      | f-b306- 71e3c069e77e'     | 1.0                         | 0.5473684210526315     |
|    | CUST001.                 | Customer ID CUST001:  *   | **ORD-101 (2023-10-15):** | 'CUST001'} name='get_purc | args={'customer_id':      |                             |                        |
|    |                          | **Order ORD-101**         | Wireless Headphones for   | hase_history'             | 'CUST001'} name='get_purc |                             |                        |
|    |                          | (October 15, 2023):       | $120.00 - Status:         | partial_args=None         | hase_history'             |                             |                        |
|    |                          | Wireless Headphones,      | Delivered 🎧 *   **ORD-102 | will_continue=None        | partial_args=None         |                             |                        |
|    |                          | Status: delivered, Total: | (2023-11-01):** USB-C     |                           | will_continue=None        |                             |                        |
|    |                          | $120 *   **Order          | Cable, Phone Case for     |                           |                           |                             |                        |
|    |                          | ORD-102** (November 1,    | $35.00 - Status: Refunded |                           |                           |                             |                        |
|    |                          | 2023): USB-C Cable, Phone | 📱  Is there anything else |                           |                           |                             |                        |
|    |                          | Case, Status: refunded,   | I can help you with       |                           |                           |                             |                        |
|    |                          | Total: $35  Let me know   | regarding these orders?   |                           |                           |                             |                        |
|    |                          | if you have any other     |                           |                           |                           |                             |                        |
|    |                          | questions or need further |                           |                           |                           |                             |                        |
|    |                          | assistance! 🛍️            |                           |                           |                           |                             |                        |
+----+--------------------------+---------------------------+---------------------------+---------------------------+---------------------------+-----------------------------+------------------------+



********************************************************************
Eval Set Id: customer_service_eval
Eval Id: product_info_check
Overall Eval Status: PASSED
---------------------------------------------------------------------
Metric: tool_trajectory_avg_score, Status: PASSED, Score: 1.0, Threshold: 0.8
---------------------------------------------------------------------
Metric: response_match_score, Status: PASSED, Score: 0.6829268292682927, Threshold: 0.5
---------------------------------------------------------------------
Invocation Details:
+----+----------------------+---------------------------+---------------------------+---------------------------+---------------------------+-----------------------------+------------------------+
|    | prompt               | expected_response         | actual_response           | expected_tool_calls       | actual_tool_calls         | tool_trajectory_avg_score   | response_match_score   |
+====+======================+===========================+===========================+===========================+===========================+=============================+========================+
|  0 | Do you have wireless | Yes, we have wireless     | Yes, we do! 🎧 We have     | id=None                   | id='adk-4571d660-a92b-412 | Status: PASSED, Score:      | Status: PASSED, Score: |
|    | headphones in stock? | headphones in stock! They | noise-canceling wireless  | args={'product_name':     | a-a79e- 5c54f8b8af2d'     | 1.0                         | 0.6829268292682927     |
|    |                      | are priced at $120.00 and | headphones with a 20-hour | 'wireless headphones'} na | args={'product_name':     |                             |                        |
|    |                      | feature noise-canceling   | battery life available    | me='lookup_product_info'  | 'wireless headphones'} na |                             |                        |
|    |                      | with a 20-hour battery    | for $120.                 | partial_args=None         | me='lookup_product_info'  |                             |                        |
|    |                      | life. 🎧                   |                           | will_continue=None        | partial_args=None         |                             |                        |
|    |                      |                           |                           |                           | will_continue=None        |                             |                        |
+----+----------------------+---------------------------+---------------------------+---------------------------+---------------------------+-----------------------------+------------------------+



********************************************************************
Eval Set Id: customer_service_eval
Eval Id: refund_request
Overall Eval Status: PASSED
---------------------------------------------------------------------
Metric: tool_trajectory_avg_score, Status: PASSED, Score: 1.0, Threshold: 0.8
---------------------------------------------------------------------
Metric: response_match_score, Status: PASSED, Score: 0.6216216216216216, Threshold: 0.5
---------------------------------------------------------------------
Invocation Details:
+----+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+-----------------------------+------------------------+
|    | prompt                    | expected_response         | actual_response           | expected_tool_calls       | actual_tool_calls         | tool_trajectory_avg_score   | response_match_score   |
+====+===========================+===========================+===========================+===========================+===========================+=============================+========================+
|  0 | I want a refund for order | Your refund for order     | Your refund for order     | id=None args={'order_id': | id='adk-fb8ff1cc- cf87-41 | Status: PASSED, Score:      | Status: PASSED, Score: |
|    | ORD-102 because it was    | **ORD-102** due to        | **ORD-102** has been      | 'ORD-102', 'reason':      | f2-9b11-d4571b14287f'     | 1.0                         | 0.6216216216216216     |
|    | damaged.                  | "damaged" has been        | successfully processed!   | 'damaged'}                | args={'order_id':         |                             |                        |
|    |                           | successfully processed!   | You should see a full     | name='issue_refund'       | 'ORD-102', 'reason':      |                             |                        |
|    |                           | Refund amount: **$35.0**. | refund of $35.0 appear in | partial_args=None         | 'damaged'}                |                             |                        |
|    |                           | Your order status has     | your account shortly. We  | will_continue=None        | name='issue_refund'       |                             |                        |
|    |                           | been updated to           | apologize for the         |                           | partial_args=None         |                             |                        |
|    |                           | **refunded**.  Is there   | inconvenience! Is there   |                           | will_continue=None        |                             |                        |
|    |                           | anything else I can help  | anything else I can       |                           |                           |                             |                        |
|    |                           | you with today? 🛍️        | assist you with today? 😊  |                           |                           |                             |                        |
+----+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+-----------------------------+------------------------+

Это означает, что ваш агент использовал правильные инструменты и предоставил ответ, в достаточной степени соответствующий вашим ожиданиям.

9. (Необязательно: только для чтения) — устранение неполадок и отладка

Тесты будут падать. Это их работа. Но как их исправить? Давайте проанализируем распространённые сценарии сбоев и способы их отладки.

Сценарий А: провал «Траектории»

Ошибка:

Result: FAILED
Reason: Criteria 'tool_trajectory_avg_score' failed. Score 0.0 < Threshold 1.0
Details:
EXPECTED: tool: lookup_order, then tool: issue_refund
ACTUAL:   tool: issue_refund

Диагноз : Агент пропустил этап проверки (lookup_order). Это логическая ошибка.

Как устранить неполадки :

  • Не гадайте : вернитесь в веб-интерфейс ADK (adk web).
  • Воспроизвести : введите в чат точный текст из неудавшегося теста.
  • Trace : Откройте окно Trace. Посмотрите на вкладку «График».
  • Исправление запроса : Обычно требуется обновить системный запрос. Измените : «Вы — полезный агент». На : «Вы — полезный агент. ВАЖНО: Перед вызовом issue_refund ОБЯЗАТЕЛЬНО вызовите lookup_order для проверки данных.
  • Адаптируйте тест : если бизнес-логика изменилась (например, проверка больше не требуется), то тест неверен. Обновите eval.test.json в соответствии с новыми реалиями.

Сценарий Б: Провал «ROUGE»

Ошибка:

Result: FAILED
Reason: Criteria 'response_match_score' failed. Score 0.45 < Threshold 0.8
Expected: "The refund has been processed successfully."
Actual:   "I've gone ahead and returned the money to your card."

Диагноз : Агент поступил правильно, но использовал другие слова. ROUGE (совпадение слов) наложил штраф.

Как исправить :

  • Неправильно? Если значение верно, не меняйте подсказку.
  • Настройте порог : уменьшите порог в test_config.json (например, с 0.8 до 0.5 ).
  • Обновите метрику : переключитесь на final_response_match_v2 в вашей конфигурации. Она использует LLM для чтения обоих предложений и определения, означают ли они одно и то же.

10. CI/CD с Pytest (pytest)

pytest

Команды CLI предназначены для людей. pytest — для машин. Для обеспечения надёжности в производственной среде мы заключаем наши оценки в набор тестов Python. Это позволяет вашему конвейеру CI/CD (GitHub Actions, Jenkins) блокировать развертывание в случае сбоя работы агента.

Что содержится в этом файле?

Этот файл Python служит связующим звеном между вашим исполнителем CI/CD и оценщиком ADK. Он должен:

  • Загрузите свой агент : динамически импортируйте код своего агента.
  • Сброс состояния : убедитесь, что память агента чиста, чтобы тесты не перетекали друг в друга.
  • Запустить оценку : вызвать AgentEvaluator.evaluate() программно.
  • Подтвердить успешность : если оценка низкая, сборка считается проваленной.

Код интеграционного теста

👉 Откройте customer_service_agent/test_agent_eval.py . Этот скрипт использует AgentEvaluator.evaluate для запуска тестов, определённых в eval.test.json .

👉 Откройте customer_service_agent/test_agent_eval.py в вашем редакторе.

Введите следующий код:

from google.adk.evaluation.agent_evaluator import AgentEvaluator
import pytest
import importlib
import sys
import os

@pytest.mark.asyncio
async def test_with_single_test_file():
    """Test the agent's basic ability via a session file."""
    # Load the agent module robustly
    module_name = "customer_service_agent.agent"
    try:
        agent_module = importlib.import_module(module_name)
        # Reset the mock data to ensure a fresh state for the test
        if hasattr(agent_module, 'reset_mock_data'):
            agent_module.reset_mock_data()
    except ImportError:
        # Fallback if running from a different context
        sys.path.append(os.getcwd())
        agent_module = importlib.import_module(module_name)
        if hasattr(agent_module, 'reset_mock_data'):
            agent_module.reset_mock_data()
    
    # Use absolute path to the eval file to be robust to where pytest is run
    script_dir = os.path.dirname(os.path.abspath(__file__))
    eval_file = os.path.join(script_dir, "eval.test.json")
    
    await AgentEvaluator.evaluate(
        agent_module=module_name,
        eval_dataset_file_path_or_dir=eval_file,
        num_runs=1,
    )

Запустить Pytest

👉 В терминале выполните:

cd ~/adk_eval_starter
uv pip install pytest
uv run pytest customer_service_agent/test_agent_eval.py

Вы увидите такой результат:

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=============== 1 passed, 15 warnings in 12.84s ===============

11. Заключение

Поздравляем! Вы успешно оценили своего специалиста по работе с клиентами с помощью ADK Eval.

Что вы узнали

В этой лабораторной работе вы узнали, как:

  • Создайте золотой набор данных , чтобы обеспечить надежную основу для вашего агента.
  • Понять конфигурацию оценки , чтобы определить критерии успеха.
  • Запускайте автоматизированные оценки для раннего выявления регрессий.

Внедрив ADK Eval в процесс разработки, вы сможете уверенно создавать агенты, зная, что любые изменения в поведении будут обнаружены вашими автоматизированными тестами.