- 人工智能
- AI Agent
- Agent 框架
- 大模型
- 工具调用
- RAG
- 提示工程
- 强化学习
【免费下载链接】agent-core
openJiuwen agent-core可提供AI Agent开发、运行、调优与演进相关的全套SDK能力
PromptTemplate是 openJiuwen agent-core 提供的提示词模板类,用于定义带占位符的提示词内容(支持字符串与消息列表两种形态),并通过format()与to_messages()完成占位符替换与消息化转换。本文以该类的官方 API 文档为主体,结合仓库源码(openjiuwen/core/foundation/prompt/template.py、assemble/assembler.py)与单元测试(tests/unit_tests/core/foundation/prompt/test_template_assemble.py)深入剖析其参数、方法、底层组装链路与实际应用场景,帮助你直接在生产代码中编写、填充和复用提示词模板。
一、PromptTemplate 类总览
PromptTemplate继承自 pydantic 的BaseModel,是一个可插值(interpolatable)的提示词模板,支持以字符串或BaseMessage列表作为模板内容,并内置占位符替换(format)与消息转换(to_messages)能力。类定义位于 template.py:
class PromptTemplate(BaseModel): name: str = Field(default="") content: Union[str, List[BaseMessage]] = Field(default="") placeholder_prefix: str = Field(default="{{") placeholder_suffix: str = Field(default="}}")参数说明
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
content | str或List[BaseMessage] | "" | 模板内容,可以是纯文本,也可以是消息列表;必选核心参数 |
name | str | "" | 模板名称,便于在仓库中按名称注册、管理与检索 |
placeholder_prefix | str | "{{" | 占位符左边界 |
placeholder_suffix | str | "}}" | 占位符右边界 |
placeholder_prefix/placeholder_suffix共同决定占位符的识别规则。注册模板时占位符边界可以自定义传入(见下文自定义占位符示例),这为对接不同来源的既有模板(如${...}$、{...}风格)提供了便利。
二、实例化:两种 content 形态与自定义占位符
1. 字符串模板(str类型)
content为一段文本,用双花括号{{...}}标记待填充内容:
from openjiuwen.core.foundation.prompt import PromptTemplate from openjiuwen.core.foundation.llm import UserMessage, SystemMessage template = PromptTemplate( name="greeting", content="你好,{{user_name}}!今天是 {{date}}。", )2. 消息列表模板(List[BaseMessage]类型)
content为BaseMessage列表,占位符写在各条消息的content字段中,天然适合构造多轮对话/带系统角色的提示词:
template3 = PromptTemplate( name="multi_turn", content=[ SystemMessage(content="你是助手。用户叫 {{user_name}}。"), UserMessage(content="请介绍一下{{topic}}。"), ], )BaseMessage定义于openjiuwen.core.foundation.llm(参见 llm.md),仓库中常见的子类包括SystemMessage、UserMessage、AssistantMessage、ToolMessage等,均可在 tests/unit_tests/core/foundation/prompt/test_template_assemble.py 中看到实际组合用法。
3. 自定义占位符格式
通过placeholder_prefix与placeholder_suffix可自定义占位符边界,例如${...}$风格:
template2 = PromptTemplate( name="custom", content="你是一个精通${domain}$领域的小助手!", placeholder_prefix="${", placeholder_suffix="}$", )此特性在迁移已有模板时非常实用:不需要逐字改写模板文本,只需在注册PromptTemplate时声明边界即可(文档中“注册提示词模板时占位符可自定义传入”即指此用法)。
三、format:占位符填充,返回新实例
format(self, keywords: dict = None) -> PromptTemplate用keywords字典将模板中的占位符替换为实际值,返回一个新的PromptTemplate实例,不修改当前实例(源码见 template.py)。
参数:
keywords(dict,可选):变量名到替换值的映射。若为None或空字典,则返回当前模板的深拷贝(不进行任何替换)。默认值None。
返回值:填充后的新PromptTemplate。其name、placeholder_prefix、placeholder_suffix与当前实例保持一致,content为替换后的内容。
三种形态的填充示例
# 1. 字符串模板 + 占位符替换 filled = template.format(keywords={"user_name": "张三", "date": "2025-02-02"}) # filled.content == "你好,张三!今天是 2025-02-02。" # 2. 自定义占位符格式 filled2 = template2.format(keywords={"domain": "数学"}) # filled2.content == "你是一个精通数学领域的小助手!" # 3. 消息列表模板(占位符在各消息 content 中) filled3 = template3.format(keywords={"user_name": "李四", "topic": "Python"}) # 两条消息的 content 中占位符均已替换填充行为细节(有测试与源码佐证)
- 部分填充:只传入部分变量时,未提供的占位符会原样保留。测试
test_template_format(test_template_assemble.py)验证了“先填memory、后补domain”的分步填充流程,模板可以反复调用format逐次补齐变量。 - 冗余关键字:传入
keywords中多余的键会被自动过滤。源码中format只取assembler.input_keys中命中的键(template.py),测试test_template_format第 5 点验证了传入{"name": "Bob", "age": 20}时age被忽略、结果仍为"Hi Bob"(test_template_assemble.py)。 - 不传或传空字典:返回当前模板的深拷贝,内容不变(测试第 4 点,test_template_assemble.py)。
源码级原理:format 的底层链路
format的实现并不是简单的字符串replace,而是委托给PromptAssembler(assembler.py)完成:
- 以深拷贝的
content、当前占位符前后缀构造PromptAssembler; - 通过
assembler.input_keys获取模板中所有变量的输入键,从keywords中筛选有效键值; - 调用
assembler.prompt_assemble(**valid_keywords)完成填充; - 用填充后的
content构造并返回新实例。
PromptAssembler内部将模板内容解析为若干Variable(格式化器),并根据content形态选择不同的变量类型(见 assembler.py):
- 字符串模板 →
TextableVariable(文本占位符); - 消息列表中
content为str→ 每个BaseMessage对应一个TextableVariable; - 消息列表中
content为List[dict](如多模态内容块)→DictableVariable(递归处理字典/列表结构中的占位符); - 其他类型 → 不处理。
在_update阶段(assembler.py),缺失键与多余键都会触发StatusCode.PROMPT_ASSEMBLER_TEMPLATE_PARAM_ERROR异常;_format阶段则逐个执行变量求值并回写模板内容。
四、to_messages:将模板转换为消息列表
to_messages(self) -> List[BaseMessage]将当前模板内容转换为BaseMessage列表(源码见 template.py)。
返回:消息列表;若content为空则返回空列表。
转换规则:
- 字符串类型模板 → 默认包装为一条
UserMessage(content为原字符串),因为在实际 LLM 调用中,一段裸文本提示通常作为用户输入发送。 BaseMessage列表类型模板 → 校验每项均为BaseMessage,然后对每条消息深拷贝后返回,避免调用方修改影响原模板;若存在非BaseMessage项,抛出异常(错误码见下文)。- 若
content为空 → 返回空列表[]。
示例:
# 字符串模板:先填充再转消息 filled = template.format(keywords={"user_name": "张三", "date": "2025-02-02"}) messages = filled.to_messages() # [UserMessage(content="你好,张三!今天是 2025-02-02。")] # 消息列表模板:直接转消息(深拷贝) filled3 = template3.format(keywords={"user_name": "李四", "topic": "Python"}) messages3 = filled3.to_messages() # 两条消息,content 中占位符已替换 # 仅转消息、不做填充 template4 = PromptTemplate(name="simple", content="直接使用这段文字。") messages4 = template4.to_messages() # [UserMessage(content="直接使用这段文字。")]异常:当content列表中存在非BaseMessage项时抛出build_error异常,对应错误码为StatusCode.PROMPT_TEMPLATE_INVALID(值180004,见 codes.py),error_msg为"prompt template type must be in str or list[BaseMessage]"。
五、底层变量体系:TextableVariable 与 DictableVariable
理解PromptTemplate的能力边界,离不开其底层变量体系。Variable是抽象基类(variable.py),提供input_keys(输入键)、value(当前值)、eval(**kwargs)(校验并更新后返回值)等统一接口。
TextableVariable:字符串占位符
textable.py 处理字符串型占位符:
- 用正则
re.escape(prefix) + r"([^{}]*?)" + re.escape(suffix)扫描文本中的占位符; - 空占位符(如
{{}})在初始化时即抛出PROMPT_ASSEMBLER_VARIABLE_INIT_FAILED(测试test_textable_variable验证了这一点); - 支持点号嵌套路径:占位符
{{user.name}}的input_keys为["user"],填充时先按第一段取输入键,再沿路径逐层取值(dict.get或getattr)——因此既支持{"name": "Alice"}字典,也支持带同名属性的自定义对象(测试见 test_template_assemble.py); - 非
str/int/float/bool类型的替换值会自动str()转换,并记录一条 prompt 日志提示风格描述问题。
DictableVariable:结构化内容占位符
dictable.py 递归扫描 dict/list 结构中的占位符并递归替换,典型场景是多模态消息内容(content为[{"type": "text", "text": "..."}, {"type": "image_url", "image_url": {"url": "..."}}]这种 OpenAI 风格内容块)。测试test_dict_template_integration(test_template_assemble.py)演示了在UserMessage.content的 dict 列表里填充{{query}}与{{image_url}}的完整链路。
测试用例对照
test_template_assemble.py 覆盖了:
- 占位符扫描与
input_keys/placeholders提取(含嵌套路径); - 空占位符异常、数值/布尔值替换;
- 多占位符同时填充;
PromptAssembler直接组装字符串模板(含自定义${}$、{ }边界);PromptTemplate.format的完整填充、部分填充、冗余键过滤与空字典深拷贝;- 消息列表模板(含
ToolCall消息)的组装与深拷贝。
六、错误码一览
提示词模板相关错误码定义在 codes.py(Foundation 180000 – 180999 区间):
| 错误码 | 常量 | 说明 |
|---|---|---|
| 180000 | PROMPT_ASSEMBLER_VARIABLE_INIT_FAILED | 变量初始化失败,如空占位符{{}}、变量未在模板中定义、变量非Variable实例 |
| 180001 | PROMPT_ASSEMBLER_TEMPLATE_PARAM_ERROR | 组装参数错误,如_update时缺失或多余键 |
| 180002 | PROMPT_ASSEMBLER_RUNTIME_ERROR | 模板运行时错误 |
| 180003 | PROMPT_TEMPLATE_NOT_FOUND | 模板未找到 |
| 180004 | PROMPT_TEMPLATE_INVALID | 模板非法,to_messages中 content 类型不合规时触发 |
七、项目中的典型应用场景
PromptTemplate在 openJiuwen 中被广泛使用,以下三类场景可帮助你理解其定位。
1. 提示词仓库管理(PromptMgr)
prompt_manager.py 中的PromptMgr以线程安全字典(ThreadSafeDict)维护template_id -> PromptTemplate的映射,提供add_prompt/add_prompts/remove_prompt/get_prompt方法。这印证了name参数的价值:模板可以命名注册、按 ID 复用,适合在 Agent 运行资源管理中统一维护提示词资产。
2. 运行时动态填充
在 react_agent.py 中可以看到运行期动态填充的用法:
msg.content = PromptTemplate(content=msg.content).format(render_fields).content即把消息内容包装为PromptTemplate,用运行时上下文(render_fields)填充占位符后取回content。这展示了format返回新实例、不改动原始消息的“纯函数”特性在 Agent 执行链中的价值。
3. 训练/评测提示词定义
examples/rl_calculator/prompts.py 定义了 RL 计算器训练场景的系统提示词模板:
CALCULATOR_SYSTEM_PROMPT = PromptTemplate( name="calculator_system", content=( "You are a {{role}}. Use the {{tool_name}} tool to solve " "{{task_type}} problems step by step.\n" "Output the answer when you are ready. " "The answer should be surrounded by three sharps (`###`), " "in the form of {{answer_format}}." ), )role、tool_name、task_type、answer_format等占位符在实际训练/评测时由代码传入具体值,实现“同一模板、多场景复用”。仓库中 examples/rl_nl2sql/prompts.py 也是同样的模式。
八、最佳实践与注意事项
- 内容不可变、替换可重复:
format返回新实例,不会污染原始模板;结合深拷贝语义(to_messages同样深拷贝消息),可在多轮 Agent 执行中安全复用同一模板。 - 占位符边界尽早统一:默认
{{ }}与自定义${ }$、{ }均可,但同一模板内前后缀必须配对一致;迁移第三方模板时,优先通过参数声明边界,而不是改写模板文本。 - 避免空占位符:
{{}}、${}$这类空占位符会在TextableVariable/DictableVariable初始化阶段直接抛180000异常,编写模板时务必检查。 - 嵌套路径按需使用:
{{user.name}}这类点号路径适合从结构化上下文中取值,但要注意input_keys取的是第一段(user),需保证该键出现在keywords中。 - 消息列表模板注意消息类型:
content列表中每一项必须是BaseMessage子类实例,否则to_messages抛出PROMPT_TEMPLATE_INVALID(180004);字符串模板转消息时统一包装为UserMessage,如需SystemMessage等角色,应使用消息列表形态。 - 充分利用
name:结合PromptMgr这类资源管理组件(prompt_manager.py)为模板命名注册,便于在复杂 Agent 工程中集中管理与按 ID 检索。
九、总结
PromptTemplate是 openJiuwen 提示词工程的基础组件:以content(字符串或消息列表)+ 可配置占位符边界完成模板定义,以format完成不修改原实例的占位符填充,以to_messages完成消息化输出,底层由PromptAssembler配合TextableVariable/DictableVariable提供正则扫描、嵌套路径取值、非字符串自动转换与严格参数校验。无论是编写 Agent 系统提示词、构造多轮对话消息,还是复用训练/评测模板,它都是值得优先选用的基础设施;深入阅读 template.py、assembler.py 与 test_template_assemble.py 可进一步掌握其全部边界行为。
- 人工智能
- AI Agent
- Agent 框架
- 大模型
- 工具调用
- RAG
- 提示工程
- 强化学习
【免费下载链接】agent-core
openJiuwen agent-core可提供AI Agent开发、运行、调优与演进相关的全套SDK能力
相关推荐
openJiuwen agent-core PromptTemplate 全面指南:提示词模板定义、填充与消息转换
openJiuwen agent core PromptTemplate 全面指南:提示词模板定义、填充与消息转换 导读 openjiuwen.core.fou
人工智能AI AgentAgent 框架大模型工具调用RAG提示工程强化学习openJiuwen PromptTemplate 使用指南:从占位符填充到消息列表转换的完整实践
openJiuwen PromptTemplate 使用指南:从占位符填充到消息列表转换的完整实践 本指南系统讲解 openJiuwen agent core
人工智能AI AgentAgent 框架大模型工具调用RAG提示工程强化学习openJiuwen PromptTemplate 占位符填充实战:从实例化到 format 渲染的完整指南
openJiuwen PromptTemplate 占位符填充实战:从实例化到 format 渲染的完整指南 本指南以 openJiuwen agent cor
人工智能AI AgentAgent 框架大模型工具调用RAG提示工程强化学习
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考