Show HN: Strot – LLMの意図を一度コンパイルし、決定をローカルで永続的に実行
Show HN: Strot – Compile an LLM's intent once, run decisions locally forever (github.com)
要約
STROTは、大規模言語モデル(LLM)の意図を一度だけコンパイルし、その結果をローカルで実行可能な決定モデルに変換するツールです。これにより、分類、スコアリング、ルーティングなどの決定を、追加のLLM呼び出しやコストなしに、ローカルハードウェアで永続的に実行できます。コンパイル時にLLMを使用し、ランタイムでは軽量なPythonアーティファクトが決定を処理するため、低レイテンシとゼロ・マージナル・コストを実現します。
全文翻訳
STROT
[画像: PyPI] [画像: License] [画像: Python]
STROTは、決定タスクをスタンドアロンのパイプラインにコンパイルします。意図(クエリと実行可能なアクションのセット)を一度記述すると、LLMがそれをフリーズされたPythonアーティファクトにコンパイルします。それ以降は、軽量なローカルモデルが実際の決定を行います — CPU上で、実行時のAPI呼び出しなしで、型指定されたJSON出力に制限されます。
私がこれを構築したのは、軽量なローカルモデルに確実に物事を「決定」させること(チケットのルーティング、テキストの分類、レコードのスコアリングなど)は、手間のかかる作業であり、ラベルの表現方法によって精度が大きく変動するためです。STROTは、コンパイラがホットパスの作業を移動させるように、その作業をコンパイル時に移動させ、結果をフリーズします。
pip install strot-ai
import strot
result = strot.run(
tickets,
query="Triage incoming support tickets into the correct workflow.",
action_registry={
"billing_dispute": "Refunds, invoice corrections, double charges",
"technical_defect": "Crashes, bugs, broken behavior",
},
llm="anthropic/claude-opus-4-8", # used once, on first compile only
)
for o in result.outcomes:
print(o["action"], round(o["confidence"], 2))
# billing_dispute 0.97
# technical_defect 0.94
LLMは、アーティファクトが最初にコンパイルされるときに一度だけ実行されます。その後、本番環境は自己完結型のPythonファイルになります。軽量なローカルモデルが各レコードを調停し、実行時に何も生成されず、すべての出力が制限され、モデルが確信を持てないレコードは推測する代わりに棄権します。
仕組み
2つのフェーズがあります。高コストで非決定的なフェーズは一度だけ実行され、低コストのフェーズはすべてのレコードに対して永続的に実行されます。
flowchart TB
subgraph compile["COMPILE — once per intent + schema"]
direction LR
A["intent + data sample"] --> B["synthesize<br/>labels · projection · handlers"]
B --> C["golden gate<br/>(must pass your known answers)"]
C --> D["teacher labels a sample<br/>(once)"]
D --> E["fit confidence threshold"]
E --> F[["frozen .py artifact"]]
end
subgraph runtime["RUNTIME — every record"]
direction LR
F --> G["project record"]
G --> H["decision model<br/>144M · CPU · ~60ms"]
H --> I{"confident?"}
I -->|yes| J["typed JSON decision"]
I -->|no| K["abstain"]
end
compile --> runtime
ロード
コンパイラは、最初のラベルの推測を信頼しません。候補となるラベリングを教師がラベル付けしたサンプルに対してスコアリングし、実際に最も良い結果を示すものを保持します。低信頼度のレコードが棄権できるようにキャリブレーションしきい値を設定し、ゴールデンレコードに合格しないアーティファクトの昇格を拒否します。
2つの使用方法
run()は、各レコードをアクションにルーティングし、コンパイルされたハンドラを実行します。
result = strot.run(records, query=..., action_registry={...}, llm=...)
decide()は、レコードごとの型指定された質問に回答します(選択肢/スコア/ブール値)。
result = strot.decide(records, questions={
"is_bug_report": {"type": "boolean", "instructions": "mentions crashes/errors?"},
"customer_sentiment": {"type": "score", "min": 1, "max": 5, "instructions": "1 angry, 5 happy"},
"routing_bucket": {"type": "choice", "options": ["billing", "engineering", "spam"]},
})
# {"booleans": {...}, "scores": {...}, "choices": {...}} with probabilities + confidence
数値
実際のモデル(SupersonicLabs/Julia-1、144M、CPU)、実際のデータセット、クリーンなDockerコンテナで実行。ベンチマークスクリプトはbenchmarks/にあり、損失も含まれています。
| Benchmark | Result |
|---|---|
| Grounded routing (398 records) | 92.5% compiled vs 74.8% naive — the compiler is worth +18pp on the same model |
| Semantic text, unseen labels (AG News) | 86.7% compiled vs 72.7% naive (+14pp) |
| Typed decisions vs a leading hosted decision API's own example | near-identical (sentiment 1.79 vs 1.8) |
| Latency / marginal cost / LLM calls per record | ~60ms · $0 · 0 |
実リスクシナリオについて
レコードレベルの非構造化テキスト、サイバー/金融/保険のトリアージが実際に実行されるような種類のもの。公開されている正解データセット、精度が解釈可能になるようにバランスの取れたクラス、示されたベースライン。STROTはテストラベルを決して見ません。(benchmarks/risk_narratives.py)
| Task — 6-class, balanced | Random | Majority | Naive | Compiled | Abstains |
|---|---|---|---|---|---|
| Cyber — VERIS/VCDB incident note → attack action | 16.7% | 16.7% | 36.8% | 39.5% | 8/114 |
| Finance — CFPB complaint → product | 16.7% | 26.4% | 54.2% | 61.1% | 5/72 |
どちらもベースラインをクリアし、コンパイラは同じ144Mモデルで精度を向上させ、低信頼度のレコードは棄権します。これらは、アーキテクチャが複雑な実際のテキストで機能することの正直な証明であり、本番の引受精度ではありません。そのためには、タスクでトレーニングされたスペシャリストをnlu=スロットに配置することになります。コンパイラ、キャリブレーション、ゲートは変わりません。
内部で実際に行われていること
- 一度コンパイルし、永続的に決定。アーティファクトはコンテンツアドレス指定されており、スキーマの変更は正確に1回の再コンパイルをトリガーし、それ以外は何もトリガーしません。
- ゴールデンレコードはプロモーションゲートであり、ヒントではありません。既知の回答に失敗したアーティファクトは提供されません。
- キャリブレーションは、コンパイル時に適合された温度スケーリングと分割共形予測です。ディスパッチされた決定は、すべてのレコードの最大α(マージナル)で誤りであり、残りは棄権します。
- 実行時に何も生成されません。出力はレジストリの選択と計算であり、保護すべき構造的な幻覚はありません。
- 決定モデルはスロット(
nlu=)です。デフォルトはローカルのJulia-1、ホストされたAPI、またはドロップインできる任意のスペシャリストです。
インストール
pip install strot-ai # core, pure stdlib
pip install strot-ai[local] # + the local decision model (torch/transformers)
pip install strot-ai[hosted] # + openai, for a hosted decision runtime
pip install strot-ai[anthropic] # + anthropic, for the synthesizer
オフライン本番環境では、ビルド時にモデルをイメージに焼き付けます。
RUN pip install strot-ai[local] \
&& python -c "import strot; strot.prefetch_nlu(local_dir='/opt/julia-1', install=True)"
ENV STROT_NLU_CHECKPOINT=/opt/julia-1
(PyPIのjuliaは無関係なパッケージです — インストールしないでください。決定モデルの推論コードは、prefetch_nluによってHugging Faceリポジトリからプルされます。)
ドキュメント
DEVELOPERS.md は、アーキテクチャ、コンパイルライフサイクル、キャリブレーションセマンティクスとその注意点、デプロイメント、モデルスワッピング、および完全なAPIをカバーしています。
ライセンス
MIT。デフォルトの決定モデルはApache-2.0(SupersonicLabs/Julia-1)です。STROT(arXiv:2505.01636)のアイデアを実装しています。