diff --git a/backend/alembic/versions/7aea705850d5_added_slack_auto_filter.py b/backend/alembic/versions/7aea705850d5_added_slack_auto_filter.py new file mode 100644 index 000000000..a07b94bd9 --- /dev/null +++ b/backend/alembic/versions/7aea705850d5_added_slack_auto_filter.py @@ -0,0 +1,35 @@ +"""added slack_auto_filter + +Revision ID: 7aea705850d5 +Revises: 4505fd7302e1 +Create Date: 2024-07-10 11:01:23.581015 + +""" +from alembic import op +import sqlalchemy as sa + +revision = "7aea705850d5" +down_revision = "4505fd7302e1" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + op.add_column( + "slack_bot_config", + sa.Column("enable_auto_filters", sa.Boolean(), nullable=True), + ) + op.execute( + "UPDATE slack_bot_config SET enable_auto_filters = FALSE WHERE enable_auto_filters IS NULL" + ) + op.alter_column( + "slack_bot_config", + "enable_auto_filters", + existing_type=sa.Boolean(), + nullable=False, + server_default=sa.false(), + ) + + +def downgrade() -> None: + op.drop_column("slack_bot_config", "enable_auto_filters") diff --git a/backend/danswer/configs/chat_configs.py b/backend/danswer/configs/chat_configs.py index acc87d4ff..19b7bb756 100644 --- a/backend/danswer/configs/chat_configs.py +++ b/backend/danswer/configs/chat_configs.py @@ -28,9 +28,6 @@ BASE_RECENCY_DECAY = 0.5 FAVOR_RECENT_DECAY_MULTIPLIER = 2.0 # Currently this next one is not configurable via env DISABLE_LLM_QUERY_ANSWERABILITY = QA_PROMPT_OVERRIDE == "weak" -DISABLE_LLM_FILTER_EXTRACTION = ( - os.environ.get("DISABLE_LLM_FILTER_EXTRACTION", "").lower() == "true" -) # Whether the LLM should evaluate all of the document chunks passed in for usefulness # in relation to the user query DISABLE_LLM_CHUNK_FILTER = ( diff --git a/backend/danswer/configs/danswerbot_configs.py b/backend/danswer/configs/danswerbot_configs.py index 5500d28c3..b75d69d1f 100644 --- a/backend/danswer/configs/danswerbot_configs.py +++ b/backend/danswer/configs/danswerbot_configs.py @@ -47,10 +47,6 @@ DANSWER_BOT_DISPLAY_ERROR_MSGS = os.environ.get( DANSWER_BOT_RESPOND_EVERY_CHANNEL = ( os.environ.get("DANSWER_BOT_RESPOND_EVERY_CHANNEL", "").lower() == "true" ) -# Auto detect query options like time cutoff or heavily favor recently updated docs -DISABLE_DANSWER_BOT_FILTER_DETECT = ( - os.environ.get("DISABLE_DANSWER_BOT_FILTER_DETECT", "").lower() == "true" -) # Add a second LLM call post Answer to verify if the Answer is valid # Throws out answers that don't directly or fully answer the user query # This is the default for all DanswerBot channels unless the channel is configured individually diff --git a/backend/danswer/danswerbot/slack/handlers/handle_message.py b/backend/danswer/danswerbot/slack/handlers/handle_message.py index 9c418e84d..a05006dec 100644 --- a/backend/danswer/danswerbot/slack/handlers/handle_message.py +++ b/backend/danswer/danswerbot/slack/handlers/handle_message.py @@ -168,8 +168,6 @@ def handle_message( if slack_bot_config and slack_bot_config.channel_config: channel_conf = slack_bot_config.channel_config if not bypass_filters and "answer_filters" in channel_conf: - "well_answered_postfilter" in channel_conf["answer_filters"] - if ( "questionmark_prefilter" in channel_conf["answer_filters"] and "?" not in messages[-1].message diff --git a/backend/danswer/danswerbot/slack/handlers/handle_regular_answer.py b/backend/danswer/danswerbot/slack/handlers/handle_regular_answer.py index 3d69ba9ac..212c65b13 100644 --- a/backend/danswer/danswerbot/slack/handlers/handle_regular_answer.py +++ b/backend/danswer/danswerbot/slack/handlers/handle_regular_answer.py @@ -22,7 +22,6 @@ from danswer.configs.danswerbot_configs import DANSWER_BOT_TARGET_CHUNK_PERCENTA from danswer.configs.danswerbot_configs import DANSWER_BOT_USE_QUOTES from danswer.configs.danswerbot_configs import DANSWER_FOLLOWUP_EMOJI from danswer.configs.danswerbot_configs import DANSWER_REACT_EMOJI -from danswer.configs.danswerbot_configs import DISABLE_DANSWER_BOT_FILTER_DETECT from danswer.configs.danswerbot_configs import ENABLE_DANSWERBOT_REFLEXION from danswer.danswerbot.slack.blocks import build_documents_blocks from danswer.danswerbot.slack.blocks import build_follow_up_block @@ -91,7 +90,6 @@ def handle_regular_answer( thread_context_percent: float = DANSWER_BOT_TARGET_CHUNK_PERCENTAGE, should_respond_with_error_msgs: bool = DANSWER_BOT_DISPLAY_ERROR_MSGS, disable_docs_only_answer: bool = DANSWER_BOT_DISABLE_DOCS_ONLY_ANSWER, - disable_auto_detect_filters: bool = DISABLE_DANSWER_BOT_FILTER_DETECT, disable_cot: bool = DANSWER_BOT_DISABLE_COT, reflexion: bool = ENABLE_DANSWERBOT_REFLEXION, ) -> bool: @@ -207,12 +205,17 @@ def handle_regular_answer( ) # Default True because no other ways to apply filters in Slack (no nice UI) + # Commenting this out because this is only available to the slackbot for now + # later we plan to implement this at the persona level where this will get + # commented back in + # auto_detect_filters = ( + # persona.llm_filter_extraction if persona is not None else True + # ) auto_detect_filters = ( - persona.llm_filter_extraction if persona is not None else True + slack_bot_config.enable_auto_filters + if slack_bot_config is not None + else False ) - if disable_auto_detect_filters: - auto_detect_filters = False - retrieval_details = RetrievalDetails( run_search=OptionalSearchSetting.ALWAYS, real_time=False, @@ -352,6 +355,31 @@ def handle_regular_answer( ) return True + only_respond_with_citations_or_quotes = ( + channel_conf + and "well_answered_postfilter" in channel_conf.get("answer_filters", []) + ) + has_citations_or_quotes = bool(answer.citations or answer.quotes) + if ( + only_respond_with_citations_or_quotes + and not has_citations_or_quotes + and not message_info.bypass_filters + ): + logger.error( + f"Unable to find citations or quotes to answer: '{answer.rephrase}' - not answering!" + ) + # Optionally, respond in thread with the error message + # Used primarily for debugging purposes + if should_respond_with_error_msgs: + respond_in_thread( + client=client, + channel=channel, + receiver_ids=None, + text="Found no citations or quotes when trying to answer.", + thread_ts=message_ts_to_respond_to, + ) + return True + # If called with the DanswerBot slash command, the question is lost so we have to reshow it restate_question_block = get_restate_blocks(messages[-1].message, is_bot_msg) diff --git a/backend/danswer/db/models.py b/backend/danswer/db/models.py index 8988a137a..f7d16743c 100644 --- a/backend/danswer/db/models.py +++ b/backend/danswer/db/models.py @@ -1195,6 +1195,9 @@ class SlackBotConfig(Base): response_type: Mapped[SlackBotResponseType] = mapped_column( Enum(SlackBotResponseType, native_enum=False), nullable=False ) + enable_auto_filters: Mapped[bool] = mapped_column( + Boolean, nullable=False, default=False + ) persona: Mapped[Persona | None] = relationship("Persona") standard_answer_categories: Mapped[list[StandardAnswerCategory]] = relationship( diff --git a/backend/danswer/db/slack_bot_config.py b/backend/danswer/db/slack_bot_config.py index aeee25bea..502d99608 100644 --- a/backend/danswer/db/slack_bot_config.py +++ b/backend/danswer/db/slack_bot_config.py @@ -53,7 +53,7 @@ def create_slack_bot_persona( description="", num_chunks=num_chunks, llm_relevance_filter=True, - llm_filter_extraction=True, + llm_filter_extraction=False, recency_bias=RecencyBiasSetting.AUTO, prompt_ids=[default_prompt.id], document_set_ids=document_set_ids, @@ -74,6 +74,7 @@ def insert_slack_bot_config( channel_config: ChannelConfig, response_type: SlackBotResponseType, standard_answer_category_ids: list[int], + enable_auto_filters: bool, db_session: Session, ) -> SlackBotConfig: existing_standard_answer_categories = fetch_standard_answer_categories_by_ids( @@ -90,6 +91,7 @@ def insert_slack_bot_config( channel_config=channel_config, response_type=response_type, standard_answer_categories=existing_standard_answer_categories, + enable_auto_filters=enable_auto_filters, ) db_session.add(slack_bot_config) db_session.commit() @@ -103,6 +105,7 @@ def update_slack_bot_config( channel_config: ChannelConfig, response_type: SlackBotResponseType, standard_answer_category_ids: list[int], + enable_auto_filters: bool, db_session: Session, ) -> SlackBotConfig: slack_bot_config = db_session.scalar( @@ -134,6 +137,7 @@ def update_slack_bot_config( slack_bot_config.standard_answer_categories = list( existing_standard_answer_categories ) + slack_bot_config.enable_auto_filters = enable_auto_filters # if the persona has changed, then clean up the old persona if persona_id != existing_persona_id and existing_persona_id: diff --git a/backend/danswer/search/preprocessing/preprocessing.py b/backend/danswer/search/preprocessing/preprocessing.py index b4be8dca6..bb2449efe 100644 --- a/backend/danswer/search/preprocessing/preprocessing.py +++ b/backend/danswer/search/preprocessing/preprocessing.py @@ -2,7 +2,6 @@ from sqlalchemy.orm import Session from danswer.configs.chat_configs import BASE_RECENCY_DECAY from danswer.configs.chat_configs import DISABLE_LLM_CHUNK_FILTER -from danswer.configs.chat_configs import DISABLE_LLM_FILTER_EXTRACTION from danswer.configs.chat_configs import FAVOR_RECENT_DECAY_MULTIPLIER from danswer.configs.chat_configs import NUM_RETURNED_HITS from danswer.db.models import User @@ -36,8 +35,6 @@ def retrieval_preprocessing( db_session: Session, bypass_acl: bool = False, include_query_intent: bool = True, - enable_auto_detect_filters: bool = False, - disable_llm_filter_extraction: bool = DISABLE_LLM_FILTER_EXTRACTION, disable_llm_chunk_filter: bool = DISABLE_LLM_CHUNK_FILTER, base_recency_decay: float = BASE_RECENCY_DECAY, favor_recent_decay_multiplier: float = FAVOR_RECENT_DECAY_MULTIPLIER, @@ -63,10 +60,7 @@ def retrieval_preprocessing( auto_detect_time_filter = True auto_detect_source_filter = True - if disable_llm_filter_extraction: - auto_detect_time_filter = False - auto_detect_source_filter = False - elif enable_auto_detect_filters is False: + if not search_request.enable_auto_detect_filters: logger.debug("Retrieval details disables auto detect filters") auto_detect_time_filter = False auto_detect_source_filter = False diff --git a/backend/danswer/server/manage/models.py b/backend/danswer/server/manage/models.py index 04ed650cd..f544df0f2 100644 --- a/backend/danswer/server/manage/models.py +++ b/backend/danswer/server/manage/models.py @@ -155,6 +155,7 @@ class SlackBotConfigCreationRequest(BaseModel): channel_names: list[str] respond_tag_only: bool = False respond_to_bots: bool = False + enable_auto_filters: bool = False # If no team members, assume respond in the channel to everyone respond_team_member_list: list[str] = [] respond_slack_group_list: list[str] = [] @@ -188,6 +189,7 @@ class SlackBotConfig(BaseModel): channel_config: ChannelConfig response_type: SlackBotResponseType standard_answer_categories: list[StandardAnswerCategory] + enable_auto_filters: bool @classmethod def from_model( @@ -208,6 +210,7 @@ class SlackBotConfig(BaseModel): StandardAnswerCategory.from_model(standard_answer_category_model) for standard_answer_category_model in slack_bot_config_model.standard_answer_categories ], + enable_auto_filters=slack_bot_config_model.enable_auto_filters, ) diff --git a/backend/danswer/server/manage/slack_bot.py b/backend/danswer/server/manage/slack_bot.py index d91226294..d5f08e269 100644 --- a/backend/danswer/server/manage/slack_bot.py +++ b/backend/danswer/server/manage/slack_bot.py @@ -115,6 +115,7 @@ def create_slack_bot_config( response_type=slack_bot_config_creation_request.response_type, standard_answer_category_ids=slack_bot_config_creation_request.standard_answer_categories, db_session=db_session, + enable_auto_filters=slack_bot_config_creation_request.enable_auto_filters, ) return SlackBotConfig.from_model(slack_bot_config_model) @@ -174,6 +175,7 @@ def patch_slack_bot_config( response_type=slack_bot_config_creation_request.response_type, standard_answer_category_ids=slack_bot_config_creation_request.standard_answer_categories, db_session=db_session, + enable_auto_filters=slack_bot_config_creation_request.enable_auto_filters, ) return SlackBotConfig.from_model(slack_bot_config_model) diff --git a/backend/danswer/tools/search/search_tool.py b/backend/danswer/tools/search/search_tool.py index bff0df423..44c5001d6 100644 --- a/backend/danswer/tools/search/search_tool.py +++ b/backend/danswer/tools/search/search_tool.py @@ -225,6 +225,9 @@ class SearchTool(Tool): chunks_above=self.chunks_above, chunks_below=self.chunks_below, full_doc=self.full_doc, + enable_auto_detect_filters=self.retrieval_options.enable_auto_detect_filters + if self.retrieval_options + else None, ), user=self.user, llm=self.llm, diff --git a/deployment/docker_compose/docker-compose.dev.yml b/deployment/docker_compose/docker-compose.dev.yml index 78654d7f5..2623cabee 100644 --- a/deployment/docker_compose/docker-compose.dev.yml +++ b/deployment/docker_compose/docker-compose.dev.yml @@ -44,7 +44,6 @@ services: - GEN_AI_MAX_TOKENS=${GEN_AI_MAX_TOKENS:-} - QA_TIMEOUT=${QA_TIMEOUT:-} - MAX_CHUNKS_FED_TO_CHAT=${MAX_CHUNKS_FED_TO_CHAT:-} - - DISABLE_LLM_FILTER_EXTRACTION=${DISABLE_LLM_FILTER_EXTRACTION:-} - DISABLE_LLM_CHUNK_FILTER=${DISABLE_LLM_CHUNK_FILTER:-} - DISABLE_LLM_CHOOSE_SEARCH=${DISABLE_LLM_CHOOSE_SEARCH:-} - DISABLE_LLM_QUERY_REPHRASE=${DISABLE_LLM_QUERY_REPHRASE:-} @@ -130,7 +129,6 @@ services: - GEN_AI_MAX_TOKENS=${GEN_AI_MAX_TOKENS:-} - QA_TIMEOUT=${QA_TIMEOUT:-} - MAX_CHUNKS_FED_TO_CHAT=${MAX_CHUNKS_FED_TO_CHAT:-} - - DISABLE_LLM_FILTER_EXTRACTION=${DISABLE_LLM_FILTER_EXTRACTION:-} - DISABLE_LLM_CHUNK_FILTER=${DISABLE_LLM_CHUNK_FILTER:-} - DISABLE_LLM_CHOOSE_SEARCH=${DISABLE_LLM_CHOOSE_SEARCH:-} - DISABLE_LLM_QUERY_REPHRASE=${DISABLE_LLM_QUERY_REPHRASE:-} diff --git a/deployment/docker_compose/docker-compose.gpu-dev.yml b/deployment/docker_compose/docker-compose.gpu-dev.yml index 71f0f920b..a46dd00a3 100644 --- a/deployment/docker_compose/docker-compose.gpu-dev.yml +++ b/deployment/docker_compose/docker-compose.gpu-dev.yml @@ -41,7 +41,6 @@ services: - GEN_AI_MAX_TOKENS=${GEN_AI_MAX_TOKENS:-} - QA_TIMEOUT=${QA_TIMEOUT:-} - MAX_CHUNKS_FED_TO_CHAT=${MAX_CHUNKS_FED_TO_CHAT:-} - - DISABLE_LLM_FILTER_EXTRACTION=${DISABLE_LLM_FILTER_EXTRACTION:-} - DISABLE_LLM_CHUNK_FILTER=${DISABLE_LLM_CHUNK_FILTER:-} - DISABLE_LLM_CHOOSE_SEARCH=${DISABLE_LLM_CHOOSE_SEARCH:-} - DISABLE_LLM_QUERY_REPHRASE=${DISABLE_LLM_QUERY_REPHRASE:-} @@ -123,7 +122,6 @@ services: - GEN_AI_MAX_TOKENS=${GEN_AI_MAX_TOKENS:-} - QA_TIMEOUT=${QA_TIMEOUT:-} - MAX_CHUNKS_FED_TO_CHAT=${MAX_CHUNKS_FED_TO_CHAT:-} - - DISABLE_LLM_FILTER_EXTRACTION=${DISABLE_LLM_FILTER_EXTRACTION:-} - DISABLE_LLM_CHUNK_FILTER=${DISABLE_LLM_CHUNK_FILTER:-} - DISABLE_LLM_CHOOSE_SEARCH=${DISABLE_LLM_CHOOSE_SEARCH:-} - DISABLE_LLM_QUERY_REPHRASE=${DISABLE_LLM_QUERY_REPHRASE:-} diff --git a/deployment/helm/values.yaml b/deployment/helm/values.yaml index b844b5be0..bb41a7511 100644 --- a/deployment/helm/values.yaml +++ b/deployment/helm/values.yaml @@ -402,7 +402,6 @@ configMap: GEN_AI_MAX_TOKENS: "" QA_TIMEOUT: "60" MAX_CHUNKS_FED_TO_CHAT: "" - DISABLE_LLM_FILTER_EXTRACTION: "" DISABLE_LLM_CHUNK_FILTER: "" DISABLE_LLM_CHOOSE_SEARCH: "" DISABLE_LLM_QUERY_REPHRASE: "" diff --git a/deployment/kubernetes/env-configmap.yaml b/deployment/kubernetes/env-configmap.yaml index da2f7e589..81918c147 100644 --- a/deployment/kubernetes/env-configmap.yaml +++ b/deployment/kubernetes/env-configmap.yaml @@ -24,7 +24,6 @@ data: GEN_AI_MAX_TOKENS: "" QA_TIMEOUT: "60" MAX_CHUNKS_FED_TO_CHAT: "" - DISABLE_LLM_FILTER_EXTRACTION: "" DISABLE_LLM_CHUNK_FILTER: "" DISABLE_LLM_CHOOSE_SEARCH: "" DISABLE_LLM_QUERY_REPHRASE: "" diff --git a/web/src/app/admin/bot/SlackBotConfigCreationForm.tsx b/web/src/app/admin/bot/SlackBotConfigCreationForm.tsx index e77124533..23968d585 100644 --- a/web/src/app/admin/bot/SlackBotConfigCreationForm.tsx +++ b/web/src/app/admin/bot/SlackBotConfigCreationForm.tsx @@ -77,6 +77,8 @@ export const SlackBotCreationForm = ({ existingSlackBotConfig?.channel_config?.respond_tag_only || false, respond_to_bots: existingSlackBotConfig?.channel_config?.respond_to_bots || false, + enable_auto_filters: + existingSlackBotConfig?.enable_auto_filters || false, respond_member_group_list: ( existingSlackBotConfig?.channel_config ?.respond_team_member_list ?? [] @@ -114,6 +116,7 @@ export const SlackBotCreationForm = ({ questionmark_prefilter_enabled: Yup.boolean().required(), respond_tag_only: Yup.boolean().required(), respond_to_bots: Yup.boolean().required(), + enable_auto_filters: Yup.boolean().required(), respond_member_group_list: Yup.array().of(Yup.string()).required(), still_need_help_enabled: Yup.boolean().required(), follow_up_tags: Yup.array().of(Yup.string()), @@ -247,6 +250,11 @@ export const SlackBotCreationForm = ({ label="Responds to Bot messages" subtext="If not set, DanswerBot will always ignore messages from Bots" /> +