第13章:AI异步与生产部署 —— 让 AI 服务稳定高效地面向用户

本章定位:解决「AI 功能写好了,但无法面向用户」这个从开发到生产最关键的跨越。

核心主题 :用三项技术 解决三个具体问题,让你的 AI 服务能支撑真实用户访问。


前期回顾

AI入门开发系列文章合集


开篇:一个真实困境

你花了几周时间,终于用 LangChain 搭好了一个 AI 问答机器人。本地运行一切正常:输入问题,等待 2 秒,得到答案。

然后你把它部署到服务器,迎来了第一批用户------

用户 A 发来问题,等了 2 秒,得到答案。😊

用户 B、C、D 同时 发来问题......用户 B 等了 2 秒,用户 C 等了 4 秒,用户 D 等了 6 秒。😡

用户 E 问了一个「什么是 Python 装饰器」------这个问题你的系统今天已经回答了 500 次,每次都花 2 秒、调用 1 次付费 API。💸

前端同学想接入你的 AI,问你 API 地址,你愣了:我是个 Python 脚本,没有 API......😅

这三个场景,浓缩了 AI 服务从"能跑"到"能用"之间的三道坎:

问题 现象 根本原因
多用户并发慢 10 个用户排队等,第 10 个等 20 秒 同步调用:一次只能处理一个请求
无法对外提供服务 前端/App/其他系统无法调用 AI 没有 HTTP API,只是个脚本
重复调用浪费钱 同一个问题每天调用 1000 次 没有缓存,每次都去调用付费 API

本章的目标,就是用三项技术逐一解决这三个问题,最终搭出一个可以真正面向用户的生产级 AI 服务


本章你将学到

  • 异步(async/await):让 10 个并发请求从等待 20 秒变成等待 2 秒
  • FastAPI:用 20 行代码把 AI 能力封装成任何客户端都能调用的 REST API
  • LLM 缓存:让重复问题 0 延迟、0 费用,把 API 成本降低 30-70%
  • 三者整合:搭建完整的生产级 AI 服务架构

前置条件

要求 说明
Python 版本 3.10+
已完成章节 第1章(LLM 基础调用)、第3章(Chain 链式调用)
环境变量 DASHSCOPE_API_KEY 已配置
安装依赖 uv sync(基础)、uv sync --extra api(FastAPI 端点)

全局架构:三项技术如何协作

在深入每项技术之前,先看清楚它们共同构成的完整系统:

读图方式

  • 用户请求进入 FastAPI(解决"可被调用"问题)
  • FastAPI 先检查 缓存(解决"重复调用"问题)
  • 缓存未命中,用 异步 方式调用 LLM(解决"并发慢"问题)

三项技术各司其职,串联成完整的服务链路。


一、问题一:并发慢 → 用异步解决

1.1 同步调用为什么慢?

LLM API 的调用分为两个阶段:

  1. 网络 I/O 等待:发送请求、等服务器响应(~95% 的时间)
  2. CPU 计算:解析响应、处理数据(~5% 的时间)

同步调用的问题是:在等待网络 I/O 期间,线程什么也做不了,只是阻塞地等待:

ini 复制代码
同步处理 4 个请求(每个 2 秒):

时间轴 →  0s         2s         4s         6s         8s
请求1:     [───等待 LLM 响应───]✓
请求2:                           [───等待───]✓
请求3:                                       [───等待───]✓
请求4:                                                   [───等待───]✓
总耗时:8 秒(4 × 2秒)

1.2 异步调用如何提速?

异步(async/await)的核心思想:等待期间,不是发呆,而是去处理其他请求

ini 复制代码
异步处理 4 个请求(每个 2 秒):

时间轴 →  0s                     2s
请求1:     [───发出,等待响应─────]✓
请求2:     [───发出,等待响应─────]✓  ← 同时发出!
请求3:     [───发出,等待响应─────]✓
请求4:     [───发出,等待响应─────]✓
总耗时:~2 秒(≈ 最慢的那一个)

