公告

任何建议或需求可联系我!


Skip to content

实现提示词

提示词是帮助构建用户与 LLM 之间对话的可重用交互模板。它们提供上下文、指令,并可以包含来自资源的动态内容。

提示词基础

MCP 中的提示词作为模板,可供 LLM 调用以生成结构化的交互。它们对于复杂的工作流程、分析任务或任何需要提供一致上下文和指令的场景特别有用。

基本提示词结构

go
// 创建一个简单的提示词
prompt := mcp.NewPrompt("code_review",
    mcp.WithPromptDescription("审查代码是否符合最佳实践和问题"),
    mcp.WithPromptArgument("code",
        mcp.Required(),
        mcp.Description("要审查的代码"),
    ),
    mcp.WithPromptArgument("language",
        mcp.Description("编程语言"),
        mcp.Default("auto-detect"),
    ),
)

提示词图标

提示词可以包含视觉标识符:

go
prompt := mcp.NewPrompt("code_review",
    mcp.WithPromptDescription("审查代码是否符合最佳实践"),
    mcp.WithPromptIcons(
        mcp.Icon{
            Src:      "https://example.com/icons/review.png",
            MIMEType: "image/png",
        },
    ),
    // ... 参数
)

显示标题

提示词及其参数可以携带人类可读的显示标题。客户端在选择器和 UI 界面中呈现标题;name 保持为稳定的程序化标识符。

go
prompt := mcp.NewPrompt("code_review",
    mcp.WithPromptTitle("代码审查"),                            // 在 UI 中显示
    mcp.WithPromptDescription("审查代码是否符合最佳实践"),
    mcp.WithArgument("code",
        mcp.ArgumentTitle("源代码"),                          // 参数显示名称
        mcp.ArgumentDescription("要审查的代码"),
        mcp.RequiredArgument(),
    ),
)

Title 为空时,客户端会回退到 Name。两个字段都使用 omitempty 序列化,因此未设置标题的现有提示词在传输时不会改变。

提示词模板

基本代码审查提示词

go
import (
    "context"
    "fmt"

    "github.com/mark3labs/mcp-go/mcp"
    "github.com/mark3labs/mcp-go/server"
)

func main() {
    s := server.NewMCPServer("Code Assistant", "1.0.0",
        server.WithPromptCapabilities(true),
    )

    // 代码审查提示词
    codeReviewPrompt := mcp.NewPrompt("code_review",
        mcp.WithPromptDescription("审查代码的最佳实践、错误和改进"),
        mcp.WithPromptArgument("code",
            mcp.Required(),
            mcp.Description("要审查的代码"),
        ),
        mcp.WithPromptArgument("language",
            mcp.Description("编程语言(如果未指定则自动检测)"),
        ),
        mcp.WithPromptArgument("focus",
            mcp.Description("要关注的特定领域"),
            mcp.Enum("security", "performance", "readability", "best-practices", "all"),
            mcp.Default("all"),
        ),
    )

    s.AddPrompt(codeReviewPrompt, handleCodeReview)
    server.ServeStdio(s)
}

func handleCodeReview(ctx context.Context, req mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
    // 安全地提取参数
    args := req.Params.Arguments
    if args == nil {
        return nil, fmt.Errorf("missing required arguments")
    }
    
    code, ok := args["code"].(string)
    if !ok {
        return nil, fmt.Errorf("code argument is required and must be a string")
    }
    
    language := getStringArg(args, "language", "auto-detect")
    focus := getStringArg(args, "focus", "all")

    // 根据关注领域构建提示词
    var instructions string
    switch focus {
    case "security":
        instructions = "特别关注安全漏洞、输入验证和潜在攻击向量。"
    case "performance":
        instructions = "关注性能优化、算法效率和资源使用。"
    case "readability":
        instructions = "关注代码清晰度、命名约定和可维护性。"
    case "best-practices":
        instructions = "关注特定语言的最佳实践和设计模式。"
    default:
        instructions = "提供涵盖安全性、性能、可读性和最佳实践的综合审查。"
    }

    return &mcp.GetPromptResult{
        Description: fmt.Sprintf("%s 代码审查", language),
        Messages: []mcp.PromptMessage{
            {
                Role: "user",
                Content: mcp.NewTextContent(fmt.Sprintf(
                    "请审查以下 %s 代码:\n\n%s\n\n说明:%s\n\n请提供:\n1. 总体评估\n2. 发现的具体问题\n3. 建议的改进\n4. 最佳实践建议\n\n代码:\n\n```\n%s\n```",
                    language, code, instructions, code,
                )),
            },
        },
    }, nil
}

