AIニュース最前線
最新ニュースAI日報Hacker日報週報動画AIツールトレンド企業

AIニュース最前線

世界中のAI最新情報を日本語で毎時更新

最新ニュース日報トレンド企業プレミアムRSS
© 2026 ainew.jp特定商取引法に基づく表記
ニュース一覧元記事を開く
Hugging Face Blog·2026年6月23日 21:51·約26分で読める

軽量ハーンネスを用いた CUGA による実用的エージェントアプリ構築:24 の動作例を紹介

#Agent Frameworks#CUGA#Hugging Face#Edge AI
TL;DR

Hugging Face は、CUGA パラダイムを活用した 24 の実用的なエージェントアプリケーション事例を公開し、軽量ハーンネス上での開発手法を示した。

AI深層分析2026年6月23日 22:04
3
注目/ 5段階
深度40%
4
関連度30%
4
実用性20%
5
革新性10%
3

キーポイント

1

CUGA パラダイムの具体化

単なる理論ではなく、CUGA(Context, Utility, Goal, Action)の概念を具体的な 24 のアプリケーション事例として実装し公開した。

2

軽量ハーンネスの実用性

大規模なインフラに依存せず、軽量な環境で動作するエージェント開発の手法とツールを提供し、開発ハードルを下げた。

3

多様なユースケースの提示

データ分析からタスク自動化まで、幅広い分野における「実用的」なエージェントの設計パターンを網羅的に示した。

影響分析・編集コメントを表示

影響分析

この発表は、AI エージェント分野が「概念検証」から「実装と展開」へと移行したことを示す重要な指標です。特に軽量環境での実用性を強調している点は、エッジデバイスやコスト効率を重視する現場開発者にとって大きな意味を持ちます。

編集コメント

理論的なフレームワークの提示に留まらず、24 の実働例を公開した点は、開発者コミュニティへの貢献として非常に評価が高い。

記事一覧に戻る

**

  • なぜフレームワークではなくハーンネスなのか
  • 一アプリ、開始から完了まで
  • 重労働を担う規約
  • デモではなくライブラリ
  • エージェントの境界内を保つ
  • 単一エージェントを超えて成長する
  • 構築によって統制される
  • 同じエージェントがたどり着く場所
  • 次のステップ
  • リソース

TL;DR** — エージェントを構築するのは主に配管作業です:ツール、状態管理、ガードレール、そして単一エージェントから複数へのスケーリング。IBM のエンタープライズ向けエージェントハーンネスである CUGA(pip install cuga)は、Configurable Generalist Agent(設定可能な汎用エージェント)の略称で、これらを処理します。そのため、あなたはツールリストとプロンプトのみを記述すればよいのです。私たちはその証明として、24 の単一ファイルアプリを構築しました。ここでは一つを最初から最後まで読み進め、その後、書き換えなしに生産環境で主権を持ちかつ統制された状態で同じエージェントが動作する様子をご覧ください。

ほとんどのアジェンティックアプリは、エージェントが実際に有用なことをする前に、配管作業に 1 週間を費やすことから始まります。フレームワークを選び、モデルクライアントを接続し、ツールアダプターを書き、UI へ状態をストリーミングする方法を構築します。その過程で、エージェントの実際の目的は何なのかを決めることになります。面白い部分は最後にやってきます。

CUGA はその逆をいくものです。IBM が提供するオープンソースのエージェントハッチ(harness)であり、プランニング、実行ループ、ツール呼び出し、そして状態管理のための配管処理をすべて代行してくれます。残るのは、まさにあなた自身の部分です:エージェントがアクセスできるツールは何か、そして何をするように指示するかという点です。これが実際にどのような感覚なのかを示すために、私たちは cuga-apps を構築しました。これは映画レコメンダーから IBM Cloud のアーキテクチャアドバイザーまで、20 以上の小規模で動作するアプリのコレクションです。それぞれが単一の FastAPI ファイルとして CUGA エージェントをラップしています。これらは読まれてコピーされるために存在します。ライブギャラリー をクリックして閲覧することもできます。

この記事では、そのうちの 1 つを取り上げ、ハッチが何からあなたを守ってくれるかを明確にし、本番環境向けにガバナンスが必要になった際に同じコードがどこへ向かうのかを示します。最初に学ぶべき新しいフレームワークはありません。FastAPI のルートを書いた経験があれば、すべての行を読み進めることができます。

なぜハッチなのか、フレームワークではないのか

この分野のあらゆるものに対して公平に問うべき質問は、「何を書く手間を省いてくれるのか」という点です。CUGA の答えは、モデルを取り巻くオーケストレーションです。本来であれば、毎回これを再構築しなければならないものです。

