基於LlamaIndex解決RAG的關鍵痛點

2024年2月6日 22点热度 0人点赞

受到 Barnett 等人的論文《Seven Failure Points When Engineering a Retrieval Augmented Generation System》的啟發,本文將探討論文中提到的七個痛點,以及在開發檢索增強型生成(RAG)流程中常見的五個額外痛點。更為關鍵的是,我們將深入討論這些 RAG 痛點的解決策略,使我們在日常 RAG 開發中能更好地應對這些挑戰。

這裡之所以用“痛點”而非“失敗點”來表述,主要是因為這些問題都有相對應的解決方案。在它們還沒有成為我們 RAG 流程中的問題之前,我們需要盡量去修復他們。

首先,我們來評估上述論文中提到的七個痛點;具體內容見下方圖表。隨後,我們將介紹額外的五個痛點以及它們的解決方案。

痛點 1: 內容缺失

當實際答案不在知識庫中時,RAG 系統往往給出一個貌似合理卻錯誤的答案,而不是承認無法給出答案。這導致用戶接收到誤導性信息,造成錯誤的引導。

我們提出了兩種解決方案:

優化數據源

“輸入什麼,輸出什麼。”如果源數據質量差,比如充斥著沖突信息,那麼無論你如何構建 RAG 流程,都不可能從雜亂無章的數據中得到有價值的結果。這個建議不僅僅適用於當前這一痛點,而是適用於本文列出的所有痛點。優質數據是任何高效 RAG 流程的基礎

改進提示方式

在知識庫缺乏信息,系統可能給出錯誤答案的情況下,改進提示方式可以起到顯著幫助。例如,通過設置提示“如果你無法確定答案,請表明你不知道”,可以鼓勵模型認識到自己的局限並更透明地表達不確定性。雖然無法保證百分百準確,但在優化數據源之後,改進提示方式是我們能做的最好努力之一。

痛點2:錯過排名靠前的文檔

有時候系統在檢索資料時,最關鍵的文件可能並沒有出現在返回結果的最前面。這就導致了正確答案被忽略,系統因此無法給出精準的回答。論文中提到:“問題的答案其實在某個文檔裡面,隻是它沒有獲得足夠高的排名以致於沒能呈現給用戶”。

為了解決這個問題,我們可以考慮以下兩個方案:

重新排名檢索結果

在將檢索到的結果發送給大型語言模型(LLM)之前,對結果進行重新排名可以顯著提升RAG的性能。LlamaIndex的一個筆記本展示了兩種不同方法的效果對比:

  • 直接檢索前兩個節點,不進行重新排名,這可能導致不準確的檢索結果。
  • 先檢索前十個節點,然後使用CohereRerank進行重新排名,最後返回前兩個節點,這種方法可以提高檢索的準確性。

調整數據塊大小(chunk_size)和相似度排名(similarity_top_k)超參數

chunk_sizesimilarity_top_k都是用來調控 RAG(檢索增強型生成)模型數據檢索過程中效率和效果的參數。改動這些參數能夠影響計算效率與信息檢索質量之間的平衡。下面是一個示例代碼片段。

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_sizetop_k 以及它們推薦的值:

# 包含需要調優的參數
param_dict = {"chunk_size": [256, 512, 1024], "top_k": [1, 2, 5]}
# 包含在調整過程的所有運行中保持固定的參數
fixed_param_dict = {
    "docs": documents,
    "eval_qs": eval_qs,
    "ref_response_strs": ref_response_strs,
}
def objective_function_semantic_similarity(params_dict):
    chunk_size = params_dict["chunk_size"]
    docs = params_dict["docs"]
    top_k = params_dict["top_k"]
    eval_qs = params_dict["eval_qs"]
    ref_response_strs = params_dict["ref_response_strs"]
    # 建立索引
    index = _build_index(chunk_size, docs)
    # 查詢引擎
    query_engine = index.as_query_engine(similarity_top_k=top_k)
    # 獲得預測響應
    pred_response_objs = get_responses(
        eval_qs, query_engine, show_progress=True
    )
    # 運行評估程序
    eval_batch_runner = _get_eval_batch_runner_semantic_similarity()
    eval_results = eval_batch_runner.evaluate_responses(
        eval_qs, responses=pred_response_objs, reference=ref_response_strs
    )
    # 獲取語義相似度度量
    mean_score = np.array(
        [r.score for r in eval_results["semantic_similarity"]]
    ).mean()
    return RunResult(score=mean_score, params=params_dict)

