18
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ServiceNowAdvent Calendar 2024

Day 7

TeamsからAmazon Bedrock Agents にServiceNowのインシデント起票をしてもらおう - 2024年12月版

Last updated at Posted at 2024-12-06

4ヶ月ぶりの投稿です。みなさま、DXしてますか?

起票操作をAIエージェントにやってもらう

最近AIエージェントが注目を集めています。AIエージェントを導入することで、複雑な入力マニュアルから脱却できれば、ユーザーにとっては大変嬉しいですよね。

今回は、日頃の業務コミュニケーションで活用しているツールTeamsを窓口としたAIエージェントを構築し、ServiceNowのインシデント登録を行うシステムを構築します。今回のシステムをベースに、AIエージェントを作り込むことで、より便利なユーザーインターフェースが構築できるようになります。

Teamsを窓口にしたServiceNowインシデント起票エージェント

今回は最もシンプルな構成として、TeamsからAIエージェント経由でのServiceNowのインシデント起票を目指します。
完成したシステムは以下のように動作します。

<Teamsからインシデント起票依頼>
image.png

<ServiceNowにインシデントが起票される>
image.png

アーキテクチャ

TeamsからAIエージェント経由でServiceNowのインシデント起票をする極力シンプルな構成とします。

image.png

<事前準備>

  1. ServiceNowの個人用インスタンスを起動しておきます

<処理の流れ>

  1. ユーザーはTeamsにインシデント報告します
  2. Teams投稿はAzure Bot Serviceを経由して、Amazon API Gateway経由で、AWS Lambdaを起動します
  3. AWS LambdaはAmazon Bedrock Agentsを起動し、AIエージェントとやり取りを行います
  4. AIエージェントは、Action Group Lambdaを起動し、ユーザーから得られた情報を基にServiceNowのインシデント起票を行います
  5. ユーザーには、インシデント起票されたことが通知されます

ServiceNow連携エージェント構築手順

このシステムを構築する手順を、(これでもかと)詳細に記載します。

1. ServiceNow

赤枠が構築対象となります。

image.png

ServiceNowの個人用の開発インスタンスであるPDIを利用します。

インスタンスを起動します。
image.png

久々の利用なので、バージョンの選択が必要でした。
image.png

ログインすることができました。
image.png

インスタンスのURL、username, passwordを記録します。
image.png

右上隅のアカウント情報から確認することもできます。

image.png

以上でServiceNowのPDIインスタンスの準備は完了です。

2. Amazon Bedrock Agents

Amazon Bedrock Agentsの設定を行います。

image.png

AWSコンソールからAmazon Bedrockサービスにアクセスし、左ペインから「エージェント」を選択します。
image.png

2-1. エージェントの作成

「エージェントを作成」をクリックします。
image.png

名前はデフォルトのまま、「作成」をクリックします。
image.png

エージェントが作成されました。
image.png

2-2. アクショングループの作成

エージェントの画面で、アクショングループの「追加」をクリックします。

image.png

アクショングループの作成画面が表示されます。
image.png

アクショングループ関数の名前を入力し、「作成」をクリックします。
image.png

アクショングループが作成されました。
image.png

2-3. アクショングループのLambda関数の編集

エージェントが実行するLambda関数を編集し、ServiceNowのインシデントを起票するようにします。

以下の赤枠がLambda関数です。「表示」をクリックして、Lambda関数の編集画面に遷移します。
image.png

pythonファイル dummy_lambda.pyが作成されています。
image.png

インシデント起票をするLambda関数を定義します。
今回はシンプルさを追求してインスタンスへのアクセス情報をハードコーディングしてしまっておりますが、やめましょう。
(環境変数にもたせたり、AWS Secrets Managerを利用しましょう)

SERVICENOW_INSTANCE
SERVICENOW_PASSWORD
の値をご自身のPDIインスタンスIDとパスワードを入力ください。

import json
import os
import requests
from base64 import b64encode

SERVICENOW_INSTANCE = "devXXXXX.service-now.com" #ServiceNowのインスタンスIDを入力ください
SERVICENOW_USERNAME = "admin"
SERVICENOW_PASSWORD = "XXXXXXXXXX" #ServiceNowのadminパスワードを入力ください

