我正在寻求有关
langchainjs
结构化工具实施的建议。
我知道这对你来说是一种心理上的牵拉,请原谅我。
问题定义
假设您有以下工具:
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 });
}
}
此工具的架构和参数类型定义如下:
const createChildNotionPageToolSchema = z.object({
page: CreateChildPageSchema,
children: z.array(NotionBlockSchema).optional(),
});
type CreatePagePayload = z.infer<typeof createChildNotionPageToolSchema>;
createChildNotionPageToolSchema
描述了完整的可能对象集(页面、概念块、富文本定义等)。 JSON 模式最终成为一个高度复杂且巨大的对象,其中具有 $ref
值来交叉引用其中的对象。
架构由多个文件组合而成:
/schemas
--- pageProperties.schema.ts
--- baseBlock.schema.ts
--- notionPage.schema.ts
--- blocks
---- callout.schema.ts
---- paragraph.schema.ts
....
....
每当我尝试将此工具与
ChatOpenAI
模型一起使用时:
const llm = new ChatOpenAI({ model: "gpt-3.5-turbo" }).bindTools([
createChildNotionPageTool
]);
const messages: any[] = [
new HumanMessage(
`Create new page "Brief Specification" with folder icon in parent page with id: 2655cfc1a73048cdb7e4dd4545d1d52d.
The page content is split by three headings: Scope, Description, Outcomes
Each heading section should contain autogenerated text.
`
),
];
const aiMessage: any = await llm.invoke(messages);
呼叫失败并显示以下消息:
Invalid schema for function 'createNotionPageTool'. Please ensure it is a valid JSON Schema.
调试完成
生成的 JSON 模式最终包含多个
$ref
值。
我认为法学硕士可能无法很好地接收复杂的模式作为功能工具调用的一部分。
特别是,根据我的理解,OpenAI 聊天无法解析其中包含交叉引用 ($ref
) 值的 JSON 模式。
幸运的是,有一些库:
zod-to-json-schema
和json-to-zod-schema
可以帮助您调试它。我的步骤如下:
zod-to-json-schema
将我的 zod 模式转换为 json 模式
具有 $refStrategy: none
配置选项的工具。它将创建
超出 zod 定义的模式,不会创建交叉引用
在里面。json-to-zod-schema
包。它给我返回了一个扁平的 zod 结构
现在已转换为 JSON 模式,内部没有引用
Langchain的功能工具执行。这些步骤使我能够想出一个新的模式,我可以在结构化工具中设置该模式,该工具将请求正确转换为 llm 并且代码成功运行。
但这又带来了另一个问题。 zod schema 的双重转换必须手动完成,而且它太大,无法进一步手动维护。仅模式的代码就有 4k 行:
line 1: z.object({
page: z.object(/*multiple zod objects here*/),
children: z.array(/* and even more here*/)
line 4363: })
深入挖掘后,我发现 langchain 的
ChatOpenAI
实现在底层使用 zod-to-json-schema
将 zod 转换为可以发送到 llm 的输出。但是没有办法在结构工具内部传递 zod-to-json-schema
的配置对象来告诉它不要使用我原始 zod 模式中的 $ref
交叉引用构建 JSON 模式。
最后,问题:
是否有办法强制执行为结构化工具创建 JSON 模式的某种方式,特别是告诉
zod-to-json-schema
内部结构化工具实现使用配置选项,例如 $refStrategy: none
?或者,也许有不同的方法来创建仍然可重用并且可以直接接受函数参数模式的工具。
好吧,明白了。看来您可以使用功能工具的特定于模型的定义。对于 OpenAI,解决方法如下:
const llm = new ChatOpenAI({ model: "gpt-3.5-turbo" });
const llmWithTools = llm.bindTools([{
type: "function",
function: {
name: "createChildNotionPageTool",
description: `
Creates new notion page inside parent page from provided input.
Accepts children as content of the page.
`,
parameters: zodToJsonSchema(parametersSchema, { $refStrategy: "none" }),
},
}]
);
上述方法允许完全控制参数字段。