前端转 Agent 开发 · 第三节:LangChain 提示词模板

🚀 前端转 Agent 开发 · 第三节:LangChain 提示词模板

📅 学习日期:2026-09-07(Day 03) 🧑‍💻 学习者:一名前端开发工程师 🎯 今日目标:搞懂 LangChain 的三大提示词模板 ------ PromptTemplate / FewShotPromptTemplate / ChatPromptTemplate


📖 写在前面

第一天我们裸调了 OpenAI 兼容 API 🤙,今天正式进入框架世界 ------ LangChain

先解决一个前端式灵魂拷问:为什么要用框架?不就是把第一天的代码包一层吗?

用 React 举例子 🤔:裸写 DOM 也能做页面,但 React 给你组件化、状态管理、生态。LangChain 之于大模型调用,就是这层关系 ------ 它把「提示词、模型、输出解析、链式调用」都标准化了。

今天的学习路线:

用前端思维先建立映射,后面看代码会非常丝滑:

前端世界 🌍 LangChain 世界 🦜
模板字符串 你好${name} PromptTemplate.from_template()
React 组件的 props format({name, gender})
Vue/React 的 <slot/> 插槽 MessagesPlaceholder("history")
中间件管道 / RxJS pipe `chain = template
封装好的请求层(axios 封装) Tongyi / ChatOpenAI 模型类

🧩 第一种:PromptTemplate(通用提示词模板)

适用场景:zero-shot ------ 不给示例,直接下指令,一次到位。

💻 示例代码

python 复制代码
from langchain_community.llms.tongyi import Tongyi
from langchain_core.prompts import PromptTemplate

# 🧩 第一步:定义模板,{name} {gender} 就是可以挖空填变量的"插槽"
prompts_template = PromptTemplate.from_template(
    "我的邻居姓{name},刚生了{gender},帮忙给起个名字,简单回答"
)

# 📝 方式一:format 手动填空,得到纯字符串
prompts_text = prompts_template.format(name='哈哈哈', gender='男')

model = Tongyi(model="qwen-max", api_key=key)  # 🔑 api-key 走环境变量更安全

# 写法一:正常调用(模板已经 format 成字符串了)
# res = model.invoke(input=prompts_text)
# print(res)

# ⛓️ 写法二:链式调用(推荐!模板和模型用管道符串起来)
chain = prompts_template | model
res = chain.invoke(input={"name": "哈哈哈", "gender": "男"})
print(res)

🖼️ 链式调用流程图

前端视角看 chain = prompts_template | model

😲 这不就是 promise.then() 或者 RxJS 的 pipe() 吗?!上游的输出是下游的输入,一管道捅到底。LangChain 里这个能力来自 Runnable 接口 ,所有组件都实现了它,所以都能用 | 串起来。

🤔 灵魂拷问:为什么不直接拼字符串?

python 复制代码
# 直接 f-string 不香吗?
prompt = f"我的邻居姓王,刚生了男,帮忙给起个名字,简单回答"

我第一反应也是这样 🙃,但认真想了下,用 PromptTemplate 有两个硬核理由:

  1. 🏭 工程化:模板集中管理、可复用、可测试。大型项目里提示词散落在各个 f-string 里 = 灾难现场,跟"组件里硬编码文案"一样难维护。
  2. ⛓️ 链式调用 :只有 PromptTemplate 这种 Runnable 对象才能用 | 接到模型上,纯字符串不行。这是为后续的 Chain、Agent 铺路。

💡 第二种:FewShotPromptTemplate(少样本模板)

适用场景:few-shot ------ 先给模型看几个"例题",再让它做"考题"。上节课接口文档问答里我们手动拼 examples,这次框架直接给你封装好了 🎁

💻 示例代码

python 复制代码
from langchain_community.llms.tongyi import Tongyi
from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate

# 📐 单条示例长什么样(也是一个小模板)
example_template = PromptTemplate.from_template("单词:{str},结果:{l}")

# 📚 示例数据:同一个词翻译成 4 种语言
examples = [
    {"str": "你好", "l": "hello"},        # 英语
    {"str": "你好", "l": "Bonjour"},      # 法语
    {"str": "你好", "l": "Здравствуй"},   # 俄语
    {"str": "你好", "l": "你好"},         # 中文
]

# 🎁 把前缀 + 示例集 + 后缀组装成完整 Few-shot 模板
prompts_templates = FewShotPromptTemplate(
    example_prompt=example_template,
    examples=examples,
    suffix="现在告诉我{word}翻译为{yy}是什么?",   # 📝 真正的"考题"
    prefix="按要求翻译单词,如以下示例:",          # 🎭 开场白
    input_variables=["word", "yy"]
)

# ⛓️ 模板本身也是 Runnable,可以直接 invoke 再转字符串
prompts = prompts_templates.invoke(input={"word": "上午好", "yy": "西班牙语"}).to_string()

model = Tongyi(model="qwen-max", api_key=key)
print(model.invoke(input=prompts))

🖼️ 组装结构图

🧠 我的代码理解

对着代码啃了半天,总结下来就是三块积木 🧱:

  • 📚 example_template + examples → 共同组成「例如」部分,相当于第一节课里手动拼的那段问答历史
  • 📝 suffix → 「我想要 」部分,input_variables 负责把变量动态填进去
  • 🎭 prefix → 开场定调,告诉模型"照着下面的例子干活"

💡 对比第一节课:当时我们手写 for 循环把 examples 塞进 messages,现在 FewShotPromptTemplate 一行配置搞定。框架的意义就是把脏活封装掉 🧹


💬 第三种:ChatPromptTemplate(对话模板)

适用场景:多轮对话、需要注入任意数量历史消息的场景。这是三种模板里最贴近 Agent 实战的一个 🔥

💻 示例代码

python 复制代码
# from langchain_community.chat_models.tongyi import ChatTongyi  # 😴 旧写法,见下方说明
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_openai import ChatOpenAI

# 💬 三段式:system 人设 + history 插槽 + human 当前问题
chat_prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "你是一个起名专家,会根据出生年月日来起名字,要求最多4个字,风格文艺"),
        MessagesPlaceholder("history"),  # 🕳️ 插槽!历史消息从这里注入
        ("human", "出生日期2026-5-26,请帮我起一个名字")
    ]
)

# 📜 历史会话(数量不限,动态传入)
message = [
    ("human", "2024-10-12"),
    ("ai", "子轩"),
    ("human", "2024-1-12"),
    ("ai", "璋宇"),
]

key = ""  # 🔑 api-key
# 🌐 base_url 必须指定!原因见下方"为什么要换包"
model = ChatOpenAI(model="qwen-max", api_key=key,
                   base_url="https://dashscope.aliyuncs.com/compatible-mode/v1")
# model = ChatTongyi(model="qwen-max", api_key=key)  # 备选:社区包写法

chain = chat_prompt | model  # ⛓️ 又见面了,管道符

res = chain.invoke({"history": message})
print(res.content)  # 📤 注意 chat 模型取 .content

🖼️ 消息组装结构图

😲 前端狂喜:MessagesPlaceholder 就是插槽!

看到 MessagesPlaceholder("history") 的瞬间我悟了 ------ 这不就是 Vue 的 <slot name="history"/> 吗?!

模板里挖一个具名坑位 🕳️,调用时 invoke({"history": message}) 往坑里塞任意长度的内容。历史消息可以是 2 条也可以是 200 条,模板本身完全不用改。跟前端"组件不变、内容由插槽注入"是同一个设计哲学 ✨

📦 为什么要换包?社区包停止维护了!

注意上面代码里构建模型的包变了:langchain_communitylangchain_openai

  • 🪦 langchain 的社区大包 langchain_community 已经在 2026 年 5 月停止维护了,官方建议迁移到各个独立的细分包
  • 🌐 换成 ChatOpenAI 后多了一个 base_url 参数,原因是:ChatOpenAI 默认请求 OpenAI 官方 https://api.openai.com/v1
  • 🔑 我的 key 是阿里云百炼的,必须指定兼容端点,否则请求就飘到 OpenAI 去了(然后报 401,钱都没地方扣 🤣)

💡 跟第一节裸调 API 时传 base_url 是同一个道理 ------ OpenAI 协议已成事实标准 ,各家模型厂商都提供兼容端点,换个 base_url 就能无缝切换供应商。前端版理解:axios 不换,换 baseURL 而已 😎


📝 今日勘误(自己踩过的坑)

❌ 原笔记写法 ✅ 正确写法 说明
key = "" //api-key key = "" # api-key 又双叒用 JS 注释了,Python 是 # 😅
model="qwen3.8-27b" 以官方文档为准(如 qwen-maxqwen-plus 模型名要去百炼控制台核对
print(res)(chat 模型) print(res.content) Chat 模型返回的是消息对象,内容在 .content

🧠 补充:普通 Tongyi(LLM)直接 print(res) 就行,但 ChatOpenAI(Chat 模型)要取 .content。两类模型返回结构不一样,别搞混。


🗺️ 明日计划

  • 📤 学习 OutputParser(输出解析器),让模型返回结构化 JSON,方便前端直接渲染
  • ⛓️ 深入 Runnable 接口:| 背后的运行机制、RunnableParallel 并行链
  • 🧠 尝试给 ChatPromptTemplate 接上 Memory(记忆),让对话真正连续起来
  • 🔧 用三大模板重构第一节的"接口文档问答",看看代码能省多少

🎯 今日总结

📌 一句话 :三大模板 = 三种"组装 Prompt 的姿势" ------ PromptTemplate 管填空 (zero-shot),FewShotPromptTemplate 管举例 (few-shot),ChatPromptTemplate 管对话 (多轮 + 历史插槽);而 | 管道符把它们和模型串成流水线。

markdown 复制代码
   🧩 填空  +  💡 举例  +  💬 对话  +  ⛓️ 管道
        =  有模有样的 LangChain 开发 🦜

第三天,从"裸调 API"升级到"框架化思维" ✅ 距离真正的 Agent,又近了一步...... 🌱

相关推荐
Cache技术分享1 小时前
516. Java 方法句柄 - 转换(进阶篇·下)
前端·后端
妙码生花1 小时前
全网 8k star 的 BuildAdmin 正式发布 Golang 版本,这次我们在CRUD赛道杀死了比赛。
前端·后端·ai编程
写代码像蔡徐抻1 小时前
三年了,AI为何还没有抢走程序员饭碗?
前端·后端·面试
梦曦i1 小时前
unix-router v0.1.0 首发:uni-app x 的 vue-router 风格路由库
前端·uni-app
Linsk1 小时前
妙用:focus解决0到auto高度过渡的边界场景
前端·css
零域码客1 小时前
一文掌握 jQuery + Flask 全栈核心知识点(前端交互 + 后端接口 + 前后端联调)
前端·python·ajax·flask·jquery·前后端联调·web全栈
এ慕ོ冬℘゜1 小时前
html理论
前端·html
IT_陈寒1 小时前
Java的HashMap竟然不是线程安全的,现在才知道!
前端·人工智能·后端
IT_陈寒1 小时前
React hooks闭包陷阱让我加了一宿班
前端·人工智能·后端