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

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

Обновлено: 22.10.2026 · AI Release · @ai_release1
Пошаговое руководство: как подключить нейросеть к wiki, базе данных и тест-менеджменту для QA

TL;DR

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

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

Проверка окружения одной командой:

python3 --version && psql --version && curl --version | head -1 && jq --version && df -h "$HOME" | tail -1

Ожидаемый вывод — четыре строки с версиями и строка вида /dev/sda1 50G 12G 36G 25% /home. Если хоть одна команда даёт command not found, установите пакет до продолжения.

Если LLM и векторное хранилище вы поднимаете у себя, а не берёте облачный API, порядок развёртывания описан в гайде Как подключить ИИ к домашнему серверу.

Пример: для облачного провайдера ключ выглядит как строка sk-... и кладётся в .env, а не в код — так он не попадёт в git.

Шаг 1. Инвентаризация трёх источников и доступов

Что сделать: создать рабочий каталог, зафиксировать в одном файле .env адреса и токены трёх систем, проверить, что каждый токен реально отдаёт данные.

Зачем: 80% времени отладки RAG (RAG — когда нейросеть сначала ищет нужные документы, а потом отвечает на их основе) уходит на «а доступ-то есть?». Проверка на этом шаге отделяет проблему доступа от проблемы качества ответов.

Как проверить: каждый curl возвращает 200, а psql — число таблиц больше нуля.

mkdir -p ~/qa-rag/connectors && cd ~/qa-rag
python3 -m venv .venv && source .venv/bin/activate
pip install requests psycopg2-binary python-dotenv

Файл ~/qa-rag/.env (права chmod 600 .env):

WIKI_BASE_URL=https://wiki.<ваш-домен>
WIKI_SPACE=QA
WIKI_TOKEN=<токен-сервисного-аккаунта>
DB_DSN=postgresql://qa_ro:<пароль>@db.<ваш-домен>:5432/qa
TMS_BASE_URL=https://tms.<ваш-домен>/api
TMS_TOKEN=<токен-тест-менеджмента>
EMBEDDING_BASE_URL=https://api.<провайдер>.com/v1
EMBEDDING_API_KEY=<ключ>
EMBEDDING_MODEL=<имя-модели-эмбеддингов>
LLM_API_KEY=<ключ>

<ваш-домен> заменяйте на реальный хост без протокола и без слэша на конце. Точные пути REST-методов у вашей wiki и тест-менеджмента сверьте с документацией — ниже проверочные вызовы даны в общем виде.

ИсточникЧто забираемДоступОбновление
Wikiстраницы пространства QAтокен, чтениепо вебхуку или раз в сутки
Базасхема с тестовыми даннымироль `qa_ro`, только SELECTпо расписанию
Тест-менеджменттест-кейсы и результаты прогоновAPI-токенпо расписанию

Проверка wiki (путь /rest/api/content — типовой, сверьте с документацией вашей платформы):

curl -sS -o /dev/null -w "%{http_code}\n" \
  -H "Authorization: Bearer $WIKI_TOKEN" \
  "$WIKI_BASE_URL/rest/api/content?spaceKey=$WIKI_SPACE&limit=1"

Ожидается 200. 401 — токен неверный, 403 — нет прав на пространство.

Проверка базы:

psql "$DB_DSN" -c "select count(*) as tables from information_schema.tables where table_schema='public';"

Ожидается таблица с колонкой tables и числом больше 0. Ошибка password authentication failed означает, что роль ещё не создана — это Шаг 2.

Пример: если тест-менеджмент отдаёт проекты по /api/v1/projects, проверка выглядит так: curl -sS -H "Authorization: Bearer $TMS_TOKEN" "$TMS_BASE_URL/v1/projects" | jq '.items | length' → 7. Любое число, кроме null, подтверждает доступ.

Шаг 2. Сборка индекса и подключение инструментов к нейросети

Иллюстрация к разделу «Шаг 2. Сборка индекса и подключение инструментов к нейросети»
Иллюстрация к разделу «Шаг 2. Сборка индекса и подключение инструментов к нейросети»

