LangChain 工程实践:构建企业级 Prompt 模块的四种模式

72 阅读8分钟

LangChain 工程实践:构建企业级 Prompt 模块的四种模式

微信图片_20260726220056_1419_113.jpg

在构建基于大语言模型(LLM)的应用时,Prompt(提示词)的质量直接决定了模型输出的效果。一个结构混乱、意图模糊的 Prompt 不仅会导致回答质量低下,还可能引发安全漏洞。

LangChain 框架提供了一套系统化的 Prompt 管理方案,从基础的字符串模板到高级的少样本学习,再到声明式的链式调用(LCEL),为不同复杂度的业务场景提供了解决方案。本文将深入探讨四种核心的 Prompt 模式,并分析其在企业级开发中的最佳实践。

. 基础模式:PromptTemplate

PromptTemplate 是最基础的提示词模板,适用于处理简单的、单轮的文本生成任务。它的核心作用是将动态变量注入到预定义的文本结构中,实现 Prompt 的复用和标准化。

适用场景:

  1. 简单的文本补全或摘要任务。
  2. 不需要复杂上下文或角色设定的问答。

代码实践:

首先,我们封装一个模型实例化工具函数,以便后续复用。

import os 
from langchain_openai import ChatOpenAI 

def get_model():
""" 实例化 LLM 模型,统一配置入口 """ 

return ChatOpenAI( 
model='qwen-plus', 
base_url=os.environ.get('base_url', 'https://dashscope.aliyuncs.com/compatible-mode/v1'), 
api_key=os.environ.get('DASHSCOPE_API_KEY'), 
temperature=0,# 生产环境建议设为 0 以保证输出稳定性 
max_tokens=1024 )

接下来,使用 PromptTemplate 构建一个简单的问答流程:

import sys
import time
from langchain_core.prompts import PromptTemplate

def basic_prompt_template():
    model = get_model()
    
    # 1. 定义模板结构
    # 使用 {variable} 作为占位符
    template = "我简单讲解一下{question}, 不超过800个字"
    prompt_template = PromptTemplate.from_template(template)
    
    # 2. 填充变量,生成最终 Prompt
    final_prompt = prompt_template.format(question='大模型是什么')
    
    # 3. 调用模型并流式输出结果
    # 流式输出能显著降低用户感知的延迟,提升交互体验
    print("=== 开始流式输出 ===")
    for chunk in model.stream(final_prompt):
        if chunk.content:
            sys.stdout.write(chunk.content)
            sys.stdout.flush()
            time.sleep(0.03) # 模拟打字机效果,实际生产可去掉
    print("\n=== 输出结束 ===")

if __name__ == '__main__':
    basic_prompt_template()

工程要点:

流式输出(Streaming):在生产环境中,model.stream() 是提升用户体验的关键。它避免了长时间的白屏等待,让用户能即时看到模型“思考”的过程。

变量注入:.format() 方法简单直接,但要注意对用户输入进行清洗,防止提示词注入攻击。

. 进阶模式:ChatPromptTemplate

随着应用场景的复杂化,简单的文本模板已无法满足需求。ChatPromptTemplate 引入了“角色”的概念,通过模拟多轮对话的结构(System, Human, AI),能更精准地控制模型的行为和输出风格。

适用场景:

  1. 需要设定特定角色(如“资深律师”、“Python 架构师”)的场景。

  2. 多轮对话系统。

  3. 需要严格约束输出格式或长度的任务。
    代码实践:

from langchain_core.prompts import ChatPromptTemplate

def chat_prompt_template():
    model = get_model()
    
    # 1. 定义多角色消息模板
    # SystemMessage: 设定模型的人设和约束
    # HumanMessage: 用户的实际输入
    chat_template = ChatPromptTemplate.from_messages([
        ("system", "你是一个{role},回答问题必须简洁,不超过{max_words}个字。"),
        ("human", "{question}")
    ])
    
    # 2. 填充所有变量
    # format_messages 会返回一个包含 SystemMessage 和 HumanMessage 对象的列表
    final_prompt = chat_template.format_messages(
        role='Python 架构师',
        max_words=800,
        question='Python 里的装饰器是什么'
    )
    
    # 3. 调试:查看最终生成的消息结构
    # 在生产环境中,这一步有助于排查 Prompt 拼接错误
    print("=== 最终 Prompt 结构 ===")
    for msg in final_prompt:
        print(f"[{msg.type.upper()}]: {msg.content[:50]}...") # 只打印前50字
    
    # 4. 流式调用
    for chunk in model.stream(final_prompt):
        if chunk.content:
            print(chunk.content, end="", flush=True)
    print()

