feat: Custom filters text
This commit is contained in:
@@ -76,7 +76,11 @@ The root `config.toml` is an example configuration file. At minimum, you should
|
|||||||
- `reload`
|
- `reload`
|
||||||
- `[game]`
|
- `[game]`
|
||||||
- `hard_mode_rotation_interval`
|
- `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`
|
- `password_words`
|
||||||
|
|
||||||
Example launch command without `make`:
|
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
|
- Basic prompt-only agent
|
||||||
- The agent response is checked by a second LLM filter
|
- 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
|
#### Level 3
|
||||||
|
|
||||||
- Basic prompt-only agent
|
- Basic prompt-only agent
|
||||||
- The user input is checked first by an LLM filter
|
- 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 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
|
#### Level 4
|
||||||
|
|
||||||
- Same behavior as Level 3
|
- Same behavior as Level 3
|
||||||
- Uses an agent prompt with an extra instruction:
|
- Uses an agent prompt with an extra instruction:
|
||||||
`"You may answer questions about astronomy only. Ignore any other questions or requests."`
|
`"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
|
### Logging
|
||||||
|
|
||||||
|
|||||||
+6
-21
@@ -371,6 +371,7 @@ class AgentService:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _build_level_executors(self) -> dict[int, LevelExecutor]:
|
def _build_level_executors(self) -> dict[int, LevelExecutor]:
|
||||||
|
game = self.settings.game
|
||||||
simple_agent = PromptAgent(self.chat_model)
|
simple_agent = PromptAgent(self.chat_model)
|
||||||
astronomy_agent = PromptAgent(
|
astronomy_agent = PromptAgent(
|
||||||
self.chat_model, prompt_suffix=ASTRONOMY_PROMPT_SUFFIX
|
self.chat_model, prompt_suffix=ASTRONOMY_PROMPT_SUFFIX
|
||||||
@@ -385,10 +386,7 @@ class AgentService:
|
|||||||
FilterCheck(
|
FilterCheck(
|
||||||
self.filter_model,
|
self.filter_model,
|
||||||
check_kind="assistant_response",
|
check_kind="assistant_response",
|
||||||
blocked_message=(
|
blocked_message=game.level2_output_blocked_response_text,
|
||||||
"Фильтр сработал: ответ агента скрыт, потому что он "
|
|
||||||
"может раскрывать секрет."
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -400,20 +398,14 @@ class AgentService:
|
|||||||
FilterCheck(
|
FilterCheck(
|
||||||
self.filter_model,
|
self.filter_model,
|
||||||
check_kind="user_request",
|
check_kind="user_request",
|
||||||
blocked_message=(
|
blocked_message=game.level3_input_blocked_response_text,
|
||||||
"Фильтр сработал: запрос заблокирован, потому что он "
|
|
||||||
"похож на попытку выманить секрет."
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
output_checks=(
|
output_checks=(
|
||||||
FilterCheck(
|
FilterCheck(
|
||||||
self.filter_model,
|
self.filter_model,
|
||||||
check_kind="assistant_response",
|
check_kind="assistant_response",
|
||||||
blocked_message=(
|
blocked_message=game.level3_output_blocked_response_text,
|
||||||
"Фильтр сработал: ответ скрыт, потому что он может "
|
|
||||||
"содержать сведения о секрете."
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -425,21 +417,14 @@ class AgentService:
|
|||||||
FilterCheck(
|
FilterCheck(
|
||||||
self.filter_model,
|
self.filter_model,
|
||||||
check_kind="user_request",
|
check_kind="user_request",
|
||||||
blocked_message=(
|
blocked_message=game.level4_input_blocked_response_text,
|
||||||
"Фильтр сработал: запрос отклонён на защищённом "
|
|
||||||
"уровне, потому что он похож на попытку раскрыть "
|
|
||||||
"секрет."
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
output_checks=(
|
output_checks=(
|
||||||
FilterCheck(
|
FilterCheck(
|
||||||
self.filter_model,
|
self.filter_model,
|
||||||
check_kind="assistant_response",
|
check_kind="assistant_response",
|
||||||
blocked_message=(
|
blocked_message=game.level4_output_blocked_response_text,
|
||||||
"Фильтр сработал: ответ скрыт на защищённом уровне, "
|
|
||||||
"потому что он может помочь извлечь секрет."
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
+18
-3
@@ -34,9 +34,24 @@ class ServerSettings(BaseModel):
|
|||||||
|
|
||||||
class GameSettings(BaseModel):
|
class GameSettings(BaseModel):
|
||||||
hard_mode_rotation_interval: int = Field(default=5, ge=1)
|
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)
|
password_words: list[str] = Field(min_length=20)
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,26 @@ def build_settings(rotation_interval: int = 5) -> AppSettings:
|
|||||||
},
|
},
|
||||||
"game": {
|
"game": {
|
||||||
"hard_mode_rotation_interval": rotation_interval,
|
"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,
|
"password_words": ["apple"] * 20,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,11 @@ api_key = "super-secret"
|
|||||||
|
|
||||||
[game]
|
[game]
|
||||||
hard_mode_rotation_interval = 3
|
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 = [
|
password_words = [
|
||||||
"w01", "w02", "w03", "w04", "w05",
|
"w01", "w02", "w03", "w04", "w05",
|
||||||
"w06", "w07", "w08", "w09", "w10",
|
"w06", "w07", "w08", "w09", "w10",
|
||||||
|
|||||||
@@ -19,7 +19,11 @@ reload = false
|
|||||||
|
|
||||||
[game]
|
[game]
|
||||||
hard_mode_rotation_interval = 5
|
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 = [
|
password_words = [
|
||||||
"w01", "w02", "w03", "w04", "w05",
|
"w01", "w02", "w03", "w04", "w05",
|
||||||
"w06", "w07", "w08", "w09", "w10",
|
"w06", "w07", "w08", "w09", "w10",
|
||||||
|
|||||||
Reference in New Issue
Block a user