目次
目次
はじめに
AI インテグレーションユニットの山崎です。この記事はヌーラボブログリレー2026 夏の1日目として投稿しています。
2026年1月からBacklog AIアシスタントを開発するチームに所属していますが、それまではBacklogのSREチームにいました。SRE業務の傍ら、2023年ごろから生成AIを使ったチャットボットの開発や、RAG(Retrieval-Augmented Generation、検索拡張生成)の検証に取り組んできました。
2024年後半、その延長として、ヌーラボが利用するBacklogスペースに蓄積された課題やWikiのデータをAmazon Bedrockのベクトルストアに取り込んでRAGを構築するPoC(概念実証)に携わる機会がありました。検索の窓口にはSlackチャットボットを採用し、約半年間取り組みました。本記事では、そのときの経験をもとに、Backlogのデータを利用したRAGの構築とSlackチャットボットの開発について紹介します。そこで向き合うことになったのは、技術の実装そのものより、「情報はあるのに見つからない」という、地味だが深い問題でした。
なお、本記事で扱う内容は2024年10月から2025年4月にかけて調査・実装・検証したものです。登場するサービス名やLLMのモデル名、選択した技術スタックは、いずれも当時選択できたものである点をお断りしておきます。
PoC 概要
Backlogには、日々の課題のやり取りやWikiのページに、さまざまな情報が蓄積されています。ただ、それを必要なときに正しく引き出せているかというと、心もとない面がありました。
PoCでは、このような課題を設定しました。
新しく入ってきたメンバーは、そもそも何をキーワードに検索すればよいのか分かりません。逆にベテランのメンバーであっても、情報が増えるほど検索結果が膨大になり、目的の1件を探し出すのに時間がかかります。キーワードが合わず検索結果がほとんど返らないという逆のケースも起こります。さらに、課題やWikiの本文に書かれていない情報、たとえば図表や添付ファイル、外部リンクの先にある情報は、そもそも検索の対象になりません。
ITツールに不慣れなメンバーや、Backlogを使う習慣がついていないメンバーも一定数います。こうしたメンバーは業務の中心をチャットツールに置いており、Backlogへの情報の集約が進みません。マネージャーが望むようなナレッジの一元管理は、実現できていませんでした。
こうした課題を抱える利用者として二つの層を想定しました。ひとつは、必要な情報をすぐに探し出せない層です。キーワードが分からない新入社員や転職者、検索結果が多すぎる、あるいは少なすぎて情報にたどり着けない組織メンバーが、ここに含まれます。もうひとつは、チャットを主な業務ツールとし、Backlogを積極的に使っていない層です。この二つの層が効率よく情報を検索し、要約を受け取れるアプリケーションを開発することで、情報検索性の向上とBacklog活用の定着を図り、組織全体の業務効率とナレッジマネジメントの質を高めることを狙いとしました。
アプリケーションが扱うデータの範囲は、Backlogの課題とWikiに絞りました。検索対象とするのはテキスト情報のみとし、課題やWikiに添付されたファイルは対象外にしました。添付ファイルまで対象に含めると検証すべき範囲が一気に広がるため、PoCにかけられる期間と工数では対応しきれないと判断しました。
Backlogはプロジェクトごとにアクセス権限が異なるため、検索結果に権限のないプロジェクトの情報が混ざれば、セキュリティ上の問題になります。このアクセス権限をどう検索に反映するかは、PoCを通じて向き合うことになった課題のひとつです。
成果物
PoCの成果物は、Slackから使えるチャットボットです。ユーザーがSlackのチャット画面でスラッシュコマンドやショートカットを実行すると、質問を入力する画面が開きます。ヌーラボが利用するBacklogスペースに蓄積された課題やWikiに関する質問を入力すると、アプリケーションがAmazon Bedrock Knowledge Bases(以下、Knowledge Bases)を利用して情報の検索と回答生成を行います。検索結果は、質問したユーザーが参加するプロジェクトの範囲に絞られます。
回答はSlackのDMで返します。DMにしたのは、二つの理由があります。
- プロジェクトに参加していないユーザーに回答が見えることを避ける
- 質問や回答が他のユーザーに見られることに抵抗が生まれるのではと仮定
Knowledge Basesでは、事前にBacklogの課題とWikiのデータをもとにベクトルストアを作成しておき、ユーザーの質問を受け取ると、ベクトルストアを検索して関連する情報を取得し、回答を生成します。この部分がRAGです。
構成図
Nulaber(ヌーラボの社員)がSlackに質問を送ると、API Gatewayがそのリクエストを受け取り、Lambdaに渡します。Lambdaは、Slackのユーザーごとにセッション情報をDynamoDBで確認します。セッションがなければBacklogでユーザーを認可し、所属プロジェクトを取得します。この所属プロジェクトの情報を検索の絞り込み条件に使いながら、Knowledge Basesに質問を渡します。Knowledge Basesは、ベクトルストア(OpenSearch Serverless)に格納された課題やWikiのデータから関連情報を検索し、回答を生成してLambdaに返します。Lambdaはこの回答をSlackのDMとしてユーザーに送信します。
インフラ構成
構成図に登場するAWSリソースの役割は次のとおりです。
| リソース | 役割 |
|---|---|
| API Gateway | Slackからのリクエストを受け取り、Lambdaに渡す |
| Lambda | Slackから届いたクエリを処理し、セッション確認や認可、Knowledge Basesへの問い合わせをまとめる |
| DynamoDB | Slackのユーザー単位でセッション情報を保持する |
| Secrets Manager | Slack Appsのシークレットキー、Knowledge Bases ID、API GatewayのURLなどの機密情報を管理する |
| S3 | Backlogの課題とWikiをMarkdownに変換したデータを保管する |
| Knowledge Bases | S3のデータを埋め込んでOpenSearch Serverlessに登録し、クエリに応じて検索結果を返す |
| OpenSearch Serverless | Knowledge Basesが使うベクトルストア |
| CloudWatch Logs | Slackへのクエリ、検索結果、LLMの回答、Lambdaの動作ログを記録する |
各AWSリソースは基本的に東京リージョン(ap-northeast-1)を利用しますが、回答を生成するLLMだけはUSリージョンを利用しています。当時最新のClaude 3.7 SonnetはUSリージョンでのみ提供されており、東京リージョンで使えるClaude 3.5より高い回答精度が見込めたため、こちらを選びました。このモデルはクロスリージョン推論に対応しており、呼び出し元のリージョンから、us-east-1、us-east-2、us-west-2のいずれかに自動的にルーティングされます。
Lambdaが認証情報や所属プロジェクトのIDなどをBacklog API側から取得する部分は、検索結果をユーザーの権限に応じて絞り込む仕組みに使われます。この点は、後述の「ユーザー属性の取得と検索時の利用」で扱います。
Amazon Bedrock Knowledge Basesの構成
データ構造
Knowledge Basesに登録するデータは、Backlogの課題とWikiをMarkdown形式に変換したものです。Markdown化することで、文章に見出しやリストといった構造を持たせられます。この構造がベクトル検索や回答生成の精度に関わってきます。
以下はサンプルです。実際の課題やWikiのデータではありません。課題は## descriptionに本文、## commentsにコメントを並べる構造にしています。
# コンプライアンス文書管理システム Created: 2025-03-20 10:57:00 by Hiroshi Tanaka Updated: 2025-03-24 11:04:43 ## description (課題の本文) ## comments ### comment_1 Created: 2025-03-21 14:32:00 by Yuki Sato (コメントの本文) ### comment_2 Created: 2025-03-21 15:17:00 by Akira Yamamoto (コメントの本文)
一方、Wikiはタグを## TAGS、本文を## CONTENTとして持たせています。
# インシデント対応手順書 ## TAGS インシデント管理 SRE 障害対応 ## CONTENT ### 1. インシデント発生時の初動対応 (手順の本文) ### 2. 障害対応フロー (図や表を含む本文) created: 2025-03-29 15:29:08 updated: 2025-04-02 17:18:08
課題とWikiのそれぞれのMarkdownファイルには、Knowledge Basesのメタデータフィルタリング用のメタデータファイルを一つずつ添えています。ここにスペースID、プロジェクトID、プロジェクトキー、プロジェクトキーID、ドメインなどの属性情報を持たせ、文書とともにベクトルストアへ登録します。検索時の絞り込みにはプロジェクトIDを、回答に添える参照先URLの生成にはプロジェクトキーとプロジェクトキーID、ドメインを使います。
課題のメタデータファイルの例は次のとおりです。
{
"metadataAttributes": {
"SpaceId": { "value": { "type": "STRING", "stringValue": "11" }, "includeForEmbedding": true },
"ProjectId": { "value": { "type": "STRING", "stringValue": "1" }, "includeForEmbedding": true },
"ProjectKey": { "value": { "type": "STRING", "stringValue": "EXAMPLE" }, "includeForEmbedding": true },
"KeyId": { "value": { "type": "STRING", "stringValue": "1" }, "includeForEmbedding": true },
"DomainName": { "value": { "type": "STRING", "stringValue": "example.backlog.jp" }, "includeForEmbedding": true }
}
}
Wikiのメタデータファイルもほぼ同じ構造ですが、参照先URLの生成に使われるProjectKeyとKeyIdは含みません。
S3のデータ構成
Knowledge Basesには、設定できるデータソースの数が5個までという制約があります(2026年6月に登場したAmazon Bedrock Managed Knowledge Baseの場合は200)。Backlogスペースごとにバケットを分けてそれぞれをデータソースとして登録すると、スペースが増えるたびにこの上限に近づいてしまいます。そこで一つのバケットの中にスペースIDごとのフォルダを並べ、バケット全体を一つのデータソースとして扱う構成にしました。
バケットの構成は次のとおりです。フォルダ名にはスペース名ではなくスペースIDを使っています。スペース名は後から変更される可能性があるためです。
my-backlog-datasources
└── output
├── 10
│ ├── issues
│ └── wikis
├── 11
│ ├── issues
│ └── wikis
├── 12
│ ├── issues
│ └── wikis
└── 13
├── issues
└── wikis
issuesとwikisのフォルダには、それぞれ課題とWikiをMarkdown形式でエクスポートしたデータを格納します。課題やWikiの追加・更新・削除が発生すると、この内容をS3に反映し、Knowledge Basesと同期することで検索結果に反映させます。
チャンキング戦略
文書をどの単位で区切るかは、検索の精度に直結します。Knowledge Basesは、埋め込みを行う前に、文書を小さな単位(チャンク)に分割しますが、このチャンクの区切り方が類似度の比較や検索、応答速度といった性能を左右します。チャンクサイズが小さすぎると必要な情報が拾えず、大きすぎると精度が下がります。
Knowledge Basesにはいくつかのチャンキング戦略が用意されており、詳細は「ナレッジベースのコンテンツのチャンキングの仕組み」にまとめられています。Slackチャットボットでは、このうちセマンティックチャンキングを選びました。AWSのドキュメントでは、セマンティックチャンキングについて次のように説明されています。
セマンティックチャンキングは自然言語処理の手法です。テキストを意味のあるチャンクに分割するので、理解度と情報検索が向上します。単に構文的な構造だけでなく、意味的なコンテンツに焦点を当てることで、検索精度を向上させることが狙いです。関連情報をより高い精度で抽出し、操作しやすくなる可能性があります。
課題やWikiをMarkdown形式にしているのは、文書構造に意味を持たせるためでもあります。この構造と、文書そのものの意味的なコンテンツの両方をチャンキングに活かすことで、精度向上を狙いました。
セマンティックチャンキングの設定値は次のとおりです。最大トークン数は、一つのチャンクに含められるテキスト量の上限を意味します。
| 設定項目 | 設定値 |
|---|---|
| 最大トークン数 | 1024 |
| バッファサイズ | 0 |
| ブレークポイントのパーセンタイルしきい値 | 95 |
最大トークン数とバッファサイズを調整し、ブレークポイントのパーセンタイルしきい値はデフォルトのままです。課題やWiki、コメントを合わせても一つの文書はさほど大きくないため、一つの文書を一つのチャンクとして扱えるサイズを狙いました。
埋め込みモデルには、Amazon(Titan Text Embeddings V2、Titan Embeddings G1 – Text V1.2)とCohere(Embed English V3、Embed Multilingual V3)の4つの候補があり、このうちTitan Embeddings G1 – Text V1.2を選びました。このモデルは文書や段落、文の意味に沿ったセマンティック表現を生成するとドキュメントに書かれており、セマンティックチャンキングとの相性を見込んでのことです。
これらの設定値に唯一の正解はなく、文書のフォーマットや量、構造によって調整が必要です。最適な値を見つけるには、検証を繰り返すしかありません。
データソースの解析オプション
Knowledge Basesには3種類のデータソース解析オプションがあり、詳細は「データソースの解析オプション」にまとめられています。デフォルトパーサーはテキストのみを解析し、Amazon Bedrock Data Automationと基盤モデルは図表や画像を含むマルチモーダルデータの解析に対応します。Slackチャットボットで扱う文書はMarkdownファイルだけなので、テキストファイルのみを解析するデフォルトパーサーを選びました。
ユーザー属性の取得と検索時の利用
ベクトルストアには、Backlogの各プロジェクトの課題やWikiが、どのプロジェクトに属するかを示すメタデータとともに格納されています。ただし、それはあくまで文書側の情報です。いま質問しているユーザーがどのプロジェクトに参加しているかは、この経路のどこにも記録されていません。ユーザーが実際に参加しているプロジェクトの範囲内で検索・回答させるには、ユーザー側の所属プロジェクトを、あらかじめ取得しておく必要があります。
初期のSlackチャットボットは、日本国内の全社員が参加しているいくつかのプロジェクトのデータのみを扱うという運用を行っていました。チャットボットとベクトルストアを結ぶ経路にBacklogの認証認可の仕組みが組み込まれておらず、ユーザーごとに検索範囲を変える手立てがなかったためです。
この課題を解決する手法として検討したのが、Backlogの認証と認可の仕組みを使ったOAuth認可です。今回のPoCでは、ヌーラボが利用するBacklogスペースのみをOAuth認可の対象としました。複数のBacklogスペースにまたがるマルチテナントにも対応できる作りにはしましたが、その動作検証までは行いませんでした。
認可までの流れは次のとおりです。まだ認可していないユーザーがSlackチャットボットを起動すると、認可画面に案内されます。対象のBacklogスペースは一つに絞っていたため、入力フォームはそのスペースに固定しました。Backlogに未ログインであれば、先にログイン画面に遷移します。認可に成功すると、取得したアクセストークンとリフレッシュトークンをSlackのユーザーIDに紐づけてDynamoDBに格納します。
認可が済んだあとは、格納しておいたアクセストークンを使って、Backlog APIから所属プロジェクトのプロジェクトIDを取得します。取得できるのは、たとえば101、205、3042、5591といったプロジェクトIDの一覧です。このプロジェクトIDの一覧を、検索時のフィルタ条件として渡します。
OAuthによる認可を行うことで、Backlog APIを通じてユーザーが参加するプロジェクトIDの一覧を取得できるようになりました。複数のBacklogスペースにまたがるマルチテナントへ発展させる場合は、同じくBacklog APIから所属スペースのスペースIDを取得し、フィルタの条件に加えることで実現できると考えています。
ユーザー属性に紐づく検索範囲の絞り込み
RAGによる検索は、ベクトルストアに格納された全データを対象にします。プロジェクトの違いを考慮せずに検索すると、Backlog上では参照権限のないはずのプロジェクトの情報にも、意図せず行き着いてしまう可能性があります。たとえば、一般のメンバーが、経営層だけが参加するプロジェクトの課題を検索で見つけて内容を取得できてしまう、といった状況です。
ここで使ったのが、メタデータフィルタリングです。今回のPoCでは、メタデータフィルタリングを利用して、ユーザーが参加するプロジェクトの情報だけを検索範囲とする実装を行いました。
たとえば、プロジェクト101と205に所属するユーザーAと、プロジェクト205と3042に所属するユーザーBがいて、それぞれのプロジェクトに文書があるとします。ユーザーAは、自分が参加する101と205の文書は検索できますが、参加していない3042の文書は検索できませんし、そこからの回答も得られません。ユーザーBも同様に、205と3042の文書だけが検索対象になります。
この絞り込みには、前述のメタデータファイルに埋め込んだプロジェクトIDを使います。SQLのIN句のように、検索対象とするプロジェクトIDを指定して検索範囲を絞り込みます。この仕組みは、「Amazon BedrockのメタデータフィルタでIN句を使って特定の文書を検索する」でも詳しく紹介しています。
bedrock_agent_client = boto3.client("bedrock-agent-runtime")
response = bedrock_agent_client.retrieve(
knowledgeBaseId=knowledgebase_id,
retrievalQuery={"text": query_value},
retrievalConfiguration={
"vectorSearchConfiguration": {
"filter": {
"in": {
"key": "ProjectId",
"value": ["101", "205"]
}
},
}
},
)
ここに渡すプロジェクトIDは、ユーザーがSlackチャットボットを認可した際にBacklog APIから取得し、セッション情報として保持しておいたものです。
メタデータフィルタを使うことで、Backlogの参照権限を超えた検索を防ぐようになりました。文書ひとつひとつにカスタムメタデータを設定する分、導入とメンテナンスのコストはかかります。
運用コスト
ここでは、インフラの構築にかかった費用、構築後の運用費用、クエリと回答にかかる費用をそれぞれ算出しました。ここで示す費用は2025年4月時点のものであり、AWSおよびAnthropic社の価格改定によって、変動している可能性があります。
Amazon Bedrock Knowledge Bases構築コスト
2025年4月2日・3日と、4月12日・13日の2回にわたって、Knowledge Basesの構築を行いました。後者は、課題のMarkdownを作り直して既存のS3バケットに反映し、Knowledge Basesを再同期したものです。いずれもWikiデータの更新は含まれていません。
4月12日・13日は、全課題のMarkdownとメタデータファイルを再投入しました。途中でS3へのアップロードが止まり、処理を再実行したため、アップロードそのものが2日間にわたりました。Knowledge Basesの再同期は差分で行われるため、埋め込み処理も両日に分散して発生しています。
サービスごとの日次費用は次のとおりです。
| サービス | 2025/4/2 | 2025/4/3 | 2025/4/12 | 2025/4/13 |
|---|---|---|---|---|
| OpenSearch Service | $41.37 | $52.13 | $60.01 | $61.04 |
| Bedrock | $142.58 | $29.95 | $150.31 | $51.40 |
| CloudWatch | $41.02 | $21.61 | $36.59 | $25.37 |
| GuardDuty | $39.51 | $8.39 | $37.51 | $10.39 |
| S3 | $5.10 | $0.24 | $5.11 | $0.25 |
| 合計 | $269.58 | $112.31 | $289.53 | $148.45 |
4月12日・13日の合計は437.98ドルですが、これはこの2日間にかかったアカウント全体の費用です。このうち、Knowledge Basesの構築で実際に増えた費用はBedrockの埋め込み処理分(2日間で201.71ドル)が中心です。OpenSearch ServiceはKnowledge BasesがなくてもPoCの間ずっと発生し続けるベースライン費用で、GuardDutyとCloudWatchはKnowledge Basesの構築とは無関係にアカウントに常時かかる費用です。
Knowledge Basesの規模は、課題とWikiのMarkdownファイルが合計536,703件、メタデータファイルが合計1,073,406件です。
運用コスト概算
運用コストの中心は、OpenSearch Serverlessの日額費用です。データ投入が完了したあとの定常状態では、この日額は約68ドルでした。月に換算すると2,000ドル強になり、一度の構築費用(Bedrockの埋め込み処理分で2日間201.71ドル)よりも、月々のOpenSearch Serverlessの費用の方が大きくなります。もう一つの運用コストはS3のストレージ費用で、構築時点では月額15.70ドル程度でした。
クエリと回答にかかるコスト
Slackから入力したクエリと、LLMからの回答にかかるコストも算出しました。このコストは、次のトークンの合計で決まります。消費するトークンは、検索用キーワードの生成数や検索結果の出力規模、最終回答の出力規模によって前後します。
- ユーザーが入力したクエリと、それを処理するシステムプロンプトにかかるトークン
- 検索用に分解したクエリと、その検索結果の出力にかかるトークン
- 検索結果をクエリとしてLLMに入力する際のトークン
- 最終回答にかかるトークン
この検証で使用したLLMはClaude 3.7 Sonnetです。
検証したいくつかの質問では、いずれも同じような傾向が見られました。クエリを検索用に分解する段階では、入力トークンが1,400前後、出力トークンが200前後で、合計は1,600トークン程度です。ところが、検索結果をもとに最終回答を生成する段階になると、入力トークンは21,000前後まで跳ね上がり、合計は22,000トークン程度になります。これは、クエリ拡張の手法によって5〜6件の検索クエリが生成され、元のクエリと合わせて6〜7件分の検索結果が入力に含まれるためです。検索結果の件数が、回答生成にかかるコストをほぼ決めていると言えます。クエリ拡張については、「Amazon Bedrock Converse APIでTool useのJSONモードを使って”クエリ拡張”と”クエリ分解”を試す」で詳しく紹介しています。
Amazon Bedrockでの基盤モデルのコスト最適化については、AWSの記事に詳しくまとめられています。
運用時の課題
検索の手法については、リランキングとクエリ拡張、クエリ分解の有用性を検証しました。採用したのは、リランキングと、元のクエリにクエリ拡張を加えた検索です。クエリ拡張を採用したことで、ユーザーが入力したクエリだけでは拾えなかった内容も回答に含まれるようになりました。クエリ拡張を使う分だけ検索の回数が増え、その結果がまとめて入力に入るため、前述の回答生成にかかるトークン数につながっています。もう一方のリランキングについては、有無やBedrockのリランクモデルの違いによる有意な差は見られませんでした。Backlogの課題やWikiには特定の領域に関する情報が多く、類似したり重複するような情報が少ないため、リランキングの効果が出にくいのかもしれません。
回答精度にも、切り分けられなかった課題が残りました。Claude 3.5 HaikuとClaude 3.5 Sonnetを比べると、回答精度に違いが見られました。一方、Claude 3.5 SonnetからClaude Sonnet 4に切り替えても、有意な差は見られませんでした(この比較は、PoCの主要な検証期間よりあとの2025年6月に追加で行ったものです)。プロンプト、チャンキング戦略、検索手法、そして元データが持つ情報量のどこに改善の余地があるのかは、時間切れで切り分けに至りませんでした。PoCでは回答精度の良し悪しを感覚的に判断していたため、これらを定量的に評価し、今後の改善材料にすることも課題となりました。
回答精度に劣らず響いたのが、応答速度です。最終的な回答を生成する段階で1〜2分かかりました。ストリーミング出力であれば待たされている感覚は薄れますが、SlackチャットボットはDMで回答を返す設計のため、回答全体が完成するまでユーザーは待つことになります。DMを選んだのは、前述のとおりです。アクセス権限を守る設計を選んだ分だけ、応答速度の面では不利な結果となりました。
もう一つ残ったのが、Knowledge Basesの再構築にかかる時間です。PoCでは、Titan Embeddings G1 – Text V1.2でベクトルストアを構築しました。運用開始後に他の埋め込みモデルに切り替える場合は、536,703件の課題・Wikiすべてを埋め込みし直す必要があります。チャンキング戦略を見直す場合も同様です。ある程度まとまったデータで検索や回答の精度が見込めたとしても、全量を投入した際に思わぬ落とし穴が見えることもあります。そのような場合に、短時間で再構築や検証を繰り返す仕組みが必要です。この仕組みの検討には至りませんでした。
PoCを振り返って、今ならどうするか
もし今、同じPoCをやり直すなら、まず手を入れたいのはチャンキング戦略とMarkdownの構造、そして埋め込みです。
ノイズの除去
課題のコメントには、「ありがとうございます」「了解しました」といった挨拶や、直前のコメントをそのまま引用した文が少なくありません。これらは人間が読む分には自然ですが、埋め込みにとっては意味のない反復にすぎず、ベクトルの重心をぼかす要因になります。Markdown化の前処理に、こうしたノイズを除去する独自のパイプラインの構築が考えられます。
チャンクサイズの見直し
PoCでは、セマンティックチャンキングのチャンクの最大トークンサイズを調整することで、一つの課題やWikiがおおむね一つのチャンクに収まるサイズを狙いました。ただ、これはあくまで「近づける」調整であり、文書によっては複数のチャンクに割れることもあります。見直すなら、サイズの調整でチャンクを揃えるのではなく、明示的に1課題を1チャンクとして扱いたいです。Knowledge BasesにはNONEというチャンキング戦略があり、これを使えばファイル単位がそのまま1チャンクになります。あるいは、先述のノイズ除去と同じ独自パイプラインの中で課題・Wiki単位にファイルを分割しておき、そのままチャンクとして扱う道もあります。
埋め込み時の重み分け
タイトルには課題の要点が凝縮されている一方、本文やコメントは分量が多く、埋め込みの結果がどうしても本文側の意味に引っ張られがちです。課題のタイトルと本文で、埋め込みにかける重みを分けたいところです。ただ、これはKnowledge Basesの標準機能の範囲外です。メタデータのincludeForEmbeddingは、埋め込みに含めるか含めないかの二値でしか制御できず、重み付けというパラメータはありません。実現するには、タイトルと本文を別々に埋め込んでから合成するような、独自のパイプラインを組む必要があります。
これらの改善案は、次の一歩として着手しやすいと考えています。
まとめ
Backlogに蓄積された課題やWikiを、Knowledge Basesを使ってSlackから検索・要約できる形にしました。この検証を通じて見えてきたのは、技術的な実現性そのものよりも、実運用に持ち込むための周辺コストの重さでした。
PoCで実現できたこと
- Backlogの課題・WikiをテキストベースでKnowledge Basesに取り込み、RAGによる検索・回答を実装できた
- OAuth認可とメタデータフィルタの組み合わせで、ユーザーの参照権限を超えない検索範囲を実現できた
- 構築・運用にかかる費用を、サービス単位で把握できた
一方で、次のような課題も残りました
- ユーザーの権限を守ることを優先した設計は、回答が返ってくるまでの体感速度を後回しにした
- 一度きりの構築費用よりも、ベクトルストアを維持し続ける月々の費用の方が大きい
- チャンキング戦略やモデル選定、リランキングの効果は、定量的な評価まで至っていない
Backlogが持つ情報を、検索する側の負担なく届けられるかどうか。キーワードが分からず探し出せない人にも、チャットを主な業務ツールとし、Backlogを積極的に使っていない人にも、探す手間をかけずに情報を届ける入口には立てたと考えています。
参考資料
- ナレッジベースでのコンテンツチャンキングの仕組み – Amazon Bedrock
- データソースの解析オプション – Amazon Bedrock
- Amazon Titan Text Embeddings モデル – Amazon Bedrock
- 認証と認可 | Backlog Developer API
- プロジェクト一覧の取得 | Backlog Developer API
- Knowledge Bases for Amazon Bedrock がメタデータフィルタリングをサポートし検索精度向上 | Amazon Web Services
- Amazon BedrockのメタデータフィルタでIN句を使って特定の文書を検索する
- Amazon Bedrock で基盤モデルを使用する際のコスト最適化 | Amazon Web Services
- Amazon Bedrock Converse APIでTool useのJSONモードを使って”クエリ拡張”と”クエリ分解”を試す

