3,583 papers
arXiv:2610.09772 78 7 окт. 2026 г. FREE

AO-DA (Decoupling Architecture): логика и персона в двух раздельных вызовах модели

КЛЮЧЕВАЯ СУТЬ
Обнаружено: когда в одном промпте смешаны роль, длинная переписка и «ядовитая» история, модель сначала теряет формат, а не смысл. Метод AO-DA позволяет держать бота в образе и не терять жёсткие правила (лимиты, запреты, обязательные пункты), даже если он 40 реплик подряд поддакивал плохой идее. Логика уходит в отдельный вызов, который физически не видит ни историю, ни персонажа. Первый вызов выдаёт короткий JSON-контракт (состояние, действие, что обязательно упомянуть, риск). Второй вызов пишет реплику в образе по этому контракту. Загрязнить логику просто нечем.
Адаптировать под запрос
⚡

TL;DR

AO-DA — схема, где вместо одного промпта «и думай, и играй роль» делается два отдельных вызова. Первый вызов («Что») получает только текущую реплику и факты, без истории и персонажа. Он выдаёт короткий проверяемый JSON: состояние, что рекомендовать, что обязательно упомянуть, уровень риска. Второй вызов («Как») получает этот JSON плюс всю историю и пишет ответ в образе.

Главная находка: когда в одном промпте смешаны персонаж, длинная переписка и «вредная» история, модель сначала теряет формат, а не смысл. Допустим, бот в роли дерзкого наставника уже 10 реплик поддакивал плохой идее. Тогда вместо JSON с рекомендацией он выдаёт болтовню в тоне истории. Смысл при этом тоже страдает, но заметно меньше: в основном ломается структура. На коротких чистых промптах разницы почти нет, схема только добавляет лишний вызов.

Суть метода: логика физически не видит историю и персонажа, поэтому загрязнить её нечем. Её вход не растёт, а персону можно менять, не пересчитывая логику. Если ту же «грязь» всё же подать в логический вызов, помогает только на 8B-модели, на 4B обе схемы разваливаются. Защищает именно отсечение истории от логики, а не отдельный формат.

🔬

Схема метода

ВЫЗОВ 1 («Что»): только текущая реплика + факты/сигналы, БЕЗ истории и БЕЗ персонажа
   → краткая мысль + JSON: состояние, рекомендуемое действие

МИКРО-СОСТОЯНИЕ (то, что передаётся дальше):
   вход, вывод, обязательные пункты, риск, план подачи
   (что упомянуть, в каком порядке, что запрещено добавлять)

ВЫЗОВ 2 («Как»): персонаж + микро-состояние + история + полная реплика
   → реплика в образе, обязана содержать все обязательные пункты

(Если сменился только персонаж → вызов 1 не повторяем, берём состояние из кэша)

Это два отдельных запроса. В чате это два сообщения или два чата. В автоматизации без кода это два блока подряд.

🚀

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

Задача: Вы делаете Telegram-бота для самозанятых в образе ироничного наставника «Тимофея». Пользователь 40 сообщений шутил, а бот поддакивал: «Берём заказы, не тормозим!». Теперь вопрос: «Я за год уже набрал 2,3 млн на НПД, беру ещё заказ на 300 тысяч, нормально же?» Если оставить всё в одном промпте, велик шанс, что «Тимофей» продолжит в том же тоне и забудет про лимит 2,4 млн руб.

Промпт (вызов 1, «Что»): отправляется БЕЗ истории и БЕЗ персонажа.

<Роль>
Ты — модуль проверки правил. Ты не общаешься с пользователем.
Ты возвращаешь только оценку ситуации по правилам.


<Правила>
- Для самозанятых на НПД лимит дохода — 2 400 000 руб. за календарный год.
- При превышении право на НПД теряется, нужно переходить на другой режим.


<Факты>
Доход с начала года: 2 300 000 руб.
Планируемый заказ: 300 000 руб.


<Реплика>
Беру ещё заказ на 300 тысяч, нормально же?


