LangChain 开发 Agent 实战:从零构建可调用工具的智能代理(附完整可运行代码)
摘要
本文面向中高级开发者,以 LangChain v0.1.18+(支持 @tool 装饰器 + create_tool_calling_agent 新范式) 为基础,手把手实现一个具备真实业务能力的 Agent:支持查询天气、执行 Python 计算、读取本地文件的多工具协同智能体 。全程避开过时的 ZeroShotAgent 和 Tool 类手动注册方式,采用官方推荐的现代 API(@tool + LLMTool + create_tool_calling_agent),并解决常见陷阱:工具参数校验失败、LLM 拒绝调用工具、Observation 截断、异步工具阻塞等问题。文末提供完整可运行代码(含 requirements.txt 和测试用例),开箱即用。
正文
一、为什么必须升级到新 Agent 范式?
LangChain 在 v0.1.16 后彻底重构 Agent 架构:
❌ 旧方式(已弃用):initialize_agent(..., agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION)
✅ 新方式(推荐):create_tool_calling_agent(llm, tools, prompt) + AgentExecutor
核心优势:
- 工具定义更 Pythonic(
@tool装饰器 + 类型注解自动转 JSON Schema) - LLM 直接输出结构化 tool_calls(OpenAI / Anthropic / Ollama 均原生支持)
- 自动处理
tool_call→tool_output→final answer的完整链路 - 支持流式响应、异步工具、自定义 Prompt 模板
✅ 本文基于
langchain-core==0.1.43,langchain==0.1.18,langchain-openai==0.1.7
二、实战:构建三工具 Agent(天气 + 计算 + 文件读取)
1. 环境准备与依赖
bash
pip install langchain langchain-openai python-dotenv requests
# 若用本地模型(如 Ollama):pip install langchain-ollama
2. 定义三个安全可控的工具(带类型注解 & 错误兜底)
python
# tools.py
from langchain_core.tools import tool
import requests
import json
import os
@tool
def get_weather(city: str) -> str:
"""获取指定城市的实时天气(模拟,实际可对接和风天气 API)"""
if not city.strip():
return "城市名不能为空"
# 模拟 API 调用(生产环境替换为 requests.get(...))
return f"【{city}】晴,25°C,湿度65%,空气质量良"
@tool
def calculate(expression: str) -> str:
"""安全执行 Python 表达式计算(禁用危险函数)"""
try:
# 白名单函数 + 字面量限制
allowed_names = {"abs": abs, "round": round, "max": max, "min": min}
result = eval(expression, {"__builtins__": {}}, allowed_names)
return str(result)
except Exception as e:
return f"计算错误:{str(e)}"
@tool
def read_file(filepath: str) -> str:
"""读取项目根目录下的文本文件(路径白名单校验)"""
# 仅允许读取 ./data/ 下的 .txt 文件
if not filepath.startswith("data/") or not filepath.endswith(".txt"):
return "拒绝访问:仅支持 data/ 目录下的 .txt 文件"
try:
with open(filepath, "r", encoding="utf-8") as f:
content = f.read()[:1000] # 防止大文件爆内存
return f"文件内容(前1000字):\n{content}"
except FileNotFoundError:
return f"文件未找到:{filepath}"
except Exception as e:
return f"读取失败:{str(e)}"
⚠️ 关键设计点:
- 所有参数必须有类型注解(
str,int等),LangChain 依赖此生成 OpenAPI Schema- 工具函数需返回
str(Observation 必须是字符串)- 加入输入校验与异常捕获,避免 Agent 因工具崩溃而卡死
3. 构建 Agent(使用 create_tool_calling_agent)
python
# agent.py
from langchain import hub
from langchain_openai import ChatOpenAI
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.messages import HumanMessage, AIMessage
from tools import get_weather, calculate, read_file
# 1. 初始化 LLM(支持 tool calling 的模型)
llm = ChatOpenAI(
model="gpt-3.5-turbo-0125", # 必须支持 function calling
temperature=0,
api_key="YOUR_OPENAI_KEY" # 或使用 os.getenv("OPENAI_API_KEY")
)
# 2. 加载官方推荐 Prompt(ReAct + Tool Calling)
prompt = hub.pull("hwchase17/openai-functions-agent")
# 3. 创建 Agent(自动注入 tools 的 schema)
agent = create_tool_calling_agent(
llm=llm,
tools=[get_weather, calculate, read_file],
prompt=prompt,
)
# 4. 封装为可执行器(支持 streaming & tracing)
agent_executor = AgentExecutor(
agent=agent,
tools=[get_weather, calculate, read_file],
verbose=True, # 查看每步推理日志
handle_parsing_errors=True, # 自动修复 LLM 输出格式错误
max_iterations=10, # 防止无限循环
)
4. 运行与调试:关键技巧
python
# main.py
if __name__ == "__main__":
# 测试用例 1:多轮工具调用
result = agent_executor.invoke({
"input": "北京天气如何?再算一下 123*456 的结果,最后读取 data/example.txt"
})
print("最终答案:", result["output"])
# 测试用例 2:流式响应(适用于 Web UI)
for chunk in agent_executor.stream({"input": "上海今天温度多少?"}):
if "output" in chunk:
print("→", chunk["output"])
elif "steps" in chunk:
for step in chunk["steps"]:
if "observation" in step:
print("🔍 工具返回:", step["observation"][:100] + "...")
5. 解决高频问题(实战避坑指南)
| 问题 | 原因 | 解决方案 |
|---|---|---|
| LLM 拒绝调用工具,直接回答 | Prompt 不匹配 / LLM 不支持 tool calling | ✅ 使用 hub.pull("hwchase17/openai-functions-agent");确认模型为 gpt-3.5-turbo-0125 或 gpt-4-turbo |
| Observation 被截断 | 默认 observation limit 为 1000 字符 | ✅ 在 AgentExecutor 中设置 max_execution_time=30, early_stopping_method="generate" |
| 异步工具阻塞主线程 | @tool 默认同步 |
✅ 改用 @asynchronous_tool(需 asyncio + await)或 ThreadPoolExecutor 包装 |
| 中文提示词失效 | LangChain 默认英文 Prompt | ✅ 自定义 Prompt:PromptTemplate.from_template("你是一个中文助手... {agent_scratchpad}") |
三、进阶:接入本地模型(Ollama)
python
# 替换 LLM 初始化部分
from langchain_ollama import ChatOllama
llm = ChatOllama(
model="qwen2:7b", # 需提前 `ollama pull qwen2:7b`
temperature=0,
num_predict=512,
# 注意:Ollama 需开启 tool calling 支持(qwen2 支持,llama3 需加 --enable-tool-call)
)
🔍 验证模型能力:
llm.invoke("你好").content→ 应返回字符串;llm.bind_tools(...).invoke(...)→ 应返回AIMessage含tool_calls
总结
本文通过 真实可运行的三工具 Agent 示例,系统性展示了 LangChain 最新 Agent 开发范式:
✅ 正确定义工具 :@tool + 类型注解 + 安全兜底
✅ 正确构建 Agent :create_tool_calling_agent + 官方 Prompt + AgentExecutor
✅ 正确调试运行:流式输出、错误处理、本地模型适配
📌 关键结论:
- 永远不要手动拼接
Tool对象 ------@tool是唯一推荐方式- Prompt 决定 Agent 行为 ------ 优先用
hub.pull(),而非自写模板- Production 环境必加
handle_parsing_errors=True和max_iterations
下一步建议:接入 RAG(VectorStoreRetriever 作为工具)、添加记忆(ConversationBufferMemory)、部署为 FastAPI 接口。
标签
LangChain Agent LLM Python AI开发 大模型应用 工具调用 ChatGPT Ollama 实战教程