IBM 开源 CUGA:轻量级智能体框架,提供二十余个单文件示例应用
Build real agentic apps using CUGA: two dozen working examples on a lightweight harness
IBM 开源了 CUGA(Configurable Generalist Agent),一个处理规划、执行循环、工具调用和状态管理的轻量级智能体框架。开发者只需提供工具列表和提示词即可构建 CugaAgent。内置计划-执行-反思循环,在 AppWorld(2025年7月–2026年2月)和 WebArena(2025年2月–9月)基准上排名第一。支持 Fast / Balanced / Accurate 三种推理模式,代码执行可在本地、Docker 或 E2B 沙箱中运行。可互换工具支持 OpenAPI、MCP 和 LangChain 函数,通过环境变量一键切换 OpenAI、watsonx、Ollama 等提供商。随框架发布二十余个单文件示例应用,涵盖电影推荐、IBM Cloud 架构顾问等场景,每个应用仅需一个 FastAPI 文件。
CUGA 把 agent 的规划、状态、策略等繁琐工程压缩成配置,开发者只写工具列表和 prompt 就能跑起 agent,配套的二十多个单文件应用是现成的模板库,对自建 agent 的团队来说省去了八成重复工作。
TL;DR —— 构建一个智能体,大部分工作都是管道工程:工具、状态、护栏、从单个智能体扩展到多个智能体。CUGA(pip install cuga),即 Configurable Generalist Agent 的缩写,是 IBM 面向企业推出的 Agent Harness,它替你处理了这些,所以你只需写一个工具列表和一个提示词。我们构建了二十多个单文件应用来证明这一点。在这里从头到尾读一个,然后看看同一个智能体如何在不重写的情况下,以主权化和受治理的方式在生产环境中运行。
大多数智能体应用在智能体真正做任何有用的事情之前,都要先花一周时间做管道工程。你选一个框架,接上模型客户端,编写工具适配器,构建某种将状态流式传输到 UI 的方式,而在这其中的某个环节,你还要决定这个智能体到底是用来干什么的。最有趣的部分反而最后才到来。
CUGA 颠覆了这一点。它是来自 IBM 的开源 Agent Harness,替你处理规划、执行循环、工具调用和状态管道。剩下的才是真正属于你的部分:智能体可以调用哪些工具,以及你让它做什么。为了展示这在实践中是什么感觉,我们构建了 cuga-apps:二十多个小巧、可运行的应用,每一个都是一个 FastAPI 文件,封装一个 CugaAgent,从电影推荐器到 IBM Cloud 架构顾问,应有尽有。它们的存在就是为了被阅读和复制。你可以 浏览在线画廊。
本文会带你走读其中一个应用,说明这个 Harness 替你卸下了哪些负担,并展示当你需要为生产环境进行治理时,同一份代码会走向何处。无需先学习新框架。如果你写过 FastAPI 路由,你就能读懂每一行。
为什么是 harness,而不是框架
在这个领域,对任何东西都值得问的一个公平问题是:它能让你省去写什么。CUGA 的答案是:围绕一个 model 的编排,否则你每次都得重新搭建。
它先规划再行动,然后以工具调用和生成代码(CodeAct)相结合的方式执行。在一个运行二十步的长任务中,大多数智能体出问题的地方在于丢失中间结果的踪迹,并在下一轮重新推导它们(往往是错的);CUGA 会保存这些状态,并运行一个反思步骤,能够捕捉到错误的调用并重新规划,而不是一味往前冲。正是这套机制让它在 AppWorld 和 WebArena 等智能体基准测试中名列前茅,而不是靠你手动调优出来的东西。
你还可以通过配置而非代码来设定成本/延迟的权衡:Fast、Balanced 和 Accurate 三种推理模式,代码执行则在你信任的任何沙箱中进行(本地、Docker/Podman 或 E2B 云端)。同一份智能体定义,不同的旋钮。这个旋钮比听起来更重要。大多数 harness 都假定底下坐着一个前沿模型,并依赖它在计划跑偏时兜底;CUGA 则自己做这些工作。规划、反思步骤、让长程运行不偏离轨道的变量追踪——这些都是 harness 在承担模型原本不得不承担的负载,这也正是它能让一个较小的开放权重模型在通常撑不住的场景下依然顶住的原因。这就是为什么托管应用运行在 gpt-oss-120b 上,而不是前沿 API 上。调用你能调用的最大模型是通常的赌注;CUGA 的赌注则是,一个较小的开放模型就够了。
CUGA 的各个组成部分没有一个是它独有的。不同之处在于,它们已经预先组装好了,所以你只需要配置它们,而不必把它们连接起来。你接触到的 API 很小——用工具列表和提示词构建一个 CugaAgent,然后 await agent.invoke(...)。这条线以下的一切都是框架本身。
具体来说,就是可互换的工具(OpenAPI、MCP 和 LangChain 函数都以相同方式绑定)、带变量管理和自我纠正的长时程规划(07/25 - 02/26 期间 AppWorld 排名 #1 以及 02/25 - 09/25 期间 WebArena 背后的机制)、声明式护栏、基于 A2A 的多智能体委派、由 Docling 驱动的 RAG,以及通过一个环境变量切换提供商(pip install cuga,然后是 OpenAI、watsonx、Ollama 等)——每一项原本都需要你自己构建。名称的第一个词就说明了它的作用:可配置;难的部分都已处理妥当,所以你的工作就只是任务本身。
一个应用,从开始到完成
这是 IBM Cloud 顾问——一个能为架构推荐真实 IBM Cloud 服务的智能体。整个东西都装在一个文件里:一个 main.py,包含智能体工厂、工具和提示词,外加一个小型 UI。
整个智能体就是这样:
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 是这个应用保存其状态和任何策略的地方。承载这个应用的两个参数是 tools 和 special_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."""
...
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,它的 docstring 就是智能体读取以决定何时调用它的依据。你只需编写属于你自己的那一个工具,其余的借用即可。
云顾问的提示词告诉智能体在命名任何服务之前先搜索目录,推荐三到七个服务并说明每个服务在设计中的角色,并且绝不编造服务名称。最后这条规则很有价值:一个推荐不存在的 IBM Cloud 服务的智能体比没有智能体更糟,因此提示词强制每一条推荐都必须先经过目录查询。以有序步骤并带有明确"不要编造"规则写成的提示词表现良好;以人物角色写成的提示词则会跑偏。
这就是那个应用。一个工具、一套流程、四行构造函数。围绕它的 FastAPI 路由都是普通的 Web 代码:浏览器向 /ask 提交问题,实时面板则轮询一个 /session/{thread_id} 端点来获取状态。这里没有数据库;状态是一个按 thread_id 划分的 Python dict,只有智能体通过它的工具来写入。智能体在运行中途调用工具的那一刻,面板就会重绘。UI 并不是逻辑的第二份副本;它是对智能体所变更状态的视图。
真正挑大梁的约定
有一个细节很容易被忽略,结果却是承重的关键:每个内联工具都返回同样的小信封。成功看起来像 {"ok": true, "data": {...}};失败看起来像 {"ok": false, "code": "...", "error": "..."}。
它看起来像是样板代码。其实不是。CUGA 的规划器能优雅地处理一个已声明的失败(“地理编码没有返回任何结果,跳过那一部分继续往下走”),却会被一个未声明的失败卡住——此时原始堆栈跟踪会在规划中途冒出来,整个运行就脱轨了。在这些应用中,能够可靠运行的那些,其工具从不会向智能体抛出裸异常。一个无聊的约定,但它决定了智能体是能恢复过来,还是一头栽倒。
上面的拆分之所以划算,只是因为通用那一半已经在某处运行着。应用反复调用的那些能力——网页搜索、Wikipedia/arXiv、地理编码与天气、金融行情,以及另外几项——都托管在 7 个公共 MCP 服务器(36 个工具) 上,部署于 IBM Code Engine,无需认证。一个小型桥接层会自动解析它们的 URL,而 实时画廊 提供了一个 MCP Tool Explorer,让你在把任何工具接入智能体之前,先通过表单调用它们。
是一个库,而不是一个演示
有二十多个打磨精良的应用,这件事本身的原因比其中任何一个都更重要:一旦你读懂了那个云顾问应用,你就读懂了它们全部。它们共享同一套骨架——电影推荐应用把 IBM 目录工具换成了 knowledge MCP 服务器,网页研究应用几乎完全依赖 web——所以 cuga-apps 实际上是一个起点目录。你克隆这个仓库,找到最接近你想法的应用,然后编辑它的工具列表和提示词(HOW_TO_BUILD_AN_APP_FAST.md 和 ADDING_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 给它们打上了 ship-ready、for-later 或 exploratory 的标签,并默认显示 ship-ready;从云端顾问或电影推荐器入手,可以获得一个可用的基线。
让你的智能体保持在边界之内
一个搜索目录的演示智能体风险很低。把同样的模式指向会写文件、运行 shell 命令或触碰生产环境的东西,问题就变了:你如何阻止它做出让你后悔的事?
CUGA 在运行时中回答这个问题,而不是在你事后添加的包装层里。这个开源智能体自带一套策略系统,你把策略附加到同一个智能体对象上:
await agent.policies.add_intent_guard(
name="Block force-push",
keywords=["--force", "--no-verify"],
response="Blocked: destructive git flags are not permitted.",
)
这就是 Intent Guard,六种策略类型之一,每一种都回答团队在放任智能体自主运行之前会提出的一个问题:
- Intent Guard——它能否直接拒绝某个请求?
- Tool Approval——它能否在风险工具运行之前暂停下来等待人工介入?
- Tool Guide——我能否在不重写某个工具的情况下引导它的使用方式?
- Playbook——我能否为某个反复出现的任务固定一套已知有效的流程?
- Output Formatter——我能否强制最终回复符合某种要求的格式?
第六种类型 CustomPolicy 是当以上都不适用时的逃生通道。时机值得把握好,因为它并非全都发生在同一个阶段:Intent Guard 在智能体选择工具之前检查请求,Tool Approval 在智能体生成代码之后运行,并检查该代码使用了哪些工具,而 Output Formatter 只在最终消息生成之后才触发。触发条件也超越了关键词匹配:它们存放在一个 sqlite-vec 存储中并进行语义匹配,因此策略会基于用户的意图触发,而不仅仅是精确的关键词。可以按语义相似度、按智能体状态,或按某个特定工具被触发来匹配。策略本身存放在构造函数指定的那个 .cuga 文件夹中,与代码一起进行版本管理,而不是在单独的配置中漂移。
想找一个可运行的示例,可以打开 Ouroboros——这是一个由七个智能体组成的获客应用,它把三条策略(一个意图守卫、一个工具指南和一个输出格式化器)挂载到它的主管智能体上,因此它是唯一一个在同一份文件里同时演示治理机制和多智能体形态的应用。
超越单一智能体的扩展
一旦应用超出了单一对话循环的规模,有两种扩展方式就变得重要了。当某个智能体将被自身的上下文淹没时(工具太多、需要理清的证据太多),你就要拆分工作。一个 CugaSupervisor 会把任务委派给各个专家 CugaAgent,每个专家都有自己的工具、提示词和隔离的上下文,而主管智能体只需推理该把子任务交给哪个专家。无论底层有多少工具,它的规划面都保持很小,而且某个不稳定的工具只会导致一次委派失败,而不是整个运行失败。专家甚至不必是本地智能体;它可以是经由 A2A 访问的外部智能体,以同样的方式被委派。增加一项能力意味着增加一个专家,而不是重写一个协调者。
另一种扩展方式打包的是专业知识而非工具:Agent Skills,一个包含 SKILL.md 操作手册的文件夹,智能体只在任务需要时才把它拉入上下文,因此单个提示词不必承载智能体可能需要的所有知识。两者都保留相同的构建块(工具、提示词、状态、策略),只是组合的层级更高了一层。
Ouroboros,前面提到的那个获客应用,把这种模式具体化了。它有一个主管,统辖七个专家(侦察员、网站审计员、客户之声、人员查找器、技术栈扫描器、收入估算器,以及一个负责综合的推销邮件撰写者)。每个专家都是一个加载到 CugaAgent 中的技能,主管通过一个自动生成的 delegate_to_<name> 工具来调用它。增加第八个只需一行工厂代码,而无需重写协调器。如果你想端到端地了解多智能体的形态,可以读一读它的 main.py 和 ARCHITECTURE.md。
还有第三种扩展,它指向技能本身。借助 ALTK-Evolve——CUGA 的在职学习框架——智能体会从自己的运行中改进技能,这样今天完成的任务会让明天的任务更快、更准确。专家加载的 SKILL.md 最终会在你编写的内容之上,承载智能体所学到的东西。同样的构建模块,只不过现在使用一个会教会下一个。你不再需要做的,是为一个上周已经解决的问题反复重新写提示词。
从构造上就受治理
治理位于技术栈中的哪个位置,决定了生产故事如何展开。一个极简的智能体库交给你好用的原语,而把治理(策略、审批、审计、身份)留给你自己去拼装。CUGA 走的是另一条路:策略、人在环中的审批、.cuga 状态文件夹以及自托管,从第一行代码起就是这套框架的一部分,而不是你后来才添加的一层。
当你把智能体投入生产环境时,这会改变工作的方向。你不是在为一个为开放访问而构建的东西事后加装控制措施;控制平面已经存在。受治理的路径是默认选项,而未受治理的捷径才是你需要主动选择的。因此剩下的工作范围很窄:收紧围绕少数真正接触外部世界的工具的沙箱,而不是在它们周围发明治理机制。
同一个智能体最终会走向何处
这就是回报所在,也是这一切之所以这样构建的原因。因为该运行框架小巧、开源、与模型无关,并且已经实现了自我治理,所以你在笔记本电脑上编写的智能体,和在锁定部署环境中运行的智能体是同一个。你不需要移植它。你只需重新部署它。
这就是 IBM Sovereign Core 所构建的基础,也是我们把 CUGA 推进到的下一步。我们已另行撰文介绍了细节,但简而言之:Sovereign Core 在我们称之为边界隔离的机制下运行 CUGA 智能体:数据、控制平面和执行引擎位于同一逻辑边界内,智能体在租户自有工作区中的瞬态隔离容器内运行。模型也在那里运行。部署默认 gpt-oss-120b 在你的基础设施内完全气隙隔离运行,工具只能访问私有 VNET,且每个工具都需单独审批。每一步推理都会向留在租户内的 Grafana Tempo 后端发出 OpenTelemetry 追踪,没有任何遥测数据回传外部。没有任何东西离开边界。
智能体的定义并不会为了达到这一点而改变;改变的是围绕它的部署方式。而之所以能做到这一点,是因为上述的一切——能力、策略和模型选择全都存在于一个你可以阅读的运行时之中。这正是我们构建它时所下的赌注:当智能体的运行时是一个黑箱时,主权只是一种承诺;但当它是开放代码时,主权就是你可以亲自查验的东西。你克隆的应用和你编写的智能体,都建立在支撑这一主张的同一个开放运行时之上。
不过,对开发者的启示本身就站得住脚。一个智能体应用可以只是一个你能装在脑子里的文件。工具和提示词是你真正需要编写的唯一部分。这些应用是一个可供学习的库,而不是一个封闭的演示。而当风险上升时,治理已经内置于运行时之中——你无需为了让它安全而重建智能体。
后续步骤
克隆仓库并运行一个应用。托管的 MCP 服务器意味着你不需要第三方密钥,只需要一个 LLM 提供商。本文中的应用运行在开放权重的 gpt-oss-120b 之上——与托管画廊和我们的 Sovereign Core 部署所用的是同一个模型——但由于模型只需一行即可替换(create_llm 读取单个环境变量),你可以将任何应用指向 OpenAI、Anthropic、watsonx 或本地 Ollama 模型,而无需改动代码,并且指向本地模型时完全没有 API 成本:
首先请查看我们的快速入门指南 此处。如果你想设置所有应用,请确保 Docker 正在运行,然后按照以下步骤操作。
git clone https://github.com/cuga-project/cuga-apps.git
cd build
cp .env.example .env
docker compose up --build
然后打开 apps/ibm_cloud_advisor/main.py 并从头到尾读一遍——它是内联工具加 MCP 模式最清晰的示例。修改系统提示词,添加一个工具,然后观察行为的变化。MCP Tool Explorer 列出了每一个托管工具,并配有可直接调用它的表单,这是在把工具接入智能体之前快速检查管道是否通畅的好办法。
那就试试吧。pip install cuga,克隆 cuga-apps,然后运行一个应用——或者先浏览在线画廊。运行框架位于 cuga-agent,项目主页是 cuga.dev。如果有什么出问题、某个应用行为异常,或者你有想法,我们很想听到:提交 issue、发 PR、贡献你自己的应用,或者直接联系我们——这个仓库就是为了被不断添加而建的,我们会阅读收到的每一条内容。
资源
- cuga-apps —— 本文中提到的应用、MCP 服务器和 UI
- cuga-apps/apps —— 二十多个精心打磨的单文件智能体应用(内部目录;从这里克隆)
- cuga-apps/mcp_servers —— 应用所借用的共享 MCP 服务器(web、knowledge、geo、finance、code、text……)
- 在线应用画廊 + MCP Tool Explorer —— 每个应用都配有一个启动按钮,还有一个可直接调用每个托管 MCP 工具的表单
- cuga-agent — CUGA 运行时与策略系统
- cuga.dev — CUGA 项目主页(
pip install cuga) - Open by Design: Generalist and Pre-Built Agents in the Sovereign Core — IBM 社区文章,介绍 CUGA 如何在 Sovereign Core 中运行(Srivastava、Marreed、Thomas,2026 年 4 月)
- IBM Sovereign Core — 产品页面
来源:Hugging Face:Blog(RSS) · huggingface.co