if __name__ == '__main__':
    chat_prompt_template()

工程要点:

角色分离:将“指令”(System)和“数据”(Human)分离,符合大模型的训练机理,能显著提高指令遵循能力。

调试友好:final_prompt 是一个消息对象列表,打印出来可以清晰地看到最终发送给模型的内容,便于排查问题。

. 高级模式:Few-Shot Prompting (少样本提示)

当模型面对复杂指令或特定格式要求时,单纯的文字描述往往不够准确。此时,通过“少样本提示”(Few-Shot Prompting),给模型展示几个“输入-输出”的范例,让它“照猫画虎”,是提高输出稳定性的杀手锏。

适用场景:

  1. 强制模型输出 JSON、XML 等结构化数据。
  2. 复杂的文本分类或情感分析。
  3. 风格迁移或特定文体的写作。
    代码实践: 这里我们结合 LCEL(LangChain Expression Language)管道模式,让代码更加简洁。
from langchain_core.output_parsers import StrOutputParser

def few_shot_prompting():
    model = get_model()
    
    # 1. 构建包含示例的 Prompt
    # 注意:在 f-string 或 template 中,如果需要输出大括号,需使用双大括号 {{}} 转义
    few_shot_template = ChatPromptTemplate.from_messages([
        ("system", "你是一个数据格式化助手。请严格模仿下面的范例,输出 JSON 格式。不要输出多余的废话。"),
        ("human", """
            范例:
            输入:苹果
            输出:{{"name": "苹果", "category": "水果"}}

            输入:冰箱
            输出:{{"name": "冰箱", "category": "家电"}}

            现在的输入:{content_to_format}
""")
    ])
    
    # 2. 使用 LCEL 构建链式调用
    # Prompt -> Model -> Parser
    # 这种声明式写法逻辑清晰,且易于维护
    chain = few_shot_template | model | StrOutputParser()
    
    # 3. 执行调用
    result = chain.invoke({"content_to_format": "大模型是什么"})
    
    print(f"=== 结构化输出结果 ===\n{result}")
    # 此时 result 已经是纯字符串,可直接用于 json.loads() 解析

if __name__ == '__main__':
    few_shot_prompting()
    

工程要点:

示例质量:Few-Shot 的效果取决于示例的质量。示例必须准确、无歧义,且覆盖边缘情况。

LCEL 管道:' | ' 操作符将 Prompt、Model 和 OutputParser 串联起来,形成了一条清晰的数据处理流水线。StrOutputParser 自动将模型返回的 AIMessage 对象转换为纯字符串,省去了手动提取 .content 的繁琐步骤。

总结与最佳实践

模式核心优势推荐场景
PromptTemplate简单、轻量简单的文本补全、摘要
ChatPromptTemplate支持角色设定、结构化聊天机器人、角色扮演、复杂指令
Few-Shot + LCEL输出稳定、格式可控结构化数据提取、复杂逻辑推理

以下是完整代码:

# 导包
import sys
import os
import time
from langchain_openai import ChatOpenAI
from langchain_core.prompts import PromptTemplate, ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser


# 1. 实例化模型
def get_model():
    model = ChatOpenAI(
        model='qwen-plus',
        base_url=os.environ.get('base_url', 'https://dashscope.aliyuncs.com/compatible-mode/v1'),
        api_key=os.environ.get('DASHSCOPE_API_KEY'),
        temperature=0,
        max_tokens=1024
    )
    return model


