在 LlamaIndex 與 LangChain 之間做選擇:全面指南

在 LlamaIndex 與 LangChain 之間做選擇:全面指南

重點摘要

  • LlamaIndex: 專精於資料攝取、結構化,以及利用私有或領域特定資料來執行進階問答與文件理解等任務。
  • LangChain: 提供一個開源的綜合框架,用於開發、部署和擴展 LLM 應用,支援多樣化的使用案例,包括對話機器人、翻譯和複雜工作流程。
  • 自訂 LLM 整合: 提供詳細的逐步程式碼指南,示範如何在 LlamaIndex 與 LangChain 框架中實作自訂 LLM,並展示各自整合與利用外部 API(例如 Novita AI)的方法。

引言

在人工智慧與自然語言處理快速演進的領域中,有兩個框架已成為開發者在處理大型語言模型(LLM)時的強大工具:LlamaIndex 與 LangChain。本文旨在深入比較 LlamaIndex 與 LangChain,探討其主要功能、使用案例與實際應用。透過剖析各框架的核心功能、定價模式與整合能力,我們將幫助您做出明智的決定,選擇最適合您特定需求的工具。

什麼是 LlamaIndex?

LlamaIndex 是一個精巧的資料框架,旨在為大型語言模型(LLM)提供與上下文相關的、使用者專屬的資料,從而強化 LLM 的能力。與預先訓練於公開資料的通用型 LLM 不同,LlamaIndex 讓這些模型能夠存取和利用私有、領域特定或問題導向的資料,這些資料通常被鎖在 API 後方、資料庫中,或困在 PDF 等非結構化格式裡。

主要功能與能力

  • 資料攝取:LlamaIndex 提供資料連接器,能無縫攝取來自各種來源(包括但不限於 API、PDF 和 SQL 資料庫)的原始格式資料。
  • 資料結構化:它將攝取的資料結構化為中介表示,以利 LLM 高效消費,確保高效能。
  • 自然語言存取:LlamaIndex 提供引擎,讓資料能透過自然語言存取——透過查詢引擎進行問答,透過聊天引擎支援對話互動。
  • 知識工作者:框架包含代理程式,這些代理程式是 LLM 驅動的知識工作者,並配備多種工具,從簡單輔助到複雜 API 整合。
  • 可觀察性與評估:它整合了嚴謹的實驗、評估與監控工具,確保應用程式能持續改進。

使用案例

LlamaIndex 支援多樣化的使用案例,例如:

  • 檢索增強生成(RAG) 用於進階問答系統。
  • 能夠進行有意義、具上下文感知對話的 聊天機器人
  • 從非結構化文件中進行 文件理解 與資料萃取。
  • 能夠進行研究並執行操作的 自主代理
  • 整合文字與圖片等多種資料類型的 多模態應用
  • 對特定資料進行模型微調以提升效能。

什麼是 LangChain?

LangChain 是一個先進的框架,專門設計用來簡化由大型語言模型(LLM)驅動的應用程式的開發、產品化與部署。它提供一整套工具與函式庫,涵蓋 LLM 應用生命週期的每個階段,確保開發流程順暢且高效。

主要功能與能力

  • 開發:LangChain 提供開源建構模組、元件與第三方整合,簡化 LLM 應用程式的建立。LangGraph 是關鍵元件,能建構具狀態的代理,並支援串流資料與人機協作流程。
  • 產品化:LangSmith 是一個強大的工具,用於檢查、監控和評估 LLM 鏈的效能。它能深入洞察應用程式效能,確保持續優化與安心部署。
  • 部署:LangGraph Cloud 可將 LangGraph 應用程式轉換為生產就緒的 API 與助手,方便將 LLM 應用程式擴展並整合到各種系統中。
  • 階層式組織:框架採用階層式組織,各層級元件相互連接,確保應用開發的模組化與靈活性。

開源函式庫

  • langchain-core:提供基礎抽象與 LangChain 表達式語言,作為框架的基礎。
  • langchain-community:整合第三方服務,擴展 LangChain 的能力。
  • 夥伴套件:輕量級套件,如 langchain-openai 和 langchain-anthropic,提供特定整合,增強框架的靈活性。
  • langchain:包含鏈、代理與檢索策略,構成應用的認知架構。
  • LangGraph:用 LLM 建構具狀態多代理應用的強大工具,採用基於圖形的步驟模型,可與 LangChain 整合或獨立使用。
  • LangServe:將 LangChain 鏈部署為 REST API,方便與網頁服務整合。
  • LangSmith:開發者平台,提供除錯、測試、評估與監控 LLM 應用程式的完整工具套件。

