Architecture · How it works

整个系统 如何运作

从外部数据到你看到的一个数字,中间发生了什么。本页只描述已经在生产跑着的部分,未落地的想法不写进来。
外部数据 → 确定性计算 → LLM 只写叙事 → 四个出口

🗺 全景 数据源 · 服务 · 出口

① 外部数据源 ② 处理与服务 · 阿里云 ECS ③ 出口 行情与财报 yfinance美股·港股 edgartoolsSEC 申报 baostockA 股·中文名 tushare · akshareA 股补充 Google News个股新闻 多源覆盖同一标的时 跨源交叉校验 → ⚠️ 存疑标记 产业事件 RSS · 中英文9 源 Google News JSONL · 文本 · wiki 4 个英文源封 ECS 出口 IP,已禁用 Docker Compose · Caddy 自动 HTTPS web-backend · 四层 api.oaf.world investresearch_data 取数 · 归一 · 交叉校验 · 熔断重试 ← 凭证只在这层 investresearch_tools 确定性计算:DCF · 可比 · 行业聚合 · 异动 investresearch_agent LLM 编排:只写叙事,不碰数字 investresearch_api FastAPI 端点 · 限流 · 指标 agent · 卫星产业事件管线 agent.oaf.world 规则分类器 5 主线 · 维度 · thesis 影响 (LLM 仅低置信时复核) SQLite 落盘 events · companies · thesis_state · jobs 决策层 + 证伪层 周报 · 双视角 · alerts · triggers · red flags 网关只放行只读 GET 白名单,写端点在门外被挡 网页 oaf.world 看板 · 工作台 卫星专题 · 每日复盘 · 周报 命令行 npx invesresearch quote NVDA 零依赖 · 无需密钥 飞书 每日复盘 · 周报定时推送 文件 markdown · HTML · CSV · PPTX
模块 子层 虚线框 = 同一台 ECS 上的三个容器 竖线 = 汇流总线,四个出口都同时读两个服务

🧱 四块分别是什么

目录是什么跑在哪对外地址
web/ + 根级页面静态站:看板、工作台、卫星专题、每日复盘Cloudflare Pagesoaf.world
web-backend/智能投研 REST 服务(Python 四层)阿里云海外 ECS · Dockerapi.oaf.world
agent/卫星互联网产业决策 agent同一台 ECS · Dockeragent.oaf.world
cli/零依赖 Node 命令行客户端用户自己的机器npm invesresearch

命令行不是第四个服务。 它只是上面两个公开只读接口的瘦客户端 —— 所以能做到零依赖、无需密钥,也没有任何私有东西经过它。

⚖️ 为什么这样分层 这是整套设计里最要紧的一件事

LLM 拿到的永远是已经算好的数字,它只被要求「讲述」,不被允许「计算」。 改数字这件事在架构上就做不到 —— 计算全部发生在工具层,LLM 编排层只往叙事字段写内容,不回写任何数值字段。

同理,产业事件的分类器是规则优先的:关键词命中加极性判断得出主线与 thesis 影响,LLM 只在规则拿不准时兜底。没有 LLM key 时整条管线照常跑,只是不做复核。

🧭 一条数据的完整旅程 以在工作台问「英伟达的护城河在哪」为例

  1. 浏览器发出请求
    POST api.oaf.world/ask
  2. 网关反向代理
    转到内网的 api 容器,容器端口不对公网暴露
  3. 解析意图与实体
    识别出这是单标的问题、关注点是护城河,实体命中 US:NVDA
  4. 取数
    回到取数层拉报价与财报,多源时可交叉校验
  5. 确定性计算
    算 DCF 内在价值、相对现价的上行空间、可比区间
  6. 交给 LLM 叙述
    把算好的数字连同护城河要点交出去,只要求组织语言
  7. 返回结构化结果
    评级 · 目标价 · 护城河 · 看多 · 看空 · 研判 · 免责声明
  8. 渲染
    前端出卡片;命令行排成研判卡,末尾追加免责声明

全程约 4 秒。其中第 5 步的数字是确定性的 —— 同样的输入、同样的假设,永远得到同样的估值

🔁 部署与刷新节奏

三个容器

  • api —— 投研后端,只在内网监听
  • satagent —— 产业 agent,同样内网
  • caddy —— 反向代理 + 自动 HTTPS 证书

网关对产业 agent 只放行只读 GET 白名单,写端点在门外就被挡掉,不进后端。

宿主定时任务

  • data-refresh —— 抓新闻,更新事件归档
  • api-db-refresh —— 重建数据库并原子换库
  • daily-feishu —— 每日复盘推送
  • weekly-feishu —— 周报推送

前端走 Cloudflare Pages,推主干即部署;页面对实时数据用本地缓存先渲染、后台再刷新。

换库有一道硬保护

新库为空就不换,保留原库并报错退出。这是一次生产事故的产物:当时磁盘写满,数据库页缓存让查询看起来一切正常(日志全绿、报告上千行),但数据根本没落盘,空库被换上了生产。现在重建完会重新打开文件核对行数,为空则拒绝换库。

🔒 五条设计不变量 每一条都能指到具体代码

不变量落在哪
数字来自工具计算全在工具层;给 LLM 的只有算好的结果;命令行的渲染层明令禁止任何算术
LLM 只写叙事编排层的输出只进叙事字段,不回写数值字段
缺数显式降级不编取不到就留空;渲染成破折号,且真实的 0 不会被吞掉
凭证只在边界层密钥落在部署环境变量;命令行有专门单测断言它从不发鉴权头
离线可测依赖注入 + 假数据源,全部测试不联网

还有一条贯穿始终:强制免责声明 —— 所有模型产出的出口都带。

📖 继续读

本页描述的所有产出仅用于研究效率提升与教育目的,不构成任何投资建议。投资有风险,决策需谨慎。