行動する前に計画を立て、ツール呼び出しと生成されたコード(CodeAct)を組み合わせて実行します。20 ステップにわたる長いタスクにおいて、多くのエージェントが失敗するのは中間結果の追跡を失い、次のターンでそれを再導出しようとして(しばしば誤って)しまう点にあります。CUGA はその状態を保持し、不適切な呼び出しを検出して先へ進むのではなく再計画を行うリフレクションステップを実行します。この仕組みこそが、手動で調整するものではなく、AppWorld や WebArena といったエージェントベンチマークで首位を獲得させる理由です。

コストとレイテンシのトレードオフも、コードではなく設定から選択できます:高速、バランス型、高精度の推論モードがあり、信頼できるサンドボックス(ローカル、Docker/Podman、または E2B クラウド)でコードを実行できます。エージェント定義は同じまま、ダイヤルを回すだけです。このダイヤルの重要性は、一見すると過大評価されているように思えるほどです。多くのハーンスは背後に最前線のモデルが存在し、計画が外れた際にそのモデルに回復を依存することを前提としています。しかし CUGA はその作業自体を行います。計画、リフレクションステップ、長い実行を軌道上に保つ変数追跡——これらは、本来ならモデルが行わなければならない負荷をハーンスが担う仕組みです。これが、通常では耐えられないような小規模なオープンウェイトモデルでも機能させる理由となります。そのため、ホストされたアプリは最前線の API ではなく gpt-oss-120b で動作します。呼び出せる最大のモデルを使うのが一般的な戦略ですが、CUGA のアプローチは、より小さなオープンソースのモデルで十分であるというものです。

個々の構成要素に CUGA 固有の独自性はありません。異なる点は、これらが事前に組み立てられて提供されるため、接続するのではなく設定を行うだけで済むことです。あなたが触れる API は非常に小さく、ツールリストとプロンプトを指定して CugaAgent を構築し、その後 agent.invoke(...) を待機するだけです。その下のすべてがハーンです。

具体的には、相互交換可能なツール(OpenAPI、MCP、および LangChain 関数はすべて同じ方法でバインドされる)、変数管理と自己修正を備えた長期計画(2025 年 7 月 25 日から 2026 年 2 月 26 日にかけての AppWorld の #1 および 2025 年 2 月 25 日から 2025 年 9 月 25 日にかけての WebArena の背後にある仕組み)、宣言型ガードレール、A2A を介したマルチエージェント委譲、Docling による RAG(Retrieval-Augmented Generation:検索強化生成)、そして単一の環境変数でプロバイダーを切り替える機能(pip install cuga でインストール後、OpenAI、watsonx、Ollama などへ)です。これらは本来すべて自分で構築する必要があるものです。名前の最初の単語がその役割を果たします:*Configurable*(設定可能)。難しい部分は処理済みなので、あなたの仕事はタスク自体に集中することだけです。

一つのアプリを最初から最後まで

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"),

)

4 つの引数です。モデルは、環境変数に応じて OpenAI、Anthropic、watsonx、LiteLLM、または Ollama に接続する小さなファクトリ関数(create_llm)から取得されます。アプリコード内でどのモデルが背後にあるかを特定する情報は一切含まれていません。cuga_folder は、このアプリが状態やポリシーを保持する場所です。アプリを引き渡す 2 つの引数は、tools と special_instructions です。

ツールは、ローカル関数とホストされた関数を組み合わせたものです:

def _make_tools():

from langchain_core.tools import tool

@tool

def search_ibm_catalog(query: str) -> str:

"""IBM Cloud Global Catalog を検索して、実際の IBM Cloud サービスを確認します。

サービスを推奨する前に必ずこの関数を呼び出し、サービスが存在することを確認してください。"""

... # カタログ 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 のようなもので、そのドキュストリング(docstring)がエージェントによって参照され、いつ呼び出すかを判断する根拠となります。あなたは自分だけのツールを一つ書き、残りは他から借用すればよいのです。

クラウドアドバイザーのプロンプトは、エージェントに対してサービス名を挙げる前にカタログを検索し、各サービスの設計における役割とともに 3 から 7 のサービスを推奨し、決して架空のサービス名を発明しないよう指示しています。最後のルールがその価値を発揮します:存在しない IBM Cloud サービスを推薦するエージェントがいるよりも、エージェント自体が存在しない方がマシです。そのためプロンプトは、すべての推奨事項をまずカタログ検索を経由させることを強制しています。「順序立てたステップ」として記述され、「作り出さないで」という明確なルールを含むプロンプトは振る舞いを示しますが、ペルソナとして書かれたプロンプトは迷走します。

これがアプリの全体像です。ツール一つ、手順一つ、コンストラクターに 4 行。これを取り巻く FastAPI のルートは通常の Web コードです:ブラウザが /ask に質問を投稿し、ライブパネルが状態を確認するために /session/{thread_id} エンドポイントをポーリングします。データベースはありません;状態はスレッド ID ごとの Python ディクショナリであり、エージェントがそのツールを通じてのみ書き込みます。実行中にエージェントがツールを呼び出す瞬間、パネルは再描画されます。UI はロジックの複製ではありません;それはエージェントによって変更された状態へのビューなのです。

