Contextile

宣言 · v0.1 草案 · 2026-07

AI‑friendly
Architecture

为 AI 的认知边界设计的生产架构。

解决从产品原型到生产级应用的最后一公里。

阅读宣言 5 分钟上手

摘要

AI 已经能写出正确的代码,但软件交付并没有因此变快——因为 AI 仍在为人类协作而设计的架构上工作。本文提出一种面向 AI 认知边界的架构模式:应用被拆解为页面,页面由相互独立的组件构成,每个组件由一段前端代码和一个专属后端函数组成,小到可以被完整装进模型的上下文窗口;页面由配置驱动的渲染框架动态组装。在这套架构上,AI 可以独立完成开发、部署与端到端验证,人从方案的产出者转变为方案的审核者。本文同时给出这套架构的开放标准草案(第十二章),任何团队都可以用自己的基础设施实现它。

目录
  1. 引言最后一公里
  2. 01痛点
  3. 02根因
  4. 03方案
  5. 04组件化
  6. 05FaaS
  7. 06复用上移
  8. 07AIRS
  9. 08基建
  10. 09完整旅程
  11. 10组织
  12. 11弊端与回应
  13. 12架构标准
  14. 13产品迭代
  15. 结语一起来定义
引言

最后一公里

过去两年,AI 生成代码的能力以肉眼可见的速度逼近甚至超过人类工程师。但一个尴尬的事实是:大多数团队的软件交付并没有变快。

产品经理用 AI 十分钟做出了以假乱真的产品原型,然后呢?然后这个原型被截图、被贴进需求文档、被排进下个双周迭代,由工程师在一个百万行的代码仓库里重新实现一遍。AI 在十分钟内完成的事情,组织需要一个月才能把它送到用户面前。

这就是「最后一公里」问题:从产品原型到生产级应用之间,隔着整个传统研发体系。

本宣言的三个主张:

  1. 问题不在模型,在架构。AI 很强,但它在为另一个时代设计的架构上工作。
  2. 存在一种为 AI 认知边界设计的架构,它能让 AI 独立完成开发、部署与验证的完整闭环。
  3. 这种架构可以被定义为一套开放标准,与任何公司的具体基础设施解耦。
01

痛点:AI 很强,交付没有变快

对产品经理而言:AI 生成产品原型已经不是问题,但从产品原型到可上线的应用,仍然需要技术团队介入。原型做得越快,等待排期的落差就越刺眼。

对工程师而言:AI 生成代码已经不是问题,但联调、测试、部署、验证仍需人工介入。Coding 往往只占一个研发周期 20% 的时间,AI 把这 20% 压缩到极致之后,剩下 80% 的流程成本纹丝不动。

对组织而言:AI 作为效率工具确实让产品、技术各自提效了,但组织形态没有改变——还是同样的角色分工、同样的协作链路、同样的迭代周期。最终的产能未见明显提升。

三个痛点指向同一个根因。

02

根因:架构在为另一种成本函数优化

AI 很强,但仍在传统人类的技术架构上 Coding,无法充分释放 AI 的潜能。

当下最主流的系统架构是微服务架构:一个逻辑应用由一系列微服务构成,每个微服务有独立的代码仓库,独立开发、部署、运维。它有两个与 AI 天然冲突的特征。

第一,代码仓库对 AI 来说仍然过大。 微服务虽然把庞大的应用拆成了若干「微」服务,但每个微服务的仓库仍有几万到几十万行。这对 AI 造成了很高的认知负载:它必须先在海量代码里检索、猜测、拼凑出与本次需求相关的上下文,才能开始工作。检索会遗漏,猜测会出错,所以 AI 改代码仍有相当比例的错误,仍需人类工程师兜底。今天业界的主流补救方案——更强的代码检索、更大的上下文窗口、仓库级索引——都是在为「装不下」打补丁。

第二,传统架构面向人类优化,而不是面向 AI。 传统架构强调复用性与可读性:系统要分层,越往下层越通用;每层之间定义不同的数据模型(DO、DTO、BO……),层与层之间的数据交换产生大量核心逻辑之外的胶水代码。这些设计在它的时代完全正确——因为一套系统最大的成本是工程师的人力成本,复用和规范能减少重复劳动、对抗人员流动。但代价是代码仓库无限膨胀,以及理解任何一个功能都需要跨越多层、多仓库的上下文。

一句话概括:架构是成本函数的影子。

人力昂贵的时代,我们发明了复用、分层、DRY,用「读懂成本」换「重写成本」。而 AI 时代的成本函数反转了:生成代码的边际成本趋近于零,真正稀缺的资源是单次任务所需的上下文。当成本函数变了,架构的优化目标就该变:

传统架构 AI-friendly 架构
稀缺资源 工程师人力 模型的有效上下文
优化目标 减少重复劳动(复用、分层) 减少单次任务的认知负载(边界、自包含)
重复代码 罪恶(DRY) 可接受的成本
跨模块耦合 可管理的代价 头号债务
交付单元 应用 / 服务 组件

这个判断不必停留在推演——它可以被测量。为此我们构建了公开基准 Contextile-Bench:同一个 Coding Agent、同一组产品需求、黑盒评分,分别在共享分层的传统架构与组件自包含的 Contextile 上完成同样的任务,并把应用规模从 S 一路放大到 L。

First-pass success as the application scales Contextile-Bench · corrected pass@1 · 24–32 runs per point 90 95 100% S ≈ 2–3k lines M ≈ 4–9k lines L ≈ 136–186k lines 100% 96.9% 95.8% 93.8% Contextile 100% Baseline 91.7% Y axis starts at 88%. Baseline = conventional shared-layer architecture. Line counts are authored code + docs per arm.
图:Contextile-Bench 缩放实验的修正后一次通过率。每个点覆盖该规模下的全部运行(24–32 次);应用体量从 S 的两三千行扩到 L 的 13.6 万–18.6 万行。原始评分、修正账本与分析代码见基准仓库。

实验结果画出了一条清晰的分界线。在万行以内的小仓库上,两种架构不相上下——无论代码怎么组织,Agent 的一次通过率都在 93% 以上。而当仓库跨过 10 万行,走势分化了:传统架构的一次通过率随规模一路下滑(100% → 96.9% → 91.7%),Contextile 则在最大的 L 规模上保持全对(24/24)。

解决之道不是让 AI 学会在百万行仓库里游泳,而是把海拆成鱼缸

03

方案:AI-friendly Architecture

3.1核心模型:应用 → 页面 → 组件

这套架构的设计理念:一个应用由若干个页面构成,每个页面由若干个组件构成,不再有「应用」这个部署概念。组件是最小的开发、部署、运维单元,组件之间相互独立——可以把组件理解为一个更小粒度的应用。

每个组件包含两部分:

  • 一段前端代码:负责渲染组件,开发完成后直接发布到 CDN;
  • 一个专属后端函数:专门为这个组件提供动态数据,部署为 FaaS 服务。

前端组件与后端函数是一对一的组合关系:一个函数只服务于一个组件。

一个页面(pageId)页面渲染框架通用壳层:配置解析 · 组件加载 · 数据编排 · 事件总线 · 降级组件 A前端(ESM)组件 B前端(ESM)组件 C前端(ESM)1:11:11:1函数 A函数 B函数 C← FaaS领域服务 / 存量接口经 AIRS 检索,原生调用

3.2页面渲染框架

页面不再是被「构建」出来的产物,而是被「配置」出来的运行时组装结果。

用户访问固定的页面 URL,URL 中携带 pageId。页面渲染框架根据 pageId 向页面配置服务查询该页面的配置——配置声明了这个页面由哪些组件构成、每个组件的前端代码地址、后端函数标识。框架并行加载所有组件代码、并行请求所有组件函数获取初始数据,数据到达即渲染,组件之间互不阻塞。

浏览器页面渲染框架基础设施访问 /p?pageId=product-detailgetPage(pageId)页面配置服务页面配置(组件清单)并行 ×NCDN:加载组件 ESM并行 ×NFaaS:请求初始数据逐组件流式渲染数据到达即渲染,互不阻塞,失败组件按配置降级

这带来一个关键性质:发布组件,而不是发布应用。新增或修改一个组件,只需发布该组件的前端产物和函数,再发布一个新的页面配置版本;回滚等于把配置指针切回上一个版本。整个过程不涉及任何「应用级」的构建与部署,也就不存在应用级的发布风险。

3.3七条设计原则

  1. 组件是最小交付单元。开发、部署、运维、回滚都以组件为单位,不再有应用级发布。
  2. 一个组件 = 一段前端 + 一个专属函数。前后端在同一个上下文里被理解和修改,联调消失了——因为「联」的两端本来就在一起。
  3. 全量上下文。组件必须小到能被完整装进模型的上下文窗口,并留出足够的推理余量。这是一条硬约束,也是整套架构的第一性原理。
  4. 上下文完整性优先于复用。允许组件之间重复,禁止组件之间耦合。重复是成本,耦合是债务;AI 把重复的成本打到了地板,却对耦合无能为力。
  5. 页面即配置。页面结构是数据而不是代码,变更页面 = 发布新版本配置,回滚 = 切换版本指针。
  6. 基建对机器可操作。部署、调用、测试、日志查询都必须是 AI 可调用的 API,而不是人类专属的控制台按钮。
  7. 环境是验证的唯一真相。AI 的自测闭环必须落在真实渲染和真实调用上——截图、DOM、控制台、网络请求——而不是模型对自己代码的自我评价。
04

为什么要组件化拆分

组件化是这套架构的核心理念。通过组件化,庞大的应用被拆分成若干独立的小组件,AI 基于组件维度 Coding,无需感知任何庞大的代码仓库。

认知负载的消除。组件本身很小(几百到几千行代码),AI 可以将组件的前后端代码全部加载进上下文。它不需要在数万行的仓库里 grep 本次需求要改的内容,不需要猜测某个函数在别处是否还有调用方,不需要理解五层抽象——它看到的就是全部。在 Contextile-Bench 的主实验中,Agent 就是这样在这套架构上独立承接产品需求的:96 次任务运行,94 次一次通过全部黑盒验收(98%),没有人类兜底。

爆炸半径的封锁。组件的边界就是爆炸半径。一次修改最多毁掉一个组件,而一个组件的故障在页面配置层有明确的降级策略(隐藏、占位、兜底文案)。这道边界在基准里同样看得见:Contextile-Bench 覆盖 S/M/L 三档规模的 80 条实验记录中,传统架构累计出现 8 次「改这里、坏那里」的净回归,Contextile 是 0 次。这让「让 AI 直接改生产代码」从冒险变成了工程上可控的决策。

非技术人员的直接驾驭。当单次变更的复杂度被压缩到「一个组件」的尺度,审核的单元也随之变小:人按组件验收结果即可,不必把整个应用装进脑子。这为没有技术背景的人直接驱动 AI Coding 打开了大门——比如产品经理一人驾驭产品的完整迭代。

05

为什么要 FaaS 化部署

每个组件要获取动态数据,就需要一个专属后端服务为它提供数据。这个专属后端服务由 FaaS 承载非常合适。

我敢说,FaaS 将是 AI 时代最重要的技术基础设施。

FaaS 的核心理念是函数是一等公民:没有应用的概念,每个服务是一个独立的函数,独立开发、独立部署、独立运维。这与「组件是最小交付单元」严丝合缝——组件的后端天然就该是一个函数。

一对一的组合关系带来了决定性的简化:AI 在编写组件函数时,完全不需要考虑系统级的复用性。它不需要设计给未来调用方使用的通用接口,不需要兼容其他场景,只解决当下这个组件的数据需求。函数的职责聚焦到极致,AI 根据组件需求直接产出这个函数是很容易的事。

需要说明的是:本架构对「FaaS」的要求是一份契约而非某个具体产品——凡是能提供「组件专属、可独立部署、可编程调用、带环境隔离」的函数运行时,无论是公有云函数计算、边缘函数、还是自建的轻量容器运行时,都可以实现这份契约(见第十二章 §5)。

06

为什么允许重复——复用的位置变了

「每个组件一个专属函数、组件之间不共享代码」——听到这里,任何受过训练的工程师都会本能地皱眉:这违反 DRY。

但 DRY 是有经济学前提的。重复的真正代价从来不是「多写了一遍」,而是「改的时候要改 N 处、还可能漏改」。当 AI 把「改 N 处」的边际成本压到接近于零(一条指令批量修改所有副本,且每个副本都在各自的小上下文里被正确理解),重复的代价就只剩下存储——而存储不要钱。

反过来,错误抽象的代价在 AI 时代被放大了。一个被五个场景共用的抽象层,是每个 Agent 每次任务都必须装载的上下文税;一次为了「未来可能的复用」而做的过度设计,会让之后每一次修改都要先理解这份设计。Sandi Metz 的名言在 AI 时代更加成立:错误的抽象远比重复昂贵。

所以本架构的主张不是「不要复用」,而是复用上移

  • 代码不复用:组件之间通过复制而非依赖来共享实现。拷贝即所有,改坏了只坏自己。
  • 接口复用:真正沉淀业务能力的地方是领域服务和存量接口,组件函数是它们的轻量编排层(如何让 AI 找到该用的接口,见下一章)。
  • 资产复用:视觉一致性靠设计 tokens、组件模板、脚手架来保证——复用发生在「生成时」而不是「运行时」。

让复用发生在接口和设计资产层,而不是代码层。

07

组件函数的依赖从哪儿来:AIRS

组件函数不生产核心业务逻辑,它编排存量能力:查商品、查库存、查优惠券、下单——这些能力以 HTTP / RPC 接口的形式存在于企业的领域服务中,成千上万。

于是出现了 AI 时代的一个新问题:AI 怎么在海量存量接口中,快速准确地找到当前需求真正该用的那一个?接口文档散落各处、口径腐烂、命名各异,人类工程师靠部落知识和口口相传解决这个问题,AI 没有部落。

