看懂这个项目 backend AI 代码的逐文件讲解

2 阅读17分钟

看懂这个项目 backend AI 代码的逐文件讲解

1. 这篇文档解决什么问题

如果你现在打开这个项目的 backend/,很可能会有这种感觉:

  • 文件很多
  • 名词很多
  • 不知道先看哪个
  • 即使看了某个文件,也不知道它在整体里扮演什么角色

这篇文档的目标不是逐行翻译源码,而是帮你建立一张“源码地图”:

每个关键文件是干什么的,它和谁配合,它在整条 AI 链路里处于哪一层。

你只要先把这张地图建立起来,再回去看代码,就会顺很多。


2. 先建立整体脑图:backend 在做什么

这个项目的 backend/ 本质上是一个:

基于 FastAPI + LangChain 的 AI 服务端

它主要负责 4 件事:

  1. 对外暴露 API
  2. 管理对话会话
  3. 执行 RAG 文档问答
  4. 执行 Agent 多工具问答

你可以先把后端理解成下面这条总链路:

前端请求
-> FastAPI 路由
-> 业务服务层
-> RAG / Agent
-> 模型 / 向量库 / 工具
-> 返回结果

所以你看 backend 的时候,不要把它当成一堆散文件,而要把它当成一条流。


3. backend 的推荐阅读顺序

先把结论放前面。

如果你是第一次读这个项目,最推荐按这个顺序:

  1. backend/main.py
  2. backend/app/router/chat.py
  3. backend/app/router/chat_service.py
  4. backend/app/rag/rag_service.py
  5. backend/app/rag/vector_store.py
  6. backend/app/rag/reorder_service.py
  7. backend/app/agent/agent_tools.py
  8. backend/app/agent/agent.py
  9. backend/app/services/database_session_manager.py
  10. backend/app/models/chat_history.py
  11. backend/app/utils/factory.py
  12. backend/app/utils/config.py
  13. backend/app/utils/prompt_loader.py
  14. backend/app/schemas/models.py

这个顺序的逻辑是:

  • 先看入口
  • 再看接口
  • 再看业务总调度
  • 再看 AI 核心实现
  • 最后看配置、模型、数据结构

4. 第一站:backend/main.py

这是后端应用入口。

你可以把它理解成:

整个 FastAPI 服务的总开关

4.1 这个文件做了什么

主要职责有:

  • 创建 FastAPI() 实例
  • 注册全局限流中间件
  • 注册请求耗时中间件
  • 注册 CORS
  • 加载路由
  • 注册异常处理
  • 在启动时初始化数据库、Redis、会话管理器、重排序模型

4.2 为什么先看它

因为它能回答你两个最关键的问题:

  1. 这个服务启动后有哪些能力
  2. 启动时依赖了哪些基础设施

4.3 从它能看出什么

你会发现这个后端不是一个纯内存 demo,而是有真实工程能力的:

  • MySQL
  • Redis
  • 会话持久化
  • 限流
  • 模型初始化

所以它已经是“可落地系统”,不是只演示 AI 调用。


5. 第二站:backend/app/router/chat.py

这是最值得优先看的路由文件。

它是整个 AI 能力的对外接口层。

5.1 这个文件提供了哪些能力

从接口上看,它主要暴露了:

  • Agent 流式问答
  • RAG 问答
  • 获取会话历史
  • 删除会话
  • 获取会话列表
  • 上传单个文件进向量库
  • 上传多个文件进向量库
  • 清空用户向量数据
  • 文档重排序

5.2 为什么它重要

因为它相当于一张功能目录表。

你看到这些接口后,就知道这个后端到底支持哪些 AI 功能,而不是只在源码里猜。

5.3 怎么看这个文件

读这个文件时,不要一开始纠结每个细节。

你重点看:

  • 每个接口的 URL
  • 每个接口依赖哪些参数
  • 每个接口最终调用谁

