跳到主要内容

AI 工具型应用最小项目(结构化输出)

目标:用“结构化输出 + 可编辑 + 可保存”做一个可产品化的工具。

目录

项目目标与范围

  • 必须有:JSON 结构化输出、可编辑、版本保存
  • 暂不需要:权限体系、协作评论、复杂模板市场

架构图(最小闭环)

项目结构(最小可跑)

tool-demo/
server/
generate.js
web/
App.jsx
ResultEditor.jsx

输出模板(最小 Prompt)

请输出 JSON:
{
"title": "...",
"items": [{ "name": "...", "priority": "P1" }]
}

JSON 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"]
}

最小接口(伪代码)

接口返回格式(建议)

{ "result": { "title": "...", "items": [ { "name": "...", "priority": "P1" } ] } }
// POST /tool/generate -> 返回结构化结果
app.post("/tool/generate", async (req, res) => {
const { input } = req.body;
const result = await callLLM(input);
res.json({ result });
});

前端编辑与保存(伪代码)

const [result, setResult] = useState({});
const [history, setHistory] = useState([]);

function saveVersion() {
setHistory((h) => [...h, { time: Date.now(), data: result }]);
}

校验与重试策略(最小可用)

  1. 模型输出后先做 JSON 解析
  2. Schema 校验失败 → 把错误原因回传给模型重试 1 次
  3. 仍失败 → 降级为可读文本 + 手动编辑

运行步骤(最少流程)

  1. 生成:提交输入 → 返回 JSON
  2. 编辑:前端可修改字段
  3. 保存:保存版本并可回滚

验收标准

  • JSON 可解析 + 结构稳定
  • 结果可编辑并保存版本
  • 超长输入会被拦截或提示

常见坑排查清单

  • 输出不稳定:加 JSON schema 校验 + 自动重试
  • 用户改完没保存:保存版本 + 对比差异
  • 缺少回滚:至少保留 3-5 个历史版本
  • 成本失控:限制输入长度 + 限制 max_tokens

详细实现解析(结构化输出)

为什么必须用 JSON

  • 可直接驱动 UI
  • 可存入数据库
  • 可用于后续流程(比如生成任务/拆解需求)

校验失败的处理策略

  1. 直接重试(带失败原因)
  2. 追问补齐字段
  3. 最后降级为可读文本

版本管理建议

  • 保存最近 3~5 次版本
  • 标注时间与变更说明
  • 支持一键回滚

Mermaid:结构化输出流程

调试与排障

  • JSON 解析失败:提示模型“严格 JSON”
  • 输出字段缺失:强制 required 字段
  • 结果不稳定:锁定温度与Top-p

扩展方向

  • 结果对比视图
  • 模板市场(不同场景)
  • 结果一键导出(Markdown/CSV)

UI 设计细节(最小但可用)

  • 左侧输入区
  • 右侧结果编辑区
  • 底部版本列表

结果编辑器示例(伪代码)

function ResultEditor({ value, onChange }) {
return (
<textarea value={JSON.stringify(value, null, 2)} onChange={(e) => onChange(e.target.value)} />
);
}

版本对比(最小思路)

function diff(oldVal, newVal) {
// 伪代码:对比 JSON 字段
return Object.keys(newVal).filter((k) => oldVal[k] !== newVal[k]);
}

示例用例(可直接测试)

  • 输入:"生成一份会议纪要"
  • 期望:返回 JSON 且包含 title/items

运行日志样例

[generate] ok
[validate] schema pass
[save] version=3

FAQ

Q: 为什么输出经常不稳定?

A: 降低温度 + 加强 schema 校验。

Q: 版本保存太多怎么办?

A: 只保留最近 5-10 个版本。

详细实现解析(前端)

字段编辑策略

  • 直接编辑 JSON
  • 或映射为表单控件

表单映射示例(伪代码)

<input value={result.title} onChange={(e)=>setResult({ ...result, title: e.target.value })} />

详细实现解析(后端)

  • 保证输出为 JSON
  • 输出前做 schema 校验
  • 失败自动重试

评估指标建议

  • JSON 合格率
  • 用户编辑次数
  • 版本回滚率

Mermaid:版本保存流程

运行日志模板

[generate] ok
[validate] pass
[save] version=4

FAQ(扩展)

Q: 为什么不直接输出 Markdown?

A: 结构化输出更便于编辑与存储。

Q: 用户输入太长怎么办?

A: 限制输入长度 + 引导分段。

交付物清单(工具型项目)

  • 一段 30 秒演示视频
  • 一份示例输入/输出 JSON
  • 一份指标记录(合格率)

示例输入与输出

输入:

生成一份产品需求草案

输出(JSON):

{
"title": "产品需求草案",
"items": [
{ "name": "核心功能", "priority": "P1" }
]
}

完整可运行代码(Mock 版)

源码目录:docs/demos/tool-demo

目录结构

tool-demo/
server/
index.js
package.json
public/
index.html

server/index.js(结构化输出)

import express from "express";
import path from "path";
import { fileURLToPath } from "url";

const app = express();
app.use(express.json());

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

function buildResult(input) {
return {
title: "自动生成结果",
items: [{ name: input || "默认任务", priority: "P1" }]
};
}

app.post("/tool/generate", (req, res) => {
const { input } = req.body || {};
const result = buildResult(input);
res.json({ result });
});

app.listen(3003, () => {
console.log("Tool demo at http://localhost:3003");
});

public/index.html(最小前端)

<input id="input" placeholder="请输入需求" />
<button id="gen">生成</button>
<textarea id="result"></textarea>

运行方式

cd docs/demos/tool-demo/server
npm i
npm run dev