文章目录
- LangChain中SingleAction Agent与ReAct Agent
-
- 一、核心概念对比
- 二、详细对比表
- 三、SingleAction Agent实现示例
- 四、ReAct Agent类型及示例
- 五、选择指南
- 六、性能优化建议
LangChain中SingleAction Agent与ReAct Agent
一、核心概念对比
1. SingleAction Agent (单动作代理)
特点:
- 每次只执行一个动作(调用一个工具或直接返回LLM响应)
- 不进行多步推理循环
- 轻量级实现,适合简单任务
典型架构:
输入 → 决策(选择工具或直接响应)→ 执行 → 输出
2. ReAct Agent (推理+动作代理)
特点:
- 结合推理(Reasoning)和动作(Acting)的循环过程
- 支持多步决策和工具链调用
- 适合复杂任务处理
典型架构:
思考 → 决定动作 → 执行 → 观察结果 → 循环直到完成任务
二、详细对比表
特性 | SingleAction Agent | ReAct Agent |
---|---|---|
执行方式 | 单步执行 | 多步循环执行 |
复杂度 | 简单任务 | 复杂任务 |
工具支持 | 0-1个工具 | 多个工具协同 |
历史记忆 | 默认无 | 部分类型支持 |
资源消耗 | 低 | 较高 |
典型应用 | 简单查询、直接响应 | 数学计算、搜索、多步问题分解 |
实现类 | LLMSingleActionAgent |
ZeroShotReactDescription 等 |
三、SingleAction Agent实现示例
from langchain.agents import Tool, LLMSingleActionAgent, AgentExecutor
from langchain.chains import LLMChain
from langchain_openai import ChatOpenAI
import os
# 1. 准确定义工具(名称和描述要清晰)
def get_word_length(word: str) -> int:
return len(word)
tools = [
Tool(
name="字符串长度计算", # 工具名称必须唯一且明确
func=get_word_length,
description="计算英文单词的长度,输入一个单词,返回它的字符数"
)
]
# 2. 重构Prompt模板(强制要求Final Answer)
# ========== ReAct风格Prompt与Parser ===========
from langchain.prompts import StringPromptTemplate
REACT_AGENT_TMPL = """你是一个帮助用户解决问题的助手。
你可以使用以下工具:
{tools}
按照以下格式回答问题:
---
Question: 用户的问题
Thought: 我需要思考如何回答这个问题
Action: 工具名称
Action Input: 工具的输入
Observation: 工具返回的结果
...(这个思考/行动/行动输入/观察可以重复几次)
Thought: 现在我知道答案了
Final Answer: 给用户的最终答案
---
注意:
1. 回答要专业、简洁、准确
2. 如果需要调用工具请严格按照格式输出,否则直接输出Final Answer
Question: {input}
{agent_scratchpad}
"""
class ReActPromptTemplate(StringPromptTemplate):
"""
:function: ReActPromptTemplate
:param template: 模板字符串
:param tools: 工具列表
:return: 格式化后的prompt
"""
template: str
tools: list
def format(self, **kwargs) -> str:
intermediate_steps = kwargs.pop("intermediate_steps")
thoughts = ""
for action, observation in intermediate_steps:
thoughts += action.log
thoughts += f"\nObservation: {
observation}\nThought: "
kwargs["agent_scratchpad"] = thoughts
kwargs["tools"] = "\n".join([f"{
tool.name}: {
tool.description}" for tool in self.tools])
return self.template.format(**kwargs)
prompt = ReActPromptTemplate(
template=REACT_AGENT_TMPL,
tools=tools,
input_variables=["input", "intermediate_steps"]
)
import re
from langchain.agents import AgentOutputParser
from langchain.schema import AgentAction, AgentFinish
class ReActOutputParser(AgentOutputParser):
"""
:function: ReActOutputParser
:param text: LLM输出
:return: AgentAction 或 AgentFinish
"""
def parse(self, text: str):
# 检查Final Answer
if "Final Answer:" in text:
return AgentFinish(
return_values={
"output": text.split("Final Answer:")[-1].strip()},
log=text,
)
# 尝试解析Action结构
match = re.search(r"Action\s*:(.*?)\nAction Input\s*:(.*)", text, re.DOTALL)
if match:
action = match.group(1).strip()
action_input = match.group(2).strip()
return AgentAction(tool=action, tool_input=action_input, log=text)
# 兜底:直接输出
return AgentFinish(return_values={
"output": text.strip()}, log=text)
# 3. 创建llm
BASE_URL="https://dashscope.aliyuncs.com/compatible-mode/v1"
MODEL = "qwen-turbo"
API_KEY = os.getenv('DASHSCOPE_API_KEY')
llm = ChatOpenAI(
model= MODEL, # 默认的大模型为GPT-3.5-turbo,比较便宜
openai_api_base= BASE_URL,
openai_api_key= API_KEY
)
#4. Create LLMChain first
llm_chain = LLMChain(llm=llm, prompt=prompt)
# 5. Create output parser
output_parser = ReActOutputParser()
# 6. 定义的工具名称
tool_names = [tool.name for tool in tools]
# 7. 定义SingleActionAgent
agent = LLMSingleActionAgent(
llm_chain=llm_chain,
output_parser=output_parser,
allowed_tools=tool_names,
stop=["\nObservation:"]
)
# 8. 执行时传入工具描述
agent_executor = AgentExecutor.from_agent_and_tools(
agent=agent,
tools=tools,
verbose=True,
max_iterations=5,
)
# 9. 运行(确保输入格式正确)
try:
result = agent_executor.run("单词'hello'的长度是多少?")
print(f"执行结果: {
result}")
except Exception as e:
print(f"执行过程中出现错误: {
str(e)}")
运行输出结果如下
> Entering new AgentExecutor chain...
---
Thought: 我需要计算单词'hello'的长度。
Action: 字符串长度计算
Action Input: hello
Observation:5
我现在知道答案了。
Final Answer: 单词'hello'的长度是5。
> Finished chain.
执行结果: 单词'hello'的长度是5。
四、ReAct Agent类型及示例
1. 用agent = ZeroShotAgent 定义agent.
特点:零样本学习,不保留历史
适用场景:单轮任务,不需要上下文记忆,但实际经过对memory的配置和prompt配合,也能实现上下文记忆。
示例程序总结:注意定义agent = ZeroShotAgent,需要定义llm_chain,prompt和tools这几个参数。
agent = ZeroShotAgent(
llm_chain=LLMChain(llm=llm, prompt=PromptTemplate.from_template(prefix + suffix)),
tools=tools,
verbose=True
)
完整示例,可成功执行
from langchain.agents import Tool, ZeroShotAgent, AgentExecutor
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
import os
# 1. 定义一个简单的加法计算器工具
def simple_add(expression: str) -> str:
"""简单的加法计算器"""
try:
# 移除所有空格和引号
expression = expression.strip().strip('"\'')
# 分割数字
numbers = expression.split('+')
# 转换为整数并求和
result = sum(int(num.strip()) for num in numbers)
return str(result)
except Exception as e:
return f"计算失败:{
str(e)}"
tools = [
Tool(
name="SimpleAdd",
func=simple_add,
description="简单的加法计算器,输入格式为'数字+数字',例如:1+2"
)
]
# 2. 创建ZeroShotAgent的提示模板
prefix = """你是一个帮助用户解决问题的助手。你可以使用以下工具:
{tools}
请使用以下格式:
Question: 输入的问题
Thought: 你需要思考如何解决这个问题
Action: 要使用的工具名称
Action Input: 工具的输入
Observation: 工具的输出
... (这个思考/行动/观察可以重复多次)
Thought: 我现在知道最终答案
Final Answer: 对原始输入问题的最终答案
现在开始:
Question: {input}
"""
suffix = """
{agent_scratchpad}
"""
# 创建llm
BASE_URL="https://dashscope.aliyuncs.com/compatible-mode/v1"
MODEL = "qwen-turbo"
API_KEY = os.getenv('DASHSCOPE_API_KEY')
llm = ChatOpenAI(
model= MODEL, # 默认的大模型为GPT-3.5-turbo,比较便宜
openai_api_base= BASE_URL,
openai_api_key= API_KEY
)
# 创建agent
agent = ZeroShotAgent(
llm_chain=LLMChain(llm=llm, prompt=PromptTemplate.from_template(prefix + suffix)),
tools=tools,
verbose=True
)
# 执行
agent_executor = AgentExecutor.from_agent_and_tools(
agent=agent,
tools=tools,
verbose=True,
max_iterations=10
)
# 运行
result = agent_executor.invoke({
"input": "计算 1 + 2 等于多少?",
"tools": "\n".join([f"{
tool.name}: {
tool.description}" for tool in tools])
})
print("最终输出:", result["output"])
输出结果如下:
> Entering new AgentExecutor chain...
Thought: 这是一个简单的加法计算,我可以直接使用SimpleAdd工具来计算。
Action: SimpleAdd
Action Input: 1+2
Observation: 3
Thought:我现在知道最终答案。
Final Answer: 1 + 2 等于 3。
> Finished chain.
最终输出: 1 + 2 等于 3。
在此基础上,我增加了工具,使其可以自行选择合适的工具进行处理
from langchain.agents import Tool, ZeroShotAgent, AgentExecutor
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
import os
# 1. 定义工具函数
def simple_add(expression: str) -> str:
"""简单的加法计算器"""
try:
# 移除所有空格和引号
expression = expression.strip().strip('"\'')
# 分割数字
numbers = expression.split('+')
# 转换为整数并求和
result = sum(int(num.strip()) for num in numbers)
return str(result)
except Exception as e:
return f"计算失败:{
str(e)}"
def get_word_length(word: str) -> str:
"""计算字符串长度"""
try:
# 移除所有空格和引号
word = word.strip().strip('"\'')
return str(len(word))
except Exception as e:
return f"计算失败:{
str(e)}"
# 2. 创建工具列表
tools = [
Tool(
name="SimpleAdd",
func=simple_add,
description="简单的加法计算器,输入格式为'数字+数字',例如:1+2"
),
Tool(
name="WordLength",
func=get_word_length,
description="计算字符串长度,输入一个字符串,返回它的字符数,例如:'hello'"
)
]
# 3. 创建ZeroShotAgent的提示模板
prefix = """你是一个帮助用户解决问题的助手。你可以使用以下工具:
{tools}
请使用以下格式:
Question: 输入的问题
Thought: 你需要思考如何解决这个问题
Action: 要使用的工具名称
Action Input: 工具的输入
Observation: 工具的输出
... (这个思考/行动/观察可以重复多次)
Thought: 我现在知道最终答案
Final Answer: 对原始输入问题的最终答案
现在开始:
Question: {input}
"""
suffix = """
{agent_scratchpad}
"""
# 创建llm
BASE_URL="https://dashscope.aliyuncs.com/compatible-mode/v1"
MODEL = "qwen-turbo"
API_KEY = os.getenv('DASHSCOPE_API_KEY')
llm = ChatOpenAI(
model= MODEL, # 默认的大模型为GPT-3.5-turbo,比较便宜
openai_api_base= BASE_URL,
openai_api_key= API_KEY
)
# 创建agent
agent = ZeroShotAgent(
llm_chain=LLMChain(llm=llm, prompt=PromptTemplate.from_template(prefix + suffix