TL;DR
CNL-P — формальный язык для промптов с точной грамматикой (BNF-нотация) и строгой семантикой. Язык структурирует промпт через явные секции: PERSONA (роль), CONSTRAINTS (ограничения), TYPES (типы данных), VARIABLES (переменные), WORKER (workflow с командами и условиями). Это как писать код, но естественным языком — есть синтаксис, типы, модули.
Исследователи обнаружили что обычные NL-промпты теряют в модульности и строгости процесса. Когда промпт усложняется — добавляются переменные, условия, API-вызовы — неструктурированный текст превращается в кашу. Непонятно где что определено, какие типы у переменных, как данные передаются между шагами. Модель может неправильно интерпретировать неявные связи.
CNL-P решает через формализацию: каждая сущность (переменная, тип, команда) явно определена с указанием типа и позиции в workflow. Модель видит чёткую структуру — какие данные входят, какие выходят, какие условия проверяются. Плюс есть linting tool — статический анализ промптов как код (проверка синтаксиса, типов, несуществующих переменных). Это первая работа, где NL-промпты проверяются программно.
Схема метода
CNL-P определяет агента через иерархию секций:
[DEFINE_AGENT: ИМЯ_АГЕНТА]
[DEFINE_PERSONA:]
ROLE: описание роли
[Опциональные аспекты]
[END_PERSONA]
[DEFINE_CONSTRAINTS:]
Ограничение_1: описание
Ограничение_2: описание
[END_CONSTRAINTS]
[DEFINE_TYPES:]
СложныйТип = {поле_1: тип, поле_2: тип}
[END_TYPES]
[DEFINE_VARIABLES:]
"описание" переменная_1: тип
"описание" переменная_2: тип
[END_VARIABLES]
[DEFINE_WORKER: ВОРКЕР_ИМЯ]
[INPUTS] <REF>входная_переменная [END_INPUTS]
[OUTPUTS] <REF>выходная_переменная [END_OUTPUTS]
[MAIN_FLOW]
[SEQUENTIAL_BLOCK]
COMMAND-1 [COMMAND действие RESULT переменная: тип]
COMMAND-2 [CALL api_имя WITH {параметр: значение}]
[END_SEQUENTIAL_BLOCK]
[IF условие]
COMMAND-3 [COMMAND действие]
[END_IF]
[END_MAIN_FLOW]
[END_WORKER]
[END_AGENT]
Ключевые элементы:
переменная— ссылка на переменнуюRESULT переменная: тип— сохранение результата командыCALL api_имя WITH {...}— вызов API- IF-блоки для условной логики
- Явное указание типов:
text,number,boolean, сложные структуры
Всё это в одном промпте — LLM интерпретирует как инструкции.
Пример применения
⚠️ Ограничения метода: CNL-P эффективен для сложных multi-step задач с явными данными, условиями, API-вызовами. Не подходит для простых one-shot вопросов ("напиши стих") — избыточная формализация. Требует понимания структуры для создания/проверки промпта.
Задача: Ты — предприниматель, запускаешь сервис доставки завтраков в Москве. Нужен агент, который анализирует конкурентов (парсит Яндекс.Еду через API), твои финансы (берёт из Google Sheets), и выдаёт рекомендацию: в какой район выходить первым.
Промпт (упрощённая версия CNL-P):
[DEFINE_AGENT: РынокАнализатор]
[DEFINE_PERSONA:]
ROLE: Ты аналитик-стратег для стартапов в food-tech.
Специализируешься на анализе локальных рынков доставки еды в России.
[END_PERSONA]
[DEFINE_CONSTRAINTS:]
География: Только Москва, районы внутри МКАД
Бюджет: Рекомендация должна учитывать стартовый капитал пользователя
Данные: Используй только проверенные источники (API Яндекс.Еды, Google Sheets)
[END_CONSTRAINTS]
[DEFINE_TYPES:]
Район = {
название: text,
конкуренты: number,
средний_чек: number,
плотность_населения: number
}
Финансы = {
стартовый_капитал: number,
месячные_расходы: number
}
[END_TYPES]
[DEFINE_VARIABLES:]
"Список районов Москвы для анализа" районы: List[Район]
"Финансовые данные стартапа" финансы: Финансы
"Итоговая рекомендация" рекомендация: text
[END_VARIABLES]
[DEFINE_WORKER: АнализРайонов]
[INPUTS]
<REF>районы
<REF>финансы
[END_INPUTS]
[OUTPUTS]
<REF>рекомендация
[END_OUTPUTS]
[MAIN_FLOW]
[SEQUENTIAL_BLOCK]
COMMAND-1 [CALL yandex_eda_api WITH {районы: <REF>районы}
RESPONSE конкуренты_данные: List[Район] SET]
COMMAND-2 [CALL google_sheets_api WITH {sheet_id: "финансы"}
RESPONSE <REF>финансы SET]
COMMAND-3 [COMMAND Для каждого района из <REF>конкуренты_данные
посчитай индекс привлекательности:
(плотность_населения * средний_чек) / (конкуренты + 1)
RESULT индексы: List[number] SET]
[END_SEQUENTIAL_BLOCK]
[IF <REF>финансы.стартовый_капитал < 1000000]
COMMAND-4 [COMMAND Выбери районы где индекс > 70 И конкуренты < 5
RESULT топ_районы: List[Район] SET]
[ELSE]
COMMAND-5 [COMMAND Выбери районы где индекс > 50
RESULT топ_районы: List[Район] SET]
[END_IF]
[SEQUENTIAL_BLOCK]
COMMAND-6 [COMMAND Сгенерируй рекомендацию на основе <REF>топ_районы:
- Топ-3 района
- Обоснование выбора каждого
- Оценка стартовых инвестиций
- Риски и возможности
RESULT <REF>рекомендация SET]
COMMAND-7 [DISPLAY <REF>рекомендация]
[END_SEQUENTIAL_BLOCK]
[END_MAIN_FLOW]
[END_WORKER]
[END_AGENT]
Результат:
Модель выполнит последовательность действий:
- Вызовет API Яндекс.Еды (симуляция) для получения данных по районам
- Загрузит финансы из Google Sheets (симуляция)
- Посчитает индекс привлекательности для каждого района
- В зависимости от бюджета (<1M или >1M рублей) отфильтрует районы по разным критериям
- Сгенерирует структурированную рекомендацию: топ-3 района с обоснованием, оценкой инвестиций и рисков
- Выведет финальную рекомендацию
Вся логика — условия, вызовы API, передача данных — явно прописана в промпте. Модель не додумывает что делать, а следует чёткому workflow.
Почему это работает
Слабость LLM: Неструктурированный текст промпта допускает множественные интерпретации. Когда в промпте смешаны роль, ограничения, переменные, условия — модель может:
- Неправильно понять какие данные нужны на входе
- Пропустить проверку условия
- Использовать переменную до её определения
- Перепутать типы данных (текст вместо числа)
Чем сложнее промпт, тем выше риск. LLM "читает" текст линейно, но структура workflow не очевидна.
Сильная сторона LLM: Модели отлично следуют явным структурированным инструкциям. Если чётко сказать "сначала вызови API_A, результат сохрани в переменную X типа число, потом если X > 100 то сделай Y" — модель выполнит точно. LLM любит когда границы модулей выделены, типы указаны, порядок действий пронумерован.
Как CNL-P использует сильную сторону:
- Формальная структура устраняет двусмысленность —
[DEFINE_PERSONA:]...[END_PERSONA]явно отделяет роль от инструкций. Модель знает "это описание роли, это не команда к действию". - Явные типы предотвращают ошибки — если переменная
budget: number, модель не попытается записать туда текст. Это как type hints в Python — подсказка для интерпретатора. - Ссылки
<REF>делают зависимости видимыми — когда команда используетvariable, модель понимает "эта переменная должна быть определена ранее". Как import в коде. - Sequential/IF блоки задают порядок выполнения — модель не додумывает что делать дальше, а следует workflow. Как функция с чёткими шагами.
Рычаги управления промптом:
- Секции PERSONA/CONSTRAINTS → меняй роль и ограничения под задачу (аналитик vs креативщик)
- Типы в TYPES/VARIABLES → добавь сложные структуры если данные многоуровневые
- IF-условия → настрой логику ветвления (пороги, критерии)
- COMMAND-индексы → измени порядок шагов
- API-вызовы → замени реальные API на симуляцию для тестирования
- RESULT SET/APPEND → контролируй как сохраняются промежуточные результаты
Шаблон промпта
[DEFINE_AGENT: {имя_агента}]
[DEFINE_PERSONA:]
ROLE: {описание роли и экспертизы}
{дополнительные_аспекты}: {описание}
[END_PERSONA]
[DEFINE_CONSTRAINTS:]
{ограничение_1}: {что нельзя или обязательно}
{ограничение_2}: {что нельзя или обязательно}
[END_CONSTRAINTS]
[DEFINE_TYPES:]
{СложныйТип} = {
{поле_1}: {тип},
{поле_2}: {тип}
}
[END_TYPES]
[DEFINE_VARIABLES:]
"{описание назначения}" {переменная_1}: {тип}
"{описание назначения}" {переменная_2}: {тип}
[END_VARIABLES]
[DEFINE_WORKER: {имя_воркера}]
[INPUTS]
<REF>{входная_переменная}
[END_INPUTS]
[OUTPUTS]
<REF>{выходная_переменная}
[END_OUTPUTS]
[MAIN_FLOW]
[SEQUENTIAL_BLOCK]
COMMAND-1 [COMMAND {описание действия} RESULT {переменная}: {тип} SET]
COMMAND-2 [CALL {api_имя} WITH {{параметр}: {значение}} RESPONSE {переменная}: {тип} SET]
[END_SEQUENTIAL_BLOCK]
[IF {условие с <REF>переменная}]
COMMAND-3 [COMMAND {действие при истине}]
[ELSEIF {другое условие}]
COMMAND-4 [COMMAND {действие при другой истине}]
[ELSE]
COMMAND-5 [COMMAND {действие по умолчанию}]
[END_IF]
[SEQUENTIAL_BLOCK]
COMMAND-6 [DISPLAY {что показать пользователю}]
[END_SEQUENTIAL_BLOCK]
[END_MAIN_FLOW]
[END_WORKER]
[END_AGENT]
Что подставлять:
{имя_агента}— краткое имя без пробелов (МаркетАнализатор){описание роли}— кто этот агент, какая экспертиза{ограничение}— формат, лимиты, запреты{СложныйТип}— если данные структурированы (например, Клиент с полями имя/возраст/email){переменная}: {тип}— имя переменной и её тип (text,number,boolean,List[тип], или вашСложныйТип){api_имя}— имя API для вызова (может быть фиктивным, модель симулирует)переменная— ссылка на ранее определённую переменнуюRESULT переменная: тип SET— сохранение результата команды в переменную
Упрощённые типы:
text— текстnumber— числоboolean— true/falseList[тип]— список элементов типа
🚀 Быстрый старт — вставь в чат:
Вот шаблон CNL-P для создания формализованного агента. Адаптируй его под мою задачу: [твоя задача].
Задавай вопросы, чтобы заполнить все секции корректно.
[вставить шаблон выше]
LLM спросит какие входные данные нужны, какие API вызывать, какая логика ветвления — потому что CNL-P требует явного определения всех элементов workflow. Модель возьмёт структуру шаблона и заполнит конкретными значениями под твою задачу.
Важно: CNL-P — это не просто текстовый шаблон, это формальный язык с синтаксисом. Модель интерпретирует [DEFINE_PERSONA:] не как текст, а как инструкцию "следующий блок — определение роли". Поэтому структура критична — не меняй ключевые слова в [ ].
Ограничения
⚠️ Сложность для новичков: Полный синтаксис CNL-P требует понимания формальных языков (BNF-грамматика). Не-программисты могут столкнуться с барьером при создании промптов с нуля. Linting tool требует технических навыков для интерпретации ошибок.
⚠️ Избыточность для простых задач: Для one-shot вопросов ("перефразируй текст", "предложи идеи") формализация CNL-P избыточна. Проще использовать обычный NL-промпт. CNL-P оправдан когда нужны условия, API-вызовы, многошаговая логика.
⚠️ Зависимость от transformer agent: Для конвертации NL → CNL-P нужен специальный агент (в исследовании использовали LLM с промптом-конвертером). Без него создание CNL-P вручную трудозатратно. При этом конвертер может не всегда корректно интерпретировать сложные требования.
⚠️ Linting tool не в чате: Статический анализ (проверка типов, синтаксиса) работает вне ChatGPT/Claude — нужен отдельный инструмент. В обычном чате LLM может пропустить ошибки в CNL-P структуре. Linting показал 100% точность vs 76% у GPT-4o, но это внешний инструмент.
⚠️ Не заменяет код для реальной интеграции: CNL-P описывает workflow, но не выполняет реальные API-вызовы. Для интеграции с Яндекс.Едой, Google Sheets нужен код на Python/JS. CNL-P — это "спецификация агента", не исполняемая программа (пока).
Как исследовали
Исследователи взяли 93 популярных промпта из GitHub (репозиторий "Awesome ChatGPT Prompts" с 113K звёзд) и конвертировали каждый в три формата: CNL-P, RISEN (известный NL-шаблон), RODES (другой NL-шаблон). Затем оценили по пяти критериям: соответствие оригиналу, модульность, расширяемость, читаемость, строгость процесса.
Три группы оценивали независимо:
- GPT-4o — без объяснений про CNL-P, просто оценка по критериям (0-100 баллов)
- Техническая группа — 4 программиста с 4+ годами опыта (low/medium/high оценка на 30 промптах)
- Нетехническая группа — 2 человека из образования и бизнеса (тоже low/medium/high)
Результаты удивили: CNL-P намного опережал RISEN и RODES в техгруппе по модульности (+30-40%) и строгости процесса (+25-35%). Интересно, что нетехническая группа оценила CNL-P ближе к LLM — обе группы видели преимущества структурированности, но технари ценили это сильнее. GPT-4o показал среднее мнение между двумя группами.
Почему CNL-P выиграл: Технари отметили что RISEN сужает область применения агента из-за секции "Expectation" (ожидания) — она делает агента заточенным под конкретную задачу. CNL-P же определяет general-purpose агента с чётким workflow, который можно переиспользовать. Нетехнари снизили оценку CNL-P за читаемость — им потребовалось время на понимание TYPES и VARIABLES, хотя структура визуально понравилась.
Вторая часть: Проверили понимает ли LLM CNL-P без объяснений. Взяли 6 classification tasks (от простых до сложных, включая математические задачи) из датасета Natural Instructions. Прогнали через 5 моделей (GPT-4o, Gemini-1.5-Pro, GPT-4o-Mini, Llama3-70B, Claude-3-Haiku) с промптами в 4 форматах: NL, CNL-P, RISEN, RODES.
Вывод: CNL-P показал сопоставимые результаты с NL (разница <5% по accuracy почти везде). Это значит LLM понимает структуру CNL-P интуитивно — не нужны Few-Shot примеры или объяснения синтаксиса. Более того, на сложных задачах (математика, многошаговый reasoning) CNL-P иногда превосходил NL за счёт явного workflow.
Третья часть: Тестировали linting tool — статический анализатор CNL-P. Создали 47 тестовых случаев с ошибками (неправильные типы, несуществующие переменные, нарушение синтаксиса). Сравнили точность linting tool vs GPT-4o в обнаружении ошибок.
Результат шокирует: Linting tool — 100% точность, 0% false positives. GPT-4o — 76.6% точность, 19% false positives (придумывал ошибки которых не было). Причина: linting работает программно (парсинг JSON-структуры CNL-P, проверка типов через Pydantic), а LLM "додумывает" из-за вероятностной природы.
Инсайт для практики: Это первая работа о статическом анализе NL-промптов. Показывает что промпты можно проверять как код — до отправки в модель. Снижает риск ошибок в продакшене (когда промпт — часть критического workflow).
Оригинал из исследования
Контекст: Исследователи дали пример CNL-P агента для фитнес-ассистента. Это полный синтаксис CNL-P — дословно из paper (Figure 15 в Appendix).
[DEFINE_AGENT: FITNESS_ADVISOR]
[DEFINE_PERSONA:]
ROLE: Fitness and health assistant providing workout routines and diet plans.
EXPERTISE: Exercise science, nutrition, wellness coaching
GUIDELINES: Share only safe and verified health tips, avoiding harmful content
[END_PERSONA]
[DEFINE_CONSTRAINTS:]
SAFETY: No extreme diets or dangerous exercises
SCOPE: Focus on general fitness, not medical diagnosis
LANGUAGE: Clear, encouraging, non-judgmental
[END_CONSTRAINTS]
[DEFINE_TYPES:]
UserAccountFitness = {
age: number,
weight: number,
height: number,
fitness_goal: [lose_weight, gain_muscle, maintain, improve_endurance],
activity_level: [sedentary, lightly_active, moderately_active, very_active]
}
WorkoutPlan = {
duration_weeks: number,
exercises: List[text],
frequency_per_week: number
}
DietPlan = {
daily_calories: number,
macros: {protein: number, carbs: number, fats: number},
meal_suggestions: List[text]
}
[END_TYPES]
[DEFINE_VARIABLES:]
"User's fitness profile" _user_account_fitness: UserAccountFitness
"Generated workout plan" _workout_plan: WorkoutPlan
"Generated diet plan" _diet_plan: DietPlan
[END_VARIABLES]
[DEFINE_WORKER: FitnessPlanGenerator]
[INPUTS]
<REF>_user_account_fitness
[END_INPUTS]
[OUTPUTS]
<REF>_workout_plan
<REF>_diet_plan
[END_OUTPUTS]
[MAIN_FLOW]
[SEQUENTIAL_BLOCK]
COMMAND-1 [CALL get_workout_plan WITH {
user: <REF>_user_account_fitness,
preference: "home_workout"
} RESPONSE <REF>_workout_plan SET]
COMMAND-2 [CALL get_diet_plan WITH {
user: <REF>_user_account_fitness,
preference: "balanced"
} RESPONSE <REF>_diet_plan SET]
[END_SEQUENTIAL_BLOCK]
[IF <REF>_user_account_fitness.fitness_goal == lose_weight]
COMMAND-3 [COMMAND Adjust <REF>_diet_plan.daily_calories to
create 500 calorie deficit based on <REF>_user_account_fitness.weight
RESULT <REF>_diet_plan SET]
[ELSEIF <REF>_user_account_fitness.fitness_goal == gain_muscle]
COMMAND-4 [COMMAND Increase <REF>_diet_plan.macros.protein to
2g per kg of <REF>_user_account_fitness.weight
RESULT <REF>_diet_plan SET]
[END_IF]
[SEQUENTIAL_BLOCK]
COMMAND-5 [DISPLAY Workout plan: <REF>_workout_plan]
COMMAND-6 [DISPLAY Diet plan: <REF>_diet_plan]
COMMAND-7 [DISPLAY Motivational message based on <REF>_user_account_fitness.fitness_goal]
[END_SEQUENTIAL_BLOCK]
[END_MAIN_FLOW]
[END_WORKER]
[END_AGENT]
Ключевые элементы оригинала:
- Энумы в типах —
fitness_goal: [lose_weight, gain_muscle, ...]задаёт allowed values - Вложенные структуры —
macros: {protein: number, ...}внутриDietPlan - Условная логика по значению —
IF variable == valueпроверяет конкретное значение - Математические операции — "создай дефицит 500 калорий" в COMMAND-3
- API-симуляция —
CALL get_workout_planможет быть реальным API или просто инструкцией модели сгенерировать план
Это production-ready структура — можно копировать, менять типы/переменные под свою задачу, добавлять новые COMMAND или IF-блоки.
Адаптации и экстраполяции
💡 Адаптация: CNL-P для личных финансов
Та же структура, другая задача — управление личным бюджетом. Агент анализирует траты (из банковского API), категоризует, выдаёт рекомендации.
[DEFINE_AGENT: БюджетАнализатор]
[DEFINE_PERSONA:]
ROLE: Финансовый советник для личных финансов
EXPERTISE: Бюджетирование, анализ трат, финансовое планирование
[END_PERSONA]
[DEFINE_TYPES:]
Транзакция = {
дата: text,
сумма: number,
категория: [еда, транспорт, развлечения, жильё, другое],
описание: text
}
Бюджет = {
месяц: text,
доход: number,
траты_по_категориям: {еда: number, транспорт: number, ...},
экономия: number
}
[END_TYPES]
[DEFINE_VARIABLES:]
"Список транзакций за месяц" транзакции: List[Транзакция]
"Анализ бюджета" бюджет: Бюджет
"Рекомендации" советы: text
[END_VARIABLES]
[DEFINE_WORKER: АнализБюджета]
[MAIN_FLOW]
[SEQUENTIAL_BLOCK]
COMMAND-1 [CALL bank_api WITH {month: "текущий"}
RESPONSE <REF>транзакции SET]
COMMAND-2 [COMMAND Для каждой транзакции из <REF>транзакции
суммируй по категориям
RESULT <REF>бюджет.траты_по_категориям SET]
[END_SEQUENTIAL_BLOCK]
[IF <REF>бюджет.траты_по_категориям.еда > 30000]
COMMAND-3 [COMMAND Создай совет: "Траты на еду превышают норму (30к₽).
Рассмотри готовку дома вместо доставки."
RESULT <REF>советы APPEND]
[END_IF]
[SEQUENTIAL_BLOCK]
COMMAND-4 [DISPLAY Бюджет: <REF>бюджет]
COMMAND-5 [DISPLAY Советы: <REF>советы]
[END_SEQUENTIAL_BLOCK]
[END_MAIN_FLOW]
[END_WORKER]
[END_AGENT]
Изменения: Другие типы (Транзакция, Бюджет), другой API (bank_api), другая логика условий (проверка лимитов по категориям). Структура та же — PERSONA, TYPES, VARIABLES, WORKER с IF-блоками.
🔧 Техника: Добавить DEBUG-режим → видеть промежуточные шаги
По умолчанию CNL-P показывает только финальный результат (команды с DISPLAY). Чтобы видеть каждый шаг — добавь DISPLAY после каждой команды с RESULT.
[SEQUENTIAL_BLOCK]
COMMAND-1 [CALL yandex_eda_api WITH {...} RESPONSE данные: List[Район] SET]
COMMAND-1.1 [DISPLAY DEBUG: Получено районов: <REF>данные]
COMMAND-2 [COMMAND Посчитай индексы RESULT индексы: List[number] SET]
COMMAND-2.1 [DISPLAY DEBUG: Индексы: <REF>индексы]
[END_SEQUENTIAL_BLOCK]
Эффект: LLM будет выводить промежуточные результаты после каждой команды. Полезно для отладки сложных workflow — видишь где именно логика ломается.
🔧 Техника: Сделать условия гибкими → параметризация порогов
Жёсткие пороги в IF (> 1000000) неудобны — каждый раз менять промпт. Вынеси в переменные:
[DEFINE_VARIABLES:]
"Порог бюджета для разных стратегий" порог_бюджета: number
"Минимальный индекс района" мин_индекс: number
[END_VARIABLES]
[IF <REF>финансы.стартовый_капитал < <REF>порог_бюджета]
COMMAND-4 [COMMAND Выбери районы где индекс > <REF>мин_индекс]
[END_IF]
Эффект: Теперь достаточно изменить значения порог_бюджета и мін_индекс в INPUTS — логика IF подстраивается автоматически. Переиспользование промпта для разных сценариев без изменения workflow.
🔧 Техника: Добавить валидацию входных данных → защита от ошибок
CNL-P не проверяет корректность входных данных по умолчанию. Добавь VALIDATION_BLOCK в начало MAIN_FLOW:
[MAIN_FLOW]
[SEQUENTIAL_BLOCK]
COMMAND-0 [COMMAND Проверь что <REF>финансы.стартовый_капитал > 0
И <REF>районы содержит хотя бы 1 элемент
RESULT валидация: boolean SET]
[END_SEQUENTIAL_BLOCK]
[IF <REF>валидация == false]
COMMAND-ERR [DISPLAY Ошибка: некорректные входные данные]
[EXIT]
[END_IF]
[SEQUENTIAL_BLOCK]
... # основная логика
[END_SEQUENTIAL_BLOCK]
[END_MAIN_FLOW]
Эффект: Агент не выполнит workflow если входные данные битые. Early exit вместо краша посередине.
💡 Экстраполяция: Комбинация CNL-P + Memory для long-running агентов
CNL-P описывает stateless workflow — каждый запуск независим. Но можно добавить memory через специальную переменную _session_state:
[DEFINE_TYPES:]
СостояниеСессии = {
история_запросов: List[text],
контекст: text,
предыдущие_рекомендации: List[text]
}
[END_TYPES]
[DEFINE_VARIABLES:]
"Состояние между запусками" _session_state: СостояниеСессии
[END_VARIABLES]
[MAIN_FLOW]
[SEQUENTIAL_BLOCK]
COMMAND-1 [COMMAND Загрузи <REF>_session_state из хранилища
RESULT <REF>_session_state SET]
COMMAND-2 [COMMAND Добавь текущий запрос в <REF>_session_state.история_запросов
RESULT <REF>_session_state SET]
... # основная логика с учётом контекста
COMMAND-N [COMMAND Сохрани обновлённый <REF>_session_state в хранилище]
[END_SEQUENTIAL_BLOCK]
[END_MAIN_FLOW]
Эффект: Агент помнит предыдущие взаимодействия. Например, фитнес-ассистент видит что пользователь уже спрашивал про диету → не повторяет информацию, а углубляет.
Комбинация с CNL-P: Memory — это просто специальная переменная типа "история". CNL-P workflow загружает её в начале, обновляет, сохраняет в конце. Stateful агент на базе stateless языка.
Ресурсы
Оригинальная работа: "When Prompt Engineering Meets Software Engineering: CNL-P as Natural and Robust "APIs" for Human-AI Interaction" — Zhenchang Xing, Yang Liu, Zhuo Cheng, Qing Huang, Dehai Zhao, Daniel Sun, Chenhua Liu (2025, ICLR)
Авторы из:
- CSIRO's Data61 (Австралия) — Zhenchang Xing, Dehai Zhao
- Jiangxi Normal University (Китай) — Yang Liu, Zhuo Cheng, Qing Huang, Chenhua Liu
- Newcastle University (UK) — Daniel Sun
Ключевые отсылки из исследования:
- RISEN framework — популярный NL-шаблон для промптов (Role, Input, Steps, Expectation, Narrowing)
- RODES framework — другой NL-шаблон (Role, Objective, Details, Examples, Sense Check)
- TypeChat (Microsoft) — вдохновение для type checking в CNL-P
- Pydantic — используется в linting tool для валидации типов Python
- DSPy, LangChain, Semantic Kernel — PL-based методы для управления промптами (CNL-P позиционируется как альтернатива)
GitHub репозиторий: github.com/Irasoo/CNL-P — содержит код linting tool, примеры промптов, датасеты экспериментов
