❝
你的 RAG 系统检索效果不好?80% 的原因出在查询预处理上。本文系统梳理 7 种查询预处理方案,重点讲清原理、关键细节和提示词设计。
❞
一、为什么查询预处理如此重要?
在 RAG 系统中,有一个被大多数人忽略的关键环节——「查询预处理(Query Preprocessing)」。
看一个典型场景:
用户:什么是 Transformer?助手:Transformer 是一种基于自注意力机制的神经网络架构……用户:它和 RNN 有什么区别?
最后一句"它和 RNN 有什么区别?"——如果直接拿这句话去向量数据库检索,「向量数据库完全不知道"它"指的是 Transformer」,检索结果大概率跑偏。
查询预处理要解决的核心问题就是:「将用户的原始查询转化为更适合检索的形式。」
一个好的查询预处理,可以将检索的 「Recall@10 提升 15%~40%」,直接决定最终回答的质量。
二、查询预处理的整体架构
┌──────────────┐│ 用户提问 │└──────┬───────┘ ↓┌──────────────────────────┐│ 第一层:查询预处理 │ ← 本文重点│ 查询改写/意图识别/查询扩展 │└──────────┬───────────────┘ ↓┌──────────────────────────┐│ 第二层:向量检索(粗排) │└──────────┬───────────────┘ ↓┌──────────────────────────┐│ 第三层:精排 Reranker │└──────────┬───────────────┘ ↓┌──────────────────────────┐│ 第四层:LLM 生成回答 │└──────────────────────────┘
在深入各方案之前,先看一下接口抽象。不管用哪种方案,对外暴露的接口应该是统一的:
// Enhancer 查询增强器接口type Enhancer interface { EnhanceQuery(ctx context.Context, req *Request) (*Enhanced, error)}type Request struct { Query string // 用户当前查询 History []Message // 对话历史}type Enhanced struct { Enhanced string // 增强后的查询 Keywords []string // 提取的关键词}
有了统一接口,不同方案可以自由切换和组合。接下来逐一剖析。
三、方案一:Passthrough(直接透传)
原理
最简单的方案——「什么都不做」,直接把用户的原始查询传给检索模块。
用户查询: "Go语言怎么做依赖注入?" ↓检索查询: "Go语言怎么做依赖注入?" (原封不动)
关键实现
type PassthroughEnhancer struct{}func (p *PassthroughEnhancer) EnhanceQuery( ctx context.Context, req *Request,) (*Enhanced, error) { return &Enhanced{ Enhanced: req.Query, Keywords: []string{req.Query}, }, nil}
适用场景
- ✅ 「单轮对话」,用户查询本身完整、自包含
- ✅ 「MVP 快速上线」,先跑通 RAG 全流程
- ✅ 「成本敏感」,不愿为每次查询额外调用模型
- ❌ 多轮对话,口语化查询
一句话总结
❝
零延迟、零成本、零依赖,但完全依赖用户输入质量。适合作为起步方案和降级兜底。
❞

