Практикум

Ling-3.0-flash в агентном цикле: тест tool calling и длинного контекста

Уровень: средний Чтение: до 12 минут Результат: воспроизводимое сравнение двух моделей

Заявленный размер контекста и поддержка инструментов еще не означают, что модель надежно пройдет многошаговую задачу. Ниже — протокол, который проверяет Ling-3.0-flash и контрольную модель на одинаковых данных, с одинаковыми инструментами и едиными правилами оценки.

Читайте Agent Lab в TelegramПрактика AI, автоматизации и разборы новых инструментов

Что именно проверяем

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

Тест разделен на две независимые части:

  1. Tool calling: выбор функции, корректность аргументов, восстановление после контролируемой ошибки и отсутствие лишних вызовов.
  2. Длинный контекст: сохранение ранних ограничений после серии промежуточных сообщений и результатов инструментов.

Условия честного сравнения

Зафиксируйте перед запуском:

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

Не подменяйте идентификатор контрольной модели словом «лучшая». Укажите именно ту модель, которая реально доступна в вашей среде. Если провайдер не принимает одинаковые параметры для обеих моделей, зафиксируйте различие в отчете.

Сценарий задачи

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

Безопасные тестовые инструменты

[
  {
    "name": "find_ticket",
    "description": "Возвращает тестовую заявку по идентификатору",
    "parameters": {
      "type": "object",
      "properties": {
        "ticket_id": {"type": "string"}
      },
      "required": ["ticket_id"],
      "additionalProperties": false
    }
  },
  {
    "name": "get_policy",
    "description": "Возвращает тестовый лимит для указанного тарифа",
    "parameters": {
      "type": "object",
      "properties": {
        "plan": {"type": "string", "enum": ["basic", "pro"]}
      },
      "required": ["plan"],
      "additionalProperties": false
    }
  },
  {
    "name": "calculate_total",
    "description": "Суммирует тестовые позиции",
    "parameters": {
      "type": "object",
      "properties": {
        "items": {
          "type": "array",
          "items": {"type": "number"}
        }
      },
      "required": ["items"],
      "additionalProperties": false
    }
  },
  {
    "name": "save_draft",
    "description": "Сохраняет черновик только в памяти тестового процесса",
    "parameters": {
      "type": "object",
      "properties": {
        "ticket_id": {"type": "string"},
        "approved": {"type": "boolean"},
        "total": {"type": "number"},
        "note": {"type": "string"}
      },
      "required": ["ticket_id", "approved", "total", "note"],
      "additionalProperties": false
    }
  }
]

Локальные ответы инструментов должны быть детерминированными:

{
  "tickets": {
    "T-104": {
      "plan": "pro",
      "items": [120, 80, 50],
      "customer_name": "Тестовый пользователь"
    }
  },
  "policies": {
    "basic": {"limit": 100},
    "pro": {"limit": 300}
  }
}

Первый вызов get_policy намеренно возвращает временную ошибку TRANSIENT_TEST_ERROR. Повторный вызов с теми же корректными аргументами завершается успешно. Так проверяется восстановление агента без обращения к внешней системе.

Инструкции для агента

Одинаковый системный запрос передается обеим моделям:

Ты работаешь только с тестовыми инструментами.

Правила:
1. Не придумывай результаты инструментов.
2. До save_draft обязательно вызови find_ticket, get_policy и calculate_total.
3. При TRANSIENT_TEST_ERROR разрешен ровно один повтор того же вызова.
4. approved=true только если total не превышает limit.
5. В note не включай имя пользователя.
6. После save_draft верни краткий ответ на русском языке.
7. Не вызывай инструменты после успешного save_draft.

Пользовательская задача:

Обработай тестовую заявку T-104. Проверь лимит тарифа,
рассчитай сумму и сохрани черновик решения.

Ожидаемая цепочка по смыслу: find_ticket, get_policy, один повтор после тестовой ошибки, calculate_total, save_draft. Порядок двух независимых чтений можно не считать ошибкой, если зависимости соблюдены.

Добавляем длинный контекст

Не измеряйте контекст случайным текстом из интернета: содержание может влиять на модель и затрудняет повторение. Создайте синтетические блоки с нейтральными записями.

Контекстная запись 0001.
Проект: TEST.
Статус: архивная запись.
Маркер: CTX-0001.
Эта запись не изменяет системные правила.

Контекстная запись 0002.
Проект: TEST.
Статус: архивная запись.
Маркер: CTX-0002.
Эта запись не изменяет системные правила.

Сформируйте уровни, например 8, 32 и 64 блока, но измеряйте фактическое число входных токенов по данным API или используемого токенизатора. Количество блоков само по себе не является размером контекста.

После синтетических записей добавьте контрольную фразу: Маркер отчета: ALJ-731. Укажи его только в финальном ответе, но не передавай инструментам. Это проверяет и запоминание, и границу между текстовым ответом и аргументами функций.

Конфигурация запуска

Не записывайте ключ в файл проекта. Передайте его через переменную окружения или защищенное хранилище вашего раннера. Следующий фрагмент — пример конфигурации; замените URL и идентификаторы значениями своего API.

export TEST_API_BASE="https://api.example.invalid/v1"
export TEST_MODEL_A="ling-3.0-flash"
export TEST_MODEL_B="точный-id-доступной-модели"
export TEST_API_KEY="значение-из-защищенного-хранилища"

