Eino - ChatTemplate 的应用
Eino - ChatTemplate 的应用
前言
在 AI 应用开发中,Prompt(提示词)是与大模型交互的核心。一个好的提示词工程能够让 AI 理解任务需求并生成高质量的回复。Eino 框架提供了强大的 ChatTemplate 功能,支持模板化管理提示词、变量替换、多角色对话等高级特性。
本文将详细介绍 ChatTemplate 的各种应用场景,帮助你掌握提示词模板化的核心技能,代码链接。
一、ChatTemplate 概述
1.1 什么是 ChatTemplate
ChatTemplate 是 Eino 框架中用于管理对话消息的模板结构,它允许开发者:
- 模板化:将提示词以模板形式定义,运行时替换变量
- 多角色支持:支持 System、User、Assistant 等多种消息类型
- 灵活格式化:支持 FString 等多种格式化方式
1.2 核心概念
ChatTemplate
├── prompt.FromMessages() # 创建模板
├── schema.FString # 格式化器(类似 Python f-string)
├── template.Format() # 格式化模板
└── Message Types
├── SystemMessage # 系统消息
├── UserMessage # 用户消息
└── AssistantMessage # 助手消息
二、基础用法:变量替换
2.1 简单变量替换
var_replace.go 展示了最基础的变量替换功能:
template := prompt.FromMessages(
schema.FString,
schema.SystemMessage("你是一个{role}"),
schema.UserMessage("{question}"),
)
variables := map[string]any{
"role": "热爱运动的程序员",
"question": "运动和工作哪个更重要?",
}
messages, _ := template.Format(ctx, variables)
运行结果:
1. [system] 你是一个热爱运动的程序员。
2. [user] 运动和工作哪个更重要?
2.2 FString 格式化器
schema.FString 是一种类似 Python f-string 的格式化器,使用 {变量名} 语法:
schema.SystemMessage("你是一个{role}") // {role} 会被替换
schema.UserMessage("{question}") // {question} 会被替换
FString 特点:
- 语法简洁,类似 Python f-string
- 支持任意数量的变量
- 变量不存在时返回错误
2.3 完整代码解析
func main() {
// 1. 创建模板
template := prompt.FromMessages(
schema.FString,
schema.SystemMessage("你是一个{role}"),
schema.UserMessage("{question}"),
)
// 2. 准备变量
variables := map[string]any{
"role": "热爱运动的程序员",
"question": "运动和工作哪个更重要?",
}
// 3. 格式化消息
messages, err := template.Format(ctx, variables)
if err != nil {
log.Fatalf("格式化失败: %v", err)
}
// 4. 查看生成的消息
for i, msg := range messages {
fmt.Printf("%d. [%s] %s\n", i+1, msg.Role, msg.Content)
}
}
三、模板复用:结构化设计
3.1 PromptTemplates 管理器
var_replace.go 中的 PromptTemplates 结构体展示了如何组织和管理多个模板:
type PromptTemplates struct{}
// 翻译助手模板
func (p *PromptTemplates) Translator(sourceLang, targetLang string) prompt.ChatTemplate {
return prompt.FromMessages(
schema.FString,
schema.SystemMessage(fmt.Sprintf(
"你是一个专业的翻译助手。请将%s翻译成%s。\n"+
"要求:\n"+
"1. 保持原文的语气和风格\n"+
"2. 确保翻译准确、流畅\n"+
"3. 只返回翻译结果,不要添加解释",
sourceLang, targetLang,
)),
schema.UserMessage("{text}"),
)
}
3.2 多种模板类型
翻译助手模板
func (p *PromptTemplates) Translator(sourceLang, targetLang string) prompt.ChatTemplate {
return prompt.FromMessages(
schema.FString,
schema.SystemMessage(fmt.Sprintf(
"你是一个专业的翻译助手。请将%s翻译成%s。\n"+
"要求:\n"+
"1. 保持原文的语气和风格\n"+
"2. 确保翻译准确、流畅\n"+
"3. 只返回翻译结果,不要添加解释",
sourceLang, targetLang,
)),
schema.UserMessage("{text}"),
)
}
// 使用示例
template := templates.Translator("中文", "英文")
messages := template.Format(ctx, map[string]any{
"text": "Eino 是一个强大的 AI 开发框架",
})
代码审查模板
func (p *PromptTemplates) CodeReviewer(language string) prompt.ChatTemplate {
return prompt.FromMessages(
schema.FString,
schema.SystemMessage(fmt.Sprintf(
"你是一个资深的%s开发专家。请审查以下代码,并提供:\n"+
"1. 潜在的bug或问题\n"+
"2. 性能优化建议\n"+
"3. 代码风格改进建议\n"+
"4. 安全性评估",
language,
)),
schema.UserMessage("请审查以下代码:\n\n```{language}\n{code}\n```"),
)
}
// 使用示例
template := templates.CodeReviewer("Go")
messages := template.Format(ctx, map[string]any{
"language": "go",
"code": `func add(a, b int) int {
return a + b
}`,
})
技术面试官模板
func (p *PromptTemplates) TechInterviewer(position, level string) prompt.ChatTemplate {
return prompt.FromMessages(
schema.FString,
schema.SystemMessage(fmt.Sprintf(
"你是一位%s职位的面试官,针对%s级别的候选人。\n"+
"请根据候选人的回答:\n"+
"1. 评估答案的准确性和深度\n"+
"2. 提出有针对性的追问\n"+
"3. 给出建设性的反馈",
position, level,
)),
schema.UserMessage("候选人回答:{answer}\n\n请评估并追问。"),
)
}
// 使用示例
template := templates.TechInterviewer("Go后端开发", "中级")
messages := template.Format(ctx, map[string]any{
"answer": "goroutine 是 Go 语言的轻量级线程",
})
3.3 模板使用流程
创建模板管理器
│
▼
┌─────────────────┐
│ PromptTemplates │
└────────┬────────┘
│
├── Translator() ──────▶ 翻译助手模板
├── CodeReviewer() ────▶ 代码审查模板
└── TechInterviewer() ▶ 技术面试模板
│
▼
┌────────────┐
│ Format(ctx,│
│ variables) │
└─────┬──────┘
│
▼
┌────────────┐
│ []*Message │
└────────────┘
四、多角色消息
4.1 支持的消息类型
multi_type.go 展示了 Eino 支持的多种消息类型:
template := prompt.FromMessages(
schema.FString,
// System: 系统提示,定义 AI 的角色和行为
schema.SystemMessage("你是{role},你的专长是{expertise}"),
// User: 用户消息
schema.UserMessage("我的问题是:{question}"),
// Assistant: AI 的历史回复(用于多轮对话)
schema.AssistantMessage("我理解了,让我思考一下...", []schema.ToolCall{}),
// User: 继续对话
schema.UserMessage("请详细说明"),
)
4.2 消息类型说明
| 类型 | 用途 | 特点 |
|---|---|---|
| SystemMessage | 系统提示词 | 定义 AI 角色、行为规则 |
| UserMessage | 用户消息 | 用户输入 |
| AssistantMessage | 助手消息 | AI 历史回复,支持多轮对话 |
4.3 完整示例
func main() {
ctx := context.Background()
template := prompt.FromMessages(
schema.FString,
schema.SystemMessage("你是{role},你的专长是{expertise}"),
schema.UserMessage("我的问题是:{question}"),
schema.AssistantMessage("我理解了,让我思考一下...", []schema.ToolCall{}),
schema.UserMessage("请详细说明"),
)
variables := map[string]any{
"role": "一位了解哲学的程序员",
"expertise": "分析和取舍确定性问题",
"question": "在不确定的环境中,如何做出最佳决策?",
}
messages, _ := template.Format(ctx, variables)
for i, msg := range messages {
fmt.Printf("%d. [%s]\n %s\n\n", i+1, msg.Role, msg.Content)
}
}
运行结果:
1. [system]
你是一位了解哲学的程序员,你的专长是分析和取舍确定性问题。
2. [user]
我的问题是:在不确定的环境中,如何做出最佳决策?
3. [assistant]
我理解了,让我思考一下...
4. [user]
请详细说明
五、复杂数据结构
5.1 结构体映射
complex_logic.go 展示了如何将复杂数据结构用于模板:
type UserProfile struct {
Name string
Age int
Intersts []string
VIPLevel int
}
// 准备用户数据
user := UserProfile{
Name: "张三",
Age: 28,
Interests: []string{"编程", "阅读", "旅行"},
VIPLevel: 3,
}
variables := map[string]any{
"name": user.Name,
"age": user.Age,
"interests": fmt.Sprintf("%v", user.Interests),
"vip_level": user.VIPLevel,
}
5.2 模板中的多行文本
template := prompt.FromMessages(
schema.FString,
schema.SystemMessage("你是一个智能推荐助手"),
schema.UserMessage(`用户信息:
姓名:{name}
年龄:{age}
兴趣:{interests}
VIP等级:{vip_level}
请根据以上信息推荐合适的内容。`),
)
5.3 格式化集合类型
对于切片等集合类型,需要使用 fmt.Sprintf 或 strings.Join 转换:
// 方式1: 使用 fmt.Sprintf
"interests": fmt.Sprintf("%v", user.Interests)
// 输出: [编程 阅读 旅行]
// 方式2: 使用 strings.Join
"interests": strings.Join(user.Interests, "、")
// 输出: 编程、阅读、旅行
5.4 完整示例
func main() {
template := prompt.FromMessages(
schema.FString,
schema.SystemMessage("你是一个智能推荐助手"),
schema.UserMessage(`用户信息:
姓名:{name}
年龄:{age}
兴趣:{interests}
VIP等级:{vip_level}
请根据以上信息推荐合适的内容。`),
)
user := UserProfile{
Name: "张三",
Age: 28,
Intersts: []string{"编程", "阅读", "旅行"},
VIPLevel: 3,
}
variables := map[string]any{
"name": user.Name,
"age": user.Age,
"interests": fmt.Sprintf("%v", user.Interests),
"vip_level": user.VIPLevel,
}
messages, _ := template.Format(ctx, variables)
for _, msg := range messages {
fmt.Printf("[%s]\n%s\n\n", msg.Role, msg.Content)
}
}
运行结果:
[system]
你是一个智能推荐助手
[user]
用户信息:
姓名:张三
年龄:28
兴趣:[编程 阅读 旅行]
VIP等级:3
请根据以上信息推荐合适的内容。
六、与大模型结合
6.1 完整调用流程
model_multiplex.go 展示了将 ChatTemplate 与大模型结合的完整流程:
func main() {
// 1. 加载配置
cfg, _ := loadConfig(*configPath)
// 2. 创建 ChatTemplate
template := prompt.FromMessages(
schema.FString,
schema.SystemMessage("你是一个{role}"),
schema.UserMessage("{question}"),
)
// 3. 准备变量
variables := map[string]any{
"role": "热爱运动的程序员",
"question": "运动和工作哪个更重要?",
}
// 4. 格式化消息
messages, _ := template.Format(ctx, variables)
// 5. 查看生成的消息
for i, msg := range messages {
fmt.Printf("%d. [%s] %s\n", i+1, msg.Role, msg.Content)
}
// 6. 创建 ChatModel
chatModel, _ := openai.NewChatModel(ctx, &openai.ChatModelConfig{
APIKey: cfg.Model.APIKey,
Model: cfg.Model.ModelName,
BaseURL: cfg.Model.BaseURL,
})
// 7. 生成响应
response, _ := chatModel.Generate(ctx, messages)
fmt.Printf("\nAI 回答:\n%s\n", response.Content)
}
6.2 流程图
┌─────────────────────────────────────────────────────────────┐
│ 完整调用流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ │
│ │ 1. 配置加载 │ loadConfig(config.yml) │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ 2. 创建模板 │ prompt.FromMessages(...) │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ ┌─────────────┐ │
│ │ 3. 准备变量 │───▶│ variables │ │
│ └──────┬───────┘ └─────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ 4. 格式化消息 │ template.Format(ctx, variables) │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ ┌─────────────┐ │
│ │ 5. 创建模型 │───▶│ ChatModel │ │
│ └──────┬───────┘ └─────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ 6. 生成响应 │ chatModel.Generate(ctx, messages) │
│ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
七、最佳实践
7.1 提示词设计原则
| 原则 | 说明 | 示例 |
|---|---|---|
| 角色明确 | 指定 AI 扮演的角色 | “你是一个专业的翻译助手” |
| 任务清晰 | 明确说明要做什么 | “请将以下中文翻译成英文” |
| 格式要求 | 说明输出格式要求 | “只输出译文,不要添加解释” |
| 约束条件 | 说明限制或禁止项 | “不要添加引号” |
7.2 模板组织建议
// 推荐:使用结构体管理模板
type PromptTemplates struct{}
// 推荐:函数返回模板,而非直接使用
func (p *PromptTemplates) Translator(sourceLang, targetLang string) prompt.ChatTemplate {
return prompt.FromMessages(...)
}
// 不推荐:每次创建新模板
template := prompt.FromMessages(...) // 重复代码
7.3 变量命名规范
// 推荐:清晰的变量名
variables := map[string]any{
"source_lang": "中文",
"target_lang": "英文",
"text": "Hello",
}
// 不推荐:模糊的变量名
variables := map[string]any{
"s": "中文",
"t": "英文",
"x": "Hello",
}
7.4 错误处理
messages, err := template.Format(ctx, variables)
if err != nil {
// 检查变量缺失等错误
log.Fatalf("格式化失败: %v", err)
}
response, err := chatModel.Generate(ctx, messages)
if err != nil {
// 处理 API 调用错误
log.Printf("生成失败: %v", err)
}
八、配置管理
8.1 配置文件结构
model:
base_url: "https://api.minimaxi.com/v1"
api_key: "your-api-key"
model_name: "MiniMax-M2.7"
timeout: 30
temperature: 0.7
top_p: 0.9
max_tokens: 500
app:
host: "0.0.0.0"
port: 8080
8.2 配置加载
type Config struct {
Model ModelConfig `yaml:"model"`
App AppConfig `yaml:"app"`
}
type ModelConfig struct {
BaseURL string `yaml:"base_url"`
APIKey string `yaml:"api_key"`
ModelName string `yaml:"model_name"`
Timeout int `yaml:"timeout"`
Temperature float64 `yaml:"temperature"`
TopP float64 `yaml:"top_p"`
MaxTokens int `yaml:"max_tokens"`
}
func loadConfig(configPath string) (*Config, error) {
data, err := os.ReadFile(configPath)
if err != nil {
return nil, fmt.Errorf("读取配置文件失败: %w", err)
}
var config Config
if err := yaml.Unmarshal(data, &config); err != nil {
return nil, fmt.Errorf("解析配置文件失败: %w", err)
}
return &config, nil
}
8.3 命令行参数
func main() {
configPath := flag.String("config", "config.yml", "配置文件路径")
flag.Parse()
cfg, err := loadConfig(*configPath)
if err != nil {
log.Fatalf("加载配置失败: %v", err)
}
}
九、运行示例
9.1 var_replace.go
go run var_replace.go -config ../config.yml
输出示例:
===== 翻译示例 =====
翻译结果: Eino is a powerful AI development framework
===== 代码审查示例 =====
审查结果:
1. **潜在bug**: 代码没有错误处理,建议添加...
===== 面试官示例 =====
面试官反馈:
很好,你对 goroutine 的理解基本正确...
9.2 model_multiplex.go
go run model_multiplex.go -config ../config.yml
输出示例:
生成的消息:
1. [system] 你是一个热爱运动的程序员。
2. [user] 运动和工作哪个更重要?
AI 回答:
运动和工作都很重要...
9.3 multi_type.go
go run multi_type.go
输出示例:
1. [system]
你是一位了解哲学的程序员,你的专长是分析和取舍确定性问题。
2. [user]
我的问题是:在不确定的环境中,如何做出最佳决策?
3. [assistant]
我理解了,让我思考一下...
4. [user]
请详细说明
9.4 complex_logic.go
go run complex_logic.go
输出示例:
[system]
你是一个智能推荐助手
[user]
用户信息:
姓名:张三
年龄:28
兴趣:[编程 阅读 旅行]
VIP等级:3
请根据以上信息推荐合适的内容。
十、总结
10.1 核心功能回顾
| 功能 | 说明 | 示例文件 |
|---|---|---|
| 变量替换 | 模板中动态替换变量 | var_replace.go |
| 模板复用 | 通过函数封装模板创建 | var_replace.go |
| 多角色 | System/User/Assistant | multi_type.go |
| 复杂数据 | 结构体、切片等 | complex_logic.go |
| 模型结合 | 模板 + 大模型调用 | model_multiplex.go |
10.2 ChatTemplate 优势
- 可维护性:模板与代码分离,便于修改
- 可复用性:一次定义,多次使用
- 可测试性:模板可以独立测试
- 可读性:清晰的提示词结构
10.3 进阶主题
- 模板组合:多个模板组合使用
- 条件渲染:根据变量决定渲染内容
- 模板校验:验证变量完整性
- 模板缓存:避免重复创建模板
通过本文的学习,你应该掌握了:
- ChatTemplate 基础:创建、格式化、变量替换
- 多角色消息:System、User、Assistant 消息
- 模板管理:结构化组织多个模板
- 工程实践:配置管理、错误处理、最佳实践
ChatTemplate 是 Eino 框架中处理提示词的核心组件,掌握它能够让你的 AI 应用开发更加高效和规范。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)