Prompt、Skill 与 MCP 不是三种写法:客服 AI 出错,往往是内容放错了位置

我把退款规则写得非常详细,模型也能准确复述规则。

可到了实际运行时,它没有查询订单,就直接告诉用户:

“您的退款已经成功,款项将原路退回。”

问题是,退款工具根本没有被调用,系统也没有返回任何成功结果。

规则写错了吗?没有。模型没看懂吗?也不是。

真正的问题,是规则写在了错误的位置。

很多人搭建 AI 客服时,会把退款政策、订单号、工具参数、回复语气、人工升级条件全部塞进一条超长 Prompt。后来接入技能文件和 MCP,又把同样的内容复制过去。

最终出现了三份“看起来差不多”的说明。

它们单独看都很合理,放在一起却可能造成上下文膨胀、规则冲突、工具误调用,甚至让模型把“符合退款条件”误解成“拥有退款权限”。

这不是 Prompt 写作问题,而是一个小型的 AI 应用架构问题

同一个客服任务,为什么会出现三份说明?

假设用户提出这样的要求:

订单物流延迟,我已经不需要商品了,希望立即退款。

模型需要完成五件事:

1. 查询订单真实状态;

2. 检查订单是否符合退款政策;

3. 判断是否需要人工介入;

4. 在执行退款前取得用户确认;

5. 根据真实处理结果生成客服回复。

最常见的做法,是把整套要求全部写进 Prompt:

你是一名客服。退款规则是:未发货订单可以申请退款,

已发货订单需要判断是否能够拦截……

所有订单都先调用 get_order。

get_order 参数包括 order_id,返回订单状态、支付状态……

当前订单号是 CN2025XXXX。

如果退款金额超过 500 元,需要升级人工客服。

如果符合退款条件,调用 create_refund_request。

回复必须使用友好的中文,并控制在 150 字以内。

这段话混合了至少四类内容:

  • 当前用户和订单信息;
  • 长期有效的退款政策;
  • 工具参数与调用方法;
  • 本轮回复格式。

当系统规模很小时,它可能可以运行。但随着政策更新、工具增加和客服场景变复杂,这条 Prompt 会像一个不断塞东西的行李箱:不是装不下,而是每次找东西都更困难。

正确的理解不是“Prompt、Skill 和 MCP 应该选哪一个”,而是:

  • Prompt:这一次要做什么
  • 技能文件:这类任务通常怎么做
  • MCP 工具说明:模型可以调用什么、应该怎么调用
  • 服务端:这个动作到底允不允许执行

需要说明的是,不同产品对“技能文件”的命名和加载机制并不相同。有些叫 Skill,有些叫知识文件、规则模块或工作流说明。

本文讨论的是它们共同承担的角色:可复用、可维护的流程与领域知识层。

三层到底各管什么?

先看这张职责边界表。

| 维度 | Prompt | 技能文件 | MCP 工具说明 | | 核心职责 | 当前任务与上下文 | 可复用流程与知识 | 外部能力接口契约 | | 生命周期 | 单轮或短期 | 中长期、可版本化 | 随工具接口更新 | | 典型内容 | 用户诉求、订单号、语气 | SOP、政策、判断步骤 | 参数、返回值、错误信息 | | 不该放什么 | 大量长期规则 | 当前用户敏感数据 | 长篇话术、完整业务制度 | | 常见故障 | Prompt 膨胀 | 数据污染、规则冲突 | 误调用、参数猜测 | | 谁负责维护 | 使用者或应用 | 业务与知识维护者 | 工具开发者 |

Prompt:描述“这一次”

Prompt 最适合承载具有临时性的内容,例如:

  • 当前用户希望退款;
  • 当前订单号;
  • 用户给出的退款原因;
  • 本轮回复使用中文;
  • 回复控制在指定长度内;
  • 这次需要先解释,再询问确认。

判断标准很简单:

换一个用户、一个订单或一次会话,这段内容是否可能改变?

如果答案是“会”,它通常应该放在 Prompt。

技能文件:规定“这一类任务怎么处理”

