はじめに
Claude CodeやCursorでAndroid開発をしていると、必ず壁にぶつかります。
- logcatをそのまま貼ると数千行
- UIAutomator XMLは1画面で数百KB
adb dumpsysの出力は何万行にもなる
単純にトークン数を削減するだけなら通常のgzip圧縮で済みます。しかし**LLMに渡すデータには「意味圧縮」**が必要です。目的が根本的に違うからです。
| 通常の圧縮 | LLM向け意味圧縮 | |
|---|---|---|
| 目的 | バイト数を減らす | reasoningノイズを減らす |
| 基準 | 再現可能性 | AIの理解しやすさ |
| 出力 | 元データと等価 | 意味的に等価 |
多段パイプライン構成
LLM向け意味圧縮の基本構成はこうです。
input
↓ parser (構造化)
↓ normalizer (表記揺れ削除)
↓ dedupe (重複除去)
↓ semantic reduction (不要情報除去)
↓ structuring (整理)
↓ encoder (TOON/DSL化)
↓ LLM
各ステップを順に説明します。
1. Parser — まず構造化する
入力を構造化することが最初の仕事です。
logcatの例:
05-28 10:00:00 E MyApp: NullPointerException
↓
{
"time": "05-28 10:00:00",
"level": "E",
"tag": "MyApp",
"message": "NullPointerException"
}
構造化することで後段のフィルタリングが容易になります。
2. Normalizer — 表記揺れを削除する
同じ意味の情報がフォーマット違いで重複しているのを統一します。
package名の短縮:
com.example.myapp.feature.login.LoginViewModel
↓
LoginViewModel
例外クラスの正規化:
java.lang.NullPointerException
↓
NPE
3. Dedupe — 重複を除去する
LLMにとって繰り返しはほぼ有害です。
入力:
Loading...
Loading...
Loading...
Loading...
圧縮後:
Loading... x4
さらに重大な例として、同じstacktraceが100回繰り返される場合:
EXCEPTION repeated x100 { type=NPE source=LoginViewModel.kt line=42 }
これだけで大量のトークンを節約できます。
4. Semantic Reduction — AIに不要なものを落とす
ここがLLM圧縮の核心です。
Android特有の除外すべきノイズログ
以下はAIのデバッグに必要ないノイズです。
| タグ | 内容 |
|---|---|
BufferQueue |
グラフィックスシステム内部 |
OpenGLRenderer |
レンダリングエンジン |
libEGL |
OpenGL ES |
AudioTrack |
音声内部処理 |
TrafficStats |
ネットワーク統計 |
chatty |
ログ省略メッセージ |
GC_ |
ガベージコレクション |
フィルタ例:
NOISE_PATTERNS = [
r"BufferQueue",
r"OpenGLRenderer",
r"libEGL",
r"AudioTrack",
r"chatty",
r"GC_",
]
def filter_noise(line: str) -> bool:
return not any(re.search(p, line) for p in NOISE_PATTERNS)
残すべき重要ログ
Exception / ANR / Activity lifecycle / Network error / Firebase / WorkManager
5. Structuring — LLMが理解しやすい形に整理する
LLMは整理された情報に強いです。
Before:
MainActivity created
Fragment onResume called
API request started
After:
ACTIVITY{ name=MainActivity state=created }
FRAGMENT{ state=onResume }
API{ state=start }
ラベルを明示するだけで、AIの理解率が大きく変わります。
6. Encoder — TOON/DSL化
最後に独自フォーマット(TOON)に変換します。
events[3]{type,target,state}:
ACT|MainActivity|created
API|LoginApi|start
ERR|Auth|401
1行でより多くの情報を表現でき、コンテキスト内に収まる情報量が増えます。
UIAutomatorとUI tree圧縮
Android MCPを使う場合、UIAutomator XMLはさらに冗長です。
元のXML(抜粋):
{
"x": 120,
"y": 400,
"width": 200,
"height": 48,
"padding": 0,
"alpha": 1.0,
"focusable": false,
"clickable": true,
"text": "Login"
}
圧縮後:
BTN[text=Login]
LLMにとってpaddingやalphaはほぼ不要です。clickable=true かつ text があるものだけ残すルールで圧縮すると、同じ情報を1/20以下のトークンで渡せます。
ドメイン特化が一番効く
汎用圧縮より、Android専用の圧縮ロジックを持つことが最も効果的です。
ログカテゴリ自動分類
CATEGORIES = {
"lifecycle": ["onCreate", "onResume", "onPause", "onDestroy"],
"crash": ["Exception", "ANR", "Fatal"],
"network": ["Retrofit", "OkHttp", "HttpException"],
"database": ["Room", "SQLite"],
"compose": ["Recomposition", "Composition"],
"firebase": ["Firebase", "Firestore", "FCM"],
"workmanager": ["WorkManager", "Worker"],
}
カテゴリ別に分類してAIに渡すと、関連情報がまとまってデバッグ精度が上がります。
重要度スコアによるコンテキスト制御
priority=10 EXCEPTION / ANR
priority=8 Network error
priority=5 Lifecycle event
priority=3 Debug log
priority=1 Verbose
コンテキスト制限があるときは高優先度から埋めていきます。
用途別コマンド化
スラッシュコマンド形式にするとAIとの連携が自然になります。
/logcat → logcat専用圧縮
/uiauto → UIAutomator XML専用圧縮
/json → 大型JSON専用圧縮
/stacktrace → stacktraceのみ抽出
使用例:
/logcat
05-28 10:00:00 D MyApp: Loading
05-28 10:00:01 D MyApp: Loading
05-28 10:00:02 E MyApp: NullPointerException at LoginViewModel.kt:42
↓
LOG{
repeated[ "Loading" x2 ]
error{ type=NPE source=LoginViewModel.kt line=42 }
}
MCPサーバー化まで
このパイプラインはMCPサーバーとして実装できます。
@mcp.tool()
def compress_logcat(text: str) -> str:
return run_pipeline(text, mode="logcat")
@mcp.tool()
def compress_uiauto(xml: str) -> str:
return run_pipeline(xml, mode="uiauto")
@mcp.tool()
def compress_json(data: str) -> str:
return run_pipeline(data, mode="json")
Claude DesktopやClaude Codeからツールとして自動的に呼び出せるようになります。圧縮を意識せず使えるのが理想形です。
まとめ
| ステップ | 効果 |
|---|---|
| Parser | 後段フィルタリングを可能にする |
| Normalizer | 同一情報の重複を排除する |
| Dedupe | 繰り返しログを折りたたむ |
| Semantic Reduction | AIに不要なノイズを除く |
| Structuring | AIが理解しやすい形に整える |
| Encoder (TOON) | 情報密度を高める |
重要なのは「AIに不要なものを知っていること」です。通常の圧縮はバイトを減らしますが、LLM向け意味圧縮はreasoningノイズを減らします。この違いを意識することで、Android MCPとAIの組み合わせが格段に強くなります。