闂傚倸鍊烽懗鑸电仚缂備胶绮崹鍓佹崲濞戞瑧绡€闁稿濮ら惄顖炲极閹剧粯鏅搁柨鐕傛嫹
MYSQL濠电姷鏁告慨浼村垂閻撳簶鏋栨繛鎴炩棨濞差亝鏅插璺猴龚閸╃偤姊洪棃娑氬闁瑰嘲顑夊畷顖炲川鐎涙ḿ鍘繝銏f硾閻楀棝宕濆鎵佸亾闂堟稑绨婚柟鍑ゆ嫹
SQL闂傚倷娴囬褍霉閻戣棄鏋侀柟闂寸閸屻劎鎲搁弬璺ㄦ殾闁汇垹澹婇弫鍥煟濮楀棗浜滃ù婊堢畺閺岋綁濮€閵堝棙閿柣銏╁灠閻栧ジ寮诲☉妯锋瀻婵炲棙鍔曢锟�
MYSQL闂傚倷娴囬褍顫濋敃鍌︾稏濠㈣泛鑻弸鍫⑩偓骞垮劚閹峰銆掓繝姘厱閻忕偛澧介埥澶岀磼閸撲礁浠遍柡灞剧洴婵$兘顢涘⿰鍛闂備浇妗ㄧ欢銈夊箯閿燂拷
闂傚倸鍊烽懗鑸电仚缂備胶绮崹鍓佹崲濞戞瑧绡€闁稿濮ら惄顖炲极閹剧粯鏅搁柨鐕傛嫹
闂傚倸鍊风粈渚€骞栭锔藉亱闁糕剝鐟ч惌鎾绘倵濞戞鎴﹀矗韫囨稒鐓熼柡鍐ㄥ€哥敮鍫曟⒒閸屻倕鐏﹂柡灞炬礃缁绘盯宕归鐓幮ゆ繝纰樺墲閻撯€翅缚瑜斿﹢渚€姊虹紒妯曟垹绮婇幘顔肩;闁瑰墽绮崑鍕磽娴e顏堫敂閳轰讲鏀介柣鎰▕閸ょ喎鈹戦娑欏唉妤犵偛绻橀弫鎾绘晸閿燂拷
闂傚倸鍊烽懗鍫曞储瑜旈妴鍐╂償閵忋埄娲稿┑鐘诧工鐎氼參宕h箛娑欑厓闁告繂瀚埀顒€鎽滃▎銏ゆ倷閻戞ḿ鍘遍梺闈涱樈閸ㄦ娊鎮鹃柆宥嗙厸濞达絽婀遍惌鎺楁煛鐏炶濡奸柍钘夘槸铻i柛顭戝櫘娴煎啴姊绘担椋庝覆缂傚秳鑳剁划濠氬冀瑜滈崵鏇熴亜閺冨倸浜剧€规洖顦妴鎺戭潩閻撳海浠柡宥佲偓鏂ユ斀闁绘劕妯婇崵鐔封攽椤栨稒灏︽鐐茬箻閺佹捇鏁撻敓锟�
闂傚倷娴囧畷鍨叏瀹曞洦濯奸柡灞诲劚閻ょ偓绻涢崱妯虹仼缂佲偓婵犲啯鍙忔俊鐐额嚙娴滈箖姊虹拠鈥崇仩闁哥喐娼欓悾鐑芥偄绾拌鲸鏅㈡繛杈剧秬椤曟牠宕埀顒勬⒒閸屾瑨鍏屾い銏狅躬椤㈡岸寮介鐐电崶濠德板€愰崑鎾淬亜閳轰降鍋㈢€规洖銈搁幃銏㈡偘閳╁啰浜欓梺璇查缁犲秹宕曟潏鈹惧亾濮樼厧骞楃紒瀣樀婵偓闁绘瑢鍋撻柣鏂挎閹鎷呯粵瀣秷闁诲孩鐔幏锟�

细数RAG的12个痛点,英伟达高级架构师亲授解决方案-人工智能

首页 2024-07-06 14:54:07

检索增强式生成(RAG)是一种使用检索提升语言模型的技术。具体来说,就是在语言模型生成答案之前,先从广泛的文档数据库中检索相关信息,然后利用这些信息来引导生成过程。这种技术能极大提升内容的准确性和相关性,并能有效缓解幻觉问题,提高知识更新的速度,并增强内容生成的可追溯性。RAG 无疑是最激动人心的人工智能研究领域之一。有关 RAG 的更多详情请参阅本站专栏文章《专补大模型短板的RAG有哪些新进展?这篇综述讲明白了》。

