fix: skip KB retrieval for blank prompts#8073
Conversation
There was a problem hiding this comment.
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="tests/unit/test_astr_main_agent.py" line_range="345-360" />
<code_context>
assert req.system_prompt == "System"
+ @pytest.mark.asyncio
+ @pytest.mark.parametrize("prompt", ["", " \n\t"])
+ async def test_apply_kb_blank_prompt(self, prompt, mock_event, mock_context):
+ """Test applying knowledge base when prompt is blank."""
+ module = ama
+ req = ProviderRequest(prompt=prompt, system_prompt="System")
+ config = module.MainAgentBuildConfig(
+ tool_call_timeout=60, kb_agentic_mode=False
+ )
+ retrieve = AsyncMock(return_value="KB result")
+
+ with patch("astrbot.core.astr_main_agent.retrieve_knowledge_base", retrieve):
+ await module._apply_kb(mock_event, req, mock_context, config)
+
+ retrieve.assert_not_awaited()
+ assert req.system_prompt == "System"
+
@pytest.mark.asyncio
</code_context>
<issue_to_address>
**suggestion (testing):** Add a test case for prompts with surrounding whitespace that should still trigger KB retrieval
To fully exercise the new `strip()` condition, please add a case like `" hello "` where the prompt is non-empty after stripping. That test should assert `retrieve_knowledge_base` is awaited and receives the original prompt, confirming we don’t skip retrieval when only leading/trailing whitespace is present.
```suggestion
@pytest.mark.asyncio
@pytest.mark.parametrize("prompt", ["", " \n\t"])
async def test_apply_kb_blank_prompt(self, prompt, mock_event, mock_context):
"""Test applying knowledge base when prompt is blank."""
module = ama
req = ProviderRequest(prompt=prompt, system_prompt="System")
config = module.MainAgentBuildConfig(
tool_call_timeout=60, kb_agentic_mode=False
)
retrieve = AsyncMock(return_value="KB result")
with patch("astrbot.core.astr_main_agent.retrieve_knowledge_base", retrieve):
await module._apply_kb(mock_event, req, mock_context, config)
retrieve.assert_not_awaited()
assert req.system_prompt == "System"
@pytest.mark.asyncio
async def test_apply_kb_prompt_with_surrounding_whitespace(
self, mock_event, mock_context
):
"""Test applying knowledge base when prompt has surrounding whitespace but is non-empty."""
module = ama
prompt = " hello "
req = ProviderRequest(prompt=prompt, system_prompt="System")
config = module.MainAgentBuildConfig(
tool_call_timeout=60, kb_agentic_mode=False
)
retrieve = AsyncMock(return_value="KB result")
with patch("astrbot.core.astr_main_agent.retrieve_knowledge_base", retrieve):
await module._apply_kb(mock_event, req, mock_context, config)
retrieve.assert_awaited_once_with(mock_event, req, mock_context, config)
# Ensure we passed the original prompt object through to retrieval
assert req.prompt == prompt
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| @pytest.mark.asyncio | ||
| @pytest.mark.parametrize("prompt", ["", " \n\t"]) | ||
| async def test_apply_kb_blank_prompt(self, prompt, mock_event, mock_context): | ||
| """Test applying knowledge base when prompt is blank.""" | ||
| module = ama | ||
| req = ProviderRequest(prompt=prompt, system_prompt="System") | ||
| config = module.MainAgentBuildConfig( | ||
| tool_call_timeout=60, kb_agentic_mode=False | ||
| ) | ||
| retrieve = AsyncMock(return_value="KB result") | ||
|
|
||
| with patch("astrbot.core.astr_main_agent.retrieve_knowledge_base", retrieve): | ||
| await module._apply_kb(mock_event, req, mock_context, config) | ||
|
|
||
| retrieve.assert_not_awaited() | ||
| assert req.system_prompt == "System" |
There was a problem hiding this comment.
suggestion (testing): Add a test case for prompts with surrounding whitespace that should still trigger KB retrieval
To fully exercise the new strip() condition, please add a case like " hello " where the prompt is non-empty after stripping. That test should assert retrieve_knowledge_base is awaited and receives the original prompt, confirming we don’t skip retrieval when only leading/trailing whitespace is present.
| @pytest.mark.asyncio | |
| @pytest.mark.parametrize("prompt", ["", " \n\t"]) | |
| async def test_apply_kb_blank_prompt(self, prompt, mock_event, mock_context): | |
| """Test applying knowledge base when prompt is blank.""" | |
| module = ama | |
| req = ProviderRequest(prompt=prompt, system_prompt="System") | |
| config = module.MainAgentBuildConfig( | |
| tool_call_timeout=60, kb_agentic_mode=False | |
| ) | |
| retrieve = AsyncMock(return_value="KB result") | |
| with patch("astrbot.core.astr_main_agent.retrieve_knowledge_base", retrieve): | |
| await module._apply_kb(mock_event, req, mock_context, config) | |
| retrieve.assert_not_awaited() | |
| assert req.system_prompt == "System" | |
| @pytest.mark.asyncio | |
| @pytest.mark.parametrize("prompt", ["", " \n\t"]) | |
| async def test_apply_kb_blank_prompt(self, prompt, mock_event, mock_context): | |
| """Test applying knowledge base when prompt is blank.""" | |
| module = ama | |
| req = ProviderRequest(prompt=prompt, system_prompt="System") | |
| config = module.MainAgentBuildConfig( | |
| tool_call_timeout=60, kb_agentic_mode=False | |
| ) | |
| retrieve = AsyncMock(return_value="KB result") | |
| with patch("astrbot.core.astr_main_agent.retrieve_knowledge_base", retrieve): | |
| await module._apply_kb(mock_event, req, mock_context, config) | |
| retrieve.assert_not_awaited() | |
| assert req.system_prompt == "System" | |
| @pytest.mark.asyncio | |
| async def test_apply_kb_prompt_with_surrounding_whitespace( | |
| self, mock_event, mock_context | |
| ): | |
| """Test applying knowledge base when prompt has surrounding whitespace but is non-empty.""" | |
| module = ama | |
| prompt = " hello " | |
| req = ProviderRequest(prompt=prompt, system_prompt="System") | |
| config = module.MainAgentBuildConfig( | |
| tool_call_timeout=60, kb_agentic_mode=False | |
| ) | |
| retrieve = AsyncMock(return_value="KB result") | |
| with patch("astrbot.core.astr_main_agent.retrieve_knowledge_base", retrieve): | |
| await module._apply_kb(mock_event, req, mock_context, config) | |
| retrieve.assert_awaited_once_with(mock_event, req, mock_context, config) | |
| # Ensure we passed the original prompt object through to retrieval | |
| assert req.prompt == prompt |
There was a problem hiding this comment.
Code Review
This pull request introduces a check to skip knowledge base retrieval when the prompt is empty or contains only whitespace, along with a new unit test to verify this behavior. A review comment suggests that because this check is performed after prompt decoration, it might still trigger retrieval if a prefix or default summary prompt has been added, recommending that the check be performed on the original user prompt instead.
| ) -> None: | ||
| if not config.kb_agentic_mode: | ||
| if req.prompt is None: | ||
| if req.prompt is None or not req.prompt.strip(): |
There was a problem hiding this comment.
The check for blank prompts is a valid improvement to avoid unnecessary knowledge base queries. However, it's worth noting that _apply_kb is called after _decorate_llm_request in build_main_agent. If a prompt_prefix is configured or if _apply_file_extract has set a default summary prompt (e.g., "总结一下文件里面讲了什么?"), req.prompt will no longer be blank or whitespace-only at this point. This means KB retrieval might still be triggered with these placeholder or prefix strings. Consider if the check should ideally happen against the original user prompt before decoration.
Fixes #8070.
Summary
To verify
Summary by Sourcery
Skip non-agentic knowledge base retrieval when provider prompts are blank or whitespace-only and add regression coverage for this behavior.
Bug Fixes:
Tests: