一、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 OpenAIimport osfrom dotenv import load_dotenvload_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
功能:
- 获取回复:调用大模型获取回答。检查最终答案:通过正则匹配检查是否包含 "最终答案" 标记,若有则输出并结束对话。检查工具调用:通过正则匹配提取工具名和参数,调用
get_closing_price
获取股票收盘价。循环更新:将工具调用结果(观察)添加到消息列表,继续对话直到得到最终答案或无法解析。3.执行结果
工作流程总结:
- 一个良好的 prompt 设计向 LLM 提问LLM 接收到问题后,根据我们设定的步骤去思考,去调用外部工具将LLM 返回的结果,和思考过程,回传给 LLM 模型—— (轮询)
- LLM 先分析出来自己是要用哪一个工具函数的我们再将 LLM 的分析结果传回给大模型大模型调用对应的工具函数得到数据继续将得到的数据传给 LLM
5.大模型得到最终答案后返回结果终止循环