第 3 课 / 共 7 课16 分钟2 个闯关

提示词模板与 few-shot

ChatPromptTemplate、写好 system 的五条、花括号转义的坑。

提示词是代码的一部分

新手写 AI 应用最常见的做法是用 f-string 拼提示词:

prompt = f"请把下面的文字翻译成英文:{text}"

能跑,但很快会出问题:提示词散落在代码各处、多轮对话的 system 消息没法复用、用户输入里带的花括号会炸、改一句话要翻遍全项目。

ChatPromptTemplate 就是把提示词变成一个可以复用、可以传参、可以测试的对象

两种写法

from langchain_core.prompts import ChatPromptTemplate

# 单条用户消息
p1 = ChatPromptTemplate.from_template("把下面内容翻译成{lang}:\n{text}")

# 带 system 的完整对话结构(更常用)
p2 = ChatPromptTemplate.from_messages([
    ("system", "你是一个专业翻译,只输出译文,不要任何解释和引号。"),
    ("user", "把下面内容翻译成{lang}:\n{text}"),
])

print(p2.invoke({"lang": "英文", "text": "今天天气不错"}))

先单独 invoke 一下模板,把填好的提示词打印出来看一眼——这是调试 AI 应用最有效的一招。很多"模型不听话"其实是提示词根本没填对。

写好 system 提示的五条

  1. 给角色:"你是一个有十年经验的 Python 面试官",比"你是助手"约束力强得多。
  2. 给规则,用否定式:"不要解释"、"不要输出 markdown 代码块"。模型很容易加一堆客套话,必须明确禁止。
  3. 给格式:想要什么形状,就把形状写出来。要 JSON 就把字段列清楚。
  4. 给例子:一两个示例(few-shot)比十句描述都管用,这是性价比最高的一招。
  5. 给边界:"如果资料里没有答案,就回答'我不知道',不要编造。"

few-shot:用例子教它

from langchain_core.prompts import ChatPromptTemplate, FewShotChatMessagePromptTemplate

examples = [
    {"input": "我要退货", "output": "售后"},
    {"input": "怎么开发票", "output": "财务"},
    {"input": "App 打不开", "output": "技术"},
]

example_prompt = ChatPromptTemplate.from_messages([
    ("user", "{input}"),
    ("assistant", "{output}"),
])

few_shot = FewShotChatMessagePromptTemplate(
    examples=examples,
    example_prompt=example_prompt,
)

final = ChatPromptTemplate.from_messages([
    ("system", "你是工单分类器。只输出分类名,不要其它任何字。"),
    few_shot,
    ("user", "{input}"),
])

chain = final | llm | StrOutputParser()
print(chain.invoke({"input": "付款失败了"}))    # 财务

它的实际效果,等价于把示例伪装成"之前的几轮对话"塞进上下文。模型看到自己"曾经"这么回答过,就会照着格式继续。

分类、抽取、格式转换这三类任务,加 few-shot 几乎总是能显著提升稳定性。

花括号的坑

模板里 {} 是占位符。如果你的提示词本身要出现花括号(比如要求输出 JSON),必须双写转义

ChatPromptTemplate.from_template(
    '按这个格式输出:{{"name": "...", "age": 0}}\n内容:{text}'
)

单写会报 KeyError: '"name"'。这是写 JSON 输出提示时百分百会踩的坑。

把提示词单独存放

项目大了之后,提示词应该从代码里拆出来:

# prompts.py
CLASSIFY_SYSTEM = """你是工单分类器。
可选分类:售后 / 财务 / 技术 / 其它。
只输出分类名本身,不要标点,不要解释。
无法判断时输出:其它"""

好处是改提示词不用碰业务逻辑,也方便做版本对比。提示词要像代码一样管理起来:改动要有理由,效果要能对比。

10 秒自测

想让模型输出 {"ok": true} 这样的字面内容,模板里该怎么写?

双写花括号:{{"ok": true}}。单写会被当成变量占位符。

广告位(未配置 AdSense,上线后在此展示)

动手闯关

读懂了不算会,写出来才算

0/2 已通过

闯关和判题完全免费,交错了不扣任何东西。卡住随时点「问 AI」,它能看到你正在写的代码。

关卡 01填空+12 点 · +15 XP

花括号怎么转义

想让提示词里出现字面的 `{"ok": true}`,在模板里应该怎么写这对花括号?直接把整段填进来: (提示:需要转义)

登录后闯关拿点数
关卡 02选择+10 点 · +15 XP

few-shot 为什么管用

在提示词里加入两三个"输入-输出"示例,本质上是在做什么?

  • 可能是多选,选错不扣点数,随便试。
登录后闯关拿点数

学完了?标记一下

标记完成会记进度、涨 20 XP,还会点亮连续学习天数。