把祝福语塞进向量库,就能“走心”吗?RAG 在祝福场景的真实答案

0 阅读10分钟

这个问题看似小,其实很“工程”

“祝福语生成”这种场景,一旦你做过一版微调(比如「码上拜年」),很快就会有人问下一句:

 

“既然我们有大量祝福语样本,那要不要上 RAG?用向量数据库检索几条相似的,再让模型改写一下,会不会更稳?”

 

这句话听起来很对,甚至非常工程化:

有数据 → 入库 → 检索 → 生成,闭环就有了。

 

但祝福这件事偏偏很刁钻:它不是知识问答,不是事实查证,更不是“召回越多越好”。

它靠的是“分寸”“关系”“语气”,靠的是你能不能让对方觉得:这句话是写给我的,而不是从哪里抄来的。

 

所以这篇文章我想把话说得直一点:

 

RAG 做祝福检索不是不能做,但你得先搞清楚:你在用 RAG 解决什么问题。

否则向量库越建越大,TopK 越调越高,最后效果反而会退回“模板拼贴”。

 

一、先给结论:RAG 做祝福检索“靠谱吗”?取决于你要检索什么

如果你说的“祝福检索”是:

 

把一堆祝福语当作语料,检索几条相似的祝福,然后让模型改写成新的祝福。

 

这种做法在工程上能跑通,但大概率会遇到三个问题:

  • 结果越来越像“模板拼接”

  • 风格一致性很难保证(尤其多来源语料)

  • 你以为在检索“走心”,其实只是在检索“像祝福的句子”

 

如果你说的“祝福检索”是:

 

检索与对象相关的事实材料,比如关系、经历、共同回忆、客户项目细节、最近发生的事,再让模型基于这些事实写祝福。

 

那 RAG 会非常靠谱,而且往往是“走心”的关键来源。

 

一句话总结:

 

RAG 更适合检索“你们之间发生过什么”,不适合检索“别人怎么写祝福”。

 

41.png  

 

二、祝福场景的本质:缺的不是信息,而是“表达偏好”

春节祝福这种任务,你要的输出不是“正确答案”,而是“合适的说法”。

通用模型的问题也不是“不知道祝福怎么写”,而是它默认会落到一种安全平均的表达区:

  • 词很对

  • 句式很全

  • 但没有你们的关系,没有具体性,没有“这句话只属于你”的感觉

 

微调(SFT/LoRA)擅长做的是:把“合适的说法”变成默认选项,让模型在生成空间里优先选中更自然、更贴近场景的表达方式。

 

而 RAG 擅长做的是:把模型看不到的信息补进来。

 

所以当你用 RAG 去检索祝福语本身,你其实在做一件有点别扭的事:

 

你用“信息补全工具”,去解决“表达偏好问题”。

 

这也是很多祝福 RAG 项目看起来很努力,结果却越来越像模板的原因。

 

三、RAG 检索祝福语为什么容易翻车:三种典型失败模式

风格混杂,模型被迫折中

向量库里祝福语来源可能很杂:公众号、朋友圈、公司模板、古风、网络梗、商务措辞。

检索出来的 TopK 往往不是同一语气体系下的东西,模型拿到这些证据后只能“强行综合”。

 

你最后得到的文本常见特征是:

  • 前两句像微信聊天

  • 后两句像正式贺电

  • 中间突然插个网络梗又不搭

 

这不是模型水平不行,是你给它的证据本身就不一致。

 

相似度检索到的是“结构相似”,不是“关系相似”

向量检索很擅长找“语义相近”的句子,但祝福语里大量是固定结构:

 

“新春到 / 祝你 / 事业顺利 / 阖家幸福”

这类句子在 embedding 空间里会聚成一团,你检索到的往往是“同款结构”,而不是“适合你们关系”的表达。

 

换句话说:

 

你检索到的相似,是“像祝福”,不是“像你”。

 

召回越多,越像拼贴,越容易胡说

很多人遇到“不够走心”第一反应是把 TopK 调大:5 不够就 10,10 不够就 20。

但祝福场景里,TopK 变大几乎一定会带来:

  • 重复信息增多

  • 风格冲突增多

  • 模型综合压力变大

  • 自信但空泛的句子变多

 

最终输出常常更像“堆辞藻”,而不是更走心。

 

四、那 RAG 在祝福场景到底该怎么用才对

我更建议把祝福 RAG 的定位改成四个字:

 

检索“关系证据”。

 

你不要把向量库当成“祝福语仓库”,而要当成“关系记忆库”,里面存的应该是:

  • 称呼偏好(对方喜欢被怎么叫)

  • 关系类型(同事/客户/家人/恋人)

  • 共同经历(项目、旅行、加班、某次饭局)

  • 近期事件(换工作、升职、搬家、孩子出生)

  • 对方兴趣点(马术、摄影、某个梗)

  • 你们的沟通风格(爱玩笑、讨厌肉麻、喜欢简短)

 

这些东西才是“走心”的燃料。

而“怎么说得合适”,交给微调后的模型去做。

 

五、向量数据库实战:做一个“祝福关系记忆库”的最小可用方案

这里我给一个尽量实操的流程,不追求完美,但你照着做能跑起来,效果也更容易靠谱。

 

数据结构:不要只存文本,至少把元信息带上

你要检索的是“哪些经历最相关”,而不是“哪句祝福最像”。所以每条记录最好长这样:

  • person_id / contact_id

  • relationship(客户/同事/家人…)

  • scene(拜年/感谢/道歉/祝贺…)

  • time(时间戳)

  • content(事件描述或事实)

  • tags(马术/项目/旅行/加班…)

 

向量化:embedding 用来找“相关经历”,不是找“祝福模板”

