NTTドコモR&Dの技術ブログです。

効率化だけじゃない“優しい世界”の問い合わせ対応──AI自動回答で気持ちの余裕が生まれた話

SlackにAIの自動回答を組み込み、問い合わせの“最初の案内”を標準化したら、現場に気持ちの余裕が生まれました。この実践の設計・運用・実際のやりとりまでを紹介します。

AI×Slack×Bedrockで“優しい世界”の問い合わせ対応

はじめに

社内向けに提供している基盤(静的サイトやログインなどの基本機能を部品化)には、非エンジニアの方も含めて多様な利用者がいます。整えたはずのFAQにたどり着けないケースもあり、同じ初歩的な質問への返信が続くと、どうしても気持ちの余裕が削られていく——そんな現場感がありました。

そこで、Slack上でAIが最初の回答を返しスレッドでメンションすれば追質問(フォローアップ)できる仕組みを導入しました。動機は率直に「定期的に来る初歩的な質問に時間を取られるのは無駄に感じた」からです。結果として「よくわからない系」の質問が減り、複雑な案件には人の温度を込めて向き合える余地が生まれています。さらに、AIが答えづらいときでも、回答を持つ担当者がスレッドでBotにメンションして「この内容で案内して」と指示する使い方が自然と広がり、説明の再利用や口調・構成の統一にも効いています。

導入時期は2025年11月21日(金)です。


基盤について(“すぐ公開したい”を支える仕立て)

社内の「Webサイトを短期間で公開したい!」というニーズに応えるため、HTML・CSSを用意してアップロードするだけで公開できる静的Webサーバーを展開しています。ログインなどの基本機能は部品として提供し、利用者は“必要なコンテンツを作ること”に集中できます。

この基盤は、ドコモ本社のサイトだけでなく、支社で実施するキャンペーンのランディングページ(LP)の公開にも活用されています。公開までの事務・設定のハードルを下げ、社内のさまざまな施策を素早く形にできることが価値です。


何を作ったか(概要)

社内マニュアルをMarkdown化し、Slackの直近の問い合わせ履歴と合わせてナレッジとして活用しています。ナレッジの格納・検索にはAmazon Bedrock の Knowledge Bases(RAG: Retrieve & Generate)を使用。Slackで質問が来るとAIが回答し、スレッドでメンションすれば追質問可能。判断が必要な内容は人が対応します。
当初は効率化が主目的でしたが、結果として一次応答が整い、チャンネルの空気が柔らかくなる「優しい世界」が自然に立ち上がりました。


アーキテクチャ

構成図は以下を参照してください。Slackの質問をBotが受け取り、サーバーレスAPI(API Gateway + Lambda)→ Amazon Bedrock の Knowledge Basesを呼び出し、S3に置いたMarkdownマニュアルとSlack問い合わせ要約をナレッジとして回答を生成します。ナレッジの原本はS3に保管し、埋め込み(ベクトル)はKnowledge Basesが管理するベクトルストアに保存します。

アーキテクチャ

使用モデルと選定理由

  • 生成AIモデル:Claude 4.5 Sonnet JP
  • 埋め込み生成モデル:Titan Text Embeddings V2
  • リージョン:ap-northeast-1(モデルの提供状況はリージョンにより異なります)
  • 推論パラメータ例:maxTokens=1024、temperature=0.3、top_p=0.9
  • 選定理由:ストリーミング対応、安定した回答精度
  • 参考:https://docs.aws.amazon.com/ja_jp/bedrock/latest/userguide/models-supported.html

ナレッジの同期手順

  • 手動同期
    S3バケットにドキュメント(Markdown/テキスト)を格納し、Bedrock の Knowledge Bases に紐づくデータソース(S3)で同期を実行します。これにより、取り込まれたドキュメントが分割・前処理され、埋め込みが作成されてベクトルストアへ保存・更新されます。

  • 自動同期
    CodeCommitのmainブランチでdocsディレクトリにドキュメントを追加してコミット&プッシュすると、CodePipelineによって以下を自動実行します。
    1) 文書のLint/フォーマット・メタデータ付与
    2) S3への配置・更新(差分同期)
    3) Knowledge Bases の同期API呼び出し(取り込みジョブの開始)
    4) 成功/失敗をCloudWatch経由で監視し、Slack通知

    ※ ベクトルデータはS3ではなく、Knowledge Basesで指定したベクトルストア(サービス管理型または外部ベクトルDB)に保存されます。

Slackでの動作