四、方案二:规则/统计方法(Rule-Based)
原理
通过预定义的规则和统计方法对查询进行预处理:
原始查询: "请问一下 trasformer 的 self atention 机制是怎么运作的呢?" ↓ 停用词移除 → "trasformer self atention 机制 运作" ↓ 拼写纠错 → "transformer self attention 机制 运作" ↓ 同义词扩展 → keywords: ["transformer", "self-attention", "自注意力", "机制"]
四个核心操作:
- 「停用词移除」——去掉"的"、“了”、"请问"等无意义词
- 「同义词扩展」——将"ML"扩展为"Machine Learning"
- 「拼写纠错」——将"Trasformer"纠正为"Transformer"
- 「词干提取」——将"running"还原为"run"(英文场景)
关键实现
核心数据结构就是两张表——停用词表和同义词表:
type RuleBasedEnhancer struct { stopWords map[string]bool // 停用词表 synonyms map[string][]string // 同义词映射}func (e *RuleBasedEnhancer) EnhanceQuery( ctx context.Context, req *Request,) (*Enhanced, error) { tokens := tokenize(req.Query) // 1. 移除停用词 filtered := make([]string, 0, len(tokens)) for _, t := range tokens { if !e.stopWords[strings.ToLower(t)] { filtered = append(filtered, t) } } // 2. 同义词扩展(扩充关键词列表,不改变主查询) keywords := make([]string, 0) for _, t := range filtered { keywords = append(keywords, t) if syns, ok := e.synonyms[strings.ToLower(t)]; ok { keywords = append(keywords, syns...) } } return &Enhanced{ Enhanced: strings.Join(filtered, " "), Keywords: keywords, }, nil}
「关键细节:同义词表的维护策略」
同义词表不是随便写的,需要按优先级分层:
| 层级 | 来源 | 示例 |
|---|---|---|
| 通用缩写 | 行业通用 | k8s→kubernetes , db→database |
| 领域术语 | 业务知识库 | DI→dependency injection→依赖注入 |
| 口语映射 | 用户行为日志 | 挂了→服务不可用 , 卡了→性能问题 |
适用场景
- ✅ 有明确的行业术语/缩写词表
- ✅ 延迟要求极高(<1ms)
- ✅ 搜索引擎式关键词匹配场景
- ❌ 无法处理语义理解、多轮上下文
一句话总结
❝
延迟极低、可控性强、可解释,但需要人工维护词表,无法处理复杂语义。
❞
五、方案三:基于小模型的 NER + 关键词提取
原理
使用轻量 NLP 模型从查询中提取结构化信息:
原始查询: "谷歌在2017年提出的Transformer架构是怎么处理长序列问题的?" ↓ NER 实体提取 实体: [谷歌(ORG), 2017(DATE), Transformer(TECH)] ↓ 关键词提取 + TF-IDF 排序 关键词: ["Transformer", "长序列", "架构"] ↓ 组合 增强查询: "Transformer架构 长序列处理"
两个核心任务:
- 「命名实体识别(NER)」——提取人名、组织名、技术名词等实体
- 「关键词提取」——用 TF-IDF 或词性标注识别最重要的术语
关键实现
Go 中常用 jieba 分词 + 词性标注来实现:
type NERKeywordEnhancer struct { segmenter *gojieba.Jieba idf map[string]float64}func (e *NERKeywordEnhancer) EnhanceQuery( ctx context.Context, req *Request,) (*Enhanced, error) { // 分词 + 词性标注 words := e.segmenter.Tag(req.Query) // 只保留名词(n)、专有名词(nr/ns/nt)、英文(eng) keywords := make([]string, 0) for _, w := range words { word, pos, _ := strings.Cut(w, "/") if strings.HasPrefix(pos, "n") || pos == "eng" { keywords = append(keywords, word) } } // TF-IDF 排序,保留 Top-5 sort.Slice(keywords, func(i, j int) bool { return e.idf[keywords[i]] > e.idf[keywords[j]] }) iflen(keywords) > 5 { keywords = keywords[:5] } return &Enhanced{ Enhanced: strings.Join(keywords, " "), Keywords: keywords, }, nil}
「关键细节:词性过滤规则」
不是所有词性都有检索价值,经验上保留的词性标签:
| 保留 | 词性 | 说明 |
|---|---|---|
| ✅ | n/nr/ns/nt | 名词、人名、地名、机构名 |
| ✅ | eng | 英文词(通常是技术术语) |
| ✅ | vn | 动名词(如"编程"、“部署”) |
| ❌ | v/d/p/c/u | 动词、副词、介词、连词、助词 |
适用场景
- ✅ 混合检索(关键词检索 + 向量检索)
- ✅ 延迟可接受 10~50ms
- ✅ 可离线部署,不依赖外部 API
- ❌ 无法处理多轮上下文和深度语义理解
一句话总结
❝
低延迟可离线,适合从查询中提取结构化信息辅助检索,但语义理解能力有限。
❞
六、方案四:LLM 查询改写(Query Rewriting)⭐
❝
这是当前**「最主流」**的方案,重点讲。
❞
原理
将用户的**「对话历史」和「当前查询」发给 LLM,LLM 理解上下文后输出一个「独立的、适合检索的查询」**。
对话历史: 用户: 什么是 Transformer? 助手: Transformer 是一种基于自注意力机制的神经网络架构... 用户: 它和 RNN 有什么区别? ↓ [LLM 查询改写] ↓改写结果: "Transformer架构与RNN循环神经网络的区别对比"
🔑 提示词设计(核心)
提示词是这个方案的灵魂。设计要点:
「System Prompt」——定义角色和规则:
你是一个查询改写助手。你的任务是将用户的对话式查询改写为适合向量数据库检索的独立查询。规则:1. 改写后的查询必须是独立的,不依赖对话上下文即可理解2. 解析所有指代词("它"、"这个"、"那个"等),替换为具体名词3. 保留关键技术术语,不要过度简化4. 改写结果应该是一个陈述性的短语或短句,不要用疑问句5. 如果当前查询已经足够明确,保持原样即可,不要过度改写6. 只输出改写后的查询,不要解释
「User Prompt」——动态构建:
对话历史:用户:什么是 gRPC?助手:gRPC 是 Google 开发的高性能 RPC 框架...当前查询:它支持哪些语言?请改写上述查询。
「为什么提示词要这样写?几个关键细节:」
- 「“陈述性短语,不要疑问句”」——向量数据库中的文档是陈述性的,用陈述句检索相似度更高
- 「“不要过度改写”」——有些 LLM 会把简单查询"润色"得面目全非,反而降低检索效果
- 「“只输出改写后的查询”」——避免 LLM 输出"好的,改写结果如下:…"这类废话
- 「Temperature 设为 0」——查询改写需要确定性输出,不需要创造性
关键实现
const queryRewriteSystemPrompt = `你是一个查询改写助手。你的任务是将用户的对话式查询改写为适合向量数据库检索的独立查询。规则:1. 改写后的查询必须是独立的,不依赖对话上下文即可理解2. 解析所有指代词("它"、"这个"、"那个"等),替换为具体名词3. 保留关键技术术语,不要过度简化4. 改写结果应该是一个陈述性的短语或短句,不要用疑问句5. 如果当前查询已经足够明确,保持原样即可,不要过度改写6. 只输出改写后的查询,不要解释示例:对话历史:用户:什么是 gRPC?助手:gRPC 是 Google 开发的高性能 RPC 框架...当前查询:它支持哪些语言?改写结果:gRPC 支持的编程语言列表`type LLMQueryRewriter struct { client LLMClient model string}func (r *LLMQueryRewriter) EnhanceQuery( ctx context.Context, req *Request,) (*Enhanced, error) { prompt := r.buildUserPrompt(req) resp, err := r.client.ChatCompletion(ctx, &ChatRequest{ Model: r.model, Messages: []Message{ {Role: "system", Content: queryRewriteSystemPrompt}, {Role: "user", Content: prompt}, }, MaxTokens: 200, // 改写查询不需要太长 Temperature: 0.0, // 确定性输出 }) if err != nil { // 降级:返回原始查询,不要让预处理失败阻断整个流程 return &Enhanced{Enhanced: req.Query, Keywords: []string{req.Query}}, nil } enhanced := strings.TrimSpace(resp.Content) return &Enhanced{Enhanced: enhanced, Keywords: extractKeywords(enhanced)}, nil}func (r *LLMQueryRewriter) buildUserPrompt(req *Request) string { var sb strings.Builder iflen(req.History) > 0 { sb.WriteString("对话历史:\n") for _, msg := range req.History { role := "用户" if msg.Role == "assistant" { role = "助手" } sb.WriteString(fmt.Sprintf("%s:%s\n", role, msg.Content)) } sb.WriteString("\n") } sb.WriteString(fmt.Sprintf("当前查询:%s\n\n请改写上述查询。", req.Query)) return sb.String()}
模型选择
查询改写任务**「不需要大模型」**,7B~8B 的轻量模型完全够用:
| 模型 | 延迟 | 成本 | 推荐度 |
|---|---|---|---|
| GPT-4o-mini | ~300ms | ~$0.0001/次 | ⭐⭐⭐⭐⭐ |
| DeepSeek-V3 | ~400ms | ~$0.0001/次 | ⭐⭐⭐⭐⭐ |
| Qwen2.5-7B(自部署) | ~100ms | 自部署成本 | ⭐⭐⭐⭐ |
适用场景
- ✅ 「多轮对话」(必须方案)
- ✅ 口语化查询、跨语言检索
- ❌ 超低延迟场景(200~500ms 额外延迟)
- ❌ 完全离线环境
一句话总结
❝
效果最好的通用方案,多轮对话的刚需。注意降级策略和 Temperature 设为 0。
❞
七、方案五:HyDE(假想文档嵌入)
原理
HyDE(Hypothetical Document Embedding)由 CMU 在 2022 年提出,思路非常巧妙:
「不直接用查询去检索,而是先让 LLM 生成一个"假想的回答文档",用这个假想文档的 Embedding 去检索真实文档。」
用户查询: "Go语言怎么做依赖注入?" ↓ LLM 生成假想回答假想文档: "在Go语言中,依赖注入通常通过构造函数参数传递来实现。 常见模式包括:构造函数注入、Functional Options 模式、 Wire 框架的编译时注入、接口驱动设计……" ↓ 对假想文档做 Embedding ↓ 用该向量检索真实文档
「为什么有效?」
向量空间中,「"问题"和"回答"的向量距离通常较远」。用问题向量检索回答文档,天然存在语义鸿沟:
向量空间: 问题向量 ● ↗ ↖ (距离远)真实文档A ● ● 真实文档B ↑(距离近)假想文档 ● ← 用这个向量检索,和真实文档天然更近
假想文档本身就是"回答"的形式,它的向量和知识库中的真实文档向量天然更接近。
🔑 提示词设计(核心)
HyDE 的提示词有两个关键要求:
- 「生成的内容要像一篇文档片段」,而不是对话式回答
- 「要尽量覆盖相关术语」,因为最终目的是用 Embedding 做检索
请针对以下问题,写一段专业的技术文档片段。要求:1. 直接给出内容,不要包含"根据"、"以下是"等引导语2. 尽量覆盖相关的技术术语和概念3. 内容格式应该像知识库中的文档,而不是聊天回答4. 长度控制在 150~200 字问题:{query}
「关键细节:为什么要强调"像文档而不是聊天回答"?」
因为你的知识库里存的是文档,如果假想文档的语体是"首先我来给你解释一下……",它的 Embedding 会偏向对话风格,反而和文档的距离变远。
关键实现
type HyDEEnhancer struct { llmClient LLMClient model string}func (h *HyDEEnhancer) EnhanceQuery( ctx context.Context, req *Request,) (*Enhanced, error) { hypoDoc, err := h.generateHypotheticalDoc(ctx, req.Query) if err != nil { return &Enhanced{Enhanced: req.Query, Keywords: []string{req.Query}}, nil } // 返回假想文档作为增强查询,后续 Retriever 会对它做 Embedding 并检索 return &Enhanced{Enhanced: hypoDoc, Keywords: extractKeywords(hypoDoc)}, nil}func (h *HyDEEnhancer) generateHypotheticalDoc( ctx context.Context, query string,) (string, error) { prompt := fmt.Sprintf(`请针对以下问题,写一段专业的技术文档片段。要求:1. 直接给出内容,不要包含"根据"、"以下是"等引导语2. 尽量覆盖相关的技术术语和概念3. 内容格式应该像知识库中的文档,而不是聊天回答4. 长度控制在 150~200 字问题:%s`, query) resp, err := h.llmClient.ChatCompletion(ctx, &ChatRequest{ Model: h.model, Messages: []Message{ {Role: "user", Content: prompt}, }, MaxTokens: 300, Temperature: 0.7, // 稍高温度,覆盖更多术语 }) if err != nil { return"", fmt.Errorf("generate hypothetical document: %w", err) } return strings.TrimSpace(resp.Content), nil}
「注意 Temperature 设为 0.7」——和查询改写不同,这里希望生成的内容更丰富、覆盖更多术语,所以温度稍高。
适用场景
- ✅ 「简短查询」——用户只输入几个词,但需要匹配长文档
- ✅ 「专业领域」——用户查询和文档之间存在术语鸿沟
- ❌ 实时性要求高(500ms~2s 延迟)
- ❌ LLM 幻觉敏感场景(假想文档可能包含错误信息)
一句话总结
❝
巧妙地用"假想回答"弥补问题和文档之间的语义鸿沟,对简短查询效果显著。注意提示词要强调"像文档不像聊天"。
❞
八、方案六:Multi-Query(多查询扩展)
原理
核心思路:「一个问题从不同角度生成多个查询变体」,分别检索后用排序融合算法合并结果。
原始查询: "如何优化 Go 程序的内存使用?" ↓ LLM 生成多个变体┌─────────────────────────────────────┐│ 变体1: "Go语言内存优化最佳实践" ││ 变体2: "Golang 减少内存分配和GC压力" ││ 变体3: "Go内存泄漏排查和pprof使用" ││ 变体4: "Go sync.Pool对象池内存复用" │└─────────────────┬───────────────────┘ ↓ 分别检索 → RRF 融合排序 → 更全面的结果
🔑 提示词设计(核心)
Multi-Query 的提示词有一个核心要求——「变体之间要有差异化」,不能换个措辞说同一件事:
请从不同角度改写以下查询,生成 4 个搜索查询变体。原始查询:{query}要求:1. 每行一个查询变体,不要编号2. 每个变体必须是独立的、完整的查询3. 变体之间要有明确的角度差异,例如: - 概念解释角度 - 实现方法角度 - 最佳实践角度 - 常见问题/排错角度4. 不要只是换个措辞说同一件事5. 只输出查询变体,不要其他内容
「关键细节:"不要只换措辞"这条为什么重要?」
如果 4 个变体只是同义改写(“优化内存”、“减少内存”、“内存性能调优”、“内存管理优化”),它们检索到的文档高度重叠,Multi-Query 就退化成了普通查询改写,白白多花了 4 倍检索成本。
RRF 排序融合算法
Multi-Query 的检索结果需要用 「Reciprocal Rank Fusion(RRF)」 合并:
公式:RRF_score(doc) = Σ 1/(k + rank_i) 其中 k 通常取 60示例(3 个查询变体):查询1排序: [文档A, 文档B, 文档C]查询2排序: [文档C, 文档A, 文档E]查询3排序: [文档A, 文档E, 文档C]文档A: 1/(60+0) + 1/(60+1) + 1/(60+0) = 0.0498 ← 排第1文档C: 1/(60+2) + 1/(60+0) + 1/(60+2) = 0.0489 ← 排第2文档E: 0 + 1/(60+2) + 1/(60+1) = 0.0325 ← 排第3
关键实现
type MultiQueryEnhancer struct { llmClient LLMClient model string numQueries int}func (m *MultiQueryEnhancer) EnhanceQuery( ctx context.Context, req *Request,) (*Enhanced, error) { variants, err := m.generateVariants(ctx, req.Query) if err != nil { return &Enhanced{Enhanced: req.Query, Keywords: []string{req.Query}}, nil } // 原始查询 + 变体 allQueries := append([]string{req.Query}, variants...) return &Enhanced{ Enhanced: strings.Join(allQueries, "\n"), Keywords: dedup(extractAllKeywords(allQueries)), }, nil}// RRF 融合排序(配合 Retriever 使用)func rrfFusion(results [][]Document, k int) []Document { scores := make(map[string]float64) docs := make(map[string]Document) for _, ranking := range results { for rank, doc := range ranking { scores[doc.ID] += 1.0 / float64(k+rank) docs[doc.ID] = doc } } // 按 RRF 分数降序排列 type scored struct { doc Document score float64 } sorted := make([]scored, 0, len(docs)) for id, doc := range docs { sorted = append(sorted, scored{doc: doc, score: scores[id]}) } sort.Slice(sorted, func(i, j int) bool { return sorted[i].score > sorted[j].score }) result := make([]Document, len(sorted)) for i, s := range sorted { result[i] = s.doc } return result}
适用场景
- ✅ 「高召回率要求」——不能漏掉任何相关文档
- ✅ 「复杂问题」——涉及多个维度和子主题
- ❌ 实时对话(总延迟 1~3s)
- ❌ 成本敏感(多次 LLM 调用 + 多次检索)
一句话总结
❝
召回率最高的方案,但延迟和成本也最高。提示词的关键是确保变体之间有真正的角度差异。
❞
九、方案七:Step-Back Prompting(后退提示)
原理
由 Google DeepMind 在 2023 年提出,核心思路:
「不直接检索具体问题,而是先"后退一步",将问题抽象为更高层次的概念性问题,用抽象问题检索背景知识,再结合原始问题检索具体细节。」
原始查询(具体): "gRPC-Go 中如何实现双向流式 RPC?" ↓ Step-Back 抽象抽象查询(通用): "gRPC 流式通信的类型和实现模式" ↓ 用抽象查询检索 → 背景知识(流式 RPC 的四种类型、原理) 用原始查询检索 → 具体细节(Go 代码实现) ↓ 合并两组结果,LLM 同时拿到背景和细节来回答
🔑 提示词设计(核心)
Step-Back 的提示词需要精确控制"后退"的粒度——太粗会检索到不相关的内容,太细等于没后退:
你是一个搜索专家。给定一个具体的技术问题,请"后退一步",生成一个更高层次的概念性问题,用于检索回答原始问题所需的背景知识。规则:1. 抽象问题应该覆盖原始问题所属的知识领域2. 保留核心主题,不要太笼统("什么是编程?"就太笼统了)3. 只输出一个问题,不要解释示例:具体问题:Python 3.12 中 type 语句的语法是什么?抽象问题:Python 类型系统和类型注解的语法特性具体问题:React useEffect 的依赖数组为空时会怎样?抽象问题:React Hooks 中 useEffect 的生命周期和依赖机制具体问题:{query}抽象问题:
「关键细节:为什么要给示例?」
Step-Back 的"后退粒度"很难用规则描述清楚,但 「few-shot 示例可以隐式传达粒度标准」。示例中"Python 3.12 type 语句 → Python 类型系统"就是一个恰到好处的后退——退到了所属知识领域,但没退到"什么是 Python"。
关键实现
type StepBackEnhancer struct { llmClient LLMClient model string}func (s *StepBackEnhancer) EnhanceQuery( ctx context.Context, req *Request,) (*Enhanced, error) { abstractQuery, err := s.generateStepBack(ctx, req.Query) if err != nil { return &Enhanced{Enhanced: req.Query, Keywords: []string{req.Query}}, nil } // 同时返回原始查询和抽象查询,后续分别检索再合并 combined := req.Query + "\n" + abstractQuery keywords := dedup(append( extractKeywords(req.Query), extractKeywords(abstractQuery)..., )) return &Enhanced{Enhanced: combined, Keywords: keywords}, nil}
适用场景
- ✅ **「需要背景知识才能回答」**的问题
- ✅ 「教程/文档检索」——知识库中有概念文档和实操文档
- ❌ 简单直接的事实性问题("Go 的 goroutine 上限是多少?"不需要后退)
一句话总结
❝
通过"后退一步"检索背景知识,让回答更有深度。提示词的关键是用 few-shot 示例控制后退粒度。
❞
十、方案对比总结
全维度对比
| 维度 | Passthrough | 规则方法 | 小模型NER | LLM改写 | HyDE | Multi-Query | Step-Back |
|---|---|---|---|---|---|---|---|
| 「延迟」 | 0ms | <1ms | 10-50ms | 200-500ms | 0.5-2s | 1-3s | 300-600ms |
| 「成本」 | 免费 | 免费 | 低 | 中 | 中高 | 高 | 中 |
| 「精度提升」 | 无 | 低 | 中 | 高 | 很高 | 最高 | 高 |
| 「多轮支持」 | ❌ | ❌ | ❌ | ✅ | ❌ | ⚠️ | ❌ |
| 「实现复杂度」 | 极低 | 低 | 中 | 低 | 中 | 高 | 低 |
选型决策树
你的场景是什么?│├─ 单轮 + 查询质量高? → Passthrough├─ 有多轮对话? → LLM 查询改写(必须)│ ├─ 还需要更高召回率?→ + Multi-Query│ └─ 术语鸿沟大? → + HyDE├─ 延迟要求 < 10ms? → 规则方法├─ 延迟要求 < 50ms? → 小模型 NER└─ 需要背景知识? → Step-Back + LLM 改写
十一、实战建议
从简单开始,逐步升级
- 「MVP 阶段」:Passthrough,跑通全流程
- 「优化阶段」:加入 LLM 查询改写
- 「精细化阶段」:按需引入 HyDE / Multi-Query
降级策略是必须的
任何使用外部模型的方案,都**「必须」**有降级处理。LLM 挂了不能让整个 RAG 挂:
func (r *LLMQueryRewriter) EnhanceQuery( ctx context.Context, req *Request,) (*Enhanced, error) { result, err := r.callLLM(ctx, req) if err != nil { log.WarnfContext(ctx, "LLM rewrite failed, falling back: %v", err) return r.fallback.EnhanceQuery(ctx, req) // 降级到规则方法或 Passthrough } return result, nil}
缓存可以大幅降低成本
对于重复查询,缓存改写结果可以同时省时间和省钱:
type CachedEnhancer struct { inner Enhancer cache *lru.Cache}func (c *CachedEnhancer) EnhanceQuery( ctx context.Context, req *Request,) (*Enhanced, error) { key := buildCacheKey(req) if cached, ok := c.cache.Get(key); ok { return cached.(*Enhanced), nil } result, err := c.inner.EnhanceQuery(ctx, req) if err != nil { returnnil, err } c.cache.Add(key, result) return result, nil}
提示词设计的通用原则
回顾全文,各方案的提示词有一些共性原则:
| 原则 | 说明 | 反例 |
|---|---|---|
| 「限制输出格式」 | “只输出改写结果,不要解释” | LLM 输出"好的,改写如下:…" |
| 「给 few-shot 示例」 | 示例比规则描述更直观 | 只写规则不给示例,LLM 理解偏差 |
| 「明确边界」 | “如果已经足够明确,保持原样” | LLM 过度改写简单查询 |
| 「控制温度」 | 改写用 0,生成用 0.7 | 改写用高温度导致不稳定 |
| 「匹配目标形式」 | HyDE 要"像文档",改写要"陈述句" | HyDE 生成对话式回答 |
十二、写在最后
查询预处理是 RAG 系统中被严重低估的环节。很多团队花大量时间调优 Embedding 模型和 Reranker,却忽略了最前面的查询预处理。
「记住一句话:Garbage In, Garbage Out。」
如果查询本身有问题,后面的检索和排序做得再好也无济于事。
选择适合你场景的方案,从简单开始,逐步优化——这才是 RAG 优化的正确姿势。
普通人如何抓住AI大模型的风口?
领取方式在文末
为什么要学习大模型?
目前AI大模型的技术岗位与能力培养随着人工智能技术的迅速发展和应用 , 大模型作为其中的重要组成部分 , 正逐渐成为推动人工智能发展的重要引擎 。大模型以其强大的数据处理和模式识别能力, 广泛应用于自然语言处理 、计算机视觉 、 智能推荐等领域 ,为各行各业带来了革命性的改变和机遇 。
目前,开源人工智能大模型已应用于医疗、政务、法律、汽车、娱乐、金融、互联网、教育、制造业、企业服务等多个场景,其中,应用于金融、企业服务、制造业和法律领域的大模型在本次调研中占比超过 30%。

随着AI大模型技术的迅速发展,相关岗位的需求也日益增加。大模型产业链催生了一批高薪新职业:

人工智能大潮已来,不加入就可能被淘汰。如果你是技术人,尤其是互联网从业者,现在就开始学习AI大模型技术,真的是给你的人生一个重要建议!
最后
只要你真心想学习AI大模型技术,这份精心整理的学习资料我愿意无偿分享给你,但是想学技术去乱搞的人别来找我!
在当前这个人工智能高速发展的时代,AI大模型正在深刻改变各行各业。我国对高水平AI人才的需求也日益增长,真正懂技术、能落地的人才依旧紧缺。我也希望通过这份资料,能够帮助更多有志于AI领域的朋友入门并深入学习。
真诚无偿分享!!!
vx扫描下方二维码即可
加上后会一个个给大家发
【附赠一节免费的直播讲座,技术大佬带你学习大模型的相关知识、学习思路、就业前景以及怎么结合当前的工作发展方向等,欢迎大家~】

大模型全套学习资料展示
自我们与MoPaaS魔泊云合作以来,我们不断打磨课程体系与技术内容,在细节上精益求精,同时在技术层面也新增了许多前沿且实用的内容,力求为大家带来更系统、更实战、更落地的大模型学习体验。

希望这份系统、实用的大模型学习路径,能够帮助你从零入门,进阶到实战,真正掌握AI时代的核心技能!
01 教学内容

-
从零到精通完整闭环:【基础理论 →RAG开发 → Agent设计 → 模型微调与私有化部署调→热门技术】5大模块,内容比传统教材更贴近企业实战!
-
大量真实项目案例: 带你亲自上手搞数据清洗、模型调优这些硬核操作,把课本知识变成真本事!
02适学人群
应届毕业生: 无工作经验但想要系统学习AI大模型技术,期待通过实战项目掌握核心技术。
零基础转型: 非技术背景但关注AI应用场景,计划通过低代码工具实现“AI+行业”跨界。
业务赋能突破瓶颈: 传统开发者(Java/前端等)学习Transformer架构与LangChain框架,向AI全栈工程师转型。

vx扫描下方二维码即可
【附赠一节免费的直播讲座,技术大佬带你学习大模型的相关知识、学习思路、就业前景以及怎么结合当前的工作发展方向等,欢迎大家~】

本教程比较珍贵,仅限大家自行学习,不要传播!更严禁商用!
03 入门到进阶学习路线图
大模型学习路线图,整体分为5个大的阶段:

04 视频和书籍PDF合集

从0到掌握主流大模型技术视频教程(涵盖模型训练、微调、RAG、LangChain、Agent开发等实战方向)

新手必备的大模型学习PDF书单来了!全是硬核知识,帮你少走弯路(不吹牛,真有用)

05 行业报告+白皮书合集
收集70+报告与白皮书,了解行业最新动态!

06 90+份面试题/经验
AI大模型岗位面试经验总结(谁学技术不是为了赚$呢,找个好的岗位很重要)

07 deepseek部署包+技巧大全

由于篇幅有限
只展示部分资料
并且还在持续更新中…
真诚无偿分享!!!
vx扫描下方二维码即可
加上后会一个个给大家发
【附赠一节免费的直播讲座,技术大佬带你学习大模型的相关知识、学习思路、就业前景以及怎么结合当前的工作发展方向等,欢迎大家~】

275



被折叠的 条评论
为什么被折叠?



