python-sdk/i18n/zh/pages/servers/prompts.md

151 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
translation:
sections: [d65c098f37f5b6c3, dd0c2724d6f2877e, 6835bb3570c6714c, ffe823cb0fedd488, f33651add1b59094]
tool: 1
---
# 提示词 {#prompts}
**提示词**是由用户挑选的消息模板。
工具是给模型用的。提示词正好相反:用户在客户端的菜单里(比如斜杠命令或按钮)选一个,填好参数,渲染出来的消息就进入对话,就像是用户自己打出来的一样。
在一个返回文本的函数上加 `@mcp.prompt()`,就声明了一个提示词。
## 第一个提示词 {#your-first-prompt}
```python title="server.py" hl_lines="6-9"
--8<-- "docs_src/prompts/tutorial001.py"
```
SDK 从中读取的三样东西和工具一样:
* **名称**就是函数名:`review_code`。
* 客户端显示的**描述**是 docstring:`Review a piece of code.`
* **参数**来自函数的形参。`code` 没有默认值,所以是必填的。
客户端从 `prompts/list` 拿到的就是这些:
```json
{
"name": "review_code",
"description": "Review a piece of code.",
"arguments": [
{"name": "code", "required": true}
]
}
```
这里没有 JSON Schema。提示词的参数是一个扁平的**具名字符串值**列表:是给人填的表单,而不是由模型构造的载荷。
### 渲染 {#rendering-it}
客户端用 `prompts/get` 渲染模板,并传入参数。你的函数运行后,返回的 `str` 会变成**一条用户消息**:
```json
{
"description": "Review a piece of code.",
"messages": [
{
"role": "user",
"content": {
"type": "text",
"text": "Please review this code:\n\ndef add(a, b): return a + b"
}
}
],
"resultType": "complete"
}
```
提示词的完整流程就是这样:按名称列出,按需渲染,放进对话。
!!! check
`required` 的检查发生在你的函数运行之前。渲染 `review_code` 时不传 `code`,请求本身就会失败,并返回一个 JSON-RPC 错误(错误码 `-32603`):
```text
mcp.shared.exceptions.MCPError: Internal server error
```
这里没有工具那种可以交回给模型的错误结果,因为整个环节里根本没有模型:调用会直接抛出异常。原因(`Missing required arguments: {'code'}`)会记在服务器的日志里。
### 试一试 {#try-it}
用 MCP Inspector 运行服务器:
```console
uv run mcp dev server.py
```
打开 **Prompts** 标签页,选择 `review_code`。Inspector 会画出一个表单,带一个必填的 `code` 字段。填好、渲染,返回的正是上面那条用户消息。
## 不止一条消息 {#more-than-one-message}
代码审查只要一条消息。调试则是一段对话,而提示词可以把整段对话的开头都铺好。
把返回值从 `str` 换成消息列表:
```python title="server.py" hl_lines="2 13-20"
--8<-- "docs_src/prompts/tutorial002.py"
```
* `UserMessage` 和 `AssistantMessage` 来自 `mcp.server.mcpserver.prompts.base`。给它们一个 `str`,它们会替你包装成 `TextContent`。角色由类名决定。
* `Message` 是它们的公共基类。用它作返回值注解。
现在渲染 `debug_error` 会按顺序产生三条消息:
```json
{
"description": "Start a debugging conversation.",
"messages": [
{"role": "user", "content": {"type": "text", "text": "I'm seeing this error:"}},
{"role": "user", "content": {"type": "text", "text": "TypeError: 'int' object is not iterable"}},
{
"role": "assistant",
"content": {"type": "text", "text": "I'll help debug that. What have you tried so far?"}
}
],
"resultType": "complete"
}
```
注意最后一条。预先填入一轮 `assistant` 发言,就能引导模型的**下一条**回复,而不用让用户自己把引导的话敲出来。
## 标题和参数描述 {#titles-and-argument-descriptions}
`review_code` 是函数名,不是标签。给客户端一个更适合放在按钮上的名字,并给每个参数加上描述,让表单一目了然:
```python title="server.py" hl_lines="10-13"
--8<-- "docs_src/prompts/tutorial003.py"
```
* `title="Code review"` 是给人看的名称,和工具的 `title` 一模一样。
* `Annotated[str, Field(description=...)]` 和 **[工具](tools.md)** 用来描述工具参数的是同一种写法。这里描述直接落在参数上,而不是写进模式里。
* `language` 有默认值,所以不再是必填参数。
现在 `prompts/list` 里的这一项包含了客户端画好一个表单所需的全部信息:
```json
{
"name": "review_code",
"title": "Code review",
"description": "Review a piece of code.",
"arguments": [
{"name": "code", "description": "The code to review.", "required": true},
{"name": "language", "description": "The language the code is written in.", "required": false}
]
}
```
!!! info
如果读过 **[工具](tools.md)**,这一页的内容你其实都已经会了。装饰器一样,用 docstring 作描述一样,`Annotated`/`Field` 也一样。变的只有两点:由谁触发(用户),以及结果去哪儿(进入对话)。
## 回顾 {#recap}
* 在函数上加 `@mcp.prompt()`,它就成了提示词。名称取自函数名,描述取自 docstring。
* 提示词由**用户控制**:客户端列出它们,用户选一个并填好参数。
* 参数是一个扁平的具名字符串列表(没有模式)。有默认值的形参是可选的。
* 返回 `str`,它就变成一条用户消息。返回 `UserMessage` / `AssistantMessage` 的列表,可以为多轮对话铺好开头。
* `title=` 和 `Field(description=...)` 是客户端放进 UI 里的内容。
* 缺少必填参数会让整个请求失败。没有针对单个提示词的错误结果。
要在服务器端为提示词(或资源模板)的参数提供自动补全,见 **[补全](completions.md)**。