← Все гайды AI Release
EN Подписаться на @ai_release1

Пошаговое руководство: как развернуть self-hosted голосового агента Lampline и импортировать агента из Dialogflow CX

Обновлено: 20.10.2026 · AI Release · @ai_release1
Пошаговое руководство: как развернуть self-hosted голосового агента Lampline и импортировать агента из Dialogflow CX

TL;DR

- Linux-сервер (Ubuntu 22.04 LTS или совместимый дистрибутив), root/sudo, статический IP

- Docker Engine и плагин Docker Compose v2 (проверка: docker compose version)

- git, curl, jq, python3, zip/unzip

- Домен <ваш-домен> и TLS-сертификат (например, Let's Encrypt) для HTTPS

- Проект Google Cloud с агентом Dialogflow CX и роль Dialogflow API Admin (или Owner)

- Установленный gcloud CLI для вызова REST API Dialogflow

- Экспорт агента из Dialogflow CX — архив .blob

Требования и подготовка

Иллюстрация к разделу «Требования и подготовка»
Иллюстрация к разделу «Требования и подготовка»

Если сервер у вас домашний, а не облачный, сначала пройдите как подключить ИИ к домашнему серверу — там разобраны проброс портов и базовая изоляция сервисов.

Шаг 1. Подготовка хоста и секретов

Что сделать: установите Docker, утилиты и создайте каталог проекта с файлом переменных окружения.

Зачем: все компоненты Lampline распространяются как контейнеры; переменные окружения описывают домен, токен API и доступ к Google Cloud, чтобы не хардкодить секреты в конфиг.

sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg git jq python3 unzip
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER
newgrp docker

mkdir -p ~/lampline/secrets ~/lampline/data
cd ~/lampline

Пример: файл ~/lampline/.env:

LAMPLINE_DOMAIN=<ваш-домен>
LAMPLINE_PUBLIC_URL=https://<ваш-домен>
LAMPLINE_API_TOKEN=<токен-из-панели-или-сгенерированный>
LAMPLINE_HTTP_PORT=8000
GOOGLE_APPLICATION_CREDENTIALS=/run/secrets/gcp-sa.json
DIALOGFLOW_PROJECT_ID=<project-id>
DIALOGFLOW_LOCATION=<region, например europe-west1>

Как проверить:

docker compose version
ss -ltnp | grep -E ':(80|443|8000)\b' || echo "порты свободны"
ls -l secrets/gcp-sa.json

Ожидаемый результат: строка вида Docker Compose version v2.x, сообщение порты свободны и файл ключа с правами -rw-------. Имена переменных LAMPLINE_* — плейсхолдеры: точный список сверьте с документацией Lampline, раздел конфигурации.

Почему это работает: Docker читает .env при каждом docker compose up, поэтому смена домена или токена не требует пересборки образа — достаточно перезапуска.

Шаг 2. Развёртывание Lampline через Docker Compose

Что сделать: опишите сервис в docker-compose.yml, поднимите контейнер и заверните его в reverse proxy с TLS.

Зачем: Compose фиксирует порты, тома и монтирование ключа Google в одном файле — это воспроизводимо при переустановке и переносе на другой сервер.

services:
  lampline:
    image: <registry>/lampline:<тег-из-документации>
    env_file: .env
    ports:
      - "8000:8000"
    volumes:
      - ./data:/var/lib/lampline
      - ./secrets/gcp-sa.json:/run/secrets/gcp-sa.json:ro
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-fsS", "http://localhost:8000/"]
      interval: 30s
      timeout: 5s
      retries: 3
cd ~/lampline
docker compose pull
docker compose up -d
docker compose ps

Пример: успешный docker compose ps показывает lampline ... Up (healthy) — статус healthy означает, что внутренний healthcheck прошёл и приложение отвечает на HTTP.

Дальше настройте Nginx как reverse proxy: proxy_pass http://127.0.0.1:8000; для <ваш-домен> и сертификат от Let's Encrypt (например, certbot --nginx -d <ваш-домен>). Имя образа, тег и внутренний порт сверьте с документацией Lampline — универсальных значений здесь нет.

Как проверить:

curl -sS -o /dev/null -w "%{http_code}\n" https://<ваш-домен>/
docker compose logs --tail=50 lampline | grep -i -E "error|listen"

Ожидаемый результат: код 200 или 401 (если включена авторизация — это нормально) и строка лога о старте сервера без error. Код 502 означает, что Nginx жив, а контейнер — нет.

Шаг 3. Экспорт агента из Dialogflow CX и импорт в Lampline

Иллюстрация к разделу «Шаг 3. Экспорт агента из Dialogflow CX и импорт в Lampline»
Иллюстрация к разделу «Шаг 3. Экспорт агента из Dialogflow CX и импорт в Lampline»

Что сделать: выгрузите агента из Dialogflow CX в архив .blob, проверьте его локально и загрузите в Lampline.

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

Экспорт в консоли: откройте агента → Manage → Export agent → выберите формат экспорта → скачайте файл. Точные названия пунктов меню сверьте с актуальной документацией Dialogflow CX — Google периодически их меняет.

Проверка архива перед импортом:

import json, zipfile

with zipfile.ZipFile("agent.blob") as z:
    names = z.namelist()
    print(len(names), "файлов в архиве")
    agent = json.loads(z.read("agent.json"))
    print("Агент:", agent["displayName"])
    print("Язык:", agent.get("defaultLanguageCode"))

Пример вывода: 214 файлов в архиве, Агент: SupportBot, Язык: ru. Если agent.json в архиве нет — распечатайте names[:20] и сверьте структуру с документацией формата экспорта.

Загрузка в Lampline (путь эндпоинта и имя поля возьмите из документации Lampline):

curl -sS -X POST "https://<ваш-домен>/api/agents/import" \
  -H "Authorization: Bearer ${LAMPLINE_API_TOKEN}" \
  -F "file=@agent.blob" | jq

Если Lampline ожидает не файл, а уже восстановленного агента через API Google, используйте штатный метод restore Dialogflow CX — он принимает содержимое архива в base64:

TOKEN=$(gcloud auth print-access-token)
curl -sS -X POST \
  "https://${DIALOGFLOW_LOCATION}-dialogflow.googleapis.com/v3/projects/${DIALOGFLOW_PROJECT_ID}/locations/${DIALOGFLOW_LOCATION}/agents/${DIALOGFLOW_AGENT_ID}:restore" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/json" \
  -d "{\"agentContent\":\"$(base64 -w0 agent.blob)\"}"

Почему это работает: :restore — стандартный метод Dialogflow CX, который принимает тот же архив, что отдаёт экспорт, и разворачивает его в указанном агенте; base64 -w0 даёт одну строку без переносов, иначе JSON сломается.

Как проверить:

curl -sS "https://<ваш-домен>/api/agents" \
  -H "Authorization: Bearer ${LAMPLINE_API_TOKEN}" | jq '.[].name'

Ожидаемый результат: в списке появилось имя вашего агента (например, SupportBot), а на странице агента в UI число интентов совпадает с числом файлов интентов в архиве. Расхождение — повод смотреть лог импорта.

Шаг 4. Проверка работы на реальном диалоге

Иллюстрация к разделу «Шаг 4. Проверка работы на реальном диалоге»
Иллюстрация к разделу «Шаг 4. Проверка работы на реальном диалоге»

Что сделать: прогоните тестовую реплику через голосовой канал и сверьте ответ агента с исходным сценарием в Dialogflow.

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

curl -sS -X POST "https://<ваш-домен>/api/agents/SupportBot/query" \
  -H "Authorization: Bearer ${LAMPLINE_API_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"text":"Как перевыпустить пропуск?"}' | jq

Пример ожидаемого ответа: {"reply":"Уточните номер пропуска","intent":"pass_reissue","confidence":0.87} — имя интента должно совпадать с тем, что вы видите в Dialogflow CX. Если в ответе intent: "Default Fallback Intent" — маршруты не перенеслись.

Что проверяемГде смотретьОжидаемый результат
Контейнер`docker compose ps``Up (healthy)`
HTTPS`curl -I https://<ваш-домен>``HTTP/2 200` или `401`
Агент в списке`GET /api/agents`имя агента из Dialogflow
ИнтентыUI агентачисло = числу файлов в архиве
Диалог`POST /query`ответ по нужному интенту

Для постоянного наблюдения за сервером и контейнерами удобно поднять бота — инструкция в гайде как настроить мониторинг VPS через Telegram-бота с Mini App. Точные пути эндпоинтов query и agents сверьте с документацией Lampline.

Возможные проблемы и решения

Проблема. Импорт отклонён с отказом доступа к Dialogflow

gcloud projects get-iam-policy ${DIALOGFLOW_PROJECT_ID} \
  --flatten="bindings[].members" \
  --filter="bindings.members:<sa-email>" --format="value(bindings.role)"
python3 -c "import json;print(json.load(open('secrets/gcp-sa.json'))['project_id'])"

Нужна строка с ролью roles/dialogflow.admin, а project_id в ключе должен совпадать с DIALOGFLOW_PROJECT_ID.

Проблема. Архив не принимается как содержимое агента

unzip -l agent.blob | head
base64 -w0 agent.blob | wc -l   # должно быть 1 (одна строка)

Проблема. Контейнер падает сразу после старта

uname -m
docker compose down && docker compose pull && docker compose up -d

Если uname -m вернул aarch64, а в реестре только amd64-образ, добавьте в сервис platform: linux/amd64 — но это медленнее, чем нативный образ.

Резюме и следующие шаги

Вы развернули Lampline в Docker, закрыли его HTTPS-прокси и перенесли агента из Dialogflow CX архивом .blob, проверив импорт тестовым запросом. Дальше настройте резервное копирование каталога ./data и подключите голосовой канал (STT/TTS) — параметры сверьте с документацией Lampline.

FAQ

Нужна ли GPU для self-hosted голосового агента?

Для контейнерного развёртывания Lampline GPU не требуется; она нужна только локальным моделям распознавания и синтеза речи. Требования к ресурсам под конкретный голосовой движок сверьте с документацией.

Чем .blob отличается от обычного JSON-экспорта?

.blob — это ZIP-архив: внутри agent.json с настройками агента и отдельные файлы интентов, флоу и сущностей. Именно его принимает метод :restore.

Можно ли тем же способом перенести агента из Dialogflow ES?

Нет. ES и CX — разные форматы и разные API; архив CX не развернётся в ES-агенте. Порядок миграции между версиями сверьте с документацией Google.

Что будет, если импортировать агента повторно?

Повторный импорт перезаписывает содержимое целевого агента. Безопаснее загружать в нового агента и переключать трафик после проверки.

🤖 Кратко для ИИ