Android - TECH PLAY - TECH PLAY

TECH PLAY

Android

イベント

マガジン

技術ブログ

こんにちは、トモニテ開発部 iOS エンジニアの村田です。 iOS エンジニアもしくは Android・クロスプラットフォームを含めてモバイルエンジニアの皆さんに対して気になっていることがあります。 みなさん AI 開発どんな感じでやってますか?どんなハーネス組んでますか? エンジニアリング業界では、単に指示を出して書いてもらう「バイブコーディング」の次の段階として、AI エージェントの自律化や「ハーネスエンジニアリング」「ループエンジニアリング」といった話題が急速に広がっています。 Web やサーバーサイド領域では、こうした最新の AI 活用の情報が活発に共有されている一方、iOS(モバイル)開発における実践的なナレッジはまだまだ各所に散らばっており個々で孤軍奮闘している印象を受けています。 私自身、久しぶりに iOS 開発に取り組んでいて、Claude Code と git worktree を用いた並行開発をする中で iOS 特有のハマりどころをいくつか感じました。 今回は「並行開発」という観点にフォーカスして、iOS で並行開発したときに感じた課題と対処方法を記載します。 開発環境 前提として、以下のような環境・仕組みで開発しています。 使用技術 AIエージェント : Claude Code エディタ : VSCode 並行開発 : Git Worktree 対象 : iOS アプリ(Swift / UIKit / SPM / .xcodeproj) ビルド方法 : XcodeBuildMCP(Claude 経由の MCP)・XcodeBuildMCP(CLI 版)・Xcode(GUI) ディレクトリ構成 <repo>-trees/ ← worktree develop/ ← メイン worktree(base ブランチ) feature-A/ ← タスクごとの worktree(並列) feature-B/ ← タスクごとの worktree(並列) refactor-C/ ← タスクごとの worktree(並列) ... 開発手順 タスク開始時に git worktree add で develop ブランチから新規 worktree を切る worktree 配下で Claude Code のセッションを開始し、要件定義 → 実装 → PR 作成など開発フローを進行 タスクが終わったら、その worktree ごと片付ける ---bin なぜ並行開発が欠かせないのか あちこちで語られている話なので、要点だけ。 AI に開発させると、人間の役割は「実装する人」から「複数のエージェントを監督する人」に変わります。「どこまで自律的に AI に開発させられているか」にも依りますが、設計・実装・ビルド・テストと多くのフェーズで人間の手が空くようになるため、1 タスクを直列で進めるよりも複数タスクを並行で回す方が効率よく進められます。 そこで注目を浴びたのが git worktree です。ブランチごとに独立した作業ディレクトリ(worktree)を持てるため、作業ファイルの競合を気にせず、安全に複数タスクを同時進行できます。 そうして git worktree を用いて iOS 開発を始めたのですが、いくつか課題が発生しました。 問題その1: DerivedData がストレージを食い尽くす 何が起きたか iOS のビルドでは DerivedData を生成します。DerivedData には Xcode がビルドのたびに吐き出す中間生成物(ビルドキャッシュ・インデックス・成果物など)が含まれており、デフォルトでは ~/Library/Developer/Xcode/DerivedData/ に生成されます。XcodeBuildMCP でビルドする場合は、 ~/Library/Developer/XcodeBuildMCP/workspaces/<worktree>-<hash>/DerivedData/<プロジェクト名>-<hash> に生成されます。 DerivedData は worktree の内部ではなく、ユーザー共通の場所にまとめて溜まるため、worktree の数に比例して独立したビルドキャッシュが蓄積されていきます。 私の環境では 1 worktree あたり数 GB〜20 GB 台、合計およそ 86 GB になっていました。 結果としてディスクの空き容量が枯渇し、スワップ領域も確保できなくなって、ビルドどころではなくなりました。 # Xcode(GUI)の既定 — プロジェクト名 + ハッシュ名 ~/Library/Developer/Xcode/DerivedData/ ├── <プロジェクト名>-a1b2c3d4efgh…/ ├── <プロジェクト名>-e5f6g7h8ijkl…/ ├── <プロジェクト名>-i9j0k1l2mnop…/ ├── <プロジェクト名>-q7r8s9t0uvwx…/ └── … # XcodeBuildMCP の既定 — worktree 名 + ハッシュ名 ~/Library/Developer/XcodeBuildMCP/workspaces/ ├── develop-a1b2c3…/DerivedData/ 19 GB ├── feature-A-d4e5f6…/DerivedData/ 21 GB ├── feature-B-g7h8i9…/DerivedData/ 11 GB ├── feature-C-j0k1l2…/DerivedData/ 8.8 GB └── …(他 4 worktree) 26 GB 計 86 GB キャッシュを削除しようと試みたところで Xcode の場合、DerivedData のフォルダ名がハッシュ化されていて、フォルダ名だけではどの worktree に対応するかわからない ビルドしなくてもインデックス更新などで更新日時が変わるため、「更新日が古い=不要」という判断も効かない といった理由により、使い終わった worktree のゴミだけを削除することが難しかったです。 かといって全部消すと、全 worktree がコールドビルドに逆戻りしてしまいます。 XcodeBuildMCP はデフォルトでフォルダ名に worktree 名が入るため対応関係は分かりやすいのですが、 git worktree remove (worktree の削除)をしても、この孤児フォルダが残り続ける点は Xcode の既定と同じです。 対処方針: DerivedData を worktree 配下に保存する 対応策として DerivedData の置き場所を worktree フォルダの直下( <worktree>/DerivedData )に固定すると、次のメリットが得られました。 どのキャッシュがどの worktree のものか、置き場所を見れば分かる git worktree remove すれば DerivedData も一緒に消える 開発時のライフサイクルは以下のようなイメージです。 DerivedData の置き場所を変更する方法 ① Xcode の GUI でビルドする場合 全プロジェクト一律でよい場合 : Xcode → Settings → Locations → Derived Data を Default から Relative に変える 特定のプロジェクトだけ有効にしたい場合 :対象プロジェクトを Xcode で開いた状態でメニューの File → Workspace Settings… ( .xcworkspace を開いていない場合は Project Settings… )を選び、 Derived Data を Workspace-relative Location に切り替える 後者の場合、実態としてはプロジェクト内の WorkspaceSettings.xcsettings ( xcuserdata 配下・通常は Git 管理外のユーザーローカル)の設定と同等のため、GUI を使わず次の内容を直接書いても実現できます。 <? xml version = "1.0" encoding = "UTF-8" ?> <!-- <project>.xcodeproj/project.xcworkspace/xcuserdata/<user>.xcuserdatad/WorkspaceSettings.xcsettings --> <! DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd" > <plist version = "1.0" > <dict> <key> DerivedDataLocationStyle </key> <string> WorkspaceRelativePath </string> <key> DerivedDataCustomLocation </key> <string> DerivedData </string> </dict> </plist> ② XcodeBuildMCP でビルドする場合 こちらは .xcodebuildmcp/config.yaml の derivedDataPath で決まります(worktree のルートからの相対パスで解決されます)。 # <worktree>/.xcodebuildmcp/config.yaml schemaVersion : 1 sessionDefaults : projectPath : "<プロジェクトパス>" scheme : "<スキーム名>" derivedDataPath : "./DerivedData" platform : "iOS" useLatestOS : false bundleId : "<バンドル ID>" 💡 どちらの方法でも DerivedData がリポジトリ配下に生成されるため、 .gitignore に DerivedData/ を追加する必要があります。 ただし「Xcode 版で特定のプロジェクトだけ Relative にしている場合」や「XcodeBuildMCP 版で .xcodebuildmcp/config.yaml を Git 管理していない場合」は、新しい worktree を作るたびにこれらの設定を行う必要があります。毎回手動で設定するのは面倒なので、Git の post-checkout hook で worktree の作成時に自動設定されるようにするのがおすすめです。 post-checkout hook で DerivedData の設定を自動化する git worktree add や git checkout を実行すると、 post-checkout という hook が発火します。hook は共通の Git ディレクトリ( git rev-parse --git-common-dir )に置かれ全 worktree で共有されるので、そこに設定することで新規 worktree 作成時の処理を仕込むことができます。 下記のような処理を .git/hooks/post-checkout に記述することで、新規 worktree 作成時に「DerivedData を各 worktree 配下( <worktree>/DerivedData )に保存する」ように設定できます。 なお以下の hook では ② の config.yaml を直接出力していますが、正の config.yaml をデフォルトブランチなどで管理し、post-checkout で cp する方式でも構いません。 #!/bin/bash # .git/hooks/post-checkout if [ " $3 " = "1" ]; then PROJECT = $( find . -maxdepth 1 -name " *.xcodeproj " | head -1 ) if [ -n " $PROJECT " ]; then # ① Xcode GUI 用: WorkspaceSettings に worktree 相対の DerivedData を書く DIR = " ${PROJECT} /project.xcworkspace/xcuserdata/ $( whoami ) .xcuserdatad " PLIST = " ${DIR} /WorkspaceSettings.xcsettings " mkdir -p " $DIR " [ ! -f " $PLIST " ] && plutil -create xml1 " $PLIST " plutil -replace DerivedDataLocationStyle -string WorkspaceRelativePath " $PLIST " plutil -replace DerivedDataCustomLocation -string DerivedData " $PLIST " # ② XcodeBuildMCP 用: config.yaml を worktree 直下に生成 if [ ! -f .xcodebuildmcp/config.yaml ]; then mkdir -p .xcodebuildmcp cat > .xcodebuildmcp/config.yaml <<'YAML' schemaVersion: 1 sessionDefaults: projectPath: "<プロジェクトパス>" scheme: "<スキーム名>" derivedDataPath: "./DerivedData" platform: "iOS" useLatestOS: false bundleId: "<バンドル ID>" YAML fi fi fi 問題その2: シミュレータを複数セッションが奪い合う 何が起きたか iOS 開発では、シミュレータ上での実操作が必要な場面が多々あります。 画面情報・遷移情報の取得 コード変更後の動作確認 E2E テストの実行 AI に並行開発させている中でこれらの動作をさせようとすると、1 台のシミュレータを複数のセッション(エージェント)が奪い合い、開発が滞る問題が発生しました。 操作の割り込み・競合: あるエージェントの検証中に、別のエージェントが起動・操作を行って画面を奪い合う 状態の破壊: 実行中のアプリ領域やデータが上書きされ、E2E テストや動作確認が誤判定される 処理の順番待ち: シミュレータの空き待ちが発生し、並行開発のスピード感が失われる 対処方針: worktree ごとに専用シミュレータを持たせる 対策として、 worktree ごとに専用シミュレータを持たせる運用にしました。 具体的にはシミュレータ名を <worktree 名> - <元の機種名> (例: feature-A - iPhone 16 Pro )のように紐付けます。これにより「このセッションが触っていいのはこの 1 台のみ」と明確にし、他のセッションで稼働中のシミュレータへの誤干渉を防いでいます。タスクが完了して役目を終えたシミュレータはシャットダウンし、別の worktree での開発で名前を変更して再利用する流れです。 💡 基本的には AI による並行開発を前提としていますが、人間が最終的な動作確認を行う場合にもメリットがあります。各 worktree 専用のシミュレータ上にビルド済みアプリがそのまま残っているため、スムーズに動作確認を進められます。 シミュレータの選定ルール ある worktree の開発で使うシミュレータの選定ルールは、以下のようにしました。 worktree 名で始まるシミュレータが起動済みなら、それをそのまま使う worktree 名で始まるシミュレータが未起動なら、起動して使う 無ければ、起動していないシミュレータを <worktree 名> - <元の機種名> にリネームして起動する これを実装に落とし込んだものが以下のコードです。 resolve_udid は ①→③ の順に「その条件に合うシミュレータがあるか」を確認していき、最初に見つかった 1 台を、その worktree に対応するシミュレータの UDID(デバイスの一意 ID)として採用します(見つかった時点で残りは確認しません)。あとはこの UDID を指定してビルドすれば、その worktree 専用のシミュレータに向けて実行できます。 wt = " $( basename " $PWD " ) " # worktree 名(例: feature-A)をシミュレータ名の接頭辞に使う # シミュレータ一覧を JSON で取得して devices_json にキャッシュする refresh_devices() { devices_json = $( xcrun simctl list devices available --json ) ; } # 未起動のシミュレータを起動する boot_sim() { xcrun simctl boot " $1 " 2 > /dev/null ; } # UDID から元の機種名を引く(既に worktree 名が付いていれば落とす。付け足すと再利用のたびに接頭辞が積み重なるため) sim_name() { printf ' %s ' " $devices_json " | jq -r --arg u " $1 " \ ' [.devices[][] | select(.udid == $u) | .name][0] // empty | sub("^.+ - "; "") ' } # 指定した起動状態(booted / unbooted)で、worktree 名で始まるシミュレータの UDID を返す(無ければ空文字) pick_named() { printf ' %s ' " $devices_json " | jq -r --arg wt " $wt " --arg want " $1 " \ ' [.devices[][] | select((.name | startswith($wt + " - ")) and (if $want == "booted" then .state == "Booted" else .state != "Booted" end)) | .udid][0] // empty ' } # 未起動(Shutdown)の空きシミュレータを1台返す(無ければ空文字) pick_spare() { printf ' %s ' " $devices_json " | jq -r \ ' [.devices[][] | select(.state == "Shutdown") | .udid][0] // empty ' } resolve_udid() { refresh_devices # ① worktree 名で始まるシミュレータが起動済みなら、そのまま使う udid = $( pick_named booted ) ; [ -n " $udid " ] && { echo " $udid "; return; } # ② worktree 名で始まるシミュレータが未起動なら、起動して使う udid = $( pick_named unbooted ) ; [ -n " $udid " ] && { boot_sim " $udid "; echo " $udid "; return; } # ③ 無ければ、空きシミュレータの接頭辞を「<worktree 名> - 」に付け替えて起動する spare = $( pick_spare ) [ -z " $spare " ] && { echo " 空きシミュレータがありません " >&2; return 1 ; } xcrun simctl rename " $spare " " $wt - $( sim_name " $spare " ) " boot_sim " $spare " echo " $spare " } 開発フローとクロージング処理 ここまでの処理を開発フローに沿って並べると次のようになります。 開始 : タスクごとに worktree を切り、専用の作業場を用意する 実装 : その worktree で Claude セッションを開始し、1 つの機能を実装する 動作確認 : その worktree 専用のシミュレータを起動し、ビルド & 実行・テストを行う レビュー : 実装が固まったら PR を作成する クロージング処理 : PR マージと同時に、worktree 削除・Issue クローズ・シミュレータのシャットダウンを行う 開発フローの最後には、クロージング処理を置いています。 close-feature のようなスキルにまとめ、PR マージ → Issue クローズ → worktree 削除 → 専用シミュレータのシャットダウンを一括で実行しています。 このクロージング処理をフローに組み込むことで、問題その1で挙げた DerivedData によるストレージ圧迫を防ぎつつ(worktree を削除すれば配下の DerivedData も一緒に消える)、起動したままのシミュレータが積み上がってメモリを圧迫するのも同時に抑えられます(シャットダウンした端末は、次のタスクで再利用される)。 問題その3: .xcodeproj のコンフリクトが多発する .xcodeproj を Git 管理しているとブランチの切り替えやマージのたびにコンフリクトが起きやすい、という問題があります。これ自体は昔からある iOS 開発の悩みですが、AI に複数タスクを並行開発させるようになってコンフリクトの頻度も増え、無視できないコストになったと感じています。 トモニテの PJ では実現できていませんが、下記の理由により XcodeGen を用いた YAML 管理への移行を検討しています。 1. 並行開発でのコンフリクト軽減 git worktree などを活用して複数ブランチでの並行開発を進める場合、 project.pbxproj のコンフリクトが多発する可能性があります。 特に AI の活用によって開発の速度や並行性が上がるほど、その発生頻度も多くなりがちです。 XcodeGen を導入して .xcodeproj を自動生成の成果物として扱い .gitignore に追加することで、 .xcodeproj でのコンフリクト問題を解消できると考えています。 2. AI と YAML の相性 Xcode のプロジェクト管理は GUI 操作を前提とした仕組みであり、AI エージェントとは相性が良くありません。これを project.yml による宣言的なテキスト管理に切り替えることで、「YAML での管理・変更 → コマンド実行( xcodegen generate )」という AI に適したフローで構成を変更できるようになると考えています。 3. コードレビューのしやすさ コード差分が複雑な pbxproj からシンプルな project.yml に変わることで、変更内容を容易に把握できます。 AI がコードを書き、人間がレビューするフェーズでは可読性の観点でもメリットがあると考えています。 まとめと残課題 ここまで git worktree を用いた iOS の並行開発で出会った問題点と、その対処方法を紹介してきました。 とはいえ、こうして並行タスクを回す仕組みを整えても、human-in-the-loop 的な体制では並行開発の効果も限界があると感じています。監督する人間のコンテキストスイッチがボトルネックになるため私の場合、同時に見られるのは 3〜4 タスクほどでした。これでは開発生産性も頭打ちになり、「プロダクトや事業をどう伸ばすか」という本質的な問いに集中できないと感じています。 この課題を突破するためには、やはり「ループエンジニアリング」など AI がより自律的に開発を回せるような仕組みを追求していくことが不可欠だと感じています。 関連リンク XcodeBuildMCP XcodeGen
こんにちは、ソリューションアーキテクトの田邊です。2026 年 6 月 25 日から 26 日にかけて幕張メッセで開催された AWS Summit Japan 2026 の AWS for Industries Zone(ブース番号 044 )にて、スマートグラスと生成 AI エージェントを組み合わせた倉庫ピッキング支援デモを展示しました。本ブログでは、展示内容とその裏で動いている AWS サービス構成を、デモの体験に沿ってご紹介します。 背景:倉庫ピッキング業務の課題 倉庫のピッキング業務は物流オペレーションの中でも人手に依存する割合が高く、ハンディターミナル(専用の携帯端末)の導入は進んでいるものの、以下のような課題が現場に残っています。 両手が塞がる : 商品を持つ・置く動作と端末操作が競合し、重量物のハンドリング時に効率が落ちる 視線の移動 : 端末画面と棚を交互に見る必要があり、ピッキングミスや作業テンポの低下につながる 教育コスト : 新人・パート作業者が端末操作や棚配置を覚えるまで時間がかかる 多言語対応 : 外国人作業者が増える中、日本語のみの指示系統ではオンボーディングに時間がかかる これらの課題に対して、スマートグラスと生成 AI エージェントを組み合わせ、「見るだけ・話すだけ」で業務システムにアクセスできる新しい業務体験を提案するデモを企画しました。 デモの全体像 今回のデモでは、倉庫のピッキング業務を題材に、スマートグラスと生成 AI エージェントによるハンズフリー業務支援を紹介しました。特徴は以下の2点です。 1. 音声だけで完結する業務システム操作 「ピッキングリストをください」と話しかけるだけで、倉庫管理システム( WMS )から作業リストを取得し、音声で案内 商品の QR コードをスマートグラスでスキャンするだけで、ピッキング完了が自動で記録 端末画面のタップは不要。両手で商品を扱いながら業務を進められる 2. 自然な多言語対話 Amazon Nova 2 Sonic により、人と話しているような低遅延で自然な音声対話を実現 英語・スペイン語・ドイツ語・フランス語・イタリア語・ポルトガル語・ヒンディー語に対応(話した言語を自動判定して同じ言語で応答) 商品の取扱注意など業務ナレッジも、社内マニュアルから探して読み上げ 使用したスマートグラス 本デモでは、Android を搭載したスマートグラス 2 機種を用意し、来場者に体験いただきました。両機種とも AI エージェントと対話するアプリを単体で動作させることができ、それぞれ形状・視認性・装着感に特徴があります。 Vuzix M400 — Android11 を搭載し単体で動作するモノキュラー(単眼)型のスマートグラスです。1,280 万画素のカメラでバーコード読み取りに対応し、本体 68 g、IP 67の防水防塵性能で倉庫環境にも適しています。ノイズキャンセリングマイクを搭載しており、周囲に環境音がある現場でも音声を正確に拾うことができます。 RayNeo X3 Pro — Android を搭載したフルカラー MicroLED ディスプレイを持つ眼鏡型のスマートグラスです。バーコード読み取りに加え、音声・映像を組み合わせたマルチモーダルな対話に対応します。輝度 6,000 ニットの高い視認性で、明るい場所でも表示内容がしっかり見えます。装着感が眼鏡に近く、より日常的なユースケースにも馴染むデザインです。 なお、本デモのアプリは Android で動作する仕組みのため、Vuzix・RayNeo に限らず、Android 対応の他のスマートグラスやタブレット・スマートフォンでも同様の体験を実現できます。 アーキテクチャ構成 デモのアーキテクチャは以下のような構成になっています。 スマートグラス上の Android アプリはシンプルな役割に絞り、会話の理解・業務データの取得・回答生成といったロジックはすべてクラウド側の Amazon Bedrock AgentCore Runtime に集約しています。全体の処理の流れは次のとおりです。 認証 : 端末にクラウドの長期パスワード的な情報を置かず、Amazon Cognito と AWS Lambda により一時的な接続 URL を発行するセキュアな仕組み 音声送受信 : スマートグラスから作業者の音声をリアルタイムに Amazon Bedrock AgentCore Runtime へ送信。Amazon Nova 2 Sonic が音声を直接理解し、応答の音声を返す 業務データへの問い合わせ : エージェントが必要に応じて Amazon Bedrock AgentCore Gateway を介し、ツール(関数)を呼び出し、Amazon DynamoDB ( WMS データ)や Amazon Bedrock Knowledge Bases (社内マニュアル)からデータを取得 この構成により、スマートグラス側は音声とカメラの入出力に専念でき、エージェントの機能追加やプロンプト調整はクラウド側の変更だけで反映されます。以下、デモのシナリオを順に追いながら、各ステップで動いているサービスを見ていきます。 ① 音声でタスク取得 作業者がスマートグラスに「ピッキングリストをください」と話しかけると、生成 AI エージェントが WMS から作業リストを取得し、棚番号・商品名・数量を音声と画面で案内します。 裏側では、スマートグラスから送られてきた音声をクラウド上の Amazon Nova 2 Sonic が受け取ります。Amazon Nova 2 Sonic は音声を直接理解し、そのまま音声で応答を返せる生成 AI モデルです。従来の「音声を一度文字に起こしてから生成 AI に渡し、生成された文章を再び音声にする」という 3 段階の処理と違い、音声のまま処理するため、人と話しているような自然で低遅延なやり取りが可能になります。作業者の意図が「ピッキングリストの取得」だと判断されると、エージェントが WMS 用のツールを呼び出し、Amazon Dynamo DB からリストを取り出して音声で読み上げ、同時にタスク一覧を画面に表示します。 ② QR スキャンで商品照合・完了 案内された棚に移動し、商品のQR コードをスキャンすると、エージェントが商品を照合し、ピッキング完了を WMS に自動で記録します。次のアイテムがある場合は続けて音声で棚の場所を案内し、全アイテム完了時には作業時間もフィードバックします。 ここでは、音声とカメラという異なる入力を、同じ会話の流れの中で扱っています。QR スキャンの結果はテキスト情報として Amazon Nova 2 Sonic に渡り、エージェントは「今、この作業者は音声で受けたタスクの商品をスキャンした」と文脈を理解した上で、Amazon Dynamo DB に完了記録を書き込みます。作業者は「モードを切り替える」といった意識をせず、話す・スキャン・話す、というテンポで作業を進められます。 ③ 視覚支援と業務ナレッジ照会 「棚の場所が分からない」と聞けば倉庫マップで棚位置をハイライト表示、「タイミングベルトの取扱注意点は?」と聞けば社内マニュアルから該当箇所を音声で読み上げます。 業務ナレッジの音声応答は、Amazon Bedrock Knowledge Bases という機能で実現しています。これは、事前に社内のピッキングマニュアルなどのドキュメントを Amazon S3 に置いておくと、生成 AI が質問の意図に合わせて関連する記述を意味的に検索してくれる仕組みです。エージェントは検索結果をもとに要点をまとめ、Amazon Nova 2 Sonic を通じて自然な音声で回答します。マニュアルを更新しても、それを取り込み直すだけで、エージェントの回答が常に最新の内容に保たれます。 1 会話あたりのコスト ブース来場者から多くいただいた質問がコスト面でした。本デモの構成で、ピッキング 4 アイテムを約 3 分で処理する会話1回あたりのコストは、およそ 8.9 円( 1 USD = 160 円換算)です。1 端末あたり 100 会話/日 × 30 日で月額約 26,720 円と、実運用に耐える水準です。コストの大半(約 78 %)は音声の生成( AI の応答音声)が占めるため、AI の応答を簡潔にする工夫がコスト削減に最も効きます。 期待される効果 本ソリューションの導入で、以下のような効果が期待できます。 作業者の身体的・認知的負荷の低減 : 端末操作から解放され、視線を作業対象に集中できる 教育コストの削減 : 音声で作業指示・マニュアル照会ができ、新人・短期雇用者の即戦力化が容易 多言語対応による人材活用 : 外国人作業者にも母語で指示・案内が可能 既存 WMS を活かした導入 : 現行の業務システムを置き換えず、生成 AI エージェントから連携 本デモのコアである「生成 AI エージェント × ウェアラブルデバイス × 音声インタラクション」の組み合わせは、倉庫ピッキングに限らず、「両手を使う現場作業×システム連携」が求められる幅広い領域に応用可能です。製造ラインでの作業指示と部品照合、医療現場での検体照合と電子カルテ入力、設備点検・警備での手順書参照とレポート入力、店舗のバックヤード在庫確認など、応用先は多岐にわたります。 まとめ AWS Summit Japan 2026 で展示した「スマートグラス × 生成 AI エージェント」は、倉庫ピッキング業務における「両手が塞がる」「教育コストが高い」「多言語対応が難しい」という課題に対し、見るだけ・話すだけで業務システムにアクセスできる新しい業務体験を提案するものです。Amazon Bedrock AgentCore Runtime と Amazon Nova2 Sonic の組み合わせで、サーバレスで実装できます。物流業界は 2024 年問題をはじめ様々な課題に直面していますが、生成 AI エージェントを既存の業務システムに繋ぐことで、現場の負荷を減らしながら生産性を高めることが可能です。ご興味のある方は、担当ソリューションアーキテクトまでお気軽にご相談ください。 会場では倉庫ピッキング以外のユースケースについても多くのご相談やディスカッションをいただき、このソリューションパターンへの関心の高さを実感しています。 この展示は、ソリューションアーキテクト横山、駒野、山本、田邊が担当しました。
    株式会社エブリーは、「前向きなきっかけを、ひとりひとりの日常にとどける。」というミッションのもと、デリッシュキッチン、retail HUB、トモニテ、MOMENTH といった BtoC・BtoB を横断するメディアやサービスを展開しています。同社では、小売事業者向けサービス retail HUB におけるピッキングサービスの新規開発にあたり、データベースとして Amazon Aurora DSQL を採用しました。本ブログでは、お客様の開発チームに伺った Aurora DSQL 採用の背景、導入の取り組み、そして導入後に得られた効果についてご紹介します。 対象システム 今回 Aurora DSQL を採用したのは、 retail HUB 事業のネットスーパーサービスにおけるピッキングサービスです。 retail HUB は、お客様が提供する小売事業者向けの DX ソリューションです。店頭サイネージによるレシピ提案、デジタルチラシ、ネットスーパーアプリの提供、店頭運営の効率化、CRM によるロイヤルカスタマー育成まで、小売事業者の販促プロセス全体をデジタル化し、業務効率化ときめ細やかな顧客アプローチを実現しています。 retail HUB 事業のネットスーパーサービスでは、店舗側が売り場から注文商品をピックアップする作業が発生しますが、従来この運用は紙のリストで行われており、商品を探すのに時間がかかることや習熟度による作業スピードのばらつきなどにより人的ミスの防止が難しく、誤ピックによる取り直しが発生するといった課題がありました。この問題を解決するため、ピッキングアプリ「retail HUB Picker」の開発が求められました。 アーキテクチャ ピッキングサービスのアーキテクチャは、ピッキングアプリ(Android アプリ)から Amazon ECS + ALB で構成された API サーバーに接続し、担当者の認証管理には Amazon Cognito を利用しています。バックエンドのデータベースとして Aurora DSQL を採用し、ピッキング対象の商品情報やピッキング状態、担当者情報の格納・参照に使用しています。 ピッキングサービスのシステムアーキテクチャは以下のとおりです。今回新規に開発したピッキングシステムは既存のネットスーパーシステムとは分離しており、注文データを連携する箇所のみで結合しています。 データベース選定の背景 今回のピッキングサービスは新規開発であり、データベースの選定にあたってはシステムの特性に合わせた検討が行われました。データベースに求められる要件は以下でした。 安定性と可用性 ピッキング作業中にシステムが停止すると店舗のピッキング業務に影響を与え、導入店舗数が増えるほどその影響範囲も大きくなるため、安定性と高い可用性が重要な要件でした。また、小売店舗は土日も稼働しているため、運営側の都合でメンテナンス時間を設定しにくいというビジネス上の課題も考慮する必要がありました。 低コストによるスモールスタート 初期フェーズではリクエスト数が限定的であり、構築・運用にあまりコストをかけたくないという要望がありました。一方で、今後サービスの成長に伴いトラフィックの増加も想定されるため、高いスケーラビリティを備えたデータベースであることが望ましいと考えていました。 運用負荷の軽減 メンテナンスウィンドウに伴う運用負荷が課題となっていました。新規サービスでは、こうした運用負荷を極力下げたいという考えがありました。 Aurora DSQL を選択した理由 お客様では当初、既存システムで利用している Amazon RDS for MySQL や Amazon Aurora MySQL の導入を想定していました。しかし、上記の要件を踏まえて検討を進めた結果、サーバーレスの分散データベースである Aurora DSQL が採用されました。その理由は以下の通りです。 安定性と可用性 — シングルリージョン構成で 99.99%(マルチリージョン構成では 99.999%)の可用性を備えたサーバーレスの分散データベースであり、インフラ管理が不要。ピッキング作業中のシステム停止リスクを低く抑えられる 低コストによるスモールスタート — 従量制の課金モデルで初期コストを抑えつつ、将来のサービス成長に伴うトラフィック増加にも自動スケールで対応できる 運用負荷の軽減 — パッチ適用がダウンタイムなしで自動的に行われるため、関係者との調整や作業工数が不要になる 加えて、Aurora DSQL が PostgreSQL との互換性を備えていたことで、社内の既存知見を活かしながら導入できる点も後押しとなりました。また、お客様の開発チームには分散データベースへの技術的な関心が高く、Aurora DSQL を通じて得られる知見が今後の技術選定の指標になるという期待も大きく、採用の決め手の一つとなりました。 Aurora DSQL とは Aurora DSQL は、AWS が提供するサーバーレスの分散 SQL データベースです。従来のデータベースのようにクエリ処理・ストレージ・トランザクション管理が密結合した構成ではなく、それぞれが独立したコンポーネントに分かれています。各コンポーネントがワークロードに応じて個別にスケールするため、特定の処理がボトルネックになりにくく、低レイテンシーで強固な一貫性を実現しています。また、PostgreSQL との互換性を備えており、既存の PostgreSQL の知見やツールを活かして開発を進めることができます。 お客様が選定の理由に挙げた以下の 3 つについて、Aurora DSQL の特性を簡単に説明します。 安定性と可用性 Aurora DSQL では、すべての書き込みトランザクションを分散トランザクションログにコミットし、コミットされたすべてのログデータを 3 つのアベイラビリティーゾーンにあるストレージレプリカに同期レプリケーションします。これにより、Aurora の Multi-AZ 構成と同等の 99.99% の可用性を実現しています。以下の図は、Aurora DSQL の可用性に関する特性を示しています。 低コストによるスモールスタート 課金はリクエスト数やデータ量に応じた従量制で、リクエスト数が少ない段階ではコストを低く抑えられます。アーキテクチャを変更することなく自動的にスケールするため、小規模な構成から始めて、トラフィックの増加に応じてシームレスにスケールすることができます。以下の図は、Aurora DSQL のコストモデルを示しています。 運用負荷の軽減 サーバーのプロビジョニングやパッチ適用、インフラのアップグレードといった管理作業が不要です。パッチ適用やセキュリティアップデートはダウンタイムなしで自動的に処理されるため、メンテナンスウィンドウの調整や計画停止が不要です。以下の図は、Aurora DSQL と従来のデータベースにおけるメンテナンスの違いを示しています。 開発時の課題 開発スケジュール 開発スケジュールは以下のとおりです。 時期 内容 2025年5月 小売事業者に対するヒアリング(事業部門+開発部門) 2025年6月 運用分析、開発要件定義、分析要件定義、システム設計 2025年7月〜8月 開発(アプリケーション、API サーバー、インフラ、分析基盤) 2025年9月上旬 社内 QA 2025年9月中旬 リリース、小売事業者にて検証・運用開始 Aurora DSQL を用いた開発にあたっては、PostgreSQL との互換性に関していくつかの課題がありました。 スキーマ変更の制約 Aurora DSQL ではカラム追加時にデフォルト値を指定する構文がサポートされていないことが開発中に判明しました。PostgreSQL では一般的に使用される構文であるため、既存の知見をそのまま適用できないケースでした。対処として、カラムのみを追加し、デフォルト値や NOT NULL 制約はソフトウェアレベルで保証する実装としました。なお、サービスリリース前であったため、最終的にはテーブルを再作成することで問題を回避しました。このように、事前のドキュメント確認だけでは把握しきれず、実際の操作を通じて発見される差分もありました。 ローカル開発環境との互換性 当初ローカル開発では PostgreSQL のコンテナを使用していましたが、 CREATE INDEX を CREATE INDEX ASYNC に変更する必要があるなど、Aurora DSQL との互換性がない部分が判明したため、ローカル環境でも Aurora DSQL を使用する方式に切り替えました。 トランザクションサイズの制限 Aurora DSQL にはトランザクションデータ件数に制限があるため、大量のデータを一括で処理する実装には工夫が必要でした。この制限を回避するため、大量のデータ投入処理においては全体を 1 トランザクションにまとめず、処理を分割する設計としました。具体的には、データ量が大きい投入処理ではトランザクションを使わずに実行し、途中でエラーが発生しても何度でもやり直せる設計としました。その上で、整合性の担保が必要な少量のデータ更新処理だけをトランザクション内で実行するようにしました。 こうした課題を一つずつ解消しながら開発を進め、ピッキングサービスは無事にローンチを迎えました。 ローンチと導入後の効果 2025 年 9 月中旬にローンチしてから数ヶ月が経過していますが、大きな問題は発生しておらず、安定した稼働を続けています。 導入後に得られた効果は以下のとおりです。 コスト削減 Aurora PostgreSQL(Provisioned)で想定していたインスタンスサイズと比較すると、コストは 90% 以上低くなっています。従量制のコストモデルにより、初期フェーズにおいて大幅なコスト削減を実現しました。 以下は、今回のワークロードを想定したコスト比較の試算です。Aurora PostgreSQL(Provisioned)を 100 とした場合の相対コストを示しています。 構成 Pattern S コスト比 Pattern M コスト比 Pattern L コスト比 Aurora PostgreSQL (Provisioned) 100% 100% 100% Aurora Serverless v2 41% 41% 66% Aurora DSQL 4% 6% 12% 安定稼働とメンテナンスフリー サービス導入後は安定して稼働しており、パフォーマンス上の問題も発生していません。メンテナンスウィンドウが不要であるため、基盤のメンテナンス作業そのものだけでなく、それに伴う小売事業者やサービス利用者との調整業務も不要となりました。既存システムでは 3 ヶ月ごとのパッチアップデートのたびに、メンテナンス時間帯の調整、影響範囲の洗い出し、小売事業者や関係部署への連携が必要でしたが、Aurora DSQL ではこうした業務コストがゼロになり、運用負荷が大きく削減されました。 スケーラビリティの確保 現時点でのリクエスト数の変動については特に大きな問題は発生していません。今後のサービス成長に伴うトラフィック増加についても、検証の結果スケーリングに問題がないことを確認しており、今後のトラフィック増加にも不安なく運用できる見通しです。 お客様の声 お客様に Aurora DSQL の導入効果について伺ったところ、次のように述べています。 スケーラビリティと安定性の要件が高いシステムにおいて Aurora DSQL を選択する利点は高いと考えています。 – 内原 章 氏 株式会社エブリー 開発本部 開発2部 部長 今後の展望 お客様では、今回のピッキングサービスでの導入実績を踏まえ、スケーラビリティの要件が高いシステムにおいて Aurora DSQL を選択肢として検討していく方針です。新規開発だけでなく、既存システムのリプレースにおいても Aurora DSQL の活用を視野に入れています。 また、Aurora DSQL のさらなる進化への期待として、PostgreSQL との互換性向上を挙げています。特に RLS(Row Level Security)のような機能がサポートされることで、より幅広いユースケースに対応しやすくなると考えています。 Aurora DSQL は、高い可用性とスケーラビリティを必要とするシステムにおいて、運用負荷とコストの低減が期待できるデータベースです。本ブログが、同様の課題を持つお客様にとって参考になれば幸いです。

動画

書籍