译:工具:你只需要代码

发布于 2025年7月11日

原文: https://lucumr.pocoo.org/2025/7/3/tools/
作者: Armin Ronacher
译者: Gemini 2.5 Pro

如果你在 Twitter 上关注我,你就会知道我最近不太看好 MCP (模型上下文协议)。不是说我讨厌这个想法,只是我发现它并不像宣传的那样好用。在我看来,MCP 有两个主要缺陷:

  1. 它不是真正可组合的。 大多数组合都是通过推理(inference)实现的。
  2. 它需要太多上下文。 你必须预先提供大量输入,而且每次工具调用消耗的上下文,都比直接编写和运行代码还要多。

做一个简单的实验就能说明问题:试着用 GitHub MCP 完成一个 GitHub 任务,然后用 gh CLI 工具再做一遍。你几乎肯定会发现,后者对上下文的利用效率高得多,你也能更快地达到目的。

但 MCP 是未来!

我想回应一下我收到的关于我这个立场的一些反馈。我在 Agentic Coding (智能体编程) 的背景下对 MCP 做了广泛的评估,因为在这里它的局限性最容易被观察到。一种反馈是,MCP 对于通用的代码生成可能意义不大,因为模型在这方面已经做得很好了,但它对于终端用户的应用却很有意义,比如,在一家金融公司自动化处理某个特定领域的任务。另一种反馈是,我需要着眼于未来,在未来,模型将能够使用更多的工具,处理更复杂的任务。

我目前的看法是,我的数据表明,现在的 MCP 永远都会比写代码更难用,主要是因为它依赖于推理。如果你看看现在为了支持更多工具而提出的方法,这些方案都包含一个过滤层。你把所有的工具都传给一个 LLM,让它根据当前的任务进行筛选。到目前为止,还没有人提出更好的方法。

我相信这一点很可能同样成立——即使对于非编程的、特定领域的任务,你也不应该使用当前形式的 MCP——主要原因在于,即便是在那些场景下,代码生成也依然是更好的选择,因为它具有可组合性。

用 Shell 脚本取代你自己

思考这个问题的方式是,当你没有 AI 时,作为一名软件工程师,你解决问题的首选工具就是代码。对于非软件工程师来说,代码可能遥不可及。人们手动完成的许多任务,其实都可以通过软件自动化。挑战在于找到人来写这个软件。如果你在一个小众领域工作,自己又不是程序员,你可能不会拿起编程书去学写代码,也可能找不到一个愿意为你解决特定问题而提供定制软件的开发者。是的,也许你的任务需要一些推理,但许多人确实一直都需要这些定制软件。

我们常说“用一个 shell 脚本取代自己”是有原因的,因为这件事已经发生了很久。有了 LLM 和编程,想法就变成了用 LLM 来取代自己,而不是用 shell 脚本。但你会遇到三个问题:成本、速度和普适的可靠性。所有这些问题都是我们在考虑使用工具或 MCP 之前就需要处理的。我们需要想办法确保我们的自动化任务在规模化时能够正确工作。

规模化自动化

自动化的关键在于自动化那些会反复发生的事情。你不会去自动化一个一次性的、永远不会重现的变更。你会开始自动化那些机器能真正给你带来生产力提升的事情,因为你只需要做一两次,弄清楚如何让它工作,然后让机器重复一千次。对于这种重复,有非常充分的理由支持始终使用代码。这是因为,如果我们指示机器用推理来完成它,它可能行得通,特别是对于小任务,但这需要验证,而验证花费的时间几乎和一开始自己动手做一样多。让 LLM 为你计算,某种程度上可行,但更好的办法是让 LLM 写 Python 代码来进行计算。为什么?首先,你可以审查的是公式,而不是计算结果。我们可以自己写,也可以用 LLM 作为裁判,来判断方法是否正确。我们基本不需要验证 Python 的计算是否正确,你可以信赖它。所以,通过选择代码生成来解决任务,我们离能够自己验证和确认过程更近了一步,而不是寄希望于 LLM 推理正确。

这显然远不止于计算。以这个博客为例。我最近把整个博客从 reStructuredText 转换成了 Markdown。我把这个转换任务拖了很久,部分原因是我有点懒。但也是因为,当我懒到考虑用 LLM 来做这件事时,我根本不相信它能在转换过程中不出任何问题。我担心如果它用尽了上下文,可能会开始胡编乱造文本,或者稍微改变措辞。就是说,我太担心那些细微的退化问题了。

我最终还是用了 LLM,但我让它用一种不同的方式来完成这个转换:通过代码。

LLM 到代码再到 LLM

  1. 我让 LLM 执行从 reStructuredText 到 Markdown 的核心转换,但我也要求它以一种使用底层 AST (抽象语法树) 的方式来做。所以,我指示它将 reStructuredText 解析成一个实际的 reStructuredText AST,然后将其转换为 Markdown AST,最后像以前一样渲染成 HTML。这给了我一个中间转换步骤和一个可比较的最终结果。
  2. 然后,我让它写一个脚本来比较新旧 HTML,在进行一些它认为比较所必需的基本清理后进行差异比对(diffing)。我让它考虑什么样的转换错误是真正可以接受的。于是,它通读了自己写的脚本,找出由于已知的技术限制(例如,我使用的 Markdown 库和 reStructuredText 库渲染脚注的方式不同,所以即使语法匹配正确,HTML 看起来也会不一样)而可能与原始输出不匹配的地方。我让它在那个脚本里对这些差异进行补偿。
  3. 完成之后,我让它创建第三个脚本,我可以用这个脚本来处理数百个文件的输出,分析差异,以便回到智能体循环(agentic loop)中进行下一次迭代。

