Серверы AMD EPYC 9354 — от 27000 ₽ в месяц или 45 ₽ в час ⭐ 64 ядра, 2.0 ГГц / 384 ГБ RAM / 2× 1.92 TБ SSD

30.04.2026

OpenWebUI: System Prompt vs Skills vs MCP Tools — разбираем на живом примере валидации URL

server one
HOSTKEY

В последних версиях OpenWebUI появились Skills, и я решил сразу же их «пристроить» в дело. Одной из задач их применения виделась валидация ссылок, которые чат-бот техподдержки отдает в своем ответе: модель должна отвечать на вопросы по документации, строить корректные ссылки на статьи и не выдумывать несуществующие эндпоинты и URL.

AI-платформа

Готовые серверы с LLM и инструментами для ИИ и машинного обучения.

Казалось бы, простая задача — всего лишь нужно написать в системном промте: «Проверяй ссылки перед отправкой». Но модель не умеет делать HTTP-запросы. Она — текстогенератор, а не браузер. Поэтому встал вопрос:

«Как гарантировать, что сгенерированная ссылка действительно работает, а не ведёт на 404?»

В текущей экосистеме OpenWebUI мы имеем три уровня абстракции:

  1. System Prompt — инструкция для LLM
  2. Skills — пост-процессоры ответа
  3. MCP Tools — исполняемый код для действий «в реальном мире»

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

Карта территории: три слоя архитектуры

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

Каждый слой решает свою задачу. Давайте разберём их по порядку.

Уровень 1: System Prompt — «Должностная инструкция»

System Prompt — это текстовый контекст, который «настраивает» поведение языковой модели до генерации ответа. Это не код, не конфигурация — это естественный язык, который модель интерпретирует как правила поведения. В нашем случае это правила для поиска информации в базе знаний, ее интерпретация, форматирование.

Кратко стартовый блок и блок формирования ссылок выглядят вот так:

<role>
ИИ-ассистент техподдержки HOSTKEY. Задача: помогать по серверам, 
панели Invapi и документации hostkey.ru.
</role>

<rules>
### 🌐 ЯЗЫК (приоритет №1)
- Отвечай ТОЛЬКО на русском, независимо от языка вопроса.

### 🔗 ССЫЛКИ — АЛГОРИТМ (строго)
Файл в базе: `<раздел>@<тема>@ru.md`
Преобразование:
1. Убрать `@ru.md` → `faq@network_settings`
2. Разбить по `@` → `["faq","network_settings"]`
3. Собрать URL: `https://hostkey.ru/documentation/faq/network_settings/`
</rules>

Что делает System Prompt в данном случае:

  • Задаёт роль, тон и тематику ответов;
  • Обучает модель правильно формировать ссылки по бизнес-алгоритму;
  • Запрещает нежелательные действия (код, выдуманные URL);

Чего он не делает:

  • Не проверяет, существует ли ссылка на самом деле;
  • Не делает сетевые запросы;
  • Не знает о существовании инструмента url_fetch_mcp — для модели это «магия».

System Prompt — это должностная инструкция сотрудника. Он знает, как надо писать отчёт, но не может выйти в поле и проверить данные.

Уровень 2: Skills — «Редактор с лупой»

Новый инструментарий Skills в OpenWebUI — это декларативные скрипты (в формате Markdown с метаданными YAML), которые выполняются после генерации ответа моделью. Они могут:

  • Парсить и анализировать текст ответа
  • Вызывать внешние инструменты (MCP Tools)
  • Модифицировать вывод перед отправкой пользователю

Если системный промт привязан к конкретной модели, то Skills могут вызываться и использоваться различными моделями совместно. Достаточно указать их при создании кастомной модели в Workspace. Мы реиспользуем этот Skills, например, в переводчиках, чтобы не было «битых» ссылок.

В нашем случае нам нужен валидатор ссылок, то есть Skill url-validator-with-mcp.

---
name: url-validator-with-mcp
description: Validates URLs via url_fetch_mcp, removes invalid ones, 
             and ensures proper formatting for valid links.
version: "2.0"
tags: [validation, urls, links, mcp, formatting, self-check]
requires_tools: ["url_fetch_mcp"]
---
# 🔗 URL Validator Skill (MCP-backed + Format Enforcement)

## 🎯 Purpose
After generating a response containing URLs:
1. **Validate accessibility** using `url_fetch_mcp`
2. **Remove entirely** invalid/unreachable links (text + URL)
3. **Enforce proper formatting** for valid links
4. Output ONLY the cleaned, validated response — no logs, no commentary

