Article
量化交易系统开发实录(七):AI 工程化落地——从 speckit 到 BMAD
以交易日历与日线聚合需求为单一案例,解释 AI 工程化如何通过规格驱动、BMAD 角色交接和人工质量门禁进入真实量化系统交付。
读者读到这一篇时,已经经历了系统边界、真实缺陷、测试防线、性能治理和架构演进。AI 工程化不应该把这些纪律替换掉,而是把它们组织成可追踪、可审计、可签收的交付闭环。
在量化交易系统里,AI 最大的价值不是“更快写出一段代码”,而是让规格、测试、实现、审查、文档和验收证据之间形成稳定链路。交易日历、跨夜归属、日线聚合、半日市处理、分层归一处理、指标增量计算和图表性能优化都不是单点函数问题。只要业务语义没有写清楚,AI 生成的代码越快,后续返工越快进入系统核心。
系列阅读顺序
推荐阅读路径是 Part1 -> Part2 -> Part3 -> Part4 -> Part5 -> Part6 -> Part7。最后再看 AI 工程化,是为了让读者先理解系统、缺陷、测试、性能和重构,再判断 AI 应该进入哪些受约束的环节。
这一篇关注四个问题:
- 规格驱动如何把业务语义、接口、测试和验收证据连起来。
- BMAD 多 Agent 协作如何降低单一 AI 输出的盲区。
- 提示词工程如何从“写得更详细”升级为“边界、输入、输出、验收都可检查”。
- 人机分工如何避免把业务语义签收、架构取舍和风险接受交给黑盒。
读者可以用一个简单判断来评估 AI 工程化是否真的生效:一次 AI 辅助交付结束后,代码库里是否能找到需求来源、澄清决策、实现计划、测试证据、性能证据和维护说明。如果只能找到一段代码和几句对话记录,这仍然是一次临时协作;如果每个关键判断都能回到工件链,AI 才真正进入工程体系。
引子:AI 写得越快,为什么维护反而可能更慢
交易系统很容易出现一个反直觉现象:AI 让代码生成速度大幅提升,但如果缺少规格、测试和质量门禁,系统维护成本会同步上升。一个“K 线聚合函数”可以很快生成,三个月后却可能成为性能瓶颈、测试盲区和业务语义债务。
常见失控信号包括:
- 函数能跑,但没有文档,下一位维护者无法确认交易日归属规则。
- 没有测试,跨夜、半日市、假期、数据断层只能靠人工回忆。
- 代码只覆盖 happy path,周五夜盘、假期前夕夜盘、临时休市需要不断补丁。
- prompt 只要求“实现功能”,没有要求类型注解、复杂度、边界条件和验收证据。
- AI 生成的方案看似完整,但没有解释哪些决策需要人工签收。
这不是 AI 本身的问题,而是交付链路缺少工程边界。AI 可以承担候选实现、测试草案、文档初稿和结构化检查,但交易系统里的业务语义、风险接受、上线窗口、回滚条件和质量签收必须由人负责。读者真正需要关注的是:AI 输出进入代码库之前,是否已经被规格、测试、审查和证据约束住。
开源背景:Spec Kit 与 BMAD 提供了两类互补能力
读者如果想把这一套方法迁移到自己的工程体系,首先需要区分两个开源项目的定位。
Spec Kit 是 GitHub 开源的 Spec-Driven Development 工具包。它强调把软件开发的起点从“直接写代码”前移到“可执行规格”,让团队先关注产品场景和可预测结果,再进入实现。对量化交易系统来说,Spec Kit 的启发在于:交易日归属、半日市、回测与实盘一致性、性能预算这些问题,都应该先进入规格、澄清、计划和验收链路,而不是在实现阶段靠 prompt 临场补充。
BMAD-METHOD 是开源的 Agile AI-driven Development 方法和模块生态。它的核心价值不是让 AI 自动替代团队,而是通过角色化 Agent 和结构化工作流,把需求澄清、架构、实现、审查、测试和文档变成协作过程。对交易系统来说,BMAD 的启发在于:Architect、Developer、QA、Reviewer、Documenter 这些角色可以由 AI 参与,但每个角色必须交付可追踪工件,不能只留下对话结论。
这两个项目分别解决两个问题:Spec Kit 让“规格”成为实现入口,BMAD 让“多角色协作”成为质量控制手段。真正进入生产级交付时,仅有规格还不够,因为实现过程会失控;仅有多 Agent 也不够,因为角色之间可能缺少共同规格。后面讨论的 BMAD-Speckit-SDD-Flow,正是把这两类能力进一步组合成一条受治理的 AI 交付流。
第一部分:speckit——规格驱动的 AI 开发
speckit 可以理解为一套规格驱动开发流程。它不是某个单一工具,而是把需求、澄清、计划、实现和验收组织成稳定工件链:
Specify:明确业务需求,写成可引用的规格。Clarify:消除歧义,记录技术决策和待确认问题。Plan:拆解实现步骤、依赖关系、风险和验证方式。Implement:在规格约束下生成或编写代码。Checklist:对照规格、测试和证据完成验收。
这个流程和传统瀑布最大的区别在于:每一步都可以使用 AI 加速,但决策权仍然在人。AI 不直接决定交易日定义、不直接接受半日市风险、不直接签收指标结果;AI 负责把候选内容结构化,人负责确认语义和边界。
对量化交易系统来说,规格驱动还有一个额外价值:它把“业务正确性”和“代码正确性”分开。代码可以通过类型检查和单元测试,但业务语义仍然可能错。例如函数返回了一个日期对象,并不代表它返回了正确交易日;日线聚合能算出 OHLC,也不代表它没有把周五夜盘算进周五。speckit 要解决的正是这种语义断层。
这张图回答的是一个关键问题:为什么 AI 工程化不能从 prompt 直接跳到代码。交易系统的需求通常先落在业务语义上,例如“周五夜盘归属于下周一交易日”。这个语义需要进入 Specify,再通过 Clarify 变成交易日定义、半日市规则、假期来源和异常处理策略。只有这些工件稳定后,Plan 才能拆任务,Implement 才能生成代码,Checklist 才能验证结果。
如果某一步缺失,后果通常很具体。缺少 Specify,AI 会把自然日当成交易日;缺少 Clarify,半日市和临时休市会被写成硬编码;缺少 Plan,实现顺序可能先做 UI 再补数据语义;缺少 Checklist,测试通过也无法证明真实行情边界被覆盖。规格驱动不是为了减慢速度,而是为了避免速度直接变成返工。
实战案例一:交易日历与日线聚合
交易日历与日线聚合是 AI 工程化的典型样本,因为它看起来像一个普通聚合函数,实际涉及业务语义、时区、交易所规则、数据完整性和 UI 解释。
业务复杂性至少包括四类:
- 跨夜交易:周五夜盘 17:15 到次日 03:00 归属于下周一交易日,而不是自然日周五。
- 假期休市:圣诞、元旦、春节等公众假期完全休市,不能生成误导性 K 线。
- 半日休市:除夕、圣诞前夕等只开上午盘,通常 09:15 到 12:30,下午不再生成 K 线。
- 强制收盘:半日市在 12:30 强制收盘,金融假期前夕夜盘在 03:00 强制收盘。
图 2 的重点不是“流程更复杂”,而是每个业务约束都要有落点。周五夜盘归属不是一句描述,它必须对应 get_trading_day(timestamp) 的语义、覆盖周五 23:30 和周一 00:30 的 fixture、验证日线 OHLC 的测试,以及最后能被复查的验收证据。否则 AI 生成的聚合逻辑即使通过了普通样本,也可能在真实盘面里污染指标。
Specify:把业务需求写成可验收规格
交易日历与日线聚合的规格可以拆成四个用户故事。
| 编号 | 优先级 | 业务目标 | 核心验收场景 |
|---|---|---|---|
| US-001 | P0 | 根据香港期货交易日历判断交易日 | 2024-01-08 返回交易日,2024-01-06 返回非交易日,2024-01-01 公众假期返回非交易日 |
| US-002 | P0 | 周五夜盘数据归属于下周一 | 周五 23:30 的 1 分钟 K 线归属于 2024-01-08,而不是 2024-01-05;周一 10:00 归属于周一 |
| US-003 | P1 | 正确处理半日休市 | 除夕只返回 09:15-12:30;12:30 后不再生成 K 线;假期前夕夜盘 03:00 后不再生成 K 线 |
| US-004 | P0 | 正确聚合日线 OHLC | 开盘价取第一根分钟线,最高价取分钟线最高价最大值,最低价取分钟线最低价最小值,收盘价取最后一根分钟线,成交量求和 |
功能需求需要继续细化:
FR-001:支持香港期货交易所交易日历,覆盖 2020-2030。FR-002:区分完整交易日和半日交易日。FR-003:夜盘 17:15 到次日 03:00 归属于下一交易日。FR-004:日盘 09:15-12:00、13:00-16:30 归属当日;半日市日盘 09:15-12:30。FR-005:跨午夜数据 00:00-03:00 归属于同一交易日。FR-006:半日市下午时段不生成 K 线。FR-007:假期前夕夜盘在 03:00 强制收盘。
非功能需求也必须写入规格,而不是留在口头期望里:
SC-001:日历查询延迟小于 1ms。SC-002:1000 根分钟线聚合为日线小于 50ms。SC-003:缓存 10 年日历数据时内存占用小于 100MB。
技术约束同样不能省略:
- 基于 Python 3.10+。
- 可使用
pandas-market-calendars作为基础日历能力。 - 需要支持 HKFE 定制。
- 需要兼容系统既有
BarData结构。 - 必须处理时区转换和夏令时边界。
验收标准最终落到测试清单:
- 正常交易日识别正确。
- 周末识别为非交易日。
- 公众假期识别正确。
- 周五夜盘归属下周一。
- 半日市上午交易正常,下午休市。
- 跨午夜数据 00:00-03:00 归属正确。
- 日历查询满足
SC-001。 - 日线聚合满足
SC-002。
Clarify:把歧义变成技术决策记录
规格写完后,还不能立刻实现。交易系统的歧义通常藏在“大家以为自己理解一致”的地方,尤其是交易日定义、半日市处理和假期来源。
第一个决策是交易日定义。系统采用港交所官方交易日定义:交易日以日盘日期为准,前一晚夜盘和次日日盘属于同一交易日,周五夜盘归属于下周一。这个决策会影响日线聚合、指标窗口、回测切片和 UI 标注。
| 物理时间 | 所属交易日 | 说明 |
|---|---|---|
| 2024-01-05 09:15 | 2024-01-05 | 周五日盘开始 |
| 2024-01-05 17:15 | 2024-01-08 | 下周一夜盘开始 |
| 2024-01-05 23:30 | 2024-01-08 | 周五夜盘归属下周一 |
| 2024-01-08 00:30 | 2024-01-08 | 跨午夜仍属于同一交易日 |
| 2024-01-08 03:00 | 2024-01-08 | 夜盘结束 |
| 2024-01-08 09:15 | 2024-01-08 | 日盘开始 |
关键实现逻辑可以保留为最小示意,而不是让长代码块淹没业务语义:
def get_trading_day(timestamp: datetime) -> date:
"""示意代码:根据香港时间戳返回所属交易日。"""
hk_time = timestamp.astimezone(HONG_KONG_TZ)
current_date = hk_time.date()
current_time = hk_time.time()
if current_time >= time(17, 15) or current_time < time(3, 0):
return get_next_trading_day(current_date)
return current_date
第二个决策是半日休市处理。半日市日期每年不同,疫情、台风或交易所特别安排还可能临时改变,因此规则不应硬编码在聚合函数里。更稳妥的方式是用配置表维护半日市日期、原因、上午收盘时间和夜盘强制收盘时间,例如 2024-02-09 除夕、2024-12-24 圣诞前夕、2024-12-31 新年前夕都需要独立记录。配置化的收益是规则变更时可以先更新日历和测试,再触发聚合逻辑验证。
第三个决策是假期日历来源。可以基于 pandas-market-calendars 定制 HKFE 日历,再补充香港特有假期、半日市标记和台风等特殊休市 API。这样做的关键不是依赖某个库,而是把“官方日历 + 本地修正 + 手动特殊事件”分成三层,避免把交易所规则散落到聚合器、数据导入器和 UI 提示里。
Clarify 阶段还要记录两个容易被忽略的问题:
- 非预期休市如何处理:提供
add_holiday(date, reason)这样的手动入口,已生成 K 线不直接删除,而是标记为“不完整交易日”,UI 显示警告。 - 数据断层如何处理:缺失交易日不生成误导性日线,UI 显示“数据缺失”占位,并保留数据补录入口。
Plan:把规格拆成可交付阶段
计划不是任务列表堆叠,而是依赖关系、风险和验证方式的落地。
| 阶段 | 目标文件或模块 | 主要内容 | 验证重点 |
|---|---|---|---|
| Phase 1 | hkfe_calendar.py、calendar_config.json | is_trading_day、is_half_day、get_trading_session、get_trading_day | 完整交易日、半日市、周末、公众假期 |
| Phase 2 | daily_bar_aggregator.py | aggregate、handle_night_session、handle_half_day、validate_completeness | 多场景日线聚合、不完整交易日标记 |
| Phase 3 | vnpy_datamanager、vnpy_datarecorder | 数据导入和记录阶段自动识别交易日 | 夜盘数据归属、数据层兼容 |
| Phase 4 | trading_day_indicator.py、图表 UI | 半日市、假期、不完整数据提示和数据补录界面 | 用户可见状态和数据补录路径 |
这个计划的依赖关系是 Phase 1 -> Phase 2 -> Phase 3 -> Phase 4。日历语义没有稳定之前,不应该先写 UI;聚合器没有测试之前,不应该接入数据层;数据层没有归属证据之前,不应该进入回测和实盘共用路径。
计划阶段还需要明确每个阶段的退出条件。Phase 1 的退出条件不是“日历类写完”,而是关键日期样本全部通过;Phase 2 的退出条件不是“聚合函数能跑”,而是完整交易日、周五夜盘、跨午夜、半日市和缺失数据全部有断言;Phase 3 的退出条件不是“数据层接上了”,而是导入、记录和查询返回同一交易日语义;Phase 4 的退出条件不是“界面显示了提示”,而是用户能区分完整、半日、假期和不完整交易日。
Implement:在约束下生成代码
规格和决策稳定后,给 AI 的输入需要从“帮忙写一个聚合函数”升级为可执行约束:
基于交易日历与日线聚合规格实现 DailyBarAggregator。
必须满足:
1. 所有参数和返回值使用类型注解。
2. 处理空输入、跨午夜数据、非交易日数据。
3. 周五夜盘必须归属下周一。
4. 半日市 12:30 强制收盘后不再生成 K 线。
5. 不完整交易日必须标记,不能生成误导性 OHLC。
6. 每个 public 方法必须有单元测试。
7. 1000 根分钟线聚合耗时必须小于 50ms。
测试必须覆盖:
正常交易日、周五夜盘、周一跨午夜、半日市、公众假期、不完整交易日。
输出必须包含:
实现代码、pytest 单元测试、复杂度分析、边界情况说明。
这样的 prompt 不只是更长,而是让 AI 输出进入可检查边界。关键业务逻辑已经在规格和 Clarify 中定义,AI 没有自由解释“夜盘属于哪一天”的空间。
这里还需要注意一个常见误区:prompt 中写了约束,不代表约束已经被满足。约束必须有对应证据。例如“每个 public 方法必须有单元测试”对应测试文件和覆盖报告;“1000 根分钟线聚合小于 50ms”对应 benchmark 输出;“不完整交易日不生成错误 OHLC”对应异常样本和断言;“周五夜盘归属下周一”对应固定日期 fixture。没有证据的约束只是愿望。
扩展规格:分层数据归一处理
交易日历之后,系统还会遇到分层数据归一处理问题。主周期、辅助周期、指标周期和 UI 显示周期如果各自维护边界基准,策略和图表很容易出现错位。
一个可落地的决策是:以主周期,也就是图表显示周期为基准,其他周期数据按规则归一。方案对比如下:
| 方案 | 复杂度 | 精度 | 适用判断 |
|---|---|---|---|
| 主周期基准 + 插值 | 中 | 高 | 适合作为主方案,便于 UI 和策略共享时间语义 |
| 独立边界基准 | 低 | 中 | 实现简单,但读者很难判断分段引用是否一致 |
| 全部重采样 | 高 | 高 | 精度较高,但计算成本和边界复杂度更高 |
数据缺失时不能自动填充,因为填充会制造不存在的行情。更稳妥的策略是显示空位,在 UI 上标注“数据不可用”,并让策略层明确知道该周期数据缺失。这样会增加使用者的认知成本,但能避免缺失数据被静默当成真实信号。
分层计划可以拆成四个阶段:
- Phase 1:实现
trading_calendar.py和bar_aggregator.py,提供交易日历、交易时段、日线聚合和任意周期聚合。 - Phase 2:实现
multi_timeframe_data.py和timeframe.py,封装fetch_bars、align_timeframes、周期定义和转换。 - Phase 3:让
chart_window.py、chart_widget.py和period_selector.py支持多 SubChart 和周期切换。 - Phase 4:完成数据层与 UI 层集成,增加缓存、E2E 场景和性能验证。
给 AI 的实现输入也必须带约束:
基于规格实现 BarAggregator。
必须满足:
1. 使用类型注解和 docstring。
2. 处理空输入、数据不连续、跨夜交易。
3. 每个 public 方法必须有单元测试。
4. 10000 根分钟线聚合必须小于 50ms。
5. 归一规则必须引用跨夜交易归属决策。
输出必须包含:
实现代码、pytest 测试、复杂度分析。
这个例子说明 speckit 的作用不是生成更多文档,而是把“需求 -> 决策 -> 计划 -> 实现 -> 证据”的链路固定下来。
读者在自己的系统里落地 speckit 时,可以先从一条高风险规则开始,而不是一次性覆盖所有模块。适合切入的规则通常有三个特征:业务语义容易被误解,错误会污染指标或订单,人工复盘时很难只靠日志还原。例如跨夜归属、半日市、主力合约切换、手续费模型、滑点模型、风控冻结和撮合延迟,都适合先被规格化。
实战案例二:图表性能优化
另一个典型案例是图表加载 10000 根 K 线需要 3 秒,目标是降到 100ms 以内。如果直接让 AI “优化性能”,很容易得到缓存、并发、NumPy、异步加载等混合建议,但无法判断哪个建议对应真实瓶颈。
Clarify 阶段先记录三个决策:
D1数据缓存策略:使用内存 LRU、磁盘缓存、数据库三级缓存,由SlidingWindowBarManager控制窗口数据。D2渲染优化:通过VisibleAreaTracker只计算可见范围,虚拟列表只渲染 viewport 内的 K 线。D3图片缓存:静态 K 线缓存为位图,由LRUPictureCache复用不变化的图形对象。
还需要记录两个权衡:
| 权衡 | 候选方案 | 选择理由 |
|---|---|---|
| 内存 vs 速度 | 全量缓存、按需加载、滑动窗口 + 位图缓存 | 全量缓存占用过高,按需加载交互慢,滑动窗口 + 位图缓存能在内存和响应之间取得平衡 |
| 实时性 vs 流畅度 | 实时行情更新时全量重绘,或只重绘最后一根 K 线 | 只重绘最后一根 K 线,避免每个 tick 触发全量绘制 |
这类性能规格的关键收益是把“优化方向”变成“可验证假设”。读者能清楚看到:缓存解决数据重复访问,虚拟化解决可见区域绘制,位图缓存解决静态图形重复绘制,实时更新策略解决最后一根 K 线的刷新成本。
性能优化也要避免“AI 方案堆叠”。如果 prompt 同时要求缓存、并行、NumPy、异步和渲染优化,AI 很容易给出看似全面却不可验证的组合。更稳妥的方式是先把 3 秒加载拆成数据读取、数据转换、指标计算、图形对象构建和绘制刷新,再逐段建立假设。每个假设都应该有进入条件和退出条件:进入条件是 profile 或 benchmark 证明瓶颈存在,退出条件是优化前后数据、正确性断言和回退方案都可见。
speckit 带来的收益可以从四个角度观察:
| 指标 | 使用前 | 使用后 |
|---|---|---|
| 需求返工率 | 高 | 显著降低 |
| 架构争议时间 | 数小时 | 决策文档化 |
| 新人理解需求 | 1-2 天 | 阅读规格约 30 分钟 |
| AI 代码质量 | 偏低 | 明显提升 |
第二部分:BMAD——多 Agent 协作开发
speckit 解决的是需求到代码的追踪问题,BMAD 解决的是代码质量和多视角审查问题。单一 AI 很容易沿着第一个可行方案一路生成下去,缺少架构、实现、审查、测试和文档之间的交叉校验。
BMAD 可以拆成五个角色:
| 角色 | 输入 | 输出 | 主要风险控制点 |
|---|---|---|---|
| Architect | 需求规格 | 架构方案、接口定义、核心算法伪代码 | 边界是否清楚,复杂度是否合理 |
| Implementer | 架构方案 | 可运行代码 | 是否遵守接口、类型、异常和性能约束 |
| Reviewer | 实现代码 | 审查报告、问题列表 | 是否存在边界错误、浮点误差、隐性状态 |
| Tester | 代码和需求 | 测试代码、测试报告 | 是否覆盖正常、边界、异常和性能场景 |
| Documenter | 最终代码 | API 文档、使用示例、注意事项 | 下一位维护者是否能独立理解 |
读者需要警惕一种“形式化 BMAD”:多个角色都被调用了,但每个角色只是复述上一轮输出。真正有效的 BMAD 必须制造差异化压力。Architect 应该质疑边界,Implementer 应该暴露实现限制,Reviewer 应该找错,Tester 应该把错转成可重复样本,Documenter 应该让维护者能独立接手。角色之间没有冲突和修正,往往说明流程没有真正发挥作用。
这张图的重点是“工件交接”,不是“多个 Agent 看起来更热闹”。Architect 交付的是边界和接口,Implementer 交付的是受约束代码,Reviewer 交付的是问题和修复建议,Tester 交付的是可复现测试,Documenter 交付的是维护说明。任何一个角色只输出自然语言结论而没有工件,后续追踪都会断开。
完整案例:指标计算重构
指标计算模块最初使用 Pandas DataFrame 批量计算,性能成为瓶颈。目标是把 10000 根 K 线计算 RSI 的耗时从约 150ms 降到 5ms 以内,同时让回测和实时交易使用同一套指标实现。
Architect 阶段关注边界和复杂度。输入需要说明当前使用 Pandas 批量计算、需要支持增量更新、内存占用降低 50%、计算延迟小于 10ms,并要求输出核心抽象、数据流、增量 MA/EMA/RSI 伪代码、文件组织建议和风险评估。
核心抽象可以保留在一个短代码块里:
class IncrementalIndicator(ABC):
"""增量指标基类。"""
@abstractmethod
def update(self, bar: BarData) -> Optional[IndicatorValue]:
pass
@abstractmethod
def reset(self) -> None:
pass
@property
@abstractmethod
def is_ready(self) -> bool:
pass
class IncrementalMA(IncrementalIndicator):
def __init__(self, period: int):
self.period = period
self.values = deque(maxlen=period)
self.total = 0.0
def update(self, bar: BarData) -> Optional[float]:
if len(self.values) == self.period:
self.total -= self.values[0]
self.values.append(bar.close)
self.total += bar.close
return None if len(self.values) < self.period else self.total / self.period
这个抽象传达了两个重要原则:指标实例保存必要状态,update 只处理新增 Bar;状态边界明确后,回测和实时行情可以共享同一条计算路径。
这个案例里,Architect 的价值不是写出 IncrementalIndicator 这个名字,而是把指标计算的状态边界暴露出来。Pandas 批量计算的优势是表达简洁,缺点是实时路径里容易重复扫描历史窗口。增量指标的优势是单次更新成本稳定,缺点是状态初始化、回放恢复、重置和数值稳定性都要被显式管理。Architect 必须把这些收益和代价同时写出来,否则 Implementer 只会得到一个“把 Pandas 改成手写循环”的模糊任务。
Implementer 阶段实现 IncrementalRSI,约束包括:
- 严格遵循
IncrementalIndicator接口。 - 支持 Wilder 平滑方法,也就是
SMMA(today) = (SMMA(yesterday) * (period - 1) + value) / period。 - 内存复杂度为 O(1),只保留必要状态。
- 包含类型注解、docstring 和完整 pytest。
- 前
period根 Bar 数据不足时返回None。 - 价格不变时 RSI 返回 50。
- 全涨、全跌和连续微涨时需要数值稳定性保护。
Reviewer 阶段发现的典型问题有三类:
- 初始阶段计算错误:前
period根 Bar 应该使用简单平均,而不是直接使用 Wilder 平滑。 - 零除保护缺失:平均涨跌都为 0 时会出现
0/0,价格不变应该返回 50。 - 数值稳定性不足:连续微涨或微跌时,SMMA 可能受到浮点误差影响,需要 epsilon 或明确分支。
Tester 阶段需要把这些问题转成测试,而不是只在审查报告里提醒。测试清单至少包括:
- 第一根 Bar 返回
None。 - 第
period - 1根 Bar 仍返回None。 - 第
period根 Bar 返回 0 到 100 之间的有效值。 - 价格连续不变时 RSI 等于 50。
- 连续上涨时 RSI 大于 50。
- 连续下跌时 RSI 小于 50。
- Wilder 平滑结果处于合理范围,并可与参考实现对照。
Documenter 阶段需要补齐使用方式、算法说明、注意事项和性能特征:
- 使用方式:创建
IncrementalRSI(period=14),每根 Bar 调用update,返回None表示数据不足。 - 算法说明:初始阶段使用简单平均,之后使用 Wilder 平滑。
- 注意事项:前
period - 1根 Bar 不产出指标,价格不变返回 50,内存占用与历史数据量无关。 - 性能特征:单次更新 O(1),固定内存,10000 根 K 线计算约 3ms,相比 Pandas 批量计算约 150ms 有明显改善。
这五轮协作形成的闭环,比任何单轮 prompt 都更重要。Architect 防止接口边界漂移,Implementer 把边界落成代码,Reviewer 找出算法和数值漏洞,Tester 把漏洞固化为回归保护,Documenter 把使用约束传递给后续维护者。没有 Reviewer,初始 RSI 计算错误可能直接进入主干;没有 Tester,价格不变返回 50 的规则会停留在口头;没有 Documenter,下一位维护者可能不知道初始阶段为什么不能直接 Wilder 平滑。
BMAD 质量门禁
BMAD 只有配合质量门禁才有意义。否则多个 Agent 只是轮流生成文本,并不能改变系统质量。
质量门禁可以按五级设置:
- Architect 方案必须通过接口完整性和复杂度分析。
- Implementer 代码必须通过单元测试、类型检查和接口约束。
- Reviewer 审查必须无严重问题,代码质量达到约定阈值。
- Tester 测试必须覆盖边界情况和性能约束。
- Documenter 文档必须包含 API 说明、使用示例和注意事项。
BMAD 的收益不是“交付时间一定更短”。更现实的结果是:平均交付时间可能从 1 天增加到 1.5 天,但 Bug 逃逸率降低、边界覆盖率提升、文档完整度提升,维护成本下降。对交易系统来说,这个权衡通常是值得的,因为实盘事故和错误指标的代价远高于多半天交付时间。
质量门禁还应该保留拒绝路径。Architect 方案如果没有说明回测和实盘是否共享接口,就不能进入实现;Implementer 代码如果没有类型和异常边界,就不能进入 Review;Reviewer 发现严重问题时,不能让 Tester 用更多测试去“证明它能跑”;Tester 没有覆盖边界样本时,Documenter 不应该写成稳定能力。门禁的价值在于让失败尽早暴露,而不是让流程看起来顺利。
第三部分:AI 提示词工程最佳实践
提示词工程不是把需求写得更长,而是把角色、约束、输入、输出、示例、反问和上下文都变成可检查结构。
一个实用的判断标准是:prompt 中的每个句子是否能影响输出。如果某句话不能影响接口、测试、性能、错误处理、文档或验收,它可能只是语气修饰。交易系统里的 prompt 应该减少“尽量高质量”“写得优雅”这类不可验收表述,增加“输入为空时返回什么”“跨夜归属如何判断”“性能目标是多少”“失败时如何降级”这类可验证约束。
原则一:角色激活
角色应该具体到领域、经验和审查风格。例如“量化交易系统架构师,有 10 年高性能计算经验,专长低延迟系统设计、Python 性能优化和金融数据结构,风格注重边界情况、简洁实现和可测试性”。相比“帮忙优化一个指标”,这样的角色设置能让 AI 更倾向于讨论复杂度、状态和测试。
原则二:约束清单
约束必须区分硬性约束和建议。硬性约束包括:内存占用 O(1)、单次 update O(1)、必须包含类型注解、每个 public 方法必须有单元测试。建议可以包括:使用 deque 存储滑动窗口、考虑浮点误差、添加 benchmark。硬约束用于验收,建议用于引导实现。
原则三:输入输出格式
输入输出格式要明确到数据结构。例如输入是 List[BarData],包含 open/high/low/close/volume;period 是整数周期。输出包括实现代码、复杂度分析和 pytest 测试。格式明确后,AI 更容易稳定产出可接入代码,而不是写成无法落地的说明文。
原则四:反问确认
复杂任务应该先让 AI 提出 3 到 5 个澄清问题。K 线聚合函数最需要澄清的问题包括:
- 输入 K 线是字典、类还是 DataFrame。
- 目标周期只支持分钟转小时,还是支持任意周期。
- 数据缺失时跳过、填充还是报错。
- 跨夜交易如何归属,周五夜盘算周五还是下周一。
- 性能目标是实时流式处理还是批量处理。
这些问题看起来基础,但通常正是事故来源。
原则五:迭代求精
模糊反馈会让 AI 随机重写。更好的反馈是指出具体位置、具体问题和修复要求。例如“除法缺少零保护,分母为 0 时价格不变返回 50”,“当前时间复杂度为 O(n),需要改成增量状态 O(1)”,“缺少 period > len(data) 的处理”。结构化反馈能让迭代变成收敛过程。
原则六:示例驱动
提供正常、边界和异常示例可以显著降低误解。EMA 示例可以写成:输入 [100, 101, 102, 101, 100],period=3,alpha=2/(3+1)=0.5,输出依次为 [100, 100.5, 101.25, 101.125, 100.5625]。这个例子同时表达初始化方式、递推公式和预期数值。
原则七:上下文管理
大项目需要提供足够上下文,但不能把所有代码一次性塞给 AI。更有效的上下文包括:
- 技术栈:Python 3.10、PyQt6、SQLite 或其他实际栈。
- 已有文件:
core/data.py定义BarData,core/indicators.py定义指标基类。 - 架构约束:所有指标必须继承
IncrementalIndicator。 - 当前任务:实现
IncrementalEMA或IncrementalRSI。
一个完整 prompt 可以组织成这样:
角色:量化交易系统开发专家,有 8 年 Python 高性能计算经验。
任务:实现增量 EMA 计算器。
背景:
- 已有 IncrementalIndicator 基类。
- 用于实时行情推送场景,每次收到新 bar 时增量更新。
- EMA 公式为 EMA(today) = alpha * price + (1 - alpha) * EMA(yesterday)。
约束:
1. 继承 IncrementalIndicator。
2. 第一根 bar 返回 price,后续使用 EMA 公式。
3. 内存 O(1),不存储历史数组。
4. 包含类型注解、docstring 和单元测试。
示例:
输入 [100, 101, 102, 101, 100],period=3。
输出 [100, 100.5, 101.25, 101.125, 100.5625]。
实现前先提出 2-3 个需要澄清的问题。
第四部分:AI 辅助的边界与策略
AI 可以进入很多工程环节,但不同环节的签收权不能混在一起。
AI 比较擅长的任务包括:样板代码、数据类、配置解析、日志、重命名、提取函数、格式化、给定函数的单元测试、复杂代码解释、docstring 和 README 初稿。这些任务边界清晰,输出容易验证。
AI 可以承担候选实现但必须人工 Review 的任务包括:有明确规格的具体功能、复现步骤清楚的简单 Bug 修复、目标数据明确的性能优化。这类任务需要测试和审查才能进入主干。
AI 不适合直接主导的任务包括:核心架构设计、需求分析、复杂调试和技术选型。原因不是 AI 不能给出建议,而是它缺少业务上下文、团队约束、历史债务、上线风险和长期维护成本的真实感知。
人机分工可以落在下面这张表:
| 环节 | 主导方 | AI 的作用 | 人的责任 |
|---|---|---|---|
| 需求分析 | 人 | 提出澄清问题、整理规格草案 | 确认业务语义和优先级 |
| 架构设计 | 人 | 提供候选方案和风险清单 | 选择边界、接受代价 |
| 规格编写 | 人 + AI | 草拟 user story、验收标准、约束 | 签收可验收语义 |
| 代码实现 | AI 可主导 | 生成候选代码 | Review、测试、合并 |
| 测试编写 | AI 可主导 | 扩展测试用例 | 判断断言是否代表真实风险 |
| 文档维护 | AI 可主导 | 生成初稿和变更说明 | 确认文档不误导维护者 |
这套分工的底线是:AI 可以产生候选,但不能独立签收语义风险。
边界策略还需要落到日常 Code Review。评审清单可以要求:AI 生成代码是否标注来源和约束,是否有对应规格,是否有边界测试,是否有性能证据,是否有人工签收的业务语义,是否有回滚路径。这样做不是为了排斥 AI,而是让 AI 产出和人工代码遵守同一套工程纪律。
第五部分:用 AI 重构遗留代码
AI 辅助重构最适合从边界清晰、风险可控的遗留模块开始。典型场景是一个 2000 行的 chart_widget.py 同时混杂数据获取、图表渲染和用户交互。随着功能增加,这个文件会成为修改禁区:改一个指标展示可能影响数据加载,改一个交互事件可能触发渲染回归。
第一步是让 AI 分析现状,但输入必须要求结构化输出:
- 违反单一职责的位置。
- 循环依赖。
- 难以测试的部分。
- 重构优先级。
- 每个问题对应的位置、描述、建议方案和优先级。
如果 AI 只输出“建议拆分模块”,价值很低;如果它能指出数据访问、渲染状态、用户交互和事件订阅之间的耦合点,后续才有可执行入口。
第二步是让 AI 设计新架构。约束必须包括:
- 不改变外部接口,保持向后兼容。
- 每一层可以独立测试。
- 使用观察者模式解耦数据变化和 UI 更新。
- 支持未来增加新图表类型。
- 输出文件组织建议、关键类定义和数据流说明。
第三步是让 AI 生成迁移计划。计划需要分阶段迁移,每个阶段可独立运行,每个阶段有对应测试,并且写清工作量、依赖关系和回滚策略。AI 可能生成四个阶段,团队可以根据实际风险调整为三阶段;关键不是阶段数,而是每个阶段都能独立验证。
第四步是逐阶段实现。每个阶段都应遵循同一节奏:AI 根据规格生成候选代码,人工 Review,运行测试,修复问题,再进入下一阶段。
第五步是验证。完整测试套件至少证明三件事:新旧版本功能输出一致,性能没有劣化,代码覆盖率达到约定阈值。
遗留代码重构尤其需要限制 AI 的修改半径。一次重构如果同时改文件结构、改事件模型、改渲染逻辑、改数据访问和改 UI 交互,Review 会很难判断哪个变化引入了风险。更稳妥的方式是先抽接口,保留旧路径;再让新路径和旧路径并行输出;然后用测试和用户场景确认一致;最后移除旧链路。AI 可以生成迁移步骤,但每一步是否可回滚、是否能保留旧行为,仍然需要人工判断。
重构结果可以用数据表达:
- 代码从 2000 行单文件,变成 3 个文件约 1500 行。
- 测试覆盖率从约 30% 提升到约 80%。
- 修改响应时间从“改一处需要 2 天”下降到“改一处需要 2 小时”。
- 更重要的是,团队成员重新敢于维护这个模块。
这说明 AI 辅助重构的目标不是让目录结构看起来更漂亮,而是降低维护者同时记住的上下文数量。数据层、渲染层和控制层拆开以后,测试、审查和性能定位都有了更明确的入口。
第六部分:BMAD-Speckit-SDD-Flow——把实践沉淀成受治理的交付流
前面讨论的是方法,真正落地时还会遇到更细的工程问题:规格写了,但实现入口怎么判断 ready;多 Agent 启动了,但谁决定下一条全局路径;审查做了,但失败是否真的能阻断;测试跑了,但证据是否能回到看板、评分和训练数据。这些问题在量化交易系统的 AI 工程化交付中反复出现,尤其是在交易日历、指标重构、图表性能、测试补全和遗留代码拆分这些任务上,会不断暴露“流程能跑,但治理不闭环”的风险。
BMAD-Speckit-SDD-Flow 就是在这类实践中沉淀出来的开源项目。它基于 BMAD-METHOD 与 Spec Kit 构建,把需求规范、审计流程、运行监控和评分反馈整合成一条完整交付链路。它不是再发明一个 prompt 模板,而是把 specify -> plan -> audit -> readiness gate -> runtime governance -> close-out 固化为可安装、可检查、可观测的工程面。
从技术架构看,这个项目可以理解为五层交付架构:
| 层级 | 关注点 | 对量化交易系统的意义 |
|---|---|---|
| Product Def | 产品定义和业务语义 | 交易日归属、半日市、风控边界先被定义清楚 |
| Epic Planning | 史诗和跨模块计划 | 分层数据、回测实盘统一接口、图表性能分阶段拆解 |
| Story Dev | Story 生命周期 | 每个故事都有规格、任务、测试和验收路径 |
| Technical Implementation | 技术实现 | 子代理只能执行 bounded packet,不擅自改变全局路线 |
| Finish | 收口与证据 | 通过、需修复、阻塞、重跑都会进入执行记录和看板 |
这套架构的关键不是层级名称,而是把“进入实现之前”和“实现结束之后”都纳入治理。很多 AI 工程流只关注中间那段代码生成,真正出问题的往往是两端:前面没有 ready baseline,后面没有 close-out 证据。
从模块角度看,项目提供了几类核心组件:
_bmad/:工作流模块、钩子、提示词、路由和宿主侧资产的规范源。packages/scoring/:评分引擎、就绪漂移评估、看板投影、诊断输入和训练数据提取。dashboard:默认运行时可观测层,用于查看运行时状态、快照和评分投影。runtime-mcp:可选 MCP 工具接口,只有需要把运行时数据暴露给 Agent 工具面时才启用。speckit-workflow:覆盖 Specify、Plan、GAPS、Tasks、TDD,并带强制审计循环。bmad-story-assistant、bmad-bug-assistant、bmad-standalone-tasks:分别服务 Story、Bug 和独立任务路径,但全局路线仍由主 Agent 读取inspect后决定。
它重点治理五类常见 AI coding failure modes。
第一类是 requirement hallucination。AI 很容易在需求不完整时自行补全业务语义,例如默认自然日就是交易日、默认半日市没有夜盘、默认缺失数据可以填充。交易系统里,这类“看似合理的补全”会直接污染指标和回测。BMAD-Speckit-SDD-Flow 用 Specify、Clarify、GAPS 和 Cross-Document Traceability 把需求、澄清问题、假设和任务绑定起来。没有被规格和澄清记录承接的语义,不能直接变成实现。
第二类是 implementation drift。即使初始规格正确,Agent 在实现过程中也可能逐步偏离原始约束:为了让测试通过改了接口,为了简化代码绕过性能预算,为了赶进度把回测和实盘写成两套逻辑。项目用 story packet、bounded task、主 Agent inspect 和任务级 traceability 控制实现半径。子代理只执行被授权的 packet,不决定全局路线;实现结果必须回到规格、任务、测试和证据链,而不是只看代码是否能运行。
第三类是 pseudo-implementation without E2E integration evidence。这是最隐蔽的一类失败:代码、单元测试和文档都存在,但没有端到端集成证据,功能没有真正接入真实路径。量化系统里常见表现是聚合器单测通过,但 UI、数据导入、回测引擎和实盘监控没有共用同一语义。项目引入 Smoke E2E Readiness 和 Evidence Proof Chain,要求关键路径有最小冒烟场景、证据链和验收记录。没有 E2E 接入证据的实现,只能视为候选实现,不能视为交付完成。
第四类是 one-pass execution without critical iterative reasoning。一次性执行通常会把设计、实现、测试、修复和收口压成一轮,缺少批判性迭代。AI 可能第一轮给出可运行方案,但没有经历 Reviewer 的反例、Tester 的边界样本和重新设计。项目把审计循环、required-fixes、blocked、rerun 和 scoring 作为流程的一部分,让失败不被吞掉。对 RSI 初始化、半日市归属、性能预算这类问题,必须允许流程回退到澄清、计划或实现阶段,而不是一轮跑完就关闭。
第五类是 premature closure without reviewable delivery artifacts。很多 AI 交付会在“代码已改、测试已跑”后过早结束,但后续维护者看不到规格、决策、失败修复、E2E 证据和收口结论。项目把 close-out、packet execution truth、dashboard、coach 和 SFT extraction 串起来,让 pass、required-fixes、blocked、rerun 等结果变成可复查资产。对长期维护的交易系统来说,这意味着失败样本、修复过程、审计结论和最终证据可以服务下一轮诊断,而不是散落在聊天记录、终端输出和个人记忆里。
一个可落地的使用方式是先从消费项目安装,而不是直接改框架源码:
npx --yes --package bmad-speckit-sdd-flow@latest bmad-speckit version
npx --yes --package bmad-speckit-sdd-flow@latest bmad-speckit-init . --agent codex --full --no-package-json
npx --yes --package bmad-speckit-sdd-flow@latest bmad-speckit check
npx --yes --package bmad-speckit-sdd-flow@latest bmad-speckit dashboard-status
这类工具最适合用于高风险、长链路、证据要求高的交付场景,例如交易日历、撮合引擎、指标重构、回测实盘统一接口、风控状态机和性能治理。对普通小修复,它可能显得偏重;对真实资金风险、多人协作和长期维护来说,强制规格、审计、就绪、运行时管控和证据收口反而能降低长期成本。
总结:AI 工程化的三个核心原则
第一,规格先行。AI 需要约束,规格就是最有效的约束。花 30 分钟写清楚交易日、半日市、数据断层和验收标准,通常能省下数小时返工。
第二,多 Agent 协作。单一 AI 容易陷入局部最优。BMAD 的 Architect、Implementer、Reviewer、Tester、Documenter 可以从架构、实现、审查、测试和文档五个角度降低盲区。
第三,人机分工。AI 做候选、扩展和整理,人负责语义、风险和签收。交易系统面对的是真实行情、真实资金和长期维护,任何 AI 输出都必须经过规格、测试、审查和证据闭环。
工具与资源
开源项目入口:
- GitHub Spec Kit:GitHub 开源的 Spec-Driven Development 工具包,用于把产品场景、规格和实现入口连接起来。
- BMAD-METHOD:开源 Agile AI-driven Development 方法和模块生态,用角色化 Agent 与工作流强化协作质量。
- BMAD-Speckit-SDD-Flow:基于 BMAD-METHOD 与 Spec Kit 的治理型 SDD 交付流,提供运行时管控、强制审计、看板和 npm 安装路径。
speckit 命令可以按功能组织:/speckit.specify <feature-name> 创建规格,/speckit.clarify <decision-topic> 记录技术决策,/speckit.plan 生成实现计划,/speckit.checklist 做验收检查。
BMAD Agent 可以按角色激活:/bmad-agent-bmm-architect 用于架构方案,/bmad-agent-bmm-dev 用于候选实现,/bmad-agent-bmm-qa 用于测试和质量检查。
常见工具包括 Cursor AI 编辑器、Claude Code CLI、Codex、speckit 规格模板、BMAD 多 Agent 工作流和 bmad-speckit-sdd-flow。工具本身不是重点,重点是每个输出都要进入规格、测试、审查、运行时管控和验收证据。
系列收束
AI 工程化是本系列的能力增强层。前面的系统边界、真实缺陷、测试防线、性能治理和架构演进,最终都需要交付流程承接。读者回到自己的系统时,可以先从一个最小闭环开始:选一个语义风险明确的功能,写清规格和澄清决策,拆计划,生成候选实现,补测试和文档,再用质量门禁签收。
如果 AI 让代码变快,却让证据变少,系统风险会上升。如果 AI 让规格、测试、审查和文档都变得更可追踪,它才真正进入了工程化。
Series context
你正在阅读:量化交易系统开发实录
当前为第 7 / 7 篇。阅读进度只写入此浏览器的 localStorage,用于回到系列页时定位继续阅读入口。
Series Path
当前系列章节
点击章节会在此浏览器记录本地阅读进度;刷新后可继续阅读。
- 量化交易系统开发实录(一):项目启动与架构设计的五个关键决策 以 Micang Trader 为案例,从系统边界、数据流、交易时段归属、回测实盘统一接口和 AI 协作边界出发,建立整个量化交易系统系列的架构主线。
- 量化交易系统开发实录(二):Python Pitfalls 实战避坑指南(上) 把 Python 陷阱从长清单重组为量化交易系统的工程风险参考篇:语法与作用域、类型与状态、并发与状态三类风险如何放大为真实交易系统问题。
- 量化交易系统开发实录(三):Python Pitfalls 实战避坑指南(下) 继续把 Python 风险重组为参考篇:GUI 生命周期、异步网络失败、安全边界和部署基础设施如何影响量化交易系统的长期稳定性。
- 量化交易系统开发实录(四):测试驱动敏捷开发(AI Agent 辅助) 从一个跨夜交易日边界 bug 出发,重构量化交易系统的测试防线:缺陷导向测试金字塔、AI TDD 分工、边界时间、数据血缘和 CI Gate。
- 量化交易系统开发实录(五):Python 性能调优实战 把性能优化从经验猜测改造成可验证的侦查流程:从 3 秒图表延迟出发,定位真实瓶颈,比较优化方案,建立 benchmark 与回退策略。
- 量化交易系统开发实录(六):架构演进与重构决策 复盘 Micang Trader 的五次重构,解释系统如何从初始快照演进为更清晰的目标架构,并把技术债务和 ADR 决策纳入长期治理。
- 量化交易系统开发实录(七):AI 工程化落地——从 speckit 到 BMAD 以交易日历与日线聚合需求为单一案例,解释 AI 工程化如何通过规格驱动、BMAD 角色交接和人工质量门禁进入真实量化系统交付。
Reading path
继续沿这条专题路径阅读
按推荐顺序继续阅读 量化系统开发实战 相关内容,而不是只看同专题的随机文章。
Next step
继续深入这个专题
如果这篇内容对你有帮助,下一步可以回到专题页继续系统阅读,或者订阅后续更新。
正在加载评论...
评论与讨论
使用 GitHub 账号登录参与讨论,评论将同步至 GitHub Discussions