微信扫码
添加专属顾问
我要投稿
探索多种RAG优化策略及其在Langchain中的实现,有效解决幻觉问题。核心内容:1. RAG优化策略整合与Langchain实现2. 名词嵌入对比训练及性能评估3. 业务分析与RAG搜索能力增强
这篇文档整合了多种rag优化策略,并且使用langchain实现。可以有效的解决幻觉的问题。
我们将把RAG论文中的想法整合到RAG代理中:
具体的逻辑图如下:
大致意思为:
1、首先根据问题描述判断是从rag获取信息还是网络搜索
2、如果rag获取的信息中出现幻觉,则重新回到网络进行搜索
3、根据问题和信息生成答案,然后查看答案和问题的资料判断是否有幻觉。
4、最终生成问题的答案。
5、在生成答案的过程中发现内容信息不相关,则会loop回去网络搜索重新生成答案。
名词嵌入对比训练
我们用nomic-bert-2048初始化nomic嵌入的训练。我们的对比数据集由约2.35亿个文本对组成。我们在收集Nomic Atlas的过程中广泛验证了其质量。你可以在nomic ai/constrastors代码库中找到数据集的详细信息,也可以在nomic Atlas中探索500万对子集。
在大规模文本嵌入基准测试(MTEB)中,nomic嵌入的性能优于Text-Embedding-ada-002和jina-embeddings-v2-base-en。
nomic和其他的embedding算法比较下来,效果更好。
62.39 | 85.53 | ||||||
58.20 | |||||||
不过我们要使用qwen-max对应的embedding
我们根据上面的摘要,拆分成多个模块。一步步的实现。增加rag搜索的能力。总体的业务流程如下:
1、在start后面隐藏了一个条件边(route结点)【决定将问题路由到不同的检索方法】
2、retrieve结点【返回知识库获取的数据信息】
3、grade_documents结点【确定检索到的文档是否与问题相关如果任何文档不相关,我们将设置一个标志来运行网络搜索】
4、web_search【网络搜索:根据问题在网上寻找答案】
5、generate【根据文档的内容生成答案】
6、增加条件边grade_generation_v_documents_and_question【确定生成是否基于文档并回答问题、是否产生幻觉】
可以将问题路由到不同的检索方法。我们通过Agent来决定路由到哪个方向。
# Prompt
router_prompt = """You are an expert at routing a user question to a vectorstore or web search.
The vectorstore contains documents related to agents, prompt engineering, and adversarial attacks.
Use the vectorstore for questions on these topics. For all else, and especially for current events, use web-search.
Return JSON with single key, datasource, that is 'websearch' or 'vectorstore' depending on the question.
Here is the user question: \n\n {question}.
"""
router_prompt = ChatPromptTemplate.from_template(router_prompt)
#json格式输出
class router_out(BaseModel):
datasource: str = Field(description="选择'websearch' or 'vectorstore'")
res :str = Field(description="结果")
router_llm = router_prompt | model.with_structured_output(router_out)
1、我们建立一个prompt。
您是将用户问题路由到向量库或网络搜索的专家。
向量库包含与agents, prompt engineering, and adversarial attacks相关的文档。【可以根据知识库内容修改,也可以再增加一个agent总结知识库的内容】
使用向量库回答有关这些主题的问题。对于所有其他内容,尤其是时事,请使用网络搜索。
根据问题的不同,返回带有单键数据源的JSON,即“websearch”或“vectorstore”。
这是用户的问题:\n\n{question}。
2、将结果格式化输出:
输出作为一个BaseModel的类,里面有两个对象datasource和res
class router_out(BaseModel):
datasource: str = Field(description="选择'websearch' or 'vectorstore'")
res :str = Field(description="结果")
定义知识库返回的节点
def retrieve(state):
"""
Retrieve documents from vectorstore
Args:
state (dict): The current graph state
Returns:
state (dict): New key added to state, documents, that contains retrieved documents
"""
print("---RETRIEVE---")
question = state["question"]
# Write retrieved documents to documents key in state
documents = retriever.invoke(question)
return {"documents": documents}
def generate(state):
"""
Generate answer using RAG on retrieved documents
Args:
state (dict): The current graph state
Returns:
state (dict): New key added to state, generation, that contains LLM generation
"""
print("---GENERATE---")
question = state["question"]
documents = state["documents"]
loop_step = state.get("loop_step", 0)
# RAG generation
docs_txt = format_docs(documents)
rag_prompt_formatted = rag_prompt.format(context=docs_txt, question=question)
generation = model.invoke([HumanMessage(content=rag_prompt_formatted)])
return {"generation": generation.content, "loop_step": loop_step + 1}
def grade_documents(state):
"""
Determines whether the retrieved documents are relevant to the question
If any document is not relevant, we will set a flag to run web search
Args:
state (dict): The current graph state
Returns:
state (dict): Filtered out irrelevant documents and updated web_search state
"""
print("---CHECK DOCUMENT RELEVANCE TO QUESTION---")
question = state["question"]
documents = state["documents"]
# Score each doc
filtered_docs = []
web_search = "No"
for d in documents:
result = grader_llm.invoke(
{"document": d, "question": question}
)
grade = result.binary_score
# Document relevant
if grade.lower() == "yes":
print("---GRADE: DOCUMENT RELEVANT---")
filtered_docs.append(d)
# Document not relevant
else:
print("---GRADE: DOCUMENT NOT RELEVANT---")
# We do not include the document in filtered_docs
# We set a flag to indicate that we want to run web search
web_search = "Yes"
continue
return {"documents": filtered_docs, "web_search": web_search}
1、遍历所有知识库返回的文档,只要有一个文档内容和问题无关。我们就需要通过网络搜索进行补充。
def grade_generation_v_documents_and_question(state):
print("---CHECK HALLUCINATIONS---")
question = state["question"]
documents = state["documents"]
generation = state["generation"]
max_retries = state.get("max_retries", 3) # Default to 3 if not provided
result = hallucination_llm.invoke(
{"documents": format_docs(documents), "generation": generation}
)
grade =result.binary_score
# Check hallucination
if grade == "yes":
print("---DECISION: GENERATION IS GROUNDED IN DOCUMENTS---")
# Check question-answering
print("---GRADE GENERATION vs QUESTION---")
# Test using question and generation from above
result = answer_llm.invoke({"question":question,"generation": generation})
grade = result.binary_score
if grade == "yes":
print("---DECISION: GENERATION ADDRESSES QUESTION---")
return "useful"
elif state["loop_step"] <= max_retries:
print("---DECISION: GENERATION DOES NOT ADDRESS QUESTION---")
return "not useful"
else:
print("---DECISION: MAX RETRIES REACHED---")
return "max retries"
elif state["loop_step"] <= max_retries:
print("---DECISION: GENERATION IS NOT GROUNDED IN DOCUMENTS, RE-TRY---")
return "not supported"
else:
print("---DECISION: MAX RETRIES REACHED---")
return "max retries"
1、确定生成是否基于文档并回答问题
如果不相关且循环次数<3,则输出不支持。重新返回generate结点
2、根据最终问题的回答判断是否相关
如果不相关且循环次数<3,则输出无用,则返回websearch结点。

