08_LangChain开发Agent智能体

引言

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的强大之处在于它可以使用各种工具。在这个例子中,我们将创建两种类型的工具:

  1. Tavily搜索工具(用于在线搜索)
  2. 基于本地数据的检索工具

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智能体。我们探讨了以下关键点:

  1. Agent的基本概念和工作原理
  2. 如何创建和使用工具(搜索工具和检索工具)
  3. 如何设置语言模型并使其能够调用工具
  4. 如何创建完整的代理系统
  5. 如何添加记忆功能,使代理能够记住过去的交互
  6. 如何使用LangSmith跟踪和调试代理行为

Agent是LangChain生态系统中最强大的功能之一,它允许我们创建能够与外部世界交互的智能系统。通过合理设计工具和提示,我们可以构建出能够解决各种复杂问题的智能代理。

随着您对LangChain的深入了解,您可能希望探索更高级的代理框架,如LangGraph,它提供了更大的灵活性和控制性。

参考资源

相关推荐
hayson5 小时前
langchaingo用法详解及源码解析(二)
langchain·llm
掘我的金5 小时前
07_LangChain代理与工具使用
langchain
王国强20097 小时前
LangChain 设计原理分析⁹ | 如何实现检索增强生成(RAG)
langchain
weixin_4380774911 小时前
langchain入门笔记02:几个实际应用
服务器·langchain·rag
陈敬雷-充电了么-CEO兼CTO13 小时前
OpenAI 开源模型 GPT-OSS深度拆解:从1170亿参数到单卡部署,重构AI开源生态
人工智能·gpt·chatgpt·重构·langchain·开源·transformer
都叫我大帅哥15 小时前
时间旅行者的秘密武器:LangGraph Checkpoint全解
python·langchain
王国强20091 天前
LangChain 设计原理分析⁸ | Agent 架构设计详解:自定义 Tool、插件与中间态管理
langchain
掘我的金1 天前
05_LangChain消息存储与管理
langchain
掘我的金1 天前
06_LangChain多模态输入与自定义输出
langchain