下面给出一个代码示例展示如何使用 LangChain 通义千问Qwen通过 ReAct Agent 安全地调用自定义工具完成数学计算任务。示例代码取自《AI Agent智能体开发实践》第8章。# -*- coding: utf-8 -*- Created on Fri Jul 25 09:55:25 2025 author: liguo from langchain.tools import tool from langchain.agents import AgentExecutor, create_react_agent from langchain import hub from langchain_community.chat_models import ChatTongyi import os # 核心计算函数不被 tool 装饰避免递归调用工具对象 def _factorial(n: int) - int: 内部阶乘计算函数使用循环避免递归栈和工具调用问题 if n 0: raise ValueError(阶乘不支持负数) result 1 for i in range(1, n 1): result * i return result # 工具层函数负责接收输入、类型转换、调用核心函数 tool def calculate_factorial(n: int) - int: 计算给定数字的阶乘 # 确保输入是整数兼容字符串输入 if isinstance(n, str): n int(n.strip()) return _factorial(n) # 工具列表 tools [calculate_factorial] # 初始化 Qwen 模型请替换为你自己的 DashScope API Key llm ChatTongyi( modelqwen-max, # 也可用 qwen-turbo, qwen-plus temperature0, #dashscope_api_keyos.getenv(DASHSCOPE_API_KEY) # 推荐在终端或系统环境变量中设置 DASHSCOPE_API_KEY ) # 拉取 ReAct 提示词模板 prompt hub.pull(hwchase17/react) # 创建 Agent agent create_react_agent(llm, tools, prompt) # 创建执行器 executor AgentExecutor(agentagent, toolstools, verboseTrue) # 执行任务 if __name__ __main__: response executor.invoke({input: 计算5的阶乘}) print(\n *50) print(最终结果:, response[output])下面我按模块 执行流程对你给出的代码做一次逐行、偏实战向的解析帮助你真正理解每一步在干什么、为什么要这样写。一、整体结构概览你的代码可以分为6 个层次导入依赖核心计算函数不暴露给 AgentLangChain Tool 包装函数工具注册 LLM 初始化ReAct Agent 构建执行与结果输出二、逐段解析1️⃣ 头部 编码声明# -*- coding: utf-8 -*-✅ 确保 Python 能正确处理中文注释✅ 在 Python 3 中不是必须但写工具/脚本时仍是好习惯2️⃣ 导入模块from langchain.tools import tool from langchain.agents import AgentExecutor, create_react_agent from langchain import hub from langchain_community.chat_models import ChatTongyi import os各模块作用模块作用tool把普通函数注册为 Agent 可调用的工具AgentExecutor实际运行 Agent 的引擎create_react_agent创建 ReAct 模式 Agenthub从 LangChain Hub 拉取 PromptChatTongyi通义千问QwenLLMos读取环境变量3️⃣ 核心计算函数⚠️ 关键点def _factorial(n: int) - int: 内部阶乘计算函数使用循环避免递归栈和工具调用问题 if n 0: raise ValueError(阶乘不支持负数) result 1 for i in range(1, n 1): result * i return result✅ 为什么不用递归❌ 递归写法def factorial(n): return n * factorial(n-1)问题Python 递归深度有限LangChain Agent容易误以为这是工具极易触发无限递归调用工具✅ 你用了循环 私有函数_factorial只做计算不会被tool装饰Agent永远看不到它✅ 这是LangChain 工具设计的最佳实践4️⃣ Tool 层Agent 可见的唯一入口tool def calculate_factorial(n: int) - int: 计算给定数字的阶乘 if isinstance(n, str): n int(n.strip()) return _factorial(n)这一层做了 3 件事✅ 1. 注册为工具tool会把它变成Tool( namecalculate_factorial, funccalculate_factorial, description计算给定数字的阶乘 )Agent只能看到这个工具✅ 2. 输入类型容错if isinstance(n, str): n int(n.strip())原因LLM 经常返回5而不是5JSON / Agent 解析不稳定✅ 这一步非常关键否则容易报错✅ 3. 调用核心逻辑return _factorial(n)✅ 工具 ≠ 业务逻辑✅ 解耦方便测试、复用、维护5️⃣ 工具注册tools [calculate_factorial]✅ Agent 可用的工具列表✅ 以后加工具只需tools [calculate_factorial, add, multiply]6️⃣ 初始化大模型Qwenllm ChatTongyi( modelqwen-max, temperature0, )参数解释参数含义model通义千问模型temperature0输出确定性强数学问题必选✅API Key 通过环境变量注入安全7️⃣ 拉取 ReAct Promptprompt hub.pull(hwchase17/react)ReAct 是什么ReAct Reasoning ActingPrompt 强制 LLM 按如下格式思考Thought: 我要算 5 的阶乘 Action: calculate_factorial Action Input: 5 Observation: 120 Final Answer: 120✅ 这是工具调用的标准范式⚠️ 缺点依赖 LangChain Hub有时慢8️⃣ 创建 Agentagent create_react_agent(llm, tools, prompt)等价于告诉 Agent你有一个大脑LLM你有这些工具tools你必须按这个 Prompt 的格式思考9️⃣ 创建执行器AgentExecutorexecutor AgentExecutor( agentagent, toolstools, verboseTrue )AgentExecutor 的职责功能说明解析 LLM 输出Thought / Action调用工具calculate_factorial把结果塞回 LLMObservation控制循环防止死循环✅verboseTrue打印完整推理过程 执行任务response executor.invoke({input: 计算5的阶乘})实际发生了什么Agent 收到问题决定使用calculate_factorial调用calculate_factorial(5)得到120生成最终自然语言回答最终输出print(response[output])示例5的阶乘是120。三、整体执行流程图文字版用户输入 ↓ AgentExecutor ↓ ReAct Prompt LLM ↓ Action: calculate_factorial ↓ Tool 调用 ↓ _factorial() ↓ Observation ↓ Final Answer四、一句话总结✅ 这是一个结构正确、工程化、可扩展的 LangChain Tool ReAct Agent 示例​✅ 你已经避开了 90% 新手会踩的坑递归 / 工具循环 / 输入类型​​