第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时的重要性?