広告

Aver: あなたのコードベースにはAI向けのAPIがない

Dev.to / 2026/3/31

💬 オピニオンSignals & Early TrendsIdeas & Deep AnalysisTools & Practical Usage

要点

  • この記事は、「AI-first/native」なプログラミングの主な障害は、LLM生成のコスト(トークン)ではなく、理解コストであると主張する。エージェントは、ソースコードだけから意図、制約、そして副作用を推測するのが難しい。
  • 既存のコードベースを「考古学サイト」のようなものとして捉え、重要な設計上の意図や権限が、パターンの中に暗黙的に埋め込まれているため、下流のエージェントが振る舞いを理解したり、安全に変更したりするのが困難だと位置づける。
  • Averを、AIエージェントがより多くの意味を保持しつつ活用できるように設計されたAIネイティブ言語として紹介する。意図、効果、アーキテクチャ上の意思決定、期待される振る舞いを言語文法に符号化することで、AIエージェントに伝わる情報を増やす。
  • この記事では、コードが書かれるまでのトークン効率は重要だが、継続的な理解、レビュー、修復、進化のためには、意味的な構造と、強制可能な仕様のほうがより重要であるとしている。
  • 全体としてAverは、最適化の対象を「入力トークンを減らすこと」から「理解を増やすこと」へと転換し、AIシステムが高コストな再構成や推測を行う必要を減らすことを目指す、と示されている。

いくつかのプロジェクトが、自分たちを「AIネイティブ」または「AIファースト」な言語だと名乗り始めています。提案の内容はだいたい同じです。トークンを少なくする、物事を書く方法を一つに絞る、構文をシンプルにする。指標は入力コストです――LLMがファイルをどれだけ安く生成できるか。

ボトルネックは生成コストではありません。問題は理解コストです。次にこのコードに触れるエージェントが、コードが何をするのか何が許されているのかなぜこのように書かれたのかを、すべての行を読まずに理解できるか。生成は速くなり、さらに安くなっています。理解は遅くなり、さらに高くなっています。なぜなら、エージェントが必要とする情報はほとんどの場合、そもそもソーステキスト自体には含まれていないからです。

Aver は、こうした問題を中心に設計されたAIネイティブ言語です。「入力トークンを減らす」ことではありません。出力側の理解を増やす。

あらゆるコードベースは考古学の遺跡である

ClaudeやGPTにPythonプロジェクトを渡して、機能追加を依頼してみてください。大量のファイルを読み込みます。どれが重要かを推測します。変数名やコメントから意図を推測しますが、それらが古くなっていることもあります。どの関数がネットワークと通信しているのか、どれが純粋なのか、そして2019年のStack Overflowの回答を継承したのか、意図して選んだアーキテクチャ上の判断なのかを信頼できる形で知る手段はありません。

AIは、元の作者が持っていた情報を復元するのです。ただし、その情報は成果物(アーティファクト)には符号化されていません。意図、制約、設計上の判断理由――それらのすべては、存在するのであれば、コード内の暗黙のパターンとしてしか存在しません。

そのコードには、最も頻繁にコードを読む対象(読み手)に向けたAPIがありません。

トークン効率は確かに重要。だがそれだけではない。

AIファースト言語の分野では、よく知られた主張があります。選択肢が少ないほど、ライブラリも少なくなる。モデルに覚えさせるべき仕様も短くなる。選択の麻痺を減らし、トークンコストを減らせば、言語はAIにとってより良くなる。

これは確かに最適化目標の一つです。CRUDエンドポイントを生成するのに1,800トークンではなく900トークンで済む言語は、生成コストが本当に安くなります。ですが、短いプログラムは判読可能なプログラムではありません。トークン効率で勝っても、次のエージェントが関数の意図を理解できない、どの呼び出しに副作用があるか判断できない、ある方式が他よりなぜ選ばれたのか分からない、比較のための期待される挙動が分からない――さらに何かが壊れたときに、何が起きたのかを知るためにエラーメッセージを正規表現で解釈しなければならない、というコードになる可能性があります。

トークン効率はコードを書くことに効きます。意味的な表面(セマンティックな表面)は、コードを理解するレビューする修復する進化させることに効きます。Aver言語は、プログラムを作るのに必要な最小トークン数で主に競いません。競うのは、プログラムが存在した後に保存される意味が最も多いことです。

AIファースト言語がエージェントに公開するもの

言語は、意図、効果、アーキテクチャ上の意思決定、そして期待される挙動を、文法の一部としてエンコードします――解析され、型検査され、強制され、エクスポート可能である:

fn fetchUser(id: String) -> Result<HttpResponse, String>
    ? "Fetches a user record by ID from the external API."
    ! [Http.get]
    Http.get("https://api.example.com/users/{id}")

? の行は、説明(リテラル)です――関数のシグネチャの一部であり、コンパイラによって解析され、ツールによってエクスポートされます。コードの横に置くコメントではありません。ツールチェーンが理解している、コードに関する宣言です。

! [Http.get] は宣言された効果(エフェクト)です――静的にも実行時にも強制されます。関数本体が、宣言せずにDisk.writeText を呼び出していたら、それはコンパイルエラーになります。このシグネチャを読むエージェントは、本体を読まなくても副作用の完全な集合を把握できます。

これらの発想は、それぞれ単体では新しいものではありません。重要なのは、それらが一つのエクスポート可能な表面(サーフェス)として合成されていること――そしてそれをエクスポートする具体的なコマンドがあることです。

aver context:エージェントがコードベースに入る場所

ここが中核です。

