LangChain Agents 调用外部工具(Tools)是其核心能力之一——让大语言模型(LLM)不仅能“思考”,还能“行动”。下面我将从 原理、定义方式、调用机制、安全实践、实战示例 五个维度,系统讲解如何在 LangChain 中集成和使用外部工具。


一、核心原理:Agent 如何调用工具?

LangChain Agent 的工作流程如下:

sequenceDiagram
    User->>Agent: “今天北京天气?明天适合跑步吗?”
    Agent->>LLM: 根据 prompt 推理下一步
    LLM-->>Agent: Thought: 需要查天气 → Action: Search("北京天气")
    Agent->>Tool (Search): 调用 search("北京天气")
    Tool-->>Agent: Observation: "北京今天晴,25°C"
    Agent->>LLM: 继续推理
    LLM-->>Agent: Thought: 需判断是否适合跑步 → Action: Calculator("25 > 20")
    Agent->>Tool (Calculator): 调用 calculator("25 > 20")
    Tool-->>Agent: Observation: "True"
    Agent->>LLM: 整合信息
    LLM-->>User: 今天北京25°C,天气晴朗,适合跑步!

关键点

  • LLM 不直接执行代码,而是输出 结构化指令(如 JSON 或 function call)
  • Agent Executor 解析指令调用对应工具返回结果
  • 工具必须是 纯函数(输入 → 输出,无副作用或可控副作用)

二、定义工具的三种方式

方式 1:使用 @tool 装饰器(推荐)

from langchain.tools import tool

@tool
def multiply(a: int, b: int) -> int:
    """将两个整数相乘"""
    return a * b

# 自动提取名称 "multiply" 和描述
print(multiply.name)      # "multiply"
print(multiply.description)  # "将两个整数相乘"

✅ 优点:自动解析函数签名和 docstring,支持类型提示


方式 2:手动创建 Tool 对象

from langchain.tools import Tool

def get_current_time() -> str:
    from datetime import datetime
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")

time_tool = Tool(
    name="CurrentTime",
    func=get_current_time,
    description="获取当前日期和时间"
)

✅ 适用场景:需要自定义名称/描述,或包装第三方库


方式 3:使用 LangChain 内置工具(开箱即用)

from langchain_community.tools import (
    DuckDuckGoSearchRun,
    WikipediaQueryRun,
    ArxivQueryRun
)
from langchain_community.utilities import WikipediaAPIWrapper

search = DuckDuckGoSearchRun()
wiki = WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper())
arxiv = ArxivQueryRun()

🔌 常见内置工具:

  • 网络搜索:DuckDuckGoSearchRun, GoogleSearchRun
  • 知识库:WikipediaQueryRun, ArxivQueryRun
  • 数学计算:LLMMathChain
  • 数据库:SQLDatabaseToolkit

三、工具调用机制详解

1. Agent 如何“知道”有哪些工具?

通过 Prompt 模板 显式告知 LLM 可用工具列表:

你是一个智能助手,可以使用以下工具:

- Search: useful for when you need to answer questions about current events. Input should be a search query.
- Calculator: useful for math calculations. Input should be a valid Python expression.

Use the following format:

Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should be one of [Search, Calculator]
Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question

📌 现代方式:使用 OpenAI Functions / Tool Calling 协议(更可靠)

  • LLM 直接输出 JSON 格式的 function call
  • 无需解析自然语言,减少错误

2. 执行过程(AgentExecutor)

from langchain.agents import AgentExecutor

agent_executor = AgentAssistant(
    agent=your_agent,
    tools=[search_tool, calc_tool],
    verbose=True,          # 打印每一步
    max_iterations=10,     # 防止无限循环
    handle_parsing_errors=True  # 处理 LLM 输出格式错误
)

response = agent_executor.invoke({"input": "2024年奥运会主办城市人口多少?"})

⚙️ 执行逻辑:

  1. 将用户输入 + 工具列表注入 prompt
  2. 调用 LLM 获取 action
  3. 匹配工具名称 → 调用函数
  4. 将结果作为 observation 返回 LLM
  5. 重复直到得到 Final Answer

