前言
书接上文 , 学习了聊天模式下的 promptTemplate , 现在我们学习多阶段处理文本信息场景下的pipeline promptTemplate
我的行文思路是
- 提出组合 prompt : PipelinePrompt 的组成
- 场景分析 : 造一个场景 , 进行业务分析和代码思路分析
- 应用场景 : 列举 pipeline promptTemplate 的应用场景 , 加深理解
组合 prompt
LangChain 包含一个名为 PipelinePromptTemplate
的类,在自然语言处理的很多任务里,往往需要分多个阶段来处理文本信息,而 PipelinePrompt 就能发挥很好的作用。
PipelinePrompt 由两个主要部分组成:
- Final prompt
最终提示词:返回的最终提示 - Pipeline prompts
流水线提示词:一个由字符串名称和提示模板组成的元组列表。每个提示模板将被格式化,然后作为具有相同名称的变量传递给未来的提示模板。
参考官方网址 :js.langchain.com/docs/how_to…
场景分析
在此之前 ,我们先场景化理解一下 : 什么是 Pipline Prompt 和什么 Final Prompt
假设我们要创建一个旅游攻略生成的流程,首先需要精准捕获用户需求,然后基于这些信息查找合适城市,在基于城市确定热门景点,接着了解景点周边的美食推荐,最后将这些信息整合起来生成一份完整的旅游攻略。
这个场景就很适合用 Final prompt
和 Pipeline prompts
来实现,因为它涉及多个步骤且后一步骤依赖前一步骤的结果。
ok ,置身这种场景下 , 我们首先不急着写代码 , 先把思路捋顺了 ~
业务逻辑分析
- 确定旅游城市:
首先要确定一个适合旅游的城市,我们先设定了一个特定的条件,即适合春季去旅游的城市。所以第一个阶段就是引导语言模型基于 “春季” 这个季节信息,推荐出一个合适的城市,为后续的旅游攻略构建打下基础。这个阶段相当于是在众多可能的旅游目的地中,先筛选出符合特定时间条件的那一个,就像我们计划旅行时先确定要去哪个地方一样。
- 查找热门景点:
在确定了具体的旅游城市后,接下来自然是要了解这个城市有哪些值得去的地方,也就是查找该城市的热门景点。所以第二个阶段的任务就是让语言模型依据上一阶段得到的城市名称,列举出这个城市的三个热门景点。此时就像我们已经到了目的地,开始规划具体要去游玩的景点了。
- 推荐景点美食:
游玩景点的同时,美食也是旅游体验中不可或缺的一部分。那么第三个阶段就是基于前面确定的城市以及找到的热门景点,让语言模型推荐出这些景点周边有哪些特色美食。这一步是在进一步丰富旅游攻略的内容,让游客不仅知道玩什么,还清楚吃什么。
- 整合生成攻略:
前面三个阶段分别得到了旅游城市、热门景点以及景点周边美食的信息,最后一个阶段就是把这些分散的信息整合起来,形成一份完整的旅游攻略。这个阶段的任务就是利用语言模型,将之前各个部分的内容有条理地组织起来,最终生成一份涵盖了旅游各方面关键信息的攻略,就像把之前规划好的游玩、美食等内容汇总到一个文档里呈现给游客。
经过上面的分析 ,我们可以得到pipelinePrompts
const pipelinePrompts = [
["destinationPrompt", ChatPromptTemplate.fromTemplate("请推荐一个适合{season}季节去旅游的城市")],
["attractionsPrompt", ChatPromptTemplate.fromTemplate("列举出{city}的三个热门景点")],
["foodPrompt", ChatPromptTemplate.fromTemplate("推荐{city}的{attractions}景点周边的特色美食")],
["finalPrompt", ChatPromptTemplate.fromTemplate("基于前面提到的旅游城市{city},它的热门景点{attractions}以及景点周边美食{food},生成一份完整的旅游攻略")],
];
我们分别对上面流水线提示词中四个包含字符串名称和提示模板的元组 创建对应每个提示模板的可运行链(Runnable)
// 1.确定旅游城市
const destinationChain = RunnableSequence.from([
RunnablePassthrough.assign({
season: () => "春季" // 将值包装成函数返回形式,避免类型问题
}),
function (input) { return input.season; },
function (season) { return ChatPromptTemplate.fromTemplate("请推荐一个适合{season}季节去旅游的城市").format({ season }); },
llm,
new StringOutputParser()
]);
// 2.根据前面的确定的旅游城市 , 确定旅游景点
const attractionsChain = RunnableSequence.from([
function (input) { return input.city; },
function (city) { return ChatPromptTemplate.fromTemplate("列举出{city}的三个热门景点").format({ city }); },
llm,
new StringOutputParser()
]);
// 3. 根据前面确定的旅游景点 , 确定美食
const foodChain = RunnableSequence.from([
function (input) {
return { city: input.city, attractions: input.attractions };
},
function (input) {
return ChatPromptTemplate.fromTemplate("推荐{city}的{attractions}景点周边的特色美食").format({ city: input.city, attractions: input.attractions });
},
llm,
new StringOutputParser()
]);
// 整合前面三点的信息 生成最终的prompt finalChain
const finalChain = RunnableSequence.from([
function (input) { return input; },
function (input) {
return ChatPromptTemplate.fromTemplate("基于前面提到的旅游城市{city},它的热门景点{attractions}以及景点周边美食{food},生成一份完整的旅游攻略").format({ city: input.city, attractions: input.attractions, food: input.food });
},
llm,
new StringOutputParser()
]);
最后 , 构建流水线执行逻辑,将各个链按顺序组合起来
// 构建流水线执行逻辑,将各个链按顺序组合起来
const pipeline = RunnableSequence.from([
destinationChain,
function (result) { return { city: result }; },
attractionsChain,
function (result) { return { city: result.city, attractions: result }; },
foodChain,
function (result) { return { city: result.city, attractions: result.attractions, food: result }; },
finalChain
]);
// 执行流水线,得到最终结果,这个最终结果就是Final prompt引导生成的内容
pipeline.invoke({}).then((finalResult) => {
console.log(finalResult);
});
运行结果如下 :
技术思路回顾
- 提示模板的运用:
为了引导语言模型完成每个阶段的任务,定义了一组流水线提示词(Pipeline prompts
),每个提示词都是一个带有变量的模板。
比如在确定旅游城市阶段,提示模板里有
{season}
变量,通过传入 “春季” 这个值,就能让语言模型根据这个特定季节去推荐城市;在后续查找景点、推荐美食以及整合攻略的阶段,也都通过相应的变量来传递前面阶段获取到的信息,使得语言模型能清楚知道要基于哪些内容来生成下一步的结果。这些提示模板就像是给语言模型下达的一道道指令,告诉它每个阶段具体要做什么事。
- 可运行链的构建:
针对每个阶段的提示模板,都创建了对应的可运行链(Runnable
)。每个可运行链代表了一个阶段从输入参数、格式化提示模板、调用语言模型到解析输出结果的完整过程。
例如,对于确定旅游城市的可运行链,先设置好初始的季节参数输入,然后对相应的提示模板进行格式化,接着把格式化后的提示文本发送给语言模型处理,最后解析返回的结果,这样就完成了这个阶段的任务执行。通过构建这样一个个可运行链,将每个阶段的任务操作都清晰地封装起来,方便后续按照顺序组合它们,同时也确保了每个阶段都能准确地执行对应的任务。
- 流水线执行逻辑组合:
各个可运行链构建好后,将它们按照任务的先后顺序组合起来,形成一个完整的流水线执行逻辑。在这个组合过程中,要注意每个链执行完后的结果如何准确地传递给下一个链,通过一些中间的处理函数,对结果进行提取、整理,确保下一个链能获取到正确的输入参数,使得整个流程像一条顺畅的流水线一样,一环扣一环地执行下去,逐步完成从确定城市到生成完整旅游攻略的所有任务。
应用场景
为了将来运用的时候 , 可以反射这个思路 , 这里查找了应用场景 , 使之具象化 ~
智能客服场景
在智能客服系统中,面对客户咨询的不同问题类型,常常需要经过多步骤的引导和解答。
比如客户咨询某个产品出现故障的情况,首先可以通过一个 Prompt 让模型判断问题所属的大致类别(是硬件故障、软件故障还是操作使用问题等),得到这个分类结果后,再借助另一个 Prompt 引导模型根据具体的类别去查找对应的解决方案知识库,并生成合适的回复内容给客户。PipelinePrompt 可以确保这些步骤连贯、有序地进行,使得智能客服能更高效地应对多样化的客户咨询,提供更精准、满意的答复。
内容创作辅助
对于内容创作者来说,PipelinePrompt 也大有用处。
假设要创作一篇情节丰富的故事,一开始可以用一个 Prompt 引导模型构思故事的背景设定、主要人物等基础元素,把这些构思好的内容作为后续创作的基础。接着通过另一个 Prompt,让模型基于前面的基础元素去进一步拓展情节,丰富故事的发展脉络,如此这般经过多个 Prompt 按顺序引导,逐步完善故事内容,帮助创作者更有条理地生成高质量的创作素材,提高创作效率。
再比如写一篇专业性较强的行业报告时,先通过 Prompt 引导模型收集相关的数据资料,确定报告的核心观点等,之后再用其他 Prompt 依次引导模型对各部分内容进行细化阐述、结构编排等工作,借助 PipelinePrompt 实现多阶段、有逻辑的创作引导,助力写出逻辑清晰、内容详实的行业报告。
教育领域的个性化学习引导
在教育领域,针对不同学习能力和学习进度的学生,PipelinePrompt 可以用于制定个性化的学习引导方案。
比如对于学习数学的学生,刚开始可以用一个 Prompt 引导模型分析学生在某个知识点上的掌握情况(是概念理解不清、解题方法不会还是计算容易出错等),根据分析结果,再通过另一个 Prompt 引导模型为该学生定制相应的学习建议、推荐合适的练习题等,后续还能继续通过其他 Prompt 引导模型对学生完成练习后的情况进行反馈评估,进而调整后续的学习引导内容。
通过 PipelinePrompt 构建起这样一个多阶段的学习引导流程,能够更好地满足不同学生的学习需求,促进个性化学习的开展。
总结
打完,收工 ; 困了 , 睡觉 ~