微信扫码
与创始人交个朋友
我要投稿
今天是2024年5月19日,星期日,北京,天气晴。
昨天,我们讲了知识图谱增强RAG问答时候可以做的几个阶段性注入的方案。
今天,我们系统性的看看RAG在真实langchain中实践的一些策略,推荐大家看看。
关于RAG,可以看看langchain出品的RAG系列,地址在:https://github.com/langchain-ai/rag-from-scratch系列,其做了很细致的拆分和讲解,并且有对应的代码,如下概览:
大体可以切分成如下部分:
一个是索引Indexing部分:
另一个是生成Generation部分:
Query Transformations查询转换侧重于重写和/或修改问题以便检索,整体流程如下:
其中重要的流程如下:
1、Multi Query多查询策略
该方法从多个角度重写用户问题,为每个重写的问题检索文档,返回所有查询的唯一文档。在实现上,将一个查询变成多个查询:https://python.langchain.com/docs/modules/data_connection/retrievers/MultiQueryRetriever
对应的代码具象化如下:
2、RAG-Fusion多查询结果融合策略
从多个角度重写用户问题,检索每个重写问题的文档,并组合多个搜索结果列表的排名,以使用倒数排名融合(RRF)生成单一、统一的排名。其思想在于:将多个召回查询的结果进行合并:https://github.com/langchain-ai/langchain/blob/master/cookbook/rag_fusion.ipynb?ref=blog.langchain.dev,https://towardsdatascience.com/forget-rag-the-future-is-rag-fusion-1147298d8ad1
对应代码实现:
3、Decomposition问题分解策略
Decomposition问题分解将一个复杂问题分解成多个子问题,将问题分解为一组子问题/问题,可以按顺序解决(使用第一个问题的答案+检索来回答第二个问题),也可以并行解决(将每个答案合并为最终答案),这个是向下分解,与Multi Query是不同的方案,
1)Answer recursively迭代式回答:在问题分解的基础上,逐步迭代出答案,将上一步问题的答案,与下一步骤的答案进行拼接,送入大模型进行问答:https://arxiv.org/pdf/2205.10625.pdf,https://arxiv.org/abs/2212.10509.pdf
对应prompt形式化如下:
2)Answer individually,当然,也可以让每个subquery分别进行处理,然后得到答案,然后再拼接成一个QA pairspprompt最终形成答案。
如具体实现如下:
4、Step Back问答回退策略
Step Back问答回退,首先提示LLM提出一个关于高级概念或原则的通用后退问题,并检索有关它们的相关事实,使用此基础来帮助回答用户问题。构成上包括抽象abstracton和推理reasoning两个步骤,来源于工作https://arxiv.org/pdf/2310.06117.pdf,比如给定一个问题,需要提示大模型,找到回答该问题的一个前置问题。
得到前置问题及其答案后,再将其整体与当前问题进行合并,最后送入大模型进行问答,得到最终答案:
对应的prompt如下:
5、HyDE混合策略
该策略思想为:LLM将问题转换为回答问题的假设文档。使用嵌入的假设文档检索真实文档,前提是doc-doc相似性搜索可以产生更多相关匹配。由于query与doc之间是不对称检索,因此这个时候,可以先根据query生成一个doc,然后根据doc生成对应的embedding,再跟原先documents进行检索:
例如下图中的query,每个有对应的instruction,通过chatgpt生成generated doument,然后以此进行召回,最后生成real document;
具体对应的具象化实现可以看看:
对应的文档和论文可以查看:https://github.com/langchain-ai/langchain/blob/master/cookbook/hypothetical_document_embeddings.ipynb,https://arxiv.org/abs/2212.10496
RAG Routing路由,主要解决的是从获取query之后,所需要执行的问题意图分类的问题,处理的是问题域选择问题:
可用的方案包括,Logical and Semantic routing,基于逻辑规则和语义的路由分发:https://python.langchain.com/docs/use_cases/query_analysis/techniques/routing#routing-to-multiple-indexes
对应的具象化实现如下:
可以通过function call来实现:
也可以基于语义来实现分发Semantic routing,https://python.langchain.com/docs/expression_language/cookbook/embedding_router
在实现上,可以为每个意图都设定一个prompt,然后进行判定,一个具象化的实现如下:
Query Construction,主要解决的问题是不同检索知识库,如mysql数据库、图数据库GraphDB、向量化数据库vectorDB的查询转换。使用LLM将自然语言转换为其中DSL是一种与给定数据库(SQL、Cypher等)交互所需的领域特定语言:https://blog.langchain.dev/query-construction/,https://blog.langchain.dev/enhancing-rag-based-applications-accuracy-by-constructing-and-leveraging-knowledge-graphs/
正在具体实现上,可以查看的方案,可以如下:
Query structuring for metadata filters,基于元数据过滤器的问题构建,例如,许多向量化存储都包含元数据字段,例如:
这样就可以根据元数据过滤特定的数据chunk:https://python.langchain.com/docs/use_cases/query_analysis/techniques/structuring
关于文档chunk切分这个事情,索引的组织其实也是一个很有趣的话题,这块在切分上可以做优化,也可以做多种表达方式的索引multi-representation indexing、特定化的embedding或者层级性的索引:
例如Multi-representation Indexing,使用LLM生成针对检索进行优化的文档摘要(“命题”)。嵌入这些摘要以进行相似性搜索,但将完整文档返回给LLM进行生成:https://blog.langchain.dev/semi-structured-multi-modal-rag/,https://python.langchain.com/docs/modules/data_connection/retrievers/multi_vector,https://arxiv.org/abs/2312.06648
例如,可以针对一个text,切分形成多个检索单位retrieval units,包括:passages、sentences,propositions
可以通过小的chunk,来实现对父级documents的索引,查看:https://python.langchain.com/v0.1/docs/modules/data_connection/retrievers/parent_document_retriever/
此外,也可以进一步来看看关于层级性索引的方案:RAPTOR,https://arxiv.org/pdf/2401.18059.pdf,对应的代码放在:https://github.com/langchain-ai/langchain/blob/master/cookbook/RAPTOR.ipynb,其思想在于对文档进行生成聚类摘要,然后将设计成层级性。具体实现上,将语料库中的文档聚类,并递归地总结相似的文档。将它们全部编入索引,生成较低级别的文档和摘要,可以检索这些文档和摘要来回答从详细到更高级别的问题。
但以上还是停留在文本层级,也可以做token到text级,这里可以使用ColBERT,为段落中的每个token生成一个受上下文影响的向量,ColBERT同样为查询中的每个token生成向量,然后,每个文档的得分就是每个查询嵌入与任意文档嵌入的最大相似度之和,这块可以看:https://hackernoon.com/how-colbert-helps-developers-overcome-the-limits-of-rag
在完成对问题的改写、不同知识库查询的构建以及意图分发、查询对象索引的构建之后,我们可以进一步优化Retrieval检索,包括ranking、refinement增强以及自适应检索adaptive retrival。
具体采用的方案可以如下:
Re-ranking,这个可以作为rag fusion的替换方案,当做一个过滤筛子进行排序,示意图如下:
在具体实现上,可以使用Cohere Re-Rank方案,https://python.langchain.com/v0.1/docs/integrations/retrievers/cohere-reranker/#doing-reranking-with-coherererank, https://cohere.com/blog/rerank
具象化的例子如下:
一个对比的效果如下:
此外,也可以使用CRAG(Corrective-RAG,CRAG),地址:https://github.com/langchain-ai/langgraph/blob/main/examples/rag/langgraph_crag.ipynb,https://github.com/langchain-ai/langgraph/blob/main/examples/rag/langgraph_crag_mistral.ipynb,https://github.com/langchain-ai/langgraph/blob/main/examples/rag/langgraph_crag_local.ipynb,其本质上是一种adaptive-RAG策略,实现方式为在循环单元测试中自我纠正检索错误,以确定文档相关性并返回到网络搜索,即纠对检索文档的自我反思/自我评分,主要采用如下步骤:
如果至少有一个文档超过了相关性阈值,则进入生成阶段,在生成之前,进行知识细化 将文档划分为知识条带(knowledge strip) , 对每个知识条进行分级,过滤不相关的知识条,如果所有文档都低于相关性阈值,或者分级者不确定,那么框架就会寻找额外的数据源,并使用网络搜索来补充检索。
关于生成阶段,大家最常见的,就是Self-RAG(https://arxiv.org/pdf/2310.11511),对应地址可以参考:https://github.com/langchain-ai/langgraph/tree/main/examples/rag,https://github.com/langchain-ai/langgraph/blob/main/examples/rag/langgraph_self_rag_mistral_nomic.ipynb,其基本思想在于:使用循环单元测试自行纠正RAG错误,以检查文档相关性、答案幻觉和答案质量。
其实现流程如下:
其思想在于,对检索到的文件和世代进行自我反思/自我评分。
整个过程可以进一步形式化如下:
本文主要围绕langchain这个RAG实现项目中所提到的一些优化策略,这些方案做了阶段性的划分,也有对应的实践代码,可以进一步提升大家的认知,感兴趣的可以多看看。
1、https://github.com/langchain-ai/rag-from-scratch
53AI,企业落地应用大模型首选服务商
产品:大模型应用平台+智能体定制开发+落地咨询服务
承诺:先做场景POC验证,看到效果再签署服务协议。零风险落地应用大模型,已交付160+中大型企业
2024-05-28
2024-04-26
2024-08-21
2024-04-11
2024-08-13
2024-07-09
2024-07-18
2024-10-25
2024-07-01
2024-06-17