0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【AWS Skill Builder】『Building Generative AI Applications Using Amazon Bedrock』コースをやってみた - その 1

Last updated at Posted at 2025-03-14

はじめに

AWS Skill Builderで生成AIアプリケーションの学習をしていたところ、『Building Generative AI Applications Using Amazon Bedrock』というコースに出会いました。このコースでは、実際のコードでアプリケーションを動かせるデモがあり、アプリケーション開発の理解にとても役立ちます。

しかし、まだ英語版のみなので、紹介がてら日本語で内容をまとめてみようと思います。

本記事の説明

  • コース上のデモの内容に基づき、デモで扱われる知識・技術の説明をします
  • コースにある資料の完全な日本語訳ではありません
  • デモの概要の説明はしますが、デモの具体的な実施やコードの記載はありません
    • 無料のコースなので、Skill Builderに登録すれば、すぐにデモのリソースにアクセスできます
  • この題のトピックは「その1~その3」の3部構成です
    その 1(FM編):この記事
    その 2(RAG編):投稿済み
    その 3(Agent編):投稿済み

コースの概要

コースのコンテンツは、

Module 1~4
BedrockやLangChainに関するレッスン
Demo 1
LLMを用いた簡単なデモ
Module 5
RAGに関するレッスン
Demo 2
RAGを用いたデモ
Module 6
エージェントに関するレッスン
Demo 3
エージェントのデモ

となっており、「知識の習得 → それに基づくデモ」という流れが3つある構成です。(記事もそれに倣います。)一応コースレベルとしては、Advancedとなっており、生成AIやAWSに関する予備知識が多少必要です。

生成AIの基盤モデルに関しては以前こちらの記事でまとめています

デモでは、実際にAWSのリソースを作成し、Amazon SageMaker上のJupyter環境でコードを実行します。コースは無料ですが、デモ内で利用するAWSリソースには普通に料金が発生します
自分は費用をなるべく抑えたかったので、コース上の手順とは別の方法を試しました。それらも補足情報として記載したいと思います。

↑私がコースのデモを完了するまでにかかったコストは、$0.19でした
(追記)
PineconeのAPIKeyの保存に使用したSecrets Managerが無料枠だったらしく、加算に漏れていました。執筆時点で1シークレットあたり、$0.40 / 月(日割り有)でその分の課金も来ます。

BedrockとLangChainについて

その1の記事では、コースのDemo 1で登場する知識をまとめます。

APIメソッド

InvokeModel

Amazon Bedrockのモデルにリクエストを送り、生成された回答を得るには、InvokeModelメソッドを使用します。

example.py
import boto3
import json

bedrock_client = boto3.client('bedrock-runtime')
prompt = "What is LLM?" # LLMに送るユーザーの質問
body = json.dumps({
    "inputText": prompt, 
    "textGenerationConfig": {
        "maxTokenCount": 8192,
        "stopSequences": [],
        "temperature": 0,
        "topP": 1
    }
})

response = bedrock_client.invoke_model(
     body = body,
     modelId = 'amazon.titan-text-express-v1', # 回答生成させるモデルのID
     accept = 'application/json',
     contentType = 'application/json'
)
response_body = json.loads(response.get('body').read())
print(response_body.get('results')[0].get('outputText'))
出力結果
LLM stands for Large Language Model. It is a neural network architecture that is trained on large amounts of text data to generate human-like text. LLMs are used in a variety of applications, including chatbots, virtual assistants, and language translation.

ドキュメント → invoke_model - Boto3 1.36.21 documentation

InvokeModelWithResponseStream

InvokeModelメソッドと同様に、モデルの呼び出しを行うメソッドですが、InvokeModelWithResponseStreamでは、レスポンスがストリーム形式で返ってきます。この形式は、モデルの出力を早く取得したい場合や、より長い文章を生成させる場合に役立つそうです。

以下の例のように、回答がいくつかのチャンクに分割され、ひとつのチャンクの出力は途中で途切れています。

example.py
prompt = "Write a tech blog on LLM usin 10 sentences."
# inputの他の設定はinvoke_modelと同じなので省略
response = bedrock_client.invoke_model_with_response_stream(...)
stream = response.get('body')
if stream:
     for event in stream:
          chunk = event.get('chunk')
          if chunk:
               output = json.loads(chunk.get('bytes').decode()).get('outputText')
               print(output)
出力結果
Artificial intelligence (AI) has made significant strides in recent years, with one of the most exciting developments being the rise of large language models (LLMs). LLMs are computer programs that can understand and generate

ドキュメント → invoke_model_with_response_stream - Boto3 1.37.4 documentation

推論のパラメータ

基盤モデル(FM)にリクエストを送る際、いくつかの推論パラメータを設定することでFMのレスポンスを調整することができます。ここでは5つの代表的なパラメータを紹介します。

