🟡 LangChain 高频用法
🔘语言模型调用(LLM):让 AI 开口说话
假设你要做一个问答助手,用户问“你好”,AI 得回答“こんにちは”。这需要调用外部 LLM,比如 OpenAI 的 GPT。LangChain 的 ChatOpenAI
是最常用的类,封装了模型交互。
from langchain_openai import ChatOpenAI
# 实例化 LLM
llm = ChatOpenAI(openai_api_key="your-api-key",model_name="gpt-3.5-turbo",temperature=0.)
# 调用生成回答
response = llm.invoke("你好") # invoke 是 ChatOpenAI 类里预定义的实例方法,返回对象(内容+元数据)
print(response.content) # invoke 返回的是对象,我们通常只关心文本。提取纯文本内容
🔘 提示词管理(Prompts):告诉 AI 干什么
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
# 基础提示词
prompt = ChatPromptTemplate.from_messages([
("system", "你是编程专家,回答要准确"),
("human", "{input}")
])
# 带上下文的提示词
prompt_with_history = ChatPromptTemplate.from_messages([
("system", "你是编程专家,基于上下文回答"),
MessagesPlaceholder(variable_name="chat_history"),
("human", "{input}")
])
# 测试
formatted = prompt.invoke({"input": "Python 谁发明的?"})
print(formatted)
ChatPromptTemplate
(类):LangChain 自带的类,用于创建消息模板。把多角色消息组织成标准格式,供 LLM 处理。ChatPromptTemplate.from_messages
(静态方法):接收消息列表(元组列表),参数:每个元组是(角色, 内容)
,角色可选 "system"、"human"、"ai"。,返回模板对象。把散乱的指令整合成结构化提示。MessagesPlaceholder
(类):LangChain 自带的类,创建占位符。 参数:variable_name
指定变量名(这里是 "chat_history")。动态插入历史消息,实现上下文感知。prompt.invoke
(方法):模板对象的方法,接收字典(键匹配占位符),返回ChatMessage
列表。生成最终提示,供 LLM 使用。
🔘 上下文记忆(Memory):让 AI 有记忆
from langchain.memory import ConversationBufferMemory
# 实例化内存
memory = ConversationBufferMemory(return_messages=True)
# 保存对话
memory.save_context({"input": "我叫小明"}, {"output": "好的,小明"})
# 加载历史
history = memory.load_memory_variables({})
print(history["chat_history"])
ConversationBufferMemory
(类):LangChain 自带的内存管理工具类,管理对话历史。参数:return_messages=True
确保返回List[BaseMessage]
,匹配提示词。memory.save_context
(实例方法)参数是两个字典,键是 "input" 和 "output"。保存输入和输出。memory.load_memory_variables
(实例方法)参数是个空字典,加载历史。
🔘 输出解析(Output Parsers):让结果更干净
为什么需要?
代码实践:
from langchain_core.output_parsers import StrOutputParser
parser = StrOutputParser()
raw_output = llm.invoke("Python 谁发明的?")
text = parser.invoke(raw_output)
print(text)
代码拆解:
StrOutputParser
(类):LLM 输出是AIMessage
对象,我们只想要文本。StrOutputParser
是LangChain 自带的用于解析输出。提取纯文本的类parser.invoke
(实例方法)接收AIMessage
,返回字符串。
🔘 检索增强(Retrieval / RAG):给 AI 补知识
from langchain.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
loader = PyPDFLoader("langchain_docs.pdf")
docs = loader.load()
splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
split_docs = splitter.split_documents(docs)
embeddings = OpenAIEmbeddings(openai_api_key="your-api-key")
vectorstore = FAISS.from_documents(split_docs, embeddings)
retriever = vectorstore.as_retriever()
results = retriever.invoke("最新版本")
代码拆解:
PyPDFLoader
(类):加载 PDF。- 方法:
load()
返回文档列表。 - 为什么用?把文件转为可处理的数据。
- 方法:
RecursiveCharacterTextSplitter
(类):切分文本。- 参数:
chunk_size
(块大小)、chunk_overlap
(重叠)。 - 方法:
split_documents
返回切分后的文档。 - 为什么用?大文档需分块,便于检索。
- 参数:
OpenAIEmbeddings
(类):生成嵌入。- 为什么用?把文本转为向量,供 FAISS 使用。
FAISS
(类):向量数据库。- 方法:
from_documents
(建索引)、as_retriever
(转检索器)。 - 为什么用?高效存储和查询。
- 方法:
retriever.invoke
(方法):检索相关文档。- 为什么用?返回匹配输入的文档片段。
场景: 知识库问答。
🔘 工具调用(Tools):让 AI 用外挂
为什么需要?
用户问“北京天气如何?”,模型得查 API。Tool
和 create_openai_tools_agent
实现工具调用。
代码实践:
from langchain.tools import Tool
from langchain.agents import create_openai_tools_agent
def get_weather(city):
return f"{city} 今天 20°C"
weather_tool = Tool(name="Weather", func=get_weather, description="查天气")
agent = create_openai_tools_agent(llm, [weather_tool], prompt)
代码拆解:
Tool
(类):包装函数为工具,让模型识别和调用。。参数:name
(名称)、func
(函数)、description
(描述)。create_openai_tools_agent
(函数):创建代理。参数:llm
(模型)、tools
(工具列表)、prompt
(提示词)。
在 langchain
中,Tool
的设计本质上是为了满足以下两个核心需求:
- 动态选择:
Agent
需要根据用户的输入和上下文,从多个工具中选择最合适的工具。 - 链式集成:工具需要能够无缝地嵌入到复杂的工作流(如
Chain
或Agent
)中,与其他模块协作完成任务。
weather_tool = Tool(
name="Weather API",
func=get_weather,
description="Get the current weather for a specific location."
)
calculator_tool = Tool(
name="Calculator",
func=calculate,
description="Evaluate a mathematical expression."
)
当用户输入“纽约的天气怎么样?”时,Agent
会根据 description
判断应该调用 Weather API
工具,而不是 Calculator
工具。Tool
提供了一个统一的接口(run
方法),使得它可以轻松地嵌入到 Chain
或其他工作流中。例如:
from langchain.chains import SimpleSequentialChain
# 创建一个链
chain = SimpleSequentialChain(chains=[weather_tool, summarize_tool])
# 执行链
result = chain.run("New York")
在这个例子中,weather_tool
和 summarize_tool
被串联起来,形成一个完整的流程。如果没有 Tool
封装,你需要手动处理每个函数的调用逻辑,这会增加复杂性。如果你直接调用函数或 API,确实可以完成简单的任务,但在复杂的场景中会面临以下问题:首先是缺乏动态选择能力
直接调用函数时,你需要手动编写逻辑来决定调用哪个函数。例如:
user_input = "What's the weather in New York?"
if "weather" in user_input:
result = get_weather("New York")
elif "calculate" in user_input:
result = calculate(user_input)
else:
result = "I don't understand."
这种硬编码的方式有几个问题:
- 扩展性差:每增加一个新功能,都需要修改代码。
- 维护成本高:随着功能增多,判断逻辑会变得越来越复杂。
- 不够智能:无法利用语言模型的能力进行语义理解。
在 langchain
中,链(Chain
)是一个重要的概念,用于将多个模块串联起来完成复杂任务。如果直接调用函数,你需要手动处理每个函数的输入和输出格式,确保它们能够无缝协作。例如:
def chain_workflow(input):
step1_result = get_weather(input)
step2_result = summarize(step1_result)
return step2_result
这种方式的问题在于:
- 耦合性强:每个步骤都紧密依赖于前一个步骤的输出格式。
- 灵活性差:如果需要调整工作流(如插入新步骤),需要修改整个代码结构。
而使用 Tool
封装后,每个工具都可以通过统一的接口被调用,简化了链式集成的过程。
Tool
的动态选择与链式集成示例
以下是一个完整的示例,展示如何使用 Tool
实现动态选择和链式集成:
(1)定义工具
from langchain.tools import Tool
def get_weather(location: str) -> str:
return f"The weather in {location} is sunny."
def calculate(expression: str) -> str:
return str(eval(expression))
weather_tool = Tool(
name="Weather API",
func=get_weather,
description="Get the current weather for a specific location."
)
calculator_tool = Tool(
name="Calculator",
func=calculate,
description="Evaluate a mathematical expression."
)
(2)创建 Agent
并动态选择工具
from langchain.agents import initialize_agent, AgentType
from langchain.llms import OpenAI
# 初始化语言模型
llm = OpenAI(temperature=0)
# 初始化 Agent
agent = initialize_agent(
tools=[weather_tool, calculator_tool],
llm=llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True
)
# 用户输入
user_input = "What's the weather in New York?"
response = agent.run(user_input)
print(response) # 输出:The weather in New York is sunny.
在这个例子中,Agent
根据用户输入动态选择了 Weather API
工具。
(3)创建链并集成工具
from langchain.chains import SimpleSequentialChain
# 创建链
chain = SimpleSequentialChain(chains=[weather_tool, calculator_tool])
# 执行链
result = chain.run("New York")
print(result)
🔘 链式组合(Runnable / LCEL):搭流水线
from langchain_core.runnables import RunnablePassthrough
chain = (
RunnablePassthrough.assign(history=lambda x: "历史")
| prompt
| llm
| parser
)
result = chain.invoke({"input": "你好"})
- RunnablePassthrough 是一个类,属于 LangChain 的 Runnable 家族,核心作用是“透传”(pass through),也就是把输入原封不动地传递下去,同时可以选择性地做一些加工,即如果想动态的再去加工这次的输入,用方法:
assign
添加字段。(在 LCEL 中,链是通过 |(管道符)串起来的,每个环节的输出是下一个环节的输入。RunnablePassthrough.assign 的特别之处在于,它能让你在链的某个阶段“插一脚”,往输入里塞点额外的东西,而不干扰主流程。)
🟡 LangChain 实战体验
假设我们正在打造一个智能助手,它的任务很简单:能记住用户的对话历史并根据上下文回答问题就行。用户先说“我叫小明”,然后问“我叫什么名字?”,助手应该回答“你叫小明”。这个需求虽然基础,但涵盖了 LangChain 的核心能力:通过“链”组合模块,实现上下文感知的问答。我们从头开始设计,把 LangChain 的关键组件逐步融入,配上代码,一步步构建这个助手。
🔘ChatOpenAI LLM
首先,我们需要一个“大脑”来生成回答,也就是调用语言模型的节点。假设我们选择 OpenAI 的 GPT-3.5-turbo 模型作为助手的内核。LangChain 提供了自带的对象 ChatOpenAI
,我们可以创建一个实例,命名为 LLMAPI
,并设置 API 密钥、模型名称和温度参数。温度设为 0.7,表示回答稍微有点创意但不失准确。这个节点就像助手的“思考中枢”,准备好接收输入并输出回答。
from langchain_openai import ChatOpenAI
# 创建 LLM 节点
LLMAPI = ChatOpenAI(
openai_api_key="your-api-key", # 替换为你的实际密钥
model_name="gpt-3.5-turbo",
temperature=0.7
)
🔘ChatPromptTemplate 模板
有了“大脑”,下一步是设计提示词,告诉模型它的身份和任务。LangChain 用自带的对象 ChatPromptTemplate
来实现这个功能,它的方法 from_messages
接受一个消息列表,每个消息由角色和内容组成。我们先定义一个 system
角色,内容是“你是一个智能助手,根据用户的提问和上下文提供准确的回答”,这给助手定了个基调。但如果只写 system
和用户的当前输入(human
角色,用 {input}
表示),助手就只能看到眼前的问题,无法记住之前的对话,这显然无法满足我们的场景需求。
为了让助手有“记忆”,我们引入 LangChain 自带的对象 MessagesPlaceholder
。它像一个动态插槽,可以插入对话历史。我们给它取个名字 chat_history
,插在 system
和 human
之间。这样,提示词模板就包含三部分:系统指令、历史消息、当前输入。这个节点我们命名为 Prompt
,它不仅是输入的起点,还通过 MessagesPlaceholder
搭建了上下文的桥梁。
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
# 创建提示词节点
Prompt = ChatPromptTemplate.from_messages([
("system", "你是一个智能助手,根据用户的提问和上下文提供准确的回答。"),
MessagesPlaceholder(variable_name="chat_history"), # 动态插入对话历史
("human", "{input}") # 用户当前输入
])
🔘ConversationBufferMemory 记忆
但这里有个问题:chat_history
从哪里来?MessagesPlaceholder
只是个占位符,不会自己生成历史。这就需要一个专门管理上下文的节点。有人可能会误以为 LangChain 的 StrOutputParser
是干这个的,因为名字里有“Parser”,听起来像在解析上下文。但这是个易混淆点——StrOutputParser
的实际作用是把模型的复杂输出(比如 AIMessage
对象)解析成简单字符串,跟上下文管理无关。真正的“记忆库”应该是 LangChain 自带的对象 ConversationBufferMemory
。我们创建一个实例 memory
,设置 return_messages=True
,确保它返回的消息格式(List[BaseMessage]
)能匹配 MessagesPlaceholder
的需求。
from langchain.memory import ConversationBufferMemory
# 创建上下文节点
memory = ConversationBufferMemory(return_messages=True) # 保存并返回消息历史
🔘StrOutputParser 与 RunnablePassthrough
现在,我们有了三个核心部件:LLMAPI
(模型)、Prompt
(提示词)、memory
(上下文)。但它们还得串起来形成一个“链”,这就要用到 LangChain 的 LCEL 语法,那根竖杠 |
表示前一个节点的输出作为后一个节点的输入。不过,顺序得设计好。如果写成 LLMAPI | Prompt
,就像先让模型说话再告诉它说什么,逻辑不通。正确的流程是:先准备输入(提示词 + 上下文),再送给模型,最后处理输出。
假设用户输入“我叫小明”,我们希望链能自动加载历史(如果有),组合提示,然后生成回答,最后保存上下文。为此,我们需要一个“输入装配”步骤。LangChain 提供了自带对象 RunnablePassthrough
,它能传递输入并动态添加字段。我们用它的 assign
方法从 memory
加载 chat_history
,这就像在输入里加了个“记忆包”。然后,这个输入流入 Prompt
,生成完整的消息列表,再交给 LLMAPI
生成回答。模型输出可能是复杂对象,我们用 StrOutputParser
解析成字符串。
🔘完整的链
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
# 创建输出解析器
parser = StrOutputParser()
# 构建链
chain = (
RunnablePassthrough.assign(chat_history=lambda x: memory.load_memory_variables({})["chat_history"])
| Prompt
| LLMAPI
| parser
)
让我们运行一下,看看效果。第一次,用户输入“我叫小明”:
# 测试第一次输入
input_text = "我叫小明"
result = chain.invoke({"input": input_text})
print(result) # 输出类似: "好的,小明,我记住了"
# 保存对话历史
memory.save_context({"input": input_text}, {"output": result})
第二次,用户问“我叫什么名字?”:
# 测试第二次输入
result2 = chain.invoke({"input": "我叫什么名字?"})
print(result2) # 输出: "你叫小明"
整个过程是这样的:用户输入“我叫小明”后,RunnablePassthrough
检查 memory
,发现历史为空,就只带着当前输入走下去。Prompt
把系统指令和输入组合成提示,LLMAPI
生成回答,parser
解析成字符串。保存到 memory
后,第二次输入“我叫什么名字?”时,RunnablePassthrough
从 memory
加载历史,Prompt
组合出包含“小明”的提示,模型看到上下文,自然回答“你叫小明”。环环相扣,上下文无缝衔接。
这个链是“顺序型”的基础版本。如果场景复杂,比如用户问“今天天气怎么样?”,我们可以用 RunnableBranch
加判断逻辑,或者在 Prompt
前挂载检索器实现 RAG,从外部数据源找答案。每个节点还能扩展,比如加数据清洗、工具调用,潜力无限。
我们已经有一个能记住对话历史的智能助手,比如用户说“我叫小明”,再问“我叫什么名字?”,它能回答“你叫小明”。但现在,场景升级了:用户可能问“Python 的创始人是谁?”(需要外部知识库)、“我的订单号 12345 的状态是什么?”(需要查 MySQL 数据库)、“输入里有脏话怎么办?”(需要数据清洗),甚至“今天北京的天气如何?”(需要调用外部 API)。这些需求超出了基础模型的能力,我们需要拓展每个节点,让助手变得更强大。以下是逐步实现的过程。
🔘挂载 RAG,引入外部知识库
假设用户问“Python 的创始人是谁?”,模型可能不知道,或者回答不准确。我们可以通过 RAG(Retrieval-Augmented Generation)从外部知识库检索信息,增强回答。LangChain 支持 RAG 的核心是“检索器”(Retriever),我们可以把这个功能挂载在 Prompt
节点之前,作为输入的增强步骤。
想象我们有一堆关于编程历史的 PDF 文档,我们先用 LangChain 自带的对象 PyPDFLoader
加载这些文档,再用 RecursiveCharacterTextSplitter
(自带对象)切分成小块,然后用 FAISS
(向量数据库)和 OpenAIEmbeddings
(自带对象)构建索引,形成一个检索器 retriever
。这个检索器能根据用户输入找到相关文档片段。
from langchain.document_loaders import PyPDFLoader(PDF加载模块)
from langchain.text_splitter import RecursiveCharacterTextSplitter(切分模块)
from langchain_openai import OpenAIEmbeddings(嵌入模块)
from langchain.vectorstores import FAISS(向量数据库)
# 加载外部知识库(假设有一堆 PDF 文件)
loader = PyPDFLoader("programming_history.pdf")
documents = loader.load()
# 切分文档
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
docs = text_splitter.split_documents(documents)
# 创建向量数据库和检索器
embeddings = OpenAIEmbeddings(openai_api_key="your-api-key")
vectorstore = FAISS.from_documents(docs, embeddings)
retriever = vectorstore.as_retriever()
现在,我们把 retriever
融入链中。通过自带对象 RunnablePassthrough
,我们在输入处理时添加检索结果。Prompt
模板也要调整,增加一个 {context}
字段来接收检索到的内容。这样,链的第一步变成了:接收用户输入,检索相关文档,组合成提示。
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
# 调整 Prompt,加入检索上下文
Prompt = ChatPromptTemplate.from_messages([
("system", "你是一个智能助手,根据用户的提问、上下文和外部知识提供准确回答。外部知识:{context}"),
MessagesPlaceholder(variable_name="chat_history"),
("human", "{input}")
])
🔘连接本地 MySQL 数据库
假设用户问“我的订单号 12345 的状态是什么?”,我们需要从本地 MySQL 数据库查询订单状态。LangChain 提供了与 SQL 数据库交互的工具,我们可以用自带对象 SQLDatabase
和 SQLDatabaseChain
来实现。但为了更灵活,我们创建一个自定义工具,挂载到链的某个节点。
先定义一个函数 query_order_status
,用 Python 的 mysql-connector
连接数据库并查询:
import mysql.connector
def query_order_status(order_id):
conn = mysql.connector.connect(
host="localhost",
user="your_username",
password="your_password",
database="shop_db"
)
cursor = conn.cursor()
cursor.execute("SELECT status FROM orders WHERE order_id = %s", (order_id,))
result = cursor.fetchone()
conn.close()
return result[0] if result else "订单未找到"
然后,用 LangChain 自带对象
Tool
将这个函数包装成工具,命名为order_lookup_tool
,并集成到链中。
我们可以在 LLMAPI
节点后加一个工具调用步骤,但更优雅的方式是让模型自己决定是否调用工具,这需要用到 LangChain 的 Agent 机制。稍后会整合。
from langchain.tools import Tool
order_lookup_tool = Tool(
name="OrderLookup",
func=query_order_status,
description="根据订单号查询订单状态"
)
🔘数据清洗
假设用户输入“我操,Langchian这玩意儿到底谁发明的?”,我们不希望脏话直接传给模型。数据清洗可以放在输入处理的早期,挂载到 RunnablePassthrough
节点。我们定义一个清洗函数 clean_input
,用简单规则替换脏话,然后用自带对象 RunnableLambda
包装成可执行节点。
from langchain_core.runnables import RunnableLambda
def clean_input(inputs):
text = inputs["input"]
dirty_words = {"我操": "哎呀", "操": "哎"} # 简单替换规则
for dirty, clean in dirty_words.items():
text = text.replace(dirty, clean)
inputs["input"] = text
return inputs
cleaner = RunnableLambda(clean_input)
RunnableLambda
是 langchain
中的一个工具,用于将普通的 Python 函数包装成一个可以在链(Chain)或工作流中执行的节点。它将函数集成到链中,让普通函数可以像其他模块一样被链式调用。Tool
和 RunnableLambda
都可以封装函数,但它们的设计目的和适用场景完全不同:Tool
是为 Agent
动态选择工具而设计的。它通过 description
提供语义化信息,让 LLM 根据用户输入决定是否调用某个工具。Tool
通常用于封装外部 API 或复杂功能(如天气查询、计算器等),这些功能需要在运行时根据上下文动态调用。数据清洗是一个固定的预处理步骤,与用户意图无关,也不需要 LLM 来决定是否执行。因此,使用 Tool
是不必要的。:RunnableLambda
适用于那些不需要动态选择、只需要按顺序执行的逻辑。它直接将普通函数包装成链中的一个节点,无需额外的语义化描述或动态选择机制。相比 Tool
,RunnableLambda
更加轻量,适合处理简单的任务(如数据清洗、格式转换等)。
🔘 调用外部 API 工具
假设用户问“今天北京的天气如何?”,我们需要调用天气 API(比如 OpenWeatherMap)。定义一个函数 get_weather
,用 requests
获取数据,然后包装成工具:
import requests
def get_weather(city):
api_key = "your_weather_api_key"
url = f"http://api.openweathermap.org/data/2.5/weather?q={city}&appid={api_key}&units=metric"
response = requests.get(url).json()
if response.get("cod") == 200:
temp = response["main"]["temp"]
return f"{city} 今天温度是 {temp}°C"
return "无法获取天气信息"
weather_tool = Tool(
name="WeatherCheck",
func=get_weather,
description="查询指定城市的天气"
)
🔘 整合所有节点,构建完整链
现在,我们有 RAG 检索器、订单查询工具、数据清洗、天气工具,怎么把它们整合呢?单纯的顺序链不够用了,因为模型需要根据输入决定调用哪个工具。这时候,LangChain 的 Agent 机制派上用场。我们用自带对象 create_openai_tools_agent
创建一个代理,让模型自己选择工具,同时保留上下文记忆。
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.memory import ConversationBufferMemory
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain.agents import create_openai_tools_agent, AgentExecutor
# LLM 节点
LLMAPI = ChatOpenAI(openai_api_key="your-api-key", model_name="gpt-3.5-turbo", temperature=0.7)
# 提示词节点(含 RAG 上下文)
Prompt = ChatPromptTemplate.from_messages([
("system", "你是一个智能助手,根据用户的提问、上下文和外部知识提供准确回答。外部知识:{context}"),
MessagesPlaceholder(variable_name="chat_history"),
("human", "{input}")
])
# 上下文记忆
memory = ConversationBufferMemory(return_messages=True)
# 工具列表
tools = [order_lookup_tool, weather_tool]
# 构建带 RAG 和清洗的输入链
input_chain = (
cleaner # 数据清洗
| RunnablePassthrough.assign(context=lambda x: retriever.get_relevant_documents(x["input"])) # RAG 检索
| RunnablePassthrough.assign(chat_history=lambda x: memory.load_memory_variables({})["chat_history"]) # 加载历史
)
# 创建 Agent
agent = create_openai_tools_agent(LLMAPI, tools, Prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, memory=memory)
# 测试
print(agent_executor.invoke({"input": "我叫小明"})) # 输出:{"output": "好的,小明,我记住了"}
print(agent_executor.invoke({"input": "我叫什么名字?"})) # 输出:{"output": "你叫小明"}
print(agent_executor.invoke({"input": "Python 的创始人是谁?"})) # 输出:{"output": "Python 的创始人是 Guido van Rossum"}
print(agent_executor.invoke({"input": "我的订单号 12345 的状态是什么?"})) # 输出:{"output": "订单状态:已发货"}
print(agent_executor.invoke({"input": "我操,今天北京天气如何?"})) # 输出:{"output": "哎呀,北京今天温度是 15°C"}
整个链的流程是这样的:用户输入先经过 cleaner
清洗脏话,然后 RunnablePassthrough
加载 RAG 检索结果和对话历史,组合成完整输入。Prompt
把这些塞进提示模板,交给 LLMAPI
。模型通过 Agent 机制判断是否调用工具(订单查询或天气 API),最后输出回答并保存到 memory
。每个节点都得到了拓展:Prompt
加了 RAG 上下文,输入链加了清洗和检索,LLMAPI
通过 Agent 支持工具调用。