FastMCP之Prompts

一、什么是提示词

提示词就像给 AI 模型(比如 ChatGPT 这类)准备的「带填空的固定说法模板」------ 模板里的 "填空" 就是可替换的参数。

当有人(客户端)要用到这个提示词时,流程是这样的:

  • FastMCP 先找到你提前定义好的这个模板;
  • 如果模板里有 "填空"(参数),就按你之前设定的规则(比如 "填空必须是数字""不能空着"),检查对方填的内容合不合格;
  • 检查没问题后,你的程序(函数)就用这些填好的、合格的信息去干活;
  • 最后会生成一段完整的话,传给 AI 模型,告诉 AI 该怎么回应才对。

这么做的好处是:你能做出一套统一的、能反复用的模板,不管在不同的平台(客户端)、不同场景下,AI 的回应逻辑都一致,不用每次都重新编提示词。

二、定义提示词

定义提示词最常见的方式是装饰一个 Python 函数。该装饰器会将函数名用作提示词的标识符。

python 复制代码
from fastmcp import FastMCP
from fastmcp.prompts.prompt import Message, PromptMessage, TextContent

mcp = FastMCP(name="PromptServer")

# Basic prompt returning a string (converted to user message automatically)
@mcp.prompt
def ask_about_topic(topic: str) -> str:
    """Generates a user message asking for an explanation of a topic."""
    return f"Can you please explain the concept of '{topic}'?"

# Prompt returning a specific message type
@mcp.prompt
def generate_code_request(language: str, task_description: str) -> PromptMessage:
    """Generates a user message requesting code generation."""
    content = f"Write a {language} function that performs the following task: {task_description}"
    return PromptMessage(role="user", content=TextContent(type="text", text=content))

核心概念

  • Name :默认情况下,提示名称取自函数名称。
  • Parameters 函数参数定义了生成提示词所需的输入。
  • 推断的元数据
    • 提示词名称:取自函数名称(ask_about_topic)
    • 提示词描述:取自函数的 docstring

带有 * args 或 **kwargs 的函数不支持作为提示词。存在这一限制是因为 FastMCP 需要为 MCP 协议生成完整的参数模式,而这对于可变参数列表来说是无法实现的。

三、装饰器参数

虽然 FastMCP 会从你的函数中推断出名称和描述,但你可以使用 @mcp.prompt 装饰器的参数来覆盖这些内容并添加额外的元数据:

python 复制代码
@mcp.prompt(
    name="analyze_data_request",          # Custom prompt name
    description="Creates a request to analyze data with specific parameters",  # Custom description
    tags={"analysis", "data"},            # Optional categorization tags
    meta={"version": "1.1", "author": "data-team"}  # Custom metadata
)
def data_analysis_prompt(
    data_uri: str = Field(description="The URI of the resource containing the data."),
    analysis_type: str = Field(default="summary", description="Type of analysis.")
) -> str:
    """This docstring is ignored when description is provided."""
    return f"Please perform a '{analysis_type}' analysis on the data found at {data_uri}."
名称 类型 说明
name str \ None 设置通过 MCP 公开的显式提示名称。如果未提供,则使用函数名称
title str \ None 提示词的易读标题
description str \ None 提供通过 MCP 公开的描述。如果设置了此选项,函数的文档字符串将为此目的而被忽略。
tags set[str] \ None 一组用于对提示词进行分类的字符串。服务器以及在某些情况下的客户端可以使用这些字符串来筛选或分组可用的提示词。
enabled bool \ 默认值 True 一个用于启用或禁用提示的布尔值。有关更多信息,请参见 "禁用提示"。
icons list[Icon] \ None 此提示词的可选图标表示列表。详见 "图标" 部分的详细示例。
meta dict[str, Any] \ None 关于提示词的可选元信息。这些数据会作为客户端提示词对象的_meta 字段传递给 MCP 客户端,可用于自定义元数据、版本控制或其他特定于应用程序的用途。

四、参数类型

MCP 规范要求所有提示参数都以字符串形式传递,但 FastMCP 允许你使用类型注解(指定参数类型),以提供更好的开发者体验。当你使用诸如 list [int] 或 dict [str, str] 之类的复杂类型时,FastMCP 会:

  1. 自动将来自 MCP 客户端的字符串参数转换为预期类型
  2. 生成有用的描述,展示所需的确切 JSON 字符串格式
  3. 保留直接使用方式 ------ 您仍然可以使用类型正确的参数调用提示词

由于 MCP 规范仅允许字符串参数,客户端需要知道对于复杂类型应使用何种字符串格式。FastMCP 通过自动用 JSON 模式信息增强参数描述解决了这一问题,让人类和大语言模型(LLMs)都能清楚地了解如何格式化其参数。

python 复制代码
@mcp.prompt
def analyze_data(
    numbers: list[int],
    metadata: dict[str, str], 
    threshold: float
) -> str:
    """Analyze numerical data."""
    avg = sum(numbers) / len(numbers)
    return f"Average: {avg}, above threshold: {avg > threshold}"

