系列文章 3 之 1 — 架构设计、权衡取舍以及塑造它们的实战故事


AI 协同办公大厅
起步:是一句对话,而非一份规格书
最初的版本是一个运行在本地(localhost)的 Python MVP。它的运行勉强能够揭示出更宏大的可能性,但同时也因为暴露出的重重局限性,让我们意识到架构必须彻底推倒重来。在几周内,本地的 Python 代码被封存为“历史参考资料”,整个项目在 Cloudflare 原生无服务器架构上重获新生:包括基于 Hono 框架的边缘后台 Worker、部署在 Cloudflare Pages 上的 React/Vite 前端,以及一个不断扩展的边缘持久化绑定网络。
这就是很多人如果没有亲身体验过“感性编码(Vibe Coding)”就不会理解的地方:你最终构建出来的,绝不是你最初规划的那个东西。你是在构建第一个原型向你揭示出的真理。 最初的提示词说的是“帮我写个工具”。而最终生长出来的,却是一个充满生命力的自主研究流。每一项新功能的加入都在重塑架构,而每一次架构的微调又会暴露出新的边界问题。这些问题促使我们的设计越来越贴近生产现实。这并不是失败。这正是迭代的本质。
哲学基石:专业化分工与对抗性协同
专注于研究央行货币政策和国债收益率曲线的宏观策略师。 远比大多数企业高管更了解行业竞争格局的行业分析师。 构建数百行复杂财务估值模型、并在多种极端情景下进行压力测试的个股研究员。 利用统计学证据验证基本面推论的量化分析师。 总是以“如果你错了会怎么样?”来质疑每一个仓位的风险控制经理。 敏锐捕捉市场情绪脉搏的情绪分析师。
然而,仅仅实现专业化分工还远远不够。第二个设计洞察——同时也是最难在代码中落地的一点——是:有组织的建设性分歧,比无组织的盲目共识能产生更有价值的投资决策。 我们将在第二篇文章中详细展开这一点。
5层边缘架构:各司其职的底座

系统边缘架构全景图

5层边缘架构全景图
决定第 4 层生死的设计权衡
这种代理设计是一个深思熟虑的取舍。另一种方案是构建一个“胖 Worker”——即让边缘 Worker 亲自掌控大模型的完整执行生命周期。这固然会带来更强的控制力,但会成为运维上的噩梦:你需要亲自维护来自五家不同供应商的 API 密钥、处理高并发下的限流与降级熔断逻辑,还要编写复杂的沙箱清理代码。通过将这些操作下放给专门的编排器,并保持边缘 Worker 足够“轻”,我们得以把精力集中在只有 Worker 才能做好的事情上:机构状态、分析记忆、结构化协同以及运营遥测。
关键的安全防线:边缘 Worker 是系统里唯一持有上游 API 凭证的组件,浏览器端对此完全无感知。这不仅仅是最佳实践,更是让系统能够安全部署在公网上的架构 invariant。即使用户打开浏览器的开发者工具查看网络请求,他们也只能看到我们的边缘 Worker 域名,绝不会接触到任何大模型的原生密钥。
此外,边缘 Worker 还通过异步机制归档执行产物——拦截有价值的 API 响应并在后台静默写入对象存储,而不会阻塞对前端用户的响应。这听起来很简单,但在实际运行中,它曾是我们最痛苦的一次生产故障的导火索(详见下文)。
数据持久化层与物理容量天花板
关于边缘分布式数据库,我们买来的惨痛教训:它们存在单条 SQL 语句参数个数的物理限制,而这在本地开发环境中是检测不到的。当我们在测试环境中仅运行 5 名分析师时,每行批量写入 15 个字段共计 75 个参数,一切正常。然而,当生产环境扩展到 42 名分析师时,单次批量写入的参数量瞬间突破了底层限制。整个系统的自举装载函数在每次 Tick 定时触发时开始静默失败。由于错误在请求边界被吞掉,外部接口依然返回 HTTP 200,但内部批量更新数据库的操作早已崩溃。我们最终是通过结构化 JSON 日志查看器才从日常杂讯中捕捉到了这一隐蔽报错。
修复方法很简单:将批量写入按每组 12 行进行切片(Chunking)分批提交。但这个教训具有普适性:任何直接在不断增长的内存集合上通过 .map() 拼接数据库批量写入的代码,都是一颗随时会爆的定时炸弹。 我们目前在三个核心模块中全面推广了这种切片写入模式。
语义关联层:双通道向量索引
事实稽核索引(Claim Verification Index) 用于对从分析师报告中提取出来的单个事实陈述进行嵌入。这使得我们在第三篇文章中将要详述的“混合事实稽核管线(Fact-Check Hybrid)”能够实时捕捉到分析师是否在重复一段已被研究院判定为虚假的信息——这种自我矛盾会立即触发最高优先级的修正工单。
这两个索引都使用运行在边缘节点本地的稠密向量嵌入模型,生成向量时无需进行任何外部 API 调用。

