点击上方 前端Q关注公众号回复加群加入前端Q技术交流你有没有这种感觉同样一个模型有人写的 Prompt 就是比你的好用这不是玄学是工程。为什么前端需要学 Prompt Engineering你可能觉得 Prompt Engineering 是给 AI 研究员玩的跟前端没啥关系。但现实是——你每天都在写 Prompt▸在 Cursor 里给 AI 下指令写代码▸在项目里调用 OpenAI / Claude API▸配置CLAUDE.md/.cursorrules规则文件▸给 RAG 系统写检索和生成模板上面这些全都是 Prompt Engineering 的应用场景。掌握 System Prompt 设计模式和 Few-Shot 策略能让你的 AI 输出质量直接上一个台阶。一、Prompt 的基本结构在正式讲设计模式之前先搞清楚一个 API 调用里 Prompt 的结构typescriptimport Anthropic from anthropic-ai/sdk;const client new Anthropic();const response await client.messages.create({model: claude-sonnet-4-20250514,max_tokens: 1024,// ① System Prompt —— 设定角色、规则、背景知识system: 你是一个资深前端工程师精通 React 和 TypeScript。回答要简洁、有代码示例使用中文。,messages: [// ② Few-Shot Examples —— 给模型看几个标准答案{ role: user, content: 如何用 React 实现一个计数器 },{ role: assistant, content: tsx\nconst [count, setCount] useState(0);\nE6DB74 },// ③ 真正的用户问题{ role: user, content: 如何用 React 实现一个 Todo List },],});一个完整的 Prompt 由三层组成层级作用类比System Prompt设定角色、规则、输出格式新员工入职培训手册Few-Shot Examples给几个输入→输出的示范老员工带新人做几个案例User Prompt当前要处理的具体任务今天分配的工作任务关键认知System Prompt 决定了模型是谁Few-Shot 决定了模型怎么做User Prompt 决定了模型做什么。二、System Prompt 的 4 种设计模式System Prompt 不是随便写两句话就行的它有明确的设计模式。我总结了工作中最常用的 4 种▎模式一角色扮演Role Playing最常用的模式给 LLM 一个明确的身份定位。typescriptconst systemPrompt 你是一名有 10 年经验的前端架构师专注于 React 生态。你的特点- 偏好函数式组件和 Hooks- 重视 TypeScript 类型安全- 关注性能优化和可维护性- 代码风格遵循 Airbnb 规范;为什么有效角色设定不是装模作样它实际上在做两件事缩小输出空间模型不再漫无目的地生成而是沿着特定角色的知识和风格来回答激活相关知识模型会优先调用与该角色相关的训练数据前端实战示例——代码审查助手typescriptconst codeReviewSystem 你是一名严格的前端代码审查员。审查维度按优先级排序1. 安全性XSS、CSRF、敏感数据泄露2. 性能不必要的 re-render、内存泄漏、大包体积3. 可维护性命名规范、组件拆分合理性、类型覆盖4. 代码风格ESLint 规则合规、一致性输出格式- 每个问题给出 [严重/警告/建议] 标签- 附上修复后的代码示例- 最后给出整体评分1-10;▎模式二规则约束Rule Constraints给模型划定明确的行为边界告诉它什么能做、什么不能做。typescriptconst constrainedSystem 你是一个 API 文档生成助手。必须遵守的规则1. 只回答与前端开发相关的问题其他领域回复这不在我的专业范围内2. 代码示例必须使用 TypeScript不允许 any 类型3. 所有异步操作必须有错误处理4. 不得推荐已废弃的 API如 componentWillMount5. 涉及安全敏感操作时必须提醒用户注意风险禁止事项- 不输出与任务无关的闲聊- 不编造不存在的 API- 不给出未经验证的性能数据;关键技巧规则约束最好用正面表述 负面表述结合的方式▸正面必须用 TypeScript▸负面不允许 any 类型这比单独用任何一种都更有效因为模型对边界更敏感。▎模式三输出格式控制Output Format当你需要把 LLM 的输出直接喂给下游代码处理时格式控制是必须的。typescriptconst formatSystem 你是一个前端组件分析器。分析用户给出的 React 组件代码按以下 JSON 格式输出{componentName: 组件名称,type: functional | class,props: [{ name: 属性名, type: TS类型, required: true/false, description: 描述 }],hooks: [useState, useEffect],dependencies: [外部依赖包名],complexity: low | medium | high,suggestions: [优化建议1, 优化建议2]}注意- 输出纯 JSON不要加 markdown 代码块- 所有字段都必须填写没有则用空数组或 unknown- complexity 根据嵌套层级、条件分支数量、hook 数量综合判断;进阶技巧——结合 Zod 做运行时校验typescriptimport { z } from zod;const ComponentAnalysis z.object({componentName: z.string(),type: z.enum([functional, class]),props: z.array(z.object({name: z.string(),type: z.string(),required: z.boolean(),description: z.string(),})),hooks: z.array(z.string()),dependencies: z.array(z.string()),complexity: z.enum([low, medium, high]),suggestions: z.array(z.string()),});async function analyzeComponent(code: string) {const response await client.messages.create({model: claude-sonnet-4-20250514,system: formatSystem,messages: [{ role: user, content: code }],max_tokens: 2048,});const text response.content[0].type text ? response.content[0].text : ;const parsed JSON.parse(text);return ComponentAnalysis.parse(parsed); // 运行时类型校验}▎模式四知识注入Knowledge Injection在 System Prompt 里直接塞入领域知识让模型基于你的私有信息来回答。typescriptconst knowledgeSystem 你是我们团队的前端技术顾问。以下是项目的技术栈和规范## 技术栈- 框架Next.js 15 (App Router)- 状态管理Zustand v5- 样式方案Tailwind CSS v4- API 层tRPC Tanstack Query v5- 测试Vitest Testing Library## 代码规范- 组件文件使用 PascalCase 命名- Hook 文件以 use 开头放在 hooks/ 目录- 服务端组件优先只在需要交互时用 use client- 所有 API 调用走 tRPC router## 目录结构src/app/ # Next.js App Router 页面components/ # 公共组件features/ # 业务模块按功能拆分hooks/ # 自定义 Hookslib/ # 工具函数server/ # tRPC router 和服务端逻辑回答问题时必须严格遵循上述技术栈和规范。;这就是 CLAUDE.md / .cursorrules 文件的本质——它们就是一种知识注入型 System Prompt只不过由 IDE 自动注入到对话上下文里。三、Few-Shot 策略让模型照葫芦画瓢Few-Shot 是 Prompt Engineering 里最立竿见影的技巧。简单说就是在 Prompt 里给几个标准答案模型就会模仿着来。▎Zero-Shot vs One-Shot vs Few-Shottypescript// Zero-Shot只给指令不给示例const zeroShot {system: 把用户输入的中文技术名词翻译成标准英文术语。,messages: [{ role: user, content: 响应式设计 }]};// 输出可能是Responsive Design ✅ 也可能是 Reactive Design ❌// One-Shot给 1 个示例const oneShot {system: 把用户输入的中文技术名词翻译成标准英文术语。,messages: [{ role: user, content: 虚拟DOM },{ role: assistant, content: Virtual DOM },{ role: user, content: 响应式设计 }]};// 输出更稳定Responsive Design ✅// Few-Shot给 3~5 个示例const fewShot {system: 把用户输入的中文技术名词翻译成标准英文术语。,messages: [{ role: user, content: 虚拟DOM },{ role: assistant, content: Virtual DOM },{ role: user, content: 服务端渲染 },{ role: assistant, content: Server-Side Rendering (SSR) },{ role: user, content: 代码分割 },{ role: assistant, content: Code Splitting },{ role: user, content: 响应式设计 }]};// 输出最稳定格式也一致 ✅经验法则策略适用场景Token 开销准确率Zero-Shot简单、明确的任务最低~60-70%One-Shot需要格式示范的任务低~80%Few-Shot (3-5)复杂格式 / 分类 / 风格要求高的任务中等~90-95%▎Few-Shot 示例的选择策略给什么样的示例直接影响效果。这里有 3 个原则原则 1覆盖边界情况typescriptconst classificationExamples [// 典型案例{ input: useState 的初始值可以是函数吗, label: React-Hooks },// 边界案例——跨领域的{ input: Next.js 的 getServerSideProps 算 Hook 吗, label: Next.js-SSR },// 容易混淆的{ input: useEffect 和 useLayoutEffect 有什么区别, label: React-Hooks },// 否定案例{ input: 如何用 Python 搭建 REST API, label: Out-of-scope },];原则 2示例要多样化但格式要统一typescript// ❌ 反面教材——示例太相似const badExamples [{ input: 什么是 useState, output: React Hook用于... },{ input: 什么是 useEffect, output: React Hook用于... },{ input: 什么是 useRef, output: React Hook用于... },];// ✅ 正确做法——输入多样输出格式统一const goodExamples [{ input: 什么是 useState, output: **分类**State Hook\n**用途**管理组件局部状态\n**示例**const [val, setVal] useState(初始值) },{ input: 如何做路由懒加载, output: **分类**性能优化\n**用途**按需加载路由组件\n**示例**E6DB74const Page lazy(() import(./Page)) },{ input: CSS Modules 和 Tailwind 选哪个, output: **分类**样式方案对比\n**用途**组件级样式隔离 vs 原子化 CSS\n**示例**根据团队规模和项目类型选择... },];原则 3动态 Few-Shot —— 根据用户输入动态选择最相关的示例这是高级玩法在 RAG 场景里特别有用typescriptimport { cosineSimilarity } from ./utils;interface Example {input: string;output: string;embedding: number[];}async function dynamicFewShot(userQuery: string,examplePool: Example[],topK: number 3): PromiseExample[] {// 1. 把用户输入向量化const queryEmbedding await getEmbedding(userQuery);// 2. 计算与所有候选示例的相似度const scored examplePool.map(ex ({...ex,score: cosineSimilarity(queryEmbedding, ex.embedding),}));// 3. 选出最相关的 Top-K 个return scored.sort((a, b) b.score - a.score).slice(0, topK);}// 使用const selectedExamples await dynamicFewShot(userInput, allExamples, 3);const messages [...selectedExamples.flatMap(ex [{ role: user as const, content: ex.input },{ role: assistant as const, content: ex.output },]),{ role: user as const, content: userInput },];核心思想静态 Few-Shot 浪费 Token很多示例跟当前问题无关动态 Few-Shot 让每个 Token 都花在刀刃上。四、Chain-of-Thought让模型想清楚再回答Chain-of-ThoughtCoT是让 LLM 展示推理过程的技巧。对于需要逻辑推理的任务特别有效。▎基础用法typescriptconst cotSystem 你是一个前端性能优化顾问。当用户描述性能问题时你需要1. 先分析可能的原因列出 2-3 个2. 对每个原因解释为什么会导致这个问题3. 给出排查步骤4. 最后给出推荐的解决方案请一步一步思考不要跳过推理过程。;// 用户输入我的 React 列表页滚动很卡▎结合 Few-Shot 的 CoTtypescriptconst cotFewShot {system: 你是前端 Bug 诊断专家。按照现象 → 分析 → 根因 → 修复的步骤回答。,messages: [{role: user,content: 组件 mount 后 API 请求发了两次},{role: assistant,content: **现象**组件挂载后同一个 API 请求被触发了两次。**分析**1. React 18 的 Strict Mode 会在开发模式下故意 double-invoke useEffect2. 可能存在多个 useEffect 都触发了同一请求3. 父组件 re-render 导致子组件重新挂载**根因**大概率是 React 18 Strict Mode 的行为。在开发模式下React 会先挂载 → 卸载 → 重新挂载组件以检测副作用是否正确清理。**修复**\\E6DB74\tsxuseEffect(() {const controller new AbortController();fetchData({ signal: controller.signal });return () controller.abort(); // 清理函数中取消请求}, []);\E6DB74\\E6DB74这样第一次挂载的请求会在卸载时被 abort只有第二次的请求会完成。},{role: user,content: 页面白屏了控制台没有报错},],};▎CoT 的前端应用场景场景不用 CoT用 CoT代码审查这段代码有问题第 15 行的 useEffect 缺少依赖项 → 会导致闭包陷阱 → 建议加上 deps方案选型用 Zustand需求是跨组件共享 → Redux 太重 → Jotai 原子化不适合 → Zustand 轻量且 API 简单Bug 定位检查一下网络请求白屏无报错 → 可能是 SSR hydration 不匹配 → 检查 useEffect 中的 DOM 操作五、Prompt 链式调用把大象装进冰箱遇到复杂任务怎么办一个 Prompt 搞不定就分多步这就是 Prompt Chain链式调用。▎核心思想把一步到位的大任务拆成多步小任务每一步的输出作为下一步的输入需求描述 → [Prompt 1: 需求分析] → 结构化需求→ [Prompt 2: 方案设计] → 技术方案→ [Prompt 3: 代码生成] → 初版代码→ [Prompt 4: 代码审查] → 最终代码▎实战自动化组件生成流水线typescriptinterface PipelineContext {requirement: string;analysis?: string;design?: string;code?: string;review?: string;}// Step 1: 需求分析async function analyzeRequirement(ctx: PipelineContext): PromisePipelineContext {const response await llm({system: 你是需求分析师。把用户的自然语言需求转成结构化描述。输出 JSON{ features: string[], props: string[], interactions: string[], edgeCases: string[] },user: ctx.requirement,});return { ...ctx, analysis: response };}// Step 2: 技术方案设计async function designSolution(ctx: PipelineContext): PromisePipelineContext {const response await llm({system: 你是前端架构师。根据需求分析结果设计组件的技术方案。包括组件拆分、状态设计、Props 接口、关键实现思路。,user: 需求分析结果\n${ctx.analysis},});return { ...ctx, design: response };}// Step 3: 代码生成async function generateCode(ctx: PipelineContext): PromisePipelineContext {const response await llm({system: 你是资深 React 开发者。根据技术方案生成完整的 TypeScript React 组件代码。要求函数式组件、完整类型定义、包含基本测试用例。,user: E6DB74技术方案\n${ctx.design},});return { ...ctx, code: response };}// Step 4: 代码审查async function reviewCode(ctx: PipelineContext): PromisePipelineContext {const response await llm({system: 你是严格的代码审查员。审查以下代码给出修改建议并输出最终优化版本。重点关注类型安全、性能、可访问性a11y、边界情况处理。,user: E6DB74原始需求${ctx.requirement}\n\n代码\n${ctx.code},});return { ...ctx, review: response };}// 串联整个流水线async function componentPipeline(requirement: string) {let ctx: PipelineContext { requirement };ctx await analyzeRequirement(ctx);ctx await designSolution(ctx);ctx await generateCode(ctx);ctx await reviewCode(ctx);return ctx;}// 使用const result await componentPipeline(做一个支持拖拽排序的 Kanban 看板组件要有列和卡片支持跨列拖拽);▎链式调用 vs 单次调用对比维度单次调用链式调用输出质量中等容易遗漏细节高每步都聚焦一个小目标可控性低黑盒一把梭高每步可检查和修正Token 消耗低一次请求高多次请求延迟低高串行多次适用场景简单任务复杂的多步骤任务什么时候用链式调用判断标准很简单如果你发现一个 Prompt 写得越来越长、越来越难维护那就该拆了。六、Prompt 版本管理与测试Prompt 也是代码需要版本管理和自动化测试。▎Prompt 模板化管理typescript// prompts/code-review.tsexport const CODE_REVIEW_PROMPT {version: 2.1.0,lastUpdated: 2026-03-13,system: 你是一名前端代码审查员...完整 system prompt,temperature: 0.3,model: claude-sonnet-4-20250514,} as const;// prompts/index.tsexport { CODE_REVIEW_PROMPT } from ./code-review;export { COMPONENT_GEN_PROMPT } from ./component-gen;export { BUG_DIAGNOSIS_PROMPT } from ./bug-diagnosis;// prompts/changelog.md// ## v2.1.0 (2026-03-13)// - 新增 a11y 审查维度// - 修复对 Server Component 误报的问题// ## v2.0.0 (2026-02-20)// - 重构输出格式为结构化 JSON▎自动化 Prompt 测试typescriptimport { describe, it, expect } from vitest;interface PromptTestCase {name: string;input: string;expectedBehavior: {containsKeywords?: string[];matchesFormat?: RegExp;sentiment?: positive | negative | neutral;maxLength?: number;};}const testCases: PromptTestCase[] [{name: 应该识别出 useEffect 缺少依赖项,input: useEffect(() {fetchUser(userId);}, []);,expectedBehavior: {containsKeywords: [依赖, userId, deps],matchesFormat: /\[严重|警告|建议\]/,},},{name: 对于合规代码不应误报,input: const [count, setCount] useState(0);return button onClick{() setCount(c c 1)}{count}/button;,expectedBehavior: {containsKeywords: [良好, 评分],sentiment: positive,},},];describe(Code Review Prompt v2.1.0, () {testCases.forEach(tc {it(tc.name, async () {const response await callLLM({system: CODE_REVIEW_PROMPT.system,user: tc.input,});if (tc.expectedBehavior.containsKeywords) {tc.expectedBehavior.containsKeywords.forEach(kw {expect(response).toContain(kw);});}if (tc.expectedBehavior.matchesFormat) {expect(response).toMatch(tc.expectedBehavior.matchesFormat);}if (tc.expectedBehavior.maxLength) {expect(response.length).toBeLessThan(tc.expectedBehavior.maxLength);}});});});▎LLM-as-Judge用 AI 评估 AI当人工评估跟不上迭代速度时可以用一个裁判模型来自动打分typescriptasync function llmJudge(prompt: string,output: string,criteria: string[]): Promise{ score: number; feedback: string } {const judgeResponse await llm({system: 你是一个严格的输出质量评估专家。根据以下评估维度给输出打分1-10并给出详细反馈。评估维度${criteria.join(、)},user: E6DB74原始 Prompt${prompt}\n\n模型输出${output},});return JSON.parse(judgeResponse);}// 批量评估async function batchEvaluate(promptVersion: string, testInputs: string[]) {const results await Promise.all(testInputs.map(async input {const output await callLLM({ system: promptVersion, user: input });const judge await llmJudge(input, output, [准确性, 完整性, 格式合规]);return { input, output, ...judge };}));const avgScore results.reduce((sum, r) sum r.score, 0) / results.length;console.log(E6DB74Prompt 版本平均得分${avgScore.toFixed(2)});return results;}七、避坑指南5 个常见的 Prompt 陷阱▎坑 1System Prompt 写成了许愿文typescript// ❌ 太模糊等于没写const bad 请生成高质量的代码;// ✅ 具体、可衡量const good 生成的代码需要满足以下标准1. TypeScript strict 模式无报错2. 单个函数不超过 30 行3. 所有 Props 都有 JSDoc 注释4. 包含至少 2 个单元测试用例;▎坑 2Few-Shot 示例和实际任务差距太大typescript// ❌ 示例是简单翻译实际任务是复杂分析const badFewShot [{ input: Hello, output: 你好 }, // 简单翻译示例// 但实际问任务分析这段 500 行的代码有什么性能问题];// ✅ 示例难度要匹配实际任务const goodFewShot [{input: 分析以下代码的性能问题\nfor(let i of arr) { document.getElementById(x).style.color red; },output: 问题循环内部重复查询 DOM。建议将 getElementById 提到循环外部...,},];▎坑 3Prompt 太长导致注意力稀释LLM 的注意力不是均匀的——开头和结尾的权重最高中间容易被忽略。typescript// ❌ 把重要规则埋在中间const bad 你是...(50行角色设定)...(100行知识库)注意输出必须是JSON格式 // ← 这条被淹没了...(50行其他规则);// ✅ 重要规则放在开头和结尾const good 【核心要求】输出必须是严格的 JSON 格式无其他内容。你是...(角色设定)...(知识库)【再次提醒】确保输出是可直接 JSON.parse 的纯 JSON。;▎坑 4温度参数设置不合理typescript// 代码生成要确定性temperature 调低const codeGen { temperature: 0.2, top_p: 0.9 };// 创意写作要多样性temperature 调高const creative { temperature: 0.8, top_p: 0.95 };// 分类/判断任务要最确定的答案const classification { temperature: 0 };▎坑 5不做回归测试就改 Prompt改一行 Prompt 可能影响所有场景的输出。一定要建立测试套件typescript// 每次修改 Prompt 前// 1. 先跑一遍测试套件记录基准分// 2. 修改 Prompt// 3. 再跑测试套件对比新旧分数// 4. 只有不低于基准分才允许上线async function regressionTest(oldPrompt: string, newPrompt: string) {const testInputs loadTestSuite(code-review);const [oldScores, newScores] await Promise.all([batchEvaluate(oldPrompt, testInputs),batchEvaluate(newPrompt, testInputs),]);const oldAvg average(oldScores.map(s s.score));const newAvg average(newScores.map(s s.score));if (newAvg oldAvg * 0.95) {throw new Error(Prompt 回归旧版 ${oldAvg.toFixed(2)} → 新版 ${newAvg.toFixed(2)});}console.log(E6DB74✅ 回归测试通过${oldAvg.toFixed(2)} → ${newAvg.toFixed(2)});}八、完整实战构建一个 Prompt 管理 SDK把上面所有技巧组合起来封装成项目里能直接用的 SDKtypescript// lib/prompt-manager.tsinterface PromptConfig {version: string;system: string;fewShotExamples?: Array{ input: string; output: string };temperature?: number;model?: string;maxTokens?: number;}class PromptManager {private prompts: Mapstring, PromptConfig new Map();private history: Mapstring, PromptConfig[] new Map();register(name: string, config: PromptConfig) {// 保存历史版本const prev this.history.get(name) || [];const current this.prompts.get(name);if (current) prev.push(current);this.history.set(name, prev);this.prompts.set(name, config);}async execute(name: string, userInput: string) {const config this.prompts.get(name);if (!config) throw new Error(Prompt ${name} not found);const messages: Array{ role: user | assistant; content: string } [];// 组装 Few-Shotif (config.fewShotExamples) {for (const ex of config.fewShotExamples) {messages.push({ role: user, content: ex.input });messages.push({ role: assistant, content: ex.output });}}messages.push({ role: user, content: userInput });return await callLLM({system: config.system,messages,temperature: config.temperature ?? 0.3,model: config.model ?? claude-sonnet-4-20250514,maxTokens: config.maxTokens ?? 2048,});}rollback(name: string) {const prev this.history.get(name);if (!prev || prev.length 0) throw new Error(No previous version);this.prompts.set(name, prev.pop()!);}}// 使用示例const pm new PromptManager();pm.register(code-review, {version: 2.1.0,system: E6DB74你是一名前端代码审查员...,fewShotExamples: [{ input: ...有问题的代码..., output: ...[警告] 分析和修复建议... },],temperature: 0.2,});const result await pm.execute(code-review, userCode);九、总结一张表回顾这篇文章的核心知识点主题核心要点适用场景角色扮演给模型一个明确的专家身份所有场景的基础规则约束正面 负面双重约束需要控制边界的场景输出格式JSON Zod 运行时校验需要程序化消费输出知识注入在 System Prompt 塞入私有知识项目特定规范、API 文档Few-Shot3~5 个多样化示例格式要求高、分类任务动态 Few-Shot向量相似度选择示例大型示例库、RAG 场景CoT让模型展示推理过程逻辑推理、Bug 诊断链式调用大任务拆成小步骤复杂的多步骤任务Prompt 测试自动化回归测试 LLM-as-Judge生产环境的 Prompt 管理▎推荐资源▸OpenAI Prompt Engineering Guide —— 官方最佳实践▸Anthropic Prompt Engineering —— Claude 的 Prompt 技巧▸LangChain.js Prompt Templates —— 代码级 Prompt 管理▸Prompt Engineering Guide —— 社区整理的完整指南往期推荐Multi-Agent Teams让多个专家 Agent 像团队一样协作AI Agent 是怎么想一步做一步的拆解 ReAct 模式从零开始用 LangChain.js 构建你的第一个 Tool-Calling Agent最后点个在看支持我吧
Prompt Engineering 进阶:System Prompt 设计模式与 Few-Shot 策略
点击上方 前端Q关注公众号回复加群加入前端Q技术交流你有没有这种感觉同样一个模型有人写的 Prompt 就是比你的好用这不是玄学是工程。为什么前端需要学 Prompt Engineering你可能觉得 Prompt Engineering 是给 AI 研究员玩的跟前端没啥关系。但现实是——你每天都在写 Prompt▸在 Cursor 里给 AI 下指令写代码▸在项目里调用 OpenAI / Claude API▸配置CLAUDE.md/.cursorrules规则文件▸给 RAG 系统写检索和生成模板上面这些全都是 Prompt Engineering 的应用场景。掌握 System Prompt 设计模式和 Few-Shot 策略能让你的 AI 输出质量直接上一个台阶。一、Prompt 的基本结构在正式讲设计模式之前先搞清楚一个 API 调用里 Prompt 的结构typescriptimport Anthropic from anthropic-ai/sdk;const client new Anthropic();const response await client.messages.create({model: claude-sonnet-4-20250514,max_tokens: 1024,// ① System Prompt —— 设定角色、规则、背景知识system: 你是一个资深前端工程师精通 React 和 TypeScript。回答要简洁、有代码示例使用中文。,messages: [// ② Few-Shot Examples —— 给模型看几个标准答案{ role: user, content: 如何用 React 实现一个计数器 },{ role: assistant, content: tsx\nconst [count, setCount] useState(0);\nE6DB74 },// ③ 真正的用户问题{ role: user, content: 如何用 React 实现一个 Todo List },],});一个完整的 Prompt 由三层组成层级作用类比System Prompt设定角色、规则、输出格式新员工入职培训手册Few-Shot Examples给几个输入→输出的示范老员工带新人做几个案例User Prompt当前要处理的具体任务今天分配的工作任务关键认知System Prompt 决定了模型是谁Few-Shot 决定了模型怎么做User Prompt 决定了模型做什么。二、System Prompt 的 4 种设计模式System Prompt 不是随便写两句话就行的它有明确的设计模式。我总结了工作中最常用的 4 种▎模式一角色扮演Role Playing最常用的模式给 LLM 一个明确的身份定位。typescriptconst systemPrompt 你是一名有 10 年经验的前端架构师专注于 React 生态。你的特点- 偏好函数式组件和 Hooks- 重视 TypeScript 类型安全- 关注性能优化和可维护性- 代码风格遵循 Airbnb 规范;为什么有效角色设定不是装模作样它实际上在做两件事缩小输出空间模型不再漫无目的地生成而是沿着特定角色的知识和风格来回答激活相关知识模型会优先调用与该角色相关的训练数据前端实战示例——代码审查助手typescriptconst codeReviewSystem 你是一名严格的前端代码审查员。审查维度按优先级排序1. 安全性XSS、CSRF、敏感数据泄露2. 性能不必要的 re-render、内存泄漏、大包体积3. 可维护性命名规范、组件拆分合理性、类型覆盖4. 代码风格ESLint 规则合规、一致性输出格式- 每个问题给出 [严重/警告/建议] 标签- 附上修复后的代码示例- 最后给出整体评分1-10;▎模式二规则约束Rule Constraints给模型划定明确的行为边界告诉它什么能做、什么不能做。typescriptconst constrainedSystem 你是一个 API 文档生成助手。必须遵守的规则1. 只回答与前端开发相关的问题其他领域回复这不在我的专业范围内2. 代码示例必须使用 TypeScript不允许 any 类型3. 所有异步操作必须有错误处理4. 不得推荐已废弃的 API如 componentWillMount5. 涉及安全敏感操作时必须提醒用户注意风险禁止事项- 不输出与任务无关的闲聊- 不编造不存在的 API- 不给出未经验证的性能数据;关键技巧规则约束最好用正面表述 负面表述结合的方式▸正面必须用 TypeScript▸负面不允许 any 类型这比单独用任何一种都更有效因为模型对边界更敏感。▎模式三输出格式控制Output Format当你需要把 LLM 的输出直接喂给下游代码处理时格式控制是必须的。typescriptconst formatSystem 你是一个前端组件分析器。分析用户给出的 React 组件代码按以下 JSON 格式输出{componentName: 组件名称,type: functional | class,props: [{ name: 属性名, type: TS类型, required: true/false, description: 描述 }],hooks: [useState, useEffect],dependencies: [外部依赖包名],complexity: low | medium | high,suggestions: [优化建议1, 优化建议2]}注意- 输出纯 JSON不要加 markdown 代码块- 所有字段都必须填写没有则用空数组或 unknown- complexity 根据嵌套层级、条件分支数量、hook 数量综合判断;进阶技巧——结合 Zod 做运行时校验typescriptimport { z } from zod;const ComponentAnalysis z.object({componentName: z.string(),type: z.enum([functional, class]),props: z.array(z.object({name: z.string(),type: z.string(),required: z.boolean(),description: z.string(),})),hooks: z.array(z.string()),dependencies: z.array(z.string()),complexity: z.enum([low, medium, high]),suggestions: z.array(z.string()),});async function analyzeComponent(code: string) {const response await client.messages.create({model: claude-sonnet-4-20250514,system: formatSystem,messages: [{ role: user, content: code }],max_tokens: 2048,});const text response.content[0].type text ? response.content[0].text : ;const parsed JSON.parse(text);return ComponentAnalysis.parse(parsed); // 运行时类型校验}▎模式四知识注入Knowledge Injection在 System Prompt 里直接塞入领域知识让模型基于你的私有信息来回答。typescriptconst knowledgeSystem 你是我们团队的前端技术顾问。以下是项目的技术栈和规范## 技术栈- 框架Next.js 15 (App Router)- 状态管理Zustand v5- 样式方案Tailwind CSS v4- API 层tRPC Tanstack Query v5- 测试Vitest Testing Library## 代码规范- 组件文件使用 PascalCase 命名- Hook 文件以 use 开头放在 hooks/ 目录- 服务端组件优先只在需要交互时用 use client- 所有 API 调用走 tRPC router## 目录结构src/app/ # Next.js App Router 页面components/ # 公共组件features/ # 业务模块按功能拆分hooks/ # 自定义 Hookslib/ # 工具函数server/ # tRPC router 和服务端逻辑回答问题时必须严格遵循上述技术栈和规范。;这就是 CLAUDE.md / .cursorrules 文件的本质——它们就是一种知识注入型 System Prompt只不过由 IDE 自动注入到对话上下文里。三、Few-Shot 策略让模型照葫芦画瓢Few-Shot 是 Prompt Engineering 里最立竿见影的技巧。简单说就是在 Prompt 里给几个标准答案模型就会模仿着来。▎Zero-Shot vs One-Shot vs Few-Shottypescript// Zero-Shot只给指令不给示例const zeroShot {system: 把用户输入的中文技术名词翻译成标准英文术语。,messages: [{ role: user, content: 响应式设计 }]};// 输出可能是Responsive Design ✅ 也可能是 Reactive Design ❌// One-Shot给 1 个示例const oneShot {system: 把用户输入的中文技术名词翻译成标准英文术语。,messages: [{ role: user, content: 虚拟DOM },{ role: assistant, content: Virtual DOM },{ role: user, content: 响应式设计 }]};// 输出更稳定Responsive Design ✅// Few-Shot给 3~5 个示例const fewShot {system: 把用户输入的中文技术名词翻译成标准英文术语。,messages: [{ role: user, content: 虚拟DOM },{ role: assistant, content: Virtual DOM },{ role: user, content: 服务端渲染 },{ role: assistant, content: Server-Side Rendering (SSR) },{ role: user, content: 代码分割 },{ role: assistant, content: Code Splitting },{ role: user, content: 响应式设计 }]};// 输出最稳定格式也一致 ✅经验法则策略适用场景Token 开销准确率Zero-Shot简单、明确的任务最低~60-70%One-Shot需要格式示范的任务低~80%Few-Shot (3-5)复杂格式 / 分类 / 风格要求高的任务中等~90-95%▎Few-Shot 示例的选择策略给什么样的示例直接影响效果。这里有 3 个原则原则 1覆盖边界情况typescriptconst classificationExamples [// 典型案例{ input: useState 的初始值可以是函数吗, label: React-Hooks },// 边界案例——跨领域的{ input: Next.js 的 getServerSideProps 算 Hook 吗, label: Next.js-SSR },// 容易混淆的{ input: useEffect 和 useLayoutEffect 有什么区别, label: React-Hooks },// 否定案例{ input: 如何用 Python 搭建 REST API, label: Out-of-scope },];原则 2示例要多样化但格式要统一typescript// ❌ 反面教材——示例太相似const badExamples [{ input: 什么是 useState, output: React Hook用于... },{ input: 什么是 useEffect, output: React Hook用于... },{ input: 什么是 useRef, output: React Hook用于... },];// ✅ 正确做法——输入多样输出格式统一const goodExamples [{ input: 什么是 useState, output: **分类**State Hook\n**用途**管理组件局部状态\n**示例**const [val, setVal] useState(初始值) },{ input: 如何做路由懒加载, output: **分类**性能优化\n**用途**按需加载路由组件\n**示例**E6DB74const Page lazy(() import(./Page)) },{ input: CSS Modules 和 Tailwind 选哪个, output: **分类**样式方案对比\n**用途**组件级样式隔离 vs 原子化 CSS\n**示例**根据团队规模和项目类型选择... },];原则 3动态 Few-Shot —— 根据用户输入动态选择最相关的示例这是高级玩法在 RAG 场景里特别有用typescriptimport { cosineSimilarity } from ./utils;interface Example {input: string;output: string;embedding: number[];}async function dynamicFewShot(userQuery: string,examplePool: Example[],topK: number 3): PromiseExample[] {// 1. 把用户输入向量化const queryEmbedding await getEmbedding(userQuery);// 2. 计算与所有候选示例的相似度const scored examplePool.map(ex ({...ex,score: cosineSimilarity(queryEmbedding, ex.embedding),}));// 3. 选出最相关的 Top-K 个return scored.sort((a, b) b.score - a.score).slice(0, topK);}// 使用const selectedExamples await dynamicFewShot(userInput, allExamples, 3);const messages [...selectedExamples.flatMap(ex [{ role: user as const, content: ex.input },{ role: assistant as const, content: ex.output },]),{ role: user as const, content: userInput },];核心思想静态 Few-Shot 浪费 Token很多示例跟当前问题无关动态 Few-Shot 让每个 Token 都花在刀刃上。四、Chain-of-Thought让模型想清楚再回答Chain-of-ThoughtCoT是让 LLM 展示推理过程的技巧。对于需要逻辑推理的任务特别有效。▎基础用法typescriptconst cotSystem 你是一个前端性能优化顾问。当用户描述性能问题时你需要1. 先分析可能的原因列出 2-3 个2. 对每个原因解释为什么会导致这个问题3. 给出排查步骤4. 最后给出推荐的解决方案请一步一步思考不要跳过推理过程。;// 用户输入我的 React 列表页滚动很卡▎结合 Few-Shot 的 CoTtypescriptconst cotFewShot {system: 你是前端 Bug 诊断专家。按照现象 → 分析 → 根因 → 修复的步骤回答。,messages: [{role: user,content: 组件 mount 后 API 请求发了两次},{role: assistant,content: **现象**组件挂载后同一个 API 请求被触发了两次。**分析**1. React 18 的 Strict Mode 会在开发模式下故意 double-invoke useEffect2. 可能存在多个 useEffect 都触发了同一请求3. 父组件 re-render 导致子组件重新挂载**根因**大概率是 React 18 Strict Mode 的行为。在开发模式下React 会先挂载 → 卸载 → 重新挂载组件以检测副作用是否正确清理。**修复**\\E6DB74\tsxuseEffect(() {const controller new AbortController();fetchData({ signal: controller.signal });return () controller.abort(); // 清理函数中取消请求}, []);\E6DB74\\E6DB74这样第一次挂载的请求会在卸载时被 abort只有第二次的请求会完成。},{role: user,content: 页面白屏了控制台没有报错},],};▎CoT 的前端应用场景场景不用 CoT用 CoT代码审查这段代码有问题第 15 行的 useEffect 缺少依赖项 → 会导致闭包陷阱 → 建议加上 deps方案选型用 Zustand需求是跨组件共享 → Redux 太重 → Jotai 原子化不适合 → Zustand 轻量且 API 简单Bug 定位检查一下网络请求白屏无报错 → 可能是 SSR hydration 不匹配 → 检查 useEffect 中的 DOM 操作五、Prompt 链式调用把大象装进冰箱遇到复杂任务怎么办一个 Prompt 搞不定就分多步这就是 Prompt Chain链式调用。▎核心思想把一步到位的大任务拆成多步小任务每一步的输出作为下一步的输入需求描述 → [Prompt 1: 需求分析] → 结构化需求→ [Prompt 2: 方案设计] → 技术方案→ [Prompt 3: 代码生成] → 初版代码→ [Prompt 4: 代码审查] → 最终代码▎实战自动化组件生成流水线typescriptinterface PipelineContext {requirement: string;analysis?: string;design?: string;code?: string;review?: string;}// Step 1: 需求分析async function analyzeRequirement(ctx: PipelineContext): PromisePipelineContext {const response await llm({system: 你是需求分析师。把用户的自然语言需求转成结构化描述。输出 JSON{ features: string[], props: string[], interactions: string[], edgeCases: string[] },user: ctx.requirement,});return { ...ctx, analysis: response };}// Step 2: 技术方案设计async function designSolution(ctx: PipelineContext): PromisePipelineContext {const response await llm({system: 你是前端架构师。根据需求分析结果设计组件的技术方案。包括组件拆分、状态设计、Props 接口、关键实现思路。,user: 需求分析结果\n${ctx.analysis},});return { ...ctx, design: response };}// Step 3: 代码生成async function generateCode(ctx: PipelineContext): PromisePipelineContext {const response await llm({system: 你是资深 React 开发者。根据技术方案生成完整的 TypeScript React 组件代码。要求函数式组件、完整类型定义、包含基本测试用例。,user: E6DB74技术方案\n${ctx.design},});return { ...ctx, code: response };}// Step 4: 代码审查async function reviewCode(ctx: PipelineContext): PromisePipelineContext {const response await llm({system: 你是严格的代码审查员。审查以下代码给出修改建议并输出最终优化版本。重点关注类型安全、性能、可访问性a11y、边界情况处理。,user: E6DB74原始需求${ctx.requirement}\n\n代码\n${ctx.code},});return { ...ctx, review: response };}// 串联整个流水线async function componentPipeline(requirement: string) {let ctx: PipelineContext { requirement };ctx await analyzeRequirement(ctx);ctx await designSolution(ctx);ctx await generateCode(ctx);ctx await reviewCode(ctx);return ctx;}// 使用const result await componentPipeline(做一个支持拖拽排序的 Kanban 看板组件要有列和卡片支持跨列拖拽);▎链式调用 vs 单次调用对比维度单次调用链式调用输出质量中等容易遗漏细节高每步都聚焦一个小目标可控性低黑盒一把梭高每步可检查和修正Token 消耗低一次请求高多次请求延迟低高串行多次适用场景简单任务复杂的多步骤任务什么时候用链式调用判断标准很简单如果你发现一个 Prompt 写得越来越长、越来越难维护那就该拆了。六、Prompt 版本管理与测试Prompt 也是代码需要版本管理和自动化测试。▎Prompt 模板化管理typescript// prompts/code-review.tsexport const CODE_REVIEW_PROMPT {version: 2.1.0,lastUpdated: 2026-03-13,system: 你是一名前端代码审查员...完整 system prompt,temperature: 0.3,model: claude-sonnet-4-20250514,} as const;// prompts/index.tsexport { CODE_REVIEW_PROMPT } from ./code-review;export { COMPONENT_GEN_PROMPT } from ./component-gen;export { BUG_DIAGNOSIS_PROMPT } from ./bug-diagnosis;// prompts/changelog.md// ## v2.1.0 (2026-03-13)// - 新增 a11y 审查维度// - 修复对 Server Component 误报的问题// ## v2.0.0 (2026-02-20)// - 重构输出格式为结构化 JSON▎自动化 Prompt 测试typescriptimport { describe, it, expect } from vitest;interface PromptTestCase {name: string;input: string;expectedBehavior: {containsKeywords?: string[];matchesFormat?: RegExp;sentiment?: positive | negative | neutral;maxLength?: number;};}const testCases: PromptTestCase[] [{name: 应该识别出 useEffect 缺少依赖项,input: useEffect(() {fetchUser(userId);}, []);,expectedBehavior: {containsKeywords: [依赖, userId, deps],matchesFormat: /\[严重|警告|建议\]/,},},{name: 对于合规代码不应误报,input: const [count, setCount] useState(0);return button onClick{() setCount(c c 1)}{count}/button;,expectedBehavior: {containsKeywords: [良好, 评分],sentiment: positive,},},];describe(Code Review Prompt v2.1.0, () {testCases.forEach(tc {it(tc.name, async () {const response await callLLM({system: CODE_REVIEW_PROMPT.system,user: tc.input,});if (tc.expectedBehavior.containsKeywords) {tc.expectedBehavior.containsKeywords.forEach(kw {expect(response).toContain(kw);});}if (tc.expectedBehavior.matchesFormat) {expect(response).toMatch(tc.expectedBehavior.matchesFormat);}if (tc.expectedBehavior.maxLength) {expect(response.length).toBeLessThan(tc.expectedBehavior.maxLength);}});});});▎LLM-as-Judge用 AI 评估 AI当人工评估跟不上迭代速度时可以用一个裁判模型来自动打分typescriptasync function llmJudge(prompt: string,output: string,criteria: string[]): Promise{ score: number; feedback: string } {const judgeResponse await llm({system: 你是一个严格的输出质量评估专家。根据以下评估维度给输出打分1-10并给出详细反馈。评估维度${criteria.join(、)},user: E6DB74原始 Prompt${prompt}\n\n模型输出${output},});return JSON.parse(judgeResponse);}// 批量评估async function batchEvaluate(promptVersion: string, testInputs: string[]) {const results await Promise.all(testInputs.map(async input {const output await callLLM({ system: promptVersion, user: input });const judge await llmJudge(input, output, [准确性, 完整性, 格式合规]);return { input, output, ...judge };}));const avgScore results.reduce((sum, r) sum r.score, 0) / results.length;console.log(E6DB74Prompt 版本平均得分${avgScore.toFixed(2)});return results;}七、避坑指南5 个常见的 Prompt 陷阱▎坑 1System Prompt 写成了许愿文typescript// ❌ 太模糊等于没写const bad 请生成高质量的代码;// ✅ 具体、可衡量const good 生成的代码需要满足以下标准1. TypeScript strict 模式无报错2. 单个函数不超过 30 行3. 所有 Props 都有 JSDoc 注释4. 包含至少 2 个单元测试用例;▎坑 2Few-Shot 示例和实际任务差距太大typescript// ❌ 示例是简单翻译实际任务是复杂分析const badFewShot [{ input: Hello, output: 你好 }, // 简单翻译示例// 但实际问任务分析这段 500 行的代码有什么性能问题];// ✅ 示例难度要匹配实际任务const goodFewShot [{input: 分析以下代码的性能问题\nfor(let i of arr) { document.getElementById(x).style.color red; },output: 问题循环内部重复查询 DOM。建议将 getElementById 提到循环外部...,},];▎坑 3Prompt 太长导致注意力稀释LLM 的注意力不是均匀的——开头和结尾的权重最高中间容易被忽略。typescript// ❌ 把重要规则埋在中间const bad 你是...(50行角色设定)...(100行知识库)注意输出必须是JSON格式 // ← 这条被淹没了...(50行其他规则);// ✅ 重要规则放在开头和结尾const good 【核心要求】输出必须是严格的 JSON 格式无其他内容。你是...(角色设定)...(知识库)【再次提醒】确保输出是可直接 JSON.parse 的纯 JSON。;▎坑 4温度参数设置不合理typescript// 代码生成要确定性temperature 调低const codeGen { temperature: 0.2, top_p: 0.9 };// 创意写作要多样性temperature 调高const creative { temperature: 0.8, top_p: 0.95 };// 分类/判断任务要最确定的答案const classification { temperature: 0 };▎坑 5不做回归测试就改 Prompt改一行 Prompt 可能影响所有场景的输出。一定要建立测试套件typescript// 每次修改 Prompt 前// 1. 先跑一遍测试套件记录基准分// 2. 修改 Prompt// 3. 再跑测试套件对比新旧分数// 4. 只有不低于基准分才允许上线async function regressionTest(oldPrompt: string, newPrompt: string) {const testInputs loadTestSuite(code-review);const [oldScores, newScores] await Promise.all([batchEvaluate(oldPrompt, testInputs),batchEvaluate(newPrompt, testInputs),]);const oldAvg average(oldScores.map(s s.score));const newAvg average(newScores.map(s s.score));if (newAvg oldAvg * 0.95) {throw new Error(Prompt 回归旧版 ${oldAvg.toFixed(2)} → 新版 ${newAvg.toFixed(2)});}console.log(E6DB74✅ 回归测试通过${oldAvg.toFixed(2)} → ${newAvg.toFixed(2)});}八、完整实战构建一个 Prompt 管理 SDK把上面所有技巧组合起来封装成项目里能直接用的 SDKtypescript// lib/prompt-manager.tsinterface PromptConfig {version: string;system: string;fewShotExamples?: Array{ input: string; output: string };temperature?: number;model?: string;maxTokens?: number;}class PromptManager {private prompts: Mapstring, PromptConfig new Map();private history: Mapstring, PromptConfig[] new Map();register(name: string, config: PromptConfig) {// 保存历史版本const prev this.history.get(name) || [];const current this.prompts.get(name);if (current) prev.push(current);this.history.set(name, prev);this.prompts.set(name, config);}async execute(name: string, userInput: string) {const config this.prompts.get(name);if (!config) throw new Error(Prompt ${name} not found);const messages: Array{ role: user | assistant; content: string } [];// 组装 Few-Shotif (config.fewShotExamples) {for (const ex of config.fewShotExamples) {messages.push({ role: user, content: ex.input });messages.push({ role: assistant, content: ex.output });}}messages.push({ role: user, content: userInput });return await callLLM({system: config.system,messages,temperature: config.temperature ?? 0.3,model: config.model ?? claude-sonnet-4-20250514,maxTokens: config.maxTokens ?? 2048,});}rollback(name: string) {const prev this.history.get(name);if (!prev || prev.length 0) throw new Error(No previous version);this.prompts.set(name, prev.pop()!);}}// 使用示例const pm new PromptManager();pm.register(code-review, {version: 2.1.0,system: E6DB74你是一名前端代码审查员...,fewShotExamples: [{ input: ...有问题的代码..., output: ...[警告] 分析和修复建议... },],temperature: 0.2,});const result await pm.execute(code-review, userCode);九、总结一张表回顾这篇文章的核心知识点主题核心要点适用场景角色扮演给模型一个明确的专家身份所有场景的基础规则约束正面 负面双重约束需要控制边界的场景输出格式JSON Zod 运行时校验需要程序化消费输出知识注入在 System Prompt 塞入私有知识项目特定规范、API 文档Few-Shot3~5 个多样化示例格式要求高、分类任务动态 Few-Shot向量相似度选择示例大型示例库、RAG 场景CoT让模型展示推理过程逻辑推理、Bug 诊断链式调用大任务拆成小步骤复杂的多步骤任务Prompt 测试自动化回归测试 LLM-as-Judge生产环境的 Prompt 管理▎推荐资源▸OpenAI Prompt Engineering Guide —— 官方最佳实践▸Anthropic Prompt Engineering —— Claude 的 Prompt 技巧▸LangChain.js Prompt Templates —— 代码级 Prompt 管理▸Prompt Engineering Guide —— 社区整理的完整指南往期推荐Multi-Agent Teams让多个专家 Agent 像团队一样协作AI Agent 是怎么想一步做一步的拆解 ReAct 模式从零开始用 LangChain.js 构建你的第一个 Tool-Calling Agent最后点个在看支持我吧