MINARA

机构模式: 运维参考

多智能体投委会的分析师恢复契约与规范资产预解析

minara_institution_analyze 可以运行 Minara 默认投委会流程, 也可以运行网页界面中为当前会话保存的 Roundtable。本页说明 默认分析路径使用的底层恢复与资产解析行为。阶段编排、Agent 设置、模板和不可变运行快照见 Institution Mode

默认流程包含并行分析、多空辩论、研究综合、交易方案、风险辩论 和最终组合判断。自定义 Roundtable 可以替换这套安排,同时保留 相同的只读安全边界。

流水线超时和基准配置见 环境变量: Institution Mode

Roundtable 状态与快照

Builder 为每个 Institution 会话保存一套活动流程。保存时会校验预期 版本,因此另一个浏览器窗口不会悄悄覆盖较新的修改,而会收到冲突。 如果会话没有已保存流程,网关会依次采用最近一次运行快照和内置默认值。

Agent、阶段和 Roundtable 模板分别存储。内置模板不可修改。运行开始时, 完整流程会复制到不可变快照,其中包含阶段结果、Agent 用量、最终状态和 报告文件。相关接口包括:

分析师恢复,synthesis-and-parse

每个 Phase-1 分析师 slot 先在自由的 tool 调用循环里跑 (submit_analyst_report 始终和角色数据工具一起暴露)。 当主循环提交了一份真实、非 stub 报告时,slot 附上捕获的 tool_outputs[] 并返回。

当主循环没提交(turn 上限触发、模型写了散文却忘了提交)或 提交了空/占位参数时,编排器跑 一次 综合 turn:

  • 不带 tools,不带 tool_choice。开启 thinking,这是之前在 tool_choice: { type: "tool" } 下失败的调用,因为 Anthropic 拒绝那种组合,留给模型填充参数的推理空间为零。

  • 用户消息要求严格的三段散文格式:

    HEADLINE: <一句结论>
    
    KEY FINDINGS:
    - <finding 1, 引用工具名 + 具体数字>
    - <finding 2, ...>
    
    CONFIDENCE: <0.0 到 1.0 之间的数字>

编排器通过 parseSynthesisProseToReport 在服务端把散文直接 解析为 AnalystReport。解析器宽容混合的 bullet 风格、段落 标记前后的 markdown 强调标记、以及范围之外的置信度 (截断至 [0, 1])。

当综合 turn 的散文为空、格式错乱、或者所有 bullet 都长得像 占位("tried X: ok")时,编排器回落到 buildSubagentSummaryReport,通用的"始终产出可用结果" 构造器。两种分支:

分支触发条件HeadlineConfidence
部分 tool 成功toolsTried.some(t => t.status === "ok")"<ticker> (<role>): raw tool summary (model synthesis unavailable)"0.3
全部 tool 失败/无 tool 调用toolsTried.every(t => t.status !== "ok") 或为空"<ticker> (<role>): no data gathered this session""... no tools available this session"0.1

当部分 tool 成功时,报告引用捕获的 tool 数据(每个 tool 一条 bullet,从其 preview 派生),下游阶段就能看到返回了什么。 当全部失败时,报告枚举尝试过的 tool,最后以角色的领域默认推理 一句话结尾(每个角色一句,定义在 roles.ts 角色定义旁边)。

无论哪种分支,slot 的 ok 标志都是 true,旧的 "data-gap" 概念已经退役。每个 Phase 1 slot 现在都给主智能体提供一份可用 总结,Phase 2-6 始终运行。

Tool outputs,捕获返回数据面

每份 AnalystReport 携带一个可选的 tool_outputs[],由编排器 从 slot 的会话中填充。每个 tool 调用一条:

{
  tool: string;           // 工具名
  ok: boolean;            // true 表示调用成功
  preview: string;        // 成功:截断的 JSON / 文本(~1500 字符)
                          // 失败:错误信息字符串
  args_summary?: string;  // 调用输入的一行摘要
  error_code?: string;    // 结构化失败类别(如果有)
}

