首页
看点啥
插画图片
首页 看点啥 Prompt 的组织管理

Prompt 的组织管理

2026-07-03 0

Prompt 是 Agent 的任务说明书。它负责把模型需要遵守的规则、当前用户输入、上下文资料和输出要求组织清楚。

Prompt 组织管理

这一篇主要看这些内容:

PromptTemplate
  -> 模块化拆分
  -> partial 预填变量
  -> Message / ChatPromptTemplate
  -> MessagesPlaceholder
  -> FewShotPromptTemplate
  -> ExampleSelector

先记住一句话:PromptTemplate 管字符串,ChatPromptTemplate 管消息数组。

Message 是什么

调用聊天模型时,通常不是只传一段孤立文本,而是传一组带角色的消息。

角色的意义是让模型分清楚:哪些是长期规则,哪些是本轮用户问题,哪些是历史回答,哪些是工具结果。

常见角色:

所以 Message 可以理解成 Agent 的上下文格式。PromptTemplate 先把变量整理成内容,ChatPromptTemplate 再把这些内容分配到不同角色里。

PromptTemplate

PromptTemplate{变量名} 占位,再用 format() 填充变量。

下面用一个很轻的 NBA 案例:给詹姆斯写一段球员观察稿

from langchain_core.prompts import PromptTemplate
observation_template = PromptTemplate.from_template(
    """
你是一位{role},回答风格:{tone}。
面向读者:{audience}。请写一段 NBA 球员观察:{player}观察主题:
{topic}比赛背景:
{game_context}分析角度:
{angle}输出要求:
1. 先给出一句核心判断。
2. 再展开 2~3 个观察点。
3. 不要编造具体数据。
4. 控制在 {word_count_hint} 字左右。
""".strip()
)prompt = observation_template.format(
    role="懂 NBA 的内容作者",
    tone="清楚、克制、有球迷视角",
    audience="喜欢詹姆斯的普通读者",
    player="勒布朗·詹姆斯",
    topic="老将核心如何影响比赛节奏",
    game_context="不引用实时比赛数据,只基于常见比赛观察来写。",
    angle="组织进攻、转换节奏、关键回合选择",
    word_count_hint="250",
)print(prompt)

这段代码里有三个关键点:

这样比手写字符串拼接清楚:

这里的重点不是语法,而是思路:把会变化的内容变成参数,把不变的任务结构留在模板里。

模块化拆分

复杂 Prompt 不要一直往一个大字符串里塞,应该拆成多个小模块,再汇总成最终 Prompt。

在 Python 版里,可以直接用多个 PromptTemplate 手动组合。重点是掌握这个思路:拆模块,再汇总

from langchain_core.prompts import PromptTemplate
# 模型身份和回答风格
persona_prompt = PromptTemplate.from_template(
    """你是一位{role},回答风格:{tone}。
面向读者:{audience}。"""
)# 本次 NBA 观察稿的资料
context_prompt = PromptTemplate.from_template(
    """【观察资料】
球员:{player}
主题:{topic}
比赛背景:{game_context}
分析角度:{angle}"""
)# 具体写作任务
task_prompt = PromptTemplate.from_template(
    """请写一段 NBA 球员观察稿:
1. 先给出核心判断。
2. 再展开 2~3 个观察点。
3. 不要编造具体数据。"""
)# 输出格式
format_prompt = PromptTemplate.from_template(
    """输出要求:
- 篇幅:约 {word_count_hint} 字。
- 语气:{tone_constraint}。
- 直接输出正文,不要列太多术语。"""
)# 最终汇总
final_prompt = PromptTemplate.from_template(
    """{persona_block}{context_block}{task_block}{format_block}"""
)
def format_player_observation(data: dict[str, str]) -> str:
    """把拆开的 Prompt 模块合并成最终提示词。"""    return final_prompt.format(
        persona_block=persona_prompt.format(**data),
        context_block=context_prompt.format(**data),
        task_block=task_prompt.format(),
        format_block=format_prompt.format(**data),
    )

这段代码里有几个名字容易混:

重点不是一定要用某个类,而是 Prompt 设计上不要把所有内容堆在一个大字符串里。

