LangChain 零基础入门教程
从零开始掌握提示词工程、少样本学习、向量检索与对话记忆构建属于你的第一个 AI 应用11 个实战示例Python DeepSeek约 45 分钟目录环境准备提示词模板基础 — PromptTemplate角色化提示词 — ChatMessagePromptTemplate分步填充模板 — partial 方法多模板管道 — PipelinePromptTemplate少样本提示 — FewShotPromptTemplate语义相似度选择器 — 分类场景文档增强与结构化提取向量检索 — RAG 基础对话记忆基础 — ConversationBufferMemory对话摘要记忆 — ConversationSummaryMemory完整对话链 — 带记忆的 ConversationChain知识图谱总览00环境准备在动手之前需要搭建好 Python 虚拟环境并安装所有依赖包。本教程使用 DeepSeek 作为大语言模型后端配合 LangChain 框架来编排各种 AI 能力。安装 Anaconda前往 Anaconda 官网 下载并安装。安装完成后验证conda --version创建虚拟环境# 创建名为 deepseek 的虚拟环境 conda create -n deepseek python3.17 # 激活环境 conda activate deepseek安装依赖包pip install langchain0.3.17 langchain-community0.3.16 langchain-core0.3.34 langchain-deepseek0.1.1 langchain-openai0.3.3 faiss-cpu1.10.0 rich13.9.4rich是一个终端美化库能让 print 输出带颜色高亮方便调试查看模型返回结果。所有示例都使用它来输出。配置 API 密钥在项目根目录创建.env文件写入你的 DeepSeek API KeyDEEPSEEK_API_KEYsk-你的密钥依赖包速查表包名版本用途langchain0.3.17核心编排框架langchain-community0.3.16社区集成嵌入模型等langchain-core0.3.34基础抽象层Prompt、Memory 等langchain-deepseek0.1.1DeepSeek 模型适配器langchain-openai0.3.3OpenAI 兼容接口faiss-cpu1.10.0向量相似度搜索rich13.9.4终端美化输出01提示词模板基础与模型打交道的最基本方式就是提示词Prompt。LangChain 提供了 ChatMessagePromptTemplate让你不用每次都手拼字符串而是通过模板加占位符的方式动态生成提示词。核心思路想象你在做一封邮件模板 —— 先写好固定格式把会变的部分留成空格。LangChain 的提示词模板就是干这个的固定文本 占位符变量 最终提示词。代码拆解01-prompt.py第一步创建模型实例和提示词模板Pythonfrom langchain_core.prompts import ChatMessagePromptTemplate from langchain_deepseek import ChatDeepSeek from rich import print from dotenv import load_dotenv load_dotenv() # 1. 创建模型实体 — langchain_deepseek 提供的 DeepSeek 接口 llm ChatDeepSeek(modeldeepseek-chat) # 2. 创建提示词模板 — {subject} 是占位符 prompt 我可以如何帮助您解决{subject}的问题 # 3. 给模板指定一个角色role chat_message_prompt ChatMessagePromptTemplate.from_template( role销售顾问, templateprompt ) # 4. 填入占位符内容生成最终提示词 formatted_prompt chat_message_prompt.format(subject产品咨询) prompts [str(formatted_prompt)] # 5. 让模型回答 response llm.generate(prompts) print(response)逐行理解1创建模型ChatDeepSeek(modeldeepseek-chat)是 LangChain 调用 DeepSeek 的入口。你可以把它理解为模型的一个遥控器。2定义模板{subject}是占位符运行时会被替换为实际值类似 Python 的 f-string。3绑定角色from_template(role销售顾问)告诉模型你现在扮演销售顾问这会影响模型回答的语气和角度。4填充并调用.format(subject产品咨询)把占位符替换成具体内容然后传给模型生成回答。学到了什么LangChain 把给模型发消息这件事拆成了三个部分 —— 模型选择、模板定义、参数填充。这样你只需要改参数就能复用同一套模板。02角色化提示词上一个示例展示了角色绑定这个示例更进一步 —— 把角色作为模板的一个可配置项让同一个模板适配不同的业务场景。代码拆解02-prompt-role.py同一个模板通过更换 role 参数切换不同业务角色Pythonfrom langchain_core.prompts import ChatMessagePromptTemplate from langchain_deepseek import ChatDeepSeek from dotenv import load_dotenv from rich import print load_dotenv() llm ChatDeepSeek(modeldeepseek-chat) # 定义一个客服通用模板 template 你作为一个经验丰富的客服代表为用户问题提供解答:{Query} # 绑定角色为技术支持 chat_message_prompt ChatMessagePromptTemplate.from_template( role技术支持, templatetemplate ) # 填入用户问题 formatted_prompt chat_message_prompt.format(Query产品如何使用) prompts str(formatted_prompt) print(prompts) # 先看拼出来的提示词长什么样 response llm.generate([prompts]) print(response) # 模型的回答对比示例 01示例 01 的角色是写死的销售顾问而这里你只需要把role技术支持换成role售后专员或其他角色模型就会以不同身份回答同一个问题。写死角色适合固定场景比如你的系统只有一个客服身份不需要切换。参数化角色适合多场景系统根据用户需求动态分配不同角色的客服来回答问题。03分步填充模板实际业务中有些信息用户一开始就会提供有些则需要后续追问。LangChain 的 partial 方法支持先填一部分再填另一部分。生活类比就像填表 —— 你先填了姓名电话留空过一会儿再回来补电话。partial 就是先把能填的填上。代码拆解03-prompt-part.py两步填充先确定产品再追问具体问题Pythonfrom langchain.prompts import PromptTemplate from langchain_deepseek import ChatDeepSeek from dotenv import load_dotenv from rich import print load_dotenv() llm ChatDeepSeek(modeldeepseek-chat) # 创建模板有两个占位符product 和 problem prompt PromptTemplate( template我想知道关于{product}的{problem}问题?, input_variables[product, problem] ) # 第一次输入 — 用户先告诉系统他关心手机 partial_prompt prompt.partial(product手机) # 第二次输入 — 用户追问恢复出厂设置 formatted_prompt partial_prompt.format(problem恢复出厂设置) print(formatted_prompt) # 输出: 我想知道关于手机的恢复出厂设置问题? response llm.generate([formatted_prompt]) print(response)核心价值在多轮对话或分步表单场景中partial 让你不需要一次性收集所有参数而是有多少填多少。这在构建聊天机器人时非常有用。04多模板管道当你的提示词需要由多个子模块组合而成时PipelinePromptTemplate 可以把它们串联起来像流水线一样依次填充最终拼成完整的提示词。流水线类比想象一条汽车装配线 —— 不同的工位负责安装不同的零件最终组合成一整车。PipelinePromptTemplate 就是把多个子模板装配成一个大模板。代码拆解04-multi-template.py四个子模板通过管道拼接模拟客服系统收集用户信息Pythonfrom langchain.prompts.pipeline import PipelinePromptTemplate from langchain.prompts.prompt import PromptTemplate from langchain_deepseek import ChatDeepSeek from dotenv import load_dotenv from rich import print load_dotenv() llm ChatDeepSeek(modeldeepseek-chat) # 大模板 — 定义最终结构用占位符引用各子模板 full_template {category_select} {brand_select} {OS_select} {problem_select} full_prompt PromptTemplate.from_template(full_template) # 子模板1角色介绍 person_select 你好 我是{person} person_prompt PromptTemplate.from_template(person_select) # 子模板2品牌信息 brand_template 我了解您使用的是 {brand}手机 brand_prompt PromptTemplate.from_template(brand_template) # 子模板3操作系统 os_template 操作系统为{os} os_prompt PromptTemplate.from_template(os_template) # 子模板4问题描述 problem_template 您遇到了{problem}的问题 我可以为您解决 problem_prompt PromptTemplate.from_template(problem_template) # 定义大模板占位符与子模板的映射关系 input_prompts [ (category_select, person_prompt), (brand_select, brand_prompt), (OS_select, os_prompt), (problem_select, problem_prompt) ] # 创建管道 pipeline_prompt PipelinePromptTemplate( final_promptfull_prompt, pipeline_promptsinput_prompts ) # 一次性填入所有子模板的参数 formatted_prompt pipeline_prompt.format( person技术支持, brand华为, osHarmonyOS, problem恢复出厂设置操作, ) response llm.generate([str(formatted_prompt)]) print(response)使用场景当你有一段固定的开场白加上动态变化的业务信息时管道模板可以把它们解耦成独立的子模板方便单独维护和复用。05少样本提示有时候告诉模型怎么做比告诉它做什么更有效。FewShotPromptTemplate 通过提供若干输入-输出示例让模型学会你的期望格式和回答风格。类比理解就像培训新员工 —— 与其给他一本厚厚的手册不如先给他看几个标准案例让他照着做。FewShot 就是给模型的标准案例。代码拆解05-examples.py用四个客服案例教模型先回答、再确认的回复风格Pythonfrom langchain.prompts import PromptTemplate, FewShotPromptTemplate from langchain.prompts.example_selector import LengthBasedExampleSelector from langchain_deepseek import ChatDeepSeek from dotenv import load_dotenv from rich import print load_dotenv() llm ChatDeepSeek(modeldeepseek-chat) # 四组标准案例 — 每组包含问题和期望的回答 examples [ {input: 如何重置密码, output: 请前往登录页面点击忘记密码链接...}, {input: 怎样查询订单状态, output: 请登录您的账户然后点击我的订单...}, {input: 如何申请退货, output: 请登录您的账户找到相应的订单...}, {input: 如何使用优惠券, output: 在结账页面找到使用优惠券...}, ] # 定义示例的展示格式 example_prompt PromptTemplate( input_variables[input, output], template问题{input}\n回答{output} ) # LengthBasedExampleSelector 根据输入长度动态选择示例数量 example_selector LengthBasedExampleSelector( examplesexamples, example_promptexample_prompt ) # 组装 FewShot 提示词 dynamic_prompt FewShotPromptTemplate( example_selectorexample_selector, example_promptexample_prompt, prefix回答以下客户的问题并提供额外的解释或信息然后询问他们是否满意。, suffix问题:{query}\n回答:, input_variables[query], ) # 查看实际拼出的完整提示词 print(dynamic_prompt.format(query如何取消订单?)) # 发给模型 output llm.generate([dynamic_prompt.format(query如何取消订单?)]) print(output)关键概念组件作用examples你准备的标准案例列表每组包含 input 和 outputexample_prompt每个案例在提示词中如何展示的格式LengthBasedExampleSelector根据输入长度自动决定放多少个示例输入越长放的示例越少节省 tokenprefix / suffix在示例列表前后加的说明文字告诉模型上下文和任务06语义相似度选择器上一个示例按长度选案例这个示例升级为按语义相似度选案例 —— 用户问一个问题系统自动找到含义最接近的历史案例让模型参考着回答。这在 自动客服分类 场景中非常实用。技术路线整个过程涉及 嵌入模型Embedding和 向量数据库FAISS。文本先被嵌入模型转换为数学向量然后用 FAISS 做相似度搜索找到最接近的示例。代码拆解06-category.py将用户问题自动分类到账户/订单/退货/账单/促销等类别Pythonfrom langchain.prompts.example_selector import SemanticSimilarityExampleSelector from langchain.vectorstores import FAISS from langchain.prompts import FewShotPromptTemplate, PromptTemplate from langchain_deepseek import ChatDeepSeek from langchain_community.embeddings import HuggingFaceBgeEmbeddings from dotenv import load_dotenv from rich import print import torch load_dotenv() llm ChatDeepSeek(modeldeepseek-chat) # 示例列表 — 每组包含用户问题和对应分类 examples [ {input: 我忘记了密码怎么重置, output: 账户问题}, {input: 我的订单在哪里已经过了一周了, output: 订单问题}, {input: 我收到了一个有缺陷的物品我怎么退货, output: 退货和退款问题}, {input: 我想更改我的送货地址。, output: 订单问题}, {input: 我怎么升级我的会员资格, output: 账户问题}, {input: 我的订单被收了两次费我该怎么办, output: 账单问题}, {input: 送货的商品不是我订购的我怎么换货, output: 退货和退款问题}, {input: 我怎么取消我的订单, output: 订单问题}, {input: 我的优惠码不起作用你能帮帮我吗, output: 促销问题}, {input: 我无法登录我的账户我该怎么办, output: 账户问题} ] # 初始化中文嵌入模型 model_name BAAI/bge-large-zh-v1.5 model_kwargs {device: cuda if torch.cuda.is_available() else cpu} encode_kwargs {normalize_embeddings: True} hf HuggingFaceBgeEmbeddings( model_namemodel_name, model_kwargsmodel_kwargs, encode_kwargsencode_kwargs ) # 用语义相似度选择最接近的示例k1 表示只选 1 个最相似的 example_selector SemanticSimilarityExampleSelector.from_examples( examples, hf, FAISS, k1 ) # 组装提示词 similar_prompt FewShotPromptTemplate( example_selectorexample_selector, example_promptexample_prompt, prefix以下是一个客户服务查询请将其分类, suffix输入{query}\n输出, input_variables[query], ) my_query 我的订单被收了两次费我该怎么办 print(similar_prompt.format(querymy_query)) response llm.generate([str(similar_prompt.format(querymy_query))]) print(response)注意这段代码需要下载BAAI/bge-large-zh-v1.5嵌入模型约 1.2GB。首次运行会自动从 HuggingFace 下载建议提前准备好网络环境。如果有 NVIDIA 显卡会自动使用 GPU 加速。对比两种选择器选择器选择依据适用场景LengthBasedExampleSelector输入文本长度控制 token 用量输入越长示例越少SemanticSimilarityExampleSelector语义向量距离找到最相关的案例提升分类准确度07文档增强与结构化提取真实业务中原始数据往往是杂乱的文本。LangChain 的 Document 对象可以携带结构化的元数据。这个示例展示了如何让模型分析一段产品评价自动提取出产品名称、情感倾向、评分等结构化信息。代码拆解07-emotion.py让模型把非结构化的产品评价转化为 JSON 元数据Pythonfrom langchain.schema import Document from langchain_deepseek import ChatDeepSeek from langchain.prompts import PromptTemplate from dotenv import load_dotenv from rich import print import json load_dotenv() llm ChatDeepSeek(modeldeepseek-chat) # 提示词模板 — 要求模型以 JSON 格式返回分析结果 template 请分析以下产品评价提取以下信息并以JSON格式返回: - 产品名称 - 情感倾向(正面/负面) - 评分(1-5星) 评价内容: {review} 返回格式示例: {{产品: 产品名称, 情感: 正面/负面, 评分: 数字}} JSON格式结果: prompt PromptTemplate(input_variables[review], templatetemplate) # 原始文档 original_documents [ Document(page_content华为P40评价\nBy 用户A\n\n我非常喜欢这款手机摄像头非常好。5星满分。), Document(page_content三星Galaxy评价\nBy 用户B\n\n电池续航令人失望。给2星。), ] # 处理每篇文档 for doc in original_documents: formatted_prompt prompt.format(reviewdoc.page_content) response llm.generate([formatted_prompt]) try: result_text response.generations[0][0].text # 从模型返回中提取 JSON json_start result_text.find({) json_end result_text.rfind(}) 1 json_str result_text[json_start:json_end] doc.metadata json.loads(json_str) # 存入文档元数据 except Exception as e: doc.metadata {error: str(e), raw_response: result_text} # 打印增强后的文档 print( *[d.page_content \n\n json.dumps(d.metadata, ensure_asciiFalse, indent2) for d in original_documents], sep\n\n---------------\n\n )处理流程1原始数据创建Document对象内容是用户自由写的评价文本。2模型分析通过提示词要求模型以 JSON 格式输出结构化信息产品名、情感、评分。3元数据挂载解析模型返回的 JSON存入doc.metadata文档从此自带结构。08向量检索 — RAG 基础RAGRetrieval-Augmented Generation检索增强生成是目前 AI 应用最热门的架构之一。它的核心思想是先从知识库中检索相关内容再交给模型回答从而让模型拥有记忆和知识。这个示例做了什么把一段手机描述文本切分成小片段用嵌入模型转换成向量存入 FAISS 向量数据库。当用户提问手机分辨率如何时系统自动找到最相关的片段返回。代码拆解08-retrieval.py文本切分 → 向量化 → 存入 FAISS → 相似度搜索Pythonimport torch from langchain_community.embeddings import HuggingFaceBgeEmbeddings from langchain_deepseek import ChatDeepSeek from dotenv import load_dotenv from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.vectorstores import FAISS load_dotenv() # 初始化嵌入模型 model_name BAAI/bge-large-zh-v1.5 model_kwargs {device: cuda if torch.cuda.is_available() else cpu} encode_kwargs {normalize_embeddings: True} hf HuggingFaceBgeEmbeddings( model_namemodel_name, model_kwargsmodel_kwargs, encode_kwargsencode_kwargs ) llm ChatDeepSeek(modeldeepseek-chat) # 原始文档 — 一段手机参数描述 raw_documents 该款智能手机配备了一块6.7英寸的超清液晶显示屏分辨率高达3200x1440... 后置4800万像素摄像头支持5G网络面部解锁等 # 步骤1文本切分 — 每 100 字一段重叠 20 字防止语义被切断 text_splitter RecursiveCharacterTextSplitter( chunk_size100, chunk_overlap20, length_functionlen ) documents text_splitter.split_text(textraw_documents) # 步骤2向量化并存入 FAISS vectorStore FAISS.from_texts(documents, hf) # 步骤3查询 query 手机分辨率如何 docs vectorStore.similarity_search(query) print(docs[0].page_content) # 输出最相关的文本片段关键参数解释参数值含义chunk_size100每段文本最多 100 个字符。太小会丢失上下文太大影响检索精度。chunk_overlap20相邻片段重叠 20 字符确保边界处的语义不被截断。normalize_embeddingsTrue对向量做归一化使相似度计算更稳定。这是 RAG 的最简形态只用向量检索 原始片段返回。完整的 RAG 还会把检索到的片段塞进提示词让模型基于检索结果来回答。后面的示例 09-11 会在此基础上引入对话记忆能力。09对话记忆基础大模型本身是无状态的 —— 它不记得你上一句话说了什么。ConversationBufferMemory 为模型添加了短期记忆自动把历史对话追加到每次请求中。代码拆解09-memory.py三轮连续对话模型能记住之前的上下文Pythonfrom langchain.memory import ConversationBufferMemory from langchain_deepseek import ChatDeepSeek from dotenv import load_dotenv from langchain.chains import ConversationChain load_dotenv() llm ChatDeepSeek(modeldeepseek-chat) # 创建带记忆的对话链 conversation ConversationChain( llmllm, verboseTrue, memoryConversationBufferMemory() ) # 第一轮对话 conversation.predict(input如何退货) # 第二轮对话 — 模型记得你在问退货相关的事 conversation.predict(input我是3月1日买的手机订单号忘记了) # 第三轮对话 — 模型还记得前两轮的上下文 conversation.predict(input如何查找订单号)verboseTrue会在终端打印每次发送给模型的完整内容包括历史对话这对调试和理解模型行为非常有帮助。窗口记忆补充说明代码中注释掉的ConversationBufferWindowMemory(k2)是一种滑动窗口记忆 —— 只保留最近 k 轮对话。这在长对话中可以控制 token 消耗避免提示词过长。ConversationBufferMemory记住所有历史对话。适合短对话简单直接但对话越多 token 消耗越大。ConversationBufferWindowMemory只保留最近 k 轮。适合长对话场景在记忆完整性和 token 成本之间做平衡。10对话摘要记忆当对话越来越长把所有历史都塞进提示词显然不现实。ConversationSummaryMemory 用大模型本身来总结之前的对话只保留摘要大大压缩了记忆的长度。代码拆解10-long-conversation-01.py用模型生成对话摘要压缩记忆长度Pythonfrom langchain.memory import ConversationSummaryMemory from langchain_deepseek import ChatDeepSeek from dotenv import load_dotenv from rich import print load_dotenv() llm ChatDeepSeek(modeldeepseek-chat) # 创建摘要记忆 memory ConversationSummaryMemory(llmllm, return_messagesTrue) # 保存三段对话历史 memory.save_context( {input: 记录1:如何退货}, {output: 您需要查看该商家的退货政策,根据订单号退货} ) memory.save_context( {input: 记录2:我是3月1日买的手机订单号忘记了}, {output: 通过网站使用电话号码进行搜索} ) memory.save_context( {input: 记录3:如何查找订单号}, {output: 在订单确认电子邮件中找到订单号} ) # 查看保存的消息 messages memory.chat_memory.messages print(messages) # 基于当前消息 之前的摘要预测新的摘要 previous_summary 用户已经下单购买手机并且完成了货物的签收 reposne memory.predict_new_summary(messages, previous_summary) print(reposne)工作原理ConversationSummaryMemory 内部维护一个不断更新的摘要字符串。每新增一轮对话就把新对话和旧摘要一起交给模型让它生成一份融合了新信息的摘要。这就像你读完一章书后写一段小结读完下一章再更新小结。11完整对话链这个示例把前面的摘要记忆和对话链结合起来演示了一个 带长期记忆的完整聊天机器人。它通过ChatMessageHistory管理消息列表通过ConversationSummaryMemory压缩历史通过ConversationChain把一切串起来。代码拆解11-long-conversation-02.py完整的带记忆对话链历史 摘要 新问题 → 回答Pythonfrom langchain.memory import ConversationSummaryMemory, ChatMessageHistory from langchain_deepseek import ChatDeepSeek from dotenv import load_dotenv from langchain.chains import ConversationChain from rich import print load_dotenv() llm ChatDeepSeek(modeldeepseek-chat) # 手动构建对话历史 history ChatMessageHistory() history.add_user_message(记录1:如何退货) history.add_ai_message(您需要查看该商家的退货政策,根据订单号退货) history.add_user_message(记录2:我是3月1日买的手机订单号忘记了) history.add_ai_message(通过网站使用电话号码进行搜索) history.add_user_message(记录3:如何查找订单号) history.add_ai_message(在订单确认电子邮件中找到订单号) # 从历史创建摘要记忆 memory ConversationSummaryMemory.from_messages( llmllm, chat_memoryhistory, return_messagesTrue ) # 创建带摘要记忆的对话链 conversation_with_summary ConversationChain( llmllm, memorymemory, verboseTrue ) # 新问题 — 模型会基于摘要记忆理解之前的对话背景 response conversation_with_summary.predict(input你好,我的问题还没有解决) print(response)三个 Memory 组件对比Memory 类型存储方式优点缺点ConversationBufferMemory完整历史信息无损对话长了 token 爆炸ConversationBufferWindowMemory最近 k 轮可控的 token 用量丢失早期上下文ConversationSummaryMemory压缩摘要兼顾长度和关键信息摘要可能遗漏细节12知识图谱总览下面这张图展示了 11 个示例之间的知识依赖关系。建议按编号顺序学习每一步都建立在前一步的基础之上。对话记忆文档与检索少样本学习使用嵌入FAISSDocument对象提示词工程01 PromptTemplate 模板基础02 ChatMessagePrompt 角色化03 partial 分步填充04 PipelinePrompt 多模板管道05 FewShotPrompt 案例教学06 SemanticSimilarity 语义选择器07 Document 结构化提取08 FAISS RAG 向量检索09 BufferMemory 全量记忆10 SummaryMemory 摘要记忆11 ConversationChain 完整对话链11 个示例的知识依赖关系图谱学习路线建议1提示词篇01-04掌握 LangChain 的提示词模板体系。这是所有后续内容的地基 —— 无论做什么 AI 应用都离不开给模型写好提示词。2少样本篇05-06学会用示例教模型你的期望格式和分类标准。引入了嵌入模型和向量数据库的概念。3检索篇07-08掌握 Document 对象和 FAISS 向量检索这是构建 RAG 应用的核心能力。4记忆篇09-11让模型记住历史对话。从最简单的全量记忆到摘要压缩最终组装成完整的对话链。