
目次
- 目次
- はじめに
- アーキテクチャ
- Amazon Bedrock Knowledge BasesでRAGを構築する
- AI-ChatBot を作成する
- RAG の検索精度と回答精度を向上させるために
- まとめ
- 終わりに
はじめに
doda DevBizOps Group Advent Calendar 2025の17日目担当の松本です。
最近では CI/CD の文化が広く定着し、私たちの部署でも GitHub Actions を中心に自動化が進んでいます。一方で、設計書・仕様書・ナレッジは更新されず陳腐化しがちで、最新仕様を知るにはコードを直接読む必要がある、という場面も少なくありません。
しかしソースコードは慣れていない人にとって理解が難しく、ドキュメント代わりに扱うには負担が大きいという課題があります。
そこで本記事では、ソースコードや仕様書をベクトル化して検索・参照できる 社内向け RAG(Retrieval-Augmented Generation) を構築し、実用性を検証します。
アーキテクチャ
私たちの部署では主に AWS を利用しており、コード管理には GitHub、ナレッジツールには Atlassian を利用しているため、Amazon Bedrock Knowledge Bases を採用して RAG を構築しました。
最終的なアーキテクチャは下記のようになります。

本番構成では ECS(Fargate)上の API が Aurora PostgreSQL や Bedrock KB にアクセスする想定です。しかし今回は AI SDK と Bedrock KB の動作検証が目的 なので、ECS や Aurora は省略し、ローカルのPC上の Next.js アプリケーションと Docker 上の PostgreSQL を用いて検証しています。
コードの全量はこちらから見れます。
github.com
Amazon Bedrock Knowledge BasesでRAGを構築する
基本的にインフラは AWS CDK を利用して構築しています。
AWS Cloud Development Kit (AWS CDK) を利用すると、TypeScript、Python、Java、C#、Go などのプログラミング言語を使用してInfrastructure as Code(IaC)を実現することができます。
Amazon Bedrock Knowledge Bases (以下 Bedrock KB ) は AWS 上で簡単に RAG を構築できるサービスです。一般的な RAG の構成のうち、データソースのチャンキングやエンべディング、ベクトルストアへの格納までを行ってくれるので内部の処理をあまり意識せずに利用できる点が魅力です。

2024年7月からプレビュー版ではありますが Confluence がデータソースとしてサポートされています。
また、GitHub 上のソースコードやドキュメントは S3 に配置すれば Bedrock KB 側がエンべディングしてくれるため、GitHub Actions の CI/CD フローにも組み込みやすいです。
Bedrock KB ではベクトルストアを指定する必要がありますが、利用可能なサービスは以下のとおりです。
- Amazon OpenSearch Serverless
- Amazon OpenSearch Service Managed Clusters
- Amazon S3 Vectors
- Amazon Aurora (RDS)
- Neptune Analytics graphs (GraphRAG)
- Pinecone
- Redis Enterprise Cloud
- MongoDB Atlas
ただし現時点の Confluence コネクタはプレビュー版で、インデックスの保存先として OpenSearch Serverless のみをサポートしています。
Confluence の認証情報作成
Confluence の認証方式
Confluence をデータソースに指定する場合、認証パターンは2つあります。
- Confluence API Token を利用したBasic認証
- Atlassian App を利用したOAuth2.0 (3LO)
API Token 方式では最大でも1年の有効期限があり、また権限自体は個人に紐づくため、担当者の変更や退職するような組織での利用は適していません。そのため多少準備が面倒ではあるものの、OAuth2.0 (3LO) を選択しました。
Atlassian OAuth App の作成
OAuth方式の場合は、Atlassian OAuth Appを作成する必要があります。こちらはAtlassian Developer コンソール上から簡単に作成できます。
OAuthアプリの認証情報の取得手順は下記の通りです。 developer.atlassian.com
注意点
個人的にハマりポイントでしたが、OAuth App に追加する Confluence API の権限は Classic Scopes では上手く連携できず、
Granular Scopes で下記に示されている権限を与える必要がありました。
特に offline_access 権限は必須で、これを付与しないと RefreshToken が発行されません。
docs.aws.amazon.com
このようにして得た認証情報は、下記のような形式で Secrets Manager に登録する必要があります。
{ "confluenceAppKey": "your client_id", "confluenceAppSecret": "your client_secret", "confluenceAccessToken": "your access_token", "confluenceRefreshToken": "your refresh_token" }
※余談ですが、通常AccessTokenの期限は60分ですが、有効期限切れと判断した場合 Bedrock KB 側が RefreshToken を用いて再度 AccessToken を発行、Secrets Manager の値を自動更新してくれます。
Atlassian の RefreshToken は90日間有効で、使用すると有効期限が延長されるためブラウザでの認証は最初だけで済みます。
Secrets Manager 用の Stack はこちら。
Bedrock KB の作成
ナレッジベースや OpenSearch Serverless コレクションの作成には generative-ai-cdk-constructs ライブラリを利用しました。
こちらはAWSの提供するオープンソースの生成AI系 L3コンストラクトで、Bedrock KB や OpenSearch Serverless もパターン化されているものを使うことができるので、プロパティの指定だけで作成できます。
Knowledge Bases, OpenSearch Serverless 用の Stackはこちら。
RAGのテスト出力を行う
SecretsManager や Bedrock KB のStack をデプロイしたのち、RAGが機能するかをテストしてみます。
GitHub と Confluence を横断して検索できるかを確かめるべく、S3 にはこのリポジトリのソースコードを、Confluence には架空の技術選定会議の議事録を置いてみました。


