一、组件概述

Prompt 组件是一个功能强大的提示词模板引擎,专门设计用于简化与大语言模型(LLM)的交互过程。它通过模板化管理,实现了对话消息的动态生成、标准化组装和复用,显著提升了开发效率。

核心价值

  • 动态变量替换:支持多种模板语法,实现灵活的变量填充

  • 消息结构化:规范化系统指令、用户输入和模型输出的格式

  • 模板复用:一次定义,多次使用,确保提示词一致性

二、模板引擎详解

1. FString 格式 (schema.FString)

特点:简单直观的字符串插值,适合基础替换场景

语法规则

  • 使用 {变量名} 格式进行占位

  • 支持嵌套对象访问:{user.name}

  • 自动类型转换和空值处理

适用场景

  • 简单的文本替换需求

  • 不需要复杂逻辑的静态模板

  • 性能要求较高的场景

// 示例模板
template := prompt.FromMessages(schema.FString,
    schema.SystemMessage("你是一个{role}专家,擅长{domain}领域"),
    schema.UserMessage("请帮我{task},具体要求:{requirement}"),
)

2. GoTemplate 格式 (schema.GoTemplate)

特点:基于 Go 标准库的强大模板引擎,支持复杂逻辑

语法特性

  • 条件判断:{{if .condition}}...{{end}}

  • 循环遍历:{{range .items}}...{{end}}

  • 函数调用:{{.value | upper}}

  • 管道操作:{{.data | json | indent}}

适用场景

  • 需要条件逻辑的复杂模板

  • 数据结构遍历需求

  • 需要自定义函数的场景

// 示例模板
template := prompt.FromMessages(schema.GoTemplate,
    schema.SystemMessage(`{{if .expert}}作为{{.expert}}专家,{{end}}请用{{.tone}}的语气回答`),
    schema.UserMessage(`问题:{{.question}}{{if .context}}
相关背景:{{.context}}{{end}}`),
)

3. Jinja2 格式 (schema.Jinja2)

特点:兼容流行的 Jinja2 语法,适合 Python 背景的开发者

语法特性

  • 条件语句:{% if condition %}...{% endif %}

  • 循环控制:{% for item in items %}...{% endfor %}

  • 过滤器:{{ variable | filter }}

  • 模板继承:支持宏和包含

适用场景

  • 从 Python 项目迁移的场景

  • 需要复杂模板逻辑的项目

  • 团队熟悉 Jinja2 语法的情况

