MINARA

学習システム

Agent が繰り返しタスクを時間とともに改善していく仕組み

Minara Agent には学習ループが組み込まれています。成功したツール呼び出しのシーケンスを記録し、次のターン以降に提案として表示します。モデルのファインチューニングとは異なり、すべて SQLite の行として管理されます。トレーニングジョブも、モデル更新も、オフラインパイプラインも不要です。このページでは各コンポーネントとスキルシステムとの連携を説明します。

「学習」の意味について。 Minara における「学習」とは、ファインチューニングや重みの更新ではありません。モデル自体は変わりません。変わるのは、ターンごとに Agent が SQLite から取得する内容です。具体的には、実績のある {tool_name, args} シーケンスのライブラリ、自由記述のガイダンスノート、そして構造化メソドロジーです。過去の成功例に似た新しいターンでは、その過去のシーケンスが提案として表示されます。それだけです。この設計は、高度さよりも監査可能性を優先しています。「学習済み」の動作はすべて、読み取り・編集・削除可能な行として存在し、オペレーターが確認できない動作は一切持続しません。

実際の動作を見る: 機能 → 自己改善では、ユーザー向けのインターフェースを紹介しています。Agent に学習内容を保存させる方法や、それが以降のセッションでどう表示されるかを確認できます。

特定のスキル呼び出しが正しかったかどうかをロール単位で LLM が2段階で判定する、並行的な意思決定リフレクションループについては、ロールメモリを参照してください。このシステムは本ページのシステムと並行して動作し、異なる問いに答えます。「どうやって成功したか」ではなく、「この具体的な判断は正しかったか、その理由は何か」を問うものです。

学習される内容

learnings テーブル(および apps/agent/src/learning/ 配下の関連テーブル)には、3種類のアーティファクトが格納されます。

  1. ツールシーケンス。 Agent がタスクを達成するために実行した {tool_name, args} のペアを順序付きリストで記録したものです。ターン終了時に Agent が skill_learn を明示的に呼び出したときに記録されます。
  2. ガイダンスノート。 「Polymarket の価格取得には、特定マーケットの URL に対して web_extract を使うこと。API のレート制限は 10 rpm。」といった短い自由記述です。ツールシーケンスに付随して保存されます。
  3. メソドロジー。 learning/structured-methodology.ts が保存する、成功基準を持つ構造化された多段階プランです。単純なツールシーケンスでは表現しきれないディープリサーチのワークフローで使用されます。

フィードバックループ

learning-system diagram

review-engine

learning/review-engine.ts は、ターン終了時に動作する軽量な LLM パスです(app.ts にインストールされた review-engine-hook.ts 経由で呼ばれます)。処理内容は以下のとおりです。

  1. ターンのツール呼び出しシーケンスを検査する。
  2. 呼び出し回数が N 件未満のターン、または明らかな失敗を除外する。
  3. 「このタスクは完了したか?どれほど新規性があるか?どれほど再利用可能か?」と問う構造化プロンプトで、安価なモデル(高速ティア)を呼び出す。
  4. {score, summary, suggested_trigger, suggested_tool_sequence} を含む ReviewResult を出力する。

スコアが閾値を超えた場合、その結果はスキルマネージャーに渡されます。

skill-manager

learning/skill-manager.tslearnings テーブルを管理します。レビューが基準を満たした場合、次の形式で書き込みます。

{
  id: uuid,
  name: "hyperliquid_open_long_with_tp_sl",
  trigger: "open long on hyperliquid with tp/sl",
  tool_sequence: [...],
  guidance: "always set TP before SL; Hyperliquid's 'reduce_only' flag...",
  created_at,
  success_count: 1,
  failure_count: 0,
  last_used_at: null,
}

重複排除も行います。ほぼ同一のトリガーが既に存在する場合(learning/similarity.ts のコサイン類似度と learning/tfidf.ts の TF-IDF で判定)、新しい観察結果は重複行を作成せず、既存行のカウンターを更新します。

evaluation-loop