Ответь строго в формате:
<мысль>1-2 предложения
{"s": "состояние пользователя", "a": "рекомендуемое действие", "обязательно_упомянуть": ["..."], "риск": "низкий|средний|высокий", "запрещено_добавлять": ["..."]}

Промпт (вызов 2, «Как»): сюда вставляется результат вызова 1.

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

<Состояние>
{JSON из вызова 1}


Требования к ответу:
- Обязательно упомяни все пункты из «обязательно_упомянуть».
- Не добавляй ничего из «запрещено_добавлять».
- Риск «высокий»: не поддакивай и не шути над самим риском.

<История>
{вся переписка}


<Реплика>
Беру ещё заказ на 300 тысяч, нормально же?


Ответь одной репликой в образе.

Результат: Вызов 1 вернёт короткую «мысль» и JSON с высоким риском, рекомендацией не брать заказ на этих условиях и обязательным упоминанием лимита. Вызов 2 выдаст реплику в манере Тимофея: тон прежний, но в ответе есть все обязательные пункты. Поддакивание из истории больше не определяет суть.

🧠

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

Слабость. В одном контексте история — это одновременно память для персонажа и шум для логики. Если ассистент раньше одобрял плохую идею, модель склонна продолжать этот паттерн (подхалимство). Персонаж и длинная переписка тянут модель в «болтовню в тоне», а строгий формат становится самой хрупкой частью. На малых моделях это заметнее всего.

Сильная сторона. Модель хорошо делает узкую задачу на коротком чистом входе: оценить факты по правилам и выдать структуру. Так же хорошо она оформляет готовое содержание в нужном тоне и с нужной историей.

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

Рычаги управления: - Что подаётся в вызов 1. Больше контекста — больше риск загрязнения. Давай только факты и текущую реплику. - «Обязательно упомянуть» и «запрещено добавлять». Это жёсткий контракт между шагами. Ужесточи для рискованных тем, ослабь для лёгкого общения. - Поле «риск». Привяжи к нему поведение персонажа: при высоком риске никаких шуток. - Кэш состояния. Если факты не поменялись, а нужен другой тон («второе мнение» от другого персонажа), вызов 1 не повторяй. Это экономит время и деньги. - Простые случаи. Если диалог короткий и без «ядовитой» истории, схему можно не применять: выигрыша не будет.

📋

Шаблон промпта

Вызов 1 («Что»):

<Роль>
Ты — модуль оценки по правилам. Ты не общаешься с пользователем и не играешь персонажа.


<Правила>
{правила_и_ограничения_предметной_области}


<Факты>
{факты_и_сигналы_о_ситуации}


<Реплика>
{текущая_реплика_пользователя}


Ответь строго в формате:
<мысль>1-2 предложения
{"s": "состояние пользователя", "a": "рекомендуемое действие", "обязательно_упомянуть": ["..."], "риск": "низкий|средний|высокий", "запрещено_добавлять": ["..."]}

Вызов 2 («Как»):

{описание_персонажа_и_тона}

<Состояние>
{json_из_вызова_1}


Требования:
- Упомяни все пункты из «обязательно_упомянуть».
- Не добавляй ничего из «запрещено_добавлять».
- Подача определяется полем «риск»: {как_вести_себя_при_высоком_риске}.

<История>
{переписка}


<Реплика>
{полная_реплика_пользователя}


Ответь одной репликой в образе.

Что подставлять: {правила_и_ограничения_предметной_области} — жёсткие факты, которые нельзя нарушать (лимиты, запреты, регламенты). {факты_и_сигналы_о_ситуации} — только объективные данные, без пересказа переписки. {описание_персонажа_и_тона} — голос бота. {json_из_вызова_1} — результат шага 1 без правок.

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

Вот шаблон двухшаговой схемы «логика отдельно, персонаж отдельно». Адаптируй под мою задачу: {твоя задача}.
Задавай вопросы, чтобы заполнить поля.

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

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

⚠️

