アプリ開発から、システム全体の設計へ
2026年10月、AWSとOpenAI APIを利用した個人向けLLMシステムの開発に取り組みました。
それ以前には、React NativeとFirebaseを利用したiOSゲームアプリ「ことばと!」を開発していました。
「ことばと!」では、企画・仕様決定・ゲームバランス・品質検証を中心に担当し、Claude CodeによるAI支援を活用しながら、App Storeの審査通過まで進めました。
この経験から、AIを活用することで個人でもアプリケーションを開発できる一方、技術構成や運用、データ管理などについても理解を深めたいと考えるようになりました。
そこで次の開発では、単にAIを利用したアプリを作るのではなく、クラウド、認証、バックエンド、API、データ管理まで含めて、一つのシステムとして設計することを目標にしました。
なぜ個人LLMを作ろうと考えたのか
生成AIを利用する中で、自分が保有する文書や情報を必要に応じて検索し、その内容に基づいて回答できる環境があれば便利だと考えました。
また、既存のAIサービスを利用するだけでは、通信経路やデータ管理、モデルの選択などを自分の要件に合わせて調整できる範囲には限界があります。
そこで、以下の要件を設定しました。
- 自分のPCから利用できるWeb UIを用意する
- 文書を登録し、その内容をAIが検索・参照できるようにする
- 認証情報やアクセス経路を適切に管理する
- 将来的なLLMモデルの変更を考慮する
- 運用費用と管理負担をできるだけ抑える
- 将来的にモバイルアプリへ展開できる構造を目指す
重要視したのは、すべてを独自開発することではありません。
既存のクラウドサービスやAPIの役割を理解し、目的に適した形で組み合わせることです。
システムの構成
今回のシステムでは、ローカルWeb UIとAWS上のバックエンドを組み合わせています。
主な技術構成は以下のとおりです。
バックエンド
- Python / FastAPI
- AWS Lambda
- Harness・APIアダプター
クラウド・インフラ
- Amazon ECR
- AWS IAM
- AWS Secrets Manager
- AWS SAM / CloudFormation
- Docker
AI・データ管理
- OpenAI API
- File Search / Vector Store
- SQLite
フロントエンド
- ローカルWeb UI
- 127.0.0.1限定のローカル中継サーバー
処理の流れは、ローカルWeb UIから中継サーバーを経由し、AWS Lambda上のバックエンドへアクセスする構成です。
Lambda上のバックエンドはOpenAI APIと連携し、チャットへの応答や文書検索を実行します。
文書管理については、ローカルのSQLiteを利用するとともに、検索対象の文書をVector Storeへ登録する仕組みを実装しました。
この構成により、ローカル環境とクラウドの役割を分離しています。
技術選定で重視したこと
1. AWS Lambdaを採用した理由
バックエンドの実行環境にはAWS Lambdaを採用しました。
個人利用を前提としているため、常時稼働するサーバーを維持するよりも、必要なときに処理を実行するサーバーレス構成が適していると考えたためです。
また、コンテナイメージをECRに保存し、AWS SAMとCloudFormationで構成を管理することで、デプロイや設定変更を再現しやすい形にしました。
一方で、Lambdaには実行時間やリソースなどの制約があります。
将来的に長時間処理や継続的な処理が必要になれば、Amazon ECSなどの別の実行環境も比較する必要があると考えています。
2. 特定のLLMに依存しない構造
生成AIの分野では、新しいモデルが登場し、性能や価格、利用可能な機能が変化し続けています。
そのため、特定のLLMを前提にアプリケーション全体を構築すると、将来モデルを変更する際の修正範囲が大きくなる可能性があります。
そこで、BackendとHarness、モデルに接続するアダプターの役割を分離しました。
アプリケーションの機能と、実際にAIモデルを呼び出す部分を区別することで、将来的なモデル変更やAPIプロバイダーの切り替えを考慮した構成にしています。
ただし、異なるモデルやサービスではAPI仕様や対応機能も異なるため、完全な互換性が保証されるわけではありません。
今後、複数モデルへの対応を進める際には、アダプターごとの実装と動作検証が必要になります。
3. セキュリティとアクセス制御
個人文書を扱うことを想定しているため、認証情報やアクセス経路の設計も重視しました。
ローカルWebサーバーは127.0.0.1でのみ待ち受けるように設定し、外部ネットワークから直接アクセスできない構成にしています。
AWS LambdaのFunction URLにはAWS_IAM認証を採用し、ローカル中継からSigV4署名付きリクエストを送信します。
また、OpenAI APIキーはAWS Secrets Managerで管理し、ソースコードへ直接埋め込まないようにしています。
ローカル中継には、Host・Originの検証、CSRF対策、リクエストサイズ制限、タイムアウト処理なども実装しました。
これらは単独ですべてのリスクを防ぐものではありませんが、通信経路ごとに必要な制御を設けることを意識しました。
RAGによる文書検索機能
今回の開発で実装した主な機能の一つが、RAG(Retrieval-Augmented Generation)です。
RAGは、LLMが回答する際に外部の文書や情報を検索し、その内容を利用する仕組みです。
今回のシステムでは、OpenAI APIのFile SearchとVector Storeを利用しています。
主な機能は以下のとおりです。
- 文書の登録・管理
- CSVデータのテキスト変換
- Vector Storeへの登録
- 文書内容に基づく検索
- 検索結果を利用した回答生成
- 回答に関連する出典情報の表示
例えば、架空の在庫データをCSVとして登録し、その内容について自然言語で質問する検証を行いました。
その際、日本語、引用符、セル内改行を含むデータが適切に扱われるかも確認しています。
検索対象となる文書を直接プロンプトに貼り付けるのではなく、必要な情報を検索して回答に利用する構成としたことで、文書データを扱うAIアプリケーションの仕組みを学ぶことができました。
開発中に直面した問題
今回の開発では、プログラムそのものよりも、AWSの権限や認証、サービス間の接続で苦労する場面がありました。
特に難しかったのは、IAMポリシーとロール、Lambdaの実行権限、Function URLへのアクセス制御などです。
AWSでは、ユーザーが操作できる範囲と、Lambdaなどのサービスが実行時に利用する権限が区別されています。
最初はこの関係を理解することに時間がかかりましたが、実際のエラーを調査しながら、認証と認可、サービス間の権限の違いを整理しました。
また、OpenAI APIとの連携では、Secrets Managerに登録されていたAPIキーが無効になり、認証エラーが発生したこともありました。
この際は、通信経路、Lambdaの設定、Secrets Managerの登録値、API側の応答を順に確認することで原因を特定し、修正しました。
これらの経験から、問題が発生した際に一度に複数の設定を変更するのではなく、原因を段階的に切り分けることの重要性を学びました。
AIコーディングツールの活用と検証
開発ではCodexなどのAIコーディングツールを利用しました。
AIによるコード生成を活用することで実装を進めやすくなる一方、生成されたコードの正確性や安全性が自動的に保証されるわけではありません。
そのため、要件や構成を検討し、実装内容を確認しながら、必要に応じて修正とテストを重ねました。
特に、単体機能が動くことと、システム全体が正常に連携することは異なるため、E2Eテストによる確認を重視しました。
公開用ポートフォリオの整理時点では、以下のテスト結果を記録しています。
- Pythonテスト:271件成功
- UIテスト:10件成功
- AWS Lambda経由のチャット動作確認
- 文書登録から検索・出典表示までのE2E確認
また、開発経緯や技術選定の理由、人間とAIの担当範囲も文書化し、第三者が確認できる形に整理しました。
なお、これらは実施した範囲での検証結果であり、商用運用を想定した負荷試験や長期稼働の保証を意味するものではありません。
今後の開発計画
現在のWeb版を基盤として、今後は以下の機能追加を計画しています。
1. Amazon Cognitoによるログイン認証
現在のシステムは、ローカルPCから利用する個人向けの構成です。
将来的にモバイルアプリや複数端末からの利用へ拡張する場合、現在のローカル中継を前提とした認証方式だけでは十分ではありません。
そこで、Amazon Cognitoを利用したユーザー認証・ログイン機能の導入を検討しています。
認証情報の管理だけでなく、ユーザーごとのアクセス制御や文書データの分離についても設計する予定です。
2. iOSアプリへの展開
Web版で実装したチャット・文書検索機能を、iOSアプリからも利用できるようにすることを目指しています。
以前開発した「ことばと!」でのReact Native・Expoの経験も活用したいと考えています。
ただし、モバイルアプリでは現在のローカル中継をそのまま利用することが難しいため、APIへのアクセス経路、ユーザー認証、トークン管理などを再設計する必要があります。
また、モバイル端末にAWSの長期認証情報を直接保存しない構成を検討します。
3. 複数LLMモデルへの対応
現在のOpenAI API連携を基盤とし、将来的には異なるモデルやAPIプロバイダーを選択できる仕組みを目指しています。
モデルごとに性能、料金、対応機能が異なるため、用途や利用条件に応じて選択できることには価値があると考えています。
一方で、モデルを増やすほど設定、テスト、保守の負担も大きくなるため、単に対応数を増やすのではなく、実際の利用目的に応じて優先順位を決める予定です。
4. データ管理と運用面の改善
複数端末や複数ユーザーでの利用を想定した場合、現在のSQLiteによるローカル文書管理の方式についても見直しが必要になります。
今後は、クラウド側でのデータ保存やユーザー単位の権限管理、バックアップ、障害発生時の復旧なども検討していきます。
ただし、機能を増やせば、その分だけ運用コストやシステムの複雑さも増加します。
そのため、必要性の高い機能から段階的に実装する方針です。
開発を通じて得たこと
今回の個人LLM開発では、ローカル環境でのプログラム実行から始め、AWSへのデプロイ、API認証、文書検索、セキュリティ対策、テストまで経験しました。
特に印象に残ったのは、システム開発では、一つひとつの技術を知っていることだけでなく、それぞれの役割や依存関係を理解することが重要だという点です。
また、ある問題を改善するための技術選定が、必ずしもすべての面で最善になるとは限りません。
例えば、Lambdaを採用すれば常時サーバーを管理する負担は減らせますが、実行時間などの制約が生じます。
セキュリティを強化すれば管理上のリスクを抑えられる一方で、認証・認可の設計や運用は複雑になります。
こうしたトレードオフを理解し、目的に応じて判断することが、システム設計には必要だと考えています。
これから目指すこと
「ことばと!」の開発では、企画から製品化までの工程を経験しました。
今回の個人LLMでは、その経験をさらに広げ、クラウド、バックエンド、認証、AI API、データ管理を組み合わせるシステム開発に取り組みました。
大学で学んだ哲学的な分析と、個人開発を通じて得た技術的な経験を組み合わせ、今後は実務の中で課題解決に関わりたいと考えています。
特に、AI活用、DX推進、業務改善、自社サービス開発などの領域で、利用者や現場の課題を理解し、技術的な解決策の検討から実装・検証まで取り組みたいと考えています。
技術を目的ではなく、課題解決の手段として活用する。
この考え方を軸に、今後も設計と実装の両面から経験を積んでいきたいと思います。
GitHub・開発資料
今回開発した個人LLMの公開用リポジトリです。
ソースコード、README、アーキテクチャ、設計判断、開発履歴、テスト記録を掲載しています。
GitHub|Personal LLM Portfolio
https://github.com/git-aro0717/personal-llm-portfolio
※公開リポジトリは採用向けのポートフォリオとして整理したもので、個人文書や認証情報などは含めていません。