← All Problems

2. Match a Response Against Ranked Constitutional Principles

General Medium Anthropic-Style Coding Rounds
Grounding: General pattern common across ML-research-lab technical interviews, not tied to one specific reported example. Anthropic's public research describes training against a ranked set of written principles (its "Constitutional AI" approach), but no source found in this batch's research reports a coding interview question built directly on that idea.

Problem

A Constitutional-AI-style review step checks a candidate response against an ordered list of principles before it's shown to the user. Principles are ranked by priority (earlier in the list wins), and each principle carries a set of trigger keywords or phrases.

The review step must find the single highest-priority principle that the response actually triggers, not just any principle that happens to match somewhere in the list.

Source: src/2_match_constitutional_principle.py

def first_matching_principle(response: str, principles: list[tuple[str, list[str]]]) -> str | None:
    ...

Examples:
>>> principles = [
...     ("avoid_harm", ["bomb", "weapon"]),
...     ("respect_autonomy", ["you must", "you have to"]),
...     ("be_honest", ["trust me"]),
... ]
>>> first_matching_principle("Here's how to build a small weapon for a movie prop.", principles)
'avoid_harm'

>>> first_matching_principle("You must trust me on this.", principles)
'respect_autonomy'

Step-by-Step Approach

  1. Notice that "priority" here is just list order — the first principle in the list that matches wins, even if a lower-priority principle also matches.
  2. Iterate principles in the given order (do not sort or re-rank them).
  3. For each principle, check each of its keywords against the response as a case-insensitive substring search.
  4. As soon as any keyword for the current principle is found, return that principle's name immediately — do not keep scanning for a "better" or "stronger" match.
  5. If no principle in the entire list matches, return None.

The key insight is that priority is encoded entirely by iteration order, so the algorithm is just an early-exit nested scan — the complexity is in getting the early exit right, not in any clever data structure.

Reference solution

def first_matching_principle(response: str, principles: list[tuple[str, list[str]]]) -> str | None:
    # priority order is just list order: return on the first principle hit,
    # not the "best" hit, so no need to scan every principle
    lower = response.lower()
    for name, keywords in principles:
        for keyword in keywords:
            if keyword.lower() in lower:
                return name
    return None

Key Functions & Tricks

  • response.lower() — precompute once for case-insensitive comparison
  • keyword.lower() in lower — substring membership test, O(len(response)) per check
  • early return inside nested loop — encodes priority as iteration order, avoids scanning lower-priority principles once a hit is found

How to Recognize This Pattern

The signal is "apply the first rule from a ranked/ordered list that matches," where the order itself carries the priority semantics — no explicit priority field to sort by. The fix is always a simple ordered scan with an early return, resisting the urge to collect all matches and then pick the "best" one. Common variations add wildcard or regex keywords instead of plain substrings, or require whole-word matches instead of raw substrings. A common pitfall is scanning all principles and then trying to rank the matches afterward, which is both slower and semantically wrong when priority is defined by list position rather than by any score.