You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LangChainJS结构化工具复杂Zod类型生成不兼容JSON Schema求助

LangChainJS结构化工具Schema问题解决方案

问题定义

实现了一个基于StructuredTool的Notion子页面创建工具,代码如下:

export class CreateChildNotionPageTool extends StructuredTool {
  name = "createChildNotionPageTool";
  description = `
    Creates new notion page inside parent page from provided input.
    Accepts children as content of the page.
  `;
  schema = createChildNotionPageToolSchema;

  private api = new NotionAPIWrapper();

  protected async _call({
    page,
    children,
  }: CreatePagePayload): Promise<unknown> {
    return this.api.createPage({ ...page, children });
  }
}

工具的Schema由多个跨文件的Zod结构组合而成:

const createChildNotionPageToolSchema = z.object({
  page: CreateChildPageSchema,
  children: z.array(NotionBlockSchema).optional(),
});

type CreatePagePayload = z.infer<typeof createChildNotionPageToolSchema>;

将工具绑定到ChatOpenAI调用时,触发错误:Invalid schema for function 'createNotionPageTool'. Please ensure it is a valid JSON Schema.

问题根源

LangChainJS底层使用zod-to-json-schema生成工具的JSON Schema,但默认会保留$ref引用,而OpenAI无法解析包含跨文件$ref的Schema。手动转换为无引用的扁平Schema可正常运行,但生成的代码长达4000行,维护成本极高。

解决方案

1. 重写单个工具的Schema生成逻辑

直接在工具类中重写getJSONSchema方法,手动调用zod-to-json-schema并指定$refStrategy: none:

import { StructuredTool } from "langchain/tools";
import { zodToJsonSchema } from "zod-to-json-schema";

export class CreateChildNotionPageTool extends StructuredTool {
  // 原有属性和方法不变

  getJSONSchema() {
    return zodToJsonSchema(this.schema, {
      $refStrategy: "none",
    });
  }
}

优点:针对性修改,代码侵入性低;缺点:每个工具都需要单独重写,适合少量工具场景。

2. 手动构建工具并传入预扁平化Schema

提前生成扁平化的JSON Schema,直接传入Tool类替代StructuredTool:

import { ChatOpenAI } from "@langchain/openai";
import { Tool } from "langchain/tools";
import { zodToJsonSchema } from "zod-to-json-schema";

// 预生成无引用的JSON Schema
const flatSchema = zodToJsonSchema(createChildNotionPageToolSchema, {
  $refStrategy: "none",
});

// 手动创建工具
const createChildNotionPageTool = new Tool({
  name: "createChildNotionPageTool",
  description: "Creates new notion page inside parent page from provided input. Accepts children as content of the page.",
  schema: flatSchema,
  async func(input) {
    const api = new NotionAPIWrapper();
    return api.createPage({ ...input.page, children: input.children });
  },
});

// 绑定工具到LLM
const llm = new ChatOpenAI({ model: "gpt-3.5-turbo" }).bindTools([createChildNotionPageTool]);

优点:跳过StructuredTool的默认处理逻辑,灵活度高;缺点:需要手动维护工具的输入类型,适合临时或简单工具场景。

3. 封装通用扁平化Schema工具类

创建一个继承自StructuredTool的通用类,统一处理Schema扁平化逻辑,所有工具都可复用:

import { StructuredTool, StructuredToolOptions } from "langchain/tools";
import { ZodSchema } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";

// 通用扁平化工具类
export class FlatStructuredTool<RunInput extends ZodSchema> extends StructuredTool<RunInput> {
  constructor(options: Omit<StructuredToolOptions<RunInput>, "getJSONSchema">) {
    super(options);
  }

  getJSONSchema() {
    return zodToJsonSchema(this.schema, {
      $refStrategy: "none",
    });
  }
}

// 业务工具继承通用类
export class CreateChildNotionPageTool extends FlatStructuredTool<typeof createChildNotionPageToolSchema> {
  name = "createChildNotionPageTool";
  description = `
    Creates new notion page inside parent page from provided input.
    Accepts children as content of the page.
  `;
  schema = createChildNotionPageToolSchema;

  private api = new NotionAPIWrapper();

  protected async _call({ page, children }: CreatePagePayload): Promise<unknown> {
    return this.api.createPage({ ...page, children });
  }
}

优点:一次封装,所有工具复用,维护成本低;缺点:需要额外封装通用类,适合多工具场景。

前置依赖

确保安装zod-to-json-schema依赖:

npm install zod-to-json-schema

内容的提问来源于stack exchange,提问作者Pavlo Sobchuk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 23:30:54