提示词结果

python 复制代码
{
  "name": "analyze_data",
  "description": "Analyze numerical data.",
  "arguments": [
    {
      "name": "numbers",
      "description": "Provide as a JSON string matching the following schema: {\"items\":{\"type\":\"integer\"},\"type\":\"array\"}",
      "required": true
    },
    {
      "name": "metadata", 
      "description": "Provide as a JSON string matching the following schema: {\"additionalProperties\":{\"type\":\"string\"},\"type\":\"object\"}",
      "required": true
    },
    {
      "name": "threshold",
      "description": "Provide as a JSON string matching the following schema: {\"type\":\"number\"}",
      "required": true
    }
  ]
}

客户端调用提示词

python 复制代码
{
  "numbers": "[1, 2, 3, 4, 5]",
  "metadata": "{\"source\": \"api\", \"version\": \"1.0\"}",
  "threshold": "2.5"
}

直接使用定义的类型调用

python 复制代码
# This also works for direct calls
result = await prompt.render({
    "numbers": [1, 2, 3, 4, 5],
    "metadata": {"source": "api", "version": "1.0"}, 
    "threshold": 2.5
})

注意事项

使用此功能时,请保持类型注解简洁。复杂的嵌套类型或自定义类可能无法从 JSON 字符串中可靠地转换。自动生成的模式描述是用户获得的关于预期格式的唯一指导。

合适的选择:list [int]、dict [str, str]、float、bool

应避免的:复杂的 Pydantic 模型、深度嵌套结构、自定义类

五、返回值

FastMCP 能智能处理来自提示函数的不同返回类型:

  • str:自动转换为单个 PromptMessage
  • PromptMessage:按提供的样子直接使用。(有一个更易用的 Message 构造函数,它可以接受原始字符串,而非 TextContent 对象。)
  • list [PromptMessage | str]:用作消息序列(一次对话)。
  • PromptResult:可完全控制消息、描述和元数据。
  • Any:如果返回类型不是上述类型之一,会尝试将返回值转换为字符串,并用作 PromptMessage
python 复制代码
from fastmcp.prompts.prompt import Message

@mcp.prompt
def roleplay_scenario(character: str, situation: str) -> list[Message]:
    """Sets up a roleplaying scenario with initial messages."""
    return [
        Message(f"Let's roleplay. You are {character}. The situation is: {situation}"),
        Message("Okay, I understand. I am ready. What happens next?", role="assistant")
    ]

六、提示词结果

要完全控制提示响应,请返回一个 PromptResult 对象。这使您能够在提示消息旁包含元数据,这对于向客户端传递运行时信息非常有用。

python 复制代码
from fastmcp import FastMCP
from fastmcp.prompts import PromptResult, Message

mcp = FastMCP(name="PromptServer")

@mcp.prompt
def code_review(code: str) -> PromptResult:
    """Returns a code review prompt with metadata."""
    return PromptResult(
        messages=[
            Message(f"Please review this code:\n\n```\n{code}\n```"),
        ],
        description="Code review prompt",
        meta={"review_type": "security", "priority": "high"}
    )

PromptResult的字段

  • message 一个代表要发送给大语言模型的对话的 PromptMessageMessage 对象列表
  • description 提示结果的可选描述。如果未提供,默认使用提示的文档字符串。
  • meta 可选的元数据字典,它将包含在 MCP 响应的_meta 字段中。可将其用于运行时元数据,如分类、优先级或其他特定于客户端的数据。

PromptResult 中的 meta 字段用于存储特定于此次渲染响应的运行时元数据。这与 @mcp.prompt (meta={...}) 中的 meta 参数不同,后者提供的是关于提示定义本身的静态元数据(在列出提示时返回)。

你仍然可以从你的提示函数中返回普通字符串、PromptMessage 或列表 ------ 只有当你需要包含元数据时,才需要选用 PromptResult。

函数签名中的参数除非有默认值,否则都被视为必填参数。

python 复制代码
@mcp.prompt
def data_analysis_prompt(
    data_uri: str,                        # Required - no default value
    analysis_type: str = "summary",       # Optional - has default value
    include_charts: bool = False          # Optional - has default value
) -> str:
    """Creates a request to analyze data with specific parameters."""
    prompt = f"Please perform a '{analysis_type}' analysis on the data found at {data_uri}."
    if include_charts:
        prompt += " Include relevant charts and visualizations."
    return prompt

在这个示例中,客户端必须提供 data_uri。如果省略 analysis_type 或 include_charts,将使用它们的默认值。

七、禁用提示

你可以通过启用或禁用提示词来控制它们的可见性和可用性。禁用的提示词不会出现在可用提示词列表中,且尝试调用禁用的提示词会导致 "未知提示词" 错误。