提速原理 :4 个请求同时发出,同时在"等",但等待是交错的------等待期间线程会切换去处理其他协程。这正是 Python asyncio 事件循环干的事。

1.3 Python asyncio 三个核心概念(速览)

理解异步只需要掌握三个概念:

python 复制代码
# ① async def ------ 定义一个"可以暂停的函数"(协程)
async def fetch_answer(question: str) -> str:
    response = await llm.ainvoke(question)   # ← await 是暂停点
    return response.content

# ② await ------ "暂停当前函数,让出控制权,等待结果"
#   只能在 async def 内部使用
#   在等待期间,事件循环可以去执行其他协程

# ③ asyncio.gather() ------ "同时执行多个协程,等所有都完成"
async def main():
    results = await asyncio.gather(
        fetch_answer("问题1"),   # 三个协程同时运行
        fetch_answer("问题2"),
        fetch_answer("问题3"),
    )
    return results

# asyncio.run() ------ 同步代码进入异步世界的入口
answers = asyncio.run(main())

1.4 LangChain 异步 API 完整对照表

LangChain 所有调用方法都有对应的异步版本,用法完全相同:

同步方法 异步对应 适用场景
llm.invoke(msg) await llm.ainvoke(msg) 单个请求,需要完整响应
llm.stream(msg) async for chunk in llm.astream(msg) 流式输出,打字机效果
chain.batch(inputs) await chain.abatch(inputs) 批量并发处理多条数据

1.5 代码实战:性能对比

代码文件:lessons/13_production/01_async_llm.py

python 复制代码
import asyncio
import os
import time
from typing import Optional

from langchain_core.messages import HumanMessage
from langchain_openai import ChatOpenAI
from dotenv import load_dotenv

load_dotenv()

llm = ChatOpenAI(
    model="qwen-plus",
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    temperature=0.3,
)

# ── 同步版本:逐个等待,串行执行 ────────────────────────────────
def sync_batch(questions: list[str]) -> list[str]:
    """同步处理:每个问题等待完成,才处理下一个。"""
    results = []
    for q in questions:
        response = llm.invoke([HumanMessage(content=q)])  # 阻塞 2 秒
        results.append(response.content[:50])
    return results

# ── 异步版本:同时发出所有请求 ──────────────────────────────────
async def async_batch(questions: list[str]) -> list[str]:
    """异步并发:同时发出所有请求,等最慢的那个返回。"""

    async def one(q: str) -> str:
        response = await llm.ainvoke([HumanMessage(content=q)])  # 非阻塞
        return response.content[:50]

    results = await asyncio.gather(*[one(q) for q in questions])
    return list(results)

# ── 测试 ────────────────────────────────────────────────────────
questions = [
    "用一句话介绍 Python",
    "用一句话介绍 LangChain",
    "用一句话介绍向量数据库",
    "用一句话介绍 Transformer",
]

print(f"处理 {len(questions)} 个问题\n")

t0 = time.time()
sync_batch(questions)
print(f"同步耗时:{time.time() - t0:.2f}s")   # 预期 ~8 秒

t0 = time.time()
asyncio.run(async_batch(questions))
print(f"异步耗时:{time.time() - t0:.2f}s")   # 预期 ~2 秒

实测结果参考(因网络状况而异):

并发数 同步耗时 异步耗时 提速倍数
4 个请求 ~8 秒 ~2 秒 4x
10 个请求 ~20 秒 ~2-3 秒 7-10x
翻译 50 条 ~100 秒 ~5-8 秒 12-20x

1.6 生产必备:超时控制 + 并发限制

直接 asyncio.gather 有两个生产问题:

  • 没有超时限制:一个慢请求会"拖死"整批任务
  • 没有并发限制:100 个请求同时发出,可能触发 API 速率限制(429 错误)
