1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【AWS】デジタル庁の源内AI(OSS)を月千円以下の最安構成で動かす!CDKデプロイ手順とハマりどころ解消Tips

1
Last updated at Posted at 2026-10-27

1. はじめに

デジタル庁がオープンソースとして公開している生成AI利活用基盤「源内(GitHub: digital-go-jp/genai-ai-api)」。その中に含まれる「行政実務用RAG(aws/query-expansion-rag)」は、クエリ拡張やリランキングが組み込まれた非常に完成度の高いAWS RAG環境です。

しかし、デフォルト構成のままデプロイすると Amazon OpenSearch Serverless (AOSS) の待機課金により、使っていなくても月額数万円の固定費が発生してしまいます。

本記事では、この源内RAGを Amazon Bedrock S3 Vectors と Amazon Nova Lite に切り替えます。これにより、「待機固定費ゼロ・月額千円以下・1クエリ約0.1円」 で動かす最安構成を実現しました。具体的なデプロイ手順と、遭遇しやすいエラーの解消Tipsをまとめます。


2. 前提環境

  • OS: Linux / macOS
  • Node.js: v22.x
  • Python: 3.12 〜 3.14
  • AWS CLI: v2.x(aws configure 設定済み)
  • AWS環境: 東京リージョン(ap-northeast-1)

3. 最安構成への設定変更手順

リポジトリをクローンした後、aws/query-expansion-rag 配下の設定ファイルを2箇所書き換えます。

git clone https://github.com/digital-go-jp/genai-ai-api.git
cd genai-ai-api/aws/query-expansion-rag
npm ci

① ベクトルストアを S3 Vectors に切り替え

parameter.ts および cdk.json 内で、OpenSearch用の設定を外し、S3 Vectors用スタックを有効化します。

parameter.ts
// OpenSearch構成を無効化(空配列に)
export const qeRagAppNamesWithSharedCmek: string[] = [];

// S3 Vectors構成を有効化
export const qeRagAppNamesWithS3Vectors: string[] = ['qerag-s3v-1'];

これで待機中のOCU課金が完全にゼロになります。

② LLMを Amazon Nova Lite に統一

config/apps/qerag.toml を開き、モデルIDと出力トークン数を設定します。

config/apps/qerag.toml
[query_expansion]
modelId = "amazon.nova-lite-v1:0"
maxTokens = 5000

[rerank]
modelId = "amazon.nova-lite-v1:0"
maxTokens = 5000

[generation]
modelId = "amazon.nova-lite-v1:0"
maxTokens = 5000
embeddingModelId = "amazon.titan-embed-text-v2:0"

[!NOTE]
maxTokens を 5000 に設定している理由は後述のTipsを参照してください。


4. デプロイとデータ同期

① CDK デプロイの実行

以下のコマンドで、API Gateway、Lambda、Bedrock Knowledge Base、S3等の全スタックを一括デプロイします。

npx cdk deploy --all -c env=-dev

正常に完了すると、CloudFormation Outputs に API エンドポイントや Knowledge Base ID が出力されます。

② 投入データの前処理(Shift_JIS → UTF-8 変換)

官公庁のオープンデータや e-Stat の統計表(CSV)は Shift_JIS(CP932) で配布されているケースが多くあります。
しかし、AWS Bedrock Knowledge Base は UTF-8 前提のため、そのままアップロードすると文字化けして正常に検索されません。

Pythonの encode/decode 等を用いて、投入前に必ず UTF-8 へ一括変換しておきます。

convert_utf8.py
import chardet

with open("raw_data.csv", "rb") as f:
    raw = f.read()
    encoding = chardet.detect(raw)["encoding"]

text = raw.decode(encoding or "cp932")
with open("processed_data.csv", "w", encoding="utf-8") as f:
    f.write(text)

③ S3 へのアップロードとナレッジベース同期

