跳到主要内容

ADR-014 — 实现语言与核心运行时技术栈(Python 追认 + 多语言演进触发器与兜底)

草案(M0 L8 整改期补治理洞)。 起因:owner 发现整个架构与工程化落地默认采纳 Python 却从未留下选型评估痕迹——这是"文档理据洞",不是"实质未决"(选择早已做出且 M0 已跑在其上)。本 ADR 不是重新选型 bake-off,而是:① 追认已成事实的核心语言;② 把"何时必须重新评估、如何让未来多语言化保持线性成本"钉死,回应 owner 关切——改造不能拖到成本指数化才做

§0 决策简述

  1. 核心运行时语言 = Python 3.13(追认):FinBayes 认知/编排 spine 用 Python(+ uv / ruff / pytest / Pydantic v2 / asyncio / SQLite)。
  2. 只锁 spine,不锁全栈:客户端层、性能敏感模块、规模化数据层显式不锁定 Python(部署形态另归 arch-rewrite/ADR-006 待写)。
  3. 多语言以"边界抽取"演进,非"整体重写":未来引入 TS/Rust/Go 时,从干净边界抽取单个组件,Python 始终是认知 spine——把改造成本结构性地压成线性而非指数。
  4. 现在就钉死重评估触发器 + 里程碑兜底(§3):保证"按需触发"可执行,且有硬兜底防无限推迟到"太晚"。

§1 上下文与取证

  • 语言一直是隐式默认:architecture.md 通篇假定 Python(asyncio §12、src layout §27、Pydantic 数据对象、click/typer CLI、SQLite binding、keyring),M0 代码已全在 Python、60 测试绿。
  • 既有 ADR 都不覆盖语言选型ADR-003 工程实施栈与协作讲的是 OpenSpec+Archon+Claude/Codex 工具/协作栈;arch-rewrite/ADR-005(待写)是 Python 内部并发原语;arch-rewrite/ADR-006(待写)是部署形态无任何 ADR 评估"为何 Python 而非 TS/Rust/Go"
  • owner 关切(2026-05-30):后续需在合适阶段做更全面的语言/栈评估(Python→TS?性能敏感模块 Rust/Go?),可按需触发,但不能太晚,避免改造成本指数增大。本 ADR 即为此关切提供机制。

§2 决策

D1 · 核心运行时语言 = Python 3.13(追认,低后悔)

理据:

  • 领域强绑定:FinBayes 是 LLM 认知层,Python 是 LLM 生态母语——provider SDK、Pydantic 结构化输出、eval/ML 工具链全 Python-first,换语言是逆生态。
  • 已落地无沉没成本理由:M0 已跑通,现在换=扔可用代码换零 M0 价值。
  • 无性能热点:当前无逼迫上 Rust/Go 的算力瓶颈。

D2 · 锁定范围(只锁 spine)

部分是否锁 Python归属
核心认知 / 任务编排 / 状态管理 runtime(本 ADR)本 ADR
客户端 / 前端层不锁(未来可 TS)触发后另评(§3)
性能敏感模块不锁(未来可 Rust/Go)触发后另评(§3)
规模化数据层不锁(SQLite → ? 按规模)部署形态 arch-rewrite/ADR-006

D3 · 成本遏制设计规则(现在就做的便宜保险)

要让未来抽取保持线性,现在零成本/低成本做两件事:

  • 容器边界 contract 保持可序列化:子系统间接口的数据对象(Pydantic)设计上对 JSON/protobuf 友好,使任一边界未来可升级为跨进程/跨语言序列化边界,无需重构内部。
  • 热点逻辑隔离在接口后:任何潜在性能敏感逻辑收口到清晰接口,便于将来整块抽走换语言,不与编排逻辑缠绕。

这是回应"成本指数化"的结构性答案:永远不"迁移整个系统",只在干净边界"抽取单个组件",成本随组件数线性增长。

D4 · 多语言演进方式 = 边界抽取,不整体重写

  • Python 永远是认知 / 编排 spine。
  • TS 若进入,进客户端层(加法,Python 后端 + TS 前端是常规组合,非迁移)。
  • Rust/Go 若进入,进隔离的性能模块(PyO3 扩展 或 sidecar 服务),只换该模块。

§3 重评估触发器 + 兜底("不能太晚"的硬保证)

事件型触发器(leading indicators,早响应而非滞后)

任一触发即启动对应范围的深度评估(非全栈,仅触发范围):

#触发条件(可观测、前瞻)评估范围
T1产品从 CLI 走向真实 GUI/Web 客户端客户端层选 TS / 其他
T2某模块实测 perf 不达 SLO,且 profiler 把瓶颈归因到语言/运行时(非算法/IO)该模块抽取为 Rust/Go
T3多用户并发下 GIL / 单线程事件循环成可测瓶颈并发模型 / 服务化 / 局部换语言
T4关键能力只在他栈生态存在(Python 无对等)该能力模块选型

里程碑兜底检查点(防无限推迟)

在 M2 规模化 / 首次多用户部署之前,无论上述触发器是否已响,强制做一次"技术栈适配性 review"——这是"不能太晚"的硬兜底:把语言/栈问题在成本仍线性的最晚安全点强制摆上台面,不允许默默拖过。

设计意图:触发器负责"该早就早",兜底检查点负责"再晚不能晚过 M2 规模化前"。两者合起来杜绝"拖到代码全耦合才发现要改"。

§4 与相邻决议关系

  • ADR-003 工程实施栈与协作:工具/协作栈(OpenSpec+Archon+Claude/Codex),与本 ADR(实现语言)正交。
  • arch-rewrite/ADR-005(待写):Python 内部并发原语(asyncio),是本 ADR D1 之下的细化。
  • arch-rewrite/ADR-006(待写):部署形态(本地/远程/混合),承接本 ADR D2 中"规模化数据层 / 服务化"。
  • ADR-008 LLM Provider 接口抽象:provider 适配已是清晰边界,符合 D3 边界抽取原则。

§5 留待触发时深评(本 ADR 不现在定)

  1. 各模块的具体 perf SLO 阈值(T2/T3 判定线)。
  2. 跨语言边界序列化格式(JSON vs protobuf vs gRPC)。
  3. TS / Rust / Go 之间的具体选型(触发时按场景 bake-off)。
  4. 服务化拆分粒度(与 arch-rewrite/ADR-006 部署形态合并评估)。

§6 变更记录

  • 2026-05-30(草案):补语言选型治理洞——追认 Python core spine + 成本遏制设计规则 + 多语言边界抽取演进 + 重评估触发器 T1–T4 + M2 前里程碑兜底检查点。回应 owner"按需触发但不能太晚"关切。
  • 2026-05-31(accepted):owner 签字。Python 核心 spine 追认生效;TS/Go 按 T1–T4 触发 + M2 前强制复审引入,非现在 bake-off。ADR-005(asyncio 并发)作为本 ADR D1 之下的细化同步 accepted。