跳转至

MCP构建Prompts

Prompts 是 MCP 三大原语中最容易被忽视的一个,但用好了能大幅提升 AI 应用的体验。本篇讲怎么设计和构建 Prompts。

1. Prompts 是什么

Prompts 是 Server 提供给用户的预制提示词模板。用户通过客户端(如 Claude Desktop 的 / 命令)触发,Server 会根据参数生成一段精心设计的提示词发给模型。

可以理解为 Server 给用户提供的"高质量提示词工具箱"

场景 说明
Code Review 用户选中代码,触发 /code_review,得到统一标准的代码审查
Bug 分析 /analyze_bug 接收错误日志,自动按规范输出排查思路
翻译 /translate 接收文本和目标语言,应用最佳翻译 prompt
总结 /summarize 用一致的格式总结文档

2. 与 Tool 和 Resource 的区别

维度 Tool Resource Prompt
触发方 模型 用户/客户端 用户
作用 执行操作 提供数据 启动一段对话
是否调用 LLM 否(在 Server 端) 是(生成 prompt 发给 LLM)

关键差异: Prompt 不是返回结果给用户,而是返回一个 prompt 让客户端用它去问 LLM

3. 基础 Prompt

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("prompts-demo")

@mcp.prompt()
def code_review(code: str, language: str = "Python") -> str:
    """对代码进行严格的 Code Review"""
    return f"""请对下面的 {language} 代码进行严格的 Code Review。

【代码】
```{language.lower()}
{code}
```

请重点关注:
1. 代码可读性
2. 潜在 bug
3. 性能问题
4. 安全隐患
5. 是否符合 {language} 最佳实践

请用 Markdown 格式输出 review 报告,每个问题给出具体行号和修改建议。
"""

在 Claude Desktop 中输入 /code_review,会弹出参数表单,填入后 Claude 就会按这个 prompt 回答。

4. 多消息 Prompt

简单 Prompt 返回一个字符串,会作为单条 user 消息发给模型。复杂场景可以返回消息列表

from mcp.server.fastmcp import FastMCP
from mcp.server.fastmcp.prompts import base

mcp = FastMCP("prompts-demo")

@mcp.prompt()
def debug_session(error_log: str) -> list[base.Message]:
    """启动一次 debug 会话,预设系统行为"""
    return [
        base.AssistantMessage(
            content="我会以专业调试工程师的身份,帮你分析错误日志,找出根因并提供修复方案。请告诉我你的问题。"
        ),
        base.UserMessage(
            content=f"这是错误日志:\n\n```\n{error_log}\n```\n\n请帮我分析。"
        ),
    ]

返回的列表会作为对话历史预填进 Claude,相当于让对话从一个"已经预热"的状态开始。

5. 参数说明(描述很重要)

像 Tool 一样,Prompt 的参数也需要好的描述,便于客户端表单展示:

from typing import Annotated
from pydantic import Field

@mcp.prompt()
def translate(
    text: Annotated[str, Field(description="要翻译的文本")],
    target_lang: Annotated[
        str,
        Field(description="目标语言,如 '英文'、'日文'、'法文'")
    ] = "英文",
    style: Annotated[
        str,
        Field(description="翻译风格:'正式'、'口语'、'文学'")
    ] = "正式",
) -> str:
    """将文本翻译成指定语言"""
    return f"""请将下面的文本翻译成{target_lang},使用{style}的风格。

要求:
- 准确传达原文意思
- 符合{target_lang}的表达习惯
- 保留原文的语气和情感

【原文】
{text}

只输出翻译结果,不要任何解释。
"""

在 Claude Desktop 触发 /translate 时会显示一个表单,让用户填写各参数。

6. 实战:开发助手 Prompt 套装

一个完整的开发助手 Server,提供多个有用的 Prompts:

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("dev-helper")

@mcp.prompt()
def explain_code(code: str, level: str = "中级") -> str:
    """解释代码(按受众水平定制深度)"""
    return f"""请解释下面的代码。受众水平:{level}(初级/中级/高级)。

```
{code}
```

要求:
- 初级:用类比和大白话,不引入太多术语
- 中级:解释关键技术点和设计意图
- 高级:分析底层原理、性能特点、潜在改进
"""

@mcp.prompt()
def write_test(code: str, framework: str = "pytest") -> str:
    """为给定代码生成单元测试"""
    return f"""请为下面的代码生成完整的 {framework} 单元测试。

```
{code}
```

要求:
1. 覆盖正常路径
2. 覆盖边界情况(空输入、最大值、None 等)
3. 覆盖异常路径(错误输入应该抛出什么)
4. 测试函数名清晰,命名格式 test_<功能>_<场景>
5. 每个测试只验证一件事
"""