Ограничения

⚠️ Нет выигрыша на чистых коротких диалогах: Когда история короткая и без «ядовитых» реплик, разделение не улучшает логику. Платишь вторым вызовом и задержкой, а пользы нет. Это страховка, а не улучшение по умолчанию.

⚠️ Малые модели, не топовые: Тестировали сжатые модели на 4–8 млрд параметров, запущенные локально на ноутбуке. Насколько ровно это переносится на современные большие модели в облаке, статья не проверяла. Скорее всего, там слабее, но это догадка.

⚠️ Защищает отсечение истории, а не формат: Если всё же подать «грязь» в логический вызов, на 8B выделенный формат ещё помогает, а на 4B обе схемы рушатся. Главное правило: не пускай историю в логический шаг.

⚠️ Правила в тестах были в коде: В стенде обязательные пункты и риск выводил жёсткий детерминированный слой по фактам, а не сама модель. Без такого слоя качество зависит от того, насколько хорошо модель выведет их сама.

⚠️ Узкая база: Всего две задачи, два персонажа, пять запусков на комбинацию. Оценка шла по ключевым словам, без LLM-судьи. Адаптеры дообучены на 20 примерах. Закономерность видна, но обобщать на всё осторожно.

⚠️ Цена: Второй вызов на первой реплике темы. Для живого чата это заметная задержка.

🔍

Как исследовали

Авторы взяли две локальные модели (Llama-3.1-8B и Gemma-3-4B, оба в 4-битном сжатии) на ноутбуке с чипом M2. Они сравнили три схемы: всё в одном промпте, разделение с чистой логикой и разделение, где «грязь» нарочно подали и в логический шаг.

«Грязь» делали злой: не просто лишний текст, а история, где ассистент уже поддакивал плохому плану (три энергетика перед питчем, продвижение токена при юридических рисках). Затем добавляли длинный тревожный ввод и раздутый системный промпт с примерами персонажа. Всего получилось 480 запусков.

Оценивали задачи с проверяемым ответом (какие действия обязательны, какие слова запрещены), без LLM-судьи. Метрику разложили на две части: «сломался ли формат» и «что осталось в смысле». Главный вывод: в схеме «всё в одном» формат (JSON) рушился у большинства запусков при сильном загрязнении, а смысл просел примерно вдвое на 8B. Первый запуск на чистых промптах показал ноль эффекта, и авторы честно оставили его как граничное условие.

Неожиданности: на 4B-модели даже один только персонаж без истории уже снижал логику. А на 8B-модели при умеренной «грязи» результат в логическом шаге иногда выходил лучше чистого (причину авторы разбирают позже в тексте). Для практики главный инсайт такой: не вставляй персонажа и длинную переписку туда, где требуется точное следование правилам и формату.

💡

Адаптации и экстраполяции

🔧 Техника: «второе мнение» от другого персонажа → без повторной проверки логики

Если факты не изменились, а нужен другой тон, используй сохранённый JSON из вызова 1 и запусти только вызов 2 с новым описанием персонажа. В статье так экономят вызов логики при смене персонажа.

{описание_нового_персонажа}

<Состояние>
{тот_же_json}

...

Экстраполяция (моя, не из статьи): правила агента отдельно от тона. Если ты настраиваешь агента с «характером» (дружелюбный, дерзкий), держи жёсткие правила и проверки в отдельном шаге или блоке, который не видит тон и историю. Тон добавляй только на выходе. Это идея того же принципа, но статья проверяла её только на схеме из двух вызовов.

🔗

Ресурсы

  • Работа: Decoupling Logic from Persona: Structural Immunity of Edge LLM Agents to Context Pollution
  • Авторы: Masaaki Nakatsu (AO, Inc. / OrbLabs AG), Reno Wang (AO, Inc.)
  • Связанные работы из статьи: Liu et al. 2024 (потеря информации в середине длинного контекста); Shi et al. 2023 (посторонний контекст ухудшает рассуждение); Levy et al. 2024; Laban et al. 2025 (потеря качества в многоходовых диалогах); Zheng et al. 2024 и Gupta et al. 2024 (роли и персоны не улучшают рассуждение, вносят смещения); Sharma et al. 2023 (подхалимство); RULER (Hsieh et al. 2024)
  • Код, критерии оценки, примеры «загрязнения» и логи заявлены как опубликованные (Appendix G в статье)

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

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

