priompt

by Anysphere (open source) · TypeScript / Node.js, OpenAI API, любой LLM с токенным лимитом

Skill AI Assistants Open Source v0.3.20

Priompt (priority + prompt) — библиотека для управления контекстным окном через приоритеты. Разработана командой Cursor: позволяет декларативно описать что должно попасть в промпт, и автоматически обрезает низкоприоритетный контент под токенный лимит. Возможности: - JSX-подобный синтаксис для компоновки промптов - Приоритеты: `<scope p={1}>` — высокоприоритетный блок всегда попадает - Автоматическая обрезка по токенному лимиту - Счётчик токенов через tiktoken - Preview-режим: посмотреть финальный промпт до отправки - TypeScript-типизация для всех компонентов - Используется в production в Cursor

v0.3.20
current
Добавлен 19.06.2026 · Обновлён 19.06.2026 · AI Assistants
Установка
# npm:
npm install @anysphere/priompt

# Пример:
import { render, scope, first } from "@anysphere/priompt";

const prompt = (
  <scope p={1}>
    <system>You are a helpful assistant.</system>
    <first>
      {recentMessages.map(m => <message role={m.role}>{m.content}</message>)}
    </first>
    <scope p={0.5}>
      {/* Этот блок обрежется первым при нехватке токенов */}
      <docs>{longDocumentation}</docs>
    </scope>
  </scope>
);

const rendered = await render(prompt, { tokenLimit: 4096 });
переведено ИИ

Priompt

Priompt (priority + prompt) — это JSX-библиотека для промптинга. Она использует приоритеты для решения, что включать в окно контекста.

Priompt — это попытка создать библиотеку дизайна промптов, вдохновлённую веб-библиотеками, такими как React. Подробнее о мотивации можно прочитать здесь.

Установка

Установка через npm:

npm install @anysphere/priompt && npm install -D @anysphere/priompt-preview

или

yarn add @anysphere/priompt && yarn add --dev @anysphere/priompt-preview

или

pnpm add @anysphere/priompt && pnpm add -D @anysphere/priompt-preview

Примеры

Прочитайте examples/README.md), чтобы запустить примеры.

Принципы

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

function ExamplePrompt(
  props: PromptProps<{
    name: string,
    message: string,
    history: { case: "user" | "assistant", message: string }[],
  }>
): PromptElement {
  const capitalizedName = props.name[0].toUpperCase() + props.name.slice(1);
  return (
    <>
      <SystemMessage>
        The user's name is {capitalizedName}. Please respond to them kindly.
      </SystemMessage>
      {props.history.map((m, i) => (
        <scope prel={-(props.history.length - i)}>
          {m.case === "user" ? (
            <UserMessage>{m.message}</UserMessage>
          ) : (
            <AssistantMessage>{m.message}</AssistantMessage>
          )}
        </scope>
      ))}
      <UserMessage>{props.message}</UserMessage>
      <empty tokens={1000} />
    </>
  );
}

Компонент рендерится только один раз. У каждого дочернего элемента есть приоритет, где более высокий приоритет означает, что элемент важнее для включения в промпт. Если приоритет не указан, элемент включается тогда и только тогда, когда включен его родитель. Абсолютные приоритеты указываются с помощью p, а относительные — с помощью prel.

В приведенном выше примере мы всегда включаем системное сообщение и последнее сообщение пользователя, а также включаем как можно больше сообщений из истории, где более поздние сообщения имеют приоритет над более ранними.

Ключевое обещание рендерера priompt:

Пусть $T$ — это лимит токенов, а $\text{Prompt}(p_\text{cutoff})$ — функция, создающая промпт путем включения всех областей (scope) с приоритетом $p_\text{scope} \geq p_\text{cutoff}$ и никаких других. Тогда отрендеренный промпт равен $\text{\textbf{P}} = \text{Prompt}(p_\text{opt-cutoff})$, где $p_\text{opt-cutoff}$ — минимальное значение такое, что $|\text{Prompt}(p_\text{opt-cutoff})| \leq T$.

