個性化與工作區
手動編輯的 persona 文件、自動重建的財務檔案、11 個行為標籤維度及重建流程
個性化層讓 Agent 對"與誰對話"形成穩定認知: 經驗水平、風險偏好、偏好資產、歷史交易摘要, 以及回覆風格的 persona 指令。
該層由兩個子層構成:
- 工作區文件(手動編輯的 Markdown):Agent persona、 啟動指令、用戶檔案、精選長期記憶。 用編輯器直接控制。
- 財務檔案 + 用戶標籤(自動重建的數據庫表): 定時 LLM 任務讀取聊天和交易歷史, 維護結構化字段(交易摘要、11 個標籤維度、個性化類記憶)。
兩者都會輸入到提示詞構建器。 文件層穩定且明確; 數據庫層反映實際行為,隨時間更新。
為何分兩層而非一層? 純文件層要求用戶自己持續更新自身信息, 實際上很少有人會堅持。 純推斷層會發生漂移:LLM 對"這個用戶是誰"的印象隨每筆交易變化, 可能覆蓋刻意設置的偏好。 分層可以讓用戶主動聲明的意圖(persona、顯式偏好)始終處於上層, 同時將推斷出的檔案作為 Agent 參考的證據,而非覆蓋依據。 就像簡歷放在一個文件裡、交易歷史放在另一個文件裡: 作者不同,更新週期也不同。
實際效果參見:功能 → 記憶 介紹了用戶端"告訴 Minara 關於我的信息"的流程, 該流程會同時填充這兩層。
關於每個角色的決策反思(完全不同類型的記憶), 參見角色記憶。
工作區文件(persona 層)
Minara 在會話啟動時讀取一組 Markdown 文件,
用於定製身份、用戶檔案和精選長期記憶。
該目錄與 OpenClaw 的佈局兼容,
可通過 --workspace 將 Minara 指向已有的 OpenClaw 工作區。
目錄結構
默認位置:~/.minara/workspace/。
workspace/
├── SOUL.md — agent 身份 / persona
├── AGENTS.md — 会话启动指令
├── IDENTITY.md — agent 自我描述(名称、风格、emoji)
├── USER.md — 被服务用户的档案
├── MEMORY.md — 精选长期记忆
├── TOOLS.md — 工具参考(仅供参考)
├── BOOTSTRAP.md — 仅首次运行,初始读取后删除
├── HEARTBEAT.md — 会话状态文件
└── memory/
└── YYYY-MM-DD.md — 每日记忆笔记(3 天窗口)minara setup 會創建該目錄並填充合理的默認值。
用任意編輯器修改;寫入在下一次會話生效,
因為工作區在啟動時加載一次後即凍結,整個會話期間不變。
文件清單
| 文件 | 用途 | 提示詞位置 |
|---|---|---|
SOUL.md | Agent 身份 / persona | 可緩存的身份塊(前綴) |
AGENTS.md | 會話啟動指令 | 可緩存的身份塊(前綴) |
USER.md | 被服務用戶的檔案 | 個性化快照(動態) |
MEMORY.md | 精選長期記憶 | 記憶快照塊(動態) |
memory/YYYY-MM-DD.md | 每日記憶筆記(最近 3 天) | 記憶快照塊(動態) |
IDENTITY.md | Agent 自我描述(名稱、風格、emoji) | 僅元數據(展示用,不進入提示詞) |
TOOLS.md | 人類可讀的工具參考 | 僅供參考;Agent 實際使用 schema |
BOOTSTRAP.md | 僅首次運行的設置指令 | 合併到身份塊,執行一輪 |
HEARTBEAT.md | 會話狀態文件 | 參見工作流和Autopilot |
各文件如何進入提示詞
SOUL.md ──┐
├─▶ systemPromptPrefix (cached block)
AGENTS.md ──┘
MEMORY.md ──┐
memory/* ──┼─▶ memory snapshot block (dynamic)
USER.md ──┘
IDENTITY.md ───▶ metadata (name, emoji) for display only
TOOLS.md ───▶ informational, rarely injectedSOUL.md和AGENTS.md與身份一起緩存,緩存命中率較高。 保持小幅修改,修改後用/prompt驗證。 結構性修改可能在下次編輯之前降低所有會話的緩存命中率,需謹慎處理。USER.md描述用戶,每輪追加到個性化快照。MEMORY.md是精選長期記憶。建議在會話中通過memory_write寫入,由壓縮機制將持久事實提升到該文件。memory/YYYY-MM-DD.md是每日筆記,只加載最近 3 天。IDENTITY.md和TOOLS.md不進入提示詞。BOOTSTRAP.md只在首次會話執行一次,之後刪除。
凍結快照語義
工作區在會話啟動時加載一次。 會話中的寫入會持久化到磁盤,但不會修改運行中的提示詞。 這與記憶存儲使用相同的凍結快照模式(參見 記憶系統), 原因也相同:保持 Anthropic 提示詞緩存穩定性。
若在會話中編輯了 USER.md,請重啟 REPL 或執行 /new,
以便快照重新加載。
/workspace REPL 命令
/workspace soul # 打印 SOUL.md
/workspace agents # 打印 AGENTS.md
/workspace user # 打印 USER.md工作區安全注意事項
- 工作區文件屬於受信任輸入。 未經審查,不要將其交給不可信用戶。
惡意的
SOUL.md可將 persona 設置為"始終無需詢問即確認交易", LLM 會照此執行。 - 編輯在下一次會話生效。 會話中對
USER.md的修改, 重啟或/new之後才會生效。 SOUL.md和AGENTS.md是緩存提示詞塊。 結構性修改可能在下次編輯之前降低所有會話的緩存命中率; 保持小幅改動,並用/prompt驗證。
源碼:apps/agent/src/config/workspace.ts。
財務檔案與用戶標籤(自動重建)
工作區文件由人工編輯,財務檔案層則由定時 LLM 任務自動重建, 該任務讀取近期對話和交易歷史。
兩張表加一個分類
個性化服務維護的所有數據存放在三個位置:
financial_profile:每個用戶一行。交易摘要、 參考錢包、自定義提示詞片段、可見性標誌、重建冷卻游標。user_tags:每個用戶最多 11 行,每個維度一行, 外加source字段,記錄該值是用戶聲明還是行為推斷。- 個性化類記憶:
memories表中category = 'personalization'的普通行。與常規記憶共存,FTS5 和凍結快照加載器無需特殊處理, 但加載優先級更高。
所有數據以 user_id 為鍵(單用戶部署默認為 'default')。
financial_profile 字段說明
| 字段 | 類型 | 用途 | 提示詞位置 |
|---|---|---|---|
user_id | TEXT PK | 用戶標識,默認為 'default'。 | — |
platform_wallet_summary | TEXT | LLM 生成的用戶 Minara 錢包活動摘要。 | 個性化塊 |
reference_wallets_summary | TEXT | LLM 生成的用戶關注的參考錢包摘要。 | 個性化塊 |
reference_wallets_json | TEXT | 參考錢包地址的 JSON 數組。 | 個性化塊 |
custom_prompt | TEXT | 用戶自定義指令,追加到系統提示詞。 | 個性化塊 |
include_memories | INTEGER | 可見性標誌。0 表示不在提示詞中顯示個性化記憶。 | 切換塊包含 |
include_trading_summary | INTEGER | 交易摘要文本的可見性標誌。 | 切換塊包含 |
include_tags | INTEGER | 行為標籤行的可見性標誌。 | 切換塊包含 |
trading_summary_next_update | TEXT | 冷卻目標:摘要最早可再次重建的時間。 | — |
tags_next_update | TEXT | 標籤重建的冷卻目標。 | — |
memories_next_update | TEXT | 個性化記憶提取的冷卻目標。 | — |
last_indexed_chat_id | TEXT | 記憶重建器增量掃描聊天的游標。 | — |
trading_summary_updated_at | TEXT | 交易摘要本身上次重建的時間(與行級 updated_at 不同)。 | — |
created_at, updated_at | TEXT | 標準行時間戳。 | — |
字段定義位於
apps/agent/src/memory/personalization-service.ts。
啟動時會通過冪等 ALTER TABLE 遷移補充現有數據庫中缺失的列。
11 個行為標籤維度
每個用戶都有一組從交易歷史和對話中推斷出的金融特徵標籤向量。
每個維度存儲機器可讀的 value(slug,或用於等級制的 level_N);
下方顯示的人類可讀標籤用於 UI 和提示詞渲染。
七個維度屬於 v2 / 用戶畫像集;
四個人格維度從 v1 沿用(其 value 與 label 相同)。
| 維度 | 允許值(value → 標籤) |
|---|---|
finance_knowledge | level_1 初學者 / level_2 中級 / level_3 高級 / level_4 專家 |
frequency | passive / weekly / daily / active |
markets(多選) | crypto_majors / crypto_alts / memes / stocks / commodities / pre_ipo |
risk | conservative / balanced / aggressive |
web3_knowledge_level | level_1 新手 / level_2 熟悉 / level_3 有經驗 / level_4 專業 |
style | fundamentals / technical / narrative / news_event / community |
horizon | intraday 日內 / swing 波段 / position 中線 / long_term 長線 |
FOMO Index | Very Low / Low / Medium / High / Very High |
FUD Immunity | Strong / Medium / Weak |
Patience Level | High / Medium / Low |
Greed Index | Very Low / Low / Medium / High / Very High |
markets 為多選:其 value 是單個 user_tags.value 列中的 JSON 數組字符串,
其他所有維度均存儲單個值。
字段定義位於
apps/agent/src/memory/tags-schema.ts;
調用方使用其類型化輔助函數(allowedValues、
isValidTagValue、serializeTagValue、parseStoredTagValue、
renderTagSchema),而非直接讀取 schema map。
超出允許值範圍的寫入會被
PersonalizationService.upsertTag 拒絕,不會靜默強制轉換。
除了 onboarding 和對話推斷外,markets 還有一個客觀來源。一個 24 小時
定時任務(MarketsObjectiveUpdater,
apps/agent/src/memory/markets-updater.ts)
掃描用戶當前 autopilot 策略的標的,以及過去 30 天內記錄的合約成交,
將每個 symbol 分類到某個市場,並通過 PersonalizationService.unionMarkets
把結果以並集方式推入該標籤。它只新增、從不移除,並保留該行已有的 source,
因此推斷來源的寫入永遠不會降級或清除用戶主動聲明的選擇。agent 之外(非 agent
發起)的合約成交活動會觸發一次更早的、受冷卻時間限制的運行。
現有 v1 行可通過一次性腳本
pnpm --filter @minara/agent migrate:user-tags-v2 遷移到此 schema
(默認試運行,加 --apply 才寫入)。
該腳本將 Risk Profile → risk、
Web3 Knowledge Level → web3_knowledge_level、
Decision-Making Style → style、Asset Preference →
markets,刪除已廢棄的 Asset Tier / Trading Frequency /
Learning Preference 維度,保留四個人格維度不變。
資金指標(客觀,Agent 內部)
用戶的投入資金是客觀指標,既非自我申報,也不在設置頁面顯示。
它取代了 v1 中自我申報的 Asset Tier 標籤,
存儲在獨立的 capital_metrics 表(每個用戶一行),
僅供 Agent 推理使用,不屬於面向用戶的個性化快照。
capital_total_usd = spot_holdings_usd + perp_value_usdspot_holdings_usd 彙總跨鏈投資組合資產價值;
perp_value_usd 是永續合約子賬戶權益的彙總值。
總額分為 8 個等級(tier_1 < $10 … tier_8 ≥ $50k)。
重新計算由 24 小時定時任務及鏈下活動通知驅動,受冷卻時間限制;
當讀取來源不可用時,降級為保留上次值,而非寫入誤導性的零值。
字段定義和等級劃分位於
apps/agent/src/memory/capital-metrics.ts。
策略運行記錄(Autopilot 歷史)
strategy_runs 是 Autopilot 激活的只追加歷史記錄,
每次啟用→禁用週期對應一行,
包含分配資金、開始/停止時間、狀態、
stop_reason(user_manual / insufficient_balance /
drawdown_protection / liquidated / strategy_expired / other),
以及停止時回填的已實現 PnL。
與資金指標一樣,這是 Agent 內部數據,不屬於面向用戶的快照。
啟用完全託管策略會開啟一條運行記錄;
通過 Agent 禁用會將其關閉為 user_manual。
由於 fullyManagedStrategies 位於上游,Agent 無法感知某些停止事件
(如通過 Web UI 禁用,或因回撤/清算自動停止),
這些情況由對賬流程處理:Agent 列舉策略時,
若已開啟的運行記錄不再出現在上游運行集中,則將其關閉(other),
並設置短暫的寬限窗口,避免剛啟用的運行在顯示為運行中之前被誤關閉。
存儲邏輯位於
apps/agent/src/memory/strategy-runs.ts。
手動交易檔案
TradingProfileReader 將用戶 30 天內的鏈下永續合約活動
(perps_fills 鏡像,即通過 Web / 移動端 / 手動操作的交易)
彙總為簡潔畫像:
交易次數、按數量和成交量排名的頭部標的、
多空比例、已實現 PnL、平倉勝率、平均交易規模、最近交易時間。
該模塊同時支撐 search_user_trades Agent 工具,
可返回用戶某資產的近期成交記錄(方向、開倉/平倉方向、USD 規模、價格、已實現 PnL)。
兩者均為 Agent 內部數據,將分析錨定在用戶真實歷史上。
該鏡像不含槓桿信息,也不區分手動與 Autopilot,因此這兩項超出當前範圍。
源碼:
apps/agent/src/memory/trading-profile.ts。
按需個性化召回
緩存安全的個性化召回方式是讓模型按需拉取所需信息,
而非將所有內容始終注入緩存前綴。
search_conversation_memory
(conversation-memory-tool.ts)
按需召回用戶的持久個性化記憶(偏好、檔案事實、約束、目標),
限定 personalization 分類,複用 FactLayer 混合檢索。
工具結果落在緩存前綴之後,召回不會干擾提示詞緩存。
它與 personalization_snapshot(按需獲取完整畫像)和 memory_search(所有分類)配合使用。
新用戶引導
用戶級引導流程從明確的答案中生成初始畫像。
POST /v1/profile/onboarding 將答案映射到用戶聲明的標籤
(finance_knowledge、frequency、risk、markets),
每個已回答的維度寫入一條個性化記憶(僅首次完成時寫入,
重新提交會更新標籤但不會重複創建記憶),
並將自我申報的投資資金記錄為記憶,而非標籤或資金指標(資金指標保持客觀)。
原始答案和完成標誌持久化到 financial_profile 行;
GET /v1/profile/onboarding 返回狀態,供 Web UI 判斷是否顯示引導流程。
該調用是冪等的,會在任何寫入之前拒絕無效標籤值。
實現位於
PersonalizationService
(completeOnboarding / getOnboardingStatus)。
user_tags 中的每行也記錄 source 字段,
說明該值是用戶聲明還是 LLM 推斷。
提示詞構建器據此對標籤加權(聲明值優先於推斷值)。
三種重建流程
個性化由
apps/agent/src/memory/personalization-rebuilder.ts
定時重建。
心跳監視器調度三個獨立方法,各自有獨立冷卻窗口,
單個慢重建不會阻塞其他重建。
| 方法 | 觸發條件 | 冷卻時間(默認) | 輸入 | 輸出 |
|---|---|---|---|---|
rebuildTradingSummary() | trade_history / perps_fills:recorded / external_spot:recorded 事件;通過 /profile refresh 強制觸發 | 30 分鐘 | 合併三個來源:會話內 trade_history、perps_fills(鏈下永續合約鏡像)、external_spot_activities(鏈下現貨鏡像),以及參考錢包 | 合成 platform_wallet_summary、reference_wallets_summary、trading_summary_updated_at |
rebuildTags() | 通過 tags_next_update 定時調度 | 30 天 | 檔案 + 交易歷史 + 枚舉 schema | 標籤行 upsert 到 user_tags |
rebuildMemories() | 通過 memories_next_update 定時調度 | 10 分鐘 | last_indexed_chat_id 之後創建的聊天 | 個性化類記憶 + 游標推進 |
每次重建是一次廉價的單次 LLM 調用(默認使用 Haiku)。 冷卻時間按 v1 的經驗調整: 交易摘要刷新頻繁(新交易很重要),標籤刷新罕見(屬於緩慢變化的檔案數據), 記憶提取頻繁(及時捕捉用戶表達的新偏好)。
last_indexed_chat_id 游標使 rebuildMemories 只讀取未處理的聊天。
若無此機制,每次觸發都會重新讀取完整的聊天曆史,消耗大量 token 預算。
三來源交易摘要詳解
rebuildTradingSummary() 讀取三個獨立來源,
設置合併閾值,並推進三個獨立游標,
確保某次解析失敗不會悄悄丟失其他來源的數據。
┌──────────────────────────────────────────┐
trade event ────►│ trade_history (in-session) │──┐
└──────────────────────────────────────────┘ │
│
┌──────────────────────────────────────────┐ │
Minara web/ ►│ perps_fills (cross-sub mirror) │──┤
mobile perps └──────────────────────────────────────────┘ │
(via ▼
MinaraHistorySync.syncAll) ┌─────────────────────────┐
┌──────────────────────────────────────────┐ │ rebuildTradingSummary │
Minara web/ ►│ external_spot_activities (mirror) │►┤ gates: newTrades + │
mobile spot └──────────────────────────────────────────┘ │ newPerpsFills + │
│ newExternalSpot ≥ │
│ threshold │
│ │
│ LLM emits 4 fields → │
│ platformWalletSummary │
│ spotBreakdown │
│ perpsBreakdown │
│ referenceWalletsSummary│
│ → composed into one │
│ platform_wallet_summary│
│ string with Spot: / │
│ Perps: prefixes │
└─────────────────────────┘三個獨立游標存儲在 financial_profile 行上:
trading_summary_last_trade_id_seen(原有)trading_summary_last_perps_fill_id_seen(新增)trading_summary_last_external_spot_id_seen(新增)
三個游標僅在 LLM 返回可解析響應且新摘要已寫入後才推進。 解析失敗時所有游標保持原位,下次重建會重試同一窗口,不會悄悄丟失任何來源。
MinaraHistorySync 觸發路徑
鏈下鏡像表由 MinaraHistorySync
(apps/agent/src/memory/minara-history-sync.ts)填充。
同步是即發即忘的,自帶節流,失敗時最多隻會導致新增 0 行。
三條觸發路徑:
- 交易事件搭載:
eventBus.on("trade:recorded", () => minaraHistorySync.scheduleSync())。Agent 自身记录交易时,用户很可能也在 Web / 移动端操作,此时同步成本低且及时。5 分钟节流(historySyncMinIntervalMs)可合併突發請求。 - 安全網定時器:每 30 分鐘,應用計時器調用
minaraHistorySync.runIfStale(),確保漏掉事件時鏡像不會長期停滯。 - 強制刷新:CLI
/profile refresh(或對應的 HTTP 接口POST /v1/profile/refresh)繞過節流,在重建前執行runOnce(),保證下次摘要能看到最新的鏈下活動。
連續失敗次數達到 historySyncMaxFailures(默認 5)後,
該 (source, sub_account_id) 鍵在常規調度中會被跳過。
自 last_synced_at 起經過 historySyncFailureCooldownMs(默認 30 分鐘)後,
會主動觸發一次探測。探測成功則將 consecutive_failures 重置為 0,
防止瞬時故障永久停用鏡像。
與 memory.trading-cases 的邊界
memory.trading-cases(methodology_cases SQLite 表)是獨立的記憶,
與個性化畫像並列存在,互不重疊。
分離的原因是兩份記錄面向不同的消費方,混合會相互汙染:
memory.trading-cases是 Agent 的學習循環。 每行是 Agent 在會話中做出的一次決策,歸因到一個或多個方法論 ID, 並在事後以 Wilson 畢業機制打分。 消費方是方法論系統,用來決定某個方法論是否應繼續被推薦。- 個性化畫像(本頁)是 Agent 對用戶是誰的認知, 彙總為一段 Agent 始終隨系統提示詞攜帶的描述段落。 它讀取會話內交易 + 鏈下永續合約 + 鏈下現貨數據。
MinaraHistorySync 的外部成交記錄故意不寫入 methodology_cases,
因為它們不攜帶方法論 ID 或提示詞 hash,
反向歸因會汙染方法論畢業所依賴的 Wilson 統計數據。
出於同樣原因,Web UI 中的交易案例頁是隻讀審計看板,編輯會破壞學習語料庫。
與普通 memory_write 的關係
個性化重建不經過審計日誌鉤子,這是刻意設計:
- 重建按計劃運行。每次觸發都會產生大量審計行, 而輸出是派生數據而非用戶操作。審計日誌會被重建噪音填滿。
- 用戶發起的
memory_write仍走正常的工具調度路徑, 並以完整推理落入audit。用戶主動發起,因此用戶行為可審計。
若需瞭解個性化重建的上次運行時間,
可直接查詢該行的 trading_summary_updated_at 或 tags_next_update。
對於單條個性化記憶寫入,可在 memories 表中按
category = 'personalization' 過濾 created_at 查詢。
配置
冷卻間隔、LLM 模型和啟動時重建行為配置於
apps/agent/src/memory/financial-profile-config.ts。
默認值直接沿用 v1:
tradingSummaryCooldownMs:30 分鐘tagsCooldownMs:30 天memoriesCooldownMs:10 分鐘rebuildOnBoot:false
未提供 LLM 客戶端時(用於測試),重建為空操作。
如有需要,可通過
MINARA_PERSONALIZATION_REBUILD=disabled 在生產環境完全關閉該服務;
但請注意,關閉後持久記憶永遠不會進入 personalization 分類。
/profile REPL 命令
在 REPL 中查看當前個性化快照:
/profile打印財務檔案行、活躍用戶標籤、近期個性化記憶,以及自定義提示詞片段(如有)。
這是排查"Agent 為何這樣表現"最快的方式:
若檔案顯示 risk: conservative,Agent 卻建議 10 倍槓桿,
說明上游某處出現了問題。
編輯檔案字段
直接字段編輯通過配置 CLI 完成:
minara config get financial.custom_prompt
minara config set financial.custom_prompt "Always prefer stablecoin pairs."標籤編輯通過個性化服務完成。 最簡單的方式是讓 Agent 從對話中推斷。 內部輔助函數支持直接手動 upsert,用於 CI 數據預填,但不對外暴露為 CLI 命令。
安全注意事項
- 個性化重建由 LLM 驅動。 Haiku 調用成本低但不為零;
生產環境請設置
MINARA_DAILY_CAP_USD。 錯誤配置的重建循環可能悄悄消耗預算。 custom_prompt與SOUL.md一樣屬於受信任輸入。 能編輯它的用戶可以改變 Agent 的行為。 多租戶部署需在自有認證層後面限制寫入權限。- 標籤推斷不代表事實。 標籤向量是基於聊天和交易樣本的盡力推斷。 Agent 將聲明值視為強於推斷值,但兩者都不應用來覆蓋用戶在對話中的明確指令。
- 部分重建會留下過期狀態。 若 LLM 調用在重建中途超時, 冷卻時間仍然會推進。下次重建正常運行,期間會出現短暫的過期窗口。 請根據實際情況調整冷卻時間。