返回项目列表
市场情报

TMZ

Tracking Market Zeitgeist

一条正在原地重构的市场情报流水线:一个ReAct编排器调度五个可替换的专家——采集、富化、新颖度、评估、信号——运行在同一条已经在生产环境跑着的确定性批处理流水线之上,并把每一次决策都记录成可回放的推理轨迹。一个受环境变量控制的A2A服务器把结果暴露给生态系统里的其他系统——在这个生态里的第一次"反向数据流"中,TMZ还会读回Trader Joe自己的自选股列表,让它的扫描收敛到这个家庭真正持有的仓位上,而不是一份静态的股票清单。

分享这篇案例 →
5
市场情报专家
ReAct scheduling replaceable experts
编排方式
TraderJoe
消费方
难点所在

难点在于:原地重构一条正在生产环境运行的流水线——每个专家都先以行为完全一致的封装形式上线,经过一致性测试验证,然后才允许编排逻辑真正改变运行方式。

架构一览
已上线 · 新一代架构已设计
截至 2026-07-14
ReAct orchestrator scheduling replaceable expertsConfig-driven LLM & agent configExternalized prompt storeReplayable reasoning-trace storeA2A protocol peer (market_signals, signal_accuracy)Pluggable collection-source registryMetadata-only A2A request audit
完整的内部 Agent 阵容
交接给交接给交接给交接给orchestratorcollection_expertenrichment_expertnovelty_expertevaluation_expertsignal_expert
Agent

ReAct orchestrator scheduling five replaceable Experts over the same deterministic batch pipeline already running in production

TMZ 在生态系统中
技术栈

Python, Postgres, Dagu (batch trigger), Grafana

01一条分阶段的流水线,不是推倒重来

今天的生产环境循环已经是分阶段的:main.py的循环驱动器依次运行schema初始化、股票代码解析、抓取校验、落库、富化、三个自愈式回填、评估、信号导出,每个阶段都把结果写进pipeline_runs表里的一条记录。这套结构正是重构的地基,而不是被丢弃的东西——阶段变成专家,循环驱动器变成编排器。但今天,这套结构挤在一个1047行的巨型模块里,没有稳定的接口:阶段封装函数接收的是具体函数作为参数,而不是一个可以被另一种实现满足的接口。每个专家上线的第一步都是对同一个已验证函数做纯粹的重构——行为完全一致,在任何编排逻辑被打开之前先验证过——这样一个今晚还在生产环境跑着的系统,可以在不下线的情况下演进。

02五个专家,只有一层

采集、富化、新颖度、评估、信号,这五个专家各自实现一个最简的专家协议,并封装流水线里已经验证过的逻辑——采集专家负责抓取、校验、落库;富化专家负责L1情绪打分、L2深度阅读,外加回填;新颖度专家负责指纹去重和打分;评估专家负责对照真实市场结果算T+1/T+5准确率;信号专家负责Trader Joe今天就在直接从Postgres读取的那份导出契约。每一个都能独立单测、独立替换——未来接入Finnhub或RSS,只是多实现一个采集专家,而不是去改抓取脚本本身。它们刻意只保持一层:没有专家会派生子专家,和这个作品集里其他每一个系统一样的"编排器加专家"结构。

03会推理、但不会乱跑的循环

编排器跑的是一个有边界的"思考-行动-观察"循环,默认策略就是今天这套固定的阶段顺序——ReAct在这里只是机制,不是不确定性的许可证,一个一致性测试会验证编排器开关状态下写入数据库的结果完全一致。每一步都会写进一张新的推理轨迹表:哪个专家跑的、它考虑了什么、它做了什么、一份脱敏后的观察数据,还有一个和A2A层共用的关联ID,让一次跨系统调用和催生它的内部推理能通过同一个键对上。一个回放CLI可以从这张表里把任意一个循环完整重建出来——这是真正的审计能力,而今天,一次运行结束后只留得下计数和耗时,推理过程本身是留不下来的。

04一个A2A对等方,而不只是信号源

一个受环境变量控制的对等服务器,把TMZ的信号契约同时暴露给Trader Joe和Family CFO,把准确率契约暴露给Trader Joe,序列化时套用比底层导出表更严格的隐私白名单——原始链接和原始数据永远不会离开这个进程。它刻意做成双通道:现有的Postgres直读照常工作,HTTP接口是一层附加的、独立开关的能力,在有对等方真正切换过去读取之前,行为完全零变化。TMZ不只是提供方,也是消费方——它会读回Trader Joe自己的自选股列表,这是这个生态里的第一次"反向数据流",让它自己的扫描收敛到这个家庭真正持有的仓位,而不是一份静态的股票清单。

05配置和提示词,搬出代码库

TMZ今天所有LLM调用用的提示词,都是写死在富化模块里的字符串常量;重构把它们外置成一个按语言和名字分类、有版本管理的提示词库,存放路径可以用环境变量覆盖,还留着内嵌兜底,这样即便镜像打包出错也只是降级,而不是直接崩溃。同样的原则也用在其他一切运维人员可能想调的东西上——每个agent用哪个LLM提供商和模型、打分权重公式、新颖度和评估阈值——统统从代码常量搬进一份YAML配置文件,遵循"环境变量优先于YAML、YAML优先于代码默认值"的顺序,这样金丝雀部署可以指向一份备用配置文件,一次阈值调整也变成一次可评审的单行diff,而不用重新构建镜像。它还顺手根治了一个真实发生过、反复中招的故障模式:新文件因为Dockerfile和CI工作流各自手写了一份文件清单而悄悄漏部署——包结构重整之后,两边都改成了一次性的整目录拷贝。

技术栈

Python、Postgres、OpenRouter(DeepSeek V4 Flash)、Dagu调度的批处理周期、yfinance数据采集、自建Gitea Actions CI/CD。

— 简历与联系方式

聊。