LangChain.js 如何用 bindTools 与 JsonOutputToolsParser 从文本中抽取结构化实体
【免费下载链接】langchainjsThe agent engineering platform项目地址: https://gitcode.com/GitHub_Trending/la/langchainjs
假设你有一段自由文本,需要把其中的实体(人名、年龄、身高、发色等)抽成结构化的 JSON 对象。LangChain.js 仓库中给出了可直接运行的做法:用ChatOpenAI(或ChatAnthropic)的bindTools把 Zod schema 绑定为"函数",让模型按 schema 返回工具调用,再用JsonOutputToolsParser把这些工具调用解析成普通 JSON 数组。整条链路不需要执行任何工具,工具调用在这里纯粹充当结构化输出的载体。
主要示例代码在 examples/src/extraction/openai_tool_calling_extraction.ts,解析器实现在 json_output_tools_parsers.ts。
准备条件
- 一个 Node.js 项目,安装核心包与 OpenAI 集成包(安装方式来自 langchain-openai 包 README):
npm install @langchain/openai @langchain/core- 设置 OpenAI API Key 环境变量:
export OPENAI_API_KEY=your-api-key- 示例代码使用 Zod 3 的子路径导入
zod/v3,而 examples 包 的devDependencies中是"zod": "^4.3.6"(peerDependencies 允许^3.25.76 || ^4),所以还需要安装:
npm install zod另外,仓库约定所有 LangChain 包依赖同一个@langchain/core实例,README 建议在package.json中为pnpm/npm/yarn添加对应的 overrides 字段固定版本。
主路径:用 OpenAI 模型抽取实体
下面是仓库示例文件的完整代码,可直接保存为.ts文件后用tsx或ts-node运行:
import { z } from "zod/v3"; import { ChatOpenAI } from "@langchain/openai"; import { ChatPromptTemplate } from "@langchain/core/prompts"; import { JsonOutputToolsParser } from "@langchain/core/output_parsers/openai_tools"; const EXTRACTION_TEMPLATE = `Extract and save the relevant entities mentioned \ in the following passage together with their properties. If a property is not present and is not required in the function parameters, do not include it in the output.`; const prompt = ChatPromptTemplate.fromMessages([ ["system", EXTRACTION_TEMPLATE], ["human", "{input}"], ]); const person = z.object({ name: z.string().describe("The person's name"), age: z.string().describe("The person's age"), }); const model = new ChatOpenAI({ model: "gpt-3.5-turbo-1106", temperature: 0, }).bindTools([ { name: "person", description: "A person", schema: person, }, ]); const parser = new JsonOutputToolsParser(); const chain = prompt.pipe(model).pipe(parser); const res = await chain.invoke({ input: "jane is 2 and bob is 3", }); console.log(res);各环节的作用:
- Zod schema(
person):定义要抽取的实体结构和字段说明。bindTools接收{ name, description, schema }形式的工具定义,name会成为解析结果中的实体类型标识。 ChatPromptTemplate:系统消息固定抽取规则(缺失且非必填的属性不要输出),人类消息用{input}占位,运行时传入待抽取的文本。prompt.pipe(model).pipe(parser):标准的 Runnable 管道——提示词渲染后发给绑定工具的模型,模型输出交给解析器。new ChatOpenAI({ model: "gpt-3.5-turbo-1106", temperature: 0 }):示例用低温度保证抽取稳定。模型名可按你的账户可用模型替换。
结果验证
示例文件注释中给出的运行输出(文档示例,实际内容会随模型输出略有差异):
[ { name: 'person', arguments: { name: 'jane', age: '2' } }, { name: 'person', arguments: { name: 'bob', age: '3' } } ]判断抽取是否完成的依据有两条,都来自仓库文档:
- 结果数量:openai_tools.int.test.ts 中有一个 "Extraction" 集成测试,用同样的
bindTools+JsonOutputToolsParser链路让模型输出两个笑话,断言expect(res.length).toBe(2)。也就是说,解析结果是数组,其长度对应模型返回的工具调用条数——你可以按待抽取实体的预期数量断言。 - 字段结构:按 解析器源码,每个解析结果的字段为
{ type, args, id? },其中type是工具名(示例中为"person"),args是按 schema 解析出的对象;仅当构造解析器时传returnId: true时才带上id。Anthropic 变体示例注释中的输出正是这种结构:
[ { "type": "person", "args": { "name": "Alex", "height": 5, "hairColor": "blonde" } }, { "type": "person", "args": { "name": "Claudia", "height": 6, "hairColor": "brunette" } } ]如果消息里没有tool_calls,parsePartialResult返回空数组[];工具参数不是合法 JSON 时,parseToolCall会抛出OutputParserException。
可选分支一:用 Anthropic 模型并强制选择工具
同样的模式适用于ChatAnthropic,仓库示例见 anthropic_tools/extraction.ts,需要额外安装@langchain/anthropic。与 OpenAI 主路径相比有两个差异:
import { z } from "zod/v3"; import { ChatAnthropic } from "@langchain/anthropic"; import { PromptTemplate } from "@langchain/core/prompts"; import { JsonOutputToolsParser } from "@langchain/core/output_parsers/openai_tools"; const prompt = PromptTemplate.fromTemplate(EXTRACTION_TEMPLATE); const schema = z.object({ name: z.string().describe("The name of a person"), height: z.number().describe("The person's height"), hairColor: z.optional(z.string()).describe("The person's hair color"), }); const model = new ChatAnthropic({ temperature: 0.1, model: "claude-3-sonnet-20240229", }) .bindTools([ { name: "person", description: "Extracts the relevant people from the passage.", schema, }, ]) .withConfig({ // Can also set to "auto" to let the model choose a tool tool_choice: { type: "tool", name: "person", }, }); const chain = await prompt.pipe(model).pipe(new JsonOutputToolsParser()); const response = await chain.invoke({ input: "Alex is 5 feet tall. Claudia is 1 foot taller than Alex and jumps higher than him. Claudia is a brunette and Alex is blonde.", });- 用
z.optional(...)声明可缺失字段,主路径示例里则靠提示词约束"缺失属性不输出"。 - 通过
.withConfig({ tool_choice: { type: "tool", name: "person" } })强制模型调用指定工具;示例注释说明也可以设为"auto"让模型自行选择。chain是await出来的,因为withConfig返回 Promise。
可选分支二:只关心单一工具时用 JsonOutputKeyToolsParser
如果你的场景只绑定了一个抽取工具,解析器源码中还有JsonOutputKeyToolsParser:构造参数为{ keyName, returnSingle?, zodSchema?, serializableSchema?, returnId? }。它会过滤出type === keyName的调用,默认只返回args;returnSingle: true时返回第一个结果而不是数组;提供zodSchema或serializableSchema时会对结果做 schema 校验,校验失败同样抛出OutputParserException。
限制
- 该链路依赖模型返回工具调用消息:模型没有产生
tool_calls时解析结果为空数组,需要按你自己的任务逻辑判断是"文本中确实没有实体"还是"模型未按约定输出"。 JsonOutputToolsParser不校验字段内容(如args是否符合 schema),要做 schema 校验应使用带zodSchema的JsonOutputKeyToolsParser,或在拿到args后自行用 Zod 解析。- 示例中的模型名(
gpt-3.5-turbo-1106、claude-3-sonnet-20240229)来自仓库示例文件,实际运行时替换为你账户可访问的模型。
【免费下载链接】langchainjsThe agent engineering platform项目地址: https://gitcode.com/GitHub_Trending/la/langchainjs
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考