Skip to content

Namespace: llm.feedback.* — User Feedback Payloads

Module: spanforge.namespaces.feedback
Added in: 2.0.12 (Phase 13)
Events covered: llm.feedback.submitted, llm.feedback.summary

This namespace covers payload types for collecting and aggregating user feedback on LLM responses. Use spanforge.sdk.feedback to emit these events without constructing the dataclasses directly.


Classes

ClassEventDescription
FeedbackRating(enum)Supported rating modalities
FeedbackSubmittedPayloadllm.feedback.submittedA single feedback submission
FeedbackSummaryPayloadllm.feedback.summaryAggregated feedback for a session or window

FeedbackRating

class FeedbackRating(str, Enum)

Supported user feedback rating modalities. All values are also valid as plain strings when passed to sf_feedback.submit().

ValueStringNumeric value (numeric_value())Description
THUMBS_UP"thumbs_up"1.0Binary positive feedback
THUMBS_DOWN"thumbs_down"0.0Binary negative feedback
STAR_1"star_1"0.01 out of 5 stars
STAR_2"star_2"0.252 out of 5 stars
STAR_3"star_3"0.53 out of 5 stars
STAR_4"star_4"0.754 out of 5 stars
STAR_5"star_5"1.05 out of 5 stars
LIKERT_1"likert_1"0.0Strongly disagree
LIKERT_2"likert_2"0.25Disagree
LIKERT_3"likert_3"0.5Neutral
LIKERT_4"likert_4"0.75Agree
LIKERT_5"likert_5"1.0Strongly agree
FREE_TEXT"free_text"NoneOpen-ended qualitative comment

numeric_value() -> float | None

Returns a normalised 0.0–1.0 value for ratings that have one, or None for FREE_TEXT.

  • Thumbs: THUMBS_UP → 1.0, THUMBS_DOWN → 0.0
  • Star / Likert: (value - 1) / 4 mapped to [0.0, 1.0]
from spanforge.namespaces.feedback import FeedbackRating

FeedbackRating.STAR_4.numeric_value()   # 0.75
FeedbackRating.LIKERT_3.numeric_value() # 0.5
FeedbackRating.THUMBS_UP.numeric_value() # 1.0
FeedbackRating.FREE_TEXT.numeric_value() # None

FeedbackSubmittedPayload

Payload for llm.feedback.submitted events.

@dataclass
class FeedbackSubmittedPayload:
    feedback_id: str
    session_id: str
    trace_id: str
    rating: FeedbackRating
    comment_hash: str = ""
    user_id_hash: str = ""
    source: str = "api"
    metadata: dict[str, Any] = field(default_factory=dict)
    linked_trust_dimension: str | None = None
FieldTypeValidationDescription
feedback_idstrnon-emptyUnique feedback record identifier (ULID)
session_idstrnon-emptySession or conversation this feedback belongs to
trace_idstrTrace ID of the specific LLM call being rated
ratingFeedbackRatingvalid enumThe feedback rating type
comment_hashstrSHA-256 hex digest of free-text comment; "" when no comment
user_id_hashstrSHA-256 hex digest of the user identifier; "" for anonymous submissions
sourcestrFeedback channel (e.g. "api", "ui", "email")
metadatadictArbitrary key-value metadata
linked_trust_dimensionstr | NoneT.R.U.S.T. dimension ("transparency", "reliability", "user_trust", "security", "traceability")

Privacy: Raw comment text and user IDs are never stored. Only their SHA-256 hashes are persisted, making it impossible to recover the original values.

Methods: to_dict() -> dict, from_dict(data: dict) -> FeedbackSubmittedPayload


FeedbackSummaryPayload

Payload for llm.feedback.summary events. Aggregated feedback statistics over a session or time window.

@dataclass
class FeedbackSummaryPayload:
    session_id: str
    total_feedback: int = 0
    thumbs_up_count: int = 0
    thumbs_down_count: int = 0
    avg_star_rating: float | None = None
    avg_likert_score: float | None = None
    free_text_count: int = 0
    positive_rate: float = 0.0
FieldTypeValidationDescription
session_idstrnon-emptySession or aggregation window identifier
total_feedbackintTotal feedback events in the window
thumbs_up_countintCount of THUMBS_UP ratings
thumbs_down_countintCount of THUMBS_DOWN ratings
avg_star_ratingfloat | NoneMean star rating (1–5); None if no star ratings
avg_likert_scorefloat | NoneMean Likert score (1–5); None if no Likert ratings
free_text_countintNumber of free-text comments submitted
positive_ratefloat[0.0, 1.0]Fraction of positive feedback across all numeric ratings

Methods: to_dict() -> dict, from_dict(data: dict) -> FeedbackSummaryPayload


Usage example

from spanforge.namespaces.feedback import FeedbackRating

# Prefer the high-level client:
from spanforge.sdk import sf_feedback

fb_id = sf_feedback.submit(
    session_id="sess-abc",
    trace_id="trace-xyz",
    rating=FeedbackRating.STAR_4,
)
summary = sf_feedback.get_summary("sess-abc")
print(summary.avg_star_rating)   # 4.0
print(summary.positive_rate)     # 0.75

Related