大模型辅助的 UI 文案生成:让每一个按钮都说“人话“

大模型辅助的 UI 文案生成:让每一个按钮都说“人话“
大模型辅助的 UI 文案生成让每一个按钮都说人话一、点击确定代表您同意我们的服务条款和隐私政策以及数据收集协议你一定见过这种按钮文案。它的问题不是写错了而是写得太正确了——正确到用户根本不想读。UI 文案UX Writing是设计中最容易被忽视的环节。设计师会把大量精力花在间距、色彩、动效上但按钮上的文字往往是最后一分钟随手写的。而事实是一段好的按钮文案比一个精美的渐变背景更能提升转化率。大语言模型LLM在这个领域的表现出人意料地好——因为它不需要理解设计它只需要理解语言。这篇文章我会讲如何用 AI 为你的 UI 组件生成说人话的文案从单个按钮到完整页面的文案生成管线。二、UI 文案的生成约束不是写得好而是写得对UI 文案的五种核心类型类型示例组件文案要求字数限制操作按钮CTA、提交、确认动词开头结果明确≤6 字提示信息Tooltip、Toast一句话说清状态≤20 字错误提示表单校验错误说清楚哪里错了怎么办≤40 字空状态空列表、无结果安抚引导下一步≤30 字占位文本Input placeholder给出具体示例≤15 字品牌语调的量化不同品牌需要不同的文案语调。我定义了一个语调三元组来量化语调 (亲和度, 专业度, 简洁度) - 亲和度 0-100冷漠, 10像朋友聊天 - 专业度 0-100通俗, 10学术/法律腔 - 简洁度 0-100啰嗦, 10电报不同场景的推荐语调场景语调三元组按钮示例医疗健康(7, 8, 7)查看检查报告金融理财(4, 9, 9)确认交易社交娱乐(9, 3, 6)来找点好玩的企业办公(5, 7, 8)提交审批教育学习(8, 6, 5)开始今天的学习之旅三、AI 文案生成引擎的实现/** * AI UI 文案生成引擎 */ interface CopyContext { /** 组件类型 */ componentType: button | toast | error | empty | placeholder; /** 业务场景描述 */ scenario: string; /** 品牌语调 */ brandTone: { warmth: number; // 亲和度 0-10 professionalism: number; // 专业度 0-10 conciseness: number; // 简洁度 0-10 }; /** 目标用户画像 */ audience?: string; /** 操作的结果用户点击后会发生什么 */ actionResult?: string; } interface CopyCandidate { text: string; score: number; // 综合评分 breakdown: { lengthScore: number; toneScore: number; clarityScore: number; }; } class UXCopyGenerator { /** 字数限制配置 */ private readonly LENGTH_LIMITS { button: { max: 6, ideal: 4 }, toast: { max: 20, ideal: 12 }, error: { max: 40, ideal: 20 }, empty: { max: 30, ideal: 15 }, placeholder: { max: 15, ideal: 8 }, }; /** * 基于 Prompt 工程生成候选文案 * * 调用的实际是 LLM API这里展示的是 Prompt 构建逻辑 */ buildPrompt(context: CopyContext): string { const limits this.LENGTH_LIMITS[context.componentType]; return 你是一个专业的 UI/UX 文案设计师。 请为以下场景生成 5 个候选文案 **组件类型**${context.componentType} **业务场景**${context.scenario} **用户操作后发生什么**${context.actionResult || 无特殊说明} **目标用户**${context.audience || 普通用户} **文案约束** - 字数不超过 ${limits.max} 字理想是 ${limits.ideal} 字 - 亲和度要求${context.brandTone.warmth}/10${this.describeWarmth(context.brandTone.warmth)} - 专业度要求${context.brandTone.professionalism}/10${this.describeProfessionalism(context.brandTone.professionalism)} - 简洁度要求${context.brandTone.conciseness}/10${this.describeConciseness(context.brandTone.conciseness)} **排版要求** ${this.getFormatRequirements(context.componentType)} 请直接输出 5 个候选文案每行一个不要编号。; } /** 打分引擎评估候选文案 */ scoreCandidate(text: string, context: CopyContext): CopyCandidate { const limits this.LENGTH_LIMITS[context.componentType]; // 评分维度一长度评分 const length text.length; let lengthScore 0; if (length context.brandTone.conciseness * 0.8 1) { lengthScore 1.0; } else if (length limits.ideal) { lengthScore 0.8; } else if (length limits.max) { lengthScore 0.5; } else { lengthScore 0.1; // 超长严重扣分 } // 评分维度二清晰度评分 let clarityScore 0.5; // 有动词 → 加分 if (this.hasActionVerb(text)) clarityScore 0.2; // 有明确结果 → 加分 if (text.includes(成功) || text.includes(完成) || text.includes(已) || text.includes(请)) { clarityScore 0.15; } // 没有模糊词 → 加分 if (!text.includes(可能) !text.includes(大概) !text.includes(或许)) { clarityScore 0.15; } // 评分维度三语调匹配度 const toneScore this.calculateToneMatch(text, context.brandTone); // 加权综合评分 const total lengthScore * 0.25 clarityScore * 0.4 toneScore * 0.35; return { text, score: total, breakdown: { lengthScore, toneScore, clarityScore }, }; } /** * 语调匹配度计算 * * 基于关键词和句式特征估算文本的语调 */ private calculateToneMatch(text: string, target: CopyContext[brandTone]): number { let estimatedWarmth 5; let estimatedProfessionalism 5; // 温暖度估计 if (/[!~]/.test(text)) estimatedWarmth 1; if (text.includes(吧) || text.includes(哦) || text.includes(呢)) estimatedWarmth 1; if (text.includes(您)) estimatedWarmth 1; if (text.includes(请)) estimatedProfessionalism 1; // 专业度估计 if (text.includes(确认) || text.includes(提交)) estimatedProfessionalism 1; if (text.includes(审核) || text.includes(验证)) estimatedProfessionalism 1; // 计算匹配度 const warmthDiff Math.abs(target.warmth - estimatedWarmth) / 10; const profDiff Math.abs(target.professionalism - estimatedProfessionalism) / 10; return 1 - (warmthDiff profDiff) / 2; } private hasActionVerb(text: string): boolean { const verbs [查看, 提交, 保存, 删除, 搜索, 分享, 下载, 上传, 开始, 取消, 确认, 发送, 添加, 编辑]; return verbs.some(v text.includes(v)); } private describeWarmth(score: number): string { if (score 8) return 非常亲切像朋友间的对话; if (score 6) return 温和友好保持适度的亲近感; if (score 4) return 中性不冷不热; return 专业克制避免情感表达; } private describeProfessionalism(score: number): string { if (score 8) return 高度专业使用行业术语; if (score 6) return 半正式兼顾专业和可读; return 通俗易懂避免专业术语; } private describeConciseness(score: number): string { if (score 8) return 极度精简能省则省; if (score 6) return 适中说清楚但不啰嗦; return 详细说明允许一定冗余; } private getFormatRequirements(type: string): string { const formats: Recordstring, string { button: 动词开头如查看报告不使用确定这种泛化词, toast: 陈述句说清当前状态如保存成功不使用疑问句, error: 先说哪里错了再说怎么办如邮箱格式不正确请输入有效的邮箱地址, empty: 先安抚再引导如还没有收藏内容去发现好文章吧, placeholder: 给出一个具体的示例值如例如张三不说请输入, }; return formats[type] || ; } /** * 批量生成 自动筛选 * * 调用 LLM 生成 5 个候选 → 逐一打分 → 返回 Top 3 */ async generateAndSelect(context: CopyContext): PromiseCopyCandidate[] { // 实际项目中使用 LLM API const candidates await this.callLLM(this.buildPrompt(context)); return candidates .map(text this.scoreCandidate(text, context)) .sort((a, b) b.score - a.score) .slice(0, 3); // 返回 Top 3 } private async callLLM(prompt: string): Promisestring[] { // 实际调用 OpenAI / Claude / 本地模型 // 这里返回模拟数据 return [ 查看详情, 了解更多, 点击查看, 前往查看, 打开详情, ]; } }四、边界AI 文案的三个不能不能替代法律合规审核涉及用户协议、隐私政策、金融交易确认等具有法律效力的文案AI 生成的内容需要法务团队最终审核。一个字的偏差可能导致法律纠纷。不能理解品牌的历史包袱一个品牌可能刻意避免某些词汇比如优惠听起来像打折AI 不知道这些。品牌语调词典需要人工维护。不能判断场景敏感度在医疗、金融、法律产品中一句轻松搞定可能让用户觉得你在不尊重严肃的事情。场景敏感度需要人工判断。五、总结好的 UI 文案不是写得漂亮而是写得准确。它需要同时满足四个约束字数合适、语调一致、动词明确、场景匹配。大语言模型的优势在于它可以同时考虑所有约束来生成候选文案而传统做法通常只能一条一条人工调整。把 AI 定位为文案初稿生成器人在最后把关——这是目前 UI 文案生产的最佳实践。作者李慕杰Leo / 8limujie一个终于不用再写点击确定这种废话的前端匠人