智能组件服务的运营止损边界
让模型生成界面并不难,难的是把生成结果放进长期运行的产品。模型可能返回无效属性、引用不存在的组件,也可能在修复失败时不断重试。如果系统把这些结果直接交给主页面执行,一次普通的生成失败就可能演变成页面卡死、接口排队或调用费用失控。
运营止损的重点不是让模型永不犯错,而是限制错误能走多远。生成服务应有明确的输入范围、输出协议、资源预算和降级路径。任何一层无法确认结果时,都要能停在原地,回到已经验证的基础组件。
先缩小模型能够表达的内容
直接让模型返回任意 React 代码,意味着它可以创建循环、发起网络请求、读取全局对象,甚至引用项目中不存在的依赖。即便在执行前做 AST 检查,也很难用少量规则证明一段任意代码安全。静态检查适合拦截明确禁止的语法,不能代替完整的隔离环境。
更稳妥的做法是让模型输出受限的组件描述,例如组件类型、数据字段、布局和经过白名单约束的属性。渲染端只认识已经注册的组件,不执行模型返回的函数或表达式。这样,模型负责从需求中选择结构,真正的事件处理、数据访问和权限判断仍由应用代码掌握。
输出协议至少要校验以下内容:
- 组件类型是否在允许列表中;
- 属性名称和类型是否符合对应组件定义;
- 数据引用是否来自本次任务允许的数据集;
- 嵌套深度、节点数量和文本长度是否超出页面预算;
- 事件是否只能绑定到预先注册的动作。
校验失败时,不要把整段错误和原始业务数据继续塞回模型。先按错误类别处理:结构可以修复时允许有限重试;出现未知组件、越权数据引用或预算超限时直接拒绝。相同输入连续得到相同错误,也应停止,而不是期待下一次随机生成会碰巧正确。
预算要绑定到一次任务
重试次数、Token 和总时限应按任务分别计算,不能用一个进程级计数器混在一起。请求结束、用户取消或页面离开后,剩余生成步骤都应终止。下面的 TypeScript 片段只展示控制关系:每次生成后更新当前任务预算,通过校验才返回;失败达到边界就交给兜底组件。
interface GenerateResult { spec: unknown; tokens: number; } interface Budget { maxAttempts: number; maxTokens: number; } type ValidationResult = | { ok: true; value: ComponentSpec } | { ok: false; retryable: boolean; reason: string }; async function generateWithFallback( generate: (signal: AbortSignal) => Promise<GenerateResult>, validate: (input: unknown) => ValidationResult, fallback: ComponentSpec, budget: Budget, signal: AbortSignal, ): Promise<ComponentSpec> { let attempts = 0; let tokens = 0; while (attempts < budget.maxAttempts && tokens < budget.maxTokens) { if (signal.aborted) return fallback; attempts += 1; const result = await generate(signal); tokens += result.tokens; if (tokens > budget.maxTokens) return fallback; const checked = validate(result.spec); if (checked.ok) return checked.value; if (!checked.retryable) return fallback; } return fallback; }示例中的预算值由调用方提供,具体大小需要根据任务类型和实际调用分布确定。代码还需要在工程里补上超时、错误分类和观测事件,不能把所有异常都当成可重试错误。对会写入外部系统的动作,还要使用幂等标识,避免客户端超时后重复提交。
隔离渲染不等于藏进 Shadow DOM
Shadow DOM 能隔离部分样式,不是安全沙箱。Web Worker 适合放计算任务,但不能直接渲染 DOM。若产品确实必须运行生成代码,需要使用独立来源的受限 iframe,配置严格的sandbox和内容安全策略,并通过窄化的消息协议交换数据。即便如此,也要限制运行时间、消息大小和可调用能力。
多数低代码场景并不需要走到这一步。使用受限组件描述,可以在当前应用中由可信渲染器完成页面生成。渲染前检查节点预算,渲染中捕获组件错误,渲染后监控主线程长任务。任何阶段超出边界,都切回静态模板,并告诉运营人员哪些输入没有被采用。
兜底组件不能只是空白页。它应保留核心数据和最基本的查看、筛选或提交路径,让业务仍能继续。生成结果失败时,页面要区分“尚未生成”和“生成失败后已降级”,避免运营人员误以为新配置已经生效。
日常观察只留决定所需的信号
生成服务可以记录任务标识、模型与协议版本、尝试次数、Token 区间、校验失败类别和是否降级。默认不记录用户输入全文、生成代码或页面数据。排查确实需要样本时,先做脱敏并限制保存时间。
告警也要对应动作。短时间内校验失败增加,可以暂停该协议版本;同一任务反复重试,应立即终止任务;渲染错误上升,则停止放量并回退到上一版可信渲染器。只把指标铺满大屏,却没有明确继续、限制或回退条件,故障时仍然会靠临场判断。
巡检应定期回放几类输入:正常组件、未知组件、过深嵌套、超长文本、取消请求和依赖不可用。重点确认失败会收敛,兜底页面可用,取消后不会继续产生模型调用。规则更新后使用同一批案例复测,才能知道边界有没有被无意放宽。
智能组件服务可以允许生成结果不完美,但不能允许它绕过应用的权限、资源和发布流程。把模型限制在受控协议内,把预算绑定到单次任务,再为失败准备一个确实能用的基础组件,运营止损才不只是告警后的紧急开关。