LangChain框架的出現,有效解決了開發者在構建複雜生成式AI應用時所面臨的諸多挑戰。它提供了一套模組化的抽象概念和工具,涵蓋了與大語言模型(LLM)互動所需的關鍵功能,包含模型輸入輸出、檢索、鏈、代理、記憶體和回撥等。這些模組可以獨立使用,也可以靈活組合,以滿足不同應用場景的需求。LangChain支援Python和TypeScript兩種程式語言,並與多種LLM供應商相容,降低了開發門檻,提升了開發效率。
LangChain:進階文字生成技術的核心框架
隨著生成式AI技術的快速發展,簡單的提示工程技術已不足以應對複雜的AI任務。為瞭解決這些挑戰,LangChain應運而生,成為開發者手中的強大工具。本文將探討LangChain的核心概念、主要功能模組以及環境設定方法。
LangChain簡介
LangChain是一個開源框架,支援Python和TypeScript兩種程式語言。它旨在建立更強大、更具互動性的LLM(大語言模型)應用程式。該框架的核心目標包括:
- 增強資料感知能力:建立語言模型與外部資料來源之間的無縫連線
- 提升代理能力:賦予語言模型與環境互動並產生影響的能力
LangChain的主要功能模組
LangChain提供了一系列模組化的抽象概念,涵蓋了與LLM互動所需的關鍵功能。目前主要包含六大核心模組:
1. Model I/O(模型輸入/輸出)
負責處理與語言模型相關的輸入輸出操作,是與LLM互動的基礎。
2. Retrieval(檢索)
專注於為LLM檢索相關文字,提升模型的資訊取得能力。
3. Chains(鏈)
也稱為LangChain可執行單元,允許構建一系列的LLM操作或函式呼叫,實作複雜任務的自動化處理。
4. Agents(代理)
使鏈能夠根據高層指令或指示決定使用哪些工具,大幅提升了系統的自主決策能力。
5. Memory(記憶)
負責在不同執行之間保持應用程式的狀態,確保連續性和上下文理解。
6. Callbacks(回撥)
允許在特定事件(如生成新token時)執行額外的程式碼,增強了系統的靈活性。
環境設定與安裝
要在本地環境中使用LangChain,需要完成以下步驟:
安裝LangChain
- 使用pip:
pip install langchain langchain-openai
- 使用conda:
conda install -c conda-forge langchain langchain-openai
- 使用pip:
設定虛擬環境(建議)
# 建立虛擬環境 python -m venv venv # 啟動虛擬環境 source venv/bin/activate # 安裝依賴套件 pip install -r requirements.txt
組態模型提供者
- 例如使用OpenAI模型,需要安裝
openai
套件:pip install openai
- 設定環境變數
OPENAI_API_KEY
或在程式碼中直接傳入API金鑰
- 例如使用OpenAI模型,需要安裝
初始化ChatOpenAI模型
from langchain_openai.chat_models import ChatOpenAI # 直接傳入API金鑰(適用於原型開發) chat = ChatOpenAI(api_key="your_api_key_here")
LangChain的優勢與應用場景
LangChain為開發複雜的生成式AI應用提供了強大的支援。其主要優勢包括:
- 模組化設計:各功能模組可獨立使用或組合,靈活性高
- 增強LLM能力:透過與外部資料的連線和代理功能的實作,大幅拓展了LLM的應用範圍
- 簡化開發流程:提供了豐富的抽象層和實作,大大降低了開發複雜AI應用的門檻
透過LangChain,開發者可以更輕鬆地構建諸如:
- 長篇內容摘要
- 具有角色、情節和世界觀的故事生成
- 複雜推理任務
- 具備自主決策能力的AI代理
總之,LangChain代表了當前LLM應用開發的前沿技術,為開發者開啟了通往更複雜、更智慧AI系統的大門。隨著持續的發展和最佳化,LangChain有望在未來的AI應用開發中扮演越來越重要的角色。
內容解密:
本章節介紹了LangChain的基本概念、主要功能模組以及環境設定方法。透過詳細的程式碼範例和實作步驟,讀者可以快速掌握如何在自己的專案中使用LangChain來構建更強大的LLM應用。特別強調了該框架在增強資料感知和代理能力方面的優勢,以及在複雜生成式AI任務中的應用潛力。
隨著生成式AI技術的不斷進步,LangChain作為一個開源框架,將持續演進以滿足日益增長的複雜應用需求。未來可期待的功能包括但不限於:
- 更多模型供應商的整合
- 更強大的代理決策能力
- 更豐富的記憶體管理機制
- 更完善的多模態支援
這些發展將進一步鞏固LangChain在LLM應用開發領域的領先地位,為開發者提供更多創新的可能性。
內容解密:
本段落討論了LangChain未來的發展方向和可能的功能擴充套件。透過分析該框架的發展趨勢,可以預見其在未來將如何持續影響和塑造LLM應用的開發模式,為開發者帶來更多創新的機會和挑戰。
使用 LangChain 進行高效的文字生成與互動式聊天模型
在現代人工智慧(AI)與大語言模型(LLM)的發展中,如何有效地管理和使用 API 金鑰(API keys)成為了一項重要的安全課題。直接在指令碼中硬編碼(hardcoding)API 金鑰並不是一個好的做法,因為這會帶來潛在的安全風險。相反,使用環境變數或設定檔來管理金鑰是一種更為安全和靈活的方法。
LangChain:統一不同模型 API 的框架
在 LLM 的應用中,不同模型之間的 API 介面差異是一個常見的挑戰。這種缺乏標準化的情況會增加提示工程(prompt engineering)的複雜度,並阻礙不同模型之間的無縫整合。而 LangChain 的出現,正是為瞭解決這一問題。
LangChain 提供了一個全面的框架,能夠簡化不同模型之間的介面差異。透過 LangChain,開發者無需針對不同的模型重寫提示或程式碼,從而大大節省了開發時間和資源。LangChain 的平台無關性(platform-agnostic)設計,使其能夠支援多種模型,包括 Anthropic、Vertex AI、OpenAI 和 BedrockChat 等。
聊天模型(Chat Models)
聊天模型,如 GPT-4,已經成為與 OpenAI API 互動的主要方式。與傳統的「輸入文字,輸出文字」的模式不同,聊天模型採用了一種根據訊息(message-based)的互動方式。在 LangChain 中,目前支援的訊息型別包括 AIMessage
、HumanMessage
和 SystemMessage
。
訊息型別詳解
SystemMessage
:代表提供給 AI 系統的指令,用於引導 AI 的行為或動作。HumanMessage
:代表人類使用者與 AI 系統互動的資訊,如問題或指令。AIMessage
:代表 AI 系統本身的回應,通常是對HumanMessage
的回應或SystemMessage
指令的結果。
使用 LangChain 建立一個笑話生成器
from langchain_openai.chat_models import ChatOpenAI
from langchain.schema import AIMessage, HumanMessage, SystemMessage
# 初始化 ChatOpenAI 例項,設定溫度引數為 0.5
chat = ChatOpenAI(temperature=0.5)
# 定義訊息列表
messages = [
SystemMessage(content='''扮演一家新創公司的資深軟體工程師。'''),
HumanMessage(content='''請提供一個關於軟體工程師的有趣笑話。''')
]
# 呼叫聊天模型並取得回應
response = chat.invoke(input=messages)
print(response.content)
輸出範例
當然,這裡有個輕鬆的笑話:
為什麼軟體工程師會破產?
因為他在賭博中輸掉了他的網域名稱,無法負擔續約費用。
程式碼解析
- 首先,匯入必要的模組,包括
ChatOpenAI
、AIMessage
、HumanMessage
和SystemMessage
。 - 建立一個
ChatOpenAI
例項,並設定temperature
引數為 0.5,以控制輸出的隨機性。 - 建立一個訊息列表
messages
,其中包含一個SystemMessage
和一個HumanMessage
。 - 使用
.invoke()
方法呼叫聊天模型,並傳入messages
列表。 - 列印出模型的回應內容。
串流聊天模型(Streaming Chat Models)
在使用 ChatGPT 等聊天模型時,我們經常會觀察到文字逐字逐句地傳回給使用者。這種模式被稱為串流(streaming),它能夠顯著提升聊天應用程式的效能。
for chunk in chat.stream(messages):
print(chunk.content, end="", flush=True)
串流的優勢與挑戰
串流的主要優勢在於它能夠減少使用者的等待時間,並提升互動體驗。然而,這種技術也帶來了一些挑戰,例如在處理串流輸出的過程中,需要即時解析和回應正在生成的訊息內容。
生成多個 LLM 回應
在某些場景下,開發者可能需要生成多個 LLM 回應,例如在創作社交媒體帖子時。LangChain 的 .batch()
方法允許開發者平行傳送多個 API 請求,從而提高效率。
# 建立兩個相同的訊息列表
synchronous_llm_result = chat.batch([messages]*2)
print(synchronous_llm_result)
輸出範例
[AIMessage(content='''當然,這裡有個輕鬆的笑話:
為什麼軟體工程師會破產?
因為他一直忘記 Ctrl+Z 他的開支!'''),
AIMessage(content='''當然,這裡有個輕鬆的笑話:
為什麼軟體工程師偏愛暗黑模式?
因為這樣對他們的「位元」視力比較友善!''')]
LangChain 中的非同步處理與批次處理最佳化
在現代軟體開發中,特別是在涉及大量 API 請求或複雜工作流程的應用程式中,效能最佳化是至關重要的。LangChain 提供了一系列工具和技術來提升應用程式的效能,特別是在批次處理和非同步處理方面。
使用 RunnableConfig 進行批次處理最佳化
LangChain 中的 Runnable
物件提供了 batch
方法,用於平行處理多個輸入。透過 RunnableConfig
,開發者可以精細控制批次處理的行為,特別是並發限制。
from langchain_core.runnables.config import RunnableConfig
# 建立具有所需並發限制的 RunnableConfig
config = RunnableConfig(max_concurrency=5)
# 使用 batch 方法並傳入 config
results = chat.batch([messages, messages], config=config)
內容解密:
RunnableConfig
允許開發者設定max_concurrency
引數,控制同時執行的任務數量。- 適當的並發限制可以避免資源耗盡,同時最大化系統吞吐量。
- 在處理大量 API 請求時,這種控制尤為重要,可以防止觸發伺服器端的速率限制。
非同步函式在 LangChain 中的應用
LangChain 支援非同步(async)函式,使得多個 API 請求可以平行執行,大幅降低整體延遲。
# 使用非同步版本的 invoke 和 batch 方法
results = await chat.ainvoke(messages)
results = await chat.abatch([messages, messages])
內容解密:
- 非同步函式以
a
字首命名,如ainvoke
和abatch
。 - 這些函式允許平行執行多個操作,而不會阻塞主執行緒。
- 在複雜的工作流程中,非同步處理可以顯著提升效能和使用者經驗。
LangChain Prompt Templates 的重要性
隨著 LLM 應用程式規模的擴大,使用 Prompt Templates 成為最佳實踐。這些範本提供了可重複使用的提示結構,並支援引數化。
from langchain_openai.chat_models import ChatOpenAI
from langchain_core.prompts import SystemMessagePromptTemplate, ChatPromptTemplate
template = """
你是一個創意顧問,為企業創作名稱。
請遵循以下原則:
{principles}
請為 {industry} 產業中涉及 {context} 的新創企業生成五個吸引人的名稱。
"""
# 建立 Prompt Template
system_prompt = SystemMessagePromptTemplate.from_template(template)
chat_prompt = ChatPromptTemplate.from_messages([system_prompt])
# 建立 LCEL 鏈
chain = chat_prompt | model
result = chain.invoke({
"industry": "醫療",
"context": "自動總結病歷",
"principles": "1. 簡短易記\n2. 易於發音\n3. 獨特不重複"
})
內容解密:
- Prompt Templates 允許開發者定義可重複使用的提示結構。
- 支援引數化,使得同一個範本可以應用於不同的場景。
- 提供了輸入驗證、多提示組合等進階功能。
- 可以儲存和載入提示範本,方便版本控制和團隊協作。
LangChain Expression Language (LCEL) 的管道運算子
LCEL 是 LangChain 的核心組成部分,它使用管道運算子 |
將不同的元件連線起來,形成資料處理流程。
# 建立 LCEL 鏈
chain = chat_prompt | model
# 呼叫鏈
result = chain.invoke(input_data)
內容解密:
- 管道運算子
|
將前一個元件的輸出作為下一個元件的輸入。 - 這種設計使得構建複雜的工作流程變得簡單直觀。
- 元件的順序非常重要,錯誤的順序可能導致執行錯誤。
商業名稱生成器的實作範例
讓我們建立一個使用 Prompt Template 的商業名稱生成器:
# 定義完整的商業名稱生成器流程
def generate_business_names(industry, context, principles):
# 建立 LCEL 鏈
chain = chat_prompt | model
# 呼叫鏈並傳入引數
result = chain.invoke({
"industry": industry,
"context": context,
"principles": principles
})
return result.content
# 使用範例
industry = "醫療"
context = "建立 AI 解決方案以自動總結病歷"
principles = "1. 每個名稱應簡短易記\n2. 易於發音\n3. 獨特不重複"
names = generate_business_names(industry, context, principles)
print(names)
內容解密:
- 這個範例展示瞭如何將 Prompt Template 和 LCEL 結合使用。
- 透過引數化提示範本,可以為不同的產業和情境生成合適的商業名稱。
- 輸出的格式是經過精心設計的數值列表,便於閱讀和後續處理。
最佳實踐:提供明確的指示和格式規範
在與 LLM 互動時,提供明確的指示和格式規範至關重要。這有助於模型理解任務要求並產生符合預期的輸出。
# 良好的提示範例
"請生成五到七個 {industry} 產業中涉及 {context} 的新創企業名稱,並遵循以下原則:{principles}"
內容解密:
- 明確指定任務目標(生成企業名稱)。
- 提供具體的格式要求(數值列表)。
- 給出評估標準(吸引人、符合產業特點等)。
使用 PromptTemplate 與聊天模型的高階技術
LangChain 提供了一個稱為 PromptTemplate 的傳統範本,需要 input_variables
和 template
引數。這種範本適用於需要結構化輸入的場景,能夠有效地組織和管理提示內容。
PromptTemplate 的基本用法
首先,我們來看看如何使用 PromptTemplate 建立一個系統訊息範本:
from langchain_core.prompts import PromptTemplate
from langchain.prompts.chat import SystemMessagePromptTemplate
from langchain_openai.chat_models import ChatOpenAI
# 定義 PromptTemplate
prompt = PromptTemplate(
template='''You are a helpful assistant that translates {input_language} to {output_language}.''',
input_variables=["input_language", "output_language"],
)
# 建立 SystemMessagePromptTemplate
system_message_prompt = SystemMessagePromptTemplate(prompt=prompt)
# 初始化 ChatOpenAI 模型
chat = ChatOpenAI()
# 呼叫模型並傳入格式化後的訊息
result = chat.invoke(system_message_prompt.format_messages(
input_language="English", output_language="French"
))
print(result)
輸出結果:
AIMessage(content="Vous êtes un assistant utile qui traduit l'anglais en français.", additional_kwargs={}, example=False)
內容解密:
- 我們首先從
langchain_core.prompts
匯入PromptTemplate
,用於建立結構化的提示範本。 - 使用
PromptTemplate
定義了一個翻譯助手的範本,包含input_language
和output_language
兩個變數。 - 透過
SystemMessagePromptTemplate
將PromptTemplate
包裝成系統訊息範本。 - 初始化
ChatOpenAI
模型並呼叫invoke
方法,傳入格式化後的系統訊息。 - 最終輸出結果為法語翻譯的內容。
輸出解析器(Output Parsers)的高階應用
在 LangChain 中,輸出解析器(Output Parsers)提供了一種高層次的抽象,用於從大語言模型(LLM)的字串輸出中解析結構化資料。目前可用的輸出解析器包括:
- 清單解析器(List Parser)
- 日期時間解析器(Datetime Parser)
- 列舉解析器(Enum Parser)
- 自動修復解析器(Auto-fixing Parser)
- Pydantic(JSON)解析器
- 重試解析器(Retry Parser)
- 結構化輸出解析器(Structured Output Parser)
- XML 解析器
這些解析器提供了兩個重要的功能:
.get_format_instructions()
:提供必要的指令以輸出可被解析的結構化格式。.parse(llm_output: str)
:負責將 LLM 的輸出解析為預定義的格式。
使用 Pydantic(JSON)解析器的範例
Pydantic 解析器利用了 Python 中的 Pydantic 函式庫,提供了根據 Python 型別註解的資料驗證功能。
from langchain_core.prompts.chat import (
ChatPromptTemplate,
SystemMessagePromptTemplate,
)
from langchain_openai.chat_models import ChatOpenAI
from langchain.output_parsers import PydanticOutputParser
from pydantic.v1 import BaseModel, Field
from typing import List
# 定義資料模型
class BusinessName(BaseModel):
name: str = Field(description="The name of the business")
rating_score: float = Field(description='''The rating score of the business. 0 is the worst, 10 is the best.''')
class BusinessNames(BaseModel):
names: List[BusinessName] = Field(description='''A list of business names''')
# 初始化 PydanticOutputParser
parser = PydanticOutputParser(pydantic_object=BusinessNames)
# 定義生成商業名稱的原則
principles = """
- The name must be easy to remember.
- Use the {industry} industry and Company context to create an effective name.
- The name must be easy to pronounce.
- You must only return the name without any other text or characters.
- Avoid returning full stops, \n, or any other characters.
- The maximum length of the name must be 10 characters.
"""
# 定義聊天範本
template = """Generate five business names for a new start-up company in the {industry} industry.
You must follow the following principles: {principles}
{format_instructions}
"""
# 建立 SystemMessagePromptTemplate 和 ChatPromptTemplate
system_message_prompt = SystemMessagePromptTemplate.from_template(template)
chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt])
# 初始化 ChatOpenAI 模型並建立 LCEL 鏈
model = ChatOpenAI(temperature=0.0)
prompt_and_model = chat_prompt | model
# 呼叫模型並解析輸出
result = prompt_and_model.invoke(
{
"principles": principles,
"industry": "Data Science",
"format_instructions": parser.get_format_instructions(),
}
)
# 解析輸出結果
parsed_result = parser.parse(result.content)
print(parsed_result)
輸出結果:
names=[BusinessName(name='DataWiz', rating_score=8.5), BusinessName(name='InsightIQ', rating_score=9.2), BusinessName(name='AnalytiQ', rating_score=7.8), BusinessName(name='SciData', rating_score=8.1), BusinessName(name='InfoMax', rating_score=9.5)]
內容解密:
- 我們定義了兩個 Pydantic 模型:
BusinessName
和BusinessNames
,用於結構化商業名稱及其評分。 - 使用
PydanticOutputParser
初始化一個解析器,將輸出解析為BusinessNames
物件。 - 定義了一個生成商業名稱的聊天範本,包含行業、原則和格式指令等變數。
- 建立了一個 LCEL 鏈,將聊天提示、模型呼叫和輸出解析串聯起來。
- 呼叫模型並傳入格式化後的輸入,最終解析輸出結果為結構化的商業名稱列表。
將輸出解析器整合到 LCEL 鏈中
我們可以直接將輸出解析器新增到 LCEL 鏈中,簡化呼叫流程:
chain = chat_prompt | model | parser
result = chain.invoke(
{
"principles": principles,
"industry": "Data Science",
"format_instructions": parser.get_format_instructions(),
}
)
print(result)
輸出結果:
names=[BusinessName(name='DataTech', rating_score=9.5), ...]
內容解密:
- 將輸出解析器直接整合到 LCEL 鏈中,實作端對端的處理流程。
- 鏈條負責提示格式化、模型呼叫和輸出解析,大幅簡化了程式碼邏輯。