但 RAG 也并非完美,用户在使用时也常会遭遇一些「痛点」。近日,英伟达生成式AI高级解决方案架构师Wenqi Glantz 在 Towards Data Science 发布了一篇文章,梳理了 12 个 RAG 的痛点并给出了相应的解决方案。

文章目录如下:

痛点 1:内容缺失
痛点 2:错过排名靠前的文档
痛点 3:不在上下文中——合并策略的局限
痛点 4:未提取出来
痛点 5:格式错误
痛点 6:不正确的具体说明
痛点 7:不完备
痛点 8:数据摄取的可扩展性
痛点 9:结构化数据问答
痛点 10:从复杂 PDF 提取数据
痛点 11:后备模型
痛点 12:LLM 安全

其中 7 个痛点(见下图)来自 Barnett et al. 的论文《Seven Failure Points When Engineering a Retrieval Augmented Generation System》,此外还另外增加了 5 个常见痛点。

这些痛点对应的解决方案如下:?

痛点 1:内容缺失

知识库中缺失上下文。当知识库中没有答案时,RAG 系统会提供一个看似可信但并不正确的答案,而不会承认它不知道。用户会收到错误信息,遭遇挫折。

人们提出了两种解决方案:

清洁数据

输入垃圾,那也必定输出垃圾。如果你的源数据质量低劣,比如包含互相冲突的信息,那不管你的 RAG 工作构建得多么好,它都不可能用你输入的垃圾神奇地输出高质量结果。这个解决方案不仅适用于这个痛点,而且适用于本文列出的所有痛点。任何 RAG 工作流程想要获得优良表现,都必须先清洁数据。

下面列出了几个清洁数据的常用策略:

  • 移除噪声和不相关信息:这包括移除特殊字符、停用词(stop words,如 the 和 a)、HTML 标签。
  • 识别和纠正错误:包括拼写错误、错别字和语法错误。可以使用拼写检查器和语言模型等工具来解决这个问题。
  • 去重:移除重复数据记录或可能导致检索过程出现偏差的相似记录。

unstructured.io 的核心软件库提供了一整套清洁工具可以帮助解决这些数据清洁需求。值得一试。

更好的提词设计

对于因为信息缺乏而导致系统给出看似可信却不正确结果的问题,更好的提词设计能提供很大帮助。通过为系统给出「如果你不确定答案是什么,就告诉我你不知道」这样的指示,就能鼓励模型承认自己的局限,并更透明地向用户传达它的不确定。虽然不能保证 100% 准确度,但在清洁数据之后,精心设计 prompt 是最好的做法之一。

痛点 2:错过排名靠前的文档

初始检索过程中缺失上下文。在系统的检索组件返回的结果中,关键性的文档可能并不靠前。正确的答案被忽视了,这会导致系统无法给出准确响应。上述论文中写道:「问题的答案就在文档中,但排名不够高,就没有返回给用户。」

研究者提出了两种解决方案:

对 chunk_size 和 similarity_top_k 进行超参数微调

chunk_size 和 similarity_top_k 这两个参数可用于管理 RAG 模型的数据检索过程的效率和效果。调整这两个参数会影响被检索信息的计算效率和质量之间的权衡。作者在之前一篇文章中探索了对 chunk_size 和 similarity_top_k 进行超参数微调的细节:

请访问:https://medium.com/gitconnected/automating-hyperparameter-tuning-with-llamaindex-72fdd68e3b90?

下面给出了示例代码:
param_tuner = ParamTuner(param_fn=objective_function_semantic_similarity,param_dict=param_dict,fixed_param_dict=fixed_param_dict,show_progress=True,)results = param_tuner.tune()

objective_function_semantic_similarity 函数的定义如下,其中 param_dict 包含了参数 chunk_size 和 top_k 以及它们对应的值:
import osfrom llama_index.postprocessor.cohere_rerank import CohereRerankapi_key = os.environ["COHERE_API_KEY"]cohere_rerank = CohereRerank(api_key=api_key, top_n=2) # return top 2 nodes from rerankerquery_engine = index.as_query_engine(similarity_top_k=10, # we can set a high top_k here to ensure maximum relevant retrievalnode_postprocessors=[cohere_rerank], # pass the reranker to node_postprocessors)response = query_engine.query("What did Sam Altman do in this essay?",)

另外,还可以使用多种嵌入和重新排名工具评估和提升检索器的性能。