为此,本架构定义了一套 AIRS——Agentic Interface Retrieval Specification(AI 编程接口检索规范)

  • 每个接口按统一的元数据标准登记:语义化描述、参数与返回值 Schema、真实调用示例、负责人、SLA、稳定性等级;
  • 提供一个面向 Agent 的检索服务:Agent 用自然语言描述数据需求,检索服务返回排序后的候选接口及其完整契约;
  • AIRS 是研发期设施,不是运行时设施:代码生成并上线后,组件函数仍通过原生 HTTP / RPC 直连目标服务,AIRS 不代理任何线上流量,不引入任何运行时依赖。

与 MCP 的关系:MCP 解决的是「Agent 在运行时如何调用工具」,AIRS 解决的是「Agent 在编码时如何发现存量接口、并生成原生调用代码」。两者互补,作用在软件生命周期的不同阶段。

AIRS 的详细契约见第十二章 §6。

08

配套基础设施:让基建对机器可操作

前几章解决的是 AI 在 Coding 环节的问题。但 Coding 往往只占研发周期 20% 的时间——要让 AI 真正接管交付,就必须把测试、部署这些依赖人力的环节也变成 AI 可以独立操作的接口。

部署接口。基础设施层必须提供组件的程序化部署能力:前端代码发布至 CDN(内容寻址、URL 不可变)、后端代码部署为函数、部署状态可查询且有确定性的成功/失败判据。「确定性判据」不是洁癖:如果部署没有机器可判定的终态(接口调用成功不代表部署成功),自动化调用方就无法可靠区分成功、失败与仍在进行,Agent 的自动化链路会在这里反复翻车。

模拟器。要让 AI 端到端自测,必须给 AI 一个能渲染真实页面的模拟器:加载指定版本的页面配置与组件代码、注入测试身份与参数、真实调用指定环境的函数,返回截图、DOM 结构、控制台日志与网络请求记录。模拟器同时服务两个客户:AI 用它做功能验证(原则七:环境是验证的唯一真相),人用它做审核预览——两者看到的是同一个真实渲染结果。

可观测。每次函数调用携带贯穿式 traceId,日志可按 traceId / 时间范围程序化查询。Agent 排障的闭环是「调用失败 → 查日志 → 定位 → 修复 → 重试」,其中每一步都必须是 API。

环境模型。基础设施必须提供环境隔离语义(至少:开发环境 / 预发环境 / 生产环境),且部署范围与调用白名单是两个独立的控制面——允许自动部署到多环境,不等于允许 Agent 调用任意环境。生产环境的发布必须经过人审门禁。

09

一个需求的完整旅程

以一个通用电商场景走一遍全流程。需求:「在商品详情页增加一个『到手价计算器』组件,展示叠加优惠券后的最终价格。」

  1. 理解页面:Agent 读取 product-detail 的页面配置,了解现有组件清单,确定新组件的插入位置。
  2. 创建组件:按组件标准(§1)生成脚手架——price-calculator/ 目录,含前端入口、函数入口、组件说明文件、测试。
  3. 检索接口:通过 AIRS 检索「查询用户在指定商品上可用的优惠券」,获得候选接口的 Schema 与调用示例,将接口契约快照存入组件目录(上下文自包含)。
  4. 编写代码:前端组件 + 专属函数合计几百行,全量在上下文中一次写就。函数编排优惠券接口与价格接口,前端按设计 tokens 渲染。
  5. 部署开发环境:调用部署接口发布前端产物与函数,轮询部署状态至确定性成功。
  6. 模拟器自测:注入测试用户渲染真实页面,断言截图与 DOM、检查控制台无错误。发现「无可用券」时组件白屏——补上兜底展示,重新部署、重测通过。
  7. 提交人审:产出物 = 代码 diff + 模拟器预览链接 + 自测记录。人审核的是交付物,不是过程。
  8. 发布上线:审核通过后发布新版本页面配置,线上生效。如需回滚,把配置指针切回上一版本即可,秒级完成。

整个旅程中,人只出现在第 7 步。

10

人才与组织的转变

这套架构屏蔽了产品的技术实现细节,通过降低 AI 的认知负载,让「编码、测试、部署交给 AI 独立完成」成为可能。人的注意力从「怎么实现」转向「该做什么」——聚焦产品本身、聚焦用户价值本身。

在这套架构之上,组织所需要的人才画像也发生了变化,我们称之为「AI 产品全栈工程师」

  • 具备产品思维,产品的迭代进化由 TA 一人驱动;
  • 具备基本的技术素养,当 AI 在少数情况下出错时,有能力定位和解决问题;
  • 核心工作是设定方向、审核产出、把控风险——人从方案的产出者,转变为方案的审核者。

