Files
TrueGrowth/docs/PROMPT_OPTIMIZE_LESSONS.md

266 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Prompt Optimize 与生成链路经验总结
更新日期2026-04-19
## 这轮暴露出的高价值规律
1. 显式选择必须压过隐式上下文
当用户已经明确选择了模型时,不能再偷偷继承旧的 provider/profile。
否则 UI 显示是 A实际请求却跑到 B最后问题会表现成“模型名被改写”“请求走错适配器”“参数形态不对”。
落地原则:
- 只要有显式 `modelId + modelRef`,请求路由就以它为准
- 只有在显式选择缺失时,才允许回退到 preset / legacy route
- `modelId``modelRef` 必须一起校验,不能允许旧 ref 残留
2. 草稿态只能覆盖“它真的有值”的部分
这轮“重新生成视频没带参考图”本质上不是弹窗没透传,而是空草稿把默认值吃掉了。
`draft` 存在,不代表 `draft.images` 就应该覆盖系统默认参考图。
落地原则:
- 草稿字段要按“非空覆盖”处理,而不是“对象存在就整体覆盖”
- 对数组字段尤其要区分:`undefined``[]``[有效值]`
- 默认参考图这类系统推导值,应该作为二级回退保留
建议判断顺序:
- 非空草稿值
- 当前页面可推导默认值
- 最终兜底空值
3. 嵌套弹窗默认挂顶层,不挂父弹窗内容区
Prompt Optimize 的 open 状态已经变成 `true`,但用户看不到,根因是它被 portal 到父弹窗内部,吃到了父容器的 `overflow: hidden` 和层叠上下文。
落地原则:
- 二级弹窗、确认框、轻量配置弹窗默认挂到 `document.body`
- 只有在明确需要“跟随父容器裁剪/定位”时,才挂到父节点
- 如果日志显示 open=true 但肉眼不可见,优先查 portal root / overflow / z-index而不是先怀疑状态管理
4. 真正值钱的修复是收敛判断规则,不是追加特判
这轮几个问题表面不同:
- 模型名串 provider
- 视频重生不带参考图
- 优化弹窗 open 了但看不见
本质都属于“状态来源优先级不清”。
如果只在单点加 if短期能过但后面会在别的入口复发。
更稳的做法是统一规则:
- 显式输入优先于隐式上下文
- 非空用户态优先于系统默认态
- 顶层浮层优先于局部裁剪容器
## 后续开发检查清单
每次新增生成入口、草稿恢复、弹窗嵌套时,先过这 5 个问题:
- 当前请求到底由哪个 `modelId / modelRef` 驱动?
- 有没有旧 ref、旧 provider 被复用?
- 草稿字段为空时,是否错误覆盖了默认值?
- 二级弹窗挂载到了哪里?父容器是否会裁剪?
- 这次修复是在补规则,还是在补特判?
## 结论
这轮最该记住的不是某一个 bug而是三条优先级
- 显式选择 > 隐式路由
- 非空草稿 > 系统默认
- 顶层 portal > 父容器挂载
后面继续做生成链路和弹窗能力时,只要这三条不乱,很多“看起来离谱”的问题会直接消失。
## 2026-04-26提示词优化弹窗 WinBox 化与控制区收敛
这轮把“提示词优化”从普通 Dialog 改为 `WinBoxWindow` 承载,并连续调整了内容布局、底部控制条和历史入口。暴露出的经验不是“换一个弹窗组件”这么简单,而是浮动窗口里表单、控制区、历史数据的边界要更清楚。
### 1. WinBox 只负责窗口能力,业务内容必须保持 React 管理
第三方窗口库容易让内容挂载、关闭回调和 React 状态脱节。项目里已有 `WinBoxWindow` 封装,业务组件应该复用它,而不是直接 `new WinBox`
落地原则:
- 标题、关闭、拖拽、缩放交给 `WinBoxWindow`
- 表单内容仍由 React 渲染到 WinBox body portal
- 关闭时继续走原有 `handleClose`,保证 abort、草稿、模式状态被清理
- `open=false` 时不挂载窗口内容,避免输入栏常驻时提前加载 WinBox 和历史面板
### 2. 弹窗内容区和底部控制区要分层
这轮多次调整后,比较稳定的结构是:
- 内容区:只放当前提示词、补充要求、优化结果
- 底部控制区:放输出模式、模型选择、主操作按钮
- WinBox 标题栏:只放窗口标题和窗口控制按钮
不要把模型选择、说明文字、取消按钮都塞进内容区。内容区越纯textarea 的自适应高度越容易做,滚动条也越少。
### 3. 主输入框吃剩余高度,辅助输入框固定高度
弹窗中间出现大片空白时,不应该靠缩小窗口或写死两个 textarea 的高度解决。更稳的是让主输入框所在 section 变成 flex 容器里的可伸缩项。
落地原则:
- “当前提示词”是主输入,`flex: 1`textarea 跟随剩余高度撑开
- “补充要求”是辅助输入,固定一个稳定高度
- 有优化结果时再切成左右分栏,结果草稿 textarea 吃右侧剩余高度
- 控制区固定在底部,不参与内容区滚动
### 4. 模型选择优先复用 AI 输入框的紧凑展示
提示词优化弹窗里的模型选择不是配置表单,而是生成前的轻量控制。它应该使用 AI 输入框同款的 minimal 展示,而不是大号 form 下拉。
落地原则:
- 使用 `ModelDropdown` 的 minimal 形态:来源图标、`#`、短模型名、健康状态、下箭头
- 输出模式和模型选择放在同一控制组
- 主按钮保持最右,用户视线和点击路径更稳定
- WinBox 右上角已有关闭按钮时,不再重复放“取消”按钮
### 5. 历史入口要区分数据语义
“当前提示词”可以复用全局提示词历史,因为它本质上仍是可生成的 prompt。“补充要求”则是优化指令不应该混进全局提示词历史。
落地原则:
- 当前提示词历史:复用 `usePromptHistory`
- 补充要求历史:使用独立 key小容量、去重、按时间倒序
- 只在点击“开始优化”时写历史,不在输入过程中持续写
- 历史展示要有上限,避免长列表导致弹窗卡顿
- localStorage 读写必须 `try/catch`,失败不能影响优化主流程
### 6. 回归检查清单
后续再改提示词优化弹窗时,先检查:
- WinBox 关闭是否仍会 abort 正在进行的优化请求?
- `open=false` 时是否避免不必要挂载?
- 当前提示词 textarea 是否吃掉内容区剩余高度?
- 输出模式、模型选择、生成按钮是否仍在底部控制区?
- 当前提示词历史和补充要求历史是否仍然分开?
- 历史列表是否有限制,是否避免每次输入都写存储?
- 目标单测和 drawnix typecheck 是否通过?
## 2026-04-26内置提示词预览瘦身与 tips 侧向展示
这轮优化提示词预览时,核心问题不是“预览样式不好看”,而是内置提示词把大量图片和视频样片放进 `public`,导致构建和部署都要携带这些静态资源。内置提示词的价值应该来自文本本身,预览只应该来自用户真实生成过的结果。
### 1. 内置提示词不应该绑定重媒体预览
`apps/web/public/prompt-examples` 里的内置图片、视频会直接进入 Web 静态资源体积,尤其视频样片会显著放大产物。默认提示词越多,资源目录越容易变成不可见的构建负担。
落地原则:
- 内置提示词只维护文本、分类和基础描述
- 不再通过数组下标或静态路径给内置提示词补预览
- 预览图、视频封面、poster 只来自用户生成历史
- 删除内置预览资源时同步删除引用逻辑和测试假设
### 2. 预览来源要表达数据语义
提示词列表里“有预览”应该表示用户已经生成过可复用结果,而不是系统塞了一个演示样片。否则用户会误以为内置提示词自带可用素材,也会让测试绑定到静态资源路径。
落地原则:
- 用户历史记录有 `imageUrl / previewUrl / posterSrc` 时才生成 `previewExamples`
- 内置提示词没有生成结果时展示文本 tips
- 单测校验“用户生成结果才有预览”的语义,不校验某个静态资源路径
- 不用 index 映射补默认预览,避免提示词删减或排序后串图
### 3. 内置提示词要少而实用
提示词入口不是素材库,内置项太多会增加选择成本。默认列表应该覆盖高频生成场景,让用户一眼能改、能用、能出结果。
落地原则:
- 每类保留少量高质量提示词
- 文案尽量包含主体、风格、画面/输出约束
- 删除泛泛而谈、只适合演示、不容易直接复用的项
- 后续新增内置提示词时优先问:它是否比用户自己输入更省时间?
### 4. tips 应该在列表右侧展示
没有预览时tips 如果覆盖在列表内部,会挡住后续选项,尤其在长列表或窄面板里更明显。提示信息应该辅助选择,而不是抢占选择路径。
落地原则:
- 无预览的提示词 tips 默认从列表项右侧弹出
- tips 使用稳定宽度和换行,避免撑开列表项
- hover 只改变浮层,不改变列表布局高度
- 面板宽度不足时再考虑边界兜底,而不是回到覆盖列表内容
### 5. 回归检查清单
后续再改提示词预览和内置提示词时,先检查:
- Web 静态资源目录是否新增了非必要图片或视频?
- 内置提示词是否又和静态预览路径产生绑定?
- 用户生成历史是否仍能展示 image / video / poster 预览?
- 删除或重排内置提示词后,是否不会出现串图?
- 无预览 tips 是否展示在列表右侧,且不挡住其他选项?
- 目标单测、drawnix typecheck、`git diff --check` 是否通过?
## 2026-04-26提示词优化公共能力与知识库模板化
这轮把散落在 AI 输入框、图片/视频工具、PPT、爆款音乐里的“提示词优化”收敛成公共服务和公共按钮。真正的经验不是多抽一个组件而是“同一个动作在不同业务场景里有不同优化语义”公共能力必须同时保留统一调用方式和场景差异。
### 1. 公共能力要收敛入口,不要抹平场景
提示词优化看起来都是一个 Sparkles 按钮但图片、视频、音频、Agent、PPT 公共提示词、PPT 单页提示词、音乐创作的优化方向完全不同。如果只用 `type=image/video/audio` 这类粗粒度类型,后续会把历史、提示词、埋点和默认模式都搅在一起。
落地原则:
- 使用稳定的 `scenarioId` 表达入口语义,例如 `ai-input.agent``ppt.common``music.create-song`
- `type` 表达优化模型语义,`historyType` 表达历史分桶,二者不能强行合并
- PPT 公共提示词可以是视觉优化语义,但历史必须进入 `ppt-common`
- 公共按钮只负责打开弹窗和回填,场景差异放到 registry/service
### 2. 可编辑系统提示词要放知识库正文,不放 metadata
提示词优化模板是用户会长期编辑的内容,不应该塞进代码常量或列表 metadata。列表元数据适合 title、directoryId、sourceUrl、tags模板正文应该走知识库正文存储避免列表加载时把大文本一起拉出来。
落地原则:
- 模板笔记通过 `sourceUrl=aitu://prompt-optimization/<scenarioId>` 绑定,避免只靠标题匹配
- 用户非空正文优先,内置模板只兜底
- 目录或笔记缺失时自动恢复,空正文回填默认模板
- 知识库打开时补齐全部默认模板,不能只在用户首次点击某个场景时懒创建一篇
- 不把大提示词放进 `KBNoteMeta.metadata`,避免知识库列表和搜索出现不必要内存压力
### 3. 模板变量不能成为唯一输入来源
用户可能误删 `{{originalPrompt}}``{{requirements}}`,如果服务完全依赖模板变量,优化请求会丢掉真正输入。模板可编辑,但原始提示词和补充要求必须由系统固定追加,保证请求总有权威输入块。
落地原则:
- 支持模板变量:`{{originalPrompt}}``{{requirements}}``{{language}}``{{mode}}``{{scenarioName}}`
- 渲染模板后始终追加固定输入块
- 固定输入块里明确“原始提示词”“补充要求”“输出要求”
- 单测覆盖“自定义模板不含变量时仍包含原始输入”
### 4. React 组件里避免 HMR 半更新暴露裸变量
这轮出现过 `scenarioId is not defined`。源码已解构 props但浏览器热更新时可能加载到半旧变换结果。对跨多入口的公共弹窗props 字段最好从 `props` 显式取值,避免 refactor 时出现裸变量引用残留。
落地原则:
- 公共弹窗 props 多、兼容旧调用时,优先 `props` 入参后显式取字段
- 新增可选 props 时跑真实入口,不只跑单测
- HMR 出现变量未定义时,先确认浏览器加载的变换版本,再用更稳的写法消除裸变量
- 兼容旧调用时,`scenarioId` 可选,`type` 仍作为 fallback
### 5. 结果区不要做双层胶囊
优化结果草稿本质是一个可编辑 textarea不需要再包一层带边框和底色的结果卡。双层边框会让用户误以为有两个可编辑区域也会让左右输入框上沿不齐。
落地原则:
- 结果区外层只负责布局,不再加边框、底色和内边距
- textarea 自身承担可编辑边界
- “回填”属于提交当前编辑成果,放在“开始优化”右侧;没有优化结果草稿时也可回填当前提示词
- “用结果继续优化”才属于结果操作,继续保留在底部结果操作区,避免挤占结果标题行
### 6. 回归检查清单
后续再改提示词优化公共能力时,先检查:
- 新入口是否有独立 `scenarioId`,而不是复用过粗的 `type`
- `type``historyType``defaultMode` 是否按场景分开配置
- 知识库「提示词优化」目录打开后是否能看到全部默认模板
- 用户改过的非空模板是否不会被覆盖
- 空模板、缺失模板、缺失目录是否能自动恢复
- 模板删除变量后,最终请求是否仍包含原始提示词和补充要求
- AI 输入框、图片/视频工具、PPT 公共/单页、音乐创作入口是否都能打开公共按钮并回填
- 结果区是否只有 textarea 自身边框,左右输入框上沿是否对齐
- 目标单测、OpenSpec validate、`git diff --check` 是否通过?