引言
Agent(智能体)是LangChain生态系统中的核心概念,它允许语言模型不仅仅输出文本,而是能够采取行动并与外部世界交互。在本章中,我们将深入探讨如何创建和运行Agent,使其能够利用多种工具完成复杂任务。
单独来说,语言模型无法采取行动 - 它们只能输出文本。LangChain的一个重要用例是创建代理(Agent)。代理是使用LLM作为推理引擎的系统,用于确定应采取哪些行动以及这些行动的输入应该是什么。然后可以将这些行动的结果反馈给代理,并确定是否需要更多行动,或者是否可以结束。
在本章中,我们将构建一个可以与多种不同工具进行交互的代理:一个是本地数据库,另一个是搜索引擎。您将能够向该代理提问,观察它调用工具,并与它进行对话。
关键概念
在开始构建Agent之前,我们需要了解几个关键概念:
- 语言模型:特别是它们的工具调用能力
- 检索器(Retrievers):向我们的代理公开特定信息的组件
- 工具(Tools):代理可以使用的功能,如搜索引擎
- 聊天历史(Chat History):允许代理"记住"过去的交互
- LangSmith:用于调试和跟踪应用程序的工具
环境设置
安装必要的包
首先,我们需要安装LangChain及其相关依赖:
bash
pip install langchain langchain-openai langchain-community tavily-python
设置LangSmith(可选但推荐)
LangSmith是一个强大的工具,可以帮助我们调试和跟踪代理的行为:
python
import os
# 设置LangSmith环境变量
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "your-langsmith-api-key" # 替换为你的API密钥
os.environ["LANGCHAIN_PROJECT"] = "langchain-agent-tutorial" # 项目名称
定义工具
Agent的强大之处在于它可以使用各种工具。在这个例子中,我们将创建两种类型的工具:
- Tavily搜索工具(用于在线搜索)
- 基于本地数据的检索工具
1. 设置Tavily搜索工具
Tavily是一个专为AI应用设计的搜索引擎API。首先,我们需要设置Tavily API密钥:
python
import os
os.environ["TAVILY_API_KEY"] = "your-tavily-api-key" # 替换为你的API密钥
from langchain_community.tools.tavily_search import TavilySearchResults
# 创建搜索工具
search_tool = TavilySearchResults(max_results=3)
2. 创建本地检索工具
接下来,我们将创建一个基于本地数据的检索工具。这个工具将允许代理从我们提供的文档中检索信息。
python
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from langchain.tools.retriever import create_retriever_tool
# 1. 加载文档
loader = TextLoader("./data/company_info.txt") # 替换为你的文档路径
documents = loader.load()
# 2. 分割文档
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
splits = text_splitter.split_documents(documents)
# 3. 创建向量存储
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(splits, embeddings)
# 4. 创建检索器
retriever = vectorstore.as_retriever()
# 5. 将检索器转换为工具
retriever_tool = create_retriever_tool(
retriever,
"company_info_search",
"搜索公司内部信息,包括产品、服务、政策等。当问题涉及公司特定信息时使用此工具。"
)
整合工具
现在我们有了两个工具,可以将它们整合到一个列表中:
python
tools = [search_tool, retriever_tool]
设置语言模型
接下来,我们需要设置一个支持工具调用的语言模型:
python
from langchain_openai import ChatOpenAI
# 创建语言模型
model = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
# 让模型了解可用的工具
model_with_tools = model.bind_tools(tools)
测试模型的工具调用能力
在创建完整的代理之前,让我们测试一下模型的工具调用能力:
python
from langchain_core.messages import HumanMessage
# 测试普通消息
response = model_with_tools.invoke([
HumanMessage(content="今天天气怎么样?")
])
print("普通响应:", response.content)
# 测试需要工具调用的消息
response = model_with_tools.invoke([
HumanMessage(content="搜索关于量子计算的最新进展")
])
print("工具调用:", response.tool_calls)
创建代理
现在,我们可以创建一个完整的代理,它能够自动决定何时使用工具以及如何处理工具返回的结果:
python
from langchain.agents import create_tool_calling_agent
from langchain.agents import AgentExecutor
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
# 1. 创建提示模板
prompt = ChatPromptTemplate.from_messages([
("system", """你是一个有用的AI助手,可以回答用户的问题。
你可以使用以下工具来帮助回答问题:
{tools}
使用以下格式:
问题: 用户的问题
思考: 你应该总是思考要做什么
行动: 工具名称 (参数)
观察: 工具的结果
思考: 我现在知道答案了
回答: 对用户问题的回答
当你不需要使用工具时,直接回答用户的问题。
{chat_history}
"""),
MessagesPlaceholder(variable_name="chat_history"),
("human", "{input}"),
])
# 2. 创建代理
agent = create_tool_calling_agent(model, tools, prompt)
# 3. 创建代理执行器
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
运行代理
现在我们可以运行代理并测试它的能力:
python
# 测试不需要工具的查询
result = agent_executor.invoke({"input": "你好,请介绍一下你自己"})
print(result["output"])
# 测试需要检索器的查询
result = agent_executor.invoke({"input": "我们公司的主要产品是什么?"})
print(result["output"])
# 测试需要搜索工具的查询
result = agent_executor.invoke({"input": "2023年诺贝尔物理学奖获得者是谁?"})
print(result["output"])
添加记忆功能
目前,我们的代理是无状态的,它不会记住之前的交互。为了添加记忆功能,我们需要传递聊天历史:
python
# 手动管理聊天历史
from langchain_core.messages import AIMessage, HumanMessage
chat_history = []
# 第一次交互
result = agent_executor.invoke({
"input": "我们公司最畅销的产品是什么?",
"chat_history": chat_history
})
print(result["output"])
# 更新聊天历史
chat_history.append(HumanMessage(content="我们公司最畅销的产品是什么?"))
chat_history.append(AIMessage(content=result["output"]))
# 第二次交互(引用前一个问题)
result = agent_executor.invoke({
"input": "它的价格是多少?",
"chat_history": chat_history
})
print(result["output"])
自动管理聊天历史
为了更方便地管理聊天历史,我们可以使用RunnableWithMessageHistory
:
python
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_community.chat_message_histories import ChatMessageHistory
# 创建消息存储
message_history = ChatMessageHistory()
# 包装代理执行器
agent_with_memory = RunnableWithMessageHistory(
agent_executor,
lambda session_id: message_history,
input_messages_key="input",
history_messages_key="chat_history"
)
# 使用带有记忆的代理
result = agent_with_memory.invoke(
{"input": "你能告诉我们公司的退款政策吗?"},
config={"configurable": {"session_id": "unique-session-id"}}
)
print(result["output"])
# 后续问题
result = agent_with_memory.invoke(
{"input": "如果产品已经使用了,还能退款吗?"},
config={"configurable": {"session_id": "unique-session-id"}}
)
print(result["output"])
使用LangSmith跟踪和调试
LangSmith提供了强大的可视化和调试功能,帮助我们理解代理的决策过程:
python
# 执行代理并在LangSmith中跟踪
result = agent_executor.invoke({"input": "比较我们的产品与竞争对手的区别"})
# 查看LangSmith跟踪
print("查看详细跟踪:https://smith.langchain.com/project/langchain-agent-tutorial")
完整代码示例
下面是一个完整的代码示例,整合了上述所有概念:
python
import os
from langchain_openai import ChatOpenAI
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from langchain.tools.retriever import create_retriever_tool
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import AIMessage, HumanMessage
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_community.chat_message_histories import ChatMessageHistory
# 设置API密钥
os.environ["OPENAI_API_KEY"] = "your-openai-api-key"
os.environ["TAVILY_API_KEY"] = "your-tavily-api-key"
# 设置LangSmith(可选)
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "your-langsmith-api-key"
os.environ["LANGCHAIN_PROJECT"] = "langchain-agent-tutorial"
# 创建Tavily搜索工具
search_tool = TavilySearchResults(max_results=3)
# 创建本地检索工具
# 假设我们有一个包含公司信息的文本文件
with open("company_info.txt", "w") as f:
f.write("""
我们的公司成立于2010年,是一家专注于人工智能解决方案的科技公司。
我们的主要产品包括:
1. AI助手Pro - 我们最畅销的产品,售价¥999/年
2. 智能数据分析平台 - 企业版售价¥5,999/年
3. 自动化客服系统 - 根据规模定价,起价¥2,999/月
我们的退款政策:
- 购买后14天内,如果对产品不满意,可以申请全额退款
- 已经使用的产品不支持退款
- 企业版产品需要联系客户经理处理退款事宜
我们的竞争优势:
- 专有的自然语言处理技术,准确率比竞争对手高15%
- 7x24小时客户支持
- 定制化解决方案能力
- 本地化部署选项,保护数据隐私
""")
loader = TextLoader("company_info.txt")
documents = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
splits = text_splitter.split_documents(documents)
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(splits, embeddings)
retriever = vectorstore.as_retriever()
retriever_tool = create_retriever_tool(
retriever,
"company_info_search",
"搜索公司内部信息,包括产品、服务、政策等。当问题涉及公司特定信息时使用此工具。"
)
# 整合工具
tools = [search_tool, retriever_tool]
# 创建语言模型
model = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
# 创建提示模板
prompt = ChatPromptTemplate.from_messages([
("system", """你是一个有用的AI助手,可以回答用户的问题。
你可以使用以下工具来帮助回答问题:
{tools}
使用以下格式:
问题: 用户的问题
思考: 你应该总是思考要做什么
行动: 工具名称 (参数)
观察: 工具的结果
思考: 我现在知道答案了
回答: 对用户问题的回答
当你不需要使用工具时,直接回答用户的问题。
"""),
MessagesPlaceholder(variable_name="chat_history"),
("human", "{input}"),
])
# 创建代理
agent = create_tool_calling_agent(model, tools, prompt)
# 创建代理执行器
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
# 创建带有记忆的代理
message_history = ChatMessageHistory()
agent_with_memory = RunnableWithMessageHistory(
agent_executor,
lambda session_id: message_history,
input_messages_key="input",
history_messages_key="chat_history"
)
# 使用代理
print("=== 测试不需要工具的查询 ===")
result = agent_executor.invoke({"input": "你好,请介绍一下你自己"})
print(result["output"])
print("\n=== 测试需要检索器的查询 ===")
result = agent_executor.invoke({"input": "我们公司的主要产品是什么?"})
print(result["output"])
print("\n=== 测试需要搜索工具的查询 ===")
result = agent_executor.invoke({"input": "2023年诺贝尔物理学奖获得者是谁?"})
print(result["output"])
print("\n=== 测试带有记忆的代理 ===")
result = agent_with_memory.invoke(
{"input": "我们公司最畅销的产品是什么?"},
config={"configurable": {"session_id": "unique-session-id"}}
)
print(result["output"])
result = agent_with_memory.invoke(
{"input": "它的价格是多少?"},
config={"configurable": {"session_id": "unique-session-id"}}
)
print(result["output"])
# 清理
import os
if os.path.exists("company_info.txt"):
os.remove("company_info.txt")
高级Agent开发技巧
1. 自定义代理类型
LangChain提供了多种代理类型,每种都有不同的决策流程:
python
# 使用ReAct代理
from langchain.agents import create_react_agent
react_agent = create_react_agent(model, tools, prompt)
2. 处理工具错误
在实际应用中,工具可能会失败。我们可以添加错误处理:
python
# 创建带有错误处理的代理执行器
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True,
handle_tool_error=True, # 启用工具错误处理
max_iterations=5 # 限制最大迭代次数
)
3. 添加人类反馈循环
在某些情况下,我们可能希望在代理执行关键操作前获取人类确认:
python
from langchain.agents import AgentExecutor
def should_continue(output):
"""决定是否继续执行或请求人类确认"""
if "critical_operation" in output:
user_input = input("代理想执行关键操作。是否继续?(y/n): ")
return user_input.lower() == 'y'
return True
# 创建带有人类反馈的代理执行器
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True,
handle_tool_error=True,
intermediate_steps_callback=should_continue
)
结论
在本章中,我们学习了如何使用LangChain创建和运行Agent智能体。我们探讨了以下关键点:
- Agent的基本概念和工作原理
- 如何创建和使用工具(搜索工具和检索工具)
- 如何设置语言模型并使其能够调用工具
- 如何创建完整的代理系统
- 如何添加记忆功能,使代理能够记住过去的交互
- 如何使用LangSmith跟踪和调试代理行为
Agent是LangChain生态系统中最强大的功能之一,它允许我们创建能够与外部世界交互的智能系统。通过合理设计工具和提示,我们可以构建出能够解决各种复杂问题的智能代理。
随着您对LangChain的深入了解,您可能希望探索更高级的代理框架,如LangGraph,它提供了更大的灵活性和控制性。