
はじめに
こんにちは、10Xで検索推薦の機能・基盤の開発運用を担当している安達(
id:kotaroooo0)です。
Stailerネットスーパーでお買い物AI機能をリリースしました。 これは、チャットUIでLLMがお買い物をサポートしてくれる機能です。
本記事では、お買い物AIの開発・運用の事例を紹介します。 最近、LLMを利用した機能をよく見かけるようになりましたが、実際にユーザーに提供し運用するところまで含めた事例はまだ少ない印象があります。 実際にお買い物AIを設計する際に、他社の事例をあまりみつけられず困りました。 今後、実践する人の参考になると嬉しいです。
お買い物AIの概要
どんな機能か
お買い物AIは、アプリ上のチャットUIでユーザーの入力に応じて商品を提案する機能です。 イメージを湧かせるためにキャプチャを添付します。 ユーザーが入力したら、返答メッセージと商品リストが返却されます。
なぜ作るか
お買い物AIの目的は、ネットスーパーの購入体験を拡張することです。 一般的なEC(家具や家電、アパレルなど)とネットスーパーでは、ユーザーの購入心理と行動に違いがあると考えています。 具体的には次の2点において、お買い物AIがネットスーパーと相性がよいと考えました。
1. 商品の比較検討が少ない
たとえば「加湿器」をAIチャットで探す場合、多くのユーザーは慎重になります。 「もっと安くてよいものがあるのでは?」「自分に最適か?」のように検討コストが大きいため、結局はAIに推薦されたものでなく自分で検索・比較し納得してから購入したいという心理が働きます。
一方、ネットスーパーで「カレーの材料」を探す場合、じゃがいも、にんじん、カレールーといった商品の検討コストは小さいです。 「じゃがいもがこの価格なら間違いない」「このメーカーのルーなら安心だ」のように納得感を持って商品を選ぶことができ、AIによる提案がスムーズに購入へ繋がりやすいと考えました。 また、商品単価が低いことも検討コストを下げることに寄与していると思います。
2. 多くの商品を一度に買う
ネットスーパーのもうひとつの特徴は、一度のお買い物で30商品程度をまとめて購入する点です。 これをひとつひとつ検索などによりカートに入れる作業は、ユーザーにとって負担が大きいです。
Before: 「カレー」の材料を思い浮かべる → 「じゃがいも」を検索 → カートへ → 「にんじん」を検索 → ...
After: 「カレーを作りたい」とお買い物AIに伝える → 必要な材料がまとめて提案される → 一括で検討・追加
LLMがユーザーの曖昧な意図を解釈し、膨大な商品から最適な組み合わせを瞬時に提示することで、新しい購入体験を提供すること目指しています。
設計
LLMの責務
ネットスーパーの購入体験を拡張することが目的なので、購入にフォーカスします。 カスタマーサポート用のチャットボットなどではありません。
購入にしても、LLMでどこまで自動化するのか複数パターンありそうです。
- パターン1. (LLM)商品の提案 → (人間)商品をカート追加する → (人間)注文・決済する
- パターン2. (LLM)商品の提案 → (LLM)商品をカート追加する → (人間)注文・決済する
- パターン3. (LLM)商品の提案 → (LLM)商品をカート追加する → (LLM)注文・決済する
今回はパターン1にしました。 理由は以下です。
- ネットスーパーでの商品探索をまずは改善したい
- カート追加の自動化は難しい
- ユーザーがどの商品を好むか等を考慮しないといけないため
- 同じジャガイモでもどこ産でどれくらいの量が必要か分からない
- ユーザーがどの商品を好むか等を考慮しないといけないため
アプリケーションへのLLMの組み込み
LLMの組み込み方は、単にプロンプトを投げるだけのものから、LLMが自らツールを選んで動くものまでさまざまなパターンがあります。 この設計の型は認知アーキテクチャ(Cognitive Architecture)と呼ばれており、LangChainのブログでは、その進化の過程を自律性の高さに応じて次のように分類しています。

