Amazon Lexは、自然言語モデルを使用して、アプリケーション用のインタラクティブインターフェイスを設計、構築、テスト、および配布する完全な管理AIサービスです。したがって、Amazon Lexで作られたチャットボットは、継続的な会話を送信して受信できるように意図を識別できるため、意図を満たすために必要な情報を表示できます。さらに、Amazon Kendraを使用して、Amazon Lexで特定されていない意図に答えることができます。同様に、サードパーティのオープンAPIを使用すると、同様の効果を得ることができます。 2022年11月、ChatGptがリリースされ、優れた会話能力が示され、ChatGptをOpen APIおよびKendraとして使用することが可能になりました。この投稿では、ChatGPTをオープンAPIとして使用して、事前に定義されていない意図に答えるインタラクティブなチャットボットを実装する方法を説明したいと思います。
ここで実装するアーキテクチャは次のとおりです。 Amazon CloudFrontを使用して、チャット用のWebページを提供します。ユーザーが入力したチャットメッセージは、Amazon API GatewayとAWS Lambdaを使用してLexの意図に答えます。ただし、Lexで認識されていない意図がある場合、Lambda関数を使用してChatGPTでクエリを行い、結果がチャットウィンドウに表示されます。このようなインタラクティブなチャットボットを構成するためのインフラストラクチャは、AWS CDKを使用して作成および管理されます。すべてのインフラストラクチャはサーバーレス(サーバーレス)で構成されているため、メンテナンス面の効率的で変動するトラフィックでも、自動スケーリングを通じてシステムを安定に動作させることができます。

