LIFULL Creators Blog

LIFULL Creators Blogとは、株式会社LIFULLの社員が記事を共有するブログです。自分の役立つ経験や知識を広めることで世界をもっとFULLにしていきます。

ネイティブアプリチームに作った"コードに質問できる"環境の裏側についての話

こんにちは、LIFULL HOME'Sのネイティブアプリケーション開発チームでエンジニアリングマネージャーをしている佐々木です。

前回の記事では、チームの業務知識をAIに構造化して渡すことで調査工数を80〜90%削減した話を書きました。その最後に「コンテキストレイヤー」という概念に触れました。企業のデータを束ね、ビジネスロジックを理解できる層をAIエージェントに供給する基盤のことです。

今回は、そのパッケージの技術設計について掘り下げます。作ったものをあらためてコンテキストレイヤーの視点で整理してみたら、5つのレイヤーにきれいに分解できたので、その構造に沿って説明していきたいと思います。

パッケージの全体像

まず構成要素を示します。

.kiro/
├── steering/        … メインエージェントの行動ルール(5ファイル)
├── agents/          … サブエージェント定義(7体)
└── skills/          … 質問パターンごとの手順定義(45個)
docs/                … API仕様・画面マッピング・ドメイン知識
repos/               … ソースコード(6リポジトリ)

メインエージェント(オーケストレーター)が質問を受け取り、スキルを参照して適切なサブエージェントに調査を委譲する。サブエージェントは独立したコンテキストでコードを読み、結果の要約だけをメインに返す。この構造を支えているのが「5層のコンテキストレイヤー」です。

レイヤー パッケージでの実装 役割
セマンティック docs/domain-knowledge.md 業務用語・分類体系の定義
メタデータ docs/bff/, docs/backend-api/ API仕様の構造化
リネージ docs/screen-mapping.md 画面→コードの追跡可能性
ポリシー steering/delegation.md 行動ルール・制約・委譲手順
トライバルナレッジ skills/(45個) 調査手順・暗黙のノウハウ

以下、各レイヤーの設計を詳しく見ていきます。

レイヤー①:セマンティック — ドメイン知識の構造化

docs/domain-knowledge.md には、LIFULL HOME'Sアプリケーション固有の業務用語と分類体系が定義されています。

たとえば「新築」には2種類あります。

  • 新築分譲: デベロッパーが直接販売。DB仕様書Aで管理
  • 新築仲介: 築1年以内・未入居だが仲介扱いの流通物件。DB仕様書Bで管理

この区別を知らないAIは「新築の物件詳細を教えて」と聞かれたとき、どちらのDBを見ればよいかわかりません。ドメイン知識がなければ調査が始められないのです。

物件種別コード(bukken_type)の分類体系、現行BFFと新BFF(未移行)の関係など、エンジニアの頭の中にしかなかった知識をMarkdownとして書き出しています。このレイヤーがあることで、AIは質問の文脈を正しく解釈できます。

レイヤー②:メタデータ — 30リポジトリを25ファイルで表現する

LIFULL HOME'SアプリケーションのBFFはGitHub上に30のマイクロサービスリポジトリとして存在します。バックエンドAPIも39エンドポイントを持っています。これらをすべてパッケージに含めるとサイズが膨大になる上、AIのコンテキストも溢れます。

設計方針は「アプリケーションが実際に利用しているエンドポイントの仕様だけを、Markdownとして抽出する」です。

docs/
├── bff.md               … 全24エンドポイントのアーキテクチャ概要
├── bff/                 … 利用エンドポイントの詳細仕様(19ファイル)
│   ├── search-common.md     … 物件検索共通パラメータ・変換仕様
│   ├── detail-rent.md       … 賃貸物件詳細のレスポンス構造
│   ├── detail-sale.md       … 売買物件詳細
│   └── ...
├── backend-api.md       … 全39エンドポイントの一覧
└── backend-api/         … 利用エンドポイントの詳細仕様(6ファイル)

30リポジトリのコードを丸ごと入れる代わりに、各エンドポイントの入力パラメータ・レスポンス構造・変換ロジックをドキュメント化しています。steeringのreferences.mdにはこのdocs/へのルーティングだけを記述しています。「物件詳細のAPI仕様を聞かれたら docs/bff/detail-*.md を参照」という形でサブエージェントに渡します。

ソースコードを丸ごと含めるのは、UI実装を持つiOS / Android、Kotlin Multiplatform (KMP) による共通ロジック層、通知配信、DB仕様書2つの計6リポジトリだけ。この設計で190MBのzipに収まっています。

レイヤー③:リネージ — 画面名からコードへの追跡可能性

エンジニアに「物件詳細画面のコードどこ?」と聞けば即答できます。でもこの知識はエンジニアの頭の中にしかありませんでした。

これをscreen-mapping.mdとして構造化しました。

| 画面名 | iOS | Android |
|---|---|---|
| 物件詳細 | (iOSの物件詳細ディレクトリ) | (Androidの物件詳細ディレクトリ) |
| お気に入り一覧 | ... | ... |
| 問い合わせ | ... | ... |
| ... | ... | ... |

