06 一分钟搞懂langchain的Agent是如何工作的

一个典型langchain创建Agent的流程:

python 复制代码
from langchain.llms import OpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
from langchain.agents import AgentExecutor, Tool, create_react_agent
from langchain import hub

# 初始化语言模型
llm = OpenAI(temperature=0.9)

# 创建生成公司名称的链
company_name_chain = LLMChain(
    llm=llm,
    prompt=PromptTemplate(
        input_variables=["product"],
        template="What is a good name for a company that makes {product}?",
    ),
)

# 定义 Agent 可以使用的工具
tools = [
    Tool(
        name="Company Name Generator",
        func=company_name_chain.run,
        description="Useful for generating creative company names based on a product.",
    )
]

# 获取 ReAct Agent 的提示
prompt = hub.pull("hwchase17/react")

# 创建并执行 Agent
agent_executor = AgentExecutor(agent=create_react_agent(llm, tools, prompt), tools=tools, verbose=True)

# 运行 Agent
agent_result = agent_executor.invoke({"input": "我需要一个生产彩色袜子的公司的好名字。"})

print(agent_result)

我们来看下Agent是怎么工作的

🤖 代理 (Agent) 初始化与调用

一、初始化

代理的初始化通常通过工厂方法完成,如 initialize_agent(tools, llm, agent="zero-shot-react-description")

  1. initialize_agent 函数会根据指定的代理类型创建代理实例
  2. 创建代理时会设置工具、LLM 和输出解析器
  3. 最后创建 AgentExecutor 实例,它负责执行代理的决策循环 代码路径:libs/langchain/langchain/agents/initialize.py
python 复制代码
def initialize_agent(

    tools: Sequence[BaseTool],
    llm: BaseLanguageModel,
    agent: Optional[Union[Agent, AgentType]] = None,
    # ... 其他参数 ...
) -> AgentExecutor:

    """Initialize an agent."""
    # 根据agent类型创建具体的代理实例
    # ...
    return AgentExecutor.from_agent_and_tools(
        agent=_agent,
        tools=tools,
        callback_manager=callback_manager,
        # ... 其他参数 ...
    )

二、调用流程

当运行代理时(如 agent_executor.run("Find the capital of France")):

  1. run 方法调用 __call__ 方法,后者调用 invoke 方法
  2. invoke 方法会调用 _call 方法
  3. AgentExecutor 中,_call 方法实现了代理的决策循环: a. 代理观察环境状态并决定下一步行动 b. 如果代理决定使用工具,则执行工具操作 c. 将工具的输出作为观察结果返回给代理 d. 重复上述过程,直到代理决定完成任务 代码路径:libs/langchain/langchain/agents/agent.py
python 复制代码
def _call(
    self,
    inputs: dict[str, str],
    run_manager: Optional[CallbackManagerForChainRun] = None,
) -> dict[str, Any]:

    """运行代理的决策循环"""
    # 准备工具(映射)
    name_to_tool_map = {tool.name: tool for tool in self.tools}
    # 准备颜色(映射,用于日志显示)
    color_mapping = get_color_mapping([tool.name for tool in self.tools])
    # 初始化中间要执行的步骤
    intermediate_steps: list[tuple[AgentAction, str]] = []
    # 记录开始执行的时间
    time_elapsed = 0.0
    start_time = time.time()
    # 决策循环
    iterations = 0
    # 检测是否超过最大任务执行次数或者超过最大任务执行时间
    while self._should_continue(iterations, time_elapsed): 
        iterations += 1
        # 调用代理决定下一步行动
        # 执行行动并获取结果
        # 更新中间步骤
        # 检查是否完成
        # ...
        time_elapsed = time.time() - start_time

    # 处理结果并返回

    # ...
如何决定下一步的函数?
python 复制代码
def _take_next_step(

        self,
        name_to_tool_map: dict[str, BaseTool],    # 可以使用的工具
        color_mapping: dict[str, str],
        inputs: dict[str, str],    # 初始的输入
        intermediate_steps: list[tuple[AgentAction, str]],    # 前面之前已经执行过的步骤和结果
        run_manager: Optional[CallbackManagerForChainRun] = None,    # 任务管理器,用于记录过程    
    ) -> Union[AgentFinish, list[tuple[AgentAction, str]]]:

         # 核心逻辑
        return self._consume_next_step(
            [
                a
                for a in self._iter_next_step(
                    name_to_tool_map,
                    color_mapping,
                    inputs,
                    intermediate_steps,
                    run_manager,)
            ]
        )
  • 核心逻辑是将从 _iter_next_step 思考出来的所有可能的"下一步行动" 传递给_consume_next_step进行检测过滤。
