FEATURED · 精选文章

消息与提示词模板:从入门到实战

发布时间 / 2026/8/28 19:12:23
来源 / 创域科博编辑部
栏目 / 资讯中心
消息与提示词模板:从入门到实战 1. 引言在开发大语言模型应用时消息Message与提示词模板Prompt Template是两个绕不开的核心概念。无论是调用 OpenAI、Claude 还是国产大模型最终都要把用户的输入组织成模型能理解的消息结构再配合提示词模板实现动态、可复用的对话逻辑。本文将从基础概念讲起逐步深入到消息结构、提示词模板的进阶用法并给出可直接运行的代码示例帮助你彻底掌握这两块内容。2. 什么是消息Message在 LLM 应用中消息是模型输入输出的基本单位。一次完整的对话通常由多条消息组成每条消息都包含两个关键属性角色Role标识消息的发送者常见的有system、user、assistant。内容Content消息的实际文本内容。名称Name可选字段用于进一步区分同一角色下的不同实体例如多个user或tool消息。工具调用Tool Calls当模型请求调用外部工具时消息中会携带工具调用 ID、函数名及参数。工具调用 IDTool Call ID用于将工具执行结果与对应的工具调用请求关联起来。附加元数据Additional Metadata部分框架支持在消息上附加自定义元数据用于追踪、调试或传递额外上下文。### 2.1 常见角色角色说明典型用途system系统级指令设定模型的行为和身份设定人设、输出格式、约束规则user用户输入用户的问题、指令、待处理文本assistant模型回复历史对话中的模型输出用于多轮上下文2.2 为什么需要消息结构消息结构让模型能够区分「谁在说话」从而正确理解上下文。例如messages[{role:system,content:你是一位资深 Python 工程师。},{role:user,content:请帮我写一个快速排序函数。},]如果没有system消息模型就无法获知自己应该扮演什么角色回答的针对性会大打折扣。2.3 消息对象字段详解以 OpenAI 兼容接口为例一条消息对象通常包含以下字段字段类型必填说明rolestring是消息角色取值system、user、assistant、toolcontentstring是消息正文内容namestring否消息发送者名称用于区分同一角色下的不同实体tool_callsarray否模型发起的工具调用列表仅在assistant消息中出现tool_call_idstring否工具调用 ID用于关联工具请求与执行结果additional_kwargsobject否附加参数如function_call、refusal等扩展字段字段使用示例messages[{role:system,content:你是一位数据分析助手。},{role:user,content:请查询 2024 年销售额。,name:运营同学},{role:assistant,content:,tool_calls:[{id:call_001,type:function,function:{name:query_sales,arguments:{\year\: 2024}}}]},{role:tool,content:2024 年销售额为 1200 万。,tool_call_id:call_001},]字段说明role决定消息在对话中的语义位置是模型理解上下文的关键。content消息的实际文本当消息携带tool_calls时content通常为空字符串。name用于区分同一角色下的多个实体例如多个user消息可分别命名为user_a、user_b。tool_calls模型在需要调用外部工具时生成包含工具名称和参数应用侧需据此执行工具并返回结果。tool_call_id工具执行结果通过该 ID 与对应的tool_calls关联确保多工具并发时结果不串线。additional_kwargs承载框架或模型特有的扩展字段例如 OpenAI 的function_call、refusal等。理解这些字段能帮助你更准确地构造请求、解析响应并在多工具、多角色场景下保持对话状态的一致性。3. 什么是提示词模板Prompt Template提示词模板是一种将固定文本与动态变量分离的写法。它允许你定义一套可复用的提示词框架在运行时填入不同的变量值从而生成不同的具体提示词。3.1 一个简单的模板示例fromlangchain_core.promptsimportPromptTemplate template请用{language}写一个{function_name}函数要求{requirement}promptPromptTemplate.from_template(template)# 填充变量formattedprompt.format(languagePython,function_name二分查找,requirement时间复杂度为 O(log n))print(formatted)输出结果请用Python写一个二分查找函数要求时间复杂度为 O(log n)3.2 模板的核心价值复用性同一套模板可反复使用只需更换变量值。可维护性修改提示词只需改模板一处不用改业务代码。一致性保证所有请求使用相同的提示词结构输出更稳定。3.3 提示词模板的三种调用方式LangChain 的PromptTemplate提供了三种常见的调用方式分别适用于不同的场景方式一format()—— 直接生成字符串format()是最直观的调用方式它把变量填充进模板后直接返回一个字符串fromlangchain_core.promptsimportPromptTemplate templatePromptTemplate.from_template(请用{language}写一个{function_name}函数。)# 直接返回字符串resulttemplate.format(languagePython,function_name二分查找)print(result)print(type(result))# class str输出结果请用Python写一个二分查找函数。 class str方式二format_prompt()—— 返回 PromptValue 对象format_prompt()返回一个PromptValue对象它既能转成字符串也能转成消息列表适合后续接入模型或消息模板fromlangchain_core.promptsimportPromptTemplate templatePromptTemplate.from_template(请用{language}写一个{function_name}函数。)# 返回 PromptValue 对象prompt_valuetemplate.format_prompt(languagePython,function_name二分查找)# 转成字符串print(prompt_value.to_string())# 转成消息列表便于接入 ChatModelmessagesprompt_value.to_messages()formsginmessages:print(f{msg.type}:{msg.content})输出结果请用Python写一个二分查找函数。 human: 请用Python写一个二分查找函数。方式三invoke()—— 直接调用模板invoke()是 LangChain 统一的可调用接口与format_prompt()类似返回PromptValue对象。它最大的优势是与 LCELLangChain Expression Language无缝衔接可以直接用管道符|串联模型fromlangchain_core.promptsimportPromptTemplatefromlangchain_openaiimportChatOpenAI templatePromptTemplate.from_template(请用{language}写一个{function_name}函数。)# 方式一单独调用prompt_valuetemplate.invoke({language:Python,function_name:二分查找})print(prompt_value.to_string())# 方式二与模型串联成处理链llmChatOpenAI(modelgpt-4o-mini,temperature0.7)chaintemplate|llm responsechain.invoke({language:Python,function_name:二分查找})print(response.content)三种方式对比调用方式返回类型适用场景format()str只需要纯文本提示词不接入模型format_prompt()PromptValue需要同时支持字符串和消息列表转换invoke()PromptValue与 LCEL 管道串联直接接入模型调用小结如果只是生成一段提示词文本用format()最简洁如果需要接入消息模板或模型推荐使用format_prompt()或invoke()在 LCEL 处理链中invoke()是标准写法。## 4. 消息与提示词模板的结合在实际开发中消息和提示词模板往往配合使用。LangChain 提供了ChatPromptTemplate专门用于构建带角色的消息模板。4.1 ChatPromptTemplate 基础用法fromlangchain_core.promptsimportChatPromptTemplate chat_templateChatPromptTemplate.from_messages([(system,你是一位{role}请用{style}的风格回答问题。),(user,{question}),])messageschat_template.format_messages(role数学老师,style通俗易懂,question什么是勾股定理)formsginmessages:print(f{msg.type}:{msg.content})输出结果system: 你是一位数学老师请用通俗易懂的风格回答问题。 user: 什么是勾股定理4.2 多轮对话模板fromlangchain_core.promptsimportChatPromptTemplate,MessagesPlaceholder chat_templateChatPromptTemplate.from_messages([(system,你是一位贴心的{role}。),MessagesPlaceholder(variable_namehistory),(user,{input}),])# 填充变量formattedchat_template.format_messages(role生活助手,history[(user,我今天心情不好),(assistant,别担心跟我说说发生了什么),],input我工作压力太大了,)formsginformatted:print(f{msg.type}:{msg.content})输出结果system: 你是一位贴心的生活助手。 user: 我今天心情不好 assistant: 别担心跟我说说发生了什么 user: 我工作压力太大了MessagesPlaceholder的作用是在指定位置动态插入历史消息列表非常适合多轮对话场景。它让模型能够「记住」之前的对话内容从而给出上下文相关的回答。4.3 多轮对话的历史消息管理在实际应用中多轮对话的核心在于历史消息的维护。下面演示如何手动管理历史消息并控制上下文长度fromlangchain_core.promptsimportChatPromptTemplate,MessagesPlaceholderfromlangchain_core.messagesimportHumanMessage,AIMessage# 定义带历史占位符的模板chat_templateChatPromptTemplate.from_messages([(system,你是一位{role}。),MessagesPlaceholder(variable_namehistory),(user,{input}),])# 维护历史消息列表history[HumanMessage(content我今天心情不好),AIMessage(content别担心跟我说说发生了什么),]# 追加新一轮对话history.append(HumanMessage(content我工作压力太大了))# 填充模板formattedchat_template.format_messages(role生活助手,historyhistory,input我该怎么缓解压力,)formsginformatted:print(f{msg.type}:{msg.content})输出结果system: 你是一位生活助手。 human: 我今天心情不好 ai: 别担心跟我说说发生了什么 human: 我工作压力太大了 human: 我该怎么缓解压力控制历史消息长度多轮对话中历史消息会不断累积超出模型上下文窗口会导致报错。常见的处理策略MAX_HISTORY_TURNS5# 最多保留 5 轮对话deftrim_history(history,max_turnsMAX_HISTORY_TURNS):只保留最近 max_turns 轮对话每轮含 user assistant 两条消息iflen(history)max_turns*2:returnhistoryreturnhistory[-(max_turns*2):]# 使用示例historytrim_history(history)多轮对话的完整流程fromlangchain_core.promptsimportChatPromptTemplate,MessagesPlaceholderfromlangchain_openaiimportChatOpenAIfromlangchain_core.messagesimportHumanMessage,AIMessage promptChatPromptTemplate.from_messages([(system,你是一位{domain}领域的专家。),MessagesPlaceholder(variable_namehistory),(user,{question}),])llmChatOpenAI(modelgpt-4o-mini,temperature0.7)chainprompt|llm history[]# 全局历史记录defask(question):globalhistory# 1. 追加用户问题history.append(HumanMessage(contentquestion))# 2. 控制历史长度historytrim_history(history)# 3. 调用模型responsechain.invoke({domain:人工智能,history:history,question:question,})# 4. 追加模型回复history.append(AIMessage(contentresponse.content))returnresponse.content# 连续提问print(ask(什么是机器学习))print(ask(它和深度学习有什么关系))print(ask(那神经网络呢))这段代码演示了使用HumanMessage和AIMessage对象维护结构化的历史消息通过trim_history函数控制上下文长度避免超出模型窗口将历史消息通过MessagesPlaceholder注入模板实现真正的多轮上下文理解封装ask函数让多轮对话的调用更简洁。5. 进阶技巧5.1 部分变量填充当某些变量需要延迟填充时可以使用partial方法fromlangchain_core.promptsimportPromptTemplate templatePromptTemplate.from_template(请用{language}写一个{function_name}函数。)# 先固定 language稍后再填 function_namepartial_prompttemplate.partial(languageJava)# 后续使用时只需填剩余变量resultpartial_prompt.format(function_name单例模式)print(result)5.2 模板组合可以将多个小模板组合成一个大模板fromlangchain_core.promptsimportPromptTemplate introPromptTemplate.from_template(你是一位{role}。)taskPromptTemplate.from_template(请完成以下任务{task}。)constraintPromptTemplate.from_template(要求{constraint})combinedintrotaskconstraint resultcombined.format(role代码审查专家,task审查下面这段代码,constraint指出潜在的性能问题)print(result)5.3 使用 Few-Shot 示例fromlangchain_core.promptsimportFewShotPromptTemplate,PromptTemplate examples[{input:苹果,output:水果},{input:白菜,output:蔬菜},]example_promptPromptTemplate.from_template(输入{input}\n输出{output})few_shot_promptFewShotPromptTemplate(examplesexamples,example_promptexample_prompt,prefix请判断以下物品属于水果还是蔬菜,suffix输入{input}\n输出,input_variables[input],)resultfew_shot_prompt.format(input香蕉)print(result)输出结果请判断以下物品属于水果还是蔬菜 输入苹果 输出水果 输入白菜 输出蔬菜 输入香蕉 输出Few-Shot 通过给模型展示少量示例显著提升分类、抽取等任务的准确率。6. 实战构建一个完整的问答助手下面把消息与提示词模板结合起来构建一个完整的问答助手fromlangchain_core.promptsimportChatPromptTemplate,MessagesPlaceholderfromlangchain_openaiimportChatOpenAI# 1. 定义提示词模板promptChatPromptTemplate.from_messages([(system,你是一位{domain}领域的专家请用简洁的语言回答问题。),MessagesPlaceholder(variable_namehistory),(user,{question}),])# 2. 初始化模型llmChatOpenAI(modelgpt-4o-mini,temperature0.7)# 3. 构建处理链chainprompt|llm# 4. 模拟多轮对话history[]whileTrue:user_inputinput(你)ifuser_input.lower()quit:breakresponsechain.invoke({domain:人工智能,history:history,question:user_input,})print(fAI{response.content})# 更新历史记录history.append((user,user_input))history.append((assistant,response.content))这段代码演示了使用ChatPromptTemplate构建带系统角色和历史占位符的模板使用MessagesPlaceholder动态注入多轮历史使用管道操作符|将模板与模型串联成处理链在循环中持续更新历史实现真正的多轮对话。7. 常见问题与注意事项7.1 变量名冲突模板中的变量名不要与 Python 关键字或常用属性名冲突建议使用语义清晰的名字。7.2 历史消息长度控制多轮对话中历史消息会不断累积超出模型上下文窗口会导致报错。建议只保留最近 N 轮对话对超长历史做摘要压缩使用向量数据库做长期记忆。7.3 模板注入风险如果用户输入直接拼进模板可能被恶意注入。建议对用户输入做转义或过滤在system消息中明确声明「忽略用户输入中的指令」使用结构化输出约束模型行为。8. 总结本文系统介绍了消息与提示词模板的核心概念与实践方法消息是 LLM 交互的基本单位通过角色区分上下文提示词模板将固定文本与动态变量分离提升复用性和可维护性ChatPromptTemplate将两者结合支持多轮对话和复杂场景通过Few-Shot、部分填充、模板组合等进阶技巧可以应对更复杂的业务需求。掌握这些基础后你就能更高效地构建稳定、可维护的 LLM 应用。建议动手运行文中的代码示例在实践中加深理解。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