株式会社エムニ
🚀

AWS AppConfig でプロンプトをデプロイする

に公開

はじめに

AIの急激な進歩に伴い、さまざまなアプリケーションにMachine LearningやLLMが組み込まれていることが多くなっているように感じます。

従来のプロダクトは「完成させて出荷するもの」だった。しかし、生成AIを組み込んだプロダクトは、「リリース後に学習し続ける生態系」として設計される。

https://takoratta.hatenablog.com/entry/product-design-in-ai-native-era

この記事にあるように、コードによってシステムの振る舞いが決定的に記述される従来のアプリケーションとは異なり、AIネイティブ時代では、ユーザーや市場からのフィードバックやAIの進化に伴い、進化し続けていきます。
特に、LLMを用いたアプリケーションの場合、プロンプトを介して学習[1]をし、進化を続けていく生態系と考えることができるかなと思います。

ここで、LLMアプリケーションの開発において、プロンプトをどこに配置し、どのように管理するかは非常に重要な設計判断です。

本記事では、AIネイティブなプロダクト開発において、どのようにプロンプトをアプリケーションコードと疎結合に管理し、本番の実行環境にデプロイメントしていくかを、デモアプリケーションを用いて説明していきます。

TL;DR

  • 課題:
    • プロンプトだけを更新・比較・ロールバックすることが困難
    • プロンプト追加・修正に関するPRやcommitがシステム関連のレポジトリに増えてしまう
  • 解決策:
    • AWS AppConfig を用いてプロンプトを「動的な設定値」として配信・管理する
  • メリット:
    • プロンプトのデプロイがアプリケーションの再起動なしに即座に反映される
    • プロンプトエンジニアリングのライフサイクルを開発レポジトリから分離できる
    • 言語中立な YAML 形式で管理でき、バージョニングや環境ごとの配信も容易

対象読者

  • LLM アプリケーションを開発・運用しているエンジニア
  • プロンプトエンジニアリングのPDCAサイクルを高速化したい方
  • マイクロサービスやコンウェイの法則に基づいたレポジトリの分割設計に興味がある方
  • AWS AppConfig の実用的なユースケース(特に LLM 分野)を知りたい方

プロンプト管理における設計思想

レポジトリやモジュールを分割する基準の一つにコンウェイの法則(システムを設計する組織は、その組織のコミュニケーション構造を模倣した設計を生み出す)があります。

現代の LLM アプリケーションにおいて、プロンプトエンジニアリングは専門性の高い職能となりつつあり、バックエンド開発やフロントエンド開発とは異なるスキルセットや試行錯誤のサイクルを必要とします。

この背景から、プロンプト管理には以下の思想を反映すべきだと考えます。

チームとエコシステムの分離

プロンプトエンジニア(あるいはドメインエキスパート)がバックエンドの知識なしにプロンプトを改善できるよう、レポジトリやライフサイクルを分離すべき。

独立したデプロイ・サイクル

プロンプトの修正は、アプリケーションコードのロジック変更とは独立して行われるべき。

言語中立性

プロンプトが特定のプログラミング言語(Python, TypeScript 等)に依存するのは不自然で、YAML や JSON、プレーンテキストといった共通フォーマットで記述されべき。

Behavior follows Input

フロントエンド開発において UI = f(State) が定着しているように、AI プロダクトがユーザーに提供する価値(Output)は、メンタルモデルとして以下の式で表現できると考えています。[2]

Output = f(Model, Code, State, Prompt)

この視点に立つと、Prompt は単なる文字列ではなく、Code や State と並んで Output を決定づける重要な「引数」であることがわかります。

したがって、プロンプトはアプリケーションコード(ビジネスロジック)の中に埋め込むのではなく、独立した変数として管理し、適切にバージョニングされ、環境ごとに独立してデプロイ・ロールバックされるべき。


プロンプト管理における設計思想

LLM アプリケーションに求められるプロンプト管理の要件