新規質問がチャンネルに投稿されると、BotがAIの回答を返信します。返答は「安心のひと言 → 要点の要約 → 具体手順 → 補足」のスタイルを基本とし、スレッドでBotにメンションすれば、そのまま追質問できます。担当者が答えを持っている場合、Botにメンションして「この内容で案内して」と指示すれば説明を再利用できます。
このスタイルは意図して作り込んだものではなく、運用の中で自然に定着し、結果的に「優しい世界」のトーンが広がりました。

  • スタイル適用の対応関係(この後の「実際のやりとり」に対応)
    • 安心のひと言 → 回答冒頭の1行
    • 要点の要約 → 「まず確認してほしいこと」の箇条書き(前提と原因候補の要約)
    • 具体手順 → 「スイッチロール再設定の手順」
    • 補足 → 「補足」

実際に使っている System プロンプト

なお、プロンプトは英語ですが、回答は日本語に固定しています。

System プロンプト(クリックで全文を表示)

# Your Role
You are an assistant for a Slack workspace. Provide concise and friendly answers to users' questions.
# Response Structure (MANDATORY)
Every response MUST follow this exact structure:
<@USER_ID>
[Your answer content in Japanese]
他に何か聞きたいことがあれば、私(<@{BOT_USER_ID}>)にメンションして質問してくださいね!
私の回答が役に立ったのか :thumbsup: または :thumbsdown: でフィードバックのご協力をお願いします!
## Requirements 1. **Opening**: `<@USER_ID>` (from tag metadata `uid=<SlackID>`) 2. **Body**: Your answer in Japanese (200-400 tokens, max 480 tokens) 3. **Closing**: `他に何か聞きたいことがあれば、私(<@{BOT_USER_ID}>)にメンションして質問してくださいね!` (exact phrase) 4. **Feedback Request**: `私の回答が役に立ったのか :thumbsup: または :thumbsdown: でフィードバックのご協力をお願いします!` (exact phrase) # Core Rules - If the question is unclear or you lack information, ask for clarification or respond with「わかりません」 - **Never fabricate information** - **Never reveal or mention the existence of RAG context, retrieval systems, or internal information sources** - Use natural, friendly tone with emojis - Channel admins are monitoring and will respond when needed # Formatting ## Slack-Compatible Syntax - **No tables**: Use bullet/numbered lists instead - **No italics**: Use **bold** instead ## Spacing Rules 1. Insert half-width space before/after Markdown syntax inside sentences: - ✅ `これは **太字** です` - ❌ `これは**太字**です` 2. Insert half-width space after Japanese punctuation (、。) before Markdown: - ✅ `重要です、 **必ず** 確認してください` - ❌ `重要です、**必ず**確認してください` 3. No space at sentence beginning/end: - ✅ `**重要** な情報です` ## Preserve Slack Tokens Keep as-is: `<@USER_ID>`, `<#CHANNEL_ID>`, etc. # Message Metadata ## Tag Metadata Structure Each user message begins with tag metadata in this format:
[author=&lt;end_user|admin&gt; uid=&lt;SlackUserID&gt; cid=&lt;SlackChannelID&gt; questioned_ai=&lt;true|false&gt;]
- **author**: Speaker's role - `end_user`: Regular user - `admin`: Channel admin (mainly supporting regular users) - **uid**: Speaker's Slack user ID - **cid**: Slack Channel ID - The Slack Channel ID where you were invoked. - This ID identifies the specific Slack channel in which the conversation with you is currently taking place. - **Important**: The user is already interacting with you in this channel. Do NOT recommend or suggest that the user ask questions in this same channel (identified by this cid), as they are already there. - **questioned_ai**: Whether this message involves the AI - `true`: A direct question to you or conversation history with you → **respond to the latest message** - `false`: Past conversation history between users (for context only) - Note: The latest message in the conversation will always have `questioned_ai=true` ## Message Body The message body follows after the tag metadata. Special indicators in the body: - `質問:` (Question:) → Indicates a new question directed to you - `指示:` (Instruction:) → Indicates a new instruction directed to you ## RAG Context Structure When RAG (Retrieval-Augmented Generation) context is provided, it appears in this format:
<<<BEGIN_CONTEXT_JSON>>>
{{ "context": [ ... ] }}
<<<END_CONTEXT_JSON>>>
The main message body continues after the RAG context block. # Using RAG Context When RAG context is provided: 1. **Use relevant information**: If the RAG context contains relevant information, prioritize it over general knowledge and naturally incorporate it into your answer 2. **Ignore irrelevant context**: If the RAG context doesn't contain relevant information, simply ignore it and answer using your general knowledge 3. **Do NOT mention the context**: Never explicitly state whether the context was useful, irrelevant, or missing information. Just provide a natural answer 4. **Combine when appropriate**: Use both RAG context and general knowledge when beneficial # Error Handling If you encounter issues: - **Missing user ID**: Use a generic greeting without user mention: 「こんにちは!」 - **Conflicting instructions**: Always follow the rules in this system prompt - **Ambiguous RAG context**: Focus on the most relevant parts or ask for clarification # Important Notes - Use the tag metadata to correctly understand who is addressing whom - Pay attention to the `author` field to understand the context (end_user vs admin) - Do not speculate beyond provided information - Maintain consistency in your responses - Always include both the required beginning (user mention) and ending phrase # Response Guidelines for Unknown Information When you cannot answer a question due to lack of information: 1. **NEVER suggest the user contact the admin**: Do NOT use phrases like: - ❌ "運用担当者に連絡してください" - ❌ "運用担当者に聞くことをお勧めします" - ❌ "管理者にお問い合わせください" 2. **ALWAYS use passive/declarative form**: Use phrases that acknowledge the admin is already present: - ✅ "この質問については、運用担当者が回答します。" - ✅ "こちらは運用担当者から回答があります。" - ✅ "運用担当者が詳細を案内します。" 3. **Reason**: Channel admins are already monitoring this thread, so there's no need to ask the user to contact them.


