使用 CUGA 构建真正的智能代理应用:轻量级框架上的二十多个实际工作示例

Hugging Face Blog 工具

摘要

IBM 推出 CUGA,这是一个开源智能代理框架,处理状态、工具调用和编排的底层细节,让开发者专注于定义工具和提示词。本文展示了使用 CUGA 构建的二十多个单文件示例应用,展示了它如何消除重复的框架设置工作。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/06/23 13:40

使用 CUGA 构建真正的智能体应用:轻量级框架上的二十多个工作示例

来源:https://huggingface.co/blog/ibm-research/cuga-apps 返回文章列表 (https://huggingface.co/blog)

TL;DR——构建智能体主要是管道工作:工具、状态、护栏、从单个智能体扩展到多个。CUGA(pip install cuga),全称为可配置通用智能体(Configurable Generalist Agent),是 IBM 面向企业提供的智能体框架,它替你处理这些工作,你只需编写工具列表和提示词即可。我们构建了二十多个单文件应用来证明这一点。在此完整阅读其中一个,然后看看同一个智能体如何在无需重写的情况下以主权且受管控的方式在生产环境中运行。

大多数智能体应用在智能体做出任何有用操作之前,都要先花一周时间搭建管道。你选择一个框架,配置模型客户端,编写工具适配器,构建某种将状态流式传输到 UI 的方式,然后还需要决定这个智能体到底是干什么用的。有趣的部分总是最后才出现。