参阅:https://blog.llamaindex.ai/boosting-rag-picking-the-best-embedding-reranker-models-42d079022e83

此外,为了得到更好的检索性能,还能微调一个定制版的重新排名工具,其实现细节可访问:

博客链接:https://blog.llamaindex.ai/improving-retrieval-performance-by-fine-tuning-cohere-reranker-with-llamaindex-16c0c1f9b33b

痛点 3:不在上下文中——合并策略的局限

重新排名之后缺乏上下文。对于这个痛点,上述论文的定义为:「已经从数据库检索到了带答案的文档,但该文档没能成为生成答案的上下文。发生这种情况的原因是数据库返回了许多文档,之后采用了一种合并过程来检索答案。」

除了前文提到的增加重新排名工具和微调重新排名工具之外,我们还可以探索以下解决方案:

调整检索策略

LlamaIndex 提供了一系列从基础到高级的检索策略,可帮助研究者在 RAG 工作流程中实现准确的检索。

这里可以看到已分成不同类别的检索策略列表:https://docs.llamaindex.ai/en/stable/module_guides/querying/retriever/retrievers.html

  • 基于每个索引进行基本的检索
  • 高级检索和搜索
  • 自动检索
  • 知识图谱检索器
  • 组合/分层检索器

对嵌入进行微调

如果你使用开源的嵌入模型,那么为了实现更准确的检索,可以对嵌入模型进行微调。LlamaIndex 有一个微调开源嵌入模型的逐步教程,其中证明微调嵌入模型确实可以提升在多个评估指标上的表现:

教程链接:https://docs.llamaindex.ai/en/stable/examples/finetuning/embeddings/finetune_embedding.html

下面是创建微调引擎、运行微调、得到已微调模型的样本代码:
finetune_engine = SentenceTransformersFinetuneEngine(train_dataset,model_id="BAAI/bge-small-en",model_output_path="test_model",val_dataset=val_dataset,)finetune_engine.finetune()embed_model = finetune_engine.get_finetuned_model()

痛点 4:未提取出来

未正确提取上下文。系统难以从所提供的上下文提取出正确答案,尤其是当信息过载时。这会导致关键细节缺失,损害响应的质量。上述论文写道:「当上下文中有太多噪声或互相矛盾的信息时,就会出现这种情况。」

下面来看三种解决方案:

清洁数据

这个痛点的一个典型原因就是数据质量差。清洁数据的重要性值得一再强调!在责备你的 RAG 流程之前,请务必清洁你的数据。

prompt 压缩

LongLLMLingua 研究项目/论文针对长上下文情况提出了 prompt 压缩。通过将其整合进 LlamaIndex,我们可以将 LongLLMLingua 实现成一个节点后处理器,其可在检索步骤之后对上下文进行压缩,之后再将其传输给 LLM。LongLLMLingua 压缩的 prompt 能以远远更低的成本得到更高的性能。此外,整个系统会有更快的运行速度。

下面的代码设置了 LongLLMLinguaPostprocessor,其中使用了 longllmlingua 软件包来运行 prompt 压缩。

