|
12 | 12 | LOGGER = get_logger(name=__name__) |
13 | 13 |
|
14 | 14 |
|
| 15 | +IBM_EARNINGS_SEARCH_QUERIES_BY_MODE: dict[str, list[str]] = { |
| 16 | + "vector": [ |
| 17 | + "How did IBM perform financially in the fourth quarter of 2025?", |
| 18 | + "What were the main drivers of revenue growth?", |
| 19 | + "What is the company outlook for 2026?", |
| 20 | + "How did profit margins change year over year?", |
| 21 | + "What did leadership say about generative AI and growth?", |
| 22 | + ], |
| 23 | + "keyword": [ |
| 24 | + "What was free cash flow in the fourth quarter?", |
| 25 | + "What was Consulting revenue and segment profit margin?", |
| 26 | + "What was Software revenue and constant currency growth?", |
| 27 | + "What was diluted earnings per share for continuing operations?", |
| 28 | + "What are full-year 2026 expectations for revenue and free cash flow?", |
| 29 | + ], |
| 30 | + "hybrid": [ |
| 31 | + "What was IBM free cash flow and what does the company expect for 2026?", |
| 32 | + "What were segment results for Software and Infrastructure revenue?", |
| 33 | + "What was GAAP gross profit margin and pre-tax income?", |
| 34 | + "What did James Kavanaugh say about 2025 results and 2026 prospects?", |
| 35 | + "What was Consulting revenue and segment profit margin?", |
| 36 | + ], |
| 37 | +} |
| 38 | + |
| 39 | + |
15 | 40 | @pytest.mark.parametrize( |
16 | 41 | "unprivileged_model_namespace, llama_stack_server_config, vector_store", |
17 | 42 | [ |
@@ -113,37 +138,36 @@ def test_vector_stores_search( |
113 | 138 | """ |
114 | 139 | Test vector_stores search functionality using the search endpoint. |
115 | 140 |
|
116 | | - Uses a vector store with pre-uploaded TorchTune documentation files and tests the search API |
117 | | - to retrieve relevant chunks based on query text. Validates that the search |
118 | | - returns relevant results with proper metadata and content. |
| 141 | + Iterates over vector, keyword, and hybrid search modes using |
| 142 | + IBM_EARNINGS_SEARCH_QUERIES_BY_MODE. Validates that each mode returns |
| 143 | + relevant results with proper metadata and content. |
119 | 144 | """ |
120 | 145 |
|
121 | | - search_queries = [ |
122 | | - "What is LoRA fine-tuning?", |
123 | | - "How does quantization work?", |
124 | | - "What are memory optimizations?", |
125 | | - "Tell me about DoRA", |
126 | | - "What is TorchTune?", |
127 | | - ] |
128 | | - |
129 | | - for query in search_queries: |
130 | | - # Use the vector store search endpoint |
131 | | - search_response = unprivileged_llama_stack_client.vector_stores.search( |
132 | | - vector_store_id=vector_store_with_example_docs.id, query=query |
133 | | - ) |
134 | | - |
135 | | - # Validate search response |
136 | | - assert search_response is not None, f"Search response is None for query: {query}" |
137 | | - assert hasattr(search_response, "data"), "Search response missing 'data' attribute" |
138 | | - assert isinstance(search_response.data, list), "Search response data should be a list" |
139 | | - |
140 | | - # Check that we got some results |
141 | | - assert len(search_response.data) > 0, f"No search results returned for query: {query}" |
142 | | - |
143 | | - # Validate each search result |
144 | | - for result in search_response.data: |
145 | | - assert hasattr(result, "content"), "Search result missing 'content' attribute" |
146 | | - assert result.content is not None, "Search result content should not be None" |
147 | | - assert len(result.content) > 0, "Search result content should not be empty" |
148 | | - |
149 | | - LOGGER.info(f"Successfully tested vector store search with {len(search_queries)} queries") |
| 146 | + provider_id = vector_store_with_example_docs.metadata.get("provider_id", "") |
| 147 | + # FAISS does not support hybrid and keyword search modes see: |
| 148 | + # https://github.com/llamastack/llama-stack/blob/main/src/llama_stack/providers/inline/vector_io/faiss/faiss.py#L180-L196 |
| 149 | + search_modes = ["vector"] if provider_id == "faiss" else list(IBM_EARNINGS_SEARCH_QUERIES_BY_MODE) |
| 150 | + |
| 151 | + for search_mode in search_modes: |
| 152 | + queries = IBM_EARNINGS_SEARCH_QUERIES_BY_MODE[search_mode] |
| 153 | + for query in queries: |
| 154 | + search_response = unprivileged_llama_stack_client.vector_stores.search( |
| 155 | + vector_store_id=vector_store_with_example_docs.id, |
| 156 | + query=query, |
| 157 | + search_mode=search_mode, |
| 158 | + max_num_results=10, |
| 159 | + ) |
| 160 | + |
| 161 | + assert search_response is not None, f"Search response is None for mode={search_mode!r} query={query!r}" |
| 162 | + assert hasattr(search_response, "data"), "Search response missing 'data' attribute" |
| 163 | + assert isinstance(search_response.data, list), "Search response data should be a list" |
| 164 | + assert len(search_response.data) > 0, f"No search results for mode={search_mode!r} query={query!r}" |
| 165 | + |
| 166 | + for result in search_response.data: |
| 167 | + assert hasattr(result, "content"), "Search result missing 'content' attribute" |
| 168 | + assert result.content is not None, "Search result content should not be None" |
| 169 | + assert len(result.content) > 0, "Search result content should not be empty" |
| 170 | + |
| 171 | + LOGGER.info(f"Search mode {search_mode!r}: {len(queries)} queries returned results") |
| 172 | + |
| 173 | + LOGGER.info(f"Successfully tested vector store search across modes: {search_modes}") |
0 commit comments