以上の思想に基づき、本記事では以下の要件を定義しました。

  • プロンプトのバージョニングができる: 過去のプロンプトへの切り戻しや履歴管理が可能であること。
  • プロンプトは特定の言語に依存せず、疎結合である: 共有フォーマットで記述され、環境変数のように注入可能であること。
  • プロンプトを異なるレポジトリで管理することができる: プロンプト専用のレポジトリで独立して管理できること。
  • プロンプトがデプロイされたら即座にクラウドの環境に反映される: デプロイされたプロンプトが、実行中の環境に(再起動なしで)即座に反映されること。

代表的な プロンプト管理 ツール

プロンプトエンジニアリングのライフサイクルを管理するための「LLMOps」と呼ばれる分野が急速に発展しており、いくつかのツールがデファクトスタンダードとして台頭してきています。

MLflow

機械学習ライフサイクル管理のデファクトスタンダードです。近年はプロンプトエンジニアリング機能も強化されており、UI 上でプロンプトを試行錯誤し、結果を比較・評価する機能があります。実験管理(Experiment Tracking)と密結合しており、どのプロンプトでどの指標が出たかを詳細に追跡できるのが強みです。

LangSmith (LangChain)

LangChain 開発元のツールです。「LangChain Hub」と連携し、プロンプトのバージョン管理や共有が可能です。強力なプレイグラウンド機能を持ち、ブラウザ上でプロンプトの修正から実行テストまで行えるため、非エンジニアでも扱いやすいUIが特徴です。

LangFuse

オープンソースの LLM エンジニアリングプラットフォームです。プロンプト管理機能(Prompt Management)を持ち、SDK 経由でプロンプトを取得できます。キャッシュ機能も備えており、SaaS 版だけでなくセルフホストが可能である点が魅力です。

既存ツールの課題

しかし、これらの専用ツールは非常に高機能である反面、実際のプロジェクト導入にあたってはいくつかの課題も存在します。

  • 導入・運用コスト: SaaS 版は利便性が高いですが、ユーザー数や実行回数に応じた従量課金が発生します。セルフホスト版を選ぶ場合でも、別途インフラの管理コストがかかります。
  • セキュリティとデータガバナンス: プロンプトや、場合によってはユーザーの入力データ(Trace 機能利用時など)を外部サービスに送信することになり、社内のセキュリティポリシーやコンプライアンス要件と衝突する可能性があります。
  • 運用フローの分断: 既存のアプリケーションデプロイフロー(CI/CD)とは別に、プロンプト管理ツール上でのバージョン管理や権限管理を整備する必要があり、運用が複雑化するリスクがあります。

特に、「すでに AWS 等で堅牢なインフラを構築しているため、管理をクラウドプロバイダ内で完結させたい」「コードの一部というよりは、より軽量な『設定値』としてプロンプトを扱いたい」というニーズに対しては、これらの専用ツールは少し重厚すぎると感じるケースもあるかと思います。

デモアプリケーション

本記事では、汎用的な動的設定配信サービスである AWS AppConfig を活用し、LLMOpsツールに依存しすぎない、インフラネイティブなプロンプト管理のデモを紹介します。

本記事で紹介するデモアプリケーションのコードは以下のレポジトリで公開してます。
https://github.com/ogatakatsuya/deploy-prompt

技術構成

より実用的な構成にするため、ECS Fargateを主軸とした構成にしました。

プロンプトはAppConfigで管理し、AppConfig Agentを介してAP Serverはプロンプトを取得します。AppConfig Agentは定期的にAppConfigをポーリングし、キャッシュするため、外部サービスとの通信を発生させることなくプロンプトを取得でき、ネットワークレイテンシの低減および安定したレスポンスを実現することができます。

AWS AppConfig の主要概念

AppConfig を利用する上で、以下の3つの階層構造を理解する必要があります。

  • Application: 管理対象となるアプリケーションの単位です(例:myapp)。
  • Environment: デプロイ先の環境を定義します(例:dev, staging, prod)。環境ごとに異なる設定(プロンプト)を割り当てることができます。
  • Configuration Profile: 具体的な設定項目の定義です。今回は prompts という名前で、YAML 形式のプロンプト定義を管理しています。

AppConfig Agent とポーリングの仕組み

