目次
コンセプト

アーキテクチャ

このページでは、プログラムのテキストが外部システムの変更になるまでの流れと、各段階をActQLのどの部分が担うかを説明します。コンセプトを読んだあとに読むことを想定しています。

全体像

  アプリ · CLI · エージェント
        │  プログラム                           ▲  Result
        ▼                                       │
  ┌───────────────────────────────────────────────────┐
  │ Host                                              │
  │  ポリシーと判断 · 認証情報                        │
  │  処理の配置 · 受け付け · 進行の管理               │
  │  ┌─────────────────────────────────────────────┐  │
  │  │ Core                                        │  │
  │  │  check → bind → plan                        │  │
  │  │  型付きの計算 · Runの状態遷移               │  │
  │  │  実行候補の検証                             │  │
  │  └─────────────────────────────────────────────┘  │
  │  Store                                            │
  │  観測 · Result · Checkpoint · Effectの台帳        │
  └───────────────────────────────────────────────────┘
          │ 読み取り · LLM呼び出し · Effect      │ 計算
          ▼                                     ▼
  ┌───────────────────────────┐   ┌─────────────────────────┐
  │ Connector                 │   │ Compute                 │
  │  SaaS · データベース ·    │   │  エンジン自身 · DuckDB  │
  │  ファイル · LLM           │   │                         │
  └───────────────────────────┘   └─────────────────────────┘

この図が表すのは責務の分担で、プロセスの配置ではありません。どの実行経路が使えるかはHostによって異なります。

Core

Coreは、プログラムの意味を担当します。プログラムを検査し、共通の型付き表現に変換し、共通の実行計画を組み立てます。実行計画には、演算、その型と入力、外部とやり取りする境界、依存する定義、上限が含まれます。さらにCoreは、物理的な実行候補を検証して比較する共通の仕組み、型付きの計算そのもの、そして処理をいつ始めてよいか、いつ完了したか、Runをどう復旧するかを決める状態遷移を持ちます。

Coreは、ネットワーク、ファイルシステム、外部サービスのSDKに直接アクセスしません。ネイティブコード、WebAssembly、JavaScriptの各形式にコンパイルされるので、どのHostでも同じ検査が同じ意味で動きます。ターゲットごとに対応する機能の範囲は異なることがありますが、対応している機能の意味は変わりません。

Host

Hostは、Coreを実際の環境につなぐ部分です。担当するのは次のことです。

  • 読み取り、LLMの呼び出し、Effectのたびにポリシーを確認する(allow、deny、delegate)。delegateの場合は、運用者が設定した委譲先に判断を回し、すぐに答えが出なければCheckpointで待つ
  • 認証情報を管理する。そのため、プログラムに秘密情報が入ることはない
  • Storeを保持する。Runごとの永続的な記録で、何を読み、どのLLMの答えを採用し、何を送ってどんな結果だったか、Result、Checkpoint、Effectの台帳が入る。Hostに設定した保持期間のあいだ保存される
  • 処理の単位を配置し、受け付け、進行を管理し、リソースの上限を割り当てる。決まった時刻に処理を始めるスケジューラーではなく、Runを始めるのはActQLの外側にあるもの
  • 計画を環境に合わせて実行する。手元にあるConnectorと計算エンジンの能力、リソースの上限、現在の権限をもとに、Coreが定めた意味の範囲で、各部分の実行方法を選ぶ

復旧ができるのはStoreのおかげです。Runがクラッシュのあとで続けられるのは、状態を書き残していたからというだけではなく、どの入力を採用し、どの外部操作を試み、それぞれにどんな証拠が返ってきたかをHostが追えるからです。

Hostはどこで動くか

形何か何が違うか
組み込みTypeScriptやPythonのアプリの中、またはCLIの裏で動くローカルのHostStoreは設定した場所に置かれる(既定はアプリのディレクトリ)。承認は、自分のコードかCLIを通して人に届く
リモートHTTPSでプログラムを受け付けるHostアプリは同じSDKでプログラムを送る。Store、認証情報、ポリシーはサーバー側にある
ActQL Cloud同じCoreを、マネージドなHostとして提供するもの自分でHostを運用する必要がない。手元のマシンには収まらない規模の処理も任せられる

ActQLは、実行環境によってプログラムの意味が変わらないように設計されています。同じプログラムは、手元のマシンからリモートのHostへ、変更なしに移せます。ただし条件があり、そのHostに、プログラムが参照するConnectorとmodel task、計画が頼りにするCapability、見合った上限がそろっていることです。足りないものがあれば、Hostは別の意味で代替実行するのではなく、プログラムを拒否します。

Connector

Connectorは、外部システムとやり取りする唯一の場所です。Connectorは次のものを宣言します。

  • 読み取り元 — そのシステムのデータを、型とバージョンを決めて、プログラムから読める形にしたもの(1つ1つがSourceView)
  • Capability — そのシステム自身にできること。どの読み取りと書き込みに対応するか、絞り込みや集計など何を計算できるか、そのコスト
  • Effect — 実行できる型付きの変更と、その結果を確認する方法

