AI生成
AI生成
业务用途
平台提供一组「自然语言 -> 结构化产物」的生成能力,主要服务于与表单场景:
| 能力 | 端点 | 是否调大模型 | 产物 |
|---|---|---|---|
| 生成表字段 | POST /api/ai/generate/table-fields | 是 | 字段数组 JSON(含列名/注释/类型/长度/必填/默认值/理由) |
| 生成 SQL | POST /api/ai/generate/sql | 否(关键词规则) | CREATE TABLE DDL |
| 生成表单配置 | POST /api/ai/generate/form-config | 否(关键词规则) | 表单字段 JSON |
| 执行 SQL | POST /api/ai/executeSql | 否(占位) | 成功标识 |
| 应用表单建议 | POST /api/ai/applyForm | 否(占位) | 成功标识 |
只有「生成表字段」真正用 AI
generate/table-fields 调用默认大模型,按业务描述生成 8~15 个字段,是本模块的核心 AI 能力。generate/sql 与 generate/form-config 是关键词规则拼装(识别「名称/描述/状态/金额/数量」等词套模板),不消耗模型额度。executeSql / applyForm 当前是占位桩,仅返回成功标识,实际落库/应用需前端自行处理或后续扩展。
涉及文件
| 角色 | 文件路径 |
|---|---|
| AI 助手控制器 | backend/src/main/java/com/lowcode/controller/AiAssistantController.java |
| AI 调用服务 | backend/src/main/java/com/lowcode/service/AiProviderService.java |
| 模型配置实体 | backend/src/main/java/com/lowcode/entity/AiModelConfig.java |
| 表元数据实体 | backend/src/main/java/com/lowcode/entity/LcTableMeta.java |
| 前端 API | frontend/src/api/ai.ts |
后端实现(关键代码)
生成表字段(AI) /generate/table-fields
这是唯一真正调用大模型的生成接口。接收 TableFieldGenerateRequest{tableName, businessDescription, existingFields}:
- 校验
businessDescription非空。 - 查默认模型(
enabled='1' AND defaultModel='1'),查不到报「请先在系统设置中配置并启用默认AI模型」。 buildTableFieldsPrompt(request)拼 prompt,约束模型直接输出 JSON。aiProviderService.generateText(config, prompt)调用(无显式 maxTokens,走默认 2048)。normalizeGeneratedFieldsWithTableName(answer, existingFields, tableName)解析 + 清洗,返回{fields:[...], suggestedTableName?}。
@PostMapping("/generate/table-fields")
public Result<Map<String, Object>> generateTableFields(@RequestBody TableFieldGenerateRequest request) {
if (!StringUtils.hasText(request.getBusinessDescription()))
return Result.error("请描述这个表的业务用途");
try {
AiModelConfig config = aiModelConfigService.getOne(new LambdaQueryWrapper<AiModelConfig>()
.eq(AiModelConfig::getEnabled, "1")
.eq(AiModelConfig::getDefaultModel, "1")
.last("LIMIT 1"));
if (config == null) return Result.error("请先在系统设置中配置并启用默认AI模型");
String answer = aiProviderService.generateText(config, buildTableFieldsPrompt(request));
Map<String, Object> parsed = normalizeGeneratedFieldsWithTableName(
answer, request.getExistingFields(), request.getTableName());
return Result.success(parsed);
} catch (Exception e) {
return Result.error("AI生成字段失败: " + e.getMessage());
}
}表字段 prompt 规则
buildTableFieldsPrompt 关键约束:
- 表名:用户传了就用,没传让模型自己生成一个英文小写下划线表名(放进
tableName字段)。 - 已存在字段(
existingFields)跳过,不重复生成。 - 输出格式严格为
{"fields":[{columnName,columnComment,columnType,columnLength,isRequired,defaultValue,reason}], "tableName":"..."}。 - 字段名英文小写下划线;类型只能是
varchar/int/bigint/decimal/text/datetime/date/tinyint(SUPPORTED_COLUMN_TYPES)。 - 不要包含
id/tenant_id/create_time/update_time/deleted(这些由平台建表时自动补齐)。 - 生成 8 到 15 个字段。
字段清洗逻辑
normalizeGeneratedFields 用 Jackson 解析 extractJson(answer)(能剥 ```json 围栏、提取 {...} 或 [...]),逐字段校验:
columnName必须匹配[a-z][a-z0-9_]{1,63},否则丢弃;与existingFields(小写)重复则丢弃。columnType不在SUPPORTED_COLUMN_TYPES则回退varchar。columnLength按类型归一:text/datetime/date强制 0;int->11、bigint->20、decimal->12、tinyint->1、其它默认 100,上限 1000。- 输出字段:
columnName/columnComment/columnType/columnLength/isRequired/defaultValue/reason。
private static final Set<String> SUPPORTED_COLUMN_TYPES =
Set.of("varchar", "int", "bigint", "decimal", "text", "datetime", "date", "tinyint");
// 若用户没传表名,尝试从 AI 响应里取 tableName 作为 suggestedTableName
if (!StringUtils.hasText(requestedTableName) && root.has("tableName")) {
result.put("suggestedTableName", root.get("tableName").asText(""));
}默认长度表
private int defaultColumnLength(String columnType) {
return switch (columnType) {
case "int" -> 11;
case "bigint" -> 20;
case "decimal" -> 12;
case "tinyint" -> 1;
case "text", "datetime", "date" -> 0;
default -> 100; // varchar 等
};
}生成 SQL(规则) /generate/sql
generateSqlFromDescription(description, tableName) 不调模型,按关键词(名称/描述/状态/时间/金额/数量)套 VARCHAR(100) / VARCHAR(500) / TINYINT / DATETIME / DECIMAL(10,2) / INT 模板拼 CREATE TABLE,自动补 id / tenant_id / create_time / update_time / deleted / 索引:
private String generateSqlFromDescription(String description, String tableName) {
StringBuilder sql = new StringBuilder();
sql.append("CREATE TABLE `").append(tableName).append("` (\n");
sql.append(" `id` BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT 'ID',\n");
sql.append(" `tenant_id` BIGINT DEFAULT 1 COMMENT '租户ID',\n");
String[] keywords = description.split("[,,;;\\n]+");
for (String keyword : keywords) {
if (keyword.contains("名称") || keyword.contains("姓名"))
sql.append(" `name` VARCHAR(100) COMMENT '名称',\n");
else if (keyword.contains("金额") || keyword.contains("价格"))
sql.append(" `amount` DECIMAL(10,2) COMMENT '金额',\n");
// ... 状态/时间/数量/描述
}
sql.append(" `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n");
// ... update_time / deleted / INDEX idx_tenant_id
return sql.toString();
}生成表单配置(规则) /generate/form-config
generateFormConfigFromDescription(description) 同样不调模型,按关键词套 input / textarea / select / date / number 模板拼 JSON,输出 {formCode, formName, fields:[...]}。
执行 SQL(占位) /executeSql
当前是桩实现,不真正执行 SQL,只校验 sql 非空后返回 {success:true, message:"SQL执行成功", sql, affectedRows:0, tableName}。真正的建表执行由表设计器的 /api/database/table/execute/{tableId} 承担。
@PostMapping("/executeSql")
public Result<Map<String, Object>> executeSql(@RequestBody Map<String, Object> request) {
String sql = (String) request.get("sql");
if (sql == null || sql.trim().isEmpty()) return Result.error("SQL语句不能为空");
Map<String, Object> result = new HashMap<>();
result.put("success", true);
result.put("message", "SQL执行成功");
result.put("affectedRows", 0); // 占位
return Result.success(result);
}应用表单建议(占位) /applyForm
也是桩实现,接收 {formCode, suggestions},返回 {success:true, message:"建议已应用到表单", formCode, appliedSuggestions}。实际把 AI 建议写回表单配置由前端表单设计器自行处理。
前端实现
frontend/src/api/ai.ts 封装相关接口:
export const executeSql = (data: { sql: string; tableName: string }) =>
request.post<any>('/ai/executeSql', data)
export const applyForm = (data: { formCode: string; suggestions: Record<string, any> }) =>
request.post<any>('/ai/applyForm', data)
export const generateTableFields = (data: {
tableName: string
businessDescription: string
existingFields: string[]
}) => request.post<{ fields: AiGeneratedField[]; rawAnswer: string; suggestedTableName?: string }>(
'/ai/generate/table-fields', data
)
export interface AiGeneratedField {
columnName: string
columnComment: string
columnType: string
columnLength: number
isRequired: boolean
defaultValue?: string
reason?: string
}generateTableFields 的 existingFields 传当前表已有字段名数组,避免 AI 重复生成;若用户未填表名,响应里的 suggestedTableName 用于回填表名输入框。
操作步骤
AI 生成表字段(主流程)
- 先在 配好默认模型。
- 进入「表设计器」,新建/编辑一张表。
- 在「AI 生成字段」入口填写业务描述(如「采购订单管理,需要订单编号、供应商、采购员、总金额、交货日期、状态、备注」)。
- 前端调
POST /api/ai/generate/table-fields,body 含businessDescription、可选tableName、existingFields(已有字段名)。 - 后端调模型生成,清洗后返回
fields数组。 - 前端把字段追加到表设计器字段列表(已存在的自动跳过),用户可逐条微调类型/长度/必填后保存。
- 若用户没填表名,用返回的
suggestedTableName回填。

