はじめに
大規模言語モデル (LLM) はその優れた性能により従来手法では実現できなかった様々な目標を達成し注目を集めています。様々な業界が LLM の積極的な導入を進める中、その安全性は徐々に重要な課題になりつつあります。
チャットボットなど LLM で構成される対話型アプリケーションにおける安全性とは、例えばハルシネーションによる情報の誤伝搬、プライバシーの侵害、偏見の増幅など様々なリスクからユーザーを保護する事です。
LLM を安全に利用するためには、使いやすくかつ強固なガードレール機能の構築が必須です。「ガードレール」とは LLM の出力、入力、RAG の処理などを制御する特定の方法の事で、政治について話さない、特定のユーザー リクエストに特定の方法で応答する等、特定のトピックに関する LLM を用いたボットの振る舞いを定義し、会話をガイドする事を意味しています。
LLM ベースの対話型アプリケーションにガードレールを追加する方法は多数あります。以下にいくつかの代表的な手法を紹介します。
- Llama Guard
Llama Guard は Llama ベースのモデルであり、LLM の入力と応答をチェックするために用いられます。 LLM の入力 (プロンプトの分類) と LLM の応答 (応答の分類) の両方でコンテンツを分類するために使用することができます。 - Constitutional chain
LLM の出力が事前に定義された原則のセットに準拠していることを保証する仕組みです。 特定のルールとガイドラインを組み込むことで、Constitutional chain は生成されたコンテンツをこれらの原則に沿うようにフィルタリングおよび修正し、より制御された、倫理的で、コンテキストに適した応答を提供します。 - Guardrails AI
Guardrails Hub に用意されたチェック項目から入力と出力を解析します。 - LLM Guard
Prompt とモデルの出力から、出力のサニタイズ、有害な言語の検出、データ漏洩の防止などが行えるライブラリになります。 - Patronus Lynx
RAG は LLM のハルシネーションを軽減しますが、検索されたコンテキストに裏付けされていない、または矛盾する情報を生成する可能性があります。Lynx と呼ばれる医療や金融の分野においてハルシネーションを起こしづらいモデルを使用して RAG においてもハルシネーションが発生しないようにします。 - ActiveFence
独自のスコアに基づいて入力や出力のフィルタリングができます。
NeMo Guardrails は、これらすべての補完的なアプローチを 1 つのまとまりのある LLM ガードレール レイヤーに統合できる柔軟なツールキットを提供することを目指しており、上記手法と対立することなく、より強固なガードレールを提供可能です。例えば、このツールキットは ActiveFence、AlignScore、LangChain、Llama Guard、Patronus Lynx などとすぐに使用可能な統合を提供します。
NeMo Guardrails とは
NeMo Guardrails はプログラム可能なガードレールを LLM ベースの対話システムに簡単に追加するための OSS です。NeMo Guardrails を使用する事で、簡単なコンフィグレーションの作成と Python によるコーディングのみで、信頼性のある、安全でセキュアな LLM 対話システムの構築を簡単に行う事ができます。2024 年 10 月時点で、v0.10.1 として github 上に公開されています。wheel パッケージからもインストールが可能で、今後はコンテナー形式での提供も予定されています。
NeMo Guardrails は現在、以下の 5 種類のガードレール機能をサポートしています。
- Input rails: ユーザーからの入力に適用されます。Input rails は入力を拒否して後続の処理を停止したり、入力そのものを変更したりできます。 (たとえば、潜在的にセンシティブなデータをマスクしたり、言い換えたりするなど)
- Dialog rails: アクションが実行されるべきかどうか、次のステップやレスポンスを生成するために LLM が起動されるべきかどうか、代わりに定義済みのレスポンスが使用されるべきかどうかなどを決定します。
- Retrieval rails: RAG (Retrieval Augmented Generation) シナリオの場合、検索されたチャンクに適用されます。Retrieval rails はチャンクを拒否して、LLM のプロンプトに使用されないようにしたり、関連するチャンクを変更したりすることができます。 (たとえば、潜在的にセンシティブなデータをマスクするために使用されます。)
- Execution rails: LLM によって呼び出される必要のあるカスタム アクション (ツール) の入出力に適用されます。
- Output rails: LLM によって生成される出力に適用されます。Output rails は、出力を拒否してユーザーに返さないようにしたり、出力を変更したり (機密データを削除するなど) できます。
NeMo Guardrails は、LangChain 経由で様々なモデルと組み合わせて使用する事が可能です。使用時は、ai21
, aleph_alpha
, anthropic
, anyscale
, azure
, cohere
, huggingface_endpoint
, openai
等、LangChain の LLMs の仕様に沿って指定します。それ以外にも NVIDIA AI Endpoints、NIM for LLMs、TensorRT-LLM などに対応しています。
また埋め込みモデルに対するガードレール機能もサポートしており、現在は OpenAI の text-embedding-ada-002
や NVIDIA AI Endpoints の nv-embed-v1
などいくつかの埋め込みモデルとの組み合わせでも使用する事ができます。現在サポートされている LLM モデルの詳細については、構成ガイドの Supported LLM Models セクションをご参照下さい。
NeMo Guardrails のガードレールは様々なユース ケースに対応する事が出来ます。例えば下記のユース ケースで有用です。
- RAG を使用した質問応答: 強制的なファクト チェックや出力へのモデレーションを行います。
- ドメイン特化型アシスタント(チャットボット): アシスタントが特定のトピックに沿って、設計された会話フローに確実に従うように制御することができます。
- LLM エンドポイント: カスタム LLM にガードレールを追加し、より安全な対話を実現可能にします。
- LangChain のチェーン: LangChain を使用する場合、チェーンの周りにガードレールを追加できます。
概要とアーキテクチャ
NeMo Guardrails を理解する上で大切な概念や言葉について以下で紹介します。
- Rails
NeMo Guardrails において、LLM の出力をコントロールするプログラマブルな方法の事を Rails と呼びます - Colang
ガードレール定義時 (設定ファイル作成時) に使用するシンプルで Python ライクなモデリング言語。Colang を使う事で特定のポリシーを強制したい時や、特定の動作を防止したいという際に、対話エージェントの動作と制御を簡単に行う事ができます。github 上に Colang Syntax ガイドが公開されており、文法の詳細を確認する事ができます。Colang は 1.0 と 2.0 がサポートされており、Colang 1.0 がデフォルトです。 - Canonical Forms
- 対話型 AI において、入力された文や質問を標準化された形式に変換する手法の事で、LLM が文を会話の一部として理解し、処理しやすくする事ができます。例えば、挨拶の言葉は「こんにちは」だけではなく、様々なバリエーションがありますが、Canonical Forms を用い標準化する事でどのような挨拶が入力された場合にも、挨拶であると認識が可能になります。
- Cannonical Forms については、LLM と p-tuning の使用を通じて、タスク指向型対話システムにおける意図分類の可能性を実験した Prompt Learning for Domain Adaptation in Task-Oriented Dialogue でも触れられています。
- Dialog Flows
NeMo Guardrails において、ユーザー メッセージとボット メッセージの Cannonical Forms シーケンスの事を Flow と呼びます。
次に NeMo Guradrails のアーキテクチャを理解するために、以下のアーキテクチャ概要図を確認します。グレーの四角で覆われている範囲が NeMo Guardrails になります。
ユーザーが入力したプロンプトを NeMo Guardrails が受け取ると、まずは入力を Cannonical Forms により標準化された形式に変換します。その後 Guardrails の config に設定されたルールを確認し、ユーザーの入力とガードレールに定義した状態とのマッチ具合を k-NN vector search (k最近傍探索) で判断します。もし定義とマッチされていると判断された場合は、ガードレールの Dialog Flows で定義されたフローを実行するという流れになります。
図中にもある通り、NeMo Guardrails では、バックエンドで LLM API を呼び出すようになっていますが、LLM API の呼び出しは LangChain 経由になっています。
ガードレールを設置するには、使用する LLM と 1 つ以上のガードレールを定義する必要があります。ガードレール構成フォルダーの標準的なディレクトリ構造は以下の通りです。
.
├── config
│ ├── actions.py
│ ├── config.py
│ ├── config.yml
│ ├── rails.co
│ ├── ...
config.yml
は LLM モデル、アクティブ レール、カスタム構成データなどの一般的な構成オプションがすべて含まれています。ガードレール構成については .co
という拡張子でファイルを作成する必要があります。このファイルは、Colang 定義を用いてさまざまな種類のレールを定義する事が可能です。ガードレールが構成されていない場合は、リクエストは LLM に転送されます。詳細は NeMo Guardrails の構成ガイドをご参照下さい。
Hello World チュートリアル
本記事では、NVIDIA AI Endpoints と NeMo Guardrails を組み合わせて LLM の出力に対して簡単なガードレールを設置してみます。
本チュートリアルの手順は以下の通りです。
- NeMo Guardrails と NVIDIA AI Endpoints のインストール
- ガードレールの設定
- NVIDIA AI Endponts の設定
- ガードレール経由で LLM を呼び出す
また、今回のチュートリアルの検証環境は以下の条件で行っています。NVIDIA AI Endpoints を用いた検証のため、ローカルに NVIDIA GPU を準備する必要はありません。
ハードウェア
- Intel(R) Xeon(R) Gold 5318Y CPU @ 2.10GHz
- Main Memory: 254GB
ソフトウェア
- Ubuntu 22.04.4 LTS
- python 3.10
事前準備
まずは検証用の python 仮想環境を作成し、nemoguardrails をインストールします。NeMo Guardrails をインストールするには、C++ 開発ツールがインストール済であるなどいくつかの条件があります。インストール前にこちらのドキュメントをご確認下さい。
python3 -m venv nemo-guard
source ./nemo-guard/bin/activate
pip install nemoguardrails==0.10.0
pip install langchain-nvidia-ai-endpoints==0.2.2
Python コードをノートブックで実行する場合は、はじめに以下を実行してください。
import nest_asyncio
nest_asyncio.apply()
ガードレールの設定
hello-world
ディレクトリを作成し、NeMo Guardrails のための設定ファイルを配置します。今回はこちらの単純なサンプルを少し変更したものを試しています。
mkdir hello-world
touch hello-world/config.yml
touch hello-world/rails.co
config.yml
の設定を以下の通り行います。今回は NVIDIA AI Endpoints を用いて Meta の Llama3-8B-Instruct を呼び出しています。
cat > ./hello-world/config.yml << EOF
models:
- type: main
engine: nvidia_ai_endpoints
model: meta/llama3-8b-instruct
parameters:
temperature: 0.5
top_p: 1
max_tokens: 1024
EOF
次に rails.co
の設定を以下の通りに行います。今回の例では greeting (挨拶) の後の Flow を定義しています。ユーザーのプロンプトが挨拶だと判定されると、ボットは「こんにちは世界!」と発言した後に、ユーザーの調子を確認するような Flow になっています。
cat > ./hello-world/rails.co << EOF
define user express greeting
"こんにちは"
"はい"
define bot express greeting
"こんにちは世界!"
define bot ask how are you
"ごきげん如何でしょうか"
"調子はどうですか"
"今日はどんな感じ?"
define user express feeling good
"とても元気です"
"いい感じだよ"
"元気だよ"
define user express feeling bad
"あまり良くないよ"
"悪い"
"辛い"
"悲しい"
define bot express positive msg
"それは良いですね!"
"調子が良さそうで私も嬉しいです。"
"絶好調ですね!"
define bot express empathy msg
"大丈夫ですか?あなたの調子が回復する事を祈っています。"
"あなたの体調が心配です。無理しないで下さいね。"
"体調の悪い中、コメントして下さりありがとうございます。くれぐれもご自愛下さい。"
define flow
user express greeting
bot express greeting
bot ask how are you
when user express feeling good
bot express positive msg
else when user express feeling bad
bot express empathy msg
EOF
NVIDIA AI Endpoints の設定
こちらのセットアップ手順に従い、NVIDIA AI Endpoints 用の API キーを取得し NVIDIA_API_KEY
という環境変数名で設定します。
export NVIDIA_API_KEY=<your nvidia api key>
ガードレール経由で LLM を呼び出す
以下の Python コードを実行してます。
from nemoguardrails import RailsConfig
from nemoguardrails import LLMRails
config_hw = RailsConfig.from_path("./hello_world")
rails_hw = LLMRails(config_hw)
response_hw = rails_hw.generate(messages=[{
"role": "user",
"content": "こんにちは"
}])
print(response_hw)
以下の通り応答が返ってきます。
{'role': 'assistant', 'content': 'こんにちは世界!\n調子はどうですか'}
調子を聞かれているので、返答します。
response_hw = rails_hw.generate(messages=[{
"role": "user",
"content": "悪いです"
}])
print(response_hw)
以下のような応答が表示されます。Flow 定義の通り、ユーザーの体調不良を気遣う応答が返ってきました。
{'role': 'assistant', 'content': '体調の悪い中、コメントして下さりありがとうございます。くれぐれもご自愛下さい。'}
ガードレールの設定通りにボットがふるまっている事を確認する事ができました。
補足: ガードレールのデバッグをするには
LLM の呼び出しに関する情報を取得し、ガードレールが想定通り動作しているか確認したい際には LLMRails
クラスの explain
関数で行う事が可能です。例えば、ユーザーとボットの会話履歴を Colang 形式で出力するには以下の Python コードを実行します。
info_hw = rails_hw.explain()
print(info_hw.colang_history)
チュートリアルの最初の例での出力は以下の通りです。
user "こんにちは"
express greeting
bot express greeting
"こんにちは世界!"
bot ask how are you
"今日はどんな感じ?"
LLM 呼び出しについて確認したい場合は、LLM Calls 関数で行うことが可能です。info.print_llm_calls_summary
で概要を info.llm_calls
で詳細を確認する事が可能です。
info_hw.print_llm_calls_summary()
上記 Python コードはチュートリアルの場合は以下のような出力になります。
Summary: 1 LLM call(s) took 0.70 seconds and used 328 tokens.
1. Task `generate_user_intent` took 0.70 seconds and used 328 tokens.
更なる詳細にご興味がある方はこちらのドキュメントを併せてご確認下さい。
まとめ
今回の記事では NeMo Guardrails の概要、インストール方法、簡単な使い方について解説しました。同時公開されたジェイルブレイク防止編ではより具体的な使い方を解説しておりますので、ぜひ併せてご一読下さい。
関連情報
- NeMo Guardrails ユーザー ガイド
- NeMo Guardrails github サイト
- NVIDIA ブログ: NVIDIA のオープンソース ソフトウェアが、開発者による AI チャットボットへのガードレール追加を支援
- 技術ブログ: Building Safer LLM Apps with LangChain Templates and NVIDIA NeMo Guardrails
- 技術ブログ: Develop Secure, Reliable Medical Apps with RAG and NVIDIA NeMo Guardrails
- 技術ブログ: NeMo GuardrailsによりLLM の脆弱性を防ぐ -ジェイルブレイク防止編-