重責を担う規約

見落としがちでありながら、実は重要な役割を果たす詳細があります。すべてのインラインツールは同じ小さなエンベロープを返します。成功の場合は {"ok": true, "data": {...}} のような形式になり、失敗の場合は {"ok": false, "code": "...", "error": "..."} のようになります。

これは単なる定型文のように見えますが、実際はそうではありません。CUGA のプランナー(計画エンジン)は*宣言された*失敗を柔軟に処理します(例:「ジオコーディングで結果が返ってこなかったため、そのセクションをスキップして続行する」)。しかし、*未宣言の*失敗に対しては対応できず、生きたスタックトレースがプランニング中に浮き上がり、実行が破綻してしまいます。複数のアプリを比較すると、確実に動作したのは、ツールがエージェントに対して裸のエラー例外(bare exception)を投げないものでした。地味な規約ですが、これが「回復可能なエージェント」と「転倒するエージェント」の決定的な違いとなります。

上記のような分割が意味を持つのは、汎用的な部分がすでにどこかで稼働しているからです。アプリで繰り返し利用される機能——ウェブ検索、Wikipedia/arXiv、ジオコーディングと天気予報、金融クォート、その他数点——は、IBM Code Engine 上でホストされている7 つの公開 MCP サーバー(36 のツール)に実装されており、認証は不要です。小さなブリッジがこれらの URL を自動的に解決し、ライブギャラリーには、エージェントに接続する前にフォームからこれらいずれかを呼び出せるMCP ツールエクスプローラーも同梱されています。

デモではなくライブラリ

24 の洗練されたアプリが存在する理由が、単一のアプリの重要性よりもはるかに大きいのは、クラウドアドバイザーを読めば他のすべてを読み終えたことになるからです。これらは共通の骨格を持っています——映画レコメンダーでは IBM カタログツールを知識 MCP サーバーに置き換え、ウェブ研究者はほぼ完全にウェブに依存しています。つまり、cuga-apps は実際にはスタート地点のカタログなのです。リポジトリをクローンし、自分のアイデアに最も近いアプリを見つけて、そのツールのリストとプロンプトを編集します(HOW_TO_BUILD_AN_APP_FAST.md と ADDING_AN_APP.md がまさにその手順を解説しています)。いくつかのアプリは、コーディングアシスタントに仕様書 1 つと 1 行の概要を与えるだけで生成されました。モデルが再現できるほど規則的であれば、学習者であるあなたにとっても規則的です。クローンする前に、ライブギャラリーで すべてのアプリをクリックして確認できます。

また、これらはファミリー全体に展開されているため、何を作っているかに関わらず、必要な部分を既に実装したアプリが一つは存在します。研究クラスター(Paper Scout は arXiv の論文を引用数でランク付けし、Wiki Dive と Web Researcher は引用された情報の統合を行います)、日常の生産性向上セット(都市の概要、旅行、レシピ、トレイル)、PDF・音声・動画に対する RAG[Retrieval-Augmented Generation] を行うドキュメントおよびメディアグループ、ライブメトリクスを監視する運用コーナー、そして実際の IBM 製品ドキュメントに基づくエンタープライズ例があります。Ouroboros は 7 つのエージェントからなるリード獲得システムであり、マルチエージェントの構造を確認するためにオープンしてください。また Meetup Finder は Playwright を介してヘッドレス Chromium を駆使し、Meetup、Luma、Eventbrite から構造化されたイベントデータを抽出します(これらはいずれも公開検索 API を廃止しました)。ブラウザ自動化については、CUGA の起源であり、その強力な WebArena 結果の背後にある技術であるため、こちらをオープンしてください。

クローンする前に二つの注意点を。実際のカタログは外側のディレクトリではなく、内側の cuga-apps/cuga-apps/apps/ ディレクトリに存在します。また、すべてのアプリが同等に完成しているわけではないため、UI タグでは ship-ready(出荷準備完了)、for-later(後回し)、exploratory(探索的)のいずれかに分類され、デフォルトは ship-ready です。動作するベースラインとして、クラウドアドバイザーまたは映画レコメンダーから始めることをお勧めします。

エージェントを境界線内に保つ

カタログを検索するデモエージェントはリスクが低いです。同じパターンをファイルの作成やシェルコマンドの実行、あるいは本番環境へのアクセスに適用した場合、問いは変わります:どうすれば後悔するような行為を防げるか?

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)」であり、6 つのポリシータイプのうちの一つです。各タイプは、チームがエージェントを解放する前に問うべき問いに答えるものです:

  • インテントガード — 要求を即座に拒否できるか?
  • ツール承認 — リスクのあるツール実行前に人間による一時停止が可能か?
  • ツールガイド — ツールの書き換えなしで、特定のツールの使用方法を誘導できるか?
  • プレイブック — 反復タスクに対して既知の安全な手順を固定できるか?
  • 出力フォーマッター — 最終応答を必要な形状に強制できるか?

