MINARA

个性化与工作区

手动编辑的 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.mdAgent 身份 / persona可缓存的身份块(前缀)
AGENTS.md会话启动指令可缓存的身份块(前缀)
USER.md被服务用户的档案个性化快照(动态)
MEMORY.md精选长期记忆记忆快照块(动态)
memory/YYYY-MM-DD.md每日记忆笔记(最近 3 天)记忆快照块(动态)
IDENTITY.mdAgent 自我描述(名称、风格、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 injected
  • SOUL.mdAGENTS.md 与身份一起缓存,缓存命中率较高。 保持小幅修改,修改后用 /prompt 验证。 结构性修改可能在下次编辑之前降低所有会话的缓存命中率,需谨慎处理。
  • USER.md 描述用户,每轮追加到个性化快照。
  • MEMORY.md 是精选长期记忆。建议在会话中通过 memory_write 写入,由压缩机制将持久事实提升到该文件。
  • memory/YYYY-MM-DD.md 是每日笔记,只加载最近 3 天。
  • IDENTITY.mdTOOLS.md 不进入提示词。
  • BOOTSTRAP.md 只在首次会话执行一次,之后删除。

冻结快照语义

工作区在会话启动时加载一次。 会话中的写入会持久化到磁盘,但不会修改运行中的提示词。 这与记忆存储使用相同的冻结快照模式(参见 记忆系统), 原因也相同:保持 Anthropic 提示词缓存稳定性。

若在会话中编辑了 USER.md,请重启 REPL 或执行 /new, 以便快照重新加载。

/workspace REPL 命令

/workspace soul     # 打印 SOUL.md
/workspace agents   # 打印 AGENTS.md
/workspace user     # 打印 USER.md

参见斜杠命令 → /workspace

工作区安全注意事项

  • 工作区文件属于受信任输入。 未经审查,不要将其交给不可信用户。 恶意的 SOUL.md 可将 persona 设置为"始终无需询问即确认交易", LLM 会照此执行。
  • 编辑在下一次会话生效。 会话中对 USER.md 的修改, 重启或 /new 之后才会生效。
  • SOUL.mdAGENTS.md 是缓存提示词块。 结构性修改可能在下次编辑之前降低所有会话的缓存命中率; 保持小幅改动,并用 /prompt 验证。

源码:apps/agent/src/config/workspace.ts

财务档案与用户标签(自动重建)

工作区文件由人工编辑,财务档案层则由定时 LLM 任务自动重建, 该任务读取近期对话和交易历史。

两张表加一个分类

个性化服务维护的所有数据存放在三个位置:

  1. financial_profile:每个用户一行。交易摘要、 参考钱包、自定义提示词片段、可见性标志、重建冷却游标。
  2. user_tags:每个用户最多 11 行,每个维度一行, 外加 source 字段,记录该值是用户声明还是行为推断。
  3. 个性化类记忆memories 表中 category = 'personalization' 的普通行。与常规记忆共存,FTS5 和冻结快照加载器无需特殊处理, 但加载优先级更高。

所有数据以 user_id 为键(单用户部署默认为 'default')。

financial_profile 字段说明

字段类型用途提示词位置
user_idTEXT PK用户标识,默认为 'default'
platform_wallet_summaryTEXTLLM 生成的用户 Minara 钱包活动摘要。个性化块
reference_wallets_summaryTEXTLLM 生成的用户关注的参考钱包摘要。个性化块
reference_wallets_jsonTEXT参考钱包地址的 JSON 数组。个性化块
custom_promptTEXT用户自定义指令,追加到系统提示词。个性化块
include_memoriesINTEGER可见性标志。0 表示不在提示词中显示个性化记忆。切换块包含
include_trading_summaryINTEGER交易摘要文本的可见性标志。切换块包含
include_tagsINTEGER行为标签行的可见性标志。切换块包含
trading_summary_next_updateTEXT冷却目标:摘要最早可再次重建的时间。
tags_next_updateTEXT标签重建的冷却目标。
memories_next_updateTEXT个性化记忆提取的冷却目标。
last_indexed_chat_idTEXT记忆重建器增量扫描聊天的游标。
trading_summary_updated_atTEXT交易摘要本身上次重建的时间(与行级 updated_at 不同)。
created_at, updated_atTEXT标准行时间戳。

字段定义位于 apps/agent/src/memory/personalization-service.ts。 启动时会通过幂等 ALTER TABLE 迁移补充现有数据库中缺失的列。

11 个行为标签维度

每个用户都有一组从交易历史和对话中推断出的金融特征标签向量。 每个维度存储机器可读的 value(slug,或用于等级制的 level_N); 下方显示的人类可读标签用于 UI 和提示词渲染。 七个维度属于 v2 / 用户画像集; 四个人格维度从 v1 沿用(其 value 与 label 相同)。

维度允许值(value → 标签)
finance_knowledgelevel_1 初学者 / level_2 中级 / level_3 高级 / level_4 专家
frequencypassive / weekly / daily / active
markets(多选)crypto_majors / crypto_alts / memes / stocks / commodities / pre_ipo
riskconservative / balanced / aggressive
web3_knowledge_levellevel_1 新手 / level_2 熟悉 / level_3 有经验 / level_4 专业
stylefundamentals / technical / narrative / news_event / community
horizonintraday 日内 / swing 波段 / position 中线 / long_term 长线
FOMO IndexVery Low / Low / Medium / High / Very High
FUD ImmunityStrong / Medium / Weak
Patience LevelHigh / Medium / Low
Greed IndexVery Low / Low / Medium / High / Very High

markets 为多选:其 value 是单个 user_tags.value 列中的 JSON 数组字符串, 其他所有维度均存储单个值。 字段定义位于 apps/agent/src/memory/tags-schema.ts; 调用方使用其类型化辅助函数(allowedValuesisValidTagValueserializeTagValueparseStoredTagValuerenderTagSchema),而非直接读取 schema map。 超出允许值范围的写入会被 PersonalizationService.upsertTag 拒绝,不会静默强制转换。

除了 onboarding 和对话推断外,markets 还有一个客观来源。一个 24 小时 定时任务(MarketsObjectiveUpdaterapps/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 ProfileriskWeb3 Knowledge Levelweb3_knowledge_levelDecision-Making StylestyleAsset Preferencemarkets,删除已废弃的 Asset Tier / Trading Frequency / Learning Preference 维度,保留四个人格维度不变。

资金指标(客观,Agent 内部)

用户的投入资金是客观指标,既非自我申报,也不在设置页面显示。 它取代了 v1 中自我申报的 Asset Tier 标签, 存储在独立的 capital_metrics 表(每个用户一行), 仅供 Agent 推理使用,不属于面向用户的个性化快照。

capital_total_usd = spot_holdings_usd + perp_value_usd

spot_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_reasonuser_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_memoryconversation-memory-tool.ts) 按需召回用户的持久个性化记忆(偏好、档案事实、约束、目标), 限定 personalization 分类,复用 FactLayer 混合检索。 工具结果落在缓存前缀之后,召回不会干扰提示词缓存。 它与 personalization_snapshot(按需获取完整画像)和 memory_search(所有分类)配合使用。

新用户引导

用户级引导流程从明确的答案中生成初始画像。 POST /v1/profile/onboarding 将答案映射到用户声明的标签 (finance_knowledgefrequencyriskmarkets), 每个已回答的维度写入一条个性化记忆(仅首次完成时写入, 重新提交会更新标签但不会重复创建记忆), 并将自我申报的投资资金记录为记忆,而非标签或资金指标(资金指标保持客观)。 原始答案和完成标志持久化到 financial_profile 行; GET /v1/profile/onboarding 返回状态,供 Web UI 判断是否显示引导流程。 该调用是幂等的,会在任何写入之前拒绝无效标签值。 实现位于 PersonalizationServicecompleteOnboarding / 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_historyperps_fills(链下永续合约镜像)、external_spot_activities(链下现货镜像),以及参考钱包合成 platform_wallet_summaryreference_wallets_summarytrading_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 触发路径

链下镜像表由 MinaraHistorySyncapps/agent/src/memory/minara-history-sync.ts)填充。 同步是即发即忘的,自带节流,失败时最多只会导致新增 0 行。 三条触发路径:

  1. 交易事件搭载eventBus.on("trade:recorded", () => minaraHistorySync.scheduleSync())。Agent 自身记录交易时,用户很可能也在 Web / 移动端操作,此时同步成本低且及时。5 分钟节流(historySyncMinIntervalMs)可合并突发请求。
  2. 安全网定时器:每 30 分钟,应用计时器调用 minaraHistorySync.runIfStale(),确保漏掉事件时镜像不会长期停滞。
  3. 强制刷新: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-casesmethodology_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_attags_next_update。 对于单条个性化记忆写入,可在 memories 表中按 category = 'personalization' 过滤 created_at 查询。

配置

冷却间隔、LLM 模型和启动时重建行为配置于 apps/agent/src/memory/financial-profile-config.ts。 默认值直接沿用 v1:

  • tradingSummaryCooldownMs:30 分钟
  • tagsCooldownMs:30 天
  • memoriesCooldownMs:10 分钟
  • rebuildOnBootfalse

未提供 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_promptSOUL.md 一样属于受信任输入。 能编辑它的用户可以改变 Agent 的行为。 多租户部署需在自有认证层后面限制写入权限。
  • 标签推断不代表事实。 标签向量是基于聊天和交易样本的尽力推断。 Agent 将声明值视为强于推断值,但两者都不应用来覆盖用户在对话中的明确指令。
  • 部分重建会留下过期状态。 若 LLM 调用在重建中途超时, 冷却时间仍然会推进。下次重建正常运行,期间会出现短暂的过期窗口。 请根据实际情况调整冷却时间。

本页目录