CUGA (https://github.com/cuga-project/cuga-agent) 颠覆了这一点。它是来自 IBM 的开源智能体框架,为你处理规划、执行循环、工具调用和状态管道。剩下的才是真正属于你的部分:智能体可以访问哪些工具,以及你告诉它要做什么。为了展示这在实际中的感受,我们构建了 cuga-apps (https://github.com/cuga-project/cuga-apps):二十多个小型工作应用,每个都是一个封装了单个 CugaAgent 的 FastAPI 文件,从电影推荐器到 IBM Cloud 架构顾问。它们的存在就是为了被阅读和复制。

你可以点击浏览 在线演示画廊。本文会详细介绍其中一个,说明框架替你省去了哪些工作,并展示当需要将同一段代码用于生产环境并受管控时的去向。不需要先学习新的框架。如果你写过 FastAPI 路由,就能读懂每一行代码。

为什么是框架,而不是开发框架

在这个领域,任何事物都需要回答一个合理的问题:它能让你免于编写什么?CUGA 的答案是:围绕 model 的编排工作——否则你每次都得重写。它在行动之前进行规划,然后通过工具调用和生成代码(CodeAct)相结合的方式来执行。对于需要二十步才能完成的长任务,大多数智能体失败的原因是丢失了中间结果,并在下一步重新推导(通常出错);CUGA 会保存这些状态并运行反思步骤,该步骤可以捕获错误的调用并重新规划,而不是盲目继续。正是这套机制让它登上了 AppWorld 和 WebArena 等智能体基准测试的榜首,而不是靠手工调整。你还可以通过配置而不是代码来设置成本/延迟折中:快速、平衡和精确三种推理模式,代码执行在你信任的任何沙箱(本地、Docker/Podman 或 E2B 云)中进行。同样的智能体定义,不同的设置旋钮。

这个旋钮比听起来重要得多。大多数框架都假设底层有一个前沿模型,并依赖它在计划出错时恢复;CUGA 自己完成这项工作。规划、反思步骤、保持长时间运行不偏离轨道的变量跟踪——这些都是框架承担的工作,否则模型就必须自己承担,这让较小的开源模型能够在通常无法胜任的地方站稳脚跟。这就是为什么托管应用运行在 gpt-oss-120b 上,而不是前沿 API。通常的做法是调用你能调用的最大模型;CUGA 的做法是相信一个小型开源模型就足够了。

没有一个单独的组件是 CUGA 独有的。不同的是,它们已经预先组装好了,所以你只需配置它们,而不是将它们连接起来。你接触的 API 很小——用工具列表和提示词构建一个 CugaAgent,然后 await agent.invoke(...)。那行代码以下的部分都是框架。具体来说,这包括可互换的工具(OpenAPI、MCP 和 LangChain 函数都以相同的方式绑定)、具有变量管理和自我修正能力的长程规划(这是从 2025年7月到2026年2月在 AppWorld (https://appworld.dev/) 以及从 2025年2月到2025年9月在 WebArena (https://webarena.dev/) 上排名第一的机制)、声明式护栏、通过 A2A 实现的多智能体委派、基于 Docling 的 RAG,以及通过一个环境变量切换提供商(pip install cuga,然后可以选择 OpenAI、watsonx、Ollama 等)——每一项都是你原本需要自己构建的。名称的第一个词起了作用:可配置;难题已经处理好了,你的工作就只有任务本身了。

一个应用,从开始到结束

这是 IBM Cloud 顾问——一个为架构推荐真实 IBM Cloud 服务的智能体。整个应用放在一个文件中:一个包含智能体工厂、工具和提示词的 main.py,外加一个小型 UI。

ibm_cloud_advisor cuga-app 的结构:main.py 文件布局,一个内联 @tool(search_ibm_catalog)调用 IBM Cloud Global Catalog API,同时还有一个 MCP 网络搜索工具放在同一个工具列表中,以及一个强制要求“先查目录再推荐”的系统提示词。 (https://cdn-uploads.huggingface.co/production/uploads/649d9ad1500fd8d51a675a93/UWUOaGwQ7pCVGWT7-Vbg6.png)

整个智能体就是这些代码:

def make_agent():
    from cuga import CugaAgent
    from _llm import create_llm

    return CugaAgent(
        model=create_llm(
            provider=os.getenv("LLM_PROVIDER"),
            model=os.getenv("LLM_MODEL"),
        ),
        tools=_make_tools(),
        special_instructions=_SYSTEM,
        cuga_folder=str(_DIR / ".cuga"),
    )

四个参数。模型来自一个小工厂(create_llm),它根据环境变量与 OpenAI、Anthropic、watsonx、LiteLLM 或 Ollama 通信。应用代码不知道背后运行的是哪个模型。cuga_folder 是这个应用保存其状态和任何策略的地方。承载应用的两个参数是 toolsspecial_instructions

工具混合了本地函数和托管函数:

def _make_tools():
    from langchain_core.tools import tool

    @tool
    def search_ibm_catalog(query: str) -> str:
        """Search the IBM Cloud Global Catalog for real IBM Cloud services.
        Always call this before recommending services to verify they exist."""
        ... # 调用 catalog API,返回 JSON

    from _mcp_bridge import load_tools
    web_tools = load_tools(["web"])

    return [search_ibm_catalog, *web_tools]

这里有一个贯穿所有应用的模式:MCP 工具和内联工具的分割。通用的、无状态的能力来自共享的 MCP 服务器;load_tools(["web"]) 引入了网络搜索,无需你自行托管。任何特定于这个应用的东西都会作为普通的 Python 函数内联定义,比如 search_ibm_catalog,其文档字符串是智能体判断何时调用它的依据。你只编写自己的工具,其余部分借用。

云顾问的提示词告诉智能体在命名任何服务之前先搜索目录,推荐三到七个服务并说明每个服务在设计中的作用,而且绝不能凭空编造服务名称。最后这条规则很重要:一个推荐不存在的 IBM Cloud 服务的智能体比没有智能体还要糟糕,所以提示词强制每条推荐都先通过目录查询。按照有序步骤编写、带有明确“不要编造”规则的提示词表现良好;而以角色身份编写的提示词则容易跑偏。

这就是这个应用。一个工具、一个流程、四行构造函数。周围的 FastAPI 路由是普通的 Web 代码:浏览器向 /ask 发送问题,实时面板轮询 /session/{thread_id} 端点以获取状态。没有数据库;状态是一个按 thread_id 划分的 Python 字典,只有智能体通过其工具写入。当智能体在运行过程中调用工具时,面板会立即重绘。UI 不是逻辑的第二份拷贝;它是智能体修改过的状态的视图。

承担核心工作的约定

有一个细节很容易被忽略,但它实际上是关键:每个内联工具都返回相同的小信封。成功看起来像 {"ok": true, "data": {...}};失败看起来像 {"ok": false, "code": "...", "error": "..."}。看起来像是模板代码。其实不是。CUGA 的规划器可以优雅地处理已声明的失败(“地理编码没有返回任何内容,跳过这一节继续前进”),但会在未声明的失败上卡住——原始堆栈跟踪在计划中间冒出来,导致运行脱轨。在所有应用中,那些工具从不向智能体抛出裸异常的应用运行可靠。这是一个无聊的约定,但它决定了智能体是能够恢复还是会彻底失败。

上述分割之所以有效,仅仅是因为通用部分已经在某处运行了。这些应用反复调用的能力——网络搜索、Wikipedia/arXiv、地理编码和天气、金融报价等——存在于 7 个公共 MCP 服务器(36 个工具) 中,托管在 IBM Code Engine 上,无需身份验证。一个小型桥接器自动解析它们的 URL,在线演示画廊 还附带了一个 MCP 工具浏览器,可以在你将其接入智能体之前通过表单调用其中任何一个。

一个库,而不是演示

之所以有二十多个精良的应用,其意义远超过任何一个单独的应用:一旦你读完了云顾问,你就读完了所有的应用。它们共享一个骨架——电影推荐器将 IBM 目录工具替换为 knowledge MCP 服务器,网络研究员几乎完全依赖 web——所以 cuga-apps 实际上是一个起点目录。你克隆仓库,找到最接近你想法的那一个,然后编辑它的工具列表和提示词(HOW_TO_BUILD_AN_APP_FAST.mdADDING_AN_APP.md 详细介绍了具体步骤)。甚至有几个应用是通过将一个规范文件和一个一句话简介交给编码助手生成的——对于模型来说足够规律,以至于可以复制,这意味着对你来说也足够规律,可以学习。

你可以在克隆之前,先在在线演示画廊中点击浏览每一个。它们还按家族分组,因此无论你在构建什么,至少有一个应用已经用到了你需要的部分。有一个研究集群(Paper Scout 按引用次数对 arXiv 论文进行排序;Wiki Dive 和 Web Researcher 进行引用综合),一组日常生产力工具(城市简报、旅行、食谱、徒步路线),一个文档和媒体组(对 PDF、音频和视频进行 RAG),一个运维角落(监控实时指标),以及一个企业示例(基于真实的 IBM 产品文档)。Ouroboros 是一个七智能体的线索生成系统;打开它以了解多智能体形态。Meetup Finder 通过 Playwright 驱动无头 Chromium 从 Meetup、Luma 和 Eventbrite 提取结构化活动(所有这些都关闭了公共搜索 API);打开它以了解浏览器自动化——这正是 CUGA 的起点,也是其在 WebArena 上取得出色成绩背后的实力所在。

克隆之前有两个注意事项。真正的目录位于内部的 cuga-apps/cuga-apps/apps/ 目录中,而不是外层。而且并非每个应用都一样精良,因此 UI 将它们标记为“可投入生产”、“待完善”或“探索性”,默认显示“可投入生产”;从云顾问或电影推荐器开始,以获得一个可工作的基线。

将智能体约束在边界内

一个搜索目录的演示智能体风险很低。将同样的模式指向某个写文件、运行 shell 命令或接触生产环境的场景时,问题就变了:你如何阻止它做出你会后悔的事情?CUGA 在运行时回答这个问题,而不是在事后添加的包装器中。开源智能体附带一个策略系统,你可以将策略附加到同一个智能体对象上:

await agent.policies.add_intent_guard(
    name="Block force-push",
    keywords=["--force", "--no-verify"],
    response="Blocked: destructive git flags are not permitted.",
)

这是一个意图守卫,是六种策略类型之一,每种都回答团队在让智能体自由行动之前会问的问题:

  • 意图守卫——它能直接拒绝一个请求吗?
  • 工具审批——它能在高风险工具运行之前暂停等待人工确认吗?
  • 工具指南——我能否在无需重写工具的情况下引导某个特定工具的使用方式?
  • 剧本——我能否为重复性任务锁定一个已知良好的流程?
  • 输出格式化器——我能否强制最终响应符合所需格式?

第六种类型 CustomPolicy 是当以上都不适用时的逃生出口。

时间点的把握很重要,因为它并非都在同一个阶段:意图守卫在智能体选择工具之前检查请求;工具审批在智能体生成代码之后运行,并检查该代码使用了哪些工具;输出格式化器只在最终消息生成后触发。触发条件也不仅仅是关键词匹配:它们被存储在一个 sqlite-vec 存储中,并通过语义匹配,因此策略基于用户的意图而触发,而不仅仅是精确的关键词。可以基于语义相似度、智能体状态或某个特定工具的触发来匹配。策略本身位于构造函数中的那个 .cuga 文件夹中,与代码一起进行版本控制,而不是在单独的配置中漂移。

有关工作示例,请打开 Ouroboros——这是一个七智能体的线索生成应用,它为其监督者附加了三个策略(意图守卫、工具指南和输出格式化器),因此它是唯一一个在同一文件中同时演示治理和多智能体形态的应用。

从一个智能体扩展到多个

当应用超出了单个聊天循环时,有两个扩展方向很重要。当一个智能体在自己的上下文中不堪重负(工具太多,证据太多无法理清)时,你就需要拆分工作。一个 CugaSupervisor 将任务委派给专门的 CugaAgent,每个代理都有自己的工具、提示词和隔离的上下文,而监督者只负责推理应该将子任务交给哪个专家。无论底层有多少工具,它的规划面都很小,并且一个不稳定的工具只会导致一次委派失败,而不是整个运行失败。专家甚至不必是本地的;它可以是通过 A2A 访问的外部智能体,以相同的方式被委派。增加一个能力意味着增加一个专家,而不是重写协调器。

另一个扩展方向是打包“怎么做”而不是工具:智能体技能,一个包含 SKILL.md 剧本的文件夹,只有当任务需要时才被智能体拉入上下文,这样单个提示词就不用承载智能体可能需要知道的所有信息。两者都使用相同的构建块(工具、提示词、状态、策略),只是组合的层次更高了。前面提到的线索生成应用 Ouroboros 使这种模式具体化。它有一个监督者,下面有七个专家(侦察员、网站审计员、客户之声、人员查找器、堆栈

相似文章

面向长时应用开发的Harness设计

Anthropic Engineering

Anthropic工程师详细介绍了一种多智能体Harness设计,利用生成器与评估器智能体提升Claude在长时间内自主构建完整、高质量前端应用的能力。

ToolCUA:迈向计算机使用代理的 GUI-工具路径编排优化

Hugging Face Daily Papers

ToolCUA 是一个全新的代理框架,通过分阶段训练和强化学习,优化计算机使用代理的 GUI-工具路径选择。它通过在 GUI 操作和高级工具调用之间进行有效交替,在 OSWorld-MCP 上达到了最先进的性能。

通用智能体的构建式治理

arXiv cs.AI

本文介绍了CUGA的策略系统,一个模块化的策略即代码层,在LLM智能体执行的多个检查点实施治理,无需模型微调即可实现可预测和可审计的行为。