机构模式: 运维参考
多智能体投委会的分析师恢复契约与规范资产预解析
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,通用的"始终产出可用结果"
构造器。两种分支:
| 分支 | 触发条件 | Headline | Confidence |
|---|---|---|---|
| 部分 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),编排器
跑服务端预解析:
- 查 SQLite 缓存(
canonical_asset_cache表)。 - 缓存未命中或过期:并行查询 CoinGecko / CMC / DexScreener,
归一化为 chain+contract 身份(CAIP-19 风格的 discriminated
union:
evm/native/solana/cosmos/polkadot/equity)。按结果分别 TTL 持久化。 - 结果分发:
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 | 为什么 |
|---|---|---|
resolved | 30 天 | chain+contract 稳定,很少变 |
multi | 14 天 | 用户消歧可能固定到具体某条链 |
ambiguous | 7 天 | provider 数据可能收敛 |
none | 1 天 | provider 每日更新;尽快重试 |
user_supplied | 365 天 | 操作员覆写;信任人类 |
各类 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。两种路径:
- 实时解析:下一次
/institution <ticker>触发预解析, 缓存结果,之后所有角色都能看到规范身份。 - 操作员覆写:当 CoinGecko / CMC / DexScreener 都没有
这个代币(如全新发行),操作员可以直接固定规范身份。UI:
abort banner 提供合约地址表单。CLI:
minara assets pin <ticker> --chain <chain> --contract <0x...>(当部署里启用了 assets CLI)。
methodology-store 的 TICKER_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>