學習系統
Agent 如何在重複任務中持續改進
Minara Agent 內置了一個學習循環,可記錄成功的工具調用序列,並在後續輪次中以建議形式呈現。與模型微調不同,整個機制均基於 SQLite 行操作,無需訓練任務、模型更新或離線流水線。本頁說明各組成部分及其與技能系統的協作方式。
"學習"的含義。 在 Minara 中,"學習"不涉及微調或權重更新,模型本身保持不變。每輪開始前,Agent 會從 SQLite 中檢索內容:一組已驗證的
{tool_name, args}序列、自由文本指導說明,以及結構化方法論。當前輪次與歷史成功輪次相似時,歷史序列會作為建議提供。設計上以可審計性換取複雜度:所有"已學習"的行為均以數據庫行的形式存儲,可讀取、編輯或刪除,運營者可完整檢查。
實際效果請參閱:功能 → 自我提升介紹了面向用戶的界面,包括如何引導 Agent 保存一條經驗,以及這些經驗在後續會話中的呈現方式。
關於並行的決策反思循環(對特定技能調用是否正確進行兩階段 LLM 分類,按角色隔離),請參閱 角色記憶。該系統與本系統並行運行,回答的是另一個問題:不是"我如何成功",而是"這個具體決策是否正確,原因是什麼"。
學到什麼
三類產物存儲於 learnings 表及 apps/agent/src/learning/ 下的關聯表中:
- 工具序列。 Agent 成功完成任務時所執行的
{tool_name, args}有序列表,在 Agent 顯式調用skill_learn時於輪次末尾記錄。 - 指導說明。 簡短的自由文本片段,例如"獲取 Polymarket 價格時,請對具體市場 URL 使用
web_extract,API 限速為每分鐘 10 次"。與工具序列一同存儲。 - 方法論。 帶有成功標準的結構化多步計劃,由
learning/structured-methodology.ts存儲,適用於純工具序列表達力不足的深度研究工作流。
反饋循環
review-engine
learning/review-engine.ts 是一個輕量級 LLM 處理過程,在每輪結束時運行(通過安裝在 app.ts 中的 review-engine-hook.ts)。其步驟如下:
- 檢查本輪工具調用序列。
- 過濾掉調用次數少於 N 次或明顯失敗的輪次。
- 以快速檔模型調用結構化提示詞,詢問"任務是否完成?新穎性如何?可複用性如何?"
- 輸出包含
{score, summary, suggested_trigger, suggested_tool_sequence}的ReviewResult。
若評分超過閾值,結果將傳遞給技能管理器。
skill-manager
learning/skill-manager.ts 負責管理 learnings 表。收到合格評審結果後,寫入以下數據:
{
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 在每輪開始時運行,步驟如下:
- 基於用戶消息和路由上下文構建 TF-IDF 查詢。
- 對所有學習條目評分。
- 返回前 K 個匹配項(默認 3 個)。
- 傳給提示詞構建器,作為
<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 的哪些信息?"
- 學習系統回答"我通常如何處理在 Hyperliquid 帶 TP/SL 做多 BTC 的請求?"
兩者互補,Agent 同時使用。記憶查詢在技能層通過 memory_search 發起;學習查詢在 Agent 循環中於首次 LLM 調用之前發起,作為提示詞組裝的一部分。
安全屬性
學習條目是建議,絕非強制指令。具體而言:
- 學習條目無法繞過權限等級鉤子。 若建議的
tool_sequence包含四級工具,在輪次來源不允許的情況下仍會被阻止。 - 學習條目無法繞過 L3 風險門控。 若建議的序列需要激活帶
requires_user_confirmation的技能,正常確認流程照常執行。 - 學習條目不能存儲密鑰。 工具序列中記錄的
args經過與審計日誌相同的脫敏處理。 - 失敗的輪次不會成為學習條目。 評審引擎在技能管理器接觸之前已將其過濾。
檢查與管理
# 按成功率排序的顶级学习条目
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 會重新推導出來。
配置
相關環境變量(參見 env-vars):
MINARA_LEARNING_ENABLED為總開關(默認true)。MINARA_LEARNING_MIN_CALLS為觸發評審所需的最低工具調用次數(默認3)。MINARA_LEARNING_SCORE_THRESHOLD為寫入學習條目所需的評審評分(0–10,默認7)。MINARA_LEARNING_TOP_K為每輪提供的學習建議數量(默認3)。
將 MINARA_LEARNING_ENABLED=false 可完全禁用該循環:不寫入、不建議、不評審。Agent 仍正常運行,只是不會隨時間加速。
預算追蹤
學習系統發起的每次 LLM 調用均通過 learning/budget-tracker.ts 執行,該模塊按類別和時間窗口強制設置硬性上限。此設計源於一項評審警告:兩階段評判加上事後探測,若出現 bug 或對抗性提示詞,可能導致 LLM 費用暴增 10 倍。硬性預算是熔斷器。
四個類別,各自擁有獨立的每日和每月上限:
| 類別 | 用途 |
|---|---|
learning | 評審引擎、方法論提取、角色反思、技能學習 |
agent | 主 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 調用時,追蹤器會:
- 將預估費用與該類別當前的每日和每月累計值相加。
- 若預估總量超過硬性上限,在調用發出前拋出
BudgetExceededError。 - 若預估總量超過軟閾值(低於硬性上限),記錄 warn 級別的結構化日誌,但允許調用繼續。
- 調用完成後,將實際 token 數量和費用寫回
llm_usage。
預算在重啟後保持有效,因為狀態存儲於 SQLite,不依賴內存計數器。
不啟動 Agent 也可檢查消費情況:
sqlite3 $dataDir/minara.db \
"SELECT category, SUM(cost_usd) FROM llm_usage
WHERE date = date('now') GROUP BY 1;"REPL 的 /budget 命令提供相同的交互式視圖。
方法論存儲
learning/methodology-store.ts 是第二階段的核心:Agent 學習哪類分析方法能為哪類資產產生有價值的信號,並在未來類似分析中調取。
每條方法論存儲以下字段:
| 字段 | 含義 |
|---|---|
id | UUID |
asset_class | 已知資產類別之一(major_crypto、layer_1、defi_blue_chip、meme_coin、stock 等) |
methodology | 方法的自由文本描述 |
evidence | 支撐證據文本 |
confidence | Wilson 下界置信度分數,範圍 [0, 1] |
times_used | 成功應用次數 |
times_correct | 通過結果驗證的應用次數 |
quarantine | 值為 1 直至該方法通過足夠多次成功使用且未觸發異常檢測為止 |
dedup_key | 結構化字段的哈希值,用於 O(1) 語義去重 |
structured_json | 歸一化的 StructuredMethodology(見下文) |
隔離與注入防禦
新方法論初始處於 隔離 狀態,confidence: 0.1,在通過足夠多次成功使用前不會注入提示詞。每次寫入時,異常檢測會通過 scanMethodologyForInjection 掃描方法論文本,在提示詞注入模式落庫前將其攔截。
置信度提升
每次應用某方法論並驗證結果後:
- 成功:遞增
times_correct和times_used,以二項分佈的 Wilson 下界重新計算confidence(對小樣本有懲罰)。 - 失敗:僅遞增
times_used,重新計算置信度。失敗頻繁的方法論,置信度會降至注入閾值以下。 - 畢業:
confidence >= INJECTION_THRESHOLD且times_used >= MIN_USES時,將quarantine置為0,該方法論即可用於提示詞注入。
Wilson 下界優於直接計算 times_correct / times_used,因為它不會讓 1 次成功的幸運結果蓋過 30 次中成功 15 次的穩定表現。
機構模式:反思階梯
機構模式是寫入方法論存儲最頻繁的來源。每次運行都會召集多個 LLM 角色(分析師、多空辯論、風險委員會、投資組合經理)並記錄它們的決策。這些決策進入一個延遲的反思循環,將每次判斷與實際結果對照評分,並把經驗晉級回上文所述的存儲。
為何決策角色採用強制結構化工具調用
每個產出決策的角色發出的工具調用都必須匹配一個 Zod schema(AnalystReportSchema、TraderProposalSchema、PortfolioDecisionSchema 等)。與調用並存的自由文本會被丟棄。兩點原因,都與反思循環有關:
- 確定性。 反思評分需要跨運行比較相同字段。對自由文本的補救式解析會隨模型升級而漂移;固定 schema 則不會。
- 可比性。 今天置信度 0.71 的
Buy,只有在 schema 恆定時,才能與上週置信度 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"表達同一思路,卻幾乎沒有共同 token。更糟的是,Jaccard 相似度可能將"Buy BTC at support"與"Sell BTC at support"合併(相同 token,相反操作)。
learning/structured-methodology.ts 的解決方案是要求評判 LLM 輸出有限詞表的歸一化字段:
| 字段 | 允許值 |
|---|---|
direction | bullish / bearish / neutral |
primary_signal | momentum / mean_reversion / technical / fundamental / on_chain / sentiment / macro / event |
timeframe | intraday / short / medium / long |
indicators | 已知指標數組(rsi、macd、funding_rate 等) |
去重使用結構化字段的哈希值(direction + primary_signal + timeframe + 排序后的 indicators + asset_class)。哈希相同的兩條方法論視為重複,存儲層遞增現有行的計數器而非插入新行。
自由文本描述仍會保留,供人工閱讀和提示詞注入使用;結構化字段僅作為去重鍵。
相似度:Jaccard(舊版)與 TF-IDF
引入結構化去重之前,回退方案是文本相似度。目前存在兩種實現:
- Jaccard 4-gram(
learning/similarity.ts)是 v1 舊版實現,計算成本低、與語言無關,但在改寫時易出錯,且對語義取反("Buy BTC / Sell BTC"陷阱)的判斷有誤。 - TF-IDF 餘弦相似度(
learning/tfidf.ts)是推薦的替代方案,基於詞級別、具備停用詞感知能力,同樣與語言無關,處理改寫時表現更好。findMostSimilarTfidf是方法論存儲採用的默認路徑。
僅當 TF-IDF 失敗時(極少發生,如語料庫為空或分詞異常),存儲層才會回退到 Jaccard。兩者均只在結構化去重哈希未命中時才被調用,因此調用頻率遠低於 v1 時期。
編寫新的學習產物時,請直接使用 findMostSimilarTfidf,不要另行實現第三種相似度函數。
審計子系統
學習閉環會寫很多逐行 forensic 數據(methodology_lifecycle_events、methodology_cases、methodology_cron_runs),但這些表只能一次回答一個問題。審計子系統(learning/methodology-audit.ts)是聚合視圖,讀取這些 forensic 行,在六個維度上計算 0-100 複合健康分,每次 pass 落一行到 methodology_audit_reports,附結構化 findings 和運維側 advisory action。
子系統永不變更學習狀態。它的唯一寫盤點是審計報告行,以及學習 cron 自己寫的心跳行(見下文隔離不變式)。
六個評分維度
每個維度都是 learning/methodology-audit-scoring.ts 裡的純函數。函數返回 { score: number | null, findings, advisory_actions }。null 分數表示"樣本不足以誠實評分",會從複合分裡 drop 掉並把權重重分配給其他維度。
| 維度 | 讀什麼 | 測什麼 |
|---|---|---|
synthesis_quality | reflection_adjusted.reason_text parse | 懲罰 flag-side 與 recovery-side 判決之間的反覆振盪,單向 flag 或單向 recovery 的穩定走勢滿分。低樣本窗口下也會浮現 market_stress_freeze 和 synthesis_auto_demote 事件。 |
graduation_fp_rate | graduated 後續 30 天內的 demoted/requantized_by_judge | 在 FP 率上取 Wilson 下界。畢業後還沒走完觀察窗口又未反轉的不計入分子分母,所以一批新畢業不會把分數拉高。 |
attribution_integrity | 窗口內 methodology_cases.outcome_state | (0.7 × 解析率 + 0.3 × (1 − 积压占比)) × 100。無 closed case 且無 14 天以上 pending 積壓時返回 null(健康的全新安裝,沒東西可評)。不做 attribution_model drift 檢測,因為記錄值是有意保留的快照。 |
coverage_health | methodologies 中 graduated 且 times_used ≥ 10 | 按 CLAUDE.md §13 資產類標準對五大頂層組(crypto / stock / index / commodity / forex)做覆蓋度評估。五組各持有 ≥ 3 條活躍方法論得滿分,低於三組閾值後線性扣分。 |
quarantine_churn | methodology_lifecycle_events 的狀態變更類 kind | 排除 reflection_adjusted(在 6 小時 synthesis 節奏下每天可合理觸發 4 次)。高 churn = 同一條方法論在窗口內 ≥ 3 次狀態變更。 |
cron_health | methodology_cron_runs 心跳 + pending 積壓 | 滯後時間相對 2× 預期間隔加積壓懲罰。滯後 > 7 天分數歸零(loop 看起來已死)。心跳錶空 + pending 積壓非零也歸零(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 維度會被 drop,剩餘權重重新歸一化到和為 1。落庫的報告記錄 dimension_weights_used 字段,運維讀 JSON 時能看到具體哪些維度參與了打分。
隔離不變式
審計讀四張學習表(methodologies、methodology_lifecycle_events、methodology_cases、methodology_case_hints),對它們零寫入。三層保障疊加:
- 合作式空閒調度。審計 cron(
learning/methodology-audit-cron.ts)和AgentLoop.run()共享一個BusyTracker(core/busy-tracker.ts)。每個 tick 啟動前檢查inFlight > 0(跳過)和 idle 時長(不足則延期)。Orchestrator 在每個 SQL 階段之間用yieldIfBusy讓步,turn 進來時立即暫停。連續 N 次延期後飢餓守衛強制執行,避免常忙的 agent 長期不被審計。 - 純函數評分邊界。
methodology-audit-scoring.ts裡的維度評分函數只接受Methodology/MethodologyLifecycleEvent/MethodologyCase類型的純數組,結構上看不到MemoryStorehandle,無法誤調到.prepare(...).run(...)。 - E2E 表哈希不變式。
tests/e2e/methodology-audit.test.ts在每次審計 pass 前後對所有學習表做 SHA-256 哈希,要求字節級一致。這比行數比對更嚴,一個僅改updated_at的 UPDATE 行數對得上但哈希過不去。
審計對學習的唯一反向接觸點是 methodology_cron_runs 心跳行,在每次學習 cron tick 末尾寫入。in-process 調度器(learning/methodology-cron.ts)和 CLI cron 路徑(gateway/learning-cli.ts 的 runFullCronCli)都要寫這一行,保證文檔化的 system-cron 部署下審計 cron_health 維度也能正常工作。
運維這個審計子系統
cron 是 opt-in。默認參數面向日級被動監控;當學習閉環跑了一兩週積累足夠數據後,把 METHODOLOGY_AUDIT_CRON_ENABLED=1 翻開。完整 env 參考見環境變量 → 方法論審計子系統。
四個 CLI 命令覆蓋典型運維流程:
minara learning audit run [--window-days N] # 内联跑一次审计
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。
延期項:主動重評
早期方案曾設想第七個維度,隨機讓 agent 在歷史"確定性錯"的 trading case 上重新決策,看學習閉環現在會不會做出不同選擇。這塊工作被推遲。要做誠實的回放需要先凍結歷史決策上下文(價格、新聞、sentiment、當時活躍的方法論、工具輸出),讓重新決策看到的信息和原決策一致。否則問 agent "現在 ETH 該買嗎"測的是當前判斷,不是學習是否糾正了過去的錯誤。兩條前置依賴:(a) 在 case-recorder 寫 hint / case 時附帶的快照表,(b) 一個獨立的 ProbeAgentLoop,不走 createApp(),所以重放和線上 agent 零共享狀態(skill session、tool registry、hooks)。