例如:

  • RAG 问答会调用 router_service.handle_rag_query
  • 上传文件会调用 handle_add_vector_single
  • Agent 流式输出会调用 get_agent_stream_response

这就把你带到了下一层。


6. 第三站:backend/app/router/chat_service.py

这个文件名字虽然叫 chat_service.py,但它实际是:

路由层后面的业务编排层

也就是路由收到请求后,真正串起各个模块的地方。

6.1 这个文件为什么关键

因为它相当于后端 AI 业务的“总调度台”。

它把下面这些能力连接起来:

  • Agent
  • RAG
  • 向量库
  • 会话管理
  • 重排序服务

6.2 这个文件里有哪些核心方法

重点方法包括:

  • handle_agent_query
  • handle_rag_query
  • handle_get_session
  • handle_delete_session
  • handle_get_user_sessions
  • handle_add_vector_single
  • handle_add_vector_multiple
  • clean_user_upload
  • handle_reorder

6.3 它的阅读重点

你不用一开始深究所有异常处理。

先抓住一件事:

这个类的职责不是“做底层算法”,而是“把请求转给正确的底层模块”

例如:

  • RAG 问答 -> RagService
  • 上传文件 -> VectorStoreService
  • 对话历史 -> session_manager
  • 重排序 -> reorder_service

所以它是业务编排层,而不是模型层。


7. 第四站:backend/app/rag/rag_service.py

这是项目里 RAG 的核心文件之一。

如果你要看“检索增强生成到底怎么落地”,这个文件一定要啃。

7.1 这个类在做什么

RagService 可以理解为:

专门负责“从知识库查资料并生成回答”的服务类

7.2 它内部做了哪些事

主要包括:

  • 创建向量库服务
  • 初始化检索器
  • 加载 RAG 用的 Prompt
  • 创建总结链 prompt -> model -> parser
  • 使用 HyDE 增强检索
  • 调用重排序服务
  • 对多个文档做分批摘要
  • 合并摘要生成最终回答

7.3 为什么这个文件很值得学

因为它体现了一个比较完整、比较工程化的 RAG 思路,而不只是“检索一下然后直接回答”。

7.4 这个文件里的几个重点函数

initialize_retriever

作用:

  • 延迟初始化检索器

为什么要这样做?

因为不是每次对象创建都一定要马上查库、建 retriever,延迟初始化能减少不必要开销。

generate_hypothetical_document

作用:

  • 用 HyDE 生成假设性文档

这是比较高级一点的 RAG 技术。

它的思路是:

先让模型生成一段“可能的答案”,再拿这段文本去检索,比直接拿原问题检索更丰富。

retrieve_document

作用:

  • 真正从知识库中召回文档

它内部会先做 HyDE,再调用 retriever。

reorder_documents

作用:

  • 对候选文档做 rerank

这一步是为了提高最终上下文质量。

get_documents_and_summary

这是最核心的方法。

它大致做了这几步:

  1. 检索文档
  2. 提取文档内容
  3. 重排序
  4. 对前几个文档分别总结
  5. 再把多个摘要合成最终回答

这也是你最值得重点看的一段逻辑。

rag_summary

这是对外暴露的简化入口。

它把复杂过程包起来,外部只需要传 query 就行。


8. 第五站:backend/app/rag/vector_store.py

这是项目里另一个非常关键的文件。

如果 rag_service.py 是“RAG 的大脑调度”,那 vector_store.py 就是:

RAG 的知识库底座

8.1 它的职责是什么

主要负责:

  • 连接 Chroma 向量库
  • 加载各类知识文件
  • 文本切分
  • 生成 embedding
  • 建立向量索引
  • 构造检索器
  • 混合检索
  • 去重处理
  • 删除用户文档

8.2 为什么这个文件很重要

因为一个 RAG 系统效果好不好,很大程度取决于知识库构建是否合理。

而这些工作,大多都发生在这里。

8.3 这个文件里最值得看的点

