はじめに
AWS Skill Builderにある『Building Generative AI Applications Using Amazon Bedrock』というコースを紹介する記事の「その 3」になります。
記事の構成
その 1:BedrockとLangChainについて
その 2:RAGについて
その 3:この記事
Skill Builderのコース説明や記事の概要などは、その1の記事をご覧ください。
今回のその3では、コース内のDemo 3の内容に即して、エージェントに関する知識を取り扱います。
エージェント
エージェントに関しては、その1の記事でも登場し軽く概要を載せました。
AIアプリケーションとしてのエージェントとは、定義されたアクションやワークフローを使って複雑なタスクをこなすシステムを指します。エージェントは、関数やAPI、RAG、コーディングなどのツールが渡され、ユーザーからのインプットや状況に応じてそれらを使い分け、求められている回答を自律的に生成します。
その1では、LangGraphを使ったエージェントの実装を紹介しましたが、本記事ではAmazon Bedrock Agentsでの実装がメインになります。
エージェントのユースケース
エージェントは概要だけ聞いてもアプリケーションのイメージはほとんど掴めないと思いますが、AWSが代表的なユースケースのコードサンプルを公開しています。
ユースケースごとのフォルダ配下にあるREADME.md
に、それぞれのアプリケーションの概要やアーキテクチャ図があるので、それを眺めるだけで勉強になると思います。
個人的に分かりやすいと思ったのは、
エージェントの実装例
ユースケースに沿ったコードサンプルの他に、アーキテクチャに重点を置いたコードサンプルも公開しています。Amazon Bedrock Agentsの基本的な各機能がだいたい把握できます。
Demo 3で作成するエージェントは、まさにこの例のような感じです。
Amazon Bedrock Agents
AWSが提供する、エージェントアプリケーション開発のためのサービスが、Amazon Bedrock Agentsです。Amazon Bedrock Agentsの機能についてそれぞれ簡単にまとめます。
① アクショングループ
アクショングループとは、エージェントが実行できるメソッドの集まりです。エージェントには、メソッドの名前や引数が定義されたスキーマと、メソッドの説明が与えられます。ユーザーからのクエリを処理する中で、メソッドの実行が必要だと判断した際は、エージェントがそのメソッドを呼び出しレスポンスを受け取ります。
アクショングループのメソッドのスキーマ(つまりインターフェース)の記述方法と、その中身の処理の実装方法はそれぞれ2つずつ存在します。
スキーマの記述
-
OpenAPI schema
OpenAPI schemaは、JSONやYAML形式で記述できる、APIや関数の設計図です。
Path Item Objectごとに1つのメソッドが定義され、エージェントがそのメソッドを認識します。
-
関数の詳細
関数の詳細 (function details)を自分で定義できます。マネジメントコンソール上でフォームを使って作成するか、JSONを記述して作成します。
定義するのは、「名前」「説明(エージェントに渡される)」「パラメータ」「確認の有効化設定」です。{ "name": "string", "description": "string", "parameters": [ { "name": "string", "description": "string", "required": "True" | "False", "type": "string" | "number" | "integer" | "boolean" | "array" } ] }
※ドキュメントのこちらのページより引用
処理の実装
-
AWS Lambda関数
上記で定義されたスキーマを満たす関数を、AWS Lambdaで実装できます。
実装したLambdaをアクショングループに紐づければ、エージェントが呼び出した際に自動でそのロジックが実行され、レスポンスがエージェントに返されます。 -
リターンコントロール
リターンコントロールを設定すると、このメソッドが呼ばれたとき、エージェントはコントロールをアプリケーションに返し、レスポンスを待機する状態になります。そのリターンコントロールのリクエストを受けたアプリケーション側では、実装されているロジックを実行し、スキーマ通りにレスポンスをエージェントに返す必要があります。それを受け、エージェントは元のクエリ処理のセッションに復帰します。
② 他機能との統合
Knowledge Base
作成したKnowledge BaseのRAGシステムをエージェントに追加することができます。
Knowledge Baseの利用場面を適切にエージェントに伝えておけば、エージェントが処理の中で自動的にKnowledge Baseを呼び出し必要な情報を取得します。
Guardrails
Guardrailsをエージェントに追加することもできます。
(その2の記事でも登場したので、長く書きませんが)LLMが生成するテキストにセーフガードとなるポリシーを策定し、アプリケーションの信頼性や安全性を守ります。
③ エイリアス
作成と設定が完了したエージェントをデプロイする際は、エージェントエイリアスを作成する必要があります。
エイリアスは、エージェントのどれか1つのバージョンに紐づけられ、エージェントの使用時には、指定されたエイリアスに紐づくバージョンのエージェントが使われます。
エージェントを更新すると作られる新しいバージョンを、既存のエイリアスか新しいエイリアスに紐づけることができます。
エージェントに紐づいたリソース(Lambda関数など)のリンクを変更した場合も、エージェントの新しいバージョンになります。
エイリアスは以下のようなケースで利用できます。
- 環境(開発/テスト/リリース)ごとにバージョンを変える
- エージェントを使用するコード自体を変更することなく、使用するバージョンを切り替える
④ InvokeAgent
エージェントにリクエストを送るには、InvokeAgent
メソッドを使用します。
以下は、Pythonでのコード例です。
import boto3
bedrock_agent_runtime_client = boto3.client('bedrock-agent-runtime')
...
response = bedrock_agent_runtime_client.invoke_agent(
inputText = 'How many orders did AnySystem have yesterday?', # ユーザーからのクエリ
agentId = agentId, # 作成時に生成されるID
agentAliasId = 'TSTALIASID',
sessionId = 'abc123'
)
event_stream = response['completion']
for event in event_stream:
if 'chunk' in event:
data = event['chunk']['bytes']
agent_answer = data.decode('utf8')
print(agent_answer)
ドキュメント → invoke_agent - Boto3 1.37.9 documentation
⑤ セッションとメモリー
エージェントが複数回の呼び出しに渡る会話の内容を保持する機能に、セッションとメモリーがあります。
セッション
同じセッション内では、エージェントは複数の呼び出しの内容を保持します。前回のリクエストで登場した情報を覚えているので、人間と対話しているときのように質問することができます。
APIでは、引数にsessionId
を任意の文字列で指定します。(前セクションのコード例参照)
同一のsessionId
を持つ呼び出しでは、同じセッションが使用されます。
しかし、セッションの期限が切れるとエージェントは会話記録を削除するので、同じ文字列をIDに指定しても以前の会話内容をエージェントは覚えていません。
メモリー
メモリーは、複数のセッションにまたがって会話内容を保持させます。
メモリーの利用手順は、以下です。
- エージェントの設定でメモリー機能を有効にする
- APIの引数で、
memoryId
を任意の文字列で指定する - セッションが終了すると、そのセッションの要約情報がメモリーとして保存される
- 次の新しいセッションが始まる際に、メモリーに保存された以前までのセッションの内容がエージェントに与えられる
memoryId
に他の値を指定すると、別の新しいメモリーが作成されます。
また、GetAgentMemory
メソッドを用いてメモリー内容の要約を取得することもできます。
response = bedrock_agent_runtime_client.get_agent_memory(
agentId = agent_id,
agentAliasId = 'TSTALIASID',
memoryId = memory_id,
memoryType = 'SESSION_SUMMARY'
)
if 'memoryContents' in response and response['memoryContents']:
session_summary = response['memoryContents'][0]['sessionSummary']
print("Summary: " + session_summary['summaryText'])
Amazon Titan Text G1 - PremierをエージェントのLLMとして選択すると、メモリー設定は非対応のため有効にできません。
⑥ トレース
エージェントのトレースとは、クエリを受け取ってからレスポンスを生成するまでの間にエージェントが行った思考プロセスのログです。
トレースはJSON形式で、APIでenableTrace = True
を指定するとレスポンスの中にトレースが含まれます。
トレースは、エージェントが予期した動作をしているかの確認や、間違った生成の原因解明の際に役立ちます。
Demo 3
構成
今回のDemo 3では、「shopping assistant」のエージェントを作成し、以下に関するコード例を実施します。
InvokeAgent
- トレースの出力
- Guardrails
- メモリー
補足事項
-
プロファイルとリソースのリージョンの一致
その2の記事で記載したので詳細は割愛します。
-
ログ記録の設定
デモの中で、設定したS3のバケットに出力されたトレースのログをダウンロードする手順があります。しかし自分が実施してみたところ、S3にオブジェクトが何も生成されておらずエラーになりました。結局、Bedrockの「モデル呼び出しのログ記録」という設定を見つけ有効にしたところ、問題なくログが出力されるようになったので記載します。
- AWSマネジメントコンソールの「Amazon Bedrock」を開く
- サイドメニューから「Bedrock configurations > 設定」を選択
- 「モデル呼び出しのログ記録」の設定を以下のように設定
- S3バケットはデモ内で作成した、
bedrock-logging-us-east-1-{your_account_id}
を選択
- S3バケットはデモ内で作成した、
- 「設定を保存」ボタンを押す
設定を保存すると、上記のバケット内に
AWSLogs/
というプレフィックスで、オブジェクトが生成します。エージェントのログは、呼び出してから数分後に、そのフォルダ内に作成されます。S3バケットのライフサイクル設定で、ログのオブジェクトに有効期限を設定すると良いと思います。
-
必要なポリシー
Bedrockサービスに対するポリシー以外で、デモの実行に必須のポリシーは以下の通りです。1たくさんあるので漏れてたらすみません。- S3
s3:ListBucket
s3:ListAllMyBuckets
s3:PutEncryptionConfiguration
s3:GetObject
s3:CreateBucket
s3:PutObject
- IAM
iam:CreateRole
iam:CreatePolicy
iam:CreatePolicyVersion
iam:AttachRolePolicy
iam:PassRole
- Lambda
lambda:ListFunctions
lambda:GetFunction
lambda:CreateFunction
lambda:UpdateFunctionCode
- Logs
logs:DescribeDeliverySources
logs:DescribeDeliveries
logs:DescribeConfigurationTemplates
logs:PutDeliveryDestination
logs:PutDeliverySource
logs:CreateDelivery
-
logs:GetDeliveryDestination
参考:Logs sent to Amazon S3 ドキュメント
- STS
sts:GetCallerIdentity
- S3
-
自分が遭遇した問題
- 金額に関するクエリの際に、
ThrottlingException
になる- 何度かリトライして解消される場合と永遠にできない場合がありました
-
ログがS3に生成されない上記の方法で解決済み原因よく分かりませんでした
- 金額に関するクエリの際に、
おわり
長くなりましたが、ここまで3記事に分けて、Building Generative AI Applications Using Amazon Bedrockコースの紹介をしてきました。
記事に書いた通り、デモを一通りやってみるだけで非常に勉強になるのでオススメです。
-
ローカル開発環境と前回の記事で紹介したPineconeを使う場合 ↩