Обратите внимание на секцию между ---. В ней вы описываете ваш Skills и задаете, какие Tools он должен использовать. Также не забудьте включить Skills в настройках группы для ваших пользователей.

Разберемся, как же работает наш Skill:

  1. Он находит URL в сгенерированном ответе (выполняет его парсинг);
  2. Вызывает MCP Tools url_fetch_mcp передавая его последовательно найденные URL;
  3. Применяет бизнес-правила: удалять битые ссылки, форматировать рабочие;
  4. Возвращает «чистый» ответ без мета комментариев.

Чего не делает наш Skill:

  • Не учит модель, как строить ссылки (это задача системного промта);
  • Не заменяет логику бизнес-правил;
  • Не работает автономно и требует подключённого MCP Tool, так как сам он не может пройти по ссылке и проверить ответ от сервера.
Skill — это редактор, который проверяет черновик. Он не пишет за автора, но исправляет ошибки, удаляет нерабочие ссылки и приводит текст к стандарту.

Уровень 3: MCP Tools — «Курьер с прибором»

MCP (Model Context Protocol) Tools — это внешний исполняемый код (обычно Python/Node.js), который выполняет конкретные действия: запросы к API, проверка URL, работа с файлами. В OpenWebUI есть три механизма использования: встроенные инструменты, Toos и внешние MCP Tools.

В нашем случае у нас есть уже специальный сервер mcpo (MCP over HTTP) от тех же разработчиков, на котором расположен инструментарий работы с Invapi, поэтому добавить туда еще один было не проблемой. Но никто не запрещает тот же код реализовать через внутренние Tools OpenWebUI.

По факту сам инструмент — это простой fastmcp-сервер и код на питоне, который и проверяет ссылки. mcpo же в данном случае — это «переводчик» между миром локальных CLI-инструментов (MCP) и миром веб-приложений (OpenWebUI). 

Плюсом mcpo будет интерактивная документация в swagger-формате, доступная в /docs.

Наш MCP инструмент носит имя check_url()

from __future__ import annotations
import logging, re, sys, time
from dataclasses import asdict, dataclass
from typing import Optional
from urllib.parse import urlparse
import requests

logging.basicConfig(
    stream=sys.stderr,
    level=logging.INFO,
    format='%(asctime)s [URL_FETCH] %(levelname)s: %(message)s'
)
logger = logging.getLogger(__name__)

DEFAULT_TIMEOUT = 5.0
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64)..."

@dataclass
class URLCheckResult:
    valid: bool
    url: str
    normalized_url: Optional[str] = None
    status_code: Optional[int] = None
    response_time_ms: Optional[float] = None
    error: Optional[str] = None
    content_type: Optional[str] = None
    final_url: Optional[str] = None
    ssl_valid: Optional[bool] = None
    
    def to_dict(self) -> dict:
        return {k: v for k, v in asdict(self).items() if v is not None}

def check_url(
    url: str,
    timeout: float = DEFAULT_TIMEOUT,
    follow_redirects: bool = True,
    check_ssl: bool = True
) -> dict:
    """MCP Tool: Проверка доступности URL"""
    logger.info(f"MCP call: check_url(url='{url}')")
    
    # 1. Валидация формата
    is_valid, err = _validate_url_format(url)
    if not is_valid:
        return URLCheckResult(valid=False, url=url, error=err).to_dict()
    
    # 2. HTTP-запрос с обработкой ошибок
    try:
        response = requests.head(url, timeout=timeout, 
                                allow_redirects=follow_redirects,
                                verify=check_ssl)
        # ... анализ ответа ...
        return URLCheckResult(valid=True, status_code=response.status_code, 
                             response_time_ms=...).to_dict()
                             
    except requests.exceptions.Timeout:
        return URLCheckResult(valid=False, error="Таймаут").to_dict()
    except requests.exceptions.SSLError:
        return URLCheckResult(valid=False, error="SSL-ошибка").to_dict()
    # ... другие исключения ...

Что наш валидатор делает:

  • Реально «стучится» по ссылке (сетевой запрос);
  • Возвращает структурированный результат: status_code, response_time_ms, error;
  • Обрабатывает исключения: таймауты, SSL-ошибки, редиректы;

Также его можно использовать не только в нашем конкретном Skill, но и в других, а также напрямую в моделях.

Но так как это просто код на Python, то он не знает контекст диалога (кто пользователь, о чём вопрос), не принимает решений: «удалять ссылку или нет», так как это логика Skill, и не форматирует финальный ответ, а отдает только данные в json формате.

После этого остается только прописать наш MCP Tools в OpenWebUI.