AWS マネジメントコンソール上から Bedrock KB のテストを行いました。
GitHub(S3) と Confluence の両方から関連する文章が抽出されており、マルチデータソースとして機能しているのが分かります。

AI-ChatBot を作成する
次にチャットボットアプリケーション部分を作成していきます。
AI SDK
Vercel AI SDK は、Vercel の提供する AI アプリケーションのための Typescript ツールキットです。 OpenAI, Anthropic, AWS, GCP 等の特定のプロバイダを意識せずに利用できます。

例えば、AWS Bedrock でも GCP VertexAI でも、モデルを切り替えるだけで変更できます。
import { generateText } from "ai"
-- import { google } from "@ai-sdk/google"
++ import { bedrock } from "@ai-sdk/amazon-bedrock";
const { text } = await generateText({
-- model: google("gemini-2.5-flash"),
++ model: bedrock("amazon.titan-text-premier-v1:0"),
prompt: "What is love?"
})
また Vercel 社ならではの強みといったところで、Webフロントエンド、特に React.js や Next.js との親和性の高さがあります。
AI SDK は標準でストリーミングに対応しており、動的なUIの更新が非常に簡単に実現できますし、 useChat() などを用いてメッセージの取得やUIの更新も容易に行えます。
Vercel AI-ChatBot Template
Next.js と Vercel AI SDK を利用してチャットボットを作る場合は、Vercel の提供しているオープンソースのテンプレートを利用してみるのも非常によい選択肢かと思います。
このテンプレートでは、
- Next.js App router
- Vercel AI SDK
- Auth.jsによる簡易な認証
- shadcn/uiを利用したコンポーネント
- drizzle ORM
などを提供しています。
デモはこちらで確認できます。
この AI ChatBot をローカルで起動させるには、.env.exampleにもある通り、いくつかの環境変数を用意しなければいけません。必須の設定は下記の通りです。
- AUTH_SECRET
Auth.js が利用する Secret です。
npx auth secret または openssl rand -base64 32 で生成した文字列を利用します。
- POSTGRES_URL
Postgresql を起動させておき、その URL を指定します。
ローカルでの検証には下記のように docker に立てておきURLを指定します。
例: docker-compose.yml POSTGRES_URL=postgres://{user}:{password}@{hostname}:{port}/{database-name}
version: "3.8" services: postgres: image: postgres:16-alpine container_name: bedrock-kb-postgres restart: unless-stopped environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: bedrock_kb_chatbot ports: - "5432:5432" volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 5s timeout: 5s retries: 5 volumes: postgres_data:
- AI_GATEWAY_API_KEY
Vercel の AI Gateway を利用する場合は API KEY を指定すれば自動で認識してくれるようです。
また、LiteLLM などの非 Vercel の AI Gateway でも、gateway インスタンスを作成をすると利用することができるようです。
ただし今回は直に Amazon Bedrock を利用するので、代わりにAWSの認証情報を記載(またはホストやコンテナから読み込み)し
AWS_ACCESS_KEY_ID=*** AWS_SECRET_ACCESS_KEY=*** AWS_SESSION_TOKEN=***
モデルの定義部分を Bedrock 用に変更しました。
+ import { bedrock } from "@ai-sdk/amazon-bedrock"; customProvider({ languageModels: { - "chat-model": gateway.languageModel("xai/grok-2-vision-1212"), + "chat-model": bedrock("jp.anthropic.claude-sonnet-4-5-20250929-v1:0"), }), }, });
ここまでの環境変数の設定でひとまずローカル起動を確認できます。
pnpm dev で localhost:3000 にアプリケーションが立ち上がります。