你可以用中文向量模型(比如 bge 系列)做 embedding。下面是一个示意代码(以 sentence-transformers 风格写,方便理解)。

 

 


from sentence_transformers import SentenceTransformer

import numpy as np

 

model = SentenceTransformer("BAAI/bge-small-zh-v1.5")

 

def embed(texts):

    vecs = model.encode(texts, normalize_embeddings=True)

    return np.array(vecs, dtype="float32")

 

memories = [

    "去年北京项目合作,你对细节的关注和高效决策让我印象深刻",

    "年底饭局聊到马术运动,你分享了不少见解",

    "大学室友,认识八年,一起通宵赶作业,毕业后每年约一次旅行",

]

 

vectors = embed(memories)

 

 

注意我这里用了 normalize_embeddings=True,是为了后续用 cosine/inner product 更稳定,少被向量长度影响。

 

建库:先用 FAISS 跑通,再考虑 Milvus/pgvector

如果你是从 0 到 1 验证,建议先 FAISS,因为简单,足够快。

 

 


import faiss

 

dim = vectors.shape[1]

index = faiss.IndexFlatIP(dim)  # 归一化向量 + IP 等价 cosine

index.add(vectors)

 

def search(query, topk=5):

    q = embed([query])

    scores, ids = index.search(q, topk)

    return [(int(i), float(s)) for i, s in zip(ids[0], scores[0])]

 

print(search("给王总发拜年祝福,提到北京项目合作和马术", topk=3))

 

 

跑通以后你再决定要不要上:

  • Milvus(更偏向规模化、多租户、运维复杂)

  • pgvector(更贴近业务系统,SQL 友好)

  • Elasticsearch kNN(如果你本来就用 ES)

 

祝福场景通常不是吞吐瓶颈,更多是“检索到什么”的问题。

 

检索策略:TopK 不是越大越好,宁可少而准

祝福场景里,你召回的“关系证据”越多,模型越容易被迫总结成套话。

所以我的建议是:

  • TopK 小一点,比如 3~5

  • 做去重(同一事件的多次记录合并)

  • 做时间衰减(最近一年权重更高)

 

你可以用一个很朴素的打分融合:

 

 


import math

from datetime import datetime

 

def time_decay(days_ago, half_life=180):

    # 半衰期 180 天

    return 0.5 ** (days_ago / half_life)

 

def fused_score(similarity, days_ago):

    return similarity * time_decay(days_ago)

 

 

生成提示:让模型“基于证据写”,而不是“参考模板改写”

把检索到的关系证据作为“事实素材”,提示模型不要编造新的经历。

 


System:

你是一位有分寸感的祝福语助手。只使用用户提供的信息与证据要点,不要虚构经历。

 

User:

祝福对象称呼:王总

关系:客户/服务关系

风格:商务得体风

字数:50-100字

证据要点:

- 去年北京项目合作,对方对细节关注、高效决策

- 年底饭局聊到马术,对方分享见解

 

请写一段微信拜年祝福。

 

 

这一步非常关键:你用 RAG 的方式把“走心素材”喂进去,而不是把“别人的祝福句子”喂进去。

 

六、要不要把祝福语本身也入库?可以,但别当主力

如果你一定要做“祝福语检索库”,建议把它当作“辅助”,并加两道护栏:

  • 先按风格分库或分区(商务/轻松/科技梗/传统)

  • 检索出来的祝福只给模型当“灵感片段”,不能当证据

  • 让模型必须引用“关系证据”,模板只能做润色

 

否则你会非常稳定地走向:模板拼贴、风格混杂、越写越像公众号。

 

七、怎么判断“RAG 做祝福检索到底靠不靠谱”:三条评估线

祝福是主观任务,但评估不是完全没法做,你至少要盯住三个维度:

  • 事实一致性

  是否出现未提供的经历、捏造细节、关系写错

  • 风格一致性

  同一风格下输出是否稳定,是否出现突然正式或突然玩梗

  • 可直接发送率

  用户是否愿意不改就发,或改动幅度是否很大(这比任何指标都诚实)

 

如果你的 RAG 方案让“可直接发送率”下降,那它基本就不靠谱,哪怕召回看起来很强。

 

八、工程取舍:什么时候“RAG + 向量库”值得做,什么时候不值得

值得做的情况

  • 你有真实的关系素材来源

  CRM、聊天摘要、项目纪要、活动记录

  • 你要“个性化”,而不是“更华丽”

  走心的关键是具体经历,而不是更漂亮的辞藻

  • 你在意隐私与合规

  你宁可让模型少说一点,也不让它胡编经历

 

不太值得做的情况

  • 你只有一堆祝福语模板,没有关系素材

  你检索到的只会是“像祝福”的句子

  • 你希望靠 RAG 解决风格问题

  风格一致性更像微调的职责,不是检索的职责

  • 你准备靠 TopK 把效果堆上去

  祝福场景里这招副作用很大

 

如果你的目标是让祝福既走心又稳定,比较靠谱的路线往往是:用向量数据库做“关系证据召回”,用微调把风格和分寸塑成默认值。像LLaMA-Factory Online这种能快速跑通微调闭环的平台,更适合把“表达偏好”先稳住,再去接 RAG 做个性化证据补全,否则你很容易把检索当成风格修补工具,越修越乱。

 

总结:RAG 做祝福检索靠谱不靠谱,关键看你检索的是“人”,还是“句子”

我最后用一句话收住:

 

RAG 在祝福场景里不是不靠谱,而是你不能让它去检索“祝福本身”。

它更适合检索“你们的关系”,把走心的素材找出来;而“怎么说得合适”,更适合用微调去解决。