从海量 Log 到可审计结论:llm-anr 的设计思想、开发流程与最终结果
Android ANR(Application Not Responding)分析看起来像是在“读日志”,但真正困难的地方并不只是日志太多,而是证据太散、时间线不一致、系统上下文复杂,并且很容易因为某一段醒目的堆栈或日志而过早定责。
llm-anr 这个仓库要解决的正是这个问题:把 trace、EventLog、logcat、AnrManager dump、meminfo、kernel log 等多源原始材料,转换成按 ANR 事件隔离、可审计、可复盘的证据工作区,再引导 AI 或人工分析者逐层完成保守分析。
这篇文章从三个角度介绍这个项目:它为什么这样设计、开发流程如何组织,以及当前最终交付出了什么能力。
一、项目要解决的问题
在实际 Android 稳定性分析中,ANR bugreport 往往有几个典型痛点:
日志规模巨大
logcat、event log、kernel log 可能达到数百 MB 甚至 GB 级,直接把全文交给人或 LLM 都不可行。证据分布在不同来源
trace 里有线程状态和调用栈,EventLog 里有am_anranchor,logcat/AnrManager 里有 reason、CPU、PSI、dump flow,meminfo/kernel log 又提供资源压力背景。单看任何一个来源都可能误判。时间锚点并不总是直观
AnrManager: ANR in往往发生在 dump 阶段,不一定等于真实 ANR 触发时间。项目因此强调以am_anr、trace header、类型特定日志做交叉锚定。多个 ANR 容易相互污染
同一份输入里可能存在多个 ANR。如果不按 anchor 拆组,trace、logcat、AnrManager、meminfo 很容易串用,导致把 A 事件的证据套到 B 事件上。AI 容易“像专家一样武断”
ANR 分析需要候选链路、证据缺口和人工确认,而不是一上来输出“最终根因”。因此项目把所有自动分析结论都设计为保守候选:finalJudgment = false、notRootCauseYet = true、requiresHumanConfirmation = true。
所以,agent-anr 的目标不是“自动替人拍板”,而是:
高召回地抽取关键证据,用结构化方式压缩上下文,用分来源分析降低幻觉,用跨源融合形成可审计的候选根因链。
二、核心设计思想
1. Baseline evidence 是硬保证
项目最重要的设计原则之一是:baseline evidence 不可被类型策略删除。
也就是说,不管当前 ANR 被识别成 input_dispatching_timeout、no_focus_window、broadcast_timeout 还是未知类型,基础证据源都必须保留。类型模板只能做加法:增加关注窗口、关键词和提示,而不能因为“看起来不像某类问题”就把 trace、EventLog、logcat 或系统上下文裁掉。
这个原则直接服务于高召回:在早期证据不足时,宁可保留更多上下文,也不让过滤器把真正根因删掉。
2. 先锚定事件,再切分证据
llm-anr 将 ANR anchor 作为分析中心。典型 anchor 包括:
- EventLog 中的
am_anr; - trace 文件头中的 ANR 时间;
- logcat 或 AnrManager 中的 ANR reason;
- 特定类型日志,例如 InputDispatcher timeout、no focused window、broadcast timeout、service timeout 等。
当输入中出现多个 ANR 时,系统会按 anchor 拆成多个独立 group,并为每个 group 生成独立目录:
1 | anr_ai_context/ |
这样做的价值在于:每个 ANR 都有自己的证据窗口、logcat 文件、分析槽位和完成状态,避免跨事件串证据。
3. 从原始文本转向 Evidence Slice
设计文档中把核心架构概括为:
1 | Raw Data -> Evidence Slices -> Hypothesis Generation -> Causal Conclusion |
系统并不鼓励把原始日志全文直接交给 AI,而是通过预处理、过滤和归一化,把日志转为更高信噪比的证据片段。证据片段保留来源、时间、重要性、原始内容和关联实体,便于后续聚合与审计。
相关模块包括:
evidence_slice.py:Evidence Slice Schema;time_norm.py/normalizer.py:时间归一化与 Phase 2 标准化;entity_linker.py:PID/TID/UID/包名等实体关联;weighting.py:证据重要性分级;context_flooding.py:上下文防溢出策略。
这背后的思想是:LLM 不应该被迫在海量噪声中“猜重点”,而应该拿到经过工程侧处理后的高密度证据。
4. 按来源分阶段分析,避免过早综合
AI 工作区 anr_analysis.md 固定包含四个分析槽位:
- Trace-only analysis;
- EventLog / anchor-only analysis;
- Logcat + AnrManager + meminfo follow-up analysis;
- Final cross-source ANR synthesis。
前三段只允许做来源内分析,不能提前下最终根因。最终综合必须在前三段完成后再整合,并写回同一个 Markdown 文件。
这种约束非常关键:它迫使分析过程先回答“每个来源能单独证明什么”,再回答“多个来源合起来是否支持同一条因果链”。
5. 触发类型与根因提示分层
项目区分两个概念:
triggerType:ANR 触发机制,例如 input dispatch timeout、no focus window、broadcast timeout;rootCausePatternHints[]:候选根因模式,例如 deadlock、memory pressure、high load、binder wait、render fence 等。
二者不能混为一谈。一个 input dispatch timeout 可能由主线程锁等待导致,也可能由 Binder 对端、渲染 fence、系统高负载、内存压力等因素触发。触发类型回答“ANR 是怎么被系统报出来的”,根因 hint 回答“可能是什么链路造成的”。
6. 大文件过滤采用流式和窗口化思路
仓库中的算法设计文档强调“正向定位锚点 + 倒序块扫描”:
- 先流式扫描找到
am_anr等 anchor; - 记录 timestamp 和文件 offset;
- 再从 anchor 附近按时间窗口回溯;
- 只保留窗口内且语义相关的行。
工程上,这让内存占用与目标时间窗口相关,而不是与原始日志总大小相关。对于超大 logcat,这是从“能不能跑”到“可以稳定跑”的关键差异。
三、开发流程
Phase 0:输入加载与预处理
项目支持多种输入:
- fixture JSON;
- 已解压 bugreport 目录;
- 普通日志目录;
.zip;.tar、.tar.gz、.tgz、.tar.bz2、.tar.xz。
入口包括:
1 | python3 scripts/anr_to_ai.py <input> [--package <pkg>] [--anr-type <type>] |
以及包形式 CLI:
1 | python3 -m anr_evidence <input> |
加载层会识别常见 Android / 厂商目录结构,例如:
data/anr/、FS/data/anr/;event-log/;logs/、android-logs/;dropbox/;System_log/meminfo.txt;last_kmsg、lastkmsg、console_ramoops。
Phase 1:证据抽取
核心入口是 anr_evidence/extractor.py。它会完成:
- 输入标准化;
- ANR 类型识别;
- anchor candidate 收集与主 anchor 选择;
- baseline evidence 抽取;
- 类型模板的加法扩展;
- source summary 与 warning 汇总。
与之配套的模块包括:
1 | anr_evidence/extraction/ |
Phase 2:标准化
normalizer.py 负责把 Phase 1 的证据转成更统一的结构,包括来源、时间、provenance、fallback/degraded 状态等。
这个阶段的重点不是“下结论”,而是让后续阶段看到一致的数据形态。
Phase 3:辅助分析
analyzer.py 在标准化证据基础上生成:
- timeline;
- signal summary;
- trace insight;
- input insight;
- 非最终 finding。
这里仍然保持“非最终”语义,只描述现象和候选信号。
Phase 5/6/7/8:候选链路到交付报告
确定性流水线继续向后推进:
1 | python3 -m anr_evidence --hypothesize <input> |
对应模块是:
hypothesis.py:生成候选因果链;root_cause.py:生成保守根因候选;remediation.py:生成受证据门控的修复建议草案;delivery.py:渲染最终交付 Markdown 模板。
这条线强调“候选链路 + 证据强度 + 缺口 + 修复建议”,而不是单点判断。
AI 工作区:面向 Agent 的交付形态
最推荐的 Agent 入口是:
1 | python3 scripts/anr_to_ai.py <bugreport_dir_or_archive_or_fixture> \ |
它会生成:
1 | anr_ai_context/ |
index.json 是所有 ANR group 的索引;anr_analysis.md 包含分析说明、过滤证据和四个分析槽位;logcat.txt 保存该 ANR group 的过滤后 logcat,避免主文件上下文膨胀。
AI 或人工分析者必须按槽位填写:Trace → EventLog → Logcat/AnrManager → Final ANR,并把最终综合结论写回 Final ANR 槽位。
四、当前最终结果
截至当前仓库状态,agent-anr 已经形成了一个比较完整的 ANR 证据工程与辅助分析工具链。
1. 已支持的输入与证据源
输入侧支持 fixture、目录、ZIP/TAR 归档;证据侧覆盖:
- trace;
- EventLog;
- logcat;
- AnrManager dump flow;
- meminfo;
- kernel log;
- dropbox / bugreport 常见路径。
并且支持多个 ANR group 独立生成分析工作区。
2. 已支持的 ANR 类型与根因提示
触发类型包括:
input_dispatching_timeout;no_focus_window;broadcast_timeout;service_timeout;content_provider_timeout;job_scheduler_timeout;system_watchdog_swt;unknownfallback。
根因模式提示包括但不限于:
- deadlock / lock owner chain;
- Binder wait;
- render fence / vsync / buffer wait;
- native poll idle / busy / ambiguous;
- memory leak / OOM / LMK / PSI memory pressure;
- high CPU / IO / system load;
- SharedPreferences apply / DB / network / file IO / GC 等主线程阻塞模式。
3. CLI 与脚本入口完整
常用入口包括:
1 | # 生成 AI 工作区 |
此外还有 replay、dashboard、eval 等辅助能力,用于回放评估和回归验证。
4. 测试验证结果
本次基于仓库当前状态执行了完整 unittest:
1 | Ran 285 tests in 4.724s |
测试覆盖范围包括:
- AI context 生成与再生成保留分析槽;
- anchor 选择与多 ANR 分组;
- ANR 类型扩展与 root cause hint;
- AnrManager block 解析;
- ZIP/TAR/目录加载;
- Phase 2 到 Phase 8 流水线;
- context flooding;
- 跨源融合;
- entity linker;
- evidence slice;
- groundtruth eval;
- log filter 与大文件扫描;
- meminfo;
- native poll;
- pattern catalog;
- trace deadlock / lock chain / cross-trace consistency;
- source workflow;
- weighting。
这说明项目不是只有概念文档,而是已经通过较完整的单元测试与集成测试把“证据抽取—标准化—分析—候选根因—修复建议—交付”串了起来。
五、一个典型使用故事
假设我们拿到一份客户 bugreport,要分析包名为 com.example.app 的 ANR:
1 | python3 scripts/anr_to_ai.py ./bugreport --package com.example.app |
系统会先加载目录或归档,识别 trace、event log、logcat、meminfo 等来源;然后定位 am_anr 或其他 anchor;如果存在多个 ANR,会拆成多个 group;接着为每个 group 生成独立工作区。
分析者打开:
1 | anr_ai_context/index.json |
然后按顺序填写:
- Trace:主线程是否 blocked、native poll、Binder wait、锁等待、render fence;
- EventLog:
am_anr前后窗口内 Activity/Window/Input/进程/内存信号; - Logcat/AnrManager:reason、CPU、Load、PSI、Top processes、dump flow;
- Final ANR:整合时间线、直接阻塞点、候选根因链、证据质量和修复建议。
最终输出不是一句“根因是 X”,而是一份可复查的 Markdown 报告:每条结论都能回到具体来源和具体证据。
六、这个项目的工程价值
llm-anr 的价值不在于把 ANR 分析“神秘地自动化”,而在于把分析工作拆成稳定、可验证的工程步骤:
- 用 anchor 和时间窗口解决“证据从哪里来”;
- 用 source filter 和 weighting 解决“哪些证据更重要”;
- 用 Evidence Slice 和 entity link 解决“证据如何被 AI 理解”;
- 用四阶段槽位解决“AI 如何不乱下结论”;
- 用保守 JSON tail 解决“自动化结论如何留有人审边界”;
- 用 unittest / replay / eval 解决“规则变化如何防回归”。
这是一种很适合稳定性场景的 Agent 设计范式:让程序做确定性、可测试、可复用的证据工程;让 AI 做阅读、归纳、假设排序和报告组织;让人类保留最终确认权。
七、结语
ANR 分析最怕两件事:一是淹没在海量日志里,二是在证据不足时过早定责。llm-anr 的设计正好围绕这两个风险展开:高召回抽取证据,按 anchor 隔离事件,按来源分步分析,用候选链路表达不确定性,再用测试和评估守住工程质量。
从当前仓库结果看,它已经具备了一个可运行、可扩展、可审计的 ANR 分析基础设施:既能作为命令行工具独立跑确定性流水线,也能作为 AI Agent 的证据工作区生成器,把复杂 bugreport 转成结构化、可复盘的分析任务。
对稳定性工程来说,这种“证据先行、结论保守、流程可验证”的方法,可能比单次自动判断更重要。
