What Response contains: text, source nodes
Why this matters
You need to understand what data you get back from queries so you can display both the answer and its sources to users, debug retrieval quality, and verify the LLM didn't hallucinate without grounding.
Explanation
A Response object is what llamaindex returns when you query an index. It contains two critical pieces: the response text (what the LLM generated) and source nodes (the original document chunks that were retrieved and used for context).
When you call index.as_query_engine().query("your question"), the engine retrieves relevant chunks from your documents, sends them to an LLM with your question, and wraps the result in a Response object. The response.response field holds the LLM's text answer. The response.source_nodes field is a list of NodeWithScore objects: each contains the original text chunk (node.get_content()), its similarity score to your query (node.score), and metadata about where it came from.
Use this to build transparent RAG systems where you show users both the answer and which documents backed it up, or to debug why the LLM gave a wrong answer by examining what chunks it actually received.
Analogy
Think of a Response like a court brief: the main text is the lawyer's argument, and the source nodes are the cited case law and evidence in the appendix. You can read the argument alone, but to verify it's correct, you need to check the sources it claims to rely on.
Code
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.llms.openai import OpenAI
import os
os.environ["OPENAI_API_KEY"] = "your-key-here"
Settings.llm = OpenAI(model="gpt-4.1")
Settings.embed_model = OpenAIEmbedding(model="text-embedding-3-small")
documents = SimpleDirectoryReader("./data").load_data()
index = VectorStoreIndex.from_documents(documents)
query_engine = index.as_query_engine()
response = query_engine.query("What are the main benefits of machine learning?")
print(f"Response Text:\n{response.response}")
print(f"\nNumber of Source Nodes: {len(response.source_nodes)}")
for i, node in enumerate(response.source_nodes):
print(f"\nSource {i + 1}:")
print(f" Content: {node.get_content()[:100]}...")
print(f" Score: {node.score:.4f}")
print(f" Metadata: {node.metadata}") Response Text:
Machine learning offers several key benefits: it enables systems to learn from data without explicit programming, improves decision-making through pattern recognition, automates repetitive tasks, and scales efficiently to handle large datasets. It's particularly valuable in domains like healthcare for diagnostics, finance for fraud detection, and marketing for personalization.
Number of Source Nodes: 2
Source 1:
Content: Machine learning is a subset of artificial intelligence that focuses on developing algorithms that can learn from and make predictions or decisions based on data. Unlike traditional programming where rules are explicitly coded, machine learning systems automatically improve their performance through experience...
Score: 0.8234
Metadata: {'file_name': 'ml_basics.txt', 'page_label': '1'}
Source 2:
Content: The benefits of machine learning include automation of complex tasks, improved accuracy in predictions, ability to handle unstructured data like images and text, and the capacity to discover hidden patterns that humans might miss. Organizations leverage ML for competitive advantage...
Score: 0.7891
Metadata: {'file_name': 'ml_applications.txt', 'page_label': '3'} What just happened?
The code created an index from documents, built a query engine, and sent a question to it. The query engine retrieved the 2 most relevant document chunks, sent them to the GPT-4.1 LLM as context, and returned a Response object containing both the LLM's generated text and the source nodes it retrieved. We then printed the response text and looped through each source node to display its content snippet, relevance score, and metadata.
Common gotcha
Developers often forget that response.source_nodes contains the chunks the LLM *actually saw*: not all matching documents. If your source_nodes seem irrelevant, the retrieval failed (wrong similarity threshold or embedding model), not the LLM. Also, node.get_content() returns the chunk text; node.content (without parentheses) returns the Node object itself, which is a common off-by-one mistake.
Error recovery
AttributeError: 'Response' has no attribute 'response'AttributeError: 'NodeWithScore' has no attribute 'get_content'IndexError: list index out of range on source_nodesExperienced dev note
In production RAG systems, always display source_nodes to users: it's how you build trust and catch hallucinations. More importantly, log the scores: if scores are all < 0.6, your retrieval is weak and the LLM's answer is unreliable. Use source_nodes as a quality signal, not just a citation tool. Also, the Response object is lazy: accessing response.source_nodes triggers the full query, so don't check it twice if latency matters.
Check your understanding
If your query returned a Response with high-scoring source nodes that contradict the response.response text, what likely happened and how would you debug it?
Show answer hint
A correct answer would identify that the LLM received the correct grounding text but still generated an answer inconsistent with it: meaning the LLM hallucinated or misinterpreted context. Debugging involves checking the exact chunk content the LLM saw (via node.get_content()), verifying the prompt template sent to the LLM, and potentially changing the LLM model or prompt engineering rather than the retrieval.