名前 説明 タイプ デフォルト値
Temperature 単語選択のランダム性を決める値で、高いほど回答が予想しづらい Float 0
トップ P 次に選択されるであろうトークンのうち、出力確率が上位何%までを候補にするかを決める値 Float 1
トップ K 次に選択されるであろうトークンのうち、出力確率が上位何個までを候補にするかを決める値 Float -
レスポンスの最大長 生成される回答のトークンの最大の長さ Integer 512
停止シーケンス ここで列挙された単語をモデルが生成すると、そこで生成を停止する Array of strings -

参考 → Amazon Bedrock Influence response generation with inference parameters

すべてのFMがすべてのパラメータに対応している訳ではなく、モデルによって利用可能なパラメータは違う。

アーキテクチャパターン

大規模なテキスト要約

非常に長いドキュメントの要約をプロンプトに入れてFMに渡そうとすると、コンテキストの制限を超えてしまいリクエストできない、という問題が起こり得ます。それを回避する解決策として、以下のような要約パターンがあります。

  1. map_reduce
    • 長いドキュメントをいくつかのチャンクに分割し、それぞれを要約した後、すべてのチャンクの要約をまとめて要約する
  2. refine
    • ドキュメントをチャンクに分けた後、最初のチャンクを要約し、次にその要約と2番目のチャンクの内容を合わせて要約する
    • 上記のプロセスをすべてのチャンクが要約されるまで繰り返す

チャット履歴を持つAIアシスタント

このアーキテクチャパターンでは、AIアシスタントがユーザーとのチャット内容をチャット履歴としてストアに保存します。すると、FMはユーザーとの過去のチャット内容がプロンプトから与えられ、それに基づいて回答を生成することができます。

LangChain

概要

LangChainとは、LLMを利用したAIアプリケーションを、構築するためのフレームワークです。簡単にLLMによる機能を開発するための、クラスやメソッドが提供されています。

LangChainは、Python/Typescript/Javascriptの3つのプログラミング言語に対応しています。
また、AWSなどのLLMを提供する多くのプロバイダーごとに、独立した統合パッケージがあります。AWSの場合には、langchain-awsライブラリが用意されているので、そちらを使っていきます。

基本的な使い方

example.py
from langchain_aws import BedrockLLM

llm = BedrockLLM(
    model_id="amazon.titan-text-express-v1", credentials_profile_name="default"
)

response = llm.invoke(input="Where is the capital of Japan?")

プロンプトテンプレート

LangChainのPromptTemplateを用いると、プロンプトのベースとなるテキストを定義し、後から埋め込まれた変数を代入することで動的にプロンプトを作成できます。これにより、プロンプトの再利用や効率的なLLMの呼び出しが可能になります。

example.py
from langchain_core.prompts import PromptTemplate

prompt_template = PromptTemplate.from_template(
    "Tell me a information about {topic} in {sentence_num} sentences."
)

prompt = prompt_template.invoke({"topic": "cats", "sentence_num": 3})
# → text='Tell me a information about cats in 3 sentences.'
...
response = llm.invoke(prompt)

チャット履歴

アーキテクチャパターンのセクションでも登場した、チャット履歴を持つAIアシスタントが、LangChainのライブラリを用いることで実装することができます。

コース内で紹介されるLLMChainlangchain.memoryを用いた実装は、最新のv0.3では非推奨のやり方です。
How to migrate to LangGraph memory | 🦜️🔗 LangChain

LangGraph memoryのコード例
example.py
from langchain_core.messages import HumanMessage
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import START, MessagesState, StateGraph
from langchain_aws import BedrockLLM

llm = BedrockLLM(
    model_id="amazon.titan-text-express-v1", credentials_profile_name="default"
)

# Define the function that calls the model
def call_model(state: MessagesState):
    response = llm.invoke(state["messages"])
    return { "messages": response }

# Define a new graph
workflow = StateGraph(state_schema=MessagesState)
workflow.add_edge(START, "model")
workflow.add_node("model", call_model)

memory = MemorySaver()
app = workflow.compile(
    checkpointer = memory
)

# The thread id is a unique key that identifies this particular conversation.
config = { "configurable": { "thread_id": "abc123" } }

input_message = HumanMessage(content="hi! I'm Bob")
for event in app.stream({ "messages": [input_message] }, config, stream_mode="values"):
    event["messages"][-1].pretty_print()

input_message = HumanMessage(content="what was my name?")
for event in app.stream({ "messages": [input_message] }, config, stream_mode="values"):
    event["messages"][-1].pretty_print()
出力結果
Bot: Hello, Bob! How can I help you today?
...
Bot: Your name is Bob.

コードの引用元


ベクトルストア

