Step Functionsの勉強がてら、Bedrockとかを使ってreturn falseな上司とLINEしてみる。

Step Funtions触り始めて3日目の人です。
今回の目的は、Step Functionsの「**Call third-party API**」を使ってみたくてやってみた話です。ざっくり言うと、外部APIの呼び出しをLambdaとか使わなくてもできちゃうよ。みたいなやつです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635880/ca3b2c2e-885f-27b6-0fb0-b7e19de34ed4.png)
これですね。これ。

## return falseな上司とは
特に周りにそんな人がいるとかではないのですが、あえて定義するのであればこんな感じです。
```typescript
function unreasonableBoss(input: any): boolean {
　let bossMind = input;
  bossMind = null;
  return false;
}
```


## 最終的にやったこと
LINEのMessaging APIを使って、なにかメッセージを送ったら、Bedrock通して返信が返ってくるといった形です。json以外は完全ノーコードです。

![png1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635880/4ead03fb-eeef-85f8-46ff-2f9c3ad65f97.png)

## 使ったサービス
・Step Funtions
・API Gateway
・EventBridge
・Bedrock (anthropic claude-v2)
・LINE Messaging API

## やったことの流れ
　①LINEのチャンネルの設定
　②LINEからのメッセージを受けるためにAPI Gatewayを設定
　③Step Funtionsのワークフローを作成
　④LINEから受けたメッセージをBedrockに渡す
　⑤Call third-party APIにBedrockの結果を渡して、Messaging APIを叩く

  ### ①～③LINEのチャンネルの設定～Step Funtionsのワークフローを作成
  
  https://qiita.com/Todate/items/9064bcf1b67fa6cc3b81

  LINEからのメッセージを受ける部分は、上記の@Todate様の記事を参考にさせていただきました。Step Funtionsでいうところの、Passの部分までになります。 非常にわかりやすいので詳細は上記の記事を参照していただければと思いますが、今回特にエラー処理等はいれておりませんのでシンプルになっています。
  
  流れを簡単に言うと、Webhookを使ってLINEからAPI Gatewayを通してStep Functionsにメッセージを送るための設定といった感じです。

### ④LINEから受けたメッセージをBedrockに渡す
Map→Pass→Bedrockという流れではあるんですが、今回必要なものとしては、`replyToken`と`text`になりますので、Mapの部分で、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635880/9ce3cbf2-5e0b-2d53-16dc-5c0bd50a6c09.png)
eventとして子に渡しているので、Pass stateでは`text`と`replyToken`をParametersフィルターを使用して、Bedrock側に渡しています。

```json:Pass StateのParameters
{
  "replyToken.$": "$.event.replyToken",
  "output.$": "States.Format('あなたは私の上司です。\n私から、仕事に対しての提案をしますが、\n強い口調かつ理不尽に、必ず否定して日本語で返答してください。\n部下にものを言う感じで敬語は不要です。\n提案「{}」', $.event.message.text)"
}
```
受けるBedrock側に関しては、シンプルにPassで作成したプロンプトをParametersに与えて、
```json:Parameters
{
  "prompt.$": "States.Format('\n\nHuman:{}\n\nAssistant:', $.output)",
  "max_tokens_to_sample": 2000
}
```
出力の部分で、のちに**Call third-party API**で使用する`replyToken`も出力に加える形で付与します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635880/3c38d5ed-ee92-27d6-f430-90f6fa767721.png)

### ⑤Call third-party APIにBedrockの結果を渡して、Messaging APIを叩く
今回は、LINEのreplyのエンドポイントを使用するので、APIパラメータに
```
https://api.line.me/v2/bot/message/reply 
```
を設定します。メソッドは`POST`にします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635880/20724479-5d4b-c048-22bc-6805515a025c.png)

Authenticationに関しては、EventBridge接続リソースを使用して処理されますので、EventBridgeの設定が必要となります。

https://docs.aws.amazon.com/step-functions/latest/dg/connect-third-party-apis.html#http-task-authentication

EventBridgeで認証タイプをAPIキーにして、APIキー名に`Authorization`、値に`Bearer {LINEのチャネルアクセストークン}`を設定して作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635880/426be0b0-21e2-e715-773f-d7020550621f.png)

作成した、EventBridgeのARNをAuthentication設定して、あとはリクエスト本文に`replyToken`や`BedrockOutput.result(Bedrockの結果)`を記載します。
```json:リクエスト本文
{
  "replyToken.$": "$.replyToken",
  "messages": [
    {
      "type": "text",
      "text.$": "$.BedrockOutput.result"
    }
  ]
}
```
これで完成です。あとは保存して、LINEから会社でやりたいことを送ると、こんな感じに返ってきます。

![paper.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635880/cee67342-6336-cae5-2834-16bcabb86113.png)


## さいごに
実装自体はすごくシンプルで、コードをほぼ書かず画面上でポチポチでできました。Lambdaも書かなくていいのは素晴らしいです。コードを書かなくていいものは保守的にもいいと思うので。今回はチャット形式ではなく、一問一答のような形になっていますので、チャットの形でもどこかでやりたいなと。