技术选型系列文章(二下):从“选完”到“开干”——我的 HomeSense 技术选型收尾与执行前评审
前言:选完不是终点,能“通过评审”才是
在上一篇里,我分享了边缘端语言、数据库、音频处理的选型过程。但选完技术栈,就能直接开干了吗?
我的经验是:绝对不能。
在我过去的项目中,吃过太多“选完就写”的亏。代码写到一半,才发现:
-
某个依赖在两个模块间版本冲突
-
某个方案的性能实测比预期差 10 倍
-
某个看似独立的模块,实际上和另一个模块有隐式耦合
这些问题,在“选型阶段”完全可以避免——只要你多做一个动作:让 AI 帮你生成一份可执行的任务清单,然后拿它去评审。
这篇“二下”,我会讲清楚三件事:
-
剩下的技术选型(云端 Agent、安卓端、设备控制协议)
-
我是怎么让 AI 反过来问我问题,把模糊的地方彻底聊透
-
如何生成 task 文档,并拿去给另一个 AI 做评审,确保“选型”能平滑过渡到“执行”
一、剩下的技术选型:云端、安卓端、设备控制
1.1 云端 Agent 语言:为什么我弃 Python 选 TypeScript
问 AI
云端 Agent 要做意图理解、任务拆解、流式输出,还要调用豆包/DeepSeek API。Python 和 TypeScript 怎么选?
AI 给的对比
| 维度 | Python | TypeScript |
|---|---|---|
| AI 生态 | ⭐⭐⭐⭐⭐ 最强 | ⭐⭐⭐⭐ 强(Vercel AI SDK、LangChain.js) |
| 流式输出 | 需框架配合 | 原生支持(SSE、Vercel AI SDK) |
| 类型安全 | 动态 | 静态(可避免大量运行时错误) |
| 全栈统一 | 需要另一套前端 | 前后端同语言 |
| 部署 | 需 Python 环境 | 一个 Node 镜像 |
我的追问
Vercel AI SDK 是什么?它比直接调 API 好在哪?
AI 回答
Vercel AI SDK 是专门为 AI 流式应用设计的库,提供
streamText、useChat等 React 钩子,自动处理 SSE、流式解析、前端渲染。你用 LangChain.js 做决策,用 Vercel AI SDK 做流式输出,两者配合是天作之合。
我的决策
选 TypeScript + Fastify + LangChain.js + Vercel AI SDK。理由:
-
类型安全,降低多模型切换时的错误
-
Vercel AI SDK 让流式输出从“手写 SSE”变成“写对象”
-
和前端(如果有)共用类型定义
1.2 安卓端 SSE 客户端:OkHttp 还是 Retrofit?
问 AI
手机需要接收边缘端转发的 SSE 流,显示执行进度。用 OkHttp SSE 还是 Retrofit + SSE?
AI 给的对比
| 维度 | OkHttp SSE | Retrofit + SSE |
|---|---|---|
| 代码量 | 少(直接监听 EventSource) | 多(需定义接口、适配器) |
| 依赖 | okhttp-sse | retrofit + okhttp-sse |
| 学习曲线 | 低 | 中 |
| 适用场景 | 简单 SSE 客户端 | 复杂 API 集成 |
我的追问
我只需要一个 SSE 连接,需要 Retrofit 吗?
AI 回答
不需要。Retrofit 是为 REST API 设计的,SSE 是“服务端推送”,不是“请求-响应”。用 OkHttp SSE 直接监听,代码不到 50 行。
我的决策
选 OkHttp SSE。理由:极简、够用、不引入额外抽象。
1.3 设备控制协议:ADB 怎么封装?
问 AI
边缘端要执行
adb shell input tap、adb shell am start等命令。用第三方库还是直接exec.Command?
AI 给的选项
| 方案 | 优点 | 缺点 |
|---|---|---|
直接 exec.Command |
简单、无依赖 | 需处理命令行转义 |
github.com/electricbubble/gadb |
纯 Go、零依赖、截图返回 image.Image | 功能略少 |
github.com/zach-klippenstein/adb |
功能完整 | 依赖系统 adb 命令 |
我的追问
我需要截图功能,gadb 支持吗?性能如何?
AI 回答
gadb 的
Device.Screenshot()直接返回image.Image,不用调用外部命令,性能更好。且它不依赖系统 adb,编译后单个二进制。
我的决策
选 直接 exec.Command + 关键操作用 gadb 补充。理由:
-
简单命令(tap、input)用
exec.Command,零依赖 -
截图用 gadb,省去解析二进制数据
二、让 AI 反过来问我:把“模糊”变成“清晰”
2.1 为什么我要让 AI 问我问题
技术选型走到这一步,我已经有了一个完整的方案。但我发现,有几个地方我其实“没想透”:
-
流式透传时,执行命令会不会阻塞?
-
执行结果怎么插入到 SSE 流中?
-
如果边缘端执行失败,云端要不要知道?
这些不是“选哪个库”的问题,是架构细节。如果不清不楚就开干,写到一半准会卡住。
于是,我换了一种问法:
我现在已经选好了技术栈,但我还想把架构细节聊透。请你反过来问我问题,找出我架构中可能存在的模糊点、风险点或未考虑的场景。比如:流式透传时执行命令会阻塞吗?结果怎么返回?等等。你问,我来答,直到所有细节都清晰为止。
2.2 AI 问我的问题(节选)
AI 真的开始追问了:
Q1:边缘端在透传 SSE 流时,如果遇到 command 消息,执行命令会阻塞透传吗?如果不阻塞,执行结果怎么插回流里?
我的回答:不阻塞,用 goroutine 异步执行。执行结果构造为新的 SSE 消息,通过 channel 发送给主循环,主循环再写入 HTTP 响应。这样透传不中断,结果也能按顺序插入。
Q2:如果执行失败,要重试吗?重试逻辑在边缘端还是云端?
我的回答:边缘端做简单重试(3 次指数退避)。如果仍失败,构造 error 消息透传给手机,同时云端应该能感知(通过日志或回调)。
Q3:手机录音 AAC 上传后,NAS 转 WAV 再调豆包,总耗时多久?用户会等急吗?
我的回答:预估 1.5-3 秒。用户等待在可接受范围内。后续可优化为手机直接录 WAV 或流式上传。
Q4:云端 Agent 的 command 消息里,坐标参数是固定写死还是动态识别?
我的回答:MVP 阶段写死坐标(先在电视上找好)。后期加本地视觉(YOLO),动态识别按钮位置。
Q5:SQLite 的向量检索,数据量多大时性能会下降?需要提前分库吗?
我的回答:家庭场景数据量 < 1 万条,sqlite-vec 足够。不需要分库,等真不够了再迁 pgvector。
就这样,AI 一个问题接一个问题,我一个个回答。前后聊了 20 多轮,把所有模糊点都敲实了。
聊透的标准:当你对 AI 的每一个追问都能给出明确答案,且答案之间没有矛盾时,才叫“透了”。
三、生成 task 文档,拿给另一个 AI 评审
3.1 为什么要“换一个 AI”评审
同一个 AI 聊久了,容易陷入“思维惯性”。它可能会默认接受你的假设,而不是真正挑战你。所以我做了一个操作:把我整理好的 task 文档,扔给另一个 AI(比如从 Cursor 换到 DeepSeek),让它做一次独立的评审。
评审的标准是:
-
任务是否可执行(有没有缺步骤)
-
依赖关系是否明确(先做什么后做什么)
-
风险点是否标识(哪里可能卡住)
-
验收标准是否清晰(怎么算“做完”)
3.2 task 文档的核心结构(可直接拿去用)
我最终生成的 task 文档长这样:
markdown
# HomeSense MVP 执行任务清单
## Phase 1:基础环境与框架搭建(1-2天)
### 1.1 Monorepo 初始化
- [ ] 创建根目录 `homesense/`
- [ ] 初始化 Git 仓库
- [ ] 添加 `.gitignore`(Go、Node、Android 通用)
- [ ] 创建 `docker-compose.yml` 用于本地联调
### 1.2 边缘端 Go 骨架
- [ ] 创建 `edge-agent/` 目录,初始化 `go.mod`
- [ ] 实现 `main.go`:读取环境变量,启动 HTTP 服务
- [ ] 实现 `handler/voice.go`:接收手机音频,返回 202 Accepted
- [ ] 实现 `adb/adb.go`:封装 `exec.Command` 执行 `adb connect`
### 1.3 云端 Agent TypeScript 骨架
- [ ] 创建 `cloud-agent/` 目录,初始化 `package.json`
- [ ] 安装 Fastify、LangChain.js、Vercel AI SDK
- [ ] 实现 `/plan/stream` 端点:接收 `{ text }`,返回 SSE 流
- [ ] 实现 DeepSeek 客户端(占位)
### 1.4 安卓 App 骨架
- [ ] 创建 `android-app/`,最小 SDK 26
- [ ] 实现 `MainActivity`:一个录音按钮 + 一个 TextView
- [ ] 集成 OkHttp SSE,连接边缘端
## Phase 2:核心链路打通(2-3天)
### 2.1 手机录音 → NAS
- [ ] 安卓端实现 `MediaRecorder` 录 AAC(3秒)
- [ ] 安卓端通过 OkHttp POST 到边缘端 `/voice`
- [ ] 边缘端接收音频,保存临时文件
### 2.2 NAS 转码 → 云端
- [ ] 边缘端调用 FFmpeg 转 AAC 为 WAV(16kHz 单声道)
- [ ] 边缘端转发到云端 Agent `/plan/stream`(HTTP 请求)
- [ ] 云端 Agent 返回 SSE 流(先硬编码步骤)
### 2.3 云端决策 → 边缘执行
- [ ] 云端 Agent 解析文本,返回 `{ type: "command", action: "tap", ... }`
- [ ] 边缘端透传 SSE 到手机,同时识别 command 异步执行
- [ ] 边缘端执行结果通过 SSE 返回手机
## Phase 3:本地存储与记忆(2天)
- [ ] 边缘端集成 SQLite(`mattn/go-sqlite3`)
- [ ] 创建 `memory` 表:`intent`, `steps`, `success_count`
- [ ] 实现 `SaveSuccess()` 和 `FindSteps()` 方法
- [ ] 修改 `/voice` 逻辑:先查本地缓存,没有再走云端
## Phase 4:联调与演示(1-2天)
- [ ] 编写 `docker-compose.yml` 一键启动三个服务
- [ ] 录制演示视频:手机说话 → 电视响应
- [ ] 写 README 和架构图
## 风险点与备选方案
| 风险 | 应对 |
|------|------|
| FFmpeg 在机顶盒上没装 | 用 Docker 镜像或静态编译版 |
| ADB 连接不稳定 | 指数退避重试(3次) |
| 豆包 API 格式不匹配 | 用 DeepSeek 兜底 |
| 机顶盒内存不足 | 限制 SQLite 缓存大小,关闭非必要日志 |
3.3 评审结果
我把这份文档发给另一个 AI(豆包),让它做独立评审。
AI 的反馈:
-
缺验收标准:每个任务要写明“怎么算做完”,比如“边缘端能成功执行
adb shell input tap 500 200” -
缺依赖标注:比如 Phase 2 的 FFmpeg 转码依赖 Phase 1 的 FFmpeg 安装
-
缺备选方案:比如“如果豆包 API 调用失败,是否降级到 DeepSeek”
我根据反馈,把 task 文档改到第三版,AI 才说:“可以执行了。”
四、总结:我的“聊透”方法论
回顾整个技术选型过程,我总结了一套可以复用的方法:
-
先让 AI 穷举选项(不要直接问“哪个好”,要问“有哪些方案”)
-
对比优劣(让 AI 给表格,追问“为什么 A 比 B 好”)
-
追问细节(挖原理、验适配)
-
让 AI 反问(用“请你问我问题”把模糊点敲实)
-
生成 task 文档(可执行、有依赖、有验收)
-
换 AI 评审(用另一个视角挑刺)
这套方法,让我在 一行代码都没写 的情况下,就把项目从“想法”变成了“可执行的任务清单”。
代码是最后一步。在这之前,把问题聊透,让任务清单通过评审,才是真正的“准备好了”。
下一篇,我会写《从 task 到 code——如何让 AI 按照任务清单一步步执行》。如果你也在用这种方式做项目,欢迎交流。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)