别再往 Skill 里塞一切:我们如何重新思考 AI Debug Engineer

面向 Android 手机系统软件与芯片研发的一次架构思考

我们想做一名 AI Debug Engineer。

不是一个会回答 Android 问题的聊天机器人,也不是一个能帮忙写几行代码的 Copilot,而是希望它能够逐渐接手过去由工程师完成的工作:理解问题、收集证据、提出假设、定位根因、修改代码,最后证明问题真的被解决了。

这个目标听起来并不离谱。今天的模型已经能读代码、执行命令、分析日志,也知道 Binder、HAL、SELinux、Linux kernel、Android Framework 等大量公开知识。可真正开始建设后,我们却很容易陷入一种熟悉的混乱:

  • 有人把排查步骤写成 Skill;
  • 有人把芯片手册摘录放进 Skill;
  • 有人把历史案例总结成 Skill;
  • 还有人把一整套从读日志到修改代码的推断过程也写成 Skill。

结果是 Skill 越来越多、越来越长,系统却不一定越来越聪明。出现错误时,我们甚至不知道该改模型、补知识、增加工具,还是重写某个 Skill。

问题可能不在于我们积累得不够多,而在于最开始没有分清:AI Debug Engineer 到底由什么组成。

从"能力"出发,但不要停在"知识、经验、技能"

一个自然的起点是把人的能力拆成知识、经验和技能。

这个思路有价值,因为调试确实同时需要三种东西:工程师要理解系统原理,要见过相似问题,也要会操作日志、代码、设备和调试器。

但直接把人的能力分类搬到 AI 系统里,会产生一个麻烦:"技能"这个词太宽了。

对人来说,"分析一次开机失败"可以叫技能,"使用 adb"也可以叫技能,"看到某种日志后知道下一步查哪里"仍然可以叫技能。而在 Agent 系统里,这三件事分别属于执行能力、推理判断和经验参考。如果仍然把它们都称为 Skill,系统边界很快就会消失。

所以我们最终收敛到了一个更小、也更清晰的结构:

text 复制代码
                    ┌─────────────┐
                    │    Agent    │
                    │ 判断下一步   │
                    └──────┬──────┘
                           │
              ┌────────────┼────────────┐
              │            │            │
          ┌───▼───┐    ┌───▼────┐   ┌───▼────┐
          │ Tool  │    │Knowledge│   │Experience│
          │ 做动作 │    │理解系统  │   │参考过去  │
          └───────┘    └────────┘   └─────────┘

最基础的 AI Debug Engineer,只需要四个核心部分:

  1. Agent:负责判断和决策
  2. Tool:负责执行动作并返回结果
  3. Knowledge:负责提供可依赖的系统事实
  4. Experience:负责提供过去问题的参考

这四个词不是为了制造新的术语,而是为了让系统出错时能够回答一个重要问题:究竟是哪一部分出了问题?

Tool:能做什么,而不是该怎么想

Tool 是最容易定义清楚的部分。它接受明确输入,执行一个动作,返回可观察的结果。

例如:

  • 打开文件或搜索符号;
  • 获取 logcat、dmesg、tombstone;
  • 解析寄存器、反解堆栈;
  • 查询设备属性和产品配置;
  • 编译模块、刷写镜像、运行测试;
  • 比较两个版本的代码或配置。

"打开某个文件"是 Tool;"打开后重点看哪个函数"不是 Tool。后者是 Agent 根据当前问题、系统知识和已有证据做出的判断。

这个区别很重要。Tool 应尽量确定、可复现、可测试。Agent 则必须保留选择空间。假如我们把"看到 watchdog 就固定打开 A、B、C 三个文件"写死在 Tool 中,它就不再只是执行动作,而是在偷偷替 Agent 做诊断决策。

工具可以变得很强,但不应该隐藏推理。

Knowledge:不是把 Android 百科再抄一遍

谈到知识,另一个问题马上出现:LLM 本身已经了解 Android,我们还需要建设知识库吗?