ローコードでこのUI/UXが手に入ったと思うと、込み上げてくるものがありますね。
RAGをチャットボットに連携する
ひとまず Next.js アプリケーションが立ち上がったので、先ほど作成した Bedrock KB を呼び出すように変更します。
AI SDK で RAGを 直接呼び出す機能はサポートされていないため、Bedrock Agent Runtime Clinet でナレッジベースを呼び出す関数を作成し、それをToolに登録しました。
例: ナレッジベース呼び出し部分
import { BedrockAgentRuntimeClient, RetrieveCommand, RetrieveCommandInput, RetrieveCommandOutput, } from "@aws-sdk/client-bedrock-agent-runtime"; const client = new BedrockAgentRuntimeClient({ region: process.env.AWS_REGION, credentials: { accessKeyId: process.env.AWS_ACCESS_KEY_ID, secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, }, }); const input: RetrieveCommandInput = { knowledgeBaseId: process.env.KNOWLEDGE_BASE_ID, retrievalQuery: { text: query, } }; try { const command = new RetrieveCommand(input); const response: RetrieveCommandOutput = await client.send(command); }
例: Tool登録部分
const result = streamText({ model: myProvider.languageModel(selectedChatModel), system: systemPrompt({ selectedChatModel, requestHints }), messages: convertToModelMessages(uiMessages), stopWhen: stepCountIs(10), tools: { searchKnowledgeBase, }, });
ナレッジベースを連携してチャットボットアプリケーションを起動します。
「○○アプリの構成を教えて」等の質問で Confluence にあるドキュメントや GitHub の README.md をもとに回答を生成してくれました。

