<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" xmlns:tt="http://teletype.in/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Вячеслав Старцев</title><generator>teletype.in</generator><description><![CDATA[AI-агенты, автоматизация бизнес-процессов]]></description><image><url>https://img2.teletype.in/files/1f/8d/1f8d15c1-8b31-4f7a-958e-c8750b9f6364.png</url><title>Вячеслав Старцев</title><link>https://blog.promptica.ru/</link></image><link>https://blog.promptica.ru/?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=promptica</link><atom:link rel="self" type="application/rss+xml" href="https://teletype.in/rss/promptica?offset=0"></atom:link><atom:link rel="next" type="application/rss+xml" href="https://teletype.in/rss/promptica?offset=10"></atom:link><atom:link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></atom:link><pubDate>Sun, 19 Apr 2026 03:05:18 GMT</pubDate><lastBuildDate>Sun, 19 Apr 2026 03:05:18 GMT</lastBuildDate><item><guid isPermaLink="true">https://blog.promptica.ru/rag-metrics</guid><link>https://blog.promptica.ru/rag-metrics?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=promptica</link><comments>https://blog.promptica.ru/rag-metrics?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=promptica#comments</comments><dc:creator>promptica</dc:creator><title>Метрики качества RAG (шпаргалка)</title><pubDate>Sat, 07 Feb 2026 06:30:10 GMT</pubDate><media:content medium="image" url="https://img4.teletype.in/files/35/dc/35dcb88c-696b-4589-820e-f988a968ff91.png"></media:content><category>RAG</category><description><![CDATA[<img src="https://img2.teletype.in/files/1c/bd/1cbdb18a-cccf-4453-b911-00bd96460887.jpeg"></img>RAG (Retrieval-Augmented Generation) оценивают на двух уровнях: насколько хорошо нашли нужные документы и насколько хорошо сгенерировали ответ.]]></description><content:encoded><![CDATA[
  <p id="kN1k">RAG (Retrieval-Augmented Generation) оценивают на двух уровнях: насколько хорошо нашли нужные документы и насколько хорошо сгенерировали ответ.</p>
  <h2 id="1t9B">Метрики поиска (Retrieval)</h2>
  <p id="E3FY"><strong>Precision@K (точность)</strong> - какая доля из K найденных документов реально полезна.</p>
  <p id="P792">Пример: <em>система нашла 5 документов, из них 3 релевантны. Precision@5 = 3/5 = 0.6. То есть 40% мусора.</em></p>
  <p id="7spV"><strong>Recall@K (полнота)</strong> - какую долю всех нужных документов мы нашли.</p>
  <p id="ezKU">Пример: <em>в базе 10 релевантных документов, система нашла 3 из них. Recall = 3/10 = 0.3. Мы упустили 70% полезной информации.</em></p>
  <p id="SIcW"><strong>MRR (Mean Reciprocal Rank)</strong> - насколько высоко в выдаче оказался первый правильный документ.</p>
  <p id="Aepx">Пример: <em>первый релевантный документ на 3-й позиции - 1/3 = 0.33. Если бы на 1-й - 1/1 = 1.0. Чем выше, тем лучше.</em></p>
  <h2 id="VpUE">Метрики генерации (Generation)</h2>
  <p id="Tp8l"><strong>Faithfulness (верность контексту)</strong> - не выдумывает ли модель то, чего нет в найденных документах.</p>
  <p id="jzFp">Пример: <em>в документе написано &quot;выручка выросла на 15%&quot;, а модель отвечает &quot;выручка выросла на 25%&quot;. Faithfulness низкий, модель &quot;галлюцинирует&quot;.</em></p>
  <p id="E09I"><strong>Answer Relevancy (релевантность ответа)</strong> - отвечает ли модель на заданный вопрос.</p>
  <p id="UgdQ">Пример: <em>вопрос &quot;Какая цена подписки?&quot;, а модель рассказывает про историю компании. Ответ не релевантен.</em></p>
  <p id="4Sfc"><strong>Context Relevancy (релевантность контекста)</strong> - насколько найденные куски текста вообще относятся к вопросу. Если в контекст попал мусор, модели сложнее дать хороший ответ.</p>
  <h2 id="AzPA">Сквозные (end-to-end) метрики</h2>
  <p id="cTf9"><strong>Answer Correctness</strong> - просто правильный ли ответ, сравнивают с эталоном. Это итоговая оценка всей системы.</p>
  <p id="zFlW"><strong>RAGAS</strong> - популярный фреймворк, который объединяет Faithfulness, Answer Relevancy и Context Relevancy в единый скор.</p>
  <h2 id="vKvs">Как это работает на практике</h2>
  <p id="Cmh9">Представьте чат-бот по документации банка:</p>
  <ul id="0FqI">
    <li id="1wRi">Бот не находит нужный регламент - Recall низкий.</li>
    <li id="LRW3">Бот находит 10 документов, но 8 не по теме - Precision низкий.</li>
    <li id="BpYZ">Бот нашел правильный документ, но выдумал цифры - Faithfulness низкий.</li>
    <li id="9LTy">Бот отвечает правильно, но не на тот вопрос - Answer Relevancy низкий.</li>
  </ul>
  <p id="Cm4v"><strong>Главное</strong>: метрики помогают понять, где именно ломается система - на этапе поиска или на этапе генерации, и что нужно чинить.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://blog.promptica.ru/message-buffer</guid><link>https://blog.promptica.ru/message-buffer?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=promptica</link><comments>https://blog.promptica.ru/message-buffer?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=promptica#comments</comments><dc:creator>promptica</dc:creator><title>Буфер сообщений в n8n: снижаем нагрузку на AI и улучшаем качество ответов</title><pubDate>Tue, 04 Nov 2025 07:55:23 GMT</pubDate><media:content medium="image" url="https://img4.teletype.in/files/33/9b/339b281f-831b-4a19-b792-b68936eea783.png"></media:content><category>n8n</category><description><![CDATA[<img src="https://img3.teletype.in/files/69/0e/690e90ef-a1b5-4d00-a009-888ad0e035f5.png"></img>Представьте ситуацию: пользователь общается с вашим AI-ботом и в порыве эмоций отправляет 10 коротких сообщений подряд. Каждое сообщение моментально уходит на обработку в языковую модель, создавая лишнюю нагрузку и увеличивая расходы на API. При этом контекст разрывается на мелкие фрагменты и качество ответов страдает.]]></description><content:encoded><![CDATA[
  <h2 id="65un">Проблема, которую мы решаем</h2>
  <p id="6r3u">Представьте ситуацию: пользователь общается с вашим AI-ботом и в порыве эмоций отправляет 10 коротких сообщений подряд. Каждое сообщение моментально уходит на обработку в языковую модель, создавая лишнюю нагрузку и увеличивая расходы на API. При этом контекст разрывается на мелкие фрагменты и качество ответов страдает.</p>
  <p id="3rTv">Знакомо? Эта проблема типична для чат-ботов и виртуальных ассистентов. Решение простое и элегантное - <strong>буфер сообщений</strong>.</p>
  <h2 id="1WMC">Что такое буфер сообщений?</h2>
  <p id="IS2G">Буфер сообщений - это механизм накопления входящих сообщений от пользователя перед отправкой их на обработку AI. Вместо того чтобы обрабатывать каждое сообщение отдельно, мы собираем их в группу и отправляем единым пакетом.</p>
  <p id="oFAn"><strong>Когда буфер отправляет накопленные сообщения:</strong></p>
  <ul id="hp5L">
    <li id="2guB"><strong>По таймеру</strong>: Прошло 15 секунд с последнего сообщения - пользователь закончил мысль</li>
    <li id="BOCx"><strong>По лимиту слов</strong>: Накопилось 20+ слов - достаточно контекста для качественного ответа</li>
  </ul>
  <p id="FjD1">Лимиты слов и таймер можно настраивать под себя.</p>
  <h2 id="D0BV">Архитектура решения в n8n</h2>
  <p id="X9wI">Мы используем <a href="https://docs.n8n.io/code/cookbook/builtin/get-workflow-static-data/" target="_blank"><strong>Workflow</strong> <strong>Static Data</strong></a>- встроенное хранилище n8n, которое позволяет сохранять небольшие наборы данных между выполнениями workflow без внешних зависимостей вроде Redis, внешних баз данных, Airtable, Supabase, Google Sheets и т.п.</p>
  <p id="BTHF"><strong>Структура данных для каждого пользователя:</strong></p>
  <pre id="Tv2k" data-lang="javascript">{
  messages: [],           // Массив сообщений
  lastMessageTime: 0,     // Время последнего сообщения
  totalWords: 0           // Счетчик слов
}</pre>
  <p id="XGmn"><strong>Для организации буфера сообщений надо добавить только 4 обязательных ноды:</strong></p>
  <ol id="IFS4">
    <li id="CxaR"><strong>Code Node</strong> (Message Buffer) - накапливает сообщения в буфере</li>
    <li id="k85P"><strong>IF Node</strong> - проверяет готовность к отправке в AI</li>
    <li id="BLEB"><strong>Schedule Trigger Node </strong>(Flush Trigger) - триггер для проверки таймаута сброса буфера</li>
    <li id="4uMG"><strong>Code Node</strong> (Flush by timeout) - сбрасывает буферы всех пользователей, если достигнут таймаут ожидания</li>
  </ol>
  <p id="43AR">Подробнее о работе буфера сообщений в n8n смотрите в видео:</p>
  <figure id="xtCx" class="m_column">
    <iframe src="https://vk.com/video_ext.php?oid=-231789689&id=456239017&autoplay=0"></iframe>
    <figcaption>Буфер сообщений в n8n на базе Static Data</figcaption>
  </figure>
  <p id="Jc0B"><a href="https://vkvideo.ru/video-231789689_456239017" target="_blank">VK Видео</a></p>
  <p id="LsFZ"><a href="https://youtu.be/TeLwp_R9Mdo" target="_blank">YouTube</a></p>
  <p id="T2Sk"><a href="https://rutube.ru/video/d87621ea6f93b10ee3dc23e6edd4849a/" target="_blank">RuTube</a></p>
  <h2 id="W5j5">Ключевые преимущества</h2>
  <h3 id="hQHP">Многопользовательская изоляция</h3>
  <p id="cvXg">Каждый <code>user_id</code> имеет свой независимый буфер. Сообщения от разных пользователей никогда не смешиваются.</p>
  <h3 id="bR0q">Умная обработка edge cases</h3>
  <p id="CexA">Первое сообщение создает буфер автоматически. Превышение лимита слов вызывает немедленный сброс. Длинные паузы не ломают логику - буфер терпеливо ждет продолжения.</p>
  <h3 id="gPUX">Экономия ресурсов</h3>
  <p id="abC5">Вместо 10 API-запросов к языковой модели - один запрос с полным контекстом. Снижение затрат в 5-10 раз для активных пользователей.</p>
  <h3 id="Gu9F">Лучшее качество ответов</h3>
  <p id="rWKM">AI получает целостный контекст вместо разрозненных фрагментов. Это особенно важно для сложных запросов, которые пользователи формулируют несколькими сообщениями.</p>
  <h2 id="w7R7">Практический пример</h2>
  <pre id="i6G9">Пользователь отправляет:
0 сек  → &quot;Привет&quot;
3 сек  → &quot;Мне нужна помощь&quot;  
7 сек  → &quot;с настройкой webhook&quot;
15+ сек → [СБРОС]

AI получает: &quot;Привет Мне нужна помощь с настройкой webhook&quot;</pre>
  <p id="D6sI">Альтернативный сценарий - длинное сообщение на 25 слов сбрасывается немедленно, не дожидаясь таймера.</p>
  <h2 id="BRc6">Когда использовать?</h2>
  <p id="iBr3">Буфер сообщений критически важен для:</p>
  <ul id="JPQt">
    <li id="AU1W"><strong>Мессенджер-ботов</strong> (Telegram, WhatsApp, Slack)</li>
    <li id="6Hdn"><strong>Чат-поддержки</strong> с высокой нагрузкой</li>
    <li id="4dsC"><strong>AI-ассистентов</strong> для бизнес-процессов</li>
    <li id="n9Jn"><strong>Образовательных платформ</strong> с интерактивными уроками</li>
  </ul>
  <h2 id="u3Gm">Код решения</h2>
  <h3 id="MB1Z">Нода Message Buffer</h3>
  <pre id="N94Q" data-lang="javascript">// ============================================================================
// БУФЕР СООБЩЕНИЙ
// Использует Static Data Workflow для хранения буферов сообщений
// ============================================================================

