A LlamaIndex index can retain stale text when a source changes but the application keeps using the previously indexed nodes. Refreshing by document ID replaces only the changed document while leaving unrelated index content in place.
The refresh_ref_docs() method compares each incoming document with the hash stored for the same ID. It inserts a missing ID, rebuilds an ID whose text or metadata changed, and skips an unchanged document.
Document identity therefore matters more than the filename or loader used to obtain the text. Keep each doc_id stable across refreshes, use the same embedding model when reloading the index, and persist the storage context after the refresh so another process can load the replacement nodes.
$ python3 -m pip install --upgrade llama-index-core
The environment that builds and serves the index needs this package. The full llama-index package also installs llama-index-core.
Related: How to install LlamaIndex with pip
from pathlib import Path import shutil from llama_index.core import ( Document, MockEmbedding, Settings, StorageContext, VectorStoreIndex, load_index_from_storage, ) Settings.embed_model = MockEmbedding(embed_dim=8) storage_dir = Path("storage") shutil.rmtree(storage_dir, ignore_errors=True)
MockEmbedding makes the test deterministic without an API key. An existing index requires the embedding model that created its stored vectors.
The last line deletes the local storage directory before the test. Retained data requires a disposable storage_dir value and omission of that reset line.
original = Document( text="Escalate payment failures to the billing queue.", id_="support-policy", ) index = VectorStoreIndex.from_documents([original]) index.storage_context.persist(persist_dir=storage_dir)
The explicit support-policy ID is the lookup key that connects the original and replacement documents.
updated = Document( text="Escalate payment failures to the revenue operations queue.", id_="support-policy", )
storage_context = StorageContext.from_defaults(persist_dir=storage_dir) index = load_index_from_storage(storage_context)
refresh_flags = index.refresh_ref_docs([updated])
refresh_ref_docs() returns one Boolean per input document. True means that document was inserted or updated; False means its stored hash already matched.
index.storage_context.persist(persist_dir=storage_dir)
storage_context = StorageContext.from_defaults(persist_dir=storage_dir) index = load_index_from_storage(storage_context) nodes = index.as_retriever(similarity_top_k=1).retrieve("payment failures") print(f"Refresh flags: {refresh_flags}") print(f"Reloaded text: {nodes[0].node.get_content(metadata_mode='none')}")
from pathlib import Path import shutil from llama_index.core import ( Document, MockEmbedding, Settings, StorageContext, VectorStoreIndex, load_index_from_storage, ) Settings.embed_model = MockEmbedding(embed_dim=8) storage_dir = Path("storage") shutil.rmtree(storage_dir, ignore_errors=True) original = Document( text="Escalate payment failures to the billing queue.", id_="support-policy", ) index = VectorStoreIndex.from_documents([original]) index.storage_context.persist(persist_dir=storage_dir) updated = Document( text="Escalate payment failures to the revenue operations queue.", id_="support-policy", ) storage_context = StorageContext.from_defaults(persist_dir=storage_dir) index = load_index_from_storage(storage_context) refresh_flags = index.refresh_ref_docs([updated]) index.storage_context.persist(persist_dir=storage_dir) storage_context = StorageContext.from_defaults(persist_dir=storage_dir) index = load_index_from_storage(storage_context) nodes = index.as_retriever(similarity_top_k=1).retrieve("payment failures") print(f"Refresh flags: {refresh_flags}") print(f"Reloaded text: {nodes[0].node.get_content(metadata_mode='none')}")
$ python3 refresh_updated_documents.py Refresh flags: [True] Reloaded text: Escalate payment failures to the revenue operations queue.