7.4 采样与根:已弃用趋势但仍在工作


文档摘要

7.4 采样与根:已弃用趋势但仍在工作 本节摘要:本节讲两个特殊的交互能力——采样(Sampling) 与 根(Roots)。它们的方向与引导填写相反:引导填写是「服务端问用户要输入」,采样与根是「服务端问客户端要能力」。采样让工具反过来请客户端做一次 LLM 补全(用客户端的模型);根让客户端告知服务端工作区文件夹。这两个能力在 2026-07-28 已显弃用趋势(官方建议用 provider API 与显式参数替代),但仍能工作。本节讲清它们的现状与迁移方向,让你知道它们存在,但不在新代码里过度依赖。 一、采样(Sampling):让工具用客户端的模型 采样(Sampling)的方向很有意思——工具反过来请客户端做一次 LLM 补全。

7.4 采样与根:已弃用趋势但仍在工作

本节摘要:本节讲两个特殊的交互能力——采样(Sampling)根(Roots)。它们的方向与引导填写相反:引导填写是「服务端问用户要输入」,采样与根是「服务端问客户端要能力」。采样让工具反过来请客户端做一次 LLM 补全(用客户端的模型);根让客户端告知服务端工作区文件夹。这两个能力在 2026-07-28 已显弃用趋势(官方建议用 provider API 与显式参数替代),但仍能工作。本节讲清它们的现状与迁移方向,让你知道它们存在,但不在新代码里过度依赖。

一、采样(Sampling):让工具用客户端的模型

采样(Sampling)的方向很有意思——工具反过来请客户端做一次 LLM 补全。也就是说,服务端的工具执行中,可以请求客户端「用你的模型帮我生成一段文本」。

传统方向: 客户端 → 服务端:执行工具 服务端 → 客户端:返回结果 采样方向(反向): 服务端 → 客户端:请用你的模型,帮我补全这段 prompt 客户端 → 服务端:返回模型生成的文本

典型场景:工具执行中需要 LLM 推理。比如一个「总结文档」工具,它读文档后,可能想让客户端的模型帮忙提炼要点。

@mcp.tool() async def summarize_doc(doc_uri: str, ctx: Context) -> str: """Summarize a document, using the client's model.""" doc = await ctx.read_resource(doc_uri) # 采样:请客户端用它的模型总结 result = await ctx.session.sample( messages=[{"role": "user", "content": f"总结:{doc}"}], model_preferences=["claude-sonnet"], ) return result.content

服务端的工具,用了客户端的模型——这是采样的独特之处。

二、根(Roots):客户端告知工作区

根(Roots)让客户端告知服务端「我的工作区是哪些文件夹」。服务端据此知道「该操作哪些目录」。

@mcp.tool() async def scan_project(ctx: Context) -> dict: """Scan the current project.""" # 拿客户端告知的根 roots = await ctx.session.list_roots() # roots 是一组文件夹路径 return scan_files(roots)

典型场景:文件操作工具。客户端(如 IDE)告诉服务端「我的项目在 /home/user/project」,服务端的文件工具就只操作这个目录,不乱跑。

三、为什么这两个能力「弃用趋势」

采样与根在 2026-07-28 已显弃用趋势(SEP-2577)。为什么?几个原因:

能力 弃用原因 官方推荐替代
采样 让服务端依赖客户端的模型,职责混乱;模型选择应显式 用 provider API(服务端自带模型客户端)
隐式传递上下文,易出错;应用应显式传参数 显式参数(工具接受路径参数)

核心思想:服务端应该自包含,不该依赖客户端的隐式能力。采样让服务端依赖客户端的模型(隐式),根让服务端依赖客户端的工作区(隐式)——这些都让服务端行为不可预测、难测试。

⚠️ 注意:「弃用趋势」不等于「立刻不能用」。这两个能力在当前版本仍工作,SDK 仍支持。趋势是「新代码别过度依赖,官方未来可能进一步弱化」。如果你的存量代码用了它们,暂时不用急着拆,但新设计要考虑替代方案。

四、采样的替代:provider API

采样原本解决「工具执行中需要 LLM 推理」。官方推荐的替代是服务端自带模型客户端(provider API):

采样方式(弃用趋势): 工具执行中 → ctx.session.sample() → 用客户端的模型 问题:服务端依赖客户端的模型,行为不可预测 provider API 方式(推荐): 服务端启动时配置自己的模型客户端 工具执行中 → 直接用自己的模型客户端 优势:服务端自包含,行为可预测、可测试
# 概念性:服务端自带模型客户端 @mcp.tool() async def summarize_doc(doc_uri: str, ctx: Context) -> str: doc = await ctx.read_resource(doc_uri) # 用服务端自己的模型客户端(而非采样) summary = await my_model_client.complete(f"总结:{doc}") return summary

这种写法让服务端自包含——它有自己的模型,不依赖客户端。行为可预测(测试时用自己的模型)、部署可控(生产用配置的模型)。

五、根的替代:显式参数

根原本解决「服务端知道操作哪些目录」。官方推荐的替代是显式参数:

根方式(弃用趋势): 客户端告知 roots → 工具隐式用 roots 问题:工具行为依赖隐式状态,难测试、易出错 显式参数方式(推荐): 工具接受路径参数 → 模型/客户端显式传路径 优势:工具自包含,调用清晰
# 显式参数方式 @mcp.tool() async def scan_project(project_path: str) -> dict: """Scan a project at the given path.""" return scan_files(project_path) # 路径显式传入,不用 roots

模型调用时显式传 project_path,工具不依赖任何隐式状态。这种写法更清晰、更易测试。

六、新代码该怎么对待这两个能力

给新代码的明确建议:

能力 新代码建议
采样 别用。需要 LLM 推理时,服务端自带模型客户端(provider API)
慎用。需要目录信息时,用显式路径参数
能力 存量代码建议
采样 暂时保留,但在路线图里规划迁移到 provider API
暂时保留,逐步把隐式依赖改成显式参数

💡 技巧:本节的重点是「知道这两个能力存在,但别在新代码里依赖」。如果你看到老教程或存量代码用了采样/根,理解它们在干什么;但自己写新工具时,优先用 provider API(采样)与显式参数(根)。附录的 v1→v2 迁移要点会再次提到这个趋势。

七、为什么还要讲这两个能力

既然弃用,为什么还要花一节讲?三个理由:

  1. 存量代码会用到——你维护老项目时,会看到采样与根,得理解它们。
  2. 理解协议演进——知道「过去怎么做、为什么改」,能更深的理解当前设计。
  3. 边界情况——少数场景里它们仍有价值(如确实想让客户端出模型成本)。

但讲完要强调:主流方向是 provider API 与显式参数。把这两个能力当「历史包袱」对待,而不是「新工具」。

本节要点回顾

  1. 采样:工具反过来请客户端用其模型做补全,弃用趋势,推荐用 provider API 替代。
  2. :客户端告知服务端工作区文件夹,弃用趋势,推荐用显式路径参数替代。
  3. 弃用原因:让服务端依赖客户端的隐式能力,职责混乱、难测试。
  4. 「弃用趋势」≠「立刻不能用」:当前仍工作,但新代码别过度依赖。
  5. 采样替代:服务端自带模型客户端(provider API),自包含、可预测。
  6. 根替代:显式路径参数,工具自包含、调用清晰。
  7. 新代码建议:采样别用(用 provider),根慎用(用显式参数)。

采样与根清楚了,最后一节讲进度上报与日志——单向通知,与引导填写的「需要回答」形成对照。


发布者: 作者: 灏天文库 转发
评论区 (0)
U