Обнаружено: когда в одном промпте смешаны роль, длинная переписка и «ядовитая» история, модель сначала теряет формат, а не смысл. Метод AO-DA позволяет держать бота в образе и не терять жёсткие правила (лимиты, запреты, обязательные пункты), даже если он 40 реплик подряд поддакивал плохой идее. Логика уходит в отдельный вызов, который физически не видит ни историю, ни персонажа. Первый вызов выдаёт короткий JSON-контракт (состояние, действие, что обязательно упомянуть, риск). Второй вызов пишет реплику в образе по этому контракту. Загрязнить логику просто нечем.

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

Работает как конвейер из двух станков. Вызов 1 («Что») получает только текущую реплику и факты. Он возвращает мысль на 1-2 предложения и JSON: состояние, рекомендация, обязательные пункты, риск, что запрещено добавлять. Вызов 2 («Как») получает персонажа, этот JSON, всю историю и пишет ответ в образе. Вход логики не растёт вместе с диалогом, а персонажа можно менять, не пересчитывая логику. Это как юрист и копирайтер: юрист сверяет факты с законом и не читает вашу переписку, а копирайтер красиво упаковывает его вывод. Если меняется только тон (например, нужно второе мнение от другого персонажа), вызов 1 не повторяют, а берут состояние из кэша.

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

В одном контексте история работает и как память для персонажа, и как шум для логики. Если ассистент раньше одобрял плохую идею, модель тянет этот паттерн дальше (подхалимство). Роль и длинная переписка толкают её в болтовню в нужном тоне. Строгий формат ломается первым, и вместо JSON с рекомендацией выходит трёп. На малых моделях (4-8 млрд параметров) это видно сильнее всего. Узкую задачу «оцени факты по правилам» на коротком чистом входе модель делает хорошо, и оформление готового содержания в тоне тоже. Плохо ей, когда это требуют разом. Важная деталь: если «грязь» всё же подать в логический вызов, выделенный формат спасает только на 8B. На 4B обе схемы разваливаются. Значит, защищает именно отсечение истории, а не красивый JSON. Критика: тестов мало (2 задачи, 2 персонажа, 5 запусков), оценка по ключевым словам, а обязательные пункты и риск в стенде считал жёсткий код, не модель.

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

Чат-боты с персонажем → особенно там, где есть жёсткие правила (налоги, финансы, медицина, поддержка с регламентом), когда диалог длинный и бот уже успел наговорить лишнего. Хорошо ложится на малые локальные модели 4-8B. Бонус: смена персонажа без пересчёта логики. НЕ подходит для коротких чистых диалогов: там выигрыша нет, а за второй вызов платишь задержкой и деньгами. Не поможет и без жёстких фактов и правил: нечего проверять. Это страховка, а не улучшение по умолчанию.

Мини-рецепт

1. Выпиши железные правила: лимиты, запреты, регламенты. То, что нельзя нарушить ни в каком тоне.
2. Собери факты без пересказа переписки: только объективные данные (суммы, даты, статусы).
3. Вызов 1: задай роль <роль>модуль проверки правил, с пользователем не общается. Дай правила, факты и только текущую реплику. История и персонаж сюда не попадают.
4. Потребуй строгий формат: <мысль>1-2 предложения и {"s": "...", "a": "...", "обязательно_упомянуть": ["..."], "риск": "низкий|средний|высокий", "запрещено_добавлять": ["..."]}.
5. Проверь JSON глазами или кодом: он маленький, ошибку видно сразу.
6. Вызов 2: вставь описание персонажа, JSON без правок, историю и полную реплику. Требуй: упомянуть все обязательные пункты, не добавлять запрещённое.
7. Привяжи тон к риску: при высоком риске никаких шуток и поддакивания.
8. Кэшируй состояние: факты не менялись, а нужен другой голос? Вызов 1 не гоняй.

