news 2026/8/14 15:17:34

Prompts原语:标准化提示词模板

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Prompts原语:标准化提示词模板

摘要:MCP Prompts原语提供标准化提示词模板,支持参数化注入和组合调用。本文详解提示定义、消息构建、客户端调用流程和提示与工具的联动设计。

Prompts原语标准化提示词模板

前阵子我给团队维护一坨提示词,散落在十几个Python文件里,每人写法都不一样,有人把system prompt硬编码,有人用f-string拼,改一个变量得全局搜一遍。后来我把这些提示词迁移到MCP的Prompts原语里,统一用参数化模板管理,客户端能自动发现并填参数,团队再也没为"谁的提示词版本对"吵过架。这篇我把Prompts原语的设计理念和用法讲透。


Prompts原语的设计理念

MCP规范里Prompts原语让Server定义可复用的提示词模板和工作流,客户端能直接展示给用户和模型。它的核心定位是user-controlled,由用户主动选择使用,这点和Resources一样,和Tools的model-controlled不同。

Prompts的设计目标是标准化和共享。你在Server端定义好模板,参数化,加描述,任何MCP客户端连上来都能发现这些模板,用户像选斜杠命令一样选用,填几个参数就能生成一段完整的对话消息。团队共享提示词这件事从"复制粘贴代码"变成了"连同一个Server"。

一个Prompt的定义包含这些字段。name是唯一标识,description是人可读的描述,arguments是可选的参数列表,每个参数有name、description和required。客户端拿这些信息自动生成输入表单。

参数化提示模板

参数化是Prompts最实用的特性。你定义一个函数,参数就是模板变量,客户端调用时传参,函数返回组装好的消息。下面是规范里analyze-code这个prompt的参数定义。

{"name":"analyze-code","description":"Analyze code for potential improvements","arguments":[{"name":"language","description":"Programming language","required":true}]}

用FastMCP定义参数化prompt非常直观,函数参数就是模板参数,有默认值的算可选,没默认值的算必填。FastMCP还会解析docstring自动提取每个参数的描述,省得你手动写。

我发现一个隐藏好处,参数化模板天然防注入。以前用f-string拼提示词,用户输入直接插进去,容易被prompt injection。现在参数走JSON Schema校验,我在函数里做转义和校验,安全性好很多。

多消息组合与嵌入资源

Prompts不只能返回单条消息,它能返回一整个消息序列,模拟一段多轮对话。每条消息有role,可以是user或assistant。这让你能预设对话上下文,模型接手时已经有了"开场白"。

更强大的能力是嵌入资源。Prompt的消息内容可以是text类型,也可以是resource类型,直接把一个Resource的内容塞进消息里。这样你能把日志文件、代码文件和提问组合在一起,模型一次拿到完整上下文。

我做过一个debug-error的prompt模板,第一条user消息放错误描述,第二条assistant消息预设回应"我来帮你分析",第三条user消息嵌入日志资源。模型接手时对话已经有了结构,分析质量明显比单条消息高。

完整代码

下面是完整的Prompts示例,包含单消息模板、多消息组合和嵌入资源的模板。客户端测试脚本调用这些prompt。

server.py

