はじめに
1ユーザー企業の情シス担当者ですが、Claude3.5 Sonnetの力を借りながらLINEでLambdaをキックしてユーザー入力に応答させるLINEボットを作ったので備忘録まとめてみました。
※disclaimer
初心者がClaude3.5に聞きながらこねくり回して作ったので間違いやベストプラクティスに反している部分があるかもしれません。良ければコメントでご教示ください。
用意するもの
・AWSアカウント
・LINE Developerアカウント
・まとまった時間
・諦めない心
Lineアカウントを作ろう!
まず、LINEデベロッパーコンソールにアクセスし、新規アカウントを作成。ビジネス用のアカウントとして登録し、必要な情報を入力します。
ボット用チャネルも作成し、チャネル基本情報の中にある”チャネルシークレット”をどこかに控えておきましょう。同様にMessage API設定の中にある”チャネルアクセストークン”もどこかにコピペしておきます。
Lambda関数を作ろう!
LINEの設定が終わったらいよいよAWSでLambda関数を作っていきます。
AWSコンソールでLambda関数を新規作成。Python 3.12を選択し、アーキテクチャはx86_64で大丈夫です。なお、バージニアリージョンのモデルを使う場合でも後でコードで指定するので問題ないです。(1敗)
※Lambdaに乗っけたコード※
import json
import base64
import hashlib
import hmac
import boto3
import requests
CHANNEL_SECRET = 'シークレットな奴'
CHANNEL_ACCESS_TOKEN = 'あくせすとーくん'
bedrock_runtime = boto3.client(service_name='bedrock-runtime', region_name='us-east-1')
model_id = 'anthropic.claude-3-sonnet-20240229-v1:0'
system_prompt = "必ず日本語で答えてください"
max_tokens = 1000
def lambda_handler(event, context):
print(f"Received event: {json.dumps(event)}")
# Check if this is a test event
if event.get('headers', {}).get('x-line-signature') == 'test_signature':
print("This is a test event, skipping signature verification")
body = event['body']
else:
# Verify LINE signature for real requests
body = event['body']
signature = event['headers'].get('x-line-signature', '')
if not verify_signature(body, signature):
return {'statusCode': 403, 'body': 'Invalid signature'}
# Parse the LINE webhook event
line_event = json.loads(body)
# Handle the message
for event in line_event['events']:
if event['type'] == 'message' and event['message']['type'] == 'text':
reply_token = event['replyToken']
user_message = event['message']['text']
print(f"User message: {user_message}")
ai_response = get_ai_response(user_message)
print(f"AI response: {ai_response}")
send_reply(reply_token, ai_response)
return {'statusCode': 200, 'body': 'OK'}
def verify_signature(body, signature):
hash = hmac.new(CHANNEL_SECRET.encode('utf-8'),
body.encode('utf-8'), hashlib.sha256).digest()
return signature == base64.b64encode(hash).decode('utf-8')
def get_ai_response(message):
user_message = {"role": "user", "content": message}
messages = [user_message]
body = json.dumps({
"anthropic_version": "bedrock-2023-05-31",
"max_tokens": max_tokens,
"system": system_prompt,
"messages": messages,
"temperature": 0.7,
"top_p": 0.9,
})
response = bedrock_runtime.invoke_model(
modelId=model_id,
contentType='application/json',
accept='application/json',
body=body
)
response_body = json.loads(response.get('body').read())
return response_body['content'][0]['text']
def send_reply(reply_token, message):
if reply_token == "1234567890abcdef": # This is our test token
print(f"Test mode: Would have sent message: {message}")
return
url = 'https://api.line.me/v2/bot/message/reply'
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {CHANNEL_ACCESS_TOKEN}'
}
data = {
'replyToken': reply_token,
'messages': [{
'type': 'text',
'text': message
}]
}
response = requests.post(url, headers=headers, data=json.dumps(data))
print(f"Status Code: {response.status_code}")
print(f"Response Body: {response.text}")
Gatewayを作ろう!
Lambda関数とLINEを繋ぐ橋渡し役としてAPI Gatewayを設定します。まずはAPI Gatewayのページから"APIを作成"を選択。今回はHTTP APIを選びましょう。次のページに進むと、"統合"という項目が出てきます。ここで"Lambda"を選んでください。
統合の設定が終わったら、Lambda関数の選択画面に進みます。ここで先ほど作成したLambda関数の名前を入力するか、ドロップダウンリストから選択してください。リージョンも間違っていないか、念のためチェックしておきましょう。(1敗)
ルートとステージは一回スキップで大丈夫です。これでAPIの基本形ができました。
次に、作成したAPIの詳細ページより、"ルート"の設定を行います。”作成”ボタンを押して、新しいルートを追加していきましょう。
メソッドとリソースパスも忘れずに設定してください。メソッドは「POST」を選びます。準備が出来たらデプロイしてください。
いよいよ,,,
APIのデプロイ時にInvoke URLが設定されるのでLine developerのwebhook URLとしてお使いください。ここまで出来ましたらLineボットに話しかけてみてください。既読になってから文章が返信されたら成功です。
おわりに
いかがでしたか?実務ではClaude3.5にずっと聞きながら作っていました。初めてのLambdaだったのでテストの仕方や各システム間の連携が大変でしたが良い勉強になりました。
※記事を書いている最中にClaude3.5Sonnetが東京に実装されました。上記のlambdaのコード内でモデルをanthropic.claude-3-5-sonnet-20240620-v1:0とし、リージョンをap-northeast-1に修正しました。
いい感じですね。
参考文献
@minorun365 さんが共同執筆されてるRAGハンズオン本
https://www.sbcr.jp/product/4815626440/