通常、AppConfig から設定を取得するには AWS SDK を介して GetLatestConfiguration API を呼び出す必要がありますが、本プロジェクトでは AWS AppConfig Agent を採用しています。

  • AppConfig Agent とは: アプリケーションのサイドカー(または同じホスト上のプロセス)として動作するローカルプロキシです。
  • ポーリング (Polling): Agent はバックグランドで定期的に AWS AppConfig サービスに対して最新の設定がないか確認(ポーリング)を行います。デフォルトでは45秒間隔ですが、環境変数 POLL_INTERVAL で調整可能です。
  • ローカルキャッシュ: Agent は取得した設定をローカルメモリに保持し、HTTP エンドポイント(デフォルト 2772番ポート)として公開します。

実装の詳細

1. プロンプトの定義 (YAML)

プロンプトは特定の言語に依存しないよう YAML 形式で記述します。ここでは LangChain のプロンプト設定ファイル形式に準拠させています。

https://github.com/ogatakatsuya/deploy-prompt/blob/main/prompts/prompts.yaml#L1-L11

プロンプトをYAMLファイルで管理する方法は以下の記事を参考にさせていただきました。

https://zenn.dev/taku_sid/articles/20250511_yaml_prompt

2. AppConfig Agent のサイドカー配置

AWS AppConfig Agent をサイドカーとして動かします。ローカル開発時は、ホストの prompts ディレクトリをマウントし、LOCAL_DEVELOPMENT_DIRECTORY を指定することで、実際の AWS 環境を介さずに動作確認が可能です。

https://github.com/ogatakatsuya/deploy-prompt/blob/main/docker-compose.yml#L2-L8

既存のECS FargateへのAppConfig Agentのサイドカーコンテナの導入方法については以下の記事を参考にさせていただきました。

https://qiita.com/t_tsuchida/items/64ec5d8af2ce326b962e

3. プロンプトの動的取得

アプリケーション側では、AppConfig Agent が公開しているローカル HTTP エンドポイント(デフォルト 2772番ポート)を叩きます。エージェントが一定間隔(デフォルト45秒、設定変更可能)で設定をポーリングして最新化してくれるため、アプリケーションは単に HTTP GET を投げれば常に(ほぼ)最新[3]のプロンプトを取得できます。

また、推論のたびに外部リクエストが発生するのを防ぐため、シンプルなキャッシュ機構(TTL 5秒程度)を設けています。

AP Server側では、プロンプト取得のためのクライアントを実装すると良いと思います。
https://github.com/ogatakatsuya/deploy-prompt/blob/main/backend/src/prompt/manager.py

4. LLM クライアントでの利用

取得した設定値は、LangChain の load_prompt_from_config 等を利用してパースし、Gemini などの LLM クライアントのシステムプロンプトとして注入します。

https://github.com/ogatakatsuya/deploy-prompt/blob/main/backend/src/llm/gemini.py#L48-L52

5. GitHub Actionsを用いたプロンプトのデプロイ

最後に、編集したプロンプトをmainブランチにマージした時に、自動で本番環境にデプロイするワークフローをGitHub Actionsで行います。

流れとしては以下のような感じです。

  1. prompts/prompts.yaml の変更を検知してワークフローを開始
  2. yq コマンド等で YAML のバリデーションを実行(CI)
  3. AWS CLI で aws appconfig create-hosted-configuration-version を叩き、AppConfig に新しい設定バージョンを作成
  4. aws appconfig start-deployment を叩き、作成したバージョンを対象の Environment にデプロイ開始

https://github.com/ogatakatsuya/deploy-prompt/blob/main/.github/workflows/deploy-prompt.yml

6. デプロイ戦略

AppConfig の大きな利点は、Git で管理するだけでは難しい「デプロイの安全性」を担保できる点です。

  • デプロイ戦略 (Deployment Strategy): AllAtOnce(一括)、Linear(線形)、Canary(カナリア)など、新しいプロンプトをどのくらいの時間をかけて全適用するかを選択できます。例えば「10分かけて徐々に適用」といった設定が可能です。
  • ロールバック: デプロイ完了後、直ちに成功とするのではなく、一定の監視期間(ベーキングタイム)を設けることができます。何かトラブルが生じた際にはこの期間中にロールバックを行なうことができます。