四、实战:开发一个“金融数据查询 Agent”

目标:回答“苹果公司最新股价是多少?市盈率如何?”

步骤 1:定义自定义工具
import yfinance as yf
from langchain.tools import tool

@tool
def get_stock_price(ticker: str) -> dict:
    """获取股票最新价格和基本信息"""
    stock = yf.Ticker(ticker)
    hist = stock.history(period="1d")
    info = stock.info
    return {
        "price": hist['Close'].iloc[-1],
        "pe_ratio": info.get('trailingPE', 'N/A'),
        "market_cap": info.get('marketCap', 'N/A')
    }
步骤 2:创建 Agent(使用 OpenAI Functions)
from langchain_openai import ChatOpenAI
from langchain import hub
from langchain.agents import create_openai_functions_agent

llm = ChatOpenAI(model="gpt-4-turbo", temperature=0)
prompt = hub.pull("hwchase17/openai-functions-agent")

agent = create_openai_functions_agent(
    llm=llm,
    tools=[get_stock_price],
    prompt=prompt
)

executor = AgentExecutor(agent=agent, tools=[get_stock_price], verbose=True)
步骤 3:运行
result = executor.invoke({
    "input": "苹果公司(AAPL)最新股价和市盈率是多少?"
})
print(result["output"])

输出

“苹果公司(AAPL)最新股价为 192.53 美元,市盈率为 31.2。”

💡 背后调用

  • LLM 识别出需要调用 get_stock_price("AAPL")
  • 工具返回结构化数据
  • LLM 生成自然语言回答

五、高级技巧与安全实践

1. 工具输入验证(防注入攻击)

@tool
def safe_search(query: str) -> str:
    # 过滤危险字符
    if any(c in query for c in [";", "|", "&", "`"]):
        raise ValueError("Invalid characters in query")
    return DuckDuckGoSearchRun().run(query)

2. 异步工具(提升性能)

@tool
async def async_api_call(url: str) -> dict:
    import httpx
    async with httpx.AsyncClient() as client:
        resp = await client.get(url)
        return resp.json()

3. 工具缓存(避免重复调用)

from functools import lru_cache

@tool
@lru_cache(maxsize=128)
def cached_wiki(query: str) -> str:
    return WikipediaQueryRun().run(query)

4. 多工具协作

tools = [
    get_stock_price,
    DuckDuckGoSearchRun(name="NewsSearch"),
    Calculator()
]
# Agent 会根据问题自动选择组合

六、常见问题与解决方案

问题 原因 解决方案
LLM 不调用工具 描述不清 / LLM 能力不足 使用 GPT-4-Turbo,明确工具用途
工具调用参数错误 类型不匹配 使用 Pydantic 验证输入
无限循环 奖励信号缺失 设置 max_iterations=5
安全风险 执行任意代码 禁用 eval,用沙箱(如 RestrictedPython

七、总结:最佳实践清单

Do

  • @tool 装饰器定义工具,写清晰 docstring
  • 优先使用 OpenAI Functions Agent(比 ReAct 更可靠)
  • 限制工具数量(3–5 个为佳)
  • 添加输入验证和错误处理
  • 开启 verbose=True 调试

Don’t

  • 在工具中执行 os.system()eval()
  • 让工具有不可控副作用(如直接发邮件)
  • 忽略 max_iterations 导致死循环

🚀 快速模板(复制即用)

from langchain.tools import tool
from langchain_openai import ChatOpenAI
from langchain import hub
from langchain.agents import create_openai_functions_agent, AgentExecutor

@tool
def my_tool(x: str) -> str:
    """描述工具功能"""
    return f"Processed: {x}"

llm = ChatOpenAI(model="gpt-4-turbo")
prompt = hub.pull("hwchase17/openai-functions-agent")
agent = create_openai_functions_agent(llm, [my_tool], prompt)
executor = AgentExecutor(agent=agent, tools=[my_tool], verbose=True)

print(executor.invoke({"input": "用 my_tool 处理 'hello'"}))

🔗 官方工具文档:https://python.langchain.com/docs/modules/agents/tools/

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