3,583 papers
arXiv:2604.14004 73 15 апр. 2026 г. FREE

Memory Transfer Learning: абстрактные инсайты работают лучше конкретных примеров — и переносятся между задачами

КЛЮЧЕВАЯ СУТЬ
Парадокс: чем конкретнее пример прошлого опыта в промпте, тем хуже модель решает новую задачу. Модель цепляется за детали — имена, инструменты, данные — и начинает копировать прошлую ситуацию вместо того, чтобы думать о новой. Insight-формат позволяет превращать любой разобранный кейс в переносимый урок и применять его в других задачах без потери качества. Три поля: Title (название принципа), Description (когда применять), Content (механика без деталей) — модель следует принципу, а не копирует прошлую ситуацию. Один и тот же урок работает в анализе, редактуре, разработке — в любой области.
Адаптировать под запрос

TL;DR

Чем абстрактнее урок из прошлого опыта, тем лучше он работает в новых задачах — даже в совершенно других областях. Исследователи изучали, как AI-агенты используют память после решённых задач, и обнаружили: высокоуровневые принципы типа «сначала изучи структуру, потом редактируй» переносятся между разными типами задач. Конкретные записи о прошлых решениях — нет.

Главная боль: когда просишь LLM примениться к задаче и даёшь ей «пример из прошлого», слишком конкретный пример мешает. Модель начинает цепляться за детали предыдущей ситуации, которые не подходят к новой. Вместо помощи — искажение. Это называется отрицательный перенос (negative transfer): специфика прошлого опыта ломает новое решение.

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


🔬

Схема метода

ШАГ 1: Завершили задачу → попросить LLM извлечь Insight
        (в одном запросе, результат — структурированная карточка)

ШАГ 2: Сохранить Insight → в документ "уроков"
        (ручное хранение — блокнот, Notion, текстовый файл)

ШАГ 3: Новая задача (любой области) → вставить релевантные Insight'ы в промпт
        (ручной выбор, вставка в начало нового чата)

Все три шага — через обычный чат. Никакой автоматизации не нужно.


🚀

Пример применения

Задача: Артём — product manager в EdTech-стартапе. Он провёл отличный разбор с LLM: разобрал почему провалилась маркетинговая кампания. Теперь ему нужно проанализировать, почему упала конверсия в онбординге — задача другая, но хочется не начинать с нуля.

Промпт (Шаг 1 — извлечь Insight из разбора кампании):

Мы только что разобрали провал маркетинговой кампании для нашего EdTech-курса. 
Извлеки обобщённый урок в формате Insight — так, чтобы он работал 
для ЛЮБОГО анализа провалов, а не только маркетинговых:


  Короткое название принципа (5-7 слов)
  Одно предложение: что делать и когда
  
    Общий принцип работы (3-5 предложений).
    Без упоминания конкретной кампании, каналов, платформ.
    Только универсальная механика: почему это работает, 
    как применять в новой ситуации.
  

Промпт (Шаг 3 — применить Insight к новой задаче):

Я анализирую падение конверсии в онбординге нашего приложения.
Вот принцип, который помог мне в прошлом похожем анализе:

[вставить сохранённый Insight]

Используй этот принцип как ориентир. Начнём: вот данные по онбордингу...
[данные]

Результат: Модель в первом запросе выдаст карточку Insight — название принципа, одно предложение описания и 3-5 предложений содержательного принципа без привязки к деталям кампании. В третьем шаге — применит логику анализа к онбордингу, минуя типичный "нулевой старт" без контекста.


🧠

Почему это работает

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

Модель хорошо умеет применять принципы — особенно когда они сформулированы явно и без лишних деталей. Структурированный Insight — это фактически meta-prompt: он задаёт режим мышления ("сначала изучи структуру, потом редактируй"), а не конкретный алгоритм действий. Модель следует принципу, а не копирует прошлое.

Рычаги управления: - Уровень абстракции в → чем меньше конкретики (названий, цифр, платформ), тем шире применимость Insight'а - Количество сохранённых карточек → даже 5-10 хороших Insight'ов из разных задач дают ощутимый эффект - Момент извлечения → лучше сразу после задачи, пока контекст свежий: "Извлеки Insight из этого разговора" - Формат </code></strong> → короткое название помогает быстро выбрать нужный Insight при новой задаче</p> <hr /></hr> </div> </div> <div class="section-card"> <div class="section-card-header"> <span class="section-card-icon">📋</span> <h2 class="section-card-title">Шаблон промпта</h2> </div> <div class="section-card-body"> <p><strong>Шаблон 1 — Извлечь Insight после задачи:</strong></p> <div class="code-block-wrapper" style="position: relative;"> <button class="copy-button" style="position: absolute; top: 8px; right: 8px; padding: 4px 8px; background: #333; color: #fff; border: none; border-radius: 4px; cursor: pointer; font-size: 12px;">Copy</button> <pre><code>В этом разговоре мы решили задачу: {краткое описание задачи}. Извлеки обобщённый урок в формате Insight — так, чтобы он работал для других похожих ситуаций в {область применения: анализ / написание текстов / принятие решений / работа с данными}. <InsightFormat> <Title>Короткое название принципа (5-7 слов) Одно предложение: что делать и когда Универсальный принцип (3-5 предложений). Без упоминания конкретных имён, инструментов, деталей этой задачи. Только механика: почему это работает и как применять.

Шаблон 2 — Применить сохранённые Insight'ы к новой задаче:

Я работаю над задачей: {описание новой задачи}.

