NestJS如何结合LangChain,构建高效的Prompt模板?
- 内容介绍
- 文章标签
- 相关推荐
作为一名后端开发者,你可能已经迫不及待地想在自己的NestJS项目中接入像LangChain这样强大的框架了。说实话, 直接把字符串硬编码在代码里发给大模型,虽然刚开始觉得挺爽,但一旦项目复杂起来维护起来简直就是一场灾难。这时候,Prompt Template就成了你的救命稻草。今天咱们就抛开那些枯燥的官方文档, 用一种更接地气的方式,深入聊聊在NestJS环境下到底该怎么优雅地玩转LangChain的Prompt模板,一句话概括...。
NestJS中使用LangChain的Prompt模板:结构化的工作
在NestJS中使用LangChain的Prompt模板,其实就是在做“结构化”的工作。把混乱的自然语言指令,变成代码中可维护、可复用的对象,改进一下。。
PromptTemplate:基础形式
登场的是PromptTemplate。这是最基础的形式,它主要用于生成纯文本字符串。当你不需要区分消息角色,只是单纯想给LLM发送一段指令时它就是你的首选。
const quickTemplate = PromptTemplate.fromTemplate(
'请简要评价{product}在{aspect}方面的表现。'
);
const promptValue = quickTemplate.format;
你没事吧? 看完这段代码, 你可能会问,每次都要new一个实例,还要手动列inputVariables是不是有点太繁琐了?别急, LangChain也提供了一个更便捷的静态方法.fromTemplate它能自动帮你识别模板里的变量名,省去了不少敲键盘的功夫。
ChatPromptTemplate:角色扮演
现在的LLM大多是基于Chat模型的, 它们更习惯处理“对话”结构,而不是一大段纯文本。这时候,ChatPromptTemplate就该闪亮登场了。 我算是看透了。 它允许我们定义不同角色的消息,比如System、Human和AI。
import { ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate } from '@langchain/core/prompts';
async createChatPrompt {
const chatTemplate = ChatPromptTemplate.fromMessages();
const result = await chatTemplate.invoke({
role: '资深程序员',
question: 'React Hooks 的依赖项数组到底该怎么填?'
});
console.log;
}
这里有个细节需要特别注意:invoke是异步方法,必须使用await。如果你直接打印result可能会看到一个Promise对象而不是你想要的后来啊。再说一个result.messages就是我们到头来传给大模型的BaseMessage数组,里面包含了SystemMessage和HumanMessage实例,拭目以待。。
.invoke、.formatMessages和.format的区别
.invoke: 异步。返回ChatPromptValue对象。这是LangChain Runnable接口调用方式, 地道。 适合直接链式传递给LLM。
.formatMessages: 异步。直接返回BaseMessage数组。如果你只需要消息列表而不需要包装对象,用这个很方便,层次低了。。
.format: 同步。返回纯文本字符串。它会将所有消息拼接成一个字符串,通常用于调试或者不需要消息结构的场景。
const template = ChatPromptTemplate.fromMessages;
// 1. invoke
const val1 = await template.invoke;
// 2. formatMessages
const val2 = await template.formatMessages;
// 3. format
const val3 = template.format;
高级技巧:部分变量填充与动态消息列表
部分变量填充:partial功能的应用场景与实现方式对比分析
有时候, 我们会有这样的需求:一个模板里有五个变量,但其中三个是固定的,只有两个是每次请求都不一样的。如果每次都要把这三个固定的变量传一遍,那代码冗余度就太高了。
LangChain提供了partialVariables ,专门解决这个问题。我们可以预先填充一部分变量, 生成一个新的“半成品”模板.,蚌埠住了!
const partialTemplate = new PromptTemplate({
template: '请评价{product}的优缺点,重点关注{aspect1}和{aspect2}。',
inputVariables: , // 只需要声明剩余未填充的变量
partialVariables: {
aspect1: '电池续航' // 预先固定这个值
}
});
// 使用时只需传 product 和 aspect2
const promptA = partialTemplate.format({
product: '某品牌手机',
aspect2: '屏幕显示'
});
动态消息列表:MessagesPlaceholder让聊天记录无缝融入提示词
在,让它能记住上下文。但是历史记录的长度是不确定的,这时候普通的模板变量就不够用了。 这时候,MessagesPlaceholder 就派上用场了。它就像一个特殊的占位符,告诉模板:"嘿,这里到时候我会塞给你一整个消息列表,你别管有多少条,全部放进去就行。",说白了就是...
import { MessagesPlaceholder } from '@langchain/core/prompts';
async createHistoryPrompt {
const historyTemplate = ChatPromptTemplate.fromMessages();
const result = await historyTemplate.invoke({
name: '小智',
// 这里传入一个包含历史消息的数组
chat_history: ,
input: "我刚才说我叫什么?"
});
console.log;
}
这种结构非常灵活, 主要原因是它允许你在System指令和当前用户输入之间,插入任意长度的对话历史。这是实现具备记忆功能AI应用的关键一步。
"少样本提示"让模型学会举一反三
除了上述的结构化技巧,LangChain还支持“少样本提示”。简单来说就是通过给模型看几个例子,让它学会怎么回答。这在处理复杂任务时效果奇佳。
比如你想让模型学会做“情感分析”,你可以”这个逻辑,配合前面提到的 PromptTemplate ,你就能组合出非常强大的提示词策略。
虽然这部分逻辑稍微复杂一点,通常涉及到 ExampleSelector ,但其核心思想依然是模板化。你可以把“例子”看作是一种特殊的变量填充。每个例子通常是一个字典,键对应输入变量,值对应具体的输入和输出。
开发中的那些坑与避坑指南
异步与同步的混淆 在NestJS里 invoke 和 formatMessages 是异步的,千万别忘了 await ,否则你拿到的只是一个Promise对象,直接传给LLM会报错。
消息类型的选择
如果你是在做聊天机器人,优先使用 ChatPromptTemplat e ;如果只是简单的文本补全,用 PromptTemplat e
就够了。
别把简单的事情复杂化。
变量名匹配要精确无误
模板里的 {variabl e}
必须与
inputVariable s
数组或者调用时传入的对象键名完全一致,否则会报错或者出现意料之外的后来啊 。掌握了这些,你就能在NestJS中构建出既灵活又强大的AI应用了。
别光看,赶紧去你的项目里试试吧!作为一名后端开发者,你可能已经迫不及待地想在自己的NestJS项目中接入像LangChain这样强大的框架了。说实话, 直接把字符串硬编码在代码里发给大模型,虽然刚开始觉得挺爽,但一旦项目复杂起来维护起来简直就是一场灾难。这时候,Prompt Template就成了你的救命稻草。今天咱们就抛开那些枯燥的官方文档, 用一种更接地气的方式,深入聊聊在NestJS环境下到底该怎么优雅地玩转LangChain的Prompt模板,一句话概括...。
NestJS中使用LangChain的Prompt模板:结构化的工作
在NestJS中使用LangChain的Prompt模板,其实就是在做“结构化”的工作。把混乱的自然语言指令,变成代码中可维护、可复用的对象,改进一下。。
PromptTemplate:基础形式
登场的是PromptTemplate。这是最基础的形式,它主要用于生成纯文本字符串。当你不需要区分消息角色,只是单纯想给LLM发送一段指令时它就是你的首选。
const quickTemplate = PromptTemplate.fromTemplate(
'请简要评价{product}在{aspect}方面的表现。'
);
const promptValue = quickTemplate.format;
你没事吧? 看完这段代码, 你可能会问,每次都要new一个实例,还要手动列inputVariables是不是有点太繁琐了?别急, LangChain也提供了一个更便捷的静态方法.fromTemplate它能自动帮你识别模板里的变量名,省去了不少敲键盘的功夫。
ChatPromptTemplate:角色扮演
现在的LLM大多是基于Chat模型的, 它们更习惯处理“对话”结构,而不是一大段纯文本。这时候,ChatPromptTemplate就该闪亮登场了。 我算是看透了。 它允许我们定义不同角色的消息,比如System、Human和AI。
import { ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate } from '@langchain/core/prompts';
async createChatPrompt {
const chatTemplate = ChatPromptTemplate.fromMessages();
const result = await chatTemplate.invoke({
role: '资深程序员',
question: 'React Hooks 的依赖项数组到底该怎么填?'
});
console.log;
}
这里有个细节需要特别注意:invoke是异步方法,必须使用await。如果你直接打印result可能会看到一个Promise对象而不是你想要的后来啊。再说一个result.messages就是我们到头来传给大模型的BaseMessage数组,里面包含了SystemMessage和HumanMessage实例,拭目以待。。
.invoke、.formatMessages和.format的区别
.invoke: 异步。返回ChatPromptValue对象。这是LangChain Runnable接口调用方式, 地道。 适合直接链式传递给LLM。
.formatMessages: 异步。直接返回BaseMessage数组。如果你只需要消息列表而不需要包装对象,用这个很方便,层次低了。。
.format: 同步。返回纯文本字符串。它会将所有消息拼接成一个字符串,通常用于调试或者不需要消息结构的场景。
const template = ChatPromptTemplate.fromMessages;
// 1. invoke
const val1 = await template.invoke;
// 2. formatMessages
const val2 = await template.formatMessages;
// 3. format
const val3 = template.format;
高级技巧:部分变量填充与动态消息列表
部分变量填充:partial功能的应用场景与实现方式对比分析
有时候, 我们会有这样的需求:一个模板里有五个变量,但其中三个是固定的,只有两个是每次请求都不一样的。如果每次都要把这三个固定的变量传一遍,那代码冗余度就太高了。
LangChain提供了partialVariables ,专门解决这个问题。我们可以预先填充一部分变量, 生成一个新的“半成品”模板.,蚌埠住了!
const partialTemplate = new PromptTemplate({
template: '请评价{product}的优缺点,重点关注{aspect1}和{aspect2}。',
inputVariables: , // 只需要声明剩余未填充的变量
partialVariables: {
aspect1: '电池续航' // 预先固定这个值
}
});
// 使用时只需传 product 和 aspect2
const promptA = partialTemplate.format({
product: '某品牌手机',
aspect2: '屏幕显示'
});
动态消息列表:MessagesPlaceholder让聊天记录无缝融入提示词
在,让它能记住上下文。但是历史记录的长度是不确定的,这时候普通的模板变量就不够用了。 这时候,MessagesPlaceholder 就派上用场了。它就像一个特殊的占位符,告诉模板:"嘿,这里到时候我会塞给你一整个消息列表,你别管有多少条,全部放进去就行。",说白了就是...
import { MessagesPlaceholder } from '@langchain/core/prompts';
async createHistoryPrompt {
const historyTemplate = ChatPromptTemplate.fromMessages();
const result = await historyTemplate.invoke({
name: '小智',
// 这里传入一个包含历史消息的数组
chat_history: ,
input: "我刚才说我叫什么?"
});
console.log;
}
这种结构非常灵活, 主要原因是它允许你在System指令和当前用户输入之间,插入任意长度的对话历史。这是实现具备记忆功能AI应用的关键一步。
"少样本提示"让模型学会举一反三
除了上述的结构化技巧,LangChain还支持“少样本提示”。简单来说就是通过给模型看几个例子,让它学会怎么回答。这在处理复杂任务时效果奇佳。
比如你想让模型学会做“情感分析”,你可以”这个逻辑,配合前面提到的 PromptTemplate ,你就能组合出非常强大的提示词策略。
虽然这部分逻辑稍微复杂一点,通常涉及到 ExampleSelector ,但其核心思想依然是模板化。你可以把“例子”看作是一种特殊的变量填充。每个例子通常是一个字典,键对应输入变量,值对应具体的输入和输出。
开发中的那些坑与避坑指南
异步与同步的混淆 在NestJS里 invoke 和 formatMessages 是异步的,千万别忘了 await ,否则你拿到的只是一个Promise对象,直接传给LLM会报错。
消息类型的选择
如果你是在做聊天机器人,优先使用 ChatPromptTemplat e ;如果只是简单的文本补全,用 PromptTemplat e
就够了。
别把简单的事情复杂化。
变量名匹配要精确无误
模板里的 {variabl e}
必须与
inputVariable s
数组或者调用时传入的对象键名完全一致,否则会报错或者出现意料之外的后来啊 。掌握了这些,你就能在NestJS中构建出既灵活又强大的AI应用了。
别光看,赶紧去你的项目里试试吧!
