zjchina.net

Drogon · ROS 2 · 独立开发笔记

ENGINEERING NOTES/工程笔记

把「股吧」换成 Agent 团队:自绘终端,以及给它装上的秤与闸

2026 年 10 月 16 日。这篇博客有两个日子。10 月 5 日,zjchina-render 画出了第一个真实终端:经典券商三栏——左边自选股、中间蜡烛图、右侧交易面板,底部原本属于「股吧」的位置,换上了我们自己的四个 Agent。485 根真实日线、六只自选标的、debug 构建稳定 320 FPS。11 天后,这个终端背后的系统第一次完整跑了一天真生产:本地模型上线、48 条观点落库、调用零失败。同一周,我们给 Agent 团队装上三样东西:记名(每条观点带来源)、秤(基线成绩单)、闸(回归门)。第一秤就称出了坏消息——这正是秤存在的意义。

一、三栏终端,从浏览器手里拿回来

ADR-0005 早就定了渲染路线:真机设备端自绘为尊,web 浏览器只做 DOM+SSR 兜底。但路线是路线,引擎第一次画「真实页面」是另一回事。我们选了券商终端的经典三栏作为参照,原因很实际:

  1. 信息密度是最高的试炼。五档盘口、分时成交、自选股、K 线、指标——如果引擎连行情终端的密度都扛不住,工厂大屏和机器人 HMI 更别想。
  2. 它有一个我们想换掉的东西。传统终端底部的「股吧」是个噪音广场——情绪、传言、喊单。tidewatch 的四个 Agent(技术面/资金面/公告面/风控)恰好能站进这个位置:同一个位置,从围观情绪换成团队决策。这一换,终端的气质就变了。
自选股列表 真实行情 · 迷你走势 点击切换主图 蜡烛 + MA5/10/20 + 成交量 世界坐标层(相机裁剪) 交易面板 买入 卖出 挂单列表 Agent dock(原「股吧」位)· 技术面 / 资金面 / 公告面 / 风控 全部屏幕空间 overlay 层:世界几何不动,UI 独立像素坐标

落地那天站住的东西:左侧自选股是六只真实标的,行情 facade 拉两年日线,行内 30 日迷你走势线,点击切换主图零网络等待(缓存复用);中间图表 485 根日线 + MA5/10/20 + 成交量,滚轮缩放只动时间轴,十字光标带两行 tooltip;右侧交易面板有买/卖切换、圆角按钮、悬停高光,下单进挂单列表——还是演示语义,没有接真实撮合;底部 Agent dock 四个选项卡 + 消息时间线 + 输入框(支持中文 IME),Enter 发送后走 tw-server 的 /api/agents/ask,服务不在线时降级成系统提示行——不装死,不假装在线。

二、美工 Agent 的「能碰 / 不能碰」

这次页面是美工 Agent 做的初稿,我们做的验收。为了让「AI 画页面」不演变成「AI 改管线」,开工前先签了边界契约:

  • 能碰:palette.rs 全部色值(配色单一真源)、布局节奏常量、文字层级字号;
  • 不能碰:几何管线、instanced 上传路径、交互语义、revision 性能路径。需要新视觉原语(比如这次的圆角按钮),走内核侧加 Primitive + 管线 + 测试,再交给美工调色。

三天跑下来,这个边界是这次落地最值钱的东西。美工在边界内把「荧光终端」调成了「午夜蓝」主题,红涨绿跌的铁律写死在 palette 注释里;边界外它一次都没越——越界的冲动被「申请内核原语」的流程接住了,圆角管线就是这么来的。

三、三个真 bug:自绘和浏览器的本质区别

验收时我们抓到三个 bug,每一个都很小,但每一个都指向同一个事实:浏览器帮你兜住的事,自绘引擎里全得自己兜。

其一:半透明去哪了。 面板背景写着 alpha = 0.95,注释写着「半透明叠于图表之上」,悬停高光写着 alpha = 0.16。但三条几何管线的混合状态全是 BlendState::REPLACE——alpha 被静默丢弃:面板实际上不透明,悬停高光亮起来是一块实心白。浏览器里 rgba() 永远生效,自绘里混合是你自己声明的管线状态,不写就没有。修复:三条管线统一 ALPHA_BLENDING——蜡烛色 alpha 恒为 1,混合开关对它们零视觉影响,对 overlay 层是生死开关。

其二:圆角不圆。 第一版圆角用 SDF 硬裁切(d > 0 就 discard),边缘一圈锯齿。正确姿势是屏幕空间导数做 1px 软边(fwidth + smoothstep),但软边本质是让边缘像素输出半透明——所以抗锯齿必须先有 alpha 混合,两个 bug 其实是一根藤上的。修完第一个,第二个才有解。

其三:\n 塌行。 tooltip 里写了 \n 想分两行,结果文本管线是逐字符平铺排版,换行符变成了一个方框字形夹在中间,两行塌成一行。浏览器里 white-space 是默认能力,自绘里「多行文本」是一个还没有被实现的功能。修复很克制:不动内核,消费侧拆成两个 TextBlock——功能缺口先记账,不急着在引擎里长排版引擎。