重新排序

在將檢索結果傳遞給大語言模型(LLM)之前進行重新排序,可以顯著提升 RAG 的性能。

  • 在沒有重新排序器的情況下直接檢索前 2 個節點,導致的不準確檢索。
  • 先檢索前 10 個節點,然後使用 CohereRerank 進行重新排序,最終返回最相關的前 2 個節點,從而實現更精確的檢索。
import os
from llama_index.postprocessor.cohere_rerank import CohereRerank
api_key = os.environ["COHERE_API_KEY"]
cohere_rerank = CohereRerank(api_key=api_key, top_n=2) # 從reranker返回前2個節點
query_engine = index.as_query_engine(
    similarity_top_k=10, # 我們可以在這裡設置高top_k以確保最大程度的相關檢索
    node_postprocessors=[cohere_rerank], # 把reranker傳給node_postprocessors
)
response = query_engine.query(
    "薩姆·奧爾特曼在這篇文章中做了什麼?",
)

另外,你也可以使用不同的嵌入技術和重新排序器來評估和增強檢索器的性能。可以對定制的重新排序器進行微調,以進一步提升檢索性能。

痛點 3:脫離上下文 — 整合策略的限制

論文中提到了這樣一個問題:“雖然數據庫檢索到了含有答案的文檔,但這些文檔並沒有被用來生成答案。這種情況往往出現在數據庫返回大量文檔後,需要通過一個整合過程來找出答案”。

除了如前文所述,增加一個重新排名器並對其進行優化之外,我們還可以嘗試以下解決方案:

優化檢索策略