成功的调用携带漂亮打印的 JSON 预览;失败的调用直接把失败 原因带在 preview 里,操作员能直接看到 WHY 一次调用没返回 数据,而不是只看到它没返回。web-ui 里的 PersonaOutputRenderer 把这些数据渲染为结构化输出弹窗里的 "Tool outputs" 段落, 每条可点击展开。

规范资产预解析

Phase 1 派发之前,若 classifyAsset(ticker) === "unknown" (或 INSTITUTION_FORCE_RESOLVER_PREFLIGHT=true),编排器 跑服务端预解析:

  1. 查 SQLite 缓存(canonical_asset_cache 表)。
  2. 缓存未命中或过期:并行查询 CoinGecko / CMC / DexScreener, 归一化为 chain+contract 身份(CAIP-19 风格的 discriminated union:evm / native / solana / cosmos / polkadot / equity)。按结果分别 TTL 持久化。
  3. 结果分发:
    • resolved(唯一 chain+contract):补充 meta.resolved_ticker, 分析师在 preamble 看到规范身份。
    • multi(多链部署):同上,但候选数组进入消歧上下文。
    • ambiguous(provider 不一致):集中式消歧事件, 而不是四个并行 "which token did you mean?" 提问。
    • none:Phase 1 之前中止,零 LLM 调用。这是编排器 目前唯一仍会触发的 abort kind。

规范身份是 chain+contract,不是 CoinGecko id。 CoinGecko 的内部 id 是依赖他们策展的中心化索引;用作 bootstrap 输出会把整个智能体锁在某一个 provider 的世界观里。下游接受 on-chain 查询的工具直接吃 CAIP-19;provider-specific 工具 (CoinGecko 价格图)只在规范身份确定后从 sources 读自己的 id。

按结果的 TTL

缓存按结果使用不同 TTL,因为各结果的衰老速度不同:

结果默认 TTL为什么
resolved30 天chain+contract 稳定,很少变
multi14 天用户消歧可能固定到具体某条链
ambiguous7 天provider 数据可能收敛
none1 天provider 每日更新;尽快重试
user_supplied365 天操作员覆写;信任人类

各类 TTL 通过 CANONICAL_ASSET_CACHE_TTL_*_DAYS 环境变量调 (见 env-vars 参考)。

当实时聚合失败(provider 宕机、被限流)时, CANONICAL_ASSET_CACHE_FALLBACK_TO_EXPIRED=true(默认) 返回带 from_expired_fallback: true 标记的过期缓存。设为 false 当部署不能容忍任何数据漂移。

添加缺失的 ticker

智能体首次遇到新 ticker 时就学到 ticker → 规范身份映射。新代币 不需要 code deploy。两种路径:

  1. 实时解析:下一次 /institution <ticker> 触发预解析, 缓存结果,之后所有角色都能看到规范身份。
  2. 操作员覆写:当 CoinGecko / CMC / DexScreener 都没有 这个代币(如全新发行),操作员可以直接固定规范身份。UI: abort banner 提供合约地址表单。CLI: minara assets pin <ticker> --chain <chain> --contract <0x...> (当部署里启用了 assets CLI)。

methodology-storeTICKER_TO_CLASS 表依然存在,但用途 不同了(用于风险 / 投资组合代码查 asset-class)。规范解析器 在它给出新的 asset_class 信息时回写过去,但 TICKER_TO_CLASS 不再是规范身份的真理源。

在实践中检查恢复情况

institution_role_outputs.data_gap 列依然保留在 schema 上以 兼容旧行(data-gap 概念退役前写入的数据)。新写入始终设为 0。 指标聚合器 InstitutionStore.getAnalystStubMetrics 仍能读出 做历史报告,但这一列在当前的恢复路径里已经不再起作用。

逐 run 审计:

# 一次 run 所有分析师行,包含旧版 retry_count + data_gap。
minara learning methodology cases --run-id <run_id>

本页目录