三个 bug 的共同点:它们在任何浏览器项目里都不会发生,但在自绘世界里有各自的物理原因。这就是自绘的入场费——换来的是整个渲染路径上没有任何一个黑盒。

四、十一天后:团队真的上岗了

10 月 15 日晚,本地模型 qwen3:30b-a3b(18.56GB,Q4 量化,MoE 架构、3B 激活参数)部署到工作机,tidewatch 的 LLM 后端从云端切到本机。动机有两个:数据不出机;以及更根本的——自我学习的研究载体必须是自己的模型,云端的黑盒不会为你的历史表现调整半步。

10 月 16 日,系统第一次完整跑了一天真生产。launchd 三班倒:08:00 盘前计划、09:08 起盘中 60 秒轮询到 15:00、20:00 收盘复盘,漏跑有 catchup 补位。晚间复盘跑了 19 分 22 秒,48 条观点落库,LLM 调用零失败。对比云端同任务的 3 分 58 秒,本地慢了 4.9 倍——但这 19 分钟里每个 token 都烧自己的电,而且跑得慢本身暴露了该优化的地方。

一个关键取舍值得记录:K 线输入从全量截到最近 60 根,把单次运行从预估 80 分钟压进 20 分钟。截断对判断质量的影响还没做 A/B 对照——先记账,不装作没这回事。

五、问责三件套:记名、秤、闸

团队上岗容易,问责难。Agent 说的话算不算数,需要三样基础设施。

记名:每条观点带来源。 opinions/runs 两张表各加 provider/model/model_digest 三列,每条观点知道自己出自哪个提供方、哪个模型、哪份权重。设计里有一条铁律:未标明 ≠ 编造——取不到来源一律标 unspecified,宁可空着,绝不冒认。这条铁律上岗第一天就经受了检验:归因代码 21:17 才进库,而 20:00 的复盘用的是 06:08 构建的旧二进制,于是首日 48 条观点全部如实标了 unspecified——没有一条假装自己来自本地模型。系统用一次乌龙证明了它不说谎。

秤:基线成绩单。 用固定窗口(12 只标的、48 个 case)给当前模型留了第一份真基线:技术面 Brier 0.404、资金面 0.374、公告面 0.796。Brier 的随机基线是 0.25,越小越好。成绩单按模型身份过滤——只跟自己的历史比,不跟前任混算。

闸:回归门。 gate 命令拿候选模型跑同一窗口,与基线逐面对比,Brier 劣化超过容差 0.02 就以退出码 3 收场——换模型、换权重、换 prompt 这种事从此有了把关人。容差 0.02 不是拍的:同一份权重同一个窗口连跑两次,实测 Brier 抖动在 ±0.006 以内,容差取约 3.5 倍噪声——不误报;人为构造的劣化档(+0.05)是 8 倍噪声——拦得住。四步验证(自比放行、劣化档拦截、--no-fail 放行、生产成绩单带窗口警告)全部通过。

六、诚实清单

  • 第一秤称出了坏消息。 本地模型两个有效面的 Brier(0.37–0.40)都劣于随机基线 0.25——作为实盘信号,它现在不可用;作为自我学习的研究载体,正好。秤装上去就是为了称出这种事,称出来了,秤就没白装。
  • 公告面在空转。 基线窗口内 65 行公告只覆盖 13 只标的里的 7 只;有只标的挂着 50 条公告,模型照样 3 投 3 中立。公告面有效样本只有 3 条,这一面的成绩单暂时失去意义——数据覆盖是下一阶段的事。
  • 盘口五档仍空着。 日线源没有真实盘口数据,我们宁可空着也不放「演示数据」——终端里任何一格假数据都是对使用者的不诚实。
  • 好消息:旧账还了一笔。 落地那天记录的「每帧全量重建」——面板动一下、485 根蜡烛的 GPU 缓冲跟着重传——已在 L0 内核还账:场景拆成 world / overlay / text 三段独立脏标记,UI 动效不再让 5 万根蜡烛的实例缓冲陪绑重传。
  • 决策路径还没切。 真实生产里的校准系数仍用混算全量成绩单,是否也按当前模型身份过滤,等我们拍板后再动——生产路径的每一步变更都要过脑子,不过夜。

七、引擎的下一站

终端落地证明 L0 内核(instanced 管线、world/overlay 双 pass、三段增量、滚动视口裁剪)能扛住真实页面的密度。往后走三步:L1 补齐布局系统、组件原语、命中与事件路由、主题设计令牌,让消费侧不再硬算像素;L2 长领域组件——K 线图、工厂仪表盘、机器人 HMI——并覆盖大屏/平板/桌面多设备矩阵;L3 把 Agent 的思考链和工具调用画成界面,接数字孪生场景。每一步都必须有真实消费侧(tidewatch、工厂大屏)验证,不闭门造车。

股吧换成 Agent 团队,换掉的是「信息进来先经过谁」;记名、秤、闸,补上的是「说完之后谁负责」。终端的每个像素是我们引擎一笔一笔画的,终端里的每句话,现在也有了署名。

← 返回首页全部文章