技能文件负责沉淀相对稳定、可以重复使用的业务流程,例如:

  • 退款客服的标准处理顺序;
  • 如何判断订单状态;
  • 需要收集哪些证据;
  • 哪些情况必须升级人工;
  • 如何区分“已提交退款申请”和“退款已到账”;
  • 回复中不能泄露哪些内部信息。

技能文件不应该保存某个用户的订单号、手机号、地址和会话 Cookie。

Skill 是流程说明书,不是用户数据仓库。

MCP 工具说明:定义“模型能调用什么”

MCP 工具说明更像一份给模型阅读的 API 契约,应该清楚回答:

  • 这个工具有什么用途;
  • 什么时候应该调用;
  • 需要传入哪些参数;
  • 哪些参数是必填项;
  • 返回值包含哪些字段;
  • 可能返回哪些错误;
  • 是否要求确认、权限或幂等键。

例如,查询订单工具可以这样描述:

{

"name": "get_order",

"description": "根据订单号查询订单的当前状态。仅返回系统中的真实订单数据,不负责判断退款政策。",

"inputSchema": {

"type": "object",

"properties": {

"order_id": {

"type": "string",

"description": "完整订单号"

}

},

"required": ["order_id"]

}

}

这里最重要的一句话是:

“不负责判断退款政策。”

工具负责返回事实,技能负责解释事实,Prompt 则提供当前任务。

三者一旦混在一起,模型就容易分不清“查到了什么”和“应该怎么处理”。

MCP 工具说明不是安全控制

这是最容易被误解的边界。

假设你在退款工具描述中写道:

退款金额超过 500 元时禁止调用本工具。

它可以提醒模型不要调用,但不能形成真正的安全边界。

模型可能因为上下文冲突、指令注入或金额解析错误,仍然发起调用。真正可靠的做法,是由工具服务端再次检查:

  • 当前账号是否有退款权限;
  • 订单是否属于当前用户;
  • 退款金额是否超过操作额度;
  • 是否已经取得有效确认;
  • 同一订单是否重复提交;
  • 请求是否进入审计记录。
MCP 工具说明是给模型看的“能力契约”,不是业务制度,更不是鉴权系统。

内容放错层,会发生什么?

实验一:把全部 SOP 塞进 Prompt

它通常可以运行,而且在 Demo 阶段看起来很方便。

问题会在维护阶段出现:

  • 每次请求都重复发送大量相同规则;
  • 不同客服复制了不同版本;
  • 政策更新后,旧 Prompt 仍在流通;
  • 临时要求和长期规则互相覆盖;
  • Prompt 越长,定位冲突越困难。

例如,旧版 Prompt 写着“退款前必须确认”,新版 Prompt 改成“未发货订单可以直接提交”。两个版本同时存在时,问题就不再是模型能力,而是规则版本已经失控

截图 1:全部塞进 Prompt 的运行结果
发布时请插入真实测试截图,并标注:输入上下文长度、实际调用工具、传入参数、工具是否返回结果,以及最终回复是否错误承诺。本文未获得对应运行日志,因此不虚构 Token 数和调用数据。

实验二:把当前订单写进技能文件

例如有人为了“省得每次输入”,把技能文件写成:

当前订单号:CN2025XXXX

用户原因:物流延迟

退款金额:628 元

这会让一个本应长期复用的技能文件,被某次会话污染。

后续可能出现:

  • 新用户请求误用旧订单号;
  • 订单状态早已变化,文件中仍是旧数据;
  • 多个用户的数据出现在同一个上下文;
  • 技能文件进入版本库,造成隐私泄露;
  • 测试环境的数据被误用于生产环境。

如果说 Prompt 膨胀只是“费”,那么用户数据写进 Skill 就可能变成“险”。

实验三:把退款政策塞进工具描述

有人会把工具说明写成这样:

当订单延迟、商品损坏、未发货或用户不再需要时,

根据退款政策判断是否可以退款,并使用安抚语气回复用户。

符合条件时立即创建退款……

这段描述把接口、政策、判断和话术揉在了一起。