AIエージェントがAverプロジェクトで作業を始めるとき、ソースファイルを読みません。aver context を実行します。これは意図されたインターフェースであり、あらゆるエージェントにとってのコードベースへの正面入口です。

aver context examples/core/calculator.av

出力:

## Module: Calculator

> Safe calculator demonstrating Result types, match expressions,
> and co-located verification. Errors are values, not exceptions.

### `safeDivide(a: Int, b: Int) -> Result<Int, String>`
> Safe integer division. Returns Err when divisor is zero.
verify: `safeDivide(7, 0) => Result.Err("Division by zero")`,
        `safeDivide(0, 5) => Result.Ok(0)`,
        `safeDivide(9, 3) => Result.Ok(3)`

### `safeRoot(n: Int) -> Result<Int, String>`
> Returns Err for negative input, Ok otherwise. Uses match on a bool expression.
verify: `safeRoot(0 - 1) => Result.Err("Cannot take root of negative number")`,
        `safeRoot(0 - 99) => Result.Err("Cannot take root of negative number")`,
        `safeRoot(0) => Result.Ok(0)`

### Decision: NoExceptions (2024-01-15)
**Chosen:** "Result" — **Rejected:** "Exceptions", "Nullable"
> Exceptions make error paths invisible at the call site.
> Result forces the caller to acknowledge failure explicitly,
> which is essential when AI tooling reads cod…
impacts: `safeDivide`, `safeRoot`

実装の詳細はありません。シグネチャ、説明、効果、verifyブロックから期待される挙動、そしてそのモジュールを制約する設計上の意思決定だけです。約2kトークンで、エージェントは実装の前に契約(コントラクト)を手に入れます。50kトークンの生のソースをコンテキストウィンドウに流し込むのと比べてみてください。

aver context app.av --budget 10kb
aver context app.av --focus processOrder
aver context app.av --decisions-only

まず全体から入り、ズームインします。エージェントはまず契約マップを読み、その後で本当に注意を払う必要がある関数へ掘り下げます。

失敗は「読めるだけ」ではなく「解析可能」である

何かが壊れたとき、aver check は修復の提案やソース抜粋を伴う構造化された診断情報を出力します:

返却形式: {"translated": "翻訳されたHTML"}
error[type-error]: Function 'wrongReturn': 本文は String を返しますが、宣言された戻り型は Int
  at: test_errors.av:30:1
     |
  30 | fn wrongReturn() -> Int
     |                     ^^^  宣言された Int
  31 |     ? "間違った型を返しています(型チェッカーのエラー)。"
  32 |     "oops"
     |     ^^^^^^  String を返します

warning[perf-string-concat]: 再帰呼び出しで `acc` に対する文字列連結
  at: lint_demo.av:20:31
  in-fn: repeat
  repair: イテレーションごとに O(n²);リストに集めて結合することを検討してください

すべての診断には、機械可読のスラッグ、列単位までのソース位置、そして修正提案があります。 --json は NDJSON と同じように出力します — checkverifyreplay 間で同一のスキーマ — そのため、エージェントがエラーを分類し、プログラム的に修正を適用できます。

セッションをまたいで決定が生き残る

AI セッションをまたいで保持するのが最も難しいのは なぜ です。エージェントはコードを読めば、それが何をするかを再導出できます。しかし、なぜそのように書かれたのかを再導出することはできません。

Aver の decision ブロックは、判断理由(rationale)を第一級の構文としてエンコードします:

decision TailRecurrenceForPerformance
    date = "2026-02-24"
    reason =
        "素朴な fib(n-1)+fib(n-2) は指数時間で、AI が生成しやすい。"
        "末尾再帰にすると fib は線形時間になり、予測可能になる。"
    chosen = "TailRecursion"
    rejected = ["NaiveRecursion"]
    impacts = [fib, fibTR]

解析され、検証され、aver context --decisions-only 経由でエクスポートされます。今から 3 か月後にエージェントが fib に触れたとき、このブロックを読み取り、指数的なバージョンが検討され、却下されたこと — 明示的な理由つきで — を知ります。

建築上の判断理由を、慣習ではなく文法として扱う言語はあまり見かけていません。とはいえ、それが解決済み問題だという意味ではありません — 判断の質を強制するのは、やはり著者側にかかっています。ですが、このツールチェーンは、理由を型やエフェクトと同じように公開します。

レコード/リプレイがエフェクトのループを閉じる

純粋関数には verify ブロックがあります。エフェクトを伴うコードにはレコーディングがあります。 aver run --record は、呼び出し側、引数、結果に対する、すべてのエフェクト的な相互作用を捕捉します。 aver replay --test --diff は、そのレコーディングに対して決定論的に再実行します。コードがずれた場合、構造化された診断が得られます — どのエフェクトが、どの関数で、どのステップで変わったのか。

これが意味するところ

Aver は、意図、エフェクト、判断、期待される挙動、構造化された失敗を 1 つのエクスポート可能な表面に合成します。 aver context が入口です。残りのツールチェーンはそこへ流れ込みます。エージェントは、実装の前に契約を得て、リファクタリングの前に判断理由を得て、壊れたときにはパース可能な失敗を得ます。

Aver はまだ早期で未完成です。しかし、このセマンティックな表面はすでに今日動いています。 repo はここにありますマニフェストはここにありますcargo install aver-lang を実行し、aver context にモジュールを指定して、出力されるものを読んでください。

Previous posts: A prompt is a request, a language is the law | The most boring games you have Aver seen | I gave my language VM four memory lanes

広告