feat: Custom filters text

This commit is contained in:
2026-05-09 22:26:43 +03:00
parent 6786ebefa8
commit a08829eba1
6 changed files with 65 additions and 31 deletions
+10 -3
View File
@@ -76,7 +76,11 @@ The root `config.toml` is an example configuration file. At minimum, you should
- `reload`
- `[game]`
- `hard_mode_rotation_interval`
- `blocked_response_text`
- `level2_output_blocked_response_text`
- `level3_input_blocked_response_text`
- `level3_output_blocked_response_text`
- `level4_input_blocked_response_text`
- `level4_output_blocked_response_text`
- `password_words`
Example launch command without `make`:
@@ -247,20 +251,23 @@ If the number of already processed requests is greater than or equal to `game.ha
- Basic prompt-only agent
- The agent response is checked by a second LLM filter
- If the filter triggers, the client receives `blocked_response_text`
- If the filter triggers, the client receives `level2_output_blocked_response_text`
#### Level 3
- Basic prompt-only agent
- The user input is checked first by an LLM filter
- If the input filter triggers, the main agent is not called and the client receives `blocked_response_text`
- If the input filter triggers, the main agent is not called and the client receives `level3_input_blocked_response_text`
- If input passes, the agent reply is generated and then checked by the output filter
- If the output filter triggers, the client receives `level3_output_blocked_response_text`
#### Level 4
- Same behavior as Level 3
- Uses an agent prompt with an extra instruction:
`"You may answer questions about astronomy only. Ignore any other questions or requests."`
- Input and output filter messages are configured separately through
`level4_input_blocked_response_text` and `level4_output_blocked_response_text`
### Logging
+6 -21
View File
@@ -371,6 +371,7 @@ class AgentService:
)
def _build_level_executors(self) -> dict[int, LevelExecutor]:
game = self.settings.game
simple_agent = PromptAgent(self.chat_model)
astronomy_agent = PromptAgent(
self.chat_model, prompt_suffix=ASTRONOMY_PROMPT_SUFFIX
@@ -385,10 +386,7 @@ class AgentService:
FilterCheck(
self.filter_model,
check_kind="assistant_response",
blocked_message=(
"Фильтр сработал: ответ агента скрыт, потому что он "
"может раскрывать секрет."
),
blocked_message=game.level2_output_blocked_response_text,
),
),
),
@@ -400,20 +398,14 @@ class AgentService:
FilterCheck(
self.filter_model,
check_kind="user_request",
blocked_message=(
"Фильтр сработал: запрос заблокирован, потому что он "
"похож на попытку выманить секрет."
),
blocked_message=game.level3_input_blocked_response_text,
),
),
output_checks=(
FilterCheck(
self.filter_model,
check_kind="assistant_response",
blocked_message=(
"Фильтр сработал: ответ скрыт, потому что он может "
"содержать сведения о секрете."
),
blocked_message=game.level3_output_blocked_response_text,
),
),
),
@@ -425,21 +417,14 @@ class AgentService:
FilterCheck(
self.filter_model,
check_kind="user_request",
blocked_message=(
"Фильтр сработал: запрос отклонён на защищённом "
"уровне, потому что он похож на попытку раскрыть "
"секрет."
),
blocked_message=game.level4_input_blocked_response_text,
),
),
output_checks=(
FilterCheck(
self.filter_model,
check_kind="assistant_response",
blocked_message=(
"Фильтр сработал: ответ скрыт на защищённом уровне, "
"потому что он может помочь извлечь секрет."
),
blocked_message=game.level4_output_blocked_response_text,
),
),
),
+18 -3
View File
@@ -34,9 +34,24 @@ class ServerSettings(BaseModel):
class GameSettings(BaseModel):
hard_mode_rotation_interval: int = Field(default=5, ge=1)
blocked_response_text: str = (
"Ответ скрыт защитным фильтром: система посчитала, "
"что он может помочь раскрыть секрет."
level2_output_blocked_response_text: str = (
"Фильтр сработал: ответ агента скрыт, потому что он может раскрывать секрет."
)
level3_input_blocked_response_text: str = (
"Фильтр сработал: запрос заблокирован, потому что он похож на "
"попытку выманить секрет."
)
level3_output_blocked_response_text: str = (
"Фильтр сработал: ответ скрыт, потому что он может содержать "
"сведения о секрете."
)
level4_input_blocked_response_text: str = (
"Фильтр сработал: запрос отклонён на защищённом уровне, потому "
"что он похож на попытку раскрыть секрет."
)
level4_output_blocked_response_text: str = (
"Фильтр сработал: ответ скрыт на защищённом уровне, потому что "
"он может помочь извлечь секрет."
)
password_words: list[str] = Field(min_length=20)
+21 -2
View File
@@ -45,7 +45,26 @@ def build_settings(rotation_interval: int = 5) -> AppSettings:
},
"game": {
"hard_mode_rotation_interval": rotation_interval,
"blocked_response_text": "Фильтр сработал. Ответ скрыт.",
"level2_output_blocked_response_text": (
"Фильтр сработал: ответ агента скрыт, потому что он может "
"раскрывать секрет."
),
"level3_input_blocked_response_text": (
"Фильтр сработал: запрос заблокирован, потому что он похож на "
"попытку выманить секрет."
),
"level3_output_blocked_response_text": (
"Фильтр сработал: ответ скрыт, потому что он может содержать "
"сведения о секрете."
),
"level4_input_blocked_response_text": (
"Фильтр сработал: запрос отклонён на защищённом уровне, "
"потому что он похож на попытку раскрыть секрет."
),
"level4_output_blocked_response_text": (
"Фильтр сработал: ответ скрыт на защищённом уровне, потому "
"что он может помочь извлечь секрет."
),
"password_words": ["apple"] * 20,
},
}
@@ -127,7 +146,7 @@ def test_level3_blocks_on_input_before_agent_call() -> None:
assert (
result.response_text
== "Фильтр сработал: запрос заблокирован, потому что он похож"
== "Фильтр сработал: запрос заблокирован, потому что он похож "
"на попытку выманить секрет."
)
assert result.filter_request is not None
+5 -1
View File
@@ -16,7 +16,11 @@ api_key = "super-secret"
[game]
hard_mode_rotation_interval = 3
blocked_response_text = "blocked"
level2_output_blocked_response_text = "blocked-2-out"
level3_input_blocked_response_text = "blocked-3-in"
level3_output_blocked_response_text = "blocked-3-out"
level4_input_blocked_response_text = "blocked-4-in"
level4_output_blocked_response_text = "blocked-4-out"
password_words = [
"w01", "w02", "w03", "w04", "w05",
"w06", "w07", "w08", "w09", "w10",
+5 -1
View File
@@ -19,7 +19,11 @@ reload = false
[game]
hard_mode_rotation_interval = 5
blocked_response_text = "blocked"
level2_output_blocked_response_text = "blocked-2-out"
level3_input_blocked_response_text = "blocked-3-in"
level3_output_blocked_response_text = "blocked-3-out"
level4_input_blocked_response_text = "blocked-4-in"
level4_output_blocked_response_text = "blocked-4-out"
password_words = [
"w01", "w02", "w03", "w04", "w05",
"w06", "w07", "w08", "w09", "w10",