View a markdown version of this page

マルチターン強化学習用のアセットの作成 - Amazon SageMaker AI

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

マルチターン強化学習用のアセットの作成

プロンプトデータセットの形式

トレーニングデータセットは、SageMaker AI がトレーニング中にエージェントに送信するプロンプトのコレクションです。各プロンプトは 1 つのロールアウトを開始します。エージェントはロールアウトを処理し、1 つ以上のターンにわたってアクションを実行し、報酬を返します。データセットの品質と構造は、モデルが学習する内容に直接影響します。

サポートされるファイル形式

形式 拡張機能 注意事項
Apache Parquet .parquet 大規模なデータセットに推奨 — 効率的なストレージと高速ロード
JSON Lines .jsonl 1 行に 1 つの JSON オブジェクト — 作成が簡単で人間が読み取れる
JSON .json JSON オブジェクトの配列
CSV .csv ヘッダー行を持つカンマ区切り値

データセットスキーマ

プロンプト列の検出

RFT サービスは、次のルールを使用してプロンプト列を順番に検出します。

  • という名前の列promptが存在する場合、その列が使用されます。

  • それ以外の場合は、データセットの最初の列が使用されます。

あいまいさを避けるためprompt、プロンプト列には常に名前を付けます。独自の追跡目的で追加の列を含めることができますが、プロンプト列のみが RFT サービスによって読み取られます。

プロンプトの使用方法

RFT サービスはプロンプト列を読み取り、文字列値をそのままエージェントに直接渡します。コンテンツの解析、検証、変換は行いません。使用する形式は、エージェントが期待する内容に完全に依存します。単純なエージェントはプレーンテキストを取りますが、より洗練されたエージェントは会話履歴、ツール設定、報酬仕様を含む JSON 文字列を期待する場合があります。

データ保護

RFT サービスは検査なしでプロンプトを渡すため、機密性の高いコンテンツを保護する責任があります。プロンプトデータを保存する前にエンコードまたは暗号化し、エージェントでデコードまたは復号を処理することを検討してください。

一般的なアプローチ:

  • Base64 エンコーディング — 非機密データのシンプルな難読化

  • 暗号化 — 機密データまたは専有データ (エージェントが管理するキーを持つ AES など) の場合

例 1: シンプルな Q&A データセット (プレーンテキスト)

プレーンテキストプロンプトを使用した簡単なトレーニングタスク用。

ユースケース: 基本的な質問への回答、簡単な指示

Parquet (Python)

import pyarrow as pa import pyarrow.parquet as pq data = { "prompt": [ "What is 2 + 2?", "Explain the concept of machine learning.", "Write a Python function to reverse a string.", "What is the capital of France?", "How does photosynthesis work?", ] } table = pa.table(data) pq.write_table(table, "training_data.parquet")

JSON 行 (.jsonl)

{"prompt": "What is 2 + 2?"} {"prompt": "Explain the concept of machine learning."} {"prompt": "Write a Python function to reverse a string."}

例 2: ツールを使用した検索/推論

モデルの推論中に外部ツールアクセス (検索エンジンなど) を必要とするタスクの場合。

ユースケース: ウェブ検索による事実ベースの Q&A、検索で強化された推論

構造:

prompt (column) = JSON string (recommend encoded/encrypted) containing: ├── data_source: Dataset origin identifier ├── prompt: Conversation messages [system, user] ├── ability: Task category (e.g., "fact-reasoning") ├── env_class: "search" ├── reward_spec: Ground truth answer for evaluation └── extra_info: Tool configuration and metadata

行の例:

import pyarrow as pa import pyarrow.parquet as pq import json task_data = { "data_source": "searchR1_nq", "prompt": [ { "role": "system", "content": "You are a helpful and harmless assistant." }, { "role": "user", "content": "Answer the given question. You must conduct reasoning inside <think> and </think> first every time you get new information. After reasoning, if you find you lack some knowledge, you can call a search engine by <search> query </search> and it will return the top searched results between <information> and </information>. You can search as many times as you want. If you find no further external knowledge needed, you can directly provide the answer inside <answer> and </answer>, without detailed illustrations. For example, <answer> Beijing </answer>. Question: total number of death row inmates in the us?" } ], "ability": "fact-reasoning", "env_class": "search", "reward_spec": { "ground_truth": { "target": [ "2,718" ] }, "style": "rule" }, "extra_info": { "index": 0, "question": "total number of death row inmates in the us?", "split": "train", "need_tools_kwargs": true, "tools_kwargs": { "search": { "create_kwargs": { "question": "total number of death row inmates in the us?", "ground_truth": { "target": [ "2,718" ] }, "data_source": "searchR1_nq" } } } } } # Recommend: encode or encrypt before storing data = {"prompt": [json.dumps(task_data)]} table = pa.table(data) pq.write_table(table, "search_training_data.parquet")