CloudWatch Alarm と連携すれば、あらかじめ設定しておいた閾値を超えるエラーが出たら自動ロールバックする設定を行ったり、デプロイ戦略についても、ある程度自由にカスタムすることができます。

https://dev.classmethod.jp/articles/appconfig-create-a-wait-free-deployment-strategy/


デモ

まずは以下のようなプロンプトで、デプロイしてみます。

あなたは親切で丁寧な英語アシスタントです。
ユーザーからの質問に対して、分かりやすく正確な回答を提供してください。

回答のルール:
- 英語で回答する
- 簡潔で明確な説明を心がける

よくあるチャットbotのように入力された文章に対して、英語で返答文が返ってきました。

次に、プロンプトを修正して、mainブランチにpushしてみます。

あなたは親切で丁寧な英語アシスタントです。
ユーザーからの入力に対して、英語での翻訳を生成してください。

回答のルール:
- 英語で回答する
- 翻訳以外の情報は提供しない

Github Actionsに設定しているワークフローが走り、AppConfigのデプロイがトリガーされ、コンソールを確認すると、デプロイが始まっています。
完了のステータスになるのは少し時間がかかりますが、設定の更新自体は数秒で終了します。

最後に、先ほどと同じ日本語を入力すると、英語に翻訳したものが返ってきました。

さらにスケールさせる

今回はシンプルなアプリケーションの構築ですが、GitFlowや、GitHubの力を用いて、dev, stg, prodなどの環境別のデプロイメントや、GitHub Actionsの実行環境を用いたプロンプトのリントチェック、LLMを用いた生成精度の自動テスト・評価環境の整備など、柔軟性のあるさまざまな工夫を行うことができると考えています。

プロンプトエンジニアリングにおいて最も重要なのは「変更によって本当に良くなったのか・精度が落ちていないか」を評価することです。
AppConfig 単体には評価機能はありませんが、CI/CD パイプラインに組み込むことで、堅牢な評価基盤を構築できます。

また、今回は簡略化のために、モノレポで構築していますが、プロンプト専用のレポジトリを用意することもできますし、複数ファイルでプロンプト開発を行い、CIで結合したり、複数のAppConfig Profileで個別にプロンプトを管理することも可能だと思います。

まとめ

プロンプトを「デプロイが必要なコード」から「動的に注入可能な設定」へと昇華させることで、LLM アプリケーションの運用サイクルは劇的に改善されます。

このアプローチは、以下のようなメリットをもたらします。

  1. プロンプトエンジニアリングの高速化: コード変更・再ビルドなしでプロンプトを試行錯誤できる。
  2. 安全なデプロイ: AppConfig の機能を活用し、プロンプトのバリデーションや段階的なロールアウトが可能になる。
  3. 責任境界の明確化: コンウェイの法則に基づき、プロンプト管理レポジトリを分離することで、専門チームがそれぞれの関心事に集中できる。

この記事をプロンプト管理設計を再考するきっかけにしていただけると嬉しいです。

脚注
  1. In-Context Learning の意味で学習という言葉を使用しています (https://arxiv.org/pdf/2005.14165) ↩︎

  2. この式は概念的なものです。Output(UX)を生み出すための変数を列挙しています。それぞれ、Model: 使用するLLM、Code: ビジネスロジック等が記述されたコード、State: 会話履歴やRAG検索結果、Prompt: システムプロンプト等を指します。 ↩︎

  3. AppConfig Agent は設定をポーリングして取得するため、AppConfig 側でデプロイが完了してから、Agent が最新の設定を取得するまでには最大でポーリング間隔(デフォルト45秒)分のタイムラグが発生します。また、本デモではアプリケーション側でもパフォーマンス最適化のためにキャッシュ(TTL 5秒)を行っているため、これも反映遅延の要因となります。 ↩︎

GitHubで編集を提案
株式会社エムニ
株式会社エムニ

Discussion