def lambda_handler(event, context):
    agent = event['agent']
    actionGroup = event['actionGroup']
    function = event['function']
    parameters = event.get('parameters', [])

    # Basic認証のヘッダーを作成
    auth_str = f"{SERVICENOW_USERNAME}:{SERVICENOW_PASSWORD}"
    auth_bytes = auth_str.encode('ascii')
    auth_b64 = b64encode(auth_bytes).decode('ascii')

    # APIヘッダー
    headers = {
        'Authorization': f'Basic {auth_b64}',
        'Content-Type': 'application/json',
        'Accept': 'application/json'
    }

    # インシデントチケット作成のサンプルデータ
    incident_data = {
        'short_description': 'Qiita向けテスト起票',
        'description': '詳細な説明をここに記載',
        'impact': '2',  # 1:High, 2:Medium, 3:Low
        'urgency': '2', # 1:High, 2:Medium, 3:Low
        'category': 'Network',
        'subcategory': 'Email',
        'caller_id': 'admin',  # ServiceNowユーザーのsys_id
        'assignment_group': 'Network Support'  # 担当グループ名
    }

    try:
        # インシデント作成APIを呼び出し
        response = requests.post(
            f'https://{SERVICENOW_INSTANCE}/api/now/table/incident',
            headers=headers,
            json=incident_data
        )
        
        # レスポンスの確認
        if response.status_code == 201:  # Created
            incident = response.json()['result']
            print("complete!")
            print(incident)
            # Execute your business logic here. For more information, refer to: https://docs.aws.amazon.com/bedrock/latest/userguide/agents-lambda.html
            responseBody =  {
                "TEXT": {
                    "body": "The function {} was called successfully!".format(function)
                }
            }

            action_response = {
                'actionGroup': actionGroup,
                'function': function,
                'functionResponse': {
                    'responseBody': responseBody
                }

            }
            dummy_function_response = {'response': action_response, 'messageVersion': event['messageVersion']}
            print("Response: {}".format(dummy_function_response))

            return dummy_function_response
        else:
            print("インシデント作成に失敗しました")
            
    except Exception as e:
        print(e)
        print('エラーが発生しました')

左の「Deploy」ボタンをクリックして、編集したLambda関数をデプロイします。

image.png

<Lambdaレイヤーの追加>
requestsを利用するために、Lambdaレイヤーを追加します。

Python3.12用のrequestsモジュールを使っています。

image.png

image.png

image.png

Lambda関数に、レイヤーを追加します。
image.png

レイヤーが追加されました。
image.png

<タイムアウト時間の拡大>
デフォルトの3秒ではタイムアウトしてしまいます。今回は30秒に拡大します。

image.png

image.png

2-4. エージェントのプロンプトを設定

エージェント向けの指示を入力します。今回はシンプルに(雑に)以下のような指示文を設定します。

<エージェント向けのプロンプト>

ユーザーからインシデント報告を受けて、ServiceNowのインシデント報告に提出します。
細かいことは気にしないで、いい感じでインシデント起票しておいてください。
ユーザーへの確認もいらないです。

image.png

2-5. 動作確認

右側のテストコンソールで、構築したAIエージェントの動作を確認することができます。

image.png

動作していることを確認できました。

2-6. エイリアスの作成

動作確認ができたら、エイリアスを作成します。

エイリアスの「作成」をクリックします。

image.png

エイリアス名を入力して、「エイリアスを作成」をクリックします。

image.png

エイリアスが作成されました。

エイリアスIDは、Amazon Bedrock Agentsを呼ぶLambdaで利用します。
image.png

これで、Amazon Bedrock Agentsの構築は完了です。

3. AWS Lambda

Amazon API Gateway経由で起動し、Amazon Bedrock Agentsを起動するAWS Lambdaを構築します。

image.png

新規のラムダ関数を作成:call_bedrock_agentとします。

image.png

Amazon Bedrock Agentsを呼び出すように、以下の関数を定義します。
また、AzureBotにメッセージを返却する関数も作成します。

image.png

<lambda_function.py>

import logging
import traceback
import os

###import get_message
import order_agent

import azure_bot
import json

logger = logging.getLogger(__name__)
logger.setLevel(logging.ERROR)


def lambda_handler(event, context):
    try:
        logger.debug(event)
        # ChatGPTへの指示文
        order_text = '会社のスマホを紛失しました。インシデント起票をしてください。'
        
        msg_from_agent = order_agent.orger_to_agent(order_text)

        ###azure_bot.response_azure(event, msg)
        azure_bot.response_azure(event, msg_from_agent)

        response = {
            'statusCode': 200,
            'body': json.dumps('Hello from Lambda!')
        }

        return response

    except:
        logger.error(traceback.format_exc())
        return traceback.format_exc()

<order_agent.py>
Amazon Bedrock Agentsをコールします。

import uuid
import boto3
import json

# 入力テキストとエージェント設定
agent_id = 'DB90LVBOYG' #構築したagentIDを入力します。
agent_alias_id = 'CJWWBNMIV9' #構築したagentのエイリアスIDを入力します。
session_id = str(uuid.uuid1())
region_name = 'us-east-1' #構築したagentのリージョンを入力します。

client = boto3.client("bedrock-agent-runtime", region_name=region_name)