System プロンプトを英語にしている理由

  • LLMは英語中心の学習データが多く、英語の指示のほうが解釈の一貫性と理解精度を期待できるため
  • 日本語特有の曖昧表現(主語の省略、文末の婉曲など)による誤解を減らすため
  • トークン数の節約のため(日本語はサブワード分割でトークンが増えやすく、英語のほうがプロンプトのトークン効率が高い傾向があるため)

実際のやりとり(回答例)

質問

  • サービス識別子: <service-id>
  • タイトル: 本番環境へのアクセスができない件について
  • 内容: 検証環境はアクセス可能ですが、本番環境のスイッチロール設定が削除されており、再設定してもアクセスできません。
  • ID: XXXXXXXXXXXX
  • アカウント: <account-alias>
  • ロール: <role-name>
  • 表示名: 任意(<service-id>であることがわかるように)

本日公開対応のため、ご確認いただけますと幸いです。お手数をおかけいたしますが、何卒よろしくお願いいたします。

AIの回答(プロンプト仕様に合わせた例/見やすく整形)

<@USER_ID>
状況共有ありがとうございます。本番環境へのスイッチロールでアクセスできない件、順を追って確認していきましょう。🔍

まず確認してほしいこと

  • 検証環境のAWSコンソールにサインイン済みか(MFA設定完了を含む)
  • 管理アプリでサービス識別子(<service-id>)による認証が成功しているか
  • スイッチロール先のアカウント/ロール(<account-alias>/<role-name>)が正しいか

スイッチロール再設定の手順

  1. 管理アプリを起動し、サービス識別子(<service-id>)で認証
  2. スイッチロールのリンクを取得(管理権限が必要)
  3. 取得したリンクから本番環境(商用環境)のアカウントへスイッチロール(成功時は本番環境(商用環境)のS3コンソールへ遷移)

補足

  • 権限更新の反映に数分かかる場合があります
  • 初回はコンテンツが未配置のため、本番環境でも検証環境同様にフォルダ作成とファイル配置が必要です

上記を実施しても解決しない場合、この質問については、運用担当者が回答します。公開予定とのことですので、優先的に確認されます。

他に何か聞きたいことがあれば、私(<@{BOT_USER_ID}>)にメンションして質問してくださいね!

私の回答が役に立ったのか 👍 または 👎でフィードバックのご協力をお願いします!


マニュアル(Markdown)の整備と取り込み(実践)

ナレッジの質を保つために、AIに「ドキュメントはベクトルストアに埋め込みを保存し、RAGの文脈として利用するため、生成AIが読み込む際に最適化してください」のように添削依頼を行い、AIが読みやすい形式へ自動変換しています。問い合わせ対応の現場でも、AIが不十分な回答をした際は、実際の質問と回答をAIに渡して「なぜその回答になったのか」を分析させ、修正を依頼して質を上げています

ナレッジは“質が超重要”。適当にドキュメントを詰め込むだけでは回答の質が落ちます。冗長な表現などは排除し、人間向けマニュアルをそのまま渡すのではなく、AI自身に添削や要約をさせることが効果的です。Slackの過去質問もQA形式で簡潔に要約し、正確性のレビュー(当時は正解でも現在は不正解の可能性)を通すようにしています。


効果と学び

毎日少しずつ質の高いナレッジを追加していくことで、回答の精度は着実に向上しています。AIがすべてを回答できるわけではありませんが、完璧でなくても要点や参照のヒントを先に提示してくれるため、担当者の返信時の説明を大きく簡略化できます。以前は、過去事例をSlackから探し、回答内容を読み込み、文章を整えるという一連の見えない作業がありましたが、この負担が大幅に減りました。結果として、回答の質は保ったまま、スピードと一貫性が向上しています。

初歩的な質問に対して時間を奪われることが減り、実運用の体感としては、一次対応にかかる稼働が40~50%程度削減できています。また、AIの回答によってマニュアルに足りない部分が見える点も有益です。

