LangChain 提供了便捷的工具,像是 TextSplitter 和 LLMChain,方便開發者進行文字分割和任務分解,提升大語言模型的處理效率。TextSplitter 能將長文字分割成適合 LLM 處理的區塊,而 LLMChain 則能將 LLM 與其他功能模組串聯,實作更複雜的應用。在處理長文字或需要多步驟邏輯的任務時,這些工具能有效簡化開發流程。更進一步,可以利用提示鏈(Prompt Chaining)的概念,將多個提示串聯起來,引導 LLM 完成更複雜的任務,例如角色生成、情節生成、場景生成等。每個提示都專注於一個子任務,讓 LLM 更有效率地生成所需內容。
結合 LangChain 實作文字分割和任務分解
LangChain 提供了多種工具和技術,可以用於實作文字分割和任務分解。例如,可以使用 TextSplitter 類別實作文字分割,可以使用 LLMChain 類別實作任務分解。
from langchain import TextSplitter, LLMChain
text_splitter = TextSplitter(chunk_size=300)
llm_chain = LLMChain(llm=llm)
texts = text_splitter.split_text(text)
outputs = llm_chain(texts)
內容解密:
上述程式碼展示瞭如何使用 LangChain 實作文字分割和任務分解。首先,建立一個 TextSplitter 物件,用於實作文字分割。然後,建立一個 LLMChain 物件,用於實作任務分解。最後,使用 TextSplitter 將文字分割成更小的塊,然後使用 LLMChain 對每個塊進行處理。
多步驟提示鏈:提升文字生成能力
在實際應用中,單一提示往往無法完成複雜任務。這時,提示鏈(Prompt Chaining)就成了解決方案。它涉及將多個提示輸入/輸出結合起來,使用特定的LLM提示來構建一個想法。讓我們以一個電影公司為例,它希望部分自動化電影創作過程。這個過程可以分解為多個關鍵元件,例如角色建立、情節生成、場景/世界構建等。
順序鏈
為了實作這個目標,我們可以將任務分解為多個鏈,並重新組合成一個單一鏈。每個鏈負責不同的任務:
- 角色生成鏈:根據給定的型別,建立多個角色。
- 情節生成鏈:根據角色和型別,建立情節。
- 場景生成鏈:根據情節,生成缺失的場景。
實作提示鏈
現在,讓我們為每個鏈定義一個提示範本:
from langchain_core.prompts.chat import ChatPromptTemplate
# 角色生成提示
character_generation_prompt = ChatPromptTemplate.from_template(
"""根據給定的型別,為我的短篇故事腦力激盪三到五個角色。型別是 {genre}。每個角色必須有一個名稱和簡介。
你必須為每個角色提供名稱和簡介,這非常重要!
---
示例回應:
名稱:CharWiz,簡介:一位精通魔法的巫師。
名稱:CharWar,簡介:一位精通劍術的戰士。
---
角色:"""
)
# 情節生成提示
plot_generation_prompt = ChatPromptTemplate.from_template(
"""給定以下角色和型別,為短篇故事建立一個有效的情節:
角色:
{characters}
---
型別:{genre}
---
情節:"""
)
# 場景生成提示
scene_generation_plot_prompt = ChatPromptTemplate.from_template(
"""扮演一個有效的內容創作者。
給定多個角色和一個情節,你負責為每個幕生成各種場景:
你必須將情節分解為多個有效的場景:
---
角色:
{characters}
---
"""
)
圖表視覺化
以下是使用Plantuml語法對這個過程進行視覺化的示例:
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title LangChain文字分割任務分解與提示鏈應用
package "系統架構" {
package "前端層" {
component [使用者介面] as ui
component [API 客戶端] as client
}
package "後端層" {
component [API 服務] as api
component [業務邏輯] as logic
component [資料存取] as dao
}
package "資料層" {
database [主資料庫] as db
database [快取] as cache
}
}
ui --> client : 使用者操作
client --> api : HTTP 請求
api --> logic : 處理邏輯
logic --> dao : 資料操作
dao --> db : 持久化
dao --> cache : 快取
note right of api
RESTful API
或 GraphQL
end note
@enduml
圖表翻譯:
這個流程圖展示瞭如何透過順序鏈的方式來生成短篇故事。首先,根據給定的型別生成角色,然後根據角色和型別生成情節,最後根據情節生成場景。這個過程透過多步驟的提示鏈來實作,最終產生出一個完整的短篇故事。
內容解密:
每個提示範本都設計用於完成特定的任務。角色生成提示要求根據型別腦力激盆出多個角色,每個角色都有一個名稱和簡介。情節生成提示根據給定的角色和型別建立一個有效的情節。場景生成提示根據情節和角色生成缺失的場景。這些提示透過順序鏈的方式組合起來,最終產生出一個完整的短篇故事。
使用LCEL進行聊天機器人提示連結
在進行聊天機器人提示連結時,如何確保下游的聊天機器人提示範本變數可用是一個重要的問題。為瞭解決這個問題,我們可以使用LCEL(LangChain Execution Language)中的itemgetter函式從前一步中提取鍵值。
使用itemgetter函式
首先,我們需要從operator包中匯入itemgetter函式。然後,我們可以使用RunnablePassthrough函式建立一個連結,該連結將前一步的輸入直接傳遞給下一步。
from operator import itemgetter
from langchain_core.runnables import RunnablePassthrough
chain = RunnablePassthrough() | {
"genre": itemgetter("genre"),
}
chain.invoke({"genre": "fantasy"})
在這個例子中,itemgetter("genre")函式從前一步中提取了genre鍵的值,並將其作為新的鍵值新增到下一步的輸入中。
使用lambda函式
除了使用itemgetter函式外,我們還可以使用lambda函式或RunnableLambda函式來操縱前一步的字典值。
from langchain_core.runnables import RunnableLambda
chain = RunnablePassthrough() | {
"genre": itemgetter("genre"),
"upper_case_genre": lambda x: x["genre"].upper(),
"lower_case_genre": RunnableLambda(lambda x: x["genre"].lower()),
}
chain.invoke({"genre": "fantasy"})
在這個例子中,lambda函式和RunnableLambda函式分別將genre鍵的值轉換為大寫和小寫,並將結果作為新的鍵值新增到下一步的輸入中。
使用RunnableParallel函式
最後,我們可以使用RunnableParallel函式來平行執行多個連結。
from langchain_core.runnables import RunnableParallel
master_chain = RunnablePassthrough() | {
"genre": itemgetter("genre"),
"upper_case_genre": lambda x: x["genre"].upper(),
"lower_case_genre": RunnableLambda(lambda x: x["genre"].lower()),
}
master_chain_two = RunnablePassthrough() | RunnableParallel(
genre=itemgetter("genre"),
upper_case_genre=lambda x: x["genre"].upper(),
lower_case_genre=RunnableLambda(lambda x: x["genre"].lower()),
)
story_result = master_chain.invoke({"genre": "Fantasy"})
在這個例子中,RunnableParallel函式平行執行了兩個連結,分別提取了genre鍵的值,並將其轉換為大寫和小寫。
透過使用這些函式和語法,我們可以建立複雜的聊天機器人提示連結,並確保下游的聊天機器人提示範本變數可用。
使用 LangChain 進行文字生成的高階技術
LangChain 是一個強大的工具,允許使用者建立複雜的文字生成工作流程。透過使用 LangChain 的可執行模組(Runnable),使用者可以建立多個鏈條(chain)來生成文字,並將這些鏈條組合起來以建立更複雜的工作流程。
建立 LCEL 鏈條
首先,需要建立兩個 LCEL 鏈條:master_chain 和 master_chain_two。這些鏈條可以使用相同的引數進行呼叫,並傳回相同的結果。
from langchain.runnables import RunnableParallel
from langchain.runnables import RunnablePassthrough
master_chain = (
{"genre": "Fantasy"}
| RunnablePassthrough()
| RunnableParallel(
genre=itemgetter("genre"),
upper_case_genre=lambda x: x["genre"].upper(),
lower_case_genre=lambda x: x["genre"].lower(),
)
)
master_chain_two = (
{"genre": "Fantasy"}
| RunnablePassthrough()
| RunnableParallel(
genre=itemgetter("genre"),
upper_case_genre=lambda x: x["genre"].upper(),
lower_case_genre=lambda x: x["genre"].lower(),
)
)
執行 LCEL 鏈條
然後,可以執行這些鏈條並列印結果。
story_result = master_chain.invoke({"genre": "Fantasy"})
print(story_result)
story_result = master_chain_two.invoke({"genre": "Fantasy"})
print(story_result)
建立多個 LCEL 鏈條
接下來,需要建立三個 LCEL 鏈條:character_generation_chain、plot_generation_chain 和 scene_generation_plot_chain。這些鏈條可以使用不同的提示範本來生成文字。
from langchain.chat_models import ChatOpenAI
from langchain.output_parsers import StrOutputParser
model = ChatOpenAI()
character_generation_chain = (
character_generation_prompt
| model
| StrOutputParser()
)
plot_generation_chain = (
plot_generation_prompt
| model
| StrOutputParser()
)
scene_generation_plot_chain = (
scene_generation_plot_prompt
| model
| StrOutputParser()
)
組合 LCEL 鏈條
然後,可以將這些鏈條組合起來以建立一個主 LCEL 鏈條。
from langchain.runnables import RunnableParallel
from operator import itemgetter
master_chain = (
{
"characters": character_generation_chain,
"genre": RunnablePassthrough(),
}
| RunnableParallel(
characters=itemgetter("characters"),
genre=itemgetter("genre"),
plot=plot_generation_chain,
)
| RunnableParallel(
characters=itemgetter("characters"),
genre=itemgetter("genre"),
plot=itemgetter("plot"),
scenes=scene_generation_plot_chain,
)
)
執行主 LCEL 鏈條
最後,可以執行主 LCEL 鏈條並列印結果。
story_result = master_chain.invoke({"genre": "Fantasy"})
print(story_result)
這將生成一個包含角色、情節和場景的故事。場景將被分成單獨的專案 dalam 一個 Python 列表中。然後,可以建立兩個新的提示來生成角色指令碼和摘要提示。
Scene Generation and Summarization
為了建立一個有效的場景指令碼,需要考慮到前一個場景的摘要,以避免重複內容。這可以透過使用兩個 LCEL鏈來實作:一個用於生成每個場景的角色指令碼,另一個用於生成前一個場景的摘要。
載入聊天模型
首先,需要載入一個聊天模型,以便生成場景指令碼和摘要。這裡使用的是 gpt-3.5-turbo-16k 模型。
model = ChatOpenAI(model='gpt-3.5-turbo-16k')
建立 LCEL 鏈
接下來,需要建立兩個 LCEL 鏈:一個用於生成角色指令碼,另一個用於生成場景摘要。
character_script_generation_chain = (
{
"characters": RunnablePassthrough(),
"genre": RunnablePassthrough(),
"previous_scene_summary": RunnablePassthrough(),
"plot": RunnablePassthrough(),
"scene": RunnablePassthrough(),
"index": RunnablePassthrough(),
}
| character_script_prompt
| model
)
場景指令碼生成
場景指令碼生成鏈使用 character_script_prompt 來生成每個場景的角色指令碼。這個提示包含了角色、型別、前一個場景的摘要、情節、場景和索引等資訊。
summarize_prompt = ChatPromptTemplate.from_template(
template="""Given a character script, create a summary of the scene.
Character script: {character_script}""",
)
場景摘要生成
場景摘要生成鏈使用 summarize_prompt 來生成每個場景的摘要。這個提示包含了角色指令碼等資訊。
執行 LCEL 鏈
最後,需要執行 LCEL 鏈來生成場景指令碼和摘要。
generated_scenes = []
previous_scene_summary = ""
for index, scene in enumerate(scenes):
# 生成角色指令碼
character_script = character_script_generation_chain({
"characters": characters,
"genre": genre,
"previous_scene_summary": previous_scene_summary,
"plot": plot,
"scene": scene,
"index": index,
})
# 生成場景摘要
scene_summary = model(summarize_prompt({
"character_script": character_script,
}))
# 更新前一個場景的摘要
previous_scene_summary = scene_summary
# 新增生成的場景到列表中
generated_scenes.append((scene, character_script, scene_summary))
這樣,就可以生成每個場景的角色指令碼和摘要,並且避免了重複內容。
##Prompt Chaining的應用:增強LLM的生成能力
在 Prompt Chaining 的架構中,我們可以透過串聯多個任務(Tasks)來增強大語言模型(LLM)的生成能力。這個過程涉及到建立一個任務鏈(Chain),其中每個任務都專注於特定的子任務,以達到最終的目標。
建立任務鏈
首先,我們需要建立一個任務鏈,包括多個任務,如character_script_generation_chain。這個鏈結合了多個可執行的任務(Runnables),如RunnablePassthrough,以確保資料流暢順暢。此外,還引入了一個強大的模型ChatOpenAI,具有16k的上下文視窗,非常適合用於廣泛的內容生成任務。
動態豐富場景
為了增強LLM的生成能力,我們可以動態豐富每個場景,透過建立一個簡單卻有效的緩衝記憶(Buffer Memory)。這種技術確保了敘述的連續性和上下文,從而增強了LLM生成連貫的角色指令碼的能力。
結構化輸出
透過StrOutputParser,我們可以將模型輸出轉換為結構化的字串,使得生成的內容易於使用和處理。
分工合作
設計任務時,遵循「分工合作」(Divide Labor)的原則,可以使整體輸出的品質大幅提高。將任務分解為更小、更易於管理的鏈結,可以增加每個鏈結對最終目標的貢獻。使用不同的模型,如使用智慧模型進行構思和使用廉價模型進行生成,通常可以得到最佳結果。
結構化LCEL鏈
在LCEL中,確保鏈結的第一部分是可執行的型別至關重要。錯誤的程式碼可能會導致執行失敗。因此,必須謹慎設計LCEL鏈結,以確保其正確性和有效性。
綜上所述,Prompt Chaining提供了一種強大的方法來增強LLM的生成能力,透過結合多個任務、動態豐富場景、結構化輸出和分工合作。這種方法不僅提高了生成內容的品質,也增強了LLM應用於複雜任務的能力。
從技術架構視角來看,LangChain 提供了靈活且強大的機制來實作複雜的文字生成任務。本文深入探討瞭如何利用 LangChain 的核心元件,例如 TextSplitter、LLMChain、以及各種 Runnable 模組,構建多步驟提示鏈,並結合 LCEL 語法實作更精細的流程控制。透過剖析角色生成、情節生成、場景構建等案例,我們可以清楚地看到 LangChain 如何有效地組織和串聯多個 LLM 呼叫,從而完成原本單一提示難以實作的複雜目標。 然而,LangChain 的學習曲線較陡峭,需要開發者熟悉其核心概念和 API 設計。此外,在處理長文字和複雜邏輯時,效能調校和錯誤除錯也可能帶來一定的挑戰。對於追求精細化控制和高度客製化流程的開發者,深入理解 LCEL 的語法和執行機制至關重要。展望未來,隨著 LangChain 生態系統的持續發展,我們預計會有更多便捷的工具和更最佳化的執行引擎出現,進一步降低開發門檻並提升生成效率。對於希望構建高階文字生成應用的開發者而言,LangChain 值得深入研究和應用。