6 つ目のタイプである CustomPolicy は、それらのいずれにも当てはまらない場合の脱出手段です。タイミングを正しく設定することは重要であり、それは単一の段階ではありません。Intent Guard(意図ガード)はエージェントがツールを選択する前にリクエストをチェックし、Tool Approval(ツール承認)はエージェントがコードを生成した後に実行され、そのコードで使用されるツールを検査します。また、Output Formatter(出力フォーマッター)は最終メッセージが存在した場合にのみ発火します。トリガーもキーワードマッチングを超えており、sqlite-vec ストアに格納されて意味的に照合されるため、ポリシーはユーザーが*意図する*内容に基づいて発火し、単なる正確なキーワードに基づくだけではありません。意味的な類似性、エージェントの状態、または特定のツールの発火に基づいて一致させることができます。ポリシー自体は、コンストラクタから指定された .cuga フォルダ内に存在し、コードの隣でバージョン管理されており、別々の設定ファイルに任せることはありません。

動作例としては、Ouroboros を開いてください。これは 7 つのエージェントからなるリードジェネレーションアプリで、サプバイザーに対して 3 つのポリシー(意図ガード、ツールガイド、出力フォーマッター)をアタッチしています。これにより、ガバナンスとマルチエージェント構造の両方を同じファイル内でデモできる唯一のアプリとなっています。

エージェントが一つを超える段階へ

アプリが単一のチャットループを超えて成長した際、2 つの拡張機能が重要になります。1 つのエージェントが自身のコンテキスト(ツールが多すぎる、確認すべき証拠が多すぎる)に飲み込まれてしまう場合、作業を分割します。CugaSupervisor は専門的な CugaAgent に委任し、それぞれが独自のツール、プロンプト、隔離されたコンテキストを持ちます。スーパーバイザーは、どの専門家にサブタスクを渡すかという点のみについて推論を行います。その計画の表面積は、背後に存在するツールの数に関わらず小さく保たれ、不安定なツールが失敗しても、全体の処理が停止するのではなく、1 つの委任のみが影響を受けます。専門家は必ずしもローカルである必要はなく、A2A を介して到達可能な外部エージェントであってもよく、同じように委任されます。機能を追加するには、コーディネーターを再構築するのではなく、新しい専門家を追加すればよいのです。

もう一つの拡張機能は、ツールではなくノウハウをパッケージ化するものです:Agent Skills です。これは SKILL.md プレイブックを含むフォルダで、タスクが必要とする場合にのみエージェントがコンテキストに読み込みます。これにより、1 つのプロンプトにエージェントが知る必要があるすべての情報を詰め込む必要がなくなります。どちらも同じビルディングブロック(ツール、プロンプト、状態、ポリシー)を使用していますが、レベルを一つ上げて構成されています。

Ouroboros は、以前紹介したリード獲得アプリですが、このパターンを具体化しています。7 つの専門家(スカウト、サイト監査員、顧客の声担当、人物探索者、スタックスキャナー、収益推定者、そして合成を行うピッチメール作成者)を統括するスーパーバイザーが配置されています。各専門家は 1 つのスキルを CugaAgent に読み込む形で実装されており、スーパーバイザーは自動生成された delegate_to_<name> ツールを通じて呼び出します。8 番目の専門家を追加する場合でも、コーディネーターの書き換えではなく、1 行のファクトリで済みます。マルチエージェントの構造をエンドツーエンドで理解したい場合は、main.py と ARCHITECTURE.md をお読みください。

3 つ目の拡張機能があり、これはスキルそのものへと指向しています。CUGA のオン・ザ・ジョブ学習フレームワークである ALTK-Evolve を用いると、エージェントは自身の実行結果からスキルを洗練させます。これにより、今日行われたタスクが明日の処理をより高速かつ正確にします。専門家が読み込む SKILL.md には、あなたが記述した内容の上に、エージェントが学習した知見が蓄積されます。構成要素は同じですが、今回は「1 つ学ぶことで次を教える」という仕組みです。もう行う必要がなくなるのは、先週すでに解決済みの問題に対して再プロンプトを行うことです。

構築によって統制される

ガバナンス(governance)がスタックのどこに位置するかによって、生産ストーリーの展開は異なります。最小限のエージェントライブラリは優れたプリミティブを提供しますが、ガバナンス(ポリシー、承認、監査、アイデンティティ)については、それを組み立てる責任をユーザーに残します。一方、CUGA は別の道を選びます:ポリシー、人間が関与する承認プロセス、.cuga 状態フォルダ、そしてセルフホスティングは、最初の一行からハッチ(harness)の一部として組み込まれており、後から追加するレイヤーではありません。

エージェントを本番環境に導入すると、作業の方向性が変わります。オープンアクセスのために作られたものに後から制御機能を追加するのではなく、制御プレーンが最初から存在しているのです。管理されたパスがデフォルトとなり、管理されていない近道は、あえて選択するものになります。したがって残された課題は狭く、外部世界に実際に触れる限られたツールの周りにサンドボックスを強化することであり、それらに対してガバナンスを新たに発明する必要はありません。

