LangChain 03:工具与 Agent——从函数到可控行动

2026-09-01
12715 分钟
...

1、本篇任务:让 Agent 安全地读取订单

上一课得到结构化分诊结果,但模型不知道真实订单。本课增加一个只读工具 get_order,走通完整 Agent 循环,并把模型、工具包装和领域服务的责任分开。

完成后,用户问“我的 A100 发货了吗”,Agent 会选择工具;工具只按当前登录用户查询;模型基于工具结果回答。它仍然不能退款,因为我们没有提供写工具。

2、工具的本质是受 schema 约束的应用函数

一个好工具需要:稳定名称、清楚描述、窄输入 schema、结构化结果、服务端权限、受控错误。描述写给模型看,权限写给服务端执行;两者不能互相替代。

模型决定是否调用 get_order传哪个 order_id
工具层决定参数是否合法当前用户是谁能否查询
领域服务决定订单是否存在属于谁返回哪些字段

工具参数中不要包含 user_idtenant_id 让模型填写。可信身份来自认证后的 runtime/context。

3、先写与 LangChain 无关的领域服务

Python:

from dataclasses import dataclass

@dataclass(frozen=True)
class Actor:
    user_id: str
    tenant_id: str

class OrderService:
    def get_for_actor(self, actor: Actor, order_id: str) -> dict:
        row = DATABASE.get(order_id)
        if row is None or row["tenant_id"] != actor.tenant_id or row["user_id"] != actor.user_id:
            raise LookupError("ORDER_NOT_FOUND")
        return {"order_id": row["id"], "status": row["status"], "delivered_at": row["delivered_at"]}

这段服务可用普通单元测试验证,不需要模型、不需要 LangChain。工具只是它的 Agent 适配器。

4、把领域服务包装成工具

Python 的工具可从 ToolRuntime 读取可信 context:

from dataclasses import dataclass
from langchain.agents import create_agent
from langchain.tools import ToolRuntime, tool

@dataclass
class RequestContext:
    user_id: str
    tenant_id: str

@tool
def get_order(order_id: str, runtime: ToolRuntime[RequestContext]) -> dict:
    """查询当前登录用户的一笔订单。只用于读取状态,不修改订单。"""
    actor = Actor(runtime.context.user_id, runtime.context.tenant_id)
    try:
        return order_service.get_for_actor(actor, order_id)
    except LookupError:
        return {"ok": False, "code": "ORDER_NOT_FOUND"}

agent = create_agent(
    model="openai:gpt-5.5",
    tools=[get_order],
    context_schema=RequestContext,
    system_prompt="回答订单问题前必须调用 get_order;不要猜测。",
)

result = agent.invoke(
    {"messages": [{"role": "user", "content": "A100 发货了吗?"}]},
    context=RequestContext(user_id="u-1", tenant_id="t-1"),
)

TypeScript 中保持同一结构:Zod 只暴露 orderId,用户身份由服务端闭包或 runtime 注入。

import { createAgent, tool } from "langchain";
import * as z from "zod";

function toolsFor(actor: Actor) {
  const getOrder = tool(
    async ({ orderId }) => {
      try { return await orderService.getForActor(actor, orderId); }
      catch { return { ok: false, code: "ORDER_NOT_FOUND" }; }
    },
    {
      name: "get_order",
      description: "查询当前登录用户的一笔订单,只读",
      schema: z.object({ orderId: z.string().min(1).max(64) }),
    },
  );
  return [getOrder];
}

const agent = createAgent({
  model: "openai:gpt-5.5",
  tools: toolsFor(authenticatedActor),
  systemPrompt: "回答订单问题前必须调用 get_order;不要猜测。",
});

闭包创建的工具不能被跨用户缓存,否则会把 A 用户身份带进 B 用户请求。更完整的应用优先使用框架 runtime context。

5、逐步读懂 Agent 循环

用户消息进入后,模型可能产生 get_order tool call;Harness 校验参数、执行函数,再把结果作为 Tool Message 追加到 state;模型第二次调用看到真实状态并给最终答复。

这意味着一次用户请求可能包含多次模型调用。必须设置工具调用次数、总 token、超时和递归上限。模型不是循环终止条件的唯一保障。

6、工具错误不要直接抛给用户

将错误分成三类:

类型示例返回策略
用户可修复订单号格式错误稳定错误码,提示重新输入
权限/不存在其他用户订单统一 ORDER_NOT_FOUND,避免枚举资源
系统故障数据库超时记录内部异常,给模型 TEMPORARILY_UNAVAILABLE

不要把 SQL、堆栈、数据库地址作为 Tool Message 交给模型。Tool Message 会进入上下文,也可能进入 trace。

7、写工具为什么更难

