Как я разработал легковесный Guardrails для русского языка

от автора

Всем привет, меня зовут Максим. Я автор Telegram‑канала Максим Максимов // IT, AI. В этой статье расскажу о том, как я реализовал свою идею создать guardrails, который будет простым, работать быстро, но в то же время готовым к внедрению в производство. 

Поехали!

Содержание

Что такое Guardrails

Для начала давайте поймём, что такое Guardrails. Это система, роль которой — защищать другие системы от нежелательных данных или действий. Чаще всего Guardrails выступает как прослойка между системами и проверяет данные, которыми они обмениваются.

Guardrails может работать как с выходными данными системы, так и с входными.

Guardrails

Guardrails

Сценарии использования могут быть разные. Например, ваша платформа использует LLM внешних провайдеров, куда не хотелось бы отправлять персональные данные пользователей (152-ФЗ). В этой цепочке Guardrails будет ловить такие данные в тексте и, например, блокировать такие запросы либо же маскировать их.

Так как Guardrails является дополнительным звеном в работе, это может увеличивать время обработки запросов пользователей, что не очень хотелось бы. Также при использовании тяжеловесных моделей для работы с данными (например LLM) могут требоваться мощности, которые есть не у всех. 

Поэтому у меня возникла идея сделать такой Guardrails, который бы работал быстро и не требовал большого количества ресурсов. При этом я понимал, что готовые аналоги есть и их можно просто взять и использовать — но мне было интересно сделать своё: пройти путь от идеи, самому продумать архитектуру, произвести разработку и довести Guard до продакшен состояния. А значит, столкнуться с проблемами по пути и решить их. Во время реализации я ориентировался на открытые open-source решения.

Идея lite‑guardrails

Рассмотрим идею легковесного Guardrails, на которой я остановился.

Чтобы добиться легковесности и скорости, я решил не использовать никакие модели вроде BERT или LLM. Вместо этого использовались классические методы работы с текстом. Это решение, конечно, влечёт за собой некоторые проблемы — о них расскажу далее.

Основной функционал Guardrails разделён на три модуля:

Модули lite-guardrails

Модули lite‑guardrails

PII — позволяет находить персональные данные в тексте, чтобы защитить их от утечек вовне и соблюдать 152-ФЗ.

NSFW — находит в тексте небезопасный контент. В моей реализации — русский мат. Используется там, где нужно отклонять подобного рода запросы.

Relevant — находит мусор в тексте (эмодзи, текст только из знаков пунктуации, …), а также смолток («Привет», «Как дела», «Пока», …). Может использоваться как фильтр нерелевантных запросов, либо же при работе с LLM роутить такие запросы на более дешёвые модели.

Во время разработки я ориентировался только на русскоязычный текст. Но сама реализация Guardrails позволяет расширять его и на другие языки.

Далее пройдемся по самому интересному — процессу разработки. Рассмотрим сам процесс и в целом поймём, как работает lite‑guardrails. Во время работы над проектом разработку заметно упрощал Claude Code: с ним я в большей степени выступал архитектором и ревьюером кода, а также продакт‑менеджером проекта.

Основная бизнес логика

В этой части рассмотрим работу каждого модуля Guardrails, а также проведённые эксперименты и сравнения.

PII

Задача этого модуля — обнаружение персональных данных в тексте.

В качестве персональных данных были выделены следующие сущности:

  • Номер телефона

  • Email

  • URL

  • ИНН

  • Паспорт

  • СНИЛС

  • Банковская карта

  • IP

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

Телефон, email и URL детектируются чисто регулярными выражениями.

Например, регулярка для номеров:

(?:\+7|8)[\s\‑]*\(?\s*\d{3}\s*\)?[\s\‑]*\d{3}[\s\‑]*\d{2}[\s\‑]*\d{2}

Ловит номера в формате:

  • +79161234567

  • 8 916 123 45 67

  • +7 (916) 123–45-67

Для остальных сущностей после регулярки применяется алгоритмическая валидация. ИНН и СНИЛС проверяются контрольной суммой (взвешенная сумма по модулю 11 и 101 соответственно):

Алгоритм валидации ИНН

Алгоритм валидации ИНН

Банковская карта валидируется алгоритмом Луна (Luhn). Каждая вторая цифра номера удваивается (а если получилось больше 9 — из результата вычитают 9), затем все цифры суммируются. Если сумма кратна 10 — номер прошёл проверку.