learning/evaluation-loop.ts は毎ターンの開始時に動作します。処理内容は以下のとおりです。

  1. ユーザーメッセージとルーターコンテキストから TF-IDF クエリを構築する。
  2. すべての学習内容をクエリに対してスコアリングする。
  3. 上位 K 件(デフォルト 3 件)を返す。
  4. プロンプトビルダーに渡し、トリガー・ツールシーケンスの要約・ガイダンステキストを含む <learnings> ブロックとしてシステムプロンプトに追加する。

LLM はその提案を採用するかどうかを自由に判断できます。どちらの選択でも学習のカウンターは更新されます。採用してターンが成功した場合は success_count が増加し、無視された学習はゆっくりと減衰します。

メソドロジー: 構造化プラン

ディープリサーチのターンでは、別のアーティファクトであるメソドロジーが生成されます。ツールシーケンスがフラットなリストであるのに対し、メソドロジーは成功基準を持つフェーズのツリー構造です。

{
  id, name,
  phases: [
    {name: "Gather", criteria: [...], tools_used: [...]},
    {name: "Synthesize", criteria: [...], depends_on: ["Gather"]},
    {name: "Verify", criteria: [...], depends_on: ["Synthesize"]},
  ],
  asset_class: "crypto_alt",
  ...
}

ストアは learning/methodology-store.ts で管理され、ディープリサーチスキルがここから読み込んで多段階のリサーチプランを初期化します。メソドロジーは、「どのツールを呼び出すか」よりも「どんな中間エビデンスを収集するか」が重要なタスク向けの、より細粒度な学習アーティファクトです。

ベクターメモリとの違い

単純なベクターメモリは事実を保存して想起します。学習システムが保存するのは手順です。「このクラスのタスクをどう達成するか」を保存し、実行可能な提案として表示します。この違いは重要です。

  • ベクターメモリ: 「BTC について何を知っているか?」に答える。
  • 学習システム: 「TP/SL 付きで Hyperliquid に BTC のロングを入れるリクエストを、いつもどう処理するか?」に答える。

この2つは補完的であり、Agent は両方を使用します。メモリルックアップはスキルレイヤーで memory_search を介して行われ、学習のルックアップは最初の LLM 呼び出しの前、プロンプト組み立ての一環としてエージェントループ内で行われます。

セーフティ特性

学習内容は提案です。命令ではありません。具体的には以下のとおりです。

  1. 学習がパーミッションティアフックを迂回することはできません。 提案された tool_sequence にティア4のツールが含まれていても、そのターンのソースで許可されていなければブロックされます。
  2. 学習が L3 リスクゲートを迂回することはできません。 提案されたシーケンスが requires_user_confirmation スキルのアクティベーションを必要とする場合、通常の確認フローが適用されます。
  3. 学習はシークレットを保存できません。 ツールシーケンスに記録される args は、監査ログと同じリダクター処理が施されます。
  4. 失敗したターンは学習になりません。 レビューエンジンがスキルマネージャーに渡す前にフィルタリングします。

学習の確認と管理

# 成功率上位の学習内容
sqlite3 $dataDir/minara.db \
  "SELECT name, success_count, failure_count
     FROM learnings
    ORDER BY success_count - failure_count DESC LIMIT 20;"

# 最近使用した学習内容
sqlite3 $dataDir/minara.db \
  "SELECT name, last_used_at FROM learnings
    WHERE last_used_at IS NOT NULL
    ORDER BY last_used_at DESC LIMIT 10;"

# 不要な学習内容を削除
sqlite3 $dataDir/minara.db "DELETE FROM learnings WHERE id = '...'"

「降格」操作はありません。学習内容が誤っている場合は削除してください。本当に有用であれば、Agent が再度導出します。

設定

関連する環境変数(環境変数を参照):

  • MINARA_LEARNING_ENABLED はマスタースイッチです(デフォルト true)。
  • MINARA_LEARNING_MIN_CALLS はレビュー対象とする1ターンあたりの最小ツール呼び出し回数です(デフォルト 3)。
  • MINARA_LEARNING_SCORE_THRESHOLD は学習内容を書き込むために必要なレビュースコアです(0〜10、デフォルト 7)。
  • MINARA_LEARNING_TOP_K はターンごとに表示する学習内容の最大件数です(デフォルト 3)。