# server.py MCP Prompts原语完整示例# 运行方式 python server.py# 依赖安装 pip install fastmcpfromfastmcpimportFastMCP,Contextfromfastmcp.promptsimportMessage# 创建服务器实例mcp=FastMCP(name="PromptTemplatesServer")# ---------- 简单的单消息prompt ----------@mcp.promptdefcode_review(code:str,language:str="python")->str:"""生成代码审查请求的提示词. Args: code: 要审查的代码片段. language: 代码的编程语言, 默认python. """# 拼装提示词, 参数已经被FastMCP校验过return(f"请审查以下{language}代码, 重点关注潜在bug、"f"性能问题和可读性.\n\n"f"```\n{code}\n```")# ---------- 多消息组合prompt ----------@mcp.promptdefdebug_workflow(error:str)->list[Message]:"""生成调试工作流的多轮对话. Args: error: 遇到的错误描述. """# 返回多条消息, 模拟一段预设的对话开场return[# 第一条, 用户描述问题Message(f"我遇到了这个错误, 请帮我分析{error}"),# 第二条, assistant预设回应, 引导用户继续Message("好的, 我来帮你分析这个错误. 请问你之前尝试过什么方法?",role="assistant"),]# ---------- 带上下文的prompt, 读取资源嵌入 ----------@mcp.promptasyncdefanalyze_with_context(question:str,file_path:str,ctx:Context,)->list[Message]:"""结合文件内容生成分析请求. Args: question: 要分析的问题. file_path: 要参考的文件路径. """# 通过Context读取服务器上的资源, 获取文件内容# 这里复用上一篇Resources里的思路, 直接read_resourcecontents=awaitctx.read_resource(f"file:///{file_path}")file_content=contents[0].contentifcontentselse"文件为空"# 组合问题和文件内容, 让模型同时看到两者return[Message(f"请基于以下文件内容回答我的问题.\n\n问题{question}"),Message(f"以下是文件{file_path}的内容\n\n{file_content}"),]# ---------- 返回PromptResult, 带元数据 ----------@mcp.promptdefsummarize_text(text:str)->str:"""生成文本摘要请求. Args: text: 需要摘要的长文本. """returnf"请用三句话总结以下内容的核心要点.\n\n{text}"if__name__=="__main__":mcp.run()

client_test.py

# client_test.py Prompts客户端测试# 运行方式 python client_test.pyimportasynciofromfastmcpimportClientasyncdefmain():asyncwithClient("server.py")asclient:# 第一步, 列出所有可用prompt, 相当于发prompts/listprompts=awaitclient.list_prompts()print("=== 可用Prompt列表 ===")forpinprompts:print(f" 名称{p.name}")print(f" 描述{p.description}")print()# 第二步, 调用单消息prompt, 相当于发prompts/getprint("=== 调用 code_review ===")result=awaitclient.get_prompt("code_review",{"code":"def add(a, b): return a + b","language":"python"},)# result.messages 是返回的消息列表formsginresult.messages:print(f" 角色{msg.role}")print(f" 内容{msg.content.text}")print()# 第三步, 调用多消息promptprint("=== 调用 debug_workflow ===")result=awaitclient.get_prompt("debug_workflow",{"error":"TypeError unsupported operand type(s) for + int and str"},)formsginresult.messages:print(f" 角色{msg.role}")print(f" 内容{msg.content.text}")print()# 第四步, 调用摘要promptprint("=== 调用 summarize_text ===")result=awaitclient.get_prompt("summarize_text",{"text":"MCP是一个开放协议, 让大模型连接外部工具和数据源. 它定义了统一的通信标准."},)formsginresult.messages:print(f" 角色{msg.role}")print(f" 内容{msg.content.text}")if__name__=="__main__":asyncio.run(main())

效果验证

装好fastmcp后跑client_test.py,输出大致如下。

=== 可用Prompt列表 === 名称 code_review 描述 生成代码审查请求的提示词. 名称 debug_workflow 描述 生成调试工作流的多轮对话. 名称 analyze_with_context 描述 结合文件内容生成分析请求. 名称 summarize_text 描述 生成文本摘要请求. === 调用 code_review === 角色 user 内容 请审查以下python代码, 重点关注潜在bug、性能问题和可读性.

def add(a, b): return a + b

=== 调用 debug_workflow === 角色 user 内容 我遇到了这个错误, 请帮我分析 TypeError unsupported operand type(s)... 角色 assistant 内容 好的, 我来帮你分析这个错误. 请问你之前尝试过什么方法?

客户端list到四个prompt,再分别get调用,拿到组装好的消息序列。在真实MCP客户端里,这些prompt会变成斜杠命令或快捷操作,用户点一下填参数就能用。

与普通Prompt工程的区别

很多人觉得Prompts原语就是换了个地方写提示词,其实区别挺大。我做了个对比。

