第二章:提示词工程
怎么和大模型说话才能得到你想要的结果——这是大模型应用开发中最直接影响产品效果的技能。2.1 为什么提示词工程重要同样一个问题不同的提问方式模型的输出质量可以差很多❌ 含糊写法 帮我写代码 ✅ 精确写法 用 Vue3 Composition API 写一个 useLocalStorage Hook要求 1. 支持任意类型JSON 序列化/反序列化 2. 数据变化时自动同步到 localStorage 3. JSON 解析失败时返回传入的默认值 请先给出完整代码然后用 3 条要点说明关键设计决策。差距的原因很直接模型是按字面理解你说的话的含糊的指令会得到含糊的结果。2.2 四个基础原则2.2.1 角色设定在system消息里设定角色是提升输出质量最简单有效的手段// 没有角色设定——模型用通用模式回答 messages: [{ role: user, content: 解释一下 useEffect }] // 有角色设定——模型从特定视角和风格回答 messages: [ { role: system, content: 你是一位有 5 年 React 经验的前端工程师。 解释技术概念时 - 先给出一句话的核心定义 - 用真实的业务场景举例不要用计数器这种玩具示例 - 指出新手常见的误用方式 }, { role: user, content: 解释一下 useEffect 的依赖数组 } ]角色设定的几个维度维度例子专业身份你是一位资深 Vue3 架构师受众认知向有 3 年经验的前端开发者解释输出风格语言简洁每个观点不超过 2 句格式约束输出 Markdown代码块标注正确的语言边界限制只讨论前端相关内容其他话题礼貌拒绝2.2.2 任务描述要具体❌ 优化这段代码 ✅ 优化这段代码的性能 1. 识别不必要的重复渲染 2. 用 useMemo/useCallback 缓存可以缓存的计算 3. 保持代码可读性不要为了性能牺牲太多可维护性 4. 每处修改加注释说明为什么这样改2.2.3 指定输出格式不指定格式模型会随机选它认为合适的格式你的代码需要额外解析const systemPrompt 分析代码只输出 JSON不加任何解释文字格式如下 { hasIssues: boolean, issues: [{ type: string, description: string, severity: error|warning|info }], score: number, suggestions: string[] } 2.2.4 给出示例见 2.3 节 Few-shot直接描述格式不如给示例有效。模型学格式的能力远强于理解抽象描述的能力。2.3 Few-shot 提示Few-shot 是在提示词里加几个输入→输出的配对例子教会模型你想要的格式和风格。import { HumanMessage, AIMessage, SystemMessage } from langchain/core/messages // 场景从需求描述中提取组件规格说明保证格式一致 async function extractComponentSpec(requirement) { const messages [ new SystemMessage(你是前端架构师将需求转换为组件规格只输出 JSON不加解释。), // 示例 1 new HumanMessage(做一个带 loading 的搜索框支持防抖), new AIMessage(JSON.stringify({ name: SearchInput, props: [ { name: placeholder, type: string, default: 请输入 }, { name: debounce, type: number, default: 300 }, ], emits: [search, clear], features: [防抖处理, loading 状态, 清空按钮], }, null, 2)), // 示例 2 new HumanMessage(做一个支持跳页的分页组件), new AIMessage(JSON.stringify({ name: Pagination, props: [ { name: total, type: number, required: true }, { name: pageSize, type: number, default: 10 }, ], emits: [change], features: [页码跳转, 边界禁用], }, null, 2)), // 真正的请求 new HumanMessage(requirement), ] const res await model.invoke(messages) return JSON.parse(res.content) } const spec await extractComponentSpec(做一个日期范围选择器支持快捷选项近7天、近30天、本月) console.log(spec)使用建议2~5 个示例通常够用太多反而让模型过度拟合示例质量比数量重要选最典型的输入输出配对示例要覆盖边界情况空值、异常格式等2.4 思维链Chain of Thought对于复杂问题直接让模型给答案效果不好。引导模型先分步骤思考再给结论准确率会明显提升。const systemPrompt 你是一位资深架构师。分析技术方案时严格按以下步骤 【第一步】拆解核心需求和约束条件团队规模、时间、预算、技术栈 【第二步】列出 2-3 个可选方案每个方案分析优缺点 【第三步】给出推荐方案说明具体理由 【第四步】列出实施的关键风险和应对策略适合用 CoT 的场景技术方案选型分析Bug 定位先列可能原因再给解决方案需求可行性评估复杂逻辑推理不需要用的场景简单的信息查询CoT 让回答变冗长翻译、格式转换结构化数据提取用 Few-shot 更合适2.5 结构化输出前端最头疼的问题模型说返回 JSON但实际有时候会加json包裹、加解释文字导致JSON.parse报错。方式一Prompt 约束 容错解析async function extractData(text) { const res await model.invoke([ new SystemMessage(只返回 JSON格式{name:string,score:number}不加任何其他内容), new HumanMessage(text), ]) // 容错处理去掉可能出现的 json 包裹 const cleaned res.content.replace(/json\n?|\n?/g, ).trim() return JSON.parse(cleaned) }方式二withStructuredOutput推荐用这个LangChain.js 内置底层利用 Function Calling 强制返回符合 Schema 的 JSON稳定性远好于 Prompt 约束import { z } from zod const ReviewSchema z.object({ hasIssues: z.boolean(), score: z.number().min(0).max(100).describe(代码质量评分), issues: z.array(z.object({ type: z.string(), description: z.string(), severity: z.enum([error, warning, info]), })), suggestions: z.array(z.string()), }) // 用 withStructuredOutput 包装模型 const structuredModel model.withStructuredOutput(ReviewSchema) const result await structuredModel.invoke([ new SystemMessage(你是 Vue3 代码审查专家分析代码质量和潜在问题。), new HumanMessage(审查这段代码\n${code}), ]) // result 直接是解析好的对象不需要 JSON.parse不会抛异常 console.log(result.score) // 直接取字段 console.log(result.issues) // 类型安全两种方式的对比方式稳定性适用场景Prompt 约束一般模型偶尔不遵守快速原型或模型不支持 Function CallingwithStructuredOutput高底层强制约束生产项目推荐2.6 Vue3 提示词模板管理器实际项目里提示词需要复用参数化模板是工程化提示词的基础模式template div classprompt-builder aside div v-fortpl in templates :keytpl.id clickselect(tpl) :class{ active: selected?.id tpl.id } {{ tpl.name }} /div /aside main v-ifselected div v-forv in selected.variables :keyv.key label{{ v.label }}/label textarea v-ifv.multiline v-modelvalues[v.key] :placeholderv.placeholder / input v-else v-modelvalues[v.key] :placeholderv.placeholder / /div !-- 模板编译预览 -- pre{{ compiled }}/pre button clicksend :disabledloading生成/button div v-ifresult{{ result }}/div /main /div /template script setup import { ref, computed, reactive } from vue const templates [ { id: code-review, name: 代码审查, system: 你是资深前端工程师注重代码质量。, // 用 {{变量名}} 作为占位符 user: 审查以下 {{lang}} 代码重点关注 {{focus}} \\\{{lang}} {{code}} \\\ 输出① 整体评价 ② 问题列表 ③ 改进建议附代码示例, variables: [ { key: lang, label: 语言/框架, placeholder: Vue3 / React / Node.js }, { key: focus, label: 审查重点, placeholder: 性能、可读性、安全性 }, { key: code, label: 代码, multiline: true, placeholder: 粘贴代码... }, ], }, { id: component-design, name: 组件设计, system: 你是 Vue3 组件设计专家。, user: 设计一个 {{name}} 组件 功能需求{{requirements}} 技术约束{{constraints}} 输出① Props/Emits/Slots 定义 ② 核心实现思路 ③ 使用示例, variables: [ { key: name, label: 组件名称, placeholder: ImageCropper }, { key: requirements, label: 功能需求, multiline: true, placeholder: 描述组件需要实现的功能... }, { key: constraints, label: 技术约束, placeholder: 不引入第三方库 }, ], }, ] const selected ref(null) const values reactive({}) const result ref() const loading ref(false) function select(tpl) { selected.value tpl tpl.variables.forEach(v { values[v.key] }) result.value } // 核心逻辑把 {{变量}} 替换为实际填写的值 const compiled computed(() { if (!selected.value) return return selected.value.user.replace( /\{\{(\w)\}\}/g, (_, key) values[key] || {{${key}}} ) }) async function send() { if (!selected.value || loading.value) return loading.value true try { const res await fetch(/api/prompt, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ system: selected.value.system, user: compiled.value, }), }) const data await res.json() result.value data.content } finally { loading.value false } } /script这种模板方式的好处提示词和代码解耦产品经理可以直接改提示词不用动代码同一个界面可以快速做 A/B 测试对比不同提示词的效果模板可以从后端动态加载不需要发版就能调整2.7 常见错误否定指令效果差❌ 不要输出 Markdown ✅ 以纯文本格式输出不使用任何 Markdown 语法一次塞太多任务❌ 帮我分析需求、写代码、写测试、写文档 ✅ 拆成多次调用每次专注一个任务格式要求模糊❌ 用合适的格式返回 ✅ 以 JSON 格式返回结构为 { result: string, confidence: number }加礼貌用词没意义请、谢谢、麻烦不会让输出更好只是在多消耗 token。2.8 本章小结精确的角色设定 具体的任务描述 明确的格式要求是写好提示词的基本功Few-shot2~5 个示例比描述格式更有效选最典型的输入输出配对Chain of Thought在 system 里定义思考步骤引导模型先分析再给结论复杂问题效果明显结构化输出生产项目里用withStructuredOutput Zod是最稳定的方式比 Prompt 约束可靠得多提示词模板化{{变量}}替换是工程化复用提示词的最简单方式把提示词和代码解耦