// ПОЛУЧЕНИЕ ВХОДНЫХ ДАННЫХ
const userId = $input.first().json.message.chat.id;
const userMessage = $input.first().json.message.text;

const WORD_LIMIT = 20;  // Лимит слов для принудительного сброса

// ============================================================================
// ИНИЦИАЛИЗАЦИЯ ХРАНИЛИЩА
// ============================================================================

// Получение глобального static data для хранения буферов всех пользователей
const staticData = $getWorkflowStaticData(&#x27;global&#x27;);

// Инициализация структуры данных, если она еще не существует
if (!staticData.userBuffers) {
  staticData.userBuffers = {};
}

// Текущее время в секундах (Unix timestamp)
const currentTime = Math.floor(Date.now() / 1000);

// ============================================================================
// ПОЛУЧЕНИЕ ИЛИ СОЗДАНИЕ БУФЕРА ПОЛЬЗОВАТЕЛЯ
// ============================================================================

// Если буфер пользователя не существует, создаем новый
if (!staticData.userBuffers[userId]) {
  staticData.userBuffers[userId] = {
    messages: [],           // Массив накопленных сообщений
    lastMessageTime: 0,     // Timestamp последнего сообщения
    totalWords: 0           // Общее количество слов в буфере
  };
}

// Получение буфера текущего пользователя
const userBuffer = staticData.userBuffers[userId];

// ============================================================================
// ПОДСЧЕТ СЛОВ В НОВОМ СООБЩЕНИИ
// ============================================================================

/**
 * Функция для подсчета слов в тексте
 * Учитывает пробелы, переносы строк и множественные пробелы
 */
function countWords(text) {
  // Убираем лишние пробелы и разбиваем на слова
  const words = text.trim().split(/\s+/).filter(word =&gt; word.length &gt; 0);
  return words.length;
}

const newMessageWords = countWords(userMessage);

// ============================================================================
// ДОБАВЛЕНИЕ НОВОГО СООБЩЕНИЯ В БУФЕР
// ============================================================================

// Добавляем новое сообщение в массив
userBuffer.messages.push({
  text: userMessage,
  timestamp: currentTime,
  wordCount: newMessageWords
});

// Обновляем общий счетчик слов
userBuffer.totalWords += newMessageWords;

// Обновляем время последнего сообщения
userBuffer.lastMessageTime = currentTime;

// Сохраняем обновленный буфер обратно в static data
staticData.userBuffers[userId] = userBuffer;

// Формируем выходные данные
let output = {shouldProcess: false};

// ============================================================================
// ПРОВЕРКА УСЛОВИЙ СБРОСА БУФЕРА
// ============================================================================

if (userBuffer.totalWords &gt;= WORD_LIMIT) {
  // БУФЕР ГОТОВ К СБРОСУ - возвращаем данные для обработки
  
  // Переопределяем выходные данные
  output = {
    userId: userId,
    message: userBuffer.messages.map(msg =&gt; msg.text).join(&#x27; &#x27;), // склеим все сообщения в одну строку, разделив пробелом 
    shouldProcess: true
  };
  
  // ОЧИЩАЕМ БУФЕР ПОЛЬЗОВАТЕЛЯ
  staticData.userBuffers[userId] = {
    messages: [],
    lastMessageTime: 0,
    totalWords: 0
  };  
}
  
// Возвращаем данные
return [{ json: output }];
</pre>
  <h3 id="ZzYp">Нода Flush by timeout</h3>
  <pre id="AI1A" data-lang="javascript">// ПРОВЕРКА ТАЙМАУТОВ ДЛЯ ВСЕХ БУФЕРОВ
// Вызывается по расписанию (каждые 5 секунд)

const staticData = $getWorkflowStaticData(&#x27;global&#x27;);
// Текущее время в секундах (Unix timestamp)
const currentTime = Math.floor(Date.now() / 1000);
const TIMEOUT_SECONDS = 15;
const results = [];

if (staticData.userBuffers) {
  for (const userId in staticData.userBuffers) {
    const buffer = staticData.userBuffers[userId];

    // Пропускаем пустые буферы
    if (buffer.messages.length === 0) continue;
    
    // Проверяем таймаут
    const timeSinceLastMessage = currentTime - buffer.lastMessageTime;
    
    if (timeSinceLastMessage &gt;= TIMEOUT_SECONDS) {
      // Буфер готов к сбросу
      results.push({
        userId: userId,
        message: buffer.messages.map(msg =&gt; msg.text).join(&#x27; &#x27;)
      });
      
      // Очищаем буфер
      staticData.userBuffers[userId] = {
        messages: [],
        lastMessageTime: 0,
        totalWords: 0
      };
    }
  }
}

// Возвращаем все буферы, готовые к обработке
return results.map(r =&gt; ({ json: r }));</pre>
  <h3 id="LUzH">Нода Delete buffers</h3>
  <pre id="uQ3Y" data-lang="javascript">// УДАЛЕНИЕ НЕ ИСПОЛЬЗУЕМЫХ БУФЕРОВ
// Вызывается по расписанию (каждый час)

const staticData = $getWorkflowStaticData(&#x27;global&#x27;);
// Текущее время в секундах (Unix timestamp)
const currentTime = Math.floor(Date.now() / 1000);
const MAX_AGE_SECONDS = 3600; // 1 час
const buffers = staticData.userBuffers || {};

for (const userId in buffers) {
  const buffer = buffers[userId];
  const age = currentTime - buffer.lastMessageTime;
  
  // Если буфер не обновлялся больше MAX_AGE_SECONDS, удаляем его
  if (age &gt; MAX_AGE_SECONDS &amp;&amp; buffer.messages.length === 0) {
    delete staticData.userBuffers[userId];
  }
}

return [];</pre>
  <p id="HjQm">Также вы можете <a href="https://github.com/promptica/n8n-workflows/blob/main/message-buffer/message-buffer.json" target="_blank">скачать workflow n8n с буфером сообщений</a></p>
  <h2 id="aFdn">Заключение</h2>
  <p id="PCaf">Реализация буфера сообщений в n8n без внешних зависимостей - это баланс между простотой и эффективностью. Static Data Workflow предоставляет надежное хранилище, а гибкие условия сброса адаптируются под разные сценарии использования.</p>
  <p id="KMho">Копируйте код, адаптируйте под свои задачи и экономьте ресурсы уже сегодня!</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://blog.promptica.ru/llm-proxy</guid><link>https://blog.promptica.ru/llm-proxy?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=promptica</link><comments>https://blog.promptica.ru/llm-proxy?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=promptica#comments</comments><dc:creator>promptica</dc:creator><title>Доступ к зарубежным LLM с российских IP-адресов</title><pubDate>Sat, 11 Oct 2025 08:43:30 GMT</pubDate><media:content medium="image" url="https://img4.teletype.in/files/36/e1/36e13aca-a4e9-42d8-9750-7790e99b7194.png"></media:content><category>proxy</category><description><![CDATA[<img src="https://img1.teletype.in/files/49/e7/49e77132-4558-4a89-807d-ef0cc3168452.png"></img>При размещении систем автоматизации, таких как n8n или аналогичные платформы, на российских серверах для соблюдения требований 152-ФЗ о защите персональных данных, возникает техническая сложность с доступом к зарубежным языковым моделям (OpenAI, Anthropic, Google и другим). Эти сервисы в рамках соблюдения санкционного режима ограничивают подключения с российских IP-адресов.]]></description><content:encoded><![CDATA[
  <p id="A6oq">При размещении систем автоматизации, таких как n8n или аналогичные платформы, на российских серверах для соблюдения требований 152-ФЗ о защите персональных данных, возникает техническая сложность с доступом к зарубежным языковым моделям (OpenAI, Anthropic, Google и другим). Эти сервисы в рамках соблюдения санкционного режима ограничивают подключения с российских IP-адресов.</p>
  <h2 id="hdOv">Техническое решение через прокси-сервер</h2>
  <p id="ptr3">Эффективным способом обхода данного ограничения является настройка прокси-сервера в нейтральной юрисдикции. Для этого потребуется арендовать дополнительный VPS с локацией в стране, не участвующей в санкционных ограничениях - например, в Казахстане. Стоимость такого решения относительно невысока: VPS у провайдера <a href="https://beget.com/p23143033" target="_blank">Бегет</a> с казахстанской локацией обойдётся в 22 рубля в сутки (около 660 рублей в месяц).</p>
  <p id="UCeC">В данном руководстве подробно рассматривается процесс развёртывания прокси-сервера и конфигурации клиентской части. Вы научитесь настраивать автоматическое перенаправление всех запросов к зарубежным LLM через промежуточный сервер, что обеспечит стабильный доступ к AI-сервисам при сохранении данных на территории РФ в соответствии с законодательными требованиями.</p>
  <h2 id="tolO">Настройка прокси-сервера</h2>
  <p id="K2AA">Прокси-сервер будем реализовывать на базе <strong>Nginx Stream Module</strong> с SSL passthrough функциональностью. Это позволяет проксировать SSL/TLS трафик без его терминации, сохраняя end-to-end шифрование между клиентом и целевыми API. Nginx будем устанавливать в докере.</p>
  <h3 id="dsuK">1. Подключаемся к серверу по SSH</h3>
  <pre id="wS47">ssh root@ip_адрес_сервера</pre>
  <h3 id="1DQv">2. Проверяем доступ к LLM</h3>
  <p id="RCbn">Перед дальнейшими действиями нам надо убедиться, что с этого сервера есть доступ к зарубежным LLM. Проверим на примере с OpenAI:</p>
  <pre id="dU7F">curl -i https://api.openai.com/v1/models -H &quot;Authorization: Bearer YOUR_OPENAI_KEY&quot;</pre>
  <p id="ZsGj">где YOUR_OPENAI_KEY - это ваш ключ OpenAI, полученный на <a href="https://platform.openai.com/" target="_blank">https://platform.openai.com/</a></p>
  <p id="bzFT">В результате вы должны получить список моделей OpenAI. Если этого не произошло и вы получили 403 ошибку типа: <code>{&quot;error&quot;:{&quot;code&quot;:&quot;unsupported_country_region_territory&quot;,&quot;message&quot;:&quot;Country, region, or territory not supported&quot;,&quot;param&quot;:null,&quot;type&quot;:&quot;request_forbidden&quot;}}</code>, то с этого сервера нельзя подключиться к зарубежным LLM и следуют выбрать другой сервер в другой локации.</p>
  <h3 id="7Pjs">3. Устанавливаем docker</h3>
  <p id="RdTb">Установку можно произвести по <a href="https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository" target="_blank">инструкции на сайте докера</a> или выполнив действия ниже:</p>
  <pre id="CWeU"># Обновляем систему
apt update &amp;&amp; apt install -y curl ca-certificates

# Добавляем GPG ключ Docker
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc

# Добавляем репозиторий Docker
echo &quot;deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release &amp;&amp; echo &quot;${UBUNTU_CODENAME:-$VERSION_CODENAME}&quot;) stable&quot; | tee /etc/apt/sources.list.d/docker.list &gt; /dev/null

# Устанавливаем Docker
apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin</pre>
  <h3 id="JFqF">4. Создаем конфигурацию nginx</h3>
  <pre id="LCqo"># Создаем директорию для конфигурации
mkdir -p /root/llm-proxy &amp;&amp; cd /root/llm-proxy

# Создаем конфигурационный файл
cat &gt; nginx.conf &lt;&lt; &#x27;EOF&#x27;
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
  worker_connections 1024;
}

stream {
  # Определяем upstream серверы
  upstream openai_api {
    server api.openai.com:443;
  }

  upstream anthropic_api {
    server api.anthropic.com:443;
  }

  upstream cohere_api {
    server api.cohere.com:443;
  }

  # Карта для выбора upstream по SNI hostname
  map $ssl_preread_server_name $upstream {
    api.openai.com openai_api;
    api.anthropic.com anthropic_api;
    api.cohere.com cohere_api;
    default openai_api;
  }

  # Прокси сервер
  server {
    listen 443;
    ssl_preread on;
    proxy_pass $upstream;
    proxy_connect_timeout 60s;
    proxy_timeout 600s;
  }
}
EOF</pre>
  <h3 id="kUtf">5. Запускаем docker контейнер с proxy</h3>
  <pre id="v9up">docker run -d \
	--name llm-proxy \
	-p 443:443 \
	-v /root/llm-proxy/nginx.conf:/etc/nginx/nginx.conf:ro \
	--restart always \
	nginx:latest</pre>
  <h3 id="D6Iv">6. Проверяем работу контейнера</h3>
  <pre id="khcf"># Проверяем логи
docker logs llm-proxy

# Проверяем, что контейнер запущен
docker ps | grep llm-proxy</pre>
  <h2 id="ZYAL">Настройка клиента для работы через прокси-сервер</h2>
  <p id="4IPu">Для корректной работы необходимо настроить перенаправление всех запросов к зарубежным LLM через ваш прокси-сервер. Ключевая идея решения - переопределить DNS-резолвинг для доменов AI-сервисов, чтобы они указывали на IP-адрес вашего прокси вместо реальных адресов.</p>
  <h3 id="9Ya9">Принцип работы</h3>
  <p id="xlAl">Вместо стандартного DNS-разрешения мы жёстко привязываем определённые доменные имена (api.openai.com, api.anthropic.com и другие) к IP-адресу прокси-сервера. Все запросы к этим доменам автоматически направляются через промежуточный сервер, который уже имеет доступ к зарубежным LLM.</p>
  <h3 id="rG8h">Варианты реализации</h3>
  <p id="m5le"><strong>Вариант 1: Приложение запущено непосредственно на хосте</strong></p>
  <p id="Tlax">Если ваше клиентское приложение работает напрямую в операционной системе сервера, достаточно добавить соответствующие записи в системный файл <code>/etc/hosts</code>:</p>
  <pre id="RgJf">YOUR_PROXY_IP api.openai.com
YOUR_PROXY_IP api.anthropic.com
YOUR_PROXY_IP api.cohere.com</pre>
  <p id="t9ho"><strong>Вариант 2: Приложение в Docker-контейнере</strong></p>
  <p id="3sDa">При использовании Docker необходимо задействовать параметр <code>extra_hosts</code> в файле <code>docker-compose.yml</code>. Этот параметр добавляет пользовательские записи в <code>/etc/hosts</code> внутри изолированной среды контейнера, что позволяет перенаправлять запросы независимо от настроек хост-системы.</p>
  <h3 id="GDVc">Практический пример для n8n на хостинге Beget</h3>
  <p id="lwAm">Ниже представлена пошаговая инструкция настройки для популярной платформы автоматизации n8n, развёрнутой на серверах <a href="https://beget.com/p23143033" target="_blank">Бегет</a>:</p>
  <h3 id="CV13">1. Подключаемся к серверу n8n по SSH</h3>
  <pre id="id1K">ssh root@ip_адрес_сервера_n8n</pre>
  <h3 id="t9Qf">2. Переходим в папку с n8n</h3>
  <pre id="nIwm">cd /opt/beget/n8n/</pre>
  <h3 id="970i">3. Останавливаем контейнер с n8n</h3>
  <pre id="UsBk">docker compose down n8n</pre>
  <h3 id="5bSd">4. Добавляем параметр extra_hosts в docker-compose.yml</h3>
  <p id="JFo6">Находим секцию <code>x-shared: &amp;shared</code> и внутри нее после <code>volumes</code> добавляем новый параметр <code>extra_hosts</code>, вот так:</p>
  <pre id="mDpL"># Запускаем редактор nano
nano docker-compose.yml

# Добавляем extra_hosts
x-shared: &amp;shared
  restart: always
  image: docker.n8n.io/n8nio/n8n:latest
  env_file: .env
  links:
    - postgres
    - redis
  volumes:
    - n8n_storage:/home/node/.n8n
    - ./healthcheck.js:/healthcheck.js
    - ./my_user_folder/pro_files:/home/node/my_user_folder/pro_files
  extra_hosts:
    - &quot;api.openai.com:YOUR_PROXY_IP&quot;
    - &quot;api.anthropic.com:YOUR_PROXY_IP&quot;
    - &quot;api.cohere.com:YOUR_PROXY_IP&quot;
  depends_on:
    redis:
      condition: service_healthy
    postgres:
      condition: service_healthy
</pre>
  <p id="8vhR">где YOUR_PROXY_IP - это IP-адрес вашего прокси сервера</p>
  <h3 id="sfVq">5. Запускаем контейнер с n8n</h3>
  <pre id="f5LH">docker compose up -d n8n</pre>
  <h3 id="L7Pd">6. Проверяем логи</h3>
  <pre id="tn2R">docker compose logs n8n</pre>
  <p id="GFcn"><strong>Готово! Вы успешно настроили доступ к зарубежным AI-сервисам, сохранив при этом соответствие российскому законодательству. Успешной автоматизации!</strong></p>

]]></content:encoded></item><item><guid isPermaLink="true">https://blog.promptica.ru/install-adminer-n8n</guid><link>https://blog.promptica.ru/install-adminer-n8n?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=promptica</link><comments>https://blog.promptica.ru/install-adminer-n8n?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=promptica#comments</comments><dc:creator>promptica</dc:creator><title>Установка и настройка Adminer для работы с Postgres в n8n</title><pubDate>Sat, 09 Aug 2025 18:23:27 GMT</pubDate><media:content medium="image" url="https://img3.teletype.in/files/a4/61/a461a3d6-6796-4bc5-9dc8-75619e8459e6.png"></media:content><description><![CDATA[<img src="https://img2.teletype.in/files/1d/14/1d14f4da-11d3-4ac7-996a-d6c4e30cc67d.png"></img>Гайд по установке Adminer в Docker для управления встроенным Postgres в n8n: настройка домена, Traefik и работа с базами данных.]]></description><content:encoded><![CDATA[
  <p id="IFeo">Часто в workflows <strong>n8n</strong> требуется сохранить небольшой объем данных в постоянное хранилище, например, идентификатор (<code>id</code>) сущности или пару строк в кастомную таблицу.</p>
  <p id="NdDU">Поднимать для этого отдельный инстанс <strong>Postgres</strong> в Docker или заказывать облачный Postgres нецелесообразно, ведь у нас уже есть рабочий инстанс Postgres, установленный вместе с <strong>n8n</strong>. Можно использовать его, создав отдельную базу данных для экспериментов.</p>
  <p id="1kHs">Для удобного администрирования подойдет <strong>Adminer</strong> - легковесный менеджер БД с минималистичным интерфейсом и базовым функционалом, которого вполне достаточно для наших задач.</p>
  <p id="E22C">В этой инструкции разберем установку и настройку Adminer в Docker на том же VPS, где работает n8n. В примере используется облачная платформа <a href="https://beget.com/p2314303" target="_blank">Бегет</a>, где можно заказать установку n8n вместе с VPS.</p>
  <h3 id="3mO6">1. Подготовка поддомена</h3>
  <p id="8fj0">Создайте поддомен (например, <code>adminer.&lt;yourdomain.com&gt;</code>) и направьте его на IP-адрес вашего VPS.<br />Именно на этом домене будет доступен веб-интерфейс Adminer по HTTPS.</p>
  <h3 id="ctNP">2. Подключение к серверу по SSH</h3>
  <pre id="WD7q">ssh root@ip_адрес_сервера</pre>
  <h3 id="hESg">3. Переход в папку с n8n</h3>
  <pre id="cCtT">cd /opt/beget/n8n</pre>
  <h3 id="KcMI">4. Редактирование docker-compose.yml</h3>
  <p id="CPSg">Откройте файл в редакторе <strong>nano</strong>:</p>
  <pre id="X5Bi">nano docker-compose.yml</pre>
  <p id="CCw9">В секцию <code>services</code> добавьте сервис <code>adminer</code>. Замените <code>&lt;yourdomain.com&gt;</code> на свой домен.<br />Для выхода с сохранением в <strong>nano</strong> нажмите <code>Ctrl + X</code>, затем подтвердите сохранение клавишей <code>Y</code>.</p>
  <pre id="RQhS">  adminer:
    image: adminer:latest
    restart: unless-stopped
    labels:
      - traefik.enable=true
      - traefik.http.routers.adminer.rule=Host(&#x60;adminer.&lt;yourdomain.com&gt;&#x60;)
      - traefik.http.routers.adminer.tls=true
      - traefik.http.routers.adminer.entrypoints=web,websecure
      - traefik.http.routers.adminer.tls.certresolver=mytlschallenge
      - traefik.http.middlewares.adminer.headers.SSLRedirect=true
      - traefik.http.middlewares.adminer.headers.STSSeconds=315360000
      - traefik.http.middlewares.adminer.headers.browserXSSFilter=true
      - traefik.http.middlewares.adminer.headers.contentTypeNosniff=true
      - traefik.http.middlewares.adminer.headers.forceSTSHeader=true
      - traefik.http.middlewares.adminer.headers.SSLHost=adminer.&lt;yourdomain.com&gt;
      - traefik.http.middlewares.adminer.headers.STSIncludeSubdomains=true
      - traefik.http.middlewares.adminer.headers.STSPreload=true
      - traefik.port=8080
    ports:
      - 127.0.0.1:8080:8080
    depends_on:
      - postgres
</pre>
  <h3 id="1YpH">5. Загрузка образа Adminer</h3>
  <pre id="SFo7">docker compose pull adminer</pre>
  <h3 id="Og3y">6. Запуск Adminer</h3>
  <pre id="KcM7">docker compose up -d adminer</pre>
  <h3 id="x2FE">7. Проверка логов</h3>
  <pre id="QNC3">docker compose logs adminer</pre>
  <h3 id="3t8X">8. Подключение к Adminer</h3>
  <p id="z4OY">Если все сделано правильно, Adminer будет доступен по адресу:</p>
  <pre id="pGOu">https://adminer.&lt;yourdomain.com&gt;</pre>
  <p id="D4sC">Чтобы создавать базы данных и таблицы, подключитесь к Postgres с правами администратора.<br />На VPS <a href="https://chatgpt.com/c/beget.com/p2314303" target="_blank">Бегет</a> с предустановленным n8n админ - это пользователь <code>root</code>.</p>
  <p id="iQI9">Узнать пароль можно командой:</p>
  <pre id="lBz9">cat .env | grep POSTGRES_</pre>
  <p id="gPdg">Первое подключение можно выполнить к базе n8n, после чего создать свою, например <code>my_db</code>, для экспериментов.<br />В качестве сервера указывайте имя Docker-сервиса, то есть <code>postgres</code>.</p>
  <figure id="Wvvk" class="m_column">
    <img src="https://img2.teletype.in/files/1d/14/1d14f4da-11d3-4ac7-996a-d6c4e30cc67d.png" width="1405" />
  </figure>

]]></content:encoded></item><item><guid isPermaLink="true">https://blog.promptica.ru/n8n-postgresql-update</guid><link>https://blog.promptica.ru/n8n-postgresql-update?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=promptica</link><comments>https://blog.promptica.ru/n8n-postgresql-update?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=promptica#comments</comments><dc:creator>promptica</dc:creator><title>Как обновить PostgreSQL до версии 17 в n8n на VPS от Бегет</title><pubDate>Wed, 06 Aug 2025 17:30:36 GMT</pubDate><media:content medium="image" url="https://img1.teletype.in/files/c9/c0/c9c0f157-316c-44b6-b9c0-c3906e60433c.png"></media:content><description><![CDATA[<img src="https://img1.teletype.in/files/ca/56/ca56bd96-50c6-4b79-98e8-4c78f264d7cd.png"></img>При автоматической установке n8n на VPS от Beget используется устаревшая версия PostgreSQL - 11 (выпущена в 2018 году). Актуальная версия на 2025 год - PostgreSQL 17, содержащая множество улучшений в области безопасности и производительности.]]></description><content:encoded><![CDATA[
  <p id="0mZk">Многие выбирают облачную платформу <a href="https://beget.com/p2314303" target="_blank">Бегет</a> для размещения self-hosted версии n8n на VPS по следующим причинам:</p>
  <ul id="dZUP">
    <li id="UoG8"><strong>Низкие тарифы</strong> - от 9 ₽ в день. Можно пополнить баланс на 30 ₽ и протестировать работу n8n в течение трёх дней на выбранном тарифе.</li>
    <li id="ZfP5"><strong>Прозрачное проксирование запросов к OpenAI API</strong> - вы можете без проблем обращаться к <code>api.openai.com</code> даже с российских IP, минуя блокировку:<code>{&quot;error&quot;:{&quot;code&quot;:&quot;unsupported_country_region_territory&quot;, &quot;message&quot;:&quot;Country, region, or territory not supported&quot;, &quot;param&quot;:null, &quot;type&quot;:&quot;request_forbidden&quot;}} </code></li>
    <li id="JBZb"><strong>Бесплатная установка n8n</strong> - при заказе нового VPS вы можете сразу получить настроенную версию n8n с защищённым HTTPS-доступом.</li>
  </ul>
  <p id="GPDf">Однако стоит учитывать один нюанс: при автоматической установке используется устаревшая версия PostgreSQL - 11 (выпущена в 2018 году). Актуальная версия на 2025 год - <strong>PostgreSQL 17</strong>, содержащая множество улучшений в области безопасности и производительности. N8n корректно работает с 17 версией.</p>
  <p id="PXIR">Ниже - пошаговая инструкция по обновлению PostgreSQL до версии 17 для n8n на VPS от <a href="https://beget.com/p2314303" target="_blank">Бегет</a>.</p>
  <hr />
  <h2 id="Qvi1">Пошаговая инструкция</h2>
  <h3 id="8xAp">1. Подключение к серверу по SSH</h3>
  <pre id="FZ2P" data-lang="bash">ssh root@&lt;ip_адрес_сервера&gt;</pre>
  <h3 id="pZLH">2. Переход в директорию n8n</h3>
  <pre id="OGll" data-lang="bash">cd /opt/beget/n8n</pre>
  <h3 id="z7To">3. Остановка сервиса n8n</h3>
  <pre id="AxZl" data-lang="bash">docker compose stop n8n</pre>
  <h3 id="EW9x">4. Создание дампа базы данных</h3>
  <p id="MKHa">Уточните имя контейнера с PostgreSQL:</p>
  <pre id="EPIQ" data-lang="bash">docker compose ps | grep postgres</pre>
  <p id="liwh">Скорее всего, он называется <code>n8n-postgres-1</code>. Выполните дамп БД:</p>
  <pre id="fVYd" data-lang="bash">docker exec -it n8n-postgres-1 pg_dump -U root n8n &gt; n8n_backup.sql</pre>
  <h3 id="ImmT">5. Остановка сервиса PostgreSQL</h3>
  <pre id="TqmA" data-lang="bash">docker compose stop postgres</pre>
  <h3 id="V1VB">6. Создание резервных копий</h3>
  <pre id="sADD" data-lang="bash">mv db_storage db_storage_backup