入出力を実際に行い、何が起きたかの証拠を返すのはConnectorです。その入出力を始めてよいか、結果が何を意味するかを決めるのはCoreの契約です。Connectorが自分の処理を勝手に「完了」にすることはできません。また、取り消しを求めたリクエストは、Connectorの確認とHost側の実行状態の両方で停止が裏付けられるまで、止まったとは見なしません。

LLMもConnectorを通して呼びますが、INFER は独自の境界を持ちます。model taskは読み取り元とは別の契約で、LLMの呼び出しはそれ自体として認可され、上限を持ち、観測として記録されます。

プログラムが動く流れ

コンセプトの解約リスクのプログラムを例にします。Salesforceの取引先とSnowflakeの利用データをJOINし、取引先ごとの解約リスクをLLMに判定させ、リスクの高いものをSalesforceに書き戻す、というものです。図は、その各部分がどこで実行されるかを示します。図の番号はプログラムの句の順で、下の1〜7は実行の段階です。

Salesforceの取引先とSnowflakeの利用データをActQLエンジンに読み込み、JOINし、取引先ごとにINPUTの列だけをLLMに送り、型付きの答えで絞り込み、更新をプレビューして、承認後にSalesforceへ書き戻す。Snowflakeからは必要な列だけを取得する。

  1. Check(検査) — Hostが公開しているCatalogとSchemaに照らして、Coreがプログラムを検査します。名前が解決できること、列の型が合うこと、model taskの入出力が一致すること、Effectの対象と項目が書き込み可能なことを、業務データを読まずに確かめます。この例では、salesforce.accounts と snowflake.usage_30d が使う列ごと解決できること、churn-risk.v1 が level と reason を返すこと、Churn_Risk__c が Account の書き込み可能な項目であることを確認します。外部システムの実際の状態と現在の権限は、各実行境界であらためて確認します。
  2. Bind と Plan(計画) — パラメーターの値を束縛し、Coreが共通の実行計画を作ります。演算、その上限、外部とやり取りする境界がここで決まります。この例では、2つの読み取り、JOIN、LLMの呼び出し、1つのEffectが、それぞれの上限とともに並びます。計画をどう配置するかは、Hostが自分の環境とConnectorのCapabilityから決めます。読み取り元が対応する列の選択や絞り込みは読み取り元の側で実行し、JOINはローカルの計算、つまりエンジン自身かDuckDBで実行します。
  3. 受け付けと取得 — 読み取りのたびにHostがポリシーを確認します。Connectorがデータを取得し、Coreがそれを観測として取り込みます。復旧でそれを読み直すことはありません。後続のStageが新しい読み取りを宣言していれば、それは別の観測として取得します。
  4. 計算とINFER — 取り込んだ入力に対して、型付きの計算(ここではJOIN)を行います。INFER では、HostがLLMへのアクセスと INPUT の列の送信を認可し、取引先ごとに1回LLMを呼び出し、答えを1つずつ型検査して観測として記録します。その答えに対して、risk.value.level の絞り込みを続けます。
  5. プレビューとCheckpoint — Effectを適用する前に、変更内容を正確に計算します。この例では、取引先の一覧と、それぞれの新しい Churn_Risk__c と Risk_Reason__c の値です。ポリシーの答えは allow、deny、delegate のいずれかで、判断を待つ必要があれば、Runは内容を固定したプレビューとともにCheckpointで止まります。
  6. 適用と突き合わせ — Hostは承認と適用の条件を確認してからEffectを送り、Connectorの結果を検証します。適用済みと記録された操作を、もう一度適用することはありません。応答が返ってこなければ結果はunknown(不明)になり、Hostは元の操作の証拠とConnectorの契約から突き合わせます。安全を確認できない再送はしません。
  7. Resultと完了 — 名前付きのResultがStoreを通して呼び出し元に公開され、Runは succeeded、failed、cancelled のいずれかで終わります。

これは説明のための順序です。Effectのないプログラムでは5と6を通りません。複数のStageを持つプログラムでは一部の段階が繰り返されます。Resultが最後より前に公開されることもあります。

再開

Hostは、Runを続けて復旧するために必要な観測、実行状態、外部操作の証拠を保持します。承認待ち、クラッシュ、再起動で実行が中断しても、必要な証拠、権限、保持期間の条件がそろっていれば、同じRunを続けられます。取り込んだ観測は再利用し、適用済みのEffectは再送せず、結果が不明な操作は再実行ではなく突き合わせの対象にします。記録が見つからないことを「何も起きなかった」証拠として扱うこともありません。

次に読む

Source: actql/actql/docs/concepts/architecture.md at d904416674e4 · Edit on GitHub