はじめに
前回の記事「Amazon Bedrock+Anthropic Claude 3 SonnetでSlackチャットボットを作成する」では、会話履歴を保持しないシンプルなSlackチャットボットを作成しました。
本記事では、DynamoDBを使って会話履歴を保持するチャットボットを作成してみました。会話履歴の呼び出しや更新にLangchainのChatMessageHistoryを使うことで、DynamoDBに会話履歴を保存する処理を簡単に実装できました。
デモ動画
チャットボットとの会話履歴
このように、追加の質問に対し、チャットボットは会話履歴を踏まえた回答を生成しました。
tsuyshi: AIとAGIの違いをAI初学者に分かりやすく説明してください。説明は端的に、200字程度にまとめてください。
bedrock-slack-app: AIとAGIの主な違いは以下のようにまとめられます。
AI(人工知能)は、特定の狭い領域での問題解決を目的とした、人工的にプログラムされた知能システムのことです。AIは人間の知的作業を一部代替するものの、汎用的な知能は備えていません。
一方、AGI(人工般化知能)は、人間並みの汎用的な知性と理解力を持つ知能システムを指します。AGIは自己学習が可能で、様々な領域での問題解決に応用できる知能を有することが期待されています。しかし、AGIの実現にはまだ多くの課題があります。
tsuyoshi: それを実現するには、今後どのような技術やハードウェアが必要と考えられていますか?200字程度にまとめてください。
bedrock-skack-app: AGIを実現するためには、以下のような技術やハードウェアの進歩が必要とされています。
・より強力な計算能力を持つハードウェア(量子コンピューターなど)
・深層学習などの機械学習技術の高度化
・膨大なデータから知識を獲得する技術
・言語理解や推論、問題解決などの高度な人工知能技術
・人間のような感情や意識を模倣するための新たな理論
・脳科学の進歩による人間の知能メカニズムの解明
・倫理的な課題への対応(AGIの安全性など)
これらの技術が統合され、人間の知能を模倣できるようになれば、AGIの実現に近づくと考えられています。
tsuyoshi: なるほど。では、倫理的課題についてはどうでしょう? AGIの倫理的課題はどのようなものが考えられますか?200字程度にまとめてください。
bedrock-slack-app: AGIには以下のような倫理的な課題が考えられます。
・AGIの目的や価値観を人間がコントロールできるか
・AGIが人間に危害を加えるリスクをどう回避するか
・AGIによる職場の自動化が雇用に与える影響
・AGIによるプライバシー侵害やセキュリティ脅威
・AGIの意思決定の透明性と説明責任をどう確保するか
・AGIが人間を超えた場合の人間への影響
・AGIの権利や人工物としての扱いをどうするか
AGIが人間社会に大きな影響を与えることは避けられません。そのため、AGIの開発段階から倫理的配慮を十分に行い、リスクを最小限に抑える必要があります。
構成図
参考情報
環境構築
- 以下のリソースを作成・削除・変更できる権限をもつAWSユーザーを利用すること
- AWS IAM
- AWS Lambda
- AWS CloudFormation
- AWS Secrets Manager
- Amazon API Gateway
- Amazon S3
- Amazon CloudWatch Logs
- Amazon Bedrock
- Amazon DynamoDB
- 使用するAWSリージョンは、us-east-1
- Slack Appを作成するためのアカウントや権限を持っている
開発環境構築
作業環境のOSバージョン
Windows 11上のWSLでUbuntu 23.04を動かしています。
$ cat /etc/os-release | grep PRETTY_NAME
PRETTY_NAME="Ubuntu 23.04"
Python環境
$ python3 --version
Python 3.12.0
$ python3 -m venv .venv
source .venv/bin/activate
$ pip3 install --upgrade pip
$ pip3 --version
pip 24.0 from /home/xxx/.venv/lib/python3.12/site-packages/pip (python 3.12)
AWS SAM CLIインストール
AWS上でサーバーレスアプリケーションを構築、実行するAWS SAMを使用します。
Installing the AWS SAM CLI の手順に従い、AWS SAM CLIをインストールします。今回はx86_64環境でLinux OSを使用するため、x86_64 - command line installerの手順を実行します。
$ sam --version
SAM CLI, version 1.113.0
Slack Appの作成は、以前の記事を参考にしてください。今回は、App Nameをbedrock-slack-app
として作成しました。
Slackシークレット情報をSecret Managerに登録
あらたにシークレットを作成し、ここまでの手順で作成した以下のシークレット情報を登録します。シークレット名は、bedrock-slack-app
とします。このシークレット名は後述のtemplate.yaml内のSECRET_NAMEに定義しているため、異なるシークレット名を使用する場合はtemplate.yaml内のSECRET_NAMEも変更します。
シークレットキー | 値 |
---|---|
SlackSigningSecret | SlackのSigning Secret |
SlackBotToken | SlackのBot User OAuth Token |
アプリケーションの構築
ディレクトリ構造は以下のとおりです。
.
├── bedrock-slack-app
│ ├── __init__.py
│ ├── app.py
│ └── requirements.txt
├── samconfig.toml
└── template.yaml
init.pyは空のファイルです。
bedrock-slack-app/requirements.txtは以下のとおりです。boto3やrequestsも必要ですが、それらはLambdaレイヤーで追加するようtemplate.yamlに記述します。
slack-bolt
slack-sdk
langchain
template.yamlの構成
template.yaml (長いので折りたたんでいます。クリックして展開)
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Bedrock Slack App.
Resources:
BedrockAssitantFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: bedrock-slack-app/
Handler: app.lambda_handler
Runtime: python3.12
Role: !GetAtt LambdaRole.Arn
Timeout: 300
MemorySize: 512
Architectures:
- arm64
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref DynamoDBTable
Environment:
Variables:
SECRET_NAME: 'bedrock-slack-app' # Name of the secret in Secrets Manager
REGION_NAME: 'us-east-1' # Region of the secret in Secrets Manager
DYNAMODB_TABLE_NAME: !Ref DynamoDBTable
Events:
Slack:
Type: Api
Properties:
Method: POST
Path: /slack/events
Layers:
# Layer for AWS Parameter Store and Secrets Manager
# https://docs.aws.amazon.com/systems-manager/latest/userguide/ps-integration-lambda-extensions.html#ps-integration-lambda-extensions-add
- arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:11
# Layer for boto3
# https://github.com/keithrozario/Klayers?tab=readme-ov-file#list-of-arns
- arn:aws:lambda:us-east-1:770693421928:layer:Klayers-p312-arm64-boto3:3
DynamoDBTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: 'bedrock-slack-app-chat-history'
AttributeDefinitions:
- AttributeName: 'SessionId'
AttributeType: 'S'
KeySchema:
- AttributeName: 'SessionId'
KeyType: 'HASH'
BillingMode: PAY_PER_REQUEST
# IAM Role for lambda.
LambdaRole:
Type: "AWS::IAM::Role"
Properties:
RoleName: bedrock-slack-app-lambda-role
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: allow-lambda-invocation
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- lambda:InvokeFunction
- lambda:InvokeAsync
Resource: "*"
- PolicyName: SecretsManagerPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: 'secretsmanager:GetSecretValue' # Required for Lambda to retrieve the secret
Resource: "*"
- PolicyName: allow-bedrock-access
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- bedrock:InvokeModel
- bedrock:InvokeModelWithResponseStream
Resource: "*"
- PolicyName: DynamoDBCrudPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- dynamodb:PutItem
- dynamodb:GetItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource: "*"
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
BedrockLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/lambda/${BedrockAssitantFunction}
RetentionInDays: 14 # Optional. Default retention is 30 days.
Outputs:
BedrockAssitantApi:
Description: "The URL of Slack Event Subscriptions"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/slack/events"
BedrockAssitantFunction:
Description: "Bedrock Assistant Lambda Function ARN"
Value: !GetAtt BedrockAssitantFunction.Arn
BedrockAssitantFunctionIamRole:
Description: "Implicit IAM Role created for Bedrock Assistant function"
Value: !GetAtt LambdaRole.Arn
AWS SAM テンプレートファイル(template.yaml)に、作成するAWSリソースを定義します。
Lambda関数用ロールやポリシー、Lambdaの環境変数などを記述します。その他に、以下のレイヤーやリソースベースポリシーが含まれます。
- Lambda関数からSecrets Managerにアクセスするための
AWS-Parameters-and-Secrets-Lambda-Extension
レイヤー - Lambda関数内からimportするためのboto3をパッケージにしたレイヤー
- BedrockkからLambda関数を扱うためのリソースベースポリシー
- DynamoDBの操作を許可するポリシー
- DynamoDBテーブルの作成とSessionIdをプライマリキーに設定
DynamoDBテーブル名はbedrock-slack-app-chat-history
としています。そのほかに、テーブル操作を許可するポリシーを以下のようにtemplate.yamlに記述しています。
Resources:
BedrockAssitantFunction:
Type: AWS::Serverless::Function
Properties:
(途中省略)
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref DynamoDBTable
(途中省略)
DynamoDBTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: 'bedrock-slack-app-chat-history'
AttributeDefinitions:
- AttributeName: 'SessionId'
AttributeType: 'S'
KeySchema:
- AttributeName: 'SessionId'
KeyType: 'HASH'
BillingMode: PAY_PER_REQUEST
(途中省略)
LambdaRole:
Type: "AWS::IAM::Role"
Properties:
Policies:
(途中省略)
- PolicyName: DynamoDBCrudPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- dynamodb:PutItem
- dynamodb:GetItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource: "*"
Lambdaレイヤーは以下のようにtemplate.yamlに記述しています。
Layers:
# Layer for AWS Parameter Store and Secrets Manager
# https://docs.aws.amazon.com/systems-manager/latest/userguide/ps-integration-lambda-extensions.html#ps-integration-lambda-extensions-add
- arn:aws:lambda:us-east-1:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension-Arm64:11
# Layer for boto3
# https://github.com/keithrozario/Klayers?tab=readme-ov-file#list-of-arns
- arn:aws:lambda:us-east-1:770693421928:layer:Klayers-p312-boto3:4
適用すると、Lambda関数のLayersに以下のように表示されます。
リソースベースポリシーは、以下のようにtemplate.yamlに記述しています。
BacklogSearchFunction:
Type: AWS::Serverless::Function
Properties:
(途中省略)
# Resouse based policy for lambda.
PermissionForBacklogSearchToInvokeLambda:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !GetAtt BacklogSearchFunction.Arn
Action: lambda:InvokeFunction
Principal: bedrock.amazonaws.com
適用すると、Lambda関数の設定のResource-based policy statementsに以下のように表示されます。
template.yaml内のEnvironmentにあるSECRET_NAME
とREGION_NAME
には、それぞれ先ほど作成したSecrets Managerのシークレットの名前とリージョンを設定します。
samconfig.tomlの構成
samconfig.toml (長いので折りたたんでいます。クリックして展開)
# More information about the configuration file can be found here:
# https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html
version = 0.1
[default]
[default.global.parameters]
stack_name = "bedrock-slack-app"
[default.build.parameters]
cached = true
parallel = true
[default.validate.parameters]
lint = true
[default.deploy.parameters]
capabilities = "CAPABILITY_NAMED_IAM"
confirm_changeset = true
resolve_s3 = true
region = "us-east-1"
[default.package.parameters]
resolve_s3 = true
[default.sync.parameters]
watch = true
[default.local_start_api.parameters]
warm_containers = "EAGER"
[default.local_start_lambda.parameters]
warm_containers = "EAGER"
SAM CLIの実行設定ファイル(samconfig.toml)に、SAM CLIを実行する際の設定を定義します。AWS SAMのチュートリアル: Hello World アプリケーションのデプロイを実行した際に作成されるsamconfig.tomlをもとにしています。今回の例では、以下の点を変更しています。
-
[default.global.parameters]
セクションのstack_nameを"sam-app"から"bedrock-slack-app"に変更 -
[default.deploy.parameters]
セクションにregion指定を追加 -
[default.deploy.parameters]
セクションのcapabilitiesを"CAPABILITY_IAM"から"CAPABILITY_NAMED_IAM"に変更
bedrock-slack-app/app.pyの構成
bedrock-slack-app/app.p (長いので折りたたんでいます。クリックして展開)
import ast
import logging
import os
import re
import time
from typing import Any
import boto3
from botocore.exceptions import ClientError
from langchain.callbacks.base import BaseCallbackHandler
from langchain.schema import LLMResult
from langchain_community.chat_message_histories import DynamoDBChatMessageHistory
from langchain_community.chat_models import BedrockChat
from langchain_core.messages import HumanMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from slack_bolt import App
from slack_bolt.adapter.aws_lambda import SlackRequestHandler
CHAT_UPDATE_INTERVAL_SEC = 1
SlackRequestHandler.clear_all_log_handlers()
logging.basicConfig(
format="%(asctime)s [%(levelname)s] %(message)s",
level=logging.DEBUG
)
logger = logging.getLogger(__name__)
class SecretsManager:
"""
Class to retrieve secrets from Secrets Manager
Attributes:
secret_name (str): The name of the secret
region_name (str): The name of the region
client (boto3.client): The client for Secrets Manager
"""
def __init__(self, secret_name, region_name):
self.secret_name = secret_name
self.region_name = region_name
self.client = boto3.client(
service_name='secretsmanager',
region_name=region_name
)
def get_secret(self, key):
"""
Retrieves the value of a secret based on the provided key.
Args:
key (str): The key of the secret to retrieve.
Returns:
str: The value of the secret.
Raises:
ClientError: If there is an error retrieving the secret.
"""
try:
get_secret_value_response = self.client.get_secret_value(
SecretId=self.secret_name
)
except ClientError as e:
raise e
secret_data = get_secret_value_response['SecretString']
secret = ast.literal_eval(secret_data)
return secret[key]
secrets_manager = SecretsManager(
secret_name=os.environ.get("SECRET_NAME"),
region_name=os.environ.get("REGION_NAME")
)
app = App(
signing_secret=secrets_manager.get_secret("SlackSigningSecret"),
token=secrets_manager.get_secret("SlackBotToken"),
process_before_response=True,
)
class SlackStreamingCallbackHandler(BaseCallbackHandler):
"""
A callback handler for handling events during Slack streaming.
Attributes:
last_send_time (float): The timestamp of the last message sent.
message (str): The accumulated message to be sent.
Args:
channel (str): The Slack channel to send messages to.
ts (str): The timestamp of the message to be updated.
"""
last_send_time = time.time()
message = ""
def __init__(self, userid, channel, ts):
self.userid = userid
self.channel = channel
self.ts = ts
self.interval = CHAT_UPDATE_INTERVAL_SEC
self.update_count = 0
def on_llm_new_token(self, token: str, **kwargs) -> None:
"""
Event handler for a new token received.
Args:
token (str): The new token received.
**kwargs: Additional keyword arguments.
"""
self.message += token
now = time.time()
if now - self.last_send_time > self.interval:
# mention_message = f"<@{self.userid}> {self.message}"
# message_blocks = create_message_blocks(mention_message)
app.client.chat_update(
channel=self.channel,
ts=self.ts,
text=f"<@{self.userid}> {self.message}",
# blocks=message_blocks
)
self.last_send_time = now
self.update_count += 1
if self.update_count / 10 > self.interval:
self.interval = self.interval * 2
def on_llm_end(self, response: LLMResult, **kwargs: Any) -> Any:
"""
Event handler for the end of Slack streaming.
Args:
response (LLMResult): The result of the Slack streaming.
**kwargs: Additional keyword arguments.
Returns:
Any: The result of the event handling.
"""
mention_message = f"<@{self.userid}> {self.message}"
message_blocks = create_message_blocks(mention_message)
app.client.chat_update(
channel=self.channel,
ts=self.ts,
text=self.message,
blocks=message_blocks
)
def create_message_blocks(text):
"""
Creates the message blocks for updating the Slack message.
Args:
text (str): The updated text for the Slack message.
Returns:
list: The message blocks for updating the Slack message.
"""
message_context = "Claude 3 Sonnetで生成される情報は不正確な場合があります。"
message_blocks = [
{"type": "section", "text": {"type": "mrkdwn", "text": text}},
{"type": "divider"},
{"type": "context", "elements": [{"type": "mrkdwn", "text": message_context}]},
]
return message_blocks
def handle_app_mentions(event, say):
"""
Handle app mentions in Slack.
Args:
event (dict): The event data containing information about the mention.
say (function): The function used to send a message in Slack.
Returns:
None
"""
channel = event["channel"]
thread_ts = event["ts"]
input_text = re.sub("<@.*>", "", event["text"])
userid = event["user"]
id_ts = event["ts"]
if "thread_ts" in event:
id_ts = event["thread_ts"]
result = say("\n\nお待ちください...", thread_ts=thread_ts)
ts = result["ts"]
message_history = DynamoDBChatMessageHistory(
table_name="bedrock-slack-app-chat-history",
session_id=id_ts,
ttl=3600
)
system_message = """
あなたはチャットでユーザを支援するAIアシスタントです。
* Let's think step by step
* Take a deep breath
* 回答のルールが<rules></rules>にあります。 ルールを理解してください。ルールは必ず守ってください。例外はありません。
* 「〜って何?」「〜とは?」「〜を説明して」というような概要を聞く質問については、「〜の概要」と読み替えてください。
<rules>
* 日本語で質問された場合、必ず日本語で回答してください。
* 質問に具体性がなく回答できない場合は、質問の仕方をアドバイスしてください。、
</rules>
"""
prompt = ChatPromptTemplate.from_messages(
[
("system", system_message),
MessagesPlaceholder(variable_name="messages"),
MessagesPlaceholder(variable_name="human_message")
]
)
callback = SlackStreamingCallbackHandler(userid=userid, channel=channel, ts=ts)
llm = BedrockChat(
model_id="anthropic.claude-3-sonnet-20240229-v1:0",
streaming=True,
callbacks=[callback],
model_kwargs={
"max_tokens": 1000,
"temperature": 0.85,
"top_p": 0.999
},
region_name="us-east-1"
)
# chainの定義
chain = prompt | llm
content = []
content_text = {"type": "text", "text": input_text}
content.append(content_text)
result = chain.invoke(
{
"messages": message_history.messages,
"human_message": [HumanMessage(content=content)]
}
)
message_history.add_user_message(input_text)
message_history.add_ai_message(result.content)
def respond_to_slack_within_3_seconds(ack):
"""
Responds to a Slack message within 3 seconds.
Parameters:
- ack: A function to acknowledge the Slack message.
Returns:
None
"""
ack()
app.event("app_mention")(
ack=respond_to_slack_within_3_seconds,
lazy=[handle_app_mentions]
)
def lambda_handler(event, context):
"""
Lambda function handler for processing Slack events.
Args:
event (dict): The event data passed to the Lambda function.
context (object): The runtime information of the Lambda function.
Returns:
dict: The response data to be returned by the Lambda function.
"""
print(event)
retry_counts = event.get("multiValueHeaders", {}).get("X-Slack-Retry-Num", [0])
if retry_counts[0] != 0:
logging.info("Skip slack retrying(%s).", retry_counts)
return {}
slack_handler = SlackRequestHandler(app=app)
return slack_handler.handle(event, context)
bedrock-slack-backlog-rag-app/app.pyはメンションされたメッセージを取得し、Amazon Bedrockを使用して生成したテキストをストリーミングで返すアプリケーションです。また、DynamoDBChatMessageHistoryを使用して、会話履歴をDynamoDBに保存します。
ビルドとデプロイ
ビルドとデプロイ、Slack Appの設定は以前の記事を参考にしてください。
動作確認
任意のチャンネンルに、rock-slack-app
(Slack Appの作成時に設定した名前)を招待し、メンション形式で依頼をポストします。動作しない場合のログやBedrockが返すレスポンスは CloudWatch Logs に出力されているログが参考になります。
デモ動画の会話履歴は、DynamoDBのテーブルに以下のように保存されています。DynamoDBへの履歴保存や取り出しを自前で実装するとかなり手間がかかりそうですが、LangchainのChatMessageHistoryを使うことで簡単に実装できます。
{
"SessionId": {
"S": "1713112012.742099"
},
"expireAt": {
"N": "1713115654"
},
"History": {
"L": [
{
"M": {
"data": {
"M": {
"additional_kwargs": {
"M": {}
},
"content": {
"S": " AIとAGIの違いをAI初学者に分かりやすく説明してください。説明は端的に、200字程度にまとめてください。"
},
"example": {
"BOOL": false
},
"id": {
"NULL": true
},
"name": {
"NULL": true
},
"response_metadata": {
"M": {}
},
"type": {
"S": "human"
}
}
},
"type": {
"S": "human"
}
}
},
{
"M": {
"data": {
"M": {
"additional_kwargs": {
"M": {}
},
"content": {
"S": "AIとAGIの主な違いは以下のようにまとめられます。\n\nAI(人工知能)は、特定の狭い領域での問題解決を目的とした、人工的にプログラムされた知能システムのことです。AIは人間の知的作業を一部代替するものの、汎用的な知能は備えていません。\n\n一方、AGI(人工般化知能)は、人間並みの汎用的な知性と理解力を持つ知能システムを指します。AGIは自己学習が可能で、様々な領域での問題解決に応用できる知能を有することが期待されています。しかし、AGIの実現にはまだ多くの課題があります。"
},
"example": {
"BOOL": false
},
"id": {
"NULL": true
},
"name": {
"NULL": true
},
"response_metadata": {
"M": {}
},
"type": {
"S": "ai"
}
}
},
"type": {
"S": "ai"
}
}
},
{
"M": {
"data": {
"M": {
"additional_kwargs": {
"M": {}
},
"content": {
"S": " それを実現するには、今後どのような技術やハードウェアが必要と考えられていますか?200字程度にまとめてください。"
},
"example": {
"BOOL": false
},
"id": {
"NULL": true
},
"name": {
"NULL": true
},
"response_metadata": {
"M": {}
},
"type": {
"S": "human"
}
}
},
"type": {
"S": "human"
}
}
},
{
"M": {
"data": {
"M": {
"additional_kwargs": {
"M": {}
},
"content": {
"S": "AGIを実現するためには、以下のような技術やハードウェアの進歩が必要とされています。\n\n・より強力な計算能力を持つハードウェア(量子コンピューターなど)\n・深層学習などの機械学習技術の高度化\n・膨大なデータから知識を獲得する技術\n・言語理解や推論、問題解決などの高度な人工知能技術\n・人間のような感情や意識を模倣するための新たな理論\n・脳科学の進歩による人間の知能メカニズムの解明\n・倫理的な課題への対応(AGIの安全性など)\n\nこれらの技術が統合され、人間の知能を模倣できるようになれば、AGIの実現に近づくと考えられています。"
},
"example": {
"BOOL": false
},
"id": {
"NULL": true
},
"name": {
"NULL": true
},
"response_metadata": {
"M": {}
},
"type": {
"S": "ai"
}
}
},
"type": {
"S": "ai"
}
}
},
{
"M": {
"data": {
"M": {
"additional_kwargs": {
"M": {}
},
"content": {
"S": " なるほど。では、倫理的課題についてはどうでしょう? AGIの倫理的課題はどのようなものが考えられますか?200字程度にまとめてください。"
},
"example": {
"BOOL": false
},
"id": {
"NULL": true
},
"name": {
"NULL": true
},
"response_metadata": {
"M": {}
},
"type": {
"S": "human"
}
}
},
"type": {
"S": "human"
}
}
},
{
"M": {
"data": {
"M": {
"additional_kwargs": {
"M": {}
},
"content": {
"S": "AGIには以下のような倫理的な課題が考えられます。\n\n・AGIの目的や価値観を人間がコントロールできるか\n・AGIが人間に危害を加えるリスクをどう回避するか\n・AGIによる職場の自動化が雇用に与える影響\n・AGIによるプライバシー侵害やセキュリティ脅威\n・AGIの意思決定の透明性と説明責任をどう確保するか\n・AGIが人間を超えた場合の人間への影響\n・AGIの権利や人工物としての扱いをどうするか\n\nAGIが人間社会に大きな影響を与えることは避けられません。そのため、AGIの開発段階から倫理的配慮を十分に行い、リスクを最小限に抑える必要があります。"
},
"example": {
"BOOL": false
},
"id": {
"NULL": true
},
"name": {
"NULL": true
},
"response_metadata": {
"M": {}
},
"type": {
"S": "ai"
}
}
},
"type": {
"S": "ai"
}
}
}
]
}
}
if now - self.last_send_time > self.interval:
の箇所で以下のようにコメントアウトしています。ストリーミングで回答を生成している最中もSection blockを使って出力するする場合はこのコメントアウトを外してください。
# mention_message = f"<@{self.userid}> {self.message}"
# message_blocks = create_message_blocks(mention_message)
app.client.chat_update(
channel=self.channel,
ts=self.ts,
text=f"<@{self.userid}> {self.message}",
# blocks=message_blocks
)
まとめ
前回作成したSlackチャットボットをベースに、DynamoDBを使って会話履歴を保持するSlackチャットボットを作成しました。LangchainのChatMessageHistoryを使うことで、DynamoDBに会話履歴を保存する処理を簡単に実装できました。
system_messageの内容を変更することで、チャットボットのキャラクターをカスタマイズしたり、口調を調整することもできると思います。
もしくは、チャットボットへのメンションでラップのリズムに乗せて説明してください。
といったリクエストを送ると、チャットボットがそれに答えてくれます。(クオリティの善し悪しはさておき)