python 复制代码
async def safe_invoke(question: str, timeout: float = 15.0) -> Optional[str]:
    """带超时控制的安全调用------生产环境必须使用这个版本。"""
    try:
        # asyncio.wait_for:超过 timeout 秒则抛 asyncio.TimeoutError
        response = await asyncio.wait_for(
            llm.ainvoke([HumanMessage(content=question)]),
            timeout=timeout,
        )
        return response.content
    except asyncio.TimeoutError:
        print(f"  ⏰ 超时(>{timeout}s):{question[:30]}...")
        return None
    except Exception as e:
        print(f"  ❌ 调用失败:{e}")
        return None


async def batch_with_limit(
    questions: list[str],
    max_concurrent: int = 5,   # 同时最多 5 个请求
) -> list[Optional[str]]:
    """带并发限制的批量处理------防止触发 API 速率限制。"""
    # Semaphore(信号量):控制同时持有"通行证"的协程数量上限
    semaphore = asyncio.Semaphore(max_concurrent)

    async def one_with_sem(q: str) -> Optional[str]:
        async with semaphore:     # 获取通行证(超限则排队等)
            return await safe_invoke(q)
        # with 块结束自动释放通行证,下一个排队协程可以进来

    return list(await asyncio.gather(*[one_with_sem(q) for q in questions]))

1.7 流式输出:打字机效果

python 复制代码
async def stream_response(question: str) -> None:
    """流式输出:边生成边显示,不用等全部完成才显示。"""
    print("回答:", end="", flush=True)
    async for chunk in llm.astream([HumanMessage(content=question)]):
        # 每个 chunk 是 1-3 个字符,end="" 不换行,flush=True 立即刷新
        print(chunk.content, end="", flush=True)
    print()  # 结束换行

asyncio.run(stream_response("用 100 字介绍什么是 RAG"))

二、问题二:无法被调用 → 用 FastAPI 解决

2.1 为什么需要 API?

异步解决了并发问题,但你的 AI 还只是个 Python 脚本。

前端工程师用 React,他们不能 import 你的 Python 模块。移动 App 用 Swift / Kotlin,同样无法调用 Python 代码。其他后端服务要接入你的 AI 能力,也需要一个标准接口。

解决方案:将 AI 能力封装为 HTTP API。

HTTP API 是互联网通信的通用语言------任何语言、任何平台,只要能发 HTTP 请求,就能调用你的 AI。

2.2 FastAPI 是什么?为什么选它?

FastAPI 是 Python 最流行的现代 Web 框架,三个核心优势让它特别适合 AI 服务:

特性 说明 AI 服务的价值
原生异步 基于 Python asyncio,天然支持 async def 与 LangChain 异步 API 无缝结合
自动文档 访问 /docs 自动生成可交互的 Swagger UI 无需手写 API 文档
Pydantic 校验 请求/响应自动类型校验和转换 防止非法输入崩溃 AI 服务

2.3 SSE(Server-Sent Events):流式输出的标准协议

普通 HTTP 请求是"问-答"模式:发请求 → 等完整响应。但 AI 流式输出需要"持续推送":服务端边生成边推送文字片段。

SSE(Server-Sent Events) 正是为此设计的:浏览器/客户端发起一个 HTTP 连接,服务端通过这个连接持续推送数据片段,直到发送结束信号。ChatGPT 的打字机效果用的就是 SSE。

2.4 完整 FastAPI 应用代码

代码文件:lessons/13_production/02_fastapi_app.py

python 复制代码
import asyncio
import os
from typing import AsyncGenerator, Optional

import uvicorn
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse
from langchain_core.messages import HumanMessage, SystemMessage
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field
from dotenv import load_dotenv

load_dotenv()

# ── FastAPI 应用初始化 ─────────────────────────────────────────
app = FastAPI(
    title="AI 问答服务",
    description="基于 LangChain + 阿里云百炼 的 AI 问答 API",
    version="1.0.0",
)