Алгоритм валидации банковских карт - Луна (Luhn)

Алгоритм валидации банковских карт — Луна (Luhn)

IP — проверкой диапазона октетов (0–255), а паспорт РФ — структурной проверкой (код региона, год бланка, отсев одинаковых цифр и монотонных последовательностей).

Вышеперечисленные проверки были добавлены для того, чтобы уменьшить количество ложных срабатываний, так как, например, в тексте могут попадаться схожие наборы чисел, которые не являются паспортом или ИНН.

Помимо модуля обнаружения персональных данных, разработан функционал их анонимизации и деанонимизации в тексте. Также это называют псевдонимизацией.

Он позволяет при отправке данных во внешние системы (например в LLM) маскировать персональные данные в тексте и заменять их на теги ([PERSON_1], [PHONE_1], …), хранить реальные данные в контуре Guardrails и отправлять в LLM уже маскированный текст. Далее LLM генерирует ответ, используя теги. Когда мы получаем ответ от LLM, текст проходит этап демаскирования — вместо тегов мы подставляем реальные персональные данные. Таким образом, персональные данные не уходят вовне (удовлетворяя 152-ФЗ), а пользователь получает корректный ответ.

Как можно заметить, при работе данного функционала требуется хранилище для извлечённых персональных данных — о его реализации расскажу далее.

Конечно, не всегда это работает идеально: бывают ошибки, например, когда LLM путается в тегах или пишет их неправильно. 

NSFW

Это модуль, который позволяет находить небезопасный контент в тексте. На данный момент он ориентирован на обнаружение русского мата, но также может быть расширен и на другие категории.

Работает он следующим образом: заранее собирается словарь из нежелательных слов, которые детектор должен находить. Далее во время работы модуля идёт поиск этих слов в тексте, и если слово найдено — происходит срабатывание.

Модуль NSFW

Модуль NSFW

Для ускорения поиска используется не полнотекстовый поиск, а алгоритм Ахо‑Корасик, который позволяет искать нежелательные слова быстрее, чем наивный полнотекстовый поиск. Данный алгоритм работает по принципу конечного автомата, обрабатывая текст за линейное время.

За простотой данной реализации скрываются недостатки — модуль ищет NSFW только по словам, но не по смыслу. То есть если в тексте будет нежелательный контент, но в формулировках, которых нет в словаре, — он такое пропустит. Отсутствие понимания семантики — это цена скорости и неиспользования моделей для работы с текстом.

Relevant

Это модуль, который определяет, содержит ли сообщение осмысленный запрос или это смолток (приветствия, благодарности, прощания), оффтоп или бессмысленный «мусор».

Модуль Relevant

Модуль Relevant

Заранее собираются словари фраз, сгруппированные по категориям (приветствие, благодарность, прощание и так далее). Во время работы модуля текст приводится к нижнему регистру, и в нём ищутся совпадения с шаблонами всех категорий.

Ключевая идея — не просто найти шаблонную фразу, а оценить, какую долю сообщения она занимает. Для этого считается покрытие текста по буквам: сколько букв сообщения попало в найденные фразы. Если совпадения есть и покрытие превышает порог (80%), значит, сообщение почти целиком состоит из смолтока/оффтопа и помечается как нерелевантное; иначе в тексте есть содержательная часть, и оно считается релевантным. Такой подход позволяет отфильтровать чистый смолток («привет, спасибо, пока»), но не блокировать нормальный запрос, в котором вежливое приветствие идёт перед сутью.

Дополнительно работает отдельная проверка — фильтр «мусора»: если в тексте нет ни букв, ни цифр (одни символы или эмодзи), он сразу помечается нерелевантным.

Сравнение с другими решениями

Данные модули были протестированы на бенчмарках, чтобы понять их качество.

Для оценки модуля PII я взял русскоязычный бенчмарк на детекцию персональных данных.

Метрики вышли следующие:

Оценка lite-guardrails на PII бенчмарке

Оценка lite‑guardrails на PII бенчмарке

В бенчмарке намеренно встречаются опечатки в сущностях и лишние знаки пунктуации, чтобы классические регулярные выражения не могли поймать PII. На таких примерах наш модуль PII допускает ошибки (это видно по низкому Recall), но простые чёткие примеры он ловит хорошо (высокий Precision).