mkdir db_storage
cp init-data.sh init-data_backup.sh
cp docker-compose.yml docker-compose_backup.yml</pre>
  <h3 id="14xc">7. Обновление версии PostgreSQL в <code>docker-compose.yml</code></h3>
  <pre id="CKg1" data-lang="bash">sed -i &#x27;s#postgres:11#postgres:17#g&#x27; docker-compose.yml</pre>
  <h3 id="AOqb">8. Обновление скрипта инициализации <code>init-data.sh</code></h3>
  <p id="xJMi">Содержимое должно быть следующим:</p>
  <pre id="qrcm" data-lang="bash">cat &gt; init-data.sh &lt;&lt; &#x27;EOF&#x27;
#!/bin/bash
set -e;

if [ -n &quot;${POSTGRES_NON_ROOT_USER:-}&quot; ] &amp;&amp; [ -n &quot;${POSTGRES_NON_ROOT_PASSWORD:-}&quot; ]; then
    psql -v ON_ERROR_STOP=1 --username &quot;$POSTGRES_USER&quot; --dbname &quot;$POSTGRES_DB&quot; &lt;&lt;-EOSQL
        CREATE USER &quot;${POSTGRES_NON_ROOT_USER}&quot; WITH PASSWORD &#x27;${POSTGRES_NON_ROOT_PASSWORD}&#x27;;
        GRANT ALL PRIVILEGES ON DATABASE &quot;${POSTGRES_DB}&quot; TO &quot;${POSTGRES_NON_ROOT_USER}&quot;;
        GRANT CREATE ON SCHEMA public TO &quot;${POSTGRES_NON_ROOT_USER}&quot;;