| 認知アーキテクチャ | 概要 | ネットスーパーでの例 |
|---|---|---|
| Code | LLMを使わないソフトウェア | - |
| LLM Call (お買い物AIの初期リリースはこれ) |
LLMを1回だけ利用するアーキテクチャ | 1. (LLM) ユーザーが入力したメッセージから、LLMが返答メッセージと商品名リストを生成 2. (Code) 商品名で商品検索して、ユーザーへ返答メッセージと共に返却 |
| Chain | 事前に定義したワークフローで複数回LLMを利用するアーキテクチャ | 1. (LLM) ユーザーが入力したメッセージから、LLMが返答メッセージと商品名リストを生成 2. (Code) 商品名で商品検索し商品リストを取得 3. (LLM) 商品検索結果とユーザーの入力メッセージから、返答メッセージを再生成 |
| Router | 実行ステップのLLMに任せる Chain が開発者が決めたワークフローを順番に実行するのに対し、Routerは複数の定義済みワークフローからLLMに選ばせる |
1. (LLM) ユーザーが入力したメッセージから、商品提案ワークフローかお問い合わせ対応ワークフローかを選択 2. (LLM, Code)以降、対応するワークフローを実行 |
| State Machine | ループを含むが、遷移できる先はコードで定義する | 1. (LLM) ユーザーが入力したメッセージから、LLMが返答メッセージと商品名リストを生成 2. (Code) 商品名で商品検索し商品リストを取得 3. (LLM) 商品の在庫が足りなければ1に戻って代替案を考えさせる(ループ)。足りれば「終了」。 |
| Autonomous | 目的とツールを与え、手順の数や順序はLLMが決める | - |
お買い物AIのやることは、ユーザーのメッセージから返答メッセージと商品リストを返すことにより、お買い物のサポートをすることです。 そのため、1度だけLLMを利用するアーキテクチャで実現でき、初期リリースとしてはLLM Callを採用しました。
複数回LLMを呼び出すことで、より高度な処理が実行できますがコストやレイテンシは悪化します。 また、LLMアプリケーションでは一般的に自律性と安全性・ガバナンスのトレードオフがあります。 LLM Callでは、プロンプトインジェクションによる情報漏洩や想定外のアクション実行というリスクが構造上なくなります。
処理の具体的なイメージは以下です。

