当前位置: 首页 > news >正文

LangChain入门:Prompt模板与结构化输出详解

从手写提示词到结构化数据,一文搞定LangChain核心输出解析


📌 引言

在开发大模型应用时,我们常常面临两个核心问题:

  1. 如何高效地组织和管理提示词(Prompt)—— 避免代码中到处拼接字符串

  2. 如何让模型返回程序可直接使用的结构化数据—— 而不是自然语言段落

LangChain 提供了完善的解决方案:PromptTemplate系列管理输入,OutputParser系列处理输出。本文将带你从零开始,掌握这两大模块,并完成多个实战案例。


一、Prompt 基础与模板

1.1 什么是 Prompt?

Prompt就是给模型的指令。简单示例:

python

"请用中文介绍一下LangChain。"

但在实际项目中,Prompt 往往包含角色设定、任务描述、输入数据和约束条件:

python system = "你是一名资深技术顾问,擅长用通俗语言解释复杂概念。" human = "请向非技术人员介绍LangChain,字数控制在200字以内。"

如果每次都在代码中拼接,会产生大量重复和易错代码。Prompt 模板将固定部分与变量分离,提高复用性和可维护性。

1.2 PromptTemplate(纯文本模板)

适用于不需要区分系统/用户角色的简单文本任务。

python from langchain_core.prompts import PromptTemplate template = PromptTemplate.from_template( "请为产品'{product_name}'写一句广告语,突出'{feature}'。" ) prompt = template.invoke({"product_name": "智能手环", "feature": "超长续航"}) print(prompt) # 输出:请为产品'智能手环'写一句广告语,突出'超长续航'。

1.3 ChatPromptTemplate(聊天消息模板)

推荐使用,因为它可以构建结构化的消息列表(SystemMessage / HumanMessage / AIMessage),更符合现代对话模型的输入习惯。

python from langchain_core.prompts import ChatPromptTemplate chat_template = ChatPromptTemplate.from_messages([ ("system", "你是一位{role},回答要简洁专业。"), ("human", "{question}") ]) prompt_value = chat_template.invoke({ "role": "AI产品经理", "question": "什么是RAG?" }) # 内部会生成 [SystemMessage, HumanMessage]
模板类型输出形式适用场景
PromptTemplate纯字符串简单文本生成,无角色区分
ChatPromptTemplate消息列表聊天、Agent、多轮对话

二、Prompt 编写最佳实践

掌握以下四个原则,就能写出高质量的 Prompt:

  1. 明确角色—— 让模型以特定身份思考

  2. 明确任务—— 说清楚要做什么

  3. 明确约束—— 限制输出格式、字数、风格

  4. 给出输入字段—— 让模型清楚每个变量的含义


三、实战案例(Prompt 篇)

案例1:商品文案生成器

根据商品信息自动生成电商文案。

代码01_product_copywriter.py

python from langchain_core.prompts import ChatPromptTemplate from utils.model_factory import get_deepSeek_model model = get_deepSeek_model() template = ChatPromptTemplate.from_messages([ ("system", "你是一名资深电商文案写手,擅长用吸引人的语言描述产品。"), ("human", """ 请为以下商品撰写一段电商文案(150字以内),包含标题和卖点。 商品名称:{name} 核心卖点:{feature} 适用人群:{target} """) ]) prompt = template.invoke({ "name": "智能保温杯", "feature": "24小时保温,智能测温,健康提醒", "target": "注重健康的办公族" }) response = model.invoke(prompt) print(response.content)

案例2:学习计划生成器

根据学习目标生成分阶段计划。

代码02_study_plan.py

python from langchain_core.prompts import ChatPromptTemplate from utils.model_factory import get_deepSeek_model model = get_deepSeek_model() template = ChatPromptTemplate.from_messages([ ("system", "你是一位资深学习规划师。"), ("human", """ 为以下学习目标制定一份为期{days}天的学习计划。 目标:{goal} 当前水平:{level} 每日可用时间:{hours}小时 请按阶段列出每日任务,并给出学习建议。 """) ]) prompt = template.invoke({ "goal": "从零开始学习Python数据分析", "days": 30, "level": "零基础", "hours": 2 }) response = model.invoke(prompt) print(response.content)

