FastAPI 入门:结合 xiaolin 项目来理解
这篇文档是给“还没真正用过 FastAPI”的你准备的。我们不从抽象概念开始,而是直接拿 xiaolin 这个项目来理解:FastAPI 到底是怎么把“浏览器发请求”变成“后端返回结果”的。
1. 先记住:FastAPI 是干什么的
你可以先把 FastAPI 理解成一套“写后端接口的框架”。
它主要帮你做几件事:
- 定义接口路径,比如
/api/chat - 接收前端传来的参数
- 校验参数格式
- 调用业务代码
- 返回 JSON 数据
- 自动生成接口文档
/docs
在这个项目里,FastAPI 是整个后端的“入口层”。
2. 项目里 FastAPI 从哪里启动
入口文件是:
xiaolin/app/main.py
这里最重要的代码可以概括成三步:
- 创建
FastAPI(...)应用对象 - 注册中间件和路由
- 挂载静态页面和首页
你可以重点看这几个部分:
app = FastAPI(
title=config.app_name,
version=config.app_version,
description="基于 LangChain 的智能oncall运维系统",
lifespan=lifespan
)
这段的意思是:创建一个 Web 应用,并且把“启动时要做什么、关闭时要做什么”交给 lifespan 管理。
3. lifespan 是什么
在 xiaolin/app/main.py 里,项目定义了:
@asynccontextmanager
async def lifespan(app: FastAPI):
milvus_manager.connect()
yield
milvus_manager.close()
你可以把它理解成“应用级别的初始化和清理逻辑”。
这个项目里它做了两件很关键的事:
- 服务启动时连接 Milvus 向量库
- 服务关闭时断开 Milvus 连接
这类工作如果不放在启动阶段,每次请求都重新连数据库会很慢,也更乱。
4. 路由是什么
FastAPI 最核心的概念之一就是“路由”。
路由就是:
- 什么请求路径
- 用什么 HTTP 方法
- 对应哪个 Python 函数处理
比如在 xiaolin/app/main.py:
app.include_router(chat.router, prefix="/api", tags=["对话"])
app.include_router(file.router, prefix="/api", tags=["文件管理"])
app.include_router(aiops.router, prefix="/api", tags=["AIOps智能运维"])
这表示:
- 对话相关接口在
app/api/chat.py - 文件上传相关接口在
app/api/file.py - AIOps 相关接口在
app/api/aiops.py
也就是说,main.py 不自己写所有接口,而是把接口拆到不同模块里。
这是很典型、也很推荐的 FastAPI 项目结构。
5. 看一个最简单的接口:普通聊天
文件:
xiaolin/app/api/chat.py
核心代码:
@router.post("/chat")
async def chat(request: ChatRequest):
answer = await rag_agent_service.query(
request.question,
session_id=request.id
)
return {
"code": 200,
"message": "success",
"data": {
"success": True,
"answer": answer,
"errorMessage": None
}
}
这段逻辑非常值得你记住,因为它就是很多后端接口的标准套路:
@router.post("/chat")表示这是一个POST /api/chat接口request: ChatRequest表示请求体会自动按 Pydantic 模型校验- 调用 service 层
- 返回统一 JSON 结果
6. Pydantic 在这里干了什么
文件:
xiaolin/app/models/request.py
class ChatRequest(BaseModel):
id: str = Field(..., description="会话 ID", alias="Id")
question: str = Field(..., description="用户问题", alias="Question")
意思是:
- 前端要传
Id - 前端要传
Question - FastAPI 会自动把它解析成 Python 对象
比如当前端发送:
{
"Id": "session-123",
"Question": "什么是向量数据库?"
}
在接口函数里你就可以直接用:
request.idrequest.question
这就是 FastAPI 很舒服的地方:参数校验和解析都很自然。
7. FastAPI 这里为什么“路由层很薄”
这个项目结构上做得比较清楚:
api/负责收请求、回响应services/负责真正的业务逻辑models/负责数据模型core/负责底层组件
比如聊天接口并不直接写模型调用,而是交给:
xiaolin/app/services/rag_agent_service.py
文件上传接口也不直接写向量化细节,而是交给:
xiaolin/app/services/vector_index_service.py
这是你以后写后端时非常值得模仿的分层方式。
8. 文件上传接口能帮你理解完整业务流
文件:
xiaolin/app/api/file.py
上传接口做了这些事:
- 校验文件名和扩展名
- 保存到
uploads/ - 调用
vector_index_service.index_single_file(...)
也就是说,FastAPI 这里只负责“HTTP 接口入口”,真正的 RAG 建库逻辑继续往 service 层走。
这个调用链是:
前端上传文件
-> /api/upload
-> file.py
-> vector_index_service.py
-> document_splitter_service.py
-> vector_embedding_service.py
-> vector_store_manager.py
-> Milvus
9. 流式输出是怎么做的
这个项目不只是普通 JSON 返回,还支持流式对话。
文件:
xiaolin/app/api/chat.py
核心用法是:
from sse_starlette.sse import EventSourceResponse
return EventSourceResponse(event_generator())
这里用的是 SSE。
你可以先简单理解为:
- 普通接口:一次性返回完整结果
- SSE 接口:后端边生成边推给前端
所以 /api/chat_stream 适合模型流式回答。
10. FastAPI 为什么很适合做 AI 应用后端
从这个项目你能看到几个原因:
- 写 REST API 很快
- 天然支持异步
async/await - 很适合接 SSE 流式输出
- 和 Pydantic 配合非常顺手
- 自动生成文档,调试方便
对 AI 项目来说很常见的场景是:
- 聊天接口
- 文件上传
- 流式回答
- 后台任务
- 配置化服务启动
FastAPI 对这些都比较友好。
11. 你可以怎么理解这个项目里的 FastAPI 分层
建议你先用下面这个脑图去记:
main.py
-> 创建 FastAPI 应用
-> 注册路由
-> 配置 CORS
-> 挂载静态资源
api/
-> 定义接口路径
-> 接收请求
-> 调 service
-> 返回响应
services/
-> 真正业务逻辑
models/
-> 请求和响应的数据结构
core/
-> 模型、Milvus、配置等底层能力
12. 你现在最值得先读哪几个文件
如果你是第一次接触 FastAPI,我建议按这个顺序看:
xiaolin/app/main.pyxiaolin/app/api/chat.pyxiaolin/app/models/request.pyxiaolin/app/api/file.pyxiaolin/app/api/aiops.py
这样你会先掌握:
- 应用怎么启动
- 接口怎么定义
- 参数怎么接收
- 普通返回和流式返回有什么区别
13. 一句话总结
在 xiaolin 里,FastAPI 不是“负责智能”的那一层,它更像整个系统的交通枢纽:
- 接住前端请求
- 交给 LangChain/RAG/AIOps 服务处理
- 再把结果用 JSON 或 SSE 返回出去
如果你刚入门,先把 FastAPI 理解成“写接口 + 管理请求/响应 + 连接前后端”的框架就够了。
下一步最适合继续看的,就是这个项目里的 LangChain 和 RAG 调用链。
LangChain 与 RAG 入门:结合 xiaolin 项目来理解
这篇文档专门帮你建立一个清晰认识:
- LangChain 在这个项目里干什么
- RAG 是怎么跑起来的
- LangGraph、Tool、Milvus 分别是什么角色
如果你之前没做过这类 AI 应用,可以先记一句最重要的话:
这个项目不是“直接把问题发给大模型”那么简单,而是把“检索知识库、调用工具、保留会话、流式输出”都组织起来了。
1. 先分清 4 个概念
1.1 大模型
这里用的是通义千问。
在 xiaolin/app/services/rag_agent_service.py 里:
self.model = ChatQwen(
model=self.model_name,
api_key=config.dashscope_api_key,
temperature=0.7,
streaming=streaming,
)
也就是:
- 底层模型提供回答能力
- 项目通过 LangChain 生态去组织它
1.2 LangChain
LangChain 可以理解为“帮你把模型、工具、知识库、消息历史串起来的应用框架”。
它不等于模型本身。
它做的是“编排”。
1.3 RAG
RAG = Retrieval-Augmented Generation,检索增强生成。
最直白的理解是:
- 先从知识库里找相关资料
- 再把资料交给模型回答
这样比“模型纯靠自己记忆答题”更适合企业知识库场景。
1.4 LangGraph
LangGraph 可以理解为“更适合有状态工作流的 LangChain 组件”。
这个项目里:
- 聊天 Agent 用了
create_agent + checkpointer - AIOps 用了显式的
StateGraph
所以你会看到 LangChain 和 LangGraph 是一起出现的。
2. 这个项目里的 RAG 主流程是什么
建议你先记住这条主线:
上传文档
-> 文档切分
-> 生成 embedding
-> 存入 Milvus
用户提问
-> Agent 判断是否要查知识库
-> 调用 retrieve_knowledge 工具
-> 从 Milvus 检索相关文档
-> 把检索结果作为上下文交给模型
-> 模型生成最终回答
这就是这个项目的核心。
3. 上传文档后,知识库是怎么建立的
入口在:
xiaolin/app/api/file.py
上传成功后会调用:
vector_index_service.index_single_file(str(file_path))
然后继续往下走。
4. 文档怎么切分
文件:
xiaolin/app/services/document_splitter_service.py
这个服务做了两件很关键的事:
- 如果是 Markdown,先按标题切
- 再按长度做二次切分
项目里用了:
MarkdownHeaderTextSplitterRecursiveCharacterTextSplitter
这很重要,因为 RAG 不是把整篇文章直接丢给向量库,而是切成很多“较小、可检索”的分片。
这里的好处是:
- 检索更精准
- 不会把整篇超长文档都塞给模型
- 能保留标题层级信息
项目还给每个分片加了元数据:
_source_extension_file_nameh1、h2等标题信息
这些元数据后面在检索结果展示时很有用。
5. embedding 是什么
文件:
xiaolin/app/services/vector_embedding_service.py
embedding 你可以先理解成:
- 把一段文字转换成一串数字向量
- 让“语义相近的文本”在向量空间里更靠近
这样用户提问时,系统就可以按“语义相似度”找相关知识,而不是只靠关键词匹配。
这个项目封装了一个 DashScopeEmbeddings,实现了 LangChain 的标准接口:
embed_documentsembed_query
这意味着上层 LangChain 组件可以无缝调用它。
6. 向量库存在哪里
文件:
xiaolin/app/services/vector_store_manager.py
这里项目用的是:
Milvuslangchain_milvus.Milvus
注意这里不是直接自己手写很多 Milvus 查询逻辑,而是用了 LangChain 的 VectorStore 封装。
它负责:
add_documents(documents)similarity_search(query, k=3)as_retriever(...)
所以从编程体验上,你可以把它理解成:
- 一个“可以存向量、查相似文本”的知识库对象
7. 真正的检索工具在哪里
文件:
xiaolin/app/tools/knowledge_tool.py
这里定义了:
@tool(response_format="content_and_artifact")
def retrieve_knowledge(query: str):
这就是一个 LangChain Tool。
它的作用是:
- 收到查询词
- 从向量库里检索文档
- 把文档格式化成适合模型阅读的上下文文本
这里格式化后的内容长这样:
【参考资料 1】
标题: ...
来源: ...
内容:
...
也就是说,模型不是直接看原始 Milvus 结果,而是看被整理过的“参考资料”。
8. Agent 是怎么组织起来的
文件:
xiaolin/app/services/rag_agent_service.py
最核心的代码是:
self.agent = create_agent(
self.model,
tools=all_tools,
checkpointer=self.checkpointer,
)
这里你可以把 create_agent(...) 理解成:
- 给模型一组工具
- 给它消息历史能力
- 让它在对话时自行决定要不要用工具
这里的工具包含两类:
- 本地工具:
retrieve_knowledge、get_current_time - MCP 工具:从外部 MCP 服务动态加载
所以这个 Agent 并不是“只会聊天”,而是“会按需用工具聊天”。
9. 会话历史是怎么保留的
还是在 rag_agent_service.py:
self.checkpointer = MemorySaver()
然后每次请求会传:
config_dict = {
"configurable": {
"thread_id": session_id
}
}
这意味着:
- 同一个
session_id - 会共享同一条对话上下文
所以用户连续问几轮,Agent 是“记得前文”的。
这个能力是很多聊天产品的基础。
10. 流式输出是怎么和 LangChain 结合的
query_stream(...) 里用了:
async for token, metadata in self.agent.astream(
input=agent_input,
config=config_dict,
stream_mode="messages",
):
这表示 Agent 在生成过程中不断吐出消息片段。
后端再把这些片段包装成 SSE,前端就能边收边显示。
所以整体链路是:
LangChain / LangGraph astream
-> FastAPI SSE
-> 浏览器逐段渲染
11. 为什么说这个项目是“RAG + Tool + Agent”
因为它不只是“检索后拼 prompt”那么简单。
它至少做了三层事:
11.1 RAG
通过 retrieve_knowledge 访问向量库。
11.2 Tool Calling
通过 @tool 和 MCP 工具,让模型可以主动调用外部能力。
11.3 Agent
通过 create_agent(...) 让模型在对话中自己决定:
- 需不需要查知识库
- 需不需要查时间
- 需不需要调 MCP 工具
这比“固定流程的问答机器人”更灵活。
12. AIOps 为什么又用了 LangGraph
文件:
xiaolin/app/services/aiops_service.py
这里不是普通对话 Agent,而是显式构建了一个工作流图:
plannerexecutorreplanner
代码里用了:
workflow = StateGraph(PlanExecuteState)
这说明 LangGraph 特别适合这种:
- 有状态
- 有多个步骤
- 会根据中间结果决定下一步怎么走
的任务。
也就是说:
- 聊天场景:偏 Agent
- AIOps 场景:偏 Workflow
这也是 LangGraph 很常见的实际用法。
13. 你应该怎样理解 MCP
文件:
xiaolin/app/agent/mcp_client.py
MCP 可以先理解成“给模型接外部工具的一种统一协议”。
在这个项目里,它接入了:
- 日志查询服务
- 监控服务
这样模型就不只是“会说”,而是“能查真实系统数据”。
这对 AIOps 很重要,因为真正的故障诊断不能靠编。
14. 你可以把整个 LangChain 架构记成这样
FastAPI 路由
-> rag_agent_service
-> ChatQwen 大模型
-> Tools
-> retrieve_knowledge
-> get_current_time
-> MCP tools
-> checkpointer 记忆
-> 流式输出 / 一次性输出
而 retrieve_knowledge 背后又是:
retrieve_knowledge
-> VectorStoreManager
-> Milvus
-> Embeddings
-> DocumentSplitter
15. 对你这种刚入门的人,最容易混淆的点
这里我帮你拆一下:
- LangChain 不是模型,它是编排框架
- RAG 不是模型训练,它是“检索 + 生成”
- Milvus 不是大模型,它是向量数据库
- Tool 不是普通函数,它是“可以被模型调用的能力”
- LangGraph 不是前端图,而是后端工作流状态图
16. 你接下来最建议看的文件顺序
建议按这条线读:
xiaolin/app/services/rag_agent_service.pyxiaolin/app/tools/knowledge_tool.pyxiaolin/app/services/vector_index_service.pyxiaolin/app/services/document_splitter_service.pyxiaolin/app/services/vector_store_manager.pyxiaolin/app/services/vector_embedding_service.pyxiaolin/app/services/aiops_service.py
17. 一句话总结
这个项目里的 LangChain 不是单纯“调用一下模型 API”,而是把下面这些能力组装成了一个完整 AI 应用:
- 多轮对话
- 工具调用
- RAG 检索
- 会话记忆
- 流式输出
- AIOps 工作流
如果你把这条主线看懂了,后面再学更复杂的 Agent 系统就会轻松很多。
Vue 入门:先理解 Vue,再看 xiaolin 项目前端和它的关系
先说最重要的结论:
xiaolin 这个项目的前端页面并不是标准 Vue 项目。
它当前是这种结构:
xiaolin/static/index.htmlxiaolin/static/app.jsxiaolin/static/styles.css
也就是说,它是“静态 HTML + 原生 JavaScript”页面,不是你常见的那种:
src/App.vuesrc/components/*.vuevite.config.tspackage.json
所以这一篇我会做两件事:
- 先帮你快速入门 Vue
- 再告诉你这个项目前端和 Vue 的区别到底在哪
1. Vue 是干什么的
Vue 是前端框架。
你可以先把它理解成:
- 专门用来做页面交互
- 帮你更容易管理页面状态
- 帮你把 UI 拆成组件
如果不用 Vue,页面复杂起来后,你经常会自己手写很多:
document.querySelectoraddEventListener- DOM 增删改查
- 手动同步数据和页面
Vue 的核心价值,就是让你更多关注“数据是什么”,而不是“DOM 怎么改”。
2. Vue 最核心的 3 个概念
2.1 数据驱动视图
意思是:
- 数据变了
- 页面自动跟着变
比如计数器:
<template>
<button @click="count++">点击了 {{ count }} 次</button>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
这里你没有手动去找按钮再改文本,Vue 会帮你更新页面。
2.2 组件化
Vue 鼓励你把页面拆成一个个小模块。
比如聊天系统可以拆成:
- 输入框组件
- 消息列表组件
- 历史对话组件
- 顶部操作栏组件
这样代码更好维护。
2.3 指令和事件绑定
Vue 常见写法有:
v-modelv-ifv-for@click:class
它们分别对应:
- 双向绑定
- 条件渲染
- 列表渲染
- 事件监听
- 动态绑定属性
3. 标准 Vue 项目一般长什么样
如果你以后新建 Vue 项目,通常会看到这种结构:
src/
App.vue
main.js
components/
package.json
vite.config.js
App.vue 里通常会写:
<template>
<div>{{ message }}</div>
</template>
<script setup>
const message = 'Hello Vue'
</script>
<style scoped>
div { color: red; }
</style>
这就是 Vue 单文件组件。
4. 这个项目前端现在是什么模式
文件:
xiaolin/static/index.htmlxiaolin/static/app.js
它的做法更像传统页面开发:
- HTML 里先把页面骨架写好
- JS 里用类和 DOM API 管理交互
- 通过
fetch或 SSE 和后端通信
比如在 app.js 里你会看到大量:
document.querySelector(...)document.getElementById(...)addEventListener(...)
这说明它不是 Vue 的响应式写法,而是手动操作页面元素。
5. 你可以把这个项目前端理解成“Vue 之前的写法”
举个例子。
在这个项目里,初始化元素的方式是:
this.sidebar = document.querySelector('.sidebar');
this.newChatBtn = document.getElementById('newChatBtn');
this.messageInput = document.getElementById('messageInput');
这种写法的问题不是“不能用”,而是页面越来越复杂时,会出现:
- 状态分散
- DOM 引用很多
- 修改一处容易影响多处
- 功能再大一点就难维护
Vue 出现后,很多这类逻辑会换成“状态驱动组件”。
6. 如果用 Vue,这个聊天页大概会怎么拆
这正好帮助你理解 Vue。
当前这个项目页面至少可以拆成这些组件:
Sidebar.vueChatMessages.vueChatInput.vueModeSelector.vueHistoryList.vueLoadingOverlay.vue
然后在页面层统一管理状态,比如:
- 当前会话 ID
- 当前模式
quick/stream - 历史对话列表
- 当前消息列表
- 是否正在流式输出
这就是 Vue 擅长的地方。
7. 用 Vue 会怎么管理输入框
当前项目是手动取值和绑定事件。
如果换成 Vue,通常会写成:
<template>
<input v-model="message" @keydown.enter="sendMessage" />
</template>
<script setup>
import { ref } from 'vue'
const message = ref('')
function sendMessage() {
console.log(message.value)
}
</script>
你可以看到区别:
- 原生 JS:手动找 DOM、手动读值
- Vue:数据本身就是核心,页面只是显示结果
8. 用 Vue 会怎么渲染消息列表
当前项目如果要追加消息,通常要自己创建 DOM 或拼 HTML。
Vue 常见写法会是:
<template>
<div v-for="item in messages" :key="item.id">
{{ item.content }}
</div>
</template>
只要 messages 变化,页面就自动刷新。
这对聊天应用特别舒服。
9. 这个项目前端和 Vue 的相同点
虽然它没真正用 Vue,但你还是能看出一些“前端应用思路”上的共性:
- 有明确的状态,比如
currentMode、isStreaming - 有初始化逻辑
- 有事件绑定
- 有按模块划分的 UI 区域
- 有和后端 API 的通信
也就是说,它已经有“单页应用”的味道了,只是没有使用 Vue 来管理。
10. 这个项目前端和 Vue 的最大不同点
差别主要有 4 个:
10.1 没有响应式系统
Vue 会自动追踪数据变化并更新页面。
这个项目需要手动更新 UI。
10.2 没有组件系统
现在基本都在 app.js 一个大类里。
Vue 通常会拆成多个组件文件。
10.3 没有构建工具链
标准 Vue 一般会有:
Vitenpmpackage.json
这个项目没有这套工程化结构。
10.4 没有模板语法
Vue 会在模板里写:
v-forv-if@click
这里还是原生 HTML + JS 逻辑分离的方式。
11. 为什么这个项目不用 Vue 也能跑
因为前端本质上就是:
- 浏览器加载 HTML
- 执行 JavaScript
- 发 HTTP 请求给后端
- 把响应显示出来
Vue 只是让这个过程更易维护,不是唯一方案。
所以这个项目当前这种写法,做一个中小型 demo 是完全可行的。
12. 如果你打算以后认真学前端,建议怎么理解 Vue
你可以把 Vue 看成“帮你管理复杂页面的工具”。
当页面开始出现下面这些东西时,Vue 的优势就会越来越明显:
- 多个组件之间传数据
- 很多交互状态
- 列表渲染
- 条件展示
- 路由切换
- 状态共享
聊天系统、管理后台、知识库页面,都是很常见的 Vue 使用场景。
13. 对照这个项目,Vue 最适合优化哪些地方
如果以后把 xiaolin 前端改成 Vue,我会优先做这些事情:
- 把
app.js按组件拆开 - 把对话状态改成响应式数据
- 把聊天记录渲染改成列表模板
- 把模式选择、文件上传、消息流式显示拆成独立组件
- 把 API 请求封装成单独模块
这样代码会比现在更清晰。
14. 如果你是第一次学 Vue,应该先掌握什么
建议你先只学这几个点,不要一上来就学太杂:
ref和reactivev-modelv-forv-if@click- 组件
props onMountedfetch/axios调接口
掌握这些后,再回头看这个聊天页面,你就会很容易想到“如果用 Vue,该怎么重构”。
15. 给你一个最实用的结论
对这个项目来说:
- 后端框架是 FastAPI
- AI 编排核心是 LangChain / LangGraph
- 前端不是 Vue,而是原生静态页面
所以你现在别把它误认为“FastAPI + Vue 全栈项目”。
更准确地说,它是:
FastAPI + LangChain/LangGraph + 静态前端页面
16. 一句话总结
Vue 你可以先理解成“让前端页面从手动改 DOM,升级成用数据驱动组件”的框架。
而 xiaolin 这个项目虽然没真正用 Vue,但正因为它现在还是原生 JS,你反而更容易看懂 Vue 为什么会流行,以及 Vue 能帮这个聊天页面解决什么问题。