答案不是简单的"需要"或"不需要"。模型内部知识应该被视为一个很强的先验,但不是当前项目事实的权威来源。

可以把知识分成三层。

第一层是稳定、公开、通用的知识,例如 C/C++ 语义、常见并发问题、Linux 基础机制、Binder 的基本概念。大部分情况下,可以先依靠模型已有能力。

第二层是公开但与版本强相关的知识,例如某个 Android 版本的 Framework 实现、某条 AOSP 分支上的接口行为。这些内容不适合只凭模型记忆,应该在需要时查阅匹配版本的源码和文档。

第三层是企业与产品内部知识,例如私有 SoC 模块、寄存器定义、芯片 errata、Vendor HAL、产品配置、内部补丁以及未公开的设计约定。这些内容模型不可能天然知道,必须由系统提供。

因此,真正需要长期建设的知识,可以用一个不严格但很实用的公式来描述:

text 复制代码
需要的知识
- 模型能够可靠掌握的通用知识
- 可由当前代码、设备和工具即时获取的事实
= 需要额外维护的内部知识

这也意味着我们不应该先启动一个"完整 Android 知识库工程"。更合理的方式是从真实调试任务出发:当 Agent 因缺少某项稳定事实而失败,再把这项缺口补成可检索、可追溯、带版本条件的知识。

还有一条原则不能省略:越接近结论的关键事实,越不能只依赖模型印象。调试中的证据可信度大致应该遵循:

text 复制代码
当前设备与实验结果
> 当前分支的代码和配置
> 匹配版本的内部规范
> 匹配版本的公开文档
> 模型的既有认知

LLM 可以告诉我们"通常是什么",但最终需要回答的是"这台设备、这个版本、这次故障究竟是什么"。

Experience:不是一句"以前也遇到过"

经验和知识最容易混在一起。

"某寄存器的 bit 3 表示总线超时"是知识。它描述的是在给定版本和条件下可反复成立的事实。

"上次某项目进入休眠后偶现死机,最终发现是一个电源域关闭前仍有未完成访问"是经验。它来自一次具体事件,带有当时的上下文、行动和结果。

一条有用的经验,至少应该能回答:

  • 当时是什么产品、版本和环境?
  • 出现了什么现象和触发条件?
  • 做了什么检查或实验?
  • 观察到了什么?
  • 哪个假设因此被支持或排除?
  • 最终结论经过了怎样的验证?

所以经验不应该只是一个根因标签,更适合保存成一个个 Experience Episode

text 复制代码
上下文 + 触发状态 + 行动 + 观察 + 产生的影响

一张完整的 Bug 单当然可以保留,用于审计、复盘和评测;但检索时未必应该把整张 Bug 单原样塞给模型。一个复杂问题往往包含多段有价值的经验:一次无效排查、一个被排除的假设、一个关键转折点,以及最后的根因验证。把它们拆成较小的 episode,更容易在新的调试状态下被准确召回。

经验的地位也要摆正:它是新假设的来源,不是当前问题的真相。

"过去这样解决过"只说明这个方向值得检查。是否适用于眼前问题,仍然要回到当前代码、设备和实验中验证。

Agent:不是一个巨大的 Prompt

当 Tool、Knowledge、Experience 被分开后,Agent 的职责反而简单了。

它不需要装下整本 Android 百科,也不应该背诵所有历史案例。它要做的是维护当前问题的工作状态,并不断判断下一步最值得做什么。

这个工作状态至少包括:

  • 已确认的事实;
  • 当前假设及其依据;
  • 已排除的方向;
  • 已执行的动作及结果;
  • 尚缺少的信息;
  • 下一步想验证的问题。

然后 Agent 在一个循环里做选择:是继续推理,检索知识,寻找相似经验,调用工具收集新证据,向工程师请求信息,还是已经可以停止。

这里要区分 LLM 与 Agent。LLM 完成的是一次推断;Agent 则把模型、目标、工作状态、工具、权限和停止条件组织成一个持续的决策过程。

