LLM 函数调用难以扩展:代码编排更简单高效
[正文内容]
jngiam
LLM 函数调用难以扩展:代码编排更简单高效
_ 2025年5月20日 _ TL;DR: 让 LLM 接收工具调用的完整输出成本高昂且速度慢。输出 Schema 将使我们能够获得结构化数据,从而让 LLM 可以通过生成的代码来编排处理流程。在代码中使用工具调用正在变得简单且有效。 一种常见的处理 MCP 工具调用的做法是将工具的输出作为消息放回 LLM 中,并要求 LLM 执行下一步操作。这里的希望是模型能够理解数据,并确定要采取的正确下一步行动。 当数据量很小时,这可以很好地工作,但是我们发现,当我们尝试将 MCP 服务器与真实数据一起使用时,它很快就会崩溃。
现实世界中的 MCP
我们在公司中使用 Linear 和 Intercom。我们连接到他们上周发布的最新官方 MCP 服务器,以了解它们如何返回工具调用。
事实证明,这两个服务器都在其文本内容中返回了大型 JSON blob。这些数据看起来与它们的 API 类似,但文本内容没有任何预定义的 Schema。这意味着解析它们的唯一合理方法是让 LLM 解释数据。
这些 JSON blob 非常庞大!当我们要求 Linear 的 MCP 列出我们项目中的问题时,工具调用默认仅返回 50 个问题,大约 70k 个字符,对应大约 25k 个 tokens。
JSON 包含很多
id
字段,它们占用很多 tokens,并且在语义上没有意义。
在使用 Claude 和 MCP 时,整个 JSON blob 似乎会被逐字发送回模型。
这种方法很快就会遇到问题。例如,如果我们想让 AI 按截止日期对所有问题进行排序并显示它们,它将需要逐字地重新生成所有问题作为输出 tokens!这将是缓慢的、昂贵的,并且可能遗漏数据。
我们问题中的数据通常也包含许多分散注意力的信息:重现问题的步骤、错误、甚至用户使用的 prompts 或要跟进用户的说明。模型可能无法准确地发出其中一些数据,或者更糟糕的是,偏离原始指令。
数据 vs 编排
这里的核心问题是我们在同一个聊天线程中将编排和数据处理混淆在一起。
“多代理”方法尝试通过启动另一个聊天线程(“代理”)来解决此问题,该线程仅专注于数据处理部分。当经过仔细调整时,它会表现更好,但是当我们的数据已经结构良好时,它仍然很尴尬。
如果 MCP 服务器已经以 JSON 格式返回数据,那么解析数据并改为对结构化数据进行操作似乎更自然。回到我们的排序示例,与其要求 LLM 直接重新生成输出,不如对数据运行 sort
操作,然后返回新数组。没有幻觉,并且可以扩展到任何大小的输入。
代码执行作为数据处理
这听起来很熟悉,因为我们已经有了带有 AI 的代码解释器。当我们开始将代码执行作为处理来自 MCP 工具的数据的基本方式(Code Act, Smol Agents),这将为 AI 模型提供可扩展的工作方式。 变量作为内存。 LLM 可以使用变量(系统内存)来存储任何数据,而不是使用外部内存系统。存储内存是将值分配给变量,查看变量是打印它,并且模型可以选择在调用另一个函数时将变量作为参数传递。更好的是,如果使用的语言是强类型的,则模型还可以利用 Schema。 工具链。 代码可以编排多个函数调用:并行执行它们或采用一个或多个调用的输出,并将它们用作另一个调用的输入。函数调用之间的依赖关系通过代码表示的计算图隐式表示。重要的是,不需要 LLM 逐字重复数据,并且我们保证完整性。 可扩展的处理。 使用代码自然可以转换大量数据。模型可以选择使用循环,或依赖 NumPy 或 pandas 等库进行大型数据转换。 代码也可以在底层调用其他 LLM:您可以让 LLM 编写调用 LLM 的代码来进行非结构化数据处理(LLM-inception)。
MCP 准备好了吗?
MCP 规范已经定义了输入 Schema,并且他们刚刚引入了输出 Schema。 一旦输出 Schema 得到广泛应用,我们希望它们能够解锁对大型数据集的使用场景:构建自定义仪表板、创建每周完成工单的报告,或者让自主代理监控并推动停滞的问题向前发展。
代码执行的难点是什么?
现在的挑战转移到 MCP 客户端。当今大多数执行环境都在严格控制的沙箱中运行;当我们处理用户/AI 生成的代码时,安全性至关重要。 允许执行环境也访问 MCP、工具和用户数据需要仔细设计 API 密钥的存储位置以及工具的公开方式。 在我们的设计中,我们创建了使用特定 API 访问权限进行密钥化的沙盒环境,并向模型提供了有关如何调用这些 API 的文档,以便它们能够发送/检索信息而无需查看密钥。 大多数执行环境都是有状态的(例如,它们可能依赖于为每个用户会话运行 Jupyter kernels)。如果用户希望以后能够返回到 AI 任务会话,这将很难管理且成本高昂。无状态但持久的执行环境对于长时间运行(多天)的任务会话至关重要。 这些约束正在创造我们认为是一种新的运行时类别——使用 LLM 来编排和执行任务的“AI 运行时”。我们仍处于研究这种代码执行方法的所有细节的早期阶段,并且我们很乐意听取任何解决类似问题的人的反馈。如果您对我们的方法感兴趣,可以访问 Lutra 尝试一下。 9 由 Bear ʕ•ᴥ•ʔ 驱动