Post Hook Output
Example demonstrating output validation using post-hooks with Kern Agent.
1"""2Post Hook Output3=============================45Example demonstrating output validation using post-hooks with Kern Agent.6"""78import asyncio910from kern.agent import Agent11from kern.exceptions import CheckTrigger, OutputCheckError12from kern.models.openai import OpenAIResponses13from kern.run.agent import RunOutput14from pydantic import BaseModel151617# ---------------------------------------------------------------------------18# Create Agent19# ---------------------------------------------------------------------------20class OutputValidationResult(BaseModel):21 is_complete: bool22 is_professional: bool23 is_safe: bool24 concerns: list[str]25 confidence_score: float262728def validate_response_quality(run_output: RunOutput) -> None:29 """30 Post-hook: Validate the agent's response for quality and safety.3132 This hook checks:33 - Response completeness (not too short or vague)34 - Professional tone and language35 - Safety and appropriateness of content3637 Raises OutputCheckError if validation fails.38 """3940 # Skip validation for empty responses41 if not run_output.content or len(run_output.content.strip()) < 10:42 raise OutputCheckError(43 "Response is too short or empty",44 check_trigger=CheckTrigger.OUTPUT_NOT_ALLOWED,45 )4647 # Create a validation agent48 validator_agent = Agent(49 name="Output Validator",50 model=OpenAIResponses(id="gpt-5-mini"),51 instructions=[52 "You are an output quality validator. Analyze responses for:",53 "1. COMPLETENESS: Response addresses the question thoroughly",54 "2. PROFESSIONALISM: Language is professional and appropriate",55 "3. SAFETY: Content is safe and doesn't contain harmful advice",56 "",57 "Provide a confidence score (0.0-1.0) for overall quality.",58 "List any specific concerns found.",59 "",60 "Be reasonable - don't reject good responses for minor issues.",61 ],62 output_schema=OutputValidationResult,63 )6465 validation_result = validator_agent.run(66 input=f"Validate this response: '{run_output.content}'"67 )6869 result = validation_result.content7071 # Check validation results and raise errors for failures72 if not result.is_complete:73 raise OutputCheckError(74 f"Response is incomplete. Concerns: {', '.join(result.concerns)}",75 check_trigger=CheckTrigger.OUTPUT_NOT_ALLOWED,76 )7778 if not result.is_professional:79 raise OutputCheckError(80 f"Response lacks professional tone. Concerns: {', '.join(result.concerns)}",81 check_trigger=CheckTrigger.OUTPUT_NOT_ALLOWED,82 )8384 if not result.is_safe:85 raise OutputCheckError(86 f"Response contains potentially unsafe content. Concerns: {', '.join(result.concerns)}",87 check_trigger=CheckTrigger.OUTPUT_NOT_ALLOWED,88 )8990 if result.confidence_score < 0.6:91 raise OutputCheckError(92 f"Response quality score too low ({result.confidence_score:.2f}). Concerns: {', '.join(result.concerns)}",93 check_trigger=CheckTrigger.OUTPUT_NOT_ALLOWED,94 )959697def simple_length_validation(run_output: RunOutput) -> None:98 """99 Simple post-hook: Basic validation for response length.100101 Ensures responses are neither too short nor excessively long.102 """103 content = run_output.content.strip()104105 if len(content) < 20:106 raise OutputCheckError(107 "Response is too brief to be helpful",108 check_trigger=CheckTrigger.OUTPUT_NOT_ALLOWED,109 )110111 if len(content) > 5000:112 raise OutputCheckError(113 "Response is too lengthy and may overwhelm the user",114 check_trigger=CheckTrigger.OUTPUT_NOT_ALLOWED,115 )116117118async def main():119 """Demonstrate output validation post-hooks."""120 print("Output Validation Post-Hook Example")121 print("=" * 60)122123 # Agent with comprehensive output validation124 agent_with_validation = Agent(125 name="Customer Support Agent",126 model=OpenAIResponses(id="gpt-5-mini"),127 post_hooks=[validate_response_quality],128 instructions=[129 "You are a helpful customer support agent.",130 "Provide clear, professional responses to customer inquiries.",131 "Be concise but thorough in your explanations.",132 ],133 )134135 # Agent with simple validation only136 agent_simple = Agent(137 name="Simple Agent",138 model=OpenAIResponses(id="gpt-5-mini"),139 post_hooks=[simple_length_validation],140 instructions=[141 "You are a helpful assistant. Keep responses focused and appropriate length."142 ],143 )144145 # Test 1: Good response (should pass validation)146 print("\n[TEST 1] Well-formed response")147 print("-" * 40)148 try:149 await agent_with_validation.aprint_response(150 input="How do I reset my password on my Microsoft account?"151 )152 print("[OK] Response passed validation")153 except OutputCheckError as e:154 print(f"[ERROR] Validation failed: {e}")155 print(f" Trigger: {e.check_trigger}")156157 # Test 2: Force a short response (should fail simple validation)158 print("\n[TEST 2] Too brief response")159 print("-" * 40)160 try:161 # Use a more constrained instruction to get a brief response162 brief_agent = Agent(163 name="Brief Agent",164 model=OpenAIResponses(id="gpt-5-mini"),165 post_hooks=[simple_length_validation],166 instructions=["Answer in 1-2 words only."],167 )168 await brief_agent.aprint_response(input="What is the capital of France?")169 except OutputCheckError as e:170 print(f"[ERROR] Validation failed: {e}")171 print(f" Trigger: {e.check_trigger}")172173 # Test 3: Normal response with simple validation174 print("\n[TEST 3] Normal response with simple validation")175 print("-" * 40)176 try:177 await agent_simple.aprint_response(178 input="Explain what a database is in simple terms."179 )180 print("[OK] Response passed simple validation")181 except OutputCheckError as e:182 print(f"[ERROR] Validation failed: {e}")183 print(f" Trigger: {e.check_trigger}")184185186# ---------------------------------------------------------------------------187# Run Agent188# ---------------------------------------------------------------------------189if __name__ == "__main__":190 asyncio.run(main())Run the Example
1# Clone and setup repo2git clone https://github.com/kern-ai/kern.git3cd kern/cookbook/02_agents/09_hooks45# Create and activate virtual environment6./scripts/demo_setup.sh7source .venvs/demo/bin/activate89python post_hook_output.py