同じエージェントが行き着く先

これが得られる成果であり、このように構築される理由です。ハーンチが小さく、オープンソースで、モデルに依存せず、かつ自己管理されているため、ノートパソコンで書いたエージェントは、ロックダウンされたデプロイ環境でもそのまま実行されます。移植するのではなく、再デプロイするだけです。

これが IBM Sovereign Core が構築する基盤であり、私たちが CUGA を次の段階へと進めた場所でもあります。詳細は別途記載しましたが、要約すると、Sovereign Core は「境界隔離(Boundary Isolation)」と呼ばれる仕組みの下で CUGA エージェントを実行します。データ、制御プレーン、実行エンジンが同じ論理的な境界内にあり、エージェントはテナント自身のワークスペース内で一時的かつ隔離されたコンテナ上で動作します。モデルもそこで稼働します。デプロイメントのデフォルト設定では、gpt-oss-120b がインフラストラクチャ内で完全にエアギャップ(物理的に分離)された状態で実行され、ツールは個別の承認を得たプライベート VNET 内のみへのアクセスを許可されます。すべての推論ステップは OpenTelemetry トレースとして Grafana Tempo バックエンドに出力されますが、これはテナント内に留まり、外部へテレメトリを送信することはありません。境界を越えて何かが流出することは決してありません。

エージェントの定義自体が変わるわけではありません。変わるのはその周囲のデプロイメントです。これが可能である理由は、上記のすべて——機能、ポリシー、モデル選択——が、あなたが参照可能なランタイム内に存在しているからです。私たちがこれを構築する際に賭けたのは、エージェントのランタイムがブラックボックスであれば主権は単なる約束に過ぎないが、オープンなコードであれば主権は検証可能なものになる、という点です。あなたがクローンしたアプリやあなたが作成したエージェントは、この主張を支える同じオープンなランタイム上に存在します。

ただし、開発者にとっての教訓はそれ自体で成立します。エージェント型アプリケーションは、頭の中で把握できる単一のファイルで構成され得ます。実際に作成するのはツールとプロンプトのみです。これらのアプリケーションは学習のためのライブラリであり、完成されたデモではありません。そして、リスクが高まった際も、ガバナンス機能はすでにランタイム内に組み込まれており、安全性を確保するためにエージェントを再構築する必要はありません。

次のステップ

リポジトリをクローンしてアプリケーションを実行してください。ホストされた 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 # 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 — 24 の洗練されたシングルファイルエージェントアプリ(内部カタログ;ここからクローンしてください)
  • 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 Community post on how CUGA runs inside Sovereign Core (Srivastava, Marreed, Thomas, April 2026)
  • IBM Sovereign Core — product page
原文を表示

Back to Articles

Why a harness, not a framework One app, start to finish The convention that does the heavy lifting A library, not a demo Keeping your agent within the boundaries Growing past one agent Governed by construction Where the same agent ends up Next steps Resources TL;DR — Building an agent is mostly plumbing: tools, state, guardrails, scaling from one agent to many. CUGA (pip install cuga), short for Configurable Generalist Agent, the Agent Harness for the Enterprise from IBM handles that, so you write just a tool list and a prompt. We built two-dozen single-file apps to prove it. Read one end to end here, then see how the same agent runs sovereign and governed in production without a rewrite.

Most agentic apps start with a week of plumbing before the agent does anything useful. You pick a framework, wire up a model client, write tool adapters, build some way to stream state to a UI, and somewhere in there you also decide what the agent is actually for. The interesting part arrives last.

CUGA inverts that. It's the open-source agent harness from IBM that handles the planning, the execution loop, the tool calls, and the state plumbing for you. What's left is the part that's actually yours: which tools the agent can reach, and what you tell it to do. To show what that feels like in practice, we built cuga-apps: two dozen small, working apps, each a single FastAPI file wrapping one CugaAgent, from a movie recommender to an IBM Cloud architecture advisor. They exist to be read and copied.You can click through the live gallery.

This article walks through one of them, names what the harness takes off your plate, and shows where the same code goes when you need it governed for production. No new framework to learn first. If you've written a FastAPI route, you can read every line.

Why a harness, not a framework

The fair question to ask of anything in this space is what it saves you from writing. CUGA's answer: the orchestration around a model that you'd otherwise rebuild every time.

It plans before it acts, then executes with a mix of tool calls and generated code (CodeAct). On a long task that runs twenty steps, the thing that breaks most agents is losing track of intermediate results and re-deriving them (often wrong) on the next turn; CUGA holds that state and runs a reflection step that can catch a bad call and re-plan instead of barreling ahead. That machinery is why it has topped agent benchmarks like AppWorld and WebArena rather than something you tune by hand.