MINARA_LEARNING_ENABLED=false に設定すると、ループが完全に無効になります。書き込み・提案・レビューパスはすべて停止します。Agent は引き続き動作しますが、時間とともに改善されなくなります。

予算管理

学習システムが行うすべての LLM 呼び出しは learning/budget-tracker.ts を経由し、カテゴリーごと・期間ごとにハード上限が適用されます。これは、2段階ジャッジパスとポストホックプローブが、バグや悪意あるプロンプトによって際限なく反省を繰り返した場合に LLM コストが10倍以上になりうるという警告を受けて追加されました。ハード予算がサーキットブレーカーとして機能します。

4つのカテゴリーがあり、それぞれ独立した日次・月次の上限が設定されています。

カテゴリー用途
learningレビューエンジン、メソドロジー抽出、ロールリフレクション、スキル学習
agentエージェントループ本体のターン
workflowワークフローおよび Autopilot のターン
experimentオフライン実験、バックテスト、A/B テスト(本番環境では使用されません)

状態は llm_usage SQLite テーブルに永続化されます。

CREATE TABLE llm_usage (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  category TEXT NOT NULL,
  task TEXT NOT NULL,
  model TEXT NOT NULL,
  input_tokens INTEGER NOT NULL,
  output_tokens INTEGER NOT NULL,
  cost_usd REAL NOT NULL,
  date TEXT NOT NULL,
  ts TEXT NOT NULL
);

LLM を呼び出すたびに、トラッカーは以下を実行します。

  1. そのカテゴリーの現在の日次・月次合計に対して、推定コストを試算する。
  2. 試算値がハード上限を超える場合、呼び出しが実行される前に BudgetExceededError をスローする。
  3. 試算値がソフト閾値(ハード上限より低い)を超える場合、警告レベルの構造化ログを出力しつつ呼び出しを許可する。
  4. 呼び出し完了後、実際の token 数とコストを llm_usage に記録する。

予算は SQLite に保存されるため、再起動しても維持されます。リセットされるインメモリカウンターは存在しません。

Agent を起動せずに支出を確認するには以下を実行します。

sqlite3 $dataDir/minara.db \
  "SELECT category, SUM(cost_usd) FROM llm_usage
    WHERE date = date('now') GROUP BY 1;"

/budget REPL コマンドでも同じ情報をインタラクティブに確認できます。

メソドロジーストア

learning/methodology-store.ts はフェーズ2の中核です。どの分析手法がどのアセットクラスで収益性の高いシグナルを生成するかを Agent が学習し、将来の類似分析で再利用できるよう取得します。

各メソドロジーは以下のフィールドで保存されます。

フィールド意味
idUUID
asset_class既知のアセットクラスのいずれか(major_crypto, layer_1, defi_blue_chip, meme_coin, stock など)
methodology手法の自由記述
evidence根拠となるエビデンステキスト
confidence[0, 1] の範囲の Wilson 下限信頼度スコア
times_used適用された回数
times_correct結果検証をパスした適用回数
quarantine異常検知なしで N 回以上の成功実績を積むまで 1 のまま
dedup_key構造化フィールドのハッシュ。O(1) のセマンティック重複排除に使用
structured_json正規化された StructuredMethodology(下記参照)

隔離とインジェクション対策

新しいメソドロジーは confidence: 0.1隔離状態から始まります。十分な成功実績を積むまでプロンプトに注入されません。書き込みのたびに scanMethodologyForInjection による異常検知がメソドロジーのテキストに対して実行され、プロンプトインジェクションパターンをストアへの保存前に検出します。

信頼度の更新

メソドロジーが適用され、結果が検証されるたびに以下の処理が行われます。

  • 成功: times_correcttimes_used を増加し、二項分布の Wilson 下限として confidence を再計算します(小サンプルにペナルティが課されます)。
  • 失敗: times_used のみ増加し、信頼度を再計算します。失敗が多いメソドロジーは信頼度が注入閾値を下回ります。
  • 昇格: confidence >= INJECTION_THRESHOLD かつ times_used >= MIN_USES を満たした時点で quarantine = 0 になります。このメソドロジーはプロンプト注入の対象となります。

