Amazon BedrockをLangChain経由で使って会話履歴も保存してみた

Anthropic社のClaudeモデルは意外と簡単に使用開始できました。唯一の日本語対応のテキスト生成モデル、かつ唯一のチャットモデルで、100kトークンの長いコンテキストを扱えるので是非皆様ご活用ください!!
2023.10.02

こんちには。

データアナリティクス事業本部 インテグレーション部 機械学習チームの中村です。

今回はAmazon BedrockをLangChain経由で使ってみます。

マネコン上での準備

まずはModel Accessというところからモデルを有効にしていきます。以下で「Edit」を押下します。

このままでもチェックはできるのですが、今回はAnthropic社のモデルも使用したいため、以下の「Request」を押下します。

以下のようなダイアログがでるので必要事項を入力して「Request」を押下します。

その後特に時間はかからずAnthropic社のモデルも"Available"に変わります。

チェックできるものにチェックをして「Save changes」を押下します。

"In Progress"状態となるのでしばらく待ちます。

"Access granted"に変われば準備完了です。

Python環境

Python環境はローカルマシン内にRyeで構築しました。

Pythonのバージョンは3.10.13です。

ライブラリのバージョンは以下の通りです。

boto3==1.28.57
langchain==0.0.305

boto3でのテスト

まずはboto3でテストをしてみます。以下のようなコードで検証しました。

from boto3.session import Session
import json

session = Session(profile_name="{プロファイル名}")

bedrock_runtime = session.client("bedrock-runtime", region_name="us-east-1")

resp = bedrock_runtime.invoke_model(modelId="ai21.j2-ultra-v1",
    body=json.dumps({"prompt":"Hi there!", "temperature": 0.0}))

body = resp["body"].read()

json.loads(body)["completions"][0]["data"]["text"]

#
# How can I assist you today?

modelIdはAI21 Labs社のJurassic-2 Ultraモデルを指定しています。

各モデルとmodelIdの紐づけは以下を参照ください。

次はこれと同じことをLangChain経由でやってみます。

LangChain - Bedrock

非チャットモデル

LangChainのドキュメントとしては以下に記載があります。

これを参考に以下のようなコードにしました。

from boto3.session import Session
from langchain.llms import Bedrock

session = Session(profile_name="{プロファイル名}")

bedrock_runtime = session.client("bedrock-runtime", region_name="us-east-1")

llm = Bedrock(
    client=bedrock_runtime,
    model_id="ai21.j2-ultra-v1",
    model_kwargs={"temperature":0.0},
)

llm("Hi there!")

#
# How can I assist you today?

bedrock-runtimeのクライアントを引数として与えている点が公式と異なっていますが、こちらでも動作しました。

入出力はboto3を直接扱うよりも扱いやすくなっています。

ただしこれは非チャットモデルの場合で、単純なテキスト生成のタスクではこれで良いのですが、会話をしたい場合は、Chatモデルを使用します。

チャットモデル

LangChainのドキュメントとしては以下に記載があります。

現在、BedrockでチャットモデルのAPIが扱えるのは、Anthropic社のClaudeモデルのみです。

LangChainのコードでも以下のようにな実装となっています。

コードは以下のようにしました。

from boto3.session import Session
from langchain.chat_models import BedrockChat
from langchain.schema import HumanMessage

session = Session(profile_name="{プロファイル名}")

bedrock_runtime = session.client("bedrock-runtime", region_name="us-east-1")

llm = BedrockChat(
    client=bedrock_runtime,
    model_id="anthropic.claude-v1",
    model_kwargs={"temperature":0.0},
)

result = llm([
    HumanMessage(content="Hi there!")
])

print(result.content)

# Hello! My name is Claude.

チャットモデル(履歴付き)

せっかくなので会話履歴ありでも試してみましょう。せっかくなので日本語で。

from boto3.session import Session
from langchain.chat_models import BedrockChat
from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory
from langchain.prompts.chat import (
    ChatPromptTemplate,
    HumanMessagePromptTemplate,
    MessagesPlaceholder,
)

