ミシガン大学のJason Mars教授は、2026年10月20日に米ノースカロライナ州ローリーで開催された技術カンファレンス「All Things Open 2026」で、AIエージェントを言語機能として組み込んだプログラミング言語「Jac」と、その実行基盤「Jaseci」を紹介した。JacはPythonに似た構文を採用しながら、グラフ構造によるデータ管理、大規模言語モデル(LLM)の呼び出し、LLVMを利用したネイティブコンパイルなどを統合する。Python、JavaScript、TypeScript、Cなど、用途ごとに異なる言語や開発ツールを組み合わせる負担を減らし、人間とAIエージェントの双方がアプリケーションを開発しやすい環境を目指している。
AIエージェントによるソフトウェア開発が広がるにつれ、既存のツールチェーンが抱える複雑さも課題となっている。異なる言語間のコード変換やライブラリの接続、複数のビルドシステムの管理は、開発の手間だけでなく、AIエージェントが消費するトークンや実行コストの増加にもつながる。Jacは、こうした作業をコンパイラとランタイム側で吸収し、単一の言語でアプリケーション全体を記述できるようにする試みだ。ただし、公式ドキュメントを詳しく見ると、機能によって利用できるコンパイル先が異なり、メモリ管理や並行処理にも制約があることが分かる。2026年10月下旬時点の公開資料とカンファレンスでの発表内容をもとに、Jacの技術的な特徴と実務導入に向けた課題を整理する。
Python、JavaScript、ネイティブコードを統合する3つの実行環境
Jacの基本的な設計は、Pythonのスーパーセットを目指す構文を採用しながら、AIエージェント向けの機能を言語そのものに組み込むことにある。Mars教授はAll Things Openの講演で、従来の多言語環境では、異なるツールやライブラリを接続するために多くの作業が必要になると指摘した。Jacはその複雑さを減らすため、同じ言語で記述したコードを、用途に応じて異なる実行環境へ配置する仕組みを採用している。
Jacの公式資料によると、コードの配置先は主に3つの「コードスペース」に分かれる。特別な指定のないコードは、Pythonランタイムを利用するサーバー側で動作する。ブラウザなどのクライアント側ではJavaScriptやTypeScriptのエコシステムを利用し、計算性能が求められる処理はLLVMを通じてネイティブ機械語にコンパイルする。それぞれのコードスペースを明示的に指定することもでき、処理の配置先を言語側で管理する設計となっている。
| コードスペース | 実行環境 | 利用するエコシステム | 主な用途 |
|---|---|---|---|
| サーバー(Server) | Pythonランタイム | PyPI | バックエンド処理、データ管理、AIエージェントの実行 |
| クライアント(Client) | JavaScript / TypeScript | npm | ブラウザ上の処理、フロントエンド、UI |
| ネイティブ(Native) | LLVM経由の機械語 | C ABI | 高速な数値計算、低レイテンシ処理、システムレベルの連携 |
Jacを特徴づける機能の一つが、関数の処理をLLMに委ねるby llm()構文だ。従来のアプリケーションでは、LLMを利用するためにAPIクライアントを用意し、プロンプトの生成や応答の解析を個別に実装することが多い。Jacでは、関数の名前、引数、戻り値の型などを定義し、その実装をLLMに委ねられる。これはコンパイラ自体が自律的にコードを生成する仕組みではなく、プログラムの実行時に指定されたモデルへ処理を委譲する機能である。
例えば、プルリクエストのコードレビューをLLMに任せる関数は、次のように記述できる。
def review_pull_request(diff: str, context: str) -> list[str] by llm();
sem review_pull_request = "コード差分に潜むバグやセキュリティ上の問題を列挙する。";この機能を支えるのが、Jacに統合された「byLLM」だ。公式リファレンスによると、byLLMは関数名、引数と戻り値の型、semで与えられた自然言語の説明などから、LLMに渡すプロンプトを組み立てる。実行時には設定に応じてクラウドのLLM APIやローカルモデルを呼び出し、得られた応答を解析して、指定された戻り値の型に適合するか検証する。開発者がプロンプト処理を一から実装する必要を減らせる一方、生成結果の正確性や例外処理まで保証されるわけではない。
なお、Jacが掲げる「Pythonスーパーセット」や「Pythonエコシステムとの完全な互換性」については、実際に利用するコードとコンパイル先を区別して評価する必要がある。Pythonランタイムを利用するコードスペースでは既存ライブラリとの連携を重視しているが、すべてのPython構文や複雑なC拡張ライブラリが、修正なしであらゆるコードスペース上で動作するわけではない。特にLLVMを利用するネイティブ経路では、Python側で利用できる多くの機能が制限されている。
グラフ指向プログラミングと、自動永続化の制約
Jacのもう一つの柱が、オブジェクト空間プログラミング(Object-Spatial Programming:OSP)だ。これは、データをノードとエッジからなるグラフとして表現し、そのグラフ上を処理が移動するプログラミングモデルである。従来のオブジェクト指向では、オブジェクトのメソッドを呼び出したり、データを取得して処理したりするのが一般的だ。これに対してOSPでは、ノード間の関係と、その関係に沿って移動する処理を言語レベルで定義する。
OSPを構成する主要な要素は、Node、Edge、Walkerの3つだ。
| 構成要素 | 役割 | 従来のプログラミングモデルとの違い |
|---|---|---|
| Node | 属性を保持するグラフの頂点。データの基本単位となる | クラスのインスタンスやデータベースのレコードに近いが、グラフ上の接続関係を持つ |
| Edge | ノード間の関係を表し、方向や属性を持たせられる | 外部キーやオブジェクト参照とは異なり、関係そのものを明示的なグラフ要素として扱う |
| Walker | グラフを移動しながら処理を実行する主体 | 到達したノードに応じて、定義された処理(アビリティ)を呼び出す |
OSPでは、処理を実行する場所がデータの構造と結びついている。例えば、従来の方法では、データベースから取得した情報をPythonオブジェクトやJSONへ変換し、エージェントがその内容を読み取って処理する。Jacでは、ウォーカーをグラフへ送り出し、接続関係をたどりながら各ノードに定義された処理を実行できる。Mars教授は講演で、データの取り出しや変換に必要な作業を減らすことで、AIエージェントのトークン消費を大幅に削減できると主張した。
ただし、グラフ上で処理を完結させる設計が、どの程度のトークン削減や費用削減につながるかは、具体的なワークロードによって異なる。公開ドキュメントからは、一般化できる削減率や、従来のデータベース構成との包括的な費用比較を確認できない。グラフ構造を構築・維持する費用も含め、実際の処理全体で比較する必要がある。
データの永続化にも明確なルールがある。Jacの基本設計では、組み込みのrootノードから到達できるグラフ要素が永続化の対象になる。通常のローカル変数や、グラフとの接続を持たない孤立オブジェクトが、無条件に保存されるわけではない。ウォーカーの実行中に保持する一時的なデータやクロージャ内の変数についても、グラフの永続化とは区別しなければならない。
永続化したデータの構造を変更する際にも注意が必要だ。Jacには、既存データのフィールド名変更などを明示的なルールで処理する仕組みが用意されているが、変更内容から移行方法を自動推論する機能や、破壊的なスキーマ変更をビルド時に網羅的に検出する静的解析機能が完成しているわけではない。属性名の変更や型の変更、既存データとの不整合が発生する場合には、開発者が移行手順を設計する必要がある。永続化の記述量を減らせることと、運用時のデータ移行まで自動化されることは別の問題だ。
並行処理についても、Jacの言語機能だけでCPU処理が高速化されるとは限らない。公式の並行処理リファレンスによると、JacにはI/O処理を効率的に扱うasync/awaitと、ワーカースレッドで処理を実行するflow/waitがある。後者はブロッキングI/Oや、GILを解放するネイティブ拡張の処理を重ねて実行する用途に向いている。しかし、標準のCPythonランタイムではGIL(グローバルインタプリタロック)が有効なため、純粋なJacコードでCPU負荷の高い計算を複数スレッドに分けても、同時に並列実行できるわけではない。公式ドキュメントも、こうした処理には別プロセスの利用を推奨している。
また、複数のウォーカーを異なる経路へ送り出すことと、CPUコアを使った並列実行は同義ではない。グラフ全体を走査して大量のデータを一括集計する処理についても、一般的なバッチ処理エンジンのほうが適する場合があると、公式チュートリアルは説明している。OSPはグラフ上の関係や移動を伴う処理に適したモデルだが、すべての計算処理を置き換えるものではない。
LLVMネイティブコンパイルと所有権モデルの実際
Jacは、LLVMを利用したネイティブコンパイルに加え、Rustに似た所有権と借用の仕組みも採用している。Python風の構文で記述したコードを機械語へ変換し、必要に応じて参照カウントやガベージコレクション(GC)を使わないメモリ管理を選択できる点は、従来のスクリプト言語との大きな違いだ。ただし、この仕組みには厳密な条件があり、Jacのコードをネイティブコンパイルするだけで、すべての機能やメモリ安全性がそのまま引き継がれるわけではない。
ネイティブコンパイルの公式リファレンスでは、通常のJacプログラムの一部をネイティブコードとしてコンパイルする方法と、独立したネイティブバイナリを生成する方法が説明されている。例えば、処理速度が重要な数値計算だけをネイティブ側に配置し、AIエージェントやデータ永続化を扱う処理はPython側に残せる。一方、ネイティブコードスペースではOSPやLLM連携など、Jacを特徴づける多くの機能が現時点で利用できない。
| 主な機能 | サーバー(Python) | ネイティブ(LLVM) |
|---|---|---|
| 通常の関数、制御構文、基本データ型 | 対応 | 対応。ただし一部の構文に制限あり |
| OSP(Node、Edge、Walker) | 対応 | 非対応 |
by llm()によるモデル呼び出し |
対応 | 非対応 |
async/await |
対応 | 非対応 |
| PyPIパッケージの利用 | 対応 | 非対応 |
| Pythonコードの埋め込み | 対応 | 非対応 |
| LLVMによるネイティブ機械語の生成 | 対象外 | 対応 |
この違いは、Jacの導入を検討する際に重要となる。AIエージェントの処理、グラフデータ管理、高速なネイティブ計算を一つの言語で記述できても、それらをすべて同じ実行環境で動かせるわけではない。実際には、Pythonとネイティブコードの間に境界があり、機能に応じて処理を分ける必要がある。
所有権と借用の検査はオプトイン
Jacの所有権モデルでは、own、imm、共有参照の&、可変参照の&mutなどの注釈を使う。これらによって、値の所有者や参照の扱いをコンパイル時に検査できる。ただし、所有権の検査は段階的に導入する方式であり、注釈のない通常の変数まで自動的に厳格な所有権管理の対象になるわけではない。標準的なコードでは、従来のGC管理を利用する設計となっている。
Pythonバックエンドで実行する場合も、所有権注釈はコンパイル時の検査に使われるが、その情報は実行時には保持されない。このため、Jacに所有権注釈を追加しただけで、Pythonコード全体にRustと同等のメモリ安全性や実行性能が備わるわけではない。ネイティブコードで参照カウントを使わない構成を得るには、対象コード全体で必要な所有権情報を明示し、コンパイル時の検査を通す必要がある。
具体的には、ネイティブコンパイルで--gc noneと--enforce-nogcを指定し、所有権の条件を満たさないコードをエラーとして扱う。さらに--assert-no-rcを使用すると、生成されたLLVM IRに参照カウントやGC関連の処理が残っていないかを確認できる。これらの条件を満たした場合に、参照カウントを使わず、静的に決定されたタイミングでメモリを解放するバイナリを生成できる。つまり、ゼロGCはネイティブコンパイルに伴う標準的な性質ではなく、コードの書き方とビルド設定によって成立するものだ。
ネイティブ環境では、Linuxのx86_64とaarch64、macOSのx86_64とarm64、Windowsのx86_64が対応プラットフォームとして挙げられている。また、外部ライブラリとの連携にはC ABIを利用できるが、すべてのC++ライブラリをそのまま直接呼び出せるわけではない。複雑な型やオブジェクトの受け渡しでは、ABIの互換性やデータ表現を確認する必要がある。Jacが掲げる単一言語による開発環境の統合と、異なる実行基盤の制約が完全になくなることは区別すべきだろう。
ソースコードの「エジェクト」も万能ではない
講演では、Jacで記述したアプリケーションを既存の開発環境向けのソースコードとして取り出す「Eject」機能も紹介された。以前はjac ejectと呼ばれていたが、現在のCLIリファレンスではjac build --as sourceに統合されている。このコマンドは、Jacのプロジェクトから編集可能なFastAPIとJavaScriptのソースコードツリーを生成するものだ。Jacのツールチェーンに依存しない形でコードを扱いたい場合や、企業の開発・監査手順に組み込む際の選択肢となる。
ただし、この機能は任意のJacコードをPython、TypeScript、Cへ完全かつ可逆的に変換する汎用的な逆コンパイラではない。生成先は特定のアプリケーション構成を前提としており、すべての言語機能が元の意味を保ったまま相互変換できることを保証するものでもない。出力されたコードをどの程度理解・編集できるか、Jacを使わずに保守し続けられるかについては、個別のプロジェクトで検証する必要がある。
ここまでの仕様を、実務導入時の確認事項と対応づけると次のようになる。
| 項目 | Jacの主な機能 | 制約・未検証事項 | 導入時の確認事項 |
|---|---|---|---|
| コア構文・LLM連携 | Python風構文、by llm()による処理委譲 |
Pythonとの完全な互換性や、モデル応答の正確性は保証されない | 既存コードの互換性、応答の型検証、エラー処理、推論コスト |
| データ永続化 | OSP、rootからの到達可能性に基づく永続化 |
孤立オブジェクトは自動保存されず、スキーマ変更にも制約がある | データ移行、障害復旧、グラフ走査の性能 |
| 並行・並列処理 | async/await、flow/wait |
CPythonのGILにより、純粋なJacコードのCPU並列実行は制限される | プロセス分離、同時実行時の競合、スレッド利用の効果 |
| ネイティブコンパイル | LLVMによる機械語生成、C ABI連携 | OSP、LLM連携、非同期処理、PyPI利用などは非対応 | Python側との境界、データ変換、呼び出しオーバーヘッド |
| メモリ管理 | 所有権・借用の検査、ゼロGC構成 | 検査は段階的な導入方式で、完全なゼロGCには追加条件が必要 | 所有権注釈の負担、ビルド制約、生成コードの検証 |
| ソースコード出力 | jac build --as source |
特定スタック向けの出力であり、汎用的な可逆変換ではない | 生成コードの可読性、編集可能性、長期保守 |
All Things OpenでのLangGraph比較は何を示したのか
Jacの有効性を示すため、Mars教授はAll Things Openの講演で、既存のAIエージェント開発フレームワークとの比較を紹介した。カンファレンスの公式セッション説明によると、比較対象はJac、LangGraph、CrewAIの3つで、同じ仕様とLLMを使ってAIコードレビューツール「Greptile」のレプリカを構築するという内容だった。目的は、必要なコード量やインフラを接続するためのコード、設計上のトレードオフを比較することにあった。これは開発手法の違いを示すデモであり、査読を経た包括的な性能ベンチマークではない。
The Registerの10月23日付の報道によると、Mars教授はAIエージェントに各フレームワークを使わせ、アプリケーションを生成させたという。Jacでは複数のツールを並行して呼び出す多段階の構成が生成されたのに対し、LangGraphでは並行処理を利用しない単純な線形ステートマシンが生成されたと報じられている。Mars教授はこの違いを、AIに与えるツールや抽象化の水準が生成結果の品質を左右する例として紹介した。
しかし、このデモからLangGraph自体の並行処理能力がJacより劣ると結論づけることはできない。LangGraphの公式ドキュメントには、複数ノードの並行実行、Fan-outとFan-in、状態更新を統合するReducerなどの仕組みが明記されている。最大並行数を制御する設定も用意されており、フレームワークとして並行処理を実行する機能が欠けているわけではない。
今回の違いは、AIエージェントが各開発環境をどのように理解し、利用したかを反映している可能性がある。例えば、プロンプトの内容やエージェントに与えた資料、利用したライブラリのバージョン、使用可能なツールの指定によって、生成されるアーキテクチャは変わり得る。具体的な指示内容、試行回数、リトライ条件、モデルの設定などが公開されていなければ、同じ結果を再現できるかどうかも判断できない。少なくとも、単一の生成例をもってフレームワークの優劣を一般化するのは適切ではない。
公平に比較するには、生成されたコードの行数や構造だけでなく、実行性能や運用面も評価する必要がある。具体的には、処理のレイテンシ、LLMが消費するトークンと費用、エラー発生率、障害からの復帰、仕様変更への対応などが比較対象になる。Jacが少ない記述量で複雑な処理を表現できたとしても、それが常に低コストで安定した運用につながるとは限らない。
なお、Mars教授は講演の冒頭で、Bunの開発者Jarred Sumner氏が、Zigで書かれたコードをRustへ移植するためにAnthropicのトークンを16万5,000ドル分消費したというエピソードにも言及した。これは多言語間のコード変換に大きな費用がかかり得ることを説明するための事例だ。ただし、この費用がJacを使うことでどの程度削減できたかを検証したものではなく、Jacの性能や経済的な優位性を直接裏付けるデータではない。
Jacの成熟度と、実務導入に向けた課題
Jacを本番環境で採用する際には、言語機能だけでなく、ツールチェーンの成熟度と長期的な保守性も重要になる。JaseciのオープンソースプロジェクトはMITライセンスで公開されており、GitHubのJaseciリポジトリの作成日は2021年10月29日にさかのぼる。今回のカンファレンスで初めて登場した技術ではなく、数年にわたって研究と実装が進められてきたプロジェクトだ。その後も言語仕様や実行基盤の開発が続けられ、配布方式も変化している。
大きな転換点となったのが、Jac v0.30.0で導入された自己完結型のネイティブバイナリによる配布だ。現在のインストール方式では、jacバイナリに必要なランタイムが組み込まれており、ホスト環境にPython本体やpip、uvなどを個別に用意する必要はない。開発環境の構築やツールの導入を簡素化できる一方、アプリケーションが利用するJacのバージョンを適切に管理する必要がある。
特に注意したいのは、公式の設定リファレンスが、Jacのツールチェーンについてバージョン間の後方互換性を保証していないと明記している点だ。破壊的変更が新しいバージョンで導入される可能性があるため、開発元はプロジェクト設定ファイルjac.tomlで、対象のツールチェーンを明示的に指定することを推奨している。jac-versionにはPEP 440形式のバージョン指定を利用でき、例えば==0.34.3のように特定バージョンへ固定できる。公式資料には0.34.1や0.34.3といったバージョンを用いた例が見られるが、実際の導入では使用するリリースを固定し、その環境で動作を検証する必要がある。
後方互換性の保証がないことは、継続的に開発されるシステムでは無視できない問題だ。新しい言語機能やコンパイラの改善が進んでも、更新によって既存コードが動作しなくなれば、移行作業やテストの費用が発生する。特にJacでは、言語仕様だけでなく、PythonやJavaScriptとの連携、ネイティブコンパイル、データ永続化など、複数の機能が一体となっている。更新時には、これらの境界で互換性の問題が起きないかを確かめなければならない。
費用面についても、Jacがオープンソースであることと、アプリケーションを無償で運用できることは別だ。by llm()でクラウドのLLMを呼び出せばAPIの従量課金が発生し、ローカルモデルを使用する場合もGPUやホスト環境の費用がかかる。さらに、データのスキーマ変更や異なるコードスペース間の連携、ツールチェーンの更新に伴う保守工数も考慮する必要がある。Jacによってコードの記述量が減ったとしても、運用費用まで比例して減るとは限らない。
こうした制約を踏まえると、Jacの導入は小規模な概念実証(PoC)から始めるのが現実的だ。最初からすべてのコードスペースやOSPの機能を使うのではなく、サーバー側の処理と必要最小限のネイティブ処理に範囲を絞り、既存の開発環境と比較する。その際、特に確認すべき項目は次の4点となる。
- LLM連携の信頼性:
by llm()の戻り値が型定義に適合する割合、誤った応答への対処、エラーからの復帰率、推論にかかる費用。 - データ永続化の保守性: 属性や型を変更した際のマイグレーション作業、破壊的変更への対処、既存データの復旧手順。
- 既存ライブラリとの相互運用性: PythonやCのライブラリとの接続、コードスペース間のデータ受け渡し、呼び出しに伴うオーバーヘッド。
- ツールチェーンの安定性: バージョン更新によるビルドエラーや動作変更の頻度、必要な修正作業、既存コードとの互換性。
Jacの特徴は、AIエージェント向けの機能を既存言語の上にライブラリとして追加するのではなく、言語仕様と実行基盤の一部として扱おうとしている点にある。LLM呼び出し、グラフ構造、データ永続化、複数の実行環境を単一の言語で管理するという構想は、複雑化した開発環境を見直す一つの方向性を提示している。ただし、ネイティブ経路の機能制限やGILによる並列処理の制約、バージョン間の互換性など、現時点では慎重に評価すべき課題も多い。Jacが実用的な選択肢として定着するかどうかは、構文の簡潔さやデモの印象だけでなく、実際のアプリケーションで開発・運用コストをどこまで削減できるかによって判断されることになる。



