引言
低代码把门槛从「写代码」降到了「配元数据」,但配元数据本身仍有门槛:得知道平台有哪些字段类型、关系怎么建、表达式怎么写、页面怎么排。对一个只想描述业务需求的运营或产品来说,这个门槛并不低。
大模型恰好擅长「把模糊意图翻译成结构化产物」。于是「说一句话生成一个应用」成了低代码平台的新入口,也成了这两年被问得最多的问题:能不能让模型直接产出 Schema?
难点在于可控性。模型输出的东西可能语法正确但语义荒谬:编造平台不支持的字段类型、引用不存在的实体、生成看起来合理但业务上错的审批规则。而低代码的元数据一旦落库就会立刻生效,没有编译期兜底。因此这个功能的技术核心不是「怎么调模型」,而是怎么把不可控的输出约束在可控的边界内。
本文按「三个落点 → 结构化输出 → 上下文工程 → 页面与逻辑生成 → 可控性 → 校验与修复 → 人在回路 → 迭代合并 → 质量评测 → 安全防范」展开,给出可落地的生成管线设计。读完后你应当能判断:AI 生成该从哪里切入,以及哪些环节必须由平台而非模型来把关。
目录
- AI 在低代码中的三个落点
- 自然语言到 Schema
- 上下文与提示词工程
- 生成页面与业务逻辑
- 生成结果的可控性
- Schema 校验与自动修复
- 人在回路与修订
- 迭代式生成与差异合并
- 质量评测体系
- 幻觉与安全风险防范
1. AI 在低代码中的三个落点
不是所有「生成」都同等安全,先把落点按可控性排个序。
落点 A:数据建模
"做一个客户管理,客户有名称、联系人、行业、合同金额"
→ Entity + Field 列表
落点 B:页面与表单
"给客户列表加搜索和新增按钮"
→ Page Schema(表格 + 工具栏 + 表单弹窗)
落点 C:逻辑与流程
"合同金额超过 50 万要总监审批"
→ gateway 条件 + 任务分配规则
三个落点的可控性递减:数据建模的结构最固定、校验最容易、用户收益最直接;流程逻辑的自由度最高、语义最模糊、边界最多。
| 落点 | 结构固定度 | 校验难度 | 用户收益 | 建议顺序 |
|---|---|---|---|---|
| A 数据建模 | 高 | 低 | 高 | 1 |
| B 页面与表单 | 中 | 中 | 高 | 2 |
| C 逻辑与流程 | 低 | 高 | 中 | 3 |
建议从落点 A 切入,用最小的风险验证整条管线的可行性,再逐步扩展到 B 和 C。一次性把三个落点全做,等于在可控性最差的地方最先暴露问题。
2. 自然语言到 Schema
生成管线的一端是自由文本,另一端必须是严格的 Schema。中间靠结构化输出约束。
interface GenRequest {
intent: string; // 用户输入
target: 'entity' | 'page' | 'flow';
context: GenContext; // 已有模型、命名规范、字段类型清单
}
const TOOL_SCHEMA = {
name: 'create_entity',
parameters: {
type: 'object',
properties: {
name: { type: 'string', pattern: '^[a-z][a-z0-9_]{2,31}$' },
label: { type: 'string' },
fields: {
type: 'array',
items: {
type: 'object',
properties: {
name: { type: 'string' },
type: {
enum: ['string', 'text', 'integer', 'decimal',
'boolean', 'date', 'enum', 'ref'],
},
required: { type: 'boolean' },
},
required: ['name', 'type'],
},
},
},
required: ['name', 'fields'],
},
};
关键点:不要让模型输出自由文本再由平台解析,用函数调用或结构化输出把它的输出空间限制成「只能吐 Schema」。字段类型用 enum 收窄到平台真正支持的范围,模型就不会编造出 currency 或 attachment 这类不存在的类型。
3. 上下文与提示词工程
同样的模型,上下文给得对与不对,一次通过率能差出一倍。
必给的上下文:
1. 字段类型清单(enum,与平台能力严格一致)
2. 命名规范(表名单复数、字段 snake_case、长度上限)
3. 已有实体摘要(避免重复建模、支持 ref 关联)
4. 两三个范例 Schema(few-shot,比规则描述有效得多)
5. 平台硬约束(字段数上限、不支持的类型、保留字)
不要给的:
1. 与本次任务无关的实体全文
2. 内部实现细节(物理表名、列名、索引名)
3. 历史生成结果(会把上一轮的幻觉带进来)
上下文长度与准确率不是线性关系:塞进大量无关实体反而会让模型「张冠李戴」,引用到错误的对象。经验做法是按任务相关性做检索,只把可能被引用的实体摘要放进去,而不是把整个数据字典塞满窗口。
4. 生成页面与业务逻辑
页面 Schema 比实体复杂,因为它有层级、有引用、有绑定关系。
{
"type": "page",
"layout": { "kind": "list-detail" },
"blocks": [
{
"type": "table",
"entity": "customer",
"columns": ["name", "industry", "amount"],
"toolbar": [{ "action": "create", "form": "customer_form" }]
}
]
}
生成业务逻辑的三档(风险递增):
L1 声明式规则:生成 gateway 条件这类结构化规则
可控、可校验、可静态分析 → 推荐
L2 表达式:生成表达式字符串
必须过表达式校验器(字段存在性、类型、语法)
L3 代码:生成 JS/TS 片段
风险最高,必须人工评审后才允许启用
尽量把生成结果往 L1 压。用户说「金额超过 50 万要审批」,正确产物是一个结构化的条件对象,而不是一段 if (amount > 500000) {...} 的代码。结构化产物可校验、可在可视化编辑器里改、可被静态分析;代码产物则把可控性一次性让渡出去了。
5. 生成结果的可控性
可控性来自五条约束,缺一条都会漏。
1. 结构化输出:JSON Schema / 函数调用,杜绝自由文本解析
2. 白名单:字段类型、组件类型、函数名都取自平台注册表
3. 引用既有对象:优先 ref 已有实体,而不是每次都新建
4. 幂等:相同输入给相同输出(温度 0 + 结果缓存)
5. 增量:只生成缺失部分,不覆盖用户已修改的内容
第 4 条容易被忽略。用户点了两次生成,得到两个不同的 Schema,会直接摧毁信任。做法是:温度设为 0,并对「意图 + 上下文哈希」做结果缓存,同一请求短时间内返回同一结果。
5.1 白名单要覆盖到每一层
白名单不止约束字段类型,还要约束所有会被写进 Schema 的「名字」:
const ALLOWED = {
fieldTypes: new Set(['string', 'text', 'integer', 'decimal',
'boolean', 'date', 'enum', 'ref']),
components: new Set(['table', 'form', 'chart', 'tabs', 'detail']),
functions: new Set(['len', 'round', 'sum', 'upper', 'now']),
};
一旦某一层漏了白名单,模型就会从那一层钻进来:字段类型限住了,它可能在组件类型上编造 gantt;组件限住了,它可能在表达式里调用不存在的 formatCurrency。白名单必须与平台注册表同源,而不是手抄一份。
6. Schema 校验与自动修复
生成结果绝不能直接落库,必须先过与手工创建完全相同的校验管线。
function validateGenerated(schema: unknown): Issue[] {
const issues: Issue[] = [];
for (const e of entities(schema)) {
if (!/^[a-z][a-z0-9_]{2,31}$/.test(e.name)) {
issues.push({ level: 'error', path: e.name, msg: '命名不规范' });
}
const names = new Set<string>();
for (const f of e.fields) {
if (names.has(f.name)) {
issues.push({ level: 'error', path: `${e.name}.${f.name}`, msg: '字段重名' });
}
names.add(f.name);
if (f.type === 'ref' && !entityExists(f.target)) {
issues.push({ level: 'error', path: f.name, msg: '引用的实体不存在' });
}
}
}
return issues;
}
6.1 自动修复循环
把校验错误回灌给模型让它修,是提升一次通过率最有效的手段,但必须有上限。
async function generateWithRepair(req: GenRequest, maxRounds = 3) {
let out = await callModel(req);
for (let i = 0; i < maxRounds; i++) {
const issues = validateGenerated(out);
if (!issues.some((x) => x.level === 'error')) return { out, issues };
out = await callModel({ ...req, previous: out, errors: issues });
}
return { out, issues: validateGenerated(out) };
}
没有上限的修复循环会失控:模型可能在第 3 轮引入新错误,第 5 轮又改回去,成本与延迟一起涨。经验值是 2 到 3 轮,超过就交给人处理。
7. 人在回路与修订
三种交互形态:
1. 确认制:生成 → 预览 → 用户点「采用」才落库
2. 编辑制:生成 → 落到草稿 → 用户在可视化编辑器里改
3. 对话制:生成 → 用户说「把金额改成必填」→ 局部重生成
推荐编辑制:生成的产物直接进入可视化编辑器,用户改的是元数据而不是提示词。这样做有三个好处:用户不必懂提示词工程;改动被版本管理系统完整记录,可追溯可回滚;用户改完之后,平台对这份 Schema 的理解与手工创建的完全一致,后续所有能力(校验、联动、发布)都能正常作用。
对话制适合作为补充:当用户想改的地方在编辑器里操作繁琐时,一句话比点十下更快。它的实现要点是局部重生成,而不是整份重来:
async function refine(patch: PatchRequest) {
const scope = locateScope(schema, patch.targetPath); // 只取目标子树作上下文
const next = await callModel({ intent: patch.instruction, scope });
return applyPatch(schema, patch.targetPath, next); // 只替换该子树
}
把上下文收窄到目标子树,既省 token,也大幅降低模型「顺手改坏别处」的概率。
8. 迭代式生成与差异合并
真正棘手的问题是:用户已经在生成结果上改过了,重新生成会覆盖。
三种策略:
A. 只生成缺失项(增量)
B. 生成时保留用户已修改的路径(按路径级标记)
C. 生成结果走 diff 预览,用户逐条接受
function mergeGenerated(base: Schema, generated: Schema, touched: Set<string>) {
// touched 记录用户手工改过的路径,这些路径一律不覆盖
return deepMerge(base, generated, { skip: (path) => touched.has(path) });
}
这与 代码生成与领域特定语言 里的「生成基类 + 手写子类」是同一类问题的两种形态:生成与手写之间必须有清晰的、机器可判定的边界。区别只是低代码场景下的「手写」表现为「在可视化编辑器里改过的路径」。
9. 质量评测体系
没有基准集,AI 功能的迭代就是凭感觉调提示词,改好一处坏一处。
评测维度:
1. 结构合法率:生成结果能通过 Schema 校验的比例
2. 语义正确率:人工标注,生成是否符合意图
3. 一次通过率:不需要修复循环的比例
4. 采用率:用户接受生成结果的比例
5. 修订轮数:用户接受前改了几次
6. 成本:每千次生成的 token 与端到端延迟
基准集构建:
用真实需求整理 200~500 条「意图 → 期望 Schema」样本
覆盖简单建模、多实体关联、含枚举、含校验规则等分层难度
每次换模型、改提示词、调参数都完整跑一遍
采用率是最贴近业务价值的指标,但它有滞后性,不适合做日常迭代的快速反馈。日常迭代看「结构合法率 + 一次通过率」,季度回顾看「采用率 + 修订轮数」。
参考目标(以数据建模落点为例):
结构合法率 > 95% 低于此值说明输出约束没做够
一次通过率 > 80% 低于此值说明上下文或提示词有问题
采用率 > 60% 低于此值说明模型没抓住业务意图
平均修订轮数 < 1.5 高于此值说明首次生成质量不足
这些阈值不是行业标准,而是用来做回归判断:换了模型或改了提示词之后,指标掉出阈值就必须回滚,而不是「感觉还行」。
10. 幻觉与安全风险防范
幻觉的典型表现:
- 编造不存在的字段类型(用 enum 限定可治)
- 编造实体引用(校验器可治)
- 生成看似合理但业务上错的规则(只能靠人在回路)
- 把示例数据当真实数据写进模型(上下文隔离可治)
安全风险:
- 提示词注入:用户输入里夹带「忽略以上指令」
- 数据泄露:上下文里带了用户无权查看的数据
- 越权生成:生成的内容超出当前用户的权限范围
防范的核心原则是:生成侧不做权限判断,落库侧必须再过一遍权限。模型只是在帮用户「更快地表达」,它产出的候选必须和用户手工创建走完全相同的授权、校验、审计流程。任何「因为是 AI 生成的所以跳过检查」的捷径,都会在半年内变成一次安全事故。
权衡取舍
| 决策点 | 选项 A | 选项 B | 建议 |
|---|---|---|---|
| 输出形式 | 自由文本再解析 | 结构化输出 | 结构化,杜绝解析脆弱性 |
| 生成范围 | 全量重生成 | 增量生成 | 增量,保留用户修改 |
| 落库方式 | 直接落库 | 草稿 + 确认 | 草稿,可撤销 |
| 修复循环 | 无限重试 | 上限 3 轮 | 上限,控成本与延迟 |
| 权限校验 | 生成时判断 | 落库时判断 | 落库时,生成不做权限 |
| 迭代依据 | 凭感觉调参 | 基准集评测 | 基准集,否则无法收敛 |
常见坑清单
- 让模型输出自由文本再正则解析:格式一变就崩,必须用结构化输出约束。
- 字段类型不限定 enum:模型编造平台不支持的类型,落库即报错。
- 无校验直接落库:重名字段、悬空引用直接进生产环境。
- 修复循环无上限:模型反复引入新错,成本与延迟一起失控。
- 全量重生成覆盖用户修改:手工改动被吞掉,必须增量或按路径跳过。
- 无基准集:提示词改动凭感觉,改好一处坏一处。
- 生成侧做权限判断:与落库口径不一致,出现越权或误拒。
- 上下文塞无关实体:模型张冠李戴,引用到错误的对象。
- 生成的表达式不过校验器:语法对但引用了不存在的字段,运行时才炸。
- 示例数据混入上下文:模型把假数据当成真实数据生成进模型。
小结
AI 辅助低代码生成的骨架是「落点划分 → 结构化输出 → 上下文工程 → 校验与修复 → 人在回路 → 迭代合并 → 质量评测 → 安全防范」。最核心的一条原则是模型只负责生成候选,平台负责校验与落库:生成侧不碰权限、不直接写库,所有产物都要过一遍与手工创建完全相同的校验管线。另一条是评测先行:没有基准集,AI 功能的迭代无法收敛。
落点上建议从数据建模切入,它的结构最固定、校验最容易、用户收益最直接;页面与流程生成的自由度更高,需要更强的校验与更细的人在回路设计。
生成结果最终也是元数据,因此其品质上限取决于 元数据驱动架构设计 的 Schema 表达力;当生成物需要导出为可独立维护的代码时,见 代码生成与领域特定语言 。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。