|
125 | 125 |
|
126 | 126 | 5. Let's add data source for insurance policy / rental policies, etc. with AI Search
|
127 | 127 |
|
128 |
| - Create a JSON file for car rental policies. Name the file car_rental_policy.json and store it in the data folder along with the flight & hotel policies: |
| 128 | + a) Create a JSON file for car rental policies. Name the file car_rental_policy.json and store it in the data folder along with the flight & hotel policies: |
129 | 129 |
|
130 | 130 | <details>
|
131 | 131 | <summary> Click to expand/collapse</summary>
|
|
153 | 153 | </details>
|
154 | 154 |
|
155 | 155 |
|
156 |
| - Update the plugin to setup Azure OpenAI client for embeddings, create get_embedding method to generate text embeddings. Define the SearchClient class with semantic search functionality and finally initialize the search client. |
| 156 | + b) Update the plugin (car_rental_plugin.py) to setup Azure OpenAI client for embeddings, create get_embedding method to generate text embeddings. Define the SearchClient class with semantic search functionality and finally initialize the search client. |
157 | 157 |
|
158 | 158 | <details>
|
159 | 159 | <summary> Click to expand/collapse</summary>
|
|
196 | 196 |
|
197 | 197 | </details>
|
198 | 198 |
|
199 |
| - Update the Car_Rental_Tools class to include policy search: |
| 199 | + c) Update the Car_Rental_Tools class in the plugin (car_rental_plugin.py) to include policy search: |
200 | 200 |
|
201 | 201 | <details>
|
202 | 202 | <summary> Click to expand/collapse</summary>
|
|
222 | 222 |
|
223 | 223 | </details>
|
224 | 224 |
|
225 |
| - Create an embedding generation script & store it in ./scripts/generate_car_rental_policy_embeddings.py : |
| 225 | + d) Create an embedding generation script called generate_car_rental_policy_embeddings.py & in app/backend/scripts folder: |
226 | 226 |
|
227 | 227 | <details>
|
228 | 228 | <summary> Click to expand/collapse</summary>
|
|
269 | 269 | </details>
|
270 | 270 |
|
271 | 271 |
|
272 |
| - Run the embedding generation script in the terminal |
| 272 | + e) Run the embedding generation script in the terminal |
273 | 273 |
|
274 | 274 | <details>
|
275 | 275 | <summary> Click to expand/collapse</summary>
|
|
278 | 278 | cd c:\Code\multi-modal-customer-service-agent\voice_agent\app\backend
|
279 | 279 | python scripts/generate_car_rental_policy_embeddings.py
|
280 | 280 | ```
|
281 |
| - |
282 | 281 | </details>
|
283 | 282 |
|
284 |
| - The car rental policy search uses the same semantic search approach as the hotel policies. The policies are stored in JSON format with embeddings for efficient semantic search. |
| 283 | + f) After implementation, test with queries about: |
| 284 | + - Insurance coverage options and costs |
| 285 | + - Rental requirements and age restrictions |
| 286 | + - Deductibles and additional coverage options |
| 287 | + |
| 288 | + ### Expand to see the complete car_rental_plugins.py file |
| 289 | + <details> |
| 290 | + <summary> Click to expand/collapse</summary> |
| 291 | + |
| 292 | + ```python |
| 293 | + from typing import Annotated, Any |
| 294 | + from semantic_kernel.functions import kernel_function |
| 295 | + import os |
| 296 | + from openai import AzureOpenAI |
| 297 | + import json |
| 298 | + from scipy import spatial |
| 299 | + |
| 300 | + # Constants for Azure OpenAI |
| 301 | + AZURE_OPENAI_API_KEY = os.getenv("AZURE_OPENAI_API_KEY") |
| 302 | + AZURE_OPENAI_ENDPOINT = os.getenv("AZURE_OPENAI_ENDPOINT") |
| 303 | + AZURE_OPENAI_EMB_DEPLOYMENT = os.getenv("AZURE_OPENAI_EMB_DEPLOYMENT") |
| 304 | + AZURE_OPENAI_EMB_ENDPOINT = os.getenv("AZURE_OPENAI_EMB_ENDPOINT", AZURE_OPENAI_ENDPOINT) |
| 305 | + AZURE_OPENAI_EMB_API_KEY = os.getenv("AZURE_OPENAI_EMB_API_KEY", AZURE_OPENAI_API_KEY) |
| 306 | + AZURE_OPENAI_CHAT_DEPLOYMENT = os.getenv("AZURE_OPENAI_CHAT_DEPLOYMENT") |
| 307 | + |
| 308 | + # Azure OpenAI client setup |
| 309 | + embedding_client = AzureOpenAI( |
| 310 | + api_key=AZURE_OPENAI_EMB_API_KEY, |
| 311 | + azure_endpoint=AZURE_OPENAI_EMB_ENDPOINT, |
| 312 | + api_version="2023-12-01-preview" |
| 313 | + ) |
| 314 | + |
| 315 | + def get_embedding(text: str, model: str = AZURE_OPENAI_EMB_DEPLOYMENT) -> list[float]: |
| 316 | + """Generate text embeddings using Azure OpenAI.""" |
| 317 | + text = text.replace("\n", " ") |
| 318 | + return embedding_client.embeddings.create(input=[text], model=model).data[0].embedding |
285 | 319 |
|
286 |
| - The Car_Rental_Tools class now includes a method to search policies. |
| 320 | + class SearchClient: |
| 321 | + """Client for performing semantic search on a knowledge base.""" |
| 322 | + def __init__(self, emb_map_file_path: str): |
| 323 | + with open(emb_map_file_path) as file: |
| 324 | + self.chunks_emb = json.load(file) |
| 325 | + |
| 326 | + def find_article(self, question: str, topk: int = 3) -> str: |
| 327 | + """Find relevant articles based on cosine similarity.""" |
| 328 | + input_vector = get_embedding(question) |
| 329 | + cosine_list = [ |
| 330 | + (item['id'], item['policy_text'], 1 - spatial.distance.cosine(input_vector, item['policy_text_embedding'])) |
| 331 | + for item in self.chunks_emb |
| 332 | + ] |
| 333 | + cosine_list.sort(key=lambda x: x[2], reverse=True) |
| 334 | + cosine_list = cosine_list[:topk] |
| 335 | + |
| 336 | + return "\n".join(f"{chunk_id}\n{content}" for chunk_id, content, _ in cosine_list) |
287 | 337 |
|
288 |
| - The embedding generation script needs to be run once to prepare the policy data. |
| 338 | + # Initialize the search client |
| 339 | + search_client = SearchClient("./data/car_rental_policy.json") |
289 | 340 |
|
290 |
| - You can expand the policy database by adding more entries to the JSON file. |
| 341 | + # Kernel functions |
| 342 | + class Car_Rental_Tools: |
| 343 | + """Tools for car rental agent to perform various rental operations""" |
| 344 | + |
| 345 | + agent_name = "car_rental_agent" # Name of the agent |
291 | 346 |
|
292 |
| - After implementing these changes: |
| 347 | + @kernel_function( |
| 348 | + description="Search for available rental cars", |
| 349 | + name="search_cars" |
| 350 | + ) |
| 351 | + async def search_cars(self, location: str, pickup_date: str, return_date: str) -> str: |
| 352 | + # Mock implementation - replace with actual car rental API |
| 353 | + return f"Found available cars in {location} from {pickup_date} to {return_date}: \n" \ |
| 354 | + "1. Economy - Toyota Corolla ($45/day)\n" \ |
| 355 | + "2. SUV - Honda CR-V ($65/day)\n" \ |
| 356 | + "3. Luxury - BMW 5 Series ($95/day)" |
293 | 357 |
|
294 |
| - - The car rental agent will be available alongside the hotel and flight agents |
295 |
| - - The agent can be triggered through intent detection |
296 |
| - - The agent will have access to car rental specific tools through its plugin |
297 |
| - - The agent will maintain its own context and persona while handling customer interactions |
| 358 | + @kernel_function( |
| 359 | + description="Get rental car details", |
| 360 | + name="get_car_details" |
| 361 | + ) |
| 362 | + async def get_car_details(self, car_id: str) -> str: |
| 363 | + # Mock implementation |
| 364 | + car_details = { |
| 365 | + "1": "Toyota Corolla: 4 doors, 5 seats, automatic transmission, GPS, bluetooth", |
| 366 | + "2": "Honda CR-V: 5 doors, 5 seats, automatic transmission, GPS, bluetooth, roof rack", |
| 367 | + "3": "BMW 5 Series: 4 doors, 5 seats, automatic transmission, GPS, bluetooth, leather seats" |
| 368 | + } |
| 369 | + return car_details.get(car_id, "Car not found") |
298 | 370 |
|
299 |
| - Test the new agent with various car rental scenarios. |
300 | 371 |
|
301 |
| - Future steps to try on your own. |
302 |
| - - Expand the Car_Rental_Tools class with additional functions as needed. |
303 |
| - - Replace mock implementations with actual car rental API integrations |
| 372 | + @kernel_function( |
| 373 | + name="search_rental_policies", |
| 374 | + description="Search car rental and insurance policies for relevant information." |
| 375 | + ) |
| 376 | + async def search_rental_policies(self, |
| 377 | + search_query: Annotated[str, "The search query about rental or insurance policies."] |
| 378 | + ) -> str: |
| 379 | + return search_client.find_article(search_query) |
| 380 | + ``` |
| 381 | + |
| 382 | + </details> |
| 383 | + |
| 384 | +### Summarizing Exercise 1 - Adding a New Car Rental Agent with Semantic Search |
| 385 | + |
| 386 | +This exercise demonstrates how to extend the voice agent system by adding a completely new domain-specific agent for car rentals, complete with semantic search capabilities for policy information. |
| 387 | + |
| 388 | +#### Files Created: |
| 389 | +- `car_rental_agent_profile.yaml` - Defines the agent's persona and responsibilities |
| 390 | +- `car_rental_plugins.py` - Contains tools for car searching, details, and policy lookups |
| 391 | +- `car_rental_policy.json` - Stores policy data with embeddings for semantic search |
| 392 | +- `scripts/generate_car_rental_policy_embeddings.py` - Script to generate policy embeddings |
| 393 | + |
| 394 | +#### Files Updated: |
| 395 | +- `rtmt.py` - Modified to register and initialize the new car rental agent |
| 396 | +- `utility.py` - Updated to include car rental in intent detection system messages |
| 397 | + |
| 398 | +#### Key Components: |
| 399 | +1. **Agent Profile**: Defines the car rental agent's persona and scope |
| 400 | +2. **Tool Integration**: Custom tools for searching cars, viewing details, and accessing policies |
| 401 | +3. **SearchClient Class**: Implements vector similarity search using cosine distance |
| 402 | +4. **Intent Detection**: Updates to route car rental queries to the specialized agent |
| 403 | + |
| 404 | +#### Integration Benefits: |
| 405 | +- Demonstrates the extensibility of the multi-agent architecture |
| 406 | +- Adds a completely new domain (car rentals) to the existing hotel and flight agents |
| 407 | +- Semantic search provides accurate policy information retrieval |
| 408 | +- Maintains consistent agent experience while expanding capabilities |
| 409 | + |
| 410 | +#### Future Enhancements: |
| 411 | +- Expand the policy database with more detailed entries |
| 412 | +- Add domain-specific tools to the Car_Rental_Tools class |
| 413 | +- Implement actual API integrations to replace mock implementations |
| 414 | +- Create more sophisticated embedding strategies for better matching |
304 | 415 |
|
305 | 416 | ### Exercise 2: debug/fix/commit flow
|
306 | 417 | - scenario which 'fails' from a functionality standpoint -> use observability (tracing in AI Foundry), figure out the problem, change system-prompt/etc., run test suite (local run of Evaluations), then PR
|
|
0 commit comments