Что сделать: выгрузить тексты из трёх систем, нарезать их на чанки (чанк — кусок текста фиксированного размера, который ищется как единица), векторизовать, сохранить в хранилище и описать нейросети три инструмента: поиск по wiki, SQL-запрос к базе, запрос тест-кейса.

Зачем: нейросеть сама не имеет доступа к вашим системам — она умеет только вызывать описанные вами функции. Индекс нужен, чтобы в контекст попадали 3–5 релевантных кусков, а не вся wiki.

Как проверить: скрипт печатает число страниц и чанков, а тестовый поиск возвращает непустой список.

Сначала — безопасная роль в базе:

CREATE ROLE qa_ro LOGIN PASSWORD '<пароль>';
GRANT CONNECT ON DATABASE qa TO qa_ro;
GRANT USAGE ON SCHEMA public TO qa_ro;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO qa_ro;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO qa_ro;
ALTER ROLE qa_ro SET default_transaction_read_only = on;

Последняя строка запрещает запись на уровне сессии: даже если нейросеть сгенерирует DELETE, база вернёт ошибку. Это и есть причина, по которой роль создаётся до подключения модели.

Файл ~/qa-rag/index.py:

import os, requests
from dotenv import load_dotenv

load_dotenv()

def chunk(text, size=800, overlap=100):
    step = size - overlap
    return [text[i:i + size] for i in range(0, len(text), step) if text[i:i + size].strip()]

def fetch_wiki(space):
    r = requests.get(
        f"{os.environ['WIKI_BASE_URL']}/rest/api/content",
        params={"spaceKey": space, "limit": 100, "expand": "body.storage"},
        headers={"Authorization": f"Bearer {os.environ['WIKI_TOKEN']}"},
        timeout=30,
    )
    r.raise_for_status()
    return [{"id": p["id"], "title": p["title"],
             "text": p["body"]["storage"]["value"]} for p in r.json()["results"]]

def embed(texts):
    r = requests.post(
        f"{os.environ['EMBEDDING_BASE_URL']}/embeddings",
        headers={"Authorization": f"Bearer {os.environ['EMBEDDING_API_KEY']}"},
        json={"model": os.environ["EMBEDDING_MODEL"], "input": texts},
        timeout=60,
    )
    r.raise_for_status()
    return [d["embedding"] for d in r.json()["data"]]

Формат тела и ответа /embeddings сверьте с документацией провайдера: у части сервисов поля называются иначе.

Проверка нарезки:

python -c "from index import chunk; print(len(chunk('a'*2000)))"

Ожидается 3: при size=800 и overlap=100 шаг равен 700, и 2000 символов дают три куска.

Описание инструментов для модели — файл tools.json:

[
  {"name": "wiki_search",
   "description": "Поиск по QA-документации. Возвращает 5 чанков с id страницы.",
   "parameters": {"type": "object", "properties": {"query": {"type": "string"}}, "required": ["query"]}},
  {"name": "db_query",
   "description": "SELECT-запрос к базе, максимум 200 строк, только схема public.",
   "parameters": {"type": "object", "properties": {"sql": {"type": "string"}}, "required": ["sql"]}},
  {"name": "tms_get_case",
   "description": "Карточка тест-кейса по ID: шаги, ожидаемый результат, последний статус.",
   "parameters": {"type": "object", "properties": {"case_id": {"type": "string"}}, "required": ["case_id"]}}
]

Пример: на запрос «почему падает TC-1042» модель должна вызвать tms_get_case с {"case_id": "TC-1042"}, затем db_query с SELECT status, count(*) FROM runs WHERE case_id='TC-1042' GROUP BY status; — два вызова подряд, а не один общий вопрос к базе.

Шаг 3. Сквозная проверка и приёмка результата

Иллюстрация к разделу «Шаг 3. Сквозная проверка и приёмка результата»
Иллюстрация к разделу «Шаг 3. Сквозная проверка и приёмка результата»