模型可能因此:

  • 把创建退款工具当成退款资格判断工具;
  • 尚未查询订单就过早发起退款;
  • 在多个相似工具之间做出错误选择;
  • 认为“文字上符合条件”就等于“服务端允许退款”。
截图 2:工具描述混入业务规则后的调用轨迹
建议展示模型实际选择了哪个工具、是否先调用 get_order、是否获得真实订单状态、是否在确认前调用退款工具。若没有真实日志,不应制作带有虚构数据的“实测截图”。

还有一种反向错误:工具参数只写在 Prompt 或技能文件里,MCP 工具自身却描述含糊。

这种情况下,模型可能猜测参数名,把 order_id 写成 orderNumber;也可能不知道错误码含义,在超时后重复提交,造成重复操作。

放错位置的故障表

| 放错方式 | 表面上能否运行 | 长期问题 | |---|---:|---| | SOP 全写进 Prompt | 通常能 | 重复消耗、版本漂移 | | 用户数据写进技能文件 | 可能能 | 串单、过期、隐私风险 | | 工具参数只写进技能文件 | 不稳定 | 参数猜测、调用失败 | | 业务政策全塞工具描述 | 可能能 | 工具选择困难、职责混乱 | | 把权限规则只写成自然语言 | 表面能 | 无法形成真正安全边界 | | 把工具调用结果预写进 Prompt | 看似顺畅 | 模型伪造执行结果 |

现场重构:把一份总指令拆回三层

现在,我们把前面的混乱指令重新拆解。

第一步:Prompt 只保留当前任务

当前用户希望取消订单并退款。

订单号:CN2025XXXX

用户原因:物流延迟,已不再需要商品

请按照退款客服技能处理:

1. 先确认订单真实状态;

2. 未获得工具返回前,不要声称退款成功;

3. 如需执行不可逆操作,先向用户确认;

4. 最终使用简洁、友好的中文回复,控制在 150 字以内。

这里保留的是:

  • 当前订单;
  • 当前诉求;
  • 本轮回复要求;
  • 针对当前任务的操作提醒。

第二步:Skill 保存稳定流程

# 退款客服技能

处理流程

1. 查询订单状态;

2. 核对支付状态、发货状态和退款资格;

3. 符合条件时,向用户说明退款金额与预计到账时间;

4. 执行退款前取得明确确认;

5. 超过权限额度或政策存在冲突时,升级人工客服。

回复原则

  • 不承诺工具尚未确认的结果;
  • 区分“已提交退款申请”和“退款已到账”;
  • 不向用户暴露内部错误栈或敏感字段。

这份技能可以服务于不同用户和不同订单,也可以独立进行版本管理。

第三步:MCP 工具说明明确接口契约

查询订单用 get_order,判断资格可以使用 check_refund_eligibility,真正创建申请则使用 create_refund_request

退款工具应把高风险调用条件写清楚:

{

"name": "create_refund_request",

"description": "为符合条件的订单创建退款申请。调用成功仅表示申请已提交,不表示退款已到账。服务端会再次执行订单归属、退款资格、操作权限和重复请求校验。",

"inputSchema": {

"type": "object",

"properties": {

"order_id": {

"type": "string",

"description": "完整订单号"

},

"amount": {

"type": "number",

"description": "申请退款金额"

},

"reason": {

"type": "string",

"description": "退款原因"

},

"confirmation_token": {

"type": "string",

"description": "用户明确确认后生成的有效确认凭证"

},

"idempotency_key": {

"type": "string",

"description": "本次退款请求的唯一幂等键,用于防止重复提交"

}

},

"required": [

"order_id",

"amount",

"reason",

"confirmation_token",

"idempotency_key"

]

}

}

工具服务端还应定义并实际返回明确的错误类型,例如:

  • ORDER_NOT_FOUND:订单不存在;
  • PERMISSION_DENIED:当前主体无权操作;
  • CONFIRMATION_REQUIRED:缺少有效确认;
  • REFUND_NOT_ELIGIBLE:服务端判定不符合退款资格;
  • DUPLICATE_REQUEST:检测到重复提交。

这些错误不是为了让模型“背代码”,而是为了避免模型在调用失败后自行脑补结果。