EOSQL
else
    echo &quot;SETUP INFO: No Environment variables given!&quot;
fi
EOF</pre>
  <h3 id="qA5t">9. Загрузка нового образа PostgreSQL</h3>
  <pre id="hVzP" data-lang="bash">docker compose pull postgres</pre>
  <h3 id="fV5B">10. Запуск новой версии PostgreSQL</h3>
  <pre id="gCH5" data-lang="bash">docker compose up -d postgres</pre>
  <h3 id="o67P">11. Проверка логов PostgreSQL</h3>
  <p id="twcE">Убедитесь, что нет ошибок:</p>
  <pre id="G6W0" data-lang="bash">docker compose logs postgres</pre>
  <h3 id="RyH5">12. Восстановление дампа в новую базу данных</h3>
  <pre id="j7z4" data-lang="bash">cat n8n_backup.sql | docker exec -i n8n-postgres-1 psql -U root -d n8n</pre>
  <h3 id="lPDI">13. Запуск сервиса n8n</h3>
  <pre id="cJWD" data-lang="bash">docker compose start n8n</pre>
  <h3 id="i6P2">14. Проверка логов n8n</h3>
  <pre id="DNGA" data-lang="bash">docker compose logs n8n --tail 100</pre>
  <h3 id="EMua">15. Проверка интерфейса n8n</h3>
  <p id="06my">Убедитесь, что все workflows работают корректно. Если всё в порядке - удалите временные файлы:</p>
  <pre id="aSQs" data-lang="bash">rm init-data_backup.sh docker-compose_backup.yml n8n_backup.sql
rm -rf db_storage_backup</pre>
  <h3 id="6Exq">16. Очистка неиспользуемых Docker-образов</h3>
  <pre id="coKQ" data-lang="bash">docker image prune -a</pre>
  <hr />
  <p id="31pt">Если вы всё сделали по инструкции - поздравляю! Теперь ваша система работает с актуальной и безопасной версией PostgreSQL 17.</p>

]]></content:encoded></item></channel></rss>