func getStringArg(args map[string]interface{}, key, defaultValue string) string {
    if val, exists := args[key]; exists {
        if str, ok := val.(string); ok {
            return str
        }
    }
    return defaultValue
}

数据分析提示词

go
func handleDataAnalysis(ctx context.Context, req mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
    datasetURI := req.Params.Arguments["dataset_uri"].(string)
    analysisType := getStringArg(req.Params.Arguments, "analysis_type", "exploratory")
    focusAreas := getStringSliceArg(req.Params.Arguments, "focus_areas", []string{})

    // 获取数据集(这通常会从资源读取)
    dataset, err := fetchDataset(ctx, datasetURI)
    if err != nil {
        return nil, fmt.Errorf("failed to fetch dataset: %w", err)
    }

    // 构建分析说明
    var instructions strings.Builder
    instructions.WriteString("请分析提供的数据集。")

    switch analysisType {
    case "exploratory":
        instructions.WriteString("执行探索性数据分析,包括摘要统计、分布和模式。")
    case "predictive":
        instructions.WriteString("关注预测建模机会和特征关系。")
    case "diagnostic":
        instructions.WriteString("识别数据质量问题、异常值和潜在问题。")
    }

    if len(focusAreas) > 0 {
        instructions.WriteString(fmt.Sprintf(" 请特别关注:%s。", strings.Join(focusAreas, ", ")))
    }

    return &mcp.GetPromptResult{
        Description: fmt.Sprintf("%s 数据集分析", strings.Title(analysisType)),
        Messages: []mcp.PromptMessage{
            {
                Role: "user",
                Content: mcp.NewTextContent(fmt.Sprintf(`%s

数据集信息:
- 来源:%s
- 记录数:%d
- 列:%s

数据集预览:
%s

请提供综合分析,包括:
1. 数据概览和质量评估
2. 关键洞察和模式
3. 进一步分析的建议
4. 潜在问题或关注点`,
                    instructions.String(),
                    datasetURI,
                    dataset.RecordCount,
                    strings.Join(dataset.Columns, ", "),
                    dataset.Preview,
                )),
            },
        },
    }, nil
}

func getStringSliceArg(args map[string]interface{}, key string, defaultValue []string) []string {
    if val, exists := args[key]; exists {
        if slice, ok := val.([]interface{}); ok {
            result := make([]string, len(slice))
            for i, v := range slice {
                if str, ok := v.(string); ok {
                    result[i] = str
                }
            }
            return result
        }
    }
    return defaultValue
}

提示词参数

灵活参数处理

go
func handleFlexiblePrompt(ctx context.Context, req mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
    // 必需参数
    task := req.Params.Arguments["task"].(string)
    
    // 带默认值的可选参数
    tone := getStringArg(req.Params.Arguments, "tone", "professional")
    length := getStringArg(req.Params.Arguments, "length", "medium")
    audience := getStringArg(req.Params.Arguments, "audience", "general")
    
    // 数组参数
    keywords := getStringSliceArg(req.Params.Arguments, "keywords", []string{})
    
    // 对象参数
    var constraints map[string]interface{}
    if c, exists := req.Params.Arguments["constraints"]; exists {
        constraints = c.(map[string]interface{})
    }

    // 根据参数构建提示词
    prompt := buildDynamicPrompt(task, tone, length, audience, keywords, constraints)
    
    return &mcp.GetPromptResult{
        Description: fmt.Sprintf("生成 %s 内容", task),
        Messages: []mcp.PromptMessage{
            {
                Role: "user",
                Content: mcp.NewTextContent(prompt),
            },
        },
    }, nil
}

