документация — гид пользователя

Гид пользователя

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

9 разделов · от новичка до разработчика · REST API справочник

01 — что такое extellaновичок

Что такое Extella: зачем, как устроено, ключевые понятия

1.1. Зачем нужен агент, а не чат-бот

Вы наверняка уже пользовались ChatGPT, Claude или другими большими языковыми моделями. Каждый разговор начинается с чистого листа. Модель не помнит, что было вчера. Она не может открыть ваш файл, отправить письмо, запустить скрипт или сохранить отчёт. Максимум — сгенерировать код, который вы потом сами скопируете и запустите.

Extella — это не чат-бот. Это AI-агент, который выполняет задачи, а не советует, как их выполнить.

Формула: AI-чат + автоматизация + постоянная память + выполнение на твоём устройстве + персональный набор инструментов — всё в одном месте.

Вы описываете потребность. Extella создаёт Expert (исполняемый модуль), сохраняет его в библиотеке и запускает. Результат — реальный файл, отправленное сообщение, обработанные данные — остаётся на вашем устройстве. Это не текст в чате. Это объект, который живёт после завершения сессии.

1.2. Extella vs обычные LLM — фундаментальные отличия

ChatGPT говорит вам, что делать. Extella делает это за вас.

ХарактеристикаChatGPT / обычные LLMExtella
Основная задачаГенерация текстаВыполнение реальных действий
ПамятьТолько текущий чат. Новая сессия — чистый листПостоянная: 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Сохранённый исполняемый модуль — функция, которая делает одну конкретную вещьИнструмент на вашей полке
AgentAI-специалист с моделью, инструментами, инструкциями и памятьюСотрудник с должностью
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 — камень в фундамент. Один камень ничего не меняет. Сто — мост к автоматизации любой сложности. Через год у вас будет персональная система, которая знает ваш контекст, инструменты и предпочтения. И которая с каждым днём становится только сильнее.

02 — быстрый стартновичок

Быстрый старт: от установки до первого результата

Пошаговое руководство: от скачивания приложения до первого выполненного задания. Следуйте шагам по порядку — каждый строится на предыдущем.

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. Чеклист: вы готовы к работе

#ДействиеСтатус
1Extella Desktop установлен и запущен
2Listener показывает Connected в трее
3Device ID зарегистрирован (виден в интерфейсе)
4API токен получен и сохранён
5Первый запрос отправлен и получен ответ
6Первый Expert создан и виден в библиотеке
7Первое Rule добавлено
8Первый Concept сохранён

Если все 8 пунктов отмечены — платформа настроена. Теперь начинается самое интересное: наращивание системы.

03 — kv, concepts, rulesсредний

Три кита: 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 первым. Строгий алгоритм:

  1. Нужен ключ? → kv_search("<сервис> ключ токен")
  2. Нашёл? → kv_get(key) — автоматическая расшифровка
  3. Не нашёл? → только тогда спрашивает пользователя
  4. Пользователь предоставил? → 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

ПараметрRulesConcepts
ЗагрузкаАвтоматически при каждом сообщенииТолько при явном поиске 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 StoreConceptsRules
Тип данныхКлюч-значение + описаниеСемантическое знание (текст)Поведенческая инструкция
Шифрование PIN пользователя Нет Нет
ПоискТочный по ключу + семантическийТолько семантическийНет — все загружаются
Автозагрузка При каждом сообщении
Эмбеддингиpgvector (из ключа + описания)pgvector (из текста концепта)N/A
Модель эмбеддинговtext-embedding-3-smalltext-embedding-3-smallN/A
Лимит значенияTEXT (до 1 ГБ)TEXT4000 символов
Что хранит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 — данные всех агентов профиля.

04 — эксперты и автоматизациисредний

Эксперты: создание, типы и автоматизации

Expert — это атомарная автоматизация, сохранённая навсегда. Один раз создан — работает всегда. Этот раздел охватывает всё: от типов экспертов до создания автоматических задач по расписанию.

4.1. Четыре типа экспертов

1. SIMPLE — однозадачные кирпичики

