当构建不再昂贵
——AI 编程、应用系统的重构,与人的新位置
引子:一个人放下了笔
2026 年 8 月,Ruby on Rails 的创造者、37signals 的 CTO David Heinemeier Hansson 第二次坐进 Lex Fridman 的播客,聊了五个多小时。他带去一台预装了自己写的 Linux 发行版 Omarchy 的 Dell 笔记本,当作送给 Lex 的生日礼物,现场演示了从开机到进入桌面不到一分钟的安装过程。
共 73 篇文章
2026 年 8 月,Ruby on Rails 的创造者、37signals 的 CTO David Heinemeier Hansson 第二次坐进 Lex Fridman 的播客,聊了五个多小时。他带去一台预装了自己写的 Linux 发行版 Omarchy 的 Dell 笔记本,当作送给 Lex 的生日礼物,现场演示了从开机到进入桌面不到一分钟的安装过程。
你每天在写的 form、list、kanban 视图,聊天、设置中心的每一个面板,底层都是一个个 Owl 组件。组件就是一段自带逻辑和 HTML 模板、可以嵌套复用的界面单位。Owl 是 Odoo 自研的前端组件框架。Odoo 不用 React 或 Vue,是因为 ERP 前端有自己的口味:极小的包体,XML 模板(和后端 QWeb 视图一脉相承),精细的局部更新:一个几万行的表单里改一个字段,只重画那一小块。
写 Odoo 代码时,最多的两件事是:这个模型上有哪些字段,和这个方法是谁加进来的。普通 Python 工具对这两件事一无所知 —— 因为 Odoo 的扩展模型不是直接通过Python类继承获得的,而是运行时拼出来的。我们在扩展模型中无法定位被扩展模型上定义的变量和方法。
Odoo 的模型是运行时拼装出来的:一个模型由多个 addon 通过 _inherit 不断扩展,最后在 registry 里合成。这带来一个副作用——静态类型检查器看不见它。
Python 的类型检查器(Pyright、mypy)靠继承关系推断类型。但 Odoo 扩展模型并不靠 Python 继承:
class CrmLead(models.Model):
_inherit = "crm.lead"
@api.model
def attach_source(self, partner_id: int, source: str) -> None:
...
在检查器眼里,env["crm.lead"] 的类型永远是 BaseModel:它不知道这个模型上还有什么方法。
于是你想调用别处加进来的方法时,编辑器只能这样报错:
class ResPartner(models.Model):
_inherit = "res.partner"
def action_mark_referral(self) -> None:
leads = self.env["crm.lead"]
leads.attach_source(partner_id=self.id, source="referral")
# Pyright: Cannot access member "attach_source" for type "BaseModel"
⚠️ 关键在这条报错的含义:它不是说方法不存在,而是检查器不知道这个模型上有什么。
于是你既得不到补全,也得不到校验——写错参数名、传错类型,它都不会提醒你,只能整段 # type: ignore 掉。
如果你想再进一步,用 Protocol 去约束"服务层需要的模型接口",也同样做不到:检查器无法确认运行期拿到的模型实例真的满足那个接口。
Odoo 20 发布后,官方宣传里 AI 占了很大篇幅。营销归营销,我们把 20.0 的源码翻了一遍,对照 19.0,从代码层面看 AI 到底变了什么。先说清楚取材范围:社区版(odoo/odoo)两个大版本里都没有 ai 模块,产品化的 AI 功能几乎全部在企业版(odoo/enterprise)。所以本文的主战场是企业版,社区版只讲框架层的配套变化。
本文的 20 条新特性来自 Odoo 官方在 2026 年 4 月 2 日 Partner Days 上发布的 Odoo 20 路线图。发布节奏如下,新版本将在 9 月 24-26 日的 Odoo Experience 布鲁塞尔大会 期间正式发布。
api.one api.multi 已淘汰首先需要澄清,随着当前最新的Odoo版本V13.0发布以后。 api.one 和 api.multi 作为Odoo的实体类方法的装饰器的用法已经淘汰。在V13.0以后的Odoo版本中使用这两个装饰器,系统会报错。 很多人会说,你这不是闲得没事干吗?讨论一个已经淘汰的语法应用有什么意义呢?其实,这些语法虽然被淘汰了,但是要知道最新版本的Odoo的实体类方法默认就是工作在过去 api.multi 这种模式下,而 api.model 也继续在工作。所以,我们对这些淘汰语法的讨论可以加深对当前新语法的认识。
按照商业授权的不同Odoo的版本可分为:“社区版”和“企业版”。社区版提供了Odoo的整体框架和核心功能,企业版以社区版为核心提供一系列的企业专属增强模块来扩展社区版的功能并包含企业专属服务。社区版的代码公开发布在Github上: http://www.github.com/odoo/odoo ,可自由获取。企业版的代码在获得商业授权后,由Odoo公司或Odoo授权合作伙伴提供。根据Odoo官方的说明,为确保Odoo开源社区版本的竞争力,其在社区版和企业版的研发投入比例是80%之于20%。 下图说明了社区版和企业版的区别:
在模块开发中,我们往往会引入第三方的python模块。比如当我们在对业务数据做统计分析时,可能会用到pandas Python函数库。在开发者这边我们可以安装pandas包,然后就可以在Odoo模块代码中导入pandas包中的函数,类等:
在Odoo模块开发时,每一次的python代码的更改都要进行Odoo服务的重启。下面介绍一个小技巧用来代替频繁的在命令行下ctrl+c 手工重启.