组织不再需要把岗位切分得很细(运营、产品、前端、后端、算法、测试、BI、SRE 各司其职),一个产品方向只需一名 AI 产品全栈工程师,借助 Agent 集群推动产品进化。审核的粒度可以随信任度演进:初期逐产出物审核,随着质量数据积累,逐步放权到只审关键节点。

11

弊端、质疑与回应

一个诚实的架构宣言必须直面自己的代价。

1. FaaS 成本会上升。成立。一对一的函数不考虑复用,独立部署运维,机器成本高于传统的共享服务。我们的回应:这是用机器成本置换人力成本与迭代速度,而三者的价格趋势一目了然;同时函数粒度的弹性伸缩(闲时缩容到零)能覆盖大部分长尾组件的成本。

2. 人不再了解实现细节,风险如何控制?成立,且必须严肃对待。整个迭代过程人只关注最终交付物,中间实现交由 AI 完成,可能存在人未察觉的分支缺陷。我们的回应是纵深防御:确定性测试 + 模拟器真实环境验证(不是 LLM 自评)+ 人审门禁 + 组件级爆炸半径 + 秒级配置回滚 + 全链路可观测。信任,但验证。

3. 组件各写各的,视觉和体验会漂移。会,如果什么都不做。所以复用要上移(第六章):设计 tokens 和组件模板在生成时约束视觉,页面框架统一壳层行为,架构标准中的确定性校验(lint 级规则)在部署前拦截越界。

4. N 个函数是不是 N 倍的安全面?函数数量确实变多,但每个函数的权限面变小了。回应:统一的请求信封与网关鉴权、函数最小权限原则、部署门禁中内置静态安全扫描(这些扫描本身也可以是 Agent)、AIRS 登记接口的调用方审计。

5. 这不就是低代码?不是。低代码约束「人」用可视化拼装代替代码,牺牲表达力换取门槛;本架构中代码仍然是全表达力的代码,只是由 AI 来写。被约束的是边界(组件多小、依赖什么),不是表达(能写什么逻辑)。

6. 这不就是微前端 / Server-Driven UI?机制上确有交集(运行时组装、配置驱动),但目标函数不同。微前端解决的是多团队并行与渐进式升级,所以它容忍巨大的子应用;SDUI 解决的是发版灵活性。本架构解决的是 AI 的认知负载,所以它强制小组件、强制前后端 1:1、强制无代码复用——这些约束在前两者的目标下没有必要,在本架构的目标下缺一不可。

7. 复杂业务逻辑和跨组件联动怎么办?架构划定了自己的适用边界,见下。组件间联动通过页面框架的受限事件总线完成(广播语义、可序列化载荷、互不假设对方存在),禁止组件直接依赖。真正的重业务逻辑本来就不该写在组件函数里——它属于领域服务,组件函数只做编排。

8. 既然 Provider 接口(§5)要使用者自行实现,参考实现里的 MCP Server 是做什么的?两者处在依赖倒置的两侧,面向不同的消费者。Provider 接口是面向基建的 SPI,回答「部署、调用、渲染这些动作由谁实现」;MCP Server 是面向 Coding Agent 的 API,回答「Agent 怎么使用这些动作」——它把 Provider 之上的交付工作流编排成少数几个稳定的工具(例如 deploy_component = 发布前端资产 → 部署函数 → 轮询部署状态至确定性终态 → 更新页面配置),自身不实现任何基建。这带来两个结果:其一,§5 的流程纪律(如 MUST NOT 以调用成功推断部署成功)固化在工具实现里,无需每个团队在 Agent 提示词中重新发明;其二,Agent 侧的工具签名与工作流不随基建变化——本地开发时对接参考实现内置的本地 Provider,上生产换成自家适配器,Agent 无感。

适用边界。本架构最适合:C 端展示与营销页面、运营活动、增长实验、内容型页面、数据看板、管理后台——一切「页面结构清晰、迭代频繁、试错价值高」的场景。需要谨慎评估:强事务一致性的核心域(交易、账务、库存扣减本体)、重交互的工具型单页应用(编辑器、IDE)、极致性能敏感场景。我们不主张用它重写你的核心域——它是核心域外围那层需要快速进化的皮肤,而皮肤恰恰是绝大多数产品迭代发生的地方。

12

架构标准(v0.1 草案)

规范文本以 contextile/spec 仓库为准,本章为其阅读快照。 本章是规范性内容。关键词 MUST(必须)/ MUST NOT(禁止)/ SHOULD(应当)/ MAY(可以) 按 RFC 2119 解释。完整规范在独立仓库中以 RFC 流程演进。 一个团队可以只采纳部分标准,合规性分级见 §8。

