この記事は、ShipStation GlobalのKenneth Salmon、Edward Boswell、Jack Armstrong、Robert Bahn、Nick Ciubotariuとの共同執筆です。
同じITに関する質問に答え、定型的なチケットを処理することは、ITチームが他の業務に費やせるはずの時間を奪ってしまいます。その時間を取り戻すために、ShipStationのグローバルエンジニアリングチームは構築しました。 Deckhand、Slack向けのAI搭載ITヘルプデスクエージェントである、 Amazon Bedrock AgentCore.
ShipStation Global は、中小規模の出荷業者向けの主要なインテリジェント配送・ロジスティクスプラットフォームであり、チームが効率化するほど顧客へのサービスが向上するというシンプルな信念のもとに運営されています。Deckhand はこの信念を実際に機能させています。Deckhand は、厳選されたナレッジベースから日常的なITや社内の質問に回答し、エラーメッセージのスクリーンショットを読み取り、Jira Service Management のチケットを作成・更新します。
この記事では、ShipStation が Deckhand をどのようにアーキテクチャ設計したかを取り上げます。その結果、受信したチャネル問い合わせの 97.5 パーセントを解決し、従業員から 96 パーセントの肯定的なフィードバック評価を獲得しました(図 1)。
図 1: 3か月間のチャネルカバレッジと肯定的なフィードバック
ビジネス上の課題
Deckhand が解決する問題は、すべてのITチームが共感できるものです。同じ質問が繰り返し寄せられ、営業時間後にエラーメッセージが投稿され、複数のチームから情報を収集する必要があるということです。ShipStation Global では、こうしたやり取りは混雑したヘルプデスクの Slack チャネルで行われており、従業員が質問し、ITが1つのスレッドずつ回答していました。答えは通常、すでに Confluence のハウツー記事、社内イントラネットのページ、あるいは8か月前のスレッドの中に存在していました。それを見つけ出すことが難しい部分でした。
チャネルのデータによってその規模は具体的なものになりました。ローンチ前の 12 か月間で:
- 従業員は 1,500 以上のスレッドを投稿し、その量は増え続けていました。
- 従業員は米国、英国、スペイン、ポーランド、オーストラリア、フィリピンに分散していたため、質問の5分の1以上が米国の営業時間外に届いていました。
- 回答はさまざまな場所に分かれていました。Confluence 記事、イントラネットページやPDF、ITが管理するガイド、そしてチャネル自体の履歴です。
- 繰り返される質問が、構造化されたセルフサービスの手順で対応できたはずの時間を消費していました。
「Deckhand を作ったのは、ヘルプを得ることが Slack で質問するのと同じくらいシンプルであるべきだと考えたからです。チケットフォームを解読したり、虚空にメールを送ったりするのではなく。チケットは生産性の証ではなく運用上の摩擦の兆候だと私たちは考えています。Deckhand はよくある質問をその場で解決し、解決できない場合には会話をワンクリックで完全に文脈化されたチケットに変換することで、従業員エクスペリエンスを向上させ、私たちのチームを『チケットを起票してください』というフレーズを無限に繰り返すことから解放します。」
— ShipStation Global シニアディレクター IT Chris Collins
ソリューション概要
Deckhand は、Slack 上で他のチームメイトと同じように動作します。チャネルに参加し、会話を読み、Slack プロフィールからコンテキストを引き出して、ITの質問にその場で回答します。私たちは、あらゆるフレームワークやモデルを使って大規模にエージェントを構築、接続、最適化するためのプラットフォームである Amazon Bedrock AgentCore 上でこれを実行しています。Amazon Bedrock AgentCore の機能である AgentCore runtime は、分離されたセッションでエージェントをホストするため、サーバーやコンテナを運用する必要はありません。
このソリューションには、図 2 に示す 4 つの主要コンポーネントがあります。
- Slack サービス: FastAPI と Slack Bolt のアプリケーションで、 AWS App Runnerでホストされています。Slack イベントを受信し、ボットが応答すべきかどうかを判断し、リクエスターの Slack プロフィールから氏名、メールアドレス、タイムゾーン、マネージャーを含むユーザーコンテキストペイロードを構築します。
- エージェントサービス: にコンテナとしてデプロイされた Strands エージェントで、 Amazon Bedrock AgentCore runtimeを使用し、Anthropic の Claude を用いてマルチターンのツールエージェントループを管理します。 Amazon Bedrock.
- ツールと知識: 単一の AWS Lambda MCP(Model Context Protocol)ツールとして公開され、 AgentCore Gateway,はAmazon Bedrock AgentCoreの機能で、リクエストを分類し、Jiraチケットの作成・更新を行い、画像を分析します。An Amazon Bedrock ナレッジベース Confluence、社内イントラネット、Slack、マーケティングページからコンテンツをインデックス化し、それを以下に保存する。 Amazon Simple Storage Service (Amazon S3).
- 運用とフィードバック。 Amazon DynamoDB がフィードバックを保存し、 AWS X-Ray が OpenTelemetry を使用してリクエストパスをトレースし、各サービスは Amazon CloudWatch.
図 2: Slack イベントが Slack サービスと Amazon Bedrock AgentCore runtime に入り、そこから Amazon Bedrock ナレッジベース、AgentCore Gateway 対応の Lambda ツール、Jira Service Management、DynamoDB フィードバックへの個別のパスが分かれている様子を示すアーキテクチャ図。
Deckhand がメンバーとして参加しているチャンネルに従業員が投稿すると、Slack サービスはスレッドの全履歴とユーザーコンテキストを収集します。その後、AgentCore runtime API を通じてエージェントを呼び出します。エージェントはナレッジベースを検索し、必要に応じてツールを呼び出します。回答が見つかれば、最終的な応答を返します(図 3)。見つからない場合は、確認のための質問をしたり、チケットの作成を提案したりします(図 4)。
図 3: Deckhand がセルフサービスの手順を回答
図 4: Deckhand がチケットの作成を提案
Deckhand ワークフロー
このセクションでは、前提条件から実際のデプロイまで、Deckhand の実装方法を順を追って説明します。
前提条件
このパターンを実装するには、以下が必要です:
- Amazon Bedrock、AgentCore runtime、および AgentCore Gateway にアクセスできる AWS アカウント。
- イベントサブスクリプション、署名シークレット、およびユースケースに合わせたスコープ設定済みのボットトークンを備えた Slack アプリ。
- Amazon Elastic Container Registry (Amazon ECR) などのコンテナイメージレジストリ。
- Amazon S3 バケットと Amazon Bedrock ナレッジベース。
- 各ランタイムとツールにスコープ設定された AWS Identity and Access Management (IAM) ロール、およびサードパーティの認証情報用の AWS Secrets Manager エントリ。
Strands Agents と AgentCore によるエージェントの構築
エージェントは意図的に軽量に設計されています。オープンソースの Strands Agents SDKを使用すると、エージェントはモデル、ツールのセット、およびシステムプロンプトで構成されます。SDK が推論ループを管理し、モデルがツールを選択し、結果を処理し、回答を生成するまで反復することを可能にします。Deckhand のエージェントサービスは、わずか数行の Python で実装されています。
from strands import Agent
from strands.models import BedrockModel
from strands.tools.mcp import MCPClient
from strands_tools import retrieve
from mcp.client.streamable_http import streamablehttp_client
model = BedrockModel(
model_id=MODEL_ID,
max_tokens=2048,
temperature=0.3,
)
gateway = MCPClient(lambda: streamablehttp_client(url=GATEWAY_URL))
agent = Agent(
model=model,
tools=[gateway, retrieve],
system_prompt=SYSTEM_PROMPT,
)
モデル ID は環境変数で設定されるため、アプリケーションコードを変更せずにモデルを切り替えることができます。
ツールは 2 つの方法でエージェントに統合されます。Amazon Bedrock Knowledge Bases の検索は、1 回のインポートでナレッジベース検索をサポートする Strands のネイティブツールです。分類、チケット管理、ユーザー解決、画像分析などのその他の関数は、AgentCore Gateway に登録された Lambda 関数によって処理されます。Gateway はこれらを MCP ツールとして公開し、Lambda はツール名ごとに各呼び出しをルーティングします。この分離により、ツールのロジックを独立して更新でき、エージェントは再ビルドを必要とせずに Gateway から新しいツールへアクセスできます。
AgentCore runtime はエージェントをコンテナとしてホストするため、サーバーやセッション管理は不要です。Slack サービスはメッセージごとにエージェントを同期的に呼び出し、スレッドのトランスクリプトとユーザーコンテキストを提供し、最終的な応答を投稿します。従業員のプロファイルを含むコンテキストがすべてのリクエストに含まれるため、エージェントはチケットの詳細を自動的に入力できます。
ナレッジベースの設計と回答のルーティング
Deckhand は、以下のコアとなる S3 バックエンドのデータソースを持つ単一の Amazon Bedrock ナレッジベースから回答します:
- Confluence から同期された記事。
- 社内イントラネットから同期された内部ページ、PDF、およびイベント。
- Slack から抽出された解決済みのサポートスレッド(次のセクションで説明)。
各ドキュメントには、タイトル、ソース URL、コンテンツタイプ、イベント日付などのメタデータが含まれています。これにより、たとえばユーザーが今後のイベントや Austin オフィスの週次ランチメニューについて尋ねた場合など、エージェントがコンテンツをフィルタリングできます。
再帰的言語モデル(RLM)によるSlack履歴のマイニング
最も価値のあるデータソースは、解決済みのサポートスレッドのアーカイブです。Deckhandが存在する以前は、Slackは問題が解決される場でした。従業員が問題を記述し、ITが修正手順を案内した長年の記録です。この履歴は、最良のレビュアー——つまり問題が実際に解決された本人——によって検証された、有機的なナレッジベースです。ただしノイズも多い生のエクスポートには雑談、自動アラート、そして実際には解決されなかったスレッドが混在しています。未検証の修正や崩れた要約をインデックス化すると、ナレッジベースが誤った回答を正しい回答と同じ確信度で提示してしまうため、抽出には高い精度が求められます。
マイニングのプロセスは、3段階のパイプラインで構成されます(図5):
- スクリプトがSlack API経由でチャンネルの全履歴をエクスポートし、各スレッドの完全な返信を取得して、スレッドマーカー、タイムスタンプ、返信数を含む構造化ダンプを書き出します。
- DSPyのRecursive Language Model(RLM)は、Amazon Bedrock上でClaudeを実行し、そのエクスポートを単一のプロンプトとしてではなく、サンドボックス化されたPythonのread-eval-print loop(REPL)内で操作可能なメモリ空間として扱います。データに対して反復的に処理を行い、各スレッドを解決済み、未解決、エスカレーション済みに分類し、お知らせや質問でないものを除外します。厳格な基準により品質を維持します。スレッドが解決済みとみなされるのは、実行可能な完全な修正方法がスレッド自体の中に明示されている場合のみです。
- 解決済みの各スレッドについて、RLMは再帰的なサブLLM(大規模言語モデル)呼び出しをオーケストレーションし、構造化されたフィールドを抽出します。各フィールドはPydanticモデルに対して検証されます。フィールドには、問題の要約、元の質問、および解決内容が含まれます。また、修正がセルフサービスで対応可能かチケットが必要か、セルフサービスの手順、関連するアプリケーションとシステム、エラーメッセージ、タグも記録されます。サブLLM呼び出しがスキーマに適合しない結果を返した場合、RLMのコードベースのループがインタープリター内で検証エラーを捕捉し、再試行します。結果は問題ごとに整理されたmarkdownドキュメントとして書き出されます。パイプラインはそのドキュメントをAmazon S3にアップロードし、ナレッジベースがインデックス化できるようにします。
図5:Slack会話のエクスポート分類と抽出ワークフロー
私たちは〜を選びました RLM Slackの全履歴を永続的なサンドボックス変数空間に保持し、エクスポートデータに対する反復的な推論と一貫した出力構造を可能にするためです。その結果、従業員が同僚が以前に解決したことのある問題に直面した際、Deckhandは実証済みの解決策を、多くの場合実行可能な番号付きステップとして提供します。
いつ答えないべきかを見極める
共有チャンネル内のAIボットは、技術的に失敗する前に、社会的に失敗する。Deckhandの最も洗練されたロジックは、いつ黙っていればよいのかを判断する:
- エージェントはすべてのメッセージに対する最初の判断として、それがお知らせ、ソーシャルなメッセージ、あるいは人と人との会話であるかどうかを判定します。その場合、「SKIP」を出力し、Slackサービスは返信を抑制します。
- スレッドでは、元の投稿者にのみ返信します。
- 最後の返信が別の人間のサポート担当者からのものであれば、沈黙を保ちます。すでに人が対応を引き継いでいるからです。
- リプライが誰かの@メンションで始まる場合、そのメッセージはボット宛てのものではありません。
フィードバックの収集
各回答にはフィードバックボタンが付いています。賛成(サムズアップ)はそのまま記録されますが、反対(サムズダウン)を選ぶと「何が問題だったか」を記入する簡単な欄が表示されます。評価は元の質問とボットの回答とともに DynamoDB に保存されます。
ネガティブなフィードバックは、システムプロンプトやエージェントの動作を改善し、ナレッジベースの誤った情報を更新するために使用される貴重なデータセットです。
セキュリティと検証
プロンプトルールは動作を強化しますが、アクセス制御の代替にはなりません。強制はコードとインフラストラクチャを通じて管理されます:
- チケットの作成には明示的な確認が必要です。Deckhand がチケットの作成を申し出ると、Slack サービスは チケットを作成 ボタンで、選択するとエージェントを通じて確認が送信されます。チケットの更新では、ヘルプデスクプロジェクトのパターンに一致する有効なキーのみが受け付けられ、空のコメントは拒否されます。
- 分類は実際に動作する前に検証されます。リクエストの分類は独立した Amazon Bedrock Converse API Pydanticによる検証を経てからJiraに到達する、構造化されたチケットフィールドを返す呼び出し。
- 画像ツールは、Slackのファイルホストからのダウンロードのみに制限されています。ボットトークンで認証し、各リクエストを1件あたり最大5 MBまでの画像5枚に制限し、Converse APIを使用してビジョンモデルにファイルを送信します。
- 認証情報がコードに入らないようになります。Slackトークン、署名シークレット、Jiraの認証情報は以下に保存されます AWS Secrets Manager、そして各サービスとツールはそれぞれ独自のスコープ付き IAM ロールの下で実行されます。
- このプロンプトは行動面の保護措置を定めています。パスワードや多要素認証(MFA)コードを要求しないこと、資格情報をチケットのコメントに書き込まないこと、そしてチケットのフィールドに使用されるプロフィールメタデータを決して公開しないことです。
結果
Deckhandは2026年4月に登場しました。当初は1日約30件のメッセージを処理し、初夏には最大100件に達しました。最初の3ヶ月間で1,935件のメッセージを処理し、1,221件のエージェント会話を開始し、409件のJiraチケットを作成しました。メッセージの97.5パーセントに返信しました。質問の3分の1は、ITチームの誰も勤務していない時間帯に寄せられたもので、そのうちの94パーセントにDeckhandが回答しました。翌朝まで待つことになっていた人々が、その夜に回答を得ることができたのです。
フィードバックはチームが取り組むにつれて改善されました。利用者の不満を解消するためにシステムプロンプトとナレッジベースを改訂した後、肯定的な評価は4月の82パーセントから6月には96パーセントに上昇しました。
最も明確な成果はチケットの抑制でした。エージェントとの会話とは、本来ならばJiraのチケットになっていたであろう質問のことです。1,221件の会話のうち、チケットになったのはわずか409件でした。残りの812件はチャット内で処理されました。チケットを起票し、作業してクローズするまでには約30分かかります。この812件の会話は、3か月で合計約406時間、つまり年間にしておよそ1,600時間に相当します。従業員はその時間を自分の仕事に使うことができ、IT部門は受け付けにその時間を費やさずに済んだのです。
結論
Deckhandは繰り返し発生するIT関連の質問を従業員の肩代わりに引き受け、従業員とITチームの両方に時間を取り戻させました。これが機能するのは、スタックの各部分が単一の役割を持ち、マネージドサービスとして動作するからです。AgentCore runtimeがエージェントをホストし、AgentCore GatewayがLambda関数をエージェントが呼び出せるMCPツールに変換し、Amazon Bedrock Knowledge Basesが検索を担当します。チームはサーバーを立ち上げたりオーケストレーションコードを保守したりすることなく、これを出荷しました。
同様のソリューションを構築するには、適切に管理されたナレッジソースと明確に定義されたアクションから始めてください。エージェント開発については、 Amazon Bedrock AgentCore documentation および Strands Agents SDK を、コンテンツソースの接続については、 Amazon Bedrock Knowledge Bases documentation を参照してください。
お客様の組織におけるエージェンティックAIのユースケースについて相談するには、AWSアカウントチームにお問い合わせください。