目標受眾與使用案例

LangChain 專為各級開發者設計,從新手到專家,只要想在應用程式中利用 LLM 的力量。其模組化與可擴展的架構使其適用於廣泛的使用案例,包括但不限於:

  • 建立對話代理與聊天機器人。
  • 開發語言翻譯與摘要工具。
  • 建立內容生成與分類系統。
  • 使用 LLM 實作複雜工作流程。

LlamaIndex 與 LangChain:主要差異

核心功能:

  • LangChain 是一個綜合框架,旨在簡化使用大型語言模型(LLM)建立資料感知與代理式應用。它提供多種工具來支援各種 LLM 驅動的應用,著重於靈活性與進階 AI 能力。
  • LlamaIndex(原名 GPT Index)是一個專門聚焦於攝取、結構化並存取私有或領域特定資料給 LLM 的資料框架。它簡化了資訊的索引與檢索,非常適合文字搜尋與生成準確回應。

使用案例

  • LangChain 用途廣泛,可用於文字生成、語言翻譯、文字摘要與文字分類等多種應用。由於其卓越的記憶管理與鏈結能力,特別適合維持長時間且上下文相關的對話。
  • LlamaIndex 在需要高品質文字搜尋與回應優先的場景中表現出色。常見使用案例包括內容生成、文件搜尋與檢索、以及聊天機器人與虛擬助手的 LLM 增強。

定價與可用性

  • LangChain 是開源且免費的工具,其原始碼可在 GitHub 等平台上取得,任何人都可以使用。
  • LlamaIndex 是商業產品,其定價依據使用量決定,這意味著可能根據應用中的使用程度而產生費用。

自訂性與靈活性

  • LangChain 提供進階的自訂選項,適合需要根據特定需求微調應用程式的開發者。
  • LlamaIndex 提供使用者友善的功能與工具,促進私有或領域特定資料無縫整合到 LLM 中,專注於易用性與直覺的資料管理。

資料處理

  • LangChain 設計用於處理多種資料類型與來源,提供例如 Schema(用於資料組織)和 Indexes(用於高效資訊檢索)等元件。
  • LlamaIndex 強調能從其他索引組成索引,使其在涉及多個資料來源的複雜查詢與工作流程中非常高效。

整合

  • LangChain 提供與第三方服務的整合,並可透過夥伴套件擴展以支援特定 LLM 提供商。
  • LlamaIndex 提供資料連接器,可無縫整合各種資料來源,提升資料品質與效能。

LlamaIndex 與 LangChain:實際範例比較

參考 Ming 在 Medium 上的文章,以下是 LlamaIndex 與 LangChain 的一些實際範例比較。

使用本地 LLM 建立聊天機器人

以下程式碼範例展示如何使用兩個框架初始化 LLM,以及如何輸出聊天互動的結果。

LlamaIndex 程式碼:

from llama_index.llms import ChatMessage, OpenAILike

llm = OpenAILike(
    api_base="http://localhost:1234/v1",
    timeout=600,
    api_key="loremIpsum",
    is_chat_model=True,
    context_window=32768,
)
chat_history = [
    ChatMessage(role="system", content="You are a bartender."),
    ChatMessage(role="user", content="What do I enjoy drinking?"),
]
output = llm.chat(chat_history)
print(output)

LangChain 程式碼:

from langchain.schema import HumanMessage, SystemMessage
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    openai_api_base="http://localhost:1234/v1",
    request_timeout=600,
    openai_api_key="loremIpsum",
    max_tokens=32768,
)
chat_history = [
    SystemMessage(content="You are a bartender."),
    HumanMessage(content="What do I enjoy drinking?"),
]
print(llm(chat_history))

為本地檔案建立 RAG 系統

以下程式碼片段說明如何載入資料、建立索引並執行查詢。

LlamaIndex 程式碼:

from llama_index import ServiceContext, SimpleDirectoryReader, VectorStoreIndex

service_context = ServiceContext.from_defaults(  
    embed_model="local",  
    llm=llm, # This should be the LLM initialized in the task above.
)  
documents = SimpleDirectoryReader(
    input_dir="mock_notebook/",
).load_data()  
index = VectorStoreIndex.from_documents(  
    documents=documents,
    service_context=service_context,
)
engine = index.as_query_engine(  
    service_context=service_context,  
)
output = engine.query("What do I like to drink?")  
print(output)

LangChain 程式碼:

from langchain_community.document_loaders import DirectoryLoader  
  