正确的完整执行链是什么?

完成三层拆分后,一次可靠的执行顺序应该是:

1. 模型读取 Prompt,识别当前订单与退款诉求;

2. 加载退款客服 Skill,获得标准处理流程;

3. 调用 get_order 查询真实订单状态;

4. 调用资格检查工具,或根据受控政策完成判断;

5. 向用户说明可申请金额及下一步;

6. 在不可逆操作前取得明确确认;

7. 携带确认凭证和幂等键调用退款工具;

8. 根据工具真实返回值生成回复;

9. 权限不足、政策冲突或状态异常时升级人工。

注意第 8 步:如果工具只返回“申请已提交”,模型就不能回复“退款已到账”。

语言必须服从系统事实,而不是为了让客服回复显得更完整,就补上一个并不存在的结果。 截图 3:三层拆分后的完整执行轨迹
建议在截图中依次标注:加载技能、调用 get_order、传入订单号、获得真实返回、请求用户确认、调用退款工具、读取成功或错误结果、生成最终回复。截图应来自同一测试任务,避免用不同案例拼接。

安全提醒:有些东西不属于任何文本层

API Key、Cookie、用户密码不应写入 Prompt、技能文件或工具说明。

此外,还要遵守四条底线:

  • “禁止退款超过 500 元”不能只靠提示词执行,服务端必须再次校验;
  • 涉及退款、删除、发送、购买等不可逆操作,应设计明确确认机制;
  • 高风险工具应使用幂等键,避免重试造成重复退款、重复发送或重复购买;
  • 工具说明可以帮助模型正确调用能力,但不能替代鉴权、审计与风控。

即使模型完全没有按照 Prompt 行事,服务端也应该能够拒绝越权操作。

这才叫安全边界。

一套可以直接复用的判断法

以后再遇到一段说明不知道放在哪里,可以按下面四个问题判断。

1. 只对当前对话有效吗?

是,就放进 Prompt

例如当前订单号、用户本轮诉求、回复语言和临时格式要求。

2. 以后遇到同类任务还会复用吗?

是,就放进 技能文件

例如退款 SOP、升级人工条件、证据要求和标准回复框架。

3. 它是在描述外部动作的输入、输出和调用条件吗?

是,就放进 MCP 工具说明

例如参数结构、返回字段、错误码、调用限制和前置条件。

4. 它涉及真实权限、资金或安全操作吗?

不要只写在任何文本层。

必须交给服务端执行鉴权、参数验证、额度检查、审计记录、确认验证和幂等控制。

Prompt 管“这一次”,Skill 管“这一类”,MCP 管“能调用什么”;服务端管“到底允不允许”。

最有效的练习,是做一次同任务对照实验

理解概念之后,不要急着再收藏十套 Prompt 模板。

更有效的方法,是用同一个客服任务跑两遍:

1. 在 api.884819.xyz 准备一个可调用模型;

2. 复制本文的客服退款任务;

3. 先运行“混合版 Prompt”;

4. 再运行“三层拆分版”;

5. 对比上下文长度、工具选择、参数准确性和错误承诺情况;

6. 保存真实调用日志与截图,不用主观印象代替结果。

8848AI 平台内置 AI 对话功能,使用用户名和密码即可注册,不需要邮箱验证;没有月租和订阅,采用按量付费方式,Deepseek、千问等国产模型可免费使用。

新用户注册即送体验token。

成熟的 AI 应用,从来不是找到一条“万能 Prompt”。

它真正需要的,是把当前意图、稳定流程、外部能力和真实权限放回各自的位置。

下一篇,我们会故意让 Prompt、技能文件和 MCP 工具说明写入互相矛盾的规则,实测当三层开始“打架”时,模型究竟听谁的,以及为什么服务端约束永远拥有最后决定权。

下一篇预告:

《Prompt、技能文件和 MCP 说明互相打架时,模型到底听谁的?一次指令优先级实测》 本文由8848AI原创,转载请注明出处。关注8848AI,带你从零开始学AI。

#Prompt技巧 #MCP #AI客服 #AI工具调用 #Skill #人工智能 #8848AI #AI安全