案例3:客服回复生成器

模拟根据用户问题和订单信息生成回复。

代码03_customer_reply.py

python from langchain_core.prompts import ChatPromptTemplate from utils.model_factory import get_deepSeek_model model = get_deepSeek_model() template = ChatPromptTemplate.from_messages([ ("system", "你是一名专业客服,回复要礼貌且解决问题。"), ("human", """ 用户问题:{question} 订单状态:{status} 物流信息:{logistics} 请生成一段客服回复,给出明确解决方案。 """) ]) prompt = template.invoke({ "question": "我的快递显示签收但我没收到", "status": "已签收", "logistics": "2025-01-15 10:00 已由门卫代收" }) response = model.invoke(prompt) print(response.content)

四、MessagesPlaceholder:插入多轮对话历史

在构建聊天应用时,经常需要将历史消息插入到模板中。MessagesPlaceholder专门用于此。

python from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder prompt = ChatPromptTemplate.from_messages([ ("system", "你是一个乐于助人的AI助手。"), MessagesPlaceholder("history", optional=True, n_messages=4), # 最多保留4条 ("human", "{question}") ]) history = [ ("human", "我叫小明"), ("ai", "你好小明,有什么可以帮你?"), ("human", "我喜欢Python"), ("ai", "Python是很好的语言!") ] prompt_value = prompt.invoke({ "history": history, "question": "我刚才说了什么?" }) # 实际只会插入最近4条历史消息(如果超过)
参数说明
variable_name输入变量名
optional是否必须传入(默认False)
n_messages最多保留最近几条消息

五、结构化输出:让程序读懂模型结果

模型返回的自然语言虽然易读,但程序难以直接处理。我们需要让模型输出JSON或其他结构化格式。

5.1 StrOutputParser:简单的字符串提取

如果只想要纯文本内容,StrOutputParser可以将AIMessage转为普通字符串,并支持管道组合。

python from langchain_core.output_parsers import StrOutputParser from langchain_core.prompts import ChatPromptTemplate model = get_deepSeek_model() parser = StrOutputParser() chain = ChatPromptTemplate.from_template("翻译成中文:{text}") | model | parser result = chain.invoke({"text": "LangChain is awesome!"}) print(result) # 直接打印字符串

为什么不用response.content
在管道(|)中,每个组件必须是Runnable,而.content是属性,不是 Runnable。StrOutputParser正是为了合规接入管道。


5.2 Pydantic 定义输出结构

使用Pydantic声明期望的字段及类型,让模型按此格式返回。

python from pydantic import BaseModel, Field from typing import Literal class ResumeInfo(BaseModel): name: str = Field(description="候选人姓名") years_of_experience: int = Field(description="工作年限") skills: list[str] = Field(description="掌握的技术技能") target_position: str = Field(description="目标岗位")

5.3 PydanticOutputParser:手动解析

该解析器会根据 Pydantic 模型生成格式说明(get_format_instructions())并嵌入 Prompt,最后将模型输出解析成对象。

案例:简历信息抽取 (02_resume_extractor.py)

python from langchain_core.output_parsers import PydanticOutputParser from langchain_core.prompts import ChatPromptTemplate from pydantic import BaseModel, Field from utils.model_factory import get_deepSeek_model model = get_deepSeek_model() class ResumeInfo(BaseModel): name: str = Field(description="姓名") years_of_experience: int = Field(description="工作年限") skills: list[str] = Field(description="掌握的技术技能") target_position: str = Field(description="目标岗位") parser = PydanticOutputParser(pydantic_object=ResumeInfo) format_instructions = parser.get_format_instructions() template = ChatPromptTemplate.from_messages([ ("system", "你是一名招聘分析助手。\n{format_instructions}"), ("human", "{resume_content}") ]) resume_text = """ 我叫张三,工作10年,擅长Python、LangChain、FastAPI,想找智能体开发岗位。 """ prompt = template.invoke({ "format_instructions": format_instructions, "resume_content": resume_text }) response = model.invoke(prompt) result = parser.invoke(response) print(result.name) # 张三 print(result.years_of_experience) # 10 print(result.skills) # ['Python', 'LangChain', 'FastAPI'] print(result.target_position) # 智能体开发

5.4 with_structured_output:更简洁的方式

如果模型服务支持(如 OpenAI、DeepSeek 的 JSON 模式),可以直接在模型上绑定输出结构。

python structured_model = model.with_structured_output(ResumeInfo, method="json_mode") result = structured_model.invoke("从简历中提取信息:...") # 返回的 result 就是 ResumeInfo 实例

注意:使用 DeepSeek 时需指定method="json_mode",否则会报错。


案例:商品评论分析 (03_review_analyzer.py)
python from typing import Literal from langchain_core.prompts import ChatPromptTemplate from pydantic import BaseModel, Field from utils.model_factory import get_deepSeek_model class ReviewAnalysis(BaseModel): sentiment: Literal["正面", "负面", "中性"] = Field(description="情感倾向") keywords: list[str] = Field(description="关键词") summary: str = Field(description="评论总结") needs_reply: bool = Field(description="是否需要商家回复") model = get_deepSeek_model() structured_model = model.with_structured_output(ReviewAnalysis, method="json_mode") template = ChatPromptTemplate.from_messages([ ("system", "你是评论分析专家,严格按JSON格式输出。"), ("human", "分析评论:{review}") ]) prompt = template.invoke({ "review": "鼠标手感不错,也很安静,但是用了两周滚轮就有异响。" }) result = structured_model.invoke(prompt) print(result.sentiment) # 负面 print(result.keywords) # ['手感', '安静', '滚轮异响'] print(result.summary) # 用户认可手感但反映滚轮质量问题 print(result.needs_reply)# True

案例:工单分类 (04_ticket_classifier.py)
python from typing import Literal from langchain_core.output_parsers import PydanticOutputParser from langchain_core.prompts import ChatPromptTemplate from pydantic import BaseModel, Field from utils.model_factory import get_deepSeek_model class TicketResult(BaseModel): category: Literal["订单", "物流", "退款", "产品", "其他"] = Field(description="工单分类") priority: Literal["低", "中", "高"] = Field(description="优先级") reason: str = Field(description="分类原因") parser = PydanticOutputParser(pydantic_object=TicketResult) format_instructions = parser.get_format_instructions() template = ChatPromptTemplate.from_messages([ ("system", "客服工单分类助手。\n{format_instructions}"), ("human", "{question}") ]) prompt = template.invoke({ "format_instructions": format_instructions, "question": "订单显示已签收,但我没收到商品,请处理。" }) response = model.invoke(prompt) result = parser.invoke(response) print(result.category) # 物流 print(result.priority) # 高 if result.priority == "高": print("立即转人工!")

六、处理解析错误

模型输出不稳定时,可能返回不符合结构的内容。应捕获OutputParserException或通用异常。

python from langchain_core.exceptions import OutputParserException try: result = parser.parse(response.content) except OutputParserException as e: print("解析失败,原始输出:", response.content) print("错误信息:", e) # 可进行重试、日志记录或人工干预

七、结构化方式对比

方式优点缺点适用场景
StrOutputParser简单、管道兼容仅返回字符串摘要、翻译、问答
PydanticOutputParser清晰、可自定义需手动拼接格式说明需要精细控制解析过程
with_structured_output代码简洁依赖模型服务支持现代大模型(OpenAI/DeepSeek等)

建议:先掌握PydanticOutputParser理解原理,实际项目优先使用with_structured_output


八、工具函数封装:减少重复代码

为了让案例更干净,我们将模型初始化抽到utils/model_factory.py

python # utils/model_factory.py from langchain_openai import ChatOpenAI import os def get_deepSeek_model(temperature=0): return ChatOpenAI( model="deepseek-chat", api_key=os.getenv("DEEPSEEK_API_KEY"), base_url="https://api.deepseek.com/v1", temperature=temperature )

这样每个案例只需导入get_deepSeek_model即可。


九、常见问题解答

Q1:Prompt 越长越好吗?
不是。应清晰简洁,避免过多无关要求,否则模型可能顾此失彼。

Q2:模型为什么不完全按指令输出?
大模型是概率性生成,不能保证100%服从。若输出格式关键,需配合结构化输出和程序校验。

Q3:PromptTemplatevsChatPromptTemplate
如果模型支持多角色消息(System/Human),优先用ChatPromptTemplate,本课程所有案例均使用它。

Q4:为什么temperature=0
对于信息抽取、分类等确定性任务,温度设为0可获得最稳定输出。

Q5:with_structured_output没看到 JSON 字符串?
因为 LangChain 内部已将 JSON 自动解析为 Pydantic 对象,你拿到的直接就是模型实例。


📝 总结

通过本文,你学会了:

  • 使用PromptTemplate/ChatPromptTemplate管理提示词

  • 编写高质量 Prompt 的四个原则

  • 三个业务案例(文案、计划、客服)实战

  • MessagesPlaceholder处理聊天历史

  • 三种输出解析器:StrOutputParserPydanticOutputParserwith_structured_output

  • 结构化输出案例:简历抽取、评论分析、工单分类

  • 处理解析错误和异常

掌握这些技能,你就能构建出既易于维护又能与业务系统无缝对接的 LLM 应用。

http://www.jsqmd.com/news/1255965/

相关文章:

  • 厦门海沧区蒂芙尼钻石首饰回收哪里靠谱?正规门店变现指南 - 全国二奢机构参考
  • 如何成为黑客:(Kali配置与DVWA渗透实战全攻略)
  • VLC播放器美化终极指南:5分钟打造你的专属视频播放界面
  • 2026年7月发布三菱重工空调售后服务电话24小时全新专属热线升级公示最新公告 - 故障代码查询
  • 实战一:内存硬限制与 OOM Killer(终极整合版)
  • 如何简单高效地恢复微信聊天记录:终极数据解密指南
  • 双通道同步采样ADC评估实战:从硬件设计到性能验证
  • FSDP技术解析:从原理到PyTorch实战优化
  • 国内钢结构公司排行 破解选品迷茫 适配各类项目 - 信息热点
  • 技术写作与知识沉淀方法论:从信息碎片到个人品牌的系统化构建
  • 终极指南:如何用Wand-Enhancer免费优化你的WeMod游戏体验
  • 告别销售过程黑盒,灵听AI录音工牌,助力服务过程留痕 - 行业产品测评专家
  • 贵阳GEO优化服务商推荐:2026年服务商TOP3推荐与对比 - GEORANK
  • 通用 Skill 开发实战教程:从需求到落地
  • Unity开放世界实时全局光照分块烘焙策略与性能优化实践
  • OpenAI API集成实战:构建AI辅助开发环境ADE完整指南
  • Linux 零基础教程 RPM YUM 52-54
  • Mysql索引二(白话文)
  • LangGraph开发环境搭建:从下载Python到可视化调试的保姆级教程
  • ks集群部署()(centos)
  • WarcraftHelper终极指南:如何彻底优化你的魔兽争霸III游戏体验
  • 重庆定制游旅行社哪家好?重庆雾猫旅游有限公司深度定制服务解析 - 信息热点
  • 2026 徐州正规代理记账公司怎么选?闲谈本土高口碑财税公司解析 - 品牌智鉴榜
  • 酒店客服聊天机器人:基于深度学习的NLP实践
  • 你还在手动试错提示词?揭秘LLM时代创意发散新范式:语义熵值评估+跨模态联想图谱(仅开放首批50份)
  • ASL-QPSO-SVM时序预测算法原理与MATLAB实现
  • 合肥庐阳哪家回收钻石包包靠谱?持证鉴定门店简单辨别方法 - 生活时报
  • 终极Zotero Style插件指南:3步打造专业文献管理界面
  • 2026 靠谱3K平纹碳纤维管厂家|精密加工品质稳定 采购避坑干货 - 商业新知
  • 番茄小说下载器:一站式数字阅读解决方案终极指南