LangChain 开发 Agent 实战:从零构建可调用工具的智能代理(附完整可运行代码)

LangChain 开发 Agent 实战:从零构建可调用工具的智能代理(附完整可运行代码)

摘要

本文面向中高级开发者,以 LangChain v0.1.18+(支持 @tool 装饰器 + create_tool_calling_agent 新范式) 为基础,手把手实现一个具备真实业务能力的 Agent:支持查询天气、执行 Python 计算、读取本地文件的多工具协同智能体 。全程避开过时的 ZeroShotAgentTool 类手动注册方式,采用官方推荐的现代 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_calltool_outputfinal 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-0125gpt-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(...) → 应返回 AIMessagetool_calls


总结

本文通过 真实可运行的三工具 Agent 示例,系统性展示了 LangChain 最新 Agent 开发范式:

正确定义工具@tool + 类型注解 + 安全兜底

正确构建 Agentcreate_tool_calling_agent + 官方 Prompt + AgentExecutor

正确调试运行:流式输出、错误处理、本地模型适配

📌 关键结论:

  • 永远不要手动拼接 Tool 对象 ------ @tool 是唯一推荐方式
  • Prompt 决定 Agent 行为 ------ 优先用 hub.pull(),而非自写模板
  • Production 环境必加 handle_parsing_errors=Truemax_iterations

下一步建议:接入 RAG(VectorStoreRetriever 作为工具)、添加记忆(ConversationBufferMemory)、部署为 FastAPI 接口。


标签

LangChain Agent LLM Python AI开发 大模型应用 工具调用 ChatGPT Ollama 实战教程