输出解析器
在v1版本之后由于langchain对包的调整引入方式有所调整
常用解析器
在实际开发当中,我们最常用的就是json,list,或者string类型,所以我这边只写了这三种
- string
- json
- list
字符串
ts
import dotenv from "dotenv";
import {StringOutputParser} from "@langchain/core/output_parsers";
import {PromptTemplate, ChatPromptTemplate} from "@langchain/core/prompts";
dotenv.config();
function getModel(modelName) {
return new ChatOpenAI({
apiKey: process.env.API_KEY,
model: modelName || "gpt-4o-mini",
configuration: {
baseURL: process.env.BASE_URL,
},
});
}
cosnt model = getModel();
// 创建解析器
const strParser = new StringOutputParser();
// 方式1.
const chain = RunnableSequence.from([
prompt,
model,
strParser,
]);
const chain2 =prompt.pipe(model).pipe(strParser);
async function translate(question) {
return await chain.invoke({job: "英语人员", question});
}
translate('hello langchain'); // 这样就返回字符串
返回数组
ts
import { CommaSeparatedListOutputParser } from '@langchain/core/output_parsers';
import { PromptTemplate } from "@langchain/core/prompts"
import { getModel } from "../model/index.js";
import { RunnableSequence } from '@langchain/core/runnables';
const model = getModel();
// 创建解析器
const parser = new CommaSeparatedListOutputParser();
const formatInstruction = parser.getFormatInstructions();
const prompt = new PromptTemplate({
template:'请生成5个{text},\n\n{formatInstructions}',
inputVariables: ['text'],
partialVariables:{
// 这里用上面的
formatInstructions :formatInstruction
}
})
const chain = prompt.pipe(model).pipe(parser);
const res = await chain.invoke('水果');
//当然了,也可以
const prompt2 = await new PromptTemplate({
template:'请生成5个{text},\n\n{formatInstructions}',
inputVariables: ['text'],
}).partial({
formatInstructions: formatInstruction
});
const chain2 = prompt.pipe(model).pipe(parser);
const res2 = await chain2.invoke('电影');
返回json1
ts
// 返回json用这个
import { StructuredOutputParser } from '@langchain/core/output_parsers';
import { RunnableSequence } from '@langchain/core/runnables'
import { PromptTemplate } from '@langchain/core/prompts';
import { getModel } from "../model/index.js"
import { z } from 'zod';
// 描述键值对
const personSchema = z.object({
question: z.string().describe("The customer's question"),
answer: z.string().describe("The AI's answer to the customer's question"),
});
// 这样你可以配合zod来控制输入的格式,比如必须是字符串等
const parser = StructuredOutputParser.fromZodSchema(personSchema);
const formatInstructions = parser.getFormatInstructions();
const prompt = new PromptTemplate({
template: `you're a helpful AI assistant. you will answer this {description} {format_instruction}`,
inputVariables: ['description'],
partialVariables: { format_instruction: formatInstructions },
});
const model = getModel();
// 方式1
const chain = prompt.pipe(model).pipe(parser);
// 方式2
// const chain = RunnableSequence.from([prompt, model, parser]);
async function generatePersonInfo(description) {
const result = await chain.invoke({ description });
console.log("Generated Person Info:", result);
}
generatePersonInfo('什么是ai?');
返回json2
ts
import { getModel } from "../model/index.js"
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { RunnableSequence } from '@langchain/core/runnables'
import { StructuredOutputParser } from "@langchain/core/output_parsers"
const model = getModel()
const chatPrompt = ChatPromptTemplate.fromMessages([
["system", "你是一个靠谱的{role}"],
["human", "{question}"],
]);
// 这种方式没法控制
const structuredParser = StructuredOutputParser.fromNamesAndDescriptions({
q: "问题内容",
a: "回答内容"
});
const chatChain = RunnableSequence.from([
chatPrompt,
model,
structuredParser,
])
async function query(params) {
const result = await chatChain.invoke({ role: params.role, question: params.question })
console.log(result, typeof result);
}
const formatInstructions = structuredParser.getFormatInstructions();
query({
role: "助手",
question: `人工智能用英语怎么说?\n\n${formatInstructions}`
})
流式输出
ts
async function streamWithJsonParser(description) {
const rawStream = await prompt.pipe(model).stream({ description });
let bufferedJson = '';
for await (const chunk of rawStream) {
const content = chunk.content;
bufferedJson += content;
}
// 如果是前后端交互,需要返回bufferedJson 而不是解析之后的,这么做的目的是为了我们好看结果
return await parser.invoke(bufferedJson);
// 这么做,会直接把结果一下子返回来
}
streamWithJsonParser('什么是ai?').then((res) => {
console.log(res);
});
js
async function streamMode(question) {
try {
const response = await fetch('/api/stream', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ question })
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let fullContent = '';
resultDiv.innerHTML = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n');
for (const line of lines) {
if (line.startsWith('data: ')) {
try {
const data = JSON.parse(line.slice(6));
if (data.done) {
resultDiv.classList.remove('loading');
} else if (data.content) {
fullContent += data.content;
} catch (e) {
console.error('解析行失败:', e);
}
}
}
}
}