AI Agent第二站,使用LangChain框架创建ReAct Agent

519 阅读5分钟

一、LangChain 框架概述

LangChain (Hub - LangSmith)是一个专为开发基于大型语言模型(LLM)的应用程序设计的框架,其核心目标是简化 LLM 与外部工具、数据的集成流程,提升复杂应用的开发效率。

核心组件

  • 模型接口(Model I/O)

统一封装不同 LLM 的调用接口(如 OpenAI、Hugging Face 等),支持模型参数配置与流式响应处理。

  • 提示工程(Prompt Engineering)

提供模板管理、提示优化工具,支持动态构建上下文(如 Few-Shot 提示、Chain-of-Thought 提示)。

  • 链(Chains) 将多个组件串联成工作流,例如:

    • 检索 - 回答链:先检索知识库再生成回答

    • 工具调用链:触发 API 或函数获取外部数据​

  • 记忆(Memory)​

存储对话历史或中间结果,支持短期记忆(对话上下文)和长期记忆(知识库存储)。​

  • 代理(Agents)​

自主决策工具调用策略,如 ReAct 风格的代理可动态决定是否调用工具。​

使用此LangSmith框架构建ReAct Agent

二、ReAct 范式的核心思想​

ReAct(Reasoning + Action)是一种让 LLM 具备 "推理 - 行动" 循环能力的方法论,通过显式结合推理过程与工具调用,解决纯语言模型的知识局限问题。​

1. ReAct 的组成要素​

  • 推理(Reasoning)​

LLM 生成思考过程,明确当前需要解决的问题、已有的信息缺口。​

  • 行动(Action)​

基于推理结果决定调用工具(如 API、函数),并格式化参数。​

  • 观察(Observation)​

接收工具返回结果,作为新信息补充到上下文中。​

  • 循环机制​

重复 "推理 - 行动 - 观察" 直到满足回答条件。​

2. ReAct 的实践优势​

  • 可解释性:思考过程显式化,便于调试与优化​

  • 知识更新:通过工具调用获取实时数据(如天气、股价)​

  • 任务分解:将复杂问题拆解为多个可执行步骤

三、实战演练:股票收盘价分析

1. 核心组件准备

语言模型 llm.py

# 定义一个客户端,用于从LLM获取响应
from openai import OpenAI
import os
from dotenv import load_dotenv


load_dotenv('.env.local')
client = OpenAI(
  api_key=os.getenv('DEEPSEEK_API_KEY'),
  base_url='https://api.deepseek.com/v1'
)
    

提示词模板 prompt.py

REACT_PROMPT = """

{instructions}

TOOLS:

------

你可以使用以下工具:

{tools}

使用工具时,请使用以下格式

` ``

思考:我需要使用工具吗?{yes_or_no}

行动:要采取的行动,必须是{tool_name}其中之一

行动输入:该行动的输入参数

观察:行动的结果

  ` ``

当你有要回复给用户的内容,或者你不需要使用工具时,你必须使用以下格式:

`` `

思考:我需要使用工具吗?否

最终答案:[你的回复内容]

`` `

开始!
  
新的输入: {input}

{agent_scratchpad}

"""

工具 tools.py

# 工具列表,第三方函数的说明书
tools = [
  {
    "name": "get_closing_price",
    "description": "使用该工具获取指定股票的收盘价格",
    "parameters": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string",
          "description": "股票名称,例如:贵州茅台、青岛啤酒等"
        }
      },
      "required": ["name"]
    }
  }
]


def get_closing_price(name):
    name = name.strip().replace(' ', '')
    if '茅台' in name:
        return '1488'
    elif '青岛' in name or '啤酒' in name:
        return '67'
    else:
        return '未搜索到该股票'

2. 构建ReAct工作流

1. 导入必要的库

import json  # 用于处理JSON数据
from llm import client  # 导入LLM客户端
from prompt import REACT_PROMPT  # 导入预设的提示模板
from tools import get_closing_price,tools  # 导入工具函数
import re  # 导入正则表达式库
  • 功能:导入处理 JSON、调用大模型、格式化提示词、调用外部工具以及正则匹配所需的库。

2. 定义发送消息到 LLM 的函数

def send_messages(messages):
    response = client.chat.completions.create(
        model="deepseek-chat",  
        messages=messages,
    )
    return response
  • 功能:封装与大模型的通信,将消息列表发送给deepseek-chat模型并返回响应。

3. 主程序初始化

if __name__ == "__main__":
    # 设置助手角色和用户查询
    instructions = "你是一个股票助手,可以回答股票相关的问题"
    query = "青岛啤酒和贵州茅台的收盘价哪个贵?"
    
    # 构建提示词
    prompt = REACT_PROMPT.format(
        instructions=instructions,
        tools=tools,
        tool_name="get_closing_price",
        input=query,
        yes_or_no="是",
        agent_scratchpad=""
    )
    
    # 初始化消息列表
    messages = [{"role": "user", "content": prompt}]
  • 功能:设置助手角色和用户问题,使用预设模板格式化提示词,并初始化与模型的对话。

4. 对话循环处理

while True:
    # 获取模型回复
    response = send_messages(messages)
    response_text = response.choices[0].message.content
    print("大模型的回复:", response_text)

    # 检查是否有最终答案
    final_answer_match = re.search(r'最终答案\s*[::]\s*([\s\S]*)', response_text, re.IGNORECASE)
    if final_answer_match:
        final_answer = final_answer_match.group(1).strip()
        print("最终答案:", final_answer)
        break

    # 检查是否需要调用工具
    action_match = re.search(r'行动:\s*(\w+)', response_text)
    action_input_match = re.search(r'行动输入:\s*({.*?}|".*?")', response_text, re.DOTALL)
    if action_match and action_input_match:
        tool_name = action_match.group(1)
        params = json.loads(action_input_match.group(1))
        
        # 调用工具获取观察结果
        if tool_name == "get_closing_price":
            price = get_closing_price(params["name"])
            observation = f"{params['name']}的收盘价为{price}元"
            print("调用第三方API结果:", observation)
            messages.append({'role': 'user', 'content': f"观察:{observation}"})
    else:
        print("未检测到行动或最终答案")
        break
  • 功能

    1. 获取回复:调用大模型获取回答。
    2. 检查最终答案:通过正则匹配检查是否包含 "最终答案" 标记,若有则输出并结束对话。
    3. 检查工具调用:通过正则匹配提取工具名和参数,调用get_closing_price获取股票收盘价。
    4. 循环更新:将工具调用结果(观察)添加到消息列表,继续对话直到得到最终答案或无法解析。

3.执行结果

image.png 工作流程总结:

  1. 一个良好的 prompt 设计
  2. 向 LLM 提问
  3. LLM 接收到问题后,根据我们设定的步骤去思考,去调用外部工具
  4. 将LLM 返回的结果,和思考过程,回传给 LLM 模型—— (轮询)
    1. LLM 先分析出来自己是要用哪一个工具函数的
    2. 我们再将 LLM 的分析结果传回给大模型
    3. 大模型调用对应的工具函数得到数据
    4. 继续将得到的数据传给 LLM

5.大模型得到最终答案后返回结果终止循环