资讯动态

把实时数据入口从 AI 对话中拆出来:一个 FastAPI 工作站的边界设计

发布时间:2026/9/10 23:40:58 来源:尧图企业网站定制
给一个 AI 产品不断增加能力时最省事的做法是继续往聊天框里塞入口。文件处理、图片理解、热点发现、项目搜索都可以被包装成一句自然语言请求。问题是这些任务并不共享同一份数据合同。文档总结依赖用户刚刚上传的材料热点发现依赖当前采集结果开源项目选择还需要仓库身份、许可证和可回溯证据。如果界面只剩一个输入框用户很难判断回答究竟来自当前数据、历史缓存还是模型记忆。我在实现一个 FastAPI AI 工作站时最终把“工作区”和两个“当前发现页”拆成了独立路由。本文只谈这个拆分背后的工程边界。图 1开源项目页的用途分类控件9月9日真实页面局部。分类用于发现候选不代表项目能力或许可证已经核验图中数量是截图时的界面显示值。1. 先按数据合同拆路由而不是按菜单拆页面当前的路由关系可以简化成/ 工作区文件、图片、链接和自然语言任务 /topic-radar/ 当前题材来源、市场、证据状态和新鲜度 /githubai/ 开源项目仓库身份、分类、榜单和核验信息 /api/v1/ai/... 对应的只读数据接口在 FastAPI 入口中页面和数据路由分别注册。核心思路不是“多做两个页面”而是让三类请求拥有不同的失败方式、缓存方式和证据要求。app.get(/topic-radar,include_in_schemaFalse)app.get(/topic-radar/,include_in_schemaFalse)deftopic_radar_entry(request:Request)-Response:...app.include_router(create_topic_radar_router(api_prefixAPI_PREFIX))app.include_router(create_github_ai_radar_router(...))工作区可以容忍一次模型调用失败后重试当前题材页不能在来源异常时把旧数据继续标成“正在上升”项目页也不能因为后台正在刷新就临时从 GitHub 拉取一批未经校验的数据直接返回。2. 当前数据不能从模型记忆里“猜”出来热点和开源项目都属于时效性数据。模型适合解释一条已知记录却不应该负责证明这条记录是今天的。因此数据流被放在对话之前来源采集 - 规范化与身份去重 - 来源健康和新鲜度判断 - 生成可发布快照 - 只读 API - 网页筛选与详情 - 用户需要时再交给模型研究这条顺序带来一个很实际的好处页面可以明确展示“目前知道什么”而模型只负责后续理解和表达。即使模型服务暂时不可用用户仍然可以浏览已经发布且通过检查的数据。3. 来源健康必须进入公开数据合同只记录抓取成功或失败还不够。一个来源连续失败时系统至少要知道上次成功时间、当前是否降级、数据是否仍在新鲜窗口内以及下一次探测时间。对外可以投影成类似下面的结构{source:example-source,last_success_at:2026-08-30T02:10:00Z,freshness:fresh,degraded:false,next_probe_at:2026-08-30T02:20:00Z}当单个来源进入降级状态时页面仍可服务其他健康来源该来源的旧记录则不再作为“当前热点”继续参与排序。这样处理比在接口最外层返回一个笼统的 500 更有用也避免把历史数据伪装成实时结果。图 2热点页的状态分组、搜索与计数控件9月9日真实页面局部。事件数与来源信号数采用不同口径不能互换也不能把平台热度当成事实确认。4. 公共 GET 不做采集也不临时调用模型开源项目页的后台处理比普通列表更重项目需要绑定上游仓库身份、README 和 Release 证据中文内容还要与同一代事实和引用保持一致。如果每次 GET 都动态拼装这些内容延迟、成本和一致性都会失控。因此公开读取采用不可变发布版本staging 数据 - 构建候选 Release - 校验项目、证据和引用的同代关系 - 原子切换 current 指针 - 预热紧凑的公开缓存 - 公共 GET 只读取当前健康版本候选发布失败时旧的健康版本继续服务。公共请求不扫描后台目录、不现场采集 GitHub也不调用模型生成正文。这个限制看起来保守却能让页面性能和内容一致性变得可验证。5. HTML 和静态资源使用不同缓存策略实时页面的 HTML 壳需要及时拿到新的资源版本因此入口返回Cache-Control: no-cache, must-revalidate Content-Language: zh-CNCSS、JavaScript 和图片则使用版本化 URL允许浏览器长期缓存。也就是说“页面入口是否更新”和“大体积资源是否重复下载”是两个问题不能靠统一关闭缓存解决。本地验证时我会分别检查 HTML 响应头和带版本号的资源curl-Ihttp://localhost:9010/topic-radar/curl-Ihttp://localhost:9010/githubai/6. 拆分后更容易定义失败边界这套结构最终得到四条比较清楚的约束采集失败只降级对应来源不拖垮整个工作区模型失败不影响已经发布的浏览数据新版本校验失败时保留上一版健康 Release页面把日期、来源和待核验项展示出来不把排名写成结论。用户仍然可以从当前题材或项目进入下一步研究但这时模型拿到的是一条有身份、有日期、有来源的记录而不是一句“帮我找最近热门内容”的模糊请求。7. 页面拆开不代表工作流割裂工作区负责接收材料和组织输出题材页负责发现当前内容线索项目页负责发现并初步核验开源项目。它们在交互上是三个页面在工作流上仍然可以前后衔接。这篇文章讨论的是我开发的 AI 工作站中的工程取舍。截图只展示本文讨论的分类、筛选与计数控件不作为功能完整性或服务效果的证明。对我来说这次拆分最重要的结果不是多了两个入口而是用户终于能看出哪些内容来自自己的材料哪些来自当前数据哪些只是模型参与后的解释。这个边界一旦模糊功能越多产品反而越难被信任。8. 验收不能只看页面有没有打开下面是一份可在自己的本地环境执行的检查清单不是本次已经全部通过的测试报告。入口与资源分开验证。对 HTML 使用curl -I检查缓存头再从 HTML 取出实际脚本路径用curl --compressed -i检查版本化资源的响应。不要只看文件名变了就认定浏览器拿到了新内容。列表与详情交叉验证。记录同一项目在列表和详情中的标识、发布版本、数据观察时间以及 Star 数。版本相同仍不代表每个字段观察时间相同有差异应回溯字段来源不能直接取较大的数字。标签与证据分开验证。展示层存在许可证标签不等于证据层已经取得许可证文本。证据缺失时应明确未知不能由摘要或模型补成“已核验”。计数口径单独验证。一条事件可能聚合多条来源信号因此事件数不应直接等同于来源条数。来源身份去重也应独立于标题去重。失败注入只在隔离环境执行。模拟某个来源超时或候选发布校验失败检查其他健康来源与上一健康版本是否仍可读取不要为写文章在生产环境停服务。目前仍有需要改进的地方抽查中见到开源合集与详情的 Star 显示差异原因还没有查明部分项目有许可证标签但没有直接 License 文本证据。因此上文描述的是设计边界和检查方法不意味着每一条公开记录都已通过完整核验。本文由项目开发者提供文字含 AI 辅助整理代码片段用于解释结构截图为真实界面局部不包含客户数据。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价