Вот принципы, которые помогали мне в похожих ситуациях раньше:


  {вставить 1-3 сохранённых Insight'а}


Используй эти принципы как ориентир — там, где они применимы.
Начнём с {первый шаг задачи}.

Плейсхолдеры: - {краткое описание задачи} — "разбор провала кампании", "написание продающего письма", "анализ данных по продажам" - {область применения} — широко: "любой аналитической работы", "работы с текстами", "принятия решений" - {вставить 1-3 сохранённых Insight'а} — карточки из вашего документа уроков - {первый шаг задачи} — "вот данные", "вот задача клиента", "вот черновик"

🚀 Быстрый старт — вставь в чат:

Вот шаблон для извлечения переносимых уроков из задач. 
Адаптируй под мою ситуацию: [опиши свою задачу].
Задавай вопросы, чтобы заполнить поля.

[вставить шаблон выше]

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


⚠️

Ограничения

⚠️ Ручное хранение — узкое место: Метод требует дисциплины: извлекать Insight'ы после каждой значимой задачи и хранить их в доступном месте. Без этой привычки система не работает.

⚠️ Выбор нужного Insight — на вас: В автоматических системах поиск нужной карточки делает векторная база данных. Вручную нужно самому вспомнить и выбрать подходящее. При большой библиотеке (50+ карточек) это становится сложнее.

⚠️ Конкретные примеры в памяти могут навредить: Если в Insight'е остались детали прошлой задачи (названия, инструменты, конкретные данные) — модель может "залипнуть" на них вместо решения новой задачи. Правило: если сомневаешься — абстрагируй сильнее.

⚠️ Работает лучше на задачах с процессом, не с ответом: Insight'ы хорошо переносят "как действовать" (отладка, анализ, редактирование), хуже — "что ответить" (если задача зависит от уникальных данных).


🔗

Ресурсы

Memory Transfer Learning: How Memories are Transferred Across Domains in Coding Agents Kangsan Kim, Minki Kang, Taeil Kim (KAIST), Yanlai Yang, Mengye Ren (New York University), Sung Ju Hwang (KAIST, DeepAuto.ai) Сайт: memorytransfer.github.io

Ключевые отсылки: ReasoningBank (Ouyang et al., 2025), AgentKB (Tang et al., 2025), AWM (Wang et al., 2024c)


📋 Дайджест исследования

Ключевая суть

Парадокс: чем конкретнее пример прошлого опыта в промпте, тем хуже модель решает новую задачу. Модель цепляется за детали — имена, инструменты, данные — и начинает копировать прошлую ситуацию вместо того, чтобы думать о новой. Insight-формат позволяет превращать любой разобранный кейс в переносимый урок и применять его в других задачах без потери качества. Три поля: Title (название принципа), Description (когда применять), Content (механика без деталей) — модель следует принципу, а не копирует прошлую ситуацию. Один и тот же урок работает в анализе, редактуре, разработке — в любой области.

Принцип работы

LLM читает контекст прямолинейно: что вставил — то и тянет. Конкретный пример задаёт шаблон. Модель ищет аналогии, подставляет похожие детали. Если детали не совпадают — решение ломается. Это отрицательный перенос: специфика прошлого опыта тянет новое решение не туда. Убери конкретику — остаётся принцип. Модель не копирует ситуацию, а применяет логику. Исследователи назвали это разницей между эпизодической памятью (что именно случилось тогда) и семантической (как это работает в принципе). Семантическая переносится. Эпизодическая — нет.

Почему работает

Модель строит каждый ответ на основе того, что есть в контексте. Вставил конкретный пример — контекст наполнился специфическими деталями. Модель начинает работать с ними, а не с новой задачей. Детали прошлого занимают место деталей настоящего. Insight без деталей — это не пример для копирования, а режим мышления. Модель получает «как действовать» без груза «что именно было тогда». Особенно хорошо работает для задач, где важен процесс: анализ, редактура, отладка, принятие решений. Хуже — там, где результат полностью зависит от уникальных данных.

Когда применять

Аналитическая работа → для повторяющихся разборов: провалы, ретроспективы, аудиты продукта, разборы текстов. Особенно когда одни и те же ошибки встречаются в разных контекстах и хочется не начинать каждый раз с нуля. НЕ подходит для задач, где результат полностью определяется уникальными данными — там Insight не даст преимущества, потому что перенести нечего.

Мини-рецепт

1. Заверши задачу: Разбор, анализ, написание — что угодно, где нашёл рабочий подход. Это материал для извлечения.
2. Извлеки Insight сразу: Пока контекст свежий — попроси модель: Мы решили [задача]. Извлеки обобщённый урок в формате InsightFormat: Title (5-7 слов), Description (одно предложение — что делать и когда), Content (3-5 предложений принципа без конкретных деталей этой задачи).
3. Сохрани карточку: Notion, текстовый файл, заметки — не важно. Даже 5-10 карточек из разных задач уже дают эффект. Главное — хранить в одном месте и называть понятно.
4. Применяй в новых задачах: Вставь 1-3 подходящих Insight'а в начало нового чата: Вот принципы, которые помогали в похожих ситуациях: [карточки]. Используй там, где применимо. Начнём: [новая задача].

Примеры

[ПЛОХО] : Мы разбирали провал нашей email-кампании — там проблема была с сегментацией по возрасту. Используй этот разбор для анализа падения конверсии в онбординге.
[ХОРОШО] : Вот урок из прошлого анализа: Сначала ищи системную причину, потом детали Когда что-то падает — сначала проверь, не сломалась ли основная логика, потом копай в частности При анализе любого провала начинай с вопроса: изменилось ли что-то в базовой механике? Только убедившись что нет — переходи к деталям. Иначе тратишь время на симптомы, а не причину. Применяй там, где подходит. Вот данные по онбордингу: [данные]
Источник: Memory Transfer Learning: How Memories are Transferred Across Domains in Coding Agents
ArXiv ID: 2604.14004 | Сгенерировано: 2026-04-16 05:29

Проблемы LLM

ПроблемаСутьКак обойти
Конкретный пример из прошлого тянет решение в сторонуДаёшь модели контекст из прошлого разговора чтобы помочь. Но контекст содержит детали: названия, инструменты, данные. Модель цепляется за них. В итоге генерирует ответ по шаблону старой ситуации — а не думает о новой. Чем конкретнее пример, тем сильнее искажение. Проблема возникает при любой задаче: анализ, написание текстов, отладка, решенияПеред передачей в новый запрос убирай детали из контекста. Оставляй только принцип: что делать, зачем, в каких ситуациях. Конкретные имена, цифры, платформы — убирай полностью

Методы

МетодСуть
Формат «Урок» — переносимые выводы из прошлых задачПосле любой решённой задачи просишь модель извлечь урок. Не пересказ — а принцип. Структура: </code> (5-7 слов), <code><Description></code> (одно предложение — что делать и когда), <code><Content></code> (3-5 предложений: только механика, никаких деталей этой задачи). Сохраняй карточки в блокнот. При новой задаче вставляй 1-3 нужных карточки в начало запроса. <strong>Почему работает:</strong> Модель хорошо применяет явно сформулированные принципы. Принцип без деталей задаёт режим мышления, а не шаблон копирования. <strong>Когда работает:</strong> задачи с процессом (анализ, редактирование, отладка). <strong>Когда нет:</strong> задачи где нужен уникальный ответ, зависящий от конкретных данных</td></tr> </tbody></table></div> </div> </div> <!-- Simple Tab --> <div class="tab-content" id="tab-simple"> <div class="card"> <div class="card-header"> <span class="card-icon">📖</span> <span class="card-title">Простыми словами</span> </div> <div class="card-body"> <div class="simple-card"> <h2 class="simple-title">Memory Transfer Learning: How Memories are Transferred Across Domains in CodingAgents</h2> <div class="simple-meta">arXiv: <code>2604.14004</code></div> <div class="simple-content"><p>AI-агенты не умеют учиться на своих ошибках так, как мы привыкли — они не запоминают конкретные шаги, а скорее пытаются натянуть старый шаблон на новую реальность. Исследование <strong>Memory Transfer Learning</strong> доказывает: чтобы модель реально поумнела после решения задачи, ей нужно скармливать не протоколы прошлых действий, а <strong>высокоуровневые абстракции</strong>. Если заставить агента запомнить конкретный кусок кода, в новой задаче он просто начнет бездумно его копипастить, даже если тот там и даром не нужен. Но если зафиксировать сам принцип — например, <strong>сначала изучи структуру проекта, а потом лезь в конфиги</strong> — модель начинает тащить этот опыт через любые домены.</p> <p>Это как если бы ты учил друга водить машину. Если ты скажешь ему: <em>"На этом перекрестке в 14:00 нажми на тормоз на три секунды"</em>, он расшибется на следующем же повороте. Это <strong>конкретная память</strong>, и она бесполезна. Но если ты объяснишь принцип: <em>"Перед любым препятствием плавно сбрасывай скорость"</em>, он применит это и на трассе, и во дворе, и даже на велосипеде. В мире LLM это работает точно так же: <strong>детализация убивает гибкость</strong>, а общие правила создают интеллект.</p> <p>В работе проверили метод на <strong>CodingAgents</strong> и выяснили, что передача памяти между разными языками программирования или типами задач буксует, если записи слишком подробные. Работают только <strong>абстрактные уроки</strong>. Например, стратегия <em>"проверь зависимости перед компиляцией"</em> отлично переносится из Python в C++, а конкретный синтаксис — только мешает. Исследователи подтвердили, что <strong>высокоуровневые принципы</strong> позволяют агенту не тупить в незнакомой среде, потому что он ищет не знакомые буквы, а знакомую логику процесса.</p> <p>Принцип универсален и выходит далеко за рамки кодинга. Если ты менеджер и разбираешь с нейронкой провал маркетинговой кампании, не проси её запомнить, что <em>"текст на баннере был мелким"</em>. Проси сформулировать принцип: <em>"всегда проверяй читаемость ключевого оффера на мобилках"</em>. Этот <strong>абстрактный паттерн</strong> сработает потом и при дизайне приложения, и при создании презентации. <strong>SEO для памяти AI</strong> — это очистка опыта от шелухи конкретики до состояния чистого алгоритма действий.</p> <p>Короче: если хочешь, чтобы твой AI-агент реально развивался, перестань забивать его память логами и примерами <em>"как было в прошлый раз"</em>. Формулируй <strong>универсальные правила игры</strong>. Конкретика тянет модель на дно, заставляя её галлюцинировать старыми данными в новых условиях. <strong>Абстракция — это единственный способ</strong> заставить нейронку по-настоящему учиться, а не просто имитировать прошлый успех. Кто научится выжимать из задач принципы вместо фактов, тот получит агентов, которые умнеют с каждым кликом.</p></div> </div> </div> </div> </div> </div> </div> <!-- Research Adaptation Block --> <section class="research-adaptation-section" id="research-adaptation"> <h2> <svg class="section-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2"/> <circle cx="12" cy="12" r="6" stroke="currentColor" stroke-width="2"/> <circle cx="12" cy="12" r="2" fill="currentColor"/> </svg> Работа с исследованием </h2> <div class="adaptation-description"> <p>Адаптируйте исследование под ваши задачи или создайте готовый промпт на основе техник из исследования.</p> </div> <!-- Форма --> <div class="adaptation-form-container"> <form id="adaptation-form" class="adaptation-form"> <!-- Выбор модели --> <div class="model-selection"> <label for="model-select" class="form-label">Выберите модель ИИ:</label> <select id="model-select" name="model" class="model-select"> <option value="google/gemini-3-flash-preview" selected>Gemini 3 Flash (быстро, экономично)</option> <option value="anthropic/claude-sonnet-4.6">Claude Sonnet 4.6 (высокое качество, премиум)</option> </select> </div> <!-- Поле для запроса --> <div class="request-input-container"> <label for="user-request" class="form-label">Ваш запрос:</label> <textarea id="user-request" name="user_request" class="user-request-input" placeholder="Опишите вашу задачу или для чего нужен промпт..." rows="4" maxlength="2000" required ></textarea> <!-- Нижняя панель под textarea --> <div class="textarea-bottom-panel"> <div class="left-controls"> <button type="button" id="clear-btn" class="nova-adaptation-clear-btn-compact"> <svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M3 6h18M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> </svg> <span>Очистить</span> </button> </div> <div class="char-counter"> <span id="char-count">0</span> / 2000 </div> </div> </div> <!-- Кнопки действий --> <div class="form-actions"> <div class="action-button-group"> <button type="submit" id="adapt-btn" class="adapt-btn"> <span class="btn-text"> <svg class="btn-icon" width="18" height="18" viewBox="0 0 24 24" fill="none"> <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2"/> <circle cx="12" cy="12" r="6" stroke="currentColor" stroke-width="2"/> <circle cx="12" cy="12" r="2" fill="currentColor"/> </svg> Адаптировать исследование </span> <span class="btn-loading" style="display: none;"> <svg class="spinner-icon" width="18" height="18" viewBox="0 0 24 24"> <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" fill="none" stroke-dasharray="31.4" stroke-dashoffset="10"> <animateTransform attributeName="transform" type="rotate" from="0 12 12" to="360 12 12" dur="1s" repeatCount="indefinite"/> </circle> </svg> Генерирую <span class="timer-display" id="adapt-timer">00:00</span> </span> </button> <div class="cost-time-indicator"> <span class="cost-estimate">~0.5-2 N-токенов</span> <span class="time-estimate">~10-30с</span> </div> </div> <div class="action-button-group"> <button type="button" id="prompt-btn" class="prompt-btn"> <span class="btn-text"> <svg class="btn-icon" width="18" height="18" viewBox="0 0 24 24" fill="none"> <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" stroke="currentColor" stroke-width="2"/> <polyline points="14 2 14 8 20 8" stroke="currentColor" stroke-width="2"/> <line x1="16" y1="13" x2="8" y2="13" stroke="currentColor" stroke-width="2"/> <line x1="16" y1="17" x2="8" y2="17" stroke="currentColor" stroke-width="2"/> </svg> Сделать промпт </span> <span class="btn-loading" style="display: none;"> <svg class="spinner-icon" width="18" height="18" viewBox="0 0 24 24"> <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" fill="none" stroke-dasharray="31.4" stroke-dashoffset="10"> <animateTransform attributeName="transform" type="rotate" from="0 12 12" to="360 12 12" dur="1s" repeatCount="indefinite"/> </circle> </svg> Создаю <span class="timer-display" id="prompt-timer">00:00</span> </span> </button> <div class="cost-time-indicator"> <span class="cost-estimate">~0.3-1 N-токенов</span> <span class="time-estimate">~5-15с</span> </div> </div> </div> </form> </div> <!-- Результат адаптации --> <div id="adaptation-result" class="adaptation-result" style="display: none;"> <div class="result-header"> <h3 id="adaptation-title">Результат адаптации</h3> <div class="result-actions"> <button type="button" class="action-btn" onclick="copyAdaptationResult()" title="Копировать текст"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none"> <rect x="9" y="9" width="13" height="13" rx="2" ry="2" stroke="currentColor" stroke-width="2"/> <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" stroke="currentColor" stroke-width="2"/> </svg> <span>Копировать</span> </button> <button type="button" class="action-btn btn-html" onclick="downloadAdaptationHTML()" title="Скачать HTML"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none"> <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" stroke="currentColor" stroke-width="2"/> <polyline points="14,2 14,8 20,8" stroke="currentColor" stroke-width="2"/> <path d="M9 15l3 3 3-3" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> <line x1="12" y1="12" x2="12" y2="18" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> </svg> <span>HTML</span> </button> <button type="button" class="action-btn btn-pdf" onclick="downloadAdaptationPDF()" title="Скачать PDF"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none"> <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" stroke="currentColor" stroke-width="2"/> <polyline points="14,2 14,8 20,8" stroke="currentColor" stroke-width="2"/> <path d="M9 15l3 3 3-3" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> <line x1="12" y1="12" x2="12" y2="18" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> </svg> <span>PDF</span> </button> </div> </div> <div id="adaptation-content" class="result-content"></div> </div> </section> </main> <!-- Right Sidebar --> <aside class="sidebar-right"> <!-- Mobile Close Button --> <button class="sidebar-mobile-close" onclick="closeSidebar()" aria-label="Закрыть"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <line x1="18" y1="6" x2="6" y2="18"/> <line x1="6" y1="6" x2="18" y2="18"/> </svg> </button> <div class="sidebar-tabs"> <button class="sidebar-tab active" onclick="switchSidebarTab('info')">Инфо</button> <button class="sidebar-tab" onclick="switchSidebarTab('thinking')">Мысли</button> <button class="sidebar-tab" onclick="switchSidebarTab('usecases')">Кейсы</button> </div> <div class="sidebar-content-tabs"> <!-- Info Tab --> <div class="sidebar-tab-panel active" id="sidebar-info"> <!-- Evaluation Block --> <div class="evaluation-block"> <div class="evaluation-score-badge score-mid">73</div> <div class="evaluation-content-wrapper"> <div class="evaluation-verdict">НЕПЛОХО</div> <div class="evaluation-subtitle">Memory Transfer Learning: абстрактные инсайты работают лучше...</div> </div> </div> <!-- Evaluation Summary --> <div class="evaluation-summary"> <p>Исследование про автоматические агентные системы с эмбеддингами и векторным поиском — всё это требует инфраструктуры. Но <strong>главный вывод полностью применим вручную</strong>: абстрактные инсайты в формате Title/Description/Content переносятся между задачами, конкретные примеры — вредят. Формат Insight достаточно прост, чтобы запрашивать его в обычном чате. Ограничение в оценке — ручное хранение и выбор карточек сильно снижают системный эффект относительно автоматической версии.</p> </div> <!-- Two Column Layout Wrapper --> <div class="sidebar-columns-wrapper"> <!-- Left Column --> <div class="sidebar-column-left"> <div class="sidebar-section"> <div class="sidebar-section-title">ДЛЯ КОГО</div> <div class="sidebar-section-text">Тем, кто регулярно решает разнотипные задачи с LLM и хочет строить накапливаемую систему знаний</div> </div> <div class="sidebar-section"> <div class="sidebar-section-title">ЧТО МОЖНО ПРИМЕНИТЬ</div> <div class="sidebar-section-text">Формат Insight (Title/Description/Content) — запрашивается в чате, хранится вручную, вставляется в новые промпты</div> </div> <div class="sidebar-section"> <div class="sidebar-section-title">ШИРОКАЯ ПРИМЕНИМОСТЬ</div> <div class="sidebar-section-text">Coding agents → любой пользователь, который хочет переиспользовать опыт из прошлых чатов</div> </div> <!-- Categories --> <div class="sidebar-section"> <div style="margin-bottom: 16px;"> <div style="font-size: 11px; font-weight: 600; color: var(--text-muted); margin-bottom: 8px; text-transform: uppercase;">Возможности</div> <div class="category-tags"> <div class="category-tag category-tag-main"> <span>Self-Reflection</span> <span class="category-tag-pct">85%</span> </div> <div class="category-tag"> <span>Knowledge Distillation</span> <span class="category-tag-pct">15%</span> </div> </div> </div> <div style="margin-bottom: 16px;"> <div style="font-size: 11px; font-weight: 600; color: var(--text-muted); margin-bottom: 8px; text-transform: uppercase;">Область</div> <div class="category-tags"> <div class="category-tag category-tag-main"> <span>NLP</span> <span class="category-tag-pct">90%</span> </div> <div class="category-tag"> <span>Data Science</span> <span class="category-tag-pct">10%</span> </div> </div> </div> <div> <div style="font-size: 11px; font-weight: 600; color: var(--text-muted); margin-bottom: 8px; text-transform: uppercase;">Паттерн</div> <div class="category-tags"> <div class="category-tag category-tag-main"> <span>Meta-Prompting</span> <span class="category-tag-pct">95%</span> </div> </div> </div> </div> </div> <!-- Right Column --> <div class="sidebar-column-right"> <div class="sidebar-insight-box"> <div class="sidebar-card-label">💡 ИНСАЙТ</div> Чем абстрактнее урок из прошлого опыта, тем лучше он работает в новых задачах — конкретные примеры часто вредят </div> <div class="sidebar-principles-box"> <div class="sidebar-card-label">ПРИНЦИПЫ</div> <ul class="sidebar-list"> <li>Абстрактные уроки (Insight) переносятся в новые задачи лучше конкретных примеров</li> <li>Мета-знание (как работать) переносится лучше предметного знания (что делать)</li> <li>Конкретные примеры из прошлого могут вредить (отрицательный перенос)</li> <li>Кросс-доменный перенос работает через высокоуровневые принципы</li> </ul> </div> <div class="sidebar-section"> <div class="sidebar-section-title">ОГРАНИЧЕНИЕ</div> <div class="limitation-text">Система работает только при дисциплинированном ведении библиотеки Insight'ов — без этого принцип остаётся теорией</div> </div> <div class="sidebar-section source-section"> <div class="sidebar-section-title">ИСТОЧНИК</div> <div class="source-based">Основано на исследовании</div> <a href="https://arxiv.org/abs/2604.14004" target="_blank" rel="nofollow noopener" class="source-link">arXiv:2604.14004</a> </div> </div> </div> </div> <!-- Thinking Tab --> <div class="sidebar-tab-panel" id="sidebar-thinking"> <div class="sidebar-section"> <div class="sidebar-section-title">ЧТО ИССЛЕДОВАЛОСЬ</div> <div class="sidebar-section-text">Автоматические coding-агенты с векторными базами памяти, эмбеддингами OpenAI, 6 бенчмарков, GPT-5-mini</div> </div> <div class="sidebar-section"> <div class="sidebar-section-title">РАЗМЫШЛЕНИЯ</div> <div class="thinking-text"><p>Let me analyze this research paper carefully and create a summary following the format specified.</p> <p>The paper is about Memory Transfer Learning (MTL) for coding agents. Let me understand what it's actually about:</p> <ol> <li>Coding agents that use LLMs can build "memory" from past tasks</li> <li>Usually these memories are only used within the same domain</li> <li>This paper shows that memories from DIFFERENT domains can also help</li> <li>Key finding: abstract/high-level insights transfer better than specific traces</li> <li>Meta-knowledge (HOW to approach problems) transfers, not domain-specific code</li> </ol> <p>Now let me think about whether this is applicable for a regular ChatGPT/Claude user (not a programmer):</p> <p>The core technical system uses embeddings and vector search to retrieve and apply memories across different coding tasks, but the underlying principles are actually generalizable. The key insight is that abstract problem-solving strategies work across domains better than concrete implementations, and understanding the approach matters more than memorizing specific solutions. So while the automated memory infrastructure isn't something a manual user would implement, I can extract how to actually apply these principles in practice. I'm settling on a score around 68-72 because while the core principle—that abstract knowledge transfers better across domains than specific examples—is genuinely useful, applying it requires manual effort and the practical benefit for typical chat users is modest. The key takeaway is to write generalizable lessons like "always validate before submitting" rather than documenting specific instances, and I'm thinking through how to illustrate this with a concrete example, maybe someone maintaining a reusable prompt library across different projects.</p> <p>The real extractable principles are: write abstract lessons instead of specific ones, recognize how insights from one domain (like marketing copy) apply elsewhere, and focus on methodology rather than answers. For a regular user, this means building a personal library of high-level principles extracted from past conversations rather than collecting domain-specific solutions. I'd rate the actual implementation around 72—the concept is clear and somewhat actionable through manual extraction, but the full systematic version with memory pools and intelligent retrieval would require infrastructure most users don't have access to. The key insight is that users can actually apply this without the automated system—they'd manually extract insights in that Title/Description/Content format from past conversations, store them in a notes file, and paste relevant ones into new chats across different domains. It's more labor-intensive than the paper's automated approach, but the core principles are actionable in standard chat interfaces, which pushes my rating up to around 74.</p> <p>What really stands out though is the negative transfer finding—the warning that specific examples actually hurt reusability, while abstract principles transfer well. That's genuinely counter-intuitive and practical advice I can give users directly: focus on extracting the underlying principle, not the concrete details.</p> <p>For a concrete example, I'm picturing someone working across multiple domains—maybe a freelancer juggling different client projects or someone moving between marketing, finance, and HR roles—who's building a personal playbook of reusable AI workflows and lessons learned. The key is showing how an abstract insight from one domain (say, a marketing campaign strategy) can be adapted and applied to a completely different context like HR or client work.</p> </div> </div> </div> <!-- Usecases Tab --> <div class="sidebar-tab-panel" id="sidebar-usecases"> <div class="sidebar-section"> <div class="sidebar-section-title">КЕЙСЫ ПРИМЕНЕНИЯ</div> <div class="usecases-list"> <div class="usecase-item"> <div class="usecase-name">Кросс-доменный перенос опыта</div> <div class="usecase-description">Извлечение сути решения задачи A → формулирование абстрактного правила → подача правила в контекст задачи B → генерация решения на основе логики, а не шаблона.</div> </div> <div class="usecase-item"> <div class="usecase-name">Создание базы знаний принципов</div> <div class="usecase-description">Анализ логов прошлых сессий → фильтрация конкретных деталей → сохранение только высокоуровневых стратегий (heuristics) → использование их как внешнего контекста для новых чатов.</div> </div> <div class="usecase-item"> <div class="usecase-name">Предотвращение галлюцинаций по аналогии</div> <div class="usecase-description">Замена детальных примеров (few-shot) на абстрактные инструкции → снижение риска копирования нерелевантных данных → повышение точности в уникальных сценариях.</div> </div> <div class="usecase-item"> <div class="usecase-name">Оптимизация длинного контекста</div> <div class="usecase-description">Сжатие истории взаимодействия до набора уроков → подача сжатых принципов в LLM → экономия токенов при сохранении эффективности прошлых рассуждений.</div> </div> <div class="usecase-item"> <div class="usecase-name">Аудит и ревью процессов</div> <div class="usecase-description">Загрузка абстрактного чек-листа 'уроков прошлого' → сопоставление текущего плана действий с этими уроками → выявление логических ошибок на раннем этапе.</div> </div> </div> </div> <div class="sidebar-section"> <div class="sidebar-section-title">КОМУ ПОЛЕЗНО</div> <div class="usecases-list"> <div class="usecase-item"> <div class="usecase-name">Product Manager</div> <div class="usecase-description">Использует метод абстрактных уроков для анализа продуктовых метрик: извлекает высокоуровневый принцип из разбора маркетингового провала → применяет этот принцип к анализу воронки онбординга → получает структурированный аудит без привязки к деталям старой задачи.</div> </div> <div class="usecase-item"> <div class="usecase-name">Data Scientist</div> <div class="usecase-description">Применяет технику для переноса опыта между экспериментами: формулирует абстрактную стратегию предобработки данных из задачи A → внедряет её в пайплайн задачи B → избегает переобучения на специфических паттернах первого датасета.</div> </div> <div class="usecase-item"> <div class="usecase-name">Маркетолог</div> <div class="usecase-description">Использует извлеченные принципы для создания контент-стратегий: берет урок 'сначала определи tone-of-voice, затем пиши оффер' из успешного кейса в нише недвижимости → применяет его для запуска кампании в EdTech → сохраняет логику процесса при смене контекста.</div> </div> <div class="usecase-item"> <div class="usecase-name">Бизнес-аналитик</div> <div class="usecase-description">Оптимизирует процесс принятия решений: агрегирует опыт прошлых квартальных отчетов в формат 'универсальных правил проверки гипотез' → подает эти правила в системный промпт LLM → получает консистентные выводы по новым рыночным данным.</div> </div> <div class="usecase-item"> <div class="usecase-name">Prompt Engineer</div> <div class="usecase-description">Разрабатывает библиотеки мета-промптов: анализирует успешные цепочки рассуждений (CoT) → очищает их от конкретных данных до уровня логических схем → создает универсальные шаблоны для кросс-доменных задач.</div> </div> </div> </div> </div> </div> </aside> </div> <!-- Mobile Sidebar FAB --> <button class="mobile-sidebar-fab" onclick="openSidebar()" id="mobileSidebarFab"> <span class="fab-rating">73</span> </button> <script> // Theme Toggle function toggleTheme() { const root = document.documentElement; const currentTheme = root.getAttribute('data-theme') || 'light'; const newTheme = currentTheme === 'light' ? 'dark' : 'light'; root.setAttribute('data-theme', newTheme); const desktopCheckbox = document.getElementById('themeToggleCheckbox'); const mobileCheckbox = document.getElementById('themeToggleMobile'); if (desktopCheckbox) desktopCheckbox.checked = newTheme === 'dark'; if (mobileCheckbox) mobileCheckbox.checked = newTheme === 'dark'; localStorage.setItem('theme', newTheme); } // Load saved theme on page load document.addEventListener('DOMContentLoaded', function() { const savedTheme = localStorage.getItem('theme') || 'light'; const root = document.documentElement; root.setAttribute('data-theme', savedTheme); const desktopCheckbox = document.getElementById('themeToggleCheckbox'); const mobileCheckbox = document.getElementById('themeToggleMobile'); if (desktopCheckbox) { desktopCheckbox.checked = savedTheme === 'dark'; desktopCheckbox.addEventListener('change', toggleTheme); } if (mobileCheckbox) { mobileCheckbox.checked = savedTheme === 'dark'; mobileCheckbox.addEventListener('change', toggleTheme); } // User Profile Dropdown const userProfileBtn = document.getElementById('userProfileBtn'); const userDropdownMenu = document.getElementById('userDropdownMenu'); if (userProfileBtn && userDropdownMenu) { userProfileBtn.addEventListener('click', function(e) { e.stopPropagation(); const isExpanded = userProfileBtn.getAttribute('aria-expanded') === 'true'; userDropdownMenu.classList.toggle('show', !isExpanded); userProfileBtn.setAttribute('aria-expanded', !isExpanded); }); document.addEventListener('click', function(e) { if (!userProfileBtn.contains(e.target) && !userDropdownMenu.contains(e.target)) { userDropdownMenu.classList.remove('show'); userProfileBtn.setAttribute('aria-expanded', 'false'); } }); } // Mobile Drawer Menu const burgerMenu = document.getElementById('burgerMenu'); const mobileDrawer = document.getElementById('mobileDrawer'); const drawerClose = document.getElementById('drawerClose'); const drawerOverlay = document.getElementById('drawerOverlay'); function openDrawer() { mobileDrawer.classList.add('open'); drawerOverlay.classList.add('show'); document.body.style.overflow = 'hidden'; } function closeDrawer() { mobileDrawer.classList.remove('open'); drawerOverlay.classList.remove('show'); document.body.style.overflow = ''; } if (burgerMenu) burgerMenu.addEventListener('click', openDrawer); if (drawerClose) drawerClose.addEventListener('click', closeDrawer); if (drawerOverlay) drawerOverlay.addEventListener('click', closeDrawer); // Character counter const userRequest = document.getElementById('user-request'); const charCount = document.getElementById('char-count'); if (userRequest && charCount) { userRequest.addEventListener('input', function() { charCount.textContent = this.value.length; }); } // Clear button const clearBtn = document.getElementById('clear-btn'); if (clearBtn && userRequest) { clearBtn.addEventListener('click', function() { userRequest.value = ''; charCount.textContent = '0'; }); } // ===== FAVORITES FUNCTIONALITY (FIX 17.01.2026) ===== const favoriteBtn = document.getElementById('favoriteBtn'); if (favoriteBtn) { favoriteBtn.addEventListener('click', toggleFavorite); // Check initial favorite status checkFavoriteStatus(); } }); // ===== FAVORITES FUNCTIONS (FIX 17.01.2026) ===== async function toggleFavorite() { const btn = document.getElementById('favoriteBtn'); const researchId = '2604.14004'; if (!btn || !researchId) return; const originalText = btn.textContent; btn.disabled = true; btn.textContent = '⏳'; try { // First check if already in favorites const listResponse = await fetch('/api/v1/favorites/list', { method: 'GET', credentials: 'include' }); if (!listResponse.ok) { throw new Error('Failed to check favorites'); } const listData = await listResponse.json(); const isCurrentlyFavorite = listData.success && listData.data && listData.data.some(item => item.research_id === researchId); let response; if (isCurrentlyFavorite) { // Remove from favorites response = await fetch('/api/v1/favorites/remove', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ research_id: researchId }) }); } else { // Add to favorites response = await fetch('/api/v1/favorites/add', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ research_id: researchId }) }); } if (!response.ok) { throw new Error(`HTTP ${response.status}`); } const result = await response.json(); if (result.success) { if (isCurrentlyFavorite) { btn.textContent = '☆'; btn.classList.remove('in-favorites'); btn.title = 'Добавить в избранное'; } else { btn.textContent = '★'; btn.classList.add('in-favorites'); btn.title = 'В избранном'; } } else { btn.textContent = '❌'; console.error('Favorites error:', result.error); setTimeout(() => { btn.textContent = originalText; }, 2000); } } catch (error) { console.error('Favorites network error:', error); btn.textContent = '❌'; setTimeout(() => { btn.textContent = originalText; }, 2000); } finally { btn.disabled = false; } } async function checkFavoriteStatus() { const btn = document.getElementById('favoriteBtn'); const researchId = '2604.14004'; if (!btn || !researchId) return; try { const response = await fetch('/api/v1/favorites/list', { method: 'GET', credentials: 'include' }); if (response.ok) { const data = await response.json(); if (data.success && data.data) { const isInFavorites = data.data.some(item => item.research_id === researchId); if (isInFavorites) { btn.textContent = '★'; btn.classList.add('in-favorites'); btn.title = 'В избранном'; } } } } catch (error) { console.error('Error checking favorite status:', error); } } // Tab Switching with URL hash support function switchTab(tabName, updateHash = true) { document.querySelectorAll('.tab').forEach(tab => { tab.classList.remove('active'); }); const targetTab = document.querySelector(`[data-tab="${tabName}"]`); if (!targetTab) return; // Tab doesn't exist targetTab.classList.add('active'); document.querySelectorAll('.tab-content').forEach(content => { content.classList.remove('active'); }); document.getElementById(`tab-${tabName}`).classList.add('active'); const keyResultBlock = document.querySelector('.key-result-block'); if (keyResultBlock) { keyResultBlock.style.display = tabName === 'summary' ? 'block' : 'none'; } // Update URL hash (skip for summary - it's default) if (updateHash) { if (tabName === 'summary') { history.replaceState(null, '', window.location.pathname); } else { history.replaceState(null, '', `#${tabName}`); } } } // Handle URL hash on page load and hash change function handleHashNavigation() { const hash = window.location.hash.slice(1); // Remove # const validTabs = ['summary', 'digest', 'concepts', 'simple']; if (hash && validTabs.includes(hash)) { switchTab(hash, false); // Don't update hash again } } // Listen for hash changes (back/forward navigation) window.addEventListener('hashchange', handleHashNavigation); // Check hash on page load document.addEventListener('DOMContentLoaded', function() { handleHashNavigation(); }); // Sidebar Tab Switching function switchSidebarTab(tabName) { document.querySelectorAll('.sidebar-tab').forEach(tab => { tab.classList.remove('active'); }); event.target.classList.add('active'); document.querySelectorAll('.sidebar-tab-panel').forEach(panel => { panel.classList.remove('active'); }); document.getElementById(`sidebar-${tabName}`).classList.add('active'); } // Mobile Sidebar function openSidebar() { const sidebar = document.querySelector('.sidebar-right'); sidebar.classList.add('open'); document.body.style.overflow = 'hidden'; } function closeSidebar() { const sidebar = document.querySelector('.sidebar-right'); sidebar.classList.remove('open'); document.body.style.overflow = ''; } // Copy code block function copyCodeBlock(button) { const codeBlock = button.closest('pre').querySelector('code'); if (codeBlock) { navigator.clipboard.writeText(codeBlock.textContent).then(() => { const originalText = button.textContent; button.textContent = 'Скопировано!'; setTimeout(() => button.textContent = originalText, 2000); }); } } // ======================================== // ADAPTATION & PROMPT BUTTONS // ======================================== let adaptTimerInterval = null; let promptTimerInterval = null; let adaptStartTime = 0; let promptStartTime = 0; // Store internal_generation_id for PDF download let currentInternalGenerationId = null; function formatTimer(seconds) { const mins = Math.floor(seconds / 60); const secs = seconds % 60; return String(mins).padStart(2, '0') + ':' + String(secs).padStart(2, '0'); } function setButtonLoading(btn, isLoading, timerId, timerInterval) { const btnText = btn.querySelector('.btn-text'); const btnLoading = btn.querySelector('.btn-loading'); if (isLoading) { btn.disabled = true; btnText.style.display = 'none'; btnLoading.style.display = 'inline-flex'; } else { btn.disabled = false; btnText.style.display = 'inline-flex'; btnLoading.style.display = 'none'; if (timerInterval) clearInterval(timerInterval); } } function lockAllButtons(lock) { const adaptBtn = document.getElementById('adapt-btn'); const promptBtn = document.getElementById('prompt-btn'); if (lock) { adaptBtn.disabled = true; promptBtn.disabled = true; } else { adaptBtn.disabled = false; promptBtn.disabled = false; } } // Adaptation form submit document.getElementById('adaptation-form').addEventListener('submit', async function(e) { e.preventDefault(); const userRequest = document.getElementById('user-request').value.trim(); if (!userRequest) { alert('Введите запрос'); return; } const adaptBtn = document.getElementById('adapt-btn'); const resultDiv = document.getElementById('adaptation-result'); const contentDiv = document.getElementById('adaptation-content'); lockAllButtons(true); setButtonLoading(adaptBtn, true, 'adapt-timer', adaptTimerInterval); // Start timer adaptStartTime = 0; const timerEl = document.getElementById('adapt-timer'); adaptTimerInterval = setInterval(() => { adaptStartTime++; timerEl.textContent = formatTimer(adaptStartTime); }, 1000); try { const response = await fetch('/api/v1/research/adapt/2604.14004', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ research_id: '2604.14004', user_request: userRequest, model: document.getElementById('model-select').value }) }); const data = await response.json(); if (data.success) { // Convert markdown to HTML using marked.js console.log('Raw adapted_content:', data.adapted_content); let rawContent = data.adapted_content || ''; // Fix LLM markdown bugs // 1. Fix duplicate header markers: ### #### -> ####, ## ### -> ### rawContent = rawContent.replace(/^#{1,6}\s+#{1,6}\s/gm, (match) => { // Count hashes in second group and use that const secondGroup = match.match(/\s(#+)\s/); return secondGroup ? secondGroup[1] + ' ' : match; }); // HTML entity cleanup rawContent = rawContent.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&'); console.log('Cleaned content (first 500 chars):', rawContent.substring(0, 500)); console.log('Has headers (##):', /^#{1,6}\s/m.test(rawContent)); console.log('Has code blocks:', rawContent.includes('```')); const htmlContent = marked.parse(rawContent); console.log('Parsed HTML (first 500 chars):', htmlContent.substring(0, 500)); console.log('HTML has h2 tags:', htmlContent.includes('<h2>')); console.log('HTML has h3 tags:', htmlContent.includes('<h3>')); console.log('HTML has h4 tags:', htmlContent.includes('<h4>')); console.log('HTML has pre tags:', htmlContent.includes('<pre>')); contentDiv.innerHTML = htmlContent; resultDiv.style.display = 'block'; enhanceCodeBlocks(); // Store internal_generation_id for PDF download currentInternalGenerationId = data.internal_generation_id; console.log('Stored internal_generation_id:', currentInternalGenerationId); // Update result header const resultHeader = resultDiv.querySelector('.result-header h3'); if (resultHeader) resultHeader.textContent = 'Результат адаптации'; resultDiv.scrollIntoView({ behavior: 'smooth' }); } else { alert('Ошибка: ' + (data.error || 'Неизвестная ошибка')); } } catch (error) { alert('Ошибка соединения: ' + error.message); } finally { clearInterval(adaptTimerInterval); setButtonLoading(adaptBtn, false, 'adapt-timer', null); lockAllButtons(false); document.getElementById('adapt-timer').textContent = '00:00'; } }); // Prompt generation button document.getElementById('prompt-btn').addEventListener('click', async function() { const userRequest = document.getElementById('user-request').value.trim(); if (!userRequest) { alert('Введите запрос для создания промпта'); return; } const promptBtn = document.getElementById('prompt-btn'); const resultDiv = document.getElementById('adaptation-result'); const contentDiv = document.getElementById('adaptation-content'); lockAllButtons(true); setButtonLoading(promptBtn, true, 'prompt-timer', promptTimerInterval); // Start timer promptStartTime = 0; const timerEl = document.getElementById('prompt-timer'); promptTimerInterval = setInterval(() => { promptStartTime++; timerEl.textContent = formatTimer(promptStartTime); }, 1000); try { const response = await fetch('/api/v1/research/generate-prompt/2604.14004', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ research_id: '2604.14004', user_request: userRequest, model: document.getElementById('model-select').value }) }); const data = await response.json(); if (data.success) { // Get prompt and explanation directly from response console.log('Raw prompt_content:', data.prompt_content); console.log('Raw explanation_content:', data.explanation_content); const promptText = data.prompt_content || ''; const explanationText = data.explanation_content || ''; console.log('Prompt (first 200 chars):', promptText.substring(0, 200)); console.log('Explanation (first 200 chars):', explanationText.substring(0, 200)); // Build formatted content let formattedContent = ''; // Add explanation if present if (explanationText) { let cleanExplanation = explanationText; cleanExplanation = cleanExplanation.replace(/^#{1,6}\s+#{1,6}\s/gm, (match) => { const secondGroup = match.match(/\s(#+)\s/); return secondGroup ? secondGroup[1] + ' ' : match; }); cleanExplanation = cleanExplanation.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&'); formattedContent += marked.parse(cleanExplanation); } // Add the prompt itself in a styled code block if (promptText) { formattedContent += '<div class="generated-prompt-block" style="margin-top: 24px;">'; formattedContent += '<h3 style="color: #667eea; margin-bottom: 12px;">📝 Готовый промпт</h3>'; formattedContent += '<div class="prompt-code-container" style="position: relative; background: #0f172a; border-radius: 8px; overflow: hidden;">'; formattedContent += '<div class="prompt-code-header" style="background: #1e293b; padding: 8px 12px; display: flex; justify-content: space-between; align-items: center;">'; formattedContent += '<span style="color: #94a3b8; font-size: 12px;">PROMPT</span>'; formattedContent += '<button onclick="copyPromptText(this)" class="copy-prompt-btn" style="background: #667eea; color: white; border: none; padding: 4px 12px; border-radius: 4px; cursor: pointer; font-size: 12px;">Копировать</button>'; formattedContent += '</div>'; formattedContent += '<pre style="margin: 0; padding: 16px; overflow-x: auto; background: transparent;"><code class="prompt-text" style="color: #e2e8f0; white-space: pre-wrap; word-wrap: break-word; font-family: monospace; font-size: 13px; line-height: 1.6;">' + promptText.replace(/</g, '<').replace(/>/g, '>') + '</code></pre>'; formattedContent += '</div>'; formattedContent += '</div>'; } contentDiv.innerHTML = formattedContent; resultDiv.style.display = 'block'; enhanceCodeBlocks(); // Store internal_generation_id for PDF download currentInternalGenerationId = data.internal_generation_id; console.log('Stored internal_generation_id:', currentInternalGenerationId); // Update result header const resultHeader = resultDiv.querySelector('.result-header h3'); if (resultHeader) resultHeader.textContent = 'Сгенерированный промпт'; resultDiv.scrollIntoView({ behavior: 'smooth' }); } else { alert('Ошибка: ' + (data.error || 'Неизвестная ошибка')); } } catch (error) { alert('Ошибка соединения: ' + error.message); } finally { clearInterval(promptTimerInterval); setButtonLoading(promptBtn, false, 'prompt-timer', null); lockAllButtons(false); document.getElementById('prompt-timer').textContent = '00:00'; } }); // Copy prompt text to clipboard function copyPromptText(btn) { const codeEl = btn.closest('.prompt-code-container').querySelector('.prompt-text'); if (codeEl) { navigator.clipboard.writeText(codeEl.textContent).then(() => { const originalText = btn.textContent; btn.textContent = 'Скопировано!'; btn.style.background = '#22c55e'; setTimeout(() => { btn.textContent = originalText; btn.style.background = '#667eea'; }, 2000); }); } } function copyAdaptationResult() { const content = document.getElementById('adaptation-content').innerText; navigator.clipboard.writeText(content).then(() => { const btn = document.querySelector('.action-btn span'); if (btn) { const original = btn.textContent; btn.textContent = 'Скопировано!'; setTimeout(() => btn.textContent = original, 2000); } }); } // Process code blocks after render function enhanceCodeBlocks() { const contentDiv = document.getElementById('adaptation-content'); if (!contentDiv) return; // First, convert blockquotes containing prompts to code blocks enhancePromptBlockquotes(contentDiv); const preBlocks = contentDiv.querySelectorAll('pre'); preBlocks.forEach((pre, index) => { // Skip if already enhanced if (pre.querySelector('.code-block-header')) return; const code = pre.querySelector('code'); const codeText = code ? code.textContent.trim() : ''; // SHORT CODE THRESHOLD: Skip header for short code blocks (< 80 chars) // These stay as simple styled blocks without copy button if (codeText.length < 80) { pre.style.background = '#0f172a'; pre.style.borderRadius = '6px'; pre.style.padding = '8px 12px'; pre.style.margin = '0.5em 0'; pre.style.overflow = 'auto'; if (code) { code.style.color = '#e2e8f0'; code.style.fontFamily = 'monospace'; code.style.fontSize = '13px'; code.style.whiteSpace = 'pre-wrap'; code.style.wordBreak = 'break-word'; } return; // Skip adding header } const langClass = code ? Array.from(code.classList).find(c => c.startsWith('language-')) : null; const lang = langClass ? langClass.replace('language-', '').toUpperCase() : 'CODE'; // Create header (only for long code blocks) const header = document.createElement('div'); header.className = 'code-block-header'; header.innerHTML = ` <span class="code-block-lang">${lang}</span> <button type="button" class="code-copy-btn" onclick="copyCodeBlock(this)"> <svg width="12" height="12" viewBox="0 0 24 24" fill="none"> <rect x="9" y="9" width="13" height="13" rx="2" stroke="currentColor" stroke-width="2"/> <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" stroke="currentColor" stroke-width="2"/> </svg> <span>Копировать</span> </button> `; pre.style.position = 'relative'; pre.insertBefore(header, pre.firstChild); }); } // Convert blockquotes and inline quoted prompts to styled code blocks function enhancePromptBlockquotes(contentDiv) { // 1. Handle blockquotes const blockquotes = contentDiv.querySelectorAll('blockquote'); blockquotes.forEach(bq => { const prevEl = bq.previousElementSibling; const isPrompt = prevEl && /промпт/i.test(prevEl.textContent); const bqText = bq.textContent.trim(); const looksLikePrompt = bqText.length > 20; if (isPrompt || looksLikePrompt) { bq.parentNode.replaceChild(createPromptCodeBlock(bqText), bq); } }); // 2. Handle inline prompts - any quoted text that looks like a prompt const allElements = contentDiv.querySelectorAll('li, p'); allElements.forEach(el => { // Skip if already has a code block inside if (el.querySelector('pre')) return; let html = el.innerHTML; let modified = false; // Pattern: "quoted text" where text is > 30 chars and looks like a prompt // Match quotes that start with action words or look like instructions const quoteRegex = /"([^"]{30,})"/g; const matches = [...html.matchAll(quoteRegex)]; matches.forEach(match => { const fullMatch = match[0]; const quotedText = match[1]; // Check if this looks like a prompt (action verbs, instructions, etc.) const looksLikePrompt = /^(Проанализируй|Предложи|Разработай|Оцени|Напиши|Создай|Сгенерируй|Объясни|Помоги|Опиши|Найди|Выдели|Представь|Учитывая|Перед ответом|Вот моя|Отличн|Хорош|Неплох|Можешь гордиться|Теперь)/i.test(quotedText) || quotedText.includes('ключев') || quotedText.includes('контент') || quotedText.includes('SEO') || quotedText.includes('запрос') || quotedText.includes('статью') || quotedText.includes('топ-') || quotedText.includes('вариант') || quotedText.includes('семантическ'); if (looksLikePrompt) { modified = true; const codeBlock = createPromptCodeBlockHTML(quotedText); html = html.replace(fullMatch, codeBlock); } }); if (modified) { el.innerHTML = html; } }); } function createPromptCodeBlock(text) { const pre = document.createElement('pre'); pre.style.cssText = 'background: #0f172a; border-radius: 8px; margin: 1em 0; overflow: hidden; position: relative;'; const header = document.createElement('div'); header.className = 'code-block-header'; header.innerHTML = ` <span class="code-block-lang">PROMPT</span> <button type="button" class="code-copy-btn" onclick="copyCodeBlock(this)"> <svg width="12" height="12" viewBox="0 0 24 24" fill="none"> <rect x="9" y="9" width="13" height="13" rx="2" stroke="currentColor" stroke-width="2"/> <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" stroke="currentColor" stroke-width="2"/> </svg> <span>Копировать</span> </button> `; const code = document.createElement('code'); code.style.cssText = 'display: block; padding: 16px; color: #e2e8f0; white-space: pre-wrap; word-wrap: break-word; font-family: monospace; font-size: 13px; line-height: 1.6;'; let promptText = text.trim(); if (promptText.startsWith('"')) promptText = promptText.slice(1); if (promptText.endsWith('"')) promptText = promptText.slice(0, -1); code.textContent = promptText; pre.appendChild(header); pre.appendChild(code); return pre; } function createPromptCodeBlockHTML(text) { let promptText = text.trim(); const escapedText = promptText.replace(/</g, '<').replace(/>/g, '>'); return `<pre style="background: #0f172a; border-radius: 8px; margin: 0.5em 0; overflow: hidden; position: relative;"> <div class="code-block-header"> <span class="code-block-lang">PROMPT</span> <button type="button" class="code-copy-btn" onclick="copyCodeBlock(this)"> <svg width="12" height="12" viewBox="0 0 24 24" fill="none"> <rect x="9" y="9" width="13" height="13" rx="2" stroke="currentColor" stroke-width="2"/> <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" stroke="currentColor" stroke-width="2"/> </svg> <span>Копировать</span> </button> </div> <code style="display: block; padding: 16px; color: #e2e8f0; white-space: pre-wrap; word-wrap: break-word; font-family: monospace; font-size: 13px; line-height: 1.6;">${escapedText}</code> </pre>`; } function copyCodeBlock(btn) { const pre = btn.closest('pre'); const code = pre.querySelector('code'); if (!code) return; navigator.clipboard.writeText(code.textContent).then(() => { btn.classList.add('copied'); const span = btn.querySelector('span'); span.textContent = 'Скопировано!'; setTimeout(() => { btn.classList.remove('copied'); span.textContent = 'Копировать'; }, 2000); }); } function downloadAdaptationHTML() { const contentEl = document.getElementById('adaptation-content'); const title = document.getElementById('adaptation-title').textContent; const researchTitle = 'Memory Transfer Learning: абстрактные инсайты работают лучше конкретных примеров — и переносятся между задачами'; const researchId = '2604.14004'; const researchUrl = 'https://novasapiens.ru/prompt/' + researchId; // Clean content - remove code-block-header divs from exported HTML let content = contentEl.innerHTML; content = content.replace(/<div class="code-block-header">[\s\S]*?<\/div>/g, ''); const htmlTemplate = `<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>${title} - ${researchTitle}

${title}

На основе исследования: ${researchTitle}
Открыть оригинал исследования
${content}