如果以后添加 submit_refund,必须有后端权限、业务状态校验、幂等键、审计和人工审批。模型产生合法参数不代表用户已经授权。正确顺序是先创建退款草案,再中断等待批准,批准后由领域服务提交;第 05 篇实现这条链路。

8、本篇测试

  1. 领域服务:用户只能查询自己的订单。
  2. 工具 schema:空订单号、超长订单号被拒绝。
  3. 工具错误:不存在与越权均只返回 ORDER_NOT_FOUND
  4. Agent 行为:订单问题会调用工具;闲聊不会调用;工具失败不编造状态。
  5. 预算:模型连续调用工具时达到上限并受控终止。

本课产物是安全的只读订单工具。下一课增加政策知识库,并让 Agent 同时组合数据库事实和文档证据。

官方阅读:Python ToolsTypeScript ToolsAgents

如果您觉得这篇文章有帮助,请点个赞吧~

分享文章

相关文章

更多文章 →
AI2026-09-01
Deep Agents 01:何为 Agent Harness,以及如何开始
1、本篇任务:完成一份多步骤、带证据的技术调研 普通客服 Agent 的问题短、工具少、输出即时。技术调研或编码任务会持续很久,产生计划、搜索结果、文件和中间结论。Deep Agents 在 LangChain/LangGraph 之上预装规划、虚拟文件系统、上下文压缩和子 Agent,适合这类开放任务。 本课让 Agent 比较两种向量数据库,并交付一份可验证报告。 2、什么时候需要 Deep Agent 满足以下两项以上再考虑:任务...
学习
AI2026-09-01
Deep Agents 02:子 Agent、虚拟文件系统与长期记忆
1、本篇任务:让主管只看结论,让子 Agent 处理细节 技术调研会产生几十次搜索和大量文件。如果全部进入主管上下文,真正的目标会被噪音淹没。本课用两个子 Agent: 收集证据, 检查结论;主管负责计划与最终合成。 2、什么时候委派,什么时候直接调用工具 适合委派:子任务有多步;需要专门提示或工具;会产生大量中间结果;只需返回有限结论。不适合:一步查询;主管需要全部中间上下文;协调成本超过任务本身。 3、配置专门子 Agent Pyt...
学习
AI2026-09-01
Deep Agents 03:生产化、Sandbox、权限与上线验收
1、本篇任务:让 Deep Agent 在隔离环境中分析代码 只读研究 Agent 风险有限;编码 Agent 需要读写文件、安装依赖和执行测试。本课不讲如何让模型写更漂亮的代码,只讲执行环境、权限、恢复和上线验收。 2、先做威胁模型 资产包括源代码、用户文件、云凭证、生产网络和发布权限;攻击入口包括用户消息、仓库内容、网页、依赖包、MCP 返回和命令输出。 Prompt injection 不是靠一句 system prompt 解决...
学习
AI2026-09-01
LangChain 01:全景、原理与学习路线
1、本篇学完要得到什么 这一篇只解决三个问题:LangChain 到底负责什么;它与 LangGraph、Deep Agents、LangSmith 是什么关系;后面应按什么顺序学习。 贯穿整套课程的项目是“退款政策与订单助手”。它最终能够:回答知识库中的退款规则;查询当前用户的订单;生成结构化答复;对真正的退款操作进行人工审批;断线后恢复;通过评测后发布。 先记住一句话: 模型负责理解与生成,应用负责数据、权限、状态和副作用。 如果把...
学习
AI2026-09-01
LangChain 02:模型、消息与结构化输出
1、本篇任务:让模型输出成为程序可以依赖的合同 上一课只证明 Agent 能运行。本课暂时不接业务工具,只完成一个“客服分诊器”:输入用户问题,输出意图、紧急程度、是否需要人工和给用户的答复。 本课的核心不是学更多模型参数,而是理解三层合同:消息决定模型看到了什么;schema 决定程序期待什么;业务校验决定结果是否真的可用。 2、消息不是一段字符串,而是一条执行记录 一次工具型对话通常包含四种消息: | 类型 | 由谁产生 | 作用...
学习
AI2026-09-01
LangChain 04:RAG 知识库实战(Python + TypeScript)
1、本篇任务:回答退款政策,并且能指出证据 上一课的订单工具能查询业务事实,却不知道政策文本。本课构建一条完整 RAG:离线索引政策文档;在线检索相关片段;只依据证据回答;证据不足时拒答。 RAG 不是“向量数据库 + 大模型”两个词。它有两条独立管线:索引管线决定知识怎样进入系统;查询管线决定问题怎样找到证据。任何一条出错,最终回答都会错。 2、先定义文档与 chunk 合同 每个 chunk 至少保存: 引用依赖 metadata,...
学习

评论

请登录后发表评论

去登录
加载评论中...

目录