更多细节请访问这个笔记:
https://docs.llamaindex.ai/en/stable/examples/node_postprocessor/LongLLMLingua.html#longllmlingua
from llama_index.core.query_engine import RetrieverQueryEnginefrom llama_index.core.response_synthesizers import CompactAndRefinefrom llama_index.postprocessor.longllmlingua import LongLLMLinguaPostprocessorfrom llama_index.core import QueryBundlenode_postprocessor = LongLLMLinguaPostprocessor(instruction_str="Given the context, please answer the final question",target_token=300,rank_method="longllmlingua",additional_compress_kwargs={"condition_compare": True,"condition_in_question": "after","context_budget": "+100","reorder_context": "sort",? # enable document reorder},)retrieved_nodes = retriever.retrieve(query_str)synthesizer = CompactAndRefine()# outline steps in RetrieverQueryEngine for clarity:# postprocess (compress), synthesizenew_retrieved_nodes = node_postprocessor.postprocess_nodes(retrieved_nodes, query_bundle=QueryBundle(query_str=query_str))print("\n\n".join([n.get_content() for n in new_retrieved_nodes]))response = synthesizer.synthesize(query_str, new_retrieved_nodes)

LongContextReorder

论文《Lost in the Middle: How Language Models Use Long Contexts》观察到:当关键信息位于输入上下文的开头或末尾时,通常能获得最佳性能。为了解决这种「中部丢失」问题,研究者设计了 LongContextReorder,其做法是重新调整被检索节点的顺序,这对需要较大 top-k 的情况很有用。

下面的代码展示了如何在查询引擎构建期间将 LongContextReorder 定义成你的节点后处理器。更多细节,请参看这份笔记:
https://docs.llamaindex.ai/en/stable/examples/node_postprocessor/LongContextReorder.html
from llama_index.core.postprocessor import LongContextReorderreorder = LongContextReorder()reorder_engine = index.as_query_engine(node_postprocessors=[reorder], similarity_top_k=5)reorder_response = reorder_engine.query("Did the author meet Sam Altman?")

痛点 5:格式错误

输出的格式有误。当 LLM 忽视了提取特定格式的信息(如表格或列表)的指令时,就会出现这个问题,对此的解决方案有四个:

更好的提词设计

针对这个问题,可使用多种策略来提升 prompt:

  • 清晰地说明指令
  • 简化请求并使用关键词
  • 给出示例
  • 使用迭代式的 prompt 并询问后续问题

输出解析

为了确保得到所需结果,可以使用以下方式输出解析:

  • 为任意 prompt/查询提供格式说明
  • 为 LLM 输出提供「解析」

LlamaIndex 支持整合 Guardrails 和 LangChain 等其它框架提供的输出解析模块。

下面是可在 LlamaIndex 中使用的 LangChain 的输出解析模块的代码。更多细节请访问这份有关输出解析模块的文档:
https://docs.llamaindex.ai/en/stable/module_guides/querying/structured_outputs/output_parser.html
from llama_index.core import VectorStoreIndex, SimpleDirectoryReaderfrom llama_index.core.output_parsers import LangchainOutputParserfrom llama_index.llms.openai import OpenAIfrom langchain.output_parsers import StructuredOutputParser, ResponseSchema# load documents, build indexdocuments = SimpleDirectoryReader("../paul_graham_essay/data").load_data()index = VectorStoreIndex.from_documents(documents)# define output schemaresponse_schemas = [ResponseSchema(name="Education",description="Describes the author's educational experience/background.",),ResponseSchema( ? ? ? ?name="Work",description="Describes the author's work experience/background.",),]# define output parserlc_output_parser = StructuredOutputParser.from_response_schemas(response_schemas)output_parser = LangchainOutputParser(lc_output_parser)# Attach output parser to LLMllm = OpenAI(output_parser=output_parser)# obtain a structured responsequery_engine = index.as_query_engine(llm=llm)response = query_engine.query("What are a few things the author did growing up?",)print(str(response))

Pydantic 程序

Pydantic 程序是一个多功能框架,可将输入字符串转换为结构化的 Pydantic 对象。LlamaIndex 提供几类 Pydantic 程序:

  • LLM 文本补全 Pydantic 程序:这些程序使用文本补全 API 加上输出解析,可将输入文本转换成用户定义的结构化对象。
  • LLM 函数调用 Pydantic 程序:通过利用 LLM 函数调用 API,这些程序可将输入文本转换成用户指定的结构化对象。
  • 预封装 Pydantic 程序:其设计目标是将输入文本转换成预定义的结构化对象。

下面是来自 OpenAI pydantic 程序的代码。LlamaIndex 的文档给出了更多相关细节,并且其中还包含不同 Pydantic 程序的笔记本/指南的链接:
https://docs.llamaindex.ai/en/stable/module_guides/querying/structured_outputs/pydantic_program.html

OpenAI JSON 模式

OpenAI JSON 模式可让我们通过将 response_format 设置成 { "type": "json_object" } 来启用 JSON 模式的响应。当启用了 JSON 模式时,模型就只会生成能解析成有效 JSON 对象的字符串。虽然 JSON 模式会强制设定输出格式,但它无助于针对指定架构进行验证。

更多细节请访问这个文档:https://docs.llamaindex.ai/en/stable/examples/llm/openai_json_vs_function_calling.html

痛点 6:不正确的具体说明
SEO闂傚倸鍊搁崐椋庣矆娴h櫣绀婂┑鐘插€寸紓姘辨喐韫囨洘顫曢柣鎰嚟缁♀偓闂佹悶鍎滈崶顭掔船濠电姷鏁搁崑娑樜熸繝鍐洸婵犲﹤鐗婄€氬懘鏌i弬鍨倯闁绘挶鍎甸弻锝夊即閻愭祴鍋撻崷顓涘亾濮樼偓瀚�
闂傚倸鍊搁崐椋庣矆娓氣偓楠炴牠顢曢敂钘変罕闂佺硶鍓濋悷褔鎯岄幘缁樺€垫繛鎴烆伆閹达箑鐭楅煫鍥ㄧ⊕閻撶喖鏌¢崘銊モ偓鍝ユ暜閸洘鈷掗柛灞诲€曢悘锕傛煛鐏炵偓绀冪紒缁樼椤︽煡鏌¢崼顐㈠⒋鐎规洜濞€閹晝绱掑Ο閿嬪婵犵數鍋犵亸娆戝垝椤栨粍顐芥繛鎴欏灪閻撴瑩鏌涢幋娆忊偓鏍偓姘炬嫹
闂傚倸鍊风粈渚€骞栭位鍥敃閿曗偓閻ょ偓绻濇繝鍌涘櫣闁搞劍绻堥獮鏍庨鈧俊濂告煟閹惧绠撻柍瑙勫灴瀹曟帒鈹冮幘铏础闁逞屽墯閼归箖藝闁秴鐒垫い鎺嗗亾缂佺姴绉瑰畷鏇㈡焼瀹ュ懐鐤囬柟鍏兼儗閻撳绱為弽顓熺厪闁割偅绻嶅Σ褰掓煟閹惧瓨绀嬮柡灞诲妼閳规垿宕卞Δ浣诡唲濠电姷顣介崜婵嬪箖閸岀偛钃熺€广儱鐗滃銊╂⒑缁嬭法绠茬紒瀣灴濠€渚€姊洪幖鐐插姉闁哄懏绮岄悾鐑藉矗婢跺瞼顔曢梺绯曞墲閿氶柣蹇婃櫊閺岋綁顢橀悢鐑樺櫑闂佸疇顫夐崹鍧椼€佸☉妯滄棃鍩€椤掍胶顩茬紓宥囧瘲闂傚倷娴囬褍顫濋敃鍌︾稏濠㈣埖鍔曠粻鏍煕椤愶絾绀€缁炬儳娼″娲敆閳ь剛绮旈幘顔藉剹婵°倕鎳忛悡銉╂煟閺囩偛鈧湱鈧熬鎷�
婵犵數濮烽弫鎼佸磻閻愬搫鍨傞柛顐f礀缁犱即鏌熺紒銏犳灈缁炬儳顭烽弻鐔煎礈瑜忕敮娑㈡煃闁垮鐏︾紒缁樼洴瀹曞崬螣閸濆嫬袘闂備礁鎼鍡涙偡閳哄懎钃熼柣鏂挎憸閻熷綊鏌涢…鎴濇灈妞ゎ偄娲幃妤€鈻撻崹顔界亖闂佸憡鏌ㄦ鎼佸煡婢舵劖鍋ㄧ紒瀣仢缁愭稑顪冮妶鍡欏缂侇喚濞€瀹曨垰鐣濋埀顒傛閹捐纾兼繛鍡樺焾濡差喖顪冮妶鍡楃仴闁硅櫕锕㈤妴渚€寮介鐐靛€炲銈嗗笒椤︿即寮插⿰鍐炬富闁靛牆妫楃粭鎺楁倵濮樼厧澧撮柟顖氳嫰铻栭柛娑卞枤閸欏棝姊虹紒妯荤闁稿﹤婀遍埀顒佺啲閹凤拷
C闂傚倸鍊搁崐鐑芥嚄閸洖纾块柣銏⑶归悿鐐節婵犲倸鏆熸鐐存崌閺屾稖顦虫い銊ユ嚇瀹曞綊宕掗悙鑼啇闁哄鐗嗘晶浠嬪箖閸忛棿绻嗘い鎰靛亜閻忥繝鏌曢崶褍顏い銏℃礋椤㈡洟濮€閿涘嫪澹曠紓鍌氬€风拋鏌ュ磻閹炬剚鐔嗛悹杞拌閸庢垹绱掗悩鑽ょ暫闁哄瞼鍠栭獮鎴﹀箛椤撶姴娑ч梻渚€娼荤徊鑲╁垝濞嗘挸钃熼柣鏃傗拡閺佸﹦鐥鐐叉Щ濞村吋鍔曢—鍐Χ閸℃ḿ鍙嗙紓浣虹帛钃卞ǎ鍥э躬閹粓鎸婃竟鈹垮姂閺屾洘寰勯崼婵嗗Б濠碘槅鍨介幏锟