聊聊我的 AI 开发工作流:从想法到 dev 验收
这篇文章聊聊我平时做个人项目时,怎么和 AI 一起把一个想法推进到自己的 dev 服务器上,最后确认它确实能用。
个人开发时,从想清楚要做什么,到编码、部署和验证,都需要自己照顾。我会让 Claude Code、Codex 参与这些环节,分别从产品分析、开发实现和测试验证的角度处理任务。需求取舍和最后的使用体验,仍然由我来判断。
我使用的工具包括 GitHub、GitHub Actions、Harbor、Docker Compose 和飞书。本地负责开发与检查,自己的 dev 服务器负责运行部署后的服务,AI 则沿着任务记录读取上下文、执行操作和整理反馈。
下面按一个需求的推进顺序,分享我怎么组织这套工作流。
1. 我定目标,AI 按不同角色参与
同一个想法,从不同角度看会得到不同的问题。产品视角关心这个功能解决什么问题、范围是什么;开发视角关心现有代码怎么改;测试视角则要追问哪些条件下会出错,以及怎样判断结果正确。
我会把这些职责写进交给 AI 的任务里:
| 角色或环节 | 我交给它的任务 | 留下的结果 |
|---|---|---|
| 我 | 提出想法、确认规则、决定范围、实际体验 | 明确的目标与验收结论 |
| AI 产品角色 | 梳理使用场景、追问遗漏、拆分需求 | 需求说明、待确认问题 |
| AI 测试角色 | 根据需求设计用例,执行后比较预期与实际 | 测试清单、证据、缺陷记录 |
| AI 开发角色 | 阅读代码、在 worktree 中实现并自检 | 代码改动、相关测试、PR |
| AI 审查角色 | 对照需求与当前改动查找问题 | 审查意见与复查结果 |
| 流水线 | 检查、构建镜像、部署 dev、通知我 | 执行记录、镜像版本、服务状态 |
例如,一个任务可以先让 Claude Code 从产品角度梳理需求,由 Codex 实现,再让 Claude Code 在另一个会话里审查和验证。也可以交换两个工具的角色。我更关注每次交给它的职责、输入材料和完成条件。
这些角色之间通过 Issue、需求记录、代码和测试结果传递信息。到了需要做取舍的地方,AI 把问题交给我确认。
我的主流程是:想法与需求确认 → 用例准备 → worktree 开发 → PR 审查与 CI → 合并后构建镜像 → 部署自己的 dev → AI 验证与我的实际体验 → 记录结论。
2. 从一句想法开始,把需求写进 Issue
个人项目里的需求,经常先是一句很直接的话,比如:“聊天回答生成到一半,我想能随时停止。”
我会先让 AI 从产品角度展开这句话:用户在哪里触发停止?停止后已经显示的内容怎么处理?还能不能继续发送消息?如果刚好生成结束,又该显示什么状态?这些问题确认之后,再进入实现。
我给这个角色的任务可以这样写:
先从产品分析的角度梳理这个需求。
请说明使用场景、本次范围、关键交互和验收条件。
把缺少定义的行为单独列出来,向我确认后再更新需求。
这一阶段先完成需求说明。对于需要持续推进的功能或缺陷,我会用 GitHub Issue 保存这些结论。简单需求直接写在正文里;内容较多时,再关联仓库里的需求说明、测试清单或在线文档。这样即使换一个 AI 会话,也有明确的入口可以继续。
下面以“停止生成”为例,展示 Issue 中要保留的信息:
需求:聊天生成过程中支持停止回答
使用场景:回答已经不再需要,或用户希望调整问题重新发送。
本次范围:停止入口、生成状态切换、已有内容保留、后续发送。
不包含:编辑历史消息、批量操作。
确认的规则:
- 停止后保留已经展示的内容。
- 页面退出本次生成状态,可以继续发送消息。
待确认:正在执行的工具任务如何处理?
相关材料:需求记录、测试清单、界面截图、涉及的代码路径。
验收条件:正常停止、重复点击、结束时点击等场景的预期行为。
后续记录:PR、部署提交、镜像 digest、dev 地址、验证结果。这是用于说明写法的例子,具体规则需要针对功能确认。AI 提出的建议和我已经确定的要求,也会分别标明。
临时的小改动可以直接从对话开始。需要跨会话继续,或者会经历开发、审查和部署几个阶段时,我会把任务依据和结论留下来,避免下次又从头解释。
3. 补齐上下文,让 AI 先准备测试
3.1 让 AI 读到需求和现有实现
进入开发前,我会把 Issue 链接交给 AI,让它读取相关需求记录、项目规则、代码和已有测试。需求说明告诉它我想要什么,现有代码告诉它目前如何工作。
有些资料放在需要登录的在线文档或页面里。普通 URL 抓取可能只拿到登录页,也可能漏掉页面上的表格、原型和附件。遇到这种情况,我会使用具备浏览器操作能力的工具,连接已经授权、已经登录的 Chrome,读取指定内容。具体能复用哪些登录态、访问哪些页面,取决于工具和授权范围;可用的文档连接器也能承担相应读取任务。
我会要求 AI 说明实际读到了什么。折叠区域、分页表格、动态加载内容和附件尤其容易漏掉。读取受阻的部分要明确列出来,不能把登录页当作已经读完需求。
读取完成后,AI 先整理一份理解清单:本次目标、改动范围、关键规则、相关模块、验收条件以及还需要我确认的问题。引用资料时保留链接或代码位置;需求变化时,也要更新对应记录。
3.2 用测试视角检查需求有没有遗漏
需求确认之后,我会让 AI 切到测试视角,根据需求设计用例,再交给开发角色使用。这样在写代码之前,就能知道需要满足哪些条件。
仍以“停止生成”为例,测试清单可以从这些场景展开:
| 场景 | 需要提前确定或验证的行为 |
|---|---|
| 正常生成时点击停止 | 本次生成如何结束,已有内容如何保留 |
| 连续点击停止 | 是否出现重复请求或错误状态 |
| 回答刚好结束时点击 | 页面是否保持正确的完成状态 |
| 停止后发送新问题 | 新请求能否正常发起并接收回答 |
| 切换会话后操作 | 操作是否仍对应正确的会话和请求 |
| 请求失败或网络中断 | 提示、按钮和生成状态是否一致 |
测试角色会把需求没有定义的地方标出来,交给我决定。例如“停止后是否保存部分回答”必须先有明确结论,才能据此判断测试通过与否。
我也会让测试角色区分“需求明确要求的行为”和“它建议补充的行为”。最终用例以确认后的需求为依据,开发完成后仍用这份依据检查,避免把当前实现的结果直接当成正确答案。
4. 在独立 worktree 里开发,本地只运行一套服务
开始实现时,我会为任务创建独立的 worktree。AI 在对应目录里阅读、修改和验证代码,原来的工作目录可以保留其他正在进行的工作。
“A git repository can support multiple working trees, allowing you to check out more than one branch at a time.”
一个 Git 仓库可以拥有多个工作目录,同时检出多个分支。
以基线为 main 的示例仓库为例:
git fetch origin
git worktree add -b feat/issue-123 ../app-issue-123 origin/main实际执行时使用项目自己的基线、分支和目录约定。前后端分属两个仓库时,分别建立对应工作区,再把相关 PR 关联回同一个任务。
Worktree 分开的是代码目录,端口、数据库等运行资源仍需按本地开发约定使用。我本地的处理很简单:同一时间只运行当前任务的一套前后端服务。 切换任务时,先停止旧服务,再从当前 worktree 启动,并确认浏览器访问的确实是这次修改的版本。
5. 让 AI 实现、自检,再换一个视角审查
AI 完成实现后,我会让它运行项目已有的检查。Python 后端与 TypeScript 前端分别执行适用的语法或类型检查、lint、相关测试和构建,具体命令以项目配置为准。
我会看这些检查与改动有什么关系。比如修改停止生成的逻辑,就需要验证状态变化和后续发送;修复一个缺陷,则应该留下能够识别这个缺陷的回归测试。构建成功之后,功能行为还要继续验证。
本地检查通过后整理 PR,说明这次解决的问题、代码行为、验证结果和未覆盖项。随后让承担审查角色的 AI,对照需求、测试清单和实际 diff 检查。我可以让 Codex 实现、Claude Code 审查,也可以按任务调整分工。
审查意见需要有依据:相关代码在哪,什么条件会触发问题,预期和实际有什么差异。修复后重新检查对应行为;涉及业务取舍的意见由我决定。
5.1 Agent Loop 怎样推进一个具体任务
在编码和排查过程中,AI 会反复经历这样的循环:
读取需求、代码和已完成记录
→ 判断下一步
→ 调用工具修改代码或执行检查
→ 读取执行结果
→ 根据反馈继续修正,或汇总结果并结束这就是我在这里所说的 Agent Loop。比如 AI 修改停止逻辑后运行用例,发现“停止后仍然不能发送新消息”,它就需要读取失败输出,定位没有恢复的状态,修复并重新验证。
我使用 AI 编程工具本身的执行循环,再通过项目规则约定检查命令、任务范围和完成条件。外层工作流连接需求、PR、部署和验收,内层循环推进一个具体的开发或排查任务。
执行结果要区分通过、失败和没有执行。缺少必要资料、权限或测试数据时,AI 保留已经完成的部分和阻塞原因;同一个错误反复修复仍无进展时,交给我重新判断。一次任务也可以设置执行时长或轮次上限,结束时汇总结果和未完成项。
6. 通过 Actions 和 Harbor,把确定的版本部署到 dev
我用 GitHub Actions 承接代码检查、镜像构建和部署。PR 阶段先运行 CI;审查与检查通过、确认合并之后,再以主分支上的最终提交构建镜像,推送 Harbor,并部署到自己的 dev 服务器。GitHub Actions 官方说明
PR 审查与 CI 通过
→ 确认合并,检查最终提交
→ GitHub Actions 构建镜像并推送 Harbor
→ dev 拉取指定镜像,更新应用服务
→ 冒烟检查、功能验证、实际体验
→ 记录结果,通过飞书通知我服务器部署时直接使用构建好的镜像。我会把提交号和镜像 digest 记录下来,确认这次运行的到底是哪一个版本。后续再次部署同一版本时,也能找到对应产物。
标签便于阅读,digest 用于固定镜像身份。Harbor 默认允许覆盖同名标签,也提供标签不可变规则。
“The sha256 digest remains reliable and always points to the same build.”
SHA-256 摘要始终指向同一个构建产物。
前端、后端和 Worker 如果使用不同镜像,就记录各自的 digest,以及部署配置和数据库迁移版本。验收结果也与这组信息对应。
6.1 拉取镜像后,更新正在运行的容器
Compose 文件中的镜像引用指向本次要部署的 Harbor 版本。假设应用服务名为 api、web 和 worker,数据库等依赖已经运行,可以只更新这些应用服务:
docker compose pull api web worker
docker compose up -d --no-deps --no-build api web worker第一条命令成功后才执行第二条;拉取失败时,流水线应停止。示例中的服务名需要替换为项目实际名称。
“but does not start containers based on those images”
docker compose pull不会基于拉取的镜像启动容器。
镜像或配置发生变化时,docker compose up 可以重建对应容器,并保留挂载的数据卷。命令执行结束后,还要检查服务状态和实际运行的镜像。Docker Compose up 官方说明
6.2 把 dev 配置和代码版本一起核对
本地和 dev 使用各自的数据库地址、Redis、域名与凭据,数据库迁移作为明确的部署步骤处理。验证时既要确认镜像正确,也要确认服务连接的是预期环境。
前端的构建时配置也需要留意。例如 Next.js 的 NEXT_PUBLIC_* 值会在构建时写入浏览器代码。镜像中如果固定了某个 API 地址,修改容器运行环境变量不会自动改变它。需要在不同环境复用镜像时,应采用合适的相对地址、反向代理或运行时配置机制。Next.js 环境变量说明
dev 上排查问题时,如果临时修改了容器内文件,我会把修复回到代码仓库,重新构建并验证镜像,让下次部署能够重现相同结果。
7. 自己的 dev,也要分清正在验证哪个任务
我在自己的 dev 上完成部署后的功能验证。对同一个项目的同一套服务,一次验证期间保持一个明确的版本,确认这次结果后,再继续部署下一个改动。
即使只有我一个人开发,也可能同时开着不同任务或 AI 会话。如果一个任务正在浏览器里验证,另一个任务又更新了同一套服务,就很难判断测试结果属于哪个版本。因此,我会把部署顺序和验证范围一起安排。
这里讨论的是同一套应用的版本切换。同一台 dev 上的其他项目,按各自的应用配置和服务范围管理。
更新应用时,数据库、Redis 等基础服务可以继续保留。测试数据有冲突或需要恢复基线时,再处理相应数据。Docker 数据卷有独立于容器的生命周期,替换应用容器不会自动清空数据。Docker 数据卷说明
我还会核对数据库迁移是否与新版本兼容。切回旧镜像前,也要确认旧代码能使用当前结构。相关 Worker、定时任务和队列需要一起检查,避免旧任务继续影响当前验证。
每次部署记录至少保留任务、提交号、镜像 digest、dev 访问地址、迁移结果和当前验证状态。这样我和承担测试角色的 AI 都知道,这轮验证针对哪个版本。
8. AI 按用例验证,我再走一遍真实使用流程
部署结束后,先做冒烟检查,确认服务启动、关键依赖正常、页面和主要接口可访问。通过之后,再按需求和用例验证具体功能。
这时我会让 Claude Code 或 Codex 承担测试角色,把事先确认的需求、用例清单、dev 地址和部署版本交给它。对于适合自动执行的接口和浏览器用例,由 AI 操作并整理证据。
例如验证“停止生成”,就需要实际发起一次回答、触发停止、检查已展示内容和页面状态,再发送下一条消息。读取代码或看到健康接口返回成功,都不能代替这条使用路径。
测试报告可以按下面的格式整理:
任务与用例:Issue 编号、用例编号、采用的需求版本
环境与版本:dev 地址、部署提交、镜像 digest、执行时间
前置条件:账号、会话、测试数据和初始状态
操作步骤:实际执行了什么
预期与实际:分别记录,并附必要的截图或接口结果
结论:通过 / 失败 / 阻塞 / 未执行
遗留问题:需要修复或由我确认的事项用另一个会话审查或测试,可以引入不同的检查角度;结论仍要靠实际执行的证据支撑。发现需求本身有歧义时,AI 把问题交给我,我确认后再同步更新需求与用例。
AI 验证完成后,我会从真实使用的角度再走一遍关键流程,看看交互是否顺手、反馈是否清楚,以及这个功能是否解决了最初的问题。技术检查结果和我的体验结论分别记录。
飞书在这里用来通知我:构建或部署是否失败、验证是否结束、是否有需要确认的问题。流水线通过自定义机器人的 Webhook 发送摘要和任务链接,完整结果留在 Issue 或对应记录里。飞书自定义机器人说明
9. 修复失败,也检查多个任务合到一起的结果
我会把失败之后怎么继续推进,也写进任务记录:
| 失败位置 | 保留的信息 | 后续处理 |
|---|---|---|
| 本地检查或 CI | 失败命令、相关输出、对应提交 | AI 定位并修复,再运行相关检查 |
| 部署或冒烟 | 镜像版本、服务状态、错误日志 | 排查应用启动、配置或环境问题 |
| 功能验证 | 用例、预期、实际结果、复现步骤 | 回到实现环节修复,再验证失败场景 |
| 需求理解 | 冲突描述、遗漏规则、影响范围 | 交给我确认,更新需求和用例 |
修复产生新提交后,要重新形成对应的检查、镜像和验证记录。需要恢复旧应用版本时,先核对配置与数据库兼容性,恢复后的状态也单独记录。
个人开发同样会遇到多个分支组合后的问题。比如,一个任务改了接口结构,另一个任务仍按旧结构增加页面。Git 没有文本冲突,也可能在运行时出现问题。
因此,我会检查主分支上的最终提交,再构建、部署并验证组合后的行为。分支上已有的测试结果可以作为依据,但新的合并版本仍需运行相关检查和回归。
我也会留意 Issue 的关闭时机。GitHub 支持通过关闭关键词或 Development 关联,在合并到默认分支时自动关闭 Issue。为了把 dev 验收也纳入任务终点,我会使用普通引用,例如“关联需求 #123”,在验证完成后再记录结论并关闭任务。GitHub 的 PR 与 Issue 关联规则
10. 让下一次打开任务时,知道从哪里继续
对我来说,个人开发里的上下文同样需要认真维护。一个任务可能跨过几个 AI 会话,也可能隔一段时间才继续。把需求、测试清单、PR、部署版本和验证结果连起来,下一次打开记录时才能知道已经做了什么。
我让 AI 从产品角度把问题问清楚,从开发角度完成实现,再从测试角度检查结果;流水线负责重复执行检查和部署。我则负责做取舍、处理不确定的地方,以及最后实际使用这个功能。
这也是我组织这套工作流时最看重的事:从最初的想法,到自己 dev 上正在运行的版本,每一步都有依据,执行结果可以核对,遇到问题也知道该带着哪些信息继续处理。