Build real agentic apps using CUGA: two dozen working examples on a lightweight harness
TL;DR · AI 摘要
CUGA 是 IBM 开发的轻量级代理框架,通过提供工具和状态管理,简化了构建代理应用的过程。
核心要点
- CUGA 提供了工具和状态管理,简化了代理应用的构建。
- CUGA 支持 Fast、Balanced 和 Accurate 三种推理模式。
- CUGA 可以在本地、Docker/Podman 或 E2B 云中执行代码。
结构提纲
按章节快速跳转。
思维导图
用一张图看清主题之间的关系。
查看大纲文本(无障碍 / 无 JS 友好)
- CUGA 框架
- 核心机制
- 规划与执行
- 状态管理
- 工具定义
- 推理模式
- Fast
- Balanced
- Accurate
- 执行环境
- 本地
- Docker/Podman
- E2B 云
金句 / Highlights
值得收藏与分享的关键句。
CUGA 的核心优势在于它处理了代理的规划、执行循环和状态管理,用户只需定义工具和提示。
CUGA 支持 Fast、Balanced 和 Accurate 三种推理模式,用户可根据需求选择。
CUGA 可以在本地、Docker/Podman 或 E2B 云中执行代码,提供了灵活的执行环境。
使用 CUGA 构建真正的智能代理应用:基于轻量级框架的二十余个实际案例
返回文章列表
[0
[-1
企业
]
文章
发布于 2026 年 6 月 23 日
点赞
35
[
- +29
Anupama Murthi
anupamamurthi
关注
ibm-research
Hamid Adebayo
harmedox
Sami Marreed
samimarreed
Praveen Venkateswaran
praveenv
Asaf Adi
AsafAdi
Ayhan Sebin
ayhansebin
⭐ 在 GitHub 上星标 CUGA
TL;DR — 构建一个代理主要是处理各种琐事:工具、状态、安全措施、从单个代理扩展到多个代理。CUGA(pip install cuga),全称 Configurable Generalist Agent,是 IBM 为企业提供的代理框架,它处理这些繁琐的工作,因此你只需编写一个工具列表和一个提示。我们构建了二十余个单文件应用来证明这一点。在这里阅读一个完整的案例,然后看看相同的代理如何在生产环境中以主权和受控的方式运行,而无需重写。
大多数代理应用在代理开始发挥实际作用之前,都需要花费一周的时间处理各种琐事。你选择一个框架,连接一个模型客户端,编写工具适配器,构建一种将状态流式传输到 UI 的方式,同时你还需要决定代理的实际用途。真正有趣的部分是最后才出现的。
CUGA 与之相反。它是 IBM 提供的开源代理框架,负责处理规划、执行循环、工具调用以及状态管理。剩下的部分就是真正属于你的部分:代理可以访问哪些工具,以及你告诉它要做什么。为了展示实际使用中的体验,我们构建了 cuga-apps:二十余个小型、可运行的应用,每个应用都是一个 FastAPI 文件,封装了一个 CugaAgent,从电影推荐器到 IBM 云架构顾问。这些应用旨在被阅读和复制。你可以点击浏览实时画廊。
本文将逐步介绍其中一个应用,说明框架如何减轻你的负担,并展示当需要在生产环境中进行治理时,相同代码的去向。无需先学习新的框架。如果你编写过 FastAPI 路由,你就能理解每一行代码。
为什么选择框架,而不是框架
在这个领域,对任何事物提出一个公平的问题是它能帮你省去哪些编写工作。CUGA 的回答是:围绕模型的编排工作,否则你将不得不每次都重新构建。
它在行动之前进行规划,然后通过工具调用和生成代码(CodeAct)混合执行。在一项需要执行二十步的长期任务中,导致大多数代理失败的常见问题是丢失中间结果,并在下一步重新推导(通常错误);CUGA 会保留这些状态,并运行一个反思步骤,可以检测到错误的调用并重新规划,而不是一味地继续执行。这些机制就是为什么它在 AppWorld 和 WebArena 等代理基准测试中表现优异,而不是需要手动调整。
你还可以通过配置而不是代码来设置成本/延迟的权衡:快速、平衡和准确的推理模式,代码执行可以在你信任的任何沙箱中进行(本地、Docker/Podman 或 E2B 云)。相同的代理定义,不同的调节方式。这种调节方式比听起来更重要。大多数框架都假设底层有一个前沿模型,并依赖它在计划出错时进行恢复;CUGA 则自行完成这些工作。规划、反思步骤、变量跟踪以保持长期任务的正确方向——这些机制就是框架承担了模型原本需要处理的负载,这正是为什么较小的开源模型可以在通常无法胜任的情况下保持稳定。这也是为什么托管应用运行在 gpt-oss-120b 而不是前沿 API 上。运行你能调用的最大模型通常是常见的选择;CUGA 的选择是,一个较小的开源模型就足够了。
CUGA 中的每个组件都不是独有的。不同之处在于,它们是预先组装好的,因此你只需进行配置,而不是手动连接它们。你所接触的 API 非常小巧 —— 只需用工具列表和提示构建一个 CugaAgent,然后等待 agent.invoke(...) 的调用即可。在那条线以下的所有内容都是框架。
具体来说,这包括可互换的工具(OpenAPI、MCP 和 LangChain 函数都以相同方式绑定)、具有变量管理和自我纠正功能的长期规划(这是 AppWorld 从 07/25 - 02/26 和 WebArena 从 02/25 - 09/25 排名第一的底层机制)、声明式的防护措施、基于 A2A 的多代理委托、由 Docling 驱动的 RAG,以及通过一个环境变量切换提供者(pip install cuga,然后使用 OpenAI、watsonx、Ollama 等)—— 每一项你原本都需要自己构建。名字中的第一个词做了所有的工作:Configurable;困难的部分已经被处理好了,因此你的任务只是完成任务。
一个应用,从头到尾
这是 IBM Cloud 顾问 —— 一个代理,它会为架构推荐真实的 IBM Cloud 服务。整个应用都包含在一个文件中:一个 main.py,其中包含代理工厂、工具和提示,以及一个小型的用户界面。
整个代理如下所示:
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 是这个应用保存其状态和任何策略的地方。承载应用的两个参数是工具和特殊指令。
工具混合了本地函数和托管函数:
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."""
...
# hits the catalog API, returns 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 路由是普通的网络代码:浏览器向 /ask 发起一个请求,而实时面板则轮询 /session/{thread_id} 端点以获取状态。这里没有数据库;状态是一个按 thread_id 分开的 Python 字典,只有代理通过其工具对其进行写入。一旦代理在运行过程中调用了一个工具,面板就会重新绘制。这个用户界面并不是逻辑的第二个副本;它是对代理修改后的状态的一个视图。
承担主要工作的约定
一个容易被忽略但实际上是关键的细节是:每个内联工具都返回相同的小小信封。成功时看起来像 {"ok": true, "data": {...}};失败时看起来像 {"ok": false, "code": "...", "error": "..."}。
这看起来像是样板代码。但它并不是。CUGA 的计划器可以优雅地处理已声明的失败(“地理编码没有返回任何内容,跳过该部分并继续执行”),但会因为未声明的失败而出现问题,此时原始的堆栈跟踪会在计划过程中冒出来,导致整个运行偏离轨道。在所有应用中,那些运行可靠的应用都是那些工具从不向代理抛出裸异常的应用。这是一个无聊的约定,但它决定了代理是能够恢复还是直接失败。
上述的拆分之所以有效,是因为通用部分已经在某个地方运行了。这些应用反复使用的能力——网络搜索、维基百科/arXiv、地理编码和天气、金融报价,以及一些其他功能——都存在于 7 个公共 MCP 服务器(36 个工具)中,这些服务器托管在 IBM Code Engine 上,无需任何认证。一个小型的桥接器会自动解析它们的 URL,并且实时画廊提供了一个 MCP 工具探索器,可以在将其连接到代理之前,通过表单调用其中任何一个工具。
一个库,而不是一个演示
之所以有二十多个精心打磨的应用比任何一个单独的应用都更重要:一旦你阅读了云顾问,你就已经阅读了所有这些应用。它们共享一个骨架——电影推荐器将 IBM 目录工具替换为知识 MCP 服务器,网络研究员几乎完全依赖网络——因此,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 将它们标记为“showcase”或“additional apps”,默认是“showcase”;建议从云顾问或电影推荐器开始,以获得一个可用的基准。
保持代理在边界内
一个搜索目录的演示代理风险较低。将同样的模式指向一个会写文件、运行 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,当其他类型都不适用时,它是一个逃生口。时机非常重要,因为并不是所有策略都在同一阶段触发:意图保护在代理选择工具之前检查请求,工具审批在代理生成代码后运行并检查代码使用的工具,而输出格式化器只在最终消息存在后触发。触发条件不仅仅是关键字匹配:它们存储在 sqlite-vec 中,并语义匹配,因此策略是根据用户意图触发的,而不仅仅是精确匹配关键字。可以基于语义相似性、代理状态或特定工具的触发进行匹配。策略本身存储在构造器中的那个 .cuga 文件夹中,与代码并行版本化,而不是漂浮在单独的配置中。
要查看一个实际例子,打开 Ouroboros —— 一个由七个代理组成的潜在客户生成应用,它将三个策略(一个意图保护、一个工具引导和一个输出格式化器)附加到其主管代理上,因此它是唯一一个在同一文件中演示治理和多代理结构的应用。
超出一个代理的限制
当一个应用超出单一聊天循环的限制时,有两个扩展变得重要。当一个代理在自己的上下文中变得过于复杂(工具太多、需要保持的证据太多),你就可以将工作拆分。CugaSupervisor 会委托给专门的 CugaAgent,每个代理都有自己的工具、提示和独立的上下文,而主管代理只负责决定将子任务委托给哪个专门代理。无论底层有多少工具,主管代理的规划表面始终保持简洁,一个不稳定的工具只会导致一次委托失败,而不是整个运行失败。专门代理甚至不一定要本地运行;它可以通过 A2A 连接到外部代理,并以相同的方式委托。添加一个功能意味着添加一个专门代理,而不是重写协调器。
另一个扩展则打包了专业知识,而不是工具:代理技能(Agent Skills),一个包含 SKILL.md 操作手册的文件夹,代理只在任务需要时将其引入上下文,因此一个提示不需要携带代理可能需要知道的所有内容。两者都使用相同的构建模块(工具、提示、状态、策略),只是在更高层次上进行组合。
Ouroboros,之前提到的 lead-gen 应用,将这种模式具体化。它有一个监督者,管理着七位专家(侦察员、现场审计员、客户声音收集员、人员查找员、堆栈扫描员、收入估算员,以及一个能够综合信息的提案邮件撰写员)。每个专家代表一种技能,加载到 CugaAgent 中,监督者通过自动生成的 delegate_to_<name> 工具调用它们。添加第八个专家只需要一行工厂代码,而不需要重写协调器。如果你想了解完整的多代理架构,可以阅读它的 main.py 和 ARCHITECTURE.md 文件。
还有一个第三种扩展,它指向技能本身。通过 ALTK-Evolve,CUGA 的在职学习框架,代理可以从自己的运行中优化技能,使得今天完成的任务让明天的执行更快、更准确。专家加载的 SKILL.md 文件中,会保留代理在你编写内容的基础上学到的内容。使用相同的构建模块,现在一个技能可以教下一个技能。你不再需要重复提示一个你上周已经解决过的问题。
由构建所治理
治理在堆栈中的位置决定了生产故事的走向。一个最小的代理库为你提供良好的基本组件,并将治理(策略、审批、审计、身份)留给你自行组装。CUGA 选择另一条路径:策略、人机协作审批、.cuga 状态文件夹以及自托管,从第一行代码开始就是 harness 的一部分,而不是你之后添加的一层。
当你将代理投入生产时,这会改变工作的方向。你不是在为一个原本为开放访问而构建的系统添加控制机制;控制平面已经存在。受治理的路径是默认选项,而未受治理的快捷方式是你主动选择的。因此,剩下的工作变得狭窄:收紧围绕那些真正接触外部世界的工具的沙箱,而不是围绕它们发明治理机制。
同一代理的最终去向
这就是回报,也是所有这些之所以这样构建的原因。由于 harness 小、开源、模型无关,并且已经自我治理,你在笔记本电脑上编写的代理,就是运行在锁定部署中的同一代理。你不需要移植它,只需要重新部署它。
这是 IBM Sovereign Core 所构建的基础,也是我们对 CUGA 的下一步发展。我们已分别撰写了详细内容,但简短的版本是:Sovereign Core 在我们称为边界隔离的环境下运行 CUGA 代理:数据、控制平面和执行引擎位于同一逻辑边界内,代理在租户自己的工作空间中运行于短暂且隔离的容器中。模型也运行在其中。部署默认使用 gpt-oss-120b,在你的基础设施内完全断开网络,工具只能访问经过工具批准的私有 VNET。每个推理步骤都会将 OpenTelemetry 跟踪发送到 Grafana Tempo 后端,该后端保留在租户内部,没有任何遥测信息发送到外部。边界之外没有任何内容。
代理定义不会改变以实现这一点;改变的是围绕它的部署。之所以可以做到这一点,是因为上述所有内容——能力、策略和模型选择都存在于你可以阅读的运行时中。这是我们构建它时所下的赌注:当代理的运行时是一个黑箱时,主权只是一个承诺;但当它是开源代码时,主权是你可以验证的东西。你克隆的应用和你编写的代理,就是支撑这一主张的相同开源运行时。
开发者收获是独立存在的。一个智能代理应用可以是你脑海中记住的一个文件。你真正需要编写的只有工具和提示。这些应用是供你学习的库,而不是封闭的演示。当风险升高时,治理机制已经在运行时环境中 —— 你不需要重建代理来确保其安全性。
下一步
克隆仓库并运行一个应用。托管的 MCP 服务器意味着你不需要第三方密钥,只需要一个 LLM 提供商。本文中的应用运行在 open-weights 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
# 设置你的 LLM 提供商和密钥;添加 TAVILY_API_KEY /
# OPENTRIPMAP_API_KEY / ALPHA_VANTAGE_API_KEY 用于
# 使用它们的应用
docker compose up --build
# 第一次构建会很大(cuga + Chromium + MCP 依赖)
# 打开 http://localhost:8080然后打开 apps/ibm_cloud_advisor/main.py 并从头到尾阅读它 —— 这是内联工具加 MCP 模式的最清晰示例。更改系统提示,添加一个工具,并观察行为的变化。MCP 工具浏览器列出了每个托管工具,并附有直接调用它们的表单,这在将工具连接到代理之前快速检查内部结构非常方便。
所以,尝试一下吧。运行 pip install cuga,克隆 cuga-apps 并运行一个应用 —— 或者先点击实时画廊。框架位于 cuga-agent,项目主页是 cuga.dev。如果出现问题、应用行为异常或你有任何想法,请告诉我们:打开一个问题,提交一个 PR,上传你自己的应用,或直接联系我们 —— 该仓库是为添加内容而构建的,我们会阅读所有收到的内容。
资源
- cuga-apps —— 本文中的应用、MCP 服务器和 UI
- cuga-apps/apps —— 二十多个经过打磨的单文件代理应用(内部目录;从此处克隆)
- cuga-apps/mcp_servers —— 共享的 MCP 服务器(网络、知识、地理、金融、代码、文本等),应用会使用这些服务器
- 实时应用画廊 + MCP 工具浏览器 —— 每个应用后面都有一个启动按钮,还有一个表单可以直接调用每个托管的 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 —— 产品页面
本文中提到的空间 1
更多来自该作者的文章
超越 LLM:为什么可扩展的企业级 AI 采用依赖于代理逻辑
88
2026 年 6 月 1 日
ITBench-AA:前沿模型在首个代理企业 IT 任务基准测试中得分低于 50% —— 由人工分析和 IBM 进行
17
2026 年 5 月 27 日
社区
文章作者
3 天前
[2
主权、开放、自我学习代理:https://github.com/cuga-project/cuga-agent。我们期待与您合作,并欢迎您的贡献,以帮助推动开放代理社区的发展。
查看翻译
👍
1
+
回复
编辑
预览
通过拖动到文本输入框、粘贴或点击此处上传图片、音频和视频。
点击此处或粘贴以上传图片
评论
· 注册或登录以发表评论
- +23