Chroma 初始化

这里会创建:

  • Chroma

说明知识库底层使用 Chroma 作为向量数据库。

文档切分器

这里初始化了 AsyncTextSplitter

说明这个项目不是直接把整个文件塞进库里,而是先分块。

BM25 检索器

项目不仅有向量检索,还从文档中构造了:

  • BM25Retriever

这说明作者考虑到了关键词召回能力。

混合检索器

通过:

  • EnsembleRetriever

把向量检索和 BM25 检索融合起来。

这属于比“纯向量检索”更进一步的实现。

动态权重

get_dynamic_weights 会根据 query 长短动态调权重。

这是一种很典型的工程优化。

MD5 去重

文件被导入向量库前,会先计算 MD5。

这样做的好处是:

  • 避免重复入库
  • 节省存储
  • 减少重复向量化开销
文件加载

这个文件还能根据扩展名调用不同 loader:

  • txt
  • pdf
  • md
  • pptx
  • docx

说明系统是面向真实文件知识库设计的。

8.4 读这个文件时要抓住什么

你要抓住的不是每个异步细节,而是这条大线:

文件 -> 文档 -> 切分 -> embedding -> 向量库 -> retriever

只要这条线顺了,RAG 的基础就顺了。


9. 第六站:backend/app/rag/reorder_service.py

这个文件负责重排序。

9.1 为什么需要它

因为第一次检索拿回来的文档,不一定排得最准。

所以项目又加了一层:

用 reranker 模型对“问题 + 文档”重新评分排序

9.2 这个文件做了什么

主要包括:

  • 检查本地重排序模型是否存在
  • 如果没有则下载
  • 懒加载 CrossEncoder
  • 对文档列表打分
  • 返回按相似度排序后的结果

9.3 它的重要意义

它说明这个项目不是“简单能跑就行”,而是在认真优化召回结果质量。

对于 RAG 来说,这一步往往很关键。


10. 第七站:backend/app/agent/agent_tools.py

这是 Agent 的工具箱文件。

10.1 这个文件的作用

它把一些 Python 函数暴露成 Agent 可以调用的工具。

10.2 这里定义了哪些工具

主要有:

  • rag_summary_tools
  • reorder_documents_tools
  • get_user_info_tools
  • get_weather_tools
  • what_time_is_now

10.3 为什么这个文件值得重点看

因为它让你一下就能知道:

这个 Agent 到底“会什么”

一个 Agent 的边界,本质上就是由工具决定的。

10.4 最重要的工具是哪一个

最值得你关注的是:

  • rag_summary_tools

因为它体现了一个关键设计:

RAG 被封装成了 Agent 的一个工具

这意味着:

  • 用户问知识库问题时
  • Agent 可以自己决定调用 RAG

这就是 Agent 和 RAG 的连接点。


11. 第八站:backend/app/agent/agent.py

这是项目中 Agent 的核心实现文件。

11.1 这个文件在整体里处于什么位置

如果说 rag_service.py 是知识库问答核心,那 agent.py 就是:

多工具智能体的核心

11.2 这个文件主要做了什么

主要分几部分:

  • 定义 AgentFactory
  • 配置默认工具
  • 加载默认系统提示词
  • 创建聊天模型
  • 创建 Agent Prompt
  • 创建 Tool Calling Agent
  • 创建 AgentExecutor
  • 提供普通响应函数
  • 提供流式响应函数

11.3 为什么这里用了工厂模式

因为 Agent 的创建依赖很多东西:

  • 模型
  • 工具
  • 提示词
  • 执行器参数

把这些封装进工厂类后:

  • 逻辑更集中
  • 更方便复用
  • 更容易避免全局状态污染

11.4 _create_chat_model

这一步负责创建聊天模型。

也就是 Agent 背后的“决策大脑”。

11.5 _create_prompt

这里用了:

  • ChatPromptTemplate
  • MessagesPlaceholder