@mcp.prompt()
def refactor(code: str, goal: str) -> str:
    """重构代码"""
    return f"""请重构下面的代码,重构目标:{goal}

```
{code}
```

要求:
- 保持原有功能完全不变
- 提供重构后的完整代码
- 简要说明做了哪些改动以及为什么
"""

@mcp.prompt()
def commit_message(diff: str) -> str:
    """根据 git diff 生成规范的 commit message"""
    return f"""请根据下面的 git diff 生成一条符合 Conventional Commits 规范的 commit message。

```diff
{diff}
```

格式要求:
<type>(<scope>): <subject>

<body>

<footer>

- type: feat/fix/docs/style/refactor/test/chore
- subject: 50 字以内,祈使句
- body: 详细说明动机和改动
- 如果有 breaking change,在 footer 中标注

只输出 commit message,不要其他内容。
"""

if __name__ == "__main__":
    mcp.run()

注册到 Claude Desktop 后,用户就能通过 /explain_code/write_test/refactor/commit_message 快速触发这些精心设计的提示词。

7. Prompt + Resource 组合

Prompt 还能引用 Resource,构建强大的工作流:

from mcp.server.fastmcp import FastMCP
from mcp.server.fastmcp.prompts import base

mcp = FastMCP("workflow-demo")

@mcp.resource("template://email/welcome")
def email_template() -> str:
    return "欢迎加入 {company}!我们将在 {date} 进行新员工培训..."

@mcp.prompt()
def write_email(recipient: str, purpose: str) -> list[base.Message]:
    """根据预制模板写邮件"""
    return [
        base.UserMessage(content=f"""请帮我写一封邮件给 {recipient},目的:{purpose}

参考公司邮件模板(资源 URI: template://email/welcome),结合具体场景调整。
"""),
    ]

LLM 收到 prompt 后,会主动调用 Resource 读取模板,再生成邮件。

8. 异步 Prompt

如果 prompt 生成需要数据库查询或 API 调用,用异步:

import httpx

@mcp.prompt()
async def analyze_pr(pr_url: str) -> str:
    """获取 PR 内容并启动分析"""
    async with httpx.AsyncClient() as client:
        response = await client.get(pr_url)
        pr_data = response.text

    return f"""请分析这个 Pull Request 的改动,识别潜在风险和需要重点关注的点。

【PR 内容】
{pr_data}

请按以下结构输出:
1. 改动概述
2. 潜在风险(按严重程度排序)
3. 推荐的 Reviewer 关注点
"""

9. 何时使用 Prompt

判断某个能力适合做 Prompt 还是 Tool:

适合 Prompt:

  • 需要用户主动选择触发的场景
  • 关键在于"如何提问"(提示词工程)
  • 结果需要 LLM 的能力(创作、分析、解释)
  • 没有明确的"标准答案"

适合 Tool:

  • 模型可以自主决定调用
  • 关键在于"如何执行"(业务逻辑)
  • 结果是确定的(查询、计算、API 调用)

举例:

  • "翻译一段文字" → Prompt(关键是怎么写好翻译 prompt)
  • "查询数据库中的用户" → Tool(关键是怎么执行 SQL)

10. 设计建议

1. 名称用动词

code_reviewwrite_testanalyze_bug,让用户一看就知道做什么。

2. 描述要短而精

Claude Desktop 的 / 菜单只显示一行描述,要简洁有力。

3. 参数要直观

参数名要符合用户习惯,提供合理默认值,减少必填。

4. Prompt 内容要专业

Prompt 是 Server 提供的"专业知识",应该比用户自己临时写的 prompt 质量高很多。投入精力打磨。

5. 输出格式要明确

在 prompt 末尾明确要求输出格式(JSON、Markdown、纯文本等),避免模型自由发挥。

6. 留好扩展点

参数设计要考虑未来可能新增的需求,比如 styleformat 这类预留字段。

总结

  • Prompt 是 Server 提供给用户的预制提示词模板,用户通过客户端触发
  • 与 Tool/Resource 的关键区别:结果是给 LLM 看的 prompt,不是直接返回值
  • 简单 Prompt 返回 str,复杂场景返回 list[Message] 预填多轮对话
  • 参数描述用 Pydantic Field,方便客户端展示表单
  • 适合做 Prompt 的场景:用户主动选择、需要 LLM 能力、没有标准答案
  • Prompt + Resource 组合可以构建强大的工作流

评论