查看langsmith的监控信息会看到我们的任务走向和实际消耗的时间。
1、先调用retrieve后进入grade_documents
2、需要web搜索,进入web_search
3、grade_generation_v_documents_and_question 输出结果
loop_step =1
对比情况
问题:什么是cot?
答案:思维链 (CoT) 是一种通过模拟人类推理过程来解决复杂问题的技术,它将任务分解为一系列逻辑步骤,逐步引导至最终答案。这种方法提高了模型的透明度和多步推理能力,适用于多种任务如算术推理、常识推理等。然而,它也存在对高质量提示的需求和计算成本增加等局限性。
直接用rag:
自一致性抽样#
自洽采样(Wang等人,2022a)是对温度>0的多个输出进行采样,然后从这些候选者中选择最佳的一个。
选择最佳候选人的标准可能因任务而异。一般的解决方案是选择多数票。对于易于验证的任务,例如使用单元测试的编程问题,我们可以简单地运行解释器并使用单元测试验证其正确性。
思维链(CoT)#
思维链(CoT)提示(Wei等人,2022)生成一系列短句,逐步描述推理逻辑,称为推理链或理由,最终得出最终答案。CoT的优势在复杂的推理任务中更为明显,同时使用大型模型(例如,参数超过50B)。简单的任务只会从CoT提示中略微受益。
CoT提示的类型#
CoT提示的两种主要类型:
很少拍摄CoT。它是通过一些演示来提示模型,每个演示都包含手动编写(或模型生成)的高质量推理链。
用途
ChatPromptTemplate为聊天式交互场景设计,用于构建多轮对话形式的提示信息。它可以处理不同角色(如人类、AI)的消息,并按照一定的格式组合这些消息。这更符合聊天机器人、对话式 AI 等应用的需求。ChatPromptTemplate能够处理不同角色,是与PromptTemplate最大的不同。
模板结构
ChatPromptTemplate由多个消息模板组成,每个消息模板对应一个特定的角色(如 HumanMessagePromptTemplate
、AIMessagePromptTemplate
等)。这些消息模板可以包含各自的占位符,用于填充动态内容。例如:
from langchain.prompts.chat import (
ChatPromptTemplate,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate
)
# 定义系统消息模板
system_template = "你是一个乐于助人的助手,总是用简洁的语言回答问题。"
system_message_prompt = SystemMessagePromptTemplate.from_template(system_template)
# 定义用户消息模板
human_template = "请提供关于{topic}的简要信息。"
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
# 组合成聊天提示模板
chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])
# 构建提示,填充占位符
prompt = chat_prompt.format_prompt(topic="LLM").to_messages()
print(prompt)
主要参数
messages:列表类型。定义聊天消息的结构。列表中的每个元素代表一条消息,消息通常由 BaseMessagePromptTemplate 类的实例组成,比如 SystemMessagePromptTemplate、HumanMessagePromptTemplate 等,分别对应系统消息、人类消息等不同角色的消息模板。通过 messages 参数可以构建出一个完整的聊天对话流程的提示模板。
例子如下:
[HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['topic'], input_types={}, partial_variables={}, template='请提供关于{topic}的简要信息。\n\n'), additional_kwargs={})]
input_variables:列表类型。模板字符串里所有占位符的名称。
LLM的角色
“system“角色,通过分配特定行为给聊天助手来创建对话的上下文或范围。例如,如果您希望与ChatGPT在与体育相关的话题范围内进行对话,可以将”system"角色分配给聊天助手,并设置内容为"体育专家”。然后ChatGPT会表现得像体育专家一样回答您的问题。
"human"角色,代表实际的最终用户,他向ChatGPT发送提问。
"ai“角色,代表响应最终用户提示的实体。这个角色表示消息是助手(聊天模型)的响应。”ai"角色用于在当前请求中设置模型的先前响应,以保持对话的连贯性。
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费场景POC验证,效果验证后签署服务协议。零风险落地应用大模型,已交付160+中大型企业
2025-04-23
RAG进阶:Embedding Models嵌入式模型原理和选择
2025-04-23
一文搞懂RAG构建知识库和知识图谱
2025-04-23
RAG不需要切块向量化了?通过PageIndex构建Agentic RAG
2025-04-22
文档解析主流开源工具全家桶及RAG中的文档目录解析PageIndex思路解析
2025-04-22
腾讯发布Conan-Embedding-V2,登顶MTEB中英榜单,性能更强、覆盖场景更广
2025-04-22
想让 FastGPT 更猛?试试 OceanBase 向量数据库吧!
2025-04-22
RAG应用必备!10种向量数据库全解析、Weaviate、Milvus、pgvector、Qdrant等热门工具谁更强?
2025-04-22
深度拆解RAGFlow分片引擎!3大阶段+视觉增强,全网最硬核架构解析
2024-10-27
2024-09-04
2024-07-18
2024-05-05
2024-06-20
2024-06-13
2024-07-09
2024-07-09
2024-05-19
2024-07-07
2025-04-22
2025-04-22
2025-04-20
2025-04-19
2025-04-18
2025-04-16
2025-04-14
2025-04-13