消息类型

多消息对话

go
func handleConversationPrompt(ctx context.Context, req mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
    scenario := req.Params.Arguments["scenario"].(string)
    userRole := getStringArg(req.Params.Arguments, "user_role", "customer")
    
    var messages []mcp.PromptMessage
    
    switch scenario {
    case "customer_support":
        messages = []mcp.PromptMessage{
            {
                Role: "system",
                Content: mcp.NewTextContent("你是一位乐于助人的客户支持代表。请保持礼貌、专业,并以解决问题为导向。"),
            },
            {
                Role: "user",
                Content: mcp.NewTextContent(fmt.Sprintf("我是一位%s,关于您的服务有问题想问。", userRole)),
            },
            {
                Role: "assistant", 
                Content: mcp.NewTextContent("您好!我在这里提供帮助。您今天需要什么帮助?"),
            },
            {
                Role: "user",
                Content: mcp.NewTextContent("请根据客户的需求继续对话。"),
            },
        }
        
    case "technical_interview":
        messages = []mcp.PromptMessage{
            {
                Role: "system",
                Content: mcp.NewTextContent("你正在进行技术面试。提出有思考的问题并提供建设性的反馈。"),
            },
            {
                Role: "user",
                Content: mcp.NewTextContent("让我们开始技术面试。请从一个合适的问题开始。"),
            },
        }
    }
    
    return &mcp.GetPromptResult{
        Description: fmt.Sprintf("%s 对话场景", strings.Title(scenario)),
        Messages:    messages,
    }, nil
}

系统和用户角色

go
func handleRoleBasedPrompt(ctx context.Context, req mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
    expertise := req.Params.Arguments["expertise"].(string)
    task := req.Params.Arguments["task"].(string)
    context := getStringArg(req.Params.Arguments, "context", "")

    // 根据专业知识定义系统消息
    var systemMessage string
    switch expertise {
    case "software_engineer":
        systemMessage = "你是一位经验丰富的软件工程师,在系统设计、代码质量和最佳实践方面有专业知识。"
    case "data_scientist":
        systemMessage = "你是一位数据科学家,在统计分析、机器学习和数据可视化方面有专业知识。"
    case "product_manager":
        systemMessage = "你是一位产品经理,在用户体验、市场分析和功能优先级方面有专业知识。"
    default:
        systemMessage = fmt.Sprintf("你是 %s 方面的专家。", expertise)
    }

    messages := []mcp.PromptMessage{
        {
            Role: "system",
            Content: mcp.NewTextContent(systemMessage),
        },
    }

    // 如果提供了上下文则添加
    if context != "" {
        messages = append(messages, mcp.PromptMessage{
            Role: "user",
            Content: mcp.NewTextContent(fmt.Sprintf("上下文:%s", context)),
        })
    }

    // 添加主要任务
    messages = append(messages, mcp.PromptMessage{
        Role: "user",
        Content: mcp.NewTextContent(task),
    })

    return &mcp.GetPromptResult{
        Description: fmt.Sprintf("%s 任务", strings.Title(expertise)),
        Messages:    messages,
    }, nil
}

嵌入资源

包含资源数据

