0 前言
LangChain 1.x 以后,Agent 的主流写法明显收敛了:不要再围 initialize_agent、AgentType、AgentExecutor.run() 老接口转,而是统一:
python
from langchain.agents import create_agent
from langchain.tools import tool
create_agent 会创建一个基于 LangGraph 的可执行 agent。工具可以是普通函数、@tool 包装的函数,也可以来自现成的 Toolkit,如 SQLDatabaseToolkit。
本文讲解 LangChain 1.x 里 Toolkit 应该怎么用。
1 啥是Toolkit?
Tool 是一个单独能力,如:
- 查数据库表结构
- 执行 SQL 查询
- 运行 Python 代码
- 调用搜索 API
- 读取文档
- 调用外部服务
Toolkit 则是一组相关 tools 集。其价值是把某一类任务需要的工具提前封装好。例如 SQL 数据库问答通常至少需要:
- 列出有哪些表
- 查看表结构
- 执行 SQL 查询
- 检查 SQL 是否有明显错误
这些工具手写当然可以,但 LangChain 已经通过 SQLDatabaseToolkit 封装好。
官方当前也推荐用 create_agent 搭配 tools/toolkit:见 Agents、Tools、SQL Database Toolkit。
2 最小 Tool Calling Agent
LangChain 1.x 的基本模式:
python
from langchain.agents import create_agent
from langchain.tools import tool
@tool
def project_llm_config() -> str:
"""Return the local Qwen model and OpenAI-compatible endpoint configured for this project."""
return f"model={QWEN_MODEL}, base_url={QWEN_BASE_URL}"
tool_agent = create_agent(
model=llm,
tools=[project_llm_config],
system_prompt="需要查询项目本地 Qwen 配置时调用 project_llm_config 工具。",
)
调用方式不再是:
python
agent.run("...")
而是:
python
result = tool_agent.invoke({
"messages": [
{"role": "user", "content": "当前项目本地 Qwen 使用的模型和 endpoint 是什么?"}
]
})
print(result["messages"][-1].content)
LangChain 1.x 的 agent 输入输出更接近消息流,返回值里包含完整的 messages 状态。
3 Python Agent:用 PythonREPLTool
python
python_agent = create_agent(
model=llm,
tools=[PythonREPLTool()],
system_prompt=(
"你是一个 Python 编程助手。需要计算或运行 Python 代码时调用 python_repl 工具。"
"只运行用户明确要求的代码。"
),
)
调用:
python
result = python_agent.invoke({
"messages": [
{
"role": "user",
"content": "What is the 10th fibonacci number? Use Python to calculate it."
}
]
})
这里要注意安全边界:PythonREPLTool 能执行代码,不适合直接暴露给不可信用户。教学和本地实验可以用,生产环境必须加沙箱、权限限制和审计。
4 SQL Agent
SQL 是 Toolkit 最经典的用法。
先连接数据库:
python
from langchain_community.utilities import SQLDatabase
from langchain_community.agent_toolkits.sql.toolkit import SQLDatabaseToolkit
db = SQLDatabase.from_uri("sqlite:///Chinook.db")
创建 toolkit 并取出 tools:
python
sql_toolkit = SQLDatabaseToolkit(db=db, llm=llm)
sql_tools = sql_toolkit.get_tools()
print([tool.name for tool in sql_tools])
常见输出类似:
python
[
"sql_db_query",
"sql_db_schema",
"sql_db_list_tables",
"sql_db_query_checker",
]
然后交给 create_agent:
python
sql_agent = create_agent(
model=llm,
tools=sql_tools,
system_prompt=(
"你是一个 SQLite 数据库助手。回答数据库问题时先查看表结构,"
"再生成只读 SQL 查询;不要执行写入、删除或修改数据的语句。"
),
)
调用示例:
python
result = sql_agent.invoke({
"messages": [
{"role": "user", "content": "Describe the Playlist table"}
]
})
print(result["messages"][-1].content)
还可以问:
python
result = sql_agent.invoke({
"messages": [
{
"role": "user",
"content": "List the total sales per country. Which country's customers spent the most?"
}
]
})
Agent 会根据问题自动决定是否先列表、查 schema、生成 SQL、检查 SQL、执行查询,最后组织自然语言答案。
5 1.x v.s 老写法
老写法:
python
from langchain_classic.agents import initialize_agent, AgentType
agent = initialize_agent(
tools,
llm,
agent=AgentType.OPENAI_FUNCTIONS,
)
agent.run("...")
1.x 主写法:
python
from langchain.agents import create_agent
agent = create_agent(
model=llm,
tools=tools,
system_prompt="...",
)
agent.invoke({
"messages": [{"role": "user", "content": "..."}]
})
差异总结:
| 项目 | 老写法 | 1.x 主流写法 |
|---|---|---|
| Agent 创建 | initialize_agent |
create_agent |
| Agent 类型 | AgentType.OPENAI_FUNCTIONS |
通常不需要手动指定 |
| 调用方式 | agent.run(...) |
agent.invoke({"messages": [...]}) |
| 工具定义 | Tool(...) 或旧 toolkit agent |
@tool / toolkit .get_tools() |
| SQL Agent | create_sql_agent(...) |
SQLDatabaseToolkit(...).get_tools() + create_agent |
| 底层状态 | 传统 executor | LangGraph graph state |
6 工程建议
实际项目里建议遵循这几个规则:
-
Toolkit 只负责提供工具
Toolkit 不等于 agent。更清晰的结构是:
toolkit.get_tools()负责拿工具,create_agent()负责推理和调度。 -
SQL Agent 必须加系统约束
至少限制为只读查询,明确禁止
INSERT、UPDATE、DELETE、DROP。 -
真实调用加开关
Notebook 里用类似
RUN_QWEN_TOOLKIT_DEMO=1的开关,可以保证文档能从头执行,同时不会误触发长任务或外部调用。 -
PythonREPLTool 不要直接暴露到公网
它是代码执行能力,不是普通工具。生产环境必须隔离。
7 总结
LangChain 1.x 的 Toolkit 使用方式可以概括成一句话:
Toolkit 提供工具,
create_agent负责编排,模型统一走标准 ChatModel 接口。
在本项目里,就是:
python
tools = toolkit.get_tools()
agent = create_agent(model=llm, tools=tools, system_prompt="...")
result = agent.invoke({"messages": [...]})
这套写法比旧版 initialize_agent + AgentType + agent.run() 更稳定,也更贴近 LangChain 1.x 之后的主流架构。