データソース用の S3 バケットの docs/ フォルダ配下にファイルを同期し、Bedrockの取り込みジョブを開始します。

[!IMPORTANT]
【重要】S3に置くだけでは検索に反映されません!
Bedrock Knowledge BaseはS3イベント自動連携ではないため、ファイルを配置しただけではベクトル化されません。必ず以下の start-ingestion-job を実行して明示的に取り込みを開始してください。

# S3へアップロード
aws s3 sync ./processed/ s3://<データソースバケット名>/docs/ --region ap-northeast-1

# Knowledge Base の同期開始
aws bedrock-agent start-ingestion-job \
  --knowledge-base-id <KNOWLEDGE_BASE_ID> \
  --data-source-id <DATA_SOURCE_ID> \
  --region ap-northeast-1

5. 遭遇しやすいエラーと即効解消Tips 7選

Tips 1: CDK ブートストラップの SSM パラメータアクセス拒否

  • エラー:
    AccessDeniedException: User: ... is not authorized to perform: ssm:GetParameter on resource: .../cdk-bootstrap/...
  • 原因:
    CDK標準のシンセサイザーが SSM Parameter Store や AssumeRole を前提としているため発生します。
  • 解決策:
    bin/qe-rag-apis.ts で CliCredentialsStackSynthesizer を適用し、CLIの直接認証モードに切り替えます。
    bin/qe-rag-apis.ts
    const app = new cdk.App({
      defaultStackSynthesizer: new cdk.CliCredentialsStackSynthesizer()
    });
    

Tips 2: AWS SSOロール前提コードによるデプロイ失敗

  • エラー:
    Invalid principal in policy (Service: CloudFormation, Status Code: 400)
  • 原因:
    本家の switch-role-stack.ts が IAM Identity Center(旧AWS SSO)のロールを前提としているため、個人環境で失敗します。
  • 解決策:
    SSOロール未利用時は自アカウントのルートへフォールバックする条件分岐を追加します。
    aws/query-expansion-rag/lib/switch-role-stack.ts
    const assumeRolePrincipal = (props.switchRoleName === 'DummyRole' || props.switchRoleName === 'root')
      ? new iam.AccountRootPrincipal()
      : new iam.ArnPrincipal(
          `arn:aws:iam::${awsAccount}:role/aws-reserved/sso.amazonaws.com/${awsRegion}/${props.switchRoleName}`
        ).withConditions({
          StringLike: {
            'aws:userid': props.idcUserNames.map((user) => `*:${user}`),
          },
        });
    

Tips 3: メタデータJSONがない場合の引用ファイル名欠落

  • 現象:
    ドキュメントに個別のメタデータJSON(.metadata.json)を付けていない場合、Lambda側でファイル名を取得できず引用表示が空になります。
  • 解決策:
    Lambda(kb_response_processor.py)で S3 URI から直接ファイル名を抽出するフォールバック処理を実装します。
    rag-lambda/invokeModel/services/kb_response_processor.py
    # locationからS3 URIを取得してファイル名を抽出
    s3_uri = reference.get("location", {}).get("s3Location", {}).get("uri", "")
    fallback_file_name = s3_uri.split("/")[-1] if s3_uri else None
    
    if METADATA in reference:
        metadata.file_name = reference[METADATA].get(FILE_NAME) or fallback_file_name
        metadata.url = reference[METADATA].get(URL) or s3_uri
    else:
        metadata.file_name = fallback_file_name
        metadata.url = s3_uri
    

Tips 4: AWS WAF の IPSet CIDR フォーマットエラー

  • エラー:
    parameter contains formatting that is not valid., field: IP_ADDRESS, parameter: 0.0.0.0/0
  • 原因:
    AWS WAFv2 の IPSet では 0.0.0.0/0 の指定が許可されていません(/1〜/32 のみ)。
  • 解決策:
    開発環境のアクセス元IP(xxx.xxx.xxx.xxx/32)を指定するか、IP制限が不要な場合は allowedIpV4AddressRanges: null を渡します。

