
目录一、核心组件概述二、Messages聊天模型中的消息1. LangChain 中的消息类型2. AIMessage 中有哪些内容三、多轮对话与历史消息1. 没有历史消息时2. 手动携带历史消息3. 历史消息为什么需要管理4. 使用 trim_messages 裁剪消息四、PromptTemplate字符串提示词模板1. 模板的核心结构2. 模板为什么重要五、ChatPromptTemplate聊天消息模板六、MessagesPlaceholder消息占位符七、Few-Shot少样本提示1. Few-Shot 示例2. Few-Shot 的适用场景3. Few-Shot 的注意点八、Few-Shot 示例选择器1. 语义相似度选择2. MMR最大边际相关性九、总结LangChain 的核心并不只是“调用模型”。它更重要的价值是将消息、提示词、模型、解析器、检索器等能力标准化让开发者可以像搭积木一样构建 LLM 应用。一、核心组件概述LangChain 中有很多核心组件例如MessagesPrompt TemplatesOutput ParsersDocument LoadersText SplittersEmbeddingsVector StoresRetrievers。这些组件看起来很多但本质上都围绕一个目标让大模型的输入更规范 让大模型的输出更稳定 让大模型能够使用外部知识 让整个调用流程更容易组合和维护本篇先学习前三个基础组件消息 Messages ↓ 提示词模板 PromptTemplate ↓ 少样本提示 Few-Shot Prompting二、Messages聊天模型中的消息聊天模型并不是简单接收一段字符串而是接收一组消息。每条消息通常包括角色 Role内容 Content元数据 Metadata工具调用信息 Tool CallsToken 使用信息 Usage Metadata。常见角色如下角色作用system设置模型身份、规则、上下文user用户输入assistant模型回答tool工具执行结果1. LangChain 中的消息类型LangChain 对不同模型厂商的消息格式进行了统一封装。类名说明SystemMessage系统消息HumanMessage用户消息AIMessage模型回复ToolMessage工具执行结果AIMessageChunk流式输出块示例from langchain_core.messages import ( SystemMessage, HumanMessage, AIMessage ) messages [ SystemMessage(content你是一名专业的 Java 后端工程师。), HumanMessage(content什么是 IOC), AIMessage(contentIOC 是控制反转是 Spring 的核心思想之一。), HumanMessage(content那 DI 又是什么) ]将消息交给模型from langchain_openai import ChatOpenAI model ChatOpenAI(modelgpt-4o-mini) result model.invoke(messages) print(result.content)2.AIMessage中有哪些内容模型调用后返回的通常是AIMessage。其中常用属性包括print(result.content) print(result.response_metadata) print(result.usage_metadata) print(result.tool_calls)含义如下属性含义content模型回答内容response_metadata响应信息如模型名、请求 ID、结束原因usage_metadataToken 使用量tool_calls模型请求调用的工具如果模型没有调用工具tool_calls通常为空列表。三、多轮对话与历史消息很多人第一次接触 LLM 时都会问模型能记住我上一句话吗严格来说模型并不会自动保存会话记忆。每次调用模型时模型只能看到本次请求发送给它的内容。1. 没有历史消息时from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage model ChatOpenAI(modelgpt-4o-mini) result1 model.invoke([ HumanMessage(content你好我叫小明) ]) print(result1.content) result2 model.invoke([ HumanMessage(content我叫什么名字) ]) print(result2.content)第二次调用中模型没有收到“小明”这条信息所以无法回答。2. 手动携带历史消息from langchain_core.messages import ( HumanMessage, AIMessage ) messages [ HumanMessage(content你好我叫小明), AIMessage(content你好小明很高兴认识你。), HumanMessage(content我叫什么名字) ] result model.invoke(messages) print(result.content)这样模型才能根据历史消息回答你叫小明。3. 历史消息为什么需要管理多轮对话越多消息列表会越长。系统消息 第一轮用户问题 第一轮模型回答 第二轮用户问题 第二轮模型回答 ...问题在于上下文窗口有限Token 成本会持续增加太多旧消息会干扰当前任务模型可能无法聚焦真正重要的信息。因此历史消息管理通常包括保留最近几轮对话删除无关消息对旧对话做摘要按 Token 数量裁剪将会话状态存入 Redis、数据库或 LangGraph。4. 使用trim_messages裁剪消息from langchain_core.messages import ( HumanMessage, AIMessage, SystemMessage, trim_messages ) messages [ SystemMessage(content你是一个技术助手。), HumanMessage(content你好我叫小明。), AIMessage(content你好小明。), HumanMessage(content我喜欢学习 Python。), AIMessage(contentPython 很适合入门编程。), HumanMessage(content我叫什么名字) ] trimmer trim_messages( max_tokens100, strategylast, token_countermodel, include_systemTrue ) trimmed_messages trimmer.invoke(messages) result model.invoke(trimmed_messages) print(result.content)这里的核心思想是保留系统消息和较新的对话内容适当裁剪过早的历史消息。四、PromptTemplate字符串提示词模板如果项目中需要频繁生成类似提示词手动拼接字符串会很麻烦。city 西安 prompt f请介绍一下{city}的历史并列出三个著名景点。如果换一个城市就要重新拼接。LangChain 提供了PromptTemplate。from langchain_core.prompts import PromptTemplate prompt_template PromptTemplate.from_template( 请使用{language}介绍{city}的历史并列出三个著名景点。 ) prompt_value prompt_template.invoke({ language: 中文, city: 西安 }) print(prompt_value.text)输出请使用中文介绍西安的历史并列出三个著名景点。1. 模板的核心结构PromptTemplate( template请介绍{city}的历史, input_variables[city] )template固定文本和变量占位符input_variables模板需要传入的变量名称。2. 模板为什么重要提示词模板的价值包括提高复用性统一 Prompt 格式将业务数据与提示词逻辑分离更方便版本管理和维护更容易构建复杂 LCEL 链。五、ChatPromptTemplate聊天消息模板对于聊天模型更常见的是ChatPromptTemplate。它可以一次性定义系统消息、用户消息、AI 消息等结构。from langchain_core.prompts import ChatPromptTemplate prompt_template ChatPromptTemplate.from_messages([ (system, 你是一名{role}。请使用简洁、专业的语言回答。), (human, {question}) ]) prompt_value prompt_template.invoke({ role: Python 开发工程师, question: 什么是生成器 }) messages prompt_value.to_messages() print(messages)输出结果会包含SystemMessage(...) HumanMessage(...)接下来可以将模板直接接入模型from langchain_openai import ChatOpenAI from langchain_core.output_parsers import StrOutputParser model ChatOpenAI(modelgpt-4o-mini) chain prompt_template | model | StrOutputParser() result chain.invoke({ role: Python 开发工程师, question: 什么是生成器 }) print(result)这就是 LCEL 的一个典型链式写法。六、MessagesPlaceholder消息占位符有时 Prompt 中不只是插入一个字符串而是需要动态插入多条消息。例如聊天历史系统消息 历史对话 当前用户问题这时可以使用MessagesPlaceholder。from langchain_core.prompts import ( ChatPromptTemplate, MessagesPlaceholder ) from langchain_core.messages import ( HumanMessage, AIMessage ) prompt_template ChatPromptTemplate.from_messages([ (system, 你是一名耐心的编程助手。), MessagesPlaceholder(variable_namehistory), (human, {question}) ]) history [ HumanMessage(content什么是 Redis), AIMessage(contentRedis 是一个高性能内存数据库。) ] prompt_value prompt_template.invoke({ history: history, question: Redis 可以做缓存吗 }) for message in prompt_value.to_messages(): print(message)最终结构大致如下SystemMessage你是一名耐心的编程助手。 HumanMessage什么是 Redis AIMessageRedis 是一个高性能内存数据库。 HumanMessageRedis 可以做缓存吗消息占位符常用于多轮对话历史RAG 检索结果Few-Shot 示例工具调用结果动态注入系统上下文。七、Few-Shot少样本提示Few-Shot Prompting即少样本提示。它的思想是不只是告诉模型“做什么”还给模型几个“正确示例”让模型模仿示例完成任务。例如我们希望模型判断评论情绪。直接提问判断下面评论的情绪物流很慢但是商品质量很好。模型可能会回答“中性”“积极”或“混合”结果不一定稳定。如果先给它一些示例输入商品很好物流很快 输出积极 输入质量太差再也不会买了 输出消极 输入物流很慢但是商品质量很好 输出模型会更容易理解我们的分类规则和输出格式。1. Few-Shot 示例from langchain_core.prompts import ( ChatPromptTemplate, FewShotChatMessagePromptTemplate ) examples [ { input: 商品很好物流很快, output: 积极 }, { input: 质量太差再也不会买了, output: 消极 }, { input: 整体一般没有特别惊喜, output: 中性 } ] example_prompt ChatPromptTemplate.from_messages([ (human, {input}), (ai, {output}) ]) few_shot_prompt FewShotChatMessagePromptTemplate( examplesexamples, example_promptexample_prompt ) final_prompt ChatPromptTemplate.from_messages([ (system, 你是一个商品评论情绪分类助手只返回积极、消极或中性。), few_shot_prompt, (human, {input}) ])调用model ChatOpenAI(modelgpt-4o-mini) chain final_prompt | model | StrOutputParser() result chain.invoke({ input: 价格比较贵但做工不错。 }) print(result)2. Few-Shot 的适用场景Few-Shot 很适合文本分类信息抽取格式化输出特定写作风格特定业务规则多步骤推理任务难以通过一句话描述清楚的任务。3. Few-Shot 的注意点Few-Shot 并不是示例越多越好。示例过多会导致Token 消耗上升调用成本提高上下文窗口被占用模型被无关示例干扰。一个高质量示例应该具备与真实输入相似格式清晰覆盖典型情况包含边界情况不包含互相矛盾的规则。八、Few-Shot 示例选择器实际项目中示例可能有几百条甚至几千条不可能全部放进 Prompt。因此需要根据当前问题挑选最适合的几个示例。常见策略包括选择方式思路固定示例每次使用相同的几个示例按长度选择根据上下文剩余空间选择示例语义相似度选择选择与当前问题语义最接近的示例MMR 选择兼顾相关性和多样性N-Gram 重叠根据词语重叠程度选择示例1. 语义相似度选择例如有以下示例示例 1如何学习 Python 示例 2Python 入门应该看什么书 示例 3Java 项目如何部署如果当前问题是Python 初学者如何开始学习那么应该优先选择示例 1 和示例 2。语义相似度选择的核心是当前问题向量 ↓ 与示例库中的向量计算相似度 ↓ 挑选最相近的 K 个示例2. MMR最大边际相关性如果只根据相似度选择可能得到三条内容非常相近的示例。MMR 的作用是既选择和当前问题相关的示例 又避免多个示例内容过于重复它在 RAG 和 Few-Shot 中都很常见。九、总结本文学习了 LangChain 的前三个核心组件。Messages聊天模型输入和输出的标准单位PromptTemplate构建可复用的字符串提示词ChatPromptTemplate构建多角色消息模板MessagesPlaceholder动态插入历史消息或上下文Few-Shot通过示例约束模型行为示例选择器从大量示例中动态挑选最相关的内容。下一篇将继续学习输出解析、RAG、文档加载、文本分割、向量化和检索器。