提示词工程初步(一) 部署好大模型之后,我们可以用其做一些简单的问答,但如何让回答更接近我们想要的方式,这就需要用到提示词(Prompt)与提示词工程(Prompt Engineering)。通过合理设计、组织提示词,可以显著提升大模型输出的准确性、结构化程度与业务贴合度。本文基于 LangChain 框架,从基础模板到少样本学习,逐步介绍提示词工程的入门实践。
一、最简单的提示词模板:PromptTemplate 1. 核心意义
实现固定句式与动态变量分离 ,避免重复手写相似提示词,提升代码复用性与可维护性。
统一输入格式,降低因提示词写法随意导致的模型输出不稳定问题。
配合 LangChain 的链(Chain)机制,将「模板填充 + 模型调用」封装为一步调用,简化业务代码。
2. 代码实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from langchain_core.prompts import PromptTemplatefrom langchain_demo.my_llm import llmprompt_template = PromptTemplate.from_template("帮我生成一个简短的,关于{topic}的报幕词。" ) chain = prompt_template | llm resp = chain.invoke({'topic' : "相声" }) print (resp)
3. 代码说明
PromptTemplate.from_template:通过字符串快速创建模板,{变量名} 为动态填充位置。
invoke 方法用于传入参数并渲染完整提示文本。
使用管道符 | 串联模板与模型,是 LangChain 推荐的简洁链式写法。
适用于零样本、结构简单、仅需少量变量替换的常规生成场景。
二、ICL 技术:上下文少样本学习(In-Context Learning) 1. 概念与作用 ICL 即上下文内学习 ,也常被称作少样本学习(Few-Shot Learning)。核心思路是:
在提示词中加入若干高质量的「问题 - 答案」示例。
让模型从示例中学习推理逻辑、输出格式、回答风格 。
无需微调模型,即可显著提升复杂推理、结构化输出的效果。
适合多跳推理、格式严格约束、领域特定话术规范等零样本难以满足的场景。
在 LangChain 中,通过 FewShotPromptTemplate 实现标准化少样本提示管理。
2. 代码实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 from langchain_core.prompts import PromptTemplate, FewShotPromptTemplatefrom langchain_demo.my_llm import llmexamples = [ { "question" : "穆罕默德·阿里和艾伦·图灵谁活得更久?" , "answer" : """ 是否需要后续问题:是。 后续问题:穆罕默德·阿里去世时多大? 中间答案:穆罕默德·阿里去世时74岁。 后续问题:艾伦·图灵去世时多大? 中间答案:艾伦·图灵去世时41岁。 所以最终答案是:穆罕默德·阿里 """ }, { "question" : "乔治·华盛顿的外祖父是谁?" , "answer" : """ 是否需要后续问题:是。 后续问题:乔治·华盛顿的母亲是谁? 中间答案:乔治·华盛顿的母亲是玛丽·鲍尔·华盛顿。 后续问题:玛丽·鲍尔·华盛顿的父亲是谁? 中间答案:玛丽·鲍尔·华盛顿的父亲是约瑟夫·鲍尔。 所以最终答案是:约瑟夫·鲍尔 """ }, { "question" : "《大白鲨》和《007:大战皇家赌场》的导演是否来自同一个国家?" , "answer" : """ 是否需要后续问题:是。 后续问题:《大白鲨》的导演是谁? 中间答案:《大白鲨》的导演是史蒂文·斯皮尔伯格。 后续问题:史蒂文·斯皮尔伯格来自哪里? 中间答案:美国。 后续问题:《007:大战皇家赌场》的导演是谁? 中间答案:《007:大战皇家赌场》的导演是马丁·坎贝尔。 后续问题:马丁·坎贝尔来自哪里? 中间答案:新西兰。 所以最终答案是:否 """ } ] base_prompt_template = PromptTemplate.from_template('问题:{question}\n{answer}' ) final_template = FewShotPromptTemplate( examples=examples, example_prompt=base_prompt_template, suffix="问题:{input}" , input_variables=['input' ] ) chain = final_template | llm resp = chain.invoke({'input' : "中国古代历史上唐朝和宋朝哪个朝代延续时间更长" }) print (resp)
)
3. 关键参数与使用要点
examples:示例数组,每条为 question/answer 结构,内容、格式、逻辑必须统一。
example_prompt:控制每一条示例如何渲染成文本,保证所有示例格式一致。
suffix:所有示例之后追加的真实用户问题,模型会参照前面示例的范式回答。
input_variables:声明 suffix 中用到的变量,与模板占位符对应。
示例数量建议 3~5 条为宜,过少学习效果差,过多易超出上下文窗口或引入噪声。
好的,这是为您续写的「三、进阶:聊天场景中使用 ICL(FewShotChatMessagePromptTemplate)」 部分的完整内容,已根据您提供的实际运行结果进行了补充和润色:
三、进阶:聊天场景中使用 ICL(FewShotChatMessagePromptTemplate) 前面介绍的是「文本格式」的提示词 ICL,而在实际的大模型应用中,更多是聊天场景 (多轮对话、区分用户/AI 角色),此时需要使用 LangChain 专为聊天场景设计的 FewShotChatMessagePromptTemplate,它能更好地贴合聊天模型的消息格式(区分 Human/Ai/System 角色),提升对话场景下的 ICL 效果。
1. 核心概念说明
聊天场景的提示词核心是「消息列表」 ,每条消息都有明确的「角色」(human/ai/system)。
FewShotChatMessagePromptTemplate:专门用于在聊天消息列表中嵌入 ICL 示例,保持示例的角色格式与真实对话一致。
MessagesPlaceholder:消息占位符,用于动态填充后续的真实对话消息(支持多轮对话扩展)。
ChatPromptTemplate:聊天场景的提示词模板,与普通 PromptTemplate 的区别是基于「消息角色」构建。
2. 代码实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 from langchain_core.messages import HumanMessagefrom langchain_core.output_parsers import StrOutputParserfrom langchain_core.prompts import MessagesPlaceholder, FewShotChatMessagePromptTemplatefrom langchain_demo.my_llm import llmfrom langchain_core.prompts import ChatPromptTemplateexamples = [ {"input" : "2 ? 3 = 5" ,"output" : "5" }, {"input" : "3 ? 4 = 7" ,"output" : "7" }, ] base_prompt = ChatPromptTemplate.from_messages( [ ('human' , '{input}' ), ('ai' , '{output}' ), ] ) few_shot_prompt = FewShotChatMessagePromptTemplate( examples=examples, example_prompt=base_prompt, ) final_template = ChatPromptTemplate.from_messages([ ("system" , "你是一个AI助手!" ), few_shot_prompt, MessagesPlaceholder("msgs" ) ]) chain = final_template | llm resp = chain.invoke({"msgs" : [HumanMessage(content="2?9结果是多少" )]}) print (resp)
3. 代码关键解析
ChatPromptTemplate.from_messages():接收消息列表构建聊天模板,每条消息是 (角色类型, 消息内容) 元组,核心角色包括 system(定义AI行为)、human(用户输入)、ai(AI回复)。
FewShotChatMessagePromptTemplate:聊天场景专属ICL工具,将示例列表按 example_prompt 定义的「Human→Ai」格式渲染,形成完整示例对话链。
MessagesPlaceholder("msgs"):动态消息容器,调用时可传入单个/多个 HumanMessage/AIMessage,支持多轮对话扩展,无需重构模板。
示例中的 input 是用户提问格式,output 是对应标准答案,模型会从示例中学习隐藏规律(此例中是「数字相加」)。
4. 实际运行结果 运行命令输出 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 "D:\my project\new_ai_model_env\.venv\Scripts\python.exe" "D:\my project\LangchainProject\langchain_demo\提示词模板-4.py" D:\my project\new_ai_model_env\.venv\Lib\site-packages \langchain_core\_api\deprecation.py:26 : UserWarning: Core Pydantic V1 functionality isn't compatible with Python 3.14 or greater. from pydantic.v1.fields import FieldInfo as FieldInfoV1 content=' 对于 2 ? 9 ,根据前面的例子,我观察到"?" 操作似乎是将两个数字相加。2 ? 3 = 5 (即 2 + 3 = 5 )3 ? 4 = 7 (即 3 + 4 = 7 )按照这个规律,2 ? 9 的结果应该是: 2 + 9 = 11 所以,2 ? 9 = 11 ' additional_kwargs={' refusal': None} response_metadata={' token_usage': {' completion_tokens': 144, ' prompt_tokens': 84, ' total_tokens': 228, ' completion_tokens_details': {' accepted_prediction_tokens': None, ' audio_tokens': 0, ' reasoning_tokens': 0, ' rejected_prediction_tokens': None, ' text_tokens': 0}, ' prompt_tokens_details': {' audio_tokens': 0, ' cached_tokens': 0, ' text_tokens': 0, ' image_tokens': 0}, ' input_tokens': 0, ' output_tokens': 0, ' input_tokens_details': None, ' claude_cache_creation_5_m_tokens': 0, ' claude_cache_creation_1_h_tokens': 0}, ' model_provider': ' openai', ' model_name': ' claude-3-7-sonnet-20250219 ', ' system_fingerprint': None, ' id': ' msg_bdrk_013v2a4K1AkZZUY4hnLbh2Nk', ' finish_reason': ' stop', ' logprobs': None} id=' lc_run--019c185a-cca9-7581-a0c3-77edef4787db-0 ' tool_calls=[] invalid_tool_calls=[] usage_metadata={' input_tokens': 84, ' output_tokens': 144, ' total_tokens': 228, ' input_token_details': {' audio': 0, ' cache_read': 0}, ' output_token_details': {' audio': 0, ' reasoning': 0}} 进程已结束,退出代码为 0
结果解读
忽略弃用警告 :开头的 Pydantic V1 弃用警告是 LangChain 框架的版本兼容性提示,不影响程序功能运行 ,可以暂时忽略。
ICL 学习成功 :模型成功从两条示例 {2 ? 3 = 5} 和 {3 ? 4 = 7} 中,学习到了「? 代表将两个数字相加」的隐藏规律,并正确推导出 2?9 的结果是 11。
输出格式说明 :打印的 resp 对象是 LangChain 聊天模型返回的原生 AIMessage 对象,它包含多个属性:
content:核心回复内容,即模型推理出的纯文本答案。
additional_kwargs、response_metadata、usage_metadata:这些是请求的元数据,包含了本次调用的令牌消耗详情、使用的模型信息(Claude 3.7 Sonnet)、请求ID等。
优化输出(可选) :如果您仅需要模型回复的纯文本内容(即 content),可以在执行链末尾添加 StrOutputParser() 解析器:
1 chain = final_template | llm | StrOutputParser()
返回的结果变为
1 2 3 4 5 6 7 8 9 如果我们观察前面的例子: 2 ? 3 = 5 3 ? 4 = 7 我可以推断出这个"?" 操作是将两个数字相加。所以: 2 ? 9 = 2 + 9 = 11 答案是11 。
通义千问等主流聊天模型的原生交互格式(System/Human/Assistant 消息流),能有效提升指令遵循和回复的准确性。