给大模型装上“手脚”:LangChain Tools 与 Agent 深度解析

去年一个做AI招聘平台的团队发了一篇公开复盘:他们把生产环境里的 LangChain 卸掉了,改成了直接调用 Anthropic 原生 SDK。效果立竿见影------p50 延迟从 2.1 秒降到 1.4 秒,p95 延迟从 4.8 秒降到 3.2 秒。

这个案例被很多人转发,评论区清一色"LangChain 就是过度封装"、"直接调 API 不香吗"。

但很少有人追问一句:他们卸掉 LangChain 之前,用 LangChain 做了什么?

答案是:他们用 LangChain 的 Tools + Agent 搭了一套招聘筛选系统,对接了 7 个不同的数据源和 4 个第三方 API。在没有 LangChain 的情况下,这套系统根本不可能在两周内上线。

工具本身有成本,但工具解决的问题,是你自己手写代码时更大的成本。

目录

一、大模型什么都懂,但什么都做不了

二、本质是让 LLM 从"大脑"变成"大脑+手脚"

三、Tools 机制拆解:怎么给大模型装"手脚"

四、Agent 机制拆解:怎么让大模型自己"决定用哪只手"

五、一个测试场景的完整案例

六、对你意味着什么

七、最后问你一个问题

一、大模型什么都懂,但什么都做不了

ChatGPT 刚出来的时候,很多人觉得"以后不用写代码了,跟 AI 说一声就行"。

现实很快打脸。

你跟 GPT-4 说"帮我查一下明天北京的天气,然后对比一下后天,发邮件告诉我结果"。它能告诉你思路,但查不了天气、发不了邮件。它知道怎么查、怎么发,但它做不到。

大模型的知识边界在参数里,行动边界在物理世界和数字系统的接口上。

这就是 LangChain Tools 和 Agent 要解决的问题。

Tools 给大模型装上了"手"------能查数据库、能调 API、能执行代码。Agent 给大模型装上了"大脑的决策层"------能自己判断什么时候用什么工具、按什么顺序用。

很多人一上来就纠结"LangChain 重不重"、"要不要直接调 API"。但他们忽略了一个更基本的问题:你需要的是一套可扩展的"工具调用体系",还是一个一次性脚本?

如果是后者,直接调 API 确实更快。但如果是前者------你需要让大模型动态地、组合地调用多个工具------没有 LangChain 这类框架,你自己要写的胶水代码比你想象的多得多。

大模型的短板从来不是"不知道",而是"做不到"。Tools 解决的是"做到"的问题。

二、本质是让 LLM 从"大脑"变成"大脑+手脚"

先搞清楚一个概念。

LangChain 官方对 Agent 的定义很直接:用户给 Agent 一个输入消息,Agent 进入循环------调用工具、把工具返回结果和 AI 消息加入状态、继续调用,直到它决定不再调用任何工具并最终结束。

这个循环看似简单,但背后解决了一个核心问题:大模型本身没有"行动能力",它只会生成文本。Tools 把"行动"封装成可被大模型调用的函数,Agent 把"什么时候调用什么工具"的决策权交给了大模型自己。

本质上,这是在 LLM 外面包了一层"执行器"。LLM 负责推理和决策,执行器负责干活。

LangChain Agent 框架通过模块化设计把智能 Agent 拆解为三个核心部分:工具链(Tools)、推理引擎(Reasoning Engine)和执行控制器(Execution Controller)。

工具链是"手脚"------能做什么。推理引擎是"小脑"------怎么做决策。执行控制器是"神经系统"------怎么协调。

这三层缺一不可。

很多人觉得 LangChain "重",是因为他们把这三层全用了。但如果你只需要"手脚"(Tools),你可以只用 Tools 层,不用 Agent。如果你只需要"小脑"(推理),你也可以单独用 Prompt 模板。

框架重不重,取决于你怎么用。

Tools 解决"能做什么",Agent 解决"什么时候做"。两个加在一起,大模型才有了真正的行动能力。

三、Tools 机制拆解:怎么给大模型装"手脚"

3.1 Tool 的本质是什么

在 LangChain 里,一个 Tool 本质上就是一个带描述的函数。

大模型不直接执行代码。它通过"函数调用"(Function Calling)协议告诉系统:"我想调用这个函数,参数是这些"。系统收到指令后,在本地执行这个函数,把结果返回给大模型。

所以 Tool 的核心不是"怎么实现功能",而是"怎么让大模型知道有这个功能、知道什么时候用它"。

关键在三个地方:

name:工具的名字,要简洁明确

description:描述这个工具做什么、什么时候该用。大模型靠这个判断要不要调它

args_schema:参数的结构定义,告诉大模型需要传什么参数、什么类型

description 写不好,工具永远不会被调用。arg_schema 定义不清晰,大模型传的参数永远是错的。

3.2 三种定义方式

方式一:@tool 装饰器(最推荐)

from langchain_core.tools import tool

@tool

def get_weather(city: str) -> str:

"""获取指定城市的当前天气。

参数:

city: 城市名称,例如 '北京', '上海'。

"""

实际场景中替换为 API 调用

weather_data = {

"北京": "晴天,25°C",

"上海": "多云,28°C",

}

return weather_data.get(city, f"{city} 暂无数据")

函数的 docstring 自动成为工具的 description。这是最简洁的方式,适合 80% 的场景。

方式二:继承 BaseTool(需要复杂逻辑时)

适合需要复杂初始化、状态管理或错误处理的场景。

方式三:Tool 类实例化(快速封装现有函数)

适合快速把已有的函数包装成 Tool,不改动原函数代码。

3.3 Tool 设计的两条铁律