然后我让这个过程循环跑起来。我没有提供所有的文章,而是从 10 篇开始,直到差异变得很小,然后才让它处理全部。它大概跑了 30 分钟左右,等我回来时,发现结果已经处于一个相当可以接受的状态了。

这次转换的关键,并不在于 LLM 有能力完成它,而在于我最终真正信任这个过程,因为我可以审查它的方法。不仅如此,我还试着问另一个 LLM 对这个 LLM 写的代码和变更有什么看法。这让我对整个过程不会丢失数据有了高得多的信心。我感觉这样做是对的。它感觉像一个在根本上是正确的机械化过程,我能够观察它并进行抽查。最坏的情况下,出现的退化也只是轻微的 Markdown 语法错误,但文本本身不会被损坏。

这里的另一个关键是,因为推理的量是相对恒定的,所以这个过程中推理的成本只与迭代次数和样本大小成正比,而与我想要转换的文档总数无关。最终,我让它一直处理所有文档,但处理 15 个文档和 150 个文档的工作量或多或少是相同的,因为最后基于 LLM 的分析步骤并没有增加太多需要审查的东西(它已经跳过了文件中所有微小的差异)。

MCP 做不到这些

说了这么多,其实就是想说,这整个转换过程都是通过代码完成的。这是一个流水线(pipeline):从人类输入开始,生成代码,然后用 LLM 作为裁判进行迭代。你可以将这个转换模式应用到任何一个通用任务上。

举个例子,你可能会用到的一个 MCP 就是 Playwright。我发现很难在所有情况下都用代码来取代 Playwright,因为你本质上是在远程控制浏览器。你给它的任务,很大程度上涉及到读取页面、理解页面内容,然后点击下一个按钮。在这种场景下,你很难在每一步都消除推理。

但是,如果你已经知道页面是什么——例如,你正在操作你自己开发的应用——那你其实可以告诉它去写一个 Playwright Python 脚本并运行它。这个脚本可以按顺序执行许多步骤,而不需要任何推理。我注意到这种方法快得多,而且因为它理解你的代码,所以通常仍然能产生正确的结果。它不需要实时地导航、读取页面内容、寻找按钮或按下输入。相反,它会写一个单独的 Python 脚本,一次性自动化整个过程,相比之下,需要的上下文非常少。

这个过程是可重复的。一旦脚本写好了,我可以执行它 100、200 甚至 300 次,而不需要任何额外的推理。这是 MCP 通常无法提供的一个巨大优势。让一个 LLM 理解通用的、抽象的 MCP 工具调用是极其困难的。我多希望能把一个 MCP 客户端直接嵌入到 shell 脚本里,让我可以通过代码生成来高效地运行远程 MCP 服务,但实际上这非常难,因为这些工具在设计时就没有考虑到基于非推理的自动化。

还有,讽刺的是:我是个人,不是 MCP 客户端。我可以运行和调试一个脚本,但我甚至不知道如何可靠地进行 MCP 调用。这总像一场赌博,而且极难调试。我喜欢用 Claude Code 在生成代码时生成的一些小工具。其中一些,我已经让它转化成了我开发流程中的长期补充。

这会把我们带向何方?

我不知道。但这是一个有趣的时刻,我们可以思考一下,为了让有目的的智能体编程(agentic coding)中的代码生成变得更好,我们到底能做些什么。奇怪的是,MCP 在能用的时候其实相当不错。但它目前的形式感觉太像一个死胡同,无法扩展,尤其无法扩展到规模化的自动化,因为它太依赖推理了。

所以,或许我们需要寻找一种更好的抽象,来融合 MCP 的优点和代码生成的优点。为此,我们可能需要构建更好的沙箱,并且开始研究如何以一种允许智能体对推理进行某种扇出/扇入(fan out / fan in)的方式来暴露 API。实际上,我们希望尽可能多地在生成的代码中完成工作,然后在批量执行代码后,利用 LLM 的魔力来评判我们做了什么。

我也可以想象,以一种能为 LLM 提供足够上下文,让它能用人类语言向非程序员解释脚本在做什么的方式来进行代码生成,这可能会非常有趣。这或许能让那些自己不是开发者的用户也能使用这些工作流。

无论如何,我只能鼓励大家绕过 MCP,去探索其他的可能性。如果你赋予 LLM 编写代码的能力,它们能做的远不止于此。

延伸阅读

这里有一些你可能想读的文章或想看的视频:

  • 我的 Agentic Coding 演讲,我在其中对这个话题做了一些探讨。
  • Drew Breunig 的文章“如何修复你的上下文”,其中介绍了一些在你无法避免 MCP 时,改善其工具选择的尝试。
  • Manuel Odendahl 在 AI Engineer 大会上的精彩演讲“MCP 很无聊”,这是最早指出 MCP 所面临挑战的演讲之一。

评论 (0)

请登录后发表评论

暂无评论,快来发表第一条评论吧!