1. 为什么 FastAPI Streamlit 联调时 Key 总是配得乱七八糟做本地原型最舒服的组合之一就是 FastAPI 当后端、Streamlit 当界面。后端负责调模型、跑链路前端负责把输入框、按钮、结果区拼起来改一行代码就能看到效果。但真正动手时很多人卡在第一步Key 和 API 通道到底放哪。我见过最常见的三种写法。第一种是把 Key 硬编码在main.py里前端app.py又复制一份改一次要改两个文件。第二种是前端直接调模型后端只做转发结果两套 SDK、两套 base_url日志对不上。第三种是环境变量在 PowerShell 里$env:设了但 Cursor 的终端和 Streamlit 子进程读不到报 401 还找不到原因。这篇就聚焦一个目标在 Cursor 里给 FastAPI Streamlit 项目配一套统一的 Key 与 API 通道让前后端只认一个入口。交付物是三样东西——项目级settings.json、后端config.toml骨架、以及启动 FastAPI、拉起 Streamlit、验证请求链路的三步动作。适合正在用 Cursor 做本地开发、想快速跑通原型的人。核心思路很简单Key 只存一份通道只配一次后端统一出口前端只调本地接口。这样 Streamlit 永远不碰模型 KeyFastAPI 成为唯一调用方排查问题时只看一个日志源。2. TaoToken 前置把统一通道先准备好在写配置之前先把「通道」这件事定下来。TaoToken 在这里扮演的角色是统一的模型调用入口OpenAI 兼容协议所以 FastAPI 里用openai或langchain-openai都能直接接。官网入口在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 基址是 https://taotoken.net/api 。你需要先拿到一个 API Key。进控制台创建即可地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content Key 管理页在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。创建后复制那串sk-开头的字符串后面所有配置都围绕它展开。这里有个关键决定Key 不放前端也不放 Cursor 的全局设置里而是放项目根目录的.env。原因有三点。一是 Cursor 的settings.json是编辑器级配置放 Key 容易在同步或分享时泄露二是 Streamlit 重启频繁环境变量注入不稳定三是.env配合python-dotenv读取最可控后端启动时加载一次前端完全不需要知道。如果你后面要做长期编码或 Agent 类任务可以了解下 Coding Plan地址是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。原型阶段先用按量 Key 就够了。3. 可复制配置settings.json 与 config.toml 骨架3.1 项目目录结构先定好在 Cursor 里打开项目后建议目录长这样后端和前端分开配置集中在根目录cursor_tide_fast/ ├── .env ├── .cursor/ │ └── settings.json ├── config.toml ├── requirements.txt ├── backend/ │ └── main.py └── frontend/ └── app.py.env只放一行注意不要提交到 gitTAOTOKEN_API_KEYsk-你的实际Key TAOTOKEN_BASE_URLhttps://taotoken.net/api3.2 Cursor 项目级 settings.jsonCursor 支持项目级配置放在.cursor/settings.json。这里不放 Key只放解释器路径和终端环境保证 Cursor 内置终端启动时能读到虚拟环境{ python.defaultInterpreterPath: ${workspaceFolder}/.venv/Scripts/python.exe, python.terminal.activateEnvironment: true, terminal.integrated.env.windows: { PYTHONPATH: ${workspaceFolder} }, files.exclude: { **/__pycache__: true, **/.venv: true } }python.terminal.activateEnvironment设为 true 后你在 Cursor 里新开终端会自动激活.venv不用每次手动敲激活命令。PYTHONPATH指向工作区根目录这样backend和frontend之间互相 import 不会报模块找不到。3.3 后端 config.toml 骨架config.toml放在项目根目录作为后端读取模型参数的唯一来源。Key 不写在这里只写通道和模型名[api] base_url https://taotoken.net/api timeout 60 max_retries 3 [model] default gpt-4o-mini temperature 0.7 max_tokens 2048 [server] host 127.0.0.1 port 8012这样设计的好处是换模型只改config.toml一行换 Key 只改.env一行两者互不干扰。后端启动时用tomllibPython 3.11 内置读取配合dotenv加载 Key。3.4 后端 main.py 读取配置import os import tomllib from pathlib import Path from dotenv import load_dotenv from fastapi import FastAPI from pydantic import BaseModel from openai import OpenAI load_dotenv() ROOT Path(__file__).resolve().parent.parent with open(ROOT / config.toml, rb) as f: cfg tomllib.load(f) client OpenAI( api_keyos.environ[TAOTOKEN_API_KEY], base_urlcfg[api][base_url], timeoutcfg[api][timeout], ) app FastAPI() class ChatIn(BaseModel): prompt: str app.post(/chat) def chat(body: ChatIn): resp client.chat.completions.create( modelcfg[model][default], messages[{role: user, content: body.prompt}], temperaturecfg[model][temperature], ) return {reply: resp.choices[0].message.content}注意base_url直接取自config.toml没有在代码里写死。这样前端永远只调http://127.0.0.1:8012/chat不接触任何模型 Key。3.5 前端 app.py 只调本地接口import streamlit as st import httpx st.title(TIDE DIARY 原型) prompt st.text_area(输入内容, height120) if st.button(发送) and prompt: with st.spinner(请求中...): r httpx.post( http://127.0.0.1:8012/chat, json{prompt: prompt}, timeout60, ) st.write(r.json().get(reply, 无返回))Streamlit 这边完全没有openai依赖也没有 Key。它只是一个 HTTP 客户端指向本地 FastAPI。这就是「统一通道」的落地方式。4. 三步动作启动 FastAPI、拉起 Streamlit、验证链路4.1 第一步启动 FastAPI 后端在 Cursor 里新开一个终端确认虚拟环境已激活然后启动python -m uvicorn backend.main:app --host 127.0.0.1 --port 8012 --reload看到Uvicorn running on http://127.0.0.1:8012就说明后端起来了。--reload让你改main.py后自动重启原型阶段很省事。如果端口被占用先查一下$tcp Get-NetTCPConnection -LocalPort 8012 -State Listen -ErrorAction SilentlyContinue | Select-Object -First 1 if ($tcp) { Stop-Process -Id $tcp.OwningProcess -Force }4.2 第二步拉起 Streamlit 前端再开一个终端窗口不要关掉后端那个streamlit run frontend/app.py --server.headlesstrue --server.port8501浏览器打开http://localhost:8501能看到输入框和按钮就对了。--server.headlesstrue避免它自动弹浏览器在 Cursor 里更干净。4.3 第三步验证请求链路先用 curl 直接打后端确认 FastAPI 到 TaoToken 这一段通curl -X POST http://127.0.0.1:8012/chat \ -H Content-Type: application/json \ -d {\prompt\:\用一句话解释什么是 FastAPI\}返回类似{reply:FastAPI 是一个基于 Python 类型注解的高性能 Web 框架。}就说明后端链路正常。然后再去 Streamlit 页面点一次按钮如果也能返回内容说明前端到后端这一段也通了。整条链路是Streamlit → FastAPI → TaoToken → 模型 → 原路返回。任何一段出问题都能通过这两次验证快速定位。5. 本篇常见错排查5.1 401 Unauthorized最常见的原因是.env没被加载。检查两点一是.env是否在项目根目录二是load_dotenv()是否在读取os.environ之前调用。如果 Key 复制时带了空格或换行也会 401建议重新复制一次。5.2 Connection refused 到 127.0.0.1:8012说明 FastAPI 没起来或者端口不对。先确认后端终端有没有报错再看config.toml里的port和启动命令的--port是否一致。Streamlit 里写死的地址也要跟这个端口对齐。5.3 Streamlit 报 ModuleNotFoundError多半是虚拟环境没激活或者PYTHONPATH没生效。在 Cursor 里确认终端提示符前面有(.venv)没有的话手动激活一次。项目级settings.json里的python.terminal.activateEnvironment就是解决这个的。5.4 模型名报错 model not foundconfig.toml里的default要写通道支持的模型名。如果换了模型名报错先用模型对话页面确认一下可用模型列表地址是 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。确认后再改config.toml。5.5 超时但没报错原型阶段请求大模型偶尔会慢config.toml里timeout 60是秒数。如果经常超时先确认网络到https://taotoken.net/api是否正常再考虑调大 timeout。Streamlit 那边的httpx.post也要设同样的 timeout否则前端先断。6. 配置收尾与后续接入这套骨架跑通后你手里其实有了一个可复用的模板.env管 Keyconfig.toml管通道和模型参数settings.json管编辑器环境FastAPI 做唯一出口Streamlit 只做展示。后面加新接口只需要在main.py里加路由前端继续用 httpx 调本地Key 和通道完全不用动。如果你要接着做更复杂的接入比如流式输出、多模型切换、或者把 FastAPI 接到别的客户端接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里面把 base_url、鉴权头、请求格式都列清楚了。Key 管理和新建都在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。最后提醒一个实操细节.env一定要加进.gitignoreCursor 的settings.json里也别放 Key。原型阶段图快但 Key 泄露的代价比省那几秒大得多。把 Key 留在后端、通道写进 config、前端只认本地端口这三条守住后面怎么改都不会乱。
企业数字化 ERP 产品动态
相关推荐
抄作业!我给OpenClaw设定的“数字员工”SOP,效率提升了10倍 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 10:53:18
Cursor 0.46+ 快捷键冲突排查:alt+leftarrow 隐藏问题与 TaoToken 配置骨架 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 10:53:12
Humanizer In.Eight API 详解:计算“8 个时间单位之后”的 Fluent Date 接口 开发工具 【免费下载链接】Humanizer Humanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities 项目地址: https://gitcode.com/gh_mirrors/hu/Humanizer 点击查看 免费下载 本文围… · 2026/9/25 11:28:39
归一化判别图嵌入实现TE过程故障诊断的MATLAB实践 1. 项目背景与问题定义1.1 TE 过程:从仿真平台到故障诊断标准测试床聊起工业过程故障诊断,绕不开的一个名字就是 TE 过程(Tennessee Eastman Process,田纳西-伊斯曼过程)。这个仿真平台最早是 Eastman 化学公司的研究人… · 2026/9/25 11:28:32
Comsol相场法模拟横观各向同性水力压裂:建模与实操 干水力压裂数值模拟这块儿,绕不开的话题就是相场法。这两年用 Comsol 做相场断裂的案例越来越多,但大多停留在各向同性介质,一旦碰上页岩、层状岩体这类横观各向同性介质,很多默认的设置就直接失灵了。这个项目就是一次完整的实战… · 2026/9/25 11:28:32
SCL编程实战:PLC结构化控制语言核心原理与工程规范 1. 为什么SCL不是“高级梯形图”,而是PLC逻辑的精密手术刀在博途(TIA Portal)生态里,提到SCL,很多人第一反应是:“哦,那个长得像Pascal的PLC语言”;更常见的误解是把它当成“梯形图&… · 2026/9/25 11:28:08
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37