前端智能体开发(二):提示词与结构化输出:让 AI 前端可控、可解析、可交互
这张图把提示词、JSON 和动态解析器画成一条可验证的界面生产线:提示词负责定义任务和约束,结构化输出负责把结果落到可处理的字段里,解析器负责在内容增量到达时持续判断状态。AI 前端要做到“可用”,关键就在这三件事上。

这张图把提示词、JSON 和动态解析器画成一条可验证的界面生产线:提示词负责定义任务和约束,结构化输出负责把结果落到可处理的字段里,解析器负责在内容增量到达时持续判断状态。AI 前端要做到“可用”,关键就在这三件事上。
一、提示词不是魔法,而是接口契约
很多人第一次写提示词,会把它当作一句自然语言愿望。例如:
帮我生成一个学习计划。
模型当然能回答,但结果不稳定:有时很长,有时很短,有时按周写,有时按天写,有时夹杂解释,有时没有执行步骤。对聊天界面来说这可能还能接受;对应用来说,这种不稳定会变成解析失败、UI 展示混乱和业务逻辑不可控。
更可靠的提示词应该像接口契约,至少描述五件事:
- 角色:模型应该站在哪个专业视角回答。
- 目标:这次任务到底要产出什么。
- 输入:用户会给什么信息,字段含义是什么。
- 约束:不能做什么,长度、语气、范围、风险边界是什么。
- 输出:结果要用什么结构返回。
例如同样是生成学习计划,可以这样写:
你是前端学习规划助手。
目标:
根据用户的基础、时间和目标,生成 4 周学习计划。
输入字段:
- level:用户当前水平
- hoursPerWeek:每周可投入时间
- goal:学习目标
输出要求:
返回 JSON,不要输出额外解释。
字段包括 summary、weeks。
weeks 是数组,每项包含 focus、tasks、checkpoint。
这类提示词不是为了“骗模型听话”,而是让模型和程序之间形成明确协议。模型负责推理,程序负责展示、存储和继续处理。协议越清楚,前端越容易接住结果。
二、角色、示例和边界共同决定稳定性
提示词设计里最常用的三类技巧是角色设定、示例约束和边界描述。
角色设定能减少回答风格的漂移。比如“你是资深前端工程师”和“你是儿童科普助手”会产生完全不同的措辞、深度和例子。角色不要只写头衔,还要写行动方式。
你是资深前端工程师。
你会优先解释工程取舍,而不是堆概念。
你给出的代码必须能在 Vue + Vite 环境中运行。
示例约束能减少格式漂移。模型非常擅长模仿,如果你给出一组输入和输出,它更容易沿着同样结构生成结果。
输入:用户只说“地球”
输出:
{
"questions": [
{
"question": "地球是如何形成的?",
"query": ["地球形成", "太阳系早期演化"]
}
]
}
边界描述能减少危险输出。比如做儿童科普助手,要明确“不要编造数据”“不确定时要求检索”“避免成人化表达”;做面试官,要明确“不要直接给答案”“一次只问一个问题”“根据候选人的回答调整难度”。
好的提示词像一份工程需求:它不追求华丽,而追求可执行。
三、为什么结构化输出是 AI 应用的分水岭
纯文本适合阅读,不适合程序处理。结构化输出适合进入产品系统。
假设你要做一个“故事生成器”,如果模型只返回一整段文字,前端只能把它放进一个 <div>。如果模型返回 JSON,前端就可以分别渲染标题、简介、章节、关键词、图片提示词和适读年龄。
{
"title": "月亮为什么跟着我走",
"audience": "6-8 岁儿童",
"outline": [
{
"title": "第一段:孩子的疑问",
"goal": "提出生活场景"
},
{
"title": "第二段:月亮很远",
"goal": "解释视角差异"
}
],
"image_prompt": "温暖夜晚,一个孩子抬头看月亮"
}
结构化输出带来三个好处。
第一,UI 可以分区展示。标题放顶部,章节放卡片,图片提示词送给绘图模型。
第二,后续节点可以继续处理。比如把 outline 交给多个内容节点展开,把 image_prompt 交给图像节点,把 audience 交给语音合成节点调整语气。
第三,系统可以校验。字段缺失、类型错误、数组为空,都能被程序发现并重试。
这也是 AI 应用从“聊天玩具”走向“业务系统”的关键一步。
四、流式 JSON 的矛盾:用户想快,JSON 要完整
问题来了:JSON 是封闭结构。一个对象从 { 开始,到 } 才完整。如果模型流式返回:
{"title":"月亮为什么跟
这时前端不能直接 JSON.parse,因为它不是合法 JSON。必须等完整对象返回,才能解析。这样一来,流式响应的好处又被抵消了:用户虽然网络上已经收到内容,但 UI 还是不能更新。
常见解决方案有三类。
第一,要求模型输出 NDJSON,也就是每一行都是独立 JSON。优点是容易解析,缺点是会限制模型表达,也增加提示词负担。
第二,在服务端用专门的流式 JSON 库,根据固定结构解析。优点是成熟,缺点是前端直接使用不方便,而且通常依赖预设路径。
第三,自己实现一个动态 JSON 解析器。它不等待完整 JSON,而是在字符流里识别对象、数组、字符串、数字、布尔值和路径。一旦某个字段出现增量,就立刻发出事件。
第三种方案更适合 AI 前端,因为它能把结构化输出和流式体验结合起来。
五、动态解析器的核心:状态机 + 路径
一个动态 JSON 解析器至少要维护几类状态:
- 当前处于对象、数组、key、value、字符串还是数字。
- 当前嵌套层级。
- 当前字段路径。
- 当前数组下标。
- 当前 token 缓冲。
当输入字符不断进入时,解析器根据当前状态决定下一步。例如:
- 读到
{:进入对象状态。 - 读到
":可能进入 key 或 string 状态。 - 读到
::key 结束,准备读 value。 - 读到
[:进入数组状态,并记录下标。 - 读到
,:当前字段结束,准备下一个字段。 - 读到
}或]:当前层级结束,出栈。
这套逻辑本质上是手写状态机。它不需要等完整 JSON,只要能判断“当前 delta 属于哪个路径”,就可以把增量交给 UI。
例如模型正在输出:
{
"story": {
"title": "月亮为什么跟着我走",
"paragraphs": ["晚上,小明走在路上..."]
}
}
解析器可以不断发出类似事件:
{ uri: "story/title", delta: "月亮" }
{ uri: "story/title", delta: "为什么" }
{ uri: "story/paragraphs/0", delta: "晚上," }
前端拿到事件后,用 jsonuri 之类的工具把路径写回响应式对象:
parser.on("data", ({ uri, delta }) => {
const current = get(result.value, uri) || "";
set(result.value, uri, current + delta);
});
这样标题、段落和列表都能一边生成一边展示。
六、结构化流式 UI 应该怎么设计
如果只把流式结果追加到一个文本框里,用户看到的是一串逐字增长的文本。结构化流式 UI 可以更进一步,让不同字段在不同区域增长。
以“生成儿童科普文章”为例,页面可以分成四块:
- 标题区:一旦
title字段出现就展示。 - 大纲区:
outline数组逐项生成,每项变成卡片。 - 正文区:每个章节内容独立流式显示。
- 配图区:收到图片提示词后进入图像任务状态。
用户会感觉系统在一步一步完成任务,而不是一段文字在机械增长。
实现上可以把结果状态定义成:
type StoryResult = {
title: string;
outline: Array<{
section: number;
title: string;
overview: string;
}>;
sections: Record<string, string>;
imagePrompts: string[];
};
前端渲染时,不必等所有字段齐全。哪个字段到了,就渲染哪个字段。缺字段时显示骨架屏或“正在生成”。
七、错误处理比成功路径更重要
结构化输出常见失败包括:
- 模型输出了额外解释,导致 JSON 前后有自然语言。
- 字段名拼错。
- 数组格式不稳定。
- 字符串里出现未转义换行。
- 内容安全策略让模型中途停止。
- 网络中断导致对象永远不闭合。
工程上可以分层处理。
第一层是提示词约束。明确“只返回 JSON,不要额外解释”。
第二层是解析器容错。对常见缺逗号、缺引号、未闭合字符串做有限修复,但不要无限猜测。
第三层是 schema 校验。用 Zod 或 JSON Schema 检查必填字段、类型和数组长度。
第四层是重试策略。如果结构不合法,可以带着错误信息重试一次,而不是让用户重新点按钮。
const schema = z.object({
title: z.string().min(1),
outline: z.array(z.object({
title: z.string(),
overview: z.string()
})).min(1)
});
const parsed = schema.safeParse(result);
if (!parsed.success) {
await retryWithRepairPrompt(parsed.error);
}
注意,重试也要有上限。AI 系统不能陷入无限生成。
八、一个实际场景:AI 表单生成器
假设你要做一个“自然语言生成表单”的功能。用户输入:
帮我创建一个活动报名表,需要姓名、手机号、所在城市、是否需要发票。
模型应该返回:
{
"title": "活动报名表",
"fields": [
{ "key": "name", "label": "姓名", "type": "text", "required": true },
{ "key": "phone", "label": "手机号", "type": "tel", "required": true },
{ "key": "city", "label": "所在城市", "type": "select", "options": ["北京", "上海", "广州", "深圳"] },
{ "key": "invoice", "label": "是否需要发票", "type": "boolean" }
]
}
有了结构化结果,前端可以动态渲染表单;有了流式解析,用户可以看到字段一个个出现;有了 schema 校验,系统可以拒绝未知控件类型;有了提示词约束,模型不会突然输出一段营销文案。
这个功能的质量不取决于模型会不会写表单,而取决于四层契约是否稳固:
- 提示词契约:告诉模型怎么生成。
- 数据契约:定义字段和类型。
- 解析契约:流式地接住字段。
- UI 契约:把不完整状态也优雅展示出来。
九、判断提示词是否合格的标准
一个提示词是否合格,不看它写得多长,而看它能不能稳定进入工程链路。可以用五个问题检查:
- 输出能不能被程序直接消费?
- 字段缺失时能不能发现?
- 用户输入很短或很脏时是否仍有边界?
- 流式输出时 UI 是否能提前展示?
- 失败后系统能不能解释并重试?
提示词越像接口,AI 应用越像产品;提示词越像愿望,AI 应用越像抽奖。
十、从“会问”到“会接”
提示词工程的重点不是把一句话雕得很漂亮,而是让模型输出能被系统接住。结构化输出让结果进入业务对象,动态解析让流式体验不牺牲结构,schema 校验让不确定输出变得可控。
好的 AI 前端设计不是喊一句“输出稳定一点”,而是明确任务、字段、类型、错误处理和 UI 状态。提示词规定目标,JSON 规定结构,解析器负责把增量内容变成可用状态。三者配合起来,AI 才能从聊天框走进真正的应用界面。