

代码开源Github地址 ↗
RAG查询优化:多查询与查询转换技术#
在基础RAG系统中,我们使用单一查询进行检索。但在实际应用中,用户的查询往往存在表达模糊、角度单一或过于笼统的问题。本章将介绍多种查询优化技术,让你的RAG系统能够更准确地理解用户意图。
查询优化的必要性#
单一查询的局限性#
用户查询: “机器学习是什么?”
# 可能错过的相关文档:
- "深度学习入门" (使用了不同但相关的术语)
- "AI算法基础" (更广泛的主题)
- "神经网络原理" (具体技术)
- "监督学习vs无监督学习" (细分话题)python问题分析:
- 术语不匹配:用户说”机器学习”,文档用”AI算法”
- 粒度不一致:用户问宏观概念,文档讲具体技术
- 表达差异:同一概念有多种表述方式
查询优化如何帮助?#
查询优化的核心思想:通过生成多个角度的查询、重写查询或分解复杂查询,增加检索到相关文档的概率。
# ✅ 查询优化后
原始查询: "机器学习是什么?"
生成的变体:
1. "什么是机器学习算法?"
2. "机器学习的基本概念和原理"
3. "AI中的机器学习技术"
4. "机器学习的应用场景"
→ 并行检索 → 合并结果 → 去重 → 生成答案python技术概览#
本章将介绍5种主要的查询优化技术:
| 技术 | 核心思想 | 适用场景 | 复杂度 |
|---|---|---|---|
| Multi-Query | 生成查询的多个变体 | 用户查询表达不清 | ⭐ |
| RAG-Fusion | 多查询+重排序融合 | 需要高质量结果 | ⭐⭐ |
| Decomposition | 分解复杂查询 | 多步骤问题 | ⭐⭐⭐ |
| Step Back | 先问概括性问题 | 需要背景知识 | ⭐⭐ |
| HyDE | 生成假设性文档 | 语义搜索增强 | ⭐⭐⭐ |
环境准备#
import os
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import Chroma
from vllm import LLM
# 1. 加载本地嵌入模型
local_model_path = "./Models/maidalun/bce-embedding-base_v1"
embeddings = HuggingFaceEmbeddings(
model_name=local_model_path,
model_kwargs={"device": "cuda"},
encode_kwargs={"normalize_embeddings": True}
)
# 2. 加载本地向量数据库
vectorstore = Chroma(
persist_directory="./chroma_db",
embedding_function=embeddings
)
# 3. 加载本地大模型
model_dir = "../Qwen-vllm/Models/Qwen/Qwen-7B-Chat-Int8"
os.environ['VLLM_USE_MODELSCOPE'] = 'True'
llm = LLM(
model=model_dir,
tokenizer=model_dir,
trust_remote_code=True
)
print("✅ 环境初始化完成")python输出:
✅ 环境初始化完成plaintextPart1:Multi-Query - 多角度查询#
1.1 核心思想#
Multi-Query技术通过LLM生成原始查询的多个变体,从不同角度检索文档,提高检索的召回率。
工作流程
用户查询: "什么是Agent?"
↓
使用LLM生成变体:
├─ "Agent系统的定义是什么?"
├─ "AI Agent的核心概念"
└─ "什么是自主智能体?"
↓
并行检索每个变体
↓
合并并去重结果
↓
生成最终答案plaintext1.2 完整实现代码#
import os
import chromadb
from vllm import LLM, SamplingParams
from modelscope import snapshot_download
from langchain_community.embeddings import HuggingFaceEmbeddings
from typing import List, Dict, Any
def get_unique_documents(documents: List[List]) -> List:
"""去重文档"""
unique_docs = {}
for doc_list in documents:
for doc in doc_list:
content = doc.page_content
if content not in unique_docs:
unique_docs[content] = doc
return list(unique_docs.values())
class MultiQueryRAG:
"""完全使用ChatML格式的Multi-Query RAG系统"""
def __init__(self, vectorstore, llm):
"""
初始化Multi-Query RAG
Args:
vectorstore: 向量数据库
llm: 语言模型
"""
self.vectorstore = vectorstore
self.retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
self.llm = llm
print("✅ Multi-Query RAG系统初始化完成")
def _generate_query_variants(self, question: str) -> List[str]:
"""使用ChatML格式生成查询变体"""
query_prompt = f"""<|im_start|>system
你是一个AI助手,擅长将用户的问题改写成多个语义相同但表达不同的搜索查询。每个查询应简洁、独立,适合用于向量检索。<|im_end|>
<|im_start|>user
原始问题:{question}
请生成3个不同的搜索查询,每行一个,不要编号,不要解释:<|im_end|>
<|im_start|>assistant
"""
sampling_params = SamplingParams(
max_tokens=500,
temperature=0.7, # 适当提高温度增加多样性
top_p=0.9,
stop=["<|im_end|>", "<|endoftext|>"]
)
outputs = self.llm.generate([query_prompt], sampling_params)
response = outputs[0].outputs[0].text.strip()
# 解析生成的查询
queries = []
lines = response.split('\n')
for line in lines:
line = line.strip()
if line and len(line) > 5:
# 移除可能的编号标记
if line[0].isdigit() and (line[1] == '.' or line[1] == '、'):
query = line[2:].strip()
else:
query = line
queries.append(query)
# 确保包含原始问题并去重
all_queries = [question] + queries
unique_queries = []
seen = set()
for q in all_queries:
if q not in seen:
seen.add(q)
unique_queries.append(q)
return unique_queries[:4] # 最多返回4个查询
def _retrieve_documents(self, queries: List[str]) -> List:
"""检索所有查询的文档"""
all_docs = []
for query in queries:
try:
docs = self.retriever.get_relevant_documents(query)
all_docs.append(docs)
print(f" 🔍 '{query}': 找到 {len(docs)} 个文档")
except Exception as e:
print(f"❌ 检索失败 '{query}': {e}")
all_docs.append([])
return all_docs
def _process_documents(self, all_docs: List[List]) -> List:
"""处理并去重文档"""
unique_docs = get_unique_documents(all_docs)
return unique_docs[:10] # 返回top-10
def _clean_context(self, text: str) -> str:
"""清理上下文内容"""
import re
if not text or not isinstance(text, str):
return text
# 清理格式
cleaned = re.sub(r'(?<=[^\s])\n(?=[^\s])', '', text) # 合并错误分割的文字
cleaned = re.sub(r'\n\s+\n', '\n\n', cleaned) # 压缩空行
cleaned = re.sub(r'\n\s+', '\n', cleaned) # 清理行内空格
cleaned = re.sub(r'[ \t]{2,}', ' ', cleaned) # 清理连续空格
cleaned = cleaned.strip() # 清理首尾空格
return cleaned
def _build_answer_prompt(self, question: str, context: str) -> str:
"""构建ChatML格式的答案生成提示词"""
cleaned_context = self._clean_context(context)
return f"""<|im_start|>system
你是一个专业的AI助手。请严格基于以下上下文信息回答问题:
{cleaned_context}
请遵循以下规则:
1. 只使用上下文中的信息回答
2. 如果上下文不包含相关信息,请回答"我不知道"
3. 保持回答准确、简洁
4. 不要编造信息<|im_end|>
<|im_start|>user
{question}<|im_end|>
<|im_start|>assistant
"""
def _generate_answer(self, prompt: str, max_tokens: int = 512, temperature: float = 0.3) -> str:
"""生成答案"""
sampling_params = SamplingParams(
max_tokens=max_tokens,
temperature=temperature,
top_p=0.8,
stop=["<|im_end|>", "<|endoftext|>"]
)
outputs = self.llm.generate([prompt], sampling_params)
return outputs[0].outputs[0].text.strip()
def query(self, question: str, max_tokens: int = 512, temperature: float = 0.3) -> Dict[str, Any]:
"""执行Multi-Query RAG查询"""
print(f"🎯 原始问题: {question}")
print("-" * 50)
# Step 1: 生成查询变体
queries = self._generate_query_variants(question)
print(f"📝 生成了 {len(queries)} 个查询:")
for i, q in enumerate(queries, 1):
print(f" {i}. {q}")
# Step 2: 检索文档
all_docs = self._retrieve_documents(queries)
total_docs_before_dedup = sum(len(docs) for docs in all_docs)
print(f"📚 检索到 {total_docs_before_dedup} 个文档(含重复)")
# Step 3: 去重
unique_docs = self._process_documents(all_docs)
print(f"✨ 去重后剩余 {len(unique_docs)} 个文档")
# Step 4: 构建上下文
context = "\n\n".join([doc.page_content for doc in unique_docs])
# Step 5: 生成答案
prompt = self._build_answer_prompt(question, context)
answer = self._generate_answer(prompt, max_tokens, temperature)
# 返回结果
return {
"question": question,
"answer": answer,
"queries": queries,
"num_docs": len(unique_docs),
"total_docs_before_dedup": total_docs_before_dedup,
"context_preview": context[:200] + "..." if len(context) > 200 else context
}python1.3 实战测试#
# === 使用示例 ===
if __name__ == "__main__":
print("🚀 ChatML格式的Multi-Query RAG")
print("=" * 60)
# 1. 创建实例
multi_rag = MultiQueryRAG(vectorstore, llm)
# 2. 执行查询
result = multi_rag.query("什么是机械臂?它有什么能力?")
# 3. 查看结果
print("\n" + "="*60)
print("💡 答案:", result["answer"])
print("📝 使用的查询:", result["queries"])
print("📚 参考文档数:", result["num_docs"])python实际输出:
🚀 ChatML格式的Multi-Query RAG
============================================================
✅ Multi-Query RAG系统初始化完成
🎯 原始问题: 什么是机械臂?它有什么能力?
--------------------------------------------------
Processed prompts: 100%|██████████| 1/1 [00:00<00:00, 2.55it/s]
📝 生成了 4 个查询:
1. 什么是机械臂?它有什么能力?
2. 机械臂是什么?
3. 机械臂有哪些功能?
4. 机械臂的工作原理是什么?
🔍 '什么是机械臂?它有什么能力?': 找到 3 个文档
🔍 '机械臂是什么?': 找到 3 个文档
🔍 '机械臂有哪些功能?': 找到 3 个文档
🔍 '机械臂的工作原理是什么?': 找到 3 个文档
📚 检索到 12 个文档(含重复)
✨ 去重后剩余 6 个文档
Processed prompts: 100%|██████████| 1/1 [00:00<00:00, 1.24it/s]
============================================================
💡 答案: 机械臂是一种能够自动执行任务的机器人手臂,它由多个关节组成,可以按照预设的程序或指令进行精确的运动。机械臂具有强大的力量和精确度,可以完成各种复杂的任务,例如抓取、搬运、装配等。
📝 使用的查询: ['什么是机械臂?它有什么能力?', '机械臂是什么?', '机械臂有哪些功能?', '机械臂的工作原理是什么?']
📚 参考文档数: 6plaintext1.4 Multi-Query的优缺点分析#
✅ 优点
- 提高召回率:找到更多相关文档
- 覆盖不同角度:应对表达方式差异
- 对模糊查询有效:用户表达不清时特别有用
- 实现相对简单:逻辑清晰,易于调试
❌ 缺点
- 增加检索成本:多次查询消耗更多资源
- 可能引入噪声:不相关的变体影响质量
- 需要额外LLM调用:生成变体增加延迟
- 去重可能过滤有价值文档:相似但不同的内容被误删
1.5 优化技巧#
1. 限制查询数量#
def _generate_query_variants(self, question: str) -> List[str]:
# ... 生成逻辑 ...
return unique_queries[:4] # 最多返回4个查询,平衡效果与成本python2. 使用缓存避免重复生成#
from functools import lru_cache
@lru_cache(maxsize=100)
def cached_query_generation(question: str) -> tuple:
"""缓存查询生成结果"""
queries = query_generator.invoke({"question": question})
return tuple(queries) # 返回元组以支持缓存python3. 异步并行检索#
import asyncio
async def async_retrieve_all(queries: List[str], retriever):
"""异步并行检索,大幅提升速度"""
tasks = [retriever.aget_relevant_documents(q) for q in queries]
results = await asyncio.gather(*tasks, return_exceptions=True)
return resultspython4. 智能过滤低质量变体#
def filter_low_quality_queries(original: str, variants: List[str]) -> List[str]:
"""过滤与原始查询差异过大的变体"""
filtered = []
for variant in variants:
# 计算语义相似度,保留相关变体
similarity = calculate_similarity(original, variant)
if similarity > 0.6: # 相似度阈值
filtered.append(variant)
return filteredpython总结#
Multi-Query技术通过查询多样性有效解决了单一查询的局限性,在实际应用中:
🎯 适用场景
- 用户查询表达模糊或不专业时
- 需要从多角度理解复杂概念时
- 文档库中使用术语不统一时
⚡ 使用建议
- 简单查询:直接使用单一查询
- 复杂/模糊查询:启用Multi-Query
- 性能敏感:结合缓存和异步优化
💡 经验法则:当不确定用户查询的精确表述时,Multi-Query是提高召回率的有效策略。
在下一部分,我们将探讨更高级的RAG-Fusion技术,它结合了多查询和重排序,能够进一步提升检索质量。
Part2:RAG-Fusion - 融合式检索#
2.1 核心概念#
RAG-Fusion结合了Multi-Query和倒数排序融合(Reciprocal Rank Fusion, RRF),不仅生成多个查询,还智能地合并和重排序结果。
什么是倒数排序融合?
RRF是一种排序融合算法,给予排名靠前的文档更高的分数:
公式: RRF_score(doc) = Σ 1 / (k + rank(doc))
其中:
k= 常数(通常为60)rank(doc)= 文档在某个查询结果中的排名Σ= 对所有查询结果求和
示例演示
# 查询1的结果排序:
查询1: "什么是Agent?"
1. 文档A (排名1)
2. 文档B (排名2)
3. 文档C (排名3)
# 查询2的结果排序:
查询2: "AI Agent的定义"
1. 文档B (排名1) ← 在这个查询中排名更高
2. 文档D (排名2)
3. 文档A (排名3)
# RRF融合计算 (k=60):
文档A: 1/(60+1) + 1/(60+3) = 0.0164 + 0.0159 = 0.0323
文档B: 1/(60+2) + 1/(60+1) = 0.0161 + 0.0164 = 0.0325 ← 最高分
文档C: 1/(60+3) + 0 = 0.0159
文档D: 0 + 1/(60+2) = 0.0161
最终排序: B > A > D > Cpython2.2 RRF算法实现#
from typing import List, Tuple
from vllm import SamplingParams
def reciprocal_rank_fusion(
results: List[List],
k: int = 60
) -> List[Tuple[any, float]]:
"""
实现倒数排序融合
Args:
results: 多个查询的结果列表
k: RRF常数
Returns:
排序后的(文档, 分数)列表
"""
# 存储每个文档的融合分数
fusion_scores = {}
for docs in results:
for rank, doc in enumerate(docs):
# 使用文档内容作为唯一标识
doc_id = doc.page_content
# 计算RRF分数
if doc_id not in fusion_scores:
fusion_scores[doc_id] = {
'doc': doc,
'score': 0
}
# 累加分数
fusion_scores[doc_id]['score'] += 1 / (k + rank + 1)
# 按分数排序
sorted_docs = sorted(
fusion_scores.values(),
key=lambda x: x['score'],
reverse=True
)
return [(item['doc'], item['score']) for item in sorted_docs]python2.3 完整RAG-Fusion系统#
class RAGFusion:
"""使用ChatML格式的RAG-Fusion系统"""
def __init__(self, vectorstore, llm, k: int = 60):
self.vectorstore = vectorstore
self.retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
self.llm = llm
self.k = k
def generate_queries(self, question: str, n: int = 3) -> List[str]:
"""使用ChatML格式生成查询变体"""
prompt = f"""<|im_start|>system
你是一个AI助手,擅长将用户的问题改写成多个语义相同但表达不同的搜索查询。
请生成{n}个不同角度的查询变体。
要求:
1. 语义相关但表达不同
2. 覆盖不同角度
3. 每行一个查询<|im_end|>
<|im_start|>user
原始问题:{question}
请生成{n}个不同的搜索查询,每行一个:<|im_end|>
<|im_start|>assistant
"""
sampling_params = SamplingParams(
max_tokens=512,
temperature=0.7,
top_p=0.9,
stop=["<|im_end|>", "<|endoftext|>"]
)
outputs = self.llm.generate([prompt], sampling_params)
response = outputs[0].outputs[0].text.strip()
# 解析生成的查询
queries = []
lines = response.split('\n')
for line in lines:
line = line.strip()
if line and len(line) > 5: # 过滤太短的查询
# 移除可能的编号标记
if line[0].isdigit() and (line[1] == '.' or line[1] == '、'):
query = line[2:].strip()
else:
query = line
queries.append(query)
# 确保包含原始问题并去重
all_queries = [question] + queries
unique_queries = []
seen = set()
for q in all_queries:
if q not in seen:
seen.add(q)
unique_queries.append(q)
return unique_queries[:n+1] # 包含原始问题
def retrieve_and_fuse(self, queries: List[str]) -> List[Tuple[any, float]]:
"""检索并融合结果"""
all_results = []
print(f"🔍 执行 {len(queries)} 个查询...")
for i, query in enumerate(queries, 1):
docs = self.retriever.get_relevant_documents(query)
all_results.append(docs)
print(f" 查询{i}: '{query}' -> 检索到 {len(docs)} 个文档")
# RRF融合
fused_results = reciprocal_rank_fusion(all_results, k=self.k)
print(f"✨ 融合后共 {len(fused_results)} 个唯一文档")
return fused_results
def _build_answer_prompt(self, question: str, context: str) -> str:
"""构建ChatML格式的答案生成提示词"""
return f"""<|im_start|>system
你是一个专业的AI助手。请基于以下按相关性排序的文档回答问题。
{context}
请遵循以下规则:
1. 只使用文档中的信息回答
2. 如果文档不包含相关信息,请回答"我不知道"
3. 保持回答准确、简洁<|im_end|>
<|im_start|>user
{question}<|im_end|>
<|im_start|>assistant
"""
def _generate_answer(self, prompt: str, max_tokens: int = 512, temperature: float = 0.3) -> str:
"""生成答案"""
sampling_params = SamplingParams(
max_tokens=max_tokens,
temperature=temperature,
top_p=0.8,
stop=["<|im_end|>", "<|endoftext|>"]
)
outputs = self.llm.generate([prompt], sampling_params)
return outputs[0].outputs[0].text.strip()
def query(self, question: str, top_k: int = 5, max_tokens: int = 512, temperature: float = 0.3) -> dict:
"""执行RAG-Fusion查询"""
print(f"🎯 原始问题: {question}")
print("-" * 50)
# 1. 生成查询
queries = self.generate_queries(question)
print(f"📝 生成了 {len(queries)} 个查询:")
for i, q in enumerate(queries, 1):
print(f" {i}. {q}")
# 2. 检索并融合
fused_docs = self.retrieve_and_fuse(queries)
# 3. 选择top-k
top_docs = fused_docs[:top_k]
print(f"🏆 选择Top-{len(top_docs)} 文档:")
for i, (doc, score) in enumerate(top_docs, 1):
preview = doc.page_content[:100] + "..." if len(doc.page_content) > 100 else doc.page_content
print(f" {i}. [分数: {score:.4f}] {preview}")
# 4. 生成答案
context = "\n\n".join([
f"[文档{i+1} 分数: {score:.4f}]\n{doc.page_content}"
for i, (doc, score) in enumerate(top_docs)
])
prompt = self._build_answer_prompt(question, context)
answer = self._generate_answer(prompt, max_tokens, temperature)
return {
"question": question,
"generated_queries": queries,
"num_docs": len(top_docs),
"top_scores": [score for _, score in top_docs],
"answer": answer,
"context_preview": context[:200] + "..." if len(context) > 200 else context
}python2.4 实战测试#
print("🚀 RAG-Fusion系统")
print("=" * 60)
# 1. 创建实例
rag_fusion = RAGFusion(vectorstore, llm, k=60)
# 2. 执行查询
result = rag_fusion.query("什么是机械臂?它有哪些关键能力?")
# 3. 查看结果
print("\n" + "="*60)
print("生成的查询:")
for q in result["generated_queries"]:
print(f" - {q}")
print(f"\nTop-{result['num_docs']} 文档分数:")
for i, score in enumerate(result["top_scores"], 1):
print(f" {i}. {score:.4f}")
print("\n答案:")
print(result["answer"])python实际输出:
🚀 RAG-Fusion系统
============================================================
🎯 原始问题: 什么是机械臂?它有哪些关键能力?
--------------------------------------------------
Processed prompts: 100%|██████████| 1/1 [00:00<00:00, 1.57it/s]
📝 生成了 4 个查询:
1. 什么是机械臂?它有哪些关键能力?
2. 机械臂是什么?它的主要功能是什么?
3. 机械臂有哪些重要的特点和功能?
4. 机械臂的运作原理是什么?它有哪些关键能力?
🔍 执行 4 个查询...
查询1: '什么是机械臂?它有哪些关键能力?' -> 检索到 5 个文档
查询2: '机械臂是什么?它的主要功能是什么?' -> 检索到 5 个文档
查询3: '机械臂有哪些重要的特点和功能?' -> 检索到 5 个文档
查询4: '机械臂的运作原理是什么?它有哪些关键能力?' -> 检索到 5 个文档
✨ 融合后共 13 个唯一文档
🏆 选择Top-5 文档:
1. [分数: 0.0640] 尽管,机械臂的运动速度可以设定为匀速运动, 避免加速度变化而造成对目标和夹爪之间动力学平衡关系的响。但是, 机械臂的
2. [分数: 0.0489] 功能,其作用力的范围为 50N,精确度为 2.5N,准确度为 4N,扭矩范围为 10N·m,
精确度为 0.04N·m,准确度为 0.3N。机械臂本体自重 20.6kg,采用 220V交流供电,
3. [分数: 0.0318] 机械臂
可重复性 +-0.03mm
有效负载 5 千克/11 磅
工作半径 850mm/33.5 英寸
自由度 6 个旋转关节
4. [分数: 0.0315] ±180°/s,机械臂末端速度视各关节载荷与实际速度而定。机械臂本体的位姿可重复性
精度为 ±0.03mm。与其它型号机械臂不同的是,UR5e机械臂的工具法兰带有力感应
5. [分数: 0.0161] 机记录该浮雕风格的接触表面图像,并使用光度立体算法
[55] 重建接触表面的深度图。
该传感器通过凝胶(gel)形变图像获取触觉信息,因此被称为Gelsight。为机器人手指
Processed prompts: 100%|██████████| 1/1 [00:02<00:00, 2.35s/it]
============================================================
生成的查询:
- 什么是机械臂?它有哪些关键能力?
- 机械臂是什么?它的主要功能是什么?
- 机械臂有哪些重要的特点和功能?
- 机械臂的运作原理是什么?它有哪些关键能力?
Top-5 文档分数:
1. 0.0640
2. 0.0489
3. 0.0318
4. 0.0315
5. 0.0161
答案:
机械臂是一种能够按照预定程序自动完成特定任务的机器人手臂。它通常由多个关节和执行器组成,可以实现精确的运动控制和抓取操作。机械臂的关键能力包括:
1. 运动控制:机械臂可以实现精确的运动控制,包括速度、位置和方向控制。
2. 抓取操作:机械臂可以实现精确的抓取操作,包括抓取物体和释放物体。
3. 自动化操作:机械臂可以实现自动化操作,包括自动装配、搬运和拆卸等。
4. 精确度:机械臂可以实现高精度的操作,包括精确的定位和精确的抓取。
5. 功能:机械臂可以实现多种功能,包括搬运、装配、拆卸、切割、焊接、喷涂等。plaintext2.5 RAG-Fusion vs Multi-Query对比#
| 特性 | Multi-Query | RAG-Fusion | 说明 |
|---|---|---|---|
| 查询生成 | ✅ | ✅ | 都支持生成多个查询变体 |
| 并行检索 | ✅ | ✅ | 都支持并行检索多个查询 |
| 智能排序 | ❌ | ✅ RRF算法 | RAG-Fusion使用倒数排序融合 |
| 结果质量 | 中等 | 高 | RRF提升检索质量 |
| 计算成本 | 低 | 中等 | RRF增加计算开销 |
| 适用场景 | 一般检索 | 高质量需求 | 根据需求选择 |
2.6 技术选型建议#
def select_query_optimization_method(use_case: str, quality_requirement: str) -> str:
"""根据场景选择查询优化方法"""
if use_case == "simple_qa" and quality_requirement == "balanced":
return "Multi-Query" # 平衡效果与成本
elif use_case == "research" and quality_requirement == "high":
return "RAG-Fusion" # 追求最高质量
elif use_case == "real_time" and quality_requirement == "fast":
return "Single-Query" # 追求最低延迟
else:
return "Multi-Query" # 默认选择python总结#
Multi-Query vs RAG-Fusion 实战对比
| 指标 | Multi-Query | RAG-Fusion | 胜出方 |
|---|---|---|---|
| 检索文档数 | 6个 | 13个 | RAG-Fusion |
| 答案质量 | 良好 | 优秀 | RAG-Fusion |
| 响应时间 | 较快 | 稍慢 | Multi-Query |
| 实现复杂度 | 简单 | 中等 | Multi-Query |
🎯 使用建议
- 日常问答:使用Multi-Query,平衡效果与成本
- 研究分析:使用RAG-Fusion,追求最高质量
- 实时系统:使用Single-Query,追求最低延迟
- 资源充足:RAG-Fusion + 缓存优化
💡 经验总结:RRF算法通过多查询结果融合,显著提升了检索质量,特别适合对答案准确性要求高的场景。
在下一部分,我们将探讨更高级的查询分解(Decomposition)和Step Back提示技术,处理复杂的多步骤问题。
Part3: Query Decomposition - 查询分解#
3.1 核心概念#
对于复杂的多步骤问题,Query Decomposition技术将其分解为多个子问题,分别回答后再合成最终答案。这种方法特别适合处理需要多角度分析的复杂查询。
两种分解策略对比#
递归分解(Answer Recursively)#
复杂问题: "比较GPT-3和GPT-4在多模态能力上的差异"
↓
子问题1: "GPT-3有哪些能力?"
↓ 检索 + 回答
答案1: "GPT-3主要是文本模型..."
↓
子问题2: "GPT-4有哪些新能力?" (基于答案1)
↓ 检索 + 回答
答案2: "GPT-4增加了图像理解..."
↓
综合答案: "GPT-3仅支持文本,而GPT-4..."plaintext并行分解(Answer Individually)#
复杂问题: "比较Python和JavaScript在Web开发中的优劣"
↓
子问题1: "Python在Web开发中的优势"
子问题2: "JavaScript在Web开发中的优势"
子问题3: "Python在Web开发中的劣势"
子问题4: "JavaScript在Web开发中的劣势"
↓
并行检索 + 回答
↓
综合所有答案plaintext3.2 递归分解实现#
from typing import List, Dict, Any
from vllm import SamplingParams
class RecursiveDecomposition:
"""使用ChatML格式的递归查询分解"""
def __init__(self, vectorstore, llm):
self.vectorstore = vectorstore
self.retriever = vectorstore.as_retriever()
self.llm = llm
print("✅ 递归分解系统初始化完成")
def decompose_query(self, question: str) -> List[str]:
"""使用ChatML格式分解复杂查询为子问题"""
prompt = f"""<|im_start|>system
你是一个AI助手,擅长将复杂问题分解为简单的子问题。
请将以下复杂问题分解为2-4个简单的子问题:
要求:
1. 子问题应该按逻辑顺序排列
2. 每个子问题都应该是独立可回答的
3. 每行一个问题,不要编号<|im_end|>
<|im_start|>user
复杂问题:{question}
请分解为子问题,每行一个:<|im_end|>
<|im_start|>assistant
"""
sampling_params = SamplingParams(
max_tokens=512,
temperature=0.5,
top_p=0.8,
stop=["<|im_end|>", "<|endoftext|>"]
)
outputs = self.llm.generate([prompt], sampling_params)
response = outputs[0].outputs[0].text.strip()
# 解析子问题
sub_questions = []
lines = response.split('\n')
for line in lines:
line = line.strip()
if line and len(line) > 5: # 过滤太短的子问题
# 移除可能的编号标记
if line[0].isdigit() and (line[1] == '.' or line[1] == '、'):
question = line[2:].strip()
else:
question = line
sub_questions.append(question)
# 确保有子问题,如果没有则使用备选方案
if not sub_questions:
sub_questions = self._fallback_decomposition(question)
return sub_questions[:4] # 最多返回4个子问题
def _fallback_decomposition(self, question: str) -> List[str]:
"""备选分解方案"""
# 简单的基于规则的分解
sub_questions = []
if "比较" in question and "和" in question:
# 比较类问题
parts = question.split("比较")[1].split("和")
if len(parts) >= 2:
sub_questions.append(f"{parts[0].strip()}的主要特点是什么?")
sub_questions.append(f"{parts[1].strip()}的主要特点是什么?")
sub_questions.append("它们的主要差异是什么?")
elif "步骤" in question or "流程" in question:
# 步骤类问题
sub_questions.append("第一步是什么?")
sub_questions.append("关键步骤有哪些?")
sub_questions.append("最终目标是什么?")
else:
# 通用分解
sub_questions.append("基本概念是什么?")
sub_questions.append("主要应用场景有哪些?")
sub_questions.append("优势和局限性是什么?")
return sub_questions
def answer_sub_question(self, question: str, context: str = "") -> str:
"""使用ChatML格式回答单个子问题"""
# 检索相关文档
docs = self.retriever.get_relevant_documents(question)
doc_context = "\n\n".join([doc.page_content for doc in docs[:3]])
# 构建提示词
if context:
full_context = f"已知信息:\n{context}\n\n相关文档:\n{doc_context}"
else:
full_context = f"相关文档:\n{doc_context}"
prompt = f"""<|im_start|>system
你是一个专业的AI助手。请基于以下信息简洁地回答问题:
{full_context}
请遵循:
1. 只使用提供的信息
2. 保持回答简洁准确
3. 如果信息不足,请说明<|im_end|>
<|im_start|>user
问题:{question}<|im_end|>
<|im_start|>assistant
"""
sampling_params = SamplingParams(
max_tokens=300,
temperature=0.3,
top_p=0.8,
stop=["<|im_end|>", "<|endoftext|>"]
)
outputs = self.llm.generate([prompt], sampling_params)
return outputs[0].outputs[0].text.strip()
def query(self, question: str) -> Dict[str, Any]:
"""执行递归分解查询"""
print(f"🎯 原始问题: {question}")
print("-" * 50)
# 1. 分解问题
sub_questions = self.decompose_query(question)
print(f"🔍 分解为 {len(sub_questions)} 个子问题:")
for i, sq in enumerate(sub_questions, 1):
print(f" {i}. {sq}")
# 2. 递归回答
accumulated_context = ""
sub_answers = []
print("\n💡 逐步回答子问题:")
for i, sq in enumerate(sub_questions, 1):
print(f"\n 子问题{i}: {sq}")
answer = self.answer_sub_question(sq, accumulated_context)
sub_answers.append(answer)
accumulated_context += f"\n\n问题{i}: {sq}\n答案: {answer}"
print(f" 答案: {answer[:100]}...")
# 3. 综合最终答案
final_prompt = f"""<|im_start|>system
你是一个AI助手,需要基于子问题的答案来综合回答原始问题。
原始问题:{question}
子问题和答案:
{self._format_sub_qa(sub_questions, sub_answers)}
请基于以上子问题的答案,给出一个完整、连贯的综合答案。<|im_end|>
<|im_start|>user
请综合回答原始问题:{question}<|im_end|>
<|im_start|>assistant
"""
sampling_params = SamplingParams(
max_tokens=500,
temperature=0.3,
top_p=0.8,
stop=["<|im_end|>", "<|endoftext|>"]
)
outputs = self.llm.generate([final_prompt], sampling_params)
final_answer = outputs[0].outputs[0].text.strip()
return {
"question": question,
"sub_questions": sub_questions,
"sub_answers": sub_answers,
"final_answer": final_answer,
"num_sub_questions": len(sub_questions)
}
def _format_sub_qa(self, questions: List[str], answers: List[str]) -> str:
"""格式化子问题和答案"""
formatted = ""
for i, (q, a) in enumerate(zip(questions, answers), 1):
formatted += f"子问题{i}: {q}\n答案{i}: {a}\n\n"
return formatted.strip()python3.3 递归分解实战测试#
print("🚀 ChatML格式的递归分解系统")
print("=" * 60)
# 1. 创建实例
decomp = RecursiveDecomposition(vectorstore, llm)
# 2. 执行查询
result = decomp.query("比较抓取检测和滑动检测的主要差异")
# 3. 查看结果
print("\n" + "="*60)
print("📋 子问题分解:")
for i, (q, a) in enumerate(zip(result["sub_questions"], result["sub_answers"]), 1):
print(f"{i}. 问题: {q}")
print(f" 答案: {a[:100]}...")
print()
print("💡 最终综合答案:")
print(result["final_answer"])python实际输出:
🚀 ChatML格式的递归分解系统
============================================================
✅ 递归分解系统初始化完成
🎯 原始问题: 比较抓取检测和滑动检测的主要差异
--------------------------------------------------
Processed prompts: 100%|██████████| 1/1 [00:01<00:00, 1.29s/it]
🔍 分解为 4 个子问题:
1. 抓取检测和滑动检测都是用于检测物体在图像中的位置的方法,它们之间有什么主要差异?
2. 抓取检测主要依赖于物体的形状和颜色,而滑动检测主要依赖于物体的运动特征,这两者之间有什么不同?
3. 抓取检测和滑动检测在检测精度和速度方面有什么差异?
4. 抓取检测和滑动检测在应用场景上有什么不同?
💡 逐步回答子问题:
子问题1: 抓取检测和滑动检测都是用于检测物体在图像中的位置的方法,它们之间有什么主要差异?
Processed prompts: 100%|██████████| 1/1 [00:01<00:00, 1.26s/it]
答案: 抓取检测和滑动检测都是用于检测物体在图像中的位置的方法,但它们之间存在一些主要差异。抓取检测主要关注物体在图像中的位置变化,而滑动检测则更关注物体在图像中的运动状态。抓取检测通常使用视觉信息,而滑动检...
子问题2: 抓取检测主要依赖于物体的形状和颜色,而滑动检测主要依赖于物体的运动特征,这两者之间有什么不同?
Processed prompts: 100%|██████████| 1/1 [00:00<00:00, 1.04it/s]
答案: 抓取检测主要依赖于物体的形状和颜色,而滑动检测主要依赖于物体的运动特征。抓取检测通常使用视觉信息,而滑动检测则可以使用触觉信息。此外,抓取检测通常需要精确的物体定位,而滑动检测则更关注物体的运动轨迹。...
子问题3: 抓取检测和滑动检测在检测精度和速度方面有什么差异?
Processed prompts: 100%|██████████| 1/1 [00:01<00:00, 1.21s/it]
答案: 抓取检测和滑动检测在检测精度和速度方面存在差异。抓取检测主要关注物体在图像中的位置变化,而滑动检测则更关注物体在图像中的运动状态。抓取检测通常使用视觉信息,而滑动检测则可以使用触觉信息。此外,抓取检测...
子问题4: 抓取检测和滑动检测在应用场景上有什么不同?
Processed prompts: 100%|██████████| 1/1 [00:00<00:00, 1.03it/s]
答案: 抓取检测和滑动检测在应用场景上存在一些主要差异。抓取检测主要应用于物体定位和抓取,例如机器人抓取、无人机抓取等。而滑动检测则主要应用于物体运动状态的检测,例如物体滑动检测、物体滑动轨迹检测等。...
Processed prompts: 100%|██████████| 1/1 [00:02<00:00, 2.11s/it]
============================================================
📋 子问题分解:
1. 问题: 抓取检测和滑动检测都是用于检测物体在图像中的位置的方法,它们之间有什么主要差异?
答案: 抓取检测和滑动检测都是用于检测物体在图像中的位置的方法,但它们之间存在一些主要差异。抓取检测主要关注物体在图像中的位置变化,而滑动检测则更关注物体在图像中的运动状态。抓取检测通常使用视觉信息,而滑动检...
2. 问题: 抓取检测主要依赖于物体的形状和颜色,而滑动检测主要依赖于物体的运动特征,这两者之间有什么不同?
答案: 抓取检测主要依赖于物体的形状和颜色,而滑动检测主要依赖于物体的运动特征。抓取检测通常使用视觉信息,而滑动检测则可以使用触觉信息。此外,抓取检测通常需要精确的物体定位,而滑动检测则更关注物体的运动轨迹。...
3. 问题: 抓取检测和滑动检测在检测精度和速度方面有什么差异?
答案: 抓取检测和滑动检测在检测精度和速度方面存在差异。抓取检测主要关注物体在图像中的位置变化,而滑动检测则更关注物体在图像中的运动状态。抓取检测通常使用视觉信息,而滑动检测则可以使用触觉信息。此外,抓取检测...
4. 问题: 抓取检测和滑动检测在应用场景上有什么不同?
答案: 抓取检测和滑动检测在应用场景上存在一些主要差异。抓取检测主要应用于物体定位和抓取,例如机器人抓取、无人机抓取等。而滑动检测则主要应用于物体运动状态的检测,例如物体滑动检测、物体滑动轨迹检测等。...
💡 最终综合答案:
抓取检测和滑动检测都是用于检测物体在图像中的位置的方法,但它们之间存在一些主要差异。抓取检测主要关注物体在图像中的位置变化,而滑动检测则更关注物体在图像中的运动状态。抓取检测通常使用视觉信息,而滑动检测则可以使用触觉信息。此外,抓取检测通常需要精确的物体定位,而滑动检测则更关注物体的运动轨迹。抓取检测和滑动检测在检测精度和速度方面存在差异。抓取检测主要应用于物体定位和抓取,例如机器人抓取、无人机抓取等。而滑动检测则主要应用于物体运动状态的检测,例如物体滑动检测、物体滑动轨迹检测等。plaintext3.4 并行分解实现#
import asyncio
from typing import List, Dict, Any
from vllm import SamplingParams
from concurrent.futures import ThreadPoolExecutor
import time
class TrueAsyncParallelDecomposition:
"""真正的异步并行分解"""
def __init__(self, vectorstore, llm, max_workers: int = 4):
self.vectorstore = vectorstore
self.llm = llm
self.executor = ThreadPoolExecutor(max_workers=max_workers)
print("✅ 真正异步并行分解系统初始化完成")
async def _generate(self, prompt: str, max_tokens: int = 512) -> Dict[str, Any]:
"""异步生成"""
sampling_params = SamplingParams(
max_tokens=max_tokens,
temperature=0.3,
top_p=0.8
)
try:
loop = asyncio.get_event_loop()
outputs = await loop.run_in_executor(
self.executor,
lambda: self.llm.generate([prompt], sampling_params)
)
if outputs and outputs[0].outputs:
text = outputs[0].outputs[0].text.strip()
return {"success": True, "text": text}
return {"success": False, "error": "生成失败"}
except Exception as e:
return {"success": False, "error": str(e)}
async def answer_sub_question(self, question: str) -> Dict[str, Any]:
"""异步回答子问题"""
start_time = time.time()
try:
# 1. 异步检索
retriever = self.vectorstore.as_retriever()
docs = await retriever.aget_relevant_documents(question)
retrieval_time = time.time() - start_time
if not docs:
return {
"question": question,
"answer": "未找到相关文档",
"success": False,
"retrieval_time": retrieval_time
}
# 2. 构建上下文
context = "\n".join([doc.page_content[:100] for doc in docs[:2]])
# 3. 构建提示词
prompt = f"""<|im_start|>system
回答问题:<|im_end|>
<|im_start|>user
信息:{context}
问题:{question}<|im_end|>
<|im_start|>assistant
"""
# 4. 异步生成
gen_start = time.time()
result = await self._generate(prompt, max_tokens=512)
generation_time = time.time() - gen_start
if result["success"]:
return {
"question": question,
"answer": result["text"],
"success": True,
"retrieval_time": retrieval_time,
"generation_time": generation_time,
"total_time": time.time() - start_time
}
else:
return {
"question": question,
"answer": f"生成失败: {result['error']}",
"success": False,
"retrieval_time": retrieval_time,
"generation_time": generation_time,
"total_time": time.time() - start_time
}
except Exception as e:
return {
"question": question,
"answer": f"错误: {str(e)}",
"success": False,
"retrieval_time": 0,
"generation_time": 0,
"total_time": time.time() - start_time
}
async def query_parallel(self, question: str) -> Dict[str, Any]:
"""真正的异步并行查询"""
print(f"🎯 问题: {question}")
print("=" * 60)
overall_start = time.time()
# 1. 分解问题
sub_questions = [
"抓取检测是什么?",
"滑动检测是什么?",
"机械臂任务中抓取检测和滑动检测的关联是什么?"
]
print(f"🔍 分解为 {len(sub_questions)} 个子问题:")
for i, q in enumerate(sub_questions, 1):
print(f" {i}. {q}")
# 2. 🔥 真正的并行执行(关键修复)
print(f"⚡ 并行执行 {len(sub_questions)} 个子问题...")
tasks = [self.answer_sub_question(q) for q in sub_questions]
sub_results = await asyncio.gather(*tasks) # 🔥 并行执行
parallel_time = time.time() - overall_start
# 3. 分析结果
successful = [r for r in sub_results if r['success']]
print(f"\n📊 执行统计:")
print(f" ✅ 成功: {len(successful)}/{len(sub_questions)}")
print(f" ⏱️ 并行时间: {parallel_time:.2f}s")
# 显示每个子问题的执行时间
print("\n💡 子问题执行详情:")
for i, result in enumerate(sub_results, 1):
status = "✅" if result['success'] else "❌"
print(f" {i}. {status} 检索: {result['retrieval_time']:.2f}s, "
f"生成: {result['generation_time']:.2f}s, "
f"总计: {result['total_time']:.2f}s")
# 4. 综合最终答案
print("\n🧠 综合最终答案...")
if successful:
qa_context = "\n".join([
f"Q{i}: {r['question']}\nA{i}: {r['answer']}"
for i, r in enumerate(successful, 1)
])
synthesis_prompt = f"""<|im_start|>system
基于以下问答信息综合回答原始问题:<|im_end|>
<|im_start|>user
原始问题:{question}
子问题和答案:
{qa_context}
请给出综合答案:<|im_end|>
<|im_start|>assistant
"""
else:
synthesis_prompt = f"""<|im_start|>system
请回答以下问题:<|im_end|>
<|im_start|>user
问题:{question}<|im_end|>
<|im_start|>assistant
"""
final_result = await self._generate(synthesis_prompt, max_tokens=512)
total_time = time.time() - overall_start
if final_result["success"]:
final_answer = final_result["text"]
else:
final_answer = f"综合失败: {final_result['error']}"
print(f"⏱️ 总耗时: {total_time:.2f}s")
print(f"📊 并行效率: {parallel_time/total_time*100:.1f}%")
return {
"question": question,
"final_answer": final_answer,
"sub_questions": sub_questions,
"sub_results": sub_results,
"metrics": {
"total_time": total_time,
"parallel_time": parallel_time,
"success_rate": f"{len(successful)}/{len(sub_questions)}",
"parallel_efficiency": f"{parallel_time/total_time*100:.1f}%"
}
}python3.5 性能对比测试#
# === 性能对比测试 ===
async def performance_comparison():
"""性能对比:并行 vs 串行"""
print("📊 性能对比测试")
print("=" * 60)
decomp = TrueAsyncParallelDecomposition(vectorstore, llm)
try:
question = "抓取检测和滑动检测在机械臂任务中的关联"
# 并行执行
print("🚀 并行执行测试...")
parallel_start = time.time()
parallel_result = await decomp.query_parallel(question)
parallel_time = time.time() - parallel_start
# 串行执行(模拟)
print("\n🐌 串行执行测试...")
serial_start = time.time()
sub_questions = [
"抓取检测是什么?",
"滑动检测是什么?",
"机械臂任务中抓取检测和滑动检测的关联是什么?"
]
serial_results = []
for q in sub_questions:
result = await decomp.answer_sub_question(q) # 顺序执行
serial_results.append(result)
serial_time = time.time() - serial_start
print(f"\n📈 性能对比结果:")
print(f" 🚀 并行时间: {parallel_time:.2f}s")
print(f" 🐌 串行时间: {serial_time:.2f}s")
print(f" ⚡ 加速比: {serial_time/parallel_time:.2f}x")
print(f" 📊 效率提升: {(serial_time-parallel_time)/serial_time*100:.1f}%")
return {
"parallel_time": parallel_time,
"serial_time": serial_time,
"speedup": serial_time / parallel_time
}
finally:
await decomp.close()python性能对比输出:
📊 性能对比测试
============================================================
✅ 真正异步并行分解系统初始化完成
🚀 并行执行测试...
🎯 问题: 抓取检测和滑动检测在机械臂任务中的关联
============================================================
🔍 分解为 3 个子问题:
1. 抓取检测是什么?
2. 滑动检测是什么?
3. 机械臂任务中抓取检测和滑动检测的关联是什么?
⚡ 并行执行 3 个子问题...
📊 执行统计:
✅ 成功: 0/3
⏱️ 并行时间: 0.20s
💡 子问题执行详情:
1. ❌ 检索: 0.05s, 生成: 0.01s, 总计: 0.06s
2. ❌ 检索: 0.05s, 生成: 0.13s, 总计: 0.17s
3. ❌ 检索: 0.05s, 生成: 0.15s, 总计: 0.20s
🧠 综合最终答案...
⏱️ 总耗时: 1.29s
📊 并行效率: 15.7%
🐌 串行执行测试...
📈 性能对比结果:
🚀 并行时间: 1.29s
🐌 串行时间: 2.76s
⚡ 加速比: 2.14x
📊 效率提升: 53.3%
✅ 资源已关闭plaintext3.6 分解策略对比分析#
| 特性 | 递归分解 | 并行分解 | 说明 |
|---|---|---|---|
| 执行方式 | 顺序执行 | 并行执行 | 并行分解速度更快 |
| 速度 | 较慢 | 快 ⚡ | 并行可大幅加速 |
| 子问题依赖 | 支持 | 不支持 | 递归适合有逻辑顺序的问题 |
| 适用场景 | 有逻辑顺序的问题 | 独立子问题 | 根据问题特点选择 |
| 实现复杂度 | 中等 | 高 | 并行需要异步编程 |
| 资源消耗 | 低 | 高 | 并行需要更多计算资源 |
3.7 技术选型指南#
def select_decomposition_strategy(question: str) -> str:
"""根据问题特点选择分解策略"""
# 判断问题类型的关键词
sequential_keywords = ["步骤", "流程", "顺序", "首先", "然后"]
comparison_keywords = ["比较", "对比", "差异", "优缺点"]
independent_keywords = ["分别", "各自", "独立"]
# 检查关键词
has_sequential = any(keyword in question for keyword in sequential_keywords)
has_comparison = any(keyword in question for keyword in comparison_keywords)
has_independent = any(keyword in question for keyword in independent_keywords)
if has_sequential:
return "递归分解" # 有明确顺序的问题
elif has_independent or has_comparison:
return "并行分解" # 独立子问题
else:
return "递归分解" # 默认选择python3.8 最佳实践建议#
✅ 递归分解适用场景
- 步骤性指导:“如何安装Python环境?”
- 逻辑推理:“为什么机器学习需要大量数据?”
- 因果分析:“气候变化对农业的影响是什么?”
✅ 并行分解适用场景
- 多角度比较:“Python vs Java的优缺点”
- 独立概念:“机器学习的三大类型是什么?”
- 综合分析:“人工智能在医疗、金融、教育中的应用”
⚡ 性能优化技巧
# 1. 动态调整并行度
def adjust_parallelism(sub_questions: List[str]) -> int:
"""根据子问题数量调整并行度"""
if len(sub_questions) <= 2:
return 2 # 少量问题,低并行度
elif len(sub_questions) <= 4:
return 4 # 中等问题,中等并行度
else:
return min(8, len(sub_questions)) # 大量问题,高并行度
# 2. 智能超时控制
async def with_timeout(coroutine, timeout: float):
"""为异步操作添加超时控制"""
try:
return await asyncio.wait_for(coroutine, timeout=timeout)
except asyncio.TimeoutError:
return {"success": False, "error": "超时"}python总结#
查询分解技术核心价值
- 处理复杂问题:将复杂查询分解为可管理的子问题
- 提高答案质量:每个子问题得到专门回答,综合答案更全面
- 灵活的策略选择:根据问题特点选择递归或并行分解
🎯 实践建议
- 简单问题:直接使用基础检索,无需分解
- 逻辑复杂问题:使用递归分解,保持问题间的依赖关系
- 多角度问题:使用并行分解,充分利用计算资源
- 性能敏感场景:结合缓存和异步优化
💡 经验总结:查询分解技术显著提升了RAG系统处理复杂问题的能力,特别是对于需要多角度分析的学术和技术问题。
在下一部分,我们将探讨更高级的Step Back提示和HyDE技术,进一步提升RAG系统的推理能力和检索质量。
Part4: Step Back Prompting - 抽象化提问#
4.1 核心概念#
Step Back Prompting 先提出一个更抽象、更概括的问题,获取背景知识后,再回答原始具体问题。这种方法通过两步推理提升答案的质量和准确性。
为什么需要 Step Back?
❌ 直接回答可能缺乏背景
# 原始问题: "Transformer中的Multi-Head Attention有几个头?"
# 直接检索 → 可能找不到确切答案
# 文档可能只描述了原理,没说具体数字python✅ Step Back 后效果更好
# Step 1: Step Back问题
"Transformer架构的基本组成是什么?"
# Step 2: 获取背景知识
"Transformer由编码器和解码器组成,使用Multi-Head Attention..."
# Step 3: 结合背景回答原始问题
"根据原始论文,使用8个attention头..."python4.2 Step Back RAG 系统实现#
import asyncio
from typing import Dict, Any
from vllm import SamplingParams
class StepBackRAG:
"""使用ChatML格式的Step Back RAG系统"""
def __init__(self, vectorstore, llm):
self.vectorstore = vectorstore
self.retriever = vectorstore.as_retriever()
self.llm = llm
print("✅ Step Back RAG系统初始化完成")
def generate_step_back_question(self, question: str) -> str:
"""生成Step Back问题"""
# ChatML格式提示词
prompt = f"""<|im_start|>system
你是一个AI助手,擅长将具体问题转化为更抽象、更概括的问题。
给定一个具体问题,请生成一个能够提供背景知识的更抽象问题。
示例:
具体问题: "GPT-4的上下文长度是多少?"
Step Back问题: "GPT-4的主要技术特性有哪些?"
具体问题: "Python中的装饰器如何工作?"
Step Back问题: "Python中的元编程概念是什么?"
现在请为以下具体问题生成Step Back问题:<|im_end|>
<|im_start|>user
具体问题: {question}
Step Back问题:<|im_end|>
<|im_start|>assistant
"""
sampling_params = SamplingParams(
max_tokens=512,
temperature=0.3,
top_p=0.8,
stop=["<|im_end|>", "<|endoftext|>"]
)
outputs = self.llm.generate([prompt], sampling_params)
if outputs and outputs[0].outputs:
step_back_q = outputs[0].outputs[0].text.strip()
else:
step_back_q = "生成失败"
return step_back_q
def retrieve_documents(self, question: str, k: int = 3) -> str:
"""检索相关文档并构建上下文"""
docs = self.retriever.get_relevant_documents(question)
context = "\n\n".join([doc.page_content for doc in docs[:k]])
return context
def generate_final_answer(self, question: str, background: str, specific: str) -> str:
"""结合背景知识和具体信息生成最终答案"""
prompt = f"""<|im_start|>system
你是一个专业的AI助手。请基于以下背景知识和具体信息来回答问题。
背景知识提供了相关领域的理论框架和概念理解,具体信息包含了问题的直接相关内容。
请先理解背景知识,再结合具体信息给出准确、全面的答案。<|im_end|>
<|im_start|>user
背景知识:
{background}
具体信息:
{specific}
原始问题: {question}
请基于以上信息给出详细的回答:<|im_end|>
<|im_start|>assistant
"""
sampling_params = SamplingParams(
max_tokens=512,
temperature=0.3,
top_p=0.8,
stop=["<|im_end|>", "<|endoftext|>"]
)
outputs = self.llm.generate([prompt], sampling_params)
if outputs and outputs[0].outputs:
return outputs[0].outputs[0].text.strip()
else:
return "生成失败"
def query(self, question: str) -> dict:
"""执行Step Back RAG查询"""
print(f"❓ 原始问题: {question}")
print("-" * 50)
# 1. 生成Step Back问题
step_back_q = self.generate_step_back_question(question)
print(f"📚 Step Back问题: {step_back_q}")
# 2. 检索背景知识(Step Back问题)
background = self.retrieve_documents(step_back_q, k=3)
print(f"🔍 检索到背景知识,长度: {len(background)} 字符")
# 3. 检索具体信息(原始问题)
specific = self.retrieve_documents(question, k=3)
print(f"📄 检索到具体信息,长度: {len(specific)} 字符")
# 4. 结合两者生成答案
answer = self.generate_final_answer(question, background, specific)
return {
"question": question,
"step_back_question": step_back_q,
"background_preview": background[:200] + "..." if len(background) > 200 else background,
"specific_preview": specific[:200] + "..." if len(specific) > 200 else specific,
"answer": answer
}python4.3 实战测试#
# 使用示例
print("🚀 Step Back RAG系统")
print("=" * 60)
step_back_rag = StepBackRAG(vectorstore, llm)
result = step_back_rag.query("滑动检测的操作流程?")
print("\n" + "="*60)
print("💡 答案:")
print(result["answer"])
print(f"\n📊 查询详情:")
print(f"Step Back问题: {result['step_back_question']}")
print(f"背景知识预览: {result['background_preview']}")
print(f"具体信息预览: {result['specific_preview']}")python实际输出:
🚀 Step Back RAG系统
============================================================
✅ Step Back RAG系统初始化完成
❓ 原始问题: 滑动检测的操作流程?
--------------------------------------------------
Processed prompts: 100%|██████████| 1/1 [00:00<00:00, 7.72it/s]
📚 Step Back问题: 什么是滑动检测?
🔍 检索到背景知识,长度: 1250 字符
📄 检索到具体信息,长度: 980 字符
Processed prompts: 100%|██████████| 1/1 [00:00<00:00, 1.46it/s]
============================================================
💡 答案:
滑动检测的操作流程如下:
1. 滑动发生时,滑动检测算法会触发一个滑动信号。
2. 当目标发生滑动时,控制器会按照原始操作流程进行滑动检测。
📊 查询详情:
Step Back问题: 什么是滑动检测?
背景知识预览: 滑动检测是一种用于检测物体是否发生滑动的算法。它通过比较帧间的标准差来判断物体是否发生滑动。如果帧间的标准差超过设定的阈值,那么就认为物体发生了滑动。滑动检测算法通常用于机械臂的抓取任务中,以防止物体在抓取过程中滑落...
具体信息预览: 滑动检测的操作流程包括以下几个步骤:首先,系统会初始化传感器并设置阈值参数;然后,实时监测触觉信号的变化;当检测到滑动信号时,系统会触发相应的控制策略来调整抓取力...plaintext4.4 Step Back 的优势分析#
✅ 适用场景
- 问题需要背景知识:技术概念、理论框架
- 直接检索效果不好:查询太具体或术语不匹配
- 问题过于技术性强:需要理论基础支撑
- 需要概念理解:而不仅仅是事实回答
❌ 不适合的场景
- 简单事实性问题:“今天天气怎么样?”
- 已有充足直接信息:文档库中已有明确答案
- 实时数据查询:需要最新实时信息
- 过于宽泛的问题:本身已经足够抽象
性能特点
- 准确性:⭐⭐⭐⭐⭐(提供理论背景)
- 速度:⭐⭐⭐(需要两次检索)
- 资源消耗:⭐⭐⭐(中等)
- 实现复杂度:⭐⭐(相对简单)
Part5: HyDE - 假设性文档嵌入#
5.1 核心概念#
HyDE (Hypothetical Document Embeddings) 不直接检索用户查询,而是先让LLM生成一个假设性的答案文档,然后用这个文档去检索相似内容。
HyDE 的直觉理解#
传统检索的问题#
# 传统检索
用户查询: "什么是机器学习?"
↓ 直接嵌入(查询向量稀疏)
查询向量: [0.1, 0.3, -0.2, ...]
↓ 检索
找到的文档(可能不相关)pythonHyDE 检索的优势#
# HyDE检索
用户查询: "什么是机器学习?"
↓ LLM生成假设性答案
假设文档: "机器学习是人工智能的一个分支,它使计算机能够从数据中学习并做出预测..."
↓ 嵌入假设文档(文档向量丰富)
文档向量: [0.2, 0.4, -0.1, ...] # 与真实答案文档更相似!
↓ 检索
找到更相关的文档python为什么有效?#
- 查询通常很短,而文档内容丰富
- 假设性文档比查询更接近真实文档的表达方式
- 在语义空间中,答案文档之间的相似度高于查询与文档的相似度
5.2 HyDE RAG 完整实现#
class HyDERAG:
"""HyDE (Hypothetical Document Embeddings) RAG系统"""
def __init__(self, vectorstore, llm, embeddings):
self.vectorstore = vectorstore
self.llm = llm
self.embeddings = embeddings
print("✅ HyDE RAG系统初始化完成")
def generate_hypothetical_document(
self,
question: str,
style: str = "academic"
) -> str:
"""生成假设性文档"""
if style == "academic":
system_msg = "你是一位领域专家。请对以下问题写一段详细、准确的学术性回答(200-300字)。"
elif style == "concise":
system_msg = "请对以下问题写一段简洁的回答(100-150字)。"
else:
system_msg = "请对以下问题写一段回答。"
# ChatML格式提示词
prompt = f"""<|im_start|>system
{system_msg}
要求:
1. 内容准确专业
2. 结构清晰完整
3. 使用恰当的术语<|im_end|>
<|im_start|>user
{question}<|im_end|>
<|im_start|>assistant
"""
sampling_params = SamplingParams(
max_tokens=400,
temperature=0.3,
top_p=0.8,
stop=["<|im_end|>", "<|endoftext|>"]
)
outputs = self.llm.generate([prompt], sampling_params)
if outputs and outputs[0].outputs:
hypothetical_doc = outputs[0].outputs[0].text.strip()
else:
hypothetical_doc = "生成失败"
return hypothetical_doc
def search_with_hyde(
self,
question: str,
k: int = 5
) -> list:
"""使用HyDE进行检索"""
print(f"🔍 生成假设性文档...")
# 1. 生成假设性文档
hyp_doc = self.generate_hypothetical_document(question)
print(f"📝 假设性文档生成完成({len(hyp_doc)}字符):")
print(f" {hyp_doc[:150]}...\n")
# 2. 使用假设性文档检索(而不是原始查询)
docs = self.vectorstore.similarity_search(hyp_doc, k=k)
return docs
def query(self, question: str, k: int = 5) -> dict:
"""执行HyDE RAG查询"""
print(f"❓ 原始问题: {question}")
print("-" * 50)
# 1. HyDE检索
docs = self.search_with_hyde(question, k=k)
print(f"📚 使用HyDE检索到 {len(docs)} 个相关文档")
# 显示检索结果预览
for i, doc in enumerate(docs, 1):
preview = doc.page_content[:100] + "..." if len(doc.page_content) > 100 else doc.page_content
print(f" {i}. {preview}")
# 2. 生成最终答案
context = "\n\n".join([doc.page_content for doc in docs])
# ChatML格式提示词
prompt = f"""<|im_start|>system
你是一个专业的AI助手。请基于以下文档准确回答问题。
文档内容:
{context}
请确保回答:
1. 基于提供的文档信息
2. 准确、完整、专业
3. 如果信息不足,请说明<|im_end|>
<|im_start|>user
问题: {question}<|im_end|>
<|im_start|>assistant
"""
sampling_params = SamplingParams(
max_tokens=500,
temperature=0.3,
top_p=0.8,
stop=["<|im_end|>", "<|endoftext|>"]
)
outputs = self.llm.generate([prompt], sampling_params)
if outputs and outputs[0].outputs:
answer = outputs[0].outputs[0].text.strip()
else:
answer = "生成失败"
return {
"question": question,
"hypothetical_doc_preview": self.generate_hypothetical_document(question, "concise")[:200] + "...",
"num_docs": len(docs),
"answer": answer
}python5.3 实战测试#
# 使用示例
print("🚀 HyDE RAG系统")
print("=" * 60)
hyde_rag = HyDERAG(vectorstore, llm, embeddings)
result = hyde_rag.query("解释滑动检测中的触觉传感器")
print("\n" + "="*60)
print("💡 最终答案:")
print(result["answer"])
print(f"\n📊 查询详情:")
print(f"假设性文档预览: {result['hypothetical_doc_preview']}")
print(f"参考文档数量: {result['num_docs']}")python实际输出:
🚀 HyDE RAG系统
============================================================
✅ HyDE RAG系统初始化完成
❓ 原始问题: 解释滑动检测中的触觉传感器
--------------------------------------------------
🔍 生成假设性文档...
Processed prompts: 100%|██████████| 1/1 [00:01<00:00, 1.22s/it]
📝 假设性文档生成完成(285字符):
滑动检测中的触觉传感器是一种用于检测物体表面滑动的传感器。它们通常由一个弹性膜片和一个敏感元件组成,当物体滑过膜片时,敏感元件会感受到物体的滑动,并将其转化为电信号。这些传感器可以用于各种应用,如机器人导航、汽车安全系统和工业自动化...
📚 使用HyDE检索到 5 个相关文档
1. 触觉传感器是一种能够检测物体表面压力变化的传感器,当物体发生滑动时,触觉传感器会高频振动...
2. 滑动检测是机器人夹爪抓取控制的核心技术之一,通过分析触觉信号的变化来判断物体是否发生滑动...
3. 在机械臂抓取任务中,触觉传感器可以提供实时的力反馈信息,帮助系统调整抓取策略...
4. 触觉传感器的数据可以通过机器学习算法进行分析,实现更准确的滑动检测和预测...
5. 高质量的触觉传感器应该具有高灵敏度、快速响应和良好的稳定性等特点...
Processed prompts: 100%|██████████| 1/1 [00:00<00:00, 1.07it/s]
============================================================
💡 最终答案:
触觉传感器是一种能够检测物体表面压力变化的传感器,当物体发生滑动时,触觉传感器会高频振动,触觉传感器数据会发生变化,从而引起压力中心数值的变化,通过分析压力中心数值的变化可以获得物体的滑动情况。滑动检测是机器人夹爪抓取控制的核心。
📊 查询详情:
假设性文档预览: 滑动检测中的触觉传感器是一种用于检测物体表面滑动的传感器。它们通常由一个弹性膜片和一个敏感元件组成,当物体滑过膜片时,敏感元件会感受到物体的滑动,并将其转化为电信号...
参考文档数量: 5plaintext5.4 HyDE vs 传统检索对比#
| 维度 | 传统检索 | HyDE | 优势分析 |
|---|---|---|---|
| 检索对象 | 用户查询 | 假设性答案 | HyDE使用更丰富的文档向量 |
| 语义匹配 | 查询↔文档 | 答案↔答案 | 答案之间相似度更高 |
| 查询长度敏感性 | 高 | 低 | HyDE对短查询更友好 |
| 额外LLM调用 | 0 | 1次 | HyDE增加一次生成成本 |
| 适用场景 | 清晰查询 | 复杂/技术性查询 | HyDE适合专业领域 |
| 检索质量 | 中等 | 高 | HyDE找到更相关文档 |
5.5 技术选型指南#
def select_hyde_scenario(question: str) -> bool:
"""判断是否适合使用HyDE"""
hyde_keywords = ["解释", "什么是", "如何工作", "原理", "机制", "技术"]
simple_keywords = ["多少", "何时", "哪里", "是谁", "是否"]
# 检查问题类型
has_hyde_indicator = any(keyword in question for keyword in hyde_keywords)
has_simple_indicator = any(keyword in question for keyword in simple_keywords)
# 判断问题复杂度
word_count = len(question.split())
is_complex = word_count > 8 or has_hyde_indicator
return is_complex and not has_simple_indicator
# 使用示例
questions = [
"解释神经网络的反向传播算法", # 适合HyDE
"北京今天气温多少度", # 不适合HyDE
"Transformer模型的工作原理", # 适合HyDE
]
for q in questions:
should_use_hyde = select_hyde_scenario(q)
print(f"问题: '{q}' -> 使用HyDE: {should_use_hyde}")pythonPart6: 技术对比与选择指南#
6.1 综合技术对比#
| 技术 | 召回率 | 准确率 | 速度 | 成本 | 复杂度 | 适用场景 |
|---|---|---|---|---|---|---|
| Multi-Query | ⭐⭐⭐ | ⭐⭐ | ⭐⭐ | 💰💰 | ⭐ | 表达模糊的问题 |
| RAG-Fusion | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ | 💰💰💰 | ⭐⭐ | 需要高质量结果 |
| Decomposition | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐ | 💰💰💰💰 | ⭐⭐⭐ | 复杂多步骤问题 |
| Step Back | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ | 💰💰 | ⭐⭐ | 需要背景知识 |
| HyDE | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐ | 💰💰 | ⭐⭐ | 技术性强的专业问题 |
6.2 智能选择决策树#
class IntelligentRAGSelector:
"""智能RAG技术选择器"""
def __init__(self):
self.techniques = {
"multi_query": "Multi-Query",
"rag_fusion": "RAG-Fusion",
"decomposition": "Query Decomposition",
"step_back": "Step Back",
"hyde": "HyDE"
}
def analyze_question(self, question: str) -> dict:
"""分析问题特征"""
analysis = {
"length": len(question.split()),
"has_comparison": "比较" in question or "对比" in question,
"has_steps": "步骤" in question or "流程" in question,
"has_explanation": "解释" in question or "什么是" in question,
"has_technical": "原理" in question or "机制" in question,
"is_simple_fact": "多少" in question or "何时" in question
}
return analysis
def select_technique(self, question: str) -> str:
"""根据问题特征选择最佳技术"""
analysis = self.analyze_question(question)
if analysis["is_simple_fact"]:
return "base" # 基础RAG
elif analysis["has_comparison"] and analysis["length"] > 10:
return "decomposition" # 复杂比较问题
elif analysis["has_steps"]:
return "decomposition" # 步骤性问题
elif analysis["has_technical"] and analysis["has_explanation"]:
return "hyde" # 技术解释问题
elif analysis["has_explanation"] and analysis["length"] > 15:
return "step_back" # 需要背景知识的解释
elif analysis["length"] < 8:
return "multi_query" # 短而模糊的问题
else:
return "rag_fusion" # 默认选择python6.3 组合使用策略#
class AdvancedRAG:
"""组合多种技术的高级RAG系统"""
def __init__(self, vectorstore, llm, embeddings):
self.vectorstore = vectorstore
self.llm = llm
self.embeddings = embeddings
self.selector = IntelligentRAGSelector()
# 初始化各技术组件
self.multi_query = MultiQueryRAG(vectorstore, llm)
self.rag_fusion = RAGFusion(vectorstore, llm)
self.decomposition = RecursiveDecomposition(vectorstore, llm)
self.step_back = StepBackRAG(vectorstore, llm)
self.hyde = HyDERAG(vectorstore, llm, embeddings)
def intelligent_query(self, question: str) -> dict:
"""智能选择和组合技术"""
technique = self.selector.select_technique(question)
print(f"🎯 问题分析: '{question}'")
print(f"🔧 选择技术: {technique}")
if technique == "base":
# 基础RAG
retriever = self.vectorstore.as_retriever()
docs = retriever.get_relevant_documents(question)
context = "\n\n".join([doc.page_content for doc in docs[:3]])
return self._generate_simple_answer(question, context)
elif technique == "multi_query":
return self.multi_query.query(question)
elif technique == "rag_fusion":
return self.rag_fusion.query(question)
elif technique == "decomposition":
return self.decomposition.query(question)
elif technique == "step_back":
return self.step_back.query(question)
elif technique == "hyde":
return self.hyde.query(question)
def _generate_simple_answer(self, question: str, context: str) -> dict:
"""生成简单答案"""
prompt = f"""<|im_start|>system
基于以下信息回答问题:<|im_end|>
<|im_start|>user
信息:{context}
问题:{question}<|im_end|>
<|im_start|>assistant
"""
sampling_params = SamplingParams(
max_tokens=300,
temperature=0.3,
top_p=0.8
)
outputs = self.llm.generate([prompt], sampling_params)
answer = outputs[0].outputs[0].text.strip() if outputs else "生成失败"
return {
"question": question,
"answer": answer,
"technique": "base",
"context_preview": context[:200] + "..." if len(context) > 200 else context
}python6.4 性能优化与最佳实践#
缓存策略#
from functools import lru_cache
import hashlib
class CachedRAG:
"""带缓存的RAG优化器"""
def __init__(self):
self.query_cache = {}
self.technique_cache = {}
def get_cache_key(self, query: str, technique: str) -> str:
"""生成缓存键"""
content = f"{technique}:{query}"
return hashlib.md5(content.encode()).hexdigest()
@lru_cache(maxsize=100)
def cached_technique_selection(self, question: str) -> str:
"""缓存技术选择结果"""
return self.selector.select_technique(question)
def cached_query(self, question: str, technique: str) -> dict:
"""缓存查询结果"""
cache_key = self.get_cache_key(question, technique)
if cache_key in self.query_cache:
print("💾 使用缓存结果")
return self.query_cache[cache_key]
# 执行查询
result = getattr(self, technique).query(question)
self.query_cache[cache_key] = result
return resultpython并行处理优化#
import asyncio
from concurrent.futures import ThreadPoolExecutor
async def parallel_hyde_queries(questions: List[str], hyde_rag: HyDERAG) -> List[dict]:
"""并行执行多个HyDE查询"""
loop = asyncio.get_event_loop()
with ThreadPoolExecutor(max_workers=3) as executor:
tasks = [
loop.run_in_executor(executor, hyde_rag.query, question)
for question in questions
]
results = await asyncio.gather(*tasks)
return resultspython自适应参数调整#
def adaptive_parameters(question: str) -> dict:
"""根据问题动态调整参数"""
word_count = len(question.split())
if word_count < 5:
# 短查询需要更多文档
return {"k": 7, "temperature": 0.2}
elif word_count > 20:
# 长查询可以减少文档数
return {"k": 3, "temperature": 0.1}
elif "比较" in question or "分析" in question:
# 分析类问题需要更多上下文
return {"k": 6, "temperature": 0.3}
else:
return {"k": 5, "temperature": 0.3} # 默认参数python总结#
技术综合评估#
- Step Back Prompting:适合需要理论背景的复杂问题
- HyDE:在技术性、专业性问题上表现优异
- 组合策略:根据问题特征智能选择最优技术
🎯 实践建议
| 场景类型 | 推荐技术 | 原因 |
|---|---|---|
| 学术技术问题 | HyDE + Step Back | 提供专业背景和理论支撑 |
| 多角度分析 | RAG-Fusion | 综合多个查询视角 |
| 步骤性指导 | Query Decomposition | 分解复杂流程 |
| 实时简单查询 | 基础RAG | 快速响应,成本低 |
💡 核心价值:Step Back和HyDE等技术通过更智能的查询理解和更精准的检索策略,显著提升了RAG系统处理复杂专业问题的能力。
这些高级查询优化技术让RAG系统从简单的文档检索升级为真正的智能知识助手,能够处理各种复杂的信息需求。
Part7: 实战案例:智能客服与学术助手#
7.1 案例1:智能客服助手系统#
7.1.1 系统架构设计#
智能客服RAG系统通过智能路由机制,根据用户问题类型自动选择最合适的检索增强生成技术,实现精准高效的客户服务。
import asyncio
from typing import Dict, Any, List
from vllm import SamplingParams
class CustomerServiceRAG:
"""智能客服RAG系统 - 完整实现"""
def __init__(self, vectorstore, llm, embeddings):
"""
初始化智能客服系统
Args:
vectorstore: 向量数据库
llm: 语言模型
embeddings: 嵌入模型
"""
self.vectorstore = vectorstore
self.llm = llm
self.embeddings = embeddings
# 预定义场景关键词
self.scenarios = {
"product_info": ["产品", "功能", "特性", "价格", "规格", "参数", "型号"],
"troubleshooting": ["问题", "错误", "故障", "不工作", "无法", "解决", "修复"],
"how_to": ["如何", "怎么", "步骤", "教程", "操作", "使用", "安装"],
"comparison": ["比较", "对比", "哪个好", "区别", "差异", "优缺点"]
}
# 初始化各技术组件
self._initialize_components()
print("✅ 智能客服RAG系统初始化完成")
def _initialize_components(self):
"""初始化各技术组件"""
from .multi_query import MultiQueryRAG
from .rag_fusion import RAGFusion
from .decomposition import RecursiveDecomposition
from .step_back import StepBackRAG
from .hyde import HyDERAG
self.multi_query = MultiQueryRAG(self.vectorstore, self.llm)
self.rag_fusion = RAGFusion(self.vectorstore, self.llm)
self.decomposition = RecursiveDecomposition(self.vectorstore, self.llm)
self.step_back = StepBackRAG(self.vectorstore, self.llm)
self.hyde = HyDERAG(self.vectorstore, self.llm, self.embeddings)
def classify_query(self, question: str) -> Dict[str, Any]:
"""智能分类用户查询"""
question_lower = question.lower()
# 检测场景关键词
matched_scenarios = []
for scenario, keywords in self.scenarios.items():
if any(keyword in question_lower for keyword in keywords):
matched_scenarios.append(scenario)
# 分析问题复杂度
complexity = self._analyze_complexity(question)
# 确定优先级
if "troubleshooting" in matched_scenarios:
primary_scenario = "troubleshooting"
elif "how_to" in matched_scenarios:
primary_scenario = "how_to"
elif "product_info" in matched_scenarios:
primary_scenario = "product_info"
elif "comparison" in matched_scenarios:
primary_scenario = "comparison"
elif matched_scenarios:
primary_scenario = matched_scenarios[0]
else:
primary_scenario = "general"
return {
"primary_scenario": primary_scenario,
"matched_scenarios": matched_scenarios,
"complexity": complexity,
"word_count": len(question.split())
}
def _analyze_complexity(self, question: str) -> str:
"""分析问题复杂度"""
word_count = len(question.split())
if word_count <= 5:
return "simple"
elif word_count <= 10:
return "medium"
else:
return "complex"
def select_technique(self, classification: Dict[str, Any]) -> str:
"""根据分类结果选择最佳技术"""
scenario = classification["primary_scenario"]
complexity = classification["complexity"]
technique_mapping = {
"product_info": {
"simple": "multi_query",
"medium": "rag_fusion",
"complex": "hyde"
},
"troubleshooting": {
"simple": "multi_query",
"medium": "decomposition",
"complex": "decomposition"
},
"how_to": {
"simple": "step_back",
"medium": "step_back",
"complex": "decomposition"
},
"comparison": {
"simple": "multi_query",
"medium": "rag_fusion",
"complex": "decomposition"
},
"general": {
"simple": "multi_query",
"medium": "rag_fusion",
"complex": "hyde"
}
}
return technique_mapping.get(scenario, {}).get(complexity, "rag_fusion")
def execute_technique(self, question: str, technique: str) -> Dict[str, Any]:
"""执行选定的技术"""
technique_handlers = {
"multi_query": self.multi_query.query,
"rag_fusion": self.rag_fusion.query,
"decomposition": self.decomposition.query,
"step_back": self.step_back.query,
"hyde": self.hyde.query
}
if technique in technique_handlers:
return technique_handlersquestion
else:
# 默认使用RAG-Fusion
return self.rag_fusion.query(question)
def format_customer_response(self, result: Dict[str, Any], classification: Dict[str, Any]) -> Dict[str, Any]:
"""格式化客服响应"""
scenario = classification["primary_scenario"]
# 根据场景添加特定格式
if scenario == "troubleshooting":
# 故障排查类问题:步骤化格式
answer = self._format_troubleshooting_answer(result["answer"])
elif scenario == "how_to":
# 操作教程类问题:步骤化格式
answer = self._format_how_to_answer(result["answer"])
elif scenario == "product_info":
# 产品信息类问题:结构化格式
answer = self._format_product_info_answer(result["answer"])
else:
answer = result["answer"]
return {
"question": result["question"],
"answer": answer,
"technique_used": result.get("technique", "unknown"),
"scenario": scenario,
"confidence": self._calculate_confidence(result, classification),
"suggested_follow_up": self._suggest_follow_up(scenario),
"response_time": result.get("response_time", 0)
}
def _format_troubleshooting_answer(self, answer: str) -> str:
"""格式化故障排查答案"""
# 添加故障排查模板
troubleshooting_template = """🔧 **故障排查指南**
{content}
💡 **温馨提示**:
• 请按顺序尝试以上步骤
• 如果问题仍未解决,请联系技术支持"""
return troubleshooting_template.format(content=answer)
def _format_how_to_answer(self, answer: str) -> str:
"""格式化操作教程答案"""
# 添加操作步骤模板
how_to_template = """📋 **操作步骤指南**
{content}
✅ **完成检查**:
• 确保每个步骤都正确执行
• 如有疑问可参考详细文档"""
return how_to_template.format(content=answer)
def _format_product_info_answer(self, answer: str) -> str:
"""格式化产品信息答案"""
# 添加产品信息模板
product_template = """📊 **产品信息摘要**
{content}
🔍 **更多信息**:
• 查看详细规格手册
• 联系销售获取报价"""
return product_template.format(content=answer)
def _calculate_confidence(self, result: Dict[str, Any], classification: Dict[str, Any]) -> float:
"""计算回答置信度"""
base_confidence = 0.7
# 根据文档数量调整置信度
num_docs = result.get("num_docs", 0)
if num_docs >= 3:
base_confidence += 0.2
elif num_docs == 0:
base_confidence -= 0.3
# 根据问题复杂度调整
if classification["complexity"] == "simple":
base_confidence += 0.1
elif classification["complexity"] == "complex":
base_confidence -= 0.1
return min(max(base_confidence, 0.1), 1.0)
def _suggest_follow_up(self, scenario: str) -> List[str]:
"""根据场景推荐后续问题"""
follow_up_questions = {
"product_info": [
"这个产品有哪些具体型号?",
"价格和保修政策是怎样的?",
"与其他产品相比有什么优势?"
],
"troubleshooting": [
"如果以上方法无效该怎么办?",
"如何预防类似问题再次发生?",
"是否需要专业技术人员协助?"
],
"how_to": [
"有没有视频教程可以参考?",
"常见错误和解决方法有哪些?",
"高级功能如何使用?"
],
"general": [
"还有其他相关问题吗?",
"需要更详细的信息吗?",
"是否解决了您的问题?"
]
}
return follow_up_questions.get(scenario, [])
def handle_query(self, question: str) -> Dict[str, Any]:
"""处理客服查询 - 主入口"""
print(f"👤 客户查询: {question}")
print("-" * 50)
start_time = asyncio.get_event_loop().time()
# 1. 智能分类
classification = self.classify_query(question)
print(f"🔍 问题分类: {classification}")
# 2. 选择技术
technique = self.select_technique(classification)
print(f"🛠️ 选择技术: {technique}")
# 3. 执行查询
result = self.execute_technique(question, technique)
# 4. 计算响应时间
response_time = asyncio.get_event_loop().time() - start_time
result["response_time"] = response_time
# 5. 格式化响应
formatted_response = self.format_customer_response(result, classification)
print(f"⏱️ 响应时间: {response_time:.2f}s")
print(f"📊 置信度: {formatted_response['confidence']:.1%}")
return formatted_response
def batch_handle_queries(self, questions: List[str]) -> List[Dict[str, Any]]:
"""批量处理查询"""
results = []
for i, question in enumerate(questions, 1):
print(f"\n🔍 处理第 {i}/{len(questions)} 个查询...")
result = self.handle_query(question)
results.append(result)
return resultspython7.1.2 实战测试示例#
# === 智能客服系统测试 ===
def test_customer_service():
"""测试智能客服系统"""
print("🚀 智能客服RAG系统测试")
print("=" * 60)
# 初始化系统
customer_service = CustomerServiceRAG(vectorstore, llm, embeddings)
# 测试不同场景的问题
test_questions = [
# 产品信息类
"你们的最新智能机器人有哪些功能?",
# 故障排查类
"我的机器人无法启动,显示错误代码E102",
# 操作教程类
"如何设置机器人的自动巡逻模式?",
# 比较类
"旗舰款和标准款机器人有什么区别?",
# 一般问题
"机器人的保修政策是怎样的?"
]
print("📋 测试问题列表:")
for i, q in enumerate(test_questions, 1):
print(f" {i}. {q}")
print("\n" + "="*60)
# 逐个处理问题
results = []
for question in test_questions:
result = customer_service.handle_query(question)
results.append(result)
print(f"\n💡 答案摘要:")
print(f" 场景: {result['scenario']}")
print(f" 技术: {result['technique_used']}")
print(f" 置信度: {result['confidence']:.1%}")
print(f" 答案预览: {result['answer'][:100]}...")
print("-" * 40)
return results
# 运行测试
if __name__ == "__main__":
results = test_customer_service()
# 生成性能报告
print("\n📊 性能统计报告:")
total_time = sum(r["response_time"] for r in results)
avg_confidence = sum(r["confidence"] for r in results) / len(results)
print(f" 总处理时间: {total_time:.2f}s")
print(f" 平均置信度: {avg_confidence:.1%}")
print(f" 处理问题数: {len(results)}")python7.1.3 场景处理详情#
🔧 故障排查场景处理流程#
def troubleshoot_example():
"""故障排查场景示例"""
question = "机器人抓取物体时经常滑落,如何解决?"
customer_service = CustomerServiceRAG(vectorstore, llm, embeddings)
result = customer_service.handle_query(question)
# 显示详细处理过程
print("🔧 故障排查场景处理详情:")
print(f" 原始问题: {result['question']}")
print(f" 识别场景: {result['scenario']}")
print(f" 使用技术: {result['technique_used']}")
print(f" 响应格式: 步骤化故障排查指南")
print(f" 推荐后续问题: {result['suggested_follow_up']}")
return resultpython预期输出:
👤 客户查询: 机器人抓取物体时经常滑落,如何解决?
--------------------------------------------------
🔍 问题分类: {'primary_scenario': 'troubleshooting', 'matched_scenarios': ['troubleshooting'], 'complexity': 'complex', 'word_count': 8}
🛠️ 选择技术: decomposition
⏱️ 响应时间: 2.34s
📊 置信度: 85.0%
💡 答案摘要:
场景: troubleshooting
技术: decomposition
置信度: 85.0%
答案预览: 🔧 **故障排查指南** 1. 检查抓取力设置:确保抓取力足够但不过大 2. 验证物体表面:光滑表面可能需要特殊抓取策略...plaintext📚 产品信息场景处理流程#
def product_info_example():
"""产品信息场景示例"""
question = "智能机械臂的最大负载是多少?"
customer_service = CustomerServiceRAG(vectorstore, llm, embeddings)
result = customer_service.handle_query(question)
print("📚 产品信息场景处理详情:")
print(f" 原始问题: {result['question']}")
print(f" 识别场景: {result['scenario']}")
print(f" 使用技术: {result['technique_used']}")
print(f" 响应格式: 结构化产品信息")
return resultpython7.2 案例2:学术论文助手系统#
7.2.1 系统架构设计#
学术论文助手专门为研究人员设计,集成多种RAG技术来支持学术工作的各个环节。
class AcademicRAG:
"""学术论文助手系统 - 完整实现"""
def __init__(self, vectorstore, llm, embeddings):
"""
初始化学术论文助手
Args:
vectorstore: 包含学术论文的向量数据库
llm: 语言模型
embeddings: 嵌入模型
"""
self.vectorstore = vectorstore
self.llm = llm
self.embeddings = embeddings
# 初始化各技术组件
self._initialize_components()
# 学术领域关键词
self.academic_domains = {
"computer_science": ["机器学习", "深度学习", "算法", "神经网络", "AI"],
"robotics": ["机器人", "机械臂", "抓取", "运动规划", "SLAM"],
"nlp": ["自然语言处理", "文本生成", "语义分析", "词向量"],
"vision": ["计算机视觉", "图像识别", "目标检测", "分割"]
}
print("✅ 学术论文助手初始化完成")
def _initialize_components(self):
"""初始化各技术组件"""
from .multi_query import MultiQueryRAG
from .hyde import HyDERAG
from .decomposition import RecursiveDecomposition
from .step_back import StepBackRAG
from .rag_fusion import RAGFusion
self.multi_query = MultiQueryRAG(self.vectorstore, self.llm)
self.hyde = HyDERAG(self.vectorstore, self.llm, self.embeddings)
self.decomposition = RecursiveDecomposition(self.vectorstore, self.llm)
self.step_back = StepBackRAG(self.vectorstore, self.llm)
self.rag_fusion = RAGFusion(self.vectorstore, self.llm)
def identify_academic_domain(self, topic: str) -> str:
"""识别学术领域"""
topic_lower = topic.lower()
for domain, keywords in self.academic_domains.items():
if any(keyword in topic_lower for keyword in keywords):
return domain
return "general"
def literature_review(self, topic: str, depth: str = "comprehensive") -> Dict[str, Any]:
"""
生成文献综述
Args:
topic: 研究主题
depth: 综述深度 ("brief" | "standard" | "comprehensive")
"""
print(f"📚 生成文献综述: {topic}")
print(f" 深度级别: {depth}")
domain = self.identify_academic_domain(topic)
print(f" 识别领域: {domain}")
# 根据深度调整参数
depth_params = {
"brief": {"k": 3, "max_tokens": 800},
"standard": {"k": 5, "max_tokens": 1200},
"comprehensive": {"k": 8, "max_tokens": 2000}
}
params = depth_params.get(depth, depth_params["standard"])
# 1. Multi-Query广泛检索研究现状
broad_queries = [
f"{topic}的研究现状",
f"{topic}的最新进展",
f"{topic}的主要挑战",
f"{topic}的未来方向"
]
print("🔍 广泛检索研究现状...")
broad_results = []
for query in broad_queries:
result = self.multi_query.query(query, k=params["k"]//2)
broad_results.extend(result.get("documents", []))
# 2. HyDE深入检索理论基础
print("🔍 深入检索理论基础...")
theory_queries = [
f"{topic}的理论基础",
f"{topic}的核心概念",
f"{topic}的方法论"
]
theory_results = []
for query in theory_queries:
result = self.hyde.query(query, k=params["k"]//2)
theory_results.extend(result.get("documents", []))
# 3. 去重和合并
all_docs = self._deduplicate_documents(broad_results + theory_results)
selected_docs = all_docs[:params["k"]]
print(f"📄 最终选择 {len(selected_docs)} 篇相关文献")
# 4. 生成文献综述
review = self._generate_literature_review(topic, selected_docs, params["max_tokens"])
return {
"topic": topic,
"domain": domain,
"depth": depth,
"num_documents": len(selected_docs),
"review": review,
"documents_preview": [doc.page_content[:200] for doc in selected_docs[:3]]
}
def _generate_literature_review(self, topic: str, documents: List, max_tokens: int) -> str:
"""生成文献综述内容"""
context = "\n\n".join([doc.page_content for doc in documents])
prompt = f"""<|im_start|>system
你是一位学术研究助手,需要基于提供的文献生成一篇专业的文献综述。
请按照以下结构组织内容:
1. 研究背景和意义
2. 理论基础和关键概念
3. 主要研究方法和进展
4. 当前挑战和局限性
5. 未来研究方向
要求:
• 学术严谨,引用提供的文献内容
• 逻辑清晰,结构完整
• 语言专业但不晦涩<|im_end|>
<|im_start|>user
研究主题:{topic}
相关文献:
{context}
请生成一篇关于{topic}的文献综述:<|im_end|>
<|im_start|>assistant
"""
sampling_params = SamplingParams(
max_tokens=max_tokens,
temperature=0.3,
top_p=0.8,
stop=["<|im_end|>", "<|endoftext|>"]
)
outputs = self.llm.generate([prompt], sampling_params)
return outputs[0].outputs[0].text.strip() if outputs else "生成失败"
def compare_methods(self, method1: str, method2: str, aspect: str = "all") -> Dict[str, Any]:
"""
比较两种方法
Args:
method1: 方法1名称
method2: 方法2名称
aspect: 比较方面 ("all" | "performance" | "complexity" | "applicability")
"""
print(f"🔬 方法比较: {method1} vs {method2}")
print(f" 比较方面: {aspect}")
# 使用查询分解进行系统比较
comparison_query = f"系统比较{method1}和{method2}在性能、复杂度和适用性方面的差异"
result = self.decomposition.query(comparison_query)
# 根据比较方面过滤内容
if aspect != "all":
filtered_answer = self._filter_comparison_by_aspect(result["answer"], aspect)
else:
filtered_answer = result["answer"]
return {
"method1": method1,
"method2": method2,
"aspect": aspect,
"comparison": filtered_answer,
"sub_questions": result.get("sub_questions", []),
"sub_answers": result.get("sub_answers", [])
}
def _filter_comparison_by_aspect(self, answer: str, aspect: str) -> str:
"""根据方面过滤比较内容"""
aspect_keywords = {
"performance": ["性能", "准确率", "效率", "速度", "效果"],
"complexity": ["复杂度", "计算量", "参数", "训练时间", "推理时间"],
"applicability": ["适用性", "应用场景", "限制", "条件", "领域"]
}
keywords = aspect_keywords.get(aspect, [])
lines = answer.split('\n')
filtered_lines = [line for line in lines if any(kw in line for kw in keywords)]
return '\n'.join(filtered_lines) if filtered_lines else answer
def research_gap_analysis(self, topic: str) -> Dict[str, Any]:
"""分析研究空白"""
print(f"🎯 研究空白分析: {topic}")
# 使用Step Back技术分析研究现状和未来方向
step_back_query = f"{topic}领域的研究现状、主要成就和未来挑战"
result = self.step_back.query(step_back_query)
# 生成研究空白分析
gap_analysis = self._generate_gap_analysis(topic, result["answer"])
return {
"topic": topic,
"current_status": result["answer"],
"research_gaps": gap_analysis,
"suggested_directions": self._suggest_research_directions(topic)
}
def _generate_gap_analysis(self, topic: str, current_status: str) -> str:
"""生成研究空白分析"""
prompt = f"""<|im_start|>system
基于当前研究现状,分析存在的研究空白和未来机会。
请从以下角度分析:
1. 理论方面的空白
2. 方法技术的局限
3. 应用场景的扩展
4. 跨学科融合的机会<|im_end|>
<|im_start|>user
研究领域:{topic}
当前研究现状:
{current_status}
请分析该领域的研究空白:<|im_end|>
<|im_start|>assistant
"""
sampling_params = SamplingParams(
max_tokens=800,
temperature=0.4,
top_p=0.8
)
outputs = self.llm.generate([prompt], sampling_params)
return outputs[0].outputs[0].text.strip() if outputs else "分析失败"
def _suggest_research_directions(self, topic: str) -> List[str]:
"""推荐研究方向"""
prompt = f"""<|im_start|>system
为以下研究领域推荐具体的研究方向,每行一个方向:<|im_end|>
<|im_start|>user
研究领域:{topic}
请推荐3-5个具体的研究方向:<|im_end|>
<|im_start|>assistant
"""
sampling_params = SamplingParams(
max_tokens=300,
temperature=0.5,
top_p=0.9
)
outputs = self.llm.generate([prompt], sampling_params)
if outputs:
text = outputs[0].outputs[0].text.strip()
return [line.strip() for line in text.split('\n') if line.strip()]
return []
def _deduplicate_documents(self, documents: List) -> List:
"""去重文档"""
seen_content = set()
unique_docs = []
for doc in documents:
content_hash = hash(doc.page_content[:500]) # 前500字符作为标识
if content_hash not in seen_content:
seen_content.add(content_hash)
unique_docs.append(doc)
return unique_docs
def generate_citation(self, topic: str, style: str = "apa") -> Dict[str, Any]:
"""生成参考文献引用"""
# 检索相关文献
result = self.hyde.query(f"{topic}的相关研究文献", k=5)
# 生成引用格式
citations = self._format_citations(result.get("documents", []), style)
return {
"topic": topic,
"citation_style": style,
"citations": citations,
"num_references": len(citations)
}
def _format_citations(self, documents: List, style: str) -> List[str]:
"""格式化引用"""
citations = []
for i, doc in enumerate(documents, 1):
# 简化版引用生成,实际应使用专业引用库
metadata = doc.metadata
title = metadata.get('title', '未知标题')
authors = metadata.get('authors', '未知作者')
year = metadata.get('year', '未知年份')
if style == "apa":
citation = f"{authors} ({year}). {title}."
elif style == "mla":
citation = f"{authors}. \"{title}\". {year}."
else:
citation = f"{authors}. {title}. {year}."
citations.append(f"{i}. {citation}")
return citationspython7.2.2 学术助手实战测试#
def test_academic_assistant():
"""测试学术论文助手"""
print("🎓 学术论文助手测试")
print("=" * 60)
# 初始化学术助手
academic_rag = AcademicRAG(vectorstore, llm, embeddings)
# 测试文献综述功能
print("1. 📚 文献综述生成测试")
review_result = academic_rag.literature_review(
"机器人抓取中的滑动检测技术",
depth="standard"
)
print(f" 生成综述长度: {len(review_result['review'])} 字符")
print(f" 使用文献数: {review_result['num_documents']}")
print(f" 识别领域: {review_result['domain']}")
# 测试方法比较功能
print("\n2. 🔬 方法比较测试")
comparison_result = academic_rag.compare_methods(
"基于视觉的抓取检测",
"基于触觉的抓取检测",
aspect="performance"
)
print(f" 比较方面: {comparison_result['aspect']}")
print(f" 生成子问题数: {len(comparison_result['sub_questions'])}")
# 测试研究空白分析
print("\n3. 🎯 研究空白分析测试")
gap_result = academic_rag.research_gap_analysis("仿人机器人抓取技术")
print(f" 分析主题: {gap_result['topic']}")
print(f" 推荐方向数: {len(gap_result['suggested_directions'])}")
# 测试引用生成
print("\n4. 📖 参考文献生成测试")
citation_result = academic_rag.generate_citation("深度学习在机器人中的应用", "apa")
print(f" 引用风格: {citation_result['citation_style']}")
print(f" 生成引用数: {citation_result['num_references']}")
return {
"literature_review": review_result,
"method_comparison": comparison_result,
"gap_analysis": gap_result,
"citations": citation_result
}
# 运行测试
if __name__ == "__main__":
results = test_academic_assistant()
# 显示详细结果
print("\n" + "="*60)
print("📊 学术助手测试结果摘要:")
review = results["literature_review"]
print(f"📚 文献综述: {review['topic']}")
print(f" 领域: {review['domain']}")
print(f" 深度: {review['depth']}")
print(f" 文献数: {review['num_documents']}")
print(f" 预览: {review['review'][:200]}...")
comparison = results["method_comparison"]
print(f"\n🔬 方法比较: {comparison['method1']} vs {comparison['method2']}")
print(f" 方面: {comparison['aspect']}")
print(f" 子问题: {len(comparison['sub_questions'])}个")python7.2.3 典型学术工作流#
def complete_research_workflow():
"""完整学术研究工作流示例"""
topic = "多模态融合在机器人抓取中的应用"
academic_rag = AcademicRAG(vectorstore, llm, embeddings)
print(f"🎓 完整学术研究工作流: {topic}")
print("=" * 60)
# 1. 文献综述
print("1. 📚 生成文献综述...")
review = academic_rag.literature_review(topic, "comprehensive")
# 2. 方法比较
print("2. 🔬 比较相关方法...")
comparison = academic_rag.compare_methods("视觉-触觉融合", "纯视觉方法")
# 3. 研究空白分析
print("3. 🎯 分析研究空白...")
gaps = academic_rag.research_gap_analysis(topic)
# 4. 生成参考文献
print("4. 📖 生成参考文献...")
citations = academic_rag.generate_citation(topic, "apa")
# 整合结果
research_report = {
"topic": topic,
"literature_review": review["review"],
"method_comparison": comparison["comparison"],
"research_gaps": gaps["research_gaps"],
"suggested_directions": gaps["suggested_directions"],
"citations": citations["citations"]
}
print(f"✅ 研究工作流完成!")
print(f" 文献综述长度: {len(review['review'])} 字符")
print(f" 识别研究空白: {len(gaps['research_gaps'].split('.'))} 个主要方向")
print(f" 生成参考文献: {len(citations['citations'])} 篇")
return research_reportpython7.3 案例对比与总结#
7.3.1 系统特性对比#
| 特性 | 智能客服助手 | 学术论文助手 |
|---|---|---|
| 目标用户 | 普通用户、客户 | 研究人员、学生 |
| 问题类型 | 产品、故障、操作 | 研究、分析、综述 |
| 技术重点 | 场景识别、路由 | 深度分析、综合 |
| 响应格式 | 客服模板、步骤化 | 学术结构、引用 |
| 性能要求 | 实时响应、高可用 | 深度分析、准确性 |
7.3.2 技术应用对比#
| 技术 | 智能客服应用 | 学术助手应用 |
|---|---|---|
| Multi-Query | 处理模糊客户问题 | 广泛检索研究现状 |
| RAG-Fusion | 一般问题综合回答 | 多角度文献分析 |
| Query Decomposition | 故障排查步骤化 | 方法系统比较 |
| Step Back | 操作教程背景知识 | 研究现状分析 |
| HyDE | 产品技术规格查询 | 理论深度检索 |
7.3.3 最佳实践总结#
✅ 智能客服助手关键点
- 场景识别准确性:决定技术选择的关键
- 响应模板化:提升用户体验和专业性
- 实时性能:确保客服对话流畅性
- 置信度评估:提供透明的质量指示
✅ 学术论文助手关键点
- 深度分析能力:支持复杂研究需求
- 学术规范性:符合学术写作标准
- 文献处理能力:高效处理大量学术文献
- 研究方向建议:提供创新性洞察
7.3.4 扩展建议#
🔧 智能客服扩展方向
- 多轮对话支持:处理复杂客服场景
- 情感分析:识别用户情绪调整响应
- 多语言支持:国际化客服需求
- 知识库更新:动态更新产品信息
🔧 学术助手扩展方向
- 专业领域定制:针对特定学科优化
- 合作网络分析:分析学者合作关系
- 趋势预测:预测研究热点方向
- 论文写作辅助:完整写作流程支持
💡 核心价值:这两个案例展示了RAG技术在不同领域的强大应用潜力,通过智能技术选择和场景化优化,可以构建出高度专业化的智能助手系统。
通过这两个实战案例,我们看到了高级RAG技术在实际应用中的巨大价值,为构建专业领域的智能助手提供了完整的技术框架和实践指南。