main
py 225 lines 6.71 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 """RAG (Retrieval Augmented Generation) Implementation with LlamaIndex
4 ================================================================
5
6 This script demonstrates a RAG system using:
7 - LlamaIndex: For document indexing and retrieval
8 - Milvus: As vector store backend
9 - vLLM: For embedding and text generation
10
11 Features:
12 1. Document Loading & Processing
13 2. Embedding & Storage
14 3. Query Processing
15
16 Requirements:
17 1. Install dependencies:
18 pip install llama-index llama-index-readers-web \
19 llama-index-llms-openai-like \
20 llama-index-embeddings-openai-like \
21 llama-index-vector-stores-milvus \
22
23 2. Start services:
24 # Start embedding service (port 8000)
25 vllm serve ssmits/Qwen2-7B-Instruct-embed-base
26
27 # Start chat service (port 8001)
28 vllm serve qwen/Qwen1.5-0.5B-Chat --port 8001
29
30 Usage:
31 python retrieval_augmented_generation_with_llamaindex.py
32
33 Notes:
34 - Ensure both vLLM services are running before executing
35 - Default ports: 8000 (embedding), 8001 (chat)
36 - First run may take time to download models
37
38 """
39
40 import argparse
41 from argparse import Namespace
42 from typing import Any
43
44 from llama_index.core import Settings, StorageContext, VectorStoreIndex
45 from llama_index.core.node_parser import SentenceSplitter
46 from llama_index.embeddings.openai_like import OpenAILikeEmbedding
47 from llama_index.llms.openai_like import OpenAILike
48 from llama_index.readers.web import SimpleWebPageReader
49 from llama_index.vector_stores.milvus import MilvusVectorStore
50
51
52 def init_config(args: Namespace):
53 """Initialize configuration with command line arguments."""
54 return {
55 "url": args.url,
56 "embedding_model": args.embedding_model,
57 "chat_model": args.chat_model,
58 "vllm_api_key": args.vllm_api_key,
59 "embedding_endpoint": args.embedding_endpoint,
60 "chat_endpoint": args.chat_endpoint,
61 "db_path": args.db_path,
62 "chunk_size": args.chunk_size,
63 "chunk_overlap": args.chunk_overlap,
64 "top_k": args.top_k,
65 }
66
67
68 def load_documents(url: str) -> list:
69 """Load and process web documents."""
70 return SimpleWebPageReader(html_to_text=True).load_data([url])
71
72
73 def setup_models(config: dict[str, Any]):
74 """Configure embedding and chat models."""
75 Settings.embed_model = OpenAILikeEmbedding(
76 api_base=config["embedding_endpoint"],
77 api_key=config["vllm_api_key"],
78 model_name=config["embedding_model"],
79 )
80
81 Settings.llm = OpenAILike(
82 model=config["chat_model"],
83 api_key=config["vllm_api_key"],
84 api_base=config["chat_endpoint"],
85 context_window=128000,
86 is_chat_model=True,
87 is_function_calling_model=False,
88 )
89
90 Settings.transformations = [
91 SentenceSplitter(
92 chunk_size=config["chunk_size"],
93 chunk_overlap=config["chunk_overlap"],
94 )
95 ]
96
97
98 def setup_vector_store(db_path: str) -> MilvusVectorStore:
99 """Initialize vector store."""
100 sample_emb = Settings.embed_model.get_text_embedding("test")
101 print(f"Embedding dimension: {len(sample_emb)}")
102 return MilvusVectorStore(uri=db_path, dim=len(sample_emb), overwrite=True)
103
104
105 def create_index(documents: list, vector_store: MilvusVectorStore):
106 """Create document index."""
107 storage_context = StorageContext.from_defaults(vector_store=vector_store)
108 return VectorStoreIndex.from_documents(
109 documents,
110 storage_context=storage_context,
111 )
112
113
114 def query_document(index: VectorStoreIndex, question: str, top_k: int):
115 """Query document with given question."""
116 query_engine = index.as_query_engine(similarity_top_k=top_k)
117 return query_engine.query(question)
118
119
120 def get_parser() -> argparse.ArgumentParser:
121 """Parse command line arguments."""
122 parser = argparse.ArgumentParser(description="RAG with vLLM and LlamaIndex")
123
124 # Add command line arguments
125 parser.add_argument(
126 "--url",
127 default=("https://docs.vllm.ai/en/latest/getting_started/quickstart.html"),
128 help="URL of the document to process",
129 )
130 parser.add_argument(
131 "--embedding-model",
132 default="ssmits/Qwen2-7B-Instruct-embed-base",
133 help="Model name for embeddings",
134 )
135 parser.add_argument(
136 "--chat-model", default="qwen/Qwen1.5-0.5B-Chat", help="Model name for chat"
137 )
138 parser.add_argument(
139 "--vllm-api-key", default="EMPTY", help="API key for vLLM compatible services"
140 )
141 parser.add_argument(
142 "--embedding-endpoint",
143 default="http://localhost:8000/v1",
144 help="Base URL for embedding service",
145 )
146 parser.add_argument(
147 "--chat-endpoint",
148 default="http://localhost:8001/v1",
149 help="Base URL for chat service",
150 )
151 parser.add_argument(
152 "--db-path", default="./milvus_demo.db", help="Path to Milvus database"
153 )
154 parser.add_argument(
155 "-i", "--interactive", action="store_true", help="Enable interactive Q&A mode"
156 )
157 parser.add_argument(
158 "-c",
159 "--chunk-size",
160 type=int,
161 default=1000,
162 help="Chunk size for document splitting",
163 )
164 parser.add_argument(
165 "-o",
166 "--chunk-overlap",
167 type=int,
168 default=200,
169 help="Chunk overlap for document splitting",
170 )
171 parser.add_argument(
172 "-k", "--top-k", type=int, default=3, help="Number of top results to retrieve"
173 )
174
175 return parser
176
177
178 def main():
179 # Parse command line arguments
180 args = get_parser().parse_args()
181
182 # Initialize configuration
183 config = init_config(args)
184
185 # Load documents
186 documents = load_documents(config["url"])
187
188 # Setup models
189 setup_models(config)
190
191 # Setup vector store
192 vector_store = setup_vector_store(config["db_path"])
193
194 # Create index
195 index = create_index(documents, vector_store)
196
197 if args.interactive:
198 print("\nEntering interactive mode. Type 'quit' to exit.")
199 while True:
200 # Get user question
201 question = input("\nEnter your question: ")
202
203 # Check for exit command
204 if question.lower() in ["quit", "exit", "q"]:
205 print("Exiting interactive mode...")
206 break
207
208 # Get and print response
209 print("\n" + "-" * 50)
210 print("Response:\n")
211 response = query_document(index, question, config["top_k"])
212 print(response)
213 print("-" * 50)
214 else:
215 # Single query mode
216 question = "How to install vLLM?"
217 response = query_document(index, question, config["top_k"])
218 print("-" * 50)
219 print("Response:\n")
220 print(response)
221 print("-" * 50)
222
223
224 if __name__ == "__main__":
225 main()