生成 SQL / 表单配置
- 在对应入口填描述(逗号/分号/换行分隔关键词)。
- 调
POST /api/ai/generate/sql或/generate/form-config。 - 拿到 DDL 或表单 JSON,确认后复制使用(注意这两个是规则生成,能力有限,复杂场景用「生成表字段」走 AI)。

常见问题
生成表字段报「请先在系统设置中配置并启用默认AI模型」
和 一样,generate/table-fields 依赖默认模型。先去 配好并设默认。
AI 返回的字段被丢弃了一部分
normalizeGeneratedFields 严格校验:列名不匹配 [a-z][a-z0-9_]{1,63}(如含中文、大写、特殊符号)会被丢;与 existingFields 重复会被丢;类型不在白名单会回退 varchar 而非丢弃。若字段太少,检查模型是否遵循了 prompt(可换更强模型),或减少 existingFields。
生成的字段里出现了 id / create_time
prompt 明确禁止生成这些保留字段,且平台建表时会自动补齐。若模型不听话仍输出,normalizeGeneratedFields 当前不会过滤保留字段名(只过滤格式不对和重复的),需人工删除,或自行扩展清洗逻辑加 RESERVED 过滤。
generate/sql 生成的 DDL 不够智能
generateSqlFromDescription 只识别「名称/描述/状态/时间/金额/数量」等有限关键词,套固定模板。复杂业务表请改用「生成表字段」(AI)拿到结构化字段,再由表设计器的「执行建表」生成真正的 DDL。
executeSql 返回成功但表没建出来
/executeSql 是占位桩,affectedRows=0,不真正执行。建表请用表设计器的 POST /api/database/table/execute/{tableId}(由 SchemaService 真正执行 DDL)。
AI 生成的字段类型只有 8 种
SUPPORTED_COLUMN_TYPES 限定 varchar/int/bigint/decimal/text/datetime/date/tinyint。这是平台动态表引擎支持的子集,保证建表与 CRUD 兼容。需要 char/float/json 等类型需手动改字段类型。
