好的,我们可以用几张流程图来帮助理解你提供的 FastAPI + LightRAG 项目代码。
在看流程图之前,请注意代码中的一个重要变化:
在你最新提供的代码中,/query/ 和 /ingest_markdown/ 这两个API接口在每次被调用时,都会重新创建一个全新的 LightRAG 实例并重新初始化它的存储 (await rag_instance.initialize_storages()) 。这与之前我们讨论的在程序启动时创建一个全局共享的 rag_instance 不同。这种做法(每次请求都重新初始化)如果涉及到从磁盘加载大量数据(比如向量索引),可能会导致API响应非常缓慢,效率较低。
尽管如此,下面的流程图会如实反映你当前代码的逻辑。
流程图 1: FastAPI 应用启动流程
这张图展示了当你运行 python serving.py 时,FastAPI应用是如何启动和初始化的。
Code snippet
graph TD
A[开始 FastAPI 应用] --> B{Uvicorn 运行 serving.py};
B --> C[触发 @app.on_event("startup") 事件];
C --> D[执行 startup_event() 函数];
D --> E[尝试初始化全局 rag_instance];
E --> F[调用 initialize_rag_system()];
F --> G[创建 LightRAG 对象 (全局实例)];
G --> H[配置 LightRAG (工作目录, LLM, Embedding等)];
H --> I[调用 current_rag.initialize_storages()];
I --> J[从 WORKING_DIR 加载/初始化存储 (为全局RAG实例)];
J --> K[调用 initialize_pipeline_status()];
K --> L[全局 rag_instance 准备就绪];
L --> M[调用 ingest_initial_markdowns(rag_instance)];
M --> N{在 INITIAL_MARKDOWN_DIR 查找 .md 文件};
N -- 找到文件 --> O[循环遍历每个文件];
O --> P[读取文件内容];
P --> Q["记录日志 'Successfully ingested: ...' \n (注意: 代码中实际的 rag_sys.insert() 被注释掉了,所以这里只是记录日志,并未真正插入数据)"];
Q --> O;
O -- 遍历完成 --> R[记录日志 'Initial ingestion process complete'];
N -- 未找到文件 --> R;
R --> S[记录日志 'Application startup sequence completed'];
S --> T[FastAPI 应用准备好接收请求];
T --> U[启动完成];
解释:
- 应用启动后,会执行
startup_event函数。 - 该函数会调用
initialize_rag_system来创建一个全局的LightRAG实例,并从指定的工作目录 (WORKING_DIR) 加载或初始化其存储。 - 之后,会调用
ingest_initial_markdowns。但请注意,在你提供的代码中,这个函数里实际执行数据插入的rag_sys.insert(...)那行被注释掉了。 所以,启动时它会遍历./口腔_markdowns里的文件并记录“成功导入”的日志,但实际上并没有将这些文件内容插入到全局的rag_instance中。 - 完成后,FastAPI 服务就绪,等待外部请求。
流程图 2: /query/接口请求处理流程
这张图展示了当有用户向 /query/ 接口发送请求时,系统是如何处理的。
Code snippet
graph TD
A[客户端发送 POST 请求到 /query/] --> B[FastAPI 接收请求];
B --> C[解析请求体 QueryRequest (包含 query, mode, stream 参数)];
C --> D[执行 perform_query() 函数];
D --> E["创建全新的、局部的 LightRAG 实例 \n (注意: 不是使用全局实例!)"];
E --> F[配置此局部 LightRAG 实例 (工作目录, LLM, Embedding等)];
F --> G[调用局部 rag_instance.initialize_storages()];
G --> H[从 WORKING_DIR 加载/初始化存储 (为这个新的局部RAG实例)];
H --> I{局部 RAG 实例初始化成功?};
I -- 否 --> J[记录错误, 抛出 HTTPException 503];
J --> Z[结束请求 (错误)];
I -- 是 --> K[记录日志 "Received query..."];
K --> L[创建 QueryParam 对象 (包含 mode, stream)];
L --> M{请求参数 stream 为 True?};
M -- 是 (流式输出) --> N[调用局部 rag_instance.query(stream=True)];
N --> O{返回的是异步生成器?};
O -- 是 --> P[构造并返回 StreamingResponse];
P --> Z1[结束请求 (成功)];
O -- 否 --> Q[记录错误, 抛出 HTTPException 500];
Q --> Z;
M -- 否 (非流式输出) --> R[在线程池中调用局部 rag_instance.query(stream=False)];
R --> S[获取完整的 response_data];
S --> T[返回 JSONResponse {"answer": response_data}];
T --> Z1;
subgraph 查询过程中的错误处理
N ----> X[捕获查询时发生的异常];
R ----> X;
X ----> Y[记录错误, 抛出 HTTPException 500];
Y ----> Z;
end
解释:
- 当
/query/接口收到请求,会进入perform_query函数。 - 关键点: 此函数会忽略启动时创建的全局
rag_instance。它会当场创建一个全新的、局部的LightRAG实例,并立即调用initialize_storages()。这意味着每次查询都会有一次加载/初始化存储的开销。 - 然后,根据请求中的
stream参数,决定是进行流式输出还是普通输出。 - 调用
rag_instance.query()执行查询,并将结果返回给客户端。
流程图 3: /ingest_markdown/接口请求处理流程
这张图展示了当有用户向 /ingest_markdown/ 接口上传文件时,系统是如何处理的。
Code snippet
graph TD
A[客户端发送 POST 请求到 /ingest_markdown/ 并上传 .md 文件] --> B[FastAPI 接收请求];
B --> C[执行 ingest_markdown_file() 函数];
C --> D["创建全新的、局部的 LightRAG 实例 \n (注意: 不是使用全局实例!)"];
D --> E[配置此局部 LightRAG 实例 (工作目录, LLM, Embedding等)];
E --> F[调用局部 rag_instance.initialize_storages()];
F --> G[从 WORKING_DIR 加载/初始化存储 (为这个新的局部RAG实例)];
G --> H{局部 RAG 实例初始化成功?};
H -- 否 --> I[记录错误, 抛出 HTTPException 503];
I --> Z[结束请求 (错误)];
H -- 是 --> J{上传的是 .md 文件?};
J -- 否 --> K[抛出 HTTPException 400 (文件类型错误)];
K --> Z;
J -- 是 --> L[记录日志 "Received file..."];
L --> M[异步读取文件内容];
M --> N[在线程池中调用局部 rag_instance.insert(文件内容)];
N --> O[记录日志 "Successfully ingested file..."];
O --> P[返回 JSONResponse {"message": "File ingested..."}];
P --> Z1[结束请求 (成功)];
subgraph 导入过程中的错误处理
M ----> X[捕获读文件或插入数据时发生的异常];
N ----> X;
X ----> Y[记录错误, 抛出 HTTPException 500];
Y ----> Z;
end
解释:
- 当
/ingest_markdown/接口收到文件上传请求,会进入ingest_markdown_file函数。 - 关键点: 与
/query/接口类似,此函数也会当场创建一个全新的、局部的LightRAG实例,并立即调用initialize_storages()。 - 系统会检查文件是否为
.md格式。 - 如果文件有效,则读取内容,并调用
rag_instance.insert()将数据导入(同样,是在这个新创建的局部实例中)。 - 返回处理结果。
总结与提醒:
- 这些流程图清晰地展示了你当前代码的主要工作路径。
- 请特别注意在
/query/和/ingest_markdown/接口中每次都重新创建和初始化LightRAG实例的做法。 如果initialize_storages()操作比较耗时(比如需要从磁盘加载大的索引文件),这会导致你的API接口响应缓慢。通常更高效的做法是在应用启动时初始化一个全局的LightRAG实例,并在所有请求中复用这个实例。 - 启动时的
ingest_initial_markdowns函数由于insert操作被注释,目前不会实际向全局rag_instance添加数据。
希望这些流程图和解释能帮助你更好地理解代码!
好的,这里重新为你生成之前讨论的三个流程图的 Mermaid 代码。你可以将每一块代码完整地复制粘贴到 Mermaid Live Editor 或其他支持 Mermaid 的工具中查看渲染效果。
这些流程图是根据你之前提供的 Python 代码(特别是 API 接口中每次请求都重新初始化 LightRAG 实例以及启动时 ingest_initial_markdowns 函数中 insert 操作被注释掉的情况)来绘制的。
流程图 1: FastAPI 应用启动流程
Code snippet
graph TD
A[开始 FastAPI 应用] --> B{Uvicorn 运行 serving.py};
B --> C[触发 @app.on_event("startup") 事件];
C --> D[执行 startup_event() 函数];
D --> E[尝试初始化全局 rag_instance];
E --> F[调用 initialize_rag_system()];
F --> G[创建 LightRAG 对象 (全局实例)];
G --> H[配置 LightRAG (工作目录, LLM, Embedding等)];
H --> I[调用 current_rag.initialize_storages()];
I --> J[从 WORKING_DIR 加载/初始化存储 (为全局RAG实例)];
J --> K[调用 initialize_pipeline_status()];
K --> L[全局 rag_instance 准备就绪];
L --> M[调用 ingest_initial_markdowns(rag_instance)];
M --> N{在 INITIAL_MARKDOWN_DIR 查找 .md 文件};
N -- 找到文件 --> O[循环遍历每个文件];
O --> P[读取文件内容];
P --> Q["记录日志 'Successfully ingested: ...' \n (注意: 代码中实际的 rag.insert() 被注释掉了,所以这里仅记录日志)"];
Q --> O;
O -- 遍历完成 --> R[记录日志 'Initial ingestion process complete'];
N -- 未找到文件 --> R;
R --> S[记录日志 'Application startup sequence completed'];
S --> T[FastAPI 应用准备好接收请求];
T --> U[启动完成];
流程图 2: /query/接口请求处理流程
Code snippet
graph TD
A[客户端发送 POST 请求到 /query/] --> B[FastAPI 接收请求];
B --> C[解析 QueryRequest (query, mode, stream)];
C --> D[执行 perform_query() 函数];
D --> E["创建全新的、局部的 LightRAG 实例 \n (注意: 非全局实例!)"];
E --> F[配置局部 LightRAG (工作目录, LLM, Embedding)];
F --> G[调用局部 rag_instance.initialize_storages()];
G --> H[为新的局部RAG实例加载/初始化存储 (来自WORKING_DIR)];
H --> I{局部 RAG 实例初始化成功?};
I -- 否 --> J[记录错误, 抛出 HTTPException 503];
J --> Z[结束请求 (错误)];
I -- 是 --> K[记录日志 "Received query..."];
K --> L[创建 QueryParam 对象 (mode, stream)];
L --> M{请求参数 stream 为 True?};
M -- 是 (流式输出) --> N[调用局部 rag_instance.query(stream=True)];
N --> O{返回的是异步生成器?};
O -- 是 --> P[构造并返回 StreamingResponse];
P --> Z1[结束请求 (成功)];
O -- 否 --> Q[记录错误, 抛出 HTTPException 500];
Q --> Z;
M -- 否 (非流式输出) --> R[在线程池中调用局部 rag_instance.query(stream=False)];
R --> S[获取完整的 response_data];
S --> T[返回 JSONResponse {"answer": response_data}];
T --> Z1;
subgraph 查询过程中的错误处理
N ----> X[捕获查询时发生的异常];
R ----> X;
X ----> Y[记录错误, 抛出 HTTPException 500];
Y ----> Z;
end
流程图 3: /ingest_markdown/接口请求处理流程
Code snippet
graph TD
A[客户端发送 POST 请求到 /ingest_markdown/ 并上传 .md 文件] --> B[FastAPI 接收请求];
B --> C[执行 ingest_markdown_file() 函数];
C --> D["创建全新的、局部的 LightRAG 实例 \n (注意: 非全局实例!)"];
D --> E[配置局部 LightRAG (工作目录, LLM, Embedding)];
E --> F[调用局部 rag_instance.initialize_storages()];
F --> G[为新的局部RAG实例加载/初始化存储 (来自WORKING_DIR)];
G --> H{局部 RAG 实例初始化成功?};
H -- 否 --> I[记录错误, 抛出 HTTPException 503];
I --> Z[结束请求 (错误)];
H -- 是 --> J{上传的是 .md 文件?};
J -- 否 --> K[抛出 HTTPException 400 (文件类型错误)];
K --> Z;
J -- 是 --> L[记录日志 "Received file..."];
L --> M[异步读取文件内容];
M --> N[在线程池中调用局部 rag_instance.insert(文件内容)];
N --> O[记录日志 "Successfully ingested file..."];
O --> P[返回 JSONResponse {"message": "File ingested..."}];
P --> Z1[结束请求 (成功)];
subgraph 导入过程中的错误处理
M ----> X[捕获读文件或插入数据时发生的异常];
N ----> X;
X ----> Y[记录错误, 抛出 HTTPException 500];
Y ----> Z;
end
将这些代码块分别复制到 Mermaid 渲染器中,应该就能看到对应的流程图了。希望这次能顺利渲染!
感谢您的耐心等待!我已重新检查了这三个流程图的 Mermaid 代码,确认它们符合 Mermaid 语法规范。以下是可直接渲染的版本:
流程图 1: FastAPI 应用启动流程(修正版)
graph TD
A[开始 FastAPI 应用] --> B{Uvicorn 运行 serving.py}
B --> C[触发 @app.on_event startup 事件]
C --> D[执行 startup_event 函数]
D --> E[尝试初始化全局 rag_instance]
E --> F[调用 initialize_rag_system]
F --> G[创建 LightRAG 对象]
G --> H[配置 LightRAG 参数]
H --> I[调用 initialize_storages]
I --> J[从 WORKING_DIR 加载存储]
J --> K[初始化 pipeline_status]
K --> L[全局 rag_instance 就绪]
L --> M[调用 ingest_initial_markdowns]
M --> N{存在 .md 文件?}
N -->|是| O[遍历文件]
O --> P[读取文件内容]
P --> Q[记录日志]
Q --> O
N -->|否| R[记录完成日志]
O -->|完成| R
R --> S[启动完成]
流程图 2: /query/接口请求处理(修正版)
graph TD
A[POST /query/] --> B[解析 QueryRequest]
B --> C[执行 perform_query]
C --> D[创建新 LightRAG 实例]
D --> E[初始化存储]
E --> F{初始化成功?}
F -->|否| G[返回503错误]
F -->|是| H[记录查询日志]
H --> I{stream模式?}
I -->|是| J[调用流式查询]
J --> K[返回StreamingResponse]
I -->|否| L[调用普通查询]
L --> M[返回JSONResponse]
subgraph 错误处理
J -.-> N[捕获异常]
L -.-> N
N --> O[返回500错误]
end
流程图 3: /ingest_markdown/接口请求处理(修正版)
graph TD
A[POST /ingest_markdown] --> B[执行 ingest_markdown_file]
B --> C[创建新 LightRAG 实例]
C --> D[初始化存储]
D --> E{初始化成功?}
E -->|否| F[返回503错误]
E -->|是| G{是.md文件?}
G -->|否| H[返回400错误]
G -->|是| I[读取文件内容]
I --> J[调用insert方法]
J --> K[返回成功响应]
subgraph 错误处理
I -.-> L[捕获异常]
J -.-> L
L --> M[返回500错误]
end
修改说明:
- 简化了节点文字内容,避免特殊字符
- 统一使用标准流程图符号
- 确保所有箭头连接明确
- 移除了可能导致解析失败的注释
- 使用更简单的子图语法
这些图表现在应该能在所有标准 Mermaid 环境(如 Mermaid Live Editor)中正常渲染。如果需要进一步调整,可以告诉我具体需求。