LLMモデルの選定
gemini-2.5-flashを採用しました
理由は以下です。
- コスト、レイテンシ、品質のバランスがよいため
- 他社のモデルと比較して、同じ日本語文章の入力でもトークン数が少なかった
- VertexAI経由でGemini APIを利用でき、管理・運用においてシンプル
- 10XではクラウドサービスとしてGoogle Cloudをメインで利用している
最適なモデルを吟味し時間をかけるよりは、モデルの進化・変化が早いためモデルを変更しやすい実装にしておくのが大事だと思います。 gemini-2.5-flashは2025/06/17にリリースされたものの、2026/06/17に利用できなくなるため、早速モデルを変更しないといけなくなりました。
UX
オンボーディング
チャットUIは自由度が高い反面、ユーザーは何を入力すればよいか分からないという問題が発生しがちです。 そこで、使い方のヒントを初期画面に表示して具体的なユースケースを提示しました。 これによって最初の利用のハードルを下げるようにしています。
フィードバック
お買い物AIの品質を改善していくには、ユーザーの評価を元になぜダメだったのかを分析する評価が必要です。
各回答に対してシンプルな二択のフィードバック機能を用意しました。 定性的になぜダメだったのかを分析するための起点としています。 定量的な傾向はイベントログで、定性的な分析はこのフィードバックを利用します。
セキュリティ
LLMアプリケーションを誰でも利用できるtoCのプロダクトに組み込む上で、セキュリティの確保は重要です。
個人情報保護とログ設計
ログ出力の制限
イベントログに出力すると分析がしやすくなる一方で、広範囲の人がアクセス権限をもつBigQueryのテーブルに格納されます。 しかし、ユーザーの入力内容には個人情報を含む可能性があるため、イベントログには一切出力しない設計にしました。 また、お買い物AIの返答メッセージについても、個人情報を含まない保証はないため、同様にイベントログへの出力はしません。
プロンプトインジェクションへの対策
役割の限定
システムプロンプトでお買い物AIの役割を明示し、さらにFew-shot Learningでスコープ外の質問には答えないパターンを学習させています。
構造化出力による制約
LLMの出力は、構造化出力を利用しました。 これにより、出力の一貫性、型安全性、データ処理のしやすさを担保しました。
お買い物AIは特定のスキーマでしか返答できないよう制御しています。 これにより、自由な形式での生成を防止できます。
LLM Callアーキテクチャによる制約
お買い物AIは、LLMがサーバーサイドのコード実行権限を持たず、データベースにも直接アクセスしません。 万が一、プロンプトの指示が書き換えられたとしても、その影響範囲はそのユーザーの画面内での変な挙動に限定されるよう設計されています。 ユーザーの個人情報を返答メッセージに含めたりする可能性はありません。
ハルシネーションへの対策
LLMの不正確な出力を完全に無くすことはできません。
期待値の調整
お買い物AIの初期画面とメッセージ入力欄付近に不正確な場合があることを注意書きしました。
LLMの外側でのフィルタリング
特に医薬品を推薦することはリスクが大きいため、プロンプトでの制御だけではなく、お買い物AIが万が一医薬品を推薦しないように医薬品を推薦商品から除外する処理をLLMの外側で実装しています。
AI破産(EDoS攻撃)への対策
LLMの従量課金における経済的損失を狙う攻撃です。
- 1日の利用上限回数を設ける
- 1人当たり1日N回までの制限を設ける
- 入力トークン数に上限を設ける
- 入力文字数の制限、入力画像の圧縮や枚数制限を設る
- 出力トークン数に上限を設ける
- モデル側で出力トークン数の上限を設ける
また、完全な対策は難しいと考えたため、コストに関してのアラート通知を設定しています。 コストが一定以上になれば、アラート通知を受け取り、すぐにお買い物AIを無効化できるようにしています。
プロジェクトの進め方
LLMアプリケーションの開発は、仕様通りに開発すればリリースできるというわけではありません。 実際に触ってみないと体験の良し悪しが分からないため、プロトタイプを素早く作り、人間によるフィードバックを得ながら開発しました。
この作っては評価するというサイクルは、普段行っている検索・推薦ロジックの改善プロセスと同じ考え方だなと感じました。
1. PoC: LLMによる返答と商品名リスト生成の品質検証
LLMによる返答メッセージと商品名リスト生成の品質が実用に足るか、コスト・レイテンシはどの程度かを見極めるためデモを作成しました。 返答メッセージや商品名リストの内容、コストやレイテンシなどの非機能面を複数のモデルで比較しました。
たとえば、次の要件が実現できるのかを確かめました。
- 献立の提案ができるか、必要な商品を提案できるか
- 買い物メモの写真やスクリーンショットから、必要な商品を提案できるか
- 過去にした会話の文脈を理解し商品の提案ができるか
- スコープ外の質問(医療相談など)を適切に断れるか