默认情况下,所有提示词都是启用的。你可以在创建提示词时,通过装饰器中的 enabled 参数来禁用它:

python 复制代码
@mcp.prompt(enabled=False)
def experimental_prompt():
    """This prompt is not ready for use."""
    return "This is an experimental prompt."

创建提示词后,你还可以通过编程方式切换其状态:

python 复制代码
@mcp.prompt
def seasonal_prompt(): return "Happy Holidays!"

# Disable and re-enable the prompt
seasonal_prompt.disable()
seasonal_prompt.enable()

八、异步提示词

FastMCP 无缝支持标准函数(def)和异步函数(async def)作为提示词。

python 复制代码
# Synchronous prompt
@mcp.prompt
def simple_question(question: str) -> str:
    """Generates a simple question to ask the LLM."""
    return f"Question: {question}"

# Asynchronous prompt
@mcp.prompt
async def data_based_prompt(data_id: str) -> str:
    """Generates a prompt based on data that needs to be fetched."""
    # In a real scenario, you might fetch data from a database or API
    async with aiohttp.ClientSession() as session:
        async with session.get(f"https://api.example.com/data/{data_id}") as response:
            data = await response.json()
            return f"Analyze this data: {data['content']}"

当你的提示函数执行网络请求、数据库查询、文件 I/O 或外部服务调用等 I/O 操作时,请使用 async def。

九、访问MCP Context

提示词可以通过 Context 对象访问额外的 MCP 信息和功能。要访问它,请向你的提示词函数添加一个带有 Context 类型注解的参数:

python 复制代码
from fastmcp import FastMCP, Context

mcp = FastMCP(name="PromptServer")

@mcp.prompt
async def generate_report_request(report_type: str, ctx: Context) -> str:
    """Generates a request for a report."""
    return f"Please create a {report_type} report. Request ID: {ctx.request_id}"

十、通知

当提示词被添加、启用或禁用时,FastMCP 会自动向连接的客户端发送通知 / 提示词 / 列表变更通知。这使得客户端无需手动轮询变更,就能随时了解当前提示词集的最新情况。

python 复制代码
@mcp.prompt
def example_prompt() -> str:
    return "Hello!"

# These operations trigger notifications:
mcp.add_prompt(example_prompt)  # Sends prompts/list_changed notification
example_prompt.disable()        # Sends prompts/list_changed notification  
example_prompt.enable()         # Sends prompts/list_changed notification

只有当这些操作在活跃的 MCP 请求上下文中发生时(例如,从工具或其他 MCP 操作内部调用时),才会发送通知。服务器初始化期间执行的操作不会触发通知。

客户端可以使用消息处理器来处理这些通知,以自动刷新其提示列表或更新其界面。

十一、重复的提示词

您可以配置 FastMCP 服务器如何处理注册多个具有相同名称的提示的尝试。在 FastMCP 初始化期间使用 on_duplicate_prompts 设置即可。

python 复制代码
from fastmcp import FastMCP

mcp = FastMCP(
    name="PromptServer",
    on_duplicate_prompts="error"  # Raise an error if a prompt name is duplicated
)

@mcp.prompt
def greeting(): return "Hello, how can I help you today?"

# This registration attempt will raise a ValueError because
# "greeting" is already registered and the behavior is "error".
# @mcp.prompt
# def greeting(): return "Hi there! What can I do for you?"

重复行为选项包括:

  • "warn" (default): 记录一个警告,并且新的提示词会替换旧的提示词。
  • "error": 引发ValueError,防止重复注册。
  • "replace": 默默地用新提示替换现有的提示。
  • "ignore": 保留原始提示并忽略新的注册
相关推荐
路边草随风8 小时前
langchain agent动态变更系统prompt
人工智能·python·langchain·prompt
TracyCoder1239 小时前
BERT:让模型 “读懂上下文” 的双向语言学习法
人工智能·深度学习·bert
亚马逊云开发者15 小时前
Q CLI 助力合合信息实现 Aurora 的升级运营
人工智能
全栈胖叔叔-瓜州16 小时前
关于llamasharp 大模型多轮对话,模型对话无法终止,或者输出角色标识User:,或者System等角色标识问题。
前端·人工智能
坚果派·白晓明17 小时前
AI驱动的命令行工具集x-cmd鸿蒙化适配后通过DevBox安装使用
人工智能·华为·harmonyos
GISer_Jing17 小时前
前端营销技术实战:数据+AI实战指南
前端·javascript·人工智能
Dekesas969517 小时前
【深度学习】基于Faster R-CNN的黄瓜幼苗智能识别与定位系统,农业AI新突破
人工智能·深度学习·r语言
大佐不会说日语~17 小时前
Spring AI Alibaba 的 ChatClient 工具注册与 Function Calling 实践
人工智能·spring boot·python·spring·封装·spring ai
CeshirenTester18 小时前
Playwright元素定位详解:8种定位策略实战指南
人工智能·功能测试·程序人生·单元测试·自动化