from typing import Any, ClassVar, Literal from pydantic import BaseModel, Field, field_validator USEFULNESS_EVALUATOR_PROMPT: str = """You are a senior researcher evaluating document usefulness. Follow these steps: 1. Required Information: Identify key facts needed to answer the question 2. Factual Content: Check document for presence of required facts 3. Quality Assessment: Evaluate reliability/detail of presented information 4. Coverage Analysis: Determine percentage of required information covered 5. Score Synthesis: Combine factors into final usefulness score **Question:** {question} **Document Excerpt:** {context} Provide detailed reasoning through all steps, then state final score as an integer from 1-5 using format: "final_score": "" 1 = No relevant facts, 3 = Some useful facts with gaps, 5 = Comprehensive high-quality information""" class UsefulnessEvaluatorResult(BaseModel): """Structured evaluation result for document usefulness scoring system. Encapsulates both the reasoning process and final score while ensuring validation of required analytical components through Pydantic model constraints. Attributes: reasoning_chain (str): Step-by-step analysis through evaluation stages. decision (Literal["1", "2", "3", "4", "5"]): Final numerical usefulness score. Raises: ValueError: If reasoning chain misses any required analysis sections ValidationError: If score value is not in allowed range (1-5) Example: >>> try: ... result = UsefulnessEvaluatorResult( ... reasoning_chain=( ... "1. Required Information: Needs 3 economic indicators" ... "2. Factual Content: Contains GDP data" ... "3. Quality Assessment: Government statistics" ... "4. Coverage Analysis: 2/3 indicators present" ... "5. Score Synthesis: Partial official data" ... ), ... decision="3" ... ) ... print(result.decision) ... except ValidationError as e: ... print(e) 3 """ reasoning_chain: str = Field( ..., description=( "Complete analysis chain containing required sections:\n" "1. Required Information: Key facts needed for comprehensive answer\n" "2. Factual Content: Presence verification of required facts\n" "3. Quality Assessment: Source reliability and detail depth\n" "4. Coverage Analysis: Percentage of requirements fulfilled\n" "5. Score Synthesis: Final numerical score justification" ), ) decision: Literal["1", "2", "3", "4", "5"] = Field( ..., description=( "Numerical usefulness score with criteria:\n" "1 - Irrelevant/no facts | 2 - Minimal value | 3 - Partial with gaps\n" "4 - Good reliable coverage | 5 - Comprehensive high-quality" ), ) @field_validator("reasoning_chain") @classmethod def validate_reasoning_steps(cls, chain_to_validate: str) -> str: """Validate completeness of analytical reasoning chain. Ensures all required evaluation phases are present and properly formatted in the reasoning chain through section header verification. Args: chain_to_validate (str): Raw text of the reasoning chain to validate Returns: str: Validated reasoning chain if all requirements are met Raises: ValueError: If any of the required section headers are missing from the reasoning chain text Example: >>> valid_chain = ( ... "1. Required Information: Needs 5 metrics" ... "2. Factual Content: Contains 3 metrics" ... "3. Quality Assessment: Industry reports" ... "4. Coverage Analysis: 60% complete" ... "5. Score Synthesis: Partial coverage" ... ) >>> UsefulnessEvaluatorResult.validate_reasoning_steps(valid_chain) '1. Required Information: Needs 5 metrics...' """ required_steps: list[str] = [ "1. Required Information", "2. Factual Content", "3. Quality Assessment", "4. Coverage Analysis", "5. Score Synthesis", ] missing: list[str] = [step for step in required_steps if step not in chain_to_validate] if missing: msg = f"Missing required analysis sections: {', '.join(missing)}" raise ValueError(msg) return chain_to_validate model_config: ClassVar[dict[str, Any]] = { "json_schema_extra": { "example": { "reasoning_chain": ( "1. Required Information: Needs 5 climate change impacts\n" "2. Factual Content: Details 3 impacts with data\n" "3. Quality Assessment: Peer-reviewed sources cited\n" "4. Coverage Analysis: 60% of requirements met\n" "5. Score Synthesis: Strong but incomplete coverage" ), "decision": "4", } } }