詳細な操作については、以下を参照してください。
ステップ1:ユーザーは、S3に保存されているHTML、CSS、およびJavaScriptをロードして、CloudFrontのドメインを使用してChatBot Webページに接続しようとします。
ステップ2:Webページにチャットメッセージを入力します。この時点で、「/チャット」リソースは、「/チャット」リソースのJSON形式のテキストメッセージを要求します。
ステップ3:CloudFrontはAPIゲートウェイにリクエストを送信します。
ステップ4:APIゲートウェイは、 /チャットリソースに接続されたLambda関数を呼び出します。
ステップ5:Lambda関数は、Lex V2 APIを使用してLexにチャットメッセージを渡します。
ステップ6:LEXは、意図が定義された意図がある場合、対応する動作を実行します。意図が認識できない場合は、ChatGPTに連絡するリクエストを送信してください。
ステップ7:ChatGPTで回答すると、応答は前のステージの逆の順序に配信され、ユーザーに配信されます。
ソウル地域はLex V1をサポートしていませんが、Lex V2のみがサポートしています。したがって、Lex V2の認識テキストを使用して、ユーザーの入力をメッセージにメッセージに送信します。 Lex Runtime V2クライアントは次のように定義します。
import { LexRuntimeV2Client , RecognizeTextCommand } from "@aws-sdk/client-lex-runtime-v2" ; Lambda関数はイベントから分離されており、以下に示すようにボタリアシドまたは植物を使用してメッセージを配信し、Lexから配信された応答からメッセージを抽出して渡します。
const text = event . text ;
let lexParams = {
botAliasId : process . env . botAliasId ,
botId : process . env . botId ,
localeId : process . env . localeId ,
text : text ,
sessionId : process . env . sessionId ,
};
const lexClient = new LexRuntimeV2Client ();
const command = new RecognizeTextCommand ( lexParams );
const data = await lexClient . send ( command );
return {
statusCode : 200 ,
msg : data [ 'messages' ][ 0 ]. content ,
};2023年3月、ChatGptの公式Open APIがリリースされました。新しいAPIのパスは「/V1/Chat/Completions」であり、「GPT-3.5-Turbo」モデルを使用します。このモデルは、既存のモデル「Text-Davinci-003」と比較して90%低コストで使用できますが、ChatGPTで天気を検索することはできません。ここでは、ChatGPTの公式APIとのチャット中に検索をサポートする「Text-Davinci-003」モデルの使用方法について説明します。
リクエストは、Openaiが提供するChatGPT APIによって行われ、「V1/Chat/Completions」がHTTPS投稿に行われます。これを行うには、ここでフェッチを使用します。この時点で、CHATGPTに配信されるリクエストのヘッダーには、以下に示すように承認とコンテンツタイプを含める必要があります。承認に必要なAPIキーは、OpenAI:APIキーによって発行され、環境変数として保存されます。メッセージを要求する場合、ChatGPT APIトランジションガイドに従って、「ユーザー」、「システム」、または「アシスタント」として役割を指定できます。詳細なコードはここにあります(index.mjs)。
import fetch from 'node-fetch' ;
const apiKey = process . env . OPENAI_API_KEY
let msg = "" ;
const res = await fetch ( 'https://api.openai.com/v1/chat/completions' ,{
method : "POST" ,
headers : {
"Authorization" : "Bearer " + apiKey ,
"Content-Type" : "application/json" ,
},
body : JSON . stringify ({
"model" : "gpt-3.5-turbo" ,
"messages" : [
{ "role" : "user" , "content" : prompt },
],
}),
});ChatGPTから送信された応答メッセージを送信するときは、Lexに送信するときに以下の形式に送信する必要があります。この場合、セッションステートには対話と意図を含める必要があり、意図名を入力から抽出する必要があります。さらに、ChatGPTの応答メッセージは「メッセージ」の「コンテンツ」に入れられ、次のように配信されます。
if ( res . ok ) {
const data = await res . json ();
console . log ( "output: " , data . choices [ 0 ]);
msg = `[ ChatGPT ] $ { data . choices [ 0 ]. message . content }`;
console . log ( "msg: " + msg );
const intentName = event . interpretations [ 0 ]. intent . name ; // intent name
response = {
"sessionState" : {
"dialogAction" : {
"type" : "Close"
},
"intent" : {
"confirmationState" : "Confirmed" ,
"name" : intentName ,
"state" : "Fulfilled" ,
},
},
"messages" : [
{
"contentType" : "PlainText" ,
"content" : msg ,
}
]
}
} 「Text-Davinci-003」モデルは、完了APIに従って「V1/Completions」を使用します。ここでは、OpenAI node.jsライブラリを使用して実装されています。詳細なコードはここにあります(index-davinch.mjs)。
import { Configuration , OpenAIApi } from " openai ";
const configuration = new Configuration({
apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
const models = ['text-davinci-003','code-davinci-002'];
const frequency_penalty = 0.5;
const max_tokens = 2000;
const presence_penalty = 0.1;
const temperature = 0;
const top_p = 1;
const model_name = models[0];
const prompt = event.text;
const params = {
model: model_name,
prompt: prompt,
temperature: temperature,
max_tokens: max_tokens,
top_p: top_p,
frequency_penalty: frequency_penalty,
presence_penalty: presence_penalty,
};
const result = await openai.createCompletion(params);
const choices = result.data.choices;
return {
statusCode: 200,
id: result.data.id,
msg: choices[0].text,
}; クライアントは、チャットサーバーに示すようにチャットメッセージを送信し、応答が来たときに受信チャットバブルに表示します。ここのチャットサーバーのアドレスは、CloudFrontのドメインです。詳細なコードはここで確認されています(chat.js)。
function sendRequest ( text ) {
const uri = "/chat" ;
const xhr = new XMLHttpRequest ();
xhr . open ( "POST" , uri , true );
xhr . onreadystatechange = () => {
if ( xhr . readyState === 4 && xhr . status === 200 ) {
response = JSON . parse ( xhr . responseText );
console . log ( "response: " + JSON . stringify ( response ));
addReceivedMessage ( response . msg )
}
};
var requestObj = { "text" : text }
console . log ( "request: " + JSON . stringify ( requestObj ));
var blob = new Blob ([ JSON . stringify ( requestObj )], { type : 'application/json' });
xhr . send ( blob );
}ここでは、TypeScriptを使用してAWS CDKを構成できます。詳細なコードはここにあります(cdk-chatbot-sack.ts)。
LexのLambda関数は、以下のように定義されています。環境には植物と植物症を含める必要があります。ここでは、韓国語でチャットボットを使用しているため、以下に示すように「ko_kr」をローカリッドとして指定します。このラムダ関数には、LexおよびAPIゲートウェイの権限が必要です。
// Lambda for lex
const lambdaLex = new lambda . Function ( this , 'lambda-function-lex' , {
description : 'lambda for chat' ,
functionName : 'lambda-function-lex' ,
handler : 'index.handler' ,
runtime : lambda . Runtime . NODEJS_18_X ,
code : lambda . Code . fromAsset ( path . join ( __dirname , '../../lambda-lex' )),
timeout : cdk . Duration . seconds ( 120 ),
environment : {
botId : "BSZQXD0ABN" ,
botAliasId : "TSTALIASID" ,
localeId : "ko_KR" , // en_US
sessionId : "mysession-01" ,
}
});
const lexPolicy = new iam . PolicyStatement ({
actions : [ 'lex:*' ],
resources : [ '*' ],
});
lambdaLex . role ?. attachInlinePolicy (
new iam . Policy ( this , 'rekognition-policy' , {
statements : [ lexPolicy ],
}),
);
// permission for api Gateway
lambdaLex . grantInvoke ( new iam . ServicePrincipal ( 'apigateway.amazonaws.com' )); LEXの入力は、APIゲートウェイを使用して以下に示すように、「/チャット」リソースを使用してPOSTメソッドを介して受信するように設定されています。
const api = new apiGateway . RestApi ( this , 'api-chatbot' , {
description : 'API Gateway for chatbot' ,
endpointTypes : [ apiGateway . EndpointType . REGIONAL ],
deployOptions : {
stageName : stage ,
},
});
const chat = api . root . addResource ( 'chat' );
chat . addMethod ( 'POST' , new apiGateway . LambdaIntegration ( lambdaLex , {
passthroughBehavior : apiGateway . PassthroughBehavior . WHEN_NO_TEMPLATES ,
credentialsRole : role ,
integrationResponses : [{
statusCode : '200' ,
}],
proxy : false ,
}), {
methodResponses : [
{
statusCode : '200' ,
responseModels : {
'application/json' : apiGateway . Model . EMPTY_MODEL ,
},
}
]
}); CORSをバイパスするには、以下に示すように「/チャット」リソースの動作を登録します。
distribution . addBehavior ( "/chat" , new origins . RestApiOrigin ( api ), {
cachePolicy : cloudFront . CachePolicy . CACHING_DISABLED ,
allowedMethods : cloudFront . AllowedMethods . ALLOW_ALL ,
viewerProtocolPolicy : cloudFront . ViewerProtocolPolicy . REDIRECT_TO_HTTPS ,
});テキストをChatGptに送信し、応答を受信するLambda関数を準備します。 Openai_api_keyは、Openaiが発行したAPIキーです。
const lambdachat = new lambda . Function ( this , 'lambda-chatgpt' , {
description : 'lambda for chatgpt' ,
functionName : 'lambda-chatgpt' ,
handler : 'index.handler' ,
runtime : lambda . Runtime . NODEJS_18_X ,
code : lambda . Code . fromAsset ( path . join ( __dirname , '../../lambda-chatgpt' )),
timeout : cdk . Duration . seconds ( 120 ),
environment : {
OPENAI_API_KEY : "123456" ,
}
}); 便宜上、ソウル地域のCloud9を使用して配布を準備します。 Cloud9は、ブラウザでコードを作成、実行、デバッグするための便利な環境を提供します。 Cloud9コンソールを入力し、[環境を作成]を選択し、以下に示すように名前を入力します。ここで、「チャットボット」を入力しました。その後、残りは維持され、[作成]を選択します。

Cloud9が作成されたら、[開いて]してから、以下に示すように端子を準備します。

以下に示すようにソースをダウンロードしてください。
git clone https : //github.com/kyopark2014/interactive-chat-using-Lex-and-ChatGPTCDKフォルダーに移動して、必要なライブラリをインストールします。 AWS-CDK-LIBはCDK 2.0ライブラリです。
cd interactive - chat - using - Lex - and - ChatGPT / cdk - chatbot && npm install初めてCDKを使用している場合は、以下に示すようにブートストラップを実行する必要があります。ここで、ここのアカウントIDは12桁のアカウント番号を意味します。 AWSコンソールの画面を確認するか、「AWS STS Get-Caller-Identity-Query Account-ID-Output Text」コマンドを確認できます。
cdk bootstrap aws : //account-id/ap-northeast-2Amazon Lex Korean Chatbot Build WorkshopのHello World Botに従ってHelloworldボットを作成します。 「Hello World Bot」は、名前を尋ねてチェックするシンプルなグリーティングボットです。
「Hello World Bot」の作成を完了したら、ボットコンソールにアクセスして「HelloWorldbot」を選択します。以下に示すように、底体は「bszqxd0abn」であることがわかります。

[Helloworldbot]の[エイリアス]を選択すると、以下に示すようにエイリアスを知ることができます。ここから「testbotoalias」を選択します。

以下に示すように、ボタリアシドが「Tstaliasid」であることがわかります。

cloud9に戻り、左ファイルエクスプローラーに「インタラクティブチャット - 使用 - 使用 - 使用 - 使用 - ex-to-chtgpt/cdk-lex/lib/lix-lex-sack.ts」を開き、「lex for lex for lex」を開きます。 Botaliasidを更新します。 SessionIDが現在の値を維持するか、任意の値を入力しました。

さらに、「ChatGptのLambda」の環境に「openai_api_key」を入力します。事前に推奨されるキーがない場合は、OpenAI:APIキーから発行されます。

ここで、CDKを使用して完全なインフラストラクチャを作成します。
cdk deploy正常にインストールされると、次の「出力」が表示されます。ここで、DistributionDomainnameは「d3ndv6lhze8yc.cloudfront.net」であり、weburlは「https://d3ndv6lhze8y5.cloudfront.net/chat.html」です。

AWS Lex Consoleから「HellowWorldBot」を選択し、[Aliase]で[言語]を選択し、以下に示すように[韓国語(韓国(韓国)]を選択します。

[soucet]として「lambda-chatgpt」を選択し、[lambda関数バージョンまたはエイリアス]を選択し、[$ rapt]を選択し、[save]を選択します。

次に、[hellowworldbot]の[意図]に以下に示す[Fallbackintent]を選択します。

下にスクロールダウンして[高度なオプション]を完全なフィルメントから選択し、[フルフィルメントにラムダ関数を使用]を以下に有効にします。

画面上部で[ビルド]を選択して、変更されたコンテンツを適用します。

Weburlの "" https://d3ndv6lhze8yc5.cloudfront.net/chat.html "は、ブラウザのチャット画面に接続されています。以下に示すように、WebブラウザーでLexとチャットできます。意図操作の後の問題である「Lex」の問題は、意図として登録されていませんでした。ブラウザの設定に応じて、ChatGPTへの応答の一部を受け取ることができない場合があります。

インフラストラクチャを使用しなくなった場合は、以下に示すようにすべてのリソースを削除できます。
cdk destroy Amazon LexとChatGptを使用してインタラクティブなチャットボットを実装し、AWS CDKを使用してインフラストラクチャを効果的に開発および運用する方法を説明しました。 ChatGPTを使用することにより、LEXで認識されていない意図に適切な応答をユーザーに提供することで、ユーザビリティを向上させることもできます。 ChatGPTはすでに優れた会話能力を証明しており、さまざまなGPTモデルが現在発表されています。したがって、これらの人工知能モデルをLEXなどのチャットボットサービスに導入することにより、ユーザーの使いやすさを改善し、より良いサービスを提供することが期待されます。