You also set the cost/latency tradeoff from config rather than code: Fast, Balanced, and Accurate reasoning modes, with code execution in whatever sandbox you trust (local, Docker/Podman, or E2B cloud). Same agent definition, different dial. That dial matters more than it sounds. Most harnesses assume a frontier model sits underneath and lean on it to recover when a plan goes sideways; CUGA does that work itself. The planning, the reflection step, the variable-tracking that keeps a long run on course — that's the harness carrying load the model would otherwise have to, which is what lets a smaller open-weight model hold up where it normally wouldn't. It's why the hosted apps run on gpt-oss-120b rather than a frontier API. Running the biggest model you can call is the usual bet; CUGA's is that a smaller open one is enough.

None of the individual pieces is unique to CUGA. What's different is that they come pre-assembled, so you configure them instead of wiring them together. The API you touch is small — build a CugaAgent with a tool list and a prompt, then await agent.invoke(...). Everything below that line is the harness.

Concretely, that's interchangeable tools (OpenAPI, MCP, and LangChain functions all bind the same way), long-horizon planning with variable management and self-correction (the machinery behind #1 on AppWorld from 07/25 - 02/26 and WebArena from 02/25 - 09/25), declarative guardrails, multi-agent delegation over A2A, Docling-powered RAG, and one-env-var provider switching (pip install cuga, then OpenAI, watsonx, Ollama, and more) — each something you'd otherwise build yourself. The first word of the name does the work: *Configurable*; the hard parts are handled, so your job is just the task.

One app, start to finish

Here's the IBM Cloud advisor — an agent that recommends real IBM Cloud services for an architecture. The whole thing fits in one file: a main.py with the agent factory, the tools, and the prompt, plus a small UI.

The whole agent is this:

code
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"),
    )

Four arguments. The model comes from a small factory (create_llm) that speaks to OpenAI, Anthropic, watsonx, LiteLLM, or Ollama depending on an environment variable. Nothing in the app code knows which model sits behind it. The cuga_folder is where this app keeps its state and any policies. The two arguments that carry the app are tools and special_instructions.

The tools mix a local function with a hosted one:

code
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]

There's a pattern here that holds across every app: a split between MCP tools and inline tools. Generic, stateless capabilities come from shared MCP servers; load_tools(["web"]) pulls in web search without you hosting anything. Anything specific to this app gets defined inline as a normal Python function, like search_ibm_catalog, whose docstring is what the agent reads to decide when to call it. You write the one tool that's yours and borrow the rest.

The cloud advisor's prompt tells the agent to search the catalog before naming any service, recommend three to seven services with each one's role in the design, and never invent service names. That last rule earns its keep: an agent recommending IBM Cloud services that don't exist is worse than no agent, so the prompt forces every recommendation through a catalog lookup first. Prompts written as ordered steps with explicit "don't make things up" rules behave; prompts written as personas wander.

That's the app. A tool, a procedure, four lines of constructor. The FastAPI routes around it are ordinary web code: the browser posts a question to /ask, and the live panel polls a /session/{thread_id} endpoint for state. There's no database; state is a per-thread_id Python dict that only the agent writes to, through its tools. The moment the agent calls a tool mid-run, the panel redraws. The UI isn't a second copy of the logic; it's a view onto state the agent mutated.

The convention that does the heavy lifting

One detail is easy to skip and turns out to be load-bearing: every inline tool returns the same small envelope. Success looks like {"ok": true, "data": {...}}; failure looks like {"ok": false, "code": "...", "error": "..."}.

It looks like boilerplate. It isn't. CUGA's planner handles a *declared* failure gracefully ("geocoding didn't return anything, skip that section and keep going") and chokes on an *undeclared* one, where a raw stack trace bubbles up mid-plan and the run derails. Across the apps, the ones that worked reliably were the ones whose tools never threw a bare exception at the agent. A boring convention, but it's the difference between an agent that recovers and one that face-plants.

The split above only pays off because the generic half is already running somewhere. The capabilities the apps reach for over and over — web search, Wikipedia/arXiv, geocoding and weather, finance quotes, and a few more — live in 7 public MCP servers (36 tools) hosted on IBM Code Engine, no auth required. A small bridge resolves their URLs automatically, and the live gallery ships an MCP Tool Explorer to call any of them from a form before you wire it into an agent.

A library, not a demo

The reason there are two dozen polished apps matters more than any single one: once you've read the cloud advisor, you've read all of them. They share a skeleton — the movie recommender swaps the IBM catalog tool for the knowledge MCP server, the web researcher leans almost entirely on web — so cuga-apps is really a catalog of starting points. You clone the repo, find the app closest to your idea, and edit its tool list and prompt (HOW_TO_BUILD_AN_APP_FAST.md and ADDING_AN_APP.md walk through exactly that). A few apps were even generated by handing a coding assistant one spec file and a one-line brief — regular enough for a model to reproduce means regular enough for you to learn. You can click through every one in the live gallery before cloning anything.