partial 预填变量

有些变量每次都一样,比如作者身份、读者身份、输出字数、语气要求。每次 format() 都传一遍会很重复,多余。

partial() 可以先固定一部分变量。

persona_prompt_with_defaults = persona_prompt.partial(
    role="懂 NBA 的内容作者",
    tone="清楚、克制、有球迷视角",
    audience="喜欢詹姆斯的普通读者",
)format_prompt_with_defaults = format_prompt.partial(
    word_count_hint="250",
    tone_constraint="像赛后短评,不像数据报告",
)
def format_player_observation_with_defaults(player_data: dict[str, str]) -> str:
    """只传本次变化的球员观察资料,稳定规则交给 partial 预填。"""    return final_prompt.format(
        persona_block=persona_prompt_with_defaults.format(),
        context_block=context_prompt.format(**player_data),
        task_block=task_prompt.format(),
        format_block=format_prompt_with_defaults.format(),
    )
james_prompt = format_player_observation_with_defaults(
    {
        "player": "勒布朗·詹姆斯",
        "topic": "老将核心如何影响比赛节奏",
        "game_context": "不引用实时比赛数据,只基于常见比赛观察来写。",
        "angle": "组织进攻、转换节奏、关键回合选择",
    }
)

这段代码要看懂两步:

partial() 的价值不是“少写几行代码”,而是把稳定规则和动态输入分开:

稳定规则:角色、语气、读者、输出格式
动态输入:球员、主题、比赛背景、分析角度

ChatPromptTemplate

PromptTemplate 生成字符串,但聊天模型更适合接收消息数组。

ChatPromptTemplate 用来给 Prompt 分配消息角色。

from langchain_core.prompts import ChatPromptTemplate
chat_prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "{persona_block}"),
        (
            "human",
            """观察资料:
{context_block}任务:
{task_block}输出格式:
{format_block}""",
        ),
    ]
)messages = chat_prompt.format_messages(
    persona_block="你是一位懂 NBA 的内容作者,回答要克制、准确。",
    context_block="球员:勒布朗·詹姆斯n主题:老将核心如何影响比赛节奏n背景:不引用实时比赛数据。",
    task_block="写一段 NBA 球员观察稿,重点看组织进攻、转换节奏、关键回合选择。",
    format_block="输出 250 字以内中文段落。",
)print(messages)

这段代码里:

这里的重点是:systemhuman 不要混在一起。

消息角色类

除了 ("system", "...") 这种 tuple 写法,也可以用角色模板类。

from langchain_core.prompts import (
    ChatPromptTemplate,
    HumanMessagePromptTemplate,
    SystemMessagePromptTemplate,
)
persona_prompt = SystemMessagePromptTemplate.from_template(
    "你是一位{role},回答风格:{tone}。"
)context_prompt = HumanMessagePromptTemplate.from_template(
    """【观察资料】
球员:{player}
主题:{topic}
比赛背景:{game_context}
分析角度:{angle}"""
)task_prompt = HumanMessagePromptTemplate.from_template(
    "请基于资料写一段 NBA 球员观察稿,注意不要编造具体数据。"
)intro_chat_prompt = ChatPromptTemplate.from_messages(
    [persona_prompt, context_prompt, task_prompt]
)messages = intro_chat_prompt.format_messages(
    role="懂 NBA 的内容作者",
    tone="清楚、克制、有球迷视角",
    player="勒布朗·詹姆斯",
    topic="阅读比赛的经验价值",
    game_context="不引用实时比赛数据。",
    angle="防守选择、传球路线、关键回合判断",
)

这段代码和 tuple 写法做的是同一件事,只是拆得更明确:

适合这样理解:

PromptTemplate:生成字符串
SystemMessagePromptTemplate:生成 system 消息
HumanMessagePromptTemplate:生成 human 消息
ChatPromptTemplate:把多条消息模板组装起来

MessagesPlaceholder

MessagesPlaceholder 是“消息插槽”。

它不是普通字符串占位符,而是给一组历史消息留位置。