# pip install "unstructured[md]"  
loader = DirectoryLoader("mock_notebook/", glob="*.md")  
docs = loader.load()  
  
from langchain.text_splitter import RecursiveCharacterTextSplitter  
  
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)  
splits = text_splitter.split_documents(docs)  
  
from langchain_community.embeddings.fastembed import FastEmbedEmbeddings  
from langchain_community.vectorstores import Chroma  
  
vectorstore = Chroma.from_documents(documents=splits, embedding=FastEmbedEmbeddings())  
retriever = vectorstore.as_retriever()  
  
from langchain import hub  
  
# pip install langchainhub  
prompt = hub.pull("rlm/rag-prompt")  
  
  
def format_docs(docs):  
    return "\n\n".join(doc.page_content for doc in docs)  
  
  
from langchain_core.runnables import RunnablePassthrough  
  
rag_chain = (  
    {"context": retriever | format_docs, "question": RunnablePassthrough()}  
    | prompt  
    | llm # This should be the LLM initialized in the task above.
)  
print(rag_chain.invoke("What do I like to drink?"))

從比較中可以看出,LlamaIndex 專注於 RAG 系統,提供了更簡單的方法,而 LangChain 則提供了更抽象、高層次的方式。

LlamaIndex vs LangChain:如何用 LlamaIndex 使用自訂 LLM?

要將 Novita AI 的 LLM API 與 LlamaIndex 整合,您需要建立一個自訂配接器(adapter),在 LlamaIndex 框架 內包裝 Novita AI API 的呼叫。以下是概念性的範例,展示如何達成此目的。請注意,本範例假設您已具備使用 API 和 LlamaIndex 框架的基本知識。

步驟 1:為 Novita AI LLM 定義自訂配接器

首先,讓我們為 Novita AI LLM 定義自訂配接器:

class NovitaAILLM:
    def __init__(self, api_key):
        from openai import OpenAI
        self.client = OpenAI(api_key=api_key, base_url="https://api.novita.ai/v3/openai")

    def complete_chat(self, messages, stream=False, max_tokens=512):
        response = self.client.chat.completions.create(
            model="Nous-Hermes-2-Mixtral-8x7B-DPO",
            messages=messages,
            stream=stream,
            max_tokens=max_tokens
        )
        return response

步驟 2:整合到 LlamaIndex 服務上下文

接下來,您需要將此配接器整合到 LlamaIndex 的服務上下文中。以下是概念性的範例:

from llama_index import (
    KeywordTableIndex,
    SimpleDirectoryReader,
    ServiceContext,
)
from llama_index.llms import LLM

class NovitaAILLMAdapter(LLM):
    def __init__(self, api_key):
        self.novitailm = NovitaAILLM(api_key)

    def generate_text(self, prompt, stop_sequences=None, **kwargs):
        # Prepare the messages for the chat completion
        messages = [
            {"role": "system", "content": prompt}
        ]
        # Call the Novita AI LLM to complete the chat
        response = self.novitailm.complete_chat(messages)
        if isinstance(response, list):  # If streaming, collect all chunks
            return "".join([chunk.choices[0].delta.content for chunk in response])
        else:
            return response.choices[0].message.content

# Initialize the Novita AI LLM adapter with your API key
novitailm_adapter = NovitaAILLMAdapter(api_key="<YOUR Novita AI API Key>")

# Create the service context with the custom LLM adapter
service_context = ServiceContext.from_defaults(llm=novitailm_adapter)

# Load documents and build the index as before
documents = SimpleDirectoryReader("data").load_data()
index = KeywordTableIndex.from_documents(documents, service_context=service_context)

# Now you can use the index with the custom LLM for queries
query_engine = index.as_query_engine()
response = query_engine.query("What did the author do after his time at Y Combinator?")
print(response)

此範例展示如何為 Novita AI 的 LLM 建立自訂配接器,並將其整合到 LlamaIndex 框架中。您需要將 <YOUR Novita AI API Key> 替換為您在 Novita AI 取得的實際 API 金鑰。

請注意,這僅是概念性範例,可能需要根據您使用的函式庫特定版本以及 Novita AI LLM 的確切 API 細節進行調整。請務必參閱官方文件以取得最準確和最新的資訊。

LlamaIndex vs LangChain:如何用 LangChain 使用自訂 LLM?

要使用 自訂 LLMNovita AI LLM API 與 LangChain 整合,您需要建立一個自訂類別,繼承 LangChain 的 LLM 類別,並使用 Novita AI 的 API 實現其邏輯。

