qfa.services.prompts#
Prompt building blocks for the free-text analyse endpoint.
Three constants compose the analyse system message:
ANALYZE_SYSTEM_PROMPT— role.ANALYZE_GUARDRAILS_PROMPT— guardrails the model must obey.ANALYZE_ACTION_PROMPT— what to do this call.
The user message wraps the analyst question and the feedback records in
XML-style envelope tags. escape_for_tag_envelope() is applied to
every piece of untrusted text before it is embedded, so attacker-supplied
content cannot break out of the envelope.
The second (judge) LLM call uses ANALYZE_JUDGE_PROMPT filled in
by build_analyze_judge_system_message().
JUDGE_UNAVAILABLE_EXPLANATION is the substitute uncertainty text
when the judge LLM call fails.
Module attributes
Placeholder user message for every judge call. |
Functions
|
Fill |
|
Build the user message for the analyse endpoint. |
|
Build a single <feedback_record> envelope for a record. |
|
Build a <feedback_records> envelope for a sequence of records. |
|
Build the system-prompt suffix pinning the output language. |
|
Escape characters that could break an XML-style tag envelope. |
- qfa.services.prompts.JUDGE_USER_MESSAGE: str = '.'#
Placeholder user message for every judge call.
Judge prompts carry the source text, the analyst prompt and the output to score in the system message, so there is nothing left for the user turn to say. Providers still expect one, hence a single character rather than an empty string. Shared by the analyse and summarise judges so the two cannot drift apart.
- qfa.services.prompts.build_output_language_instruction(output_language: str | None, subject: str = 'analysis') str[source]#
Build the system-prompt suffix pinning the output language.
subjectnames what is written in the requested language (“analysis” for the analyse paths, “title and summary” for summarize-aggregate), so a single builder serves every task (#161).Returns an empty string when
output_languageis falsy (Noneor empty), so callers can append it unconditionally without changing the default prompt. The directive lives in the system message — never the untrusted user message — so a feedback record cannot spoof or override it.The instruction is explicit that it takes precedence over both the feedback records’ own language and any conflicting language request inside the analyst’s free-text prompt — otherwise the model tends to mirror the source records’ language, or defer to a language mentioned in the analyst’s own instruction, regardless of this directive.
This is a dumb formatter: it does NOT sanitize
output_language. Sanitization happens once at the API boundary (qfa.api.schemas.sanitize_output_language()), so the value reaching here is already a strip-and-keep’d, inert fragment (#161).
- qfa.services.prompts.escape_for_tag_envelope(text: str) str[source]#
Escape characters that could break an XML-style tag envelope.
Wraps
xml.sax.saxutils.escape()with quote escaping so an untrustedrecord.idor metadata value cannot break out of<feedback_record id="...">and inject sibling tags. Replaces&→&,<→<,>→>,"→",'→'.
- qfa.services.prompts.build_analyze_user_message(analyst_prompt: str, feedback_records: tuple[FeedbackRecordModel, ...]) str[source]#
Build the user message for the analyse endpoint.
Wraps
analyst_promptin an<analyst_instruction>envelope and every record in<feedback_record id="...">blocks inside a<feedback_records>envelope. All untrusted strings (analyst prompt, record id, record text, every metadata key, every metadata value) pass throughescape_for_tag_envelope()first.The output-language directive deliberately lives only in the analyse system message (see
build_output_language_instruction()), never here — it is trusted config, not part of the untrusted record envelope (#161).
- qfa.services.prompts.build_analyze_judge_system_message(source_text: str, analyst_prompt: str, analysis: str, output_language: str | None = None) str[source]#
Fill
ANALYZE_JUDGE_PROMPTwith source, question, and analysis.output_language, when given, pins the language of the judge’suncertainty_explanation— the only free text in the judge’s response that reaches the analyst — to the same language requested for the analysis itself.