MCP Tool — это курьер с прибором учета. Он не решает, куда ехать и что писать в отчёте. Он только измеряет: «Доставлено/не доставлено, время в пути, причина сбоя».

Полный цикл: от вопроса до ответа

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

Вход: пользователь спрашивает

«Как настроить сетевой интерфейс в панели Invapi?»

Шаг 1: Model + System Prompt

  1. LLM получает вопрос + системный промт;

  2. Находит в базе документ: controlpanel@network_interface@ru.md;

  3. Применяет алгоритм:

    "убрать @ru.md" → ["controlpanel","network_interface"] > "https://hostkey.ru/documentation/controlpanel/network_interface/" ;

  4. Генерирует черновик:

    "Откройте панель Invapi → 'Сеть' → 'Интерфейсы'.

    Подробнее: [Настройка сетевого интерфейса]

    (https://hostkey.ru/documentation/controlpanel/network_interface/)"

Шаг 2: Skill (url-validator-with-mcp)

  1. Skill получает черновик;

  2. Парсит текст, находит 1 ссылку;

  3. Вызывает MCP Tool:

    url_fetch_mcp(url="https://.../network_interface/")

  4. Получает результат:

    { "valid": true, "status_code": 200, "response_time_ms": 342 }

  5. Проверяет формат: Markdown - Да, HTTPS - Да, текст ≠ вопрос - Да ;

  6. Возвращает ответ без изменений (всё валидно).

Шаг 3: А если ссылка не валидна?

  1. MCP Tool вернул:

    { "valid": false, "error": "HTTP 404" }

  2. Skill удаляет конструкцию "[текст](ссылка)" из ответа;

  3. Выдает ответ без ссылки:

    "Откройте панель Invapi → 'Сеть' → 'Интерфейсы'.

    Точной инструкции не нашёл. Для помощи:

    [Техподдержка](https://hostkey.ru/customer-care/)."

Сравнение подходов

Так что-же лучше? System Prompt, Skill или MCP Tools. Свели все основные критерии в такую таблиц, чтобы вы могли выбрать наиболее подходящий вам инструмент.

Критерий

System Prompt

Skill

MCP Tool

Когда выполняется

До генерации ответа

После генерации

По вызову из Skill

Язык реализации

Естественный язык

Markdown + логика

Python/JS код

Доступ к сети

Нет

Только через Tools

Да

Контекст диалога

Полный

Ответ модели

Только параметры

Основная задача

Поведение, правила

Пост-обработка, координация

Конкретное действие

Гибкость

Высокая (текст)

Средняя (шаблон)

Низкая (код)

Сложность поддержки

Низкая

Средняя

Высокая

Заключение

Разработка надёжного ИИ-ассистента — это не только про «умную модель». Это про архитектуру, где составляющие ее компоненты делают своё дело:

  • System Prompt — отвечает за поведение ассистента, правила, бизнес-логику, «Знай, как надо»;
  • Skill — на нем пост-обработка и координация, «Проверь, что сделано»;
  • MCP Tool — выполняет конкретные действия «в мире», «Сделай и доложи».

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

Полезные ссылки

  • Официальная документация OpenWebUI Skills
  • Model Context Protocol Specification
  • Документация по MCP и mcpo в OpenWebUI
AI-платформа

Готовые серверы с LLM и инструментами для ИИ и машинного обучения.

Другие статьи

21.04.2026

Почему после часового созвона никто не помнит, о чём договорились

Час в Zoom прошёл, а договорённостей нет. Это не случайность: у видеовстреч есть конкретные когнитивные ограничения, которые усиливаются плохой организацией. Разбираем, почему так происходит и какие простые изменения реально помогают.

14.04.2026

«Старички» V100 в деле и модные ИИ-агенты для написания документации

Документация устаревает быстрее кода. Мы решили это через ИИ-агентов и V100. Работает, но не без нюансов.

10.04.2026

Сравнение SEO-плагинов для WordPress: Yoast SEO vs Rank Math vs AIOSEO в 2026 году

Какой SEO-плагин для WordPress выбрать в 2026 году? Сводные таблицы функций, разбор ИИ-инструментов, тесты производительности, цены, миграция и рекомендации по выбору.

10.04.2026

Yoast SEO для WordPress: полный обзор плагина в 2026 году

Yoast SEO установлен на более чем 10 миллионах сайтов WordPress. Разбираем функции, тарифы, производительность, плюсы и минусы плагина в 2026 году.

10.04.2026

Rank Math для WordPress: полный обзор плагина в 2026 году

Rank Math — быстрорастущий SEO-плагин для WordPress с более чем 3 миллионами активных установок. Разбираем функции, тарифы, плюсы и минусы в 2026 году.

Upload