以下是逐步指南:

步驟 1:安裝 OpenAI Python 函式庫

首先,確保您已安裝 OpenAI 函式庫,它將用於與 Novita AI 的 API 互動。

pip install 'openai>=1.0.0'

步驟 2:匯入所需函式庫

從 LangChain 和 OpenAI 函式庫匯入必要模組。

from typing import Any, Dict, Iterator, List, Optional
from langchain_core.callbacks.manager import CallbackManagerForLLMRun
from langchain_core.language_models.llms import LLM
from langchain_core.outputs import GenerationChunk
from openai import OpenAI

步驟 3:定義自訂 LLM 類別

繼承 LLM 類別,建立一個使用 Novita AI API 的自訂 LLM。

class NovitaAILLM(LLM):
    def __init__(self, api_key: str, model_name: str = "Nous-Hermes-2-Mixtral-8x7B-DPO"):
        self.api_key = api_key
        self.model_name = model_name
        self.client = OpenAI(api_key=api_key, base_url="https://api.novita.ai/v3/openai")

    def _call(
        self,
        prompt: str,
        stop: Optional[List[str]] = None,
        run_manager: Optional[CallbackManagerForLLMRun] = None,
        **kwargs: Any,
    ) -> str:
        """Run the LLM on the given input."""
        response = self.client.chat.completions.create(
            model=self.model_name,
            messages=[{"role": "user", "content": prompt}],
            stream=False,
            max_tokens=512,
        )
        return response.choices[0].message.content

    def _stream(
        self,
        prompt: str,
        stop: Optional[List[str]] = None,
        run_manager: Optional[CallbackManagerForLLMRun] = None,
        **kwargs: Any,
    ) -> Iterator[GenerationChunk]:
        """Stream the LLM on the given prompt."""
        response = self.client.chat.completions.create(
            model=self.model_name,
            messages=[{"role": "user", "content": prompt}],
            stream=True,
            max_tokens=512,
        )
        for chunk in response:
            chunk_text = chunk.choices[0].delta.content or ""
            yield GenerationChunk(text=chunk_text)

    @property
    def _identifying_params(self) -> Dict[str, Any]:
        """Return a dictionary of identifying parameters."""
        return {
            "model_name": self.model_name,
        }

    @property
    def _llm_type(self) -> str:
        """Get the type of language model used by this chat model. Used for logging purposes only."""
        return "NovitaAILLM"

步驟 4:初始化並使用自訂 LLM

使用您的 Novita AI API 金鑰建立自訂 LLM 的實例,並用它來生成文字。

# Replace with your actual Novita AI API key
novita_api_key = "<YOUR Novita AI API Key>"

# Initialize the custom LLM
novita_llm = NovitaAILLM(api_key=novita_api_key)

# Generate text
prompt = "Hi there!"
response = novita_llm._call(prompt=prompt)
print(response)

# Or stream the response
for chunk in novita_llm._stream(prompt=prompt):
    print(chunk.text, end="")

這段程式碼設定了一個自訂 LLM,它使用 Novita AI 的 API 根據給定的提示生成文字。_call 方法用於非串流回應,而 _stream 方法用於串流回應。請根據 Novita AI 的 API 文件與您的特定需求調整 model_name 及其他參數。

結論

總之,LlamaIndex 和 LangChain 都是處理大型語言模型的寶貴工具,各有其獨特優勢。LlamaIndex 擅長資料攝取與檢索,非常適合需要高效處理特定資料與進階問答系統的專案。LangChain 則提供更全面的框架來開發與部署 LLM 應用程式,擁有模組化架構與廣泛的整合。兩者的選擇取決於您專案的特定需求。

常見問答

LangChain 和 LlamaIndex 可以一起使用嗎?

可以,這取決於您 LLM 專案的具體需求。

LangChain 適合用於生產環境嗎?

是的,LangChain 0.1 及之後的版本已達到生產就緒狀態。

哪一個更適合 RAG:LlamaIndex 還是 LangChain?

如果您的重點是資料檢索與搜尋能力,建議選擇 LlamaIndex。若您需要一個能處理複雜工作流程的靈活框架,則 LangChain 更適合。

Novita AI 是一個全方位雲端平台,賦予您的 AI 抱負。整合 API、無伺服器、GPU 實例——您所需的成本效益工具。無需管理基礎設施,免費開始,實現您的 AI 願景。

推薦閱讀

如何使用 LangChain 建立您的 LLM:逐步指南

掌握 LangChain 串流:與 LLM 互動的技巧