在LangChain框架体系里,代理(Agent)扮演着智能任务执行者的关键角色。它区别于普通的链式结构,能够依据任务需求,动态调用不同工具(Tool)、结合语言模型的推理能力,自主规划执行步骤并完成复杂任务。无论是智能问答、代码生成,还是数据分析等场景,代理都可通过灵活组合工具与推理逻辑,将用户输入转化为有效输出 。以智能客服场景为例,代理可调用知识库检索工具获取信息,再借助语言模型组织回复话术,高效解决用户问题。
LangChain代理的运行遵循一套标准化流程。首先接收用户输入,随后通过“规划”阶段解析任务、确定执行步骤;接着进入“执行”环节,调用相应工具获取结果;若结果无法满足任务需求,代理会重新规划并循环执行,直至达成目标。此流程中,语言模型承担推理决策重任,工具负责具体功能实现,二者协同构成代理核心能力。
相较于链式结构的固定执行顺序,代理具备两大显著优势:其一,动态决策能力,能依据任务与结果灵活调整执行路径;其二,工具集成特性,可接入多样化外部工具拓展功能边界。链式结构适用于流程明确的任务,而代理更擅长应对复杂、开放的场景,如多步骤推理、跨领域知识整合等任务 。
LangChain代理主要由语言模型(LLM)、工具集(Tools)、规划器(Planner)、执行器(Executor)和记忆模块(Memory)五大核心组件构成。语言模型负责任务推理与决策;工具集包含各类功能模块,如搜索引擎、代码解释器等;规划器依据输入制定执行计划;执行器负责调用工具并处理结果;记忆模块则存储交互历史,为决策提供上下文支持。
当用户输入任务后,规划器先将任务拆解为子目标,结合语言模型生成执行步骤。执行器依步骤调用工具,工具执行后将结果反馈给语言模型,模型评估结果并判断是否需调整计划。记忆模块全程参与,持续更新交互历史,辅助语言模型理解上下文,优化后续决策 。
在LangChain源码中,代理相关核心类主要定义于langchain.agents
模块。以下为关键类及核心方法示例:
# langchain/agents/base_agent.py
class BaseAgent:
"""代理基类,定义核心接口"""
def __init__(
self,
llm: BaseLanguageModel, # 语言模型实例
tools: List[BaseTool], # 工具列表
memory: Optional[BaseMemory] = None # 记忆模块
):
self.llm = llm
self.tools = tools
self.memory = memory or ConversationBufferMemory()
def _construct_scratchpad(
self, intermediate_steps: List[Tuple[BaseTool, str]]
) -> List[BaseMessage]:
"""构建中间结果记录,用于上下文传递"""
thoughts = []
for action, observation in intermediate_steps:
thoughts.extend([
AIMessage(content=f"Action: {action.name}\nAction Input: {action.args}"),
HumanMessage(content=observation)
])
return thoughts
async def plan(
self, intermediate_steps: List[Tuple[BaseTool, str]], **kwargs: Any
) -> AgentAction:
"""规划下一步行动,需子类实现"""
raise NotImplementedError()
async def _run(self, input: str, **kwargs: Any) -> str:
"""代理主运行逻辑"""
intermediate_steps: List[Tuple[BaseTool, str]] = []
while True:
# 生成下一步行动
action = await self.plan(intermediate_steps, **kwargs)
if isinstance(action, AgentFinish):
return action.return_values["output"]
# 执行工具并获取结果
tool_result = self.tools[action.tool_index].run(action.tool_input)
intermediate_steps.append((action, tool_result))
上述代码中,BaseAgent
类定义了代理的基础框架,_construct_scratchpad
方法整合中间结果,plan
方法用于规划行动,_run
方法串联起规划与执行的核心流程。
LangChain的内置代理依据任务场景、规划策略和工具调用方式,可分为通用型代理、代码型代理、反应型代理等类别。通用型代理适用于广泛场景,具备基础规划与工具调用能力;代码型代理侧重代码生成与执行任务;反应型代理则强调快速响应、基于规则的决策逻辑 。
目前LangChain主要包含以下内置代理类型:
不同代理类型在适用场景上各有侧重。ZeroShotAgent适合快速搭建原型、处理简单任务;MRKLAgent擅长多工具协同、复杂任务拆解;ReActAgent在需要解释决策过程的场景中表现突出;PythonAgent则是编程类任务的首选。开发者需根据任务复杂度、工具需求和响应特性选择合适代理 。
ZeroShotAgent的核心优势在于“零样本”能力,即无需大量训练数据,仅通过任务描述与提示模板,就能调用工具执行任务。其决策过程依赖语言模型对提示的理解,将用户输入转化为工具调用指令。例如,用户输入“查询今日天气”,代理可解析指令并调用天气查询工具 。
提示模板是ZeroShotAgent的关键要素,其设计需明确任务目标、工具调用格式和预期输出。LangChain提供默认模板,也支持自定义。以下为模板核心结构示例:
# langchain/agents/zero_shot_agent.py
PREFIX = """你是一个智能助手,可使用以下工具完成任务:
{tool_names}
使用工具时,必须按照以下格式输出:
Action: <工具名称>
Action Input: <工具输入参数>
请仅输出上述格式的内容,避免多余解释。"""
SUFFIX = """任务描述:{input}
{agent_scratchpad}"""
ZERO_SHOT_TOOL_REACT_DESCRIPTION = """
工具名称: {name}
工具描述: {description}
"""
PREFIX
定义工具调用规范,SUFFIX
结合任务输入与中间结果生成完整提示,ZERO_SHOT_TOOL_REACT_DESCRIPTION
则用于补充工具详细信息。
在ZeroShotAgent
的plan
方法中,其执行流程如下:
AgentAction
对象。若输出无法解析,则返回错误或重新生成 。# langchain/agents/zero_shot_agent.py
class ZeroShotAgent(BaseAgent):
def plan(
self, intermediate_steps: List[Tuple[BaseTool, str]], **kwargs: Any
) -> AgentAction:
# 构建提示
full_inputs = self.get_full_inputs(intermediate_steps, **kwargs)
prompt = self.prompt.format(**full_inputs)
# 调用语言模型获取输出
llm_output = self.llm.predict(prompt)
try:
# 解析输出为AgentAction
return self.output_parser.parse(llm_output)
except OutputParserException:
# 解析失败时的处理
return AgentAction(
tool="ERROR",
tool_input=llm_output,
log=llm_output
)
MRKLAgent(Multi-Reasoning Knowledge Language Model Agent)的核心在于多推理知识整合。它支持同时调用多个工具,并通过语言模型的推理能力,对工具结果进行筛选、组合与分析。例如在回答复杂问题时,可同时调用知识库检索、数据分析工具,再整合结果生成答案 。
MRKLAgent通过配置工具优先级与适用性评分,优化调用策略。每个工具需定义description
字段描述功能,代理依据任务与描述匹配度,结合优先级权重,动态选择工具。例如,在处理代码问题时,代码解释工具的优先级高于普通文本工具。
在MRKLAgent的plan
方法中,其实现逻辑如下:
# langchain/agents/mrkl/base.py
class MRKLAgent(BaseAgent):
def plan(
self, intermediate_steps: List[Tuple[BaseTool, str]], **kwargs: Any
) -> AgentAction:
# 计算工具匹配得分
tool_scores = self._get_tool_scores(kwargs["input"])
best_tool_name = max(tool_scores, key=tool_scores.get)
best_tool = next(t for t in self.tools if t.name == best_tool_name)
# 构建提示
prompt = self.prompt.format(
input=kwargs["input"],
intermediate_steps=intermediate_steps,
tools=self.tools,
tool_names=", ".join([t.name for t in self.tools]),
best_tool_description=best_tool.description
)
# 获取工具输入参数
llm_output = self.llm.predict(prompt)
return self.output_parser.parse(llm_output, best_tool_name)
ReActAgent创新地将推理(Reasoning)与行动(Action)分离,先通过语言模型推理任务步骤,再执行对应工具。这种模式使决策过程透明化,便于用户理解与监督,同时提升了复杂任务的执行准确性 。例如在故障诊断场景中,代理可先推理可能原因,再调用检测工具验证。
ReActAgent通过记录推理过程与工具调用日志,实现决策可解释性。每次行动前,代理会生成推理语句说明选择依据;行动后,将结果与推理结合更新上下文。这些信息可直接展示给用户,增强交互可信度。
在ReActAgent的_run
方法中,其核心循环如下:
# langchain/agents/react/base.py
class ReActAgent(BaseAgent):
async def _run(self, input: str, **kwargs: Any) -> str:
intermediate_steps: List[Tuple[BaseTool, str]] = []
while True:
# 生成推理与行动
thought, action = await self._generate_thought_action(
intermediate_steps, input, **kwargs
)
if action.tool == "Final Answer":
return action.tool_input
# 执行工具
tool_result = self.tools[action.tool_index].run(action.tool_input)
intermediate_steps.append((action, tool_result))
# 更新上下文
self.memory.chat_memory.add_user_message(thought)
self.memory.chat_memory.add_assistant_message(
f"Action: {action.tool}\nAction Input: {action.tool_input}\nObservation: {tool_result}"
)
PythonAgent专注于Python代码相关任务,可依据自然语言描述生成Python代码,并调用Python解释器执行。其核心能力依赖代码生成模板与沙箱执行环境,确保代码安全运行。例如,用户输入“统计CSV文件行数”,代理可生成对应Python代码并返回结果 。
为防止恶意代码执行,PythonAgent采用沙箱隔离技术。通过限制代码访问权限(如文件系统、网络)、监控资源使用,确保代码在可控环境下运行。LangChain支持多种沙箱方案,如subprocess
子进程隔离、pysecurereader
权限控制等 。
在PythonAgent的执行流程中:
# langchain/agents/python/agent.py
class PythonAgent(BaseAgent):
def _run(self, input: str, **kwargs: Any) -> str:
code = self._generate_python_code(input)
try:
# 在沙箱中执行代码
result = self._execute_python_code(code)
return result
except Exception as e:
# 处理异常并重新生成代码
new_prompt = self._handle_error(input, code, str(e))
return self._run(new_prompt, **kwargs)
def _generate_python_code(self, input: str) -> str:
prompt = self.prompt.format(input=input)
return self.llm.predict(prompt)
def _execute_python_code(self, code: str) -> str:
# 使用subprocess创建沙箱环境
process = subprocess.Popen(
["python", "-c", code],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
stdout, stderr = process.communicate()
if stderr:
raise Exception(stderr.decode())
return stdout.decode()
通过模拟1000次简单任务(如天气查询),测试各代理响应时间。结果显示,ZeroShotAgent因提示简洁、决策直接,响应最快;ReActAgent因需额外推理步骤,耗时相对较长。但在复杂任务中,ReActAgent的规划能力可减少无效尝试,反而提升整体效率 。
在多轮复杂任务(如多步骤数据分析)测试中,MRKLAgent凭借多工具协同,准确率最高;ZeroShotAgent因依赖单次提示,处理复杂逻辑时易出错。PythonAgent在代码类任务上准确率突出,但非编程任务表现较弱。
资源消耗方面,PythonAgent因需运行Python解释器与沙箱,内存与CPU占用最高;ZeroShotAgent和ReActAgent主要依赖语言模型推理,资源消耗相对稳定;MRKLAgent在调用多个工具时,资源需求随工具数量线性增长。
LangChain提供多种记忆模块,包括ConversationBufferMemory
(存储完整对话历史)、ConversationSummaryMemory
(存储对话摘要)、ConversationTokenBufferMemory
(按Token数量控制历史长度)等。不同类型适用于不同场景,如长对话场景适合摘要记忆,资源受限场景适合Token控制记忆 。
记忆模块在代理中承担上下文传递重任。它记录用户历史输入、代理行动与结果,辅助语言模型理解当前任务背景。例如在多轮对话中,记忆模块可让代理基于之前内容延续推理,避免信息断层。
在代理类初始化时,记忆模块通过参数传入,并在运行过程中持续更新。以ConversationBufferMemory
为例:
# langchain/agents/base_agent.py
class BaseAgent:
def __init__(
self,
llm: BaseLanguageModel,
tools: List[BaseTool],
memory: Optional[BaseMemory] = None
):
self.memory = memory or ConversationBufferMemory()
async def _run(self, input: str, **kwargs: Any) -> str:
intermediate_steps: List[Tuple[BaseTool, str]] = []
while True:
# 生成行动
action = await self.plan(intermediate_steps, **kwargs)
if isinstance(action, AgentFinish):
return action.return_values["output"]
# 执行工具
tool_result = self.tools[action.tool_index].run(action.tool_input)
intermediate_steps.append((action, tool_result))
# 更新记忆
self.memory.save_context(
{"input": input},
{"intermediate_steps": intermediate_steps, "output": tool_result}
)
上述代码中,memory
在每次工具执行后更新,存储关键信息用于后续决策。
在LangChain中,自定义工具需继承BaseTool
类,并实现run
方法