from langchain_core.messages import AIMessage, HumanMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "你是一名懂 NBA 的内容作者,回答要结合历史对话,避免重复。",
        ),
        MessagesPlaceholder("history"),
        ("human", "这是用户本轮的新问题:{current_input}"),
    ]
)messages = prompt.format_messages(
    history=[
        HumanMessage(content="这篇观察稿不要编造实时数据。"),
        AIMessage(content="明白,只基于常见比赛观察来写。"),
    ],
    current_input="写一段詹姆斯如何影响比赛节奏的观察。",
)

这段代码里最重要的是 MessagesPlaceholder("history")

注意:

FewShotPromptTemplate

Few-shot 的意思是“给模型几个例子,让它照着格式回答”。

from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
examples = [
    {
        "player": "勒布朗·詹姆斯",
        "answer": "詹姆斯的价值不只在得分,还在于他能用阅读比赛的能力影响队友站位和进攻节奏。",
    },
    {
        "player": "斯蒂芬·库里",
        "answer": "库里的威胁不只来自持球投篮,他的无球跑动也会持续拉扯防守阵型。",
    },
]example_prompt = PromptTemplate.from_template(
    "球员:{player}n解释:{answer}"
)prompt = FewShotPromptTemplate(
    examples=examples,
    example_prompt=example_prompt,
    prefix="请参考下面的例子,用同样风格写 NBA 球员观察。",
    suffix="球员:{input}n解释:",
    input_variables=["input"],
)formatted = prompt.format(input="凯文·杜兰特")
print(formatted)

这段代码里:

Few-shot 适合用在:

ExampleSelector

如果例子很多,不一定每次都全部塞给模型。

ExampleSelector 的作用是:根据当前输入,挑几个最合适的例子放进 Prompt。

这里先把名字分清楚:

LengthBasedExampleSelector

按长度控制例子数量,避免 Prompt 太长。

from langchain_core.example_selectors import LengthBasedExampleSelector
from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
examples = [
    {"player": "勒布朗·詹姆斯", "answer": "重点看阅读比赛、组织进攻和关键回合选择。"},
    {"player": "斯蒂芬·库里", "answer": "重点看无球牵制、投篮威胁和空间影响。"},
    {"player": "尼古拉·约基奇", "answer": "重点看高位策应、传球视野和进攻中轴价值。"},
    {"player": "扬尼斯·阿德托昆博", "answer": "重点看冲击篮筐、转换进攻和防守覆盖。"},
]example_prompt = PromptTemplate.from_template(
    "球员:{player}n解释:{answer}"
)example_selector = LengthBasedExampleSelector(
    examples=examples,
    example_prompt=example_prompt,
    max_length=120,
)prompt = FewShotPromptTemplate(
    example_selector=example_selector,
    example_prompt=example_prompt,
    prefix="请用同样风格写 NBA 球员观察。",
    suffix="球员:{input}n解释:",
    input_variables=["input"],
)

这个选择器只关心长度,不关心语义相似度。

SemanticSimilarityExampleSelector

语义选择器会根据当前输入,挑语义最接近的例子。

这一块需要向量模型和向量库,依赖比前面更重,先了解用途即可:

用户输入:Agent 怎么查外部资料?
选择器可能挑中:RAG、Retriever、VectorStore 相关例子

适合用在:

小结

这一篇要记住几个核心点:

  1. PromptTemplate 负责字符串模板。
  2. 模块化拆分能让 Prompt 更容易维护。
  3. partial() 可以预填稳定变量。
  4. ChatPromptTemplate 负责生成带角色的消息数组。
  5. MessagesPlaceholder 给历史消息留位置。
  6. FewShotPromptTemplate 让模型照着例子回答。
  7. ExampleSelector 负责从很多例子里挑合适的例子。
喜欢(0)

上一篇

Mistral OCR 4 – Mistral AI发布的文档理解与OCR解析模型

Mistral OCR 4 – Mistral AI发布的文档理解与OCR解析模型

下一篇

Agent 跑了 7 天:团队欠下了这 5 笔运维债

Agent 跑了 7 天:团队欠下了这 5 笔运维债
猜你喜欢