|
27 | 27 | "id": "78f8c28c-0fe4-40a5-857d-6f7d9ebb0832", |
28 | 28 | "metadata": {}, |
29 | 29 | "source": [ |
30 | | - "import os\n", |
31 | 30 | "import mlrun\n", |
32 | | - "from langchain_community.callbacks.uptrain_callback import handler\n", |
33 | 31 | "from langchain_community.document_loaders import UnstructuredMarkdownLoader\n", |
34 | 32 | "from langchain_openai import OpenAIEmbeddings\n", |
35 | 33 | "from dotenv import load_dotenv\n", |
|
105 | 103 | "source": [ |
106 | 104 | "warnings.filterwarnings(\"ignore\", category=DeprecationWarning, module=\"pkg_resources\")\n", |
107 | 105 | "\n", |
108 | | - "if not os.environ.get(\"OPENAI_API_KEY\"):\n", |
| 106 | + "openai_available = os.environ.get(\"OPENAI_API_KEY\")\n", |
| 107 | + "\n", |
| 108 | + "if not openai_available:\n", |
109 | 109 | " embeddings = HuggingFaceEmbeddings(model_name=\"sentence-transformers/all-mpnet-base-v2\")\n", |
110 | 110 | "else:\n", |
111 | 111 | " embeddings = OpenAIEmbeddings(model=\"text-embedding-3-small\")\n", |
|
212 | 212 | "from mlrun.serving import ModelRunnerStep\n", |
213 | 213 | "\n", |
214 | 214 | "graph = agent_graph.set_topology(\"flow\", engine=\"async\", exist_ok=True)\n", |
215 | | - "# Step to process the data\n", |
| 215 | + "# Step to process the input this step is there to make it invocation simpler with less arguments\n", |
216 | 216 | "graph.add_step(\n", |
217 | 217 | " name=\"enrich_request\",\n", |
218 | 218 | " handler= \"enrich_request\",\n", |
219 | | - " # full_event=True,\n", |
220 | 219 | ")\n", |
221 | 220 | "\n", |
222 | | - "# Topic and toxicity guardrail router\n", |
| 221 | + "# Topic and toxicity guardrail router (from notebook 2)\n", |
223 | 222 | "guardrails_router = graph.add_step(\n", |
224 | 223 | " \"*ParallelRunMerger\",\n", |
225 | 224 | " name=\"input-guardrails\",\n", |
|
239 | 238 | " method=\"POST\",\n", |
240 | 239 | " url=toxicity_guardrail.get_url(),\n", |
241 | 240 | ")\n", |
| 241 | + "\n", |
| 242 | + "# Filtering accept and reject\n", |
242 | 243 | "graph.add_step(\n", |
243 | 244 | " name=\"guardrail-filter\",\n", |
244 | 245 | " class_name=\"GuardrailsChoice\",\n", |
245 | 246 | " mapping={\"True\": \"accept\", \"False\": \"reject\"},\n", |
246 | 247 | " after=\"input-guardrails\",\n", |
247 | 248 | ")\n", |
248 | | - "graph.add_step(name=\"accept\", handler=\"accept\", after=\"guardrail-filter\")\n", |
249 | 249 | "\n", |
| 250 | + "graph.add_step(name=\"accept\", handler=\"accept\", after=\"guardrail-filter\")\n", |
250 | 251 | "\n", |
251 | 252 | "# Add model runner step to run the sentiment and churn analysis\n", |
252 | 253 | "model_runner_step = ModelRunnerStep(\n", |
253 | 254 | " name=\"input-analysis\",\n", |
254 | 255 | " result_path=\"input_analysis_output\",\n", |
255 | 256 | " )\n", |
256 | | - "\n", |
257 | 257 | "model_runner_step.add_model(\n", |
258 | 258 | " model_class=\"SentimentAnalysisModelServer\",\n", |
259 | 259 | " endpoint_name=\"sentiment_analysis_output\",\n", |
|
270 | 270 | " churn_mappings={\"high\": 0.50, \"medium\": 0.20, \"low\": 0},\n", |
271 | 271 | " result_path=\"churn_model_output\",)\n", |
272 | 272 | "\n", |
273 | | - "graph.add_step(model_runner_step, after=[\"accept\"])\n", |
| 273 | + "graph.add_step(model_runner_step, after=[\"accept\"], full_event= True,)\n", |
274 | 274 | "\n", |
275 | 275 | "\n", |
276 | 276 | "graph.add_step(\n", |
277 | 277 | " name=\"build-context\",\n", |
278 | 278 | " class_name=\"BuildContext\",\n", |
279 | 279 | " context_mappings = {\n", |
280 | | - " \"name\": \"name\",\n", |
281 | | - " \"sentiment\": \"input_analysis_output.sentiment_analysis_output.response[0]\",\n", |
282 | | - " \"churn\": \"input_analysis_output.churn_model_output.response[0]\",\n", |
| 280 | + " \"name\": \"sentiment_analysis_output.name\", # name is nested inside sentiment_analysis_output\n", |
| 281 | + " \"sentiment\": \"sentiment_analysis_output.response[0]\", # direct path, no input_analysis_output wrapper\n", |
| 282 | + " \"churn\": \"churn_model_output.response[0]\", # direct path\n", |
283 | 283 | " },\n", |
284 | 284 | " output_key=\"formatted_prompt\",\n", |
285 | 285 | " prompt=\"\"\"\n", |
|
296 | 296 | " Use the sentiment to craft your response.\n", |
297 | 297 | " \"\"\",\n", |
298 | 298 | " after=\"input-analysis\",\n", |
| 299 | + " full_event= True,\n", |
299 | 300 | ")\n", |
300 | 301 | "# Add the BankingAgent LLM using HF or OpenAI (if OPENAI credentials)\n", |
301 | 302 | "MRS_banking_agent = ModelRunnerStep(name=\"banking-agent\")\n", |
302 | 303 | "\n", |
303 | | - "if not os.environ.get(\"OPENAI_API_KEY\"):\n", |
| 304 | + "if not openai_available:\n", |
304 | 305 | " MRS_banking_agent.add_model(\n", |
305 | 306 | " model_class=\"BankingAgentHuggingFace\",\n", |
306 | 307 | " endpoint_name=\"BankingAgentHuggingFace\",\n", |
307 | 308 | " execution_mechanism=\"naive\",\n", |
308 | | - " model_name=os.environ.get(\"HF_MODEL_NAME\", \"mistralai/Mistral-7B-Instruct-v0.2\"),\n", |
| 309 | + " model_name=os.environ.get(\"HF_MODEL_NAME\", \"Qwen/Qwen2.5-1.5B-Instruct\"),\n", |
309 | 310 | " prompt_input_key=\"formatted_prompt\",\n", |
310 | 311 | " messages_input_key=\"inputs\",\n", |
311 | 312 | " max_new_tokens=256,\n", |
|
347 | 348 | "outputs": [], |
348 | 349 | "execution_count": null |
349 | 350 | }, |
| 351 | + { |
| 352 | + "metadata": {}, |
| 353 | + "cell_type": "markdown", |
| 354 | + "source": "### Since running the LLM model is very resource demanding some systems can't run it locally so we will use the mock server only with OpenAI", |
| 355 | + "id": "294bec722b745a15" |
| 356 | + }, |
350 | 357 | { |
351 | 358 | "cell_type": "code", |
352 | 359 | "id": "a7b33baa-d143-49a9-8007-6bade49b6813", |
353 | 360 | "metadata": {}, |
354 | | - "source": "mock = agent_graph.to_mock_server()", |
| 361 | + "source": [ |
| 362 | + "if openai_available:\n", |
| 363 | + " mock = agent_graph.to_mock_server()" |
| 364 | + ], |
355 | 365 | "outputs": [], |
356 | 366 | "execution_count": null |
357 | 367 | }, |
|
390 | 400 | "id": "a8f936c3-2776-4b4c-b18e-184a94fc4c8d", |
391 | 401 | "metadata": {}, |
392 | 402 | "source": [ |
393 | | - "resp = mock.test(\n", |
394 | | - " path=\"/\",\n", |
395 | | - " body={\n", |
396 | | - " \"name\": \"John\",\n", |
397 | | - " \"inputs\": [_format_question(\"What is a mortgage, from the bank?\")],\n", |
398 | | - " \"user_id\": LOW_PROPENSITY_CHURN_USER_ID,\n", |
399 | | - " },\n", |
400 | | - ")\n", |
401 | | - "print(resp[\"outputs\"][0])" |
| 403 | + "if openai_available:\n", |
| 404 | + " resp = mock.test(\n", |
| 405 | + " path=\"/\",\n", |
| 406 | + " body={\n", |
| 407 | + " \"name\": \"John\",\n", |
| 408 | + " \"inputs\": [_format_question(\"What is a mortgage, from the bank?\")],\n", |
| 409 | + " \"user_id\": LOW_PROPENSITY_CHURN_USER_ID,\n", |
| 410 | + " },\n", |
| 411 | + " )\n", |
| 412 | + " print(resp[\"outputs\"][0])" |
402 | 413 | ], |
403 | 414 | "outputs": [], |
404 | 415 | "execution_count": null |
|
416 | 427 | "id": "6406eeea-1849-4aab-b6f0-a7e1d1f18138", |
417 | 428 | "metadata": {}, |
418 | 429 | "source": [ |
419 | | - "resp = mock.test(\n", |
420 | | - " path=\"/\",\n", |
421 | | - " body={\n", |
422 | | - " \"name\": \"John\",\n", |
423 | | - " \"inputs\": [_format_question(\"i hate you\")],\n", |
424 | | - " \"user_id\": LOW_PROPENSITY_CHURN_USER_ID,\n", |
425 | | - " },\n", |
426 | | - ")\n", |
427 | | - "print(resp[\"outputs\"][0])" |
| 430 | + "if openai_available:\n", |
| 431 | + " resp = mock.test(\n", |
| 432 | + " path=\"/\",\n", |
| 433 | + " body={\n", |
| 434 | + " \"name\": \"John\",\n", |
| 435 | + " \"inputs\": [_format_question(\"i hate you\")],\n", |
| 436 | + " \"user_id\": LOW_PROPENSITY_CHURN_USER_ID,\n", |
| 437 | + " },\n", |
| 438 | + " )\n", |
| 439 | + " print(resp[\"outputs\"][0])" |
428 | 440 | ], |
429 | 441 | "outputs": [], |
430 | 442 | "execution_count": null |
|
450 | 462 | "id": "93faf1a7-48d4-46c5-8571-03b90d2ce7b9", |
451 | 463 | "metadata": {}, |
452 | 464 | "source": [ |
453 | | - "resp = mock.test(\n", |
454 | | - " path=\"/\",\n", |
455 | | - " body={\n", |
456 | | - " \"name\": \"John\",\n", |
457 | | - " \"inputs\": [_format_question(\"how to apply for checking account?\")],\n", |
458 | | - " \"user_id\": LOW_PROPENSITY_CHURN_USER_ID,\n", |
459 | | - " },\n", |
460 | | - ")\n", |
461 | | - "print(resp[\"outputs\"][0])" |
| 465 | + "if openai_available:\n", |
| 466 | + " resp = mock.test(\n", |
| 467 | + " path=\"/\",\n", |
| 468 | + " body={\n", |
| 469 | + " \"name\": \"John\",\n", |
| 470 | + " \"inputs\": [_format_question(\"how to apply for checking account?\")],\n", |
| 471 | + " \"user_id\": LOW_PROPENSITY_CHURN_USER_ID,\n", |
| 472 | + " },\n", |
| 473 | + " )\n", |
| 474 | + " print(resp[\"outputs\"][0])" |
462 | 475 | ], |
463 | 476 | "outputs": [], |
464 | 477 | "execution_count": null |
|
476 | 489 | "id": "91d0ebe4-9c8c-4463-857e-1cd61ea42a1e", |
477 | 490 | "metadata": {}, |
478 | 491 | "source": [ |
479 | | - "resp = mock.test(\n", |
480 | | - " path=\"/\",\n", |
481 | | - " body={\n", |
482 | | - " \"name\": \"John\",\n", |
483 | | - " \"inputs\": [\n", |
484 | | - " _format_question(\n", |
485 | | - " \"how to apply for checking account? I keep trying but I'm really frustrated\"\n", |
486 | | - " )\n", |
487 | | - " ],\n", |
488 | | - " \"user_id\": LOW_PROPENSITY_CHURN_USER_ID,\n", |
489 | | - " },\n", |
490 | | - ")\n", |
491 | | - "print(resp[\"outputs\"][0])" |
| 492 | + "if openai_available:\n", |
| 493 | + " resp = mock.test(\n", |
| 494 | + " path=\"/\",\n", |
| 495 | + " body={\n", |
| 496 | + " \"name\": \"John\",\n", |
| 497 | + " \"inputs\": [\n", |
| 498 | + " _format_question(\n", |
| 499 | + " \"how to apply for checking account? I keep trying but I'm really frustrated\"\n", |
| 500 | + " )\n", |
| 501 | + " ],\n", |
| 502 | + " \"user_id\": LOW_PROPENSITY_CHURN_USER_ID,\n", |
| 503 | + " },\n", |
| 504 | + " )\n", |
| 505 | + " print(resp[\"outputs\"][0])" |
492 | 506 | ], |
493 | 507 | "outputs": [], |
494 | 508 | "execution_count": null |
|
514 | 528 | "id": "79d62a7c-02d7-41cc-8b23-a8a418284db3", |
515 | 529 | "metadata": {}, |
516 | 530 | "source": [ |
517 | | - "resp = mock.test(\n", |
518 | | - " path=\"/\",\n", |
519 | | - " body={\n", |
520 | | - " \"name\": \"Alice\",\n", |
521 | | - " \"inputs\": [\n", |
522 | | - " {\"role\": \"user\", \"content\": \"Hi—how do I open a checking account?\"},\n", |
523 | | - " {\n", |
524 | | - " \"role\": \"assistant\",\n", |
525 | | - " \"content\": \"To open a checking account, you need two forms of ID and a minimum deposit of $25.\",\n", |
526 | | - " },\n", |
527 | | - " {\"role\": \"user\", \"content\": \"Is it possible to get cashback rewards?\"},\n", |
528 | | - " ],\n", |
529 | | - " \"user_id\": HIGH_PROPENSITY_CHURN_USER_ID, # <-- High churn propensity user\n", |
530 | | - " },\n", |
531 | | - ")\n", |
532 | | - "print(resp[\"outputs\"][0])" |
| 531 | + "if openai_available:\n", |
| 532 | + " resp = mock.test(\n", |
| 533 | + " path=\"/\",\n", |
| 534 | + " body={\n", |
| 535 | + " \"name\": \"Alice\",\n", |
| 536 | + " \"inputs\": [\n", |
| 537 | + " {\"role\": \"user\", \"content\": \"Hi—how do I open a checking account?\"},\n", |
| 538 | + " {\n", |
| 539 | + " \"role\": \"assistant\",\n", |
| 540 | + " \"content\": \"To open a checking account, you need two forms of ID and a minimum deposit of $25.\",\n", |
| 541 | + " },\n", |
| 542 | + " {\"role\": \"user\", \"content\": \"Is it possible to get cashback rewards?\"},\n", |
| 543 | + " ],\n", |
| 544 | + " \"user_id\": HIGH_PROPENSITY_CHURN_USER_ID, # <-- High churn propensity user\n", |
| 545 | + " },\n", |
| 546 | + " )\n", |
| 547 | + " print(resp[\"outputs\"][0])" |
533 | 548 | ], |
534 | 549 | "outputs": [], |
535 | 550 | "execution_count": null |
|
549 | 564 | "id": "24825160-fb6a-4852-b357-accd6106c033", |
550 | 565 | "metadata": {}, |
551 | 566 | "source": [ |
552 | | - "resp" |
| 567 | + "if openai_available:\n", |
| 568 | + " resp" |
553 | 569 | ], |
554 | 570 | "outputs": [], |
555 | 571 | "execution_count": null |
|
584 | 600 | " path=\"/\",\n", |
585 | 601 | " body={\n", |
586 | 602 | " \"name\": \"Alice\",\n", |
587 | | - " \"inputs\": [\n", |
588 | | - " {\"role\": \"user\", \"content\": \"Hi—how do I open a checking account?\"},\n", |
589 | | - " {\n", |
590 | | - " \"role\": \"assistant\",\n", |
591 | | - " \"content\": \"To open a checking account, you need two forms of ID and a minimum deposit of $25.\",\n", |
592 | | - " },\n", |
593 | | - " {\"role\": \"user\", \"content\": \"Is it possible to get cashback rewards?\"},\n", |
594 | | - " ],\n", |
595 | | - " \"questions\": [\n", |
596 | | - " {\"role\": \"user\", \"content\": \"Hi—how do I open a checking account?\"},\n", |
597 | | - " {\n", |
598 | | - " \"role\": \"assistant\",\n", |
599 | | - " \"content\": \"To open a checking account, you need two forms of ID and a minimum deposit of $25.\",\n", |
600 | | - " },\n", |
601 | | - " {\"role\": \"user\", \"content\": \"Is it possible to get cashback rewards?\"},\n", |
602 | | - " ],\n", |
| 603 | + " \"inputs\": [{\"role\": \"user\", \"content\": \"Hi, how do I open a checking account?\"}],\n", |
603 | 604 | " \"user_id\": HIGH_PROPENSITY_CHURN_USER_ID, # <-- High churn propensity user\n", |
604 | 605 | " },\n", |
605 | 606 | ")\n", |
|
608 | 609 | "outputs": [], |
609 | 610 | "execution_count": null |
610 | 611 | }, |
| 612 | + { |
| 613 | + "metadata": {}, |
| 614 | + "cell_type": "code", |
| 615 | + "outputs": [], |
| 616 | + "execution_count": null, |
| 617 | + "source": [ |
| 618 | + "resp = agent_graph.invoke(\n", |
| 619 | + " path=\"/\",\n", |
| 620 | + " body={\n", |
| 621 | + " \"name\": \"Alice\",\n", |
| 622 | + " \"inputs\": [{\"role\": \"user\", \"content\": \"what is a mortgage?\"}],\n", |
| 623 | + " \"user_id\": HIGH_PROPENSITY_CHURN_USER_ID, # <-- High churn propensity user\n", |
| 624 | + " },\n", |
| 625 | + ")\n", |
| 626 | + "print(resp)" |
| 627 | + ], |
| 628 | + "id": "b77bcfda7be45b56" |
| 629 | + }, |
611 | 630 | { |
612 | 631 | "cell_type": "markdown", |
613 | 632 | "id": "53049435-bde9-4d5c-9313-f2af716cb1ee", |
|
0 commit comments