维度MCP Prompts普通Prompt工程
存储位置集中在Server端管理散落在代码或配置文件
发现方式客户端自动prompts/list发现手动维护文档或代码
参数化协议级参数校验和描述自己写f-string或模板引擎
共享范围任何MCP客户端连上就能用绑定特定应用代码
多消息原生支持多轮对话序列手动拼接消息数组
嵌入资源直接把Resource嵌入消息自己读文件再拼字符串

最实际的区别在团队协作。普通Prompt工程里,提示词改了得改代码、发版本、通知所有人。用Prompts原语,提示词在Server端维护,改了客户端自动发现新版本,零成本同步。

我团队之前有个code-review的提示词,三个人各自维护了一份,参数名都不一样。迁到Prompts原语后统一成一个code_review模板,参数叫code和language,所有人用的都是同一份,再也没出过版本不一致的问题。

常见问题与避坑

坑1,必填参数没传导致get失败。Prompt的required参数客户端必须传,漏传一个prompts/get直接报错。FastMCP里没默认值的参数就是必填的,定义模板时想清楚哪些参数真的必填,能给默认值的就给。

坑2,多消息prompt的role用错。Message默认role是user,预设assistant回应时忘了传role=“assistant”,模型把预设回应也当成用户输入,对话逻辑就乱了。多消息场景每条消息都要确认role对不对。

坑3,嵌入资源时URI写错读不到内容。Prompt里嵌入resource消息时,URI要和Resources里定义的一致。我之前模板里写了file:///notes.txt但实际资源URI是file:///{path}模板,read的时候传错了路径拿空内容。嵌入资源前先确认URI能read成功。

坑4,提示词里直接拼接用户输入被注入。参数化模板降低了风险,但如果直接把用户输入拼进提示词文本,还是有prompt injection的风险。对用户输入做长度限制和必要的转义,特别是code这种可能包含特殊内容的参数。

坑5,docstring格式不规范导致描述丢失。FastMCP靠解析docstring提取参数描述,格式不对就提取不到。用Google或NumPy风格的docstring,Args段落写清楚每个参数,FastMCP会自动填充到协议的argument description里。

小结

Prompts原语把提示词模板标准化了。核心要点有三个,参数化模板让提示词可复用可校验,多消息组合支持预设对话上下文,嵌入资源让模型一次拿到完整背景。和普通Prompt工程相比,Prompts原语的优势在集中管理、自动发现和团队共享。下一篇我们进入一个相对反直觉的原语,Sampling,它让Server反过来请求Client的LLM能力。


相关推荐

  • MCP三大原语初体验:Tools、Resources、Prompts一个都不少
    • 提示模板开发:参数化提示与组合提示
    • Tools原语深度解析:从定义到调用全流程
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/14 15:16:11

正则分组/php5版本下preg_replace /e模式下的代码执行

免责声明 本文全部实验操作均在本人完全可控的自建本地靶场环境完成,文章仅用于网络安全原理学习与技术研究。 根据《中华人民共和国网络安全法》,未经授权对任何第三方系统进行探测、命令执行、文件写入等操作属于违法行为。严禁复制、使用本文中的 Pay…

作者头像 李华
网站建设 2026/8/14 15:13:31

Kimi LeetCode 3906. 统计网格路径中好整数的数目 Rust实现

以下是 LeetCode 3906 的 Rust 实现,采用数位 DP 思路,核心是将路径上访问的 7 个格子标记为关键位,然后对 [0, x] 范围内的数进行记忆化搜索。rust impl Solution {pub fn count_good_integers_on_path(l: i64, r: i64, directions: String)…

作者头像 李华
网站建设 2026/8/14 15:04:10

Portainer:Docker可视化Web管理面板的新手首选方案

一、Portainer基本特性与优势分析Portainer作为一款轻量级的Docker可视化Web管理面板,专为简化容器管理而设计,特别适合新手用户。它通过直观的图形界面将复杂的Docker命令操作转化为简单的点击操作,大大降低了容器技术的使用门槛。Portainer…

作者头像 李华