// 示例模板
template := prompt.FromMessages(schema.Jinja2,
    schema.SystemMessage("你是一个{{role}}{% if level %} {{level}}级{% endif %}专家"),
    schema.UserMessage("问题:{{question}}{% if examples %}
示例:{{examples}}{% endif %}"),
)

三、完整使用示例

环境配置

package main

import (
    "context"
    "log"
    "os"
    "time"

    "github.com/cloudwego/eino-ext/components/model/openai"
    "github.com/cloudwego/eino/components/model"
    "github.com/cloudwego/eino/components/prompt"
    "github.com/cloudwego/eino/schema"
)

// 配置常量
const (
    DOUBAO_MODEL_NAME = "doubao-seed-1-6-251015"
    DOUBAO_BASE_URL   = "https://ark.cn-beijing.volces.com/api/v3"
)

1. 创建聊天模型

func createOpenAIChatModel(ctx context.Context) model.ToolCallingChatModel {
    key := os.Getenv("DOUBAO_API_KEY")
    if key == "" {
        log.Fatal("DOUBAO_API_KEY environment variable is required")
    }

    chatModel, err := openai.NewChatModel(ctx, &openai.ChatModelConfig{
        BaseURL: DOUBAO_BASE_URL,
        Model:   DOUBAO_MODEL_NAME,
        APIKey:  key,
    })
    if err != nil {
        log.Fatalf("创建OpenAI聊天模型失败: %v", err)
    }
    return chatModel
}

2. 模板创建与使用

// 创建FString模板(推荐用于简单场景)
func createFstringTemplate() prompt.ChatTemplate {
    return prompt.FromMessages(schema.FString,
        schema.SystemMessage("你是一位{role},请用{tone}的语气回答用户问题。"),
        schema.UserMessage("问题:{question}"),
        // 可添加助理消息模板用于多轮对话
    )
}

// 创建GoTemplate模板(推荐用于复杂逻辑)
func createGoTemplate() prompt.ChatTemplate {
    return prompt.FromMessages(schema.GoTemplate,
        schema.SystemMessage(`你是一位{{.role}}专家。
{{if .level -}}
你是{{.level}}级别的专家。
{{end -}}
请用{{.tone}}的语气回答问题。`),

        schema.UserMessage(`问题:{{.question}}
{{if .context -}}
背景信息:{{.context}}
{{end -}}
{{if .examples -}}
参考示例:{{.examples}}
{{end}}`),
    )
}

// 创建Jinja2模板
func createJinja2Template() prompt.ChatTemplate {
    return prompt.FromMessages(schema.Jinja2,
        schema.SystemMessage(`你是一位{{role}}专家{% if specialty %},擅长{{specialty}}{% endif %}。
请用{{tone}}的语气回答问题。`),

        schema.UserMessage(`问题:{{question}}
{% if constraints %}
约束条件:
{% for constraint in constraints %}
- {{constraint}}
{% endfor %}
{% endif %}`),
    )
}

3. 消息生成与格式化

func createMessagesFromTemplate(templateType string) []*schema.Message {
    var template prompt.ChatTemplate

    // 根据类型选择模板引擎
    switch templateType {
    case "fstring":
        template = createFstringTemplate()
    case "go":
        template = createGoTemplate()
    case "jinja2":
        template = createJinja2Template()
    default:
        template = createFstringTemplate() // 默认使用FString
    }

    // 模板变量数据
    variables := map[string]any{
        "role":        "资深技术专家",
        "tone":        "专业且友好",
        "question":    "如何系统性地优化大型数据库的性能?",
        "level":       "高级",
        "context":     "系统用户量超过100万,数据表有50+",
        "examples":    "包括索引优化、查询重构、硬件升级等方案",
        "specialty":   "数据库优化",
        "constraints": []string{"约束条件1", "约束条件2"},
    }

    // 格式化生成消息
    messages, err := template.Format(context.Background(), variables)
    if err != nil {
        log.Fatalf("模板格式化失败: %v", err)
    }

    log.Printf("生成的消息数量: %d", len(messages))
    for i, msg := range messages {
        log.Printf("消息%d: 角色=%s, 内容=%s", i+1, msg.Role, msg.Content)
    }

    return messages
}

4. 模型调用封装

// 普通生成模式
func generateContent(ctx context.Context, llm model.ToolCallingChatModel, messages []*schema.Message) *schema.Message {
    result, err := llm.Generate(ctx, messages)
    if err != nil {
        log.Fatalf("LLM生成失败: %v", err)
    }

    log.Printf("生成完成 - Token使用: 输入=%d, 输出=%d",
        result.ResponseMeta.Usage.PromptTokens,
        result.ResponseMeta.Usage.CompletionTokens)

    return result
}

// 流式生成模式
func streamContent(ctx context.Context, llm model.ToolCallingChatModel, messages []*schema.Message) {
    stream, err := llm.Stream(ctx, messages)
    if err != nil {
        log.Fatalf("流式生成失败: %v", err)
    }
    defer stream.Close()

    log.Println("开始流式生成...")
    var fullResponse string

    for {
        chunk, err := stream.Recv()
        if err != nil {
            break // 流结束
        }

        if chunk.Content != "" {
            print(chunk.Content)
            fullResponse += chunk.Content
        }
    }

    println() // 换行
    log.Printf("流式生成完成,总字符数: %d", len(fullResponse))
}

5. 主函数与错误处理

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
    defer cancel()

    // 1. 创建聊天模型
    log.Println("=== 初始化聊天模型 ===")
    chatModel := createOpenAIChatModel(ctx)

    // 2. 选择模板类型并生成消息
    log.Println("=== 生成对话消息 ===")
    messages := createMessagesFromTemplate("fstring") // 可改为 "go" 或 "jinja2"

    // 3. 选择生成模式
    log.Println("=== 开始内容生成 ===")

    // 模式选择:普通生成 或 流式生成
    generationMode := "stream" // 可改为 "normal"

    switch generationMode {
    case "normal":
        log.Println("使用普通生成模式...")
        result := generateContent(ctx, chatModel, messages)
        log.Printf("最终结果: %s", result.Content)

    case "stream":
        log.Println("使用流式生成模式...")
        streamContent(ctx, chatModel, messages)

    default:
        log.Println("使用默认的流式生成模式...")
        streamContent(ctx, chatModel, messages)
    }

    log.Println("=== 程序执行完成 ===")
}