AI 工具型应用最小项目(结构化输出)
目标:把“会生成内容”升级为“可编辑、可保存、可复用”的工具产品。
目录
目标与边界
这类项目和聊天机器人的区别在于:用户不只“看结果”,还要“继续编辑结果、保存结果、复用结果”。
所以你要把目标从“生成一段话”改成“生成一个结构化对象”。
当你能稳定产出结构化结果时,前端页面、数据库、后续流程才能真正接起来。
- 必须有:结构化输出、前端可编辑、版本保存
- 可选有:模板市场、多人协同、导出多格式
- 先不做:复杂权限与审批流
核心思路
工具型 AI 项目和聊天项目最大的差异:
- 聊天关注“对话体验”
- 工具关注“结果可消费”
所以必须优先 JSON(或严格结构)输出,而不是松散段落文本。
最小实现
输出 Schema
先定义 Schema 的原因是:你希望模型输出能被程序稳定消费,而不是每次都靠人工猜格式。 这份 Schema 约束了三个层次:
- 顶层必须有标题和条目列表
- 每个条目必须有名称和优先级
- 优先级只能在固定枚举中取值,避免脏数据
这相当于给模型输出加了一层“合同”,后续前后端都按合同协作。
{
"type": "object",
"properties": {
"title": { "type": "string" },
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": { "type": "string" },
"priority": { "type": "string", "enum": ["P0", "P1", "P2"] }
},
"required": ["name", "priority"]
}
}
},
"required": ["title", "items"]
}
后端接口
后端接口的职责不是“把模型结果原样透传”,而是做质量闸门:
- 接收用户输入并调用模型
- 尝试解析结构化结果
- 用 Schema 校验合法性
- 只把合法结果返回给前端
这样做的直接收益是:前端编辑器收到的数据结构稳定,不会频繁出现字段缺失导致页面报错。
app.post("/api/tool/generate", async (req, res) => {
const raw = await callLLM(req.body.input);
const parsed = JSON.parse(raw);
const valid = schema.safeParse(parsed);
if (!valid.success) {
return res.status(422).json({ code: "E_SCHEMA", message: "输出格式不合法" });
}
res.json({ result: valid.data });
});
前端编辑与版本
前端这一段要解决“可编辑”和“可回滚”两个产品需求:
result表示当前工作版本versions保存历史快照,支持误改后回退
structuredClone 的作用是深拷贝,避免历史版本和当前对象共用引用而被意外联动修改。
const [result, setResult] = useState<Result>();
const [versions, setVersions] = useState<Result[]>([]);
function saveVersion() {
if (!result) return;
setVersions((v) => [...v.slice(-4), structuredClone(result)]);
}
预期结果:用户可以放心试改,不满意随时恢复;这比单纯“生成一次文本”更接近真正可用的工具产品。
质量保障
- 输出失败时:最多自动重试 1 次
- 仍失败:降级为文本结果 + 手动编辑入口
- 记录指标:JSON 合格率、用户编辑次数、回滚率
验收标准
- 输出能稳定通过 Schema 校验
- 用户可编辑关键字段并保存历史版本
- 至少保留最近 5 个版本可回滚
- 出错时有清晰可操作提示