从一个项目说起
一个嵌入式SLAM模块------某机器人系统的核心视觉处理组件。几万行 C++,涉及 GPU 并行计算、中间件通信、状态估计算法、视觉跟踪、3D 空间计算,交叉编译跑在 ARM 嵌入式平台上。
打开代码的那一刻我是懵的。模块间的调用关系像蜘蛛网,GPU kernel 和 CPU 逻辑交织,消息回调链路跨了好几个服务。前同事留下的文档约等于零。
这时候我做了一个决定:让 AI Agent 成为我的结对编程搭档,但不是那种"帮我写个函数"的浅层用法,而是贯穿项目理解、方案设计、编码实现、测试验证、Bug 排查、知识沉淀的全流程深度协作。
这篇文章就是对这段经历的完整复盘。
一、项目理解:让 AI 替你"啃"代码,但你要定义"啃"的产出物
不要让 AI 读完就算
大多数人用 AI 辅助读代码是这样的:把文件丢给它,问"这段代码干了什么",得到一段解释,然后......就没有然后了。下次还得重新问。
我的做法不同:我要求 AI 把理解结果输出成可沉淀的文档。
具体来说,我让 AI 系统性地扫描整个代码库后,产出三样东西:
- AGENTS.md------项目导航指南,按模块分组(我这个项目分成了 8 个模块组),每个模块写清楚:职责、关键文件、对外接口、依赖关系。
- TECHNICAL_DOC.md------技术文档,包括数据流、算法原理、平台差异。
.ai/目录------知识仓库,后面会详细讲。
为什么要这样做?因为 AI 的上下文窗口是有限的。你不把知识落盘,每次新对话都要重新建立理解,效率极低。而且,这些文档不只是给 AI 看的------团队新成员入职、工作交接、甚至三个月后的你自己,都能直接受益。
多 Agent 并行探索
我用的 AI Agent 系统支持多种专用 Agent 并行工作:
- Explore Agent:代码库内部搜索,但不是简单的 grep------它理解上下文,能跨文件追踪调用链。比如我问"消息回调收到请求后,数据怎么流到 GPU kernel 的?",它能从回调函数一路追到并行计算调用。
- Librarian Agent:搜外部资料------官方文档、开源实现、学术论文。当我需要了解某个滤波算法的最佳实践时,它直接去找相关的开源项目作为参考。
关键技巧:这些 Agent 要并行发射,不要串行等待。我通常同时发出 3-5 个探索任务,比如:
Agent 1: 找出所有涉及位姿缓存的数据结构和存取逻辑
Agent 2: 追踪传感器数据从回调到 GPU 处理的完整链路
Agent 3: 搜索某类滤波器的开源实现和参数调优经验
我不等它们返回------继续看自己能看懂的部分。系统通知结果就绪后再收集。这种"异步协作"模式大幅缩短了项目理解的周期。
一个实际数据:理解这个几万行的 C++ SLAM项目,从完全陌生到能画出完整的数据流架构图,传统方式我估计要 1-2 周,用这套方法大概半天。
二、方案设计:人类把控方向,AI 负责技术深度
"先调研,再设计,审核后才能实现"
这是我给自己立的规矩,也是我用下来最重要的一条原则。
项目里前同事留下了一个"目标点 3D 跟踪"的技术方案。我让 AI 以全新的视角审视这个方案------不是让它说"好不好",而是让它从算法原理层面指出问题:
- 位置估计用的是什么方法?几何约束够不够?
- 滤波器的状态空间设计合不合理?
- 跟踪器的鲁棒性在边界场景下会不会崩?
AI 指出了几个关键问题后,我决定让它重新设计 V2 方案。但注意------我审核每一个设计决策:
- 滤波器用逆深度参数化而不是直接深度?为什么?------因为逆深度在远距离时方差更均匀,对初始化不确定性更鲁棒。OK,认同。
- 位置估计用线性初始化 + 非线性优化?------比直接三角化精度更好。OK。
- 跟踪器加了什么鲁棒性措施?------前后一致性检测、最小特征值阈值。OK。
AI 在技术深度上能给你很多超出你知识范围的方案,但方向判断必须是人类做的。
Oracle Agent:高质量架构顾问
在方案设计阶段,我还会请一个叫 Oracle 的 Agent 做评审------它是一个只读的、昂贵的、高质量推理模型。我不会在日常编码时随便用它,但在关键的架构决策节点,它的判断质量值得这个成本。
比如我让它评审 V2 方案时,它指出了一个我和 Explore Agent 都没注意到的问题:滤波器在载体静止场景下的可观测性条件。这个反馈直接影响了我后续的实现策略。
三、编码实现:多 Agent 并行开发 + 严格验证流水线
任务拆解与并行委派
V2 方案确定后,编码阶段我把任务拆成了几个独立的模块:
- 状态估计滤波器
- 几何位置估计器
- 视觉跟踪器重写
- Pipeline 集成到主循环
- 单元测试
前三个模块相对独立,我尝试了并行委派给不同的 AI Agent 实例。实话说,这一步的效果不如预期------并行开发的 Agent 之间缺乏共享上下文,接口对不上的情况时有发生。后来我调整策略:核心模块自己盯着一个 Agent 串行做,确保接口一致性;只有真正无耦合的部分才并行。
最终 7 个 Git Commits 完成整个 feature。每个 commit 都是原子的、可回退的。
嵌入式场景的特殊挑战
在这种交叉编译的 C++ 项目里用 AI,有几个独特的坑:
1. LSP 疯狂误报
我的本地开发环境跑的是 x86,目标平台是 ARM 嵌入式板卡。项目用特定构建系统管理,OpenCV 和 Eigen 等三方库通过构建系统的外部依赖机制引入。但 LSP(clangd)不认识构建系统的依赖解析,所以满屏都是红色波浪线。
这对 AI Agent 有什么影响?它会把 LSP 误报当成真错来修! 我必须明确告诉它:"三方库的 include 报错是交叉编译环境误报,忽略它们,只关注业务逻辑的真实错误。"
这种"环境约束声明"非常重要,我把它写进了 AGENTS.md,这样每次新对话 AI 都能自动加载这条规则。
2. GPU Kernel 的特殊性
GPU kernel 代码对 AI 来说是个灰色地带。它能理解 kernel 的逻辑,但对 GPU 内存模型、线程同步、shared memory 的使用往往不够精准。我的策略是:GPU 部分让 AI 读、理解、建议,但不让它直接改------至少不在没有仿真验证的情况下。
3. 中间件通信的异步复杂性
消息中间件回调的时序问题是 AI 最容易忽略的。它能正确理解单个回调函数的逻辑,但对"这个回调和那个回调的执行顺序"、"数据从发布到回调触发的延迟是多少"这类系统级问题,基本靠猜。
实际经验:我们系统的消息传输延迟超过 2 秒------这个数字是通过日志测出来的,不是 AI 推断的。但 AI 帮我计算了"在这个延迟下,缓存队列需要多大才能覆盖",这种数学计算它做得很快很准。
验证流水线:不验证 = 没完成
我给 AI Agent 设定了一条铁律:代码改完必须通过验证才能标记完成。
验证流水线包括:
- 静态分析扫描改动文件------确保没有引入新的编译错误
- Oracle Agent 做 Code Review------重点看边界条件、内存安全、线程安全
- 单元测试通过
- 离线 Demo 验证------我写了一个 1000+ 行的 Python 离线脚本,读取真实数据跑 V2 算法,可视化结果
这个流水线听起来很重,但大部分步骤 AI 自己就能完成。我只需要看最终的可视化结果和 Review 报告。
四、Bug 排查:AI 翻车最狠的一次
这部分我必须坦诚地写,因为它是我整个经历中最有价值的教训。
问题现象
系统在特定场景下计算 3D 坐标失败。日志显示当通信延迟较高时,使用"历史数据回退"的备选路径也失败了。
AI 的排查过程
我让 AI 分析日志、追踪代码、推理根因。它先后提出了好几个假设:
- "输入数据在该平台上可能未正确初始化"
- "GPU kernel 在输入数据为空时的行为可能异常"
- "数据管理模块的模式切换逻辑有问题"
每个假设都看起来有道理,AI 都能从代码中找到"支持证据"。但------全都不是根因。
真正的根因
后来发现真正的原因简单得令人哭笑不得:
系统里有两个数据缓存,功能相似但实现细节不同:
- 缓存 A:用 32 位截断时间戳做 key
- 缓存 B:用完整 64 位时间戳做 key
而查询请求带的是 32 位截断时间戳。所以缓存 A 的查找能命中,缓存 B 的查找永远失败------因为 32 位和 64 位的精确匹配不可能成功。
修复就几行代码:统一用 32 位截断值做 key。
为什么 AI 排查偏了?
复盘下来,AI 翻车的原因有三个:
1. 被人类的口头描述误导
排查过程中我告诉 AI:"时间戳的问题已经查过了,改过了,查找能命中。" 我说的是缓存 A(它确实 OK),但 AI 默认理解为所有缓存都 OK,没有独立去验证缓存 B 的 key 类型。
教训:用户说"已经修过了",不等于所有相关的数据结构都修完了。AI 必须自己验证每一个。
2. 同类数据结构没有逐个检查
两个缓存名字相似、功能相关,但 key 的存储类型不同。AI 检查了一个就默认另一个也一样。
教训:多个同类缓存/队列/Map,必须逐个检查 key 的写入类型、存储类型、查询类型是否一致。
3. 缺乏"数据类型链"思维
AI 擅长理解逻辑流,但不擅长追踪"一个值从产生到使用,类型经历了哪些变化"。在嵌入式系统中,不同位宽之间的隐式截断太常见了,AI 往往不把它当回事。
教训:排查数据匹配类问题时,要画出完整的类型链------写入时的类型 → 存储时的类型 → 查询时的类型。任何一环不一致都是潜在 Bug。
这次翻车改变了我的方法论
从此以后,我加了两条硬规则:
- 排查中学到的关键知识必须自动沉淀成文档 ------存到
.ai/discovery/目录下。不管结论对不对,排查过程本身就是知识。 - AI 的排查结论必须有代码级证据------不接受"可能是"、"推测为",必须指出具体的代码行和数据流。
五、知识沉淀体系:让 AI 越用越聪明的关键
这是我最想分享的部分,因为大多数人用 AI 辅助开发都忽略了这一环。
.ai/ 目录结构
.ai/
├── handoff/
│ └── project-chat-bootstrap.md # 工作交接文档,每个重要节点更新
├── discovery/
│ ├── debug-lesson-xxx.md # 排查教训
│ ├── data-flow-architecture.md # 架构发现
│ └── ... # 其他发现
└── design/
├── feature-v2-design.md # 方案设计文档
└── ...
每个目录的职责
handoff/------工作上下文的"存档点"
这是最重要的文件。每次完成一个重要阶段(方案设计完成、feature 开发完成、Bug 修复完成),我都会更新这个文件。它记录了:
- 当前项目状态
- 已完成的工作和关键决策
- 未解决的问题
- 下一步计划
- 关键的代码约定和环境约束
为什么重要?因为 AI 的对话是有上下文长度限制的。当对话太长需要开新会话时,只要让 AI 先读这个文件,它就能在 30 秒内恢复到之前的工作状态。
我实测过:没有 handoff 文档的新会话,AI 需要重新探索 20-30 分钟才能进入状态;有 handoff 文档的新会话,2 分钟就能继续干活。
discovery/------排查和探索过程中的发现
每次排查问题或深入研究某个模块时,不管最终结论如何,过程中的发现都记录在这里。比如:
- 消息中间件的传输延迟实测值(这个数字之后被引用了无数次)
- 某个模块在特定平台上被条件编译宏排除,导致整个函数不被编译(这坑谁踩谁知道)
- 两个看起来名字相似的类指针其实是完全不同的实现
这些零散的知识单独看不起眼,但积累起来就是对项目的深度理解。
design/------方案设计文档
算法方案、接口设计、性能评估等。让 AI 在设计阶段就输出结构化文档,后面实现时可以反复对照。
AGENTS.md:项目的"新手导航"
AGENTS.md 不是给 AI 看的 prompt(虽然它确实也能当 prompt 用),它更像是项目的导航地图。按模块分组,每个模块写清楚:
markdown
## 模块:视觉处理
- 职责:相机图像处理、去畸变、特征提取
- 关键文件:xxx.cpp, xxx.cu
- 接口:输入原始图像帧,输出处理后图像和特征点
- 依赖:OpenCV (交叉编译版), CUDA
- 注意事项:LSP 对三方库头文件的报错是误报,忽略
这种文档的价值在于:新人(包括新的 AI 对话)能在 5 分钟内知道"我要改的东西在哪个模块、涉及哪些文件、有什么坑"。
核心理念:知识的复利效应
传统开发模式下,你排查一个 Bug 花了两天,修完就忘了。下次遇到类似问题,又要重新摸索。
但如果每次都沉淀一份 discovery 文档,几个月后你的 .ai/discovery/ 目录里就有了几十份关于这个项目的深度知识。任何新的 AI 会话都可以加载这些知识,相当于"站在你过往经验的肩膀上"。
这是 AI 辅助开发的长期价值所在------不是单次对话的效率,而是知识的持续积累。
六、嵌入式场景的特殊经验
在这类项目中用 AI 辅助开发,有以下经验:
1. 交叉编译环境 = AI 的认知盲区
AI 训练数据里绝大多数是 x86 环境的代码。当你的目标平台是 ARM、RISC-V 或其他嵌入式架构时,AI 对编译器行为、内存对齐、字节序等问题的判断可靠性会下降。
我的策略:把平台差异和构建系统的关键信息写进 AGENTS.md,作为 AI 的"常识补丁"。
2. 硬件时序问题 AI 推理不了
消息延迟多少、传感器数据的到达顺序、多线程回调的竞态条件------这些依赖运行时行为的问题,AI 只能帮你分析代码逻辑,无法推断实际时序。
我的策略:时序问题必须通过日志或示波器实测。AI 的角色是"帮你分析实测数据的含义"而不是"推测时序行为"。
3. GPU Kernel 需要特别谨慎
AI 对 GPU 并行计算代码的理解通常限于逻辑层面。它可能写出"逻辑正确但性能极差"或"看起来对但有竞态"的 kernel。
我的策略:GPU 部分只让 AI 做辅助------读代码、写注释、提建议,不让它独立修改。至少在它证明自己之前。
4. 实车/实机环境无法远程调试
由于嵌入式项目的验证链路长得多:改代码 → 交叉编译 → 部署 → 运行 → 看日志。这意味着每一次"试一下"的成本都很高。
AI 在这里的价值是"减少试错次数"------通过代码级的推理,尽量在编译前就发现问题。但前面说了,它的推理不总是对的,所以还需要配合离线验证脚本来兜底。
七、可以直接用的实践建议
如果你看到这里觉得"有道理,但不知道怎么开始",这是我的建议:
第一步:在项目根目录建立 .ai/ 目录(10 分钟)
mkdir -p .ai/handoff .ai/discovery .ai/design
写一份最简单的 handoff 文档:项目是干什么的、核心模块有哪些、有什么特殊约束。不用完美,有就比没有强。
第二步:让 AI 帮你写 AGENTS.md(30 分钟)
把整个项目丢给 AI,让它按模块分组输出导航文档。你审核修正后保存。以后每次新对话让 AI 先读这个文件。
第三步:建立"改完必验证"的习惯
不管多小的改动,都跑一遍静态分析。这是用 AI 写代码最容易踩的坑------它生成的代码看起来对,但可能有类型不匹配、未定义变量等问题。自动化验证比人眼 Review 可靠。
第四步:排查问题时,同步写 discovery 文档
不要等排查完再写。边查边记。哪怕最终结论是错的(比如我那次翻车),排查过程中的发现------数据流走向、隐藏的条件编译、意外的默认值------都是有价值的知识。
第五步:定义人机分工边界
| 环节 | 人类 | AI |
|---|---|---|
| 项目理解 | 审核、修正 | 扫描、输出文档 |
| 方案设计 | 决策、审核 | 调研、设计、评审 |
| 编码 | 架构把控、接口定义 | 实现、单元测试 |
| 验证 | 看结果、判断 | 跑测试、做 Review |
| Bug 排查 | 提供环境信息、最终判断 | 代码追踪、假设生成 |
| 知识沉淀 | 建立框架 | 持续填充 |
核心原则:人类负责"判断",AI 负责"执行"。
写在最后
最后,谈一谈我的感受:AI Agent 在复杂嵌入式项目中的提效是真实的,但远没有某些营销文章吹的那么神。
它真正擅长的是:
- 快速理解大量代码并输出结构化文档
- 在多个技术方案之间做比较分析
- 编写符合既有风格的业务代码
- 并行搜索和信息聚合
它真正不擅长的是:
- 独立判断------特别是当人类提供了误导信息时
- 硬件时序和运行时行为推理
- 跨多个数据结构的一致性检查(比如那个时间戳位宽不一致的坑)
- 需要"直觉"的 Debug------那种"感觉这里不对"的第六感
最终的赢家不是"会用 AI 的人",而是"知道什么时候该信 AI、什么时候该自己判断的人"。
希望这篇复盘对你有用。如果你也在嵌入式领域尝试 AI 辅助开发,欢迎评论区交流踩坑经验。