# Unit

JudgeUnit(DiscreteScale((1, 5)), name="CXEmpathyJudge")
    .via('gpt-4o', retries=3, temperature=1.4)
    .prompt("""
        Score the following customer support conversation on empathy.

        <conversation>
        ...
        </conversation>
    """)
    .extract(RegexExtractor(pattern=RegexExtractor.FIRST_INT))
    .propagate(lambda output: Schema.of(score=output.score / 5))

Verdict comes bundled with common LLM-as-a-Judge system building blocks. These wrappers, or units,

# Anatomy of a Unit

At its heart, a Unit is simply a wrapper around an LLM inference call with a well-specified input and output. We break this requirement into three components.

  • (optional) InputSchema, which dependency units must provide (we perform append-only name-casting)
  • (required) ResponseSchema: the raw response from the LLM inference call
  • (optional) OutputSchema: by default, this is the unprocessed ResponseSchema

Refer to the Unit Execution Lifecycle section for specific details.

# Unit Registry

Reusing the same Unit name across different files is not permitted. This is to avoid ambiguity when using the previous context variable.

# Built-Ins

Unit Description Example Notebook
JudgeUnit Direct score judge with customizable score Scale and optional preceeding explanation/CoT. Open In Colab
PairwiseJudgeUnit Pairwise judge with customizable score Scale and optional preceeding explanation/CoT. Open In Colab
BestOfKJudgeUnit Best of k inputs with customizable score Scale and optional preceeding explanation/CoT. Open In Colab
CategoricalJudgeUnit Judge unit for categorical decisions (e.g., 'Harmful' or 'Not Harmful', 'Hallucination' or 'No Hallucination'). Open In Colab
RankerUnit Rank k inputs with optional preceeding explanation/CoT. Open In Colab
ConversationalUnit Supports roles and a shared conversation history. Useful for debate, etc. Open In Colab
CoTUnit Simple reasoning unit with single string field thinking. Open In Colab

# Defining a Custom Unit

Subclass Unit to define your own units. We'll walk through the implementation of the PairwiseJudgeUnit as a case study.

from verdict import Unit
from verdict.schema import Schema

class PairwiseJudgeUnit(Unit):
    _char: str = "PairwiseJudge"

    class InputSchema(Schema):
        A: str
        B: str

    # This Unit's default Prompt template
    _prompt: Prompt = Prompt.from_template("""
        You must choose the better option between the following two options based on how well they satisfy the following single criteria:

        A:
        {input.A}

        B:
        {input.B}
    """)

    # This Unit's response produced from LLM inference
    #   * validate(ResponseSchema) must pass
    #   * process(ResponseSchema, InputSchema) -> OutputSchema
    class ResponseSchema(Schema):
        winner: DiscreteScale = DiscreteScale(['A', 'B'])

    # This Unit's output
    class OutputSchema(Schema):
        winner: str

    # Validate the ResponseSchema. This is called after the LLM inference call.
    def validate(self, input: InputSchema, response: ResponseSchema) -> None:
        pass

    # Post-process the ResponseSchema into the OutputSchema.
    def process(self, input: InputSchema, response: ResponseSchema) -> OutputSchema:
        return self.OutputSchema(winner=input.A if response.winner == 'A' else input.B)

# Subclass Checklist

You can override the following components when creating a custom Unit.

Component Optional? Description
InputSchema ✅ Previous Unit's OutputSchema casted to the current Unit's InputSchema.
ResponseSchema ❌ Schema of response generated via inference using the specified extractor.
validate ✅ Validates that the ResponseSchema is valid. Will trigger a retry if validation fails.
process ✅ Populates the OutputSchema from the ResponseSchema.
OutputSchema ✅ Passed to the next Unit.
_char ✅ Unique identifier for the Unit.