# 2. PromptTemplate 提示词模版
def prompt_template_exercise():

    # 实例化模型
    model = get_model()
    # =========================================================================

    # 创建(PromptTemplate)提示词模版
    # 1.先用 from_template() 获取要创建的提示词模版的要求
    # 2.然后用 PromptTemplate 创建提示词模版
    prompt_template = PromptTemplate.from_template('我简单讲解一下{question},不超过800个字')

    # 用 .format() 将模版中的变量值补充完整,生成最终要传给模型的提示词
    final_prompt = prompt_template.format(question='大模型是什么')

    # 将最终的提示词 传给模型 获取模型回复结果
    result = model.invoke(final_prompt)

    # 打印最终结果
    # print("==== PromptTemplate 模型回答 ====")
    # print(result.content)

    # 用流失输出的方式打印一下
    for chunk in model.stream(final_prompt):
        if chunk.content:
            sys.stdout.write(chunk.content)
            sys.stdout.flush()
            time.sleep(0.03)

    print('\n' + '====' * 10)


# 3.  ChatPromptTemplate 提示词模版
def chat_prompt_template_exercise():
    # 实例化模型
    model = get_model()

    # 创建(ChatPromptTemplate)提示词模版
    chat_prompt_template = ChatPromptTemplate.from_messages(
        [
            ('system', '你是一个{role},回答问题必须简洁,不超过{max_words}个字。'),
            ('human', '{question}')
        ]
    )

    # 用 .format_message() 将模版中的变量值补充完整,生成最终要传给模型的提示词
    final_prompt = chat_prompt_template.format_messages(
        role='Python 架构师',
        max_words=800,
        question='Python 里的装饰器是什么'
    )

    # 打印查看最终生成的提示词
    print("==== ChatPromptTemplate 提示词结构 ====")
    print(final_prompt)
    print()
    for msg in final_prompt:
        print(f'{msg.type}: {msg.content}')
    print('\n' + '====' * 10)

    # 将最终的提示词传入模型,获取模型生成的结果
    for chunk in model.stream(final_prompt):
        if chunk.content:
            sys.stdout.write(chunk.content)
            sys.stdout.flush()
            time.sleep(0.03)
    print('\n' + '====' * 10)


# 4. 使用 LCEL 管道(Prompt | Model | Parser)进行链式调用
def lcel_pipeline_exercise():

    # 实例化模型
    model = get_model()

    # 创建提示词
    prompt_template = PromptTemplate.from_template('我简单讲解一下{question},不超过100个字')

    # 构造链条
    chain = prompt_template | model | StrOutputParser()

    # 执行链条获取结果
    result = chain.invoke({"question": "大模型是什么"})

    print("==== LCEL 管道模型回答 ====")
    print(result)


# 5. (进阶)使用 FewShPromptTemplate (用少量样本提示模型)
def few_shots_prompt_template_exercise():
    # 实例化模型
    model = get_model()

    # 有时候大模型不听话,我们给它看几个例子,让它"照着格式写"
    # 比如,我们想让模型严格按 JSON 格式输出,就可以用这个。
    few_shots_prompt_template = ChatPromptTemplate.from_messages([
        ("system", "你是一个数据格式化助手。请严格模仿下面的范例,输出 JSON 格式。不要输出多余的废话。"),
        ("human", """范例:
            输入:苹果
            输出:{{"name": "苹果", "category": "水果"}}

            输入:冰箱
            输出:{{"name": "冰箱", "category": "家电"}}

            现在的输入:{content_to_format}""")
        ])

    # 构建链条
    chain = few_shots_prompt_template | model | StrOutputParser()

    # 执行链条获取结果
    result = chain.invoke({"content_to_format": "大模型是什么"})

    print(f"🚀 经过少样本训练后的输出结果(100% 遵循了 JSON 格式):\n{result}")


# 6. 测试函数
if __name__ == '__main__':
    prompt_template_exercise()
    chat_prompt_template_exercise()
    lcel_pipeline_exercise()
    few_shots_prompt_template_exercise()

在实际开发中,建议遵循以下原则:

优先使用 ChatPromptTemplate:即使是简单任务,使用 System+Human 的结构也能让 Prompt 更规范。

结构化输出必用 Few-Shot:如果需要 JSON 格式,不要只靠文字描述,一定要给示例。

拥抱 LCEL:链式调用让代码逻辑更清晰,且天然支持流式处理和异步调用,是未来的主流写法。

掌握这几种模式,你就掌握了与 LLM 高效沟通的钥匙。下一篇,我们将深入探讨 LangChain 的 Chain 模块,实现更复杂的业务逻辑编排。