ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

【LangChain框架入门级】7. 提示词模板与少样本提示

【LangChain框架入门级】7. 提示词模板与少样本提示 提示词模板与少样本提示PromptTemplate / ChatPromptTemplate / few-shot / 示例选择器只要需要动态、批量、有结构地向大模型发送请求几乎都会用到提示词模板而少样本提示通过给模型看几个「带答案的例题」能强制它按特定格式和逻辑回答。本篇讲解字符串模板、聊天消息模板、消息占位符、LangChain Hub、少样本提示的实现与两个案例以及四种示例选择器。目录提示词模板是什么解决什么问题字符串模板PromptTemplate聊天消息模板ChatPromptTemplate消息占位符MessagesPlaceholderLangChain Hub 拉取现成模板少样本提示few-shotting概念实现少样本提示案例一推理引导案例二少样本增强信息提取示例选择器Example selectors本篇小结1. 提示词模板是什么解决什么问题提示词模板是 LangChain 的核心抽象之一被广泛用于构建 LLM 应用的各个环节。一个例子想根据城市名问历史每次都写HumanMessage(请介绍上海的历史)、(请介绍西安的历史)内容重复。可以定义一个模板固定文本模板请介绍{city}的历史。输入变量[city]查询北京时把 city 赋成「北京」模板引擎就生成「请介绍北京的历史。」。本质提示词模板是一个可复用的提示词蓝图运行时用变量填充占位符生成最终提示词。类似编程里的字符串格式化。它解决四个核心问题可复用一个模板用于无数类似查询。关注点分离提示结构工程与具体内容、数据分开。一致性提示结构统一输出更稳定、可预测。可维护改风格只需改一个模板文件不用到处改代码。2. 字符串模板PromptTemplatePromptTemplate类实现了标准 Runnable 接口fromlangchain_core.promptsimportPromptTemplate# 方式一from_template 定义prompt_templatePromptTemplate.from_template(Translate the following into {language})# 实例化填充变量resultprompt_template.invoke({language:Chinese})print(result.text)# Translate the following into Chinese也可以直接初始化# 方式二直接构造prompt_templatePromptTemplate(input_variables[language],# 需要传入的变量名列表templateTranslate the following into {language},)关键参数template提示模板字符串。input_variables需要作为提示输入的变量名称列表。from_template()从模板字符串快速创建实例的类方法。3. 聊天消息模板ChatPromptTemplateChatPromptTemplate专为聊天模型设计可以方便地构建包含 SystemMessage、HumanMessage、AIMessage 的消息模板fromlangchain_core.promptsimportChatPromptTemplate# 0.2.24 版本后可直接用 ChatPromptTemplate() 初始化# 更早版本需要用 ChatPromptTemplate.from_messages()prompt_templateChatPromptTemplate([(system,Translate the following into {language}.),(user,{text}),])# 实例化填充变量messages_valueprompt_template.invoke({language:Chinese,text:what is your name?,})# 关键to_messages() 得到真正的消息列表messagesmessages_value.to_messages()print(messages)打印结果[SystemMessage(contentTranslate the following into Chinese.),HumanMessage(contentwhat is your name?),]把结果发给模型即可得到答案fromlangchain_openaiimportChatOpenAIfromlangchain_core.output_parsersimportStrOutputParser modelChatOpenAI(modelgpt-4o-mini)parserStrOutputParser()print(parser.invoke(model.invoke(messages)))# 你的名字是什么因为 ChatPromptTemplate 也是 Runnable可以直接串成链还能流式输出chainprompt_template|model|parserfortokeninchain.stream({language:English,text:你好我叫斯蒂芬很高兴认识你,}):print(token,end|)# |Hello|, my| name| is| Stephen|...4. 消息占位符MessagesPlaceholder如果想把一整段消息列表插到模板的特定位置比如把历史对话塞进去用MessagesPlaceholderfromlangchain_core.promptsimportChatPromptTemplate,MessagesPlaceholderfromlangchain_core.messagesimportHumanMessage,AIMessage prompt_templateChatPromptTemplate([(system,你是一个聊天助手),MessagesPlaceholder(msgs),# 消息占位符位置留给 msgs 变量])# 要插入的消息列表例如历史对话messages_to_pass[HumanMessage(content中国首都是哪里?),AIMessage(content中国首都是北京。),HumanMessage(content那法国呢?),]formatted_promptprompt_template.invoke({msgs:messages_to_pass})print(formatted_prompt)效果系统消息之后整段历史消息被原样插入。不显式使用 MessagesPlaceholder 也能实现用placeholder这个特殊元组prompt_templateChatPromptTemplate([(system,You are a helpful assistant),(placeholder,{msgs}),# 等价于 MessagesPlaceholder(msgs)])5. LangChain Hub 拉取现成模板LangChain Hub 是一个上传、浏览、拉取、管理提示词的平台类似「提示词界的 GitHub」用于共享和发现 Prompt。官网https://smith.langchain.com/hub/ 登录后可浏览所有现成提示。以收藏量很高的hardkothari/prompt-maker提示词生成器为例它能自动优化提示。先配置LANGSMITH_API_KEY环境变量再从 hub 拉取fromlangchain_openaiimportChatOpenAIfromlangsmithimportClient# 从 hub 拉取提示模板clientClient()promptclient.pull_prompt(hardkothari/prompt-maker,include_modelTrue)modelChatOpenAI(modelgpt-4o-mini)chainprompt|modelwhileTrue:taskinput(\n你的任务是什么输入 quit 退出\n)iftaskquit:breaklazy_promptinput(\n你当前的提示是什么\n)iflazy_promptquit:breakprint(\n Response:)# prompt-maker 会把粗糙的原始提示优化成结构完整的高质量提示chain.invoke({lazy_prompt:lazy_prompt,task:task}).pretty_print()价值输入一句粗糙的需求prompt-maker 会自动补全成包含 Instructions、Context、Example 的结构化提示大幅减少手动调提示的工作量。6. 少样本提示few-shotting概念少样本提示是通过向 LLM 提供少量具体示例或样本来教会它如何执行特定任务的技术。零样本提示直接给题、不给任何例子模型凭已有知识回答。比如问What is 2 9?模型可能表示看不懂这个符号。少样本提示给题之前先看几道「附有正确答案的例题」模型通过例题理解规则。例如先给几个例题让模型学会「」符号代表「加号」examples[{input:2 2,output:4},{input:2 3,output:5},]再问What is 2 9?模型就能按规则得出 11。它能解决的问题强制特定输出格式JSON、XML、特定列表样式样例即格式样板。难用文字描述的任务如「用莎士比亚风格写作」给例子比写长指令有效。多步推理任务示例可展示思考链引导模型遵循类似推理路径。核心提供正确示例可减少模型「胡说八道」把输出约束在范例范围内。7. 实现少样本提示第一步也是最重要的一步提出一个好的示例数据集——示例应运行时相关、清晰、信息丰富并提供模型还不知道的信息。然后把示例集实例化成模型能读懂的聊天消息用FewShotChatMessagePromptTemplatefromlangchain_core.promptsimportChatPromptTemplate,FewShotChatMessagePromptTemplate examples[{input:2 2,output:4},{input:2 3,output:5},]# 用来格式化「单个示例」的模板一问一答example_promptChatPromptTemplate([(human,{input}),(ai,{output}),])# 少样本模板把所有示例按上面的格式组装few_shot_promptFewShotChatMessagePromptTemplate(example_promptexample_prompt,# 格式化单个示例examplesexamples,# 样本示例列表)print(few_shot_prompt.invoke({}).to_messages())得到示例转化的消息列表[HumanMessage(content2 2),AIMessage(content4),HumanMessage(content2 3),AIMessage(content5),]最后把「系统消息 少样本提示 真正的问题」拼成完整模板fromlangchain_openaiimportChatOpenAI final_promptChatPromptTemplate([(system,你是一个神奇的数学奇才。),few_shot_prompt,# 插入示例(human,{input}),# 真正的问题])modelChatOpenAI(modelgpt-4o-mini)chainfinal_prompt|model chain.invoke({input:What is 2 9?})# 输出答案11FewShotChatMessagePromptTemplate关键参数examples样本示例、example_prompt格式化单个示例的模板同样实现了 Runnable 接口。8. 案例一推理引导希望模型回答比较类问题时先分析、再得出结论展示思考过程而不是直接甩答案。先定义字符串模板和示例集示例里展示「是否需要后续问题 → 逐步追问 → 中间答案 → 最终答案」的完整推理链fromlangchain_core.promptsimportPromptTemplate example_promptPromptTemplate.from_template(Question: {question}\n{answer})examples[{question:李白和杜甫谁更长寿,answer: 是否需要后续问题是的。 后续问题李白享年多少岁 中间答案李白享年61岁。 后续问题杜甫享年多少岁 中间答案杜甫享年58岁。 所以最终答案是李白 ,},# 还可加入「腾讯创始人」「孙中山外祖父」「红高粱 vs 霸王别姬导演」等示例]用FewShotPromptTemplate字符串版少样本模板组装fromlangchain_core.promptsimportFewShotPromptTemplate promptFewShotPromptTemplate(examplesexamples,example_promptexample_prompt,prefix,# 示例之前的模板字符串suffixQuestion: {input},# 示例之后、放真正问题input_variables[input],)print(prompt.invoke({input:《教父》和《星球大战》的导演来自同一个国家吗}).to_string())FewShotPromptTemplate参数examples、example_prompt、prefix示例前、suffix示例后、input_variables。调用模型后模型会模仿示例先追问两位导演分别是谁、来自哪里再得出「是」的结论而不是直接回答。9. 案例二少样本增强信息提取结合「结构化输出 少样本」实现一个从文本中提取人物信息的系统。期望输入「篮球场上身高两米的中锋王伟默契地将球传给一米七的后卫挚友李明……」输出结构化的人物列表。第一步定义结构化返回对象fromtypingimportList,OptionalfrompydanticimportBaseModel,FieldclassPerson(BaseModel):一个人的信息。name:Optional[str]Field(defaultNone,description这个人的名字)hair_color:Optional[str]Field(defaultNone,description头发的颜色)skin_color:Optional[str]Field(defaultNone,description肤色)height_in_meters:Optional[str]Field(defaultNone,description以米为单位的高度)classData(BaseModel):提取关于人的数据。people:List[Person]第二步定义两个关键示例覆盖边界情况无人场景文本中没有人名期望返回空列表。部分信息场景只有名字、其他字段缺失。examples[(海洋是广阔而蓝色的。它有两万多英尺深。,Data(people[]),# 没有人物信息),(小强从中国远行到美国。,Data(people[Person(name小强,height_in_metersNone,skin_colorNone,hair_colorNone),]),),]第三步定义提示词模板用 MessagesPlaceholder 留给示例fromlangchain_core.promptsimportChatPromptTemplate,MessagesPlaceholderfromlangchain_core.messagesimportSystemMessage prompt_templateChatPromptTemplate([SystemMessage(content你是一个提取信息的专家只从文本中提取相关信息。如果你不知道要提取的属性的值属性值返回null),MessagesPlaceholder(example_messages),(user,{new_message}),])第四步用 tool_example_to_messages 把示例构造成消息fromlangchain_core.utils.function_callingimporttool_example_to_messages example_messages[]fortxt,tool_callinexamples:# 根据是否提取到人物生成 AI 响应文本iftool_call.people:ai_response检测到人else:ai_response未检测到人# 把单个示例文本 期望的结构化输出转成消息列表example_messages.extend(tool_example_to_messages(txt,[tool_call],ai_responseai_response))tool_example_to_messages测试阶段、可能变化把单个示例转成模型可识别的消息列表参数为input文本、tool_callsBaseModel 工具调用列表、ai_response可选的最终 AI 消息内容返回消息列表。一个示例会被构造成 4 条消息HumanMessage → AIMessage(tool) → ToolMessage → AIMessage。第五步绑定结构化输出组链调用fromlangchain_openaiimportChatOpenAI modelChatOpenAI(modelgpt-4o-mini)structured_modelmodel.with_structured_output(schemaData)chainprompt_template|structured_model resultchain.invoke({example_messages:example_messages,new_message:篮球场上身高两米的中锋王伟默契地将球传给一米七的后卫挚友李明完成一记绝杀。,})print(result)结果people[Person(name王伟,hair_colorNone,skin_colorNone,height_in_meters2.0),Person(name李明,hair_colorNone,skin_colorNone,height_in_meters1.7),]总结该案例展示了 Pydantic 定义输出模式、少样本引导行为、模板动态组装上下文、链式调用简化流程最终从非结构化文本精准提取结构化数据。10. 示例选择器Example selectors示例不是越多越好更多示例通常提高性能但更大的提示会增加成本和延迟超过阈值太多示例反而混淆模型。最佳数量取决于模型、任务、示例质量需要实验。当有大量示例时没必要全部传给模型。示例选择器根据输入从示例集合中挑选正确的示例子集。四种选择策略本质都是 NLP 相似度衡量问题Length根据特定长度内容纳的数量选择示例。Similarity用输入和示例的语义相似性选择。MMR用最大边际相关性选择。Ngram用输入和示例的 ngram 重叠选择。10.1 按长度选择LengthBasedExampleSelector担心提示超过上下文窗口时使用输入长就少选示例输入短就多选示例。fromlangchain_core.example_selectorsimportLengthBasedExampleSelectorfromlangchain_core.promptsimportFewShotPromptTemplate,PromptTemplate examples[{input:happy,output:sad},{input:tall,output:short},{input:energetic,output:lethargic},{input:sunny,output:gloomy},{input:windy,output:calm},]example_promptPromptTemplate(input_variables[input,output],templateInput: {input}\nOutput: {output},)example_selectorLengthBasedExampleSelector(examplesexamples,example_promptexample_prompt,max_length25,# 提示最大长度超过就剪切示例)# 关键FewShotPromptTemplate 传 example_selector 而不是 examplesdynamic_promptFewShotPromptTemplate(example_selectorexample_selector,example_promptexample_prompt,prefix给出每个输入的反义词,suffixInput: {adjective}\nOutput:,input_variables[adjective],)print(dynamic_prompt.invoke({adjective:big}).to_messages()[0].content)参数example_prompt、examples、max_length、get_text_length测量长度的方法默认按换行/空格分隔的单词数。输入一个超长字符串时选择器会自动少放示例。10.2 按语义相似性选择SemanticSimilarityExampleSelector语义相似衡量文本在含义上的接近程度。例如「我喜欢猫」和「我讨厌狗」字面相似度低但语义上都表达对动物的态度而「苹果很甜」和「苹果市值创新高」里「苹果」含义不同语义上不相似。# 需先安装pip install -U langchain-chromafromlangchain_chromaimportChromafromlangchain_core.example_selectorsimportSemanticSimilarityExampleSelectorfromlangchain_openaiimportOpenAIEmbeddings example_selectorSemanticSimilarityExampleSelector.from_examples(examples,OpenAIEmbeddings(),# embeddings用于度量语义相似度的嵌入接口Chroma,# vectorstore_cls存储嵌入、做相似性搜索的向量库k1,# k最终选择的示例数量默认 4)similar_promptFewShotPromptTemplate(example_selectorexample_selector,example_promptexample_prompt,prefix给出每个输入的反义词,suffixInput: {adjective}\nOutput:,input_variables[adjective],)# 输入 worried会选到语义最接近的 happy → sadprint(similar_prompt.invoke({adjective:worried}).to_messages()[0].content)10.3 按最大边际相关性选择MMR语义相似性像面试官「按匹配度给每个应聘者打分」MMR 像团队经理「组建一个团队」每个成员都要满足基本职位要求相关性。但希望团队技能多样、减少冗余新颖性 / 多样性。策略先招一个最匹配的之后招的人既要技术达标、又要和已招的人技能互补。适用场景推荐系统推荐相关但不同类型的物品避免「信息茧房」。文档摘要选代表主旨又包含不同信息的句子避免重复。RAG检索完一堆相关文档后用 MMR 去重、多样化筛选再交给 LLM提升答案质量、减少幻觉。fromlangchain_core.example_selectorsimportMaxMarginalRelevanceExampleSelector example_selectorMaxMarginalRelevanceExampleSelector.from_examples(examples,OpenAIEmbeddings(),Chroma,k2,)# 用法与语义相似选择器相同只是结果兼顾相关性与多样性10.4 按 ngram 重叠选择NGramOverlapExampleSelectorngram文本序列中连续的 n 个词或字符。ngram 重叠通过计算两段文本共同拥有的 ngram 数量衡量相似度是一种表面形式匹配。例如「苹果手机很好用」和「这款手机很好用」单词重复度高、ngram 重叠高而「苹果手机很好用」和「iPhone 非常不错」含义相近但字面不同传统 ngram 重叠为 0——它对同义词无能为力。语义 ngram 重叠则比较词背后的语义向量不看「苹果」和「iPhone」字面是否相同而算它们向量是否相似常用于剽窃检测发现换词但保留核心思想的内容。# 需先安装pip install nltk、pip install -U langchain_communityfromlangchain_community.example_selectorsimportNGramOverlapExampleSelector examples[{input:See Spot run.,output:看见Spot跑。},{input:My dog barks.,output:我的狗叫。},{input:Spot can run.,output:Spot可以跑。},]example_selectorNGramOverlapExampleSelector(examplesexamples,example_promptexample_prompt,threshold-1.0,# 阈值负数只排序不排除0.0 排除无重叠示例1.0 排除全部)dynamic_promptFewShotPromptTemplate(example_selectorexample_selector,example_promptexample_prompt,prefix给出每个输入的中文翻译,suffixInput: {sentence}\nOutput:,input_variables[sentence],)# 输入 Spot can run fast.示例按重叠分数排序print(dynamic_prompt.invoke({sentence:Spot can run fast.}).to_messages()[0].content)阈值规则要记牢-1.0排序但不排除0.0排除不相关示例1.0返回空列表。11. 本篇小结提示词模板 可复用的提示词蓝图解决复用、分离、一致、可维护四个问题。PromptTemplate处理字符串ChatPromptTemplate处理消息用to_messages()取出MessagesPlaceholder插入整段消息列表。LangChain Hub 可拉取共享模板如 prompt-maker 自动优化提示。少样本提示 给模型看带答案的例题用于约束格式、描述难写的任务、引导推理链用FewShotChatMessagePromptTemplate/FewShotPromptTemplate实现。示例选择器在示例很多时挑子集Length 按长度、Similarity 按语义、MMR 兼顾相关与多样、Ngram 按字面重叠。记忆点MMR 防「信息茧房」、Ngram 阈值-1/0/1三档行为。下一篇我们讲输出解析器Output parsers看它如何把模型的非结构化文本转换成 JSON、Pydantic 对象等结构化格式。
返回列表