因此,Agent 的基础配置应该短而稳定,主要描述角色、目标、证据原则、成功条件和权限边界。Android 机制、项目资料、历史问题和具体命令不应全部堆进基础 Prompt,而应在需要时通过对应接口进入上下文。

固定 Flow,不等于固定推理

调试的大流程看起来确实很直觉:接收问题、分析、定位、修改、验证。为什么还需要把 Flow 固定下来?

因为需要固定的不是"先看哪一行日志",而是系统的外部协议。

例如,一个 Bug 可以有相对稳定的状态:

text 复制代码
问题接入 → 调查中 → 根因候选 → 修复候选 → 验证中 → 已解决 / 阻塞

每个状态可以规定最少需要留下什么证据、什么情况下允许进入下一阶段、哪些动作需要审批,以及什么才算真正完成。但在"调查中",Agent 先看日志还是代码、先查知识还是案例、提出几个假设、设计什么实验,都应该保持开放。

换句话说:

固定的是状态、证据、权限和验收;开放的是假设、搜索路径与实验设计。

错误的规范会限制 AI,这个担心完全成立。因此规范最好分为三个强度:

  • 必须遵守:安全边界、版本匹配、证据来源、操作权限和真实验证;
  • 默认建议:高频且通常有效的检查策略,Agent 可以说明理由后偏离;
  • 自由判断:假设生成、检索顺序、工具组合和新实验设计。

能用工具强制保证的约束,不要只写在 Prompt 中;能用验收结果判断的事情,不要过度规定中间步骤。

Codex Skill 到底放在哪里

到这里,"技能"和 Codex 里的 Skill 就可以彻底分开了。

在我们的架构语言中,技能若指"打开文件、采集日志、刷写设备",更接近 Tool;若指"判断该看哪里",则属于 Agent 的推理能力。

而 Codex Skill 是一种工程上的打包形式。OpenAI 官方文档将它描述为可复用工作流的创作格式:一个 Skill 可以包含指令、参考资料、资源和可选脚本,并在任务匹配时被加载。也正因为它是"包装",里面技术上什么都能放,才更需要我们自己维持语义边界。OpenAI:Build skills

一个好的 Skill 更像装配说明和入口:

  • 它说明适用场景和触发条件;
  • 它告诉 Agent 可使用哪些工具;
  • 它指向哪些知识源和经验源;
  • 它规定必要的输出、验证与安全边界。

但知识的权威正文、历史案例的源数据以及工具本身,不应该因为"方便"就全部复制进 Skill。否则同一事实会散落在几十个 Skill 中,无法独立更新,也无法判断哪份才是最新版本。

简单地说:

Skill 是组装方式,不是我们能力体系中的第五种内容。

先用 Codex,还是从头开发一个 Agent

在当前阶段,我们倾向于先把 Codex 当作 Agent 运行时,而不是立即从零开发一个完整 Agent。

原因不是 Codex 已经自动解决了领域调试,而是它已经提供了不少昂贵的通用能力:多轮任务推进、代码与工作区操作、命令执行、根据结果继续判断、权限控制以及修改后的验证。我们可以把精力集中在真正具有组织差异的部分:芯片与产品知识、调试工具、经验检索、问题状态和验收标准。

早期可以让工程师直接在 Codex 中运行真实案例,观察它在哪里失败。当流程逐渐稳定,需要接入 CI、Bug 平台、设备农场或内部系统时,再通过 Codex SDK 将同样的能力嵌入自动化流程。官方文档也将 Codex SDK 定位为对本地 Codex Agent 的程序化控制方式,可用于内部工具、工作流和 CI。OpenAI:Codex SDK

只有当我们明确需要自己的任务队列、大规模并发、跨设备调度、组织级权限、审计系统或特殊交互界面时,才有充分理由建设更完整的外层平台。即便如此,也未必需要重新实现底层 Agent 的全部能力。

这条路线的核心不是"永远依赖 Codex",而是先验证领域系统,再决定哪些基础设施值得自建。