生产环境全局仪表盘 UI
指代协议:为什么探讨“该用哪个模型”是个伪命题
每一个大模型执行后端都实现了一套完全统一的接口规范。边缘 Worker 发送格式化的 Prompt 以及工作区上下文,最终只接收生成的标准化文件和一份纯文本摘要。它完全不需要关心底层到底是一个拥有 200K 上下文的闭源长文本模型,还是一个具备自动文件编辑功能的开源代码微调模型。
我们在生产环境中发现这一点的核心原因:通过对同一个控制组研究课题下不同分析师产出的真实报告进行深度交叉比对,我们惊讶地发现,不同大模型的真实质量画像与其市场营销宣传之间存在巨大鸿沟:
某代码微调大模型:产出了一份 13.5 KB 的超详实报告,其中包含 31 个真实的来源 URL 以及 15 个标号引用——报告中的每一个核心数据都能精准追溯到国际能源署(IEA)、政府统计局或主流行业协会。这是我们研究院的“信任锚点”。 某全能型商业大模型:在仓位配置逻辑、触发条件设定以及三态权重矩阵上表现出极强的内部推论逻辑,但外部事实引用深度明显不足。 某主打快速响应的大模型:产出了极具说服力、行文流畅且判断果断的摘要,塞满了具体的数据,但引用的来源数量为零。全是自信的断言,缺乏任何地面锚定。这是典型的“高幻觉风险”画像。 某最新发布的主流模型:在分析单一白板卡片时展现出极深邃的洞察力,但其输出的结构稳定性较差——约有 30% 的卡片会夹杂对话元数据,而非干净的结构化论文。
实时动作分类器
36名分析师车队:设计权衡与尚未解决的张力

分析师车队列表与状态 UI
宏观与策略组(5名 Agent) — 包含宏观策略师、首席策略师、交易策略师、政策分析师和主题研究员。宏观策略师做出的每日评估报告会被自动灌入所有下游个股分析师的执行上下文中。如果宏观策略师判定美联储态度偏向鹰派,个股研究员在构建其 DCF 折现模型时就必须调高无风险利率假设。
行业与个股研究组(6名以上 Agent) — 覆盖科技、医疗、消费、工业、能源和金融等核心板块。个股研究员负责执行我们最引以为傲的“12阶段个股深度研究 SOP”。
量化与风控组(3名 Agent) — 量化分析师负责对 Alpha 因子进行回测并构建多因子评分卡。风控经理负责对所有头寸进行压力测试。情绪分析师实时量化全网的恐慌与贪婪指数。
固定收益与衍生品组(2名 Agent) — 覆盖利率债、信用利差、期权套利策略以及波动率曲面分析。
院务与社论支持组 — 包含早报主编、日报主编、事实稽核员、数据科学家以及两位特殊的“院务 Agent”: - 质量合规官(QA Manager):负责无情地审计每一份最终交付报告的文件完整性、数据一致性以及事实引用质量。 - 系统诊断官(Diagnostician):负责每日对全院分析师的工作状态、响应速度和认知偏差进行诊断,并输出诊断工单。
尚未完全解决的“过度路由”问题
我们的优化手段是引入角色分层约束:为每名分析师打上角色标签(primary 主分析师、specialist 领域专家、reviewer 风控复核、editorial 社论主编)。分派 Prompt 被强行注入逻辑偏好:默认优先路由给主分析师,只有在面临狭窄专业子课题时才允许拉入领域专家,并且严禁在尚未论证出具体脆弱性资产前拉入风控复核分析师。
这一硬性规约非常有效——白板研究链的聚焦度提升了数倍。然而,诊断官的每日遥测报告依然显示,风控经理收到的白板卡片分派比例仍略微偏高。其深层原因在于,当大模型面临复杂的未知探索方向时,很容易将“引入风控进行压力测试”作为最安全的“偷懒”选项。我们为此又补充了一段反默认条款(“在将任务指派给风控经理前,必须用一句话写明具体的资产脆弱点假设——如果你写不出来,就必须指派给主分析师”),这进一步缓解了路由失衡。但彻底消除这一偏见仍是我们正在攻克的架构难题。
12阶段个股深度研究 SOP

