denselinkage.matching.LangChainMatcher

class denselinkage.matching.LangChainMatcher(*, llm: Any, prompt: str, retry: RetryPolicy | None = None, max_concurrency: int = 1)[source]

Bases: Matcher

LLM matcher (extra: [langchain]).

The llm is injected (any LangChain chat model); model / operational / domain config stay separate. Prompt/output contract: prompt carries ONLY the semantic question and may reference the pair fields ({record_a} / {record_b}). The response structure is framework-owned — the matcher binds structured output and returns typed MatchDecision``s; callers never parse text and the prompt never asks for a format. On exhausted ``retry the matcher yields a MatchError(reason=...) for that pair (aligned by position), never raising into the batch.

__init__ raises plain ValueError (API misuse, tier 3) if prompt references any placeholder other than {record_a} / {record_b}. Such a template cannot render for a single pair. Left to fail at call time it would spend the whole retry budget per pair and surface as a MatchError, which is reserved for a pair the matcher could not decide. Using only one of the two, or neither, renders and is accepted.

match(pairs: Sequence[CandidatePair]) → list[MatchDecision | MatchError][source]

One outcome per input pair, aligned by position. A pair the matcher cannot decide yields a MatchError (never raises into the batch, so one bad call does not abort the rest).

See CandidatePair.similarity_score for the contract on handling optional similarity hints.