しかし、回答した内容を見ると Confluence から取得した内容が大半を占めており、あまりソースコードには触れられていませんでした。
RAG の検索精度と回答精度を向上させるために
ここまで RAG を比較的容易に構築できましたが、実際の運用を見越すと検索精度と回答精度を高めるのは非常に重要です。
以下に、私が期待する出力を得るために工夫したこと、やってよかったと思うことをいくつか紹介します。
ただし、具体的な評価や比較はここでは行いません。
プロンプトエンジニアリング
AI SDK Chatbot テンプレートのシステムプロンプトをそのまま利用している場合、
ナレッジベースを利用せずに推論してしまったり、ナレッジベースに無い回答も生成してしまいます。
またナレッジベースに特化したQAアシスタントという役割もやや不明瞭です。
AWS Summit Japan 2025で行われていた下記の講演ではプロンプトエンジニアリングについても触れられていました。
今回はそれをもとに下記のようにプロンプトを変更しました。
あなたはソフトウェア開発プロジェクトに特化したナレッジベースQAアシスタントです。ナレッジベースから取得した検索結果のみを利用してユーザーのクエリに回答することが主な役割です。 ナレッジベースには以下の情報が含まれています: - GitHubリポジトリのソースコード - Confluenceの技術ドキュメント - 会議議事録と設計決定 - 要件仕様書とアーキテクチャドキュメント - プロジェクト要件、技術仕様、設計根拠 # ルール 1. **検索結果のみを使用**: 回答は必ず検索結果に基づいて行い、推測や一般知識は使用しないこと 2. **見つからない場合は明示**: 検索結果に答えが見つからない場合は、見つけられなかったことを正直に述べること 3. **ユーザー発言の検証**: ユーザーの発言は真実であるとは限らないため、検索結果を再度確認して事実を確認すること 4. **必ずツールを使用**: プロジェクトに関する質問には必ずsearchKnowledgeBaseツールを使用すること 5. **必ず根拠となる情報を明示**: ユーザーに回答の根拠となる情報を提示すること **searchKnowledgeBaseツールを使用すべき質問:** - システムアーキテクチャや設計 - コード実装の詳細 - 技術的決定とその根拠 - プロジェクト要件や仕様 - 会議のノートや議論の結果 - その他プロジェクト固有の情報 # 例示 ## 例1: 情報が見つかった場合 **質問**: アプリケーションAのシステム構成図について教えて。 **良い回答例**: 検索結果によると、インフラストラクチャはCDKを用いて構成されており、以下のサービスを使用しています: - Amazon Bedrock Knowledge Bases: ナレッジベース管理 - OpenSearch Serverless: ベクトルストア - Titan Embed Text V2: 埋め込みモデル 詳細はinfra/lib/stack/bedrock-kb-stack.tsで確認できます。 ## 例2: 情報が見つかった場合 **質問**: 認証機能の実装方法は? **良い回答例**: 検索結果によると、Auth.jsを使用した認証システムが実装されています: - 認証プロバイダーの設定: lib/auth/config.ts - セッション管理: Redis - 認証タイプ: OAuth2とCredentials認証に対応 ## 例3: 情報が見つからなかった場合 **質問**: データベースのマイグレーション手順は? **良い回答例**: 申し訳ございませんが、データベースのマイグレーション手順に関する情報はナレッジベースから見つかりませんでした。別のキーワードで検索するか、より具体的な質問をしていただけますか? # 回答ガイドライン - searchKnowledgeBaseツールから返された検索結果のみを使用してください - 検索結果が見つかった場合、関連するファイル名や具体的な実装内容を含めてください - 検索結果が見つからなかった場合、正直にその旨を伝えてください - マークダウン形式で見やすく整形してください - 箇条書きや見出しを適切に使用してください 回答は簡潔で正確、かつ役立つものにしてください。常にナレッジベースの検索結果を一般知識よりも優先してください。
ハイブリッド検索とリランク
同動画の中では、Bedrock KB で利用できる様々な機能についても紹介されています。
ハイブリッド検索
ハイブリッド検索はキーワード検索とセマンティック検索(ベクトル検索)の両方を組み合わせて最も適合する結果を返します。
What is the cost of the book "<book_name>" on <website_name>?
この書籍名とウェブサイト名のクエリでは、特定の書籍の価格を知りたいのでキーワード検索でも良い結果が得られるでしょう。ただし、“cost” という単語については、類義語の “price” が使われているケースもあり得るため、テキストの意味を理解できるセマンティック検索を使う方が適切です。
リランク
またリランクを行うことで、リランクモデルを利用してクエリの関連性を計算し、計算したスコアに基づいて結果の順序を変更します。
サポートされているモデルは下記の通りです。
- Amazon Rerank 1.0
- Cohere Rerank 3.5
これらの機能は Bedrock Retrieve API で指定することが出来ます。
const input: RetrieveCommandInput = {
knowledgeBaseId: kbId,
retrievalQuery: {
text: query,
},
retrievalConfiguration: {
vectorSearchConfiguration: {
numberOfResults,
+ overrideSearchType: "HYBRID", // セマンティック + キーワード検索
+ rerankingConfiguration: {
+ type: "BEDROCK_RERANKING_MODEL",
+ bedrockRerankingConfiguration: {
+ numberOfRerankedResults: numberOfResults,
+ modelConfiguration: {
+ modelArn: `arn:aws:bedrock:${process.env.AWS_REGION}::foundation-model/cohere.rerank-v3-5:0`,
+ },
+ },
+ },
},
},
};
チャンキング戦略
Bedrock がドキュメントやコンテンツをベクトル化する際に、チャンキングというチャンク単位での分割を行っています。
このチャンキングに Bedrock で利用できるものには下記があります。
- デフォルトチャンキング
- 固定サイズチャンキング
- 階層的チャンキング
- セマンティックチャンキング
- チャンキング無し
Confluence のチャンキング
Confluence データソースはデフォルトでは固定サイズのチャンキングを行ってしまいますが、これだと下記のような問題が発生する可能性があるでしょう(実際にはチャンク同士はオーバラップしているため、これは極端な例ではありますが)。
たとえばチャンク化戦略に固定サイズを選択し、以下のようなチャンクに区切られたと想定します。
「就業規則の適用範囲」について質問したとします。赤線で囲った上部と中間のチャンクが該当する部分です。
返すチャンクの数にもよりますが 1 つだと仮定した場合、おそらく緑の文章が返されるでしょう。緑が返されると言うことは、 水色の文章に該当する「し、別に定める場合はこの限りではない。」の部分が抜けているため、回答精度が下がる可能性があります。

