🤖 AI-агенты для бизнеса

Цикл разработки нового агента

Пошаговый процесс создания нового AI-агента на платформе Agent OS — от кейсов до деплоя и постоянного мониторинга. Вся логика агента описывается конфигурацией (YAML), Rust-код менять не нужно. Разработка идёт test-first: сначала фиксируем, какие вопросы агент должен решать, потом строим данные и инструменты под эти кейсы.

Кейсы → Данные → Инструменты → Отладка → Тесты → Агент → Хуки → Бенч → Деплой → Мониторинг
  1       2          3           4        5       6       7       8       9          10
Мониторинг → новые кейсы → шаг 1 (цикл повторяется)

Шаг 1. Кейсы и бенч-сценарии (test-first)

До всякого кода фиксируем, что агент должен уметь: реальные вопросы пользователей и ожидаемые ответы. Агенты бывают разные, и кейсы зависят от типа агента (подробнее про типы — agents-overview.md):

Тип агента Пример кейса Что проверяем в ответе
Поддержка (FAQ) по базе знаний «Как поступить в НГУ?», «Какие стипендии?» Ответ по базе знаний, ссылки на источник, отсутствие выдумок
Консультант / продавец (e-commerce) «Подбери ноутбук до 80 тыс. для учёбы», «Сравни эти две модели» Найденные товары со ссылками, учтены фильтры, рекомендация
Ассистент сотрудника «Оформи отпуск с 1 августа», «Сбрось пароль от почты» Правильный вызов действия, уточнение недостающих данных, подтверждение
Аналитик данных «Сколько заказов за июль по регионам?» Корректный SQL → ответ + график/таблица
Наблюдатель / мониторинг «Предупреди, если температура в рефрижераторе выше нормы» Срабатывание триггера, упреждающее уведомление

Плюс тяжёлые сценарии (комбинации фильтров, краевые случаи), мультишаговые цепочки (выбор → сравнение → оформление) и multi-turn (проверка удержания контекста: «расскажи подробнее про первый»).

Кейсы оформляются в config/agents/<агент>/bench/scenarios.yaml — этот же файл позже прогоняет бенчмарк (шаг 8):

name: "NGU Agent"
model: "ngu-agent"

scenarios:
  - name: "Поступление"
    turns:
      - user: "Как поступить в нгу"
        assert:
          contains: [поступлен]
          min_links: 1
          valid_urls: true

Типы проверок: contains (подстроки), min_links/min_urls (минимум markdown-ссылок), valid_urls (все ссылки http/https). Советы: для редких результатов min_links: 1; valid_urls: true ловит битые ссылки; русские запросы для русскоязычных агентов.

Шаг 2. Данные и источники: API, адаптеры, скрейп

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

2a. Разбор источников и API

Источник Что это Движок
Публичные страницы сайта HTML со структурированным JSON внутри <script> site_tool (live fetch + extract)
Внутренний API сайта JSON-эндпоинты (поиск, каталог, фильтры) адаптер под API или site_tool с method: POST
RSS-ленты Новости и обновления rss_tool
Документы (PDF) Инструкции, каталоги, регламенты pdf_tool
Готовые дампы/выгрузки JSON-файлы с данными (бренды, товары) json_tool (предазагруженный JSON)
Большой корпус страниц для поиска Весь сайт для RAG-поиска archive_tool (шаг 2c)

Что выяснить про каждый источник: формат ответа, параметры запроса, нужны ли заголовки/ключи (подставляются из окружения через env_var()), лимиты и пагинация, частота обновления данных.

Адаптер — это либо YAML-конфиг существующего движка (для site_tool достаточно описать fetch + extract + output), либо, если нужно нестандартное поведение (сложная логика, не-HTTP источник), — новый движок на Rust: реализовать ToolHandler и зарегистрировать фабрику в agent_os_tools/src/registry.rs. Для готовых дампов/выгрузок есть универсальный движок json_tool (декларативный поиск по JSON-файлу: search + computed-поля на MiniJinja). Пример — config/agents/drom/tools/drom_find_brands.yaml: поиск марок по предазагруженному data/drom_brands.json.

2b. Скрейп сайта

cargo run --bin scraper -- https://nsu.ru -w 8 -d 3 -n 500