Wilson 下限が単純な times_correct / times_used より優れているのは、1回の成功という幸運な結果が 15/30 の安定した勝者を上回ることを防ぐためです。

機関モード: リフレクションラダー

機関モード(Institution Mode)は、メソドロジーストアへ最も多く書き込む発生源です。各実行は複数の LLM ロール(アナリスト、強気/弱気ディベート、リスク委員会、ポートフォリオマネージャー)を招集し、それらの決定を記録します。これらの決定は遅延リフレクションループに送られ、各判断を実際の結果と照合してスコア付けし、教訓を上記のストアへ昇格させます。

決定ロールが強制構造化ツール呼び出しを使う理由

決定を生成する各ロールは、Zod スキーマ(AnalystReportSchemaTraderProposalSchemaPortfolioDecisionSchema など)に一致するツール呼び出しを発行しなければなりません。呼び出しと並ぶ自由形式の散文は破棄されます。理由は2つあり、いずれもリフレクションループに関わります。

  • 決定性。 リフレクションスコアリングは実行をまたいで同じフィールドを比較します。自由テキストへのレスキューパースはモデルアップグレードで揺らぎますが、固定スキーマは揺らぎません。
  • 比較可能性。 今日の信頼度 0.71 の Buy が先週の信頼度 0.62 の Buy と直接比較できるのは、スキーマが一定の場合だけです。

INSTITUTION_LEARNING_ENABLED=1 のとき、キャプチャフックは各実行の後に institution_runs(実行メタデータ)と institution_role_outputs(各ロールの構造化出力)を書き込みます。リフレクションラダーは各ウィンドウが期日を迎えたときに institution_reflections を後から書き込みます。

ラダー

learning/institution/reflect.ts のランナーは、各実行を固定スケジュールで再訪します。

ウィンドウトリガー問い
1d実行の 24 時間後トリガーは妥当だったか?
7d実行の 7 日後ベースケースは実現したか?
30d実行の 30 日後期間の見積もりは正しかったか?
90d / 180d / 365dより長期論旨は持続的だったか?
lazy次にその ticker が照会されたときその実行の Phase 0 振り返りとして再利用

各標準ウィンドウは実行を実現価格の動き(price-source.ts)と照合してスコア付けし、実行のロール出力で引用された各メソドロジーについて、その結果を methodologyStore.recordOutcome() に渡します。メソドロジーはその Wilson 信頼エッジ(>= 0.55 で表面化)で昇格します。これは上記の信頼度更新パスが適用するのと同じゲートであり、わずかな実行数で不安定なルールが昇格することはありません。lazy および手動のリフレクションはスナップショットであり、このループには関与しません。

構造化メソドロジーの重複排除

自由記述テキストの重複排除は困難です。「Buy BTC on RSI dip」と「Enter long when RSI oversold」は同じ意図ですが、ほぼトークンを共有しません。さらに、Jaccard 類似度では「Buy BTC at support」と「Sell BTC at support」(同一トークン、逆の行動)が統合されてしまう問題もあります。

learning/structured-methodology.ts では、ジャッジ LLM に有限の語彙から正規化されたフィールドを出力させることでこの問題を解決しています。

フィールド許容値
directionbullish / bearish / neutral
primary_signalmomentum / mean_reversion / technical / fundamental / on_chain / sentiment / macro / event
timeframeintraday / short / medium / long
indicators既知のインジケーターの配列(rsi, macd, funding_rate など)

重複排除は構造化フィールドのハッシュdirection + primary_signal + timeframe + ソート済みインジケーター + asset_class)を使用します。同じハッシュを持つ2つのメソドロジーは重複とみなされ、ストアは新しい行を挿入せず既存行のカウンターを増加します。

自由記述は人間が読む場合やプロンプト注入のために引き続き保存されます。構造化フィールドは純粋に重複排除キーとして機能します。

類似度: Jaccard(レガシー)vs TF-IDF

