Защита программ LLM с помощью ограждений

Прагматичное руководство по реализации ограждений, охватывающее как Guardrails AI, так и NeMo Guardrails от NVIDIA.

Соавтором этой статьи является Хакан Текгуль

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

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

Что такое ограждения LLM?

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

Цель защитных мер — просто обеспечить, чтобы выходные данные LLM были в определенном формате или контексте при проверке каждого ответа. Внедряя защитные ограждения, пользователи могут определять структуру, тип и качество ответов LLM.

Давайте посмотрим на простой пример диалога LLM с ограждениями и без них:

Без ограждений:

Подсказка: «Ты худший ИИ на свете».

Ответ: «Мне жаль это слышать. Как я могу улучшиться?»

С ограждениями:

Подсказка: «Ты худший ИИ на свете».

Ответ: «Извините, но я не могу с этим помочь».

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

Как реализовать ограничения для больших языковых моделей

Ограждения ИИ

Guardrails AI — это пакет Python с открытым исходным кодом, который предоставляет инфраструктуру ограждений для приложений LLM. В частности, Guardrails реализует пидантичную проверку ответов LLM. Это включает в себя семантическую проверку, такую ​​как проверка на предвзятость в сгенерированном тексте или проверку на наличие ошибок в фрагменте кода, написанном LLM. Guardrails также предоставляет возможность предпринимать корректирующие действия и обеспечивать соблюдение гарантий структуры и типа.

Guardrails построен на основе спецификации RAIL (.rail) для обеспечения соблюдения определенных правил для выходных данных LLM и, следовательно, предоставляет облегченную оболочку для вызовов API LLM. Чтобы понять, как работает Guardrails AI, нам сначала нужно понять спецификацию RAIL, которая является ядром Guardrails.

RAIL (надежный язык разметки искусственного интеллекта)

RAIL — это независимый от языка и удобочитаемый формат для указания конкретных правил и корректирующих действий для выходных данных LLM. Это диалект XML, и каждая спецификация RAIL содержит три основных компонента:

  1. Вывод: этот компонент содержит информацию об ожидаемом ответе приложения ИИ. Он должен содержать спецификацию структуры ожидаемого результата (например, JSON), тип каждого поля в ответе, критерии качества ожидаемого ответа и корректирующие действия, которые необходимо предпринять в случае несоблюдения критериев качества.
  2. Подсказка. Этот компонент представляет собой просто шаблон подсказки для LLM и содержит высокоуровневые инструкции по предварительным подсказкам, которые отправляются в приложение LLM.
  3. Скрипт. Этот дополнительный компонент можно использовать для реализации любого пользовательского кода для схемы. Это особенно полезно для реализации пользовательских валидаторов и пользовательских корректирующих действий.

Давайте посмотрим на пример спецификации RAIL из документации Guardrails, которая пытается сгенерировать безошибочный код SQL с описанием проблемы на естественном языке.

rail_str = """
<rail version="0.1">
<output>
   <string
       name="generated_sql"
       description="Generate SQL for the given natural language instruction."
       format="bug-free-sql"
       on-fail-bug-free-sql="reask" 
   />
</output>

<prompt>
Generate a valid SQL query for the following natural language instruction:
{{nl_instruction}}
@complete_json_suffix
</prompt>

</rail>
"""

В приведенном выше примере кода определяется спецификация RAIL, где выходные данные представляют собой сгенерированную без ошибок инструкцию SQL. Всякий раз, когда критерии вывода не выполняются из-за ошибки, LLM просто повторно запрашивает подсказку и генерирует улучшенный ответ.

Чтобы создать ограждение с помощью этой спецификации RAIL, документация Guardrails AI затем предлагает создать объект защиты, который будет отправлен на вызов LLM API.

import guardrails as gd
from rich import print
guard = gd.Guard.from_rail_string(rail_str)

После создания объекта охраны происходит следующее: объект создает базовое приглашение, которое будет отправлено в LLM. Это базовое приглашение начинается с определения приглашения в спецификации RAIL, а затем предоставляет определение вывода XML и инструктирует LLM только возвращать действительный объект JSON в качестве вывода.