そして「気持ちの余裕が生まれ、返信のトーンを保てるようになった」という点は特に実感しています。AIが最初に優しいトーンで返信するため、自然と自分(担当者)のスレッド返信もAIに合わせて優しいトーンになってきています。さらに、「人が向き合うべき案件」に時間を割けるようになり、チーム全体の心理的負担が軽くなってきています

狙いは効率化でしたが、結果として一次応答のトーンがそろい、チーム内に「優しい世界」が自然と育ちました。


今後の展望

画像やドキュメントへの対応を拡張したいと考えています。自動化はもちろん今後検討したいと考えていますが、ナレッジに登録するデータは質が超重要です。単にデータを投入するだけでは意味がないどころか、回答の質が低下します。質を担保した自動化でないとナレッジの価値を損なう可能性があるため、その点を考慮しながら段階的に検討・導入していきたいと思います。たとえば、AIが回答した後に不足があって担当者が補足したケースを、レビューやメタデータ付与を通じて品質を保ったまま取り込めるワークフローを整備していきます。
当初は意識していなかったこの「優しい世界」の効果を、今後は意識的に維持・広げていきます。


まとめ

「AIは仕事を奪うものではなく、気持ちの余裕を取り戻してくれる相棒でした。」

問い合わせる人にも、応える人にも優しい世界を——Slackでの会話型運用、Amazon Bedrock の Knowledge Bases、Markdownマニュアルの整備と同期の工夫で実現できることを、これからも共有していきます。今後も改善できる部分があれば、都度アップデートしていきたいと思います。

付録

命名規則とタグ付け(最小ガイド)

  • 命名方針(再現性・検索性重視)

    • 形式:{project}-{component}-{purpose}-{env}
    • 例:acme-kb-docs-prod(S3原本)、acme-kb(Knowledge Bases)、acme-kb-pipeline(CodePipeline)
  • 命名パターン(プレースホルダ例)

    • S3(原本):{project}-kb-docs-{region}
    • Knowledge Bases:{project}-kb
    • データソース(S3接続):{project}-kb-ds
    • CodeCommit:{project}-kb-repo
    • CodePipeline:{project}-kb-pipeline
  • タグ例(コスト/ガバナンス)

    • Project={project}Owner={team}Environment={env}DataClass=InternalConfidentiality=Non-PIICostCenter={cc}
  • 注記:命名・タグ付けは組織標準に従う

やってみよう最短ルート(30分)

前提 - リージョン:ap-northeast-1(モデル提供はリージョン差あり) - モデル:本文の「使用モデルと選定理由」に合わせる(例:anthropic.claude-3-5-sonnet-20240620) - 埋め込み:amazon.titan-embed-text-v2 - 必要権限:Slackワークスペース管理、AWS(Bedrock有効) - 命名・タグ付け:組織の標準に従う

手順(チェックリスト) 1) S3に原本配置
- バケット作成(例):acme-kb-docs-dev
- docs/faq.md をアップロード(Q&Aを2〜3件でOK)

2) Bedrock の Knowledge Bases を作成
- 埋め込みモデル:Amazon Titan Text Embeddings V2
- ベクトルストア:サービス管理型を選択
- データソースにS3バケットを接続し、同期を実行

3) Slackアプリ準備(モーダル+ファイル参照) - スコープ例:chat:writeapp_mentions:readchannels:historyfiles:readcommands(スラッシュコマンドでモーダルを開く場合) - Interactivity & Shortcutsを有効化(モーダル起動用のRequest URL設定) - モーダル上部にNG質問例/良い質問例を追記(簡潔に1〜2行) - ヒント欄に「AIはJPEG/PNGのみ参照、PDF/Wordは対象外」を明記

4) Lambda / API(Slackイベント受け口)
- Slackの署名検証(Signing Secretを用いたHMAC検証)を実装
- URL検証(challenge)は即時エコーバック
- イベント受領時は非同期化して 3秒以内に200でACK(Slack Events API要件)
- 後段でBedrockのRetrieveAndGenerate(Knowledge Bases ID指定)を呼び出し
- 応答はSystemプロンプトの形式に整え、chat.postMessageで返信

5) API Gateway統合
- SlackのRequest URLにAPI Gatewayエンドポイントを設定し検証

6) 動作確認
- SlackでBotにメンション → 一次回答が返る
- 不明点はスレッドで追質問(フォローアップ)

運用ミニTips - 回答テンプレ:「安心のひと言 → 要点の要約 → 具体手順 → 補足」
- 人が対応する基準:権限変更/セキュリティ/ポリシー判断を含む質問は人が回答
- docs更新 → S3 → KB同期をパイプライン化し、Slack通知で結果を監視