LangChain工具调用Agent与MCP
LangChain系列文章目录
第一章 LangChain 简介和核心包
第二章 LangChain 提示词工程
第三章 LangChain 工作流
第四章 LangChain服务部署与链路监控
第五章 LangChain 消息管理与聊天历史存储
第六章 LangChain多模态输入与自定义输出
第七章 LangChain 工具
第八章 LangChain工具调用Agent与MCP
文章目录
- LangChain系列文章目录
- 前言
- LangChain工具调用Agent
- 一、创建和运行Agent
- 二、创建工具Tool
- 三、代理和工具代理和工具代理执行器
- 四、创建工具代理和工具代理执行器
-
- 1.使用create_tool_calling_agent()方法,创建一个通用的工具调用代理对象agent,为支持工具调用(tool calling)的LLM设计。
- 2.create_tool_calling_agent()方法生成的Agent对象,需要特定的提示模板prompt。
- 3.为create_tool_calling_agent()方法自定义提示模板prompt
- 4.使用AgentExecutor()方法,将一个工具调用Agent对象,创建成一个工具代理执行器对象agent_executor。
- 5.使用代理执行器对象agent_executor的invoke方法执行
- 6.代理异步使用工具
- 五、创建agent方法:create_react_agent()与create_tool_calling_agent()对比
- 六、链中使用代理
- 七、记忆
- 八、Agent使用MCP工具
- 总结
前言
本文主要整理 LangChain 工具调用 Agent 相关内容,包括 Agent 工作流程、Tool 与 Agent 的区别、Tavily 工具、检索器工具、模型绑定工具、工具代理执行器、create_tool_calling_agent、create_react_agent、Agent 记忆,以及 MCP 工具调用等内容。
LangChain工具调用Agent
一、创建和运行Agent
1.代理作用
- 大语言模型无法执行实际操作,只能输出文本或内容(AIGC)。
- LangChain代理是使用LLM作为推理引擎的系统,用于确定应采取某些操作以及这些操作应该的输入参数。然后操作结果可能会再反馈给代理,并确定是否需要更多操作,或者是否结束。
- 使用LangChain构建代理适合入门级使用,如果希望更好的灵活性和控制性。要使用更高级的代理创建能力,可以使用LangGraph。
2.Agent工作流程
- Agent工作流程
- 第一次LLM调用:分析(用户输入),决定需要调用A工具(有可能异步调用多个工具)
- 第二次LLM调用:整合分析(用户输入+A工具结果),决定需要调用B工具(如果需要)
- 第三次次LLM调用:整合分析(用户输入+A工具结果+B工具结果),给出最终答案
- agent_scratchpad:
- prompt中最后有个placeholder,variable_name值是agent_scratchpad,存储Agent在执行过程中的中间思考步骤和工具调用记录。
- 工具调用的记录
- 工具返回的结果
- Agent的思考过程。模型会看到类似这样的内容:
- Thought: 用户问了关于时间的问题,我需要获取当前时间
- Action: Current_Time-tool
- Action Input: {}
- Observation: 2024年1月15日,14时30分25秒
- Thought: 现在我知道了当前时间,可以回答用户了
- 最终输出的生成。模型会基于以下内容生成最终的回答
- 系统提示词(小芳的人设)
- 对话历史
- 用户当前输入
- 工具调用的完整记录和结果
- 示例。如用户问:“现在几点了?”
- Agent分析:需要获取时间信息
- 调用工具:current_time()返回"2024年1月15日,14时30分25秒"
- 模型整合:结合小芳的人设,生成回答
- 输出:“哈哈哈,现在是2024年1月15日下午2点30分啦!怎么啦宝贝,是不是又熬夜了想确认时间?你这样下去身体会受不了的啦~”
- 关键点
- 工具结果不是直接输出,而是作为上下文提供给模型
- 模型会根据人设和上下文重新组织语言
- 最终输出是模型生成的,保持了角色一致性
3.创建和运行代理包括:
- 选用具有调用工具能力的大语言模型
- 使用工具(页面搜索和检索器也是一种工具)操作某个外部程序
- 聊天历史,允许记住过去的交互,并在回答问题时考虑这些交互。
- 使用LangSmith/ Verbose调试和跟踪程序
4.工具(Tool)与代理(Agent)的区别
| 特性 | 工具(Tool) | 代理(Agent) |
|---|---|---|
| 作用 | 完成单一任务(如搜索、计算) | 协调多个工具,根据输入决定调用哪些工具 |
| 是否自主决策 | 否(被动执行) | 是(依赖LLM推理) |
| 例子 | TavilySearch 仅执行搜索 | 需通过AgentExecutor组合多个工具 |
5.创建代理(Agent)过程
- 创建工具对象Tool
- 将多个工具组成一个工具列表Tools
- 创建一个有工具调用能力的代理Agent,并指明调用的工具列表
- 将有工具调用能力的代理创建成一个代理执行器Agent_executor
- 在链中使用代理执行器
- 创建有记忆能力的代理执行器(可选)
- 创建有MCP调用能力的代理执行器(可选)
二、创建工具Tool
1.创建搜索工具(Tavily示例)
- 工具目的是被大语言模型所调用,执行某些操作。
- 使用Tavily搜索引擎作为工具。
- Tavily需要API密钥。并且需要安装:pip install langchain_tavily
- TavilySearch()封装了Tavily搜索引擎的API调用逻辑。返回工具对象。
- TavilySearch()参数:
- tavily_api_key:Tavily的API密钥(必填)。默认None
- max_results:返回的最大结果数量。默认5
- include_raw_content:是否在结果中包含网页原始内容(可能增加延迟)。默认False
- include_images:是否包含图片结果。默认False
- include_answers:是否尝试提取直接答案(如知识图谱)。默认False
- search_depth:搜索深度"basic"(快速,默认)或 “advanced”(更全面)
代码
from langchain_tavily import TavilySearch
search_tool = TavilySearch(
max_results=1,
tavily_api_key="************"
)
print(search_tool.invoke("今天上海天气怎么样"))
结果
[
{
"title": "今日天气-上海市气象局",
"url": "http://sh.cma.gov.cn/sh/tqyb/jrtq/",
"content": "05月27日 星期二·晴. 多云·19℃~27℃·东南风 风力4-5级.",
"score": 0.78154784,
}
]
2.创建检索器工具
- 检索器Retriever用于从文本集合或知识库中(使用embedding模型)检索相关信息。为大语言模型提供知识背景
- WebBaseLoader()是LangChain提供的一个文档加载器(Loader),用于从网页URL中加载内容并转换为LangChain可处理的文档加载器(Loader对象)。参数
- web_path:网页URL(字符串或列表)。支持多个URL批量加载。(必填)
- continue_on_failure:加载URL失败时是否跳过或抛出异常,默认False。
- verify_ssl bool:是否验证SSL证书(False跳过证书验证),默认True。
- proxy:设置代理服务器(如 “http://your-proxy:port”)。
- requests_kwargs:传递给requests.get()的额外参数,如headers、timeout
- 如提示:USER_AGENT environment variable not set, consider setting it to identify your requests. 就是没有设置头部信息可以设置(设置了好像不起效果)
- bs_kwargs:传递给BeautifulSoup解析器的参数(如指定解析器{“features”: “lxml”})。
- 返回加载器Loader对象后,使用load()方法,返回Document文档对象列表
- 递归字符文本分割,使用RecursiveCharacterTextSplitter(separators, chunk_size, chunk_overlap)方法,对文本分割,返回文本分割对象text_splitter。参数
- separators为多级别分割字符列表,级别从高到低,默认[“\n\n”, “\n”, " ", “”]
- chunk_size为目标分割块大小数值,默认4000
- chunk_overlap为块之间的重叠大小数值,默认200
- 返回文本分割对象text_splitter后,使用split_documents(documents)方法,对指定Document文档对象列表进行分割,返回切分好的Document文档对象列表
- 使用FAISS.from_documents(documents, embeddings)方法,加载Document列表到向量数据库,返回向量数据库对象db。参数:
- documents为要添加到向量库的Document列表。
- embedding为嵌入函数。默认为None。
- 返回向量数据库对象db后,使用as_retriever()方法,返回向量数据库检索器对象retriever
- 返回向量数据库检索器对象retriever后,可使用retriever.invoke(input)方法,搜索数据库内向量值最接近的数据。
- 使用create_retriever_tool()方法,用于将检索器对象retriever创建成工具对象。参数:
- retriever:是 任何实现了BaseRetriever接口的检索器实例(如VectorStoreRetriever、BM25Retriever等)。
- name:是 工具的唯一标识名称(Agent调用时使用的名称,需简洁无空格)。
- description:工具的功能描述(Agent根据描述决定是否调用此工具)。
代码
from langchain.tools.retriever import create_retriever_tool
from langchain_community.document_loaders import WebBaseLoader
from langchain_community.vectorstores import FAISS
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
embeddings = HuggingFaceEmbeddings(
model_name="D:/python/envs/lc/hfmodel/sentence-transformers/all-MiniLM-L6-v2",
)
# 搜索搜狗百科,猫页面
custom_headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "zh-CN,zh;q=0.9",
}
loader = WebBaseLoader(
web_path="https://baike.sogou.com/v29867.htm",
requests_kwargs={"headers": custom_headers}
)
documents = loader.load()
docs = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200,
).split_documents(documents)
vector = FAISS.from_documents(documents=docs, embedding=embeddings)
retriever = vector.as_retriever()
print(retriever.invoke("猫的特征")[0])
retriever_tool = create_retriever_tool(
retriever=retriever,
name="sogo_search",
description="搜索搜狗百科",
)
结果
USER_AGENT environment variable not set, consider setting it to identify your requests.
page_content='分类
主題
專題' metadata={'source': 'https://zh.wikipedia.org/wiki/%E7%8C%AB', 'title': '猫 - 维基百科,自由的百科全书', 'language': 'zh'}
3.创建工具列表,将工具打包成一个工具列表,任由模型选择使用。
tools = [search_tool, retriever_tool]
4.模型绑定工具
- 使用模型的bind_tools()方法,来让模型绑定工具。让模型有决定是否调用工具的输出(返回中有tool_calls属性),但不是真正执行调用工具。
- 可以用来测试。如果有输入后,模型是否会使用工具,使用了什么工具。而不是真正的调用工具。
- 参数tools为工具列表
- 返回对象使用tool_calls属性获取使用的工具信息列表
代码
# 使用以上两个工具
...
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
model = ChatOpenAI(
model="Pro/deepseek-ai/DeepSeek-V3",
openai_api_key="************",
openai_api_base="https://api.siliconflow.cn/v1",
temperature=0.7,
max_tokens=8000,
)
tools = [search_tool, retriever_tool]
model_with_tools = model.bind_tools(tools=tools)
response = model_with_tools.invoke([HumanMessage(content="你好")])
print(f"ContentString: {response.content}")
print(f"ToolCalls: {response.tool_calls}")
response = model_with_tools.invoke([HumanMessage(content="今天上海天气怎么样")])
print(f"ContentString: {response.content}")
print(f"ToolCalls: {response.tool_calls}")
结果
ContentString: 你好!有什么可以帮助你的吗?
ToolCalls: []
ContentString: 为了获取上海今天的天气信息,我需要使用一个可靠的搜索引擎来查找最新的天气数据。让我来搜索一下。
ToolCalls:
[
{
"name": "tavily_search_results_json",
"args": {"query": "今天上海天气"},
"id": "call_EOxYscVIVjttlbztWoR1CvTm",
"type": "tool_call",
}
]
三、代理和工具代理和工具代理执行器
1.原理
- 代理:一个有prompt或有历史记录等背景信息的LLM链条。根据模型和prompt来回答用户的问题
- 工具代理:一个代理,prompt内容上有可以被调用工具的列表和每个工具的调用规则。并且选中调用的工具后,指明输出的内容。(因为工具代理执行器会根据输出内容,给到工具来获取执行结果)
- 工具代理执行器:根据用户输入,先用工具代理决定是否需要调用工具,(否就直接输出结果),是就输出调用工具的参数,再使用参数执行工具,输出工具执行结果。再一次工具代理,prompt是用户的输入和工具调用后的执行结果(可能包括步骤),输出是否需要再循环使用工具代理或者输出结果给用户。
2.工具代理执行器
- 工具代理是工具代理执行器中的一步,作用是决定是否调用工具。
- 使用model.bind_tools(tools=tools)方法,是模型绑定工具。就是让模型输出AIMessage消息,并且消息内部可能有tool_calls属性。
- 使用create_tool_calling_agent()方法等,是生成一个工具代理。
- 使用AgentExecutor()方法,是生成一个工具代理执行器。
- 工具代理执行器类似LangGraph中的一个工具调用图。有工具节点和llm节点。
- 工具代理执行器流程:

