# RAG 程式筆記
這一行就代表了全部 RAG 的過程
```python
index = VectorStoreIndex.from_documents(documents,show_progress=True)
```
會先進到 from_documents
`
llama_index\core\indices\base.py\BaseIndex\from_documents
`
然後會直接到此處建立儲存上下文的物件 **storage_context**
storage_context 現在是 **None** (預設), 如果之前有儲存此資料時才會需要在.from_documents()中添加 storage_context
```python
# 建立 storage_context 物件
storage_context = storage_context or StorageContext.from_defaults()
```
StorageContext.from_defaults() 位於 `llama_index\core\storage`
此物件可以放的參數是:
```
docstore:文件存儲
index_store:索引存儲
vector_store:向量存儲
graph_store:圖形存儲
image_store:映像存儲
persist_dir:持久目錄 (之前儲存的 index)
```
以上如果沒有放 都會是 None。
當 persist_dir 為 None , 其他存儲格式會是預設值
這邊先看 index_store 跟 vector_store
```
index_store = index_store or SimpleIndexStore()
```
SimpleIndexStore() 其實就是 simple key-value store 簡單鍵值存儲
`llama_index\core\storage\index_store\SimpleIndexStore()`
```
vector_stores = vector_stores or {DEFAULT_VECTOR_STORE: SimpleVectorStore()}
```
storage_context 最後回傳的資料為一個類別的實例
```
return cls(
docstore=docstore,
index_store=index_store,
vector_stores=vector_stores, # type: ignore
graph_store=graph_store,
)
```
接著設定 transformation 物件, 這是用來判斷要使用哪一種方式將文件切割成結點
```python=
transformations = transformations or transformations_from_settings_or_context(
Settings, service_context
)
```
transformations 初始值為 None。
service_context 初始值也為 None。
接著執行 transformations_from_settings_or_context(),
我們有放入 service_comtext 參數, 所以最終會回傳預設的設定:
```python
return settings.transformations
```
而 settings.transformations 的由來是:
```python
self._transformations = [self.node_parser]
```
node_parser 是 SentenceSplitter 物件
```python
self._node_parser = SentenceSplitter()
```
剛才的回傳結果就是下面這個串列
`
[SentenceSplitter(include_metadata=True, include_prev_next_rel=True, callback_manager=<llama_index.core.callbacks.base.CallbackManager object at 0x0000015DC58807C0>, id_func=<function default_id_func at 0x0000015DC233D0D0>, chunk_size=1024, chunk_overlap=200, separator=' ', paragraph_separator='\n\n\n', secondary_chunking_regex='[^,.;。?!]+[,.;。?!]?')]
`
上述寫好了文件切個與行程節點的規則, 稍後會一個個步驟講解。
接著開始為 documents 做標記 id
```python
for doc in documents:
docstore.set_document_hash(doc.get_doc_id(), doc.hash)
```
而 doc.get_doc_id() 的功能就是取得 documents 的 id
```python=
def get_doc_id(self) -> str:
"""TODO: Deprecated: Get document ID."""
return self.id_
```
self.id_ 看起來就像是
`'109f26d7-6f6f-4e3f-b16d-04122bdb3d65'`
第二個參數 doc.hash:
主要是做哈希編碼
```python=
def hash(self) -> str:
doc_identity = str(self.text) + str(self.metadata)
return str(sha256(doc_identity.encode("utf-8", "surrogatepass")).hexdigest())
```
self.text 就是資料裡面所以的文字
`'申請人\r\n本人、父、母、祖父、祖母、戶長、同居人或撫養人。\r\n如係...`
self.metadata 就是資料本身的資訊
`{'file_path': 'C:\\Users\\Admin\\Desktop\\data\\出生地登記.txt', 'file_name': '出生地登記...`
doc.hash 最後回傳值為:
`'7f8e0bce3caef174c6e24cb4e76f33799bc0b6a587eaffd3bfd7301f5623525a'`
參數理解過後, 回到函數
```python
def set_document_hash(self, doc_id: str, doc_hash: str) -> None:
"""Set the hash for a given doc_id."""
metadata = {"doc_hash": doc_hash}
self._kvstore.put(doc_id, metadata, collection=self._metadata_collection)
```
目的是建立一個 doc_hash 的字典, 最後會將 metadata 儲存在 _kvstore.put 裡面, kvstore 就是 SimpleKVStore, 用於儲存 metadata 的類別。
因為我們有多個文件, 所以會有多個 doc
```python
for doc in documents:
docstore.set_document_hash(doc.get_doc_id(), doc.hash)
```
跑完之後就可以儲存完所有 doc 的 metadata
接著我們進行下一步: run_transformations
目的是將切片文件轉換成節點。
```python
nodes = run_transformations(
documents, # type: ignore
transformations,
show_progress=show_progress,
**kwargs,
)
```
我們先來看參數:
documents 就是我們的原始文件, transformations 就是切片的必要資料, show_progress 就是是否輸出切片及轉節點的進度。
show_progress 預設是 False。