Параметры: -w воркеры, -d глубина обхода, -n максимум страниц, -r пауза между запросами, -o путь архива, -m путь карты навигации.

Анализ собранного архива — найти повторяющиеся блоки (шапки, футеры, меню), которые нужно вычистить из текста:

cargo run --bin scraper -- --analyze site.archive

2c. RAG-архив

Для полнотекстового поиска страницы складываются в бинарный архив ArchiveBuilder (чанки с перекрытием, n-граммы 1–3 порядка как неявный стемминг для русского, BM25). Структура архива:

data/<источник>/
├── meta.json      — название источника, число документов, аббревиатуры
├── docs.bin       — документы-чанки
└── terms.bin      — словарь терминов и постинги

Аббревиатуры извлекаются автоматически из паттернов вида «Автоматизации Физико-Технических Исследований (АФТИ)» — поиск по «афти» находит полное название.

Готовые примеры: data/ngu/ (НГУ, собирается из crawled pages при старте), data/hg/ (HobbyGames, ~4300 товаров).

Шаг 3. Инструменты

Инструмент = YAML-файл в config/agents/<агент>/tools/*.yaml. Доступные движки (kind:):

kind Что делает
site_tool HTTP-запрос → извлечение полей (JSON-указатели, array match, transforms) → форматирование
archive_tool Поиск по архиву: search, search_grouped, lookup, read_chunks, outline + фильтры по meta-полям
pdf_tool Скачивание PDF и чтение по страницам
rss_tool Поиск по RSS-лентам
json_tool Декларативный поиск по предазагруженному JSON (search.paths, computed)

Плюс встроенные инструменты ядра: http_fetch, fs_read, job_done.

Пример минимального site_tool:

kind: site_tool
name: my_scraper
description: Scrapes example.com product pages.
parameters:
  type: object
  properties:
    url: { type: string, description: "Product page URL" }
  required: [url]

fetch:
  url: "{{ input.url }}"        # MiniJinja-шаблон
  timeout_secs: 10

source:
  type: script_json             # JSON внутри <script> на странице
  contains: productData

extract:
  title:
    pointer: /productData/title
  price:
    pointer: /productData/price
    transform: int

Ключевые возможности site_tool:

Шаг 4. Локальная отладка инструмента

Проверять любой YAML-инструмент можно без сервера и без LLM:

cargo build --bin site_tool --release
./target/release/site_tool config/agents/ngu/tools/ngu_search.yaml '{"query":"поступление"}'

Вывод показывает: переданные аргументы, call_template (что видит пользователь до вызова), ответ LLM и result_template. Поддерживаются все движки: site_tool, archive_tool, pdf_tool, rss_tool, json_tool.

Шаг 5. Тесты инструментов

Тесты — YAML-файлы в config/agents/<агент>/tests/*.yaml, находятся автоматически. Два вида:

Fixture-тесты (kind: site_tool_tests) — без сети, данные подаются напрямую. Запуск: cargo test.

kind: site_tool_tests
tool: tools/my_tool.yaml

tests:
  - name: "extracts correctly"
    input: { url: "https://example.com/p/1" }
    fixture: { productData: { title: "Widget", price: 99 } }
    assert:
      - { path: /title, equals: "Widget" }
      - { path: /price, equals: 99 }

Live-тесты (kind: site_tool_live_tests, archive_tool_live_tests, rss_tool_live_tests) — реальные HTTP-запросы, помечены #[ignore]. Запуск: cargo test -- --ignored.

kind: site_tool_live_tests
tool: tools/my_tool.yaml

tests:
  - name: "structure smoke test"
    fetch: true
    input: { url: "https://example.com/p/1" }
    assert:
      - { path: /title, not_null: true }

Типы проверок: equals, not_null, len, contains.

Шаг 6. Конфигурация агента

config/agents/<агент>/agent.yaml — всё поведение агента:

name: ngu-agent
welcome: |
  👋 Привет! Я ассистент НГУ...
instructions: |
  You are an assistant for NGU (nsu.ru).
  Use ngu_search to find ANY information...
  Answer in Russian, helpful and informative. Always cite source URLs.
tools:                # встроенные инструменты ядра
  - http_fetch
tool_files:           # YAML-инструменты (пути относительно каталога агента)
  - tools/ngu_search.yaml
hook_files:           # хуки (см. шаг 7)
  - hooks/faq_cache.yaml

Советы по instructions:

Шаг 7. Хуки (опционально)

Хук перехватывает сообщения в конвейере. Готовый пример — faq_cache (DuckDB): запоминает пары вопрос-ответ, LLM-судья определяет похожие вопросы, кэшированный ответ либо вставляется как подсказка (short_circuit: false), либо возвращается сразу без вызова LLM (short_circuit: true) — экономит токены и ускоряет ответы.

kind: faq_cache
name: faq_cache
db_path: data/faq_cache_ngu.db
max_candidates: 5
min_confidence: 0.7
short_circuit: true
store: { enabled: true, min_question_chars: 8, min_answer_chars: 8 }
llm:
  base_url: https://api.deepseek.com
  api_key_env: DEEPSEEK_API_KEY
  model: deepseek-chat

Шаг 8. Прогон бенча и итерация

Прогоняем сценарии из шага 1:

# Продакшн-сервер
cargo run --bin agent_bench --release -- --url=https://176.108.251.90 --agent=ngu --max=5

# Локальный сервер (нужен DEEPSEEK_API_KEY в .env)
cargo run --bin agent_bench --release -- --port=3001 --max=3

Флаги: --agent= фильтр по агенту, --name= по имени сценария (регулярка), --parallel=, --max= ограничение, --timeout=.

После прогона: смотреть / в консоли, разбирать bench_report_*.json (поля failures, error), сравнивать два отчёта для поиска регрессий. Провалы чинятся правкой instructions, инструментов или данных — при необходимости добавляем новые кейсы в scenarios.yaml — и цикл повторяется.

Шаг 9. Публикация и деплой

Страница на сайте

  1. Контент: config/web/pages/<агент>.md;
  2. Регистрация: карточка в cards: или запись в extra_pages: в config/web/index.md;
  3. Демо на живых сайтах — запись в demos: (открывается /demo/overlay?model=<агент>).

Сайт читается из config/web/ при старте сервера — правки контента требуют только перезапуска, без пересборки.

Деплой на сервер

scp -i ~/.ssh/ssh-pk-025d38 -r config/ data/ realityfaker@176.108.251.90:/home/realityfaker/agent_os/
ssh -i ~/.ssh/ssh-pk-025d38 realityfaker@176.108.251.90 "sudo kill \$(pgrep agent_web_bot); cd /home/realityfaker/agent_os && sudo bash -c 'set -a && source .env && set +a && nohup ./target/release/agent_web_bot > agent_os.log 2>&1 &'"
curl -sk https://176.108.251.90/health

Если менялся Rust-код (новый движок инструмента, хук) — пересобрать cargo build --release -p agent_web_bot перед перезапуском.

Шаг 10. Мониторинг и итерации

После деплоя цикл не заканчивается — агент работает в проде, и это главный источник данных для следующей итерации.

Что смотреть

Источник Где Что даёт
Логи сервера ssh ... "tail -50 agent_os.log" Ошибки запуска, падения, warnings
JSONL-логи logs/*.jsonl на сервере События ядра: спавн, сообщения, tool-вызовы, ошибки
Event DB (DuckDB) logs/events.db SQL-запросы по событиям: частоты ошибок, топ запросов
FAQ-кэш data/faq_cache_<агент>.db Реальные вопросы пользователей — топ новых кейсов
Бенч на проде agent_bench --url=... --max=5 Регрессии после обновлений
Health curl -sk https://.../health Жив ли сервис

Итерация

  1. Раз в период (или после каждого деплоя) прогонять бенч на проде и сравнивать отчёты — ловить регрессии;
  2. Собирать реальные вопросы из FAQ-кэша и логов — вопросы, на которые агент ответил плохо или не ответил, становятся новыми кейсами в bench/scenarios.yaml (шаг 1);
  3. Править instructions, инструменты или данные — и проходить цикл заново: тесты → бенч → деплой;
  4. Обновлять базу знаний/архивы по мере изменения сайта-источника.

Так цикл замыкается: каждый проход делает агента точнее, а кейсы — ближе к реальным запросам пользователей.

Чек-лист