智能体 · 检索
- 段落
- 92 本站的术语表和图例
- 嵌入模型
- all-MiniLM-L6-v2 384 维
- 检索
- 按余弦取前 3
- 模型
- Qwen3-1.7B
全部步骤
把知识切成段落
可供取用的知识是本站自己的文本(英文版):85 条术语表定义和 7 行图例,共 92 个段落。在别处训练的模型从没读过它们。
92 个段落 · 术语表 85 + 图例 7文本变成向量
嵌入模型把每个段落读一遍,输出一个向量:all-MiniLM-L6-v2 是一个 6 层的 BERT,把最后一层在各词元上取平均,再把结果缩放到长度 1。问题也以同样方式嵌入。
文本 → 384 个数,长度 1意思相近,空间上也相近
讲相关事物的段落得到相似的向量。压到两维(它们的前两个主成分)后,相关的术语聚在一起,问题落在回答它的那行图例附近。两维只保留了部分信息,所以其他相近的段落可能看起来很远。
384 维中的 2 维,仅供目测按余弦相似度排序
检索就是点积:问题的向量与每个段落的向量逐一相乘,从高到低排。保留前 3 个。第二个问题的答案只排在第 2 位;词语重叠让 “Few-shot prompting” 排到了第一。
分数 = q · d(两者长度都是 1)· 保留前 3 个段落放进提示词
程序把排在最前的段落贴进提示词,放在问题上方,并附上只根据它们作答的指令。模型看待检索到的文本,和看待上下文中其他任何东西完全一样。
211 个词元:指令 + 3 个段落 + 问题有检索与无检索
没有段落时,Qwen3-1.7B 猜的是斜线格子在随便什么地方可能表示什么。有了段落,它按本站的图例来回答。检索没有改变模型;它改变的是摆在模型面前的东西。
同一个模型 · 有无段落检索失手时
检索会悄无声息地失手。“Which word came first” 与讲位置的段落没有共同的词,一个都没检索回来。问题也可能找到了对的段落,而那个段落恰好没有答案。被告知只用上下文时,模型会如实说明,而它自己作答时则编了一个名字。
段落不对,回答就弱
代码
embedder = SentenceTransformer("all-MiniLM-L6-v2")
P = embedder.encode(passages, normalize_embeddings=True) # once, ahead of time: (84, 384)
q = embedder.encode(question, normalize_embeddings=True) # (384,)
scores = P @ q # cosine similarity, since both have length 1
top = scores.argsort()[::-1][:3]
context = '\n'.join(f'[{i + 1}] {passages[j]}' for i, j in enumerate(top))
answer = llm(f'Answer using only the context below.\n\nContext:\n{context}\n\nQuestion: {question}')