个人AI助手 - 阶段1 项目初始化 + 基础Model I/O
阶段定位
本节是个人 AI 助手首期基座搭建阶段。核心任务:从零搭建前后端基础工程,标准化 Model I/O 调用链路,跑通单轮流式 AI 对话。
本阶段不做复杂业务功能,只完成底层底座从 0 到 1 的落地,为后续多轮对话、RAG、工具调用提供支撑。
2. 核心技术设计
本章聚焦:为什么这么开发。内容包括技术选型、架构分层、设计规范与避坑思路。
2.1 阶段目标
功能目标:完成环境搭建、后端接口开发、前后端联调,打通「前端输入—后端处理—大模型推理—流式返回—前端渲染」链路,实现单轮基础 AI 对话。
架构目标:落地 Model I/O 标准化体系,统一大模型输入输出流程,解耦模型逻辑与业务接口,搭建可扩展、低耦合的轻量化底座。
2.2 架构分层
采用前后端分离的轻量化三层架构,遵循单一职责、高内聚低耦合原则。
- 前端交互层:基于已有 Vue2 项目二次开发,仅负责页面渲染、用户交互、请求转发与结果展示,不参与后端逻辑与模型计算。
- 后端服务层:基于 FastAPI + Uvicorn 搭建异步 Web 服务,负责接口路由、请求接收、逻辑调度、流式响应返回。
- 模型调度层:自研 Model I/O 标准化链路,封装提示词模板、大模型调用、输出解析,统一 AI 能力底层调用规范。
2.3 技术选型
Web 框架:FastAPI,淘汰 Flask、Django
- Django 太重,内置后台、权限、ORM 等本项目不需要的功能,启动笨重、资源占用高。
- Flask 是同步阻塞架构,无原生异步、无自动接口文档,对流式长连接支持差,需要手写大量底层逻辑。
- FastAPI 轻量、原生异步、支持长连接与流式响应,自带
/docs交互式接口文档,适合 AI 对话场景。
ASGI 服务器:Uvicorn,淘汰 Gunicorn、Waitress
- Gunicorn 仅支持 WSGI 同步模式,不兼容 FastAPI 异步特性,会导致流式对话截断、卡顿。
- Waitress 主打 Windows 同步服务,对异步任务、流式响应、高并发支持弱。
- Uvicorn 是 FastAPI 官方适配的 ASGI 异步服务器,支持异步 IO、长连接、流式推送,支持热更新。
大模型开发框架:LangChain,淘汰原生 SDK 裸调用
- 原生 SDK 裸调用:提示词、参数、解析逻辑零散,代码冗余,复用性差,切换模型需要大面积重构。
- LangChain 提供标准化提示词模板、链路组装、输出解析、模型调度能力,便于后续迭代 RAG、多轮记忆、工具调用。
前端方案:已有 Vue2 项目二次开发,淘汰 Vue3 从零搭建、React 开发
- Vue3 从零搭建需要重新配置工程、路由、UI、聊天交互,基建工作量大。
- React 学习成本高、开发周期长,对极简聊天 UI 属于过度开发。
- 成熟 Vue2 聊天项目已封装聊天 UI、消息渲染、发送交互,只需改造接口请求逻辑即可对接后端。
2.4 Model I/O 标准化设计
针对原生大模型调用零散、参数混乱、格式不统一、维护困难的问题,设计标准化闭环链路。
- 输入标准化:用
ChatPromptTemplate固定「系统人设 + 用户输入」模板结构,修改人设不改业务代码。 - 调用标准化:用
ChatZhipuAI封装模型基础参数、密钥安全管理与流式推理配置,固化温度、最大生成长度、流式输出开关等参数。 - 输出标准化:用
StrOutputParser屏蔽模型原生结构化数据差异,统一输出纯文本,适配前端直接渲染。
2.5 性能与架构优化
- 懒加载:服务启动不初始化大模型链路,首次请求再加载,减少冷启动耗时与闲置资源占用。
- 异步流式响应:基于 FastAPI 异步特性与
StreamingResponse,边生成边推送,实现前端逐字输出。 - 开发环境热更新:用
--reload实现代码实时生效,严格区分开发/生产环境。
2.6 设计亮点与避坑
设计亮点
- 架构分层解耦:模型逻辑、后端接口逻辑、前端视图逻辑分离。
- AI 调用标准化:统一大模型输入、调用、输出全流程规范。
- 工程化规范:模块化拆分、环境变量密钥管理,避免密钥硬编码、结构混乱。
规避传统 AI Demo 痛点
- 规避代码耦合:独立封装 LLM 配置工具类,模型调用与业务接口拆分。
- 规避资源浪费:自定义模型链路懒加载,首次请求才加载。
- 规避适配性差:Model I/O 标准化输出解析,统一返回格式,降低前后端联调成本。
- 规避调试低效:Uvicorn 热更新 + FastAPI 自带可视化接口文档,代码修改实时生效、接口在线调试。
3. 核心技术实现
本章聚焦:具体怎么做、代码怎么写、服务怎么搭、功能怎么调通。
3.1 环境搭建
- 创建 Python 虚拟环境,隔离第三方依赖。
- 安装核心依赖:
fastapi、uvicorn、langchain-community、dashscope、python-dotenv等。 - 根目录创建
.env,配置TONGYI_API_KEY,实现密钥脱敏管理。 - 验证依赖版本匹配、无导入报错。
3.2 核心代码
3.2.1 Model I/O 链路代码落地
创建 config 分层目录,新建 llm_config.py,封装完整 LLM 工具类。
# config/llm_config.py
import os
from typing import List
from dotenv import load_dotenv
from langchain_community.chat_models import ChatZhipuAI
from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables import RunnableWithMessageHistory
load_dotenv()
ZHIPU_API_KEY = os.getenv('ZHIPU_API_KEY')
# 模型参数
MODEL_NAME = 'glm-4-flash'
TIMEOUT = 60
chat_prompt_template = ChatPromptTemplate.from_messages([
("system",
"你是瑶瑶的私人助手,协助她完成工作生活学习上的事情。\n" # Python 隐式字符串拼接:多个字符串字面量相邻出现,解释器会自动把它们合并成一个字符串
"如果用户消息中提供了参考资料,请务必严格基于资料回答;"
"资料中没有的信息不要编造,可以说明“资料中未提及”。\n"
"如果没有提供参考资料,则正常回答。"),
("user", "用户问题:{user_input}"),
])
class LLM:
# 瑶瑶的私人助手 Chain
# 自带:提示词 + 输出解析器 + 流式输出 + 智谱模型 + 多轮对话记忆
@staticmethod
def get_chain(
model_name: str = MODEL_NAME,
timeout: int = TIMEOUT,
):
# 预设参数组合:不同业务场景(RAG问答 / 长文深度 / 快速省钱 / 工具调用)
# plus = 日常 RAG:0.7 + 2000 + streaming = True
# max = 长文 / 深度:0.6 + 4096 + streaming = True
# turbo = 省钱快答:0.7 + 1024 + streaming = True
# 工具调用:温度 0.2、不流式
chat_model = ChatZhipuAI(
model=model_name,
api_key=ZHIPU_API_KEY,
timeout=timeout,
temperature=0.7,
max_tokens=2000,
streaming=True,
verbose=False
)
parser = StrOutputParser()
chain = chat_prompt_template | chat_model | parser
return chain
通过静态方法封装链路,外部无需实例化,可直接全局调用。
3.2.2 FastAPI 服务与核心接口
创建 api 分层目录,新建 chat_endpoint.py,定义 /chat 对话接口。
import json
import time
from datetime import datetime
from fastapi import APIRouter
from fastapi.responses import StreamingResponse
from langchain_classic.retrievers import ContextualCompressionRetriever
from pydantic import BaseModel
# 项目内部模块导入:配置、LLM、向量、缓存工具、Token工具
from config.app_config import CACHE_TTL
from config.llm_config import get_session_history
from core.embeddings import embeddings
from core.llm_loader import get_chain
from utils.cache_util import session_question_answer_total, init_session_cache, clean_expired_session_cache, get_cached_answer
from utils.token_util import tokenizer, session_token_total, calculate_input_tokens
from utils.retriever import get_best_retriever
from core.reranker import RawDashScopeRerank
from core.context_compress import create_compression_retriever
router = APIRouter()
# 请求入参模型:前端请求必须携带用户提问+会话ID
class ChatRequest(BaseModel):
user_input: str
session_id: str
use_rag: bool
# ===================== 对话主接口 =====================
# 同步接口,返回流式响应,实际生成逻辑下放至 generate_stream
@router.post("/chat")
def chat(body: ChatRequest):
# body是请求体(FastAPI 按类型自动从 body 解析)
# 若要访问完整请求(headers/url/method 等),需额外加一个 Request 类型入参
print("body: ", body)
chain = get_chain()
# 把 session_id 放进 config.configurable
config = {"configurable": {"session_id": body.session_id}}
# 返回流式生成器
# generate_stream 负责"怎么产出数据"
# StreamingResponse 负责"怎么把产出的数据通过 HTTP 一块块送出去"
return StreamingResponse(generate_stream(body, chain, config), media_type="text/plain")
# ===================== 流式生成总入口函数:串联全流程 =====================
# 执行顺序:初始化缓存→清理过期→匹配缓存→命中缓存直接返回/未命中调用LLM
def generate_stream(req: ChatRequest, chain, config):
# 记录接口开始时间
start_time = datetime.now()
print("开始时间:", start_time.strftime("%Y-%m-%d %H:%M:%S"))
# 问题文本向量化
question_vector = embeddings.embed_query(req.user_input)
yield from stream_llm_result(req, chain, config, start_time, question_vector)
# ===================== 工具:调用LLM流式输出,finally中收尾统计&落地缓存 =====================
def stream_llm_result(req, chain, config, start_time, question_vector):
chunk_list = ""
try:
# 迭代流式分片,拼接完整回答
for chunk in chain.stream({"user_input": req.user_input, "context":context}, config=config):
chunk_list += chunk
yield chunk
finally:
# LLM生成结束后统一处理
yield from handle_llm_finish(req, chunk_list, start_time, question_vector, context)
# ===================== 工具:LLM生成完毕后置处理 =====================
def handle_llm_finish(req, chunk_list, start_time, question_vector, context):
end = datetime.now()
cost_ms = int((end - start_time).total_seconds() * 1000)
print(f"本次输出耗时:{cost_ms} ms")
创建 main.py,作为后端服务主入口,实现服务初始化、CORS 配置、路由挂载与服务根路由。
# 使用 FastAPI 框架搭建的一个后端服务的主入口文件
# 本文件作用:初始化 Web 服务、配置跨域规则,并将各个功能模块的路由(API 接口)组装在一起,共同对外提供服务
# 引入 FastAPI 核心类用于创建应用
from fastapi import FastAPI
# 引入 CORS 中间件用于解决前端跨域请求问题
from starlette.middleware.cors import CORSMiddleware
# 路由全部来自api目录
from api.chat_endpoint import router as chat_router
from api.upload import router as upload_router
from api.knowledge import router as knowledge_router
from api.agent_endpoint import router as agent_router
# 初始化FastAPI服务实例,设置 API 文档的标题为“瑶瑶助手 API”
app = FastAPI(title="瑶瑶助手 API")
# 配置跨域中间件 (CORS)
# 允许任何前端(如浏览器里的 Vue/React 页面)向这个后端发送请求
# allow_origins=["*"] 表示不限制请求来源,这在开发阶段很方便,但在生产环境通常需要改成具体的域名以保证安全
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # 允许所有来源(开发环境用)
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# 挂载路由
# 将导入的 router 注册到主应用 app 中,注册后,这些文件定义的具体接口才能被外部访问到
app.include_router(chat_router)
# 测试接口
# 浏览器访问 http://127.0.0.1:8000/ 时,会返回 {"message": "瑶瑶助手已启动成功"},用于快速检查服务是否正常运行。
@app.get("/")
def home():
return {"message": "瑶瑶助手已启动成功"}
关键点:异步接口适配流式场景,全局变量缓存模型链路,落地懒加载与异步流式响应。
3.3 服务启动与本地运行
-
基础启动:
uvicorn main:app --reload -
完整本地启动:
uvicorn main:app --host 127.0.0.1 --port 8000 --reload -
本地访问地址:http://127.0.0.1:8000
-
热更新:开启
--reload,监听文件变更自动重启;开发环境启用,生产环境关闭。 -
接口文档:FastAPI 自动生成 Swagger 文档 http://127.0.0.1:8000/docs ,支持接口查看、参数配置、在线调试。
3.4 联调与问题修复
- 解决热更新残留进程、缓存导致旧接口生效的问题,手动重启服务保证代码更新生效。
- 解决模型重复初始化、资源占用过高的问题,用懒加载优化资源调度。
- 解决前后端格式不匹配问题,统一 Model I/O 输出格式,前端无需适配改造即可渲染。
- 完成多轮测试,保证接口稳定、流式输出不截断、无乱码、无报错。
4. 阶段交付成果
- 架构交付:完整落地 Model I/O 标准化架构,实现输入、调用、输出全链路统一封装。
- 后端工程交付:可稳定运行的 FastAPI 异步服务、懒加载优化、流式对话接口、可视化调试文档。
- 工程规范交付:虚拟环境隔离、环境变量密钥管理、模块化分层代码结构。
- 功能交付:前后端联调通跑,实现稳定流畅的基础单轮 AI 对话能力。
5. 项目运行效果
- 服务运行:本地 8000 端口稳定监听,启动快速、无报错,
/docs可正常访问调试。 - 接口运行:
/chat请求正常、参数解析正常、模型推理稳定。 - 对话交互:前端发送消息后,AI 逐字流式回复,流畅无卡顿、无截断、无乱码。
- 整体效果:架构稳定、链路通畅、体验良好,完成首期基座搭建与基础对话通跑目标。
6. 后续迭代价值
本阶段搭建的标准化 Model I/O 架构与解耦式前后端底座,后续可直接迭代多轮对话记忆、RAG 知识库问答、AI 工具调用、多模型切换、对话历史管理等功能,无需重构底层代码。