# CORS 中间件:允许浏览器跨域调用(生产环境应替换 * 为具体域名)
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# ── LLM 工厂(每次请求动态创建,支持按请求自定义 temperature)─
def create_llm(temperature: float = 0.7) -> ChatOpenAI:
    api_key = os.getenv("DASHSCOPE_API_KEY")
    if not api_key:
        raise ValueError("DASHSCOPE_API_KEY 环境变量未设置")
    return ChatOpenAI(
        model="qwen-plus",
        base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
        api_key=api_key,
        temperature=temperature,
    )

# ── Pydantic 请求/响应模型(自动校验输入,防止非法参数)────────
class ChatRequest(BaseModel):
    message: str = Field(..., description="用户消息", min_length=1, max_length=4000)
    system_prompt: Optional[str] = Field(
        default="你是一个有帮助的 AI 助手,请用中文回答。",
        description="系统提示词",
    )
    temperature: float = Field(default=0.7, ge=0.0, le=2.0)

class ChatResponse(BaseModel):
    answer: str = Field(description="AI 的回答")
    model: str = Field(description="使用的模型")

# ── 端点一:健康检查(监控/负载均衡探针使用)──────────────────
@app.get("/health")
async def health_check() -> dict:
    """返回服务状态,用于 Kubernetes 就绪探针或负载均衡健康检查。"""
    return {
        "status": "healthy",
        "llm_configured": bool(os.getenv("DASHSCOPE_API_KEY")),
    }

# ── 端点二:标准聊天(等待完整回答)──────────────────────────
@app.post("/chat", response_model=ChatResponse)
async def chat(request: ChatRequest) -> ChatResponse:
    """等待 LLM 生成完整回答后返回。
    
    适用:需要完整答案后再处理的场景(如结果分析、格式化输出)。
    """
    try:
        llm = create_llm(temperature=request.temperature)
        response = await llm.ainvoke([
            SystemMessage(content=request.system_prompt or "你是一个有帮助的 AI 助手。"),
            HumanMessage(content=request.message),
        ])
        return ChatResponse(answer=response.content, model="qwen-plus")
    except ValueError as e:
        raise HTTPException(status_code=500, detail=str(e)) from e
    except Exception as e:
        raise HTTPException(status_code=502, detail=f"LLM 调用失败: {str(e)}") from e

# ── 端点三:流式聊天(SSE 逐字推送)──────────────────────────
@app.post("/chat/stream")
async def chat_stream(request: ChatRequest) -> StreamingResponse:
    """以 SSE 格式逐块推送 AI 回答,实现打字机效果。
    
    适用:交互式聊天界面,长文本生成,需要减少首字节延迟的场景。
    
    SSE 数据格式(每行):data: <内容>\\n\\n
    结束信号:data: [DONE]\\n\\n
    """
    async def generate() -> AsyncGenerator[str, None]:
        try:
            llm = create_llm(temperature=request.temperature)
            messages = [
                SystemMessage(content=request.system_prompt or "你是一个有帮助的 AI 助手。"),
                HumanMessage(content=request.message),
            ]
            async for chunk in llm.astream(messages):
                if chunk.content:
                    # SSE 标准格式:每条消息以 "data: " 开头,以 "\n\n" 结尾
                    yield f"data: {chunk.content}\n\n"
            yield "data: [DONE]\n\n"
        except Exception as e:
            yield f"data: [ERROR] {str(e)}\n\n"

    return StreamingResponse(
        generate(),
        media_type="text/event-stream",
        headers={
            "Cache-Control": "no-cache",    # 禁止代理缓存
            "X-Accel-Buffering": "no",      # 禁止 Nginx 缓冲(确保实时推送)
        },
    )

# ── 启动服务 ──────────────────────────────────────────────────
if __name__ == "__main__":
    print("🚀 AI 问答服务启动中...")
    print("   文档地址:http://localhost:8000/docs")
    uvicorn.run(app, host="0.0.0.0", port=8000, log_level="info")

2.5 测试你的 API

bash 复制代码
# 1. 安装依赖
uv sync --extra api