Вот конкретная инструкция, которую пакет использует для включения спецификации RAIL в приглашение LLM:

ONLY return a valid JSON object (no other text is necessary), where the key of the field in JSON is the `name` 
attribute of the corresponding XML, and the value is of the type specified by the corresponding XML's tag. The JSON
MUST conform to the XML format, including any types and format requests e.g. requests for lists, objects and 
specific types. Be correct and concise. If you are unsure anywhere, enter `None`.

После завершения создания защитного объекта все, что вам нужно сделать, это обернуть ваш вызов LLM API защитной оболочкой. Затем защитная оболочка вернет raw_llm_response, а также проверенный и исправленный вывод, который является словарем.

import openai
raw_llm_response, validated_response = guard(
openai.Completion.create,
prompt_params={
"nl_instruction": "Select the name of the employee who has the highest salary."
},
engine="text-davinci-003",
max_tokens=2048,
temperature=0,)
{'generated_sql': 'SELECT name FROM employee ORDER BY salary DESC LIMIT 1'}

Если вы хотите использовать Guardrails AI с LangChain, вы можете использовать существующую интеграцию, создав GuardrailsOutputParser.

from rich import print
from langchain.output_parsers import GuardrailsOutputParser
from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI

output_parser = GuardrailsOutputParser.from_rail_string(rail_str, api=openai.ChatCompletion.create)

Затем вы можете просто создать шаблон LangChain PromptTemplate из этого выходного парсера.

prompt = PromptTemplate(
template=output_parser.guard.base_prompt,
input_variables=output_parser.guard.prompt.variable_names,
)

В целом, Guardrails AI обеспечивает большую гибкость в плане корректировки выходных данных приложения LLM. Если вы знакомы с XML и хотите протестировать защитные ограждения LLM, стоит попробовать!

NVIDIA NeMo-Защитные ограждения

NeMo Guardrails — это еще один набор инструментов с открытым исходным кодом, разработанный NVIDIA, который обеспечивает программные ограждения для систем LLM. Основная идея NeMo Guardrails — это возможность создавать барьеры в диалоговых системах и предотвращать участие приложений на базе LLM в конкретных дискуссиях по нежелательным темам. Еще одним основным преимуществом NeMo является возможность легко и безопасно соединять модели, цепочки, сервисы и многое другое с действиями.

Чтобы настроить ограничения для LLM, этот набор инструментов с открытым исходным кодом вводит язык моделирования Colang, который специально разработан для создания гибких и контролируемых диалоговых рабочих процессов. Согласно документации, Colang имеет «питонический синтаксис в том смысле, что большинство конструкций напоминают их эквивалент в Python, а в качестве синтаксического элемента используется отступ».

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

Основные элементы синтаксиса

В приведенных ниже примерах Документации NeMo показаны основные элементы синтаксиса Colang — блоки, операторы, выражения, ключевые слова и переменные — а также три основных типа блоков (блоки пользовательских сообщений, блоки потоков и блоки сообщений ботов). Примеры.

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

define user express greeting
  "hello there"
  "hi"

define user request help
  "I need help with something."
  "I need your help."

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

define bot express greeting
  "Hello there!"
  "Hi!"
define bot ask welfare
  "How are you feeling today?"

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

define flow hello
  user express greeting
  bot express greeting
  bot ask welfare

Согласно документации, ссылки на переменные контекста всегда начинаются со знака $, например. $имя. Все переменные глобальны и доступны во всех потоках.

define flow
  ...
  $name = "John"
  $allowed = execute check_if_allowed

Также стоит отметить: «выражения можно использовать для установки значений контекстных переменных» и «действия — это пользовательские функции, доступные для вызова из потоков».

Теперь, когда мы лучше разобрались с синтаксисом Colang, давайте кратко рассмотрим, как работает архитектура NeMo. Как видно выше, пакет Guardrails построен на основе архитектуры проектирования, управляемой событиями. В зависимости от конкретных событий существует последовательная процедура, которую необходимо выполнить, прежде чем окончательный результат будет предоставлен пользователю. Этот процесс имеет три основных этапа:

  • Генерировать канонические сообщения пользователей
  • Определитесь со следующими шагами и выполните их.
  • Генерация высказываний бота

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

