AI - 使用LangChain请求LLM结构化生成内容
AI - 使用LangChain请求LLM结构化生成内容
基于深度学习的大型语言模型(LLM)不仅可以生成文本,还可以帮助我们完成许多复杂任务,如自动化客服、内容创作和数据分析。然而,如何从这些模型中结构化地获取输出,仍然是一个关键问题。在这篇文章中,我们将探索如何使用 JavaScript 和 LangChain 构建一个简单的 LLM结构化输出的应用程序。
场景
在构建 LLM 应用程序时,许多时候我们不仅仅需要模型生成文本,还需要它按照我们指定的格式输出结果。这样的需求在以下场景中非常常见:
- 数据处理和分析:当我们需要对生成的数据进一步处理和分析时,结构化数据会更加便于处理。
- 系统集成:在复杂系统中,各个组件的协作往往需要标准化的数据格式,以确保不同模块之间的兼容性和数据流的顺畅。
- 用户界面展示:结构化的数据更容易在用户界面中展示,让用户可以直观地理解内容。
好处
一致性
结构化输出可以确保返回的数据格式一致。这对于解析和处理数据非常重要,尤其是在需要进一步操作或存储数据的情况下。
易于调试
标准化的数据格式使得调试过程更加容易。通过固定的结构,我们可以迅速识别并修复可能存在的格式或内容问题。
自动化
结构化数据更便于自动化处理。无论是将数据存储到数据库中,还是进行进一步的分析和可视化,结构化数据都能大大简化这些过程。
实现结构化内容生成的方式
在利用大型语言模型(LLM)生成结构化内容时,我们可以通过直接设置提示(prompting)或使用withStructuredOutput
方法来达到目的。这两种方法都有其独特的优点和适用场合。以下是对这两种方法的比较:
通过提示(Prompting)
通过提示法实现结构化内容生成,主要依赖于构建一个明确的文本提示,指导模型生成所需格式的输出。
优点
- 简单易行:不需要额外的工具或库,只需精心设计提示即可。
- 灵活性高:可以自由地设计和修改提示内容,适应不同的需求。
- 模型无关:适用于不同类型的语言模型(如GPT-3、BERT等),无论其内部细节如何。
缺点
- 依赖人工设计质量:提示的设计质量直接影响输出的准确性和格式一致性。
- 不易维护和扩展:复杂的提示容易变得冗长和难以管理,修改提示可能导致意料之外的问题。
- 高变异性:模型可能因细微的提示变化生成不同的格式,缺乏一致性和稳定性。
使用withStructuredOutput
withStructuredOutput
方法是LangChain库提供的一种方法,通过定义结构化输出的模式来指导模型生成特定格式的内容。
优点
- 强一致性:通过预定义的数据模式确保输出的格式和内容一致。
- 易于维护和扩展:更改结构化输出模式比更改提示更为简单和直观,不需要修改大量提示文本。
- 自动化:减少了手动调试和格式化的麻烦,通过明确的模式定义确保输出的准确性。
缺点
- 依赖工具库:需要学习和使用LangChain或类似工具库提供的API。
- 灵活性较低:输出格式固定,适应特定需求相对简单,但面对复杂和变动频繁的需求时可能不灵活。
示例代码
示例代码来主体源于LangChain官网,有兴趣的小伙伴可以去官网查看。下面将通过多种方式提示 LLM 讲一个笑话,并要求返回包括笑话的开头(setup),笑点(punchline),笑话的搞笑程度(rating)以及为什么它很搞笑(reason)的结构化输出。
第一步:设置开发环境
首先,创建一个新目录并进入该目录:
mkdir langchain-structure-output-app
cd langchain-structure-output-app
初始化一个新的Node.js项目:
npm init -y
安装必要的依赖:
# 安装langchain
npm install langchain @langchain/core --save
# 安装groq的langchain开发包
npm install @langchain/groq --save
# 安装环境变量配置库
npm install dotenv --save
# 安装JSONSchema生成库
npm install zod --save
第二步:创建项目结构
创建项目所需的文件和目录结构:
langchain-structure-output-app
├── index.js
├── .env
└── package.json
第三步:配置环境变量
在项目目录中创建一个 .env
文件,并添加Groq API密钥:
GROQ_API_KEY=your_groq_api_key_here
第四步:编写主应用程序
在 index.js
中编写应用程序代码,配置LangChain并创建翻译功能。
// 引入LangChain开发包,ChatGroq是用于与Groq语言模型交互的类
import { ChatGroq } from "@langchain/groq";
// 导入 dotenv,它是一个零依赖模块,能够从.env文件中加载环境变量到process.env中
import dotenv from "dotenv";
// 导入zod用于TypeScript优先的模式验证,并带有静态类型推断功能
import { z } from "zod";
// 加载 .env 文件中的环境变量GROQ_API_KEY
dotenv.config();
// 配置Groq LLM(语言模型),设置模型名称和温度参数
const model = new ChatGroq({
model: "mixtral-8x7b-32768", // 使用的模型名称
temperature: 0, // 温度参数,决定输出的随机性
});
第五步:JsonSchema结构化输出
/**
* 通过JsonSchema实现结构化输出
*
* @param {string} model LLM实例
* @param {boolean} includeRaw 是否包含原始内容,默认不包含
*/
async function tellJoke(model, includeRaw = false) {
// 定义结构化的笑话对象模式
const joke = z.object({
setup: z.string().describe("The setup of the joke"), // 笑话的开场部分,为字符串类型
rating: z.number().describe("How funny the joke is, from 1 to 10"), // 笑话的搞笑程度评分,1到10的数字类型
punchline: z.string().describe("The punchline to the joke"), // 笑点部分,为字符串类型
reason: z.string().describe("The reason why it is funny"), // 可笑的原因,为字符串类型
});
// 使用withStructuredOutput方法,将输出格式化为定义好的笑话模式
// 设置输出格式名为“joke”
const structuredLlm = model.withStructuredOutput(joke, {
includeRaw: includeRaw,
name: "joke",
});
// 通过invoke方法向模型询问一个关于狗的笑话并获取结构化的输出
const answer = await structuredLlm.invoke("Tell me a joke about dogs");
// 打印输出的笑话结果
console.log(answer);
}
await tellJoke(model);
用以下命令或者npm start
运行应用程序:
node index.js
输出结果是一个标准的JSON格式,如下所示:
bash-3.2$ npm start
> langchain-structure-output-app@1.0.0 start
> node index
{
setup: 'Why did the scarecrow adopt a dog?',
rating: 5,
punchline: 'Because he needed a bark-ing buddy!',
reason: "It's a play on words between 'bark' and 'scarecrow's job'"
}
然后并非所有的LLM都支持结构化内容输出,对于不支持的情况,可以考虑将tellJoke(model, includeRaw = false)
的第二个参数includeRaw
置成true,这样可以返回原始内容,如下所示,然后开发者可以进行自定义解析。
{
raw: AIMessage {
"content": "",
"additional_kwargs": {
"tool_calls": [
{
"id": "call_sxtk",
"type": "function",
"function": "[Object]"
}
]
},
"response_metadata": {
"tokenUsage": {
"completionTokens": 158,
"promptTokens": 1280,
"totalTokens": 1438
},
"finish_reason": "tool_calls"
},
"tool_calls": [
{
"name": "joke",
"args": {
"setup": "Why did the scarecrow adopt a dog?",
"rating": 5,
"punchline": "Because he needed a bark-ing buddy!",
"reason": "It's a play on words between 'bark' and 'scarecrow's job'"
},
"type": "tool_call",
"id": "call_sxtk"
}
],
"invalid_tool_calls": [],
"usage_metadata": {
"input_tokens": 1280,
"output_tokens": 158,
"total_tokens": 1438
}
},
parsed: {
setup: 'Why did the scarecrow adopt a dog?',
rating: 5,
punchline: 'Because he needed a bark-ing buddy!',
reason: "It's a play on words between 'bark' and 'scarecrow's job'"
}
}
第六步:OpenAI风格结构化输出
// 通过OpenAI-style JSON schema 实现结构化输出
async function tellJoke2(model) {
// 定义结构化的笑话对象模式
const structuredLlm = model.withStructuredOutput({
name: "joke",
description: "Joke to tell user.",
parameters: {
title: "Joke",
type: "object",
properties: {
setup: { type: "string", description: "The setup for the joke" },
rating: { type: "number", description: "How funny the joke is, from 1 to 10" },
punchline: { type: "string", description: "The punchline to the joke" },
reason: { type: "string", description: "The reason why it is funny" }
},
required: ["setup", "punchline", "rating", "reason"],
},
});
// 通过invoke方法向模型询问一个关于老鼠的笑话并获取结构化的输出
// 设置输出格式名为“joke”
const answer = await structuredLlm.invoke("Tell me a joke about mouse", { name: "joke" });
// 打印输出的笑话结果
console.log(answer);
}
await tellJoke2(model);
用以下命令或者npm start
运行应用程序:
node index.js
输出结果是一个标准的JSON格式,如下所示:
bash-3.2$ npm start
> langchain-structure-output-app@1.0.0 start
> node index
{
setup: "Why don't mice use spell check?",
punchline: "Because they're afraid of making a misspell-mouse!",
rating: 5,
reason: "It's a play on words related to the question."
}
总结
在本文中,我们使用LangChain和JavaScript创建了一个简单的格式化输出应用程序,通过配置Groq API并使用LangChain框架,在利用大型语言模型(LLM)生成结构化内容时,我们可以通过直接设置提示(prompting)或使用withStructuredOutput
方法来达到目的。在这个基础上,您可以扩展该应用程序,以支持更多的功能和更复杂的应用场景。希望本教程对您有所帮助!