# 2. 启动服务
python 02_fastapi_app.py

# 3. 浏览器打开 http://localhost:8000/docs (Swagger UI)

# 4. 命令行测试------标准聊天
curl -X POST http://localhost:8000/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "用一句话介绍 RAG 技术"}'

# 5. 命令行测试------流式聊天(--no-buffer 禁用 curl 的输出缓冲)
curl -X POST http://localhost:8000/chat/stream \
  -H "Content-Type: application/json" \
  -d '{"message": "详细介绍一下 Python 的异步编程"}' \
  --no-buffer

预期输出(流式接口):

kotlin 复制代码
data: Python
data: 的
data: 异步
data: 编程
data: 基于
data: asyncio
...
data: [DONE]

三、问题三:重复调用浪费 → 用缓存解决

3.1 重复调用有多浪费?

先用数字说话:

arduino 复制代码
场景:一个 FAQ 问答系统,用户每天问 10,000 个问题
其中 30% 是重复问题(如"什么是 Python"被问了 3,000 次)

没有缓存:
  10,000 次 × 0.01元/次 = 100元/天
  其中 3,000 次重复调用 = 30元/天(纯浪费)

有缓存:
  第一次问"什么是 Python":调用 LLM(0.01元)
  后续 2,999 次:命中缓存(0元,0延迟)
  节省:2,999 × 0.01 = 29.99元/天

一年下来:29.99 × 365 ≈ 11,000 元

缓存的价值不只是省钱,命中缓存的响应时间从 ~2000ms 降至 ~1ms------用户完全感知不到延迟。

3.2 LangChain 缓存的工作原理

ini 复制代码
缓存键 = hash(模型名称 + 提示词 + temperature)
            ↓
相同模型 + 相同问题 + 相同 temperature = 相同 key = 命中缓存

注意:temperature > 0 时,同一问题每次输出不同,
      缓存的意义是保证"第二次问同样的问题,返回第一次的答案"
      仅适合 temperature=0 的确定性场景

开启缓存只需一行代码,之后所有 LLM 调用自动使用缓存,无需修改业务代码:

python 复制代码
from langchain_core.globals import set_llm_cache
set_llm_cache(InMemoryCache())   # 这一行之后,所有 llm.invoke() 自动缓存

3.3 两种内置缓存选型

方案 A:InMemoryCache(开发/测试首选)

python 复制代码
# 进程内存缓存------重启后失效,适合开发调试
import os
import time
from langchain_core.globals import set_llm_cache
from langchain_community.cache import InMemoryCache
from langchain_core.messages import HumanMessage
from langchain_openai import ChatOpenAI
from dotenv import load_dotenv

load_dotenv()

llm = ChatOpenAI(
    model="qwen-plus",
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    temperature=0,           # ← 缓存必须用 temperature=0(确定性输出)
)

set_llm_cache(InMemoryCache())   # 开启内存缓存

question = "Python 中什么是装饰器?用一句话回答"

# 第一次调用:缓存未命中,实际调用 LLM
t0 = time.time()
r1 = llm.invoke([HumanMessage(content=question)])
print(f"第一次(LLM 调用):{time.time()-t0:.3f}s  → {r1.content[:60]}")

# 第二次调用:相同问题,命中缓存,直接返回
t0 = time.time()
r2 = llm.invoke([HumanMessage(content=question)])
print(f"第二次(缓存命中):{time.time()-t0:.3f}s  → {r2.content[:60]}")

# 典型输出:
# 第一次(LLM 调用):2.135s  → 装饰器是一种函数,用于在不修改原函数代码的情况下...
# 第二次(缓存命中):0.001s  → 装饰器是一种函数,用于在不修改原函数代码的情况下...

方案 B:SQLiteCache(单机生产推荐)

python 复制代码
# SQLite 文件缓存------程序重启后缓存仍然有效
from langchain_community.cache import SQLiteCache

