第11章 進階:LangChain與外部工具調用
1. 引言
在上一章,我們成功地創造了我們的第一個“生命”——一個可以對話的機器人。我們為它的誕生而興奮,但很快我們就會發現它的局限性。它就像一個被囚禁在玻璃房中的天才大腦,擁有淵博的知識,卻與真實世界完全隔離。
- 你問它:“今天的天氣怎么樣?” 它會抱歉地告訴你,它的知識截止于202x年,無法獲取實時信息。
- 你問它:“345乘以123等于多少?” 它可能會給出一個看似合理但實際上錯誤的結果,因為它是在“預測”一個答案,而不是在“計算”。
- 你讓它:“幫我總結一下這個網頁的內容:[URL]”。它會告訴你它無法訪問互聯網。
這個“玻璃房”,就是大語言模型固有的兩大局限:知識的非時效性和能力的非行動性。要打破這堵墻,我們需要為它裝上“眼睛”(訪問網絡)、“耳朵”(讀取文件)和“雙手”(調用工具)。
本章,我們將學習一個革命性的框架——LangChain
。LangChain
就像一個“超級膠水”或“瑞士軍刀”,它提供了一整套標準化的組件和接口,可以輕松地將我們的大模型與外部數據源、API和各種工具“鏈接”在一起,構建出遠比簡單對話復雜和強大的應用程序。
本章學習目標:
- 理解LLM的核心局限:深刻認識為什么LLM需要與外部世界交互。
- 掌握LangChain的核心思想:理解“鏈(Chain)”的概念,以及它如何編排和組合不同的AI組件。
- 學習LangChain的核心組件:熟悉
Models
,Prompt Templates
,Chains
,Tools
和Agents
這些構建塊。 - 構建一個智能代理(Agent):親手創造一個能自主思考、決策并使用外部工具(如搜索引擎)來回答問題的智能應用。
本章核心問題:
- 如何讓大模型獲取訓練數據之外的、最新的知識?
- 如何賦予大模型使用計算器、搜索引擎、數據庫查詢等“超能力”?
- 什么是“智能代理(Agent)”?它和我們之前寫的聊天機器人有什么本質區別?
如果說上一章我們學會了如何“使用”一個大腦,那么本章,我們將學習如何為這個大腦構建一個完整的“身體”和“神經系統”,讓它的智能真正得以延伸和作用于真實世界。
2. 正文
2.1 打破“次元壁”:為何需要LangChain?
一個標準的大語言模型(LLM),本質上是一個函數:輸入一段文本,輸出一段文本。f(prompt) -> completion
。它的所有能力都封裝在這個函數內部。LangChain
的核心哲學,就是不把LLM看作一個封閉的黑盒,而是看作一個可以被編排和調度的核心引擎。
LangChain
主要解決了LLM的兩大痛點:
- 數據連接 (Data Connection): LLM的知識是靜態的。
LangChain
可以幫助LLM連接到各種外部數據源,如個人文檔、數據庫、API等,實現基于私有數據或實時數據的問答。 - 代理能力 (Agency): LLM本身無法采取行動。
LangChain
引入了“智能代理”的概念,讓LLM可以根據用戶的指令,自主地決定調用哪個外部工具(如搜索引擎、計算器、Python解釋器),并利用工具返回的結果來完成任務。
直觀比喻:從博學的教授到全能的CEO
- 標準LLM:一位知識淵博但被鎖在圖書館里的老教授。他能回答你基于館內藏書的所有問題,但對外界發生的新鮮事一無所知,也無法派人幫你辦事。
- 使用LangChain的LLM:一位運籌帷幄的CEO。他自己(LLM)是大腦,負責思考和決策。他手下有一群能力各異的專業助理(Tools),比如市場研究員(搜索引擎)、財務分析師(計算器)、法務顧問(數據庫查詢)等。當接到一個復雜任務時,CEO會思考(Reasoning),然后指令相應的助理去執行(Action),并根據助理反饋的結果,進行下一步的思考和決策,直到任務完成。
2.2 LangChain核心組件解構
LangChain
通過一系列標準化的組件,讓構建復雜應用變得模塊化和簡單。
graph TDsubgraph LangChain應用構建塊A[Models<br/>(語言模型)]B[Prompt Templates<br/>(提示詞模板)]C[Chains<br/>(調用鏈)]D[Agents & Tools<br/>(代理與工具)]endA & B --> C;A & D --> E{復雜LLM應用};C --> E;
-
Models: 這是核心的“大腦”。LangChain為各種LLM(如OpenAI的GPT系列、Hugging Face上的開源模型等)提供了統一的接口,讓你可以在不修改上層代碼的情況下,輕松切換底層模型。
-
Prompt Templates: 這是與模型溝通的“話術”。我們很少直接將用戶的輸入發給模型,而是會用一個模板把它包裝一下,給出更清晰的指令。
LangChain
的PromptTemplate
可以輕松地處理帶有變量的提示詞。from langchain.prompts import PromptTemplatetemplate = "請將以下英文翻譯成{language}: {text}" prompt = PromptTemplate(template=template, input_variables=["language", "text"])formatted_prompt = prompt.format(language="法語", text="Hello, world!") # -> "請將以下英文翻譯成法語: Hello, world!"
-
Chains: 這是
LangChain
名字的由來,也是其最核心的抽象。鏈就是將多個組件(可以是LLM,也可以是其他鏈)按順序組合在一起,完成一個特定的任務。最基礎的鏈是LLMChain
,它簡單地將PromptTemplate
和Model
鏈接在一起。 -
Agents & Tools: 這是
LangChain
最強大、最神奇的部分。- Tool: 一個工具就是一個函數,它能執行一個特定的、原子化的任務。例如,
GoogleSearchTool
、CalculatorTool
、PythonREPLTool
。 - Agent: 一個代理就是一個搭載了LLM的決策引擎。它接收用戶的復雜指令,然后自主地進行思考,決定是否需要使用工具、使用哪個工具、以及如何使用這個工具。這個思考-行動的循環被稱為ReAct (Reason + Act)。
- Tool: 一個工具就是一個函數,它能執行一個特定的、原子化的任務。例如,
2.3 代碼實戰:打造一個能上網搜索的“研究員”Bot
現在,我們將利用LangChain
的Agent
和Tool
,把我們上一章的機器人,從一個“聊天家”升級為一個能上網沖浪的“研究員”。
場景定義
我們要構建一個問答機器人。當被問到一個它知識范圍內不知道的問題時(比如關于最近發生的新聞),它應該能自動使用搜索引擎來查找答案,然后根據搜索結果,給出最終的回答。
環境準備
首先,我們需要安裝LangChain
以及一些必要的依賴庫。我們使用DuckDuckGo
作為搜索引擎,因為它不需要申請API Key,非常方便。
# 如果你還沒有安裝過langchain
pip install langchain langchain-openai# 安裝DuckDuckGo搜索工具的依賴
pip install duckduckgo-search
langchain
: LangChain核心庫。langchain-openai
:LangChain
與OpenAI模型集成的庫。為了演示方便,我們這里使用OpenAI,因為它對Agent的支持最成熟。duckduckgo-search
: DuckDuckGo搜索引擎的Python包。
獲取OpenAI API Key
Agent需要一個足夠聰明的LLM來做決策。目前開源模型在這方面還在追趕,OpenAI的GPT系列是效果最好的。你需要:
- 訪問 OpenAI官網 注冊一個賬戶。
- 在個人賬戶設置中,找到
API keys
頁面,創建一個新的密鑰(Secret Key)。 - 重要:將你的密鑰設置為一個環境變量,以便代碼可以安全地讀取它。
- 在Linux或macOS的終端中:
export OPENAI_API_KEY="sk-..."
- 在Windows的CMD中:
set OPENAI_API_KEY="sk-..."
- (注意:每次關閉終端后都需要重新設置,或者將其寫入你的shell配置文件如
.zshrc
或.bash_profile
中)
- 在Linux或macOS的終端中:
完整Python代碼
創建一個名為 agent_app.py
的文件,并復制以下代碼。
# 1. 導入必要的庫
import gradio as gr
from langchain_openai import OpenAI
from langchain.agents import load_tools, initialize_agent, AgentType
import os# 確保你已經設置了環境變量 OPENAI_API_KEY
if "OPENAI_API_KEY" not in os.environ:print("錯誤:請先設置環境變量 OPENAI_API_KEY")exit()# 2. 初始化LLM(大腦)
# temperature=0 表示我們希望模型盡可能給出基于事實的、確定性的回答
llm = OpenAI(temperature=0)# 3. 加載工具(手臂)
# LangChain內置了很多工具,我們這里加載兩個:
# 'ddg-search':DuckDuckGo搜索引擎
# 'llm-math':一個使用LLM來進行數學計算的工具
tools = load_tools(["ddg-search", "llm-math"], llm=llm)# 4. 初始化Agent(指揮官)
# Agent需要三樣東西:llm, tools, 和一個agent類型
# ZERO_SHOT_REACT_DESCRIPTION: 這是一種最通用的Agent類型,
# 它通過觀察工具的描述來決定在什么時候使用什么工具。
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True # 設置為True,可以在終端看到Agent的思考過程
)# 5. 定義核心的交互函數
def research_chat(query):"""接收用戶查詢,并由Agent來執行獲取答案。"""print(f"用戶查詢: {query}")# agent.run(query) 是LangChain v0.1.0之前的用法# 在新版本中,推薦使用 agent.invokeresponse = agent.invoke({"input": query})return response["output"]# 6. 創建并啟動Gradio界面
demo = gr.Interface(fn=research_chat,inputs=gr.Textbox(lines=2, placeholder="例如: 2023年F1年度總冠軍是誰? 或者 345 * 123.4 等于多少?"),outputs="text",title="我的智能研究員Bot",description="這是一個由LangChain驅動的智能代理,它能上網搜索和進行計算。"
)if __name__ == "__main__":demo.launch()
運行與體驗
- 確保你已設置好
OPENAI_API_KEY
環境變量。 - 在終端運行腳本:
python agent_app.py
- 在瀏覽器中打開Gradio提供的本地URL。
見證思考過程
現在,嘗試在輸入框中問一個它“不可能知道”的問題,比如:“2023年的奧斯卡最佳影片是什么?”
提交后,不要只看瀏覽器界面的最終結果,一定要回到你的終端,你會看到類似下面這樣的輸出(verbose=True
的效果):
> Entering new AgentExecutor chain...I need to find out the winner of the Best Picture award at the 2023 Oscars. I will use a search engine for this.
Action: duckduckgo_search
Action Input: "2023 Academy Awards Best Picture winner"
Observation: The 95th Academy Awards ceremony, presented by the Academy of Motion Picture Arts and Sciences (AMPAS), honored the best films of 2022 and took place on March 12, 2023. ... Everything Everywhere All at Once won seven awards, including Best Picture.
Thought: I have found the answer. The winner was "Everything Everywhere All at Once". I should present this information to the user.
Final Answer: 2023年的奧斯卡最佳影片是《瞬息全宇宙》(Everything Everywhere All at Once)。> Finished chain.
看到這些Thought, Action, Observation了嗎?這就是Agent的“內心獨白”!
- Thought: 它首先思考,認識到自己需要查找信息。
- Action: 它決定使用
duckduckgo_search
工具,并確定了搜索的關鍵詞。 - Observation: 這是它從工具(搜索引擎)那里得到的返回結果。
- Thought: 它再次思考,發現已經從返回結果中找到了答案。
- Final Answer: 它將最終答案組織成流暢的語言,返回給用戶。
現在,再試一個數學問題:“目前圓周率的第100位小數是多少?”。它會先嘗試用llm-math
計算,失敗后(因為它算不了這么復雜),可能會轉而使用搜索,這就是智能的體現!
3. 總結與預告
本章,我們為囚禁在“玻璃房”中的天才大腦,成功地連接了外部世界。我們不再局限于它靜態的知識,而是賦予了它獲取新知和執行任務的能力。
本章核心要點:
- LLM的局限:我們理解了標準LLM存在知識截止和無法行動兩大痛點。
- LangChain:我們學習了這個強大的框架,它通過鏈(Chains)的思想,將模型、提示詞、工具等組件模塊化地組合在一起。
- 智能代理(Agent):我們掌握了LangChain中最激動人心的概念。Agent是一個能自主思考、決策、并調用工具的智能體,其核心是**ReAct (Reason+Act)**的循環。
- 實戰:我們親手構建了一個“研究員Bot”,它能根據需要,自動調用搜索引擎和計算器來解決問題,我們還“窺探”了它完整的思考過程。
我們已經學會了如何使用一個強大的、通用的預訓練模型,并把它連接到外部工具。但是,如果我們的需求非常特殊和專業呢?比如,我需要一個只回答我公司內部文檔的客服機器人,或者一個能理解醫學術語的醫療問答AI。通用模型雖然知識淵博,但在這些“私有領域”可能表現不佳。
如何讓我們自己的數據,深刻地“注入”到模型中,讓它成為一個特定領域的專家?這,就是我們下一章要學習的,大模型應用中另一個極其重要的技術:《創造:Fine-tuning完全指南》。我們將學習如何用自己的數據集,去“微調”一個開源的基礎模型,把它定制成我們專屬的AI。
4. 課后練習
- 探索更多工具:
LangChain
支持非常多的工具。請你嘗試閱讀LangChain的文檔,為我們的Agent再添加一個wikipedia
工具。看看當你問一個關于歷史人物的問題時,它會優先選擇維基百科還是DuckDuckGo。 - 定制Agent“性格”:
initialize_agent
函數可以接收一個agent_kwargs
參數,你可以在其中定制Agent的“系統提示詞”。請嘗試修改代碼,給Agent設定一個角色,例如:“你是一個言簡意賅的AI助手,總是用一句話回答問題。” 觀察它的回答風格是否發生了變化。 - 思想實驗:Agent在決策使用哪個工具時,是依據
tools
列表中每個工具的description
(描述)。如果我們把ddg-search
工具的描述改成“一個用來查詢食譜的工具”,你認為當用戶問天氣時會發生什么?這個實驗說明了什么在構建Agent時的重要性?