§0术语

术语 定义
页面(Page) 由 pageId 标识的一次运行时组装结果,结构由页面配置声明
组件(Component) 最小交付单元,= 前端产物 + 专属函数 + 清单文件
组件函数(Component Function) 专属于某一个组件的后端函数,1:1 绑定
页面配置(Page Config) 声明页面组件清单及其装配参数的版本化 JSON 文档
渲染框架(Renderer) 解析页面配置、加载组件、编排数据、处理降级的通用运行时
Provider 基础设施的适配接口(配置、函数、资产、模拟器四类)
数据信封(Envelope) 渲染框架与组件函数之间的标准请求/响应格式

§1组件标准

1.1 目录结构。组件 MUST 是一个自包含目录:

price-calculator/
├── component.json        # 组件清单(见 1.2)
├── CLAUDE.md             # 面向 Agent 的组件说明(见 §7)
├── frontend/
│   ├── index.jsx         # 前端入口,ESM 默认导出
│   └── styles.css        # 作用域隔离的样式
├── backend/
│   ├── handler.ts        # 组件专属函数入口
│   └── apis.md           # 该函数依赖的外部接口契约快照(AIRS 检索结果落档)
└── tests/
    ├── frontend.test.jsx
    └── backend.test.ts

1.2 组件清单。component.json MUST 存在:

{
  "componentId": "price-calculator",
  "name": "到手价计算器",
  "owner": "example-team",
  "frontend": { "entry": "frontend/index.jsx" },
  "backend":  { "entry": "backend/handler.ts", "runtime": "node20" },
  "budget":   { "maxSourceLines": 3000 },
  "test":     { "command": "npm test" }
}

1.3 尺寸预算。组件前后端源码合计 SHOULD ≤ 3,000 行。这个数字是经验值,其背后的硬规则是:组件全量源码装入主流模型上下文后,MUST 仍保留至少一半空间用于推理、对话与工具输出。超出预算的组件 MUST 拆分为多个组件。

1.4 隔离性。

  • 组件 MUST NOT import 其他组件的任何代码;
  • 组件 MUST NOT 读写其他组件的 DOM 或全局状态;
  • 组件间通信 MUST 经由渲染框架的事件总线(§3.4);
  • 样式 MUST 作用域隔离,MUST NOT 使用裸元素选择器或修改 :root
  • 基础运行时(react / react-dom / 设计系统基础包)由渲染框架经 import map 统一提供,组件 MAY 依赖这份白名单,其余依赖 MUST 打包进组件自身产物。

§2页面配置契约

页面配置是一份版本化的 JSON 文档:

{
  "pageId": "product-detail",
  "version": "42",
  "meta": { "title": "商品详情" },
  "components": [
    {
      "componentId": "price-calculator",
      "frontend": {
        "format": "esm",
        "url": "https://assets.example.com/components/price-calculator/42/index.js",
        "integrity": "sha384-…"
      },
      "function": {
        "name": "shop.product-detail.price-calculator",
        "timeoutMs": 3000,
        "required": false
      },
      "props": { "showDiscounts": true },
      "fallback": "hide"
    }
  ]
}

规则:

  • 配置版本 MUST 不可变:发布 = 产生新版本,回滚 = 移动活跃版本指针(§5.1);
  • frontend.url MUST 内容寻址(哈希入路径或文件名),SHOULD 携带子资源完整性校验(integrity);
  • fallback MUST ∈ hide | skeleton | message,声明该组件失败时的降级表现;
  • required: true 的组件失败时,渲染框架 MUST 执行页面级降级策略;required: false 的组件失败 MUST NOT 阻塞其他组件渲染;
  • 渲染框架 MUST 并行发起所有组件的初始取数,逐组件流式渲染。

§3数据契约

3.1 请求信封(渲染框架 → 组件函数):

{
  "page":      { "pageId": "product-detail", "version": "42", "query": { "productId": "1234" } },
  "component": { "componentId": "price-calculator", "props": { "showDiscounts": true } },
  "context":   { "traceId": "ctx-9f3c…", "user": { "id": "u_888" }, "device": "mobile", "locale": "zh-CN" },
  "action":    "initial",
  "params":    {}
}

action = "initial" 表示首屏取数;交互期二次取数使用组件自定义的 action 名,路由在函数内部完成。

3.2 响应信封(组件函数 → 渲染框架):

{
  "success": true,
  "data": { "finalPrice": 128.0, "discounts": ["…"] },
  "errorCode": null,
  "errorMessage": null,
  "traceId": "ctx-9f3c…",
  "costMs": 87
}

失败时 success=falseerrorCode MUST 机器可判定,errorMessage SHOULD 人类可读且可行动。

