04|ChatTemplate 实战:让提示词成为可维护的代码
《Eino 实战:用 Go 构建 AI 应用与智能体》· 第 04 篇
关键词:ChatTemplate、FString、GoTemplate、Jinja2、MessagesPlaceholder、变量校验
前置条件:已完成 [03|ChatModel 实战](03|ChatModel 实战:消息、参数与多轮对话.md),理解消息列表与角色。
第 03 篇里,我们是这样拼消息的:
schema.SystemMessage("你是工单助手。请把工单描述整理成摘要……")schema.UserMessage(ticket)只有两条消息时,这没什么问题。但很快你会需要把参考资料、历史对话、业务分类一起放进去,还可能要在多个流程里复用同一套角色设定。字符串拼接会迅速变成一团难以维护、更难以测试的代码。
ChatTemplate 要解决的就是这件事:把提示词从零散的字符串,变成一份有变量、有结构、可以校验的模板。
一、模板的本质:一个填变量的函数
ChatTemplate的接口只有一个方法:
typeChatTemplateinterface{Format(ctx context.Context,vsmap[string]any,opts...Option)([]*schema.Message,error)}输入是变量映射,输出是消息列表。可以把它理解成map[string]any → []*schema.Message的转换器。
这里有一个重要定位:模板只负责组织消息,不负责调用模型。它通常放在模型之前,作为上下文准备环节。生成回答是ChatModel的事。
二、三种模板语法
prompt.FromMessages的第一个参数决定变量替换语法:
| 语法 | 常量 | 特点 | 适用场景 |
|---|---|---|---|
| FString | schema.FString | {变量名}直接替换,简单直观 | 大多数业务提示词 |
| GoTemplate | schema.GoTemplate | Go 标准库text/template语法,支持条件与循环 | 需要逻辑分支时 |
| Jinja2 | schema.Jinja2 | Jinja2 语法,生态成熟 | 团队已有 Jinja2 模板资产 |
FString 底层由pyfmt实现(Python 风格的格式化),GoTemplate 走text/template,Jinja2 由gonja解析。先猜清楚用哪种语法,再写占位符——写成 GoTemplate 的{ {.name}}却声明成 FString,变量不会被替换。
日常建议从 FString 开始:可读性最好,也最容易排查变量问题。需要条件渲染时再换 GoTemplate 或 Jinja2。
三、构建模板的几种方式
除了prompt.FromMessages,还有几个便捷构造函数:
schema.SystemMessage("你是工单助手。")// role = systemschema.UserMessage("打印机离线怎么办?")// role = userschema.AssistantMessage("已记录。",nil)// role = assistantschema.ToolMessage("调用结果",toolCallID)// role = toolschema.MessagesPlaceholder("history",false)// 插入 []*schema.Message