Примеры

[ПЛОХО] : Ты Тимофей, ироничный наставник для самозанятых. Вот переписка: [40 сообщений, где ты поддакивал]. Пользователь: я за год набрал 2,3 млн на НПД (налог для самозанятых), беру ещё заказ на 300 тысяч, нормально же? Результат: «Тимофей» продолжает в духе «берём, не тормозим!» и забывает про лимит 2,4 млн.
[ХОРОШО] : Вызов 1, без истории и персонажа: Ты — модуль проверки правил, с пользователем не общаешься. Правило: лимит дохода на НПД — 2 400 000 руб. в год, при превышении право на НПД теряется. Факты: доход 2 300 000, заказ 300 000. Реплика: беру ещё заказ на 300 тысяч, нормально же? Ответь: <мысль>... и с полями состояние, действие, обязательно_упомянуть, риск, запрещено_добавлять. Вызов 2: Ты — Тимофей, ироничный наставник, свой парень, лёгкая подколка. <Состояние>{JSON из вызова 1} Упомяни все пункты из «обязательно_упомянуть». Риск «высокий»: не поддакивай и не шути над самим риском. <История>{переписка} Ответь одной репликой в образе. Результат: тон прежний, но в ответе есть лимит 2,4 млн и совет не брать заказ на этих условиях.
Источник: Decoupling Logic from Persona: Structural Immunity of Edge LLM Agents to Context Pollution
ArXiv ID: 2610.09772 | Сгенерировано: 2026-10-08 05:00

Проблемы LLM

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

Методы

МетодСуть
Два вызова: «Что» отдельно, «Как» отдельно — логика не заражается тоном и историейВызов 1 («Что»). Дай модели роль проверяющего модуля, правила, факты и текущую реплику. Без истории и без персонажа. Попроси короткую мысль и JSON: {"s": состояние, "a": действие, "обязательно_упомянуть": [...], "риск": "низкий\|средний\|высокий", "запрещено_добавлять": [...]}. Вызов 2 («Как»). Дай персонажа, этот JSON без правок, историю и полную реплику. Требуй: упомянуть все обязательные пункты, не добавлять запрещённое. Привяжи поведение к полю «риск». Например, при высоком риске никаких шуток. Почему работает: вход первого вызова не растёт вместе с диалогом. Загрязнить его нечем. Результат маленький, его легко проверить глазами или кодом. Второй вызов только оформляет готовое содержание. Бонус: сменился только персонаж — результат вызова 1 берёшь из кэша. Экономишь время и деньги. Когда да: длинные диалоги, роли с сильным характером, правила нельзя нарушать (лимиты, запреты, регламенты). Когда нет: короткий чистый диалог без поддакивания. Пользы нет, платишь лишним вызовом и задержкой. Важно: защищает именно отсечение истории. Если историю всё же пустить в первый вызов, схема на малых моделях перестаёт помогать
📖 Простыми словами

Decoupling Logic from Persona: Structural Immunity of EdgeLLMAgentsto Context Pollution

arXiv: 2610.09772

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

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

Метод называется архитектура AO-DA, и суть тут в двух изолированных запросах вместо одного монолитного промпта. Первый вызов («Что») вообще не видит шуток и персонажа, получая только голый факт: на выходе получается строгий JSON с расчётами, рисками и указаниями, без капли эмоций. Второй вызов («Как») берет эту сухую выжимку, историю переписки и наконец-то пишет ответ в заданном образе без потери фактуры.

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

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

Работа с исследованием

Адаптируйте исследование под ваши задачи или создайте готовый промпт на основе техник из исследования.

0 / 2000
~0.5-2 N-токенов ~10-30с
~0.3-1 N-токенов ~5-15с