In docs I have found only 1 way to add guardrail to a task:
blog_task = Task(
description="Write a blog post about AI",
expected_output="A blog post under 200 words",
agent=blog_agent,
guardrail=validate_blog_content # Add the guardrail function
)
But I`m using decorators syntax to define my whole crew:
@CrewBase
class MyCrew:
agents_config = "config/agents.yaml"
tasks_config = "config/tasks.yaml"
@agent
....
@task
....
So all works well but this task definition with guardrail:
@task
def my_task(self) -> Task:
return Task(
config=self.tasks_config["my_task"],
guardrail=validate_text_output,
)
Is it valid: to pass guardrail function this way using decorators approach?
If yes - why Im getting this error?
[Flow._execute_single_listener] Error in method create_content: 1 validation error for Task
guardrail
Value error, If return type is annotated, it must be Tuple[bool, Any] [type=value_error, input_value=<function validate_text_o...t at 0x000002AC24F9FEC0>, input_type=function]
Yes, I’m passing the function itself, exactly as stated in documentation, but Tuple is expected.
Why?
Is there a way to correctly pass a guardrail function if using Crew Class with Decorators?
1 Like
Hello @Alex_Koniushenko can you share your validate_blog_content() function please. let’s debug that !
Yes, sure
Here it is:
def validate_text_output(result: str) → Tuple[bool, Union[Dict[str, Any], str]]:
“”“Validate that the content is valid text and not binary data.”“”
try:
if not result.strip():
return (
False,
{
“error”: “Content is empty”,
“code”: “EMPTY_CONTENT”,
“context”: {“length”: len(result)},
},
)
binary_signatures = ["%PDF", "\x00"]
if any(result.startswith(sig) for sig in binary_signatures):
return (
False,
{
"error": "Content appears to be binary data",
"code": "BINARY_CONTENT",
"context": {
"content_start": result[:10]
},
},
)
return True, result.strip()
except Exception as e:
return (
False,
{
"error": f"Unexpected error during validation: {str(e)}",
"code": "SYSTEM_ERROR",
},
)
Sorry for late reply :
here one exemple of function to extract Json structure of output :
def validate_json_output2(result: str) -> Tuple[bool, Any]:
json_pattern = r"\{.*\}"
match = re.search(json_pattern, result.raw, re.DOTALL)
if match:
json_data = match.group()
print(json_data)
return (True, json_data)
else:
return (False, "Output must be JSoN format")
class WriteDescription(BaseModel):
Description: str = Field(description="la description détaillée du canapé")
@task
def DescriBot_task(self) -> Task:
return Task(
config=self.tasks_config['DescriBot_task'],
output_pydantic = WriteDescription,
guardrail = validate_json_output2
)
I had the same error which was fix by changing to “Tuple[bool, Any]”
You also need to change result by result.raw which is equal to the string output