)
一、PromptTemplate通用提示词模板LangChain提供了PromptTemplate类用来协助优化提示词PromptTemplate表示提示词模板可以构建一个自定义的基础提示词模板支持变量的注入最终生成所需的提示词zone-shot思想没有任何提示完全基于模型内部训练的数据完成答复完全信赖模型1. 标准写法Ⅰ 提示词文本占位测试PromptTemplate通过from_template来创建带有占位符的字符串提示词通过format对PromptTemplate对象的占位字符串提示词赋值导包from langchain_core.prompts import PromptTemplate# 导包fromlangchain_core.promptsimportPromptTemplate prompt_templatePromptTemplate.from_template(我最喜欢的乐队是{bandname}我最喜欢的歌手是{singer}可以帮我简单介绍一下嘛)# 调用.format方法注入信息prompt_textprompt_template.format(bandnamebeyond,singer黄家驹)print(prompt_text)# 我最喜欢的乐队是beyond我最喜欢的歌手是黄家驹可以帮我简单介绍一下嘛Ⅱ 完整示例有了上面的占位符的测试可以拿到完整的字符串提示词喂给大模型即可# 标准写法fromlangchain_core.promptsimportPromptTemplatefromlangchain_ollamaimportOllamaLLM # 和romptTemplate.from_template看起来比较类似但没办法加入Chain链 # PromptTemplate.from_templat得到是PromptTemplate类对象可以加入到链中但字符串不可以 bandnamebeyond, singer黄家驹 prompt_text f我最喜欢的乐队是{bandname}我最喜欢的歌手是{singer}可以帮我简单介绍一下嘛 prompt_templatePromptTemplate.from_template(我最喜欢的乐队是{bandname}我最喜欢的歌手是{singer}可以帮我简单介绍一下嘛)# 调用.format方法注入信息prompt_textprompt_template.format(bandnamebeyond,singer黄家驹)print(prompt_text)# 我最喜欢的乐队是beyond我最喜欢的歌手是黄家驹可以帮我简单介绍一下嘛modelOllamaLLM(modelgemma4:12b)resmodel.stream(inputprompt_text)forchunkinres:print(chunk,end,flushTrue)2. 基于Chain链写法chain prompt_template | model将prompt_template作为输出作为model的输入chain.stream(input{bandname: beyond,singer:黄家驹})喂给模型的时候加入对应prompt_template的占位值完整流程chain prompt_template | model①chain.stream(input{bandname: beyond,singer:黄家驹})拿到占位值②填充PromptTemplate.from_template里面的字符串对应的占位符的值得到完整的prompt③将完整的prompt喂给modelfromlangchain_core.promptsimportPromptTemplatefromlangchain_ollamaimportOllamaLLM prompt_templatePromptTemplate.from_template(我最喜欢的乐队是{bandname}我最喜欢的歌手是{singer}可以帮我简单介绍一下嘛)modelOllamaLLM(modelgemma4:12b)chainprompt_template|model reschain.stream(input{bandname:beyond,singer:黄家驹})forchunkinres:print(chunk,end,flushTrue)3. 小结基于PromptTemplate类可以得到提示词模板支持基于模板注入变量得到最终提示词。zero-shot思想不给任何提示全靠模型输出可以基于PromptTemplate直接完成few-shot思想给少量的demo供模型参考需要更换为FewShotPromptTemplate使用PromptTemplate类的优势使用Template模板构建提示词在大型工程中更容易做标准化模板Template模板类支持LangChain框架的链式调用Runnable接口等字符串没办法加入chainPromptTemplateFewShotPromptTemplateChatPromptTemplate二、FewShotPromptTemplateFewShot提示词模板导包from langchain_core.prompts import FewShotPromptTemplate1. 基本格式FewShotPromptTemplate(example_promptNone,# 示例数据的模板list内套字典examplesNone,# 示例的数据用来注入动态数据list内嵌套字典prefixNone,# 示例之前的提示词suffixNone,# 示例之后的提示词input_variablesNone# 声明在前缀或后缀中所需要注入的变量名)2. 提示词文本占位测试fromlangchain_core.promptsimportPromptTemplate,FewShotPromptTemplate# 示例模板example_templatePromptTemplate.from_template(心情: {feel}, 听歌:{song})# 示例动态数据注入必须是list内部嵌套字典后续不需要动模板直接在这里加数据即可examples_data[{feel:犹豫不决,song:不再犹豫},{feel:想妈妈了,song:真的爱你},{feel:失恋,song:喜欢你}]few_shot_templateFewShotPromptTemplate(example_promptexample_template,# 示例数据的模板examplesexamples_data,# 示例的数据用来注入动态数据list内嵌套字典prefix我是beyond的fan当处于某种心情时应该听beyond的哪些歌给你如下的示例,# 示例之前的提示词suffix基于上面的示例请告诉我当我的心情是{now_feel}时我应该听beyond的什么歌,# 示例之后的提示词input_variables[now_feel]# 声明在前缀或后缀中所需要注入的变量名)prompt_textfew_shot_template.invoke(input{now_feel:开心}).to_string()print(prompt_text)运行内容有了提示词直接喂给模型即可3. 完整示例fromlangchain_core.promptsimportPromptTemplate,FewShotPromptTemplatefromlangchain_ollamaimportOllamaLLM# 示例模板example_templatePromptTemplate.from_template(心情: {feel}, 听歌:{song})# 示例动态数据注入必须是list内部嵌套字典后续不需要动模板直接在这里加数据即可examples_data[{feel:犹豫不决,song:不再犹豫},{feel:想妈妈了,song:真的爱你},{feel:失恋,song:喜欢你}]few_shot_templateFewShotPromptTemplate(example_promptexample_template,# 示例数据的模板examplesexamples_data,# 示例的数据用来注入动态数据list内嵌套字典prefix我是beyond的fan当处于某种心情时应该听beyond的哪些歌给你如下的示例,# 示例之前的提示词suffix基于上面的示例请告诉我当我的心情是{now_feel}时我应该听beyond的什么歌,# 示例之后的提示词input_variables[now_feel]# 声明在前缀或后缀中所需要注入的变量名)prompt_textfew_shot_template.invoke(input{now_feel:开心}).to_string()modelOllamaLLM(modelgemma4:12b)resmodel.stream(inputprompt_text)forchunkinres:print(chunk,end,flushTrue)运行结果4. 小结FewShotPromptTemplate类对象构建需要五个核心参数example_prompt: 示例数据的提示词模板examples: 示例数据list内嵌字典prefix: 组装提示词示例数据前内容suffix: 组装提示词示例数据后内容input_variables: 列表注入的变量列表三、模板类的format和invoke方法1. 模板对象的format方法prompt_template.formatprompt_templatePromptTemplate.from_template(我最喜欢的乐队是{bandname}我最喜欢的歌手是{singer}可以帮我简单介绍一下嘛)# 调用.format方法注入信息prompt_textprompt_template.format(bandnamebeyond,singer黄家驹)2. 模板对象的invoke方法few_shot_template.invoke# 示例模板example_templatePromptTemplate.from_template(心情: {feel}, 听歌:{song})# 示例动态数据注入必须是list内部嵌套字典后续不需要动模板直接在这里加数据即可examples_data[{feel:犹豫不决,song:不再犹豫},{feel:想妈妈了,song:真的爱你},{feel:失恋,song:喜欢你}]few_shot_templateFewShotPromptTemplate(example_promptexample_template,# 示例数据的模板examplesexamples_data,# 示例的数据用来注入动态数据list内嵌套字典prefix我是beyond的fan当处于某种心情时应该听beyond的哪些歌给你如下的示例,# 示例之前的提示词suffix基于上面的示例请告诉我当我的心情是{now_feel}时我应该听beyond的什么歌,# 示例之后的提示词input_variables[now_feel]# 声明在前缀或后缀中所需要注入的变量名)prompt_textfew_shot_template.invoke(input{now_feel:开心}).to_string()3. format和invoke的区别关系PromptTemplate、FewShotPromptTemplate和ChatPromptTemplate这些类对象都有format和invoke这两个方法Ⅰ 继承关系Ⅱ 区别区别formatinvoke功能纯字符串替换解析占位符生成提示词Runnable接口标准方法解析占位符生成提示词返回值字符串PromptValue类对象通过.to_string()转换为字符串传参.format(k1v1, k2v2, ...).invoke({k1:v1, k2:v2, ...})解析支持解析{}占位符支持解析{}占位符和MessagesPlaceholder结构化占位符Ⅲ 代码验证①format方法三个类的继承关系最终都是继承BasePromptTemplatePromptTemplate-StringPromptTemplate-BasePromptTemplate FewShotPromptTemplate-StringPromptTemplate-BasePromptTemplate ChatPromptTemplate-BaseChatPromptTemplate-BasePromptTemplateBasePromptTemplate的format是个抽象方法故子类必须去实现②invoke方法...-BasePromptTemplate-RunnableSerializable-RunnableBasePromptTemplate类下有个RunnableSerializable这个RunnableSerializable继承了RunnableRunnab类下有一个抽象的invoke方法③format返回值——纯字符串template.format的返回值是纯字符串class strfromlangchain_core.promptsimportPromptTemplatefromlangchain_core.promptsimportFewShotPromptTemplatefromlangchain_core.promptsimportChatPromptTemplate templatePromptTemplate.from_template(Beyond的核心成员{name}代表作{sing})restemplate.format(name黄家驹,sing《海阔天空》)print(res,type(res))# Beyond的核心成员黄家驹代表作《海阔天空》 class str④invoke返回值——类对象template.invoke的返回值是PromptTemplate类对象class langchain_core.prompt_values.StringPromptValuefromlangchain_core.promptsimportPromptTemplatefromlangchain_core.promptsimportFewShotPromptTemplatefromlangchain_core.promptsimportChatPromptTemplate templatePromptTemplate.from_template(Beyond的核心成员{name}代表作{sing})res2template.invoke({name:黄家强,sing:《冷雨夜》})print(res2,type(res2))# textBeyond的核心成员黄家强代表作《冷雨夜》 class langchain_core.prompt_values.StringPromptValue四、ChatPromptTemplate聊天提示词模板1. 介绍PromptTemplate:通用提示词模板支持动态注入信息FewShotPromptTemplate:支持基于模板注入任意数量的示例信息ChatPromptTemplate:支持注入任意数量的历史会话信息通过from_messages方法从列表中获取多轮次会话作为聊天的基础模板PromptTemplate类用的from_template仅能接入一条消息ChatPromptTemplate类用的from_messages可以接入一个list的消息2. 静态注入版本导包from langchain_core.prompts import ChatPromptTemplatefromlangchain_core.promptsimportChatPromptTemplate ChatPromptTemplate.from_messages([(system,你是一个民谣歌手),(ai,ok我已经明白我的身份),(human,来一首民谣)]历史会话信息并不是静态的固定的而是随着对话的进行不停地积攒即动态的所以历史会话信息需要支持动态注入3. 动态注入版本导包from langchain_core.prompts import MessagesPlaceholder, ChatPromptTemplate注意多了MessagesPlaceholderMessagesPlaceholder提供history作为占位的key基于invoke动态注入历史会话记录必须是invokeformat返回值是纯字符串,故无法注入fromlangchain_core.promptsimportMessagesPlaceholder,ChatPromptTemplate chat_prompt_templateChatPromptTemplate.from_messages([(system,你是一个民谣歌手),MessagesPlaceholder(history),(human,再来一首民谣)])history_data[(human,来首伤感民谣),(ai,我知道那些夏天就像青春一样回不来我也不会再对谁满怀期待),(human,很好听再来一首),(ai,青春又醉倒在岌岌无名的坏靠嬉笑来度过这破碎的年代)]prompt_textchat_prompt_template.invoke({history:history_data}).to_string()4. 完整动态注入版本Ⅰ 提示词文本占位测试fromlangchain_core.promptsimportMessagesPlaceholder,ChatPromptTemplate chat_prompt_templateChatPromptTemplate.from_messages([(system,你是一个民谣歌手),MessagesPlaceholder(history),(human,再来一首民谣)])history_data[(human,来首伤感民谣),(ai,我知道那些夏天就像青春一样回不来我也不会再对谁满怀期待),(human,很好听再来一首),(ai,青春又醉倒在岌岌无名的坏靠嬉笑来度过这破碎的年代)]prompt_textchat_prompt_template.invoke({history:history_data}).to_string()print(prompt_text,type(prompt_text))运行内容提示词没问题后丢给模型就行Ⅱ 完整代码fromlangchain_core.promptsimportMessagesPlaceholder,ChatPromptTemplatefromlangchain_ollamaimportChatOllama chat_prompt_templateChatPromptTemplate.from_messages([(system,你是一个民谣歌手),MessagesPlaceholder(history),(human,再来一首民谣)])history_data[(human,来首伤感民谣),(ai,我知道那些夏天就像青春一样回不来我也不会再对谁满怀期待),(human,很好听再来一首),(ai,青春又醉倒在岌岌无名的坏靠嬉笑来度过这破碎的年代)]prompt_textchat_prompt_template.invoke({history:history_data}).to_string()modelChatOllama(modelgemma4:12b)resmodel.invoke(prompt_text)print(res.content,type(res))# 因为model.invoke返回的是一个对象里面内容很多其中content为模型的输出内容故这里只拿有用的信息输出 # 也可以用stream流式输出 res model.stream(prompt_text) print(res, type(res)) for chunk in res: print(chunk, end, flushTrue) 运行结果