12阶段个股深度研究 SOP
我们攻克的一个严重输入传播缺陷:在早期运行中,当用户发起对某个特定标的(如苹果公司 AAPL)的深度研究时,系统跑完 12 个阶段后,输出的报告内容偶尔会莫名其妙变成英特尔(INTC)或塔吉特(TGT)。排查后我们发现,底层的编排器默认不会将初始任务的入参自动透传给工作流的每一个子步骤——每个子步骤只接收注册工作流时写入的静态 Prompt 模板。
为了彻底解决这一数据流穿透问题,我们修改了执行机制:不再重复调用全局唯一的静态工作流 ID,而是针对每一个标的动态注册一个专属的个股工作流,直接将目标 Ticker 硬编码进每个阶段的 Prompt 文本中。这给了我们极大的启示:永远不要想当然地认为底层的中间件会按照你脑补的方式去传递数据。阅读真实的运行日志,而不是只看框架的说明文档。

生产环境实战故事:塑造系统演进的严重 Bug
静默中断的早报服务
紧急排查发现,我们用于拉取上游编排产物的 scheduled sync(定时同步)函数因为承载了太多历史数据,其运行耗时突破了 Cloudflare Worker 的 CPU 时间限制。该函数在每 5 分钟 Tick 触发时,都会无条件地重新对所有会话中的每一个归档文件进行扫描和重新归档。
随着研究历史的不断累积,同步工作量呈指数级上升,最终在一个 Tick 内无法完成。Worker 被边缘容器直接强制杀死。而记录“系统已处理到此位置”的游标(Cursor)更新操作位于同步循环的最末端,因此永远无法被执行。到了下一个 5 分钟,系统重新从最初的未处理位置开始同步,再次超时被杀,陷入死循环。
这个隐蔽的死循环同时引发了两个灾难性后果:首先是外部业务的中断(游标永远无法推进,导致当天的早报无法被调度);其次是高昂的边缘对象存储写入账单(因为同一个历史文件每 5 分钟就被重复上传一次,产生了大量的写操作,但由于数据库索引未发生变化,我们在应用层的监控图表上对此完全失焦)。
修复方案:我们在归档机制中引入了“无变化跳过(skip-if-unchanged)”逻辑——在执行写入前对比历史归档索引的大小,完全一致则直接跳过,并对每一个处理单元包裹独立的 try/catch,防止单个网络抖动导致整个同步任务崩溃。优化后,该同步函数的耗时从 883 秒骤降至 53 秒,且运行异常平稳。
运维心得:在边缘开发中,必须在设计阶段就确保定时任务具备自我防御能力。一个超出执行窗口被强杀的定时任务是不会抛出传统应用层错误的。如果你发现某个高频定时任务的监控指标出现了大面积的空白,这本身就是最危险的告警信号:这意味着它在记录成功指标之前,就已经被容器强制销毁了。
穿越回两年前的分析师
大模型完全知道它在“模拟”。它甚至在报告里开诚布公地声明它在模拟。然后,它非常敬业地基于两年前的一场地产政策利好事件,编造了一整份数据详实但对今天毫无参考价值的行业报告——仅仅是因为这一历史事件在它的训练语料中与该选题具有最高的检索匹配度。
修复方案:我们在每个 Agent 的自举 Prompt 中注入了硬性的动态日期锚点。但我们绝不能在工作流注册时硬编码一个静态的时间戳字符串(因为工作流定义的缓存存在 24 小时的 TTL,静态时间戳会导致大模型的时间感发生漂移)。我们让 Prompt 指导大模型在初始化沙箱时,通过执行终端 shell 命令来动态获取当前服务器的绝对系统时间。
运维心得:如果你没有在 Prompt 中以无可置疑的方式告诉大模型“今天到底是哪一天”,它就会根据你给出的研究选题,自发地在训练语料中检索 recall 权重最高的历史时间段,并安之若素地在那里安家落户。这并不是 Bug,大模型只是在极其完美地执行它被赋予的概率预测任务。
不存在的 workbench 网页
最终我们发现,这个精心编写的组件在整个前端中根本没有被渲染。前端路由配置中遗漏了该路径。React Router 的 Catch-All 兜底规则非常平滑地将这一未识别的 URL 重定向到了系统主仪表盘。我们几个小时的辛苦调整,其实一直是在修改一个根本没有被加载的死文件。
修复方案:在路由配置文件中补上 3 行路由映射。那个让我们折腾了半天的精致页面瞬间跃然屏上。
运维心得:当用户向你抱怨“两个页面看起来完全一样”而你又百思不得其解时,第一步要做的不是去改 CSS,而是去确认这个页面是否真的被浏览器渲染了。
跨越API边界的协同故事:两名 Agent 的握手
这场协同始于一次双向崩溃。在研究院 Worker 端:定时同步函数由于累积了过多无用文件,运行越来越慢,陷入死循环;而在编排器端:新引入的底层模型接口在执行深度个股研究时,返回的全部是“空心卡片”——仅包含几百个字符的客套问候语,而原本应当承载数十个核心财务分析文件的文件系统里空无一物。
研究院 Worker 的 Agent 极其自信地给出了它的诊断意见:“新模型在沙箱里跑完了研究,但从来没有把生成的文件写进工作区同步路径,导致同步机制读不到数据。这看起来是你们那边的同步 bug。”
这个推论听起来天衣无缝。然而,它几乎完全是错的。
编排器的 Agent 并没有盲目争辩。它选择用对照试验来说话:它在沙箱中运行了一个完全一致的控制组,证实了在相同的会话中,其他大模型接口能够完美生成并同步所有财务文件。随后,它将那个新模型的执行链路拆解为五个具体的故障源头:一个被无意吞掉的命令行 Flag、一个被阻塞的标准输入流(stdin)、一个 5 分钟的超时天花板、一个临时工作目录(scratch directory)的重定向冲突,以及高并发下的写入碰撞。研究院将责任归咎于“数据传输管道”,而事实是底层“生产者”根本没能在正确的物理位置生成文件。
在接下来的 24 小时里,两个 Agent 展开了一场极其优雅的协作共建——它们在一天之内往来交换了四份核心设计文档,每一次迭代都将双方的系统契约打磨得更加锐利。研究院 Worker 要求提供细粒度的任务 Deadline;编排器则提议引入幂等键(Idempotency Key)。它们在文档中字斟句酌地探讨 Deadline 到底应当限定排队等待时间还是总执行寿命。它们通过验证代码来收敛分歧,而非打口水仗。
在这一过程中,人类运营人员的角色:绝非信息传递的传话筒,而是拥有最终否决权的“守门人”。AI Agent 完成了 95% 以上最艰苦的系统阅读、契约谈判和双端代码编写工作。人类程序员则站在杠杆率最高的位置:对少数不可逆的、涉及系统边界的决策进行审批。Agent 提议,人类审批,Agent 执行。
这种“Agent 提议,人类审批”的模式,现已成为我们处理所有跨系统变更的黄金准则。它沉淀出了一份令人惊叹的副产物:一份详细记录了两个复杂系统如何就某个技术接口达成一致的、可供审计的完整纸面协议。最近,通过这种协作方式设计并上线的一套“主动推送回调系统(Push-Callback)”,从最初设计到最终在生产环境平稳部署,仅耗时不到 24 小时。人类运营人员在这个过程中只扮演了合同审核者的角色,一行代码也未曾修改。
尚未攻克的堡垒
1. 幻觉与数据编造无法从物理上完全消灭:虽然《事实引用强制令》与质量合规官(QA Manager)的加入大幅压低了幻觉比例,但在高强度运行中,大模型偶尔还是会通过伪造一个看起来极其逼真的来源 URL 来强行通过引用审计。我们正在构建的“混合事实稽核管线(Fact-Check Hybrid)”的第三层级(特定权威域名的直接穿透校验)是我们的下一道防线,但该模块目前尚未全面在生产环境铺开。
2. 风控复核分析师的过度指派:如前所述,虽然软性角色标签起到了明显的分流作用,但大模型在决策链路中依然存在将“引入风控”作为避险默认项的内在偏见。
3. 单一运营人员的决策瓶颈:当前系统架构默认仅支持一位人类运营人员。缺乏多角色权限管理(RBAC)、多运营人交接协议以及运营决策冲突调解机制。这适用于个人开发环境,但在团队级协作中会立即遭遇瓶颈。
4. 真实市场实操业绩的缺失:我们在第三篇文章中将要介绍的“模拟交易盘(Paper Book)”目前正处于测试起步阶段。在经历至少两轮完整的牛熊市场周期考验前,整个研究院的决策能力依然停留在“理论假设”阶段,缺乏真正的铁证支持。
5. 常驻上下文空间的物理局限:随着分析师运行时间的累积,其常驻记忆(Standing Memory)文件的体积正在快速膨胀。每次启动任务时执行的 Step 0g 动态自举已经开始逼近部分大模型接口的上下文承载极限。我们急需设计一套既能保留最关键核心论点、又能对历史繁杂论据进行合理遗忘的“记忆压缩算法”,而我们目前还缺乏能够指引这一遗忘周期的第一性原理。

下期预告:我们将带您深入剖析如何通过“白板引擎”与“对抗性研讨协议(Committee Deliberation)”让盲目共识无处藏身——包括那次几乎拖垮边缘数据库的元数据体积溢出 Bug,以及如何用不到 1 秒的主动回调架构替代高昂的 30 秒轮询机制。

夜雨聆风