ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

运维转型大模型全栈开发:FastAPI+Ollama实战踩坑与落地路径

运维转型大模型全栈开发:FastAPI+Ollama实战踩坑与落地路径 1. 从命令行到模型推理一个运维人的转型起点两年前我还在机房巡检、写Shell脚本、盯着Zabbix面板上的CPU曲线发呆。那时候我对“大模型”这三个字的理解大概就停留在“能聊天的东西”这个层面。直到有一次业务方提了个需求想把内部知识库做成问答接口我才第一次认真去翻Python的安装教程第一次在终端里敲下pip install fastapi。说实话那会儿连虚拟环境都没搞明白装个numpy库折腾了一下午最后发现是pip源的问题。这篇文章不是教程合集也不是什么转型励志故事。我想把这两年从系统运维切到大模型全栈开发过程中真正踩过的坑、真正跑通的链路、真正觉得“原来如此”的那些瞬间原原本本写出来。如果你也是运维出身或者刚接触Python和大模型想搞清楚一个完整的AI应用从后端到模型推理到底怎么串起来那这篇内容应该能帮你省掉不少搜索“fastapi项目目录结构”“fastapi调用ollama”“大模型微调实战”的时间。核心关键词就几个大模型、全栈开发、系统运维、Python、FastAPI。我会围绕这五个词把转型路径拆成可操作的模块每个模块都给出我实际用过的方案和参数。不保证是最优解但保证是跑通过的。2. 运维思维和开发思维到底差在哪2.1 从“保稳定”到“能迭代”的认知切换做运维的时候我的核心KPI是可用性。一台机器上线我关心的是它能不能扛住峰值、日志有没有地方存、挂了能不能自动拉起。这种思维惯性带到开发里第一个撞上的墙就是我总想把东西设计得“太稳”。比如写一个API接口我会花大量时间考虑异常捕获、重试机制、连接池大小结果业务逻辑本身反而写得潦草。后来带我的那个后端老哥说了一句话点醒我“运维是让已经跑起来的东西别停开发是让还没跑起来的东西先跑起来。”这句话听着简单但转换过来花了差不多三个月。具体到FastAPI项目里我开始学会先把路由跑通、把请求响应链路打通再去补中间件和监控。这个顺序反过来项目永远出不了第一版。2.2 工具链的重叠与迁移运维背景其实有个隐藏优势对Linux、网络、进程管理这些底层东西熟。这在部署大模型的时候特别明显。很多人卡在“ollama部署大模型”这一步是因为不熟悉systemd服务配置、不知道怎么看GPU显存占用、不会用nvidia-smi排查。而这些对我来说就是日常。但劣势也很明显Python的包管理、虚拟环境、依赖冲突这些“开发侧”的问题运维平时接触得少。我建议运维转型的第一步不是去学什么高级框架而是把python安装教程里最基础的那套流程走三遍官网下载、配置PATH、创建venv、pip安装、导出requirements.txt。听起来简单但真到项目里python安装numpy库的方法这种问题能卡住半天。2.3 一个具体的思维对照表维度运维思维开发思维转型后的平衡点代码质量能跑就行稳定优先可读、可测、可扩展先跑通再重构但接口定义要清晰部署方式手动配置记录文档自动化、容器化Docker Compose起步逐步上K8s日志处理集中收集告警为主结构化输出便于调试JSON日志uvicorn访问日志分离故障处理先恢复再排查先复现再修复保留现场加详细traceback学习路径广度优先啥都懂点深度优先啃透一个以项目驱动用到什么学什么这张表是我自己总结的不一定对所有人适用但至少反映了我从“盯着监控面板”到“盯着IDE调试器”的转变过程。3. Python和FastAPI为什么是这套组合3.1 选型背后的实际考量市面上Python后端框架不少Flask、Django、FastAPI各有拥趸。我选FastAPI不是因为它最流行而是因为三个很实际的原因。第一异步支持原生。大模型推理接口的响应时间通常比较长如果用同步框架一个请求占一个线程并发上来直接崩。FastAPI基于Starlette原生支持async/await配合uvicorn跑起来单机并发能力比Flask强不少。我实测过同一个推理接口Flask同步模式下10个并发就开始排队FastAPI异步模式下50个并发还能保持响应。第二自动生成API文档。FastAPI内置Swagger UI和ReDoc写完路由直接访问/docs就能看到交互式文档。这对前后端联调太重要了。以前用Flask还得手动维护接口文档现在只要类型注解写清楚文档自动生成。第三Pydantic模型校验。请求体和响应体的数据结构用Pydantic定义类型不对直接返回422省掉大量手写校验逻辑。而且Pydantic的模型定义和JSON Schema天然对应后面接大模型的结构化输出特别方便。3.2 FastAPI项目目录结构怎么搭网上搜“fastapi项目目录结构”能出来一堆方案我试过好几种最后稳定下来的结构是这样的project/ ├── app/ │ ├── __init__.py │ ├── main.py # 入口创建FastAPI实例 │ ├── config.py # 配置管理读环境变量 │ ├── models/ # Pydantic模型 │ │ ├── __init__.py │ │ ├── request.py │ │ └── response.py │ ├── routers/ # 路由层 │ │ ├── __init__.py │ │ ├── chat.py │ │ └── health.py │ ├── services/ # 业务逻辑层 │ │ ├── __init__.py │ │ ├── llm_service.py │ │ └── vector_service.py │ ├── utils/ # 工具函数 │ │ ├── __init__.py │ │ └── logger.py │ └── dependencies.py # 依赖注入 ├── tests/ ├── requirements.txt ├── Dockerfile └── docker-compose.yml这个结构的好处是分层清晰。routers只负责接收请求和返回响应services放真正的业务逻辑models定义数据结构。改一个功能通常只动一层不会牵一发动全身。3.3 安装和启动的实操细节fastapi安装本身很简单但有几个细节容易忽略# 创建虚拟环境 python -m venv venv source venv/bin/activate # Windows用 venv\Scripts\activate # 安装核心依赖 pip install fastapi uvicorn[standard] pydantic python-multipart # 如果要用到HTTP客户端调模型接口 pip install httpx # 导出依赖 pip freeze requirements.txt启动命令我一般用这个uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload--reload只在开发环境用生产环境一定要去掉否则文件变动会触发重启影响服务稳定性。另外--workers参数在多核机器上可以设置但注意如果用了内存缓存或者本地向量库多worker之间不共享状态需要额外处理。注意uvicorn fastapi 日志丢失问题是个高频坑。默认情况下uvicorn的访问日志和应用的logger输出可能会混在一起或者被截断。我的做法是在main.py里单独配置logging把uvicorn的logger和自定义logger分开并且设置propagateFalse避免重复输出。4. 大模型接入从API调用到本地部署4.1 免费大模型API和本地部署怎么选刚开始接触大模型的时候我图省事直接调免费API。搜“免费大模型api”能找到不少但实际用下来有几个问题一是速率限制严稍微频繁一点就429二是上下文长度有限长文档处理不了三是数据要传到别人服务器内部知识库场景不太合适。后来转向本地部署试过ollama部署大模型。Ollama的好处是安装简单一条命令拉模型自带OpenAI兼容接口。fastapi调用ollama也很直接用httpx发请求就行。但本地部署对硬件有要求7B参数的模型至少需要8GB显存13B以上建议16GB起步。如果机器没有独显用CPU推理速度会慢到怀疑人生。我的建议是开发调试阶段用免费API快速验证逻辑生产环境如果数据敏感就上本地部署如果对成本不敏感可以用云服务商的推理接口。企业大模型私有化部署现在也有不少成熟方案但那是另一个话题了。4.2 FastAPI调用Ollama的完整代码下面是我实际在用的一个简化版llm_service.pyimport httpx from typing import AsyncGenerator OLLAMA_BASE_URL http://localhost:11434 DEFAULT_MODEL qwen2.5:7b async def chat_completion( prompt: str, model: str DEFAULT_MODEL, stream: bool False ) - str | AsyncGenerator[str, None]: url f{OLLAMA_BASE_URL}/api/generate payload { model: model, prompt: prompt, stream: stream, options: { temperature: 0.7, top_p: 0.9, num_ctx: 4096 } } if stream: async def stream_generator(): async with httpx.AsyncClient(timeout120.0) as client: async with client.stream(POST, url, jsonpayload) as response: async for line in response.aiter_lines(): if line: yield line return stream_generator() else: async with httpx.AsyncClient(timeout120.0) as client: response await client.post(url, jsonpayload) response.raise_for_status() return response.json()[response]这里有几个参数值得说明。temperature控制随机性0.7适合通用对话做代码生成或者结构化输出时我会调到0.2。num_ctx是上下文窗口大小Ollama默认可能是2048处理长文档要调大但注意调太大会吃显存。timeout设120秒是因为本地模型首次加载或者长文本生成可能超过默认的30秒。4.3 流式输出的路由实现流式输出对用户体验影响很大尤其是大模型生成慢的时候。FastAPI的StreamingResponse配合异步生成器就能实现from fastapi import APIRouter from fastapi.responses import StreamingResponse from app.services.llm_service import chat_completion router APIRouter(prefix/chat, tags[chat]) router.post(/stream) async def chat_stream(prompt: str): generator await chat_completion(prompt, streamTrue) return StreamingResponse(generator, media_typetext/event-stream)前端用EventSource接收就能实现打字机效果。这里要注意media_type设成text/event-stream否则浏览器可能不会按SSE处理。5. 大模型微调和上下文管理5.1 什么时候需要微调“大模型微调”这个词现在被用得很泛。我的经验是大部分场景不需要微调。如果你只是想让模型按照特定格式输出、或者回答特定领域的问题用Prompt Engineering加上RAG检索增强生成就能解决。微调适合的是有大量标注数据、需要模型学习特定风格或术语、且推理时对延迟敏感的场景。微调技术本身分好几种LoRA、QLoRA、全量微调。LoRA最实用显存占用小训练速度快效果在多数场景下够用。我做过一次7B模型的LoRA微调单卡24GB显存跑了大概6小时数据量是5000条问答对。工具链用的是LLaMA-Factory配置写YAML命令行启动比手写训练循环省事很多。5.2 上下文长度管理的实际策略“大模型上下文长度”是个绕不开的问题。模型支持的上下文窗口有限但业务文档可能很长。我的处理策略分三层第一层是截断。最简单超过窗口就砍掉最早的内容。适合对话场景因为最近的对话最重要。第二层是摘要压缩。用模型自己把长文档摘要成短文本再把摘要放进上下文。适合文档问答但摘要本身会丢失细节。第三层是向量检索。把文档切块、向量化、存向量库查询时检索最相关的几块拼进上下文。这是RAG的标准做法也是目前最实用的方案。向量库我用的Chroma轻量、Python原生、和FastAPI集成简单。5.3 RAG链路的代码骨架import chromadb from chromadb.utils import embedding_functions class VectorService: def __init__(self, persist_dir: str ./chroma_db): self.client chromadb.PersistentClient(pathpersist_dir) self.embed_fn embedding_functions.DefaultEmbeddingFunction() self.collection self.client.get_or_create_collection( nameknowledge, embedding_functionself.embed_fn ) def add_documents(self, docs: list[str], ids: list[str]): self.collection.add(documentsdocs, idsids) def search(self, query: str, top_k: int 3) - list[str]: results self.collection.query(query_texts[query], n_resultstop_k) return results[documents][0]检索到的文档块拼进Prompt里再发给大模型生成回答。这个链路跑通之后内部知识库问答的准确率比纯Prompt方式高出一大截。6. 部署、打包和常见问题排查6.1 FastAPI在Windows上的打包“fastapi windows 打包”是个搜索量挺高的问题。如果只是内部工具用PyInstaller打包成exe就行。但要注意几个点uvicorn的reload模式在打包后不能用静态文件和模板路径要用sys._MEIPASS处理如果依赖里有C扩展比如numpy、cv2打包体积会比较大。我的做法是生产环境直接用DockerWindows上装Docker Desktopdocker-compose up一键起服务。Dockerfile大概长这样FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY ./app ./app EXPOSE 8000 CMD [uvicorn, app.main:app, --host, 0.0.0.0, --port, 8000, --workers, 2]--workers 2是因为我的向量库是本地文件多worker会有并发写问题所以控制在2个。如果向量库换成远程服务worker数可以按CPU核数来设。6.2 常见问题速查表问题现象可能原因排查方法解决方案启动报ModuleNotFoundError依赖没装或虚拟环境不对pip list确认包存在激活正确venv重装依赖接口返回422请求体不符合Pydantic模型看/docs里的Schema定义调整请求参数或放宽模型校验调用Ollama超时模型加载慢或显存不足nvidia-smi看显存Ollama日志看加载进度增大timeout换小模型或加显存流式输出中断客户端断开或服务端异常看uvicorn日志和浏览器Network面板加异常捕获设置合理keep-alive日志重复输出logger传播导致检查propagate设置设propagateFalse单独配handler并发上不去同步阻塞或worker太少压测看响应时间曲线改异步加worker上负载均衡6.3 几个踩过的坑第一个坑是uvicorn日志丢失。现象是应用里logger.info的输出在终端看不到或者只看到一部分。原因是uvicorn自己配置了logging把root logger的handler覆盖了。解决方法是main.py里在创建app之前先配置好logging并且给uvicorn的logger单独设置handler。第二个坑是Ollama首次调用特别慢。模型加载到显存需要时间第一次请求可能等几十秒。我的做法是在服务启动时发一个预热请求让模型提前加载。虽然启动时间长了但用户第一次请求的体验好很多。第三个坑是向量库并发写冲突。Chroma的PersistentClient在多进程下写同一个目录会报错。如果非要多worker要么换客户端-服务端模式要么把写操作集中到一个worker里。7. 全栈开发还需要补哪些课7.1 前端不用精通但得能看懂全栈开发不代表前后端都要写到专家级别。我的前端水平大概就是能改Vue组件、能看懂React Hooks、能用fetch调接口。但这就够了。大模型应用的前端通常不复杂一个聊天界面、一个文件上传、一个结果展示用现成的UI库拼一拼就行。关键是理解前后端交互的协议。比如SSE流式输出前端要知道怎么用EventSource接收文件上传要知道用FormData跨域要知道配CORS中间件。这些在FastAPI里都有现成方案fastapi.middleware.cors.CORSMiddleware加几行配置就能解决。7.2 数据库和缓存按需学不是所有大模型应用都需要数据库。如果只是问答接口可能连数据库都不用。但如果要做对话历史、用户管理、文档管理那就得上。我的建议是从SQLite起步够用且零配置。需要并发再换PostgreSQL需要缓存再加Redis。不要一上来就搞一套微服务架构运维出身的人容易犯这个毛病总想把基础设施搭得完美结果业务代码没写几行。7.3 持续学习的方向大模型这个领域变化太快今天学的API明天可能就变了。我的策略是抓不变的东西HTTP协议、异步编程模型、数据结构、向量检索原理。这些底层知识不会过时。上层的框架和工具用到什么学什么不用追新。具体到学习资源Python官方文档和FastAPI官方文档是最好的起点。大模型基础理论可以看一些公开课但不用钻太深除非你要做训练。多数应用开发者需要的是“会用”而不是“会造”。8. 一些实际项目中的经验体会转型这两年最大的感受是运维背景不是包袱是差异化优势。当大家都在讨论模型效果的时候你能把服务部署得稳稳当当当别人还在本地调不通环境的时候你已经用Docker把整套链路容器化了。这些看起来“不AI”的技能在实际项目里恰恰是让AI落地的东西。另一个体会是不要等学完再做。我见过太多人卡在“Python入门”阶段教程看了一堆实际项目一个没跑。正确的路径是反过来先定一个最小目标比如“做一个能调用本地模型的问答接口”然后缺什么补什么。装Python遇到问题就搜“python安装教程”调Ollama报错就搜“fastapi调用ollama”这种问题驱动的学习效率比系统学习高得多。最后分享一个我常用的调试技巧在FastAPI里加一个/debug路由返回当前环境变量、Python版本、关键依赖版本、模型服务连通状态。部署到新环境时先访问这个接口能快速定位是环境问题还是代码问题。这个习惯帮我省了很多排查时间。
返回列表