3.3 前端组件契约。前端入口 MUST 是 ESM 默认导出的组件,签名如下:

export default function PriceCalculator({ data, props, context, actions }) {
  // data:    函数返回的动态数据(首屏由框架并行预取)
// props:   页面配置中的静态配置
// context: 页面上下文(用户、设备、locale——只读)
// actions: 框架注入的受限能力:
//   actions.invoke(action, params)  → 调用本组件专属函数(二次取数)
//   actions.emit(event, payload)    → 页面事件总线广播
//   actions.on(event, handler)      → 订阅页面事件
//   actions.track(event, payload)   → 埋点
  return <div>…</div>;
}

actions.invoke MUST 只能调用本组件的专属函数——跨组件取数在协议层即不可表达。

3.4 事件总线。事件名 MUST 带组件命名空间;载荷 MUST 可 JSON 序列化;广播语义,无应答保证;组件 MUST NOT 假设某个事件一定有订阅者或发布者。

§4组件函数契约

  • 函数 MUST 无状态,实例间不共享内存状态;
  • 函数 MUST 只服务一个组件(1:1),MUST NOT 被多个组件共享——需要共享的逻辑属于领域服务;
  • 函数 MUST 接受 §3.1 请求信封、返回 §3.2 响应信封,协议为 HTTP POST + JSON(满足此契约即语言无关);
  • 函数名 SHOULD 采用 {命名空间}.{pageId}.{componentId} 形式,MUST 全局唯一;
  • 函数 MUST 在 timeoutMs 预算内响应,读操作 SHOULD 幂等;
  • 日志 MUST 携带请求信封中的 traceId;
  • 对领域服务的调用 MUST 使用原生 HTTP / RPC 直连(不经过 AIRS 或其他研发期设施)。

§5Provider 接口标准

基础设施依赖被倒置为四个 Provider 接口。实现了这四个接口,任何公司的基建都能承载本架构;参考实现提供开箱即用的本地版(配置存文件、函数跑本地进程、静态资源本地伺服),用于开发与体验。

5.1 PageConfigProvider

interface PageConfigProvider {
  getPage(pageId: string, version?: string): Promise<PageConfig>;  // 缺省返回活跃版本
  publishPage(config: PageConfig): Promise<{ version: string }>;   // 版本不可变
  listVersions(pageId: string): Promise<VersionMeta[]>;
  setActiveVersion(pageId: string, version: string): Promise<void>; // 发布/回滚 = 移动指针
}

5.2 FunctionProvider

interface FunctionProvider {
  deploy(bundle: ComponentBundle, env: Env): Promise<{ deployId: string }>;
  status(deployId: string): Promise<DeployStatus>; // 终态判据 MUST 确定;FAILED MUST 携带机器可读原因
  invoke(fn: string, envelope: RequestEnvelope, env: Env): Promise<ResponseEnvelope>;
  logs(fn: string, filter: { traceId?: string; range?: TimeRange }): Promise<LogEntry[]>;
}

环境语义:Provider MUST 提供环境隔离(至少 DEV / STAGING / PROD);部署范围与调用白名单 MUST 是两个独立配置status MUST 给出确定性的终态判据,MUST NOT 要求调用方以「接口调用成功」推断「部署成功」。

5.3 AssetPublisher

interface AssetPublisher {
  publish(files: FileMap): Promise<{ urls: Record<string, string> }>;
  // URL MUST 内容寻址且不可变;SHOULD 返回 integrity 哈希
}

5.4 SimulatorProvider

interface SimulatorProvider {
  render(input: {
    pageId: string;
    overrides?: PageConfigPatch;   // 未发布的草稿配置可叠加渲染
    context: RenderContext;        // 注入测试身份与参数
    env: Env;                      // 函数调用环境(受调用白名单约束)
  }): Promise<{
    screenshot: Bytes;
    dom: string;
    console: ConsoleMessage[];
    network: NetworkRecord[];
    errors: RenderError[];
  }>;
}

模拟器 MUST 使用与生产一致的渲染框架;MUST 区分「数据已返回」与「视图已可见」两个就绪信号——白屏但接口 200 不是就绪。

§6AIRS 接口检索标准

6.1 接口元数据。每个登记接口 MUST 提供:

以下记录仅用于说明契约结构,是完全合成的示例:

{
  "name": "demo.discount.list-eligible",
  "protocol": "http",
  "endpoint": "POST /example-api/discounts/eligible",
  "semantic": "列出合成示例中指定用户可用于指定商品的价格优惠,供演示资格判断",
  "tags": ["demo", "discount", "eligibility"],
  "request":  { "$schema": "…", "properties": { "userId": {}, "productId": {} } },
  "response": { "$schema": "…", "properties": { "discounts": {} } },
  "examples": [ { "request": { "userId": "demo-user", "productId": "demo-product" }, "response": { "discounts": [] } } ],
  "owner": "example-team",
  "stability": "stable",
  "sla": { "p99Ms": 150, "availability": "99.95%" },
  "deprecated": false
}

6.2 检索协议。

POST /airs/search
{ "query": "演示用户可以在演示商品上使用哪些价格优惠", "topK": 5 }
→ 返回按相关度排序的候选接口,含完整元数据

6.3 纪律。

  • AIRS MUST 仅在研发期使用;生成代码 MUST 直连原生协议,MUST NOT 让线上流量经过检索服务;
  • Agent SHOULD 将选中接口的契约快照写入组件目录(backend/apis.md),保证组件上下文自包含;
  • semantic 字段是检索质量的生命线,MUST 面向「使用场景」而非「实现描述」撰写。

§7Agent 工作区标准

7.1 组件说明文件。每个组件 MUST 包含面向 Agent 的说明文件(CLAUDE.md / AGENTS.md),内容 MUST 覆盖:组件职责与业务背景、数据契约摘要、依赖接口清单、测试与验证命令、明确的修改边界。

7.2 上下文自包含。理解并修改组件所需的全部信息 MUST 存在于组件目录内——包括其依赖的外部接口契约快照。Agent 完成一次组件任务 MUST NOT 需要读取组件目录之外的业务代码。

7.3 修改边界。一次 Agent 任务 MUST 只修改一个组件目录;跨组件需求 MUST 拆分为多个任务(这同时是多 Agent 并行的安全前提)。

7.4 验证闭环。组件 SHOULD 提供确定性测试命令(component.jsontest.command);上线前 MUST 通过模拟器完成一次真实渲染检查(截图 + DOM + 控制台无错误)。验证的终点是环境,不是模型的自我评价。

§8合规性分级

级别 名称 要求 达到的能力
L1 渲染合规 §2 + §3 页面按配置组装渲染;后端可以是任何存量服务
L2 交付合规 L1 + §1 + §4 + §5 Agent 可通过 Provider 接口端到端部署组件
L3 AI 原生合规 L2 + §6 + §7(含模拟器) Agent 可独立完成 开发 → 部署 → 自测 → 提审 的完整闭环

配套的一致性测试套件(TCK)将随参考实现发布:跑通测试套件,即可声明相应级别的合规。

13

从组件交付到产品迭代

架构标准回答的是 Agent 如何在明确边界内交付组件。要将这种能力用于产品迭代,研发系统还需要提供几类通用机制:将需求与交付状态表示为机器可读信息;在关键决策处保留可审计的人类审核;为每次变更提供隔离执行、确定性验证与可回滚发布;并将上线后的核心业务指标用于下一轮决策。

这些机制不规定某种平台形态:可以由现有的 CI/CD、项目管理、Agent 工具与可观测系统组合实现,也可以由一体化平台提供。架构标准定义组件交付的边界与接口,不依赖任何具体的编排产品。任何团队都可以在 L2 / L3 合规的基建上实现同样的「开发 → 审核 → 上线」闭环。

结语

一起来定义 AI 时代的架构

过去五十年,我们的每一代架构——结构化、面向对象、SOA、微服务——都在为同一个约束优化:人类工程师的协作成本。这个约束刚刚松动了。这是五十年一遇的、重新思考架构第一性原理的机会。

本宣言给出的答案是:为 AI 的认知边界设计架构——组件小到装得进上下文,边界硬到锁得住爆炸半径,基建平到机器可操作,验证真到环境说了算。

这套标准将以开放的方式演进。你可以从以下入口阅读、试用或参与共建:

  • contextile.dev:阅读双语宣言、Quickstart 与项目最新入口;
  • contextile/contextile:参考实现,包含渲染器 SDK、本地一体化运行时、CLI 与 MCP Server,用于端到端交付 Contextile 组件;
  • contextile/contextile-bench:公开基准评测,提供跨架构、跨规模的实验任务、原始评分、修正账本与分析代码,支持复跑和扩展;
  • contextile/manifesto:本宣言的双语源文、图表与版本记录;
  • contextile/spec:Contextile 的规范性标准,包含规范章节、JSON Schema、类型定义与 RFC 流程。

Provider 适配器将由官方样例与社区实现共同扩展。

如果你也相信「架构应该为 AI 重新设计」,欢迎从任何一个层面参与:实现一个 Provider 适配器、提交一份 RFC、或者仅仅是在你的团队里划出一个页面试一试。

你指明方向,让产品自己生长。

—— Asher Chai(@asher-chai