说明这个 Agent 不是单轮死问答,而是支持:

  • 系统提示词
  • 聊天历史
  • 用户输入
  • 中间思考轨迹

11.6 create_agent_executor

这是 AgentFactory 的核心方法。

它把模型、prompt、tools 拼起来,最终生成:

  • AgentExecutor

你可以把执行器理解成:

真正驱动 Agent 跑起来的执行引擎

11.7 get_agent_response

这是非流式 Agent 响应函数。

它做的事情包括:

  1. 创建新的 AgentExecutor
  2. 把历史对话转成消息对象
  3. 调用 astream 执行
  4. 收集最终回答
  5. 收集中间步骤

11.8 get_agent_stream_response

这是流式版本。

它会:

  • 实时产出模型输出
  • 通过 SSE 格式发给前端
  • 最后把完整回答写入会话历史

11.9 你读这个文件时应该抓住什么

重点不是记所有 LangChain API 名字,而是抓住这条链:

用户输入 -> Agent 判断 -> 是否调工具 -> 工具返回 -> Agent 继续 -> 最终输出


12. 第九站:backend/app/services/database_session_manager.py

这个文件不是 AI 算法本身,但非常重要。

因为它负责:

把对话真正存下来

12.1 这个文件做了什么

主要负责:

  • 获取会话
  • 新建会话
  • 写入用户消息和助手消息
  • 获取历史记录
  • 删除会话
  • 获取用户会话列表

12.2 为什么 AI 项目也必须看它

因为 Agent 和 RAG 的多轮体验离不开会话管理。

如果没有这个文件:

  • 每次对话都是无记忆的
  • 无法查看历史
  • 无法继续之前的话题

12.3 你要重点理解的点

这里把数据库中的消息重新组装成:

  • (user_message, assistant_message) 的历史结构

然后给 Agent 使用。

这说明:

持久化存储层和 LangChain 的聊天历史层是连接在一起的


13. 第十站:backend/app/models/chat_history.py

这个文件定义了数据库模型。

13.1 有哪些表

主要有两张表:

  • ChatSession
  • ChatMessage

13.2 各自负责什么

ChatSession

负责保存会话本身的信息,例如:

  • 会话 ID
  • 用户 ID
  • 标题
  • 创建时间
  • 更新时间
ChatMessage

负责保存具体消息,例如:

  • 属于哪个会话
  • 角色是 user 还是 assistant
  • 文本内容
  • 创建时间

13.3 为什么它重要

因为它决定了“聊天历史在数据库中长什么样”。

如果你以后要加:

  • 多角色
  • 消息元数据
  • 消息附件
  • 更复杂会话状态

通常都要从这里入手。


14. 第十一站:backend/app/db/db_config.py

这个文件负责数据库连接。

14.1 它做了什么

主要包括:

  • 读取 MySQL 连接配置
  • 创建异步引擎
  • 创建异步 Session 工厂
  • 初始化数据库表
  • 提供数据库依赖
  • 检查数据库连接健康状态

14.2 为什么要知道它

因为你会经常遇到这种情况:

  • 项目启动失败
  • 表没创建出来
  • MySQL 连不上

这时候这个文件就是排查入口之一。


15. 第十二站:backend/app/core/rate_limit.py

这是限流逻辑。

15.1 它的作用

避免接口被高频刷爆。

15.2 它分成两层

  1. 路由依赖级限流
  2. 全局中间件限流

15.3 为什么它跟 AI 服务特别相关

因为 AI 请求通常:

  • 更贵
  • 更耗时
  • 更吃资源

所以限流比普通 CRUD 服务更有必要。


16. 第十三站:backend/app/router/user.py

这个文件是用户信息接口。

16.1 它在 AI 主链路里有什么意义

它本身不是 RAG 或 Agent 主体,但它说明:

这个 AI 后端不是孤立的,它要和用户体系打通

例如:

  • 根据 token 获取用户 ID
  • 再去 Redis 查用户信息

