RAG在祝福场景的真实答案:能当配角,当不了主角
把祝福语塞进向量库就能“走心”吗RAG 在祝福场景的真实答案不知道从什么时候开始很多团队做 AI 功能的第一反应就是“上 RAG”。我接手过一个内部测试任务用 RAG 做祝福语生成。想法看起来非常顺理成章——收集几百条高质量祝福语清洗后灌进向量库用户输入“给朋友的中秋祝福”“给导师的毕业感谢”系统从库里检索最相关的片段拼进大模型提示词生成一段个性化祝福文案。听起来优雅、有技术含量还解决了“纯靠大模型容易乱编”的痛点。但真实跑下来效果离“走心”差了十万八千里。用户反馈的普遍评价是“读起来确实顺但一看就知道是 AI 写的”“感觉每一句都似曾相识像是在拼积木”。这篇文章就来聊聊这次项目从想法到落地的完整拆解数据怎么准备、架构怎么搭、检索为什么失效、改进后效果如何以及最后我得到的那个不太好听的结论——RAG 在这个场景里能当配角但当不了主角。1. 为什么祝福语这个场景一眼看去特别适合 RAG1.1 祝福语的三重特性撞上了 RAG 的舒适区先说直觉上适配的理由。第一祝福语是典型的“知识密集 长尾需求”场景。一个人可能记不住几十种场合下该怎么措辞但语料库里可以存下几千条不同风格、不同场合、不同关系的祝福语。这天然符合“先检索、再生成”的范式。第二用户需求高度个性化。同样是中秋节祝福发给客户、发给闺蜜、发给长辈内容差异极大固定模板根本覆盖不过来。第三祝福语语料获取成本极低网上公开文案、书籍金句、历史聊天记录里的优秀表达都可以收集不像医疗、法律那种专业领域需要专家标注。这三个特征叠加在一起几乎是 RAG 的标准“样板间”。团队当时的判断是这不就是个“文档问答”的换皮版吗用户问“帮我生成一段祝福”系统回答“一段祝福”检索的是文案片段而不是事实生成压力也小。于是项目很快立项目标也很明确做一个能根据场合、关系、语气自动生成祝福文案的 Demo内部代号“某祝福生成实验”。1.2 但祝福语本质上不是“问答”而是“情绪传递”真正开始做之后才发现这个类比有致命缺陷。文档问答的核心诉求是“信息准确”比如“合同里违约为啥赔偿 30%”用户要的是事实。而祝福语的核心诉求是“情绪到位”用户要的不是信息的正确性而是读起来像“一个懂我的人在对我说一句心里话”。这个区别直接影响了检索的目标。在文档问答里检索的目标是“找到包含答案的那一段文字”而在祝福场景里检索的目标是“找到情感姿态最贴近当前关系的那一段表达”。向量检索擅长前者不擅长后者。因为句向量把“语义相近”映射到距离相近但“语义相近”在祝福语里往往不等于“情感合适”。举个例子“祝您福如东海、寿比南山”和“祝您身体健康、万事如意”在向量空间里距离很近因为它们都指向长辈祝福但这两句话的风格一个偏传统祝寿一个偏通用问候放到具体场景里选错一个味道就完全不对。向量模型能感知到“主题相近”却感知不到“语气微妙差异”“关系亲疏”“场合庄重与否”而这些才是祝福语“走心”的关键。还有一个更隐蔽的问题祝福语是强语用的文本。同一句“恭喜恭喜”放在婚礼上、放在升学宴上、放在拿到 offer 的饭局上语义看起来都是“祝贺”但情感负载完全不同。向量库里如果没有显式建模“语用场景”检索回来的片段就很容易出现“高分低配”——距离最近但用不上。这一点在后面的实测中反复被验证也是整个项目最大的坑。2. 数据准备与向量化没那么简单2.1 祝福语的数据不是“收集进来”就完了很多人以为RAG 的数据准备工作就是把祝福语扒下来、切成段、灌进向量库。但这个场景里数据的“结构化程度”直接决定了检索质量。我第一次只做了最基本的清洗去重、去乱码、去掉明显广告就急着向量化结果检索效果惨不忍睹后来重新设计了一套带多维标签的数据结构才逐步把效果拉回来。每条祝福语我最终保留了这些字段id、原文、场合标签、关系标签、语气标签、长度档位、性别倾向、风格标签、来源批次、备注。其中场合标签包括生日、婚礼、节日、升学、升职、乔迁、道歉、慰问、感谢等关系标签区分长辈、平辈、晚辈、客户、导师、朋友、恋人等语气标签区分正式、轻松、深情、俏皮、古风、现代等。这套标签体系非常重要因为后面做“规则前置”和“结果重排”时全靠这些字段做硬过滤而不是完全依赖向量打分。还要注意一个细节祝福语短文本不适合粗暴切分。文档 RAG 里常见的做法是把长文档切成 200~500 字的 chunk但祝福语录里大部分文本本来就短一条祝福可能就 20~80 字。我第一次按“句号切分”把一条“愿您岁月常新福气常伴身体安康笑口常开”切成四段检索时只能召回“笑口常开”这种碎片完全失去了完整语义。后来改成“整条不切分”每条祝福语作为一个独立文档单元入库效果立刻好了不少。在短文本场景里最少切分单元往往就是完整语义单元。2.2 嵌入模型选型通用模型不是万能的向量化这一步也踩了坑。我对比了三类嵌入方案通用开源中文句向量模型、商用 API 模型、以及在少量祝福语数据上微调过的垂直模型。结论比较现实通用模型能用但别指望它理解“祝福语的好坏”。我用一个非常简单的测试来检验模型效果给定“给女朋友的生日祝福要浪漫一点”从库里检索 top5。通用模型返回的结果里有“生日快乐感谢遇见你”这种还行的也有“祝您生日快乐健康长寿”这种明显偏长辈风格的因为向量空间里“生日”主题接近就算“相似”完全没理会“女朋友”与“浪漫”的约束。商用 API 模型稍好一些但还是会在“浪漫”和“温馨”之间混淆边界。而微调过的模型在情感风格区分上确实有提升但微调需要准备大量人工标注的“查询-正确祝福对”成本比较高对于一个小实验来说不划算。最终我的选择是用通用模型做初召回用标签体系做硬过滤再用一个轻量级重排逻辑调整顺序。这个“向量粗排 规则重排”的组合拳比单纯换更强力的嵌入模型要务实得多。嵌入模型本身是“无监督语义相似度”的产物它理解的是“字面相似”不是“场景适配”想让它在祝福场景更聪明要么花成本微调要么在检索链路里加规则约束后者显然更适合快速验证。2.3 检索参数不是拍脑袋定的向量检索库我用了常见的 HNSW 索引几个关键参数需要根据数据规模调M每个节点的连接数、efConstruction建索引时的搜索宽度、efSearch查询时的搜索宽度。我这里只有几百条数据所以 M 设小了也没问题重点是 efSearch。efSearch 太小会导致召回不全太大又会影响检索速度。实测下来数据量 1000 条级别时efSearch 设 200 就够了再多对效果的提升非常有限反而白白增加延迟。真正影响效果的其实是TopK 的取值。我第一次只取 top5 拼进提示词发现效果很差因为向量召回的前几名可能都是同一个风格模板的变体。后来把初召回扩大到了 top30再用标签过滤最后从过滤后的结果里挑 3~5 条“风格互补”的片段进提示词。这个“先宽召回、后过滤、再精选”的流程比直接 top5 稳定得多。后面会有具体对比数据。3. 搭建完整链路从检索到生成的实操细节3.1 整体架构与提示词拼装方式实验的整体流程分四步用户输入解析、初召回、过滤重排、提示词拼装与大模型生成。用户输入解析环节我需要从用户的自然语言描述中抽取出三个关键要素场合、关系、语气倾向。比如用户说“帮我写一段给导师的毕业感谢要正式一点”那么场合是“毕业感谢”关系是“导师”语气是“正式”。这个环节可以用大模型做结构化抽取也可以写规则匹配我为了让流程可复现用了“小模型抽取 关键词兜底”的方式。抽取质量直接决定后面的检索上限如果用户只说“来一段祝福”没有说明场景系统应该主动追问而不是盲目生成。提示词拼装是另一个容易翻车的地方。第一次我把检索到的祝福语原文直接塞给大模型让模型“参考这些风格生成”结果大模型把原文里的一些词汇原封不动搬了过来读起来像缝合怪。后来改为提示词里明确区分“风格参考”和“事实信息”风格参考只负责传递句式结构、措辞风格和情感基调不要求模型保留原文词语同时加入一句“以你自己的语言重新组织不要照搬参考文本”。这一改动对最终文案的“去 AI 味”帮助很大。3.2 过滤与重排向量距离说了不算重排逻辑我分了两层。第一层是硬过滤根据用户输入解析出的“关系”“场合”“语气”三个标签过滤掉不匹配的候选。比如用户要“给客户的商务祝福”凡是标签里带“朋友”“恋人”的候选全部干掉了。第二层是软排序在硬过滤后的集合里按照“向量相似度 * 0.7 风格匹配度 * 0.3”的加权分排序。这里的风格匹配度是简单的规则打分比如用户要“深情”语气候选如果标了“正式”就减分、标了“深情”就加分。这个流程跑下来之后我注意到一个有意思的现象向量相似度最高的结果往往不是用户最终最满意的结果反而是第 4、第 5 顺位的结果。因为向量相似度主要反映“主题接近度”而真实场景里用户首先排除的是“不合适”然后才是在合适的候选里挑“最喜欢的”。所以过滤的重要性大于排序的重要性——你可能选不中“最完美的那一条”但你绝不能把“完全不搭的那一条”推给用户。3.3 评测方式别只看生成文本漂不漂亮项目做到中期我们需要一个可量化的评测标准。团队内部最终定了两个指标检索命中相关率和人工走心评分。前者看流程前三步的检索结果是否匹配用户输入场景纯客观后者让用户对最终生成的祝福文案打 1~5 分纯主观。这两个指标缺一不可。只测检索命中率说明不了生成质量只测走心评分又难以定位是检索还是生成出了问题。评测集是团队同学从真实聊天记录和需求列表里整理的 30 个场景覆盖生日、婚礼、升职、道歉、感谢、节日慰问等关系覆盖长辈、朋友、同事、客户、恋人等。每个场景跑一遍完整流程记录检索结果、生成文案、人工评分。这个评测集后来成了排查问题的主要工具每次改动链路都用同一批场景回归效率很高。4. 真实踩坑记录向量库里的“高分低配”4.1 语义漂移看起来像用起来不对最典型的失败案例是这样的输入“给同事的离职祝福表达感谢和不舍”向量检索 top1 返回的是“感谢您多年来的辛勤付出祝您在新的岗位一切顺利”。乍一看非常匹配关键词全中感谢、付出、新岗位、顺利。但用户反馈“太像年会致辞而不像对要离职的同事说话”。问题出在哪向量模型认为“离职”和“岗位变动”是语义近邻但现实中“离职祝福”和“调岗祝贺”的情感色彩完全不同前者带着告别和感恩后者带着晋升的喜庆。向量空间里相距 0.8 的两句话在情感坐标里可能隔着一条河。类似的情况反复出现后我总结出一个规律向量检索在处理“主题”问题时很可靠在处理“情感姿态”时非常不可靠。主题是显性的词汇信号情感姿态是隐性的语用信号句向量模型没有针对后者做专门训练。所以链路里必须引入显式的情感/关系标签不能把“语义相似度”当成“情感适配度”。4.2 同质化召回Top10 全是同一个“味”另一个大坑是检索结果的同质化。库里祝福语数量有 800 条左右但很多出自同一批范文来源句式结构高度类似。我测试“给老师的教师节祝福”时返回的 top10 里有 6 条都以“感谢您……”开头剩余 3 条是“老师辛苦了”的变体还有 1 条跑偏成了“祝您身体健康”。这样拼进提示词后模型参考的全是同一个句式生成结果自然千篇一律、模板味浓重。这个问题的根源在于向量检索天然倾向于“找相似的”而不是“找多样的”。解决思路有两个一是在初召回后做“多样性重排”让风格标签分布更均匀二是在提示词层面要求模型把参考内容当作“素材池”而不是“风格模板”。我两个都做了效果改善明显。后面如果再优化可以考虑在召回阶段用聚类思想把“不同风格但主题相近”的候选各选几条而不是一股脑取全局距离最近的前几名。4.3 场景时效性静态向量库的硬伤祝福语有极强的时效性这是我一开始忽略的问题。库里收集的素材来自不同年份有些文案里的“新年快乐牛年大吉”到虎年再用就显得过时了。而向量库是静态的关键词检索倒还好语义检索更麻烦——用户说“今年中秋祝福”向量模型并不理解“今年中秋”和“去年中秋”的区别它只看到“中秋祝福”这个主题于是去年、前年的文案都可能被召回。库龄越老这种“时空错位”越明显。后来我意识到时效性问题本质上不是检索算法问题而是数据运营问题。RAG 项目必须配套一套“语料入库时间”的字段管理并且在下游重排时对过期语料做时间衰减。我在每条祝福语上加了“入库时间”和“有效期至”字段查询时如果用户显式提到年份就过滤掉非当年的文案如果没提则默认优先保留有效期内的素材。这样虽然不能完全解决时效性但至少不会出现“恭喜发财”配给“七夕表白”的离谱情况。4.4 长文本祝福库整段存还是拆句存库里有少数长文案比如一整段婚礼致辞两百字。最初为了检索灵活我把一段致辞按句子拆成若干条短文本结果发现一个问题检索“给朋友的婚礼祝福要幽默一点”时返回的碎片里有一条“听说你要结婚了我终于可以光明正大蹭顿饭了”单看很俏皮但它在原文里后面跟的是一大段正经的祝福前语境完全丢失。模型拿这句去生成反而被带偏写出来的文案头重脚轻。教训是短文本场景下尽量保持“一条一个完整表达单元”。如果一段话里有多个语义层次俏皮开头 深情正文 简洁收尾应该把整段存成一条最多打多个风格标签而不是物理切碎。物理切分解决的是长文档的“精确定位”问题祝福语本身不到百字不存在“定位”需求切分的收益很小、损失很大。后来我把库改成“来源完整文案优先存整条”检索质量稳定了不少。5. 改进后效果混合检索 规则前置 人机协同5.1 混合检索向量召回兜底关键词召回纠偏第一轮改进我给检索链路加了“关键词召回 向量召回”的双路混合。关键词召回用简单的 BM25 风格打分对“场合 / 关系”这类强信号词汇非常敏感比如用户输入“给客户的生日祝福”BM25 对“客户”和“生日”的匹配权重很高能精准锁定一批候选人。向量召回负责“语义扩展”当用户描述比较抽象比如“要含蓄一点不要直白说生日快乐”时向量这部分能召回一些表面没提“生日”但语义相关的文案。两路结果做融合交集部分优先剩余按加权分排序。加这一路之后检索命中相关率从 62% 提升到了 83%。为什么效果这么明显因为很多祝福语的“情感姿态”信息藏在关键词里“客户”“导师”“告别”等这些词是强判别性信号BM25 能精确匹配向量模型虽然也能捕捉但因为训练目标分散它在这些强信号上往往被“主题相似”的噪声干扰。关键词召回相当于给检索加了一道保险专治向量召回的“高分低配”。5.2 规则前置先定场景再查库第二轮改进是“规则前置”。核心思路很简单不在全库里做“大海捞针”先根据用户输入的场景标签把检索范围缩小到对应子集再在这个子集里做向量召回。具体做法是维护一个场景映射表比如“教师节感谢”“离职告别”“婚礼致辞”各有对应的标签集合。用户输入后先做标签判定规则或小模型然后从库里筛选出至少满足两个标签的候选再对这部分子集做向量排序。这一步的价值在于把“全局语义相似”变成了“局部语义相似”。以前全库检索时“给导师的毕业感谢”可能会被“开学祝福”干扰因为两者都涉及“学校”相关词汇经过标签过滤后“开学祝福”从一开始就出局了不再产生误导。这轮改进后检索命中率又升到了 89%。5.3 提示词优化让模型“参考”而不是“抄”第三轮改进集中在生成侧。之前提示词里的参考祝福语经常被模型直接“借用”导致缝合感很强。我重新设计了提示词模板核心改动有两点一是让模型从参考样例中提取“句式骨架”和“情感节奏”而不是保留原句词汇二是给模型一个明确的指令“想象你是用户本人而不是一个文案员”引导模型用第一人称的口吻输出。这里有一个细节值得说大模型非常受参考文本的“风格污染”影响。如果参考的 5 条全是“祝您”“愿您”开头的敬语模型输出的每句都会带敬语即便提示词写了“要轻松俏皮”。所以我在精选环节刻意让进入提示词的 3~5 条祝福语覆盖不同风格比如一条深情、一条直白、一条幽默。这样模型能综合不同风格而非被单一风格锁死。这个“风格混合”的技巧对生成结果的自然度提升非常明显。5.4 人机协同推荐的终极形态不是“一键生成”做到最后团队内部争论了一个问题这个功能的体验应该如何收尾一键生成走心文案还是推荐多条供用户选择我们分别做了测试。一键生成模式下用户即使对结果不满意也很少会二次编辑直接放弃的比例很高而在“推荐 3~5 条 支持小调整”的模式下用户选择一条后微微改动满意度大幅提升。这个结果其实揭示了一个产品层面的真相祝福语这个场景用户更需要的不是“被替代”而是“被启发”。他们心里其实已经隐约知道自己想说什么只是找不到合适的措辞。这时候“检索出几条接近方向的文案”比“替用户生成一条标准答案”更有价值。所以最终方案改成了“检索为主、生成为辅”系统先展示检索到的多条候选用户选中后再用大模型做局部润色比如把“生日快乐”改成“生日快乐愿今年所有遗憾都成为明年惊喜的铺垫”而不是一上来就生成整段。人机协同不是技术妥协而是这个场景下的产品正解。5.5 改进前后的评测对比把四轮改进综合到一起拿 30 个评测场景做回归人工走心评分的均值变化如下版本检索命中相关率走心评分1~5用户二次编辑率初版纯向量 top5 直接生成62%2.1无统计加入标签过滤和风格混合83%3.2约 30%再加入混合检索和规则前置89%3.8约 45%最终版检索候选 人工选择 润色89%4.2约 18%低因为满意度高这个表是内部评估结果样本量不算大但趋势很清楚每一步改进都往上拉分了但离“走心”的 5 分还有明显距离。真正能逼近 4 分以上的反而是“检索候选 人工选择”这个看起来不太“AI”的方案。这个结论很扎心但很真实。6. 关于“RAG 到底能不能让祝福走心”的最终答案6.1 技术上能解决什么不能解决什么先说结论RAG 能解决“写得出、对得上”解决不了“打动人”。“走心”是一个由接收者主观体验决定的心理感受它来源于三样东西具体细节的针对性、情感姿态的真诚感、语言节奏的自然感。RAG 能从库里检索出包含“对方名字”“共同回忆”“具体事件”的素材如果库里存了这些信息从而提高“针对性”但“真诚感”和“自然感”是模型的生成能力问题不是一个检索架构能给的。更残酷的事实是现实场景里用户往往不会把“对方是谁”“你们之间有什么故事”告诉系统。没有这些信息任何技术都只能给出泛化的祝福泛化的祝福必然“礼貌但不动人”。这和技术水平无关是信息约束决定的。所以我把这个项目的定位从“AI 生成祝福语”改成了“AI 辅助表达”期望值一旦放对产品的体验评价反而上去了。6.2 什么场景适合用 RAG 生成祝福什么场景坚决不要用基于这次实践我梳理了一个比较清晰的适用边界供以后做同类功能的人参考。适合用 RAG 做辅助的场景有三个特征量大、时效紧、表达要求中等。比如电商平台会员生日批量祝福、企业客户节日群发、活动主办方的参会感谢信这些场景需要大量个性化文案但接收者对“这是模板还是定制”的敏感度相对低重点是信息准确称呼、产品名、时间和不出错。坚决不要用 RAG 生成“成品”的场景也有三个特征关系极其亲密、情感浓度极高、容错率极低。比如给挚友的道歉信、给伴侣的求婚誓词、给逝者的悼念文字。这些场合一旦出现“模板感”不仅起不到祝福作用反而会让接收者感到敷衍甚至伤害关系。这些场景里AI 最多只能提供一个“开头思路”或“关键词提示”成稿必须是人自己写的。有些团队为了炫耀技术硬把这类场景做成功能点我认为是产品判断失误。6.3 以后再做类似功能我会换一套设计思路如果这个项目重新来一遍我不会再以“召回-生成”为绝对核心而是以“表达决策树”为核心第一步先确认用户和接收者的关系亲密度第二步确认使用场合的正式程度第三步确认用户希望表现的情绪姿态。这三个问题决定了祝福的“骨架”而 RAG 负责的事情只是从库里找出匹配骨架的“血肉”素材。系统可以有一个默认推荐但永远要给用户留出“修改骨架”的入口——因为没有人比用户更懂那段关系。产品形态上也会变化不做“输入一句话自动出整段祝福”的单轮对话框而是做一个“多步引导 素材卡片 自由拼接”的编辑器。用户选好场景和关系后系统推一组经过检索排序的短句卡片用户可以像搭积木一样选句子、拖顺序、微调用词。这种方式能让用户觉得自己在“写字”而不是在“收AI的作业”。技术难度其实不高但产品体验的差异是巨大的。这也算是我这次项目最大的产品教训技术选型要服务于“表达参与感”而不是服务于“生成自动化”。这次实验结束后我自己最大的体会是不要因为一个技术叫 RAG、叫向量库就默认它适合所有场景。技术的边界不是靠热情突破的是靠真实的用户反馈扎出来的。以后如果再听到“把祝福语塞进向量库就能走心”这种话我会先问一句我们做这个功能到底是想让 AI 替人表达还是想帮人更好地表达自己这两个目标的实现路径差别太大了。