1. 渐进式披露用“少即是多”的哲学重塑AI产品的人机交互在AI产品里摸爬滚打久了你肯定遇到过这种让人血压飙升的场景用户兴冲冲地打开你的应用在输入框里敲下“优化登录”或者“修复一个bug”然后满怀期待地按下回车。几秒后AI给你返回了一堆要么完全跑偏、要么过于笼统、要么干脆就是“我不理解你在说什么”的废话。这时候用户觉得你的AI是个“人工智障”而你心里也委屈大哥你就给我四个字我上哪去猜你是要优化登录页面的UI还是要重构OAuth2.0的鉴权流程还是要修复那个在特定安卓版本上才会触发的闪退bug这其实不能全怪用户也不能全怪AI。问题的核心在于我们默认用户都具备“完美提问”的能力而AI则被期望拥有“读心术”般的理解力。这本身就是一种不切实际的交互假设。在HagiCode这个AI代码助手的开发过程中我们被这个问题折磨了相当长一段时间。最终我们引入了一套名为“渐进式披露”的交互设计方案它不是什么高深的理论更像是一种“引导式对话”的工程化实践。简单来说就是别指望用户一口气把话说完而是通过一系列精心设计的步骤像剥洋葱一样一层一层地把用户脑子里模糊的想法引导成AI能清晰理解的结构化指令。实测下来这套方案让用户输入的平均信息量提升了近10倍AI生成技术方案的准确性和可用性也有了质的飞跃。今天我就来拆解一下我们是怎么做的以及背后的那些“坑”和“窍门”。2. 核心痛点为什么用户的输入总是“不尽如人意”在动手设计解决方案之前我们花了大量时间分析用户的实际输入行为。我们发现那些简短、模糊的输入背后通常隐藏着几个共性的问题。理解这些是设计有效交互的前提。2.1 输入质量的两极分化有些资深开发者能写出非常清晰的需求“在/src/api/auth.js中将JWT令牌的过期时间从24小时调整为可配置并增加刷新令牌的逻辑需要兼容现有/login接口。” 但更多的情况是“登录有问题”、“做个图表”、“优化性能”。后者并非用户偷懒而是在他们的认知里这个描述已经足够“具体”了。他们默认AI了解他们的项目上下文、技术栈和业务边界——这显然是个错误的假设。2.2 技术术语的“方言”问题同一个概念不同背景的开发者有不同的叫法。有人写“前端”有人写“FE”有人写“client-side”。有人用“API”有人用“接口”有人用“endpoint”。更不用说各种框架、库的特定术语和缩写。AI模型如果没有足够的上下文进行消歧很容易产生误解。比如用户说“用hooks重构”AI需要知道这是React Hooks而不是Git Hooks或其他什么。2.3 结构化信息的系统性缺失一个有效的技术方案描述至少应该包含几个维度背景为什么要做、范围改哪些文件、影响哪些模块、分析技术选型与权衡、方案具体步骤。然而用户的自然语言输入几乎总是缺失这些结构。他们直接跳到了“方案”甚至只是“目标”部分而将最重要的约束条件和上下文都默认为“共识”。这就像只给建筑师看一张卧室的照片却要求他建出整栋房子。2.4 重复问题的解释成本在团队协作中许多技术规范如代码风格、提交信息格式、API设计原则是共通的。但每个新成员或每个新需求进来时都需要重新解释一遍。用户每次输入“添加错误处理”时AI都无法自动引用项目已有的错误处理工具类或最佳实践导致每次生成的方案都可能不一样或者不符合团队规范。这些痛点导致的直接后果就是AI输出的不稳定和用户体验的挫败感。我们的解决思路不是去训练一个更“聪明”的、能脑补一切的AI而是设计一套更“聪明”的交互流程去弥补用户输入与AI理解之间的鸿沟。这就是“渐进式披露”的用武之地。3. 渐进式披露的设计哲学与四层实践“渐进式披露”并非新概念它源于人机交互设计领域核心思想是不要一次性向用户展示所有信息和选项而是根据用户的操作进程和实际需要逐步披露必要的内容。对于AI产品这再合适不过了因为人机对话本身就是渐进式的。我们将这一哲学落地为四个可执行的设计层。3.1 第一层描述优化机制——让AI帮你把话说清楚当用户输入一段简短的描述后我们的第一反应不是立刻让AI去生成代码或方案而是触发一个“描述优化”的中间步骤。这个步骤的核心目标是“结构化输出”。3.1.1 结构化的魔力我们要求优化后的描述必须遵循一个固定的模板这个模板本身就是一个迷你技术方案的骨架## 背景 [问题产生的上下文、相关业务逻辑、涉及的项目/模块] ## 分析 [技术可行性分析、可选方案对比、决策理由] ## 方案 [具体的实现步骤、关键代码位置、外部依赖] ## 实践 [核心代码示例、注意事项、测试要点]同时系统会自动提取或生成一个元数据表格例如项目内容目标仓库frontend-web主要修改路径src/components/Login/影响范围登录组件、认证状态管理权限要求需要读写auth相关模块这个做法的好处是立竿见影的。首先它强制用户在AI的辅助下进行结构化思考。其次它为后续的AI生成任务提供了极度丰富的、高质量的上下文。最后这个结构化的描述本身就可以作为技术文档的初稿一举多得。3.1.2 实现要点与“记忆注入”这个优化过程不是简单的文本润色其核心在于“记忆注入”。我们会从几个维度为AI补充上下文项目公约从代码库中提取的.eslintrc、prettier.config、项目特有的工具函数命名风格等。相似案例在历史任务中搜索功能相似的已完成方案例如“过去是如何优化登录性能的”。负面模式记录之前被用户拒绝或修改过的AI建议避免重蹈覆辙。代码实现上关键服务ProposalDescriptionOptimizer的核心逻辑如下public class ProposalDescriptionOptimizer { private readonly IProjectContextService _contextService; private readonly IMemoryVectorStore _vectorStore; private readonly IAIService _aiService; public async TaskOptimizedDescription OptimizeAsync(string rawTitle, string rawDescription, string projectId) { // 1. 构建查询上下文提取原始输入中的关键词 var queryContext BuildQueryContext(rawTitle, rawDescription); // 2. 检索相关记忆从向量数据库中查找相似的历史任务和项目规范 var relevantMemories await _vectorStore.SearchAsync(queryContext, projectId, limit: 5); // 3. 构建优化提示词将原始输入、检索到的记忆、结构化模板组合成最终提示 var optimizationPrompt BuildPrompt(rawTitle, rawDescription, relevantMemories); // 4. 调用AI进行优化 var optimizedText await _aiService.CompleteAsync(optimizationPrompt); // 5. 解析结构化结果 return ParseStructuredOutput(optimizedText); } private string BuildPrompt(string title, string description, IEnumerableMemoryItem memories) { var sb new StringBuilder(); sb.AppendLine(你是一个技术方案撰写专家。请根据用户输入参考以下项目上下文生成一个结构清晰、内容完整的技术方案描述。); sb.AppendLine(); sb.AppendLine(用户输入); sb.AppendLine($标题{title}); sb.AppendLine($描述{description}); sb.AppendLine(/用户输入); sb.AppendLine(); if (memories.Any()) { sb.AppendLine(项目上下文与历史参考); foreach (var mem in memories) { sb.AppendLine($- {mem.Content} (相关性{mem.Score:F2})); } sb.AppendLine(/项目上下文与历史参考); sb.AppendLine(); sb.AppendLine(注意历史案例仅供参考请以用户当前输入为最高优先级。若用户输入与历史案例冲突遵循用户输入。); } sb.AppendLine(); sb.AppendLine(输出格式); sb.AppendLine(请严格按照以下Markdown章节输出); sb.AppendLine(## 背景\n...\n## 分析\n...\n## 方案\n...\n## 实践\n...); sb.AppendLine(此外请推断并生成一个包含『目标仓库』、『主要修改路径』、『影响范围』的Markdown表格。); sb.AppendLine(/输出格式); return sb.ToString(); } }实操心得记忆的优先级与冲突处理这是最容易出问题的地方。我们曾遇到用户明确说“不要用Redux”但AI因为检索到一个高相似度的、使用了Redux的历史案例依然在方案中推荐了Redux。我们的解决方案是在提示词中明确加入优先级指令——“用户当前输入 项目通用规范 历史相似案例”。同时对于从代码中提取的“事实”如项目使用了TypeScript我们将其标记为高置信度源不可被历史案例覆盖而对于“建议”如“推荐使用函数组件”则标记为低置信度仅作参考。3.2 第二层语音输入能力——说话比打字更自然对于复杂的场景描述打字是低效且反人性的。想象一下你如何用键盘描述一个涉及多个步骤、包含多个条件的业务流程漏洞语音输入在这里是天然的补充。3.2.1 状态驱动的交互设计语音功能的核心不是识别准确率这由底层引擎保证而是清晰的状态管理。用户必须时刻知道系统“正在做什么”。我们定义了五个核心状态状态描述前端UI反馈空闲 (Idle)准备就绪可开始录音显示麦克风按钮等待上游 (Waiting-upstream)正在连接后端语音服务按钮禁用显示加载动画录音中 (Recording)正在录制用户语音按钮变为红色显示动态声波纹和计时器处理中 (Processing)语音转文字中显示“识别中…”提示和加载条错误 (Error)连接失败、识别失败等按钮恢复显示错误提示和重试选项前端的状态管理模型大致如下interface VoiceInputState { status: idle | waiting-upstream | recording | processing | error; duration: number; // 录音时长秒 error?: string; // 错误信息 deletedTextFingerprints: Setstring; // 关键已删除文本的指纹集合 } const useVoiceInput () { const [state, setState] useStateVoiceInputState({ status: idle, duration: 0, deletedTextFingerprints: new Set(), }); const startRecording async () { // 1. 进入等待状态检查后端服务 setState(s ({...s, status: waiting-upstream})); const isBackendReady await checkBackendService(); if (!isBackendReady) { setState(s ({...s, status: error, error: 语音服务暂不可用})); return; } // 2. 获取麦克风权限并开始录音 const stream await navigator.mediaDevices.getUserMedia({ audio: true }); // ... 初始化录音逻辑 setState(s ({...s, status: recording, duration: 0})); // 启动计时器 }; const onRecognitionResult (result: SpeechRecognitionResult) { const text result.transcript; const fingerprint generateTextFingerprint(text); // 生成文本指纹如MD5哈希 // **关键检查**如果用户之前删除了这段内容则不再显示 if (state.deletedTextFingerprints.has(fingerprint)) { return; } // 将识别结果插入输入框 appendToInputText(text); }; const handleDeleteRecognizedText (text: string) { const fingerprint generateTextFingerprint(text); // 将删除的文本指纹加入集合 setState(s ({ ...s, deletedTextFingerprints: new Set(s.deletedTextFingerprints).add(fingerprint) })); }; };3.2.2 那个至关重要的“指纹集合”上面代码中的deletedTextFingerprints是一个神来之笔它解决了一个实际体验中的大问题语音识别是流式的、可能重复的。当用户说“删除登录模块”识别引擎可能会先后返回“删除”、“删除登录”、“删除登录模块”三个片段。如果用户手动删除了输入框里的“删除登录”那么当“删除登录模块”这个更完整的结果返回时系统应该智能地跳过它因为用户显然已经否定了这个意图。我们通过为每段识别文本生成一个简短的指纹如取前几个词的哈希并记录用户删除的指纹完美地实现了这个“去重”与“意图尊重”逻辑。踩坑记录状态同步与错误恢复早期版本我们没有waiting-upstream状态直接跳到recording。结果在网络稍慢时用户按下按钮后会有0.5-1秒的“无反应期”导致用户反复点击进而触发多个录音实例造成混乱。加入明确的等待状态并配上加载动画后用户体验立刻变得顺畅。此外错误状态必须提供明确的恢复路径如“重试”按钮而不是仅仅显示一个错误码。3.3 第三层提示词管理系统——外化AI的“大脑”AI的行为本质上由提示词驱动。在HagiCode中我们摒弃了将提示词硬编码在代码里的做法而是建立了一个文件化的提示词管理系统。这相当于把AI的“思考逻辑”外置使其变得可版本化、可管理、可AB测试。3.3.1 文件结构与元数据我们的提示词仓库结构如下prompts/ ├── metadata/ # 元数据目录 │ ├── optimize-description.zh-CN.json │ ├── code-review.en-US.json │ └── ... └── templates/ # 模板目录 ├── optimize-description.zh-CN.hbs ├── code-review.en-US.hbs └── ...每个提示词由一对文件定义元数据文件 (.json)定义提示词的场景、参数、版本等信息。模板文件 (.hbs)使用Handlebars语法的实际提示词内容。一个元数据文件的例子{ scenario: optimize-description, locale: zh-CN, version: 1.2.0, parameters: [ { name: title, type: string, required: true, description: 用户输入的原始标题 }, { name: description, type: string, required: true, description: 用户输入的原始描述 }, { name: projectContext, type: object, required: false, description: 从向量库检索到的项目上下文 } ], tags: [optimization, nlp, core], description: 用于优化用户输入生成结构化技术方案描述的提示词。, author: HagiCode Core Team, lastModified: 2024-05-15 }3.3.2 模板与动态渲染模板文件则利用Handlebars语法实现动态内容注入{{! prompts/templates/optimize-description.zh-CN.hbs }} 你是一名经验丰富的技术负责人擅长将模糊的需求转化为可执行的技术方案。 任务 根据用户提供的标题和描述结合给定的项目上下文如有生成一份结构清晰、内容完整的技术方案描述。 /任务 用户输入 标题{{title}} 原始描述{{description}} /用户输入 {{#if projectContext}} 项目上下文 以下是当前项目的相关规范和历史案例请作为参考 {{#each projectContext.items}} - {{this.content}} (来源{{this.source}}) {{/each}} /项目上下文 重要指令 请优先遵循用户输入的具体要求。项目上下文仅作为技术选型和实现风格的参考若与用户要求冲突以用户要求为准。 /重要指令 {{/if}} 输出要求 1. 语言使用与用户输入相同的语言中文。 2. 结构必须包含以下四个二级标题顺序不可更改 ## 背景 ## 分析 ## 方案 ## 实践 3. 在“方案”部分后请自动生成一个“变更影响”表格包含【修改文件】、【影响模块】、【风险评估】三列。 4. 语气专业、简洁、直接。 /输出要求3.3.3 系统启动时的完整性校验我们在应用启动时会扫描整个prompts/目录进行以下校验每个.json元数据文件是否有对应的.hbs模板文件模板文件中引用的参数是否都在元数据中定义了必填参数是否都有版本号格式是否正确任何校验失败都会在启动阶段抛出错误防止运行时出现“提示词找不到”或“参数缺失”的诡异问题。这相当于为AI的“大脑”做了一次全面的开机自检。经验之谈提示词的版本化与灰度发布我们将提示词纳入Git版本控制。修改提示词就像修改代码一样需要提交、Code Review、合并。对于核心场景的提示词如optimize-description我们甚至引入了简单的灰度发布机制通过特性开关让10%的用户使用新版本的提示词对比其生成的方案质量与用户满意度数据达标后再全量发布。这让我们能安全、数据驱动地迭代AI的核心逻辑。3.4 第四层渐进式向导——拆解复杂任务对于首次使用、项目初始化、复杂配置等场景我们采用多步骤的向导模式。其核心设计原则是一次只问一件事并清晰地告诉用户当前在哪、还剩多少、上一步做了什么。3.4.1 向导的状态模型与导航逻辑我们设计了以下状态模型来管理向导流程interface WizardStep { id: number; title: string; // 步骤标题如“项目配置” description: string; // 步骤描述如“请选择要操作的项目仓库” component: React.ComponentType; // 该步骤渲染的UI组件 validate: () boolean | Promiseboolean; // 步骤数据校验函数 isSkippable?: boolean; // 该步骤是否可跳过 } interface WizardState { currentStepIndex: number; steps: WizardStep[]; stepData: Recordnumber, any; // 存储每一步收集的数据 isSubmitting: boolean; error: string | null; } // 导航逻辑的核心 const goToNextStep async (state: WizardState) { const currentStep state.steps[state.currentStepIndex]; // 1. 验证当前步骤数据 const isValid await currentStep.validate(); if (!isValid) { // 触发前端UI验证错误提示 return; } // 2. 检查是否为最后一步 if (state.currentStepIndex state.steps.length - 1) { await submitAllData(state.stepData); return; } // 3. 前进到下一步 setState({ ...state, currentStepIndex: state.currentStepIndex 1 }); }; const goToPrevStep (state: WizardState) { if (state.currentStepIndex 0) { setState({ ...state, currentStepIndex: state.currentStepIndex - 1 }); } };3.4.2 视觉反馈与防错设计向导的UI必须提供清晰的进度指示。我们使用一个顶部的进度条并明确标出每一步的标题和状态未开始、进行中、已完成。对于已完成的步骤允许用户点击回看但修改数据时会给出提示“修改此步骤数据可能会影响后续步骤是否继续”“取消”操作是一个危险操作。我们将其设计为两步第一次点击“取消”时弹出一个确认对话框并清晰列出“已输入但未保存的数据将会丢失”同时提供一个“保存草稿”的次要选项。这极大地减少了用户的误操作损失。避坑指南异步验证与步骤依赖向导中有些步骤的验证是异步的比如“检查仓库权限”。最初我们是在goToNextStep中同步调用验证导致UI卡顿。后来我们将其改为在用户填写表单时即进行异步验证如防抖查询并将验证结果缓存在步骤状态中。当用户点击“下一步”时只需检查缓存结果极大提升了流畅度。 另一个坑是步骤间的数据依赖。例如第一步选择了“前端项目”那么第二步的“构建工具”下拉框里就应该只显示Vite,Webpack等选项而不是把Maven,Gradle也列出来。我们在每一步的component渲染时会注入前面所有步骤的stepData从而实现动态的UI渲染和选项过滤。4. 效果评估与常见问题排查这套“渐进式披露”体系在HagiCode上线后我们通过数据埋点和用户反馈观察到了一些显著的变化。4.1 量化效果我们对比了方案上线前后一周的核心指标指标上线前上线后变化用户输入平均长度18字符215字符1094%AI生成方案首次采纳率32%71%122%用户单次会话平均交互轮次1.2轮3.8轮217%“输入信息不足”导致的错误率41%9%-78%用户满意度NPS1548显著提升数据说明了一切。更长的输入、更多的交互轮次并没有带来用户的反感反而因为最终得到了更准确、更可用的结果大幅提升了满意度和采纳率。4.2 典型问题与解决方案在实践过程中我们也遇到并解决了一些典型问题问题一用户觉得“描述优化”步骤多余想跳过。现象部分熟练用户认为自己能写清楚不希望多一步点击。解决方案我们增加了“智能判断”逻辑。对于输入长度超过150字符且包含一定结构化关键词如“背景”、“步骤”、“代码在xxx”的描述系统会询问用户“您的描述已较为详细是否跳过优化步骤直接生成方案” 把选择权还给用户。问题二语音识别在嘈杂环境下准确率低。现象办公室环境中识别出的文本包含大量无关词汇。解决方案首先在UI上明确提示“请在相对安静的环境中使用”。其次在识别结果返回后并非直接插入输入框而是先在一个“预览区”展示并提供一个“编辑”按钮让用户可以先修正再确认插入。同时我们集成了更先进的端点检测VAD技术减少录入空白噪音。问题三向导步骤太多用户中途流失。现象一个包含7个步骤的项目初始化向导完成率只有60%。解决方案进行步骤精简与合并。通过分析用户数据我们将“代码风格选择”和“静态检查配置”合并为一个“代码规范”步骤。将必填步骤从7个减到5个并将可选的“高级配置”步骤折叠起来默认不展示。完成率随后提升至85%。问题四提示词管理混乱多人修改冲突。现象多个开发者同时修改不同提示词合并时经常冲突。解决方案我们为提示词引入了“所有者”机制。每个核心提示词文件metadata/*.json都有一个owner字段指向一个GitHub团队。任何对该文件的修改都需要至少一名所有者的Review。同时我们建立了一个简单的CI流程在合并前自动运行提示词校验脚本和基础的语义测试。5. 总结与个人体会回顾在HagiCode中实践“渐进式披露”的整个过程我的体会是这本质上是一场交互设计思维的转变。我们不再把AI视为一个“全知全能的黑箱”用户输入一个咒语它就能吐出完美答案。而是将AI交互视为一个协作探索的过程。产品设计的重心从“如何让AI更聪明”部分转移到了“如何设计一个流程能更好地激发和捕捉用户的智慧”。这套方案的成功关键在于把握住了几个核心原则引导而非拷问通过智能补全、结构化模板来引导用户思考而不是抛出一堆冰冷的输入框。及时且透明的反馈每一个操作录音、识别、优化、导航都有明确的状态反馈让用户始终感知到系统的进展。容错与可控允许用户随时回退、修改、跳过掌控感是良好体验的基石。利用上下文将项目历史、团队规范作为“记忆”注入交互流程让AI的每一次回应都更具个性化和准确性。最后我想分享一个最朴素的感悟用户不是不愿意提供信息而是很多时候不知道你需要什么信息或者觉得提供起来太麻烦。渐进式披露的精髓就在于找到那个“恰到好处”的时机和方式把复杂的问题拆解成一系列简单的选择让用户在几乎无感的情况下贡献出高质量的信息。这个过程就像和一个有耐心的专家同事对话他通过一个个具体的问题帮你理清思路最终共同勾勒出完整的蓝图。技术实现固然重要但背后这种“以用户为中心”的共情和设计巧思才是让AI产品真正变得好用的关键。