FastAPI入门:一个浦东奶爸的深夜后端自救指南

AI产品手记
2026-03-06 06:27
阅读 1598

作者:两个娃的奶爸,坐标上海浦东,和女朋友合租在张江,房租3500(别笑,是合租两室一厅的次卧)


01. 凌晨2点,我还在改接口文档

上周五晚上11:47,小宝终于睡了——不是假睡,是真的闭眼打呼那种。我轻轻把手机塞回枕头底下,蹑手蹑脚走到客厅,打开那台服役三年的MacBook Air,屏幕亮起的瞬间,仿佛打开了另一个世界。

我的目标很朴素:用FastAPI搭个简单的AI Agent服务,支持Llama模型调用,顺便练练Prompt工程。

但现实是——我在和Swagger UI搏斗。

“为啥这个路径参数老是报422?”我一边敲代码一边小声嘀咕,生怕吵醒隔壁房间刚哄睡的大宝。女友从卧室探出头:“又搞你那个‘后端’?明天还要上班呢。”
“就半小时!”我嘴上这么说,心里清楚:今晚不搞定,下周项目评审又要被Java组的老王diss。

是的,我在一家传统金融公司做数据分析,月薪15k,技术栈主要是Pandas + SQL + Excel宏。但最近公司要搞“智能化转型”,老板拍板上AI Agent系统,而我们组——因为会Python——被临时抓壮丁,负责搭建后端服务。

问题是:我会Python,但我不会后端


02. 被Java组按在地上摩擦的日子

事情得从去年十月说起。

那天晨会,CTO宣布要开发一个“智能客服AI Agent”,能自动回答客户关于理财产品的疑问。技术选型会上,Java组的老王推了推眼镜:“后端肯定用Spring Boot,稳定、成熟、有生态。”

我弱弱举手:“能不能试试FastAPI?写起来快,还自带文档,而且我们数据团队都熟悉Python……”

会议室突然安静。老王冷笑一声:“FastAPI?玩具框架吧?扛得住高并发吗?有熔断限流吗?日志监控呢?”

我哑口无言。那一刻,我感觉自己像个拿着乐高积木冲进核电站的幼儿园小朋友。

结果可想而知:后端由Java组主导,我们数据团队只负责提供模型输出。但问题来了——他们要的接口格式极其复杂,光是JSON Schema就写了三页A4纸。每次改个字段,我都得重新跑测试、写文档、开评审会。

更糟的是,他们根本不理解什么叫“Prompt工程”。有一次,我提交了一个优化后的提示词模板,老王直接在Jira上批注:“这不是业务逻辑,别乱改输入格式。”

我差点当场裂开。

那段时间,我每天下班回家,看着两个孩子满地爬,脑子里全是RESTful API和HTTP状态码。女友看我状态不对,某天晚饭时认真问我:“要不要换个工作?或者……学点真本事?”

我沉默了很久,最后说:“我想自己搭个后端服务,证明Python也能干正事。”

于是,FastAPI成了我的救命稻草


03. FastAPI:奶爸的深夜第一行代码

我选FastAPI,不是因为它多牛,而是因为它简单到离谱

安装?一行命令:

pip install fastapi uvicorn

Hello World?

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"Hello": "浦东奶爸"}

运行?

uvicorn main:app --reload

浏览器打开 http://localhost:8000,Swagger UI 自动弹出来,连文档都不用写。

那一刻,我差点哭出来——这不就是我想要的吗?所见即所得,改完立刻生效,不用等Maven构建十年

但很快,现实又给我上了一课。


04. 接入Llama:当奶爸遇上大模型

我的目标很明确:做一个API,接收用户问题,用Llama模型生成回答,并允许通过参数调整Prompt。

但本地跑Llama?我的MacBook Air内存只有8G,光加载模型就得卡死。

解决方案:调用远程推理API(比如Together.ai或OpenRouter),或者用Ollama本地轻量部署。

我选择了后者,毕竟晚上11点后网络不太稳,远程调用容易超时。

装好Ollama,拉了个 llama3:8b 模型(占了20多G硬盘,心疼我那256G SSD),然后写了个调用函数:

import requests

def call_llama(prompt: str) -> str:
    response = requests.post(
        "http://localhost:11434/api/generate",
        json={
            "model": "llama3",
            "prompt": prompt,
            "stream": False
        }
    )
    return response.json()["response"]

接着,把FastAPI接口串起来:

from fastapi import FastAPI, HTTPException

app = FastAPI()

@app.post("/ask")
def ask_question(user_input: str):
    try:
        # 这里可以做Prompt工程!
        system_prompt = "你是一个专业理财顾问,请用简洁语言回答问题。"
        full_prompt = f"{system_prompt}\n\n用户问题:{user_input}"
        answer = call_llama(full_prompt)
        return {"answer": answer}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

跑起来!测试!

结果:小宝半夜惊醒,大哭不止。原来是我调试时不小心开了扬声器,LLM生成的回答声音太大……

但功能确实跑通了。那一刻,凌晨1:30,我靠在沙发上,啃着冷掉的泡面,心里有种说不出的爽——我居然真的做出了一个能工作的AI Agent后端