go
func handleResourceEmbeddedPrompt(ctx context.Context, req mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
    documentURI := req.Params.Arguments["document_uri"].(string)
    analysisType := getStringArg(req.Params.Arguments, "analysis_type", "summary")

    // 获取文档内容
    document, err := fetchResource(ctx, documentURI)
    if err != nil {
        return nil, fmt.Errorf("failed to fetch document: %w", err)
    }

    // 构建带有嵌入内容的分析提示词
    var instructions string
    switch analysisType {
    case "summary":
        instructions = "请提供该文档要点的简明摘要。"
    case "critique":
        instructions = "请对提出的论点和证据进行批判性分析。"
    case "questions":
        instructions = "请提出该文档引发或可用于探索的有思考的问题。"
    case "action_items":
        instructions = "请从该文档中提取可操作的项目和建议。"
    }

    return &mcp.GetPromptResult{
        Description: fmt.Sprintf("文档 %s", analysisType),
        Messages: []mcp.PromptMessage{
            {
                Role: "user",
                Content: mcp.NewTextContent(fmt.Sprintf(`%s

文档:%s
内容:
---
%s
---

请按照上述说明提供您的分析。`,
                    instructions,
                    documentURI,
                    document.Content,
                )),
            },
        },
    }, nil
}

动态资源集成

go
func handleDynamicResourcePrompt(ctx context.Context, req mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
    resourceURIs := req.Params.Arguments["resource_uris"].([]interface{})
    promptType := getStringArg(req.Params.Arguments, "prompt_type", "compare")

    // 获取所有资源
    var resources []ResourceData
    for _, uri := range resourceURIs {
        if uriStr, ok := uri.(string); ok {
            resource, err := fetchResource(ctx, uriStr)
            if err != nil {
                return nil, fmt.Errorf("failed to fetch resource %s: %w", uriStr, err)
            }
            resources = append(resources, resource)
        }
    }

    // 根据类型和资源构建提示词
    var content strings.Builder
    
    switch promptType {
    case "compare":
        content.WriteString("请比较和对比以下文档:\n\n")
        for i, resource := range resources {
            content.WriteString(fmt.Sprintf("文档 %d (%s):\n%s\n\n", i+1, resource.URI, resource.Content))
        }
        content.WriteString("请提供:\n1. 主要相似之处\n2. 重要差异\n3. 总体评估")
        
    case "synthesize":
        content.WriteString("请综合以下来源的信息:\n\n")
        for i, resource := range resources {
            content.WriteString(fmt.Sprintf("来源 %d (%s):\n%s\n\n", i+1, resource.URI, resource.Content))
        }
        content.WriteString("请创建融合所有来源洞察的统一分析。")
    }

    return &mcp.GetPromptResult{
        Description: fmt.Sprintf("%s 多个资源", strings.Title(promptType)),
        Messages: []mcp.PromptMessage{
            {
                Role: "user",
                Content: mcp.NewTextContent(content.String()),
            },
        },
    }, nil
}

高级提示词模式

条件提示词

go
func handleConditionalPrompt(ctx context.Context, req mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
    userLevel := getStringArg(req.Params.Arguments, "user_level", "beginner")
    topic := req.Params.Arguments["topic"].(string)
    includeExamples := getBoolArg(req.Params.Arguments, "include_examples", true)

    var prompt strings.Builder
    
    // 根据用户级别调整复杂度
    switch userLevel {
    case "beginner":
        prompt.WriteString(fmt.Sprintf("请用适合新手理解的方式解释 %s。", topic))
        prompt.WriteString("使用清晰的语言,避免术语。")
    case "intermediate":
        prompt.WriteString(fmt.Sprintf("请详细解释 %s。", topic))
        prompt.WriteString("包括技术细节但确保清晰。")
    case "advanced":
        prompt.WriteString(fmt.Sprintf("请对 %s 进行深入分析。", topic))
        prompt.WriteString("包括高级概念、边缘案例和技术细节。")
    }

    if includeExamples {
        prompt.WriteString("请包含相关示例和实际应用。")
    }

    return &mcp.GetPromptResult{
        Description: fmt.Sprintf("%s 面向 %s 级别的解释", topic, userLevel),
        Messages: []mcp.PromptMessage{
            {
                Role: "user",
                Content: mcp.NewTextContent(prompt.String()),
            },
        },
    }, nil
}

func getBoolArg(args map[string]interface{}, key string, defaultValue bool) bool {
    if val, exists := args[key]; exists {
        if b, ok := val.(bool); ok {
            return b
        }
    }
    return defaultValue
}

基于模板的提示词