構造化重複排除の前は、テキスト類似度がフォールバックとして使われていました。2つの実装が存在します。

  • Jaccard 4-gramlearning/similarity.ts)は v1 のレガシーです。計算コストが低く言語非依存ですが、言い換えに弱く、セマンティックな逆転(「Buy BTC / Sell BTC」問題)に対して誤った結果を返すことがあります。
  • TF-IDF コサインlearning/tfidf.ts)が推奨される代替実装です。単語レベルでストップワードを考慮し、言語非依存のまま言い換えへの対応が改善されています。メソドロジーストアが使用するデフォルトのパスは findMostSimilarTfidf です。

ストアが Jaccard にフォールバックするのは TF-IDF が失敗した場合のみです(コーパスが空の場合や異常なトークン化など、まれなケースです)。また、構造化重複排除ハッシュがミスした場合にのみこれらが呼ばれるため、v1 に比べて呼び出し回数は大幅に少なくなっています。

新しい学習アーティファクトを実装する場合は findMostSimilarTfidf を直接使用してください。3つ目の類似度関数を独自に実装しないでください。

監査サブシステム

学習ループは行単位のフォレンジックデータ(methodology_lifecycle_eventsmethodology_casesmethodology_cron_runs)を多く書き込みますが、これらのテーブルは一度に一つの質問しか答えられません。監査サブシステム(learning/methodology-audit.ts)は集約ビューで、フォレンジック行を読み取り、6 つの次元で 0-100 の複合健全性スコアを算出し、構造化された findings と運用者向けの advisory action 付きで 1 パスにつき 1 行を methodology_audit_reports に永続化します。

サブシステムは学習状態を一切変更しません。書き込みは監査レポート行と、学習 cron 自身が書く心拍行のみです(後述の隔離不変条件を参照)。

6 つのスコアリング次元

各次元は learning/methodology-audit-scoring.ts 内の純関数です。関数は { score: number | null, findings, advisory_actions } を返します。null スコアは「正直に採点するにはサンプルが足りない」を意味し、複合スコアから外され、重みは他の次元に再配分されます。

次元読み取り対象計測内容
synthesis_qualityreflection_adjusted.reason_text の解析flag 側と recovery 側の判定間の急速な振動にペナルティを課します。一方向に flag、一方向に recovery で安定した推移は満点。低サンプル窓でも market_stress_freezesynthesis_auto_demote を表面化します。
graduation_fp_rategraduated から 30 日以内の demoted/requantized_by_judgeFP 率の Wilson 下界。卒業後の観察窓を完走しておらず、まだ反転していない卒業はカウントしません。一括の新規卒業がスコアを偽って高くすることを防ぎます。
attribution_integrity窓内の methodology_cases.outcome_state(0.7 × resolve_rate + 0.3 × (1 − backlog_share)) × 100。closed が 0 かつ 14 日超の pending バックログが 0 のとき null を返します(健全な新規インストール、まだ採点対象なし)。attribution_model の drift 検出は行いません。記録値は意図的なスナップショットだからです。
coverage_healthgraduated かつ times_used ≥ 10methodologiesCLAUDE.md §13 の資産クラス標準に従い、5 つのトップレベルグループ(crypto / stock / index / commodity / forex)のカバレッジを評価。5 グループ全てが活発な方法論を 3 つ以上保有すると満点、3 グループ最低ラインを下回ると線形に減点。
quarantine_churnmethodology_lifecycle_events の状態変更系 kindreflection_adjusted を除外します(6 時間 synthesis 周期では 1 日 4 回まで合理的に発火するため)。窓内で同一の方法論に対し 3 回以上の状態変更があると高 churn とみなします。
cron_healthmethodology_cron_runs 心拍 + pending バックログ期待間隔の 2 倍に対するラグ + バックログペナルティ。ラグ 7 日超でスコアは 0(loop が死んでいるとみなす)。心拍テーブルが空かつ pending バックログが 0 でないときも 0(loop が処理を進めていないことが明らか)。

複合スコアとバンド

デフォルトの重みとバンド:

composite = 0.22·synthesis_quality + 0.22·graduation_fp_rate + 0.22·attribution_integrity
          + 0.14·coverage_health   + 0.08·quarantine_churn   + 0.12·cron_health

バンド:≥ 80 healthy · 60-79 watch · 40-59 degraded · < 40 alarm · disabled(off switch)

null 次元はドロップされ、残りの重みは合計 1 に再正規化されます。永続化されたレポートには dimension_weights_used が記録されるため、運用者が JSON を読むと正確にどの次元が寄与したかが分かります。

隔離不変条件

監査は 4 つの学習テーブル(methodologiesmethodology_lifecycle_eventsmethodology_casesmethodology_case_hints)を読み、いずれにも書き込みを行いません。3 層の保証が積み重なります:

  1. 協調的アイドルスケジューリング。監査 cron(learning/methodology-audit-cron.ts)は AgentLoop.run()BusyTrackercore/busy-tracker.ts)を共有します。各 tick で inFlight > 0(スキップ)と idle 時間(不足なら延期)をチェックし、オーケストレーターは SQL ステージ間で yieldIfBusy を呼んで譲歩し、ユーザーターンがパス中に到着すると一時停止します。連続 N 回延期後はスターベーションガードが強制実行し、常に忙しいエージェントが監査カバレッジを失わないようにします。
  2. 純関数のスコアリング境界methodology-audit-scoring.ts の次元スコアラーは Methodology / MethodologyLifecycleEvent / MethodologyCase 形の純粋な配列のみを受け取ります。MemoryStore ハンドルを一切目にしないため、誤って .prepare(...).run(...) を呼ぶことすら構造的に不可能です。
  3. エンドツーエンドのテーブルハッシュ不変条件tests/e2e/methodology-audit.test.ts は監査パスの前後で各学習テーブルを SHA-256 でハッシュし、バイトレベルの等価性をアサートします。チェックは行数パリティを超えます。updated_at を触る UPDATE は行数チェックなら通りますが、ハッシュチェックは通りません。

唯一の逆方向接触点は、学習 cron tick の末尾で書かれる methodology_cron_runs 心拍行です。in-process スケジューラ(learning/methodology-cron.ts)も CLI cron パス(gateway/learning-cli.tsrunFullCronCli)も両方この行を書くため、ドキュメント化された system-cron デプロイで監査の cron_health 次元が正常に機能します。

監査の運用

cron はオプトインです。デフォルトは日次の受動監視向けに調整されています。学習ループがスコアを付けられるだけのデータを蓄積したら(通常は 1-2 週間後)、METHODOLOGY_AUDIT_CRON_ENABLED=1 を反転させます。完全な env リファレンスは環境変数 → 方法論監査サブシステムを参照してください。

4 つの CLI コマンドが運用者ワークフローをカバーします:

minara learning audit run [--window-days N]              # 1 回のインラインパス
minara learning audit show [--latest|--pass <id>]        # レポートの確認
minara learning audit trend [--days N]                   # 複合スコア履歴 + sparkline
minara learning audit findings [--severity high|medium|low]  # findings の掘り下げ

完全な CLI 仕様は CLI サブコマンド → audit を参照してください。

保留事項:能動プローブ

初期設計では、ランダムに過去の「確実な誤り」trading case でエージェントを再実行し、学習ループが今では異なる決定を生み出すかをテストする第 7 次元を提案していました。この作業は保留されています。誠実な再生には、過去の決定コンテキスト(価格、ニュース、sentiment、当時アクティブな方法論、ツール出力)の凍結されたスナップショットが必要です。そうしないと、新しい実行は原決定と同じ情報を見られません。スナップショットなしでエージェントに「今 ETH を買うべきか」と聞くと、現在の判断を測ることになり、学習が過去の誤りを修正したかを測ることにはなりません。2 つの前提条件がこの作業をブロックします:(a) hint / case 時点で case-recorder が書き込むスナップショットテーブル、(b) createApp() を経由しない独立した ProbeAgentLoop。これによりプレイバックはライブエージェントとゼロの状態共有(skill session、tool registry、hooks)になります。

目次