Confluence のようなドキュメントの場合は、段落や見出しなど意味のまとまりがあるため「セマンティックチャンキング」を採用しました。
ソースコードのチャンキング
またソースコードを直に S3 に置いて固定サイズのチャンキングを行ってしまうと、上記と同様の問題が発生しています。その上、コードは関数やクラス等のまとまりがありますから、それらを途中で分断してしまうとより顕著に精度は悪化するでしょう。
そこで、多くのプログラミング言語に対応した高速な構文解析器ツールである Tree-sitter を利用して、関数ごとやクラスごとにチャンキングを行い Bedrock KB 側ではチャンキングを行わないようにします。
Bedrock KB では Lambda をデータソース取り込み時にカスタム変換 Lambda 関数として処理でき、例えば下記のようなソースコードを関数ごと・クラスごとチャンキングし
同時にファイル名や GitHub 等の情報をメタデータに組み込みながらナレッジベースに取り込めます。
例: typescript ソースコード
import { compare } from "bcrypt-ts"; import NextAuth, { type DefaultSession } from "next-auth"; declare module "next-auth" { interface Session extends DefaultSession { user: { id: string; type: UserType; } & DefaultSession["user"]; } interface User { id?: string; email?: string | null; type: UserType; } }
例: チャンキング後の JSON
{ "fileContents": [ { "contentType": "PLAIN_TEXT", "contentBody": "import { compare } from \"bcrypt-ts\";\nimport NextAuth, { type DefaultSession } from \"next-auth\";", "contentMetadata": { "gitProvider": "github", "gitOrganization": "myOrg", "gitRepository": "bedrock-kb-chatbot", "language": "typescript", "filePath": "src/app/api/auth/[...nextauth]/auth.ts", "type": "FUNCTION", "name": "auth", "startLine": 1, "endLine": 43 } } ] }
まとめ
本記事では Amazon Bedrock Knowledge Bases や、Vercel AI ChatBot テンプレートを利用して チャットボット(RAG) を作成しました。
データソースにはソースコードとして S3 を、 仕様書として Confluence をそれぞれ指定しています。
また検索精度と回答精度を向上させるために以下のようなことを行いました。
- システムプロンプトの改善
- ハイブリッド検索やリランクの活用
- Tree-sitter や セマンティックチャンキングを利用した効果的なチャンクの分割
- メタデータの付与
最後に、実際にチャットボットが Bedrock KB を利用して回答を生成している様子を GIF として紹介します。

終わりに
ここまで読んでくださりありがとうございます。
RAG を構築してみましたが、周辺サービスが整ってきているため比較的容易に構築自体は出来ますね。しかしながら検索精度と回答精度を高めるためには工夫が必要で、奥が深い技術だと思いました。
今回は取り組まなかったですが、別途パーサーを利用して jpeg や png 等のマルチモーダルな解析をすることも出来るでしょうし、
現時点では Confluence データソースが OpenSearch Serverless のみに対応していたため試せていませんが、2024年12月には Bedrock KB は GraphRAG をサポートしています。
Amazon Neptune を利用した GraphRAG を併用すれば、例えばソースコードのチャットボットでも関数同士の複雑な依存関係など、グラフデータを利用した正確な出力が得られそうです。
また本記事では評価や比較は行っていませんが、実際の運用では定量的に評価し、より期待した回答を生成させることも必要です。
2024年12月に RAG の評価機能 / LLM-as-a-Judge 機能 がサポートされているため、AI による定量評価でフィードバックのループを回すことも可能です。
2025年は MCP や高度な AI エージェントアーキテクチャが注目を集め、AI システム同士が連携しながら自律的にタスクをこなす時代に入りました。そうした潮流の中でも信頼できる根拠データに基づいて応答するマルチテナント向け RAG は依然として重要な技術です。
本記事が、少しでもこれからの AI アーキテクチャ設計や実装の一助になれば幸いです。

松本 佳紘 Yoshihiro Matsumoto
プロダクト&マーケティング事業本部 クライアントプロダクト本部 テクノロジー統括部 プロダクト開発1部 法人サービスアプリ刷新グループ
2022年4月にパーソルキャリアへ新卒入社。企業メディア領域のエンジニア・スクラムマスターを経て、現在はdodaサイトのマイクロサービス化やdoda CONNECTのインフラ基盤改善に従事。
※2025年12月現在の情報です。