They also fan out across families, so whatever you're building, one app already exercises the piece you need. There's a research cluster (Paper Scout ranks arXiv papers by citation count; Wiki Dive and Web Researcher do cited synthesis), an everyday-productivity set (city briefings, travel, recipes, trails), a document-and-media group that does RAG over PDFs, audio, and video, an ops corner watching live metrics, and an enterprise example over real IBM product docs. Ouroboros is a seven-agent lead-gen system; open it for the multi-agent shape. And Meetup Finder drives headless Chromium through Playwright to pull structured events off Meetup, Luma, and Eventbrite (all of which killed their public search APIs); open it for browser automation, which is where CUGA started and the muscle behind its strong WebArena results.

Two caveats before you clone. The real catalog lives in the inner cuga-apps/cuga-apps/apps/ directory, not the outer one. And not every app is equally polished, so the UI tags them ship-ready, for-later, or exploratory and defaults to ship-ready; start from the cloud advisor or movie recommender for a working baseline.

Keeping your agent within the boundaries

A demo agent that searches a catalog is low-stakes. Point the same pattern at something that writes files, runs shell commands, or touches production, and the question changes: how do you stop it doing something you'll regret?

CUGA answers this in the runtime, not in a wrapper you add afterward. The open-source agent ships a policy system, and you attach policies to the same agent object:

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

That's an Intent Guard, one of six policy types, each answering a question a team asks before letting an agent loose:

  • Intent Guard — can it refuse a request outright?
  • Tool Approval — can it pause for a human before a risky tool runs?
  • Tool Guide — can I steer how a specific tool gets used without rewriting it?
  • Playbook — can I pin a known-good procedure for a recurring task?
  • Output Formatter — can I force the final response into a required shape?

A sixth type, CustomPolicy, is the escape hatch when none of those fit. Timing is worth getting right, because it isn't all one stage: an Intent Guard checks the request before the agent picks a tool, Tool Approval runs *after* the agent has generated its code and inspects which tools that code uses, and Output Formatter fires only once the final message exists. Triggers go past keyword matching too: they're held in a sqlite-vec store and matched semantically, so a policy fires on what the user *means*, not just on an exact keyword. Match on semantic similarity, on agent state, or on a specific tool firing. The policies themselves live in that .cuga folder from the constructor, versioned next to the code rather than drifting in a separate config.

For a working example, open Ouroboros — a seven-agent lead-gen app that attaches three policies (an intent guard, a tool guide, and an output formatter) to its supervisor, so it's the one app that demos governance and the multi-agent shape in the same file.

Growing past one agent

Two extensions matter once an app outgrows a single chat loop. When one agent would drown in its own context (too many tools, too much evidence to keep straight), you split the work. A CugaSupervisor delegates to specialist CugaAgents, each with its own tools, prompt, and isolated context, and the supervisor only ever reasons about which specialist to hand a subtask to. Its planning surface stays small no matter how many tools sit underneath, and a flaky tool fails one delegation instead of the whole run. A specialist doesn't even have to be local; it can be an external agent reached over A2A, delegated to the same way. Adding a capability means adding a specialist, not rewriting a coordinator.

The other extension packages know-how rather than tools: Agent Skills, a folder with a SKILL.md playbook the agent pulls into context only when a task calls for it, so one prompt isn't carrying everything the agent might ever need to know. Both keep the same building blocks (tools, prompts, state, policies), just composed a level up.

Ouroboros, the lead-gen app from earlier makes this pattern concrete. It has a supervisor over seven specialists (scout, site auditor, voice-of-customer, person finder, stack scanner, revenue estimator, and a pitch-email writer that synthesizes). Each specialist is one skill loaded into a CugaAgent, and the supervisor calls it through an auto-generated delegate_to_<name> tool. Adding an eighth is a one-line factory, not a coordinator rewrite. Read its main.py and ARCHITECTURE.md if you want the multi-agent shape end to end.

There's a third extension, and it points back at the skills themselves. With ALTK-Evolve, CUGA's on-the-job learning framework, an agent refines a skill from its own runs so a task done today makes tomorrow's faster and more accurate. The SKILL.md a specialist loads ends up holding what the agent learned on top of what you wrote. Same building blocks, except now using one teaches the next. The thing you stop doing is re-prompting through a problem you already solved last week.

Governed by construction

Where governance lives in the stack shapes how the production story goes. A minimal agent library hands you good primitives and leaves the governance (policy, approvals, audit, identity) for you to assemble. CUGA takes the other path: policy, human-in-the-loop approval, the .cuga state folder, and self-hosting are part of the harness from the first line, not a layer you add later.

That changes the direction of the work when you take an agent to production. You're not retrofitting controls onto something built for open access; the control plane is already there. The governed path is the default, and the ungoverned shortcuts are the ones you opt into. So the remaining job is narrow: tighten the sandbox around the few tools that actually touch the outside world, rather than invent the governance around them

Where the same agent ends up