Что сделать: задать системе реальный вопрос QA-инженера и убедиться, что ответ содержит ссылку на страницу wiki, результат SQL и ID тест-кейса.

Зачем: по отдельности все три коннектора могут работать, а вместе — нет: модель «забывает» вызвать инструмент или подставляет выдуманный ID.

Как проверить: в логах есть три вызова инструментов, в ответе — три источника; при отсутствии данных модель отвечает «в документации не найдено».

curl -sS http://localhost:8080/health | jq .

Ожидаемый вывод:

{"status": "ok", "chunks": 1240}

Число 1240 — фактическое количество чанков в вашем индексе, оно зависит от объёма wiki.

Проверка поиска без модели:

curl -sS -X POST http://localhost:8080/search \
  -H "Content-Type: application/json" \
  -d '{"q":"флаки-тест на стейдже","k":5}' | jq '.results | length'

Ожидается 5. Ноль означает, что индекс пуст или запрос не совпал с лексикой документов.

Чек-лист приёмки:

Последний пункт проверяется руками:

psql "$DB_DSN" -c "DROP TABLE runs;"

Ожидается ERROR: cannot execute DROP TABLE in a read-only transaction либо permission denied for table runs.

Пример: успешный ответ на «почему TC-1042 падает на стейдже» выглядит так: «Падение связано с таймаутом внешнего сервиса (wiki: страница 88421, раздел „Известные флаки“). По данным прогонов: 12 failed, 3 passed (SQL по runs). Шаги кейса — TC-1042, последний статус failed». Три источника — три явных указания.

Как наблюдать за сервисом после запуска (порты, аптайм, уведомления в Telegram) — в гайде мониторинг VPS через Telegram-бота с Mini App.

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

Проблема. Wiki не отдаёт страницы, хотя логин верный

curl -sS -o /dev/null -w "%{http_code}\n" -H "Authorization: Bearer $WIKI_TOKEN" "$WIKI_BASE_URL/rest/api/content?limit=1"

Если без Bearer возвращается 403, а с ним 200 — дело было в схеме авторизации.

Проблема. Индекс не собирается: коннектор не видит базу

psql "postgresql://qa_ro:<пароль>@127.0.0.1:5432/qa" -c "select 1;"

Ответ ?column? = 1 означает, что дело было только в имени хоста.

Проблема. Модель отвечает «не найдено», хотя страница в wiki есть

python index.py --space "$WIKI_SPACE" --rebuild && curl -sS http://localhost:8080/health | jq '.chunks'

Число chunks должно вырасти. Точные флаги CLI задаёт ваш скрипт — если --rebuild не поддерживается, удалите каталог индекса и запустите сборку заново.

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

Три коннектора проверяются по отдельности до того, как вы дадите модели право их вызывать: сначала 200 от каждого API и роль qa_ro с SELECT, потом индекс, потом сквозной вопрос с тремя источниками в ответе. Дальше добавьте расписание переиндексации и тест на «вопрос вне базы знаний», чтобы ловить регрессии качества при смене модели эмбеддингов.

FAQ

Чем RAG отличается от дообучения модели на документации?

RAG ищет документы во время ответа и не меняет веса модели: обновили страницу — переиндексировали и всё. Дообучение меняет саму модель, стоит дороже и требует пересборки при каждой правке документа.

Нужно ли давать нейросети доступ к продакшен-базе?

Нет. Создайте отдельную роль только с SELECT и включите default_transaction_read_only, как в Шаге 2: тогда запись отклоняется на уровне транзакции, а не на уровне вашей внимательности.

Какой размер чанка выбрать?

Начните с 800 символов с перекрытием 100 и проверьте выдачу на 10 реальных вопросах. Перекрытие сохраняет смысл на границе кусков; если ответы обрываются на середине мысли — увеличьте перекрытие.

Что делать, если тест-менеджмент не имеет API?

Забирайте данные выгрузкой (CSV/JSON) по расписанию и индексируйте файл как ещё один источник. Конкретный способ выгрузки сверьте с документацией вашей системы — универсального метода нет.

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