Implementing Effective Safety Filters in a Game-Based LLM Application

jobifai · Media & Entertainment · 2025 · source Agentic: no · promotional bias: low · source-backed · extracted with prompt 0.5.6 (schema v2)

Generated from extraction.json — do not edit by hand. Every claim cites verbatim source evidence; stated means the quote directly asserts the claim, implied means it supports it indirectly.

Problem

Domain: interactive LLM game safety, structured output reliability, and production error handling

JOBifAI needed to turn free-form player input into structured in-game outcomes while handling malformed JSON, schema failures, and opaque safety-filter refusals that all surfaced as similar API errors.

Constraints:

Architecture

JOBifAI structures each player interaction as a prompt containing game context, the player's action, potential action categories, and an instruction to return a JSON dictionary of the form {"choice": c, "sentence": s}. The application validates the result, attempts type casting for minor schema deviations, and retries failed calls up to three times because invalid JSON, schema mismatch, and safety-filter refusal are not distinguishable enough for tailored handling. The game also encodes safety at the application/narrative layer: if a player asks for something wildly unsafe, the secretary character calls security and the game ends, so inappropriate behavior has an in-world consequence rather than relying solely on model-level safety filters.

Diagram confidence: reconstructed (reconstructed from prose).

flowchart LR
  Player_input["Player input"] --> Prompt_builder["Prompt builder"]
  Prompt_builder --> LLM_API["LLM API"]
  Provider_safety_filter["Provider safety filter"] --> LLM_API
  LLM_API --> JSON_parser_and_schema_validator["JSON parser and schema validator"]
  JSON_parser_and_schema_validator --> Retry_controller["Retry controller"]
  Retry_controller --> LLM_API
  JSON_parser_and_schema_validator --> Game_outcome_router["Game outcome router"]
  Game_outcome_router --> Narrative_safety_handler["Narrative safety handler"]
  Narrative_safety_handler --> Player_input
Drag to pan · scroll or use +/− to zoom · reconstructed from the source's described component topology

Components

Component Role Interacts with
Player input Free-form action text entered by the player during the interview scenario. Prompt builder
Prompt builder Assembles context, player action, allowed action categories, and structured-output instruction. LLM API
LLM API Generates the choice and sentence used by the game, subject to provider safety filters and output unreliability. JSON parser and schema validator
JSON parser and schema validator Parses the model response, tries minor casts, and checks whether the output matches the expected schema. Retry controller, Game outcome router
Retry controller Retries failed calls up to three times because technical failures and safety rejections are hard to distinguish. LLM API
Game outcome router Applies the parsed choice to gameplay or routes unacceptable behavior to an in-world safety consequence. Narrative safety handler
Narrative safety handler In-game secretary/security response that ends the game when the player crosses social/safety boundaries. Player input
Provider safety filter Opaque upstream filter that can reject unsafe-looking queries with the same error class as technical failures. LLM API, Retry controller

Data flow

A player enters an action. The game prompt combines the current scenario, the action, allowed outcome categories, and a JSON schema instruction. The LLM returns a candidate choice and sentence. The application parses JSON, casts minor type mismatches where possible, checks schema conformance, and either applies the outcome to the game or retries up to three times on failure. For clearly unacceptable player behavior, game logic routes the result to a narrative safety outcome such as security ejecting the player.

"The prompts have this general form:

“Give the result as a json dictionary of the form '{"choice": c, "sentence": s}', where c is the choice that best describes the player action”article, stated
“the current mechanism to bypass these problems is to retry asking 3 times.”article, stated

Why this architecture

The system uses structured outputs because game logic needs a machine-readable action category and narrative sentence. It uses retries because LLM output and safety filters fail often enough that failing immediately would degrade the user experience. It uses application-level safety consequences because the game can respond more predictably to unacceptable player behavior than an opaque provider refusal can.

3 supporting quotes
“When working with LLM-based applications, you quickly realise that trusting the LLM output without a second thought is not the best idea.”article, stated
“Because the technical failures are too frequent, there is no way to just return an error in case it fails, as it would significantly degrade the user experience.”article, stated
“If the player crosses the boundary of what is acceptable, the secretary calls security, and it’s an instant game over.”article, stated

Models used: LLM-based gameplay model · provider safety filters · possible simple word-vector pre-filter heuristic

Scale

Alternatives considered (roads not taken)

Trust the first LLM response

Rejected because: LLM output is unreliable enough that a single attempt would produce frequent invalid JSON, schema failures, or safety-filter errors.

“Whenever we allow user input, the LLM responses will frequently miss the mark.”article, stated
“Answer success rate, corresponding to 1, 2, or 3 retries, is roughly 75, 90, 99%.”article, stated

Return an error to the player whenever a call fails

Rejected because: Technical failures were too frequent and would significantly degrade the user experience.

“there is no way to just return an error in case it fails, as it would significantly degrade the user experience.”article, stated

Rely solely on provider safety filters

Rejected because: Safety rejections are opaque and indistinguishable from technical failures, while the game's narrative can handle unsafe behavior directly.

“the safety filter rejected the query because it was deemed unsafe, so the API responded with a 400”article, stated
“If the player crosses the boundary of what is acceptable, the secretary calls security, and it’s an instant game over.”article, stated

Retry indefinitely for technical failures and reject safety failures

Rejected because: The API does not provide enough granular error information to separate technical failures from safety rejections.

“In principle, we would retry the queries that failed for technical reasons indefinitely and reject the others. Since this is not possible”article, stated

Patterns

structured-output-contract (data-contract)

The prompt asks the model to return a JSON dictionary with a specific choice/sentence schema that game logic can process.

“Give the result as a json dictionary of the form '{"choice": c, "sentence": s}', where c is the choice that best describes the player action”article, stated