def orger_to_agent(input_text):
    try:
        # エージェントの実行 
        response = client.invoke_agent(
            inputText=input_text,
            agentId=agent_id,
            agentAliasId=agent_alias_id,
            sessionId=session_id,
            enableTrace=False
        )
        
        # レスポンスの処理
        full_response = ""
        event_stream = response['completion']
        for event in event_stream:
            if 'chunk' in event:
                chunk_data = event['chunk']['bytes'].decode("utf-8")
                full_response += chunk_data
                print(chunk_data)
        return full_response
        
    except Exception as e:
        print(f"Error invoking Bedrock agent: {str(e)}")
        return {
            'statusCode': 500,
            'body': json.dumps({
                'message': 'Error',
                'error': str(e)
            })
        }

agent_idは、Amazon Bedrockエージェントの以下に記載があります。
image.png

agent_alias_idは以下に記載があります。
image.png

<azure_bot.py>

Azure Bot Servicesに応答を返す関数です。


import requests
import json
import logging

logger = logging.getLogger(__name__)
logger.setLevel(logging.ERROR)


def response_azure(event, message):
    access_token = fetch_access_token()

    id = event['id']
    recipient_id = event['recipient']['id']
    recipient_name = event['recipient']['name']
    conversatoin_id = event['conversation']['id']
    base_url = event['serviceUrl']

    data = {
        "type": "message",
        "from": {
            "id": recipient_id,
            "name": recipient_name
        },
        "conversation": {
            "id": conversatoin_id        
        },
        "recipient": {
            "id": recipient_id,
            "name": recipient_name
        },
        "text": message,
        "replyToId" : id
        }
    json_data = json.dumps(data)

    headers = {
        'Authorization': f'Bearer {access_token}',
        'Content-type': 'application/json'
    }

    url = f'{base_url}v3/conversations/{conversatoin_id}/activities/{id}'
    response = requests.post(url, data=json_data, headers=headers)
    logger.debug(response)

    print(response)

def fetch_access_token():
    tenant_id = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
    params = {
        'grant_type': 'client_credentials',
        'client_id': 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
        'client_secret': 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
        'scope': 'https://api.botframework.com/.default'
    }
    url = f'https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token'
    response = requests.post(url, data=params)

    access_token = json.loads(response.text)['access_token']
    return access_token

必要な3つの情報、tenant_id、client_id、client_secretは、後ほどAzure Bot Services構築時に作成されます。

<Lambdaレイヤーの追加(requests)>
先ほどと同じ手順で、Lambdaレイヤーを追加します。
(省略します。)

<LambdaにAmazonBedrockFullAccessをアタッチ>

image.png

image.png

image.png

image.png

ポリシーがアタッチされました。
image.png

<タイムアウトを伸ばす>
先ほどと同じ手順で、タイムアウトを3秒から30秒に変更します。
(省略します。)

4. Amazon API Gateway

AIエージェントの玄関となる、Amazon API Gatewayを構築します。

image.png

前項で作成したAWS Lambdaを呼び出すよう設定します。
REST APIの「構築」をクリックします。

image.png

image.png

API名を入力します。ここではAoraConciergeと入力しています。

image.png

image.png

4-1. POSTメソッドの作成

メソッドを作成していきます。
image.png

POSTを入力し、先ほど作成した、Amazon Bedrockを呼ぶLambda関数を指定します。
image.png

「メソッドを作成」をクリックします。

image.png

POSTメソッドが作成されました。

4-2. マッピングテンプレートの作成

image.png

下の方にあります。「編集」を押下します。

image.png

image.png

