참고소스 수정본
This commit is contained in:
113
참고/guardrails-main/guardrails/schema/validator.py
Normal file
113
참고/guardrails-main/guardrails/schema/validator.py
Normal file
@@ -0,0 +1,113 @@
|
||||
import json
|
||||
from typing import Any, Dict, List, Optional
|
||||
from jsonschema import Draft202012Validator, ValidationError
|
||||
from referencing import Registry, jsonschema as jsonschema_ref
|
||||
|
||||
from guardrails.actions.reask import SkeletonReAsk
|
||||
from guardrails_ai.types import FailResult
|
||||
|
||||
|
||||
class SchemaValidationError(Exception):
|
||||
fields: Dict[str, List[str]] = {}
|
||||
|
||||
def __init__(self, *args: object, fields: Dict[str, List[str]]):
|
||||
self.fields = fields
|
||||
super().__init__(*args)
|
||||
|
||||
|
||||
def validate_against_schema(
|
||||
payload: Any,
|
||||
validator: Draft202012Validator,
|
||||
*,
|
||||
validate_subschema: Optional[bool] = False,
|
||||
):
|
||||
fields: Dict[str, List[str]] = {}
|
||||
error: ValidationError
|
||||
for error in validator.iter_errors(payload):
|
||||
if validate_subschema is True and error.message.endswith(
|
||||
"is a required property"
|
||||
):
|
||||
continue
|
||||
fields[error.json_path] = fields.get(error.json_path, [])
|
||||
fields[error.json_path].append(error.message)
|
||||
|
||||
if fields:
|
||||
error_message = (
|
||||
"The provided payload is not compliant with the provided schema!"
|
||||
)
|
||||
raise SchemaValidationError(error_message, fields=fields)
|
||||
|
||||
|
||||
def validate_json_schema(json_schema: Dict[str, Any]):
|
||||
"""Validates a json_schema, against the JSON Meta Schema Draft 2020-12.
|
||||
|
||||
Raises a SchemaValidationError if invalid.
|
||||
"""
|
||||
json_schema_validator = Draft202012Validator(
|
||||
{
|
||||
"$ref": "https://json-schema.org/draft/2020-12/schema",
|
||||
}
|
||||
)
|
||||
try:
|
||||
validate_against_schema(json_schema, json_schema_validator)
|
||||
except SchemaValidationError as e:
|
||||
schema_name = json_schema.get("title", json_schema.get("$id"))
|
||||
error_message = (
|
||||
f"Schema {schema_name} is not compliant with JSON Schema Draft 2020-12!"
|
||||
)
|
||||
raise SchemaValidationError(error_message, fields=e.fields)
|
||||
|
||||
|
||||
def validate_payload(
|
||||
payload: Any,
|
||||
json_schema: Dict[str, Any],
|
||||
*,
|
||||
validate_subschema: Optional[bool] = False,
|
||||
):
|
||||
"""Validates a payload, against the provided JSON Schema.
|
||||
|
||||
Raises a SchemaValidationError if invalid.
|
||||
"""
|
||||
schema_id = json_schema.get("$id", "temp-schema")
|
||||
registry = Registry().with_resources(
|
||||
[
|
||||
(
|
||||
f"urn:{schema_id}",
|
||||
jsonschema_ref.DRAFT202012.create_resource(json_schema),
|
||||
)
|
||||
]
|
||||
)
|
||||
validator = Draft202012Validator(
|
||||
{
|
||||
"$ref": f"urn:{schema_id}",
|
||||
},
|
||||
registry=registry,
|
||||
# TODO: Add custom checks for date: format,
|
||||
# time: format, date-time: format, etc.
|
||||
# format_checker=draft202012_format_checker
|
||||
)
|
||||
validate_against_schema(payload, validator, validate_subschema=validate_subschema)
|
||||
|
||||
|
||||
def schema_validation(llm_output: Any, output_schema: Dict[str, Any], **kwargs):
|
||||
validate_subschema = kwargs.get("validate_subschema", False)
|
||||
|
||||
schema_error = None
|
||||
try:
|
||||
validate_payload(
|
||||
llm_output, output_schema, validate_subschema=validate_subschema
|
||||
)
|
||||
except SchemaValidationError as sve:
|
||||
formatted_error_fields = json.dumps(sve.fields, indent=2)
|
||||
schema_error = f"JSON does not match schema:\n{formatted_error_fields}"
|
||||
|
||||
if schema_error:
|
||||
return SkeletonReAsk(
|
||||
incorrectValue=llm_output,
|
||||
failResults=[
|
||||
FailResult(
|
||||
fixValue=None,
|
||||
errorMessage=schema_error,
|
||||
)
|
||||
],
|
||||
)
|
||||
Reference in New Issue
Block a user