34画面について、各プラットフォームのディレクトリパスを対応付けています。iOS/Android間で共通化されたロジック層がある場合はその所在も記載し、サブエージェントが無駄に探索しないようにしています。

AIはこのマッピングを調査の起点として使います。「物件詳細画面の表示項目を教えて」と聞かれたら、まずここからパスを引き、それをサブエージェントへの指示に含めて並列起動する。マッピングがなければリポジトリ全体をgrepで探索することになり、検索に時間がかかる上、大量のファイルパス候補がコンテキストに載って肥大化します。マッピングを用意したことで、検索速度の向上とコンテキスト肥大化の抑制を同時に実現しています。

このマッピングは「完全な一覧」ではなく「調査の起点」と位置付けています。載っていない画面はリポジトリ内を検索して探しますし、それでも見つからなければ「見つかりませんでした」と正直に返します。

レイヤー④:ポリシー — 行動ルールと委譲構造

steering/delegation.mdはパッケージの中で最も重要なファイルです。メインエージェントの行動を制御するポリシーレイヤーとして機能します。

絶対ルール:メインはコードを読まない

自分自身で readFile、readCode、grepSearch、readMultipleFiles を
使ってリポジトリ内のコードを読んではいけない。
このルールに例外はない。「ちょっと確認するだけ」「1ファイルだけ」も禁止。

データ取得(コード調査)→ 分析 → 回答生成を1つのエージェントのコンテキスト内で全部走らせると、取得したコードが積もった時点でコンテキストが枯渇し、分析・回答生成の品質が落ちます。調査はサブエージェントの独立コンテキストで行い、結果の要約だけをメインへ返す構造にすることで、メインのコンテキストをクリーンに保っています。

サブエージェントへのスキル情報の橋渡し

Kiro IDEのサブエージェントには、スキルを読み込む手段がないという制約があります。steeringファイルはサブエージェントにも自動で注入されますが、スキル定義についてはCLI版のようなresourcesフィールドが存在せず、サブエージェントに設定できません。つまり、サブエージェントはスキルの内容を直接参照できません。

重要: サブエージェントはスキルを直接参照できない。スキルに記載された調査のヒント(具体的なファイルパス、定義箇所、調査観点など)は、サブエージェントへの指示(query)に必ず含めること。

この制約を解決するために、delegation.mdは委譲手順を5ステップで定義しています。

  1. 質問がどのリポジトリに関係するか判断する
  2. 質問の種類に応じたスキルを参照し、調査に必要な情報を把握する
  3. スキルから得た情報をサブエージェントへの指示に含めて並列起動する
  4. 各サブエージェントの結果を統合して回答する
  5. 結果が不十分な場合は追加のサブエージェントを起動する

メインエージェントはスキルの中身(ファイルパス・調査観点・注意事項)を読み取り、それをサブエージェントへの指示にそのまま含めて渡す。この「橋渡し」がdelegation.mdの核です。

7体のサブエージェント

エージェント 役割 コードを読む?
ios-investigator iOSアプリケーション調査
Android-investigator Androidアプリケーション調査
kmp-investigator KMP(iOS/Android共通ロジック)調査
db-investigator DBテーブル仕様調査
backend-investigator 通知配信ロジック調査
product-analyst 数値の分析・解釈
bq-data-fetcher BigQueryクエリ設計・実行

product-analystbq-data-fetcherは意図的に分離しています。bq-data-fetcherは「クエリを書いて実行してデータを返す」だけの役割です。そのデータに意味を見出す(So What?を言う)のはproduct-analystの仕事です。取得と分析を同一コンテキストに入れないことで、それぞれの品質を保っています。

行動定義 > ロール設定

各エージェント定義において、「あなたは最高峰のiOSエンジニアです」のようなロール設定は行っていません。LLMに対するペルソナ設定は性能向上に寄与しない(むしろ最大26.2%の劣化が報告されている)ことが研究で示されています。

代わりに、各エージェントには具体的な行動を定義しています。

  • 何をするか: 対象リポジトリのsteering配下のファイルをすべて読み、最新のルールを把握する
  • 何をしないか: コードの編集は一切行わない。書き込み系MCPツール使用禁止
  • 完了条件: 根拠となったファイルパスを必ず明示する

あいまいなロール設定より、具体的な行動指示の方がAIは正確に従ってくれます。

レイヤー⑤:トライバルナレッジ — 45個のスキル

skills/ディレクトリには45個のスキルが格納されています。PdMから「こういうことを知りたい」とリクエストがあったものと、「この人ならこういうことができたら喜ぶだろうな」と先回りして追加したものの積み重ねです。

カテゴリ
仕様調査 17 画面の表示項目、ビジネスロジック、API仕様、画面遷移、計測イベント
デザイナー支援 6 アクセシビリティチェック、実装可能性判定、アセット命名提案
データ分析 8 CVR・ファネル分析、レビュー傾向、A/Bテスト結果
統合分析 6 UX課題発見、KPI下落診断、競合比較、デザインと実装の差分
評価・意思決定支援 2 施策比較、優先順位付け
ドキュメント・タスク管理 6 仕様書ドラフト、Jiraチケット起票、ナレッジ保存