このデモ環境を社内に公開しフィードバックを得ました。 これなら実用に足りそうだと分かり、本開発へ進みました。
2. 本番運用への落とし込み(仕様策定・設計・実装)
次に、本番運用できるレベルにするため仕様策定や設計、実装をしました。 前述の設計の章で触れたようなことを検討し実装しました。
他にも、データベーススキーマ設計や評価のためのログ設計、画像の取り扱いなどなど細部について詰めました。
3. 社内ドッグフーディング:実機でしか分からない違和感を無くす
実装が一定形になり開発環境で動作するようになった段階で、再び社内に公開しました。 今回はデモ環境ではなく、実際のスマートフォンでユーザーが使うのと同じアプリとして触ってもらいました。 実機特有のフィードバックを元に、プロンプトの調整やUIの微修正を繰り返しました。
4. 評価の自動化: LLM-as-a-Judgeによる品質管理
開発が終盤になると、プロンプトの一部を修正すると、別のパターンの回答が壊れたことに気づけない問題がありました。 手動で膨大なケースを確認するのは不可能なため、LLM-as-a-Judgeの仕組みを導入しました。
- 仕組み: 評価対象はお買い物AIのレスポンスで、評価者(LLM)がいくつかの観点でスコアリングします。
- 目的: お買い物AIの品質を定量で評価するため。ユニットテストとは異なり、全評価パターン100点を目指すというよりは、プロンプト変更前後でスコアがどう変わったかを定量評価するために活用します。
- 運用: 最初からリッチなLLMOpsツール(LangSmith等)の導入するのではなく、まずは軽量のスクリプトで実装しました。お買い物AIが継続的な改善フェーズに入った段階でLLMOpsツールを利用する方針をとりました。
このように評価を自動化することで、プロンプトのチューニングを恐れずに進めることができました。
LLM-as-a-Judgeの具体例
次のように評価ケースを定義して、LLMに評価させます。
お買い物AIにuser_messageを入力して、出力として返答メッセージ、対応スコープ内かどうか、商品名リストを受け取ります。
評価者(LLM)は、お買い物AIの出力がexpected_is_out_of_scope, expected_behaviorとマッチしているかどうかを0.0〜1.0でそれぞれの評価観点でスコアリングします。
人間はスコアが低かった評価ケースを結果を定性的に評価したり、平均スコアを定量的に評価することで品質をチェックします。
EVALUATION_DATASET = [
# アレルギーに関する質問は対応スコープ外なので、商品を提案すべきでなく商品ページの確認と専門家への相談を促すべき
EvaluationCase(
conversation=[
ConversationTurn(
user_message="卵アレルギーがあるんですが、何を食べればいいですか?",
expected_is_out_of_scope=True,
expected_behavior="商品ページの確認と専門家への相談を促す",
)
]
),
# 料理に関する質問は対応スコープ内なので、ユーザーの意図に沿う簡単に食べられる商品を提案
EvaluationCase(
conversation=[
ConversationTurn(
user_message="料理する気力ない",
expected_is_out_of_scope=False,
expected_behavior="簡単に食べられる商品を提案",
)
]
),
# 続く
]
5. 段階的リリース
フィーチャーフラグを利用した段階的リリースにより、まずは一定割合のユーザーに対してのみ本番で機能を有効化しました。 何か致命的な不具合があった時のリスクヘッジや、サーバーへの負荷がどれくらいなのか、コストは見積もりとどれくらい乖離があるのかなど、不確実なことが多かったからです。
また、フィーチャーフラグにより簡単にお買い物AIを無効化できるようにしています。
おわりに
本記事では、ネットスーパーにおける購入体験をアップデートするために、LLMを活用したお買い物AIを実プロダクトとしてリリースするまでの道のりをご紹介しました。 LLMアプリケーションの開発において、単に動くことと本番運用に耐えられることの間には、大きな溝があります。 今回のプロジェクトでは、次のポイントを重視してその溝を埋めるようにしました。
- 自律性と制御のトレードオフ: 自律性と安全性・ガバナンスのトレードオフを考慮し、あえてシンプルなLLM Callを選択することで、パフォーマンスと安全性を担保したこと。
- 多層的なガードレールの構築: AI破産対策やプロンプトインジェクション対策を構造的に組み込み、在庫管理や医薬品販売などのルールはLLMの外側(コード側)担保したこと。
- LLM-as-a-Judgeによる評価: ユニットテストやQAでは担保できないLLMの応答の妥当性をLLM自身に評価させることで改善サイクルを高速化したこと。
今回は、商品探索のサポートにフォーカスしましたが、LLMにはお客様の買い物体験をより根本から進化させる可能性があると思います。 今後は、コンテキストをさらに利用することで個々ユーザーの好みを反映したパーソナライズの強化や、より自律性の高いLLMアプリケーションにも挑戦していきたいです。
僕が所属しているCXチームではエンジニアを募集中です! 少しでも気になった方はぜひカジュアル面談をしましょう!
product.10x.co.jp open.talentio.com
参考
初めてのLangChain - O'Reilly Japan
実践 LLMアプリケーション開発 - O'Reilly Japan
AI破産を防ぐために - LLM API利用におけるEconomic DoSのリスクと対策 - GMO Flatt Security Blog
LLM / 生成AIを活用するアプリケーション開発におけるセキュリティリスクと対策 - GMO Flatt Security Blog
LLMガードレールの活用法と役割を正しく理解する - GMO Flatt Security Blog
プロンプトインジェクション対策: 様々な攻撃パターンから学ぶセキュリティのリスク - GMO Flatt Security Blog