四、创建工具代理和工具代理执行器
1.使用create_tool_calling_agent()方法,创建一个通用的工具调用代理对象agent,为支持工具调用(tool calling)的LLM设计。
- 注:传递model,不是model_with_tools。因为create_tool_calling_agent会在内部调用bind_tools()。
- 参数
- llm:支持工具调用功能的语言模型
- tools:工具列表
- prompt:对话提示模板,用于控制agent的行为。需要特定的提示模板。
2.create_tool_calling_agent()方法生成的Agent对象,需要特定的提示模板prompt。
- 可以使用hub下载:
prompt = hub.pull("hwchase17/openai-functions-agent")
- 内部内容组成:
代码
from langchain import hub
prompt = hub.pull("hwchase17/openai-functions-agent")
# print(prompt.messages) # 显示结构
相当于
from langchain_core.prompts import (
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
AIMessagePromptTemplate,
)
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.prompts import MessagesPlaceholder
from langchain_core.prompts import PromptTemplate
prompt = ChatPromptTemplate.from_messages(
[
SystemMessagePromptTemplate(
prompt=PromptTemplate(
input_variables=[],
input_types={},
partial_variables={},
template="You are a helpful assistant",
),
additional_kwargs={},
),
MessagesPlaceholder(variable_name="chat_history", optional=True),
HumanMessagePromptTemplate(
prompt=PromptTemplate(
input_variables=["input"],
input_types={},
partial_variables={},
template="{input}",
),
additional_kwargs={},
),
MessagesPlaceholder(variable_name="agent_scratchpad"),
]
)
- 变量agent_scratchpad作用
- agent_scratchpad是Agent的"工作区"或"草稿本",用于存储Agent在执行过程中的中间思考步骤和工具调用记录。
- agent需要使用工具,就需要在prompt中预留agent_scratchpad存储。
- 一般在prompt的最后一行,并以placeholder形式保存:
- agent_scratchpad是Agent的"工作区"或"草稿本",用于存储Agent在执行过程中的中间思考步骤和工具调用记录。
MessagesPlaceholder(variable_name="agent_scratchpad")
("placeholder", "{agent_scratchpad}")
- 具体作用包括:
- 存储工具调用历史:记录Agent调用了哪些工具。保存工具的输入参数和返回结果。维护工具调用的时间顺序
- 支持多步推理:Agent可以基于之前的工具调用结果进行下一步决策。实现复杂任务的分步执行。避免重复调用相同的工具
- 提供上下文信息:让Agent了解当前执行到哪一步。帮助Agent判断是否需要继续调用工具。为最终回答提供完整的推理链
- 调试和可观察性:开发者可以查看Agent的完整思考过程。便于调试和优化Agent的行为。提高Agent决策的透明度
- 例如
- 初始状态:agent_scratchpad为空
- 工具调用后:agent_scratchpad会包含类似这样的内容:
Thought: 我需要搜索当前天气信息
Action: time_aware_search
Action Input: {"query": "今天东莞天气"}
Observation: [搜索结果]
3.为create_tool_calling_agent()方法自定义提示模板prompt
- 为特定目的可以自定义生成工具代理执行器的prompt,如,使得工具代理执行器有时效性。
- 自定义prompt的特点
- 每次使用Agent时,会使用当前时间工具,自动地获取时间。以便问答得更有时效性。
- 问答时,自动地确认是否搜索工具,而无需用户强调使用搜索才用。
- prompt规则
- 用MessagesPlaceholder增加变量chat_history存储对话记录。放在用户输入前
- 用MessagesPlaceholder增加变量agent_scratchpad存储Agent的记录。放在最后
- 示例
代码
from langchain.agents import create_tool_calling_agent
from langchain.agents import AgentExecutor
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
...
# 创建自定义prompt,让AI更主动地使用工具
custom_prompt = ChatPromptTemplate.from_messages([
(
"system",
"""
你是一个智能助手,具有以下能力和行为准则:
1. **时间感知**:在每次对话开始时,你应该主动获取当前时间,让用户知道现在的时间。
2. **智能搜索**:当用户询问以下类型的问题时,你应该主动使用搜索工具:
- 最新新闻、时事、股价、天气等实时信息
- 你不确定或可能过时的信息
- 具体的事实查询、数据统计
- 最新的技术发展、产品信息
- 当前发生的事件
**重要**:搜索工具已经会自动在查询前添加当前时间信息,所以你可以直接使用用户的原始查询,不需要手动添加时间。
3. **主动性**:不要等待用户明确要求搜索,要根据问题内容判断是否需要搜索最新信息。
4. **工具使用原则**:
- 优先使用工具获取准确、最新的信息
- 在回答前先思考是否需要搜索或获取时间
- 将工具获取的信息整合到自然的回答中
请始终保持友好、专业的态度,并主动使用可用的工具来提供最准确和最新的信息。
""",
),
MessagesPlaceholder(variable_name="chat_history"),
("human", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad"),
])
agent = create_tool_calling_agent(llm=llm, tools=tools, prompt=custom_prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
...
4.使用AgentExecutor()方法,将一个工具调用Agent对象,创建成一个工具代理执行器对象agent_executor。
- 与Agent区别,AgentExecutor是对Agent调用工具的整个流程的监管(包括执行流程管理和错误处理机制)。是Agent的一个封装。
- 例如,AgentExecutor会使用工具调用Agent来调用工具,但是发现结果不理想,或者调用时输入参数有误,会自动地修改输入重新调用多一次Agent来获取结果,直到结果满意为止。
- AgentExecutor类似于LangGraph的图,也是整个工作流流程地监管。
- 核心功能:
- 负责调用和控制Agent直到获得最终输出
- 迭代执行Agent返回的动作
- 持续这个过程直到生成最终答案
- 参数
- agent:用于创建计划和决定执行步骤的代理实例
- tools:代理可以调用的有效工具列表
- max_iterations:最大执行步骤数(默认15步)模型最大执行次数
- max_execution_time:执行循环的最大时间限制
- early_stopping_method:提前停止方法(‘force’或’generate’)
- handle_parsing_errors:执行失败是否不报错。默认False会报错,True则直接输出结果。
- 设为True时,当Agent输出的结果无法被「输出解析器 (OutputParser)」成功解析时,让AgentExecutor不会直接抛出程序崩溃的异常,而是进行「容错处理」并继续执Agent流程,保障Agent稳定运行。
- 如,使用ReAct风格代理(hwchase17/react),该解析器要求模型严格输出结构化标记:Thought:,Action:,Action Input:,Final Answer:。而模型输出是一段普通说明(还包含了反引号代码块和中文列表),没有包含必须的“Final Answer:”或正确的Action/Thought标记,解析器无法识别,触发错误。无法继续。设为True后,复跑验证结果正常,代理成功使用工具、并给出了最终答案。
- verbose:是否显示详细日志
5.使用代理执行器对象agent_executor的invoke方法执行
代码
from langchain_openai import ChatOpenAI
from langchain_tavily import TavilySearch
from langchain.tools.retriever import create_retriever_tool
from langchain_community.document_loaders import WebBaseLoader
from langchain_community.vectorstores import FAISS
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_huggingface import HuggingFaceEmbeddings
from langchain import hub
from langchain.agents import create_tool_calling_agent
from langchain.agents import AgentExecutor
# 模型
model = ChatOpenAI(
model="Pro/deepseek-ai/DeepSeek-V3",
openai_api_key="************",
openai_api_base="https://api.siliconflow.cn/v1",
temperature=0.7,
max_tokens=8000,
)
embeddings = HuggingFaceEmbeddings(
model_name="D:/python/envs/langchain2/hfmodel/sentence-transformers/all-MiniLM-L6-v2",
)
# 工具列表
search_tool = TavilySearch(
max_results=1, tavily_api_key="************"
)
loader = WebBaseLoader("https://zh.wikipedia.org/wiki/%E7%8C%AB")
documents = loader.load()
docs = RecursiveCharacterTextSplitter(
chunk_size=1000, chunk_overlap=200,
).split_documents(documents)
vector = FAISS.from_documents(docs, embeddings)
retriever = vector.as_retriever()
retriever_tool = create_retriever_tool(
retriever=retriever,
name="wiki_search",
description="搜索维基百科",
)
tools = [search_tool, retriever_tool]
# 创建Agent执行器对象
prompt = hub.pull("hwchase17/openai-functions-agent")
# print(prompt.messages) # 显示结构
agent = create_tool_calling_agent(llm=model, tools=tools, prompt=prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
# 执行Agent执行器
# print(agent_executor.invoke({"input": "你好"}))
# print(agent_executor.invoke({"input": "猫的特征"}))
print(agent_executor.invoke(input={"input": "猫的特征?今天上海天气怎么样?"}))
结果
> Entering new AgentExecutor chain...
Invoking: `wiki_search` with `{'query': '猫'}`
responded: ### 猫的特征
为了回答“猫的特征”这个问题,我会先使用维基百科搜索工具(wiki_search)来获取关于猫的科学分类、生理特征、行为特征等详细信 息。
### 今天上海天气怎么样
为了回答“今天上海天气怎么样”这个问题,我会使用搜索工具(tavily_search_results_json)查询最新的上海天气信息。
现在我先执行这两个工具的调用:
本页面最后修订于2025年5月22日 (星期四) 00:47。
本站的全部文字在知识共享 署名-相同方式共享 4.0协议之条款下提供,附加条款亦可能应用。(请参阅使用条款)
Wikipedia®和维基百科标志是维基媒体基金会的注册商标;维基™是维基媒体基金会的商标。
...
而貓喜好的磨爪物各不相同。家貓可能會選擇沙發、牆壁甚至人類的衣物等作為自己的磨爪物。
感官[编辑]
貓的感官適於狩獵。在哺乳類動物中,貓的聽覺、視覺、嗅覺、味覺、觸覺極敏銳。
Invoking: `tavily_search_results_json` with `{'query': '今天上海天气'}`
responded: ### 猫的特征
为了回答“猫的特征”这个问题,我会先使用维基百科搜索工具(wiki_search)来获取关于猫的科学分类、生理特征、行为特征等详细信 息。
### 今天上海天气怎么样
为了回答“今天上海天气怎么样”这个问题,我会使用搜索工具(tavily_search_results_json)查询最新的上海天气信息。
现在我先执行这两个工具的调用:
[{'title': '今天上海市天气_今日天气预报- 墨迹天气', 'url': 'https://tianqi.moji.com/today/china/shanghai/shanghai', 'content': '上海市今天实况:21度阴,湿度:67%,北风:1级。白天:27度,多云。 夜间:多云,19度,季节交替,天气偏凉,墨迹天气建议您穿着单衣单裤,年老体弱者最好加一件贴身的背心或是', 'score': 0.85509074}]
### 猫的特征
猫是一种常见的家养动物,具有以下主要特征:
1. **爪子**:猫的爪子尖锐且可伸缩,能够伸张或缩藏。趾底有脂肪肉垫,行走无声。
2. **感官**:猫的听觉、视觉、嗅觉、味觉和触觉都非常敏锐,非常适合狩猎。
3. **行为**:猫有磨爪的习惯,可能会选择家具或衣物作为磨爪物。
### 今天上海天气
根据最新天气预报:
- **当前实况**:21°C,阴天,湿度67%,北风1级。
- **白天**:多云,最高气温27°C。
- **夜间**:多云,最低气温19°C。
建议穿着单衣单裤,年老体弱者可以加一件背心。
> Finished chain.
# 结果
{
"input": "猫的特征?今天上海天气怎么样?",
"output": "### 猫的特征\n猫是一种常见的家养动物,具有以下主要特征:\n1. **爪子**:猫的爪子尖锐且可伸缩,能够伸张或缩藏。趾底有脂肪肉垫,行走无声。\n2. **感官**:猫的听觉、视觉、嗅觉、味觉和触觉都非 常敏锐,非常适合狩猎。\n3. **行为**:猫有磨爪的习惯,可能会选择家具或衣物作为磨爪物。\n\n### 今天上海天气\n根据最新天气 预报:\n- **当前实况**:21°C,阴天,湿度67%,北风1级。\n- **白天**:多云,最高气温27°C。\n- **夜间**:多云,最低气温19°C。\n \n建议穿着单衣单裤,年老体弱者可以加一件背心。",
}
6.代理异步使用工具
- agent异步使用工具:如果模型确认调用多个工具时,会同时的发起多个调用,不会调用完一个再接着一个。
- 异步使用工具有助提高速度。(建议异步使用工具)
- 示例:同时调用时间和tavily工具
代码
import asyncio
from langchain_openai import ChatOpenAI
from langchain_tavily import TavilySearch
from langchain_huggingface import HuggingFaceEmbeddings
from langchain import hub
from langchain.agents import create_tool_calling_agent
from langchain.agents import AgentExecutor
import datetime
from langchain_core.tools import tool
async def main():
# 模型
model = ChatOpenAI(
model="Pro/deepseek-ai/DeepSeek-V3",
openai_api_key="************",
openai_api_base="https://api.siliconflow.cn/v1",
temperature=0.7,
)
# 工具列表
search_tool = TavilySearch(
max_results=1, tavily_api_key="************"
)
@tool(
"Current_Time-tool",
description="Used to retrieve the current date and time.",
return_direct=False,
)
def current_time() -> str:
"""Get the current date and time"""
res = datetime.datetime.now().strftime("%Y年%m月%d日,%H时%M分%S秒")
return res
tools = [search_tool, current_time]
# 创建Agent执行器对象
prompt = hub.pull("hwchase17/openai-functions-agent")
agent = create_tool_calling_agent(llm=model, tools=tools, prompt=prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
# 异步执行Agent执行器
result3 = await agent_executor.ainvoke(
{"input": "2024年巴黎奥运会吉祥物是什么?现在几点?"}
)
print(result3)
# 运行异步主函数
if __name__ == "__main__":
asyncio.run(main())
相当于
{
"input": "2024年巴黎奥运会吉祥物是什么?现在几点?",
"output": "2024年巴黎奥运会的吉祥物是**弗里热(Phryge)**,它的设计灵感源自法国标志性的弗雷吉亚帽,象征着自由。 \n\n现在是**2025年7月29日,15:46**。",
}
五、创建agent方法:create_react_agent()与create_tool_calling_agent()对比
1.create_react_agent()
- create_react_agent()是基于ReAct(Reasoning+Acting)框架实现的代理。
- 特点
- 使用文本格式的思维链(chain-of-thought)来决定何时以及如何使用工具
- 代理的输出是自由格式的文本,包含思考过程和工具调用
- 需要LLM能够理解特定的提示格式
- 参数prompt建议使用"hwchase17/react"
- 工具调用成功率:98%
- 基本用法
代码
from langchain import hub
from langchain.agents import create_react_agent, AgentExecutor
from langchain_community.tools import Tool
from langchain_openai import ChatOpenAI
# 定义工具
tools = [
Tool(
name="Search",
func=search_tool,
description="Useful for searching the web"
)
]
# 获取提示模板
prompt = hub.pull("hwchase17/react")
# 创建LLM实例
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
# 创建代理
agent = create_react_agent(llm, tools, prompt)
# 创建执行器
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
# 运行代理
result = agent_executor.invoke({"input": "What's the weather in New York today?"})
2.create_tool_calling_agent()
- create_tool_calling_agent()是专为支持工具调用功能的LLM(如OpenAI的gpt-4)设计的代理。
- 特点
- 利用LLM原生的工具调用能力(OpenAI的Function Calling或Tool Calling)
- 更结构化的工具调用方式
- 通常更高效,因为不需要生成中间文本
- 需要LLM明确支持工具调用功能
- 参数prompt没有默认值
- 工具调用成功率:80%
- 基本用法
代码
from langchain import hub
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_community.tools import Tool
from langchain_openai import ChatOpenAI
# 定义工具
tools = [
Tool(
name="Search",
func=search_tool,
description="Useful for searching the web"
)
]
# 获取提示模板
prompt = hub.pull("hwchase17/openai-tools-agent")
# 创建支持工具调用的LLM实例
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
# 创建代理
agent = create_tool_calling_agent(llm, tools, prompt)
# 创建执行器
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
# 运行代理
result = agent_executor.invoke({"input": "What's the weather in New York today?"})
3.主要区别
| 特性 | create_react_agent | create_tool_calling_agent |
|---|---|---|
| 实现方式 | 基于文本的ReAct框架 | 基于LLM原生工具调用功能 |
| LLM 要求 | 任何能理解提示的LLM | 必须支持工具调用的LLM |
| 输出格式 | 自由文本,包含思考过程 | 结构化工具调用 |
| 效率 | 相对较低,需要生成更多文本 | 相对较高,直接调用工具 |
| 适用场景 | 通用场景,LLM不支持工具调用时 | LLM明确支持工具调用时 |
| 调试难度 | 较难,需要解析文本输出 | 较易,结构化输出 |
4.Function Calling与ReAct Agent
- create_react_agent()创建的是一个ReAct Agent,来调用工具。
- create_tool_calling_agent()使用Function Calling能力的模型来调用工具。
- Function Calling = 模型主动返回结构化调用指令
- ReAct Agent = 模型用“普通文本”写出 Action,ReAct框架去“读”并执行
5.选择建议
- 如果使用OpenAI等支持工具调用的模型,选用create_tool_calling_agent
- 如果追求更高的效率和可靠性,选用create_tool_calling_agent
- 如果使用不支持工具调用的模型,选用create_react_agent
- 如果需要更透明的思考过程用于调试,选用create_react_agent
6.LangChain的create_react_agent()
- 引用两种方式:
- 直接引用:create_react_agent()
- 使用agent方法:agent.create_react_agent()
- 使用agent时,必须有output_parser参数,定义输出格式。
代码
from langchain.agents import create_react_agent, AgentExecutor
...
agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
相当于
from langchain.agents.react import agent
from langchain.agents.agent import AgentExecutor
# 与from langchain.agents import AgentExecutor引入一样
...
agent = agent.create_react_agent(
llm=llm,
tools=tools,
prompt=prompt,
output_parser=out_parser
)
agent_executor = AgentExecutor(agent=text_agent, tools=tools, verbose=True)
- agent.create_react_agent()与create_react_agent()区别
- 我测试后认为:功能基本一样,可能create_react_agent()会好些。
- 示例
代码
from langchain.agents import create_react_agent, AgentExecutor
...
agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
response = agent_executor.invoke({"input": "2024年巴黎奥运会吉祥物是什么?"})
print(response)
相当于
from langchain.agents.react import agent
from langchain.agents.agent import AgentExecutor
...
text_agent = agent.create_react_agent(
llm=model,
tools=tools,
prompt=text_prompt,
output_parser=out
)
agent_executor = AgentExecutor(agent=text_agent, tools=tools, verbose=True)
response = agent_executor.invoke({"input": "2024年巴黎奥运会吉祥物是什么?"})
print(response)
- 与LangGraph的create_react_agent()不一样:
- LangGraph的create_react_agent()输出的是一个AgentExecutor,在LangGraph中可作为一个子图或节点使用。而不是一个Agent对象。
- 引用:from langgraph.prebuilt import create_react_agent
7.create_react_agent()提示词模板
- 可以使用hub下载:
prompt = hub.pull("hwchase17/react")
- 其实内部组成:
代码
from langchain import hub
prompt = hub.pull("hwchase17/react")
# print(prompt) # 显示结构
相当于
from langchain_core.prompts import PromptTemplate
prompt = PromptTemplate.from_template(
input_types = {},
partial_variables = {},
metadata = {
"lc_hub_owner": "hwchase17",
"lc_hub_repo": "react",
"lc_hub_commit_hash": "d15fe3c426f1c4b3f37c9198853e4a89b0e97ca7ea4d",
},
template = """Answer the following questions as best you can. You have access to the following tools:
{tools}
Use the following format:
Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should be one of [{tool_names}]
Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question
Begin!
Question: {input}
Thought:{agent_scratchpad}"""
)
8.create_react_agent()自定义提示词模板
- 自定义提示词模板,必须PromptTemplate定义变量input_variables为:[“input”, “tools”, “tool_names”, “agent_scratchpad”]
代码
from langchain.agents.react import agent
from langchain_core.prompts import PromptTemplate
from langchain.agents.structured_chat.output_parser import StructuredChatOutputParser
from langchain.agents.agent import AgentExecutor
# 与from langchain.agents import AgentExecutor引入一样
from langchain_openai import ChatOpenAI
from time_search_tool import TimeAwareSearchTool
model = ChatOpenAI(
model="doubao-seed-1-6-flash-250615",
openai_api_key="************",
openai_api_base="https://ark.cn-beijing.volces.com/api/v3",
)
search_tool = TimeAwareSearchTool()
tools = [search_tool]
custom_prompt = """
你拥有以下工具:
{tools}
工具名称列表:{tool_names}
按照以下格式执行:
Question: 需要回答的问题
Thought: 思考过程(必须分析是否需要使用工具)
Action: 选择工具(必须是 [{tool_names}] 之一)
Action Input: 工具输入参数
Observation: 工具返回结果
...(可重复多次)
Thought: 现在可以生成最终答案
Final Answer: 最终回答
开始!
Question: {input}
{agent_scratchpad}"""
text_prompt = PromptTemplate(
template=custom_prompt,
input_variables=["input", "tools", "tool_names", "agent_scratchpad"],
)
out = StructuredChatOutputParser()
text_agent = agent.create_react_agent(
llm=model,
tools=tools,
prompt=text_prompt,
output_parser=out
)
agent_executor = AgentExecutor(agent=text_agent, tools=tools, verbose=True)
response = agent_executor.invoke({"input": "2024年巴黎奥运会吉祥物是什么?"})
print(response)
六、链中使用代理
1.链(Chain)与代理(Agent)
- 在LangChain中,将工具(如搜索网页)结合到链(Chain)中通常需要通过代理(Agent)来实现。
- Agent可以动态选择工具并决定工具执行顺序,而普通Chain是固定流程。
- 链与代理核心概念区分
| 组件 | 特点 | 适用场景 |
|---|---|---|
| Chain | 固定顺序执行(如A→B→C) | 确定性的标准化流程 |
| Agent | 动态选择工具/链 | 需要决策的复杂任务 |
2.链中使用代理
- 在链中使用工具,一般是通过工具代理执行器。执行器的结果被链调用。
- 工具代理执行器只是链针对工具处理的一个部分。在链中,可以链式地继续操作其他步骤。
- 示例中,链条过程:
- 先使用代理对输入内容作搜索,返回结果
- 将结果再通过大语言模型进行处理,返回最终结果,输出。
代码
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_tavily import TavilySearch
from langchain.agents import AgentExecutor, create_tool_calling_agent
model = ChatOpenAI(
model="Pro/deepseek-ai/DeepSeek-V3",
openai_api_key="************",
openai_api_base="https://api.siliconflow.cn/v1",
temperature=0.7,
max_tokens=8000,
)
# 创建工具
search_tool = TavilySearch(
max_results=1, tavily_api_key="************"
)
tools = [search_tool]
# 创建Agen执行器
agent_prompt = ChatPromptTemplate.from_messages(
[
("system", "你是一个助手,可以搜索网络信息。回答要简短。"),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"), # Agent默认预留中间步骤记录
]
)
agent = create_tool_calling_agent(llm=model, tools=tools, prompt=agent_prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools)
# 构建链:搜索→总结
chain = (
RunnablePassthrough.assign(
search_results=lambda x: agent_executor.invoke({"input": x["inputx"]})
)
| ChatPromptTemplate.from_template("{operate}:{search_results}")
| model
| StrOutputParser()
)
# 执行
result = chain.invoke(
{"inputx": "2024年巴黎奥运会吉祥物是什么?", "operate": "用100字总结"}
)
print(result)
结果
2024年巴黎奥运会吉祥物名为“Phryge”(弗里吉),设计灵感源自法国象征自由的弗里吉亚帽。它以拟人化形象呈现,代表法国历史与奥运精神,传递团结与包容的理念。
3.异步执行链
- 异步agent的工具调用。提高速度。
代码
import asyncio
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_tavily import TavilySearch
from langchain.agents import AgentExecutor, create_tool_calling_agent
import datetime
from langchain_core.tools import tool
model = ChatOpenAI(
model="Pro/deepseek-ai/DeepSeek-V3",
openai_api_key="************",
openai_api_base="https://api.siliconflow.cn/v1",
)
# 创建工具
search_tool = TavilySearch(
max_results=1, tavily_api_key="************"
)
@tool(
"Current_Time-tool",
description="Used to retrieve the current date and time.",
return_direct=False,
)
def current_time() -> str:
"""Get the current date and time"""
res = datetime.datetime.now().strftime("%Y年%m月%d日,%H时%M分%S秒")
return res
tools = [search_tool, current_time]
# 创建Agent执行器
agent_prompt = ChatPromptTemplate.from_messages(
[
("system", "你是一个助手,可以搜索网络信息。回答要简短。"),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"), # Agent默认预留中间步骤记录
]
)
agent = create_tool_calling_agent(llm=model, tools=tools, prompt=agent_prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
# 异步函数:搜索和时间
async def get_search_results(x):
"""异步获取搜索结果"""
return await agent_executor.ainvoke({"input": x["inputx"]})
# 构建异步链:搜索→总结
chain = (
RunnablePassthrough.assign(search_results=get_search_results)
| ChatPromptTemplate.from_template("{operate}:{search_results}")
| model
| StrOutputParser()
)
# 异步主函数
async def main():
"""异步主函数"""
result = await chain.ainvoke(
{"inputx": "2024年巴黎奥运会吉祥物是什么?现在几点?", "operate": "用100字总结"}
)
print(result)
# 执行异步主函数
if __name__ == "__main__":
asyncio.run(main())
结果
2024年巴黎奥运会吉祥物是弗里热(Phryge),灵感源于法国弗雷吉亚帽。当前时间为2025年7月29日15:33。(注:该时间应为假设性回答,实际需实时查询。)
七、记忆
1.手动prompt内增加记忆
- 因为prompt内有chat_history参数,用于增加历史对话记录,可手动增加
- 示例中没有使用到工具
代码
# 与上例内容一样,只是不再使用verbose=True参数,不显示操作过程
...
from langchain_core.messages import AIMessage, HumanMessage
response = agent_executor.invoke(
{
"chat_history": [
HumanMessage(content="Hi,我的名字是Jack"),
AIMessage(content="你好Jack,很高兴见到你!有什么我可以帮助你的吗?"),
],
"input": "我的名字是什么?",
}
)
print(response)
结果
{
"chat_history": [
HumanMessage(
content="Hi,我的名字是Jack", additional_kwargs={}, response_metadata={}
),
AIMessage(
content="你好Jack,很高兴见到你!有什么我可以帮助你的吗?",
additional_kwargs={},
response_metadata={},
),
],
"input": "我的名字是什么?",
"output": "你刚刚告诉我你的名字是Jack,所以我记得你的名字是Jack!有什么需要我帮忙的吗?",
}
2.使用ChatMessageHistory和RunnableWithMessageHistory保存信息
- 构建消息存储方法
- 自建一个get_session_history()方法,用于将对话记录保存到自定义的store[session_id]中
- session_id参数,用于指定需要保存的session_id。
- 返回为ChatMessageHistory实例,LangChain提供的保存对象。
- 创建一个带会话历史记录的Runnable(链条)
- 使用RunnableWithMessageHistory()方法创建一个可以输入历史记录的链条(Runnable)对象。
- runnable参数:(必需) 要包装的基础可运行对象,可以是任何实现了 Runnable 接口的 LangChain 组件
- get_session_history参数 (必需) 工厂函数,接收session_id并返回对应的聊天消息历史存储对象的函数名称
- input_messages_key 参数:(可选) 指定用户消息输入字典中的键名
- history_messages_key参数:(可选) 指定历史消息在输入字典中的键名
代码
from langchain_openai import ChatOpenAI
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_tavily import TavilySearch
from langchain.tools.retriever import create_retriever_tool
from langchain_community.document_loaders import WebBaseLoader
from langchain_community.vectorstores import FAISS
from langchain import hub
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.chat_history import BaseChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain.agents import create_tool_calling_agent, AgentExecutor
############################创建模型#####################################
model = ChatOpenAI(
model="Pro/deepseek-ai/DeepSeek-V3",
openai_api_key="************",
openai_api_base="https://api.siliconflow.cn/v1",
temperature=0.7,
max_tokens=8000,
)
embeddings = HuggingFaceEmbeddings(
model_name="D:/python/envs/lc/hfmodel/sentence-transformers/all-MiniLM-L6-v2",
)
######################创建工具代理执行器################################
search_tool = TavilySearch(
max_results=1, tavily_api_key="************"
)
loader = WebBaseLoader("https://zh.wikipedia.org/wiki/%E7%8C%AB")
docs = loader.load()
docs_list = RecursiveCharacterTextSplitter(
chunk_size=1000, chunk_overlap=200
).split_documents(docs)
vector = FAISS.from_documents(docs_list, embeddings)
retriever = vector.as_retriever()
retriever_tool = create_retriever_tool(
retriever=retriever,
name="wiki_search",
description="搜索维基百科",
)
tools = [search_tool, retriever_tool]
prompt = hub.pull("hwchase17/openai-functions-agent")
agent = create_tool_calling_agent(model, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools)
######################创建历史记录代理################################
store = {}
def get_session_history(session_id: str) -> BaseChatMessageHistory:
if session_id not in store:
store[session_id] = ChatMessageHistory()
return store[session_id]
agent_with_chat_history = RunnableWithMessageHistory(
runnable=agent_executor,
get_session_history=get_session_history,
input_messages_key="input",
history_messages_key="chat_history",
)
######################历史记录代理推理################################
response = agent_with_chat_history.invoke(
{"input": "Hi,我的名字是Jack"},
config={"configurable": {"session_id": "123"}},
)
print(response)
response = agent_with_chat_history.invoke(
{"input": "我叫什么名字?"},
config={"configurable": {"session_id": "123"}},
)
print(response)
response = agent_with_chat_history.invoke(
{"input": "我叫什么名字?"},
config={"configurable": {"session_id": "456"}},
)
print(response)
# 也可以链式调用
chain = agent_with_chat_history | (
lambda response: {"output": response["output"]}
)
print(response)
结果
{
"input": "Hi,我的名字是Jack",
"chat_history": [],
"output": "Hi Jack! Nice to meet you. How can I assist you today?",
}
###################
{
"input": "我叫什么名字?",
"chat_history": [
HumanMessage(
content="Hi,我的名字是Jack",
additional_kwargs={},
response_metadata={}
),
AIMessage(
content="Hi Jack! Nice to meet you. How can I assist you today?",
additional_kwargs={},
response_metadata={},
),
],
"output": "你刚才告诉我你的名字是Jack,有什么我可以帮你的吗?",
}
###################
{
"input": "我叫什么名字?",
"chat_history": [],
"output": "我无法知道你的真实名字,因为我没有存储或记忆个人信息的功能。如果你愿意,可以告诉我你的名字,我会尽力帮助你!或者,如果你有其他问题,我也很乐意为你解答。",
}
###################
{
"output": "你叫 **Jack**。\n\n2024年巴黎奥运会的吉祥物是 **弗里吉帽(Phryges)**。\n\n现在的时间是 **2025年7月29日,16时15分45秒**。如果你还有其他问题,随时问我哦! 😊",
}
八、Agent使用MCP工具
1.使用FastMCP创建一个MCP服务端
- 可以使用stdio或sse方式
- 示例:
- 使用stdio创建一个算数MCP,需要在客户端指明环境执行路径的python.exe
- 使用sse创建一个天气MCP,需要运行。
math_server.py代码
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Math")
@mcp.tool()
def xx(a: int, b: int) -> int:
"""对两个整数xx运算"""
return a + b + 1
@mcp.tool()
def add(a: int, b: int) -> int:
"""对两个整数相加"""
return a + b
@mcp.tool()
def multiple(a: int, b: int) -> int:
"""对两个整数相乘"""
return a * b
if __name__ == "__main__":
mcp.run(transport="stdio") # 使用标准输入输出
weather_server.py代码,需要执行:python.exe weather_server.py
from mcp.server.fastmcp import FastMCP
mcp = FastMCP(name="Weather",port=8021)
@mcp.tool()
async def get_weather(location: str) -> str:
"""获取位置的天气。"""
return f"{location}当前天气晴朗,温度 33325°C"
if __name__ == "__main__":
mcp.run(transport="sse") # 使用SSE 传输,默认端口8021
2.Agent使用MCP客户端作为工具
- 下载langchain的MCP插件:pip install langchain-mcp-adapters
- 使用MultiServerMCPClient()配置Agent的MCP客户端(MCP服务端信息)
- 使用MultiServerMCPClient()配置MCP客户端返回MCP服务端信息对象。
- 参数为MCP服务端信息字典
- MultiServerMCPClient()可以配置多个MCP客户端
- 返回MCP服务端信息对象后,使用get_tools()获取工具对象列表
- 使用LangGraph的create_react_agent()配置Agent执行器的MCP客户端(MCP服务端信息)
- 参数model为模型对象
- 参数tools为工具对象列表
- 参数prompt为Agent的提示词(有默认值可不填写,变量为messages)
- 返回一个工具代理执行器对象agent_executor(不是代理agent)。
- 异步调用示例
代码
from langchain_mcp_adapters.client import MultiServerMCPClient
from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableLambda
import asyncio
# 创建模型
model = ChatOpenAI(
model="doubao-seed-1-6-flash-250615",
openai_api_key="************",
openai_api_base="https://ark.cn-beijing.volces.com/api/v3",
)
# 定义异步函数来处理agent
async def run_agent_chain():
# 初始化MCP客户端
client = MultiServerMCPClient({
"math": {
"command": "C:\\Users\\62845\\.conda\\envs\\mcp_test\\python.exe",
"args": [r"D:\python\envs\mcp_test\math.py"],
"transport": "stdio",
},
"weather": {
"url": "http://localhost:8021/sse",
"transport": "sse",
},
})
# 创建工具代理执行器对象agent_executor
tools = await client.get_tools()
agent_executor = create_react_agent(model, tools)
################################################
# 可以直接使用代理执行器执行
# math_response = await agent_executor.ainvoke({"messages": "请问3和5进行xx运算,结果多少?"})
# print("Math Response:", math_response["messages"][-1].content)
# weather_response = await agent_executor.ainvoke({"messages": "请问北京今天天气怎么样?"})
# print("Weather Response:", weather_response["messages"][-1].content)
# response = await agent_executor.ainvoke({"messages": "请问北京今天天气怎么样?3和5进行xx运算结果多少?"})
# print(response)
################################################
# 定义agent处理函数
async def process_with_agent(inputs):
result = await agent_executor.ainvoke({"messages": inputs["user_input"]})
return result["messages"][-1].content
# 创建后处理提示模板
post_prompt = ChatPromptTemplate.from_template(
"请将以下agent回复整理成简洁的合理的最终答案:{agent_response}"
)
# 创建输出解析器
parser = StrOutputParser()
# 构建完整的链
chain = (
RunnableLambda(process_with_agent)
| {"agent_response": lambda x: x}
| post_prompt
| model
| parser
)
# 测试链
result = await chain.ainvoke({"user_input": "请问北京今天天气怎么样?3和5进行xx运算多少?"})
return result
# 运行示例
if __name__ == "__main__":
result = asyncio.run(run_agent_chain())
print(f"最终输出: {result}")
结果
最终输出: 北京今天天气晴朗,但温度888°C不符合实际情况;3和5进行xx运算结果为9不符合正常运算逻辑(3与5常见运算如加为8、乘为15等,非9)
3.mcp的uvx的json数据改为MultiServerMCPClient()里的客户端设置
- 网络上提供的mcp,使用mcp-server-sqlite为例
- 原uvx的json数据
json数据
{
"mcpServers": {
" sqlite": {
"command": "uv",
"args": [
"--directory",
"parent_of_servers_repo/servers/src/sqlite",
"run",
" mcp-server-sqlite" ,
"--db-path",
"~/test.db"
],
}
}
}
- 先用conda环境安装mcp-server-sqlite模块:
pip install mcp-server-sqlite
- 直接用python.exe代替uv,如果失败,是因为:mcp_server_sqlite 这个包没有 main.py,所以不能直接 python -m mcp_server_sqlite
- 查找包的入口点:pip show mcp-server-sqlite
- Location 字段显示目录:C:\Users\62845.conda\envs\mcp_test\Lib\site-packages\
- 在这里找mcp_server_sqlite目录,并检查有没有cli.py、init.py文件
- 再打开环境Scripts文件夹:C:\Users\62845.conda\envs\mcp_test\Scripts
- 里面应该有一个叫mcp-server-sqlite.exe或mcp-server-sqlite-script.py的文件。
- 如果有mcp-server-sqlite-script.py文件,打开:
mcp-server-sqlite-script.py代码
from mcp_server_sqlite.cli import app
...
if __name__ == "__main__":
app()
- 可以用:python -m mcp_server_sqlite.cli
- 或用:python -c “import mcp_server_sqlite.cli as cli; cli.app()”
- 相当于:uvx run mcp-server-sqlite
- 结果是:
代码
...
client = MultiServerMCPClient({
...
"sqlite": {
"command": "C:\\Users\\62845\\.conda\\envs\\mcp_test\\python.exe",
"args": [
"-m",
"mcp_server_sqlite.cli",
"--db-path",
"D:\\python\\envs\\langchain2\\db\\database.db",
],
"transport": "stdio",
},
})
...
- 如果有mcp-server-sqlite.exe文件,直接用这个exe代替python:
C:\Users\62845\.conda\envs\mcp_test\Scripts\mcp-server-sqlite.exe
- 结果是:
代码
...
client = MultiServerMCPClient({
...
"sqlite": {
"command": "C:\\Users\\62845\\.conda\\envs\\mcp_test\\Scripts\\mcp-server-sqlite.exe",
"args": [
"--db-path",
"D:\\python\\envs\\langchain2\\db\\database.db",
],
"transport": "stdio",
},
})
...
总结
本文整理了 LangChain 工具调用 Agent 的核心知识,包括工具创建、工具列表、模型绑定工具、工具代理、工具代理执行器、ReAct Agent、带记忆的 Agent,以及通过 MCP 接入外部工具服务。实际开发中,建议根据模型是否支持原生 tool calling 来选择 create_tool_calling_agent 或 create_react_agent;如果需要更强的状态控制、分支流程和可视化调试,可以进一步使用 LangGraph 构建更灵活的 Agent 工作流。
更多推荐


所有评论(0)