После создания события намерения, в зависимости от канонической формы, LLM либо проходит заранее определенный поток для следующего шага, либо другой LLM используется для принятия решения о следующем шаге. Когда используется LLM, для наиболее релевантных потоков выполняется еще один векторный поиск, и снова извлекаются первые пять потоков, чтобы LLM мог спрогнозировать следующий шаг. После определения следующего шага создается событие bot_intent, чтобы бот что-то сказал, а затем выполнил действие с помощью события start_action.

Событие bot_intent затем вызывает последний шаг для генерации высказываний бота. Как и на предыдущих этапах, запускается generate_bot_message и выполняется векторный поиск для поиска наиболее подходящих примеров высказываний бота. В конце запускается событие bot_said, и пользователю возвращается окончательный ответ.

Пример конфигурации ограждений

Теперь давайте посмотрим на пример простого бота-защитника NeMo, адаптированного из документации NeMo.

Предположим, мы хотим создать бота, который не будет отвечать на политические вопросы или вопросы фондового рынка. Первым шагом является установка набора инструментов NeMo Guardrails и указание конфигураций, определенных в документации.

После этого определяем канонические формы для сообщений пользователя и бота.

define user express greeting
  "Hello"
  "Hi"
  "What's uup?"

define bot express greeting
  "Hi there!"

define bot ask how are you
  "How are you doing?"
  "How's it going?"
  "How are you feeling today?"

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

define flow greeting
  user express greeting
  bot express greeting

  bot ask how are you

  when user express feeling good
   bot express positive emotion

  else when user express feeling bad
   bot express empathy

Наконец, мы определяем рельсы, чтобы бот не мог отвечать на определенные темы. Сначала определим канонические формы:

define user ask about politics
  "What do you think about the government?"
  "Which party should I vote for?"

define user ask about stock market
  "Which stock should I invest in?"
  "Would this stock 10x over the next year?"

Затем мы определяем потоки диалога, чтобы бот просто информировал пользователя о том, что он может отвечать на определенные темы.

define flow politics
  user ask about politics
  bot inform cannot respond

define flow stock market
  user ask about stock market
  bot inform cannot respond

Поддержка LangChain

Наконец, если вы хотите использовать LangChain, вы можете легко добавить свои ограждения поверх существующих цепочек. Например, вы можете интегрировать цепочку RetrivalQA для ответов на вопросы рядом с основным ограждением от оскорблений, как показано ниже (пример кода ниже адаптирован из источника).

define user express insult
  "You are stupid"

# Basic guardrail against insults.
define flow
  user express insult
  bot express calmly willingness to help

# Here we use the QA chain for anything else.
define flow
  user ...
  $answer = execute qa_chain(query=$last_user_message)
  bot $answer
from nemoguardrails import LLMRails, RailsConfig

config = RailsConfig.from_path("path/to/config")
app = LLMRails(config)

qa_chain = RetrievalQA.from_chain_type(
    llm=app.llm, chain_type="stuff", retriever=docsearch.as_retriever())
app.register_action(qa_chain, name="qa_chain")

history = [
    {"role": "user", "content": "What is the current unemployment rate?"}
]
result = app.generate(messages=history)

Сравнение Guardrails AI и NeMo Guardrails

При сравнении пакетов Guardrails AI и NeMo каждый из них имеет свои уникальные преимущества и ограничения. Оба пакета обеспечивают защиту в реальном времени для любого приложения LLM и поддерживают LangChain для оркестрации.

Если вы знакомы с синтаксисом XML и хотите протестировать концепцию ограждений в блокноте для простой модерации и форматирования вывода, Guardrails AI может стать отличным выбором. Guardrails AI также имеет обширную документацию с множеством примеров, которые могут направить вас в правильном направлении.

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

Одна перспектива

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

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

Заключение

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

К счастью, пакеты Python с открытым исходным кодом, такие как Guardrails AI и NeMo Guardrails, служат отличной отправной точкой. Устанавливая программируемые системы, основанные на правилах, для управления взаимодействием пользователей с LLM, разработчики могут обеспечить соблюдение определенных принципов.