# 缓存数据存储在本地 SQLite 文件
# 程序重启后,已缓存的答案依然存在
set_llm_cache(SQLiteCache(database_path="./llm_cache.db"))

questions = [
    "什么是 LangChain?一句话",
    "什么是向量数据库?一句话",
    "什么是 RAG?一句话",
]

print("第一轮(实际调用 LLM,写入缓存):")
for q in questions:
    t0 = time.time()
    r = llm.invoke([HumanMessage(content=q)])
    print(f"  [{time.time()-t0:.2f}s] {q[:20]}... → {r.content[:40]}")

print("\n第二轮(全部命中 SQLite 缓存,即使重启程序也一样快):")
for q in questions:
    t0 = time.time()
    r = llm.invoke([HumanMessage(content=q)])
    print(f"  [{time.time()-t0:.3f}s] {q[:20]}... → {r.content[:40]}")

set_llm_cache(None)  # 测试完毕关闭缓存

3.4 缓存选型指南

场景 推荐方案 原因
本地开发、快速调试 InMemoryCache 无需文件,进程内零配置
单机生产部署 SQLiteCache 重启后缓存保留,无需额外服务
多进程 / 多机部署 RedisCache(langchain-community) 分布式共享,进程间隔离安全

注意:多个 uvicorn worker 进程共写同一个 SQLite 文件会有锁竞争。多进程生产环境必须用 Redis 缓存。


四、三者整合:完整生产级 AI 服务

现在把三项技术整合成一个服务,看看它们如何协同工作。

代码文件:lessons/13_production/02_fastapi_app.py(启动即包含完整功能)

python 复制代码
"""
三技术整合示意(不可单独运行,仅展示整合逻辑):
FastAPI(接口层)+ 异步(并发处理)+ 缓存(重复命中)
"""
from langchain_core.globals import set_llm_cache
from langchain_community.cache import SQLiteCache

# ① 应用启动时:开启全局缓存(一次配置,所有请求自动受益)
set_llm_cache(SQLiteCache(database_path="./llm_cache.db"))

# ② FastAPI 端点中:异步调用 LLM(LangChain 内部自动检查缓存)
@app.post("/chat")
async def chat(request: ChatRequest) -> ChatResponse:
    llm = create_llm(temperature=0)   # temperature=0 才能命中缓存
    # ainvoke 内部流程:
    #   1. 检查缓存 → 命中 → 直接返回(0ms,0成本)
    #   2. 未命中 → 异步调用 LLM → 存入缓存 → 返回
    response = await llm.ainvoke(messages)
    return ChatResponse(answer=response.content, model="qwen-plus")

三技术协同的效果

场景 无任何优化 三技术整合后
10 用户并发同一问题 第 10 人等 20 秒 第一人等 2 秒,其余 9 人等 <1ms
10 用户并发不同问题 第 10 人等 20 秒 所有人等 ~2 秒
前端如何接入 无法接入(Python 脚本) 调用 HTTP API 即可
1000 次重复问题/天 1000 次 API 调用 1 次 LLM + 999 次缓存命中

4.1 生产启动配置

bash 复制代码
# 开发模式(单进程,热重载)
python 02_fastapi_app.py

# 生产模式------方式1:uvicorn 直接启动(单机推荐)
uvicorn 02_fastapi_app:app \
    --host 0.0.0.0 \
    --port 8000 \
    --workers 1     # 使用 SQLiteCache 时保持单进程;用 Redis 时可增加

# 生产模式------方式2:Gunicorn + Uvicorn(更健壮的进程管理)
# 需先 pip install gunicorn
gunicorn 02_fastapi_app:app \
    --workers 1 \
    --worker-class uvicorn.workers.UvicornWorker \
    --bind 0.0.0.0:8000 \
    --timeout 60 \
    --access-logfile -

五、常见错误与排查

