LangChain 除了直接调用工具之外,还能为你带来什么?
手工编写的工具循环用于指导机器运行;LangChain将模式、历史记录以及智能体协调功能隐藏在抽象层之后,从而使产品逻辑得以聚焦。
AI应用可以直接调用LLM API并掌控所有细节。这种方式确实有优势:控制流程一目了然。但同时也存在成本——一旦产品需要的对话轮次超过一次,就会出现大量并非真正属于产品逻辑的代码。
典型的相关流程包括:
- 定义工具和架构
- 将工具发送给模型
- 处理工具调用的响应
- 执行请求的功能
- 将工具处理结果反馈回去
- 保存对话历史记录
- 协调多次工具调用
- 推动模型与工具之间的交互循环
这些步骤非常适合用来学习。但在实际的应用程序中,手动重复这些操作就会变成一项繁重的工作。
正是为了减少这种重复工作,才有了LangChain这样的框架。
手动处理一切的代价
想象一个微型计算器工具。在没有框架的情况下,其结构大致如下:
User
↓
LLM API
↓
LLM requests calculator
↓
Our code detects the request
↓
Our code executes calculator()
↓
Our code sends the result back
↓
LLM generates the final answer
只有一个工具时还比较容易管理。但一旦有二十个工具、多种模型、需要保持会话状态、支持重试以及分支式的智能体工作流,原本“简单的产品逻辑”就会变成一个复杂的编排项目。
之所以需要抽象层,是因为相关机制的发展速度远远快于功能列表的扩展速度。
LangChain 的贡献
LangChain 为模型、工具、消息以及智能体运行时提供了统一的接口规范。无需手动连接每一个环节,只需描述所需功能,让框架来处理大部分常规代码。
创建工具
一个普通的 Python 函数就可以变成一个工具:
from langchain.tools import tool
def calculator(a: float, b: float, operation: str):
"""Perform a mathematical calculation."""
if operation == "add":
return a + b
elif operation == "subtract":
return a - b
elif operation == "multiply":
return a * b
elif operation == "divide":
if b == 0:
return "Cannot divide by zero."
return a / b
return "Unknown operation."
计算器的核心逻辑依然是应用程序的逻辑部分,LangChain 只是将其封装起来,以便大型语言模型能够调用它。
将工具与模型连接
from langchain_google_genai import ChatGoogleGenerativeAI
model = ChatGoogleGenerativeAI(
model="gemini-3.5-flash-lite"
)
model_with_tools = model.bind_tools([calculator])
接着就可以进行调用:
response = model_with_tools.invoke(
"What is 2 + 6?"
)
模型可能会以结构化的工具请求形式进行回复,例如:
calculator(
a=2,
b=6,
operation="add"
)
bind_tools() 并不会实际运行计算器,它只是声明该工具可用——模型在需要时才会请求使用该工具。
抽象概念的体现位置
手动实现时,工程师需要处理整个长流程:
Create function
↓
Create tool schema
↓
Send schema to LLM
↓
Receive tool call
↓
Extract arguments
↓
Execute function
↓
Create tool result
↓
Send result back to LLM
↓
Check if another tool call is needed
↓
Repeat
使用 LangChain 后,大部分流程都在智能体运行时中完成。关注点转向了:
What capability does my application need?
↓
Define the tool
↓
Give it to the model
↓
Build the application
复杂性并未消失,只是被隐藏在了某个边界之后。
实际获得的收益
LangChain 并没有发明工具调用功能,原始 API 已经支持这一功能。其优势在于无需在每个功能中都重新设计架构、循环逻辑和历史记录处理方式,这样就可以将时间投入到产品相关的问题上:
- 助手应该具备哪些能力?
- 哪些工具属于功能范围之内?
- 当某个工具出现故障时该如何处理?
每个项目都需要使用框架吗?
并非总是如此。亲手编写工具调用代码仍是最好的学习方式。亲自走一遍流程:
LLM
↓
Tool call
↓
Application
↓
Tool execution
↓
Tool result
↓
LLM
能让后续框架的使用变得不那么神秘。在不知道某个抽象层能解决什么问题的情况下就使用它,会大大增加调试难度。
一个值得坚持的习惯是:先了解底层机制,然后再使用抽象层,这样就不必为每个任务都重新编写底层代码。那些跳过这一步的团队往往将LangChain视为魔法工具,一旦工具的架构或重试策略出现异常就会陷入困境。而同时掌握这两项技能的团队则能更快地解决问题,同时在生产事故需要时仍能直接操作底层代码。