Что такое Extella: зачем, как устроено, ключевые понятия
1.1. Зачем нужен агент, а не чат-бот
Вы наверняка уже пользовались ChatGPT, Claude или другими большими языковыми моделями. Каждый разговор начинается с чистого листа. Модель не помнит, что было вчера. Она не может открыть ваш файл, отправить письмо, запустить скрипт или сохранить отчёт. Максимум — сгенерировать код, который вы потом сами скопируете и запустите.
Extella — это не чат-бот. Это AI-агент, который выполняет задачи, а не советует, как их выполнить.
Формула: AI-чат + автоматизация + постоянная память + выполнение на твоём устройстве + персональный набор инструментов — всё в одном месте.
Вы описываете потребность. Extella создаёт Expert (исполняемый модуль), сохраняет его в библиотеке и запускает. Результат — реальный файл, отправленное сообщение, обработанные данные — остаётся на вашем устройстве. Это не текст в чате. Это объект, который живёт после завершения сессии.
1.2. Extella vs обычные LLM — фундаментальные отличия
ChatGPT говорит вам, что делать. Extella делает это за вас.
| Характеристика | ChatGPT / обычные LLM | Extella |
|---|---|---|
| Основная задача | Генерация текста | Выполнение реальных действий |
| Память | Только текущий чат. Новая сессия — чистый лист | Постоянная: Concepts, Rules, Experts сохраняются навсегда |
| Исполнение кода | Генерирует код. Запускаете вы сами | Запускает автоматически через Experts на вашем устройстве |
| Переиспользование | Каждый запрос — заново | Созданный Expert запускается повторно с любыми параметрами |
| Безопасность | Данные уходят на серверы OpenAI/Anthropic | Файлы обрабатываются локально, не покидают устройство |
| Персонализация | Системный промпт фиксирован | Rules — динамический промпт, меняется по ходу работы |
| Результат | Текст в чате | Файлы, данные, отчёты, автоматизированные процессы |
| Интеграции | Плагины (ограниченный набор) | Любые: Telegram, email, API, файловая система |
1.3. Архитектура: как это работает
Extella — клиент-серверная архитектура с двумя частями:
- Серверная часть — AI-мозг: языковая модель, база знаний, управление экспертами и агентами.
- Клиентская часть — Listener: фоновый процесс на вашем устройстве, который принимает задачи от агента и запускает их локально.
Listener — это исполнитель. Когда агент говорит «создай PDF» — Listener запускает соответствующий Expert на вашей машине с полным доступом к вашим файлам.
По умолчанию Experts запускаются напрямую в среде Listener. При необходимости строгой изоляции зависимостей используется параметр isolated=true — тогда Expert запускается в чистом Python venv. Это не Docker: нет тяжёлой виртуализации, нет нужды в root-доступе. Полный доступ к файловой системе пользователя сохраняется.
1.4. Безопасность данных
- Anthropic Claude — основная модель для чата и генерации кода в Extella.
Обрабатывает текстовые запросы. Pro-план позволяет подключать собственные LLM-провайдеры и локальные модели. - OpenAI API — только для векторных эмбеддингов (семантический поиск концептов, KV, правил и экспертов). Данные векторизуются, но не хранятся у OpenAI.
- Корпоративные файлы и API-ключи НЕ отправляются провайдерам. Файлы обрабатываются локально. Ключи хранятся в зашифрованном KV Store на устройстве.
1.5. Ключевые понятия: глоссарий
Прежде чем двигаться дальше — важно понять шесть основных сущностей платформы.
Все они будут объяснены подробно в следующих разделах.
| Сущность | Что это | Аналогия |
|---|---|---|
| Expert | Сохранённый исполняемый модуль — функция, которая делает одну конкретную вещь | Инструмент на вашей полке |
| Agent | AI-специалист с моделью, инструментами, инструкциями и памятью | Сотрудник с должностью |
| Profile | Группа агентов под одним проектом/клиентом | Отдел в компании |
| Concept | Единица технического знания с семантическим поиском | Заметка в базе знаний |
| KV Store | Зашифрованное хранилище ключ-значение: API-ключи, токены, данные | Сейф с ячейками |
| Rule | Поведенческая инструкция, встраиваемая в системный промпт агента | Должностная инструкция |
| Team | Группа агентов, работающих над одним проектом с общими Concepts, Rules и оркестрирующим агентом | Отдел или проектная команда |
1.6. Эффект накопления: почему Extella становится сильнее каждый день
Обычные AI-инструменты не накапливают ценность. Каждый новый чат в ChatGPT — чистый лист. Extella работает принципиально иначе.
Experts:
- День 1: создан Expert «читать таблицу Excel» → сохранён
- День 30: 15 Experts — библиотека инструментов
- День 90: 50+ Experts — вы не «просите AI» — вы «запускаете инструменты»
Concepts:
- Первое решение проблемы с PDF → сохранено как Concept
- Паттерн работы с конкретным API → сохранён
- Каждый Concept делает систему умнее. Это институциональная память
Rules:
- Сначала: «всегда спрашивай подтверждение перед удалением»
- Потом: «сохраняй файлы в ~/Documents/Extella/»
- Потом: «если задача > 1 шага — сначала опиши план»
С каждым Rule агент становится точнее. Через 30 дней Extella понимает вас лучше, чем когда-либо.
Метафора: каменный мост
Каждая задача, решённая с Extella — камень в фундамент. Один камень ничего не меняет. Сто — мост к автоматизации любой сложности. Через год у вас будет персональная система, которая знает ваш контекст, инструменты и предпочтения. И которая с каждым днём становится только сильнее.
Быстрый старт: от установки до первого результата
Пошаговое руководство: от скачивания приложения до первого выполненного задания. Следуйте шагам по порядку — каждый строится на предыдущем.
2.1. Шаг 1: Установка приложения и регистрация аккаунта
- Скачайте Extella Desktop с www.extella.ai для вашей ОС (macOS, Linux, Windows).
- Установите как обычное приложение.
- Зарегистрируйте аккаунт и войдите.
Сразу после входа Listener запустится в фоне и выполнит первую регистрацию:
- → Создаст запись устройства в системе
- → Получит уникальный Device ID (Target UUID)
- → Установит соединение с сервером Extella
Статус в системном трее: «Connected» — всё работает.
2.2. Шаг 2: Понятие Device ID
Device ID — уникальный идентификатор вашего устройства.
Выглядит как: 09f7d600-996c-4c9f-a19e-f5bfe433da0e.
Зачем он нужен:
- Агент знает, ГДЕ выполнять задачи. «Прочитай мой файл» — система понимает, на какой машине файл находится.
- Если у вас несколько устройств (Mac Studio дома, MacBook в офисе) — каждое имеет свой Device ID. Вы выбираете, где запустить задачу.
Где найти Device ID:
- В интерфейсе Extella Desktop — нижняя секция приложения.
- Через агента: «покажи мои устройства» — агент вернёт список с UUID и описаниями.
- Через API: POST https://prod.extella.ai/api/defaults/get_target
Default Target — устройство, на котором Experts запускаются по умолчанию. Меняется через set_default_target.
2.3. Шаг 3: Получение API токена
API токен — строка-ключ, которая подтверждает вашу личность в системе.
Нужен для аутентификации Listener и программных вызовов.
Через агента (самый простой способ):
Напишите в чат: «Сгенерируй мне API токен» — агент создаст токен мгновенно. При желании укажите имя, например «Mac Studio listener».
Скопируйте и сохраните токен — он используется для настройки Listener.
Управление токенами через агента:
- «Покажи мои токены» — список всех активных токенов
- «Отзови токен [имя]» — мгновенная деактивация
2.4. Шаг 4: Первый запрос агенту
Откройте интерфейс Extella Desktop. Напишите первый запрос на естественном языке:
«Создай PDF-презентацию из 3 слайдов о нашем продукте. Сохрани в Downloads.»
Что произойдёт:
- Агент проанализирует запрос
- Создаст Expert (исполняемый модуль — например, использующий ReportLab)
- Запустит его на вашем устройстве через Listener
- Через несколько секунд в ~/Downloads/ появится PDF-файл
Это — первый результат работы Extella.
2.5. Шаг 5: Expert сохранён в библиотеке
Созданный Expert автоматически сохраняется в вашей личной библиотеке с именем (например, generate_product_presentation_pdf). Теперь вы можете:
- Запустить снова с другими параметрами (другой текст, другое название)
- Модифицировать: «измени цвет фона на синий»
- Использовать как часть более сложного workflow
Это ключевое отличие от чат-ботов: задача решена один раз — инструмент остаётся навсегда.
2.6. Шаг 6: Первое правило (Rule)
Rule — инструкция, которая применяется при каждом взаимодействии. Добавьте первое правило:
«Добавь правило: всегда отвечай на русском языке»
Или другие полезные правила:
- «Сохраняй все файлы в ~/Documents/Extella/»
- «Если задача займёт больше одного шага — сначала опиши план»
- «Всегда спрашивай подтверждение перед удалением данных»
Теперь каждый раз, когда агент генерирует ответ или создаёт файл, эти правила учитываются автоматически — без напоминаний.
2.7. Шаг 7: Первые концепты
Concepts — долгосрочная память агента. Они накапливаются автоматически. После первого выполненного задания агент сохраняет:
- Какая библиотека подошла для PDF
- Как обрабатывать ошибки конкретного API
- Какой подход сработал для вашей задачи
Вы также можете добавить вручную:
«Запомни: для работы с таблицами я предпочитаю pandas, а не openpyxl»
Чем больше задач вы решаете — тем умнее становится ваш агент.
2.8. Чеклист: вы готовы к работе
| # | Действие | Статус |
|---|---|---|
| 1 | Extella Desktop установлен и запущен | |
| 2 | Listener показывает Connected в трее | |
| 3 | Device ID зарегистрирован (виден в интерфейсе) | |
| 4 | API токен получен и сохранён | |
| 5 | Первый запрос отправлен и получен ответ | |
| 6 | Первый Expert создан и виден в библиотеке | |
| 7 | Первое Rule добавлено | |
| 8 | Первый Concept сохранён |
Если все 8 пунктов отмечены — платформа настроена. Теперь начинается самое интересное: наращивание системы.
Три кита: KV, Концепты, Правила
Раздел 1 дал краткий глоссарий. Раздел 2 — практический старт. Здесь каждый из трёх компонентов разобран в деталях: как устроен, что умеет, когда применять, а что не хранить.
3.1. Зачем три хранилища, а не одно
| Вопрос | Решение | Почему именно так |
|---|---|---|
| Где мой API-ключ? | KV Store — точный поиск по ключу | Данные зашифрованы, ищутся точно и быстро |
| Я решал проблему с PDF — что было? | Concepts — семантический поиск | Поиск по смыслу, а не по ключевым словам |
| Агент должен всегда отвечать на русском | Rules — автозагрузка в каждый промпт | Не надо искать — всегда активны |
KV Store — это «сейф». Кладёте с точным названием — достаёте по названию.
Concepts — «поисковый индекс знаний»: находит по смыслу запроса, даже если слова разные. Rules — «рефлексы»: загружаются автоматически при каждом сообщении пользователя, агент живёт с ними с первого слова диалога.
3.2. KV Store — зашифрованное хранилище данных
Техническая структура
KV Store — таблица PostgreSQL с тремя ключевыми колонками:
- kv_key — уникальное имя ключа (string)
- kv_value — значение (string)
- kv_description — описание для семантического поиска (string)
Шифрование и PIN
Все значения зашифрованы с привязкой к PIN-коду пользователя. При прямом просмотре базы вы видите строку вида $enc:... — это зашифрованный текст. Чтобы получить реальное значение, агент обязан вызвать MCP-инструмент kv_get, который выполняет расшифровку. Это защищает credentials от утечки в логах, дампах базы и экспортах.
Важно при запуске Expert на другом устройстве: если PIN на том устройстве отличается, расшифровка даст мусор — вы увидите ошибку 'invalid decimal literal'. Решение: передать pin явно при вызове: run_expert('имя', {}, pin='ваш_pin').
Что хранится в KV Store
Типичные категории данных:
| Категория | Примеры ключей |
|---|---|
| API-ключи сервисов | telegram_bot_token, anthropic_api_key, openai_api_key, tavily_api_key |
| Target UUID устройств | mac_studio_target, ubuntu_vm_target, macbook_target |
| URL и эндпоинты | aios_backend_url, webhook_slack, api_crm_url |
| Данные сессий | session_history, cache_results (JSON-массивы) |
| Конфигурации | typefully_social_set_id, redis_url, redis_token |
KV Store хранит не только короткие строки. Значение может быть полным JSON-массивом с историей данных сессии — KV становится быстрым key-value кешем для агентов.
Семантический поиск в KV Store
Каждая запись имеет эмбеддинг (OpenAI text-embedding-3-small) из ключа + описания. Это позволяет искать по смыслу:
Семантический поиск:
# Забыли точное имя ключа?
kv_search("telegram bot token")
# Находит: telegram_bot_token, telegram_bot_token_taskboard
# Работает даже если описание на русском, а запрос на английском, и наоборот
Правила написания хорошего описания
Описание — это не комментарий. Это индекс для семантического поиска. Чем точнее и информативнее, тем надёжнее агент найдёт ключ.
# Хорошее описание:
kv_set(key="anthropic_key", value="sk-...",
description="Anthropic Claude API key (main production, обновлён 2025-03)")
# Плохое описание — поиск не поможет:
kv_set(key="k1", value="sk-...", description="key")
Алгоритм автопоиска агента — золотое правило
Агент НИКОГДА не спрашивает credentials первым. Строгий алгоритм:
- Нужен ключ? → kv_search("<сервис> ключ токен")
- Нашёл? → kv_get(key) — автоматическая расшифровка
- Не нашёл? → только тогда спрашивает пользователя
- Пользователь предоставил? → kv_set + сохранение навсегда
Если вы однажды сохранили tavily_api_key с описанием «Tavily web search API key», при следующем запросе на веб-поиск агент найдёт его сам — без единого вопроса.
Принцип: эксперт никогда не лезет в KV сам
Это фундаментальный принцип безопасности архитектуры. Expert — чистая функция. Credentials инжектирует агент через params. Эксперт получает уже расшифрованное значение как параметр — и не знает про KV Store вообще.
# НЕПРАВИЛЬНО: эксперт сам обращается к KV
def send_telegram(text: str) -> dict:
import requests
# Значение зашифровано ($enc:...) — эксперт не расшифрует!
r = requests.post("https://prod.extella.ai/api/kv/get", ...)
token = r.json()["value"] # получит мусор
# ПРАВИЛЬНО: агент расшифровывает и инжектирует
def send_telegram(text: str, bot_token: str = "") -> dict:
import requests
# bot_token уже расшифрован агентом и передан через params
url = f"https://api.telegram.org/bot{bot_token}/sendMessage"
# ... остальная логика
Это обеспечивает: безопасность (credentials не в коде), переиспользование (один эксперт, разные токены), тестируемость (любые входные данные без зависимости от KV).
3.3. Concepts — семантическая память знаний
Как работает технически
Concept — текстовый фрагмент (знание, паттерн, решение) с автоматически генерируемым эмбеддингом. Технические детали:
- База данных: PostgreSQL + расширение pgvector
- Модель эмбеддингов: OpenAI text-embedding-3-small
- Размерность вектора: 1536 измерений
- Метрика сходства: косинусное сходство (cosine similarity)
- Поиск: вычисляется эмбеддинг запроса, находятся ближайшие векторы в базе
Когда агент сохраняет концепт «Для генерации PDF в Docker используй ReportLab — не wkhtmltopdf, тот требует X11», система немедленно отправляет текст в OpenAI, получает 1536-мерный вектор и сохраняет его рядом с текстом. При поиске «создать PDF в контейнере» — запрос тоже превращается в вектор, система находит ближайший. Хотя в запросе нет слов «ReportLab» и «X11» — смысловое расстояние минимально.
Примеры концептов
- «Среда выполнения Extella: Experts запускаются на локальном устройстве через Listener. Python venv — опциональный параметр (isolated=true). Не Docker.»
- «Для чтения .docx: python-docx. Установка: extella-pip install python-docx»
- «PDF на Linux: если wkhtmltopdf недоступен — ReportLab напрямую. Установка: extella-pip install reportlab»
- «Telegram bot getUpdates: offset = последний update_id + 1. Иначе те же сообщения снова.»
Что хранить vs что не хранить
| Хранить в Concepts | НЕ хранить в Concepts |
|---|---|
| Паттерны и решения проблем | API-ключи и токены (→ KV Store) |
| Инструкции по установке библиотек | JSON-данные сессий и кэши |
| Архитектурные решения проекта | Конкретные пути к файлам |
| Бизнес-требования и спецификации | Персональные данные |
| Инсайты из опыта работы | Конфигурации с паролями или секретами |
| Технические ограничения и воркараунды | Временные данные, которые устаревают |
Почему нельзя хранить credentials в Concepts: концепты находятся по смыслу. Если сохранить API-ключ, семантический поиск найдёт его по запросу «нужен ключ» — и он попадёт в контекст как обычный текст, без расшифровки. Это нарушение безопасности.
Правильный паттерн: обобщённый вывод из опыта
Агент получил ошибку → решил → извлекает обобщённое знание → сохраняет:
# После того как агент решил проблему с PDF:
concept_add(
"Для генерации PDF в headless-среде (Docker, сервер без X11)"
" используй ReportLab. wkhtmltopdf требует графический дисплей"
" и не работает в контейнерах без Xvfb."
)
# В будущем автоматически найдётся при запросе:
concept_search("PDF в Docker")
# -> Находит с высоким сходством, хотя слов 'wkhtmltopdf' в запросе нет
Концепт — это обобщённый вывод из опыта, а не сырые данные.
Операции с концептами
| Операция | MCP-инструмент | Описание |
|---|---|---|
| Создать | concept_add | Текст → эмбеддинг → сохранение |
| Найти | concept_search | Семантический поиск по смыслу (не по ключевым словам) |
| Обновить | concept_update | Изменить текст + перегенерировать эмбеддинг |
| Удалить | concept_remove | Удалить по ID |
| Список | concept_list | Все концепты агента или профиля |
Параметр global=true позволяет искать концепты всех агентов профиля — знание одного агента доступно другим. Без global=true агент видит только свои концепты.
3.4. Rules — динамический системный промпт
Механизм загрузки
Rule — поведенческая инструкция, загружаемая при КАЖДОМ сообщении пользователя через rules_list. Схема работы:
Схема работы:
1. Пользователь отправляет сообщение
2. Система вызывает rules_list() -> получает все активные правила
3. Правила встраиваются в system prompt ДО обработки запроса
4. Агент генерирует ответ с учётом всех правил
Этот цикл происходит автоматически на каждом витке диалога.
Rule — это не запрос к памяти, а часть «личности» агента.
Агент не «вспоминает» правила — он живёт с ними с первого слова диалога. Это принципиальное отличие от Concepts, которые нужно явно искать. В дефолтном агенте уже предустановлены некоторые базовые правила и концепты — пользователь может изменять их на своё усмотрение.
Примеры правил для старта
- «Всегда отвечай на английском языке»
- «Всегда спрашивай подтверждение перед удалением файлов или данных»
- «Если задача займёт больше одного шага — сначала опиши план, потом выполняй»
- «Когда задача выполнена — коротко объясняй, что именно было сделано»
- «Сохраняй все созданные файлы в папку ~/Documents/Extella/»
- «Никогда не сохраняй credentials в Concepts — используй KV Store»
Лимиты и ограничения
Максимальная длина одного правила: 4000 символов. Этого достаточно для детальных инструкций. Для объёмных технических знаний используйте Concepts.
Правила независимы: можно иметь 50 правил, и все будут применяться одновременно. Порядок применения не гарантирован — пишите правила так, чтобы они не противоречили друг другу.
global=true для правил
Rules с global=true видны всем агентам профиля. Это позволяет задать общие правила поведения для всех агентов в одном профиле, не настраивая каждый по отдельности.
Отличие Rules от Concepts
| Параметр | Rules | Concepts |
|---|---|---|
| Загрузка | Автоматически при каждом сообщении | Только при явном поиске concept_search |
| Влияние | Всегда в system prompt | Только когда найдены и добавлены в контекст |
| Поиск | Нет — все загружаются | Семантический поиск по смыслу |
| Тип данных | Инструкции, ограничения, стиль | Знания, факты, паттерны решений |
| Лимит размера | 4000 символов на правило | Не ограничен (TEXT в PostgreSQL) |
| Пример | «Всегда отвечай на русском» | «Для PDF в Docker используй ReportLab» |
Мнемоника: если поведение должно быть ВСЕГДА — это Rule. Если знание может понадобиться ИНОГДА — это Concept.
Операции с правилами
| Операция | MCP-инструмент | Описание |
|---|---|---|
| Создать | rules_add | Новое правило (rule_id генерируется автоматически) |
| Обновить | rules_update | Изменить текст существующего правила |
| Удалить | rules_remove | Удалить правило по rule_id |
| Список | rules_list | Получить все правила (вызывается автоматически при каждом сообщении) |
3.5. Сравнительная таблица трёх хранилищ
| Характеристика | KV Store | Concepts | Rules |
|---|---|---|---|
| Тип данных | Ключ-значение + описание | Семантическое знание (текст) | Поведенческая инструкция |
| Шифрование | ✓ PIN пользователя | ✕ Нет | ✕ Нет |
| Поиск | Точный по ключу + семантический | Только семантический | Нет — все загружаются |
| Автозагрузка | ✕ | ✕ | ✓ При каждом сообщении |
| Эмбеддинги | pgvector (из ключа + описания) | pgvector (из текста концепта) | N/A |
| Модель эмбеддингов | text-embedding-3-small | text-embedding-3-small | N/A |
| Лимит значения | TEXT (до 1 ГБ) | TEXT | 4000 символов |
| Что хранит | API-ключи, UUID, URL, JSON, данные сессий | Знания, паттерны, решения, инсайты | Ограничения, протоколы, стиль ответов |
| Флаг global | ✓ | ✓ | ✓ |
| Изоляция | По agent_id / profile_id | По agent_id / profile_id | По agent_id / profile_id |
3.6. Изоляция данных: три уровня
Все основные таблицы (KV, Concepts, Rules, Targets, Experts) содержат колонки agent_id и profile_id. Трёхуровневая модель изоляции:
| Уровень | Аналогия | Описание |
|---|---|---|
| user_id | Владелец здания | Глобальный идентификатор пользователя |
| profile_id | Этаж (отдел) | Группа агентов одного проекта/клиента |
| agent_id | Кабинет на этаже | Конкретный агент внутри профиля |
Как работает флаг global
global=false (по умолчанию) — «Я вижу только свой кабинет»: агент видит только свои данные (фильтрация по agent_id). Агент «Researcher» не видит концепты агента «Writer».
global=true — «Я вижу весь этаж»: агент видит данные всех агентов профиля (фильтрация по profile_id). Researcher + Writer + Analyst — все три агента в одном профиле.
INSERT всегда ваш
При создании новой записи (concept_add, kv_set, rules_add) — система ВСЕГДА использует текущие agent_id и profile_id. Нельзя создать запись «для другого агента». Это гарантирует что данные принадлежат тому, кто их создал.
При чтении/изменении/удалении (concept_search, kv_get, rules_list) — фильтруется флагом global. Без global=true — только ваши данные. С global=true — данные всех агентов профиля.
Эксперты: создание, типы и автоматизации
Expert — это атомарная автоматизация, сохранённая навсегда. Один раз создан — работает всегда. Этот раздел охватывает всё: от типов экспертов до создания автоматических задач по расписанию.
4.1. Четыре типа экспертов
1. SIMPLE — однозадачные кирпичики
| Эксперт | Что делает | API-ключ? |
|---|---|---|
| convert_pdf_to_text | Извлекает текст из PDF | Нет |
| send_telegram_message | Отправляет сообщение | Да (bot_token) |
| excel_query | SQL-запрос к .xlsx | Нет |
| word_generate | Генерирует .docx из JSON | Нет |
2. COMPLEX — многоступенчатые пайплайны
- decompile_binary_to_pseudocode: файл → дизассемблирование → граф → псевдокод
- generate_3d_model_from_photo: фото → карта глубины → 3D-меш → .obj
3. NESTED — оркестраторы (cspl=nohup)
Вызывают других экспертов через REST API. Пример:
fetch_emails -> extract_data -> check_crm -> create_task -> send_notification
→ Подробнее о nohup-экспертах (структура скрипта, синтаксис {{placeholders}}, отсутствие return, ручной include): Раздел 8, п.8.4.
→ Паттерн параллельного запуска нескольких воркеров + синхронизация через wait_tasks: Раздел 7.
4. INTEGRATION — обёртки вокруг технологий
| Подтип | Примеры |
|---|---|
| CLI wrapper | ffmpeg, ImageMagick, pandoc, git |
| Library wrapper | Pillow, pandas, BeautifulSoup |
| External API | Telegram, OpenAI, Notion, Jira |
| Database | SQLite, PostgreSQL |
4.2. Структура эксперта: 5 обязательных элементов
Шаблон эксперта:
$extens("include.py")
include("import requests", ["extella-pip install requests"])
def expert_name(param1: str = "", param2: int = 0) -> dict:
import requests
if not param1:
return {"status": "error", "message": "param1 required"}
try:
# ... логика ...
return {"status": "success", "result": "..."}
except Exception as e:
return {"status": "error", "message": str(e)}
5 обязательных элементов каждого эксперта:
- Директива: $extens("include.py") — первая строка, обязательно
- Зависимости: include(..., ["extella-pip install ..."])
- Сигнатура: def name(param: str = "") → dict — явные типы, дефолты, никаких *args/**kwargs
- Валидация: проверка входов, ранний возврат при ошибке
- Возврат: всегда dict с полем status
4.3. Description — индекс для семантического поиска, а не комментарий
При сохранении эксперта backend генерирует embedding из полей name + description. По этому embedding работает search_blocks — семантический поиск по библиотеке. Плохое description = эксперт не найдётся, когда он нужен.
| ✕ Плохо — не ищется | ✓ Хорошо — ищется по смыслу |
|---|---|
| description="" | description="Отправляет сообщение в Telegram. Параметры: chat_id — ID чата; message — текст; bot_token_key — ключ токена в KV Store" |
| description="utility" | description="Конвертирует PDF в текст через pdfplumber. Параметры: file_path — путь к PDF; max_pages — лимит страниц (0=все)" |
Правило: description = одно предложение о том, что делает эксперт + перечисление всех параметров с их назначением.
4.4. Имена — snake_case. Сохранение с существующим именем перезаписывает эксперт
Имя эксперта — уникальный ключ в библиотеке. Требования:
- Только snake_case: send_telegram_message, convert_pdf_to_text, get_server_metrics
- Никаких пробелов, дефисов, кириллицы
- Сохранение с именем, которое уже занято → предыдущая версия перезаписывается без предупреждения
- Для версионирования используйте суффиксы: analyze_document_v2, или явно удалите старую версию
4.5. Параметр isolated=True — запуск в чистом окружении
run_expert можно вызвать с isolated=True — эксперт запустится в свежем venv без влияния зависимостей других экспертов:
run_expert('my_expert', {'param': 'value'}, isolated=True)
Когда нужен: конфликты зависимостей между экспертами, нестандартные версии библиотек, воспроизводимость при отладке.
4.6. extella-pip install — обязательное правило
include("from pdfplumber import open as pdf_open", ["extella-pip install pdfplumber"])
Всегда extella-pip install, а не pip install или pip3 install. Это гарантирует установку в правильную виртуальную среду эксперта.
Несколько зависимостей:
include("import pandas", ["extella-pip install pandas", "extella-pip install openpyxl"])
4.7. Принцип обобщения: не хардкодить
Плохо — хардкод:
def process_invoice():
file_path = "/Users/ivan/Downloads/invoice.pdf" # Работает только на одной машине!
Хорошо — параметры:
def process_invoice(file_path: str = "", output_dir: str = "") -> dict:
if not file_path:
return {"status": "error", "message": "file_path required"}
Четыре абсолютных запрета:
- ✕ Хардкодить пути, ключи, ID — всё через параметры
- ✕ *args/**kwargs в сигнатуре — только явные именованные параметры
- ✕ Возвращать бинарные данные — только путь к файлу
- ✕ Четвёртый запрет: эксперт никогда не обращается к KV Store сам
Эксперт не должен внутри своего кода вызывать /api/kv/get или любой другой Extella API для получения credentials. Это нарушает изоляцию и создаёт скрытую зависимость от облака.
| ✕ Запрещено — эксперт тянет KV сам | ✓ Правильно — агент инжектирует через params |
|---|---|
| def send_msg(chat_id): r = requests.get('/api/kv/get') token = r.json()['value'] # ... использует token | def send_msg(chat_id, bot_token=''): if not bot_token: return {'status': 'error'} # использует bot_token напрямую |
Правильная схема: агент получает credentials из KV через MCP (kv_get/kv_search) и передаёт значения в эксперт параметрами при запуске:
# Агент (вне кода эксперта):
token = kv_get('telegram_bot_token')['value'] # агент расшифровывает через PIN
run_expert('send_telegram', {'chat_id': id, 'bot_token': token}) # инжектирует
Эксперт = чистая логика без внешних вызовов. Данные и credentials = параметры от агента.
4.8. CLI-обёртки: 5 строк вместо 50
Пример: ImageMagick через subprocess:
$extens("include.py")
include("import subprocess", [])
def resize_image(input_path: str="", output_path: str="", width: int=800, height: int=600) -> dict:
import subprocess
if not input_path:
return {"status": "error", "message": "input_path required"}
size = str(width) + "x" + str(height)
cmd = ["convert", input_path, "-resize", size, output_path]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
return {"status": "error", "stderr": result.stderr}
return {"status": "success", "output": output_path}
ffmpeg, pandoc, git, docker, rsync — всё это может стать экспертом в 5-10 строк.
4.9. Cron-задания: автоматизация по расписанию
Cron-задание — это nohup-эксперт, запускающийся по расписанию. Создаётся одной фразой:
«Создай задание: каждое утро в 9:00 делай сводку метрик сервера»
Агент создаст фоновый процесс — никаких crontab-файлов, никаких YAML. Важно:
- Cron работает через Listener — устройство должно быть включено
- Логи: /tmp/nohup_<имя>.log
- Остановить: «Останови Cron-задание <название>»
- При перезагрузке — нужно перезапустить вручную
Как технически остановить Cron-задание
Cron-задание — это nohup-процесс ОС. Работает независимо от чата и Listener. Три способа остановки:
| Способ | Команда / действие | Когда |
|---|---|---|
| Через агента (рекомендуется) | «Останови Cron-задание <название>» — агент найдёт PID из .pid-файла и отправит SIGTERM | Основной способ |
| Через Listener UI | Вкладка Listener → найти процесс → кнопка Cancel | Если агент недоступен |
| Вручную через терминал | kill $(cat /tmp/nohup_<имя>.pid) или: kill <PID> | Экстренная остановка |
Диагностика — найти PID и логи запущенного задания:
cat /tmp/nohup_<имя>.pid # PID процесса
tail -f /tmp/nohup_<имя>.log # логи в реальном времени
ps aux | grep <имя> # проверить, жив ли процесс
При перезагрузке устройства nohup-процесс завершается. PID-файл остаётся, но ссылается на несуществующий процесс. Для автозапуска при рестарте — добавьте запуск эксперта в launchd (macOS) или systemd (Linux).
| Паттерн | Команда | Cron | Что делает |
|---|---|---|---|
| Мониторинг | «Каждые 5 минут проверяй доступность example.com» | */5 * * * * | Ping, KV-запись, уведомление при падении |
| Ежедневная сводка | «В 9:00 — сводка метрик сервера» | 0 9 * * * | Метрики, отчёт, концепт дня |
| Еженедельный анализ | «В воскресенье в 18:00 — анализ ошибок недели» | 0 18 * * 0 | Агрегация логов, концепты-паттерны |
| Ежемесячный аудит | «Первого числа в 10:00 — аудит токенов» | 0 10 1 * * | Сканирование токенов, отчёт |
Самоулучшающийся цикл: Cron-агент записывает концепты. На следующей неделе использует их как контекст. Через год — эксперт по истории проблем вашей системы.
Агенты и команды
Теперь, когда вы знаете Experts, Concepts, KV Store и Rules — самое время разобраться, как они объединяются в агентах и командах. Этот раздел раскрывает мощь многоагентной оркестрации, полные возможности настройки агентов на Pro-плане и то, как собрать собственную команду AI-специалистов.
5.1. Что такое агент
Агент — AI-специалист с конкретной ролью, собственной памятью и набором инструментов. В отличие от обычного чат-бота, агент — настроенная сущность: он знает свою специализацию, помнит историю взаимодействий и умеет выполнять реальные действия. Агент состоит из:
- Модели — Claude, Gemini, Qwen, Llama, GPT — вы выбираете сами
- Системных инструкций (instructions) — специализация, стиль работы и границы
- Набора инструментов (tools) — MCP-функции: concept_add, run_expert, web_search, kv_get и др.
- Профиля — изолированного рабочего пространства, в которое он входит
- Памяти — Concepts (знания), KV Store (данные и ключи), Rules (правила поведения)
Один агент может выполнять сотни задач. Несколько агентов в команде — целый специализированный отдел. Каждый агент — это отточенный инструмент под конкретную область, а не универсальный швейцарский нож.
5.2. Создание и конфигурация агента
В Plus и Flex планах дефолтный агент (или несколько агентов) подаётся в преднастроенном виде, где системный промпт и все параметры уже заданы и пользователю не нужно ничего делать. Единственное отличие Plus от Flex состоит в том, что во втором случае пользователь может использовать свой собственных ключ от LLM провайдера, а не платить кредитами за использование ключа Extella.
На Pro-плане пользователь получает полный контроль над каждым параметром агента. Это принципиальный сдвиг: вместо того чтобы принять агента из коробки, вы становитесь его архитектором. Настроить собственного агента можно в правой (выдвигающейся) панели интерфейса чатбота.
| Параметр | Что настраивается | Пример использования |
|---|---|---|
| Модель | GPT-4o, Claude Opus, Gemini Pro, Mistral, локальные через Ollama и др. | Claude Opus для глубокого анализа документов |
| System prompt | Точная инструкция: роль, стиль, границы, специализация | «Ты финансовый аналитик. Отвечай только в JSON.» |
| Temperature | Баланс точность <→ креативность (0.0 = предсказуемо, 1.0 = творчески) | 0.2 для аналитики; 0.9 для копирайтинга |
| Top-P / Top-K | Управление распределением вероятностей токенов | Top-P 0.9 для разнообразного текста |
| Max tokens | Максимальная длина ответа | 4096 для документов; 512 для кратких ответов |
| Tools & MCP | Какие инструменты доступны агенту | Только финансовые инструменты для финансиста |
| Memory settings | Какой тип памяти использует: концепты, правила, KV | Долгосрочная память + тематические концепты |
| Rules setting | Какие правила применяются в каких ситуациях | «При неопределённости — уточняй перед действием» |
| Response format | Структура вывода: текст, JSON, markdown, схема | Строгий JSON для интеграции с CRM-системой |
Примеры специализированных агентов
- Агент-аналитик: Claude Opus, temperature 0.2, только JSON-вывод, только финансовые инструменты
- Агент-копирайтер: GPT-4o, temperature 0.9, без инструментов, детальный brand voice в промпте
- Агент-ревьюер кода: Mistral, минимальный контекст, чеклист безопасности в системном промпте
- Агент-исследователь: Gemini, web_search + concept_add, максимальный контекст, высокий recursion_limit
Переиспользование: настроил один раз — используешь постоянно
Настроенные агенты сохраняются в библиотеке и доступны из выпадающего списка в любой момент. Не нужно каждый раз вставлять промпт или выбирать параметры — агент уже знает, кто он и что умеет. Рабочий процесс меняется: вместо «создать агента под задачу» вы думаете «выбрать нужного из своей библиотеки».
Лимиты на Pro-плане на количество агентов
Pro план никак не ограничивает количество независимых агентов, которые может создать пользователь.
5.3. Три паттерна взаимодействия агентов
1. Рекурсия — агент вызывает себя итеративно
Агент обрабатывает данные порциями, вызывая себя с уточнёнными параметрами. Каждая итерация — чистый контекст. Защита от бесконечного цикла — параметр recursion_limit при создании агента (рекомендуется 5–15).
Пример: CTO проверяет 47 API-endpoints на наличие тестов, по 15 за итерацию. Итерация 1: 1–15 (12 покрыты, 3 нет). Итерация 2: 16–30 (14 покрыты, 1 нет). Итерация 3: 31–47 (13 покрыты, 4 нет). Финальный отчёт: 39/47 покрыты (83%), 8 требуют тестов.
2. Эскалация — подагент сигнализирует оркестратору
Когда специализированный агент встречает ситуацию вне своей компетенции — он эскалирует обратно оркестратору. Оркестратор решает: перераспределить задачу, привлечь другого специалиста или изменить параметры делегирования.
Пример: CCO анализирует конкурентов и обнаруживает новость о $50M раунде Series B конкурента. Это стратегический фактор — CCO эскалирует оркестратору: «Обнаружен новый конкурентный фактор. Рекомендую пересмотреть позиционирование.» Оркестратор привлекает Corporate Director.
3. Кросс-вызовы — агенты одного уровня
Агенты обращаются друг к другу напрямую без посредника — когда для задачи нужны данные из смежной области. Технически — через MCP-инструмент agent_run с заранее известным agent_id целевого агента. Все вызовы логируются.
Пример: CTO напрямую спрашивает Corporate Director: «Оцени инфраструктурные затраты: 3 микросервиса, GPU A10G, 10K запросов/день.» Получает ответ $2,400/месяц и включает его в архитектурный документ без лишних hops через оркестратора.
5.4. Teams — многоагентные системы с делегированием
В традиционных платформах один агент «пытается быть всем для всех». Его контекстное окно быстро заполняется нерелевантными данными. Чем дольше сессия — тем менее точные ответы.
Extella решает это иначе – через создание Команды (Team) совместно работающей над одним проектом: агент-оркестратор получает задачу, делит её на подзадачи и делегирует каждую специализированному агенту — в чистом, полностью релевантном контексте. Каждый специалист фокусируется только на своей области.
Пример: задача «проанализируй продукт, подготовь конкурентный анализ, финансовую модель и питч для раунда Seed»:
| Шаг | Агент | Чистый контекст |
|---|---|---|
| Конкурентный анализ | CCO | Рыночные данные, G2/Gartner, ценовые модели конкурентов |
| Техническая реализуемость | CTO | Архитектура платформы, ML-модели, интеграции, стоимость |
| Финансовая модель | Corporate Director | Оценка CTO + inference costs + CAC/LTV бенчмарки |
| Питч-дека | CCO | Конкурентный анализ (шаг 1) + финансовая модель (шаг 3) |
| Синтез | Оркестратор | Все результаты: конкурентный анализ + техника + финансы + питч |
У каждого агента свои эксперты, свои KV, Concepts и Rules. Каждый фокусируется на своей экспертизе. Итог — не размытый универсальный ответ, а структурированный документ, где каждый раздел подготовлен специалистом.
Ключевое преимущество: агент-специалист с чистым контекстом 32К токенов принимает более точные решения, чем универсальный агент с переполненным контекстом 200К токенов.
Team в платформе Extella — система из нескольких агентов, которая работает как единое целое. Вы направляете задачу в Team, и она сама определяет, кому из агентов её передать — или как разбить между несколькими.
Что есть у каждой Team
- Цель и контекст — для чего создана, что делает хорошо
- Участники с ролями — каждый агент знает свою роль (Research, Writing, Review, Execution и др.)
- Собственные Concepts — база знаний, специфичная только для этой Team
- Собственные Rules — поведенческие правила, применяемые внутри системы
- Orchestration prompt — логика делегирования: по каким критериям задача передаётся агенту
Как Team принимает решения
Team работает в режиме auto: получив задачу, оркестратор анализирует её, сопоставляет с ролями участников и правилами делегирования, затем передаёт нужному агенту (или нескольким параллельно). Человек не участвует в этом распределении.
В будущем механизм делегирования будет улучшен за счёт обученной RL-модели, которая на основе накопленного опыта Team будет принимать решения быстрее и точнее.
Один агент — в нескольких Teams одновременно
Team не дублирует агентов — она ссылается на них. Важно понимать: у Team нет собственного отдельного контекста. Контекст Team — это суммарный контекст всех агентов в ней. Каждый агент сохраняет свои преднастроенные правила, концепты и системный промпт независимо от того, в какую Team он включён. Именно поэтому нельзя использовать одного и того же агента для принципиально разных задач в разных Teams: он всегда будет действовать согласно своей базовой конфигурации.
Примеры Teams
| Team | Участники (роли) | Для чего создана |
|---|---|---|
| Content Studio | Research → Writer → Editor → SEO-reviewer | Создание контент-материалов от исследования до публикации |
| Due Diligence | Financial Analyst + Legal Reviewer + Market Researcher | Сбор и синтез данных по компании для инвестиционного решения |
| Product Sprint | PM + Tech Lead + UX Reviewer | Разбор задач и формирование технических спецификаций |
| Personal Knowledge Base | Collector + Summarizer + Tagger | Структурирование входящей информации в персональную базу знаний |
Лимиты на Pro-плане на количество агентов
Лимит на создание Teams — максимум до 3. Количество агентов внутри каждой Команды ограничены до 5.
5.5. Интерфейс: My Agents и My Teams
На Pro-плане выпадающий список агентов в левой верхней панели интерфейса приобретает структуру:
▼ Default Agents
• Extella Claude Sonnet (преднастроенный)
• Extella GPT-5 (преднастроенный)
▼ My Agents
• Financial Analyst (ваш агент)
• Copywriter (ваш агент)
• Code Reviewer (ваш агент)
▼ My Teams
• Content Studio (ваша команда)
• Due Diligence (ваша команда)
• Product Sprint (ваша команда)
Каждая группа раскрываема. Любой агент и любая Team кликабельны — выбор назначает их для текущего чата. Важно: можно выбрать как Team целиком, так и отдельного агента.
Создание нового агента
Откройте правую панель настроек чатбота — секция Agent Builder содержит поля конфигурации агента: имя, модель, провайдер, system prompt, температура, инструменты. Также агента можно создать и настроить через чат — расскажите Extella, какого агента хотите создать, и она сделает всё сама.
Создание новой Team
Откройте правую панель настроек чатбота — секция Team Builder. В ней вы можете создать команду, присвоить ей название и назначить в её состав имеющихся в распоряжении агентов, определив мастер (или оркестрирующего) агента, который будет отвечать за менеджмент Команды. Настройка Team и наполнение её правилами и концептами происходит непосредственно через чат с Extella.
5.6. Создание и настройка Team через взаимодействие с Extella
Альтернативно интерфейсной настройке Team можно создать и настроить через взаимодействие с чатботом. Пользователь описывает словами, что хочет получить.
Extella через ризонинг формирует объект Team и сохраняет его.
Что описывает пользователь
- Цель Team — для каких задач создаётся, что должна делать хорошо
- Состав — каких агентов включить (из уже настроенных или новых)
- Роли — кто за что отвечает внутри системы
- Правила — как Team должна себя вести, что учитывать при делегировании
- Знания — специфический контекст, который нужен агентам системы
Пользователь может описать всё сразу или отвечать на уточняющие вопросы Extella.
Что делает Extella при создании Team
| Шаг | Что происходит автоматически |
|---|---|
| Определяет состав | Выбирает подходящих агентов из библиотеки. Если нужного нет — предлагает создать или использовать Extella Agents |
| Назначает роли | Формирует описание роли каждого агента внутри Team |
| Создаёт orchestration prompt | Инструкция для оркестратора: как распределять задачи, какие критерии учитывать |
| Создаёт Concepts Team | Сохраняет специфический контекст и знания, переданные пользователем |
| Создаёт Rules Team | Фиксирует поведенческие правила системы |
| Сохраняет Team | Объект появляется в списке My Teams в выпадающем меню |
Пример диалога создания Team
Пользователь:
«Создай команду для контент-маркетинга. Нужны: исследователь (собирает данные о теме), автор (пишет текст), редактор (проверяет стиль), SEO-специалист (оптимизирует). Работают последовательно. Правило: финальный текст должен содержать не менее 3 ключевых слов из брифа.»
Extella:
«Создаю Team Content Studio с четырьмя агентами. Назначаю цепочку: Researcher → Writer → Editor → SEO. Добавляю правило о ключевых словах в Rules Team. Готово — Content Studio появился в My Teams.»
Редактирование Team через чат
В любой момент напишите Extella в чате:
- «Добавь в Content Studio агента по соцсетям» — Extella добавит агента с ролью Social Media
- «Измени роль Researcher — теперь он отвечает за поиск статистики» — Extella обновит роль
- «Добавь правило: проверять факты через два источника» — Extella добавит правило в Rules Team
- «Убери Editor из Due Diligence» — Extella удалит агента из Team (сам агент сохранится)
5.7. Изоляция данных: два уровня
На Pro-плане данные агента (Concepts, Rules, KV Store, Experts) изолированы по умолчанию и не смешиваются с данными других агентов. Видимостью управляет параметр global, доступный в большинстве MCP-инструментов и REST-эндпоинтов.
| Уровень | Что охватывает | Параметр | По умолчанию |
|---|---|---|---|
| Agent | Только текущий агент | global=false | ✓ да |
| Profile | Все агенты внутри одного профиля | global=true | — |
Как это работает на практике:
global=false (по умолчанию) — агент видит только свои Concepts, Rules, KV-пары и Experts. Данные других агентов недоступны, даже если они в одном профиле.
global=true — агент видит данные всех агентов профиля. Используется, когда нужно разделить общую базу знаний внутри команды.
Важный принцип: изоляция — это не иерархия. Данные не «просачиваются» вверх или вниз автоматически. Разработчик или агент явно управляет областью видимости через global при каждом вызове.
Пример:
# Добавить концепт только для текущего агента (default)
concept_add(text="...", global=False)
# Найти концепт в любом агенте профиля
concept_search(query="...", global=True)
Примечание: Profile (Team) — это контейнер для агентов, а не отдельный уровень хранилища. Отдельного «Team-хранилища» для Concepts или Rules не существует.
5.8. Реальные агенты системы Extella
Ниже — реальные агенты, работающие в системе Extella. Каждый — специалист в своей области с собственной конфигурацией, инструментами и моделью.
| Имя агента | Модель | Специализация |
|---|---|---|
| Extella (CEO) | Claude Sonnet 4.6 | Главный оркестратор: делегирование, стратегия, синтез результатов |
| CCO | Gemini 2.5 Flash | B2B продажи, GTM-стратегия, конкурентный анализ, питчи, ценообразование |
| CTO | Gemini 2.5 Flash | Архитектура платформы, CSPL-эксперты, API, безопасность, инфраструктура |
| Corporate Director | Qwen 3.6 Plus | Финансы, legal, compliance, структура капитала, инвесторы |
| Extella Architect | Qwen 3.6 Plus (NVIDIA) | Сложный reasoning, глубокий архитектурный анализ |
| Llama 4 Maverick | Llama 4 Maverick | 1M контекст, multimodal, параллельная обработка больших объёмов |
| Step 3.5 Flash | Step 3.5 Flash | 196B MoE, 262K контекст — массовая обработка, написание разделов |
| Llama 3.3 70B | Llama 3.3 70B (Groq) | Сверхбыстрый инференс (300+ токен/сек) — срочные задачи |
| Architect R1 | DeepSeek R1 | Chain-of-thought reasoning, сложные логические задачи, планирование |
| Auto Router | Auto Router (OpenRouter) | Автоматический выбор оптимальной модели + fallback-цепочка |
Воркеры (Llama, Step, DeepSeek, Qwen) используются оркестратором для параллельной обработки: написание 10 разделов одновременно, анализ 5 конкурентов, генерация 20 вариантов питчей. Это «вычислительные мышцы» системы.
5.9. Рост агента во времени
Агент в Extella — не статический инструмент. Он растёт как реальный сотрудник: накапливает знания в концептах, правила в Rules, паттерны в KV Store. С каждой неделей работы становится умнее и точнее.
| Этап | Состояние агента | Что происходит | Пример |
|---|---|---|---|
| День 1 | Пустой профиль | Компетентен как хорошая LLM, но не знает ваш бизнес | CTO пишет Python, но не знает вашу архитектуру |
| Неделя 2 | 15-30 концептов, 5-10 правил | Знает стиль кода, типичные ошибки, предпочтения команды | «В проекте FastAPI+PostgreSQL+Redis. Миграции — Alembic.» |
| Месяц 3 | 100-300 концептов, Cron-паттерны | Предлагает решения из истории проекта, предсказывает проблемы | «Добавь кэширование» → сразу предлагает Redis-паттерн, который вы уже используете |
| Месяц 6 | 500+ концептов, автономная работа | Эксперт по проекту. Принимает решения без дополнительного контекста | Автономно предупреждает о деградации по историческим данным |
Путь к автономии:
- День 1: «Что вы используете для БД?»
- Неделя 2: «Рекомендую PostgreSQL, как вы уже используете»
- Месяц 3: «Добавлю Redis-кэш, аналогично модулю auth»
- Месяц 6: Агент сам предлагает изменения, реализует их, отчитывается — без дополнительного контекста
Экспорт диалогов агента
После 6 месяцев работы вы можете экспортировать все диалоги:
POST https://prod.extella.ai/api/agent/export/chats
Authorization: Bearer <your-token>
// По агенту:
{"by": "agent", "id": "agent_xyz..."}
// По профилю (все агенты):
{"by": "profile", "id": "team_abc..."}
Полученный JSON с тысячами QA-пар и обсуждений — ценный датасет для анализа качества или fine-tuning. Сам процесс обучения выполняется вне платформы Extella — на вашей инфраструктуре или через внешние сервисы.
Локальные модели и туннели
6.1. Зачем вообще нужен туннель?
В Разделе 5 вы узнали, что агенту можно подключить любую языковую модель — включая локальную, запущенную прямо на вашем ноутбуке или домашнем сервере. Это открывает огромные возможности: полная конфиденциальность данных, нулевая стоимость инференса, любые некензурированные модели, работа офлайн.
Но есть одна техническая деталь: локальные LLM-серверы (Ollama, LM Studio, llama.cpp и др.) по умолчанию слушают только localhost — адрес доступен только с того же устройства. Extella работает как облачный сервис и физически не может достучаться до вашего localhost напрямую.
Решение — туннель. Это программа, которая создаёт зашифрованный «мост» между вашим устройством и публичным HTTPS-адресом в интернете. Extella обращается к публичному адресу — туннель прозрачно перенаправляет запрос на ваш localhost. Для Extella это выглядит как обычный API-сервер в облаке.
| Сценарий | Без туннеля | С туннелем |
|---|---|---|
| Extella + локальная модель | ✕ Недостижимо | ✓ Работает через публичный URL |
| Доступ с телефона | ✕ Только localhost | ✓ Любое устройство |
| Демонстрация коллеге | ✕ Нужен VPN или присутствие | ✓ Просто скинуть URL |
| CI/CD интеграция | ✕ Нет публичного адреса | ✓ webhook + туннель |
Туннель не делает модель медленнее — он добавляет лишь 10–50ms сетевой задержки. Для текстовой генерации это незаметно.
6.2. Порты и базовый API URL
Каждый LLM-сервер слушает свой порт. Это важно знать при создании туннеля — нужно туннелировать именно тот порт, на котором работает ваша модель.
| Сервер | Порт | Базовый API URL (локальный) |
|---|---|---|
| LM Studio | 1234 | http://localhost:1234/v1/ |
| llama.cpp server | 8080 | http://localhost:8080/v1/ |
| Ollama | 11434 | http://localhost:11434/v1/ |
| Jan | 1337 | http://localhost:1337/v1/ |
| KoboldCPP | 5001 | http://localhost:5001/v1/ |
| LocalAI | 8080 | http://localhost:8080/v1/ |
Золотое правило: в поле baseURL в Extella всегда указывайте URL только до /v1/ включительно — и ничего дальше. Extella сама добавит нужный путь (/chat/completions, /embeddings и т.д.).
✓ Правильно: https://abc123.ngrok-free.app/v1/
✕ Неправильно: https://abc123.ngrok-free.app/v1/chat/completions
Ошибка с лишним эндпоинтом — самая частая причина, по которой локальная модель «не отвечает» в Extella. Проверяйте в первую очередь.
6.3. Три метода туннелирования: что выбрать
Существует несколько инструментов. Рекомендации по выбору:
| Метод | Бесплатно | Постоянный URL | Сложность | Лучший для |
|---|---|---|---|---|
| ngrok | Ограниченно* | Платно / статич. | Просто | Быстрый старт, тест |
| Cloudflare Tunnel | ✓ Полностью | ✓ Свой домен | Средне | Постоянная работа |
| LocalTunnel | ✓ Полностью | Частично | Просто | Быстрый тест без регистрации |
| Tailscale Funnel | ✓ Бесплатно | ✓ Стабильный | Средне | Если уже используете Tailscale |
* ngrok бесплатно даёт один туннель с рандомным URL. Статический домен — бесплатно с регистрацией (один домен).
Для большинства пользователей Extella рекомендую начать с ngrok (5 минут до результата), а при регулярном использовании перейти на Cloudflare Tunnel — он бесплатный, надёжный и поддерживает свой домен.
6.4. Метод 1: ngrok — самый быстрый старт
ngrok — самый простой способ получить рабочий публичный URL за 2–3 минуты. Отличный выбор для первого знакомства с темой или периодических задач.
Установка
| ОС | Команда |
|---|---|
| macOS (Homebrew) | brew install ngrok/ngrok/ngrok |
| Linux (Debian/Ubuntu) | sudo apt install ngrok (после добавления репозитория — см. ниже) |
| Windows | winget install ngrok |
Linux:
# Linux — полная установка:
curl -sSL https://ngrok-agent.s3.amazonaws.com/ngrok.asc \
| sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null
echo "deb https://ngrok-agent.s3.amazonaws.com buster main" \
| sudo tee /etc/apt/sources.list.d/ngrok.list
sudo apt update && sudo apt install ngrok
Регистрация (один раз)
ngrok требует бесплатную регистрацию на ngrok.com. После этого:
Добавить токен (скопировать из Dashboard → Your Authtoken):
ngrok config add-authtoken YOUR_TOKEN_HERE
Без токена туннель тоже работает, но ограничен по времени сессии. С токеном — без ограничений.
Запуск туннеля
Одна команда — туннель готов:
ngrok http 1234 # LM Studio
ngrok http 8080 # llama.cpp
ngrok http 11434 # Ollama
После запуска в терминале появится строка вида:
Forwarding https://abc123.ngrok-free.app -> http://localhost:1234
Ваш базовый API URL для Extella: https://abc123.ngrok-free.app/v1/
Статический URL (бесплатно)
Рандомный URL меняется при каждом перезапуске — неудобно, если URL записан в Extella. Решение — статический домен:
ngrok http --domain=your-static-name.ngrok-free.app 1234
Один статический домен бесплатен. Зарегистрировать его можно в Dashboard → Domains.
Защита паролем (рекомендуется)
Публичный URL без защиты означает, что любой в интернете может отправлять запросы вашей модели. Добавьте базовую аутентификацию:
ngrok http --basic-auth="user:strongpassword" 1234
Не оставляйте туннель открытым без аутентификации надолго. Боты активно сканируют известные ngrok-домены.
6.5. Метод 2: Cloudflare Tunnel — для постоянной работы
Cloudflare Tunnel (cloudflared) — промышленное решение от Cloudflare. Полностью бесплатное, без ограничений трафика, поддерживает привязку своего домена. Идеально, если вы планируете использовать локальную модель в Extella регулярно.
Ключевое преимущество перед ngrok: туннель не зависит от открытых портов в роутере и работает даже за двойным NAT (корпоративная сеть, мобильный интернет и т.д.).
Установка cloudflared
macOS / Windows:
brew install cloudflare/cloudflare/cloudflared # macOS
winget install Cloudflare.cloudflared # Windows
Linux (Debian/Ubuntu):
curl -L --output cloudflared.deb \
https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared.deb
Способ A: Быстрый туннель без регистрации
Если нужно быстро проверить — запустите без аккаунта:
cloudflared tunnel --url http://localhost:1234 # LM Studio
cloudflared tunnel --url http://localhost:11434 # Ollama
URL будет вида: https://some-random-name.trycloudflare.com/v1/
URL меняется при каждом перезапуске. Способ B даёт постоянный адрес.
Способ B: Постоянный туннель со своим доменом
Для постоянной работы нужна регистрация на cloudflare.com (бесплатно) и свой домен (или поддомен).
Шаг 1 — авторизация:
cloudflared tunnel login
Шаг 2 — создать туннель:
cloudflared tunnel create my-llm-tunnel
Шаг 3 — создать файл ~/.cloudflared/config.yml:
tunnel: <TUNNEL_ID>
credentials-file: /Users/YOUR_USER/.cloudflared/<TUNNEL_ID>.json
ingress:
- hostname: llm.yourdomain.com
service: http://localhost:1234
- service: http_status:404
Шаг 4 — настроить DNS:
cloudflared tunnel route dns my-llm-tunnel llm.yourdomain.com
Шаг 5 — запустить:
cloudflared tunnel run my-llm-tunnel
Ваш постоянный URL: https://llm.yourdomain.com/v1/
Автозапуск при старте системы
sudo cloudflared service install
sudo systemctl start cloudflared # Linux
# macOS: launchd-сервис создаётся автоматически
После автозапуска туннель поднимается при каждой загрузке системы. URL в Extella можно прописать один раз и забыть.
6.6. Метод 3: Альтернативы
LocalTunnel — проще некуда (Node.js)
Если ngrok кажется избыточным, а Node.js уже установлен:
npm install -g localtunnel
lt --port 1234 --subdomain my-llm
URL: https://my-llm.loca.lt/v1/ — субдомен запоминается, если имя свободно.
LocalTunnel менее стабилен, чем ngrok или Cloudflare. Подходит для разовых тестов.
Tailscale Funnel
Если вы уже используете Tailscale для VPN-сети — Funnel открывает доступ из интернета одной командой:
tailscale funnel 1234
URL формируется из имени устройства в Tailscale. Очень удобно, если Tailscale уже настроен.
6.7. Подключение к Extella: пошаговая инструкция
После того как туннель запущен и у вас есть публичный URL — добавляете модель в Extella как кастомный провайдер. Это делается в настройках агента (Раздел 5).
| Поле в Extella | Что вводить | Пример |
|---|---|---|
| provider | custom | custom |
| baseURL | URL туннеля + /v1/ | https://abc123.ngrok-free.app/v1/ |
| apiKey | Любая строка (модель не проверяет) | lm-studio или ollama |
| model | Название модели на сервере | llama-3.2-3b-instruct |
Название модели в поле model должно совпадать с тем, как модель называется на сервере. В LM Studio — это имя файла модели. В Ollama — вывод команды ollama list.
После сохранения агент будет использовать вашу локальную модель для всех запросов. При этом Concepts, KV Store, Rules и все эксперты работают точно так же — они хранятся в облаке Extella, только инференс (генерация текста) идёт через вашу модель.
6.8. Настройки локальных серверов
Прежде чем создавать туннель — убедитесь, что сервер принимает внешние подключения. По умолчанию большинство серверов слушают только localhost и отклонят запросы через туннель.
LM Studio
- Откройте вкладку Local Server
- Включите ✓ Enable CORS
- Включите ✓ Allow connections from network
- Нажмите Start Server
Без Enable CORS запросы от Extella будут отклонены браузером с ошибкой CORS policy. Это частая ловушка.
llama.cpp — параметры запуска сервера
Запуск с принятием внешних подключений:
./llama-server \
-m ./models/your-model.gguf \
--port 8080 \
--host 0.0.0.0 \
-c 4096 \
-ngl 35
Ключевой параметр: --host 0.0.0.0 (принимать от всех, а не только localhost). -ngl 35 — количество слоёв на GPU (подбирается под вашу карту).
Ollama — разрешить внешние подключения
По умолчанию Ollama принимает только localhost. Нужно изменить переменную окружения:
macOS / Linux (временно):
OLLAMA_HOST=0.0.0.0 ollama serve
Linux (постоянно через systemd):
sudo systemctl edit ollama
# Добавить в секцию [Service]:
Environment="OLLAMA_HOST=0.0.0.0"
После изменения OLLAMA_HOST перезапустите службу: sudo systemctl restart ollama
6.9. Безопасность и производительность
Безопасность — обязательно прочитать
Публичный URL без защиты означает, что любой желающий может использовать вашу модель — бесплатно за ваш счёт CPU/GPU. Это не теоретическая угроза: боты активно ищут открытые LLM-эндпоинты.
| Угроза | Решение |
|---|---|
| Несанкционированный доступ к модели | ngrok --basic-auth или Cloudflare Access |
| Перехват данных | Туннели используют HTTPS — данные зашифрованы |
| Утечка промптов | Не туннелируйте модель без необходимости, используйте vpn-сети (Tailscale) |
| DDoS на модель | Rate limiting в Cloudflare или ngrok Pro |
Самый простой вариант защиты — ngrok --basic-auth. Extella поддерживает базовую аутентификацию: укажите в apiKey строку вида user:password в формате Base64.
Производительность
- Туннель добавляет 10–50ms задержки. Для текстовой генерации незаметно.
- Для длинных ответов используйте streaming — пользователь видит текст по мере генерации, а не ждёт конца.
- Убедитесь, что LLM-сервер запущен до старта туннеля — иначе туннель создастся, но запросы будут падать.
- GPU-ускорение остаётся на вашей машине — туннель не влияет на скорость инференса.
6.10. Быстрая шпаргалка
| Инструмент | Команда | Тип URL | Рекомендация |
|---|---|---|---|
| ngrok | ngrok http 1234 | Случайный / статич. | Лучший старт |
| cloudflared (быстро) | cloudflared tunnel --url http://localhost:1234 | Случайный | Тест без регистрации |
| cloudflared (постоянный) | через config.yml + свой домен | Постоянный | Для регулярного использования |
| LocalTunnel | lt --port 1234 --subdomain my-llm | Случайный / субдомен | Быстрый разовый тест |
| Tailscale Funnel | tailscale funnel 1234 | Постоянный | Если Tailscale уже есть |
Итог в одном предложении: запустите ngrok http <порт>, возьмите URL из вывода, добавьте /v1/ в конце, вставьте в поле baseURL в настройках агента Extella — и ваша локальная модель готова к работе.
Параллельное выполнение: в 10 раз быстрее
7.1. Физика параллельности
Формула проста:
Последовательно: T = T1 + T2 + T3 + ... + TN
Параллельно: T = max(T1, T2, T3, ..., TN) + ~1 сек опроса
| Сценарий | Последовательно | parallel_task | Ускорение |
|---|---|---|---|
| 3 задачи x 15 сек | 45 сек | 16 сек | 2.8x |
| 5 задач x 20 сек | 100 сек | 21 сек | 4.8x |
| 10 задач x 30 сек | 300 сек (5 мин) | 31 сек | 9.7x |
| 20 задач x 30 сек | 600 сек (10 мин) | 31 сек | 19.4x |
Это не оптимизация — это смена формулы. Claude Code думает как LLM — последовательно. Extella parallel_task думает как железо — параллельно. Современный CPU имеет несколько ядер, каждый из которых выполняет независимые задачи одновременно.
7.2. Пять проблем синхронного режима
Проблема 1: Таймаут — результат потерян
Большинство синхронных LLM-агентов имеют жёсткий таймаут ~5 минут. Обработка 1000 файлов? Обучение? Глубокий анализ? — результат теряется без предупреждения. В parallel_task каждый воркер независим от LLM-соединения. Даже если соединение оборвётся, процесс ОС продолжает работать.
Проблема 2: Линейное накопление времени
| Задачи | Синхронно | Параллельно | Потерянное время |
|---|---|---|---|
| 2 x 30s | 60s | 31s | 29s |
| 5 x 30s | 150s | 31s | 119s |
| 10 x 30s | 300s | 31s | 269s |
Проблема 3: Невозможность отмены
В синхронном режиме нет кнопки Cancel. Заметили ошибку на 3-й секунде из 300 — всё равно ждёте. В Task Registry каждая задача имеет кнопку ✕ (SIGTERM по PID) — мгновенная остановка.
Проблема 4: Отсутствие видимости
В parallel_task каждая задача записывает статус в /tmp/pt_{uuid}.json. Агент может в любой момент прочитать файл и узнать состояние задачи: running, complete, error. Для наглядной визуализации можно опционально развернуть task_registry_server — кастомный Flask-эксперт с HTML-дашбордом (подробнее — п.7.3).
Проблема 5: Потеря traceback при ошибке
При синхронном падении — общее сообщение без контекста. В Extella каждая parallel_task-задача пишет полный traceback в файл /tmp/pt_{uuid}.json (поле error). Если запущен task_registry_server — traceback также доступен через GET /tasks/<uuid>.
7.3. Статусы задач и диагностика
Состояние каждой parallel_task-задачи хранится в файле /tmp/pt_{uuid}.json на устройстве. Это основной и единственный гарантированный механизм отслеживания — он работает без дополнительных компонентов.
| Поле в файле | Значение | Смысл |
|---|---|---|
| status | "running" | Задача выполняется |
| status | "complete" | Задача завершена успешно |
| status | "error" | Задача завершилась с ошибкой |
| result | dict от воркера | Результат (только при complete) |
| error | traceback string | Подробности ошибки (только при error) |
Пример: прочитать статус задачи вручную:
import json
from pathlib import Path
data = json.loads(Path(f'/tmp/pt_{uuid}.json').read_text())
print(data['status']) # 'running' / 'complete' / 'error'
print(data.get('result')) # результат воркера, если complete
7.3.1. Опциональный визуальный дашборд — task_registry_server
task_registry_server — это не встроенный интерфейс платформы, а отдельный кастомный эксперт (Flask-приложение), который можно запустить для наглядного мониторинга задач в браузере. Он не является обязательным: parallel_task и wait_tasks работают без него.
task_registry_server — кастомный компонент. Если он не был создан агентом в вашем аккаунте — попросите агента: «Создай task_registry_server для мониторинга параллельных задач».
Если task_registry_server запущен, он предоставляет:
| Возможность | Описание |
|---|---|
| HTML UI | Страница в браузере: http://localhost:7755 — список задач с авто-обновлением |
| GET /tasks | JSON со всеми задачами |
| GET /tasks/<uuid> | Детали конкретной задачи + логи |
| DELETE /cancel/<uuid> | SIGTERM по PID задачи → статус cancelled |
| POST /clear | Очистить все записи |
| GET /health | {ok: true, port: 7755, tasks: N} |
Запуск и управление (если эксперт создан):
# Запуск:
run_expert('task_registry_server')
# -> {"status": "success", "url": "http://localhost:7755/", "port": 7755}
# Если уже запущен:
# {"status": "already_running", "port": 7755, "tasks": 3}
# Принудительный перезапуск:
run_expert('task_registry_server', {'force_restart': '1'})
Персистентность: task_registry_server хранит состояние всех задач в /tmp/extella_task_registry.json. При рестарте сервера файл перечитывается — все записи восстанавливаются. Без task_registry_server состояние хранится только в /tmp/pt_{uuid}.json.
7.4. UUID против PID: фундаментальное дизайнерское решение
Почему не просто использовать PID процесса?
ОС переиспользует PID. Процесс завершился с PID 12345 — через секунду новый процесс может получить тот же PID. При отмене по PID вы можете убить не ту задачу, а совершенно другой процесс.
UUID v4 — глобально уникален. Никогда не переиспользуется. Не зависит от ОС, контейнеров, перезагрузок. Формат: a1b2c3d4-e5f6-7890-abcd-ef1234567890.
Все операции registry используют UUID. PID хранится только для SIGTERM при отмене.
7.5. Параметр __api_token__ (обязателен при использовании task_registry_server)
Без __api_token__ воркеры не могут зарегистрироваться в Task Registry и сообщить о результате.
Три зарезервированных параметра актуальны при использовании task_registry_server:
__registry_url__ — URL реестра (по умолчанию http://localhost:7755)
__description__ — человекочитаемое описание задачи для UI
__api_token__ — токен Extella API для регистрации задачи в реестре
Без task_registry_server параметр __api_token__ не нужен:
parallel_task работает через /tmp/pt_{uuid}.json без обращения к серверу.
7.6. 4-шаговый паттерн: полный пример
Шаг 0: Запустить Registry (обязательно первым!)
registry = run_expert('task_registry_server')
print(registry) # {"status": "success", "url": "http://localhost:7755/"}
Шаг 1: Получить API токен
API_TOKEN = kv_get('extella_api_token')['value']
Шаг 2: Запустить воркеров параллельно
# Каждый вызов возвращает UUID немедленно (~0.5 сек)
# Воркер работает в фоне как отдельный процесс ОС
r1 = run_expert('analyze_document', {
'file_path': '/tmp/doc1.pdf',
'__api_token__': API_TOKEN,
'__description__': 'Анализ: doc1.pdf'
})
r2 = run_expert('analyze_document', {
'file_path': '/tmp/doc2.pdf',
'__api_token__': API_TOKEN,
'__description__': 'Анализ: doc2.pdf'
})
r3 = run_expert('analyze_document', {
'file_path': '/tmp/doc3.pdf',
'__api_token__': API_TOKEN,
'__description__': 'Анализ: doc3.pdf'
})
uuid1 = r1['uuid']
uuid2 = r2['uuid']
uuid3 = r3['uuid']
# Все три запущены за ~1.5 сек суммарно
Шаг 3: Дождаться завершения всех
import json
results = run_expert('demo_wait_tasks', {
'uuids': json.dumps([uuid1, uuid2, uuid3]),
'timeout': 120,
'poll_interval': 2
})
# Опрашивает http://localhost:7755/tasks каждые 2 сек
# Возвращает когда ВСЕ задачи complete или timeout
# -> {
# "status": "complete",
# "summary": {"total": 3, "complete": 3, "error": 0},
# "elapsed_seconds": 31.2,
# "results": {uuid1: {...}, uuid2: {...}, uuid3: {...}}
# }
Обработка результатов
if results['summary']['error'] > 0:
# Обработать ошибочные задачи
for uuid, result in results['results'].items():
if result.get('status') == 'error':
print(f'Task {uuid} failed: {result.get("error")}')
# Перезапустить или залогировать
else:
print(f'All {results["summary"]["total"]} tasks completed')
print(f'Time: {results["elapsed_seconds"]}s')
for uuid, result in results['results'].items():
print(f'{uuid[:8]}...: {result["result"]}')
7.7. Сравнение с синхронным режимом
| Характеристика | Синхронный | parallel_task |
|---|---|---|
| Время N задач | N x T | max(T) + ~1s |
| ID задач | Нет | UUID v4 (глобально уникален) |
| Отмена | Нет | ✓ Cancel (SIGTERM) |
| Видимость | Нет | ✓ /tmp/pt_{uuid}.json; опционально — UI :7755 (если task_registry_server запущен) |
| Traceback при ошибке | Потерян | ✓ Сохранён в registry |
| Таймаут | ~5 мин, результат потерян | Настраиваемый |
| Зависимость от LLM | Полная | Процесс независим |
| Персистентность | Нет | JSON в /tmp, выживает при рестарте |
7.8. Когда использовать parallel_task
| Условие | Выбор |
|---|---|
| Задача A нужна для задачи B (зависимость) | Синхронный режим |
| Одна задача | Синхронный (overhead не стоит) |
| Каждая задача < 5 сек | Синхронный (overhead регистрации > выгода) |
| 2+ независимых задачи > 5 сек | parallel_task |
| Задача > 1 минуты | parallel_task (защита от таймаута) |
| Нужна отменяемость | parallel_task |
| Нужна видимость прогресса | parallel_task |
Практические примеры parallel_task: парсинг 10 сайтов, анализ batch из 50 CSV, генерация отчётов по разным метрикам, проверка API-endpoints на покрытие тестами.
7.9. Критические правила
task_registry_server — опциональный компонент. parallel_task работает без него (состояние в /tmp/pt_{uuid}.json). Если task_registry_server используется — запускать ДО воркеров, иначе POST /register получит ConnectionRefused.
- UUID, не PID — UUID глобально уникален и не переиспользуется ОС
- /tmp/extella_task_registry.json — единый источник правды, выживает при рестарте
- Воркер ВСЕГДА вызывает /update — даже при crash (try/except → POST статус error с traceback)
- __api_token__ = kv_get('extella_api_token')['value'] — не хардкодить токен в коде
- uuids передавать как JSON-строку: json.dumps([uuid1, uuid2]) — не Python-список
- Одна задача в один момент для тяжёлых задач — не запускать одновременно более N воркеров
CSPL — язык расширений Extella
В Разделе 7 вы уже работали с parallel_task и nohup — это два CSPL-режима. Теперь разберём полную архитектуру CSPL и почему она принципиально меняет способ создания сложных автоматизаций.
8.1. Проблема: LLM плохо генерирует объёмный точный код
Реальный эксперимент — создание Godot Level 3 (полноценная сцена с 193 нодами):
| Инструмент | Токенов | Ошибок | Повторных запусков | Итог |
|---|---|---|---|---|
| CSPL | ~1 000 | 0 | 1 | Идеально |
| fython (LLM генерирует весь Python) | ~8 000 | 7 | 4 | Много переделок |
| Claude Code | ~15 000 | 12 | 6 | Очень долго |
LLM превосходно планирует — описывает архитектуру, делит задачу. Но token-by-token генерация с probabilistic sampling принципиально не подходит для объёмного синтаксически точного кода. Одна опечатка ломает весь проект. Каждая ошибка — повторный запуск, тысячи токенов, минуты вашего времени.
Решение: сменить парадигму. Вместо «LLM пишет весь код» → «LLM пишет компактное описание, детерминированный handler генерирует код».
8.2. Принцип ЧТО vs КАК
- LLM (ЧТО): генерирует компактное JSON-описание структуры (~200 токенов для сцены из 193 нод). Это декларативное описание: какие объекты, как связаны, какие параметры.
- Handler (КАК): Python-модуль, принимающий JSON и детерминированно генерирующий полный код. Один и тот же вход — всегда один и тот же выход. Ноль галлюцинаций.
Пример: эксперт с cspl=godot_level_3 имеет в теле не Python, а JSON-описание сцены. Handler генерирует .tscn-файлы и GDScript. LLM написала 200 токенов JSON вместо 8000 токенов GDScript. Ошибок — ноль.
cspl=godot_level_3:
# Тело эксперта — не Python, а JSON-описание:
{
"scene": "main_level",
"nodes": [
{"id": 1, "type": "Node2D", "name": "Player", "pos": [100, 200]},
{"id": 2, "type": "Area2D", "name": "Hitbox", "parent": 1},
{"id": 3, "type": "Sprite2D", "name": "Sprite", "parent": 1}
],
"signals": [{"from": 2, "signal": "body_entered", "to": 1, "method": "on_hit"}]
}
# Handler godot_level_3 генерирует из этого полный .tscn + GDScript
8.3. Полная таблица созданных режимов CSPL
| Режим | Тип тела | $extens | Возвращает | Синхронность | Когда использовать |
|---|---|---|---|---|---|
| fython (default) | Python def fn() | + | dict из функции | Синхронно | Обычные эксперты (Раздел 4) |
| nohup | Python скрипт (без def) | - | {pid, log_file} | Детач-процесс | Оркестраторы, ETL, долгие задачи |
| parallel_task | Python def fn() | + | {uuid} | Асинхронно, /tmp/pt_{uuid}.json | Параллельные задачи (Раздел 7) |
| shell | Bash команды | - | {stdout, returncode} | Синхронно | CLI-обёртки: git, docker, ffmpeg |
| interpreter | Код на любом языке | - | Зависит от языка | Синхронно | Go, R, SQL, Node.js, Julia |
| cspl_builder_code | Python handler | + | — | Синхронно | Создание нового CSPL-режима |
8.4. Режим nohup — полная спецификация
nohup фундаментально отличается от fython. Тело — чистый Python-скрипт, выполняющийся от начала до конца. Listener записывает его во временный файл и запускает через subprocess.Popen(start_new_session=True) — процесс отделяется и живёт независимо.
1. Нет def fn() — чистый скрипт сверху вниз
# fython (обычный эксперт):
def my_expert(param: str = '') -> dict:
# ... логика
return {"status": "success"}
# nohup (скрипт без функции):
import os, datetime
log_path = '/tmp/nohup_test.txt'
with open(log_path, 'w') as f:
f.write(f'ran at {datetime.datetime.now()}\n')
f.write(f'cwd: {os.getcwd()}\n')
# Нет return — скрипт просто выполняется и завершается
2. Нет $extens() — include() вручную
В nohup директива $extens() не обрабатывается (нет fython-обёртки). Реализуйте include() напрямую в начале скрипта:
import sys, subprocess
def include(module, commands):
try:
exec(module, globals())
return True
except:
for cmd in commands:
parts = cmd.split()
if parts[0] in ('extella-pip', 'pip', 'pip3'):
subprocess.run([sys.executable, '-m', 'pip'] + parts[1:])
try:
exec(module, globals())
return True
except:
return False
include('import pandas', ['extella-pip install pandas'])
include('import requests', ['extella-pip install requests'])
# pandas и requests теперь доступны
3. Параметры через {{placeholders}}
Kwargs подставляются в текст скрипта ДО его запуска. В коде используйте {{имя_параметра}}:
# Параметры: api_token='abc123', file_path='/tmp/data.csv', output_dir='/tmp'
import pandas as pd
api_token = '{{api_token}}' # <- будет заменено на 'abc123'
file_path = '{{file_path}}' # <- будет заменено на '/tmp/data.csv'
output_dir = '{{output_dir}}' # <- будет заменено на '/tmp'
df = pd.read_csv(file_path)
result = df.groupby('category').sum()
result.to_csv(f'{output_dir}/output.csv', index=False)
4. Нет return — результат через файл
import json
from pathlib import Path
# ... выполнение работы ...
result = {
'status': 'success',
'processed_rows': 15000,
'errors': 3,
'output_file': '/tmp/result.csv'
}
# Обязательно записать результат:
Path('/tmp/nohup_my_script_result.json').write_text(
json.dumps(result, ensure_ascii=False)
)
5. Логи и управление
stdout/stderr → /tmp/nohup_<name>.log. Агент сразу получает ответ: {pid, log_file, pid_file}. Для мониторинга читайте лог-файл. При завершении — читайте result.json.
8.4.1. Режим wait_tasks — барьер синхронизации
wait_tasks — CSPL-режим, пара к parallel_task: принимает список UUID запущенных задач и ждёт завершения всех (или до timeout). Поллит /tmp/pt_{uuid}.json каждые 0.3–2 секунды.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| uuids | str (JSON) | обязателен | JSON-массив UUID: json.dumps([uuid1, uuid2]) — строго строка, не Python-список |
| timeout | int | 120 | Максимальное ожидание в секундах |
| poll_interval | float | 2 | Интервал опроса файлов (секунды) |
Что возвращает demo_wait_tasks:
{
"results": {
"uuid-1...": {"status": "complete", "result": {...}},
"uuid-2...": {"status": "complete", "result": {...}}
},
"summary": "2/2 completed",
"elapsed_seconds": 31.2
}
Точка входа: bridge-эксперт demo_wait_tasks (сохранён с cspl=wait_tasks). Именно его нужно вызывать через run_expert — CSPL-режим wait_tasks не вызывается напрямую.
8.4.2. Режимы shell и interpreter
Два дополнительных режима для CLI-инструментов и кода на других языках. Оба поддерживают {{placeholders}} для kwargs.
shell — встроенный bash-раннер
Тело эксперта — bash-команды. Нет функции, нет $extens. Listener запускает через subprocess и возвращает {stdout, stderr, returncode}.
# cspl='shell' — конвертация видео через ffmpeg:
ffmpeg -i {{input_path}} -vf scale=1280:720 -c:a copy {{output_path}}
# cspl='shell' — git pull:
git -C {{repo_path}} fetch origin
git -C {{repo_path}} pull --rebase
| Используйте shell для | Примеры |
|---|---|
| Медиа-обработка | ffmpeg, ImageMagick convert, sox |
| Документы | pandoc, wkhtmltopdf, libreoffice --headless |
| Git-операции | git fetch, git pull, git tag, git log |
| Системные утилиты | rsync, tar, curl, wget, find |
| Контейнеры и оркестрация | docker build/run, kubectl apply |
interpreter — код на любом установленном языке
Тело эксперта — код на любом языке. Handler компилирует/интерпретирует его на устройстве. Kwargs доступны через {{placeholders}} как в nohup.
# cspl='interpreter' — Go-код:
package main
import "fmt"
func main() {
data := "{{input}}"
fmt.Println("Processed:", data)
}
| Язык | Когда полезно |
|---|---|
| Go | Высокопроизводительная обработка данных, бинарные операции |
| R | Статистический анализ, ML-модели, ggplot-графики |
| SQL | Аналитические запросы к локальным БД |
| Node.js | JSON-обработка, работа с npm-экосистемой |
| Julia | Научные и матричные вычисления |
| Ruby | Системное администрирование, Rakefile-сценарии |
8.5. DSL: Domain-Specific Languages
CSPL позволяет создавать компактные языки для конкретных доменов. Вместо 400 строк HTML/CSS/JS — 40 строк JSON, handler генерирует полноценный сайт.
| Домен | CSPL-режим | Генерирует | Экономия токенов |
|---|---|---|---|
| Web API | api_dsl | FastAPI + Pydantic + OpenAPI | 10x |
| База данных | schema_dsl | SQL DDL + миграции Alembic | 8x |
| CI/CD пайплайн | pipeline_dsl | GitHub Actions YAML | 12x |
| Godot-уровни | godot_level_3 | .tscn + GDScript | 15x |
| HDL-схемы | hdl_dsl | Verilog / VHDL | 20x |
| Тесты | test_dsl | pytest fixtures + test cases | 6x |
| Markdown-отчёты | mini_report_dsl | HTML или Markdown | 8x |
Пример DSL для Web API (6 строк вместо сотен):
# Тело эксперта с cspl='api_dsl':
API UserService
BASE /api/users
AUTH bearer
GET / -> list[User] CACHE 60
POST / -> User BODY {name: str, email: str}
GET /:id -> User
DELETE /:id -> void
# Handler генерирует полный FastAPI-роутер, Pydantic-модели, OpenAPI-документацию
DSL-режимы из таблицы выше (api_dsl, schema_dsl, godot_level_3 и др.) — примеры кастомных handlers, созданных через cspl_builder_code. В стандартную поставку Extella они не входят. Встроенными (доступными сразу) являются только: fython, nohup, parallel_task, wait_tasks, shell, interpreter, cspl_builder_code.
8.6. cspl_builder_code: создание своего CSPL
Мета-режим: вы создаёте новый тип CSPL прямо из чата, без изменения кода платформы. Архитектура расширяема на лету.
Процесс:
- Описываете желаемый handler: «Создай CSPL для FastAPI из JSON-схемы»
- Агент пишет Python-код handler: функция принимает code body, генерирует артефакт
- Handler регистрируется как новый cspl-тип в системе
- Новый режим доступен немедленно: cspl='fastapi_generator'
# Пример простого DSL handler:
def my_report_dsl(filtered_source_code='', func_name='', kwargs=None, **extra):
lines = filtered_source_code.strip().split('\n')
html_parts = []
for line in lines:
if line.startswith('TITLE'):
html_parts.append(f'<h1>{line[6:]}</h1>')
elif line.startswith('SECTION'):
html_parts.append(f'<h2>{line[8:]}</h2>')
elif line.startswith('> '):
html_parts.append(f'<p>{line[2:]}</p>')
html = '<html><body>' + ''.join(html_parts) + '</body></html>'
output = Path('/tmp/report.html')
output.write_text(html)
return {'status': 'success', 'output': str(output), 'sections': len(html_parts)}
8.7. Рекурсивная природа CSPL: без потолка
Каждый handler может использовать другие handlers. Нет верхней планки:
- Уровень 1: fython с JSON-описанием → handler генерирует Python-классы
- Уровень 2: interpreter с Go-кодом → handler компилирует Go-бинарник
- Уровень 3: Go использует C-библиотеку → handler генерирует ctypes-обёртку
- Уровень 4: C на ARM64 → handler генерирует inline-ассемблер для оптимизации
- Уровень N: ...
CSPL — мост между декларативным описанием (что LLM делает хорошо) и императивной реализацией (что LLM делает плохо). Этот мост строится из Python, Go, C, bash, SQL, GDScript, Terraform, Dockerfile.
8.8. Когда НЕ нужен CSPL
Практически: если сомневаетесь — берите fython. CSPL окупается только на повторяющихся классах задач, где экономия токенов и ошибок значительна.
Три условия: когда CSPL оправдан
| Условие | Проверочный вопрос | Если НЕТ → |
|---|---|---|
| 1. Класс повторяющихся задач | Это будет использоваться многократно, не один раз? | fython — CSPL требует инвестиций в handler |
| 2. Логика сложнее данных | Формат вывода имеет внутренние зависимости, которые нужно вычислять? | fython — LLM справится напрямую |
| 3. Данные и логика разделяются | Чётко видно: вот что меняется каждый раз, вот что всегда одинаково? | fython — граница нечёткая, CSPL не даст выгоды |
CSPL имеет смысл только если одновременно выполняются все три условия. Нарушение хотя бы одного — берите fython.
Примеры применения правила:
| Задача | Усл.1 | Усл.2 | Усл.3 | Вывод |
|---|---|---|---|---|
| Генерация 50 схожих отчётов с разными данными | ✓ | ✓ | ✓ | CSPL ✓ |
| Один разовый скрипт парсинга CSV | ✕ | — | — | fython |
| Godot-уровни (повторяющийся паттерн) | ✓ | ✓ | ✓ | CSPL ✓ |
| Вызов OpenAI API с разными промптами | ✓ | ✕ | — | fython — логика проще данных |
| FastAPI-роутеры из JSON-схем (10+ штук) | ✓ | ✓ | ✓ | CSPL ✓ |
Ситуации, когда CSPL избыточен
| Ситуация | Рекомендация |
|---|---|
| Задача до 100 строк кода | fython — LLM напишет без ошибок |
| Уникальная одноразовая задача | fython — CSPL требует повторяющийся паттерн |
| Нужен результат немедленно | fython или shell — nohup асинхронный |
| Handler сложнее, чем сама задача | Handler должен генерировать в 10x больше кода |
| Нет готового handler для домена | Сначала создайте handler через cspl_builder_code |
REST API: программная интеграция
9.1. Три сценария: зачем вам API
Сценарий 1: Встраивание в ваш продукт
Вы строите CRM, ERP, чат-бот или любую платформу. Вместо обучения модели с нуля — вызываете готового Extella-агента через API. Ваш бэкенд отправляет промпт — Extella возвращает ответ. Пользователь вашего продукта даже не знает, что «под капотом» работает Extella.
Сценарий 2: Автоматизация фоновых задач
Каждую ночь скрипт забирает новые документы, запускает агента, получает анализ и записывает результат. CI/CD-пайплайн использует Experts для генерации документации, проверки кода, обработки логов. API поддерживает async-режим: async=true → task_id → polling /api/task/check. Идеально для фоновых задач, которые не блокируют основной процесс.
Сценарий 3: Экспорт данных для аналитики и fine-tuning
/api/agent/export/chats — полная история диалогов (ценный датасет для fine-tuning). /api/agent/export/calls — журнал вызовов: model, latency_ms, prompt_tokens, completion_tokens, created_at. Ценно для анализа стоимости AI, оптимизации промптов, fine-tuning локальных моделей.
9.2. Base URL и коварная ошибка 405
Версия API: docs.extella.ai описывает v0.7.0 — 48 эндпоинтов, 11 секций. Первичный заголовок аутентификации: X-Auth-Token. Метод Authorization: Bearer принимается как альтернатива.
Самая частая причина HTTP 405 (Method Not Allowed) — отправка API-запроса не на тот URL.
| URL | Назначение | Правило |
|---|---|---|
| https://prod.extella.ai/api/agent/* | Agents API | ВСЕ запросы к агентам |
| https://prod.extella.ai/api/expert/* | Experts API | ВСЕ запросы к экспертам |
| https://prod.extella.ai/api/concept/* | Concepts API | Работа с концептами |
| https://prod.extella.ai/api/kv/* | KV Store API | Ключ-значение |
| https://prod.extella.ai/api/rules/* | Rules API | Правила |
| https://prod.extella.ai/api/token/* | Tokens API | Управление токенами |
| https://prod.extella.ai/api/profile/* | Profiles API | Управление профилями |
Правило: для ВСЕГО что начинается с /api/ — используйте https://prod.extella.ai
9.3. Аутентификация: два равнозначных способа
# Способ 1 (предпочтительный — стандарт Bearer):
Authorization: Bearer <ваш-токен>
# Способ 2 (специфичный для Extella):
X-Auth-Token: <ваш-токен>
# Для Database Services (/api/concept/*, /api/kv/*)
# также работает передача user_id в теле запроса,
# но заголовок авторизации предпочтителен
Получение первого токена через агента: напишите «Сгенерируй API токен» — получите мгновенно. Через API:
POST https://prod.extella.ai/api/token/generate
Authorization: Bearer <существующий_токен>
Content-Type: application/json
{"name": "Production API"}
# -> {"token": "a1b2c3...", "user_id": "user_abc", "name": "Production API"}
Валидация (rate limit: 30 запросов/мин — валидируйте один раз при старте, не перед каждым запросом):
POST https://prod.extella.ai/api/token/validate
{"token": "ваш-токен"}
# -> {"valid": true, "user_id": "user_abc"}
9.4. OpenAI-совместимый режим
Если ваше приложение уже работает с OpenAI — минимальные изменения для перехода на Extella:
from openai import OpenAI
client = OpenAI(
api_key="ваш_extella_токен",
base_url="https://prod.extella.ai/v1",
)
response = client.chat.completions.create(
model="gpt-4", # игнорируется — используется модель агента
messages=[
{"role": "user", "content": "Что такое REST API?"}
],
temperature=0.7,
)
print(response.choices[0].message.content)
Режимы /api/agent/run:
- sync (по умолчанию) — блокирующий вызов, ждёт полный ответ
- stream — Server-Sent Events, токены по мере генерации (Accept: text/event-stream)
- async — немедленно возвращает task_id, результат через /api/task/check
Примечание (docs.extella.ai): агент запускается через POST /api/agent/run с передачей agent_id в теле запроса (json={"agent_id": "agent_...", "input": "..."}). Заголовок X-Agent-Id также принимается как альтернатива.
9.5. Таблица всех ключевых эндпоинтов
| Метод | Endpoint | Описание |
|---|---|---|
| POST | /api/agent/run | Запустить агента (sync/stream/async) |
| POST | /api/agent/get | Получить конфиг агента |
| POST | /api/agent/create | Создать агента (требует Pro) |
| POST | /api/agent/update | Обновить агента |
| POST | /api/agent/list | Список агентов |
| POST | /api/agent/export/chats | Экспорт истории диалогов |
| POST | /api/agent/export/calls | Журнал вызовов с метриками (параметры в теле запроса) |
| POST | /api/profile/create | Создать профиль |
| POST | /api/profile/add_agent | Добавить агента в профиль |
| POST | /api/profile/delete | Удалить профиль (агенты остаются) |
| POST | /api/profile/list | Список профилей |
| POST | /api/expert/run | Запустить эксперт |
| POST | /api/expert/save | Сохранить эксперт |
| GET | /api/expert/get/<name> | Получить эксперт по имени |
| DELETE | /api/expert/delete/<name> | Удалить эксперт |
| POST | /api/blocks/search | Семантический поиск экспертов |
| POST | /api/task/check (или /api/tasks/check) | Статус асинхронной задачи |
| POST | /api/concept/add | Добавить концепт |
| POST | /api/concept/search | Семантический поиск концептов |
| POST | /api/concept/update | Обновить концепт |
| POST | /api/concept/remove | Удалить концепт |
| POST | /api/concept/list | Список концептов |
| POST | /api/kv/set | Установить KV-пару |
| POST | /api/kv/get | Получить KV-пару |
| POST | /api/kv/search | Семантический поиск по KV |
| POST | /api/kv/list | Список KV-пар |
| POST | /api/rules/add | Добавить правило |
| POST | /api/rules/list | Список правил |
| POST | /api/rules/update | Обновить правило |
| POST | /api/rules/remove | Удалить правило |
| POST | /api/token/generate | Создать токен |
| POST | /api/token/validate | Валидировать токен |
| POST | /api/token/revoke | Отозвать токен |
| POST | /api/token/list | Список токенов |
| POST | /api/defaults/set_target | Установить устройство по умолчанию |
| POST | /api/defaults/get_target | Получить устройство по умолчанию |
Rate limits: 60 req/min per IP, 20 req/min для /api/agent/run. HTTP 429 — читайте Retry-After, используйте exponential backoff.
Эндпоинты, отсутствующие в таблице выше (полный список — docs.extella.ai):
| Метод | Endpoint | Описание |
|---|---|---|
| GET | /api/health | Health Check — статус сервера |
| POST | /api/agent/delete | Удалить агента (agent_id в теле) |
| POST | /api/kv/remove | Удалить KV-пару (key в теле) |
| POST | /api/targets/add | Добавить устройство (target, description) |
| POST | /api/targets/list | Список устройств |
| POST | /api/targets/search | Семантический поиск устройств |
| POST | /api/targets/update | Обновить устройство (id обязателен) |
| POST | /api/targets/remove | Удалить устройство (id обязателен) |
| POST | /api/experts_db/list | Список экспертов из БД (метаданные) |
9.6. Ловушки в именах полей
Ловушка 1: blocks/search возвращает matches, не results
data = response.json()
# НЕПРАВИЛЬНО:
for r in data['results']: # KeyError!
print(r['similarity'])
# ПРАВИЛЬНО:
for block in data['matches']: # 'matches'
print(block['score']) # 'score', не 'similarity'
Ловушка 2: expert/get использует camelCase
expert = response.json()
# ПРАВИЛЬНЫЕ имена полей:
code = expert['expert_code'] # не 'code'
params = expert['expert_params'] # не 'kwargs'
name = expert['expert_name'] # не 'name'
created = expert['createdAt'] # camelCase!
Ловушка 3: export/calls — параметры тоже в body (POST), как и export/chats
# export/chats — параметры в body:
requests.post(BASE+'/api/agent/export/chats',
json={'by': 'agent', 'id': 'agent_...'})
# export/calls — параметры тоже в body (POST, не GET):
requests.post(BASE+'/api/agent/export/calls',
headers=HEADERS,
json={'by': 'agent', 'id': 'agent_...',
'limit': 200, 'from': '2026-01-01T00:00:00Z'})
Ловушка 4: нет _id, только id
В ответах API нет MongoDB-стиля _id. Используется просто id. Также нет поля __v (версия документа). Это REST API, не Mongoose.
9.7. Чеклист безопасной интеграции
- Токен в переменных окружения: os.environ['EXTELLA_API_TOKEN'], не в коде
- Base URL: https://prod.extella.ai для всех /api/ запросов
- Rate limits: ловите HTTP 429, читайте Retry-After, используйте exponential backoff
- Сохраняйте agent_id после создания — без него агента не запустить
- async=true для задач > 60 сек — не блокируйте основной поток
- stream=True для UX — Accept: text/event-stream если пользователь ждёт в реальном времени
- store=False при отладке — не загрязняйте историю чатов
- global=True при поиске концептов — иначе ищете только в памяти текущего агента
- blocks/search: поле matches, не results; score, не similarity
- expert/get: expert_code, expert_params, createdAt (camelCase)
- export/calls: POST с параметрами в body: {by, id, limit, from}
- Pro план для /api/agent/create
- Валидируйте токен один раз при старте — не перед каждым запросом (rate limit 30/мин)
9.8. Типичный workflow от нуля до интеграции
1. Получить токен: POST /api/token/generate -> сохранить в .env
2. Создать агента: POST /api/agent/create -> agent_id
3. Создать профиль: POST /api/profile/create -> profile_id
4. Добавить в профиль: POST /api/profile/add_agent -> {profile_id, agent_id}
5. Запустить синхронно: POST /api/agent/run + X-Agent-Id: agent_id
Запустить async: POST /api/agent/run + {async: true} -> task_id
Проверить статус: POST /api/task/check {task_id: ...}
6. Экспорт чатов: POST /api/agent/export/chats -> датасет для fine-tuning
7. Экспорт вызовов: POST /api/agent/export/calls -> аналитика
Этот конвейер покрывает 95% сценариев интеграции. Для сложных кейсов (параллельные эксперты, семантический поиск, KV Store) — обращайтесь к разделам 3, 4 и 7.