学了 Drogon、FastAPI 和 FAISS,项目进度为什么仍可能是 0?用证据管理 AI 开发
一个 AI 项目的进度表很容易写成这样:
1 | Drogon 学习完成 |
但此时执行下面的验收,可能一个也通过不了:
1 | 能否启动 Gateway? |
“学过五个组件”和“产品完成 60%”之间没有可计算的关系。前者描述活动(activity),后者应该描述可观察结果(outcome)。如果进度只根据阅读量、代码行数或主观感觉更新,团队会在集成阶段才发现:每个组件都懂一些,但没有一条用户路径可以运行。
本文以本地 RAG 项目为例,解决一个经常被忽视的问题:怎样把学习记录转换成可验证的工程进度?我们会先诚实盘点现有证据,再写一个零依赖进度检查器,最后设计从服务骨架到 RAG 闭环的里程碑门禁。目标不是增加一套项目管理仪式,而是让“已完成”成为一个任何人都能复验的技术结论。
1. 为什么“做了很多事”仍然无法回答做到哪了?
先区分四类经常混在一起的信息:
| 类型 | 例子 | 能否直接证明功能完成 |
|---|---|---|
| 学习活动 | 阅读 Celery 文档、整理 FAISS 笔记 | 不能 |
| 设计产物 | 架构图、接口草案、数据库 ER 图 | 只能证明设计存在 |
| 实现产物 | 可构建代码、迁移脚本、容器配置 | 还需要运行验证 |
| 验收证据 | 命令、退出码、关键输出、测试报告 | 可以证明它覆盖的具体要求 |
学习与设计并非没有价值。它们降低后续决策成本,却不能替代运行结果。例如,写完一篇 Celery 状态笔记,不代表 broker 已配置正确;创建 compose.yaml,也不代表 MySQL ready 后应用一定能连接。
这也是“完成百分比”容易失真的原因。假设 60% 的分母是什么?是文件数量、工时、API 数量,还是端到端验收项?只要分母没有定义,数字便无法比较,也无法预测剩余风险。
更可靠的状态只需要三类:
1 | not_started 尚无通过证据 |
如果确实被外部条件卡住,可以额外记录 blocked,但要写清阻塞条件和解除条件,不能把“不知道下一步怎么做”长期包装成 blocked。
2. 用现有笔记盘点,当前到底能证明什么?
仅以当前笔记目录为证据,可以确认两类高价值工作已经存在。
第一,系统目标和双服务路线已经形成。整体交付边界、垂直切片和八周计划记录在 deep-research-report.md 中。
第二,关键技术已经完成第一轮学习。相关材料包括:
| 方向 | 已有笔记 | 它能证明什么 |
|---|---|---|
| C++ Web 入口 | Drogon.md | 已整理框架概念和常见接口 |
| Python API | FasthAPI.md | 已覆盖请求、异步和上传等知识 |
| 后台任务 | Celery.md | 已理解队列、worker、状态和重试 |
| 数据与缓存 | MySQL.md、Redis.md | 已整理持久化、缓存和 TTL 等基础 |
| 检索 | FAISS.md、Chunk学习笔记.md | 已进入切片与向量检索专项 |
| 模型与评估 | 句子嵌入模型.md、数据处理与数据集评估.md | 已开始关注模型、数据和评测 |
这些证据足以把“方案与知识准备”标记为完成或完成第一轮,却不能证明工程闭环已经运行。当前笔记目录尚不能提供以下证据:
- Drogon 与 FastAPI 的实际构建、启动输出;
- MySQL 迁移和 Redis 连接的运行结果;
- Celery 任务提交、worker 消费与重试记录;
- 上传、切片、索引、检索和回答的端到端测试;
- 固定问题对应的检索指标与 bad case;
- 失败注入、断线恢复和部署复现结果。
这句话必须准确理解为“这组笔记不能证明”,而不是断言其他目录或其他机器上一定没有实现。进度审计只应根据可见证据下结论,既不能虚构完成,也不能把未收集证据等同于功能必然不存在。
由此得到的合理阶段判断是:设计和技术储备已有,下一道门不是继续扩展学习面,而是产生第一个可重复运行的 walking skeleton(行走骨架)——两个服务能启动、互相调用,并由一条测试命令验证。
3. “完成”需要哪些证据,才不是一句口头状态?
一个验收项至少要记录五个字段:
1 | claim 声称完成了什么 |
例如,下面的记录比“FastAPI 已完成”更有用:
1 | claim: FastAPI readiness 可用 |
证据必须和 claim 匹配。一次 /health 返回 200 只能证明这个检查覆盖的存活或就绪条件,不能顺便证明文档上传和 RAG 都正常。单元测试通过也不能替代跨服务 E2E;反过来,一次 E2E 成功也不一定覆盖切片边界和错误处理。
什么是好的 Definition of Done?
Definition of Done(完成定义)应当在实现前写成布尔条件:
1 | Milestone:文档 ingest 闭环 |
五项全部通过才能标记 done。完成三项不是“done 60%”,而是 in_progress,3/5 gates passed。这样的表达保留了真实分母,也能直接指出剩余工作。
4. 最小可运行版本:让脚本根据证据计算状态
下面的 Python 3.9+ 程序只使用标准库。它把每个 milestone 拆成 checks;只有退出码为 0、实际观察和证据位置都非空的 check 才算通过。状态由程序计算,不手工填写。
1 | from dataclasses import dataclass |
保存为 progress_check.py 并运行:
1 | python3 progress_check.py |
预期输出:
1 | architecture_contract: status=done checks=2/2 |
脚本故意不接受一个手填的 status="done"。状态只能由 checks 推导。真实项目可以把 records 放进 JSON/YAML,或者直接从测试报告生成;但在团队规模很小时,不必先开发复杂平台,一份可读数据加一个几十行检查器已经足够。
这个最小版本仍有明确边界:非空 artifact 只是证据索引,不代表文件一定存在或没有被篡改。工程版应检查路径、时间、测试报告格式、当前 commit 和运行环境,CI 还应直接运行 command,而不是完全相信历史退出码。
5. 这段代码怎样防止“主观完成”?
Check.passed() 同时要求成功退出、观察结果和产物位置。只记录命令但没运行,exit_code 是 None;命令成功却没保存关键结果,也不能作为长期证据。
Milestone.result() 不做加权平均。三项检查通过一项时,它显示 in_progress 1/3,不会给出一个看似精确却没有决策价值的 33%。这能让开发者直接看到 gate 数量,但不暗示剩余两项和第一项工时相同。
示例还揭示一个重要事实:架构 contract 可以 done,而服务骨架仍 in progress,RAG 链路仍 not started。不同类型的进度可以同时存在,不应把它们相加成一个“项目总体 47%”。
若确实需要对外汇报,可报告最近可用 milestone、当前 gate 和风险:
1 | 最近可用版本:M0,接口与 P0 范围已固定 |
这比“完成 35%”信息密度更高,也更容易获得具体帮助。
6. RAG 项目应该设置哪些里程碑门禁?
不要按“学完 Redis、学完 FAISS”划 milestone,而要按用户可观察能力划分。
| Milestone | 用户或开发者得到什么 | 最小验收证据 |
|---|---|---|
| M0 Contract | 清楚知道系统做什么、不做什么 | API schema 检查、P0/排除项 |
| M1 Walking Skeleton | C++、Python 和依赖可以通信 | 两个 readiness + 跨服务 E2E |
| M2 Ingest | 文档能稳定变成 chunk | 固定 fixture、状态机、幂等测试 |
| M3 Retrieval | 问题能找到证据 | 固定评测集、Recall@k、索引重载一致性 |
| M4 Answer + Citation | 回答带可定位来源 | 最终 JSON schema、引用支撑检查、拒答用例 |
| M5 Streaming | 用户逐步收到并能恢复结果 | 首事件时间、终止事件、断线恢复、最终快照 |
| M6 Delivery | 陌生环境可复现 | Compose 启动、迁移、E2E、README、已知限制 |
前一 milestone 的通过测试应进入回归集。例如 M5 开始做 SSE 后,M2 的 ingest 幂等测试和 M3 的 retrieval 评测仍要运行。否则新功能可能以破坏旧闭环为代价。
当前最值得推进哪一道门?
按现有笔记能证明的范围,下一目标应是 M1,而不是继续扩展到 Ray、LoRA 或复杂 rerank:
1 | 1. 固定 Drogon 和 Python 的运行版本 |
M1 不要求 MySQL、Redis、Celery、FAISS 和 LLM 同时出现。行走骨架越小,越容易区分跨语言、构建和网络问题。依赖应在第一个需要它的业务 milestone 中加入,而不是为了架构图完整提前启动。
7. 每次开发记录什么,才对下一次有用?
开发日志不需要复述一天的所有操作。它要保存会影响后续判断的信息:目标、改变、验证、结论和下一动作。
1 | ## YYYY-MM-DD — 一句话结果 |
这个模板有几个刻意约束。
“今日目标”必须是可验证结果,不写“继续学习 Celery”。“实际改动”只列影响范围,不粘贴整段 diff。“验证”同时保存命令和结果,失败尝试只有在产生新判断时才记录。“下一动作”尽量只有一个最小可执行步骤,避免把完整 backlog 重复抄进每日日志。
不要在日志中记录 .env 内容、访问 token、数据库密码、私有文档正文或完整用户请求。排错证据需要脱敏;request ID 可以保留,Authorization 和 Cookie 不应保留。
8. 进度首页与开发日志为什么不能混成一个无限长文件?
读者打开进度首页,通常只想知道五件事:
1 | 当前可用 milestone |
每天的尝试、错误输出和决策过程属于时间线。全部堆在首页后,当前状态会被历史淹没;反过来只保留首页、每次覆盖旧结论,又会失去为什么这样决定的上下文。
最简单的维护方式不需要引入项目管理系统:文件顶部保留一个短快照,下面按日期追加日志;内容变长后再拆分历史归档。只有出现影响多个模块、以后很可能被重新讨论的决定时,才单独写 Architecture Decision Record(ADR)。不要为每个变量命名都创建决策文档。
快照更新时遵循一个原则:历史事实不改写,当前判断可以变化。例如原来计划第 3 周做 rerank,后来检索基线未达标而推迟,应记录“为什么推迟”,而不是把旧计划悄悄删掉,制造从未偏离计划的假象。
9. 记录进度时最常见的误区
误区一:学完框架等于模块完成
学习完成意味着具备开始实现的条件。模块完成还需要代码、运行结果、错误路径和验收证据。
误区二:用一个总体百分比概括所有风险
架构设计、模型质量和部署复现不能直接相加。报告最近完成的 milestone 和当前 gate,比没有分母的百分比更诚实。
误区三:命令执行过,但没有保存输出
几天后无法确认运行环境、退出码和关键结果,证据就难以复验。至少保存简短输出、版本和 commit;大日志可存 artifact,不要全部粘进 Markdown。
误区四:测试绿了,所以需求完成
先确认测试覆盖的要求。一个只断言 HTTP 200 的测试,不能证明 citations 正确,也不能证明任务失败时状态可恢复。
误区五:只记录成功,不记录改变方向的失败
无信息量的重复报错无需保留,但导致方案改变的失败必须记录。否则以后会重新走进同一个坑,却不知道当初为什么避开。
误区六:下一步同时列十个 P0
如果十件事都是“下一步”,实际上没有下一步。应选出能让当前 milestone 前进的最小动作,其余留在 backlog。
误区七:把环境变量和真实数据复制进日志
进度证据不是泄露凭证的理由。日志、截图和测试 fixture 都要使用脱敏或合成数据。
10. 什么时候适合这种证据式进度管理?
它特别适合跨语言、跨进程、依赖较多的 AI 工程,因为“局部完成但集成失败”是主要风险。个人项目也适合:中断一周后,证据和下一动作能快速恢复上下文。
对一次性、几十行、当场运行完就丢弃的实验,不必建立七级 milestone。只需保存实验问题、环境、命令、结果和结论。方法的复杂度应该与交付风险成比例。
证据式管理也不能替代判断。测试只能证明它覆盖的输入和环境;模型质量还需要有代表性的评测集与人工 bad-case 分析。脚本计算出的 done 是“满足当前完成定义”,不是“系统永远没有问题”。
11. 总结
学完 Drogon、FastAPI、Celery、Redis 和 FAISS,项目进度仍可能接近工程起点,因为学习活动没有自动变成可运行的用户路径。诚实的进度记录应区分知识储备、设计产物、实现产物和验收证据。
最重要的实践可以压缩为五点:
- 用 milestone 的布尔 gate 定义完成,不手填没有分母的百分比;
- 每项证据保存 claim、command、exit code、observed result 和 artifact;
- 只根据可见证据下结论,“没有证据”不虚构成完成,也不武断成不存在;
- 按用户闭环设置 M1~M6,而不是按学完多少框架划阶段;
- 每次日志留下一个明确的下一动作,并持续回归已经完成的 milestone。
对当前 RAG 项目,最直接的下一步是完成 M1 行走骨架:让 Drogon 与 Python 服务各自 ready,再用一条可重复的 E2E 命令证明请求确实穿过两层。等这个证据存在后,“从学明白到做出来”才真正发生。