铁律一:单一职责。 一个 Tool 只做一件事。登录就是登录,查库存就是查库存。不要写一个"万能工具"试图覆盖所有场景。

铁律二:输入输出都要结构化。 输入用 Pydantic BaseModel 定义 schema,输出用 JSON 或明确的字典结构。大模型不懂"随意格式",它只认 Schema。

四、Agent 机制拆解:怎么让大模型自己"决定用哪只手"

有了 Tools,下一个问题是:谁来决定什么时候用哪个 Tool?

这就是 Agent 的事。

4.1 ReAct 循环:推理-行动-观测

Agent 的核心执行模式叫 ReAct------Reasoning + Acting。

具体流程是:

推理(Reasoning) :面对用户的问题,Agent 先思考"我需要做什么、用什么工具"

行动(Acting) :调用对应的 Tool,获取结果

观测(Observation) :分析 Tool 返回的结果,判断任务是否完成

如果没完成,回到步骤 1,继续循环

这个循环一直持续到 Agent 认为任务完成,或者达到最大迭代次数。

4.2 上下文工程:Agent 可靠性的关键

为什么同样的 Agent,有时候工作得很好,有时候一塌糊涂?

LangChain 团队在一篇官方博客里点出了核心原因:上下文工程(Context Engineering) 。

进入模型的内容决定了模型输出什么。要让 Agent 更可靠,你需要对"进入模型的东西"有完全的控制权。

具体来说,你需要控制:

Agent 的"状态"里包含什么------不只是对话消息,还可以包含连接字符串、用户信息、运行时配置

发给模型的提示词是什么------不是写死的字符串,而是可以动态生成的函数

模型调用前做什么、调用后做什么------比如对话太长时先做摘要再送给模型

这些控制点,就是 LangChain 1.0 引入的 Middleware 机制要解决的问题。

4.3 动态工具选择:不是所有工具都要同时可见

另一个容易被忽略的设计:不是所有工具都要在一开始全部暴露给 Agent。

LangGraph 支持动态工具调用------你可以在运行的不同阶段控制哪些工具可见。

为什么重要?

强制执行工作流:要求先调用认证工具,才能暴露敏感操作

引导推理:开始时只给少量工具,任务推进后再扩展

提升可靠性:减少早期因工具过多导致的错误路径

这就像给一个新手厨师做饭------先给他刀和砧板,等他切完了再把锅和灶给他。一次给太多工具,他反而不知道从哪里下手。

五、一个测试场景的完整案例

说一个我实际做过的案例。

需求:自动化测试一个涉及"登录→查询订单→验证金额"的流程。

传统做法:写一个 Python 脚本,里面硬编码三步的 API 调用、参数构造、断言逻辑。大概 150 行代码。问题是:换一个环境(测试环境→预发布环境),API 地址变了,要改 5 处。换一个用户,token 获取方式变了,要改 3 处。

用 LangChain Tools 的做法:

定义三个 Tool:

@tool

def login(username: str, password: str) -> dict:

"""用户登录,返回 token 和 user_id"""

调用登录 API

@tool

def query_orders(token: str, user_id: str) -> list:

"""查询用户的订单列表,需要 token 和 user_id"""

@tool

def verify_amount(order_id: str, expected: float) -> bool:

"""验证订单金额是否等于期望值"""

然后创建一个 Agent,把这三个 Tool 传进去。给 Agent 的指令是:"用 test_user 登录,查询他的订单,验证第一笔订单的金额是否等于 99.9"。

Agent 自动完成:

调用 login,拿到 token 和 user_id

把 token 和 user_id 传给 query_orders,拿到订单列表

取第一笔订单的 ID,调用 verify_amount

对比:

维度

传统脚本

LangChain Tools + Agent

代码量

150 行

3 个 Tool(约 60 行)+ 1 句自然语言

换环境

改 5 处硬编码

改 1 个环境变量

新增场景

重写脚本

复用 Tool,改自然语言指令

可维护性

低(逻辑耦合)

高(Tool 独立)

关键不是省了多少行代码。关键是:当业务逻辑变化时,你改的是 Tool 的实现,还是整个流程的编排?

前者是"修一个零件",后者是"重造一台机器"。

Tool 是积木,Agent 是搭积木的人。你只需要定义好积木,搭积木的事交给 Agent。

六、对你意味着什么

对在校生

你现在学的测试理论里,大概率还没有"AI Agent"这个章节。但等你毕业的时候,这会是测试工程师的标配能力。不是让你现在就去精通 LangChain,而是让你看懂一个趋势:测试执行正在从"写脚本"变成"定义工具+描述意图" 。看得懂这个变化,你就比同龄人领先一步。

对初级工程师

你可能已经会用 Postman 调接口、用 Pytest 写用例了。下一步的能力升级点是:把"调接口"封装成 Tool,把"写用例"变成"给 Agent 下指令" 。核心不是学 LangChain 的 API,是学会"工具化思维"------把一切可重复的操作变成可被大模型调用的标准接口。

对中级工程师

你现在面临的问题是团队效率的天花板。当测试场景越来越复杂、回归范围越来越大时,靠堆人写脚本是不可持续的。Tools + Agent 提供了一条路:把测试能力拆解成可组合的 Tool,让 Agent 根据需求动态组装 。这不是"更快的脚本",这是"不用写脚本的测试"。方法论层面的升级,才是你该关注的点。

七、最后问你一个问题

你现在的测试代码里,有多少是"可被大模型调用的工具",有多少是"一次性写死的流程"?

如果你的答案是"大部分是流程",那问自己第二个问题:当业务变更时,你是改代码,还是重新描述意图?

这两个问题的答案,决定了你的测试资产是在持续积累,还是在持续贬值。