SWEDeepDiver:从哪里来,去往何处

源起

从Console程序到GUI程序

大学时代,主修专业是测控技术与仪器,和硬件打交道比较多,主要编程语言是汇编和C。后来学习Java时,Get到一个新技能:Java Swing(Java GUI框架),这之后,仿佛打开了新世界的大门,兴奋地动手做了一系列GUI程序:例如某音乐网站音乐下载器程序、物理实验报告程序等。

那时候,Java Swing早已诞生,但限于专业性质,之前写的多是汇编或者C语言控制台程序,而通过GUI框架构建的有完善图形界面的程序对我来说是全新的,之所以兴奋,是因为意识到,这种技术更具潜力,我有了利用这种技术做更多事情(实现想法和完成需求)的可能性!。

DRY(Don't Repeat Yourself)

回到当下。我是一名有多年经验的Android应用开发老狗🐶,负责开发的应用App,UI图标多采用SVG格式。当实现某个界面时,用到的图标要从Figma(设计资源网站)获取,有两种工作流:

  • 从Figma导出SVG文件,再通过一些方式(例如在线转换网站、LLM)转换为Android支持的格式(Vector Drawable),再手动复制到Android Studio(Android开发IDE)中
  • 从Figma导出SVG文件,再通过Android Studio的Asset导入功能逐个 导入(自动转换Vector Drawable,但不支持批量!)。 无论哪种,都需要在多个工具间切换,当你日复一日地重复这样的工作流时,多少会觉得厌倦,不禁会问:有没有更好的方式

后来,基于诉求,我实现了一个Figma CLI工具,核心能力如下:

  • 和Figma打通,能批量导出指定界面的SVG
  • 支持在本地将SVG批量转为Vector Drawable

只需一个导出命令,即可实现设计图标的批量导出和转换,不用在工具间来回切换,简单而直接!:

bash 复制代码
export <figma_url> -o path/to/drawable

DRY(Don't Repeat Yourself) Again

1、问题筛查和识别

作为客户端App开发,我们开发的功能直接面向用户,是可见、可交互部分。很多Bug,总是先反馈到我们。当提测需求量比较大时,我们会看到一个很长的Bug List,然后逐个去看,比较容易识别的,转给其他端(后端、前端、SDK等),不容易识别的,则要分析Log,进一步确定。事实证明有相当比例的Bug,属于其他端,我们在问题识别上就要花费不少时间,而真正属于我们的Bug,则还需要花更多时间去分析和解决。

2、持续性问题排查 除了上面提到的问题识别问题,还有些问题归属是明确的,但需要持续性处理:例如自动化测试、Monkey测试问题,会在整个产品迭代周期持续产生,需要持续跟进

3、如何优化

一次会议上,同事反馈了上述问题,大家都有同感,但一致认为上述问题是无法避免的问题,这就是我们的工作,我们能做的就是降低识别和排查成本。初步提议:写脚本 ,根据日志关键字,例如错误码,进行初步判定。但脚本的判定依赖于预定义规则 ,且对于多个业务交叉性的问题,这个规则很难通过代码实现。事实证明后面确实没人去做这件事

观察和行动

观察

AI如火如荼,自年初开始,我就一直在持续了解和学习AI相关知识:看了李沐的《动手学深度学习》、毛玉仁的《大模型原理与技术》等教程,对一些经典论文:如《Attention Is All You Need 》、《ReAct: Synergizing Reasoning and Acting in Language Models 》、《SWE-agent: Agent-Computer Interfaces Enable Automated Software Engineering》等进行了拜读,不求百分百理解,了解其核心思想为止。此外,在X(原Twitter)上关注相关领域人士,阅读相关博客,了解相关动态...

行动

后面动手用Dify搭建AI工作流,使用Coding Agent Vibe了一个AI翻译应用项目:译读(由于电脑损坏,这个项目永久丢失,还是得做好数据备份!)

我逐渐找到了上述问题解决的新思路

思路

我需要从确定性基于规则 的编程思路切换到基于神经网络 寻找解空间 的思路,用AI专家AK的理念来说,就是要从[Software 1.0 ]过渡到Software 2.0

结合先前的观察和行动结果,我的目标已经比较明确:我要做的是一个基于LLM的日志分析系统:

text 复制代码
Func = 识别用户问题并自动分析,输出诊断结论
Input = 用户问题描述、日志路径
Output = 诊断结论

规划

制定计划

一开始我采用了经典的ReAct架构 ,和ReAct论文的实现完全对齐:让Agent严格按Thought、Act、Observation的格式输出。

行动和观察

结果是我把论文中提到的问题都体验了一遍(规划路径单一、循环卡住等),另一个重要的问题:模型在思考中花费了大量Token去确保Thought-Act-Observation循环的进行(扮演好角色),导致Token效率低下。我期望模型把思考Token主要用在任务上!

调整计划

我抛弃了显式的Thought-Act-Observation的格式输出,直接利用模型的Function Calling(Tool Calling)能力实现工具调用,并配合适当的提示指令让Agent完成多轮次的隐式的Thought-Act-Observation,架构还是ReAct架构,只是实现层利用了现代模型本身的能力。

项目介绍

地址:github.com/SteveYang92...

项目名称

SWEDeepDiver 是一个复合词,SWE指软件工程,DeepDiver字面意思是深潜者 ,这里比喻深入钻研和深入探索SWEDeepDiver即软件工程领域问题的深入钻研者

项目用途

项目的初始目的是解决重复性 的Bug识别、分析和归因工作,主要面向Android端,主要支持的输入形式是问题描述和问题日志(文本),后来在实现的过程中,意识到它可以更通用

  • 多技术栈、多需求处理:可处理各种平台、技术栈的各类软件相关问题(Bug分析、性能分析、代码分析、数据统计等)
  • 工作在本地文件系统:可自由探索目录、文件,可处理各类问题附件(日志、Trace、HeapDump File、截图、录屏等)
  • 可扩展 :可利用ProcessFile工具提供的口子,接入各个平台的工具链,覆盖更多需求场景
text 复制代码
Func = 识别用户问题并自动分析,输出诊断结论
Input = 用户问题描述、问题附件包
Output = 诊断结论

SWEDeepDiver具有文件系统的常用操作能力,如Glob、Read、Grep等,它的工作空间是文件系统的一个目录

未来规划

  • 完善文件处理工具:支持更多平台工具链,支持更多SWE场景(如移动端OOM分析、卡顿分析等)
  • 完善代码分析工具:支持分析工具实现替换,支持远端仓库Clone,支持本地代码路径配置等
  • 优化Agent架构和代码:提升安全性、提升性能等
  • 提升Agent性能:提高分析质量(可回溯性、可复现性、结论确定性等)

一个例子作为本文结尾

我遇到了一个ANR(应用卡死无响应)问题,通过SWEDeepDiver进行问题分析

输入:

ini 复制代码
iuuse_bugreport = r"""
App发生ANR,请分析原因
发生时间:12-02
问题目录:workspace/case/bugreport/bugreport-dada-AQ3A.240812.002-2025-12-15-10-08-51
"""

输出:

markdown 复制代码
# 🔍 诊断报告

## 🎯 诊断结论

**基本情况**

- 进程:`co.ex`
- 主要界面:`FRPlayerPlayerActivity` / `FRPlayerListActivity`
- ANR 类型:**Input dispatching timed out(输入分发超时)**
- 发生时间:**2025-12-02 18:07:47 左右**

**更精确的结论(带不确定性说明):**

> 在用户从记录相关页面(`FRPlayerPlayerActivity` / `FRPlayerListActivity`)退到桌面时,应用在主线程上处理"焦点丢失 / 退出"相关回调时,执行了耗时操作(如大计算、同步磁盘/数据库 IO、大量资源释放等),导致约 5 秒内无法完成焦点事件处理,触发了 `Input dispatching timed out` ANR。  
> 由于 ANR 抓取堆栈时机稍晚,堆栈中已经看不到具体业务方法,只能根据时序和机制进行高置信度推断,而非 100% 确证。

**置信度**:⭐⭐⭐⭐ 中高(约 75--80%)  
(高于一般猜测,但低于"栈直接指到你代码"的确证级别)

---

## 📊 核心证据

### 1️⃣ ANR 事件与类型

**events 日志**

- `12-02 18:07:47.198`:

```text
I am_anr  : [0,26801,co.ex,955792966,
  Input dispatching timed out 
  (26d71a co.ex/co.ex.FRPlayerListActivity (server) is not responding. 
   Waited 5000ms for FocusEvent(hasFocus=false)).]
.```

含义:

- 系统向窗口 `co.ex/co.ex.FRPlayerListActivity` 发送了一个 `FocusEvent(hasFocus=false)`(即失去焦点)。
- 等待 **5 秒** 没收到"事件处理完成"的反馈,于是触发 Input ANR。

根据 Android ANR 机制([技术常识]):

- 这种 ANR 是**输入系统视角**下的 ANR:
  - InputDispatcher 给某窗口发事件 → 5s 内收不到处理完成信号 → 认为该窗口/进程"未响应"。

---

### 2️⃣ 焦点切换与 5 秒"空窗期"

**焦点切换到桌面**

- `12-02 18:07:43.331`:

```text
I input_focus: [At display 0,focus update to ... 
    com.miui.home/com.miui.home.launcher.Launcher,from setFocusedWindow.]
.```

说明:

- 此时焦点已经切换到了桌面 Launcher,用户从你的 App 退到了桌面。

**ANR 后主线程才开始处理生命周期**

紧接在 `18:07:47.198 am_anr` 之后,你的进程立刻开始处理一系列与"退出/失焦"相关的事件(都在主线程 TID=26801):

```text
18:07:47.363 I wm_on_top_resumed_lost_called: [ ..., co.ex.FRPlayerListActivity, topStateChangedWhenResumed]
18:07:47.385 I input_focus: DIE in: PopupWindow ... ViewRootImpl.die ...
18:07:47.394 I input_focus: doDie:PopupWindow ...
18:07:47.395 I wm_on_paused_called: [ ..., co.ex.FRPlayerListActivity, performPause, ...]
18:07:47.399 I wm_on_stop_called: [ ..., co.ex.FRPlayerListActivity, STOP_ACTIVITY_ITEM, ...]
18:07:47.405 I input_focus: handleWindowFocusChanged: co.ex/co.ex.FRPlayerListActivity ...
18:07:47.412 I viewroot_draw_event: [VRI[FRPlayerListActivity], Not drawing due to not visible. Reason=View.INVISIBLE]
.```

时序上:

- 18:07:43.3 → 焦点给了桌面,应用应尽快处理失焦/暂停/停止。
- 18:07:47.2 → **刚好 5 秒后**,系统判定为 ANR。
- 18:07:47.36~47.41 → 你这边主线程才开始密集执行 `onTopResumedLost` / `onPause` / `onStop` / `handleWindowFocusChanged(false)` 等。

这说明:

- 这 5 秒里,主线程**没有及时处理应该在那时刻执行的消息/回调**(焦点事件、生命周期事件)。
- 满足 Input dispatch ANR 的经典模式:[技术常识] 主线程被耗时任务占用 → 输入事件无法在 5s 内走完流程 → ANR。

---

### 3️⃣ InputDispatcher 连接状态:真正"卡住"的是 Player Activity 窗口

从 bugreport 中的 InputDispatcher dump(你提到的那一段):

```text
Connections:
  1022: channelName='7027620 co.ex/co.ex.FRPlayerPlayerActivity (server)', 
        status=NORMAL, monitor=false, responsive=false
    WaitQueue: length=1
      FocusEvent(hasFocus=true), seq=..., age=5002ms, wait=5002ms

  703: channelName='4fe2a4d co.ex/co.ex.FRPlayerListActivity (server)', 
       status=NORMAL, monitor=false, responsive=true
.```

说明:

- `FRPlayerPlayerActivity` 的输入连接上,有一个 `FocusEvent(hasFocus=true)` 已经在队列里等了 **5002 ms** 且 `responsive=false`。
- `FRPlayerListActivity` 当前被标记为 `responsive=true`。

结合 `am_anr` 的 Subject 提示 `FRPlayerListActivity` 不响应:

- 进程内实际涉及两个窗口(List 和 Player),共享同一个主线程。
- Input 系统计数时,是针对**连接维度**(某个 InputChannel),`FRPlayerPlayerActivity` 那个连接迟迟没完成焦点事件;系统在整体评估时,Subject 中标记到的是 `FRPlayerListActivity`,但本质问题还是**这个进程的主线程 5 秒内未响应输入事件**。

这进一步加强了"主线程在这段时间内被卡住"的判断。

---

### 4️⃣ ANR 堆栈:主线程已"回到空闲状态"

`/data/anr/anr_2025-12-02-18-07-47-342` 中:

```text
Subject: Input dispatching timed out (26d71a co.ex/co.ex.FRPlayerListActivity ...)

----- pid 26801 at 2025-12-02 18:07:57.3185+0800 -----
Cmd line: co.ex

".co.ex" sysTid=26801
  #00 __epoll_pwait
  #01 android::Looper::pollInner
  #02 android::Looper::pollOnce
  #03 android.os.MessageQueue_nativePollOnce
  #05 android.os.MessageQueue.next
  #06 android.os.Looper.loopOnce
  #07 android.os.Looper.loop
  ...
  #18 android.app.ActivityThread.main
  ...
.```

特征:

- 栈顶只是在 `Looper.loop` / `epoll_pwait` 上等待消息,这是一种"主线程空闲"的状态。
- 说明:**真正导致 5 秒卡顿的耗时代码,在这个采样时刻已经结束**,所以堆栈没有直接指向你的某个 Activity 方法或业务逻辑。

这也是 Android 中常见的一种情况:  
卡顿已经结束 → 抓到的 trace 只能证明"ANR 发生过",但**看不到具体卡在哪个方法**。

---

### 5️⃣ 系统资源情况:不像系统级"整体卡死"

同一 ANR 文件中的压力(pressure)指标:

```text
/proc/pressure/cpu:
  some avg10=5.47 avg60=6.60 avg300=8.27
  full avg10=0.00 ...

/proc/pressure/memory:
  full avg10=0.00 ...

/proc/pressure/io:
  full avg10=0.00 ...
.```

含义:

- CPU 有一定 `some` 压力,但 `full=0`,意味着**并不是整个系统长时间所有任务都抢不到 CPU**。
- 内存和 IO full 压力也为 0。

再看 MIUI 的 `abnormal_cpuinfo`(17:56~17:59):

```text
CPU usage ...:
  22% 26215/co.ex: 16% user + 5.9% kernel
    15% 26215/usap64
    3.7% RenderThread
    0.1% .co.ex (主线程)
.```

说明:

- 你的进程在当晚总体上属于比较重的 CPU 消费者之一,但没有看到系统级"所有东西都挂掉"的情况。

综上,更符合**应用自己在主线程做了重活**,而不是系统整体卡死。

---

## 🧠 根因推断(带置信度标注)

**假设 X:主线程在"焦点 / 生命周期回调"里执行耗时操作**(置信度:中高)

- 触发点:用户从 `FRPlayer*` 界面退出到桌面。
- 此时系统向窗口发送:
  - `FocusEvent(hasFocus=false)`(当前前台 Activity 失去焦点)
  - 生命周期回调 `onPause()` / `onStop()` / 相关 Window 回调 `onWindowFocusChanged(false)` 等。
- 在这些回调里,如果你做了:
  - 同步写入大文件 / 数据库操作;
  - 大量遍历/计算(比如处理记录数据);
  - 大量 Bitmap/资源的释放并同步 GC 整理;
  - 任何会阻塞 UI 线程数秒的操作;
- 那么主线程在 **5 秒内不能处理完输入焦点事件** → InputDispatcher 视角下就是"Input dispatching timed out" → 触发这类 ANR。

**依据:**

- `[日志]` `am_anr` 明确是 `Input dispatching timed out ... FocusEvent(hasFocus=false)`。
- `[日志]` 焦点在 18:07:43 切到了桌面,刚好约 5 秒后 ANR,在 ANR 之后数毫秒内才执行 `onTopResumedLost`、`onPause`、`onStop` 等。
- `[日志]` InputDispatcher dump 显示 `FRPlayerPlayerActivity` 的焦点事件在 WaitQueue 里等待 5002ms、`responsive=false`。
- `[日志]` ANR traces 只看到主线程在 Looper.loop 上空闲,可解释为:**耗时任务已经做完了,才抓的栈**。
- `[技术常识]` Input ANR 的典型机制就是"主线程长时间未处理输入/焦点事件"。
- `[技术常识]` 焦点丢失/退出回调中做重活,是最常见的这类 ANR 根因之一。

---

## ⚠️ 不确定性与边界

需要明确告诉你,目前无法做到 100% 确证的点有:

1. **缺少直接的应用方法栈**  
   - trace 抓到时主线程已经空闲,因此看不到"具体卡在 `onPause`/`onStop`/`onWindowFocusChanged` 或某个你自己的方法里"。

2. **这 5 秒到底在做什么?**  
   - 只能推断"主线程被阻塞 / 干重活"。
   - 无法从现有日志中确认是写文件、访问数据库、网络请求、死锁,还是多个中等耗时步骤叠加。

3. **List vs Player 窗口的责任划分**  
   - InputDispatcher dump 显示 `FRPlayerPlayerActivity` 连接上的焦点事件滞留 5002ms;
   - ANR Subject 中写的是 `FRPlayerListActivity` 不响应;
   - 实际上它们同属一个进程、共用主线程,很可能是两个界面交替切换或重叠的场景,对最终结论影响不大,但没法精确到"是哪一个 Activity 内的哪一段代码"。

---

## 🔧 建议的改进与排查方向

结合你业务中的"FRPlayerList / FRPlayerPlayer"场景,可以重点自查:

1. **检查以下回调中是否有重活在主线程执行:**
   - `FRPlayerListActivity` / `FRPlayerPlayerActivity` 及其父类里的:
     - `onPause()`
     - `onStop()`
     - `onDestroy()`
     - `onWindowFocusChanged(boolean hasFocus)`
   - 以及这些回调直接或间接调用的逻辑,比如:
     - 保存记录;
     - 关闭/导出播放数据;
     - 同步上传 / 写本地文件;
     - 加载/释放大批资源等。

2. **通用优化建议**

   - 所有**超过 50--100ms 的操作**,一律移出 UI 线程:
     - 文件读写、数据库操作、网络请求;
     - 大循环、复杂计算;
     - 大对象的批量创建 / 销毁。
   - 对在"退出页面/失焦"时触发的逻辑:
     - 尽量简化为轻量标记(如改状态、post 到后台线程)。
     - 真正耗时工作交给线程池 / 协程 / WorkManager 等后台执行。

3. **如果你能改包再复现 ANR**,建议:
   - 打开 StrictMode / 主线程耗时监控(比如对 main thread 的 Looper 打桩统计 >200ms 的 message)。
   - 在这些关键生命周期/焦点回调前后加带时间戳的日志,确认是哪一步拉长到了几秒。

---

## 🧾 小结(给你的直观结论)

- 这次 ANR 是一个**输入分发超时(Input dispatch ANR)**,不是普通的"后台服务卡住"那种。
- 触发点是:用户离开记录界面 → 系统发出焦点/生命周期事件 → 你的主线程 5 秒内没处理完。
- 日志显示:**5 秒后 ANR 触发,紧接着你的 Activity 才开始执行暂停/停止/失焦等回调**,非常符合"在这些回调里做了重活"的模式。
- 堆栈抓取时已经空闲,所以看不到具体方法名;这是唯一主要的不确定性来源。
- 建议你重点检查 `FRPlayerListActivity` / `FRPlayerPlayerActivity` 在退出/失焦时主线程做了哪些事,把任何偏重的工作都搬到后台线程去。
相关推荐
十六年开源服务商2 小时前
WordPress视频播放增强定制开发解决方案
开源
梦帮科技4 小时前
Scikit-learn特征工程实战:从数据清洗到提升模型20%准确率
人工智能·python·机器学习·数据挖掘·开源·极限编程
时光追逐者4 小时前
一个基于 .NET 开源、功能强大的分布式微服务开发框架
分布式·微服务·开源·c#·.net·.net core
想用offer打牌4 小时前
LLM参数: Temperature 与 Top-p解析
人工智能·python·llm
weixin_462446234 小时前
【原创实践】开源扣子 coze-studio 安装本地插件配置:接入“今日诗词”API(获取所有古诗词)
开源·开源扣子
探索宇宙真理.5 小时前
WordPress AI Engine信息泄露漏洞 | CVE-2025-11749 复现&研究
人工智能·经验分享·开源·安全漏洞
Mr.朱鹏5 小时前
大模型入门学习路径(Java开发者版)上
java·开发语言·spring boot·spring·大模型·llm·transformer
AI猫站长6 小时前
商汤科技孵化“大晓机器人”,联合创始人王晓刚亲自挂帅,推出开源世界模型3.0与具身超级大脑模组,万亿具身智能赛道再迎重量级玩家,行业竞争格局生变
科技·机器人·开源
zhaodiandiandian6 小时前
从跟跑到领跑 开源AI开启中国时间的产业变革
人工智能·开源