ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

langchain入门笔记03:用FastAPI把本地大模型封装成局域网接口,TaoToken统一Key接入与响应提速实录

langchain入门笔记03:用FastAPI把本地大模型封装成局域网接口,TaoToken统一Key接入与响应提速实录 1. 从本地脚本到局域网服务我踩过的第一个坑如果你已经用 LangChain 把本地大模型跑通了下一步大概率会想能不能让同一局域网里的手机、平板、同事的电脑都能调用这个模型这就是把「本地脚本」升级成「局域网接口服务」的过程。核心检索词就三个langchain 负责编排 RAG 链路fastapi 负责把链路暴露成 HTTP 接口局域网负责让多端设备访问。适合谁适合已经能在本机跑通 Ollama 或 vLLM、想让团队共享问答能力、又不想把数据发到公网的开发者。我最初的做法很朴素写个chat.pyuvicorn.run(host127.0.0.1)本机curl一切正常。结果同事用手机连过来直接超时。原因就一个127.0.0.1只监听回环地址局域网其他设备根本看不到这个端口。改成0.0.0.0之后能连上了但新的问题来了——首字延迟 5 秒起步三个人同时提问直接排队到 30 秒开外。这篇笔记就围绕「接口骨架 → 并发参数 → 统一 Key 通道 → 压测验证」这条链路把延迟和吞吐调到能感知的改善。需要先明确一个边界本文讲的是局域网内自建后端不涉及任何跨境网络工具。如果你需要统一管理多个模型供应商的 Key、或者想让本地服务和云端模型走同一套调用规范可以用 TaoToken 做统一入口后面第 2 节会给出具体配置。2. TaoToken 前置统一 Key 与 API 通道准备2.1 为什么要在本地服务里引入统一 Key本地大模型有个现实问题模型一多调用方式就乱。Ollama 走http://localhost:11434vLLM 走http://localhost:8090/v1云端模型又是另一套鉴权和地址。LangChain 虽然能用ChatOllama、ChatOpenAI分别适配但每换一个模型就要改一次代码配置散落在各处。TaoToken 在这里的角色是「统一 Key 统一 API 通道」你拿到一个 Key通过兼容 OpenAI 协议的接口去调用不同模型LangChain 侧只需要改base_url和model两个字段。这样本地 vLLM 服务和云端模型可以共用同一套settings.json结构切换时不用动业务代码。2.2 获取 Key 与确认接入信息先到控制台创建 API Key建议按项目命名方便后续轮换控制台入口https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteAPI Key 管理https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteAPI 基础地址统一用https://taotoken.net/api这个地址不加 UTM 参数直接写进配置即可。拿到 Key 后不要硬编码进 Python 文件放进环境变量或独立的settings.json后面第 3 节会给完整骨架。注意Key 只用于服务端调用不要写进前端 JS 或提交到 Git 仓库。局域网服务虽然在内网但配置文件仍建议加进.gitignore。2.3 本地模型与统一通道的分工我的实际做法是分层本地 vLLM 负责高频、大上下文的 RAG 问答走http://0.0.0.0:8090/v1TaoToken 通道负责需要更强推理、或者本地显存不够时的兜底模型。两者在 LangChain 里都是ChatOpenAI兼容对象只是base_url不同。这样接口层完全不用感知底层是本地还是远端只认统一的model名称。3. 可复制配置config.toml 与 settings.json 骨架3.1 项目目录结构先把目录定下来避免后面路径混乱llm-lan-server/ ├── app/ │ ├── __init__.py │ ├── main.py # FastAPI 入口 │ ├── chains.py # LangChain RAG 链路 │ └── schemas.py # 请求/响应模型 ├── config/ │ ├── config.toml # 服务与并发参数 │ └── settings.json # Key 与模型通道 ├── data/ │ └── docs/ # RAG 原始文档 └── requirements.txt3.2 config.toml并发与超时参数config.toml放服务级参数重点是 worker 数量、超时和流式开关[server] host 0.0.0.0 port 8080 workers 2 reload false [llm] request_timeout 120 max_concurrency 8 stream true num_predict 512 [rag] top_k 4 chunk_size 500 chunk_overlap 80workers 2是实测下来比较稳的值单 worker 在流式输出时容易阻塞2 个 worker 能覆盖局域网 5 到 8 人并发。max_concurrency控制同时打到模型的请求数超过就排队避免显存被打爆。3.3 settings.json统一 Key 与模型通道settings.json放敏感信息和模型映射结构如下{ default_channel: local, channels: { local: { base_url: http://127.0.0.1:8090/v1, api_key: EMPTY, model: Qwen3-30B }, taotoken: { base_url: https://taotoken.net/api, api_key: sk-你的Key, model: claude-sonnet-4-5 } } }本地 vLLM 的api_key填EMPTY即可它不校验TaoToken 通道填真实 Key。LangChain 侧读取时统一构造import json from langchain_openai import ChatOpenAI with open(config/settings.json, r, encodingutf-8) as f: settings json.load(f) def build_llm(channel_name: str None): name channel_name or settings[default_channel] cfg settings[channels][name] return ChatOpenAI( base_urlcfg[base_url], api_keycfg[api_key], modelcfg[model], timeout120, streamingTrue, )这样切换通道只改default_channel一个字段业务代码零改动。3.4 FastAPI 入口与流式接口app/main.py里把 RAG 链路和流式响应接起来import time import logging from fastapi import FastAPI, Request from fastapi.responses import StreamingResponse, JSONResponse from app.chains import build_rag_chain app FastAPI(titleLAN LLM Server) rag_chain build_rag_chain() app.post(/chat/rag) async def chat_rag(request: Request): start time.time() data await request.json() question data.get(message, ).strip() if not question: return JSONResponse(status_code400, content{error: empty message}) async def event_stream(): first_token_at None async for chunk in rag_chain.astream(question): if first_token_at is None: first_token_at time.time() logging.info(f首字延迟: {first_token_at - start:.2f}s) yield chunk logging.info(f总耗时: {time.time() - start:.2f}s) return StreamingResponse(event_stream(), media_typetext/plain)关键点用astream而不是ainvoke首字延迟能压到 1 秒内StreamingResponse让前端边生成边显示体感速度提升明显。4. 启动与验证curl 压测看真实数据4.1 启动命令开发阶段用 reload生产去掉uvicorn app.main:app --host 0.0.0.0 --port 8080 --workers 2如果要用config.toml驱动可以写个run.py读取配置再调uvicorn.run。启动后先确认监听地址ss -tlnp | grep 8080看到0.0.0.0:8080才算局域网可达。4.2 单次请求验证准备data.json{message: 公司出差住宿费标准是多少}用 curl 测流式响应curl.exe -X POST -N http://10.1.1.199:8080/chat/rag \ -H Content-Type: application/json \ -d data.json-N关闭缓冲能实时看到 token 逐个返回。实测首字延迟在 0.8 到 1.2 秒之间总耗时取决于答案长度。4.3 局域网多端并发对比单请求好看不代表并发好看。用hey或ab做压测hey -n 20 -c 5 -m POST \ -H Content-Type: application/json \ -d {message:出差住宿费标准} \ http://10.1.1.199:8080/chat/rag对比方法先测workers1再测workers2记录 P95 延迟。我这边workers1时 5 并发 P95 约 28 秒workers2降到 16 秒左右。如果并发再高瓶颈会转移到模型推理本身这时候要么加显存要么把部分请求分流到 TaoToken 通道。提示压测时观察nvidia-smi如果显存利用率长期 95% 以上说明max_concurrency设高了适当下调。5. 本篇常见错排查5.1 局域网设备连不上症状本机 curl 正常手机访问超时。排查顺序先确认host是0.0.0.0不是127.0.0.1再确认系统防火墙放行了 8080 端口最后确认手机和服务器在同一网段用ping验证。Windows 上还要注意「专用网络」和「公用网络」的防火墙规则是分开的。5.2 首字延迟高但总耗时正常症状等了 5 秒才出第一个字之后很快。原因通常是没用流式或者 LangChain 链路里retriever是同步阻塞的。检查两点接口是否用了StreamingResponse检索器是否用了ainvoke而不是invoke。把检索和生成都改成异步首字延迟能砍掉一大半。5.3 并发一高就报连接错误症状单请求正常5 并发开始出现Connection reset或超时。多半是 worker 数不够或模型侧排队。先把workers调到 2 到 4再检查max_concurrency是否超过显存承受能力。如果本地模型确实扛不住把非核心请求切到 TaoToken 通道用build_llm(taotoken)分流。5.4 Key 读取失败或 401症状本地通道正常切到 TaoToken 通道报鉴权错误。检查settings.json里base_url是否写成https://taotoken.net/api不要带多余路径Key 是否有多余空格。如果 Key 刚创建确认没有复制错行。接入细节以官方文档为准https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite5.5 流式输出被截断症状答案只输出一半就停了。检查num_predict是否设得太小512对大多数问答够用但长文档总结要调到1024以上。另外确认前端没有对响应做缓冲curl -N和浏览器fetch的ReadableStream都要关掉中间层缓冲。6. 下一步把通道和 Key 管起来接口跑通之后真正影响长期体验的是「通道管理」和「Key 轮换」。我的建议是本地 vLLM 作为主力通道承担高频 RAG 问答TaoToken 作为统一 Key 通道承担模型切换和兜底。需要验证不同模型效果时直接到模型对话页面对比输出质量https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite如果你打算把这个后端接到长期运行的编码助手或 Agent 工作流里按量调用不如用 Coding Plan 更省心https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite最后留一个我实测有效的调优顺序先把host改对让局域网可达再开流式把首字延迟压下来然后调workers和max_concurrency扛并发最后用统一 Key 通道解决模型切换。这四步做完局域网问答的体感会有质的变化。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进