Для модуля NSFW я также взял открытый бенчмарк для оценки детекторов NSFW в тексте.

Оценка lite-guardrails на NSFW бенчмарке

Оценка lite‑guardrails на NSFW бенчмарке

В данном случае нашему NSFW‑детектору ещё тяжелее. Большая часть ошибок связана с тем, что бенчмарк ориентирован на семантическое понимание контента, а наш детектор — только на наличие триггерных слов в тексте.

Для модуля Relevant я не нашёл подходящего бенчмарка, поэтому оценить его на внешних данных не удалось. В любом случае вывод будет тот же — модуль отлавливает смолток, ориентируясь только на наличие фраз из словаря в тексте. 

Замер времени работы lite-guardrails и NER моделей

Замер времени работы lite‑guardrails и NER моделей

Отдельно я замерил скорость. Взял ноутбук без видеокарты, только CPU, и прогнал одни и те же тексты через несколько NER‑моделей, которые ловят персональные данные, и через свой guard. Результат на графике выше: небольшая BERT‑модель (piiranha) обрабатывает один текст примерно за 186 мс, GLiNER — за 226 мс, а lite‑guardrails на том же железе тратит меньше 0.1 мс на текст. Разница в тысячи раз. Причина простая — модели каждый раз гоняют нейросеть, и без GPU это медленно, а мой guard работает на регулярках с проверкой контрольных сумм, где считать почти нечего, поэтому он отвечает практически мгновенно.

По качеству lite‑guardrails, конечно, уступает языковым моделям (таким как BERT или, например, gpt‑oss‑guard) — он не понимает смысл и ошибается на искаженных данных. Зато он хорошо ловит простые чёткие случаи, не требует ресурсов и работает за доли миллисекунды. Поэтому такое решение стоит брать, когда нет свободных мощностей, а хочется поставить что‑то быстрое и лёгкое.

API‑сервис

Для того чтобы другие системы могли удобно работать с Guardrails, я решил сделать его отдельным web‑сервисом. Для этого использовал FastAPI — популярный и удобный фреймворк для быстрой разработки API. Во время реализации я старался придерживаться слоистой архитектуры. Код модулей вынесен в слой бизнес‑логики, поверх которого располагаются внешний API и работа с данными.

Работает это следующим образом:

Обернул модули Guardrails в FastAPI

Обернул модули Guardrails в FastAPI

Для каждого модуля сделан эндпоинт, который могут вызывать внешние сервисы. Помимо одиночных вызовов добавлен функционал пакетной обработки.

Эндпоинты для работы с модулями Guardrails

Эндпоинты для работы с модулями Guardrails

Также, чтобы увеличить пропускную способность, я использую воркеры (workers) uvicorn при разворачивании сервиса. Так как при обработке запросов у нас по большей части CPU‑bound задачи, ускорить работу помогает распараллеливание по воркерам.

Работает это так: при запуске сервера с несколькими воркерами на каждом ядре CPU размещается копия FastAPI‑приложения. Запросы распределяются между этими копиями и обрабатываются параллельно, что и повышает пропускную способность сервера. При этом имеется единая база данных, с которой эти воркеры взаимодействуют.

Как мы помним, для модуля PII функционал деанонимизации требует наличия хранилища, которое будет сохранять и отдавать персональные данные при анонимизации и деанонимизации.

В lite‑guardrails это реализовано так. При вызове пользователем ручки деанонимизации на первом шаге происходит обнаружение персональных данных в тексте. После этого создаётся уникальный идентификатор запроса, а сами персональные данные заменяются на теги. Таким образом, нам нужно хранить данные в формате: ключ — идентификатор, а значение — теги и соответствующие им реальные персональные данные. Для этого использован Redis: он хранит данные в формате ключ‑значение и позволяет достаточно быстро сохранять и получать их при запросе.

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

Интеграция с LiteLLM

Если в работе используется litellm, есть возможность удобно внедрить этот guardrails, чтобы он работал при запросах к внешним LLM.

Для этого в litellm есть возможность внедрить свой кастомный guardrails. Нужно реализовать Python‑класс со структурой:

from litellm.integrations.custom_guardrail import CustomGuardrailfrom litellm.proxy._types import UserAPIKeyAuthfrom litellm.caching.dual_cache import DualCacheclass LiteGuardrails(CustomGuardrail):    async def async_pre_call_hook(        self,        user_api_key_dict: UserAPIKeyAuth,        cache: DualCache,        data: dict,        call_type: str,    ):        # проверка входящего промпта: relevant / nsfw / pii + анонимизация        ...    async def async_post_call_success_hook(        self,        data: dict,        user_api_key_dict: UserAPIKeyAuth,        response,    ):        # обработка ответа модели: деанонимизация + проверка nsfw        ...

Реализуем два хука: async_pre_call_hook отрабатывает до отправки запроса в LLM (проверяем и при необходимости блокируем/анонимизируем ввод), а async_post_call_success_hook — после ответа модели (деанонимизируем и проверяем вывод). В pre‑call PII заменяется на теги (<EMAIL_1>…), чтобы реальные данные не ушли в LLM, а в post‑call эти теги разворачиваются обратно — пользователь видит оригинальные значения.

Далее этот класс добавляется в YAML‑конфиг litellm:

…guardrails:  - guardrail_name: lite-guardrails    litellm_params:      guardrail: lite_guardrails.LiteGuardrails      mode: [pre_call, post_call]      default_on: false # (либо true - работает всегда)…

Если всё сделано правильно, после перезапуска в UI litellm будет видно, что добавленный guard работает.

Guardrails в LiteLLM

Guardrails в LiteLLM

После этого при использовании LLM через litellm будет работать guardrails. Например, анонимизация персональных данных перед отправкой во внешнюю LLM.

Панель администратора

Во время разработки я предполагал, что с Guardrails будут работать несколько клиентов или сервисов. Для того чтобы было удобно это отслеживать и администрировать, была разработана отдельная админ‑панель. Он разрабатывался с использованием React.

Админка имеет следующий функционал:

Дашборд

Дашборд в lite-guardrails

Дашборд в lite‑guardrails

Здесь размещена небольшая статистика по использованию каждого модуля: количество и процент срабатываний, а также данные по использованию Guardrails по каждому ключу.

Настройка модулей

Настройка модуля PII

Настройка модуля PII

Имеется модуль для добавления регулярных выражений для PII. Можно включить\отключить регулярные выражения, добавить новые или отредактировать старые.

Настройка NSFW модуля

Настройка NSFW модуля

Для модуля NSFW есть возможность включать/отключать словари, добавлять новые, а также редактировать старые, чтобы добавить или удалить слова, которые детектор должен отлавливать. Модуль Relevant работает схожим образом.

Таким образом, при добавлении или изменении правил можно настраивать работу guard — какие сущности он отлавливает и на какие слова триггерится.

Настройка API ключей

Настройка API ключей в lite-guardrails

Настройка API ключей в lite‑guardrails

Здесь можно создать API ключ для клиента, настроить ему RPM, а также отслеживать по логам и метрикам его использование Guardrails.

Логи запросов

Просмотр логов lite-guardrails

Просмотр логов lite‑guardrails

На страничке с логами можно посмотреть историю запросов в Guardrails, а также срабатывания. Имеется фильтр, по которому можно отфильтровать данные по метаданным, например по API‑ключу.

Демо

Демо стенд для lite-guardrails

Демо стенд для lite‑guardrails

На этой страничке можно быстро опробовать и продемонстрировать работу Guardrails на своих данных прямо внутри админки.

SDK для взаимодействия с сервисом

Для того чтобы было удобно взаимодействовать с Guardrails из своего приложения, был разработан SDK для двух языков.

На Python:

from lite_guardrails_client import GuardrailsClient, RateLimitErrorwith GuardrailsClient("https://guard.company.ru", api_key="gk_...") as guard:    out = guard.detect_pii("мой телефон +79161234567")    if out["PII_DETECT"]:        ...    # по умолчанию анонимизация без сохранения (Redis не используется, id=null)    guard.anonymize("почта ivan@example.com")            # {"id": null, "text":"почта <EMAIL_1>"}    # deanonymize=True — сохранить mapping в Redis, чтобы потом восстановить    masked = guard.anonymize("почта ivan@example.com", deanonymize=True)  # {"id":..., "text":...}    original = guard.deanonymize(masked["id"], masked["text"])    # батч    guard.detect_nsfw_batch(["текст 1", "текст 2"])

Имеется синхронный так и асинхронный клиент.

Также разработан SDK на JavaScript:

