19-Agents-Tools-StructuredOutput官方深读
核对日期:2026-05-18
官方资料:Agents https://docs.langchain.com/oss/javascript/langchain/agents;Tools https://docs.langchain.com/oss/javascript/langchain/tools;Structured output https://docs.langchain.com/oss/javascript/langchain/structured-output。
官方概念
官方 Agents 文档将 Agent 描述为“模型 + 工具 + 循环执行”的系统。createAgent() 会构建基于 LangGraph 的 graph runtime,通常包含 model node、tools node 和 middleware。Agent 直到模型给出最终输出或达到迭代限制才停止。
Tools 文档强调:工具不仅有 name/description/schema/execute,还可以访问 runtime context、long-term store、stream writer、execution info 和 server info。工具返回值也不只是一段字符串,还可以是结构化对象,或用 Command 更新状态。
Structured output 文档强调:responseFormat 可以接受 Zod、Standard Schema 或 JSON Schema;LangChain 会根据模型能力选择 provider-native structured output 或 tool-calling strategy,也允许显式使用 providerStrategy / toolStrategy。
机制
Agent 官方能力拆解
| 能力 | 官方机制 | 工程用法 |
|---|---|---|
| Static model | 创建 agent 时固定模型 | 简单 Agent、低复杂度任务 |
| Dynamic model | middleware wrapModelCall 改模型 | 按复杂度、成本、用户等级路由 |
| Static tools | 创建 agent 时传入工具列表 | 小工具集、工具边界清晰 |
| Dynamic tools | middleware 过滤或运行时注册 | 按权限、feature flag、阶段暴露工具 |
| Tool error handling | middleware wrapToolCall | 统一错误消息、有限重试、审计 |
| Dynamic system prompt | middleware 根据 state/store/runtime 构造 prompt | 个性化、长对话、环境约束 |
| Invocation | agent.invoke({ messages }) | 标准请求入口 |
| Advanced | structured output、memory、streaming、middleware | 生产可靠性闭环 |
Tools 官方能力拆解
| 工具能力 | 官方含义 | 设计建议 |
|---|---|---|
| Basic definition | 函数 + name + description + schema | schema 字段必须写 describe,减少误调用 |
| Access context | 工具通过 runtime 读取上下文 | 用户、租户、权限来自 runtime,不进模型输入 |
| Long-term memory | 工具读写 store | 用户偏好、历史记录、可更新记忆 |
| Stream writer | 工具发出自定义进度 | 长任务向前端反馈 |
| Execution info | thread id、run id | 审计和 trace 关联 |
| Server info | LangGraph Server 元数据 | 部署环境中的 assistant/user 信息 |
| Return string | 人类可读结果 | 简单查询 |
| Return object | 结构化工具结果 | 后续模型解析、业务消费 |
| Return Command | 更新 graph state | 工具需要改变状态时 |
Structured Output 策略
| 策略 | 官方机制 | 适合 | 风险 |
|---|---|---|---|
| 直接传 schema | LangChain 自动选择 provider/tool strategy | 简单抽取、模型能力明确 | provider 支持不透明时要验证 |
providerStrategy | 使用 provider 原生结构化输出 | 支持原生 schema 的模型 | 与 tools 同时使用时要确认模型支持 |
toolStrategy | 用 tool calling 模拟结构化输出 | 大多数支持 tool calling 的模型 | 会产生额外 tool call,需要处理错误 |
| union schema | 多个结构选择之一 | 分类 + 抽取混合任务 | 多输出错误要测试 |
handleError | 自定义 schema 失败反馈 | 用户输入脏、模型容易越界 | 错误消息本身也要审查 |
TypeScript 官方写法
动态模型示意:
const dynamicModelSelection = createMiddleware({
name: "DynamicModelSelection",
wrapModelCall: (request, handler) => {
const messageCount = request.messages.length;
return handler({
...request,
model: messageCount > 10 ? advancedModel : basicModel,
});
},
});
结构化输出示意:
const ProductReview = z.object({
rating: z.number().min(1).max(5).optional(),
sentiment: z.enum(["positive", "negative"]),
keyPoints: z.array(z.string()),
});
const agent = createAgent({
model,
tools,
responseFormat: toolStrategy(ProductReview, {
handleError: "请给出 1-5 的评分,并补充评论。",
}),
});
注意:上面是官方 API 形态的迁移模板;本仓库离线 runtime 只模拟概念,不替代官方包。
Python 差异
Python 中对应 create_agent、函数 tool、Pydantic/TypedDict、middleware/hook 形态。TypeScript 中 zod schema 更自然,且和前端表单、API validation 可以共用。两边都要测试 dynamic tools、tool error、structured output schema failure。
工程边界
- Tool description 是给模型看的,不是安全策略。
- Dynamic tools 是降低误调用的关键,不是锦上添花。
- Structured output 只保证形状更稳定,不保证事实正确。
- ToolStrategy 的错误反馈会进入对话历史,要避免泄露内部细节。
- Command 更新 state 时要考虑并发 reducer 和状态回放。
常见反模式
| 反模式 | 后果 |
|---|---|
| 给 Agent 暴露几十个工具 | 上下文过载、误调用增加 |
| schema 字段无描述 | 模型不知道参数语义 |
| 工具返回内部原始响应 | 泄露实现细节,模型难解析 |
| structured output 没有错误策略 | schema 失败后用户只看到异常 |
| 动态模型只按消息数路由 | 忽略风险、成本、provider 能力和用户等级 |
练习任务
- 在
src/examples/03-agent-dynamic-tools.ts里模拟按权限过滤工具,并新增“未认证用户只看 public 工具”的测试。 - 在企业知识库项目中增加
responseFormat对应的 answer schema 说明,区分 provider strategy 和 tool strategy。 - 为多工具 Agent 增加一个返回
Command语义的离线工具,模拟写入任务状态。