rasa-pro 3.13.0.dev20250612__py3-none-any.whl → 3.13.0rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rasa-pro might be problematic. Click here for more details.
- rasa/__main__.py +0 -3
- rasa/api.py +1 -1
- rasa/cli/dialogue_understanding_test.py +1 -1
- rasa/cli/e2e_test.py +1 -8
- rasa/cli/evaluate.py +1 -1
- rasa/cli/export.py +3 -1
- rasa/cli/llm_fine_tuning.py +12 -11
- rasa/cli/project_templates/defaults.py +133 -0
- rasa/cli/project_templates/tutorial/config.yml +1 -1
- rasa/cli/project_templates/tutorial/endpoints.yml +1 -1
- rasa/cli/run.py +1 -1
- rasa/cli/studio/download.py +1 -23
- rasa/cli/studio/link.py +52 -0
- rasa/cli/studio/pull.py +79 -0
- rasa/cli/studio/push.py +78 -0
- rasa/cli/studio/studio.py +12 -0
- rasa/cli/studio/train.py +0 -1
- rasa/cli/studio/upload.py +8 -0
- rasa/cli/train.py +1 -1
- rasa/cli/utils.py +1 -1
- rasa/cli/x.py +1 -1
- rasa/constants.py +2 -0
- rasa/core/__init__.py +0 -16
- rasa/core/actions/action.py +5 -1
- rasa/core/actions/action_repeat_bot_messages.py +18 -22
- rasa/core/actions/action_run_slot_rejections.py +0 -1
- rasa/core/agent.py +16 -1
- rasa/core/available_endpoints.py +146 -0
- rasa/core/brokers/pika.py +1 -2
- rasa/core/channels/__init__.py +2 -0
- rasa/core/channels/botframework.py +2 -2
- rasa/core/channels/channel.py +2 -2
- rasa/core/channels/development_inspector.py +1 -1
- rasa/core/channels/facebook.py +1 -4
- rasa/core/channels/hangouts.py +8 -5
- rasa/core/channels/inspector/README.md +3 -3
- rasa/core/channels/inspector/dist/assets/{arc-c4b064fc.js → arc-371401b1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-215b5026.js → blockDiagram-38ab4fdb-3f126156.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-2b54a0a3.js → c4Diagram-3d4e48cf-12f22eb7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/channel-f1efda17.js +1 -0
- rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-daacea5f.js → classDiagram-70f12bd4-03b1d386.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-930d4dc2.js → classDiagram-v2-f2320105-84f69d63.js} +1 -1
- rasa/core/channels/inspector/dist/assets/clone-fdf164e2.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-83c206ba.js → createText-2e5e7dd3-ca47fd38.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-b0eb01d0.js → edges-e0da2a9e-f837ca8a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-17586500.js → erDiagram-9861fffd-8717ac54.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-be2a1776.js → flowDb-956e92f1-94f38b83.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-c2120ebd.js → flowDiagram-66a62f08-b616f9fb.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-7d7a1629.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-a6ab5c48.js → flowchart-elk-definition-4a651766-f5d24bb8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-ef613457.js → ganttDiagram-c361ad54-b43ba8d9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-d59185b3.js → gitGraphDiagram-72cf32ee-c3aafaa5.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{graph-0f155405.js → graph-0d0a2c10.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3862675e-d5f1d1b7.js → index-3862675e-58ea0305.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-47737d3a.js → index-cce6f8a1.js} +3 -3
- rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-b07d141f.js → infoDiagram-f8f76790-b8f60461.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-1936d429.js → journeyDiagram-49397b02-95be5545.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-dde8d0f3.js → layout-da885b9b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-0c2c7ee0.js → line-f1c817d3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-35dd89a4.js → linear-d42801e6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-56192851.js → mindmap-definition-fc14e90a-a38923a6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-fc21ed78.js → pieDiagram-8a3498a8-ca6e71e9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-25e98518.js → quadrantDiagram-120e2f19-b290dae9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-546ff1f5.js → requirementDiagram-deff3bca-03f02ceb.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-02d8b82d.js → sankeyDiagram-04a897e0-c49eee40.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-3ca5a92e.js → sequenceDiagram-704730f1-b2cd6a3d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-128ea07c.js → stateDiagram-587899a1-e53a2028.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-95f290af.js → stateDiagram-v2-d93cdb3a-e1982a03.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-4984898a.js → styles-6aaf32cf-d0226ca5.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9a916d00-1bf266ba.js → styles-9a916d00-0e21dc00.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-c10674c1-60521c63.js → styles-c10674c1-9588494e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-a25b6e12.js → svgDrawCommon-08f97a94-be478d4f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-0fc086bf.js → timeline-definition-85554ec2-74631749.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-44ee592e.js → xychartDiagram-e933f94c-a043552f.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +1 -1
- rasa/core/channels/inspector/src/components/RecruitmentPanel.tsx +1 -1
- rasa/core/channels/mattermost.py +1 -1
- rasa/core/channels/rasa_chat.py +2 -4
- rasa/core/channels/rest.py +5 -4
- rasa/core/channels/socketio.py +56 -41
- rasa/core/channels/studio_chat.py +314 -10
- rasa/core/channels/vier_cvg.py +1 -2
- rasa/core/channels/voice_ready/audiocodes.py +2 -9
- rasa/core/channels/voice_stream/asr/azure.py +9 -0
- rasa/core/channels/voice_stream/audiocodes.py +8 -5
- rasa/core/channels/voice_stream/browser_audio.py +1 -1
- rasa/core/channels/voice_stream/genesys.py +2 -2
- rasa/core/channels/voice_stream/jambonz.py +166 -0
- rasa/core/channels/voice_stream/tts/__init__.py +8 -0
- rasa/core/channels/voice_stream/twilio_media_streams.py +17 -5
- rasa/core/channels/voice_stream/voice_channel.py +44 -24
- rasa/core/exporter.py +36 -0
- rasa/core/http_interpreter.py +3 -7
- rasa/core/information_retrieval/faiss.py +18 -11
- rasa/core/information_retrieval/ingestion/faq_parser.py +158 -0
- rasa/core/jobs.py +2 -1
- rasa/core/nlg/contextual_response_rephraser.py +48 -12
- rasa/core/nlg/generator.py +0 -1
- rasa/core/nlg/interpolator.py +2 -3
- rasa/core/nlg/summarize.py +39 -5
- rasa/core/policies/enterprise_search_policy.py +298 -184
- rasa/core/policies/enterprise_search_policy_config.py +241 -0
- rasa/core/policies/enterprise_search_prompt_with_relevancy_check_and_citation_template.jinja2 +64 -0
- rasa/core/policies/flow_policy.py +1 -1
- rasa/core/policies/flows/flow_executor.py +96 -17
- rasa/core/policies/intentless_policy.py +71 -26
- rasa/core/processor.py +104 -51
- rasa/core/run.py +33 -11
- rasa/core/tracker_stores/tracker_store.py +1 -1
- rasa/core/training/interactive.py +1 -1
- rasa/core/utils.py +35 -99
- rasa/dialogue_understanding/coexistence/intent_based_router.py +2 -1
- rasa/dialogue_understanding/coexistence/llm_based_router.py +13 -17
- rasa/dialogue_understanding/commands/__init__.py +4 -0
- rasa/dialogue_understanding/commands/can_not_handle_command.py +2 -0
- rasa/dialogue_understanding/commands/cancel_flow_command.py +6 -2
- rasa/dialogue_understanding/commands/chit_chat_answer_command.py +2 -0
- rasa/dialogue_understanding/commands/clarify_command.py +7 -3
- rasa/dialogue_understanding/commands/command_syntax_manager.py +1 -0
- rasa/dialogue_understanding/commands/correct_slots_command.py +5 -6
- rasa/dialogue_understanding/commands/error_command.py +1 -1
- rasa/dialogue_understanding/commands/human_handoff_command.py +3 -3
- rasa/dialogue_understanding/commands/knowledge_answer_command.py +2 -0
- rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +2 -0
- rasa/dialogue_understanding/commands/set_slot_command.py +15 -5
- rasa/dialogue_understanding/commands/skip_question_command.py +3 -3
- rasa/dialogue_understanding/commands/start_flow_command.py +7 -3
- rasa/dialogue_understanding/commands/utils.py +26 -2
- rasa/dialogue_understanding/generator/__init__.py +7 -1
- rasa/dialogue_understanding/generator/command_generator.py +15 -3
- rasa/dialogue_understanding/generator/command_parser.py +2 -2
- rasa/dialogue_understanding/generator/command_parser_validator.py +63 -0
- rasa/dialogue_understanding/generator/constants.py +2 -2
- rasa/dialogue_understanding/generator/nlu_command_adapter.py +2 -2
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_template.jinja2 +0 -2
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +1 -0
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +1 -0
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_claude_3_5_sonnet_20240620_template.jinja2 +79 -0
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +79 -0
- rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +28 -463
- rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +147 -0
- rasa/dialogue_understanding/generator/single_step/single_step_based_llm_command_generator.py +461 -0
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +11 -64
- rasa/dialogue_understanding/patterns/cancel.py +1 -2
- rasa/dialogue_understanding/patterns/clarify.py +1 -1
- rasa/dialogue_understanding/patterns/correction.py +2 -2
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +37 -25
- rasa/dialogue_understanding/patterns/domain_for_patterns.py +190 -0
- rasa/dialogue_understanding/processor/command_processor.py +11 -12
- rasa/dialogue_understanding/processor/command_processor_component.py +3 -3
- rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +17 -4
- rasa/dialogue_understanding/stack/utils.py +3 -1
- rasa/dialogue_understanding/utils.py +68 -12
- rasa/dialogue_understanding_test/du_test_case.py +1 -1
- rasa/dialogue_understanding_test/du_test_runner.py +4 -22
- rasa/dialogue_understanding_test/test_case_simulation/test_case_tracker_simulator.py +2 -6
- rasa/e2e_test/e2e_test_coverage_report.py +1 -1
- rasa/e2e_test/e2e_test_runner.py +1 -1
- rasa/engine/constants.py +1 -1
- rasa/engine/graph.py +2 -2
- rasa/engine/recipes/default_recipe.py +26 -2
- rasa/engine/validation.py +3 -2
- rasa/hooks.py +0 -28
- rasa/llm_fine_tuning/annotation_module.py +39 -9
- rasa/llm_fine_tuning/conversations.py +3 -0
- rasa/llm_fine_tuning/llm_data_preparation_module.py +66 -49
- rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +5 -7
- rasa/llm_fine_tuning/paraphrasing/rephrase_validator.py +52 -44
- rasa/llm_fine_tuning/paraphrasing_module.py +10 -12
- rasa/llm_fine_tuning/storage.py +4 -4
- rasa/llm_fine_tuning/utils.py +63 -1
- rasa/model_manager/model_api.py +88 -0
- rasa/model_manager/trainer_service.py +4 -4
- rasa/plugin.py +1 -11
- rasa/privacy/__init__.py +0 -0
- rasa/privacy/constants.py +83 -0
- rasa/privacy/event_broker_utils.py +77 -0
- rasa/privacy/privacy_config.py +281 -0
- rasa/privacy/privacy_config_schema.json +86 -0
- rasa/privacy/privacy_filter.py +340 -0
- rasa/privacy/privacy_manager.py +576 -0
- rasa/server.py +23 -2
- rasa/shared/constants.py +18 -0
- rasa/shared/core/command_payload_reader.py +1 -5
- rasa/shared/core/constants.py +4 -3
- rasa/shared/core/domain.py +7 -0
- rasa/shared/core/events.py +38 -10
- rasa/shared/core/flows/constants.py +2 -0
- rasa/shared/core/flows/flow.py +127 -14
- rasa/shared/core/flows/flows_list.py +18 -1
- rasa/shared/core/flows/flows_yaml_schema.json +3 -0
- rasa/shared/core/flows/steps/collect.py +46 -2
- rasa/shared/core/flows/steps/link.py +7 -2
- rasa/shared/core/flows/validation.py +25 -5
- rasa/shared/core/slots.py +28 -0
- rasa/shared/core/training_data/story_reader/yaml_story_reader.py +1 -4
- rasa/shared/exceptions.py +4 -0
- rasa/shared/providers/_configs/azure_openai_client_config.py +6 -2
- rasa/shared/providers/_configs/default_litellm_client_config.py +1 -1
- rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +1 -1
- rasa/shared/providers/_configs/openai_client_config.py +5 -1
- rasa/shared/providers/_configs/rasa_llm_client_config.py +1 -1
- rasa/shared/providers/_configs/self_hosted_llm_client_config.py +1 -1
- rasa/shared/providers/_configs/utils.py +0 -99
- rasa/shared/providers/embedding/_base_litellm_embedding_client.py +3 -0
- rasa/shared/providers/llm/_base_litellm_client.py +5 -2
- rasa/shared/utils/common.py +1 -1
- rasa/shared/utils/configs.py +110 -0
- rasa/shared/utils/constants.py +0 -3
- rasa/shared/utils/llm.py +195 -9
- rasa/shared/utils/pykwalify_extensions.py +0 -9
- rasa/shared/utils/yaml.py +32 -0
- rasa/studio/constants.py +1 -0
- rasa/studio/data_handler.py +11 -4
- rasa/studio/download.py +167 -0
- rasa/studio/link.py +200 -0
- rasa/studio/prompts.py +223 -0
- rasa/studio/pull/__init__.py +0 -0
- rasa/studio/{download/flows.py → pull/data.py} +23 -160
- rasa/studio/{download → pull}/domains.py +1 -1
- rasa/studio/pull/pull.py +235 -0
- rasa/studio/push.py +136 -0
- rasa/studio/train.py +1 -1
- rasa/studio/upload.py +117 -67
- rasa/telemetry.py +82 -25
- rasa/tracing/config.py +3 -4
- rasa/tracing/constants.py +19 -1
- rasa/tracing/instrumentation/attribute_extractors.py +30 -8
- rasa/tracing/instrumentation/instrumentation.py +53 -2
- rasa/tracing/instrumentation/metrics.py +98 -15
- rasa/tracing/metric_instrument_provider.py +75 -3
- rasa/utils/common.py +7 -22
- rasa/utils/log_utils.py +1 -45
- rasa/validator.py +2 -8
- rasa/version.py +1 -1
- {rasa_pro-3.13.0.dev20250612.dist-info → rasa_pro-3.13.0rc1.dist-info}/METADATA +8 -9
- {rasa_pro-3.13.0.dev20250612.dist-info → rasa_pro-3.13.0rc1.dist-info}/RECORD +241 -220
- rasa/anonymization/__init__.py +0 -2
- rasa/anonymization/anonymisation_rule_yaml_reader.py +0 -91
- rasa/anonymization/anonymization_pipeline.py +0 -286
- rasa/anonymization/anonymization_rule_executor.py +0 -266
- rasa/anonymization/anonymization_rule_orchestrator.py +0 -119
- rasa/anonymization/schemas/config.yml +0 -47
- rasa/anonymization/utils.py +0 -118
- rasa/core/channels/inspector/dist/assets/channel-3730f5fd.js +0 -1
- rasa/core/channels/inspector/dist/assets/clone-e847561e.js +0 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-efbbfe00.js +0 -1
- rasa/studio/download/download.py +0 -439
- /rasa/{studio/download → core/information_retrieval/ingestion}/__init__.py +0 -0
- {rasa_pro-3.13.0.dev20250612.dist-info → rasa_pro-3.13.0rc1.dist-info}/NOTICE +0 -0
- {rasa_pro-3.13.0.dev20250612.dist-info → rasa_pro-3.13.0rc1.dist-info}/WHEEL +0 -0
- {rasa_pro-3.13.0.dev20250612.dist-info → rasa_pro-3.13.0rc1.dist-info}/entry_points.txt +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import dataclasses
|
|
1
2
|
import importlib.resources
|
|
2
3
|
import json
|
|
3
4
|
import re
|
|
@@ -9,10 +10,8 @@ from jinja2 import Template
|
|
|
9
10
|
from pydantic import ValidationError
|
|
10
11
|
|
|
11
12
|
import rasa.shared.utils.io
|
|
13
|
+
from rasa.core.available_endpoints import AvailableEndpoints
|
|
12
14
|
from rasa.core.constants import (
|
|
13
|
-
POLICY_MAX_HISTORY,
|
|
14
|
-
POLICY_PRIORITY,
|
|
15
|
-
SEARCH_POLICY_PRIORITY,
|
|
16
15
|
UTTER_SOURCE_METADATA_KEY,
|
|
17
16
|
)
|
|
18
17
|
from rasa.core.information_retrieval import (
|
|
@@ -22,8 +21,15 @@ from rasa.core.information_retrieval import (
|
|
|
22
21
|
create_from_endpoint_config,
|
|
23
22
|
)
|
|
24
23
|
from rasa.core.information_retrieval.faiss import FAISS_Store
|
|
24
|
+
from rasa.core.policies.enterprise_search_policy_config import (
|
|
25
|
+
DEFAULT_EMBEDDINGS_CONFIG,
|
|
26
|
+
DEFAULT_ENTERPRISE_SEARCH_CONFIG,
|
|
27
|
+
DEFAULT_LLM_CONFIG,
|
|
28
|
+
DEFAULT_VECTOR_STORE_TYPE,
|
|
29
|
+
SOURCE_PROPERTY,
|
|
30
|
+
EnterpriseSearchPolicyConfig,
|
|
31
|
+
)
|
|
25
32
|
from rasa.core.policies.policy import Policy, PolicyPrediction
|
|
26
|
-
from rasa.core.utils import AvailableEndpoints
|
|
27
33
|
from rasa.dialogue_understanding.generator.constants import (
|
|
28
34
|
LLM_CONFIG_KEY,
|
|
29
35
|
)
|
|
@@ -49,10 +55,8 @@ from rasa.shared.constants import (
|
|
|
49
55
|
MODEL_CONFIG_KEY,
|
|
50
56
|
MODEL_GROUP_ID_CONFIG_KEY,
|
|
51
57
|
MODEL_NAME_CONFIG_KEY,
|
|
52
|
-
OPENAI_PROVIDER,
|
|
53
|
-
PROMPT_CONFIG_KEY,
|
|
54
58
|
PROVIDER_CONFIG_KEY,
|
|
55
|
-
|
|
59
|
+
RASA_PATTERN_CANNOT_HANDLE_NO_RELEVANT_ANSWER,
|
|
56
60
|
)
|
|
57
61
|
from rasa.shared.core.constants import (
|
|
58
62
|
ACTION_CANCEL_FLOW,
|
|
@@ -75,7 +79,6 @@ from rasa.shared.nlu.training_data.training_data import TrainingData
|
|
|
75
79
|
from rasa.shared.providers.embedding._langchain_embedding_client_adapter import (
|
|
76
80
|
_LangchainEmbeddingClientAdapter,
|
|
77
81
|
)
|
|
78
|
-
from rasa.shared.providers.llm.llm_client import LLMClient
|
|
79
82
|
from rasa.shared.providers.llm.llm_response import LLMResponse, measure_llm_latency
|
|
80
83
|
from rasa.shared.utils.cli import print_error_and_exit
|
|
81
84
|
from rasa.shared.utils.constants import (
|
|
@@ -88,12 +91,9 @@ from rasa.shared.utils.health_check.embeddings_health_check_mixin import (
|
|
|
88
91
|
from rasa.shared.utils.health_check.llm_health_check_mixin import LLMHealthCheckMixin
|
|
89
92
|
from rasa.shared.utils.io import deep_container_fingerprint
|
|
90
93
|
from rasa.shared.utils.llm import (
|
|
91
|
-
DEFAULT_OPENAI_CHAT_MODEL_NAME,
|
|
92
|
-
DEFAULT_OPENAI_EMBEDDING_MODEL_NAME,
|
|
93
94
|
embedder_factory,
|
|
94
95
|
get_prompt_template,
|
|
95
96
|
llm_factory,
|
|
96
|
-
resolve_model_client_config,
|
|
97
97
|
sanitize_message_for_prompt,
|
|
98
98
|
tracker_as_readable_transcript,
|
|
99
99
|
)
|
|
@@ -110,41 +110,10 @@ if TYPE_CHECKING:
|
|
|
110
110
|
|
|
111
111
|
from rasa.utils.log_utils import log_llm
|
|
112
112
|
|
|
113
|
-
|
|
113
|
+
structlogger = structlog.get_logger()
|
|
114
114
|
|
|
115
115
|
dotenv.load_dotenv("./.env")
|
|
116
116
|
|
|
117
|
-
SOURCE_PROPERTY = "source"
|
|
118
|
-
VECTOR_STORE_TYPE_PROPERTY = "type"
|
|
119
|
-
VECTOR_STORE_PROPERTY = "vector_store"
|
|
120
|
-
VECTOR_STORE_THRESHOLD_PROPERTY = "threshold"
|
|
121
|
-
TRACE_TOKENS_PROPERTY = "trace_prompt_tokens"
|
|
122
|
-
CITATION_ENABLED_PROPERTY = "citation_enabled"
|
|
123
|
-
USE_LLM_PROPERTY = "use_generative_llm"
|
|
124
|
-
MAX_MESSAGES_IN_QUERY_KEY = "max_messages_in_query"
|
|
125
|
-
|
|
126
|
-
DEFAULT_VECTOR_STORE_TYPE = "faiss"
|
|
127
|
-
DEFAULT_VECTOR_STORE_THRESHOLD = 0.0
|
|
128
|
-
DEFAULT_VECTOR_STORE = {
|
|
129
|
-
VECTOR_STORE_TYPE_PROPERTY: DEFAULT_VECTOR_STORE_TYPE,
|
|
130
|
-
SOURCE_PROPERTY: "./docs",
|
|
131
|
-
VECTOR_STORE_THRESHOLD_PROPERTY: DEFAULT_VECTOR_STORE_THRESHOLD,
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
DEFAULT_LLM_CONFIG = {
|
|
135
|
-
PROVIDER_CONFIG_KEY: OPENAI_PROVIDER,
|
|
136
|
-
MODEL_CONFIG_KEY: DEFAULT_OPENAI_CHAT_MODEL_NAME,
|
|
137
|
-
TIMEOUT_CONFIG_KEY: 10,
|
|
138
|
-
"temperature": 0.0,
|
|
139
|
-
"max_tokens": 256,
|
|
140
|
-
"max_retries": 1,
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
DEFAULT_EMBEDDINGS_CONFIG = {
|
|
144
|
-
PROVIDER_CONFIG_KEY: OPENAI_PROVIDER,
|
|
145
|
-
"model": DEFAULT_OPENAI_EMBEDDING_MODEL_NAME,
|
|
146
|
-
}
|
|
147
|
-
|
|
148
117
|
ENTERPRISE_SEARCH_PROMPT_FILE_NAME = "enterprise_search_policy_prompt.jinja2"
|
|
149
118
|
ENTERPRISE_SEARCH_CONFIG_FILE_NAME = "config.json"
|
|
150
119
|
|
|
@@ -159,6 +128,15 @@ DEFAULT_ENTERPRISE_SEARCH_PROMPT_WITH_CITATION_TEMPLATE = importlib.resources.re
|
|
|
159
128
|
"rasa.core.policies", "enterprise_search_prompt_with_citation_template.jinja2"
|
|
160
129
|
)
|
|
161
130
|
|
|
131
|
+
DEFAULT_ENTERPRISE_SEARCH_PROMPT_WITH_RELEVANCY_CHECK_AND_CITATION_TEMPLATE = (
|
|
132
|
+
importlib.resources.read_text(
|
|
133
|
+
"rasa.core.policies",
|
|
134
|
+
"enterprise_search_prompt_with_relevancy_check_and_citation_template.jinja2",
|
|
135
|
+
)
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
_ENTERPRISE_SEARCH_ANSWER_NOT_RELEVANT_PATTERN = re.compile(r"\[NO_RAG_ANSWER\]")
|
|
139
|
+
|
|
162
140
|
|
|
163
141
|
class VectorStoreConnectionError(RasaException):
|
|
164
142
|
"""Exception raised for errors in connecting to the vector store."""
|
|
@@ -168,6 +146,12 @@ class VectorStoreConfigurationError(RasaException):
|
|
|
168
146
|
"""Exception raised for errors in vector store configuration."""
|
|
169
147
|
|
|
170
148
|
|
|
149
|
+
@dataclasses.dataclass
|
|
150
|
+
class _RelevancyCheckResponse:
|
|
151
|
+
answer: Optional[str]
|
|
152
|
+
relevant: bool
|
|
153
|
+
|
|
154
|
+
|
|
171
155
|
@DefaultV1Recipe.register(
|
|
172
156
|
DefaultV1Recipe.ComponentType.POLICY_WITH_END_TO_END_SUPPORT, is_trainable=True
|
|
173
157
|
)
|
|
@@ -199,10 +183,7 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
199
183
|
@staticmethod
|
|
200
184
|
def get_default_config() -> Dict[str, Any]:
|
|
201
185
|
"""Returns the default config of the policy."""
|
|
202
|
-
return
|
|
203
|
-
POLICY_PRIORITY: SEARCH_POLICY_PRIORITY,
|
|
204
|
-
VECTOR_STORE_PROPERTY: DEFAULT_VECTOR_STORE,
|
|
205
|
-
}
|
|
186
|
+
return DEFAULT_ENTERPRISE_SEARCH_CONFIG
|
|
206
187
|
|
|
207
188
|
def __init__(
|
|
208
189
|
self,
|
|
@@ -217,76 +198,71 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
217
198
|
"""Constructs a new Policy object."""
|
|
218
199
|
super().__init__(config, model_storage, resource, execution_context, featurizer)
|
|
219
200
|
|
|
220
|
-
|
|
221
|
-
self.config[LLM_CONFIG_KEY] = resolve_model_client_config(
|
|
222
|
-
self.config.get(LLM_CONFIG_KEY), EnterpriseSearchPolicy.__name__
|
|
223
|
-
)
|
|
224
|
-
# Resolve embeddings config
|
|
225
|
-
self.config[EMBEDDINGS_CONFIG_KEY] = resolve_model_client_config(
|
|
226
|
-
self.config.get(EMBEDDINGS_CONFIG_KEY), EnterpriseSearchPolicy.__name__
|
|
227
|
-
)
|
|
201
|
+
parsed_config = EnterpriseSearchPolicyConfig.from_dict(config)
|
|
228
202
|
|
|
229
203
|
# Vector store object and configuration
|
|
230
204
|
self.vector_store = vector_store
|
|
231
|
-
self.vector_store_config =
|
|
232
|
-
|
|
233
|
-
|
|
205
|
+
self.vector_store_config = parsed_config.vector_store_config
|
|
206
|
+
self.vector_search_threshold = parsed_config.vector_store_threshold
|
|
207
|
+
self.vector_store_type = parsed_config.vector_store_type
|
|
234
208
|
|
|
235
|
-
#
|
|
236
|
-
self.embeddings_config =
|
|
237
|
-
self.config[EMBEDDINGS_CONFIG_KEY] or DEFAULT_EMBEDDINGS_CONFIG
|
|
238
|
-
)
|
|
209
|
+
# Resolved embeddings configuration for encoding the search query
|
|
210
|
+
self.embeddings_config = parsed_config.embeddings_config
|
|
239
211
|
|
|
240
|
-
# LLM Configuration for response generation
|
|
241
|
-
self.llm_config =
|
|
212
|
+
# Resolved LLM Configuration for response generation
|
|
213
|
+
self.llm_config = parsed_config.llm_config
|
|
242
214
|
|
|
243
215
|
# Maximum number of turns to include in the prompt
|
|
244
|
-
self.max_history =
|
|
216
|
+
self.max_history = parsed_config.max_history
|
|
245
217
|
|
|
246
218
|
# Maximum number of messages to include in the search query
|
|
247
|
-
self.max_messages_in_query =
|
|
219
|
+
self.max_messages_in_query = parsed_config.max_messages_in_query
|
|
220
|
+
|
|
221
|
+
# Boolean to enable/disable tracing of prompt tokens
|
|
222
|
+
self.trace_prompt_tokens = parsed_config.trace_prompt_tokens
|
|
248
223
|
|
|
249
|
-
#
|
|
250
|
-
self.
|
|
224
|
+
# Boolean to enable/disable the use of LLM for response generation
|
|
225
|
+
self.use_llm = parsed_config.use_generative_llm
|
|
251
226
|
|
|
252
|
-
#
|
|
253
|
-
|
|
227
|
+
# Boolean to enable/disable citation generation. This flag enables citation
|
|
228
|
+
# logic, but it only takes effect if `use_llm` is True.
|
|
229
|
+
self.citation_enabled = parsed_config.enable_citation
|
|
254
230
|
|
|
255
|
-
#
|
|
256
|
-
|
|
231
|
+
# Boolean to enable/disable the use of relevancy check alongside answer
|
|
232
|
+
# generation. This flag enables citation logic, but it only takes effect if
|
|
233
|
+
# `use_llm` is True.
|
|
234
|
+
self.relevancy_check_enabled = parsed_config.check_relevancy
|
|
257
235
|
|
|
236
|
+
# Resolve the prompt template. The prompt will only be used if the 'use_llm' is
|
|
237
|
+
# set to True.
|
|
258
238
|
self.prompt_template = prompt_template or get_prompt_template(
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
)
|
|
264
|
-
self.citation_prompt_template = get_prompt_template(
|
|
265
|
-
self.config.get(PROMPT_CONFIG_KEY),
|
|
266
|
-
DEFAULT_ENTERPRISE_SEARCH_PROMPT_WITH_CITATION_TEMPLATE,
|
|
239
|
+
jinja_file_path=parsed_config.prompt_template,
|
|
240
|
+
default_prompt_template=self._select_default_prompt_template_based_on_features(
|
|
241
|
+
parsed_config.check_relevancy, parsed_config.enable_citation
|
|
242
|
+
),
|
|
267
243
|
log_source_component=EnterpriseSearchPolicy.__name__,
|
|
268
244
|
log_source_method=LOG_COMPONENT_SOURCE_METHOD_INIT,
|
|
269
245
|
)
|
|
270
|
-
# If citation is enabled, use the citation prompt template
|
|
271
|
-
if self.citation_enabled:
|
|
272
|
-
self.prompt_template = self.citation_prompt_template
|
|
273
246
|
|
|
274
247
|
@classmethod
|
|
275
|
-
def _create_plain_embedder(cls,
|
|
248
|
+
def _create_plain_embedder(cls, embeddings_config: Dict[Text, Any]) -> "Embeddings":
|
|
276
249
|
"""Creates an embedder based on the given configuration.
|
|
277
250
|
|
|
251
|
+
Args:
|
|
252
|
+
embeddings_config: A resolved embeddings configuration. Resolved means the
|
|
253
|
+
configuration is either:
|
|
254
|
+
- A reference to a model group that has already been expanded into
|
|
255
|
+
its corresponding configuration using the information from
|
|
256
|
+
`endpoints.yml`, or
|
|
257
|
+
- A full configuration for the embedder defined directly (i.e. not
|
|
258
|
+
relying on model groups or indirections).
|
|
259
|
+
|
|
278
260
|
Returns:
|
|
279
|
-
|
|
261
|
+
The embedder.
|
|
280
262
|
"""
|
|
281
263
|
# Copy the config so original config is not modified
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
config[EMBEDDINGS_CONFIG_KEY] = resolve_model_client_config(
|
|
285
|
-
config.get(EMBEDDINGS_CONFIG_KEY), EnterpriseSearchPolicy.__name__
|
|
286
|
-
)
|
|
287
|
-
client = embedder_factory(
|
|
288
|
-
config.get(EMBEDDINGS_CONFIG_KEY), DEFAULT_EMBEDDINGS_CONFIG
|
|
289
|
-
)
|
|
264
|
+
embeddings_config = embeddings_config.copy()
|
|
265
|
+
client = embedder_factory(embeddings_config, DEFAULT_EMBEDDINGS_CONFIG)
|
|
290
266
|
# Wrap the embedding client in the adapter
|
|
291
267
|
return _LangchainEmbeddingClientAdapter(client)
|
|
292
268
|
|
|
@@ -352,18 +328,18 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
352
328
|
can load the policy from the resource.
|
|
353
329
|
"""
|
|
354
330
|
# Perform health checks for both LLM and embeddings client configs
|
|
355
|
-
self._perform_health_checks(
|
|
356
|
-
|
|
357
|
-
|
|
331
|
+
self._perform_health_checks(
|
|
332
|
+
self.llm_config, self.embeddings_config, "enterprise_search_policy.train"
|
|
333
|
+
)
|
|
358
334
|
|
|
359
335
|
# telemetry call to track training start
|
|
360
336
|
track_enterprise_search_policy_train_started()
|
|
361
337
|
|
|
362
338
|
# validate embedding configuration
|
|
363
339
|
try:
|
|
364
|
-
embeddings = self._create_plain_embedder(self.
|
|
340
|
+
embeddings = self._create_plain_embedder(self.embeddings_config)
|
|
365
341
|
except (ValidationError, Exception) as e:
|
|
366
|
-
|
|
342
|
+
structlogger.error(
|
|
367
343
|
"enterprise_search_policy.train.embedder_instantiation_failed",
|
|
368
344
|
message="Unable to instantiate the embedding client.",
|
|
369
345
|
error=e,
|
|
@@ -373,21 +349,25 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
373
349
|
f"required environment variables. Error: {e}"
|
|
374
350
|
)
|
|
375
351
|
|
|
376
|
-
if
|
|
377
|
-
|
|
352
|
+
if self.vector_store_type == DEFAULT_VECTOR_STORE_TYPE:
|
|
353
|
+
structlogger.info("enterprise_search_policy.train.faiss")
|
|
378
354
|
with self._model_storage.write_to(self._resource) as path:
|
|
379
355
|
self.vector_store = FAISS_Store(
|
|
380
356
|
docs_folder=self.vector_store_config.get(SOURCE_PROPERTY),
|
|
381
357
|
embeddings=embeddings,
|
|
382
358
|
index_path=path,
|
|
383
359
|
create_index=True,
|
|
360
|
+
parse_as_faq_pairs=not self.use_llm,
|
|
384
361
|
)
|
|
385
362
|
else:
|
|
386
|
-
|
|
363
|
+
structlogger.info(
|
|
364
|
+
"enterprise_search_policy.train.custom",
|
|
365
|
+
store_type=self.vector_store_type,
|
|
366
|
+
)
|
|
387
367
|
|
|
388
368
|
# telemetry call to track training completion
|
|
389
369
|
track_enterprise_search_policy_train_completed(
|
|
390
|
-
vector_store_type=
|
|
370
|
+
vector_store_type=self.vector_store_type,
|
|
391
371
|
embeddings_type=self.embeddings_config.get(PROVIDER_CONFIG_KEY),
|
|
392
372
|
embeddings_model=self.embeddings_config.get(MODEL_CONFIG_KEY)
|
|
393
373
|
or self.embeddings_config.get(MODEL_NAME_CONFIG_KEY),
|
|
@@ -399,6 +379,7 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
399
379
|
or self.llm_config.get(MODEL_NAME_CONFIG_KEY),
|
|
400
380
|
llm_model_group_id=self.llm_config.get(MODEL_GROUP_ID_CONFIG_KEY),
|
|
401
381
|
citation_enabled=self.citation_enabled,
|
|
382
|
+
relevancy_check_enabled=self.relevancy_check_enabled,
|
|
402
383
|
)
|
|
403
384
|
self.persist()
|
|
404
385
|
return self._resource
|
|
@@ -409,8 +390,11 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
409
390
|
rasa.shared.utils.io.write_text_file(
|
|
410
391
|
self.prompt_template, path / ENTERPRISE_SEARCH_PROMPT_FILE_NAME
|
|
411
392
|
)
|
|
393
|
+
config = self.config.copy()
|
|
394
|
+
config[LLM_CONFIG_KEY] = self.llm_config
|
|
395
|
+
config[EMBEDDINGS_CONFIG_KEY] = self.embeddings_config
|
|
412
396
|
rasa.shared.utils.io.dump_obj_as_json_to_file(
|
|
413
|
-
path / ENTERPRISE_SEARCH_CONFIG_FILE_NAME,
|
|
397
|
+
path / ENTERPRISE_SEARCH_CONFIG_FILE_NAME, config
|
|
414
398
|
)
|
|
415
399
|
|
|
416
400
|
def _prepare_slots_for_template(
|
|
@@ -449,9 +433,8 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
449
433
|
endpoints: Endpoints configuration.
|
|
450
434
|
"""
|
|
451
435
|
config = endpoints.vector_store if endpoints else None
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
logger.error(
|
|
436
|
+
if config is None and self.vector_store_type != DEFAULT_VECTOR_STORE_TYPE:
|
|
437
|
+
structlogger.error(
|
|
455
438
|
"enterprise_search_policy._connect_vector_store_or_raise.no_config"
|
|
456
439
|
)
|
|
457
440
|
raise VectorStoreConfigurationError(
|
|
@@ -461,7 +444,7 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
461
444
|
try:
|
|
462
445
|
self.vector_store.connect(config) # type: ignore
|
|
463
446
|
except Exception as e:
|
|
464
|
-
|
|
447
|
+
structlogger.error(
|
|
465
448
|
"enterprise_search_policy._connect_vector_store_or_raise.connect_error",
|
|
466
449
|
error=e,
|
|
467
450
|
config=config,
|
|
@@ -487,14 +470,14 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
487
470
|
transcript.append(sanitize_message_for_prompt(event.text))
|
|
488
471
|
|
|
489
472
|
search_query = " ".join(transcript[-history:][::-1])
|
|
490
|
-
|
|
473
|
+
structlogger.debug("search_query", search_query=search_query)
|
|
491
474
|
return search_query
|
|
492
475
|
|
|
493
476
|
async def predict_action_probabilities( # type: ignore[override]
|
|
494
477
|
self,
|
|
495
478
|
tracker: DialogueStateTracker,
|
|
496
479
|
domain: Domain,
|
|
497
|
-
endpoints: Optional[AvailableEndpoints],
|
|
480
|
+
endpoints: Optional[AvailableEndpoints] = None,
|
|
498
481
|
rule_only_data: Optional[Dict[Text, Any]] = None,
|
|
499
482
|
**kwargs: Any,
|
|
500
483
|
) -> PolicyPrediction:
|
|
@@ -513,23 +496,20 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
513
496
|
The prediction.
|
|
514
497
|
"""
|
|
515
498
|
logger_key = "enterprise_search_policy.predict_action_probabilities"
|
|
516
|
-
|
|
517
|
-
VECTOR_STORE_THRESHOLD_PROPERTY, DEFAULT_VECTOR_STORE_THRESHOLD
|
|
518
|
-
)
|
|
519
|
-
llm = llm_factory(self.config.get(LLM_CONFIG_KEY), DEFAULT_LLM_CONFIG)
|
|
499
|
+
|
|
520
500
|
if not self.supports_current_stack_frame(
|
|
521
501
|
tracker, False, False
|
|
522
502
|
) or self.should_abstain_in_coexistence(tracker, True):
|
|
523
503
|
return self._prediction(self._default_predictions(domain))
|
|
524
504
|
|
|
525
505
|
if not self.vector_store:
|
|
526
|
-
|
|
506
|
+
structlogger.error(f"{logger_key}.no_vector_store")
|
|
527
507
|
return self._create_prediction_internal_error(domain, tracker)
|
|
528
508
|
|
|
529
509
|
try:
|
|
530
510
|
self._connect_vector_store_or_raise(endpoints)
|
|
531
511
|
except (VectorStoreConfigurationError, VectorStoreConnectionError) as e:
|
|
532
|
-
|
|
512
|
+
structlogger.error(f"{logger_key}.connection_error", error=e)
|
|
533
513
|
return self._create_prediction_internal_error(domain, tracker)
|
|
534
514
|
|
|
535
515
|
search_query = self._prepare_search_query(
|
|
@@ -541,20 +521,19 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
541
521
|
documents = await self.vector_store.search(
|
|
542
522
|
query=search_query,
|
|
543
523
|
tracker_state=tracker_state,
|
|
544
|
-
threshold=vector_search_threshold,
|
|
524
|
+
threshold=self.vector_search_threshold,
|
|
545
525
|
)
|
|
546
526
|
except InformationRetrievalException as e:
|
|
547
|
-
|
|
527
|
+
structlogger.error(f"{logger_key}.search_error", error=e)
|
|
548
528
|
return self._create_prediction_internal_error(domain, tracker)
|
|
549
529
|
|
|
550
530
|
if not documents.results:
|
|
551
|
-
|
|
531
|
+
structlogger.info(f"{logger_key}.no_documents")
|
|
552
532
|
return self._create_prediction_cannot_handle(domain, tracker)
|
|
553
533
|
|
|
554
534
|
if self.use_llm:
|
|
555
535
|
prompt = self._render_prompt(tracker, documents.results)
|
|
556
|
-
llm_response = await self.
|
|
557
|
-
llm_response = LLMResponse.ensure_llm_response(llm_response)
|
|
536
|
+
llm_response = await self._invoke_llm(prompt)
|
|
558
537
|
|
|
559
538
|
self._add_prompt_and_llm_response_to_latest_message(
|
|
560
539
|
tracker=tracker,
|
|
@@ -564,24 +543,38 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
564
543
|
)
|
|
565
544
|
|
|
566
545
|
if llm_response is None or not llm_response.choices:
|
|
567
|
-
|
|
546
|
+
structlogger.debug(f"{logger_key}.no_llm_response")
|
|
568
547
|
response = None
|
|
569
548
|
else:
|
|
570
549
|
llm_answer = llm_response.choices[0]
|
|
571
550
|
|
|
551
|
+
if self.relevancy_check_enabled:
|
|
552
|
+
relevancy_response = self._parse_llm_relevancy_check_response(
|
|
553
|
+
llm_answer
|
|
554
|
+
)
|
|
555
|
+
if not relevancy_response.relevant:
|
|
556
|
+
structlogger.debug(f"{logger_key}.answer_not_relevant")
|
|
557
|
+
return self._create_prediction_cannot_handle(
|
|
558
|
+
domain,
|
|
559
|
+
tracker,
|
|
560
|
+
RASA_PATTERN_CANNOT_HANDLE_NO_RELEVANT_ANSWER,
|
|
561
|
+
)
|
|
562
|
+
|
|
572
563
|
if self.citation_enabled:
|
|
573
564
|
llm_answer = self.post_process_citations(llm_answer)
|
|
574
565
|
|
|
575
|
-
|
|
566
|
+
structlogger.debug(
|
|
567
|
+
f"{logger_key}.llm_answer", prompt=prompt, llm_answer=llm_answer
|
|
568
|
+
)
|
|
576
569
|
response = llm_answer
|
|
577
570
|
else:
|
|
578
571
|
response = documents.results[0].metadata.get("answer", None)
|
|
579
572
|
if not response:
|
|
580
|
-
|
|
573
|
+
structlogger.error(
|
|
581
574
|
f"{logger_key}.answer_key_missing_in_metadata",
|
|
582
575
|
search_results=documents.results,
|
|
583
576
|
)
|
|
584
|
-
|
|
577
|
+
structlogger.debug(
|
|
585
578
|
"enterprise_search_policy.predict_action_probabilities.no_llm",
|
|
586
579
|
search_results=documents,
|
|
587
580
|
)
|
|
@@ -601,7 +594,7 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
601
594
|
|
|
602
595
|
# telemetry call to track policy prediction
|
|
603
596
|
track_enterprise_search_policy_predict(
|
|
604
|
-
vector_store_type=self.
|
|
597
|
+
vector_store_type=self.vector_store_type,
|
|
605
598
|
embeddings_type=self.embeddings_config.get(PROVIDER_CONFIG_KEY),
|
|
606
599
|
embeddings_model=self.embeddings_config.get(MODEL_CONFIG_KEY)
|
|
607
600
|
or self.embeddings_config.get(MODEL_NAME_CONFIG_KEY),
|
|
@@ -613,6 +606,7 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
613
606
|
or self.llm_config.get(MODEL_NAME_CONFIG_KEY),
|
|
614
607
|
llm_model_group_id=self.llm_config.get(MODEL_GROUP_ID_CONFIG_KEY),
|
|
615
608
|
citation_enabled=self.citation_enabled,
|
|
609
|
+
relevancy_check_enabled=self.relevancy_check_enabled,
|
|
616
610
|
)
|
|
617
611
|
return self._create_prediction(
|
|
618
612
|
domain=domain, tracker=tracker, action_metadata=action_metadata
|
|
@@ -636,11 +630,12 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
636
630
|
),
|
|
637
631
|
"docs": documents,
|
|
638
632
|
"slots": self._prepare_slots_for_template(tracker),
|
|
633
|
+
"check_relevancy": self.relevancy_check_enabled,
|
|
639
634
|
"citation_enabled": self.citation_enabled,
|
|
640
635
|
}
|
|
641
636
|
prompt = Template(self.prompt_template).render(**inputs)
|
|
642
637
|
log_llm(
|
|
643
|
-
logger=
|
|
638
|
+
logger=structlogger,
|
|
644
639
|
log_module="EnterpriseSearchPolicy",
|
|
645
640
|
log_event="enterprise_search_policy._render_prompt.prompt_rendered",
|
|
646
641
|
prompt=prompt,
|
|
@@ -648,9 +643,7 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
648
643
|
return prompt
|
|
649
644
|
|
|
650
645
|
@measure_llm_latency
|
|
651
|
-
async def
|
|
652
|
-
self, llm: LLMClient, prompt: Text
|
|
653
|
-
) -> Optional[LLMResponse]:
|
|
646
|
+
async def _invoke_llm(self, prompt: Text) -> Optional[LLMResponse]:
|
|
654
647
|
"""Fetches an LLM completion for the provided prompt.
|
|
655
648
|
|
|
656
649
|
Args:
|
|
@@ -660,17 +653,32 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
660
653
|
Returns:
|
|
661
654
|
An LLMResponse object, or None if the call fails.
|
|
662
655
|
"""
|
|
656
|
+
llm = llm_factory(self.llm_config, DEFAULT_LLM_CONFIG)
|
|
663
657
|
try:
|
|
664
|
-
|
|
658
|
+
response = await llm.acompletion(prompt)
|
|
659
|
+
return LLMResponse.ensure_llm_response(response)
|
|
665
660
|
except Exception as e:
|
|
666
661
|
# unfortunately, langchain does not wrap LLM exceptions which means
|
|
667
662
|
# we have to catch all exceptions here
|
|
668
|
-
|
|
663
|
+
structlogger.error(
|
|
669
664
|
"enterprise_search_policy._generate_llm_answer.llm_error",
|
|
670
665
|
error=e,
|
|
671
666
|
)
|
|
672
667
|
return None
|
|
673
668
|
|
|
669
|
+
def _parse_llm_relevancy_check_response(
|
|
670
|
+
self, llm_answer: str
|
|
671
|
+
) -> _RelevancyCheckResponse:
|
|
672
|
+
"""Checks if the LLM response is relevant by parsing it."""
|
|
673
|
+
answer_relevant = not _ENTERPRISE_SEARCH_ANSWER_NOT_RELEVANT_PATTERN.search(
|
|
674
|
+
llm_answer
|
|
675
|
+
)
|
|
676
|
+
structlogger.debug("")
|
|
677
|
+
return _RelevancyCheckResponse(
|
|
678
|
+
answer=llm_answer if answer_relevant else None,
|
|
679
|
+
relevant=answer_relevant,
|
|
680
|
+
)
|
|
681
|
+
|
|
674
682
|
def _create_prediction(
|
|
675
683
|
self,
|
|
676
684
|
domain: Domain,
|
|
@@ -705,10 +713,18 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
705
713
|
)
|
|
706
714
|
|
|
707
715
|
def _create_prediction_cannot_handle(
|
|
708
|
-
self,
|
|
716
|
+
self,
|
|
717
|
+
domain: Domain,
|
|
718
|
+
tracker: DialogueStateTracker,
|
|
719
|
+
reason: Optional[str] = None,
|
|
709
720
|
) -> PolicyPrediction:
|
|
721
|
+
cannot_handle_stack_frame = (
|
|
722
|
+
CannotHandlePatternFlowStackFrame(reason=reason)
|
|
723
|
+
if reason is not None
|
|
724
|
+
else CannotHandlePatternFlowStackFrame()
|
|
725
|
+
)
|
|
710
726
|
return self._create_prediction_for_pattern(
|
|
711
|
-
domain, tracker,
|
|
727
|
+
domain, tracker, cannot_handle_stack_frame
|
|
712
728
|
)
|
|
713
729
|
|
|
714
730
|
def _create_prediction_for_pattern(
|
|
@@ -767,70 +783,88 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
767
783
|
**kwargs: Any,
|
|
768
784
|
) -> "EnterpriseSearchPolicy":
|
|
769
785
|
"""Loads a trained policy (see parent class for full docstring)."""
|
|
786
|
+
parsed_config = EnterpriseSearchPolicyConfig.from_dict(config)
|
|
787
|
+
|
|
770
788
|
# Perform health checks for both LLM and embeddings client configs
|
|
771
|
-
cls._perform_health_checks(
|
|
789
|
+
cls._perform_health_checks(
|
|
790
|
+
parsed_config.llm_config,
|
|
791
|
+
parsed_config.embeddings_config,
|
|
792
|
+
"enterprise_search_policy.load",
|
|
793
|
+
)
|
|
772
794
|
|
|
773
|
-
prompt_template =
|
|
795
|
+
prompt_template = cls._load_prompt_template(model_storage, resource)
|
|
796
|
+
embeddings = cls._create_plain_embedder(parsed_config.embeddings_config)
|
|
797
|
+
vector_store = cls._load_vector_store(
|
|
798
|
+
embeddings,
|
|
799
|
+
parsed_config.vector_store_type,
|
|
800
|
+
parsed_config.use_generative_llm,
|
|
801
|
+
model_storage,
|
|
802
|
+
resource,
|
|
803
|
+
)
|
|
804
|
+
|
|
805
|
+
structlogger.info("enterprise_search_policy.load", config=config)
|
|
806
|
+
|
|
807
|
+
return cls(
|
|
808
|
+
config,
|
|
809
|
+
model_storage,
|
|
810
|
+
resource,
|
|
811
|
+
execution_context,
|
|
812
|
+
vector_store=vector_store,
|
|
813
|
+
prompt_template=prompt_template,
|
|
814
|
+
)
|
|
815
|
+
|
|
816
|
+
@classmethod
|
|
817
|
+
def _load_prompt_template(
|
|
818
|
+
cls, model_storage: ModelStorage, resource: Resource
|
|
819
|
+
) -> Optional[str]:
|
|
774
820
|
try:
|
|
775
821
|
with model_storage.read_from(resource) as path:
|
|
776
|
-
|
|
822
|
+
return rasa.shared.utils.io.read_file(
|
|
777
823
|
path / ENTERPRISE_SEARCH_PROMPT_FILE_NAME
|
|
778
824
|
)
|
|
779
825
|
except (FileNotFoundError, FileIOException) as e:
|
|
780
|
-
|
|
826
|
+
structlogger.warning(
|
|
781
827
|
"enterprise_search_policy.load.failed", error=e, resource=resource.name
|
|
782
828
|
)
|
|
829
|
+
return None
|
|
783
830
|
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
831
|
+
@classmethod
|
|
832
|
+
def _load_vector_store(
|
|
833
|
+
cls,
|
|
834
|
+
embeddings: "Embeddings",
|
|
835
|
+
store_type: str,
|
|
836
|
+
use_generative_llm: bool,
|
|
837
|
+
model_storage: ModelStorage,
|
|
838
|
+
resource: Resource,
|
|
839
|
+
) -> InformationRetrieval:
|
|
791
840
|
if store_type == DEFAULT_VECTOR_STORE_TYPE:
|
|
792
841
|
# if a vector store is not specified,
|
|
793
842
|
# default to using FAISS with the index stored in the model
|
|
794
843
|
# TODO figure out a way to get path without context manager
|
|
795
844
|
with model_storage.read_from(resource) as path:
|
|
796
|
-
|
|
845
|
+
return FAISS_Store(
|
|
797
846
|
embeddings=embeddings,
|
|
798
847
|
index_path=path,
|
|
799
848
|
docs_folder=None,
|
|
800
849
|
create_index=False,
|
|
850
|
+
parse_as_faq_pairs=not use_generative_llm,
|
|
801
851
|
)
|
|
802
852
|
else:
|
|
803
|
-
|
|
853
|
+
return create_from_endpoint_config(
|
|
804
854
|
config_type=store_type,
|
|
805
855
|
embeddings=embeddings,
|
|
806
|
-
)
|
|
807
|
-
|
|
808
|
-
return cls(
|
|
809
|
-
config,
|
|
810
|
-
model_storage,
|
|
811
|
-
resource,
|
|
812
|
-
execution_context,
|
|
813
|
-
vector_store=vector_store,
|
|
814
|
-
prompt_template=prompt_template,
|
|
815
|
-
)
|
|
856
|
+
)
|
|
816
857
|
|
|
817
858
|
@classmethod
|
|
818
|
-
def _get_local_knowledge_data(
|
|
859
|
+
def _get_local_knowledge_data(
|
|
860
|
+
cls, store_type: str, source: Optional[str] = None
|
|
861
|
+
) -> Optional[List[str]]:
|
|
819
862
|
"""This is required only for local knowledge base types.
|
|
820
863
|
|
|
821
864
|
e.g. FAISS, to ensure that the graph component is retrained when the knowledge
|
|
822
865
|
base is updated.
|
|
823
866
|
"""
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
store_type = merged_config.get(VECTOR_STORE_PROPERTY, {}).get(
|
|
827
|
-
VECTOR_STORE_TYPE_PROPERTY
|
|
828
|
-
)
|
|
829
|
-
if store_type != DEFAULT_VECTOR_STORE_TYPE:
|
|
830
|
-
return None
|
|
831
|
-
|
|
832
|
-
source = merged_config.get(VECTOR_STORE_PROPERTY, {}).get(SOURCE_PROPERTY)
|
|
833
|
-
if not source:
|
|
867
|
+
if store_type != DEFAULT_VECTOR_STORE_TYPE or not source:
|
|
834
868
|
return None
|
|
835
869
|
|
|
836
870
|
docs = FAISS_Store.load_documents(source)
|
|
@@ -846,21 +880,28 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
846
880
|
@classmethod
|
|
847
881
|
def fingerprint_addon(cls, config: Dict[str, Any]) -> Optional[str]:
|
|
848
882
|
"""Add a fingerprint of enterprise search policy for the graph."""
|
|
849
|
-
|
|
883
|
+
parsed_config = EnterpriseSearchPolicyConfig.from_dict(config)
|
|
850
884
|
|
|
885
|
+
# Resolve the prompt template
|
|
886
|
+
default_prompt_template = cls._select_default_prompt_template_based_on_features(
|
|
887
|
+
parsed_config.check_relevancy, parsed_config.enable_citation
|
|
888
|
+
)
|
|
851
889
|
prompt_template = get_prompt_template(
|
|
852
|
-
|
|
853
|
-
|
|
890
|
+
jinja_file_path=parsed_config.prompt_template,
|
|
891
|
+
default_prompt_template=default_prompt_template,
|
|
854
892
|
log_source_component=EnterpriseSearchPolicy.__name__,
|
|
855
893
|
log_source_method=LOG_COMPONENT_SOURCE_METHOD_FINGERPRINT_ADDON,
|
|
856
894
|
)
|
|
857
895
|
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
embedding_config = resolve_model_client_config(
|
|
862
|
-
config.get(EMBEDDINGS_CONFIG_KEY), EnterpriseSearchPolicy.__name__
|
|
896
|
+
# Fetch the local knowledge data in case FAISS is used
|
|
897
|
+
local_knowledge_data = cls._get_local_knowledge_data(
|
|
898
|
+
parsed_config.vector_store_type, parsed_config.vector_store_source
|
|
863
899
|
)
|
|
900
|
+
|
|
901
|
+
# Get the resolved LLM and embeddings configurations
|
|
902
|
+
llm_config = parsed_config.llm_config
|
|
903
|
+
embedding_config = parsed_config.embeddings_config
|
|
904
|
+
|
|
864
905
|
return deep_container_fingerprint(
|
|
865
906
|
[prompt_template, local_knowledge_data, llm_config, embedding_config]
|
|
866
907
|
)
|
|
@@ -878,7 +919,7 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
878
919
|
Returns:
|
|
879
920
|
The post-processed LLM answer.
|
|
880
921
|
"""
|
|
881
|
-
|
|
922
|
+
structlogger.debug(
|
|
882
923
|
"enterprise_search_policy.post_process_citations", llm_answer=llm_answer
|
|
883
924
|
)
|
|
884
925
|
|
|
@@ -958,24 +999,97 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
958
999
|
|
|
959
1000
|
@classmethod
|
|
960
1001
|
def _perform_health_checks(
|
|
961
|
-
cls,
|
|
1002
|
+
cls,
|
|
1003
|
+
llm_config: Dict[Text, Any],
|
|
1004
|
+
embeddings_config: Dict[Text, Any],
|
|
1005
|
+
log_source_method: str,
|
|
962
1006
|
) -> None:
|
|
963
|
-
|
|
964
|
-
|
|
1007
|
+
"""
|
|
1008
|
+
Perform the health checks using resolved LLM and embeddings configurations.
|
|
1009
|
+
Resolved means the configuration is either:
|
|
1010
|
+
- A reference to a model group that has already been expanded into
|
|
1011
|
+
its corresponding configuration using the information from
|
|
1012
|
+
`endpoints.yml`, or
|
|
1013
|
+
- A full configuration for the embedder defined directly (i.e. not
|
|
1014
|
+
relying on model groups or indirections).
|
|
1015
|
+
|
|
1016
|
+
Args:
|
|
1017
|
+
llm_config: A resolved LLM configuration.
|
|
1018
|
+
embeddings_config: A resolved embeddings configuration.
|
|
1019
|
+
log_source_method: The method health checks has been called from.
|
|
1020
|
+
|
|
1021
|
+
"""
|
|
965
1022
|
cls.perform_llm_health_check(
|
|
966
1023
|
llm_config,
|
|
967
1024
|
DEFAULT_LLM_CONFIG,
|
|
968
1025
|
log_source_method,
|
|
969
1026
|
EnterpriseSearchPolicy.__name__,
|
|
970
1027
|
)
|
|
971
|
-
|
|
972
|
-
# Perform health check of the embeddings client config
|
|
973
|
-
embeddings_config = resolve_model_client_config(
|
|
974
|
-
config.get(EMBEDDINGS_CONFIG_KEY, {})
|
|
975
|
-
)
|
|
976
1028
|
cls.perform_embeddings_health_check(
|
|
977
1029
|
embeddings_config,
|
|
978
1030
|
DEFAULT_EMBEDDINGS_CONFIG,
|
|
979
1031
|
log_source_method,
|
|
980
1032
|
EnterpriseSearchPolicy.__name__,
|
|
981
1033
|
)
|
|
1034
|
+
|
|
1035
|
+
@classmethod
|
|
1036
|
+
def get_system_default_prompt_based_on_config(cls, config: Dict[str, Any]) -> str:
|
|
1037
|
+
"""
|
|
1038
|
+
Resolves the default prompt template for Enterprise Search Policy based on
|
|
1039
|
+
the component's configuration.
|
|
1040
|
+
|
|
1041
|
+
- The old prompt is selected when both citation and relevancy check are either
|
|
1042
|
+
disabled or not set in the configuration.
|
|
1043
|
+
- The citation prompt is used when citation is enabled and relevancy check is
|
|
1044
|
+
either disabled or not set in the configuration.
|
|
1045
|
+
- The relevancy check prompt is only used when relevancy check is enabled.
|
|
1046
|
+
|
|
1047
|
+
Args:
|
|
1048
|
+
config: The component's configuration.
|
|
1049
|
+
|
|
1050
|
+
Returns:
|
|
1051
|
+
The resolved jinja prompt template as a string.
|
|
1052
|
+
"""
|
|
1053
|
+
# Get the feature flags
|
|
1054
|
+
parsed_config = EnterpriseSearchPolicyConfig.from_dict(config)
|
|
1055
|
+
# Based on the enabled features (citation, relevancy check) fetch the
|
|
1056
|
+
# appropriate default prompt
|
|
1057
|
+
default_prompt = cls._select_default_prompt_template_based_on_features(
|
|
1058
|
+
parsed_config.check_relevancy, parsed_config.enable_citation
|
|
1059
|
+
)
|
|
1060
|
+
|
|
1061
|
+
return default_prompt
|
|
1062
|
+
|
|
1063
|
+
@classmethod
|
|
1064
|
+
def _select_default_prompt_template_based_on_features(
|
|
1065
|
+
cls,
|
|
1066
|
+
relevancy_check_enabled: bool,
|
|
1067
|
+
citation_enabled: bool,
|
|
1068
|
+
) -> str:
|
|
1069
|
+
"""
|
|
1070
|
+
Returns the appropriate default prompt template based on the feature flags.
|
|
1071
|
+
|
|
1072
|
+
The selection follows this priority:
|
|
1073
|
+
1. If relevancy check is enabled, return the prompt that includes both relevancy
|
|
1074
|
+
and citation blocks.
|
|
1075
|
+
2. If only citation is enabled, return the prompt with citation blocks.
|
|
1076
|
+
3. Otherwise, fall back to the legacy default prompt template.
|
|
1077
|
+
|
|
1078
|
+
Args:
|
|
1079
|
+
relevancy_check_enabled: Whether the LLM-generated answer should undergo
|
|
1080
|
+
relevancy evaluation.
|
|
1081
|
+
citation_enabled: Whether citations should be included in the generated
|
|
1082
|
+
answer.
|
|
1083
|
+
|
|
1084
|
+
Returns:
|
|
1085
|
+
The default prompt template corresponding to the enabled features.
|
|
1086
|
+
"""
|
|
1087
|
+
if relevancy_check_enabled:
|
|
1088
|
+
# ES prompt that has relevancy check and citations blocks
|
|
1089
|
+
return DEFAULT_ENTERPRISE_SEARCH_PROMPT_WITH_RELEVANCY_CHECK_AND_CITATION_TEMPLATE # noqa: E501
|
|
1090
|
+
elif citation_enabled:
|
|
1091
|
+
# ES prompt with citation's block - backward compatibility
|
|
1092
|
+
return DEFAULT_ENTERPRISE_SEARCH_PROMPT_WITH_CITATION_TEMPLATE
|
|
1093
|
+
else:
|
|
1094
|
+
# Legacy ES prompt - backward compatibility
|
|
1095
|
+
return DEFAULT_ENTERPRISE_SEARCH_PROMPT_TEMPLATE
|