import { GuardrailsClient, RateLimitError } from "lite-guardrails-client";const guard = new GuardrailsClient("https://guard.company.ru", "gk_...");const out = await guard.detectPii("мой телефон +79161234567");if (out.PII_DETECT) {  // ...}// по умолчанию анонимизация без сохранения (Redis не используется, id=null)await guard.anonymize("почта ivan@example.com");        // { id: null, text: "почта <EMAIL_1>" }// deanonymize=true — сохранить mapping в Redis, чтобы потом восстановитьconst masked = await guard.anonymize("почта ivan@example.com", true); // { id, text }const original = await guard.deanonymize(masked.id, masked.text);// батчawait guard.detectNsfwBatch(["текст 1", "текст 2"]);

Observability

Для того чтобы настроить более продвинутое observability, я добавил возможность интеграции с Prometheus: есть ручка /metrics, которая отдаёт метрики в нужном формате, а также заранее подготовленный YAML‑файл с конфигурацией для развёртывания Prometheus.

Prometheus

Prometheus

Также заранее подготовлена конфигурация и сформирован dashboard для Grafana, который можно развернуть вместе с Prometheus.

Grafana

Grafana

Либо же если эти сервисы уже развернуты — можно просто использовать ручку /metrics для извлечения метрик.

Развертывание

Для упрощения развёртывания используется Docker — вся конфигурация сервисов собрана в docker-compose.

docker‑compose.yml
services:  guardrails:    build: .    image: lite-guardrails    ports:      - "127.0.0.1:8000:8000"    # Внутри docker-сети доступен как guardrails:8000 (nginx, Prometheus, пробы).    expose:      - "8000"    env_file:      - .env    depends_on:      postgres:        condition: service_healthy      redis:        condition: service_healthy    healthcheck:      test: ["CMD-SHELL", "python -c \"import urllib.request; urllib.request.urlopen('http://localhost:8000/live')\""]      interval: 15s      timeout: 5s      retries: 5      start_period: 40s    restart: unless-stopped  frontend:    build:      context: ./frontend      args:        # Пусто -> UI ходит в API относительным путём через эту же nginx-проксю.        VITE_API_BASE: ${UI_API_BASE:-}    image: lite-guardrails-frontend    # ЕДИНСТВЕННАЯ публичная точка входа. Порт хоста 8080 -> nginx :80.    # Для prod поставьте перед ним TLS-терминатор или добавьте сюда 443 + сертификаты.    ports:      - "8080:80"    depends_on:      - guardrails    restart: unless-stopped  redis:    image: redis:7-alpine    # Наружу не публикуется — только внутри docker-сети (guardrails:6379).    healthcheck:      test: ["CMD", "redis-cli", "ping"]      interval: 15s      timeout: 3s      retries: 5    restart: unless-stopped  postgres:    image: postgres:16-alpine    # POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DB берутся из .env    env_file:      - .env    ports:      - "127.0.0.1:5433:5432"    volumes:      - pgdata:/var/lib/postgresql/data    healthcheck:      test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]      interval: 10s      timeout: 5s      retries: 5    restart: unless-stopped  prometheus:    image: prom/prometheus:v2.53.2    profiles: ["monitoring"]    volumes:      - ./monitoring/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro      - promdata:/prometheus    # UI/скрейп-таргет только на localhost хоста — наружу машины не торчит.    ports:      - "127.0.0.1:9090:9090"    depends_on:      - guardrails    restart: unless-stopped  grafana:    image: grafana/grafana:11.4.0    profiles: ["monitoring"]    environment:      # Логин админа (для правки). Значения берутся из .env, дефолт — admin/admin.      GF_SECURITY_ADMIN_USER: ${GRAFANA_ADMIN_USER:-admin}      GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD:-admin}      # Анонимный просмотр (Viewer) — дашборд открывается без логина. Безопасно:      # порт висит только на localhost. Редактировать можно лишь под админом.      GF_AUTH_ANONYMOUS_ENABLED: "true"      GF_AUTH_ANONYMOUS_ORG_ROLE: Viewer      GF_USERS_DEFAULT_THEME: light    volumes:      - ./monitoring/grafana/provisioning:/etc/grafana/provisioning:ro      - ./monitoring/grafana/dashboards:/var/lib/grafana/dashboards:ro      - grafanadata:/var/lib/grafana    ports:      - "127.0.0.1:3000:3000"    depends_on:      - prometheus    restart: unless-stoppedvolumes:  pgdata:  promdata:  grafanadata:

Чтобы развернуть lite‑guardrails, достаточно клонировать репозиторий, создать файл окружения и выполнить запуск:

docker compose up --build -d

После этого поднимаются основные сервисы (API + движок, Admin UI, PostgreSQL, Redis) — можно начинать пользоваться Guardrails.

Для Prometheus и Grafana в docker-compose.yml заведён профиль monitoring. Если при развёртывании нужно поднять и мониторинг, запуск выполняется так (флаг профиля идёт до up):

docker compose --profile monitoring up --build -d

Эта команда поднимет все сервисы, включая мониторинг.

CI в Github Actions

Также для повышения качества кодовой базы и уменьшения багов был добавлен CI‑workflow в GitHub Actions, в котором производится автоматическая проверка линтинга, запуск автотестов и проверка зависимостей.

CI в GitHub Actions

CI в GitHub Actions

Pipe выглядит следующим образом

ci.yml
name: CIon:  push:    branches: [main]  pull_request:    branches: [main]jobs:  lint:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v4      - uses: actions/setup-python@v5        with:          python-version: "3.12"          cache: pip      - run: pip install --group dev      - run: ruff check backend tests  test:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v4      - uses: actions/setup-python@v5        with:          python-version: "3.12"          cache: pip      - run: pip install -r requirements.txt      - run: pip install --group dev      - run: pytest -q  audit:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v4      - uses: actions/setup-python@v5        with:          python-version: "3.12"          cache: pip      - run: pip install --group dev      - run: pip-audit -r requirements.txt

Также был добавлен CD‑workflow для автоматической публикации документации (о ней расскажу ниже). Для неё тоже использовался GitHub Actions, который публикует страницу с документацией при пуше в репозиторий.

docs.yml
name: docson:  push:    branches: [main]    paths:      - docs/**      - mkdocs.yml      - .github/workflows/docs.yml  # Ручной запуск из вкладки Actions — задеплоить доку, не дожидаясь пуша в docs/**.  workflow_dispatch:permissions:  contents: write  # gh-deploy пушит собранный сайт в ветку gh-pagesjobs:  deploy:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v4      - uses: actions/setup-python@v5        with:          python-version: "3.12"      - run: pip install mkdocs-material      - run: mkdocs gh-deploy --force

Документация

Также для удобного погружения в работу инструмента я решил сформировать документацию.

Для этого я использовал крутой инструмент MkDocs, который позволяет достаточно просто собрать документацию из Markdown‑файлов, а после разместить их как страницы веб‑сайта.

Документация lite-guardrails

Документация lite‑guardrails

Даже поиск из коробки есть

Поиск по документации

Поиск по документации

Для размещения документации я использовал GitHub Pages. Это функционал GitHub, который позволяет публиковать простые сайты, используя его же в качестве хостинга. Он отлично подошёл для документации.

Для того чтобы сформировать сайт с MkDocs, достаточно создать.md файлы с документацией.

Документация в .md файлах

Документация в.md файлах

Далее на основе документации настроить YAML‑файл, в котором помимо темы, шрифтов и так далее указать путь к.md‑файлам документации.

mkdocs.yml
site_name: lite-guardrailssite_description: Быстрый self-hosted для текста — PII / NSFW / релевантностьsite_url: https://maksimov-m.github.io/lite-guardrails/docs_dir: docstheme:  …  features:    …nav:  - Обзор: index.md  - Модули: modules.md  - Развёртывание: deployment.md  - Python SDK: sdk.md  - JavaScript SDK: sdk-js.md  - Архитектура: architecture.md  - Сравнение: comparison.mdmarkdown_extensions:  …plugins:  - search:      lang: ru

Для удобства, как сказано выше, создан CD‑workflow, который автоматически деплоит документацию на сайт при пуше в GitHub.

Заключение

На этом всё! В статье я рассказал о своём ходе мыслей при формировании идеи гуарда, его разработке, а также настройке CI и мониторинга.

Делитесь в комментариях своими идеями по улучшению и доработке lite‑guardrails.

Ссылка на GitHub lite‑guardrails — https://github.com/maksimov‑m/lite‑guardrails

Подписывайтесь на мой Telegram‑канал, в котором я также рассказываю интересные вещи об IT и AI технологиях.

ссылка на оригинал статьи https://habr.com/ru/articles/1056866/