session = Session(profile_name="{プロファイル名}")

bedrock_runtime = session.client("bedrock-runtime", region_name="us-east-1")

llm = BedrockChat(
    client=bedrock_runtime,
    model_id="anthropic.claude-v1",
    model_kwargs={"temperature":0.0, "max_tokens_to_sample": 500},
)

memory = ConversationBufferMemory(return_messages=True)
prompt = ChatPromptTemplate.from_messages([
    MessagesPlaceholder(variable_name="history"),
    HumanMessagePromptTemplate.from_template("""{input}""")
])

llm_chain = ConversationChain(llm=llm, prompt=prompt, memory=memory)
result = llm_chain.run("オススメのお肉料理を一つ教えてください。")
print(result)

#  オススメのお肉料理として、ステーキを挙げたいと思います。
# 
# ステーキは高級感がありながらもシンプルで食べやすい料理です。
# 美味しいお肉を中心としたので、お肉の種類や質を選ぶことがとても重要です。
# リブロースやサーロインなどの赤身肉がおすすめです。
# 
# 調理方法としては、オイルで軽く焼いたり、グリルで焼いたり、パンで挟んだハンバーガーにしたりと、
# いろいろなバリエーションがありますが、なかでも生焼けのまま食べるのが一番の楽しみ方だと思います。
# 
# お肉に合うソースやサラダ、スープなどを添えることで、さらに美味しく頂ける一品になると思います。
# ワインなどのお酒も合わせて、特別な一時を過ごすことができるでしょう。
# 
# 皆様の好みによって、焼き加減やお肉の種類を選べば、最高のステーキを楽しむことができると思います。
# ぜひステーキをオススメしたいと思います!

良い感じに返答してくれています。ステーキが食べたくなりました。続いて作り方と材料を聞いてみます。

出力の改行は適当に付与しています。

また出力が打ち切られていたので、"max_tokens_to_sample": 500もパラメータに指定しました。

指定可能なパラメータはAnthropic社のAPI Referenceに記載がありましたので、ご参考にされてください。

会話の続きで、作り方と材料を聞いてみます。

result = llm_chain.run("その作り方と材料を教えてください。")
print(result)

#  ステーキの作り方と材料は以下のようになります。
# 
# 材料:
# 
# ・牛肉の赤身肉(リブロースやサーロインなど):1枚
# 
# ・塩とこしょう:適量
# 
# ・オリーブオイル:適量
# 
# 作り方:
# 
# 1. お肉を室温に戻しておく。
# 
# 2. お肉の表面が乾いている場合はキッチンペーパーで拭き取る。
# 
# 3. お肉に塩とこしょうをふるって両面を味付けする。
# 
# 4. フライパンにオリーブオイルを熱し、強火でお肉の表面を焼く。
# 
# 5. 表面が焼けたらひっくり返す。
# 
# 6. お肉が焼けるのに合わせて火力を調整し、焼き加減を見ながら焼き上げる。
# 
# 7. 焼き上がったら取り出し、5-10分間程度置いておく。
# 
# 8. スライスして盛り付け、ソースやサラダと一緒に召し上がる。
# 
# ポイント:
# 
# ・お肉は室温にして焼くと均一に焼け上がります。
# 
# ・焼き加減は個人の好みによりますが、生焼けがおすすめです。
# 
# ・焼いた後に置いておく「休ませる」ことで、お肉のうまみが増します。
# 
# ・ナイフでスライスするときは肉の繊維にそって切るとやわらかく切れます。

文脈を理解して回答してくれました!今夜はステーキにしたいと思います!

まとめ

LangChain経由でBedrockを使ってみました。boto3を直接叩くよりもかなり楽に実行できる気がします。

また今回使用したClaudeは日本語で100kトークンという長いコンテキストも扱え、かつチャットモデルなので今後も活用していきたいですね。 今回は、リクエストから使用するまで特に時間はかからなかったですので、是非皆様もお試しください。

本記事がAmazon Bedrockの活用の参考になれば幸いです。