05. Prompt工程:不是魔法,是手艺

很多人以为Prompt工程就是随便写几句“请聪明一点回答”,其实完全不是。

在我的FastAPI服务里,Prompt是可配置的业务逻辑

比如,我可以加个参数控制回答风格:

@app.post("/ask")
def ask_question(user_input: str, tone: str = "professional"):
    tones = {
        "professional": "你是一个专业理财顾问",
        "friendly": "你是个亲切的邻居阿姨",
        "strict": "你是个严厉的财务总监"
    }
    system_prompt = tones.get(tone, tones["professional"])
    full_prompt = f"{system_prompt}\n\n用户问题:{user_input}"
    answer = call_llama(full_prompt)
    return {"answer": answer, "tone_used": tone}

这样一来,前端可以根据场景切换语气,而不需要改模型或重训。

这才是真正的Prompt工程——把提示词当成产品功能来设计,而不是玄学调参。


06. 和Java组的“和平共处”

两周后,我又在会议上提出:“我们的AI Agent后端可以用FastAPI独立部署,通过HTTP对接你们的Java服务。”

这次我没说“替代”,而是说“补充”。

老王皱眉:“稳定性怎么保证?”

我早有准备:“Uvicorn用Gunicorn+Uvicorn workers部署,Docker容器化,Prometheus监控,日志接入ELK——这些都有现成方案。而且,它只负责AI部分,核心交易还是走你们的Spring Boot。”

他沉默了几秒,点点头:“行,你先做个Demo,跑两周压测看看。”

我知道,这是突破口。

更让我惊喜的是,HR上周找我谈话,说公司考虑设立“AI工程岗”,问我想不想转岗,薪资可能涨到22k。

我和女友商量了一晚上。她说:“你要是真喜欢搞这个,就去。反正……两个娃我也能扛。”

我鼻子一酸。


07. 给同样挣扎的新手几点建议

如果你也像我一样:

  • 不是科班出身
  • 白天搬砖,晚上带娃
  • 想学后端但被Spring Boot吓退

那么,请听一个浦东奶爸的真心话:

✅ 别怕“玩具框架”

FastAPI不是玩具,它是现代Python后端的事实标准。Starlette + Pydantic 的组合,类型安全、自动文档、异步支持,该有的都有。

✅ 先跑起来,再优化

别一上来就想搞分布式、微服务。先把一个能工作的API跑通,哪怕只服务你一个人。完成比完美重要一万倍

✅ Prompt工程是产品思维

别把LLM当成黑盒。你的Prompt就是用户界面,是业务规则,是你可以控制的变量。

✅ Java不是敌人

承认吧,很多公司还是Java为主。但你可以用FastAPI做“边缘智能层”,和Java核心系统解耦。协作,不是取代

✅ 时间挤一挤总会有

我每天只有晚上11点到凌晨1点是自由时间。但这2小时,足够我写50行代码、读一篇文档、跑一次测试。持续的小进步,胜过一次性的大冲刺


08. 写在最后:技术人的尊严,不在框架,而在解决问题

有时候我会想:为什么我要在哄睡两个娃之后,还熬夜折腾FastAPI?

不是为了跳槽涨薪(虽然也不错),也不是为了和Java组较劲。

而是因为——我不想再当那个只能提需求、不能动手实现的人

在这个AI爆炸的时代,会调用LLM不算本事,能把AI变成可靠服务,才是工程师的价值。

FastAPI给了我这个机会。它简单、透明、不装逼,就像一个深夜陪我加班的朋友。

也许哪天,我的两个娃长大了,会问我:“爸爸,你当年做什么工作?”

我希望我能说:“我用Python,给世界写了几个有用的接口。”

——哪怕只是帮客户问清楚了一个理财产品的收益率。


附:我的极简FastAPI启动模板(奶爸亲测可用)

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import requests

app = FastAPI(title="AI Agent for Sleep-Deprived Dads")

class QueryRequest(BaseModel):
    question: str
    tone: str = "professional"

def generate_with_llama(prompt: str) -> str:
    try:
        resp = requests.post("http://localhost:11434/api/generate", 
                            json={"model": "llama3", "prompt": prompt, "stream": False},
                            timeout=30)
        return resp.json().get("response", "")
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"LLM error: {str(e)}")

@app.post("/ai/ask")
def ask_ai(req: QueryRequest):
    system_prompts = {
        "professional": "你是一名专业金融顾问。",
        "friendly": "你是一位热心邻居,用简单话解释。",
        "strict": "你是一名风控官,回答必须严谨。"
    }
    prompt = f"{system_prompts.get(req.tone, system_prompts['professional'])}\n\n问题:{req.question}"
    answer = generate_with_llama(prompt)
    return {"answer": answer, "used_tone": req.tone}

部署命令(Docker版下次再写,今晚小宝又醒了……)


作者备注:本文写于2024年6月15日凌晨1:23,浦东张江某小区次卧。孩子刚睡,代码刚跑通,泡面还没凉。如果你也在深夜coding,记得——你不是一个人。

评论 0

最热最新
暂无评论
AI产品手记Lv.1
0
影响力
0
文章
0
粉丝