例 3: SQL 生成 (複雑なコンテキストでのマルチターン)

データベーススキーマ、複数ステップの推論、SQL 実行フィードバックを必要とするコード生成タスクの場合。

ユースケース: Text-to-SQL、実行検証によるコード生成

構造:

prompt (column) = JSON string (recommend encoded/encrypted) containing: ├── input_seq: Human-readable task description ├── prompt: Conversation messages [system, user] ├── env_class: "text2sql" ├── reward_spec: Ground truth SQL and evaluation config ├── instance_id: Unique task identifier ├── schema: Database schema definition ├── question: Natural language question └── extra_info: Additional metadata

行の例:

import pyarrow as pa import pyarrow.parquet as pq import json task_data = { "input_seq": "Task Overview:\nYou are a data science expert. Below, you are provided with a database schema\nand a natural language question. Your task is to understand the schema and\ngenerate a valid SQL query to answer the question.\n\nDatabase Engine: SQLite\n\nDatabase Schema:\nCREATE TABLE countries (\n country_id INTEGER PRIMARY KEY,\n english_name TEXT,\n population INTEGER\n);\n\nCREATE TABLE country_metrics (\n metric_id INTEGER PRIMARY KEY,\n country_id INTEGER,\n metric_type TEXT,\n year INTEGER,\n value REAL\n);\n\nQuestion: List all countries with their current population and average\npopulation over the last five years.", "prompt": [ { "role": "system", "content": "Task Overview:\nYou are a data science expert. Your task is to understand the schema and generate\na valid SQL query to answer the question within limited turns.\n\nInstructions:\n- Make sure you only output the information asked in the question.\n- Think through the steps before generating the final SQL query.\n\nFormat:\n- Conduct thinking inside <think>...</think> blocks.\n- You can use SQL tool written within <sql>your sql</sql> to explore or verify.\n- SQL tool output will be shown inside <observation>...</observation>.\n- Provide the final SQL query inside <solution>...</solution>." }, { "role": "user", "content": "Database Schema:\nCREATE TABLE countries (\n country_id INTEGER PRIMARY KEY,\n english_name TEXT,\n population INTEGER\n);\n\nCREATE TABLE country_metrics (\n metric_id INTEGER PRIMARY KEY,\n country_id INTEGER,\n metric_type TEXT,\n year INTEGER,\n value REAL\n);\n\nQuestion: List all countries with their current population and average\npopulation over the last five years." } ], "env_class": "text2sql", "instance_id": "sql_task_001", "reward_spec": { "ground_truth": "SELECT c.english_name, c.population, AVG(m.value) as avg_pop\nFROM countries c\nJOIN country_metrics m ON c.country_id = m.country_id\nWHERE m.metric_type = 'Population' AND m.year > strftime('%Y', 'now') - 5\nGROUP BY c.country_id;", "style": "rule" }, "schema": "CREATE TABLE countries (...); CREATE TABLE country_metrics (...);", "question": "List all countries with their current population...", "extra_info": { "split": "train", "difficulty": "medium" } } # Recommend: encode or encrypt before storing data = {"prompt": [json.dumps(task_data)]} table = pa.table(data) pq.write_table(table, "sql_training_data.parquet")

ベストプラクティス

データセットサイズ

少なくとも と等しい最小の例training_batch_size。多様性のためにバッチサイズを 10 倍以上にすることをお勧めします。

プロンプトの品質

  • 完全なコンテキスト: モデルが有用なレスポンスを生成するために必要なすべての情報を含める

  • 一貫した構造: すべてのプロンプトで一貫したフォーマットを維持する

  • 重複を避ける: 一意のプロンプトにより、トレーニングシグナルが向上します

  • 明確な手順: ツールを使用するタスクの場合は、明示的な形式の手順を指定します。

データ保護

  • プロンプトコンテンツをエンコードまたは暗号化して機密データを保護する

  • ロールアウトサーバーで復号キーを安全に管理する

  • RFT サービスは検査なしでプロンプトを渡すため、保護はユーザーの責任です

報酬関数の設計