错误 原因 解决方法
RuntimeError: This event loop is already running 在 Jupyter Notebook 或已有事件循环的环境里调用 asyncio.run() 改为直接 await,或安装 nest_asyncio 后调用 nest_asyncio.apply()
RateLimitError: 429 并发请求超过 API 速率限制 asyncio.Semaphore(5) 控制最大并发数
流式响应前端收不到数据 Nginx 等代理缓冲了 SSE 响应 响应头加 X-Accel-Buffering: no;Nginx 配置 proxy_buffering off
SQLiteCache 多进程冲突 多个 uvicorn worker 同时写同一个 SQLite 文件 多进程部署换用 RedisCache
缓存命中但答案对不上 temperature > 0,缓存存储了某一次随机输出 只在 temperature=0 的确定性场景使用缓存
asyncio.TimeoutError 频繁触发 超时时间设置过短,或 LLM API 响应偏慢 调大 timeout 参数;先监控平均响应时间再设阈值

六、关键决策速查

bash 复制代码
我的 AI 服务要对外提供接口吗?
  → 是 → 用 FastAPI(02_fastapi_app.py)
  → 否,只是批量脚本 → 跳过 FastAPI,只用 asyncio

我需要支持打字机效果吗?
  → 是 → 用 /chat/stream 端点 + SSE(astream + StreamingResponse)
  → 否 → 用 /chat 端点(ainvoke + 完整响应)

我有并发用户吗?
  → 是 → 必须用 async def 端点 + ainvoke(FastAPI 默认就是异步)
  → 否,批处理脚本 → asyncio.gather + Semaphore 限速

我的 API 调用重复率高吗?(FAQ 问答、文档分析等)
  → 高(>20%)→ 加缓存,明显降低成本和延迟
  → 低(创意写作、随机生成)→ 不适合缓存

单机还是多机部署?
  → 单机 → SQLiteCache
  → 多机 / 多进程 → RedisCache

本章小结

r 复制代码
学了什么                    解决什么                    带来什么
──────────────────────────────────────────────────────────────
异步 (ainvoke/astream)  →  并发慢(N×T 秒)         →  ~T 秒(近似并发数无关)
FastAPI + SSE           →  无法被外部调用           →  任何客户端可调用 HTTP API  
LangChain 缓存          →  重复调用浪费             →  命中时 0ms 0 成本
三者整合                →  无法上生产的脚本         →  可面向用户的生产级 AI 服务

技术是工具,产品是目的。掌握这三项,你的 AI 就从"只有我能用"变成了"所有人都能用"。


下一步探索

完成本章后,你已掌握 AI 服务从开发到生产的完整技能链。进阶方向:下一步继续学习一些扩充的知识点,多模态AI实践


AI入门开发系列文章合集
作者:阿聪谈架构

公众号:阿聪谈架构 (分享后端架构 / AI / Java 技术文章)

相关代码关注公众号:【阿聪谈架构】 回复:AI专栏代码

相关推荐
黑暗森林观察者1 小时前
AI Agent 的"记忆进化":Skills 自进化框架如何让 Agent 越用越聪明?
人工智能
兆。1 小时前
LangChain大模型服务集成指南:面向AI应用开发者
人工智能·langchain
刘一说1 小时前
AI科技热点日报 | 2026年5月29日
人工智能·科技
LucianaiB1 小时前
耗时30天,DocPilot Qwen正式开源:一个免费无广的开源文档 AI 助手
前端·后端
jkyy20141 小时前
AI健康管家:大模型赋能私域健康服务,重塑新零售智慧运营体系
人工智能·零售
薛定猫AI1 小时前
Codex 与 Claude Code 安装配置完全指南
大数据·人工智能·架构
前沿AI1 小时前
AI营销服一体化方案亮相2026中国汽车经销商大会,助力汽车销售全链路提效
大数据·人工智能·汽车
头盔小妹2 小时前
在本地调用大语言模型
人工智能·语言模型·自然语言处理
圣殿骑士-Khtangc2 小时前
智谱AI完成5亿美元融资 + AutoGLM 2.0发布:对标GPT-5 Agent Mode
人工智能