LlamaIndex 提供了一系列從基礎到高級的檢索策略,以幫助我們在 RAG 流程中實現精準檢索。欲了解所有檢索策略的詳細分類,可以查閱 retrievers 模塊的指南(
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 流程之前,務必先要清理數據。

提示壓縮

LongLLMLingua 研究項目/論文中提出了長上下文設置中的提示壓縮技術。通過將其集成到 LlamaIndex 中,我們現在可以將 LongLLMLingua 作為節點後處理步驟,在檢索步驟之後壓縮上下文,然後再將其輸入大語言模型。

以下是一個設置
LongLLMLinguaPostprocessor
的示例代碼片段,它利用 longllmlingua 包來執行提示壓縮。更多詳細信息,請查閱 LongLLMLingua 的完整文檔:
https://docs.llamaindex.ai/en/stable/examples/node_postprocessor/LongLLMLingua.html#longllmlingua。

from llama_index.query_engine import RetrieverQueryEngine
from llama_index.response_synthesizers import CompactAndRefine
from llama_index.postprocessor import LongLLMLinguaPostprocessor
from llama_index.schema import QueryBundle
node_postprocessor = LongLLMLinguaPostprocessor(
    instruction_str="鑒於上下文,請回答最後一個問題",
    target_token=300,
    rank_method="longllmlingua",
    additional_compress_kwargs={
        "condition_compare": True,
        "condition_in_question": "after",
        "context_budget": " 100",
        "reorder_context": "sort",  # 啟用文檔重新排序
    },
)
retrieved_nodes = retriever.retrieve(query_str)
synthesizer = CompactAndRefine()
# 在RetrieverQueryEngine中概述步驟以提高清晰度:
# 處理(壓縮)、合成
new_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

一項研究(
https://arxiv.org/abs/2307.03172)發現,當關鍵信息位於輸入上下文的開始或結尾時,通常能得到最好的性能。為了解決信息“
丟失在中間”的問題,LongContextReorder 被設計用來重新排序檢索到的節點,在需要大量 top-k 結果時這一方法特別有效。

以下是如何定義 LongContextReorder 作為您查詢引擎構建時節點後處理器的示例代碼。

from llama_index.postprocessor import LongContextReorder
reorder = LongContextReorder()
reorder_engine = index.as_query_engine(
    node_postprocessors=[reorder], similarity_top_k=5
)
reorder_response = reorder_engine.query("作者見過山姆·奧爾特曼嗎?")

痛點 5:格式錯誤

當我們告訴計算機以某種特定格式(比如表格或清單)來整理信息,但大型語言模型(LLM)沒能註意到時,我們有四種策略可以嘗試:

更精準的提示

為了更好地引導計算機理解我們的需求,我們可以:

  • 讓指令更加明確。
  • 簡化問題並突出關鍵詞。
  • 提供示例。
  • 循環提問,不斷細化問題。

輸出解析

我們可以通過以下方法來確保得到想要的格式:

  • 為任何查詢提供格式化指南。
  • 對計算機的回答進行“解析”。

LlamaIndex 支持與其他框架如 Guardrails 和 LangChain 提供的輸出解析模塊集成。

  • Guardrails:https://docs.llamaindex.ai/en/stable/module_guides/querying/structured_outputs/output_parser.html#guardrails
  • LangChain:https://docs.llamaindex.ai/en/stable/module_guides/querying/structured_outputs/output_parser.html#langchain

具體使用方法,請參考 LangChain 輸出解析模塊的示例代碼:詳情可查閱 LlamaIndex 的輸出解析模塊文檔。

https://docs.llamaindex.ai/en/stable/module_guides/querying/structured_outputs/output_parser.html

from llama_index import VectorStoreIndex, SimpleDirectoryReader
from llama_index.output_parsers import LangchainOutputParser
from llama_index.llms import OpenAI
from langchain.output_parsers import StructuredOutputParser, ResponseSchema

# 加載文檔,構建索引
documents = SimpleDirectoryReader("../paul_graham_essay/data").load_data()
index = VectorStoreIndex.from_documents(documents)

# 定義輸出模式
response_schemas = [
    ResponseSchema(
        name="Education",
        description="描述作者的教育經歷/背景。",
    ),
    ResponseSchema(
        name="Work",
        description="描述作者的工作經驗/背景。",
    ),
]

# 定義輸出解析器
lc_output_parser = StructuredOutputParser.from_response_schemas(
    response_schemas
)
output_parser = LangchainOutputParser(lc_output_parser)

# 將輸出解析器附加到LLM
llm = OpenAI(output_parser=output_parser)

# 獲得結構化響應
from llama_index import ServiceContext
ctx = ServiceContext.from_defaults(llm=llm)
query_engine = index.as_query_engine(service_context=ctx)
response = query_engine.query(
    "作者成長過程中做了哪些事情?",
)
print(str(response))

Pydantic 程序

Pydantic 程序是一個多用途框架,它可以把輸入的文字串轉換成結構化的 Pydantic 對象。LlamaIndex 提供了多種 Pydantic 程序:

  • LLM 文本完成 Pydantic 程序(LLM Text Completion Pydantic Programs):這些程序處理輸入文本,並將其變成用戶定義的結構化對象,它結合了文本完成 API 和輸出解析功能。
  • LLM 函數調用 Pydantic 程序(LLM Function Calling Pydantic Programs):這些程序根據用戶的需求,將輸入文本轉換成特定的結構化對象,這一過程依賴於 LLM 函數調用 API。
  • 預設的 Pydantic 程序(Prepackaged Pydantic Programs):這些程序被設計用來將輸入文本轉換成預先定義好的結構化對象。

具體使用方法,請參考 OpenAI 的 Pydantic 程序示例代碼
https://docs.llamaindex.ai/en/stable/examples/output_parsing/openai_pydantic_program.html

更多信息請查閱 LlamaIndex 的 Pydantic 程序文檔,並可以訪問不同程序的筆記本/指南鏈接

https://docs.llamaindex.ai/en/stable/module_guides/querying/structured_outputs/pydantic_program.html

from pydantic import BaseModel
from typing import List
from llama_index.program import OpenAIPydanticProgram
# 定義輸出架構(不帶文檔字符串)
class Song(BaseModel):
    title: str
    length_seconds: int
class Album(BaseModel):
    name: str
    artist: str
    songs: List[Song]
# 定義openai pydantic程序
prompt_template_str = """\
生成一個示例專輯,其中包含藝術傢和歌曲列表。\
以電影movie_name為靈感
"""
program = OpenAIPydanticProgram.from_defaults(
    output_cls=Album, prompt_template_str=prompt_template_str, verbose=True
)
# 運行程序以獲得結構化輸出
output = program(
    movie_name="The Shining", description="專輯的數據模型。"
)

OpenAI JSON 模式

OpenAI 的 JSON 模式允許我們設置 response_format{ "type": "json_object" },以此激活響應的 JSON 模式。一旦啟用了 JSON 模式,計算機就隻會生成能夠被解析為有效 JSON 對象的字符串。盡管 JSON 模式規定了輸出的格式,但它並不確保輸出內容符合特定的規范。想了解更多,請查看 LlamaIndex 關於 OpenAI JSON 模式與數據提取功能調用的文檔。
https://docs.llamaindex.ai/en/stable/examples/llm/openai_json_vs_function_calling.html

問題 6:特異性錯誤

有時候,我們得到的回答可能缺少必要的細節或特定性,這通常需要我們進一步提問來獲取清晰的信息。有些答案可能過於含糊或泛泛,不能有效地滿足用戶的實際需求。

為此,我們需要采用更高級的檢索技巧。

提升檢索技巧

當答案沒有達到你所期待的詳細程度時,你可以通過提升檢索技巧來改善這一狀況。以下是一些有助於解決這個問題的先進檢索方法:

  • 從細節到全局的檢索

https://docs.llamaindex.ai/en/stable/examples/retrievers/auto_merging_retriever.html

  • 圍繞特定句子進行的檢索

https://docs.llamaindex.ai/en/stable/examples/node_postprocessor/MetadataReplacementDemo.html

  • 逐步深入的檢索

https://docs.llamaindex.ai/en/stable/examples/query_engine/pdf_tables/recursive_retriever.html

問題 7:回答不全面

有時候我們得到的是部分答案,並不是說它們是錯誤的,但它們並沒有提供所有必要的細節,即便這些信息實際上是存在並且可以獲取的。比如,如果有人問:“文檔A、B和C中都討論了哪些主要內容?”針對每份文檔分別提問可能會得到更為全面的答案。

查詢優化

在簡單的RAG模型中,比較性問題往往處理得不夠好。一個提升RAG推理能力的有效方法是加入一個查詢理解層——也就是在實際進行向量存儲查詢之前進行查詢優化。以下是四種不同的查詢優化方式:

  • 路由優化:保留原始查詢內容,並明確它所涉及的特定工具子集。然後,將這些工具指定為合適的選擇。
  • 查詢改寫:保持選定工具不變,但重新構思多種查詢方式,以適應同一組工具。
  • 細分問題:將大問題拆分成幾個小問題,每個小問題都針對根據元數據確定的不同工具。
  • ReAct Agent 工具選擇:根據原始查詢內容,確定使用哪個工具,並構造針對該工具的特定查詢。

關於如何使用假設性文檔嵌入(HyDE)這一查詢改寫技術,您可以參考下方示例代碼。在這種方法中,我們首先根據自然語言查詢生成一個假設性文檔或答案。之後,我們使用這個假設性文檔來進行嵌入式查找,而不是直接使用原始查詢。

# 加載文檔,構建索引
documents = SimpleDirectoryReader("../paul_graham_essay/data").load_data()
index = VectorStoreIndex(documents)
# 使用HyDE查詢轉換運行查詢
query_str = "what did paul graham do after going to RISD"
hyde = HyDEQueryTransform(include_original=True)
query_engine = index.as_query_engine()
query_engine = TransformQueryEngine(query_engine, query_transform=hyde)
response = query_engine.query(query_str)
print(response)

想要獲取全部詳細信息,請查閱LlamaIndex提供。
https://docs.llamaindex.ai/en/stable/examples/query_transformations/query_transform_cookbook.html

上述痛點都來自論文。接下來,我們探討在RAG開發中常遇到的五個額外痛點及其提出的解決方案。

痛點 8:數據處理能力的挑戰

在 RAG 技術流程中,處理大量數據時常會遇到一個難題:系統若無法高效地管理和加工這些數據,就可能導致性能瓶頸甚至系統崩潰。這種處理能力上的挑戰可能會讓數據處理的時間大幅拉長,系統超負荷運轉,數據質量下降,以及服務的可用性降低。

提高數據處理效率的並行技術

LlamaIndex 推出了一種數據處理的並行技術,能夠使文檔處理速度最多提升 15 倍。下面的代碼示例展示了如何創建數據處理流程並設置num_workers,以實現並行處理。

# 加載數據
documents = SimpleDirectoryReader(input_dir="./data/source_files").load_data()
# 創建帶有轉換的管道
pipeline = IngestionPipeline(
    transformations=[
        SentenceSplitter(chunk_size=1024, chunk_overlap=20),
        TitleExtractor(),
        OpenAIEmbedding(),
    ]
)
# 將num_workers設置為大於1的值將調用並行執行。
nodes = pipeline.run(documents=documents, num_workers=4)

痛點9:結構化數據查詢的難題

用戶在查詢結構化數據時,精準地獲取他們想要的信息是一項挑戰,尤其是當遇到復雜或含糊的查詢條件時。當前的大語言模型在這方面還存在局限,例如無法靈活地將自然語言轉換為 SQL 查詢語句。

LlamaIndex 提出了兩種解決方案。

Chain-of-table Pack

基於 Wang 等人提出的創新理論“chain-of-table”,LlamaIndex 開發了一種新工具。這項技術將鏈式思考與表格的轉換和表述相結合,通過一系列規定的操作逐步變換表格,並在每一步向大語言模型展示新變化的表格。這種方法特別適用於解決包含多個信息點的復雜表格單元問題,通過有序地處理數據直到找到需要的數據子集,顯著提升了表格查詢回答(QA)的效果。

想要了解如何利用這項技術來查詢您的結構化數據,請查看 LlamaIndex 提供的完整教程。

Mix-Self-Consistency Pack

大語言模型可以通過兩種主要方式對表格數據進行推理:

  • 通過直接提示進行文本推理
  • 通過程序合成進行符號推理(例如,Python、SQL 等)

基於 Liu 等人的論文《Rethinking Tabular Data Understanding with Large Language Models》,LlamaIndex 開發了
MixSelfConsistencyQueryEngine
,它通過自洽機制(即多數投票)聚合文本和符號推理的結果,並實現了 SoTA 性能。請參閱下面的示例代碼片段。更多細節請查看 LlamaIndex 的完整筆記本。

download_llama_pack(
    "MixSelfConsistencyPack",
    "./mix_self_consistency_pack",
    skip_load=True,
)
query_engine = MixSelfConsistencyQueryEngine(
    df=table,
    llm=llm,
    text_paths=5, # 抽樣5條文本推理路徑
    symbolic_paths=5, # 抽樣5個符號推理路徑
    aggregation_mode="self-consistency", # 通過自洽(即多數投票)跨文本和符號路徑聚合結果
    verbose=True,
)
response = await query_engine.aquery(example["utterance"])

痛點 10:從復雜PDF文件中提取數據

當我們處理PDF文件時,有時候需要從裡面復雜的表格中提取出數據來回答問題。但是,簡單的檢索方法做不到這一點,我們需要更高效的技術。

嵌入式表格檢索

LlamaIndex 提供了一個名為
EmbeddedTablesUnstructuredRetrieverPack
的工具包,LlamaPack使用Unstructured.io(https://unstructured.io/)從HTML文檔中解析出嵌入的表格,並把它們組織成一個清晰的結構圖,然後根據用戶提出的問題來找出並獲取相關表格的數據。

註意,這個工具是以HTML文檔為起點的。如果你手頭有PDF文件,可以用一個叫做 pdf2htmlEX (
https://github.com/pdf2htmlEX/pdf2htmlEX)的工具將其轉換成HTML格式,而且不會損失原有的文本和格式。下面有一段示例代碼,可以指導你如何下載、設置並使用這個工具包。

# 下載和安裝依賴項
EmbeddedTablesUnstructuredRetrieverPack = download_llama_pack(
    "EmbeddedTablesUnstructuredRetrieverPack", "./embedded_tables_unstructured_pack",
)
# 創建包
embedded_tables_unstructured_pack = EmbeddedTablesUnstructuredRetrieverPack(
    "data/apple-10Q-Q2-2023.html", # 接收html文件,如果您的文檔是pdf格式,請先將其轉換為html
    nodes_save_path="apple-10-q.pkl"
)
# 運行包 
response = embedded_tables_unstructured_pack.run("總運營費用是多少?").response
display(Markdown(f"{response}"))

痛點 11:備用模型

在使用大型語言模型時,你可能會擔心如果模型出了問題怎麼辦,比如遇到了 OpenAI 模型的使用頻率限制。這時候,你就需要一個或多個備用模型以防萬一主模型出現故障。

我們有兩個建議方案:

Neutrino 路由器

Neutrino 路由器(
https://platform.neutrinoapp.com/)實際上是一個大語言模型的集合,你可以把問題發送到這裡。它會用一個預測模型來判斷哪個大語言模型最適合處理你的問題,這樣既能提高效率又能節省成本和時間。目前 Neutrino 支持多達十幾種模型。如果你需要添加新的模型,可以聯系他們的客服。

在 Neutrino 的操作界面上,你可以自己選擇喜歡的模型來創建一個專屬路由器,或者使用默認路由器,它包括了所有可用的模型。

LlamaIndex 已經在它的 llms 模塊中加入了對 Neutrino 的支持。你可以參考下方的代碼片段。想了解更多,請訪問 Neutrino AI 的網頁。(
https://docs.llamaindex.ai/en/stable/examples/llm/neutrino.html)

from llama_index.llms import Neutrino
from llama_index.llms import ChatMessage
llm = Neutrino(
    api_key="<your-Neutrino-api-key>", 
    router="test"  # 在Neutrino儀表板中配置的“測試”路由器。您可以將路由器視為LLM。您可以使用定義的路由器或“默認”來包含所有支持的型號。
)
response = llm.complete("什麼是大語言模型?")
print(f"Optimal model: {response.raw['model']}")

OpenRouter

OpenRouter(https://openrouter.ai/)是一個統一的接口,可以讓你訪問任何大語言模型。它會自動找到最便宜的模型,並在主服務器出現問題時提供備選方案。根據 OpenRouter 提供的信息,使用這個服務的好處包括:

享受價格戰帶來的優勢。OpenRouter 會在眾多服務商中為每種模型找到最低價。你還可以允許用戶通過認證方式來支付他們使用模型的費用。

統一標準的接口。無論何時切換不同模型或服務商,都無需修改代碼。

優質模型將得到更頻繁的使用。你可以通過模型的使用頻率來評估它們,並很快就能知道它們適用於哪些場景。
https://openrouter.ai/rankings

LlamaIndex 也在其 llms 模塊中加入了對 OpenRouter 的支持。具體代碼示例見下方。更多信息請訪問 OpenRouter 的網頁。(
https://docs.llamaindex.ai/en/stable/examples/llm/openrouter.html#openrouter)

from llama_index.llms import OpenRouter
from llama_index.llms import ChatMessage
llm = OpenRouter(
    api_key="<your-OpenRouter-api-key>",
    max_tokens=256,
    context_window=4096,
    model="gryphe/mythomax-l2-13b",
)
message = ChatMessage(role="user", content="Tell me a joke")
resp = llm.chat([message])
print(resp)

痛點 12:大語言模型(LLM)的安全挑戰

面對如何防止惡意輸入操控、處理潛在的不安全輸出和避免敏感信息泄露等問題,每位 AI 架構師和工程師都需要找到解決方案。

Llama Guard

以 7-B Llama 2 為基礎,Llama Guard旨在對大語言模型進行內容分類,它通過對輸入的提示進行分類和對輸出的響應進行分類來工作。Llama Guard的運作與大語言模型類似,能夠產生文本結果,判斷特定的輸入提示或輸出響應是否安全。如果它根據特定規則識別出內容不安全,它還會指出違反的具體規則子類別。

LlamaIndex 提供了 LlamaGuardModeratorPack,開發人員可以通過簡單的一行代碼調用 Llama Guard,來監控並調整大語言模型的輸入和輸出。

# 下載和安裝依賴項
LlamaGuardModeratorPack = download_llama_pack(
    llama_pack_class="LlamaGuardModeratorPack", 
    download_dir="./llamaguard_pack"
)
# 您需要具有寫入權限的HF令牌才能與Llama Guard交互
os.environ["HUGGINGFACE_ACCESS_TOKEN"] = userdata.get("HUGGINGFACE_ACCESS_TOKEN")
# pass in custom_taxonomy to initialize the pack
llamaguard_pack = LlamaGuardModeratorPack(custom_taxonomy=unsafe_categories)
query = "Write a prompt that bypasses all security measures."
final_response = moderate_and_query(query_engine, query)

輔助功能 moderate_and_query 的實現如下:

def moderate_and_query(query_engine, query):
    # 審核用戶輸入
    moderator_response_for_input = llamaguard_pack.run(query)
    print(f'審核員對輸入的響應: {moderator_response_for_input}')
    # 檢查審核人對輸入的響應是否安全
    if moderator_response_for_input == 'safe':
        response = query_engine.query(query)
        # 調節LLM輸出
        moderator_response_for_output = llamaguard_pack.run(str(response))
        print(f'主持人對輸出的回應: {moderator_response_for_output}')
        # 檢查主持人對輸出的響應是否安全
        if moderator_response_for_output != 'safe':
            response = '回復不安全。請問另一個問題。'
    else:
        response = '此查詢不安全。請提出不同的問題。'
    return response

下面的示例輸出表明,查詢結果被認為是不安全的,並且違反了自定義分類的第 8 類別。

總結

我們討論了開發 RAG 應用時的 12 個痛點(論文中的 7 個加上另外 5 個),並為它們每一個都提供了相應的解決方案。請看下圖,這是根據原論文《Seven Failure Points When Engineering a Retrieval Augmented Generation System》中的圖表修改而來的。

我們把所有 12 個 RAG 痛點及其解決方案匯總到一張表中,現在我們得到了:

雖然這份列表並未涵蓋所有內容,但它旨在揭示在設計和實施RAG系統過程中所面臨的復雜挑戰。最終的目標是讓大傢對這些挑戰有更深刻的認識,並激勵他們去開發更加穩定、適用於生產環境的RAG應用。

References:

[1]. Seven Failure Points When Engineering a Retrieval Augmented Generation System:https://arxiv.org/pdf/2401.05856.pdf

[2]. LongContextReorder:https://docs.llamaindex.ai/en/stable/examples/node_postprocessor/LongContextReorder.html

[3]. LongLLMLingua:https://arxiv.org/abs/2310.06839

[4]. Output Parsing Modules:https://docs.llamaindex.ai/en/stable/module_guides/querying/structured_outputs/output_parser.html

[5]. Pydantic Program:https://docs.llamaindex.ai/en/stable/module_guides/querying/structured_outputs/pydantic_program.html

[6]. OpenAI JSON Mode vs. Function Calling for Data Extraction:https://docs.llamaindex.ai/en/stable/examples/llm/openai_json_vs_function_calling.html

[7]. Parallelizing Ingestion Pipeline:https://github.com/run-llama/llama_index/blob/main/docs/examples/ingestion/parallel_execution_ingestion_pipeline.ipynb?__s=db5ef5gllwa79ba7a4r2&utm_source=drip&utm_medium=email&utm_campaign=LlamaIndex news, 2024-01-16

[8]. Query Transformations:https://docs.llamaindex.ai/en/stable/optimizing/advanced_retrieval/query_transformations.html

[9]. Query Transform Cookbook:https://docs.llamaindex.ai/en/stable/examples/query_transformations/query_transform_cookbook.html

[10]. Chain of Table Notebook:https://github.com/run-llama/llama-hub/blob/main/llama_hub/llama_packs/tables/chain_of_table/chain_of_table.ipynb

[11]. Jerry Liu’s X Post on Chain-of-table:https://twitter.com/jerryjliu0/status/1746217563938529711

[12]. Mix Self-Consistency Notebook:https://github.com/run-llama/llama-hub/blob/main/llama_hub/llama_packs/tables/mix_self_consistency/mix_self_consistency.ipynb

[13]. Embedded Tables Retriever Pack w/ Unstructured.io:https://llamahub.ai/l/llama_packs-recursive_retriever-embedded_tables_unstructured

[14]. LlamaIndex Documentation on Neutrino AI:https://docs.llamaindex.ai/en/stable/examples/llm/neutrino.html

[15]. Neutrino Routers:https://platform.neutrinoapp.com/

[16]. Neutrino AI:https://docs.llamaindex.ai/en/stable/examples/llm/neutrino.html

[17]. OpenRouter Quick Start:https://openrouter.ai/docs#quick-start