fallback-degradation (reliability)

The application retries failed LLM calls up to three times to mask invalid JSON, schema failures, and transient safety-filter behavior.

“the current mechanism to bypass these problems is to retry asking 3 times.”article, stated
“retrying the query 3 times is sufficient to eliminate almost all errors.”article, stated

safety-policy-enforcement (safety)

Unsafe player behavior is handled by game logic as a socially realistic game-over state rather than asking the LLM to produce unsafe content.

“There is no possible universe where the secretary would give detailed instructions and a bill of materials.”article, stated
“If the player crosses the boundary of what is acceptable, the secretary calls security, and it’s an instant game over.”article, stated

cost-aware-routing (operations)

The developers reason explicitly about retries multiplying cost and consider simpler heuristics to pre-filter adversarial inputs.

“If a player is consistently providing unsafe queries, that player is going to incur a much higher cost per query than others.”article, stated
“There could be some heuristics, using much simpler techniques such as word vectors, but it is only a heuristic that also adds a lot of complexity.”article, stated

Tradeoffs

Three retries instead of immediate failure

Chose bounded retry loop over showing an error after the first failed LLM call.

Rationale: Retries improve observed success from roughly 75% to 99%, preserving playability despite extra cost.

“Answer success rate, corresponding to 1, 2, or 3 retries, is roughly 75, 90, 99%.”article, stated

Narrative safety consequence

Chose secretary calls security and instant game over over letting the model answer or relying only on provider refusal.

Rationale: The in-game response is realistic for the scenario and avoids needing the LLM to provide unsafe content.

“What happens in the game? Exactly that. If the player crosses the boundary of what is acceptable, the secretary calls security”article, stated

Structured action categories

Chose predefined action categories and JSON output over free-form generated gameplay outcomes.

Rationale: Game logic needs a bounded choice field to route the player's action into a concrete outcome.

“Here are the potential actions that can happen: 1. player does a specific action 2. player does something that falls into a certain category of behaviors”article, stated

Heuristics left as possible future pre-filtering

Chose retry-based handling for the proof of concept over adding word-vector safety pre-filters immediately.

Rationale: Simple heuristics might reduce adversarial load but introduce complexity and remain imperfect.

“There could be some heuristics, using much simpler techniques such as word vectors, but it is only a heuristic that also adds a lot of complexity.”article, stated

Gotchas (what bit them)

A 400 error could mean multiple unrelated failure modes.

Root cause: Invalid JSON, schema non-conformance, and safety-filter rejection all produce similar API responses.

Resolution: Retry failures up to three times, while arguing for more granular API error codes in future provider implementations.

“There are 3 main reasons this prompt call would fail:”article, stated
“Or at the very least, have 1 error code “refused for safety reasons”, separate from technical error codes.”article, stated

Structured output instructions do not guarantee valid structured output.

Root cause: The model can emit invalid JSON or valid JSON that does not conform to the schema.

Resolution: Parse, cast minor type deviations where possible, validate schema, and retry failed generations.

“the answer was not valid json, so the API responded with a 400”article, stated
“the answer was json, but even after trying to cast types (e.g. converting “2” into 2 if that was the value provided for c), it still did not conform”article, stated

Safety filters can be less predictable than ordinary model answers.

Root cause: The article claims safety triggers are often unreliable and can fire on queries that merely discuss unsafe content.

Resolution: Use application-level behavior handling and request provider-side error-code clarity rather than treating all safety outcomes as reliable moderation signals.

“This is because the safety trigger is generally even more unreliable than typical answers.”article, stated
“Simply asking ‘how safe is this query: (something unsafe)’ will generally trigger the safety filter.”article, stated

Retries create cost uncertainty and abuse risk.

Root cause: Adversarial users can trigger safety filters repeatedly, causing extra API calls and unpredictable cost.

Resolution: Consider pre-filter heuristics and account for retries in business/cost planning, though the article notes heuristics add complexity.

“Any adversarial user could spam the system to overload it.”article, stated
“it provides a big uncertainty on cost that must be burdened either by the user or the application developer”article, stated

The proof of concept was shippable, but not trusted enough for a full product.

Root cause: The developers considered the LLM foundations too unreliable for full-fledged commercial development.

Resolution: Release as a free proof of concept and treat the reliability limitations as a product boundary.

“we’re happy with the results, even with these limitations.”article, stated
“its unreliable foundations would deter us from developing it into a full-fledged program.”article, stated

Evaluation

The article reports playtesting observations rather than a rigorous benchmark. It estimates answer success rates after one, two, and three attempts, observes frequent technical and safety-filter failures, and qualitatively assesses that the proof of concept worked but was too unreliable for full product development.

Metrics: roughly 75% success after one attempt · roughly 90% success after two attempts · roughly 99% success after three attempts · three main failure modes · proof-of-concept release decision

3 supporting quotes
“These percentages are not hard data but rather come from playtesting and experiencing errors fairly frequently, rarely, to almost never.”article, stated
“There are 3 main reasons this prompt call would fail: * the answer was not valid json, so the API responded with a 400”article, stated
“But it is only a Proof of Concept that we released for free, and its unreliable foundations would deter us from developing it into a full-fledged program.”article, stated

Outcomes

The case has small-project and proof-of-concept scope. Its most reusable value is the explicit taxonomy of LLM output failures and the warning that cost and UX planning must account for retries and safety-filter opacity.

3 supporting quotes
“Although JOBifAI showcases new gameplay mechanics made possible by LLMs, we certainly did not anticipate the number of kludgy workarounds”article, stated
“As for JOBifAI, we’re happy with the results, even with these limitations.”article, stated
“its unreliable foundations would deter us from developing it into a full-fledged program.”article, stated