Here's the payoff, and the reason any of this is built the way it is. Because the harness is small, open source, model-agnostic, and already governs itself, the agent you wrote on your laptop is the same agent that runs in a locked-down deployment. You don't port it. You redeploy it.

That's the foundation IBM Sovereign Core builds on, and it's where we took CUGA next. We wrote about the details separately, but the short version: Sovereign Core runs CUGA agents under what we call Boundary Isolation: data, control plane, and execution engine inside the same logical boundary, with agents running in transient, isolated containers in the tenant's own workspace. The model runs there too. Deployments default to gpt-oss-120b running fully air-gapped within your infrastructure, and tools reach only private VNETs with per-tool approval. Every reasoning step emits OpenTelemetry traces into a Grafana Tempo backend that stays in-tenant, with no telemetry phoning home. Nothing leaves the boundary.

The agent definition doesn't change to get there; the deployment around it does. And the reason that's possible is everything above — capability, policy, and model choice all live in a runtime you can read. That's the bet we made building it: when an agent's runtime is a black box, sovereignty is a promise, but when it's open code, sovereignty is something you can check. The apps you cloned and the agent you wrote are the same open runtime that claim rests on.

The developer takeaway stands on its own, though. An agentic app can be one file you hold in your head. The tools and the prompt are the only parts you really write. The apps are a library to learn from, not a sealed demo. And when the stakes rise, the governance is already in the runtime — you don't rebuild the agent to make it safe.

Next steps

Clone the repo and run an app. The hosted MCP servers mean you don't need third-party keys, just an LLM provider. The apps in this article run on the open-weights gpt-oss-120b — the same model the hosted gallery and our Sovereign Core deployments use — but because the model is a one-line swap (create_llm reads a single env var), you can point any app at OpenAI, Anthropic, watsonx, or a local Ollama model with no code change, and at a local model there's no API cost at all:

Start by reviewing our Quick Start Guide here. If you'd like to set up all the applications, ensure Docker is running and then follow the steps below.

code
git clone https://github.com/cuga-project/cuga-apps.git
cd build
cp .env.example .env          # set your LLM provider + key; add TAVILY_API_KEY /
                              # OPENTRIPMAP_API_KEY / ALPHA_VANTAGE_API_KEY for the
                              # apps that use them
docker compose up --build     # first build is large (cuga + Chromium + MCP deps)
# open http://localhost:8080

Then open apps/ibm_cloud_advisor/main.py and read it end to end — it's the clearest example of the inline-tool-plus-MCP pattern. Change the system prompt, add a tool, and watch the behavior shift. The MCP Tool Explorer lists every hosted tool with a form to call it directly, which is a quick way to check the plumbing before wiring a tool into an agent.

So try it. pip install cuga, clone cuga-apps, and run an app — or just click through the live gallery first. The harness lives at cuga-agent and the project home is cuga.dev. If something breaks, an app misbehaves, or you have an idea, we want to hear it: open an issue, file a PR, drop in your own app, or just reach out — the repo is built to be added to, and we read everything that comes in.

Resources

  • cuga-apps — the apps, MCP servers, and UI in this article
  • cuga-apps/apps — the two dozen polished single-file agent apps (the inner catalog; clone from here)
  • cuga-apps/mcp_servers — the shared MCP servers (web, knowledge, geo, finance, code, text, …) the apps borrow
  • Live app gallery + MCP Tool Explorer — every app behind a launch button, plus a form to call each hosted MCP tool directly
  • cuga-agent — the CUGA runtime and policy system
  • cuga.dev — CUGA project home (pip install cuga)
  • Open by Design: Generalist and Pre-Built Agents in the Sovereign Core — IBM Community post on how CUGA runs inside Sovereign Core (Srivastava, Marreed, Thomas, April 2026)
  • IBM Sovereign Core — product page
この記事をシェア

関連記事

Hugging Face Blog★42026年6月17日 19:18

Hugging Face Hub からロボットハードウェアへ:Strands Agents と LeRobot の連携

Hugging Face が、同社のプラットフォーム上で開発された Strands Agents および LeRobot を活用し、AI モデルを直接ロボットハードウェアに展開する取り組みを発表した。

TLDR AI★42026年6月24日 09:00

CUGA を用いた本格的なエージェントアプリ構築:軽量ハーンス上の24の動作例

IBM が公開したオープンソースの「CUGA」は、計画・実行・状態管理の複雑さを処理し、開発者がツール選択とプロンプト設計に集中できるようにするエージェント用ハーンスです。このシステムは効率的な状態維持とエラー修正機能を持ち、AppWorld などのベンチマークで他社を上回る性能を示しています。

Hugging Face Blog★32026年6月23日 09:00

Transformers.js で提案されたクロスオリジンストレージ API の実験

Hugging Face が、Transformers.js 環境で提案されているクロスオリジンストレージ API の実装可能性を実験している。

今日のまとめ

AI日報で今日の重要ニュースをまとめ読み

ニュース一覧に戻る元記事を読む