ЭкспертЧто делаетAPI-ключ?
convert_pdf_to_textИзвлекает текст из PDFНет
send_telegram_messageОтправляет сообщениеДа (bot_token)
excel_querySQL-запрос к .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 wrapperffmpeg, ImageMagick, pandoc, git
Library wrapperPillow, pandas, BeautifulSoup
External APITelegram, OpenAI, Notion, Jira
DatabaseSQLite, 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 обязательных элементов каждого эксперта:

  1. Директива: $extens("include.py") — первая строка, обязательно
  2. Зависимости: include(..., ["extella-pip install ..."])
  3. Сигнатура: def name(param: str = "") → dict — явные типы, дефолты, никаких *args/**kwargs
  4. Валидация: проверка входов, ранний возврат при ошибке
  5. Возврат: всегда 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-агент записывает концепты. На следующей неделе использует их как контекст. Через год — эксперт по истории проблем вашей системы.

05 — агенты и командысредний · pro

Агенты и команды

Теперь, когда вы знаете 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 StudioResearch → Writer → Editor → SEO-reviewerСоздание контент-материалов от исследования до публикации
Due DiligenceFinancial Analyst + Legal Reviewer + Market ResearcherСбор и синтез данных по компании для инвестиционного решения
Product SprintPM + Tech Lead + UX ReviewerРазбор задач и формирование технических спецификаций
Personal Knowledge BaseCollector + 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Главный оркестратор: делегирование, стратегия, синтез результатов
CCOGemini 2.5 FlashB2B продажи, GTM-стратегия, конкурентный анализ, питчи, ценообразование
CTOGemini 2.5 FlashАрхитектура платформы, CSPL-эксперты, API, безопасность, инфраструктура
Corporate DirectorQwen 3.6 PlusФинансы, legal, compliance, структура капитала, инвесторы
Extella ArchitectQwen 3.6 Plus (NVIDIA)Сложный reasoning, глубокий архитектурный анализ
Llama 4 MaverickLlama 4 Maverick1M контекст, multimodal, параллельная обработка больших объёмов
Step 3.5 FlashStep 3.5 Flash196B MoE, 262K контекст — массовая обработка, написание разделов
Llama 3.3 70BLlama 3.3 70B (Groq)Сверхбыстрый инференс (300+ токен/сек) — срочные задачи
Architect R1DeepSeek R1Chain-of-thought reasoning, сложные логические задачи, планирование
Auto RouterAuto Router (OpenRouter)Автоматический выбор оптимальной модели + fallback-цепочка

Воркеры (Llama, Step, DeepSeek, Qwen) используются оркестратором для параллельной обработки: написание 10 разделов одновременно, анализ 5 конкурентов, генерация 20 вариантов питчей. Это «вычислительные мышцы» системы.

5.9. Рост агента во времени

Агент в Extella — не статический инструмент. Он растёт как реальный сотрудник: накапливает знания в концептах, правила в Rules, паттерны в KV Store. С каждой неделей работы становится умнее и точнее.

ЭтапСостояние агентаЧто происходитПример
День 1Пустой профильКомпетентен как хорошая LLM, но не знает ваш бизнесCTO пишет Python, но не знает вашу архитектуру
Неделя 215-30 концептов, 5-10 правилЗнает стиль кода, типичные ошибки, предпочтения команды«В проекте FastAPI+PostgreSQL+Redis. Миграции — Alembic.»
Месяц 3100-300 концептов, Cron-паттерныПредлагает решения из истории проекта, предсказывает проблемы«Добавь кэширование» → сразу предлагает Redis-паттерн, который вы уже используете
Месяц 6500+ концептов, автономная работаЭксперт по проекту. Принимает решения без дополнительного контекстаАвтономно предупреждает о деградации по историческим данным

Путь к автономии:

  • День 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 — на вашей инфраструктуре или через внешние сервисы.

06 — локальные модели и туннелисредний · pro

Локальные модели и туннели

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 Studio1234http://localhost:1234/v1/
llama.cpp server8080http://localhost:8080/v1/
Ollama11434http://localhost:11434/v1/
Jan1337http://localhost:1337/v1/
KoboldCPP5001http://localhost:5001/v1/
LocalAI8080http://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 (после добавления репозитория — см. ниже)
Windowswinget 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Что вводитьПример
providercustomcustom
baseURLURL туннеля + /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Рекомендация
ngrokngrok http 1234Случайный / статич.Лучший старт
cloudflared (быстро)cloudflared tunnel --url http://localhost:1234СлучайныйТест без регистрации
cloudflared (постоянный)через config.yml + свой доменПостоянныйДля регулярного использования
LocalTunnellt --port 1234 --subdomain my-llmСлучайный / субдоменБыстрый разовый тест
Tailscale Funneltailscale funnel 1234ПостоянныйЕсли Tailscale уже есть

Итог в одном предложении: запустите ngrok http <порт>, возьмите URL из вывода, добавьте /v1/ в конце, вставьте в поле baseURL в настройках агента Extella — и ваша локальная модель готова к работе.

07 — параллельное выполнениеразработчик

Параллельное выполнение: в 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 30s60s31s29s
5 x 30s150s31s119s
10 x 30s300s31s269s

Проблема 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"Задача завершилась с ошибкой
resultdict от воркераРезультат (только при complete)
errortraceback 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 /tasksJSON со всеми задачами
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 Tmax(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 воркеров
08 — csplразработчик

CSPL — язык расширений Extella

В Разделе 7 вы уже работали с parallel_task и nohup — это два CSPL-режима. Теперь разберём полную архитектуру CSPL и почему она принципиально меняет способ создания сложных автоматизаций.

8.1. Проблема: LLM плохо генерирует объёмный точный код

Реальный эксперимент — создание Godot Level 3 (полноценная сцена с 193 нодами):

ИнструментТокеновОшибокПовторных запусковИтог
CSPL~1 00001Идеально
fython (LLM генерирует весь Python)~8 00074Много переделок
Claude Code~15 000126Очень долго

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)
nohupPython скрипт (без def)-{pid, log_file}Детач-процессОркестраторы, ETL, долгие задачи
parallel_taskPython def fn()+{uuid}Асинхронно, /tmp/pt_{uuid}.jsonПараллельные задачи (Раздел 7)
shellBash команды-{stdout, returncode}СинхронноCLI-обёртки: git, docker, ffmpeg
interpreterКод на любом языке-Зависит от языкаСинхронноGo, R, SQL, Node.js, Julia
cspl_builder_codePython 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 секунды.

ПараметрТипПо умолчаниюОписание
uuidsstr (JSON)обязателенJSON-массив UUID: json.dumps([uuid1, uuid2]) — строго строка, не Python-список
timeoutint120Максимальное ожидание в секундах
poll_intervalfloat2Интервал опроса файлов (секунды)

Что возвращает 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.jsJSON-обработка, работа с npm-экосистемой
JuliaНаучные и матричные вычисления
RubyСистемное администрирование, Rakefile-сценарии

8.5. DSL: Domain-Specific Languages

CSPL позволяет создавать компактные языки для конкретных доменов. Вместо 400 строк HTML/CSS/JS — 40 строк JSON, handler генерирует полноценный сайт.

ДоменCSPL-режимГенерируетЭкономия токенов
Web APIapi_dslFastAPI + Pydantic + OpenAPI10x
База данныхschema_dslSQL DDL + миграции Alembic8x
CI/CD пайплайнpipeline_dslGitHub Actions YAML12x
Godot-уровниgodot_level_3.tscn + GDScript15x
HDL-схемыhdl_dslVerilog / VHDL20x
Тестыtest_dslpytest fixtures + test cases6x
Markdown-отчётыmini_report_dslHTML или Markdown8x

Пример 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 прямо из чата, без изменения кода платформы. Архитектура расширяема на лету.

Процесс:

  1. Описываете желаемый handler: «Создай CSPL для FastAPI из JSON-схемы»
  2. Агент пишет Python-код handler: функция принимает code body, генерирует артефакт
  3. Handler регистрируется как новый cspl-тип в системе
  4. Новый режим доступен немедленно: 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
Один разовый скрипт парсинга CSVfython
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
09 — rest apiразработчик

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/healthHealth 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.