Tips 5: API Gateway 統合タイムアウト(29秒)の超過

  • エラー:
    Timeout should be between 50 ms and 29000 ms (Service: ApiGateway, Status Code: 400)
  • 原因:
    REST API の統合タイムアウト上限は 29秒(29,000ms)です。デフォルトの 180 秒のままではデプロイが拒否されます。
  • 解決策:
    parameter.ts および cdk.json の apiLambdaIntegrationTimeout を 29 に設定します。

Tips 6: Amazon Nova Lite の最大トークン数エラー

  • エラー:
    ValidationException: The maximum tokens you requested exceeds the model limit of 10000
  • 原因:
    Bedrock Converse API において、Nova Lite の最大出力トークン(maxTokens)の上限は 10,000 です。Claude向けの設定値(20,000〜40,000)のままではエラーになります。
  • 解決策:
    config/apps/qerag.toml 内の全 maxTokens を 5000 程度に引き下げて設定します。

Tips 7: cdk destroy 時に「Unable to delete data from vector store...」で削除失敗する罠

  • エラー:
    Unable to delete data from vector store for data source with ID xxxxx...
  • 原因:
    データソースの削除ポリシー(dataDeletionPolicy)がデフォルトの DELETE になっているためです。CDK破棄時にS3が先に消えると、ベクトルストア削除APIが失敗してスタック削除がブロックされます。
  • 解決策:
    データソースの dataDeletionPolicy を RETAIN に更新してから削除します。
    cleanup_fix.py
    import boto3
    client = boto3.client('bedrock-agent', region_name='ap-northeast-1')
    
    # 1. ポリシーを RETAIN に更新(ベクトルストアへのアクセスをスキップ)
    ds = client.get_data_source(knowledgeBaseId=KB_ID, dataSourceId=DS_ID)['dataSource']
    client.update_data_source(
        knowledgeBaseId=KB_ID,
        dataSourceId=DS_ID,
        name=ds['name'],
        dataDeletionPolicy='RETAIN',
        dataSourceConfiguration=ds['dataSourceConfiguration']
    )
    
    # 2. データソースとKBを削除
    client.delete_data_source(knowledgeBaseId=KB_ID, dataSourceId=DS_ID)
    client.delete_knowledge_base(knowledgeBaseId=KB_ID)
    

6. コストとレスポンスの実績

この最安構成でテストクエリを実行したパイロット検証の実測値です。

  • 平均レスポンス時間: 約 5.4 秒 / リクエスト
  • 消費トークン数: 約 89,000 tokens
  • 検証全体の総費用: $0.01188(約 1.8 円)
  • 1リクエストあたりのコスト: 約 0.1 円
  • 待機固定費: 0円(S3保存料のみ)

クエリ拡張+リランキング+回答生成という4段階パイプラインを実行しても、1回あたり約0.1円という圧倒的な低コストで運用可能です。


7. まとめ

デジタル庁の「源内AI」AWS RAGテンプレートは、S3 Vectors と Amazon Nova Lite を組み合わせることで、個人や小規模チームでもお財布に優しく安全に動かすことができます。

社内ドキュメントの検索や業務効率化のPoC環境として、ぜひ試してみてください。


関連記事・お問い合わせ

  • デジタル庁 源内AI 公式リポジトリ:
    行政実務用RAGやマルチクラウド基盤の公式コードは、GitHub(digital-go-jp/genai-ai-api) で公開されています。
  • 開発背景・アーキテクチャの解説:
    本構成の設計思想や構造別ベンチマークによる精度検証ログ(検索成功率88.9%)の詳細は、Zennの解説記事 をご覧ください。
  • 業務導入・受託開発のご相談:
    AI Nexusでは、業務効率化ツールの受託開発やAI導入コンサルティングを行っています。詳細は AI Nexus 公式サイト をご覧ください。
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?