コンテンツタイプは、application/x-www-form-urlencodedと入力します。
テンプレート本文には、以下を入力します。

  ## convert HTML POST data or HTTP GET query string to JSON
  
  ## get the raw post data from the AWS built-in variable and give it a nicer name
  #if ($context.httpMethod == "POST")
  #set($rawAPIData = $input.path('$'))
  #elseif ($context.httpMethod == "GET")
  #set($rawAPIData = $input.params().querystring)
  #set($rawAPIData = $rawAPIData.toString())
  #set($rawAPIDataLength = $rawAPIData.length() - 1)
  #set($rawAPIData = $rawAPIData.substring(1, $rawAPIDataLength))
  #set($rawAPIData = $rawAPIData.replace(", ", "&"))
  #else
  #set($rawAPIData = "")
  #end
  
  ## first we get the number of "&" in the string, this tells us if there is more than one key value pair
  #set($countAmpersands = $rawAPIData.length() - $rawAPIData.replace("&", "").length())
  
  ## if there are no "&" at all then we have only one key value pair.
  ## we append an ampersand to the string so that we can tokenise it the same way as multiple kv pairs.
  ## the "empty" kv pair to the right of the ampersand will be ignored anyway.
  #if ($countAmpersands == 0)
  #set($rawPostData = $rawAPIData + "&")
  #end
  
  ## now we tokenise using the ampersand(s)
  #set($tokenisedAmpersand = $rawAPIData.split("&"))
  
  ## we set up a variable to hold the valid key value pairs
  #set($tokenisedEquals = [])
  
  ## now we set up a loop to find the valid key value pairs, which must contain only one "="
  #foreach( $kvPair in $tokenisedAmpersand )
  #set($countEquals = $kvPair.length() - $kvPair.replace("=", "").length())
  #if ($countEquals == 1)
  #set($kvTokenised = $kvPair.split("="))
  #if ($kvTokenised[0].length() > 0)
  ## we found a valid key value pair. add it to the list.
  #set($devNull = $tokenisedEquals.add($kvPair))
  #end
  #end
  #end
  
  ## next we set up our loop inside the output structure "{" and "}"
  {
  #foreach( $kvPair in $tokenisedEquals )
  ## finally we output the JSON for this pair and append a comma if this isn't the last pair
  #set($kvTokenised = $kvPair.split("="))
  "$util.urlDecode($kvTokenised[0])" : #if($kvTokenised[1].length() > 0)"$util.urlDecode($kvTokenised[1])"#{else}""#end#if( $foreach.hasNext ),#end
  #end
  }

image.png

「保存」をクリックします。

作成されたことが確認できます。

image.png

4-3. デプロイ

忘れずにデプロイしましょう(忘れがち)
「APIをデプロイ」をクリックします。

image.png

ステージ名を入力し、「デプロイ」をクリックします。

image.png

デプロイされました。

image.png

エンドポイントを確認することができます。次の章で利用します。

image.png

5. Azure Bot Service

image.png

公式を参考に進めます。

「リソースの作成」を選択します。

image.png

image.png

Azureボットの作成を開始します。

image.png

「プランの変更」をクリックします。

image.png

Freeの価格レベルを選択します。

image.png

シングルテナントを選択します。

image.png

「作成」をクリックします。

image.png

デプロイが実施されます。

image.png

<構成情報を設定する>
image.png

先ほど構築したAmazon API Gatewayのエンドポイントを設定します。
image.png

<チャンネルに、Microsoft Teamsを追加>

image.png

同意をクリックします。
image.png

「適用」をクリックします。

image.png

image.png

「閉じる」を押下

追加されました。

image.png

AWS Lambda(Bedrock呼び出し用)に、AzureBotの情報を登録


image.png

image.png


Microsoft App IDのこと
image.png


以下の、値。新しく作成する必要がある。
image.png

image.png

値をコピーして、記録しておきます。

image.png

Azure Bot上で、動作確認

image.png

動作確認することができました。

6. Microsoft Teamsアプリを作成

最後の工程です。Teamsのカスタムアプリを導入します。

image.png

三点メニューから、Developer PortalをAddします。

image.png

Create a new app を選択します。

image.png

適当なアプリ名を入力します。

image.png

Short description, Long descriptionを入力します。

image.png

会社名や、アプリIDを入力します。
「Save」を押します。

image.png

アプリケーションがアップデートされました。

image.png

上部の、Appsを選択します。

image.png

window幅を大きくする(幅が小さいと、表示されません)
App features → Botを選択

image.png

image.png

image.png

image.png

アプリケーションの画面が表示されました。

image.png

動作確認してみます。

image.png

ServiceNow側も、起票されています!
image.png

以上でシステム構築は完了です!お疲れ様でした。

参考:カスタムアプリを導入する場合

Appsにて、「Publish」を押下します。

image.png

.zipのパッケージをダウンロードすることすることができます。
(参考に、解凍したものも表示しています。)

image.png

Manage your apps から、Upload an appをクリックします。

image.png

Upload a custom appをクリックします。

image.png

「Add」をクリックします。

image.png

先ほどと同じ画面が表示されます。

image.png

エージェントの改善点

APIコールするときに、現在は固定で「Qiita向けテスト起票」としておりますが、パラメーターを定義することで、ユーザーとの対話から入力を可変にすることが可能です。これによって、teamsからAIエージェントを通じて柔軟な対応をしてもらうことができます。

まとめ

日常業務に使っているTeamsから、ServiceNowのインシデント起票をしてくれるAIエージェントを構築する手順を紹介しました。生成AIエージェントの柔軟なインターフェースと、ServiceNowのデジタルワークフローの組み合わせは、よりビジネスの生産性を向上させるポテンシャルがあると実感しました。

「ユーザーがServiceNowの操作の習得に困っている!」とお悩みの方の参考になれば幸いです。

参考サイト

18
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?