LangChainを用いることで、簡単にドキュメントを埋め込みしたベクトルをベクトルストアに保存できます。LLMはそのドキュメントを元に回答を生成します。

  1. ドキュメントの内容を分割

    example.py
    from langchain_community.document_loaders import TextLoader
    from langchain_text_splitters import CharacterTextSplitter
    
    text_documents = TextLoader('programming.txt').load()
    text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
    documents = text_splitter.split_documents(text_documents)
    

  2. ドキュメントを埋め込みして、ベクトルストアに保存
    FAISSというライブラリのベクトルストアを用いた例

    example.py
    from langchain_aws import BedrockEmbeddings
    from langchain_community.vectorstores import FAISS
    
    embedding = BedrockEmbeddings(model_id="amazon.titan-embed-text-v1")
    
    vector_store = FAISS.from_documents(documents=documents, embedding=embedding)
    

  3. ベクトルストアを使ってLLMに推論させる

    example.py
    from langchain.indexes.vectorstore import VectorStoreIndexWrapper
    from langchain_aws import ChatBedrock
    
    index = VectorStoreIndexWrapper(vectorstore=vector_store)
    
    chat_llm = ChatBedrock(
        model_id="amazon.titan-text-express-v1",
        credentials_profile_name="default"
    )
    output = index.query("What is Python?", chat_llm)
    

チェイン

チェインによって、メソッドチェインのように、続けて呼び出される一連の処理を定義できます。以下コード内の|は、pipe operatorといい、チェインの定義に使います。

example.py
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_aws import ChatBedrock

prompt = ChatPromptTemplate.from_template(
    "Tell me a information about {topic} in 1 sentence."
)
model = ChatBedrock(
    model_id="amazon.titan-text-express-v1",
    credentials_profile_name="default"
)

chain = prompt | model | StrOutputParser()
chain.invoke({"topic": "LangChain"})
# → '\nLangChain is a platform that allows users to create and interact with AI agents using natural language.'

エージェント

AIアプリケーションとしてのエージェントとは、定義されたアクションやワークフローを使って複雑なタスクをこなすシステムを指します。エージェントは、関数やAPI、RAG、コーディングなどのツールが渡され、ユーザーからのインプットや状況に応じてそれらを使い分け、求められている回答を自律的に生成します。

コースのレッスンにある、AgentExecutorを使用した実装はレガシーな手法らしいので1、推奨されているLangGraphを用いたコード例を紹介します。

example.py
from langchain_aws import ChatBedrock
from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent

@tool
def magic_function(input: int) -> int:
    """Applies a particular processing to an input.
        Use this function to make sure of an output."""
    if (input % 2) == 0:
        return input // 2
    else:
        return input * 2

tools = [magic_function]

chat_model = ChatBedrock(
    model_id = "amazon.nova-lite-v1:0",
    credentials_profile_name = "dev"
)
langgraph_agent_executor = create_react_agent(chat_model, tools)

query = "what is the output of magic_function(4)?"
messages = langgraph_agent_executor.invoke({"messages": [("human", query)]})

print(messages["messages"][-1].content)
出力結果
<thinking> The tool has provided the output for magic_function(4). I can now provide this information to the User. </thinking>

The output of magic_function(4) is 2.

Demo 1

構成

コースのDemo 1には、大きく分けて以下の6つの実装例が含まれています。

  1. テキスト生成
    a. Bedrockの呼び出しの基礎
    b. プロンプトテンプレート
  2. テキスト要約
    a. テキスト要約の基礎
    b. 大規模なテキスト要約
  3. QA回答システムの基礎
  4. チャット履歴やベクトルストアを使ったチャットボット
  5. コード生成の基礎
  6. LangGraphを使ったエージェント

コースには、「セットアップ」と「デモの実施」でそれぞれ手順を示す説明動画があるので、それを見ながら進めることになります。

補足事項

  • デモのコードをローカルで実行する
    Skill Builderのコースでは、Jupyter NotebookのファイルをAmazon SageMaker AI上の環境で実行します。一部無料枠もありますが、それを超過すれば料金が発生します。
    そのため、自分はJupyter Notebookファイルをローカルの環境で実行し、FMの呼び出し料金のみに済ませました。環境構築の方法はこちらの別記事にまとめてますので、参考にしてください。

  • Claude 3 Sonnetのフォーム
    デモの環境準備の手順で、BedrockのFMを有効化します。デモの説明動画内にはありませんが、現在ではClaude 3 Sonnetモデルを有効化する際、フォームにユースケースの詳細を記載する必要があります。


  • Amazon Titanモデルの有効化
    前述の記事内でも言及していますが、Amazon Titanモデルは一度アクセスを有効化すると、取り消すことはできないです。

おわり

コード例のためにいい感じの質問を考えるのが難しかったです。

その2に続きます。

参考リンク

  1. https://python.langchain.com/docs/concepts/agents/#legacy-agent-concept-agentexecutor

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?