如何获取"下一步行动"?
python 复制代码
def _iter_next_step(

        self,
        name_to_tool_map: dict[str, BaseTool],    # 可以使用的工具
        color_mapping: dict[str, str],
        inputs: dict[str, str],    # 初始的输入
        intermediate_steps: list[tuple[AgentAction, str]],    # 前面之前已经执行过的步骤和结果
        run_manager: Optional[CallbackManagerForChainRun] = None,    # 任务管理器,用于记录过程    
    ) -> Iterator[Union[AgentFinish, AgentAction, AgentStep]]:
        """Take a single step in the thought-action-observation loop.
        Override this to take control of how the agent makes and acts on choices.
        """
        try:
            intermediate_steps = self._prepare_intermediate_steps(intermediate_steps)    # 整理前面的步骤
            # Call the LLM to see what to do.
            output = self._action_agent.plan(
                intermediate_steps,
                callbacks=run_manager.get_child() if run_manager else None,
                **inputs,
            )    # 将整理好的内容发送LLM
        except OutputParserException as e:
            if isinstance(self.handle_parsing_errors, bool):  
                raise_error = not self.handle_parsing_errors
            else:
                raise_error = False
            if raise_error:
                raise ValueError(
                    "An output parsing error occurred. "
                    "In order to pass this error back to the agent and have it try "
                    "again, pass `handle_parsing_errors=True` to the AgentExecutor. "
                    f"This is the error: {str(e)}"
                )

            text = str(e)
            if isinstance(self.handle_parsing_errors, bool):
                if e.send_to_llm:
                    observation = str(e.observation)
                    text = str(e.llm_output)
                else:
                    observation = "Invalid or incomplete response"
            elif isinstance(self.handle_parsing_errors, str):
                observation = self.handle_parsing_errors
            elif callable(self.handle_parsing_errors):
                observation = self.handle_parsing_errors(e)
            else:
                raise ValueError("Got unexpected type of `handle_parsing_errors`")
            output = AgentAction("_Exception", observation, text)
            if run_manager:
                run_manager.on_agent_action(output, color="green")
            tool_run_kwargs = self._action_agent.tool_run_logging_kwargs()
            observation = ExceptionTool().run(
                output.tool_input,
                verbose=self.verbose,
                color=None,
                callbacks=run_manager.get_child() if run_manager else None,
                **tool_run_kwargs,
            )
            yield AgentStep(action=output, observation=observation)
            return

  
        if isinstance(output, AgentFinish):  # 任务完成,返回最终结果
            yield output
            return
  
        actions: list[AgentAction]
        if isinstance(output, AgentAction):
            actions = [output]
        else:
            actions = output
        for agent_action in actions:
            yield agent_action
        for agent_action in actions:
            yield self._perform_agent_action(
                name_to_tool_map, color_mapping, agent_action, run_manager
            )
  1. 通过self._prepare_intermediate_steps(intermediate_steps)整理执行过的所有行动
  2. self._action_agent.plan中封装了与 大型语言模型(LLM) 的交互逻辑,将整理好的历史步骤intermediate_steps)、原始问题inputs)以及所有可用的工具信息 (并在_action_agent 内部转换为 LLM 能理解的格式)发送给 LLM处理。
  3. 分析LLM返回结果若任务完成,直接返回最终结果
    • 若任务完成,直接返回最终结果。
    • 若任务未完成:
    • 首先 yield agent_action 汇报后续的行动计划
    • yield self._perform_agent_action(...) 汇报完开始执行后续的行动计划。
如何对后续的行动计划进行检查?
python 复制代码
def _consume_next_step(
        self, values: NextStepOutput
    ) -> Union[AgentFinish, list[tuple[AgentAction, str]]]:
        if isinstance(values[-1], AgentFinish):    # 检查行动计划的最后一项是不是"AgentFinish"
            assert len(values) == 1
            return values[-1]
        else:
            return [
                (a.action, a.observation) for a in values if isinstance(a, AgentStep)
            ]    # 检查行动计划
  1. 行动计划的最后一项是"AgentFinish"
    • 如果是"AgentFinish",要确保报告里只有这一项(不应该有其他行动了)。
    • 直接返回"AgentFinish"的信号。
  2. 过滤出合法的"行动步骤",只提取出行动本身和观察到的结果a.action, a.observation并返回。

三、总结

其实并不复杂,Agent完成初始化后,首先观察环境,然后将输入与行动计划传给LLM规划下一步的行动,在获取到LLM返回的行动计划后,进行过滤判断是否执行完毕;若未完成则重复前面的过程直到完成任务。

思考下一步的任务该怎么执行,应该使用什么工具来执行,agent是关键点。

github 有帮助可以金手指点击start支持下作者

相关推荐
量子位1 小时前
Figure 机器人分拣快递新视频曝光,网友:太像人类
llm·ai编程
大模型铲屎官2 小时前
【深度学习-Day 23】框架实战:模型训练与评估核心环节详解 (MNIST实战)
人工智能·pytorch·python·深度学习·大模型·llm·mnist
AI大模型5 小时前
大模型系列炼丹术(五):LLM自回归预训练过程详解
程序员·llm
AI大模型6 小时前
大模型系列炼丹术(四):从零开始动手搭建GPT2架构
程序员·llm
用户84913717547166 小时前
🚀5 分钟实现 Markdown 智能摘要生成器:LangChain + OpenAI 实战教程
langchain·openai
红衣信7 小时前
探索 DeepSeek:智能前端与大模型的碰撞
前端·人工智能·llm
Baihai_IDP8 小时前
“一代更比一代强”:现代 RAG 架构的演进之路
人工智能·面试·llm
一 铭9 小时前
Github Copilot新特性:Copilot Spaces-成为某个主题的专家
人工智能·大模型·llm
yaocheng的ai分身10 小时前
Highlights from the Claude 4 system prompt
llm·claude
金汐脉动10 小时前
实践指南:从零开始搭建RAG驱动的智能问答系统
langchain