go
type PromptTemplate struct {
    Name        string
    Description string
    Template    string
    Variables   []string
}

var promptTemplates = map[string]PromptTemplate{
    "bug_report": {
        Name:        "Bug Report Analysis",
        Description: "分析错误报告并建议解决方案",
        Template: `请分析此错误报告:

**错误描述:** {{.description}}
**复现步骤:** {{.steps}}
**预期行为:** {{.expected}}
**实际行为:** {{.actual}}
**环境:** {{.environment}}

请提供:
1. 根本原因分析
2. 可能的解决方案
3. 预防策略
4. 优先级评估`,
        Variables: []string{"description", "steps", "expected", "actual", "environment"},
    },
    "feature_request": {
        Name:        "Feature Request Evaluation",
        Description: "评估功能请求",
        Template: `请评估此功能请求:

**功能:** {{.feature}}
**用例:** {{.use_case}}
**用户故事:** {{.user_story}}
**验收标准:** {{.criteria}}

请评估:
1. 商业价值和影响
2. 技术可行性
3. 实现复杂度
4. 潜在风险和考虑因素`,
        Variables: []string{"feature", "use_case", "user_story", "criteria"},
    },
}

func handleTemplatePrompt(ctx context.Context, req mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
    templateName := req.Params.Arguments["template"].(string)
    variables := req.Params.Arguments["variables"].(map[string]interface{})

    template, exists := promptTemplates[templateName]
    if !exists {
        return nil, fmt.Errorf("unknown template: %s", templateName)
    }

    // 替换模板变量
    content := template.Template
    for _, variable := range template.Variables {
        if value, exists := variables[variable]; exists {
            placeholder := fmt.Sprintf("{{.%s}}", variable)
            content = strings.ReplaceAll(content, placeholder, fmt.Sprintf("%v", value))
        }
    }

    return &mcp.GetPromptResult{
        Description: template.Description,
        Messages: []mcp.PromptMessage{
            {
                Role: "user",
                Content: mcp.NewTextContent(content),
            },
        },
    }, nil
}

提示词过滤

根据上下文、会话或权限过滤哪些提示词对每个客户端可见——类似于通过 WithToolFilter 进行工具过滤。

基于权限的提示词过滤

go
s := server.NewMCPServer("Prompt Server", "1.0.0",
    server.WithPromptCapabilities(true),
    server.WithPromptFilter(func(ctx context.Context, prompts []mcp.Prompt) []mcp.Prompt {
        session := server.ClientSessionFromContext(ctx)
        if session == nil {
            return nil
        }

        // 根据会话或上下文过滤提示词
        var filtered []mcp.Prompt
        for _, p := range prompts {
            if shouldExposePrompt(ctx, p) {
                filtered = append(filtered, p)
            }
        }
        return filtered
    }),
)

可以添加多个过滤器并按顺序应用:

go
s := server.NewMCPServer("Server", "1.0.0",
    server.WithPromptCapabilities(true),
    server.WithPromptFilter(roleFilter),
    server.WithPromptFilter(environmentFilter),
)

提示词处理程序中间件

用横切关注点(如日志记录、缓存或身份验证)包装提示词处理程序——类似于 WithToolHandlerMiddleware

go
s := server.NewMCPServer("Server", "1.0.0",
    server.WithPromptCapabilities(true),
    server.WithPromptHandlerMiddleware(func(next server.PromptHandlerFunc) server.PromptHandlerFunc {
        return func(ctx context.Context, req mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
            start := time.Now()
            log.Printf("Prompt requested: %s", req.Params.Name)

            result, err := next(ctx, req)

            log.Printf("Prompt %s served in %v", req.Params.Name, time.Since(start))
            return result, err
        }
    }),
)

中间件按顺序组合——第一个注册的包装最外层:

go
s := server.NewMCPServer("Server", "1.0.0",
    server.WithPromptCapabilities(true),
    server.WithPromptHandlerMiddleware(loggingMiddleware),
    server.WithPromptHandlerMiddleware(authMiddleware),
)

下一步