4ヶ月ぶりの投稿です。みなさま、DXしてますか?
起票操作をAIエージェントにやってもらう
最近AIエージェントが注目を集めています。AIエージェントを導入することで、複雑な入力マニュアルから脱却できれば、ユーザーにとっては大変嬉しいですよね。
今回は、日頃の業務コミュニケーションで活用しているツールTeamsを窓口としたAIエージェントを構築し、ServiceNowのインシデント登録を行うシステムを構築します。今回のシステムをベースに、AIエージェントを作り込むことで、より便利なユーザーインターフェースが構築できるようになります。
Teamsを窓口にしたServiceNowインシデント起票エージェント
今回は最もシンプルな構成として、TeamsからAIエージェント経由でのServiceNowのインシデント起票を目指します。
完成したシステムは以下のように動作します。
アーキテクチャ
TeamsからAIエージェント経由でServiceNowのインシデント起票をする極力シンプルな構成とします。
<事前準備>
- ServiceNowの個人用インスタンスを起動しておきます
<処理の流れ>
- ユーザーはTeamsにインシデント報告します
- Teams投稿はAzure Bot Serviceを経由して、Amazon API Gateway経由で、AWS Lambdaを起動します
- AWS LambdaはAmazon Bedrock Agentsを起動し、AIエージェントとやり取りを行います
- AIエージェントは、Action Group Lambdaを起動し、ユーザーから得られた情報を基にServiceNowのインシデント起票を行います
- ユーザーには、インシデント起票されたことが通知されます
ServiceNow連携エージェント構築手順
このシステムを構築する手順を、(これでもかと)詳細に記載します。
1. ServiceNow
赤枠が構築対象となります。
ServiceNowの個人用の開発インスタンスであるPDIを利用します。
インスタンスのURL、username, passwordを記録します。
右上隅のアカウント情報から確認することもできます。
以上でServiceNowのPDIインスタンスの準備は完了です。
2. Amazon Bedrock Agents
Amazon Bedrock Agentsの設定を行います。
AWSコンソールからAmazon Bedrockサービスにアクセスし、左ペインから「エージェント」を選択します。
2-1. エージェントの作成
2-2. アクショングループの作成
エージェントの画面で、アクショングループの「追加」をクリックします。
アクショングループ関数の名前を入力し、「作成」をクリックします。
2-3. アクショングループのLambda関数の編集
エージェントが実行するLambda関数を編集し、ServiceNowのインシデントを起票するようにします。
以下の赤枠がLambda関数です。「表示」をクリックして、Lambda関数の編集画面に遷移します。
pythonファイル dummy_lambda.pyが作成されています。
インシデント起票をする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関数をデプロイします。
<Lambdaレイヤーの追加>
requestsを利用するために、Lambdaレイヤーを追加します。
Python3.12用のrequestsモジュールを使っています。
<タイムアウト時間の拡大>
デフォルトの3秒ではタイムアウトしてしまいます。今回は30秒に拡大します。
2-4. エージェントのプロンプトを設定
エージェント向けの指示を入力します。今回はシンプルに(雑に)以下のような指示文を設定します。
<エージェント向けのプロンプト>
ユーザーからインシデント報告を受けて、ServiceNowのインシデント報告に提出します。
細かいことは気にしないで、いい感じでインシデント起票しておいてください。
ユーザーへの確認もいらないです。
2-5. 動作確認
右側のテストコンソールで、構築したAIエージェントの動作を確認することができます。
動作していることを確認できました。
2-6. エイリアスの作成
動作確認ができたら、エイリアスを作成します。
エイリアスの「作成」をクリックします。
エイリアス名を入力して、「エイリアスを作成」をクリックします。
エイリアスが作成されました。
エイリアスIDは、Amazon Bedrock Agentsを呼ぶLambdaで利用します。
これで、Amazon Bedrock Agentsの構築は完了です。
3. AWS Lambda
Amazon API Gateway経由で起動し、Amazon Bedrock Agentsを起動するAWS Lambdaを構築します。
新規のラムダ関数を作成:call_bedrock_agentとします。
Amazon Bedrock Agentsを呼び出すように、以下の関数を定義します。
また、AzureBotにメッセージを返却する関数も作成します。
<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エージェントの以下に記載があります。
<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をアタッチ>
<タイムアウトを伸ばす>
先ほどと同じ手順で、タイムアウトを3秒から30秒に変更します。
(省略します。)
4. Amazon API Gateway
AIエージェントの玄関となる、Amazon API Gatewayを構築します。
前項で作成したAWS Lambdaを呼び出すよう設定します。
REST APIの「構築」をクリックします。
API名を入力します。ここではAoraConciergeと入力しています。
4-1. POSTメソッドの作成
POSTを入力し、先ほど作成した、Amazon Bedrockを呼ぶLambda関数を指定します。
「メソッドを作成」をクリックします。
POSTメソッドが作成されました。
4-2. マッピングテンプレートの作成
下の方にあります。「編集」を押下します。
コンテンツタイプは、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
}
「保存」をクリックします。
作成されたことが確認できます。
4-3. デプロイ
忘れずにデプロイしましょう(忘れがち)
「APIをデプロイ」をクリックします。
ステージ名を入力し、「デプロイ」をクリックします。
デプロイされました。
エンドポイントを確認することができます。次の章で利用します。
5. Azure Bot Service
公式を参考に進めます。
「リソースの作成」を選択します。
Azureボットの作成を開始します。
「プランの変更」をクリックします。
Freeの価格レベルを選択します。
シングルテナントを選択します。
「作成」をクリックします。
デプロイが実施されます。
先ほど構築したAmazon API Gatewayのエンドポイントを設定します。
<チャンネルに、Microsoft Teamsを追加>
「適用」をクリックします。
「閉じる」を押下
追加されました。
AWS Lambda(Bedrock呼び出し用)に、AzureBotの情報を登録
値をコピーして、記録しておきます。
Azure Bot上で、動作確認
動作確認することができました。
6. Microsoft Teamsアプリを作成
最後の工程です。Teamsのカスタムアプリを導入します。
三点メニューから、Developer PortalをAddします。
Create a new app を選択します。
適当なアプリ名を入力します。
Short description, Long descriptionを入力します。
会社名や、アプリIDを入力します。
「Save」を押します。
アプリケーションがアップデートされました。
上部の、Appsを選択します。
window幅を大きくする(幅が小さいと、表示されません)
App features → Botを選択
アプリケーションの画面が表示されました。
動作確認してみます。
以上でシステム構築は完了です!お疲れ様でした。
参考:カスタムアプリを導入する場合
Appsにて、「Publish」を押下します。
.zipのパッケージをダウンロードすることすることができます。
(参考に、解凍したものも表示しています。)
Manage your apps から、Upload an appをクリックします。
Upload a custom appをクリックします。
「Add」をクリックします。
先ほどと同じ画面が表示されます。
エージェントの改善点
APIコールするときに、現在は固定で「Qiita向けテスト起票」としておりますが、パラメーターを定義することで、ユーザーとの対話から入力を可変にすることが可能です。これによって、teamsからAIエージェントを通じて柔軟な対応をしてもらうことができます。
まとめ
日常業務に使っているTeamsから、ServiceNowのインシデント起票をしてくれるAIエージェントを構築する手順を紹介しました。生成AIエージェントの柔軟なインターフェースと、ServiceNowのデジタルワークフローの組み合わせは、よりビジネスの生産性を向上させるポテンシャルがあると実感しました。
「ユーザーがServiceNowの操作の習得に困っている!」とお悩みの方の参考になれば幸いです。
参考サイト