報酬関数の設計は、複雑なマルチステップエージェントシステムで効果的な学習シグナルを提供するために不可欠です。マルチターン RL の報酬関数を設計するときは、次のガイドラインを考慮してください。

  • 成果ベースの報酬から始めます。最終的な結果を最初に採点して、中間報酬または報酬シェーピングを追加する前に、クリーンで信頼性の高いベースラインを確立します。

  • バイナリ報酬よりも継続的な報酬を検討してください。継続的な報酬は、より明確な部分的なクレジットシグナルを提供できますが、ゲームは簡単です。部分的なクレジットの定義が困難な場合や、クリーンベースラインが必要な場合、バイナリ報酬が推奨されます。

  • シェーピング報酬は慎重に使用してください。シェーピング報酬は学習を導くことができますが、過度に強いシェーピングやずれたシェーピングはショートカットを教える可能性があるため、控えめに使用する必要があります。

  • 報酬ハッキングから保護します。報酬を悪用しにくくし、モデルがスコアリングルールをゲームするのではなく実際のタスクを解決していることを確認します。

  • トレーニング前に検証します。トレーニング前に実際の軌道で報酬関数をテストして、バグ、抜け穴、誤解を招くシグナルをキャッチします。

  • 報酬だけでなく、行動メトリクスをモニタリングします。完了率、ターンカウント、ツールの使用、ギャップの過剰適合などのメトリクスを追跡して、モデルが意図した方法で改善していることを確認します。

報酬設計プロセス

  1. 成功がどのように見えるかを定義し、自動的にスコアリングできるかどうかを判断します。

  2. ベースモデルを評価して、ベースラインの成功率を確立します。

  3. 報酬階層を設計する: 成功に対する肯定的な報酬、失敗に対する報酬ゼロ、および退行動作に対する否定的な報酬。

  4. タイムアウト、環境エラー、不正な形式の出力、空のレスポンスなど、エッジケースを明示的に処理します。

  5. 各報酬コンポーネントで潜在的な報酬ハッキングを確認してください。

  6. トレーニング前に実際の軌道で検証します。

  7. トレーニング中に動作メトリクスとともにモニタリングします。

  8. 初期結果に基づいて反復処理します。

実際には、報酬関数はエピソードの完全なメッセージ履歴を入力として受け取り、2 つの出力を返します。1 つはスカラー報酬 (軌道品質を測定する浮動小数点スコアで、値が大きいほどパフォーマンスが向上することを示します)、もう 1 つはログ記録、デバッグ、モニタリング用のメトリクスディクショナリです。

例: エージェント報酬関数を検索する

次の例は、検索を使用して質問に回答するエージェントの報酬関数を示しています。結果の評価、フォーマットシェーピング、回答の正確性チェックを示します。

class TextAnswerReward: """Reward function to check text answer against gold answers. formula: format_coef * (correct_format - 1) + correct_answer """ gold_answers: list[str] format_coef: float = 0.1 async def __call__(self, history: list[Message]) -> tuple[float, dict[str, float]]: """Grade the completed episode by checking the final assistant message.""" final_message = None for msg in reversed(history): if msg.get("role") == "assistant": final_message = msg break if final_message is None: return 0.0, {"format": 0.0, "correct": 0.0} content = get_text_content(final_message) correct_format = float(self._extract_answer(content) is not None) correct_answer = float(self._check_answer(content)) reward = self.format_coef * (correct_format - 1) + correct_answer return reward, {"format": correct_format, "correct": correct_answer} def _extract_answer(self, text: str) -> str | None: if "Answer:" not in text: return None parts = text.split("Answer:") if len(parts) != 2: return None return parts[1].strip() def _check_answer(self, text: str) -> bool: model_answer = self._extract_answer(text) if model_answer is None or len(self.gold_answers) == 0: return False for gold in self.gold_answers: if normalize_answer(model_answer) == normalize_answer(gold): return True return False

この報酬関数には、以下の主要な設計選択肢が含まれています。

  • 正確性が優先されます。正しい回答は、形式に関係なく、常に間違った回答よりもスコアが高くなります。

  • 形式は小さなシェーピング信号です。形式係数 (0.1) は結果報酬の 10% で、モデルが形式コンプライアンスだけでは利益を得ることができないほど小さく、解析可能な出力に振り分けるのに十分な大きさです。

  • 間違った回答の間違った形式は、猶予的にペナルティが科されます。-0.1 スコアは、学習シグナルを圧倒することなく、完全に構造化されていない出力から小さな勾配を作成します。

  • 正しくない形式の回答は正しくありません。モデルがアシスタントメッセージを生成しない場合、関数は 0.0 を返し、現在はあるが不正な形式のレスポンスに対して -0.1 のアクティブなペナルティと区別します。