真正重要的是可诊断的进化

这套拆分最大的价值,不是架构图变得好看,而是系统终于可以有方向地进化。

当一次调试失败,我们可以追问:

  • Agent 已经拿到了足够信息,却选错了方向吗?那是决策问题;
  • Agent 想做正确检查,却没有可调用的动作吗?那是 Tool 缺口;
  • 关键的内部机制没有被提供,或者版本不匹配吗?那是 Knowledge 缺口;
  • 组织里曾经处理过类似问题,却没有被检索出来吗?那是 Experience 或检索问题;
  • 已经提出正确修复,却用错误标准宣布完成吗?那是验收与 Flow 问题。

每个真实 Bug 都可以成为一次评测。每次评测暴露一个可归因的缺口,再补到对应层中,而不是习惯性地"再写一个更长的 Skill"。

随着案例增加,一些经验会反复出现。被多次验证的因果机制,可以提炼成知识;反复有效的检查方式,可以沉淀成软性的 Playbook;频繁且确定的操作,可以进一步封装成 Tool。新的内容不是随意堆积,而是在系统中迁移到最合适的位置。

这才是"源源不断完善"真正需要的闭环:

text 复制代码
真实问题
  ↓
Agent 调试并留下可观察记录
  ↓
评测结果与失败归因
  ↓
补 Agent / Tool / Knowledge / Experience 中的明确缺口
  ↓
回放旧问题,确认能力真的提高

这里记录的不是模型隐秘而冗长的思维过程,而是工程上可以检查的产物:假设、证据引用、执行动作、工具结果、排除方向、下一步实验和最终验证。

如果没有评测和回放,"积累"很容易只是仓库越来越大;有了它们,我们才知道系统是真的进化了,还是仅仅换了一种写法。

结语:先让边界清楚,再让能力增长

建设 AI Debug Engineer 最诱人的做法,是尽快收集知识、编写 Skill、导入历史 Bug,再期待规模产生智能。但对于 Android 系统软件和手机芯片调试,这条路很容易造出一个内容庞大、边界含糊、无法定位自身问题的系统。

我们目前得到的结论反而非常朴素:

Agent 负责判断,Tool 负责行动,Knowledge 负责解释系统,Experience 负责提示过去。

外层 Flow 管住状态、证据、权限与验收,内层推理保持自由;Codex Skill 负责组装和复用,而不是吞掉所有内容;Codex 可以先作为通用 Agent 内核,领域能力围绕它逐步生长。

这并不是最终架构,更不是已经证明可以覆盖所有 Android Bug 的答案。它只是把一个模糊的问题变成了可以逐项建设、逐项评测、逐项修正的工程系统。

但也许这正是起点最需要完成的事:在追求让 AI 像资深工程师一样工作之前,先让我们能够说清楚------它这一次为什么做对,又为什么做错。

相关推荐
Kapaseker1 小时前
写过 4000 行 ViewModel 后,我开始这样拆 Compose 页面
android·kotlin
恋猫de小郭2 小时前
ADB Wi-Fi 2.0 ,Android 17 把无线调试的连接链路重新做了一遍
android·前端·flutter
亿是守候 & 亿是承诺2 小时前
第二章 控制系统的数学模型
android
Carson带你学Android2 小时前
ADK for Kotlin:Google 官方 AI Agent 教程来了
android·agent·ai编程
一航jason14 小时前
Android平台推理框架及试用场景模型对比
android·人工智能·ai·架构·ai编程·llama
一航jason14 小时前
Android 端侧大模型推理框架对比
android·人工智能·ai·ai编程·llama·ai-native
新时代牛马14 小时前
cyclictest 毛刺从哪来?从ftrace、latencytop、perf到IRQ/调度延迟定位
android·开发语言·python·kotlin
光电的一只菜鸡16 小时前
为什么调整LSC会对AF产生影响
android·开发语言·kotlin
凛_Lin~~16 小时前
LiveData 源码解析
android·安卓·livedata