上周我在赶一个内部工具的迭代,用豆包(Doubao)帮我写代码和梳理逻辑。说实话,一开始体验挺糟糕的。我随手把一个几十页的需求文档扔进去,跟它说“帮我实现这个功能”,结果它给我生成了一堆看着挺整齐但完全跑不通的代码,还自作主张把数据库表结构给改了。
那天下午我几乎在反复做同一件事:写提示词 -> 得到垃圾代码 -> 骂骂咧咧改提示词 -> 再得到稍微好一点的垃圾代码。这让我意识到,和 AI 协作不是“你随便说,它随便写”那么简单。你需要一套有纪律的工作流。
经过这两周的反复踩坑和调整,我摸索出了一套和豆包高效协作的工作流,核心思路就四个字:分而治之。下面是我实际操作中的具体做法。
第一步:先让它当架构师,别当码农
我犯的最大错误就是一上来就让 AI 写具体代码。正确的做法是,先让豆包帮你做系统设计,把大任务拆成小任务。
我的具体做法是,新建一个对话,先把需求文档贴进去,然后给这样的提示词:
你是一个资深架构师。请阅读以下需求文档,不要写任何代码。
我需要你输出:
1. 这个需求的核心业务逻辑是什么(用3句话概括)
2. 需要拆分成哪些独立模块(列出模块名和职责)
3. 模块之间的调用关系和数据流向
4. 每个模块的输入和输出定义
5. 你认为最大的技术风险点在哪里
输出格式用 Markdown,每个模块不超过5行描述。
关键点在于**“不要写任何代码”**这句。一旦你让 AI 边设计边写代码,它就会陷入细节,丢失全局视角。豆包在这方面尤其明显——如果你不给约束,它会很热情地给你堆代码,但逻辑是散的。
实际结果:我那个内部工具,豆包把它拆成了 5 个模块:用户鉴权、数据采集、规则引擎、通知分发、仪表盘。我拿着这个拆分方案自己审视了一遍,发现规则引擎和通知分发其实可以合并,但整体拆分思路是对的。这比我自己从头想快了至少一个小时。
第二步:给每个模块写“合同”
拆完模块后,我不再在一个对话里写所有代码。我为每个模块开一个新对话,但在开聊之前,先把“合同”定好。
所谓合同,就是模块的接口定义。比如对于规则引擎模块,我会先写:
# 规则引擎模块接口定义
# 输入:
# - events: List[Event] - 事件列表,每个Event包含type, payload, timestamp
# - rules: List[Rule] - 规则列表,每个Rule包含condition, action, priority
#
# 输出:
# - matched_actions: List[Action] - 命中的动作列表
# - execution_log: List[LogEntry] - 执行日志
#
# 约束:
# - 规则按 priority 从高到低执行
# - 同一事件最多触发3个动作
# - 执行超时阈值 500ms
def evaluate_rules(events: List[Event], rules: List[Rule]) -> Tuple[List[Action], List[LogEntry]]:
pass
然后我告诉豆包:
这是规则引擎模块的接口合同。请严格按照这个输入输出定义来实现,
不要修改函数签名,不要添加额外的类属性。
如果觉得接口设计有问题,先提出修改建议,等我确认后再实现。
这一步是整个工作流里最关键的。我之前踩过的坑是:豆包在实现模块 A 时,会“顺手”把模块 B 的逻辑也写进去,导致耦合严重。有了合同约束,它就老老实实只在边界内干活。
第三步:循环工程——终止条件比提示词更重要
这个思路来自翔宇工作流的一篇文章,他们拆解了 136 个开源循环,发现 85% 的失败都是因为终止条件缺失。我深有体会。
我之前让豆包做数据清洗,提示词是“不断清洗直到数据质量达标”。结果它循环了 20 多轮,每轮都在改不同的字段,最后把正确的数据也改坏了。
现在我设计任何循环任务,都会明确三件事:
请执行数据清洗循环,具体要求:
1. 每轮操作:检查剩余脏数据数量,选择数量最多的脏数据类型进行清洗
2. 终止条件:脏数据比例 < 2% 或 已执行5轮
3. 每轮输出:本轮清洗了什么、剩余脏数据数量、是否满足终止条件
如果终止条件满足,立即停止并输出最终报告,不要再做“额外优化”。
那个“不要再做额外优化”是我加的血泪教训。豆包有个毛病——它总觉得还能更好,你不明确喊停,它就停不下来。
第四步:上下文管理——别在一个对话里聊太多
豆包的上下文窗口虽然大,但这不意味着你该把所有东西塞进去。我发现当一个对话超过大约 15 轮交互后,豆包开始“遗忘”早期的约束条件。比如我在第 3 轮说了“用 SQLite”,到第 18 轮它突然开始写 PostgreSQL 的语法。
我的做法是:
- 架构设计对话:用完即弃,把输出存到本地文件
- 每个模块实现:独立对话,把合同和相关的数据结构定义贴进去
- 调试对话:又开新对话,只贴报错信息和相关代码片段
对话之间用文件传递上下文,而不是靠 AI 的“记忆”。这就像你不会让同事把所有讨论都装在脑子里一样——你会写文档。
第五步:用 AGENTS.md 思路维护项目规范
这个思路借鉴了 Codex 最佳实践里的 AGENTS.md 概念。我在项目根目录维护一个 CONTEXT.md 文件,内容大概是:
# 项目上下文
## 技术栈
- Python 3.11, FastAPI, SQLite
- 不使用 ORM,直接写 SQL
## 代码规范
- 函数必须有类型标注
- 错误处理用自定义异常,不裸抛 Exception
- 日志用 structlog,不用 print
## 已知决策
- 2024-01-15: 规则引擎和通知分发合并为一个模块
- 2024-01-16: 放弃 Redis,用内存缓存 + 文件持久化
每次开新对话,我先让豆包读这个文件:
请先阅读以下项目上下文,后续所有实现必须遵循这些规范。
如果我的需求和已有规范冲突,请先指出,不要自行覆盖规范。
[粘贴 CONTEXT.md 内容]
这一招让跨对话的一致性提升了很多。之前我最头疼的就是在对话 A 里定好了“不用 ORM”,到对话 B 它又给你生成 SQLAlchemy 代码。
实际效果与诚实评估
用这套工作流两周后,我的体感效率提升大概在 40% 左右。最大的改善不是“写得更快”,而是返工率明显下降——以前写 10 段代码要改 7 段,现在大概改 3 段。
但必须说几个真实的局限:
豆包对复杂业务逻辑的理解力有限。我的规则引擎里有几个涉及时间窗口聚合的场景,豆包反复理解错误,最后还是我自己写的。它更擅长结构清晰、边界明确的任务。
上下文丢失问题没有完全解决。即使有 CONTEXT.md,当单个对话轮次过多时,它还是会“走神”。我的应对是保持对话简短,超过 10 轮就开新对话。
生成代码的测试意识薄弱。豆包写的代码经常没有边界检查和异常处理。我现在固定在提示词里加一句:“所有外部输入必须做校验,所有 IO 操作必须有异常处理”,效果好了不少。
这套工作流有前期成本。写合同、维护 CONTEXT.md、设计终止条件——这些都需要时间。对于一次性小脚本,这套流程反而更慢。它适合的是中大型项目,模块多、周期长的那种。
最后一点建议:别把 AI 当神仙,也别把它当傻子。把它当成一个手速极快但需要明确指令的初级工程师——你给的边界越清晰,它交付的质量越高。工作流的核心不是什么魔法提示词,而是你自己对问题的拆解能力。