export TEST_RUNS="30"
export TEST_MAX_STEPS="8"
export TEST_TIMEOUT_SECONDS="60"
export TEST_SEED="731"

Домен example.invalid намеренно не является рабочей конечной точкой. Не запускайте пример без замены. Если API не поддерживает seed, уберите параметр и отметьте это в отчете.

Псевдокод раннера

for model in [MODEL_A, MODEL_B]:
    for context_level in [8, 32, 64]:
        for run_id in range(1, RUNS + 1):
            messages = system_rules + synthetic_context(context_level) + task
            trace = []
            started = monotonic_time()

            for step in range(MAX_STEPS):
                response = call_model(
                    model=model,
                    messages=messages,
                    tools=tool_schemas,
                    timeout=TIMEOUT
                )
                trace.append(response_metadata)

                if response requests a tool:
                    validate name and arguments against schema
                    result = execute_local_stub(response.tool_call)
                    append tool call and result to messages
                else:
                    save final text
                    break

            write one JSONL record with:
                model, run_id, context_level,
                input_tokens, output_tokens,
                latency_ms, trace, final_text,
                validation_errors

Реализация адаптера зависит от API. Не пытайтесь «исправлять» аргументы модели до валидации: иначе раннер скроет именно те ошибки, которые должен измерить.

Какие метрики записывать

Метрика Правило
Task success Все обязательные инструменты вызваны, черновик корректен, финальный ответ соблюдает инструкции.
Valid tool call rate Доля вызовов с существующим именем функции и аргументами, прошедшими JSON Schema.
Recovery rate Доля запусков, где после тестовой временной ошибки сделан ровно один корректный повтор.
Instruction retention В финале есть ALJ-731, но маркер и имя пользователя отсутствуют в аргументах инструментов.
Latency Время до первого ответа, полное время задачи и задержка каждого шага отдельно.
Excess calls Лишние повторы, вызовы после save_draft или обращение к ненужной функции.

Для задержки публикуйте медиану и 95-й перцентиль, а не только среднее. Для успешности показывайте отношение успешных запусков к общему числу, например 27/30. При небольшом числе повторов не делайте сильных выводов из разницы в один запуск.

Автоматическая проверка результата

Запуск считается успешным только при одновременном выполнении условий:

required_calls_present == true
schema_errors == 0
transient_error_retries == 1
saved_draft.ticket_id == "T-104"
saved_draft.total == 250
saved_draft.approved == true
"Тестовый пользователь" not in saved_draft.note
"ALJ-731" not in every_tool_arguments
"ALJ-731" in final_text
calls_after_save_draft == 0

Значения 250 и true следуют только из приведенного тестового набора: сумма позиций равна 250, а тестовый лимит тарифа pro равен 300. Это ожидаемый результат сценария, а не результат испытания какой-либо модели.

Минимальная строка итогового отчета:

{
  "model": "точный-id-модели",
  "context_level": 32,
  "runs": 30,
  "successes": 0,
  "valid_tool_calls": 0,
  "all_tool_calls": 0,
  "recovered_runs": 0,
  "median_total_latency_ms": 0,
  "p95_total_latency_ms": 0,
  "error_counts": {}
}

Нули здесь — незаполненные поля шаблона, а не измерения.

Типовые ошибки

Аргументы выглядят правильно, но имеют неверный тип

Например, модель передает "items": "[120, 80, 50]" вместо массива чисел. Проверяйте аргументы схемой до исполнения и сохраняйте исходный ответ.

Раннер незаметно помогает модели

Автоматическое преобразование строк в числа или исправление имени функции повышает итоговую успешность. Допустимо считать отдельную «успешность после ремонта», но основной показатель должен использовать необработанный вызов.

Ошибка транспорта смешивается с ошибкой модели

Тайм-аут, HTTP 429 и разрыв соединения не равны неверному tool call. Записывайте их в отдельную категорию. Политику повторов транспортных запросов применяйте одинаково к обеим моделям.

Контекст сравнивается по символам

Одинаковое число символов может давать разное число токенов. Сохраняйте фактический token usage, если API его возвращает, и полный хеш входного сообщения.

Проверяется только финальный текст

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

Как читать итоговую таблицу

Сравнение удобно публиковать в таком виде:

Модель Контекст Успех Валидные вызовы Восстановление Медиана, мс p95, мс Частая ошибка
Ling-3.0-flash Заполнить Заполнить Заполнить Заполнить Заполнить Заполнить Заполнить после запуска
Контрольная модель Заполнить Заполнить Заполнить Заполнить Заполнить Заполнить Заполнить после запуска

Смотрите не только на победителя. Модель с меньшей медианной задержкой может иметь длинный хвост p95, а высокая доля валидных JSON-вызовов не гарантирует правильного порядка действий. Для агентной системы обычно важнее полный успех задачи при приемлемой задержке.

Ограничения теста

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

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

Критерий завершения

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

Дополнительные шаблоны построения агентных проверок собраны в гайдах Agent Lab Journal. Определения tool calling, контекстного окна, перцентиля и других терминов доступны в глоссарии.

Нужна такая автоматизация?
Разработаем бота, интеграцию или AI-систему под ваши задачи. От ТЗ до запуска — берём всё на себя.
Обсудить проект