LangChain核心组件深入理解第四篇 -- Tool Agent运行的手和脚

摘要:LangChain Tools 是构建现代 AI Agent 的核心基石------它们让大语言模型不再只是「会说话的百科全书」,而是能够主动查询数据库、执行代码、写入状态、甚至实时推送进度的自主执行者。本文从工具基础创建出发,深入探讨 Schema 定义、上下文读取(短期记忆、Context、长期记忆、流写入)、工具返回值的多种形态及错误处理策略,最后剖析动态工具选择的设计哲学。文章基于 LangChain 官方文档,结合大量可运行代码示例,帮助读者从「会用工具」进阶到「设计好工具」。

关键词:LangChain Tools;AI Agent;ToolRuntime;工具返回值;动态工具选择;错误处理;上下文管理


文章目录

  1. [LangChain Tools 介绍](#LangChain Tools 介绍)
  2. [创建工具 Tool](#创建工具 Tool)
  3. 读取上下文:让工具「看见」世界
  4. 工具执行与返回值设计
  5. 动态工具选择:按需装配的智慧
  6. 总结与最佳实践

1. LangChain Tools介绍

在 AI Agent 的架构中,工具(Tool)是连接语言模型与现实世界的桥梁。一个纯粹的 LLM 受限于训练数据的截止时间和封闭的知识边界,无法查询实时数据、无法执行代码、无法操作外部系统------而工具正是打破这些边界的关键。

工具拓展 Agent 的能力边界,使其能够获取实时数据、执行代码、查询外部数据库,并在现实环境中执行各类操作。从底层逻辑看,工具是具备规范输入输出参数、可被调用的函数,这类函数会被交付给对话大模型。模型会结合对话上下文判断何时调用工具 以及需要传入哪些输入参数

换句话说,LangChain Tools 的本质是一套函数签名约束 + 运行时上下文注入 + 返回值协议的标准化体系。理解这一体系,是设计高质量 Agent 的前提。


2. 创建工具Tool

2.1 工具基础定义

创建工具最简单的方式是使用 @tool 装饰器。默认情况下,函数的文档字符串会作为该工具的描述,帮助模型判断何时调用此工具。

python 复制代码
from langchain.tools import tool

@tool
def search_database(query: str, limit: int = 10) -> str:
    """Search the customer database for records matching the query.

    Args:
        query: Search terms to look for
        limit: Maximum number of results to return
    """
    # 这里对接真实的数据库查询逻辑
    return f"Found {limit} results for '{query}'"

⚠️ 关键要点

  • 必须添加类型提示:类型提示用于定义工具的输入架构(Schema)。没有类型提示,框架无法推断参数类型,工具将无法正常工作。
  • 文档字符串要详实且简洁:这是模型判断「是否调用此工具」的唯一依据。描述的质量直接影响模型的决策准确度。
  • 工具 = 函数 + 元数据:LangChain 会自动从函数签名和文档字符串中提取工具名称、描述和参数 Schema。

命名建议 :工具名称建议采用蛇形命名法(例如使用 web_search,而非 Web Search)。部分模型服务商无法正常识别含空格或特殊字符的名称,甚至会直接报错拒绝调用。仅使用字母、数字、下划线与连字符命名,有助于提升在各类服务商平台的兼容性。

2.2 自定义工具属性

自定义工具名称

默认情况下,工具名称取自函数名。但在实际项目中,你可能需要更具描述性的名称------比如函数内部叫 search,但对外给模型展示为 web_search

python 复制代码
@tool("web_search")  # 自定义对外名称
def search(query: str) -> str:
    """Search the web for information."""
    return f"Results for: {query}"

print(search.name)  # 输出: web_search

这对于同一个函数注册为不同名称的多个工具的场景尤为有用。

自定义工具描述

有时函数文档字符串很长,或包含一些不该暴露给模型的实现细节,这时可以覆盖自动生成的工具描述:

python 复制代码
@tool("calculator", description="Performs arithmetic calculations. Use this for any math problems.")
def calc(expression: str) -> str:
    """Evaluate mathematical expressions."""
    return str(eval(expression))

通过 description 参数,你可以给模型更精准、更不含噪声的描述,提升调用准确度。

2.3 高级Schema定义

当工具参数不止是简单字符串和数字,而是包含枚举类型、嵌套结构、默认值等复杂场景时,就需要借助 Pydantic 模型来定义参数 Schema。

python 复制代码
from pydantic import BaseModel, Field
from typing import Literal

class WeatherInput(BaseModel):
    """Input for weather queries."""
    location: str = Field(description="City name or coordinates")
    units: Literal["celsius", "fahrenheit"] = Field(
        default="celsius",
        description="Temperature unit preference"
    )
    include_forecast: bool = Field(
        default=False,
        description="Include 5-day forecast"
    )

@tool(args_schema=WeatherInput)
def get_weather(location: str, units: str = "celsius", include_forecast: bool = False) -> str:
    """Get current weather and optional forecast."""
    temp = 22 if units == "celsius" else 72
    result = f"Current weather in {location}: {temp} degrees {units[0].upper()}"
    if include_forecast:
        result += "\nNext 5 days: Sunny"
    return result

为什么要用 Pydantic Schema?

  • Field(description=...) 给每个参数提供独立描述,模型能更准确地填充参数;
  • Literal 类型约束可选值范围,避免模型传入非法值;
  • 默认值机制让可选参数表现更稳定,减少调用失败率。

实战建议:对于参数超过 3 个或包含枚举值的工具,强烈建议使用 Pydantic Schema。虽然多写一些代码,但模型调用准确度会有显著提升。

2.4 保留参数名

LangChain 保留了一些参数名供框架内部使用,不可用作工具参数。使用这些名称会引发运行时错误。

常见的保留参数名包括那些已被 ToolRuntime 占用的字段(如 runtimestatestore 等)。在命名自定义参数时,请务必避开这些名称。


3. 读取上下文:让工具「看见」世界

工具的强大之处,不仅仅在于它能执行某个函数------更在于它能够在执行时感知当前对话状态、用户身份、持久化存储等运行时信息。一个脱离了上下文的工具就像闭着眼睛干活的人,只能处理最机械的任务。

工具可通过 工具运行时参数(ToolRuntime) 读取丰富的运行时信息:

3.1 短期记忆:State 状态

State(状态) 指仅在单次对话存续期间有效的短期记忆,其中包含消息历史记录以及你自定义的所有图状态字段。它相当于「本次对话的工作记忆」。

访问State

各类工具可通过 runtime.state 获取当前对话状态,包括消息历史和自定义字段。

python 复制代码
from langchain.tools import tool, ToolRuntime
from langchain.messages import HumanMessage

@tool
def get_last_user_message(runtime: ToolRuntime) -> str:
    """获取用户最近一条消息。"""
    messages = runtime.state["messages"]

    # 从消息列表中逆序查找最后一条人类消息
    for message in reversed(messages):
        if isinstance(message, HumanMessage):
            return message.content

    return "No user messages found"

@tool
def get_user_preference(
    pref_name: str,
    runtime: ToolRuntime
) -> str:
    """获取用户偏好设置。"""
    preferences = runtime.state.get("user_preferences", {})
    return preferences.get(pref_name, "Not set")

设计要点 :State 是短期的。对话结束,State 就消失了。不要把需要跨会话持久化的重要信息只放在 State 里。

更新State

工具不仅能读 State,还能写 State 。使用 Command 返回指令来更新状态字段,这对于需要修改 Agent 运行状态的工具非常重要。

python 复制代码
from langchain.agents import AgentState
from langchain.messages import ToolMessage
from langchain.tools import ToolRuntime, tool
from langgraph.types import Command

class CustomState(AgentState):
    user_name: str
    preferred_language: str = "English"

@tool
def set_user_name(new_name: str, runtime: ToolRuntime[None, CustomState]) -> Command:
    """设置对话中的用户名。"""
    return Command(
        update={
            "user_name": new_name,
            "messages": [
                ToolMessage(
                    content=f"User name set to {new_name}.",
                    tool_call_id=runtime.tool_call_id,
                )
            ],
        }
    )

并发写冲突警示 :当工具更新状态变量时,建议为这些字段定义归约函数。由于 LLM 可以在单轮对话中并行调用多个工具,如果多个工具同时更新同一字段,归约函数用于解决冲突(例如选择最新值或合并列表)。

3.2 Context 上下文:调用级配置

Context 提供调用时传入的不可变配置数据。与 State 不同,Context 在整个调用链路中保持不变,用于存储用户 ID、会话详情等无需在运行时修改的配置。

Context vs thread_id :通过 config={"configurable": {"thread_id": ...}} 传入的线程 ID 用于划定会话范围,管控消息历史与检查点;而 Context 则承载每次运行专属数据,供工具与中间件在调用时读取。生产环境中通常会同时传入二者:每个会话分配固定不变的线程 ID,且每次调用都携带一个 Context 对象。

python 复制代码
from dataclasses import dataclass

from langchain.agents import create_agent
from langchain.tools import tool, ToolRuntime
from langchain_core.utils.uuid import uuid7
from langchain_openai import ChatOpenAI

USER_DATABASE = {
    "user123": {
        "name": "Alice Johnson",
        "account_type": "Premium",
        "balance": 5000,
        "email": "alice@example.com",
    },
    "user456": {
        "name": "Bob Smith",
        "account_type": "Standard",
        "balance": 1200,
        "email": "bob@example.com",
    },
}

@dataclass
class UserContext:
    user_id: str

@tool
def get_account_info(runtime: ToolRuntime[UserContext]) -> str:
    """获取当前用户的账户信息。"""
    user_id = runtime.context.user_id

    if user_id in USER_DATABASE:
        user = USER_DATABASE[user_id]
        return (
            f"Account holder: {user['name']}\n"
            f"Type: {user['account_type']}\n"
            f"Balance: ${user['balance']}"
        )
    return "User not found"

model = ChatOpenAI(model="google_genai:gemini-3.5-flash")
agent = create_agent(
    model,
    tools=[get_account_info],
    context_schema=UserContext,
    system_prompt="You are a financial assistant.",
)

result = agent.invoke(
    {"messages": [{"role": "user", "content": "What's my current balance?"}]},
    config={"configurable": {"thread_id": str(uuid7())}},
    context=UserContext(user_id="user123"),
)

Context 的典型使用场景:

  • 多租户隔离 :每个用户请求携带不同的 user_id,工具自动识别当前操作者;
  • A/B 测试配置:传入实验分组标识,工具根据分组返回不同逻辑;
  • 环境切换 :传入 env="staging"env="production",工具自动切换数据源。

3.3 长期记忆:Store 存储区

基础存储区(Store)提供可跨会话留存的持久化存储。不同于 State 的短期性,存入 Store 的数据在后续会话中仍可调用,非常适合存放用户画像、学习笔记、偏好设置等需要长期保留的信息。

python 复制代码
from typing import Any
from langgraph.store.memory import InMemoryStore
from langchain.agents import create_agent
from langchain.tools import tool, ToolRuntime
from langchain_openai import ChatOpenAI

# 读取长期记忆
@tool
def get_user_info(user_id: str, runtime: ToolRuntime) -> str:
    """查找用户信息。"""
    store = runtime.store
    user_info = store.get(("users",), user_id)
    return str(user_info.value) if user_info else "Unknown user"

# 写入长期记忆
@tool
def save_user_info(user_id: str, user_info: dict[str, Any], runtime: ToolRuntime) -> str:
    """保存用户信息。"""
    store = runtime.store
    store.put(("users",), user_id, user_info)
    return "Successfully saved user info."

model = ChatOpenAI(model="gpt-5.5")

store = InMemoryStore()
agent = create_agent(
    model,
    tools=[get_user_info, save_user_info],
    store=store
)

# 第一次会话:保存用户信息
agent.invoke({
    "messages": [{"role": "user", "content": "Save the following user: userid: abc123, name: Foo, age: 25, email: foo@langchain.dev"}]
})

# 第二次会话:读取用户信息------数据依然在!
agent.invoke({
    "messages": [{"role": "user", "content": "Get user info for user with id 'abc123'"}]
})
# 输出:
# - Name: Foo
# - Age: 25
# - Email: foo@langchain.dev

Store 采用命名空间 / 键值 模式管理数据,类似于文件系统中的目录 + 文件名。("users",) 就是一个命名空间,user_id 是键。

生产环境提醒 :请选用 PostgresStore 这类持久化存储实现,而非内存存储 InMemoryStore。此处使用内存存储仅为方便演示示例代码。生产环境中 Store 的生命周期应跨越多次 Agent 调用甚至多轮对话。

3.4 流写入器:实时进度反馈

对于长时间运行的任务(如文件处理、数据分析、多步查询),用户需要感知任务进度,而不是面对一个「沉默的黑盒」。流写入器 正是为此而生------工具可以在执行过程中通过 runtime.stream_writer 向调用方推送实时更新。

python 复制代码
from langchain.tools import tool, ToolRuntime

@tool
def get_weather(city: str, runtime: ToolRuntime) -> str:
    """获取指定城市的天气(模拟长时间任务)。"""
    writer = runtime.stream_writer

    # 推送实时进度
    writer(f"🌍 正在查询城市: {city}")
    writer(f"📡 已获取 {city} 的气象数据")

    return f"It's always sunny in {city}!"

流写入器的典型使用场景:

  • 搜索工具:推送「正在搜索...→ 找到 50 条结果 → 正在排序...」;
  • 文档生成工具:推送「正在分析结构...→ 正在生成第 1/3 节...」;
  • 代码执行工具:推送「正在安装依赖...→ 正在运行测试...」。

3.5 执行信息与服务器信息

这两个 API 主要用于运维可观测性多租户服务端场景

执行信息 :通过 runtime.execution_info 获取线程 ID、运行 ID 以及重试次数,方便日志追踪和调试。

python 复制代码
from langchain.tools import tool, ToolRuntime

@tool
def log_execution_context(runtime: ToolRuntime) -> str:
    """记录执行身份信息,用于日志追踪。"""
    info = runtime.execution_info
    print(f"Thread: {info.thread_id}, Run: {info.run_id}")
    print(f"Attempt: {info.node_attempt}")
    return "done"

Requires deepagents>=0.5.0(或 langgraph>=1.1.5)。

服务器信息 :当工具在 LangGraph 服务端运行时,可通过 runtime.server_info 获取助手 ID、图谱 ID 以及已完成身份验证的用户信息。

python 复制代码
from langchain.tools import tool, ToolRuntime

@tool
def get_assistant_scoped_data(runtime: ToolRuntime) -> str:
    """获取当前助手作用域内的数据。"""
    server = runtime.server_info
    if server is not None:
        print(f"Assistant: {server.assistant_id}, Graph: {server.graph_id}")
        if server.user is not None:
            print(f"User: {server.user.identity}")
    return "done"

4. 工具执行与返回值设计

在 LangChain 中,Agent 调用工具的路径分为两层:

  • LangChain Agent 层 :通过 create_agent 创建,工具的错误处理逻辑可通过中间件配置;
  • LangGraph 工作流层 :工具执行由 ToolNode 负责,包含读取当前图状态、运行域上下文的完整实现。

而无论在哪一层,工具返回值的设计都直接影响 Agent 的后续行为。返回值的类型决定了模型是否能看到输出、状态是否被修改、甚至 Agent 循环是继续还是终止。

4.1 五种返回值类型详解

① 返回字符串 --- 适用于人类可读的结果

python 复制代码
from langchain.tools import tool

@tool
def get_weather(city: str) -> str:
    """Get weather for a city."""
    return f"It is currently sunny in {city}."

行为说明:

  1. 返回值会被转换为工具消息;
  2. 大模型读取该文本并决定后续执行操作;
  3. 除非后续由模型或其他工具修改,否则 Agent 状态字段不会发生变更。

当返回结果本身是便于人类阅读的文本时,采用此方式。

② 返回对象(字典) --- 适用于结构化数据

python 复制代码
from langchain.tools import tool

@tool
def get_weather_data(city: str) -> dict:
    """Get structured weather data for a city."""
    return {
        "city": city,
        "temperature_c": 22,
        "conditions": "sunny",
    }

行为说明:

  1. 将对象序列化后作为工具输出返回;
  2. 模型可读取指定字段并基于这些字段进行推理;
  3. 与字符串返回结果类似,该操作不会直接更新图状态。

当下游推理更适合结构化明确字段、而非自由格式文本时,采用此方式。例如:返回 JSON 供模型提取特定数值进行比较。

③ 返回指令(Command) --- 适用于需要更新状态的场景

python 复制代码
from langchain.messages import ToolMessage
from langchain.tools import ToolRuntime, tool
from langgraph.types import Command

@tool
def set_language(language: str, runtime: ToolRuntime) -> Command:
    """设置首选回复语言。"""
    return Command(
        update={
            "preferred_language": language,
            "messages": [
                ToolMessage(
                    content=f"Language set to {language}.",
                    tool_call_id=runtime.tool_call_id,
                )
            ],
        }
    )

行为说明:

  1. 该指令通过 update 方法修改状态;
  2. 更新后的状态可在同一次执行流程的后续步骤中调用;
  3. 若字段可能被并行工具调用修改,请使用归约器处理。

当工具不仅返回数据,还会变更 Agent 状态时,采用此方式。

④ 返回多模态内容 --- 适用于图文混合输出

python 复制代码
from langchain.tools import tool

@tool
def capture_screenshot() -> list[dict]:
    """截取当前页面截图。"""
    return [
        {"type": "text", "text": "Screenshot of the current page:"},
        {"type": "image", "url": "https://example.com/page.png"},
    ]

行为说明:

  1. 返回值会被转换为包含多模态内容的工具消息;
  2. 可通过 message.content_blocks 读取工具执行完成后标准化的内容块列表;
  3. 所使用的模型必须支持你返回的各类模态数据。

⚠️ 在返回图片、音频或视频内容前,请先确认该模型具备对应处理能力。

⑤ 直接从工具返回(return_direct=True --- 适用于无需模型再处理的确定答案

python 复制代码
from langchain.agents import create_agent
from langchain.tools import tool
from langchain_openai import ChatOpenAI

@tool(return_direct=True)
def fetch_order_status(order_id: str) -> str:
    """查询客户订单状态。"""
    return f"Order {order_id} is shipped and will arrive in 2 days."

agent = create_agent(
    ChatOpenAI(model="google_genai:gemini-3.5-flash"),
    tools=[fetch_order_status],
)

result = agent.invoke({
    "messages": [{"role": "user", "content": "What is the status of order #12345?"}]
})
# Agent 直接返回工具输出,不再调用模型二次处理:
# "Order 12345 is shipped and will arrive in 2 days."

行为说明:

  1. 工具正常执行,其输出内容被封装在工具消息中;
  2. Agent 终止循环流程,直接将工具输出作为最终回复返回;
  3. 若模型在单次交互中调用多个工具,仅当所有被调用工具的 return_direct 均设为 True 时,该机制才会生效。

适用场景:工具输出已是完整、可直接呈现给用户的答案;无需额外逻辑推演,希望省去一次多余的模型调用;需要保证原始输出不被模型改写、概括或二次处理。

不适用场景 :当工具返回结果需要进一步推理、汇总,或需要串联调用其他工具时,不适合将 return_direct 设置为 True。

4.2 错误处理的生产级实践

工具调用不可避免地会遇到各种异常------网络波动、超时、参数错误、业务逻辑校验失败......一个健壮的 Agent 必须有完善的错误处理机制。LangChain 通过中间件提供了灵活的错误处理能力。

python 复制代码
"""
生产级错误处理的代码示例(可区分可重试异常、支持动态配置、埋点扩展):

设计原则:
- 区分网络 / 临时波动异常(可重试)和参数错误 / 业务非法输入(不可重试);
- 把重试参数封装到闭包,支持多 Agent 差异化配置;
- 预留 Langfuse 埋点入口,统计重试次数、失败率;
"""

import time
from collections.abc import Callable
from typing import List

from langchain.agents import create_agent
from langchain.agents.middleware import wrap_tool_call
from langchain_core.messages import ToolMessage
from langchain_core.tools.tool_node import ToolCallRequest

# 可重试异常白名单:网络波动、连接超时、临时资源抢占等瞬时故障
RETRYABLE_EXCEPTIONS = (
    ConnectionError,
    TimeoutError,
    OSError,
)

def build_tool_retry_middleware(
    max_retry: int = 3,
    sleep_sec: float = 1.0,
    skip_retry_err_types: List[type[Exception]] = None
):
    """
    工厂函数:动态生成带自定义重试策略的工具中间件。
    支持不同 Agent 配置不同重试次数和间隔。
    """
    skip_exc = tuple(skip_retry_err_types) if skip_retry_err_types else ()

    @wrap_tool_call
    def tool_retry_middleware(
        request: ToolCallRequest,
        handler: Callable[[ToolCallRequest], ToolMessage],
    ) -> ToolMessage:
        retry_cnt = 0
        final_err: Exception | None = None
        tool_name = request.tool_call["name"]

        while retry_cnt <= max_retry:
            try:
                return handler(request)
            except Exception as e:
                final_err = e
                # 不可重试异常:直接跳出循环
                if isinstance(e, skip_exc):
                    break
                # 非瞬时故障,不重试
                if not isinstance(e, RETRYABLE_EXCEPTIONS):
                    break

                retry_cnt += 1
                if retry_cnt <= max_retry:
                    # 可在此处插入 Langfuse 自定义埋点,记录重试事件
                    print(f"[ToolRetryTrack] tool={tool_name}, retry={retry_cnt}, err={str(e)}")
                    time.sleep(sleep_sec)

        # 重试结束,组装错误消息返回给模型
        err_msg = (
            f"Tool {tool_name} failed. Retry count: {retry_cnt}/{max_retry}.\n"
            f"Exception: {str(final_err)}\n"
            "Tips: If params are wrong, revise your input arguments; if network error, try again later."
        )
        return ToolMessage(content=err_msg, tool_call_id=request.tool_call["id"])

    return tool_retry_middleware

# 示例 1:默认重试 3 次,间隔 1s
retry_mw_3times = build_tool_retry_middleware(max_retry=3, sleep_sec=1.0)
# 示例 2:高可靠工具仅重试 1 次
retry_mw_1time = build_tool_retry_middleware(max_retry=1, sleep_sec=0.5)

# 注入中间件创建 Agent
agent = create_agent(
    model="google_genai:gemini-3.5-flash",
    tools=[],
    middleware=[retry_mw_3times],
)

错误处理的三个关键设计决策

  1. 区分可重试 vs 不可重试ConnectionError 重试有希望成功,ValueError 重试只是浪费时间;
  2. 失败后仍返回 ToolMessage:不要让异常破裂到 Agent 层,而是返回一个结构化的错误消息,让模型自己决定下一步;
  3. 记录和监控:每次重试都应该埋点,便于后续分析工具的稳定性和优化重试策略。

5. 动态工具选择:按需装配的智慧

工具不是越多越好。每增加一个工具,都会增加模型的上下文负担(每个工具的 Schema 和描述都会挤占 token 预算),也会提高模型选错工具的概率。但工具过少又会限制 Agent 的能力边界。

动态工具选择正是解决这一矛盾的方案:可调用的工具集合在运行时动态调整,而非预先全部定义死。根据认证状态、用户权限、功能开关或对话阶段,灵活调整可用工具集。

根据工具是否预先已知,动态工具选择分为两种模式:

5.1 过滤已预注册的工具

在 Agent 创建阶段已知所有可用工具时,预先注册全部工具,然后在每次模型调用前依据运行时状态、权限或上下文动态筛选哪些工具可见。

典型应用场景:

  • 权限控制:免费用户只能看到基础工具,付费用户才能看到高级工具;
  • 对话阶段感知:初期只提供查询工具,确认用户意图后才暴露出写入工具;
  • 多租户场景:不同租户可用的工具集不同,通过 Context 来过滤。

5.2 运行时创建工具

在运行时动态发现工具时(例如从 MCP 服务器加载、根据用户数据生成、或从远程注册表获取),需要两个中间件钩子函数配合:

  • wrap_model_call:将动态工具添加至模型调用请求中;
  • wrap_tool_call:执行新增动态工具的处理逻辑。

这在以下场景中尤为重要:

  • MCP(Model Context Protocol)集成:运行时从 MCP 服务端拉取可用工具列表;
  • 用户自定义工具上传:用户在上传 CSV 文件后,自动生成针对该文件分析的专用工具;
  • 远程工具注册中心:从公司内部的工具注册表动态发现工具版本和能力。

TODO 主架构已完成,还有几个细枝末节的功能待补充。。。。。。。

  1. 总结与最佳实践

回顾全文,我们可以提炼出以下核心设计原则:

维度 最佳实践
工具创建 始终添加类型提示;文档字符串简洁但信息充分;复杂参数使用 Pydantic Schema
工具命名 使用蛇形命名法,避免空格和特殊字符;确保在不同模型服务商之间兼容
上下文读取 短期数据用 State,持久化数据用 Store,不可变配置用 Context
返回值设计 纯文本结果用字符串;结构化数据用字典;需改状态用 Command;多模态内容用标准块;确定答案用 return_direct=True
错误处理 区分可重试和不可重试异常;失败后返回 ToolMessage 而非抛出异常;记录重试事件用于可观测性
工具数量管理 使用动态工具选择,按需暴露工具,避免上下文过载
并发安全 当多个工具可能并行修改同一 State 字段时,必须定义归约函数

LangChain Tools 的设计哲学是给模型武器,但要教会它何时开枪、开什么枪,以及打不中怎么办。当你理解了这个比喻,你就真正理解了 Tools 在 Agent 系统中的位置。

相关推荐
IT_陈寒19 小时前
Redis过期key的坑,差点让线上服务崩了
前端·人工智能·后端
恋猫de小郭19 小时前
AI 又又造词,Graph 就又要替代 Loop 了?
前端·人工智能·ai编程
数智化管理手记19 小时前
全面预算管理执行偏差大?全面预算管理全流程落地步骤是什么
大数据·网络·数据库·人工智能·数据挖掘
suaizai_19 小时前
向量:深度学习的核心基石
人工智能
小码哥哥19 小时前
百度开发者中心软文_企业AI知识库的价值
人工智能·百度
aneasystone本尊19 小时前
学习 OpenMontage 的 12 条流水线
人工智能
rain_sxr19 小时前
十万点不崩:ECharts 大数据量渲染的降采样与增量更新策略
人工智能
小刘学技术19 小时前
AI人工智能决策树分类器:原理、实现与应用
开发语言·人工智能·python·算法·决策树·机器学习·数据挖掘
郑板桥3019 小时前
# AI行业周报(2026.7.11—7.19):全球AI治理新秩序诞生,中美技术博弈进入深水区
人工智能