Progressive Disclosure(段階的開示)

Kiro IDEのスキル機能Agent Skills仕様に基づいています。重要な特徴が段階的開示です。

  • セッション起動時にはスキルのフロントマター(名前・説明・トリガキーワード)だけが読み込まれる
  • ユーザーの質問がトリガへマッチしたときに初めて全文が展開される

45個のスキルの全文を常時コンテキストに載せると、それだけでコンテキストの大部分を消費します。Progressive Disclosureにより、必要なスキルだけが必要なときに展開され、コンテキストが節約されます。

目的単位での切り出し

スキルは「ステップ順」ではなく「何を明らかにするか(目的)」単位で切っています。

❌ ステップ順: search-file → read-code → format-output
✅ 目的単位:  comparing-screens / explaining-business-logic / diagnosing-kpi-drop

目的単位で切ると、再利用可能になり、各スキルに品質基準・完了条件・出力フォーマットを定義でき、複合スキルがほかのスキルを「呼び出す」構造を作れます。

複合スキルと依存関係

45個のスキルは独立して動くものと、ほかのスキルを内部で呼び出す「複合スキル」があります。delegation.mdに依存関係グラフが明記されています。

summarizing-screen ⊃ {comparing-screens, tracing-navigation, investigating-api,
                      investigating-tealium, explaining-business-logic}

drafting-specification ⊃ {comparing-screens, investigating-api,
                          analyzing-change-impact, investigating-tealium}
                        + investigating-web-site(任意)

「物件詳細画面の全体像を教えて」と聞くだけで、summarizing-screenが5つの基本スキルを順に呼び出し、表示項目・画面遷移・API仕様・計測イベント・ビジネスロジックをまとめて返します。

レイヤーを横断するしくみ:ナレッジキャッシュ

5つのレイヤーは調査のたびに参照されますが、頻出する質問のたびに毎回サブエージェントを起動してコードを読むのは非効率です。そこで調査結果をConfluenceに蓄積し、2回目以降はキャッシュから即答するしくみを入れています。

フロー: 1. 調査系スキルの起動前に、Confluenceで [KB] 接頭辞のページを検索 2. ヒット → 鮮度チェック(キャッシュの最終更新日 ≥ パッケージの更新日時なら有効) 3. 有効ならサブエージェント起動なしで即答 4. 重い調査(サブエージェント3つ以上起動したもの)の完了後 → 保存を提案

リアルタイム数値を扱うデータ分析系スキルはキャッシュ対象外にしています。昨日のCVRと今日のCVRは違うからです。

具体例:PdMが4リポジトリを横断して障害原因を特定した話

5つのレイヤーが連携して機能した実例を紹介します。

ある日、「お気に入りに追加できない」というユーザー報告がありました。PdMがこのパッケージを使って調査した結果は以下でした。

  1. ポリシー層(delegation.md)がexplaining-business-logicスキルを選択
  2. トライバルナレッジ層(スキル)が「お気に入り機能なら、共通ロジック層+iOS/Androidのキーチェイン/キーストア周りを見るべき」と指示
  3. リネージ層(screen-mapping)からお気に入り関連のパスを特定
  4. 3つのサブエージェントが並列起動(ios/Android/kmp-investigator)
  5. セマンティック層のドメイン知識を踏まえて共通ロジック層内の該当箇所でkSecAttrAccessible未設定を特定
  6. 原因判明:バックグラウンド復帰時にKeychainアクセスが失敗 → 毎日16,500件のエラーが発生していた

エンジニアに依頼していたら、割り込み待ちも含めて数日かかってもおかしくない調査です。それが数分で完了しています。4リポジトリを横断して1行のコードまで特定できたのは、5層のコンテキストレイヤーが連携した結果です。

まとめ

コードベースパッケージの技術設計は、突き詰めると「AIが正しく答えるために必要なコンテキストを、いかに効率的に供給するか」の設計です。

レイヤー 解決する問題
セマンティック AIが業務用語を誤解する
メタデータ 30リポジトリを丸ごと含められない
リネージ AIがどのファイルを見ればよいかわからない
ポリシー AIが何をすべきか/すべきでないかを制御する
トライバルナレッジ エンジニアの調査ノウハウを再現する

前回の記事で「コンテキストレイヤー」に言及したとき、それは振り返って気付いた概念でした。今回この記事を書くにあたり、あらためて自分のパッケージを5層で整理してみると、各レイヤーが明確な役割を持って連携していることがわかります。

この構造は特定のツールや言語に依存していません。実際に、同じ設計をベースに賃貸・流通チーム向けのパッケージ(18リポジトリ×13エージェント)も稼働しています。自分のチームでコンテキストレイヤーを構築する際の参考になれば幸いです。

次回は、このしくみをエンジニアのいないチームに応用して、業務効率化に取り組んだ話を書く予定です。


最後に、LIFULLではともに挑戦していける仲間を募集しています。ご興味をお持ちいただけましたら、ぜひ以下のページもご覧ください。

https://hrmos.co/pages/LIFULL/jobs/010

https://hrmos.co/pages/LIFULL/jobs/010-9998