这和“会话归属于谁”“上传的知识库属于谁”都有关。


17. 第十四站:backend/app/router/health.py

这个文件是健康检查接口。

17.1 为什么要看它

因为它会告诉你,后端启动后依赖了哪些基础服务:

  • MySQL
  • Redis

如果这两个服务不通,系统就绪检查会失败。

对于部署和排障很重要。


18. 第十五站:backend/app/utils/factory.py

这是模型工厂文件。

18.1 它做了什么

主要负责统一创建:

  • 聊天模型
  • embedding 模型

18.2 为什么要用工厂

因为模型实例的创建最好集中管理。

这样做的好处:

  • 配置统一
  • 更容易替换模型
  • 业务代码不必到处写初始化细节

18.3 这个文件在整体链路中的位置

它相当于:

给 RAG 和 Agent 提供“模型来源”


19. 第十六站:backend/app/utils/config.py

这是配置加载入口。

19.1 它加载了哪些配置

  • rag.yaml
  • chroma.yaml
  • prompt.yaml
  • agent.yaml

19.2 为什么它重要

因为你以后调项目时,很多效果和行为都不是改 Python 代码,而是改这里对应的 YAML。

例如:

  • 模型名字
  • 向量库目录
  • chunk 大小
  • prompt 文件位置

这就是典型的“配置驱动”设计。


20. 第十七站:backend/app/utils/prompt_loader.py

这个文件专门负责读取 Prompt 文件。

20.1 为什么单独做这个文件

因为 Prompt 在 AI 项目里地位很高。

单独封装后:

  • 更好维护
  • 更方便换模板
  • 更利于配置化

20.2 你看这个文件时要理解什么

它说明 Prompt 不是写死在业务代码中的,而是:

  • 先在 YAML 中配置路径
  • 再按类型加载文本模板

这是一种很常见的 AI 工程实践。


21. 第十八站:backend/app/schemas/models.py

这是请求响应模型定义文件。

21.1 它有什么作用

主要定义了:

  • 查询请求体
  • RAG 请求体
  • 会话响应结构
  • Agent 步骤结构
  • 重排序请求和响应结构

21.2 为什么这个文件也值得看

因为它能帮助你快速知道:

每个接口收什么、回什么

特别是 AgentStep 很有代表性,它说明这个项目不仅返回最终答案,还可以保留 Agent 中间步骤。


22. AI 主链路一:用户问一个知识库问题时发生了什么

现在我们把前面的文件串起来。

例如用户提问:

公司请假制度是什么?

后端大致流程如下:

  1. 请求进入 chat.py
  2. 路由调用 chat_service.pyhandle_rag_query
  3. handle_rag_query 创建 RagService
  4. RagService 调用 retrieve_document
  5. retrieve_document 通过 VectorStoreService 获取 retriever
  6. retriever 从 Chroma / BM25 混合检索相关文档
  7. reorder_service.py 对候选文档重排序
  8. rag_service.py 使用 Prompt + 模型生成最终总结
  9. 路由把结果返回给前端

你只要把这 9 步记住,RAG 主链路就基本通了。


23. AI 主链路二:用户走 Agent 问答时发生了什么

例如用户问:

先帮我查知识库里的报销制度,再告诉我现在几点。

后端大致流程如下:

  1. 请求进入 chat.py 的 Agent 流式接口
  2. 路由调用 get_agent_stream_response
  3. agent.py 从数据库拿到历史会话
  4. 创建新的 AgentExecutor
  5. Agent 根据用户问题判断需要调用哪些工具
  6. 如果需要查知识库,就调用 rag_summary_tools
  7. 如果需要查时间,就调用 what_time_is_now
  8. Agent 整合各工具结果形成最终回复
  9. 响应流式返回给前端
  10. 最终回答写入数据库会话

这就是 Agent 主链路。


24. 你可以怎么理解这些目录之间的关系

你可以把整个 backend 想成一个公司组织结构:

24.1 router/

前台接待。

负责:

  • 接请求
  • 看参数
  • 分发给业务层

24.2 services/

业务调度中心。

负责:

  • 把不同模块串起来

24.3 rag/

知识库问答部门。

负责:

  • 检索
  • 向量库
  • 重排序
  • 摘要回答

24.4 agent/

智能助手部门。

负责:

  • 工具调用
  • 多步任务
  • 智能决策

24.5 models/ + db/

数据存储部门。

负责:

  • 会话和消息落库

24.6 utils/

基础工具部门。

负责:

  • 配置
  • Prompt 加载
  • 模型工厂
  • 路径处理

这样理解后,目录就不会显得乱。


25. 初学者看源码时最容易卡住的点

25.1 一上来想逐行看懂

这很容易把自己看崩。

更好的方式是:

  1. 先知道这个文件是干什么的
  2. 再知道它调用了谁
  3. 最后才看具体实现细节

25.2 被 LangChain 类名吓住

比如:

  • ChatPromptTemplate
  • MessagesPlaceholder
  • AgentExecutor
  • EnsembleRetriever

你先不要背 API。

先把它们翻译成人话:

  • Prompt 模板
  • 消息占位符
  • Agent 执行器
  • 混合检索器

这样理解会轻松很多。

25.3 把 RAG 和 Agent 混在一起

一定要分开理解:

  • RAG 负责查知识库再回答
  • Agent 负责决定是否调用工具

但在这个项目里,它们又被组合起来了:

  • RAG 被封成了 Agent 的一个工具

这是理解这个项目 AI 结构的关键点。


26. 你接下来最适合怎么继续看代码

给你一个非常实用的方式。

第一轮:只看函数名和调用关系

目标:

  • 搞清楚“谁调谁”

第二轮:只看 4 个核心文件

重点看:

  • chat_service.py
  • rag_service.py
  • vector_store.py
  • agent.py

目标:

  • 搞懂 AI 主链路

第三轮:再看配置和存储

重点看:

  • factory.py
  • config.py
  • prompt_loader.py
  • database_session_manager.py

目标:

  • 搞懂系统是如何真正跑起来的

第四轮:最后再看优化细节

重点看:

  • HyDE
  • rerank
  • 动态权重
  • 流式输出

目标:

  • 搞懂“为什么这个项目比最基础 demo 更工程化”

27. 一张总图帮你看 backend AI 代码

flowchart TD
    A["main.py 应用入口"] --> B["router/chat.py 接口层"]
    B --> C["router/chat_service.py 业务编排"]

    C --> D["rag/rag_service.py RAG 主流程"]
    D --> E["rag/vector_store.py 知识库与检索"]
    D --> F["rag/reorder_service.py 重排序"]

    C --> G["agent/agent.py Agent 主流程"]
    G --> H["agent/agent_tools.py 工具集合"]
    H --> D

    C --> I["services/database_session_manager.py 会话管理"]
    I --> J["models/chat_history.py 数据模型"]
    J --> K["db/db_config.py MySQL 连接"]

    D --> L["utils/factory.py 模型工厂"]
    G --> L
    D --> M["utils/prompt_loader.py Prompt 加载"]
    G --> M
    L --> N["utils/config.py 配置入口"]

28. 最后做个一句话总结

如果你要用一句话概括这个项目的 backend AI 部分,可以这样说:

这个 backend 以 FastAPI 作为接口层,以 chat_service.py 作为业务编排中心,下面分成 RAG 知识库问答链路和 Agent 多工具调用链路,同时通过数据库会话管理、配置化 Prompt、模型工厂、Redis 限流等基础设施,把 AI 能力做成了一个可运行的工程化服务。

如果你愿意,我下一步还能继续给你补:

  • 《把 backend 关键文件画成调用关系图》
  • 《按源码顺序带你读 rag_service.py
  • 《按源码顺序带你读 agent.py