Строительными блоками промпта priompt являются:

  1. <scope>: позволяет устанавливать абсолютные приоритеты p или относительные prel.
  2. <first>: первый дочерний элемент с достаточно высоким приоритетом будет включен, а все последующие дочерние элементы не будут. Это полезно для реализации резервных вариантов, например, фразы (результат опущен), когда результат слишком длинный.
  3. <empty>: для указания пустого пространства, полезно для выделения токенов под генерацию.
  4. <capture>: захватывает вывод и парсит его прямо внутри промпта.
  5. <isolate>: изолирует секцию промпта с собственным лимитом токенов. Это полезно для гарантии того, что начало промпта будет одинаковым для целей кэширования. Было бы неплохо расширить это, чтобы разрешить лимиты токенов вроде 100% - 100.
  6. <br/>: принудительно создает разрыв токена в определенном месте, что полезно для обеспечения точного совпадения токенизации между двумя частями промпта (например, при реализации такого функционала, как спекулятивные правки).
  7. <config>: позволяет указать несколько распространенных конфигурационных свойств, таких как токен остановки stop и maxResponseTokens, что может сделать дамп priompt более самодостаточным и помочь с оценкой (evals).

Вы можете создавать сколько угодно компонентов, точно так же, как в React. Встроенные компоненты:

  1. <UserMessage>, <AssistantMessage> и <SystemMessage>: для построения промптов на основе сообщений.
  2. <ImageComponent>: для добавления изображений в промпт.
  3. <Tools>, <ZTools>: для указания инструментов, которые ИИ может вызывать, используя JSON-схему или тип Zod.

Продвинутые возможности

  1. onEject и onInclude: колбэки, которые можно передать в любой scope. Они вызываются, когда область исключается или включается в финальный промпт. Это позволяет изменять логику в зависимости от того, слишком ли большой элемент для промпта.
  2. Исходные карты (Sourcemaps): при установке shouldBuildSourceMap в true рендерер вычисляет отображение между фактическими символами в промпте и частью дерева JSX, от которой они исходят. Это может быть полезно для определения источников промахов кэша в промпте.
  3. Добавьте префикс DO_NOT_DUMP к ключу ваших пропсов priompt, чтобы предотвратить его дамп. Это полезно для действительно больших объектов.

Будущее

Несколько вещей, которые было бы круто добавить:

  1. Блок <max>: указать лимит limit на количество токенов в области, но в отличие от <isolate>, включать вложенные области в глобальный расчет приоритетов.
  2. Высокооптимизированный рендеринг больших деревьев: минимизация времени, затрачиваемого на токенизацию — это часть решения, но другая часть — обход распределения объектов JavaScript, и возможно, написание всего движка рендеринга, например, на Rust, сделало бы его намного быстрее.

Предупреждения

  1. Мы обнаружили, что добавление приоритетов ко всему — это своего рода антипаттерн. Возможно, приоритеты — неправильная абстракция. Тем не менее, мы нашли их полезными для построчного включения длинных файлов в промпт.
  2. Рендерер Priompt не имеет встроенной поддержки для создания кэшируемых промптов. Если вы злоупотребляете приоритетами, легко создать промпты, которые трудно кэшировать, что может увеличить ваши затраты или задержку при инференсе LLM. Нас интересуют хорошие решения в этой области, но пока создателю промпта следует самостоятельно думать о кэшировании.
  3. Обновление: Исходные карты Priompt помогают в отладке кэширования!
  4. Текущая версия priompt поддерживает разумно быструю обработку примерно 10 000 областей (этого достаточно для большинства случаев использования). Если вы хотите включить в промпт очень длинный файл (>10 000 строк) и разбиваете его построчно, вам, вероятно, стоит реализовать что-то вроде: «для строк, находящихся на расстоянии более 1000 строк от позиции курсора, используем более грубые области по 10 строк за раз».
  5. Для критичных по задержке промптов вы должны следить за временем выполнения на панели предварительного просмотра priompt. Если областей слишком много, вам, возможно, потребуется оптимизация производительности.
  6. Рендерер Priompt не всегда гарантированно создает идеальный $p_\text{opt-cutoff}$. Например, если дочерний элемент <first> с более высоким приоритетом содержит больше токенов, чем дочерний элемент с более низким приоритетом, реализованный в данный момент рендерер с двоичным поиском может вернуть (очень незначительно) неточный результат.

Вклад

Мы очень приветствуем вклад! Весь этот репозиторий находится под лицензией MIT.

Комментарии
Войдите, чтобы оставить комментарий