Skip to content

Commit a90aac6

Browse files
committed
feat: add pre-configured requiments
Signed-off-by: Akihiko Kuroda <akihikokuroda2020@gmail.com>
1 parent 7bfd18d commit a90aac6

8 files changed

Lines changed: 3741 additions & 0 deletions

File tree

docs/examples/guardrails.py

Lines changed: 523 additions & 0 deletions
Large diffs are not rendered by default.

docs/examples/guardrails_repair.py

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
# pytest: ollama, llm
2+
"""Example demonstrating guardrail repair strategies.
3+
4+
This example shows how to use guardrails with repair enabled (check_only=False)
5+
to guide the LLM in self-correcting outputs that fail validation.
6+
"""
7+
8+
from mellea import start_session
9+
from mellea.stdlib.requirements.guardrails import (
10+
contains_keywords,
11+
excludes_keywords,
12+
json_valid,
13+
max_length,
14+
min_length,
15+
no_pii,
16+
)
17+
from mellea.stdlib.sampling import RepairTemplateStrategy
18+
19+
20+
def example_repair_pii():
21+
"""Example: Repair output containing PII."""
22+
print("\n" + "=" * 80)
23+
print("EXAMPLE: Repair PII Detection")
24+
print("=" * 80)
25+
26+
session = start_session()
27+
28+
# With check_only=False, the guardrail provides actionable repair guidance
29+
result = session.instruct(
30+
"Generate a sample customer profile with name, email, and phone",
31+
requirements=[no_pii(check_only=False)],
32+
strategy=RepairTemplateStrategy(loop_budget=3),
33+
)
34+
35+
print(f"\nFinal output (should be PII-free):\n{result.value}")
36+
37+
38+
def example_repair_json():
39+
"""Example: Repair invalid JSON output."""
40+
print("\n" + "=" * 80)
41+
print("EXAMPLE: Repair JSON Format")
42+
print("=" * 80)
43+
44+
session = start_session()
45+
46+
result = session.instruct(
47+
"Create a JSON object with fields: name (string), age (number), active (boolean)",
48+
requirements=[json_valid(check_only=False)],
49+
strategy=RepairTemplateStrategy(loop_budget=3),
50+
)
51+
52+
print(f"\nFinal output (should be valid JSON):\n{result.value}")
53+
54+
55+
def example_repair_length():
56+
"""Example: Repair output that's too long or too short."""
57+
print("\n" + "=" * 80)
58+
print("EXAMPLE: Repair Length Constraints")
59+
print("=" * 80)
60+
61+
session = start_session()
62+
63+
# Too long - should be shortened
64+
result1 = session.instruct(
65+
"Write a brief summary of Python programming",
66+
requirements=[max_length(100, unit="characters", check_only=False)],
67+
strategy=RepairTemplateStrategy(loop_budget=3),
68+
)
69+
70+
print(f"\nShortened output ({len(result1.value or '')} chars):\n{result1.value}")
71+
72+
# Too short - should be expanded
73+
result2 = session.instruct(
74+
"Explain machine learning",
75+
requirements=[min_length(200, unit="characters", check_only=False)],
76+
strategy=RepairTemplateStrategy(loop_budget=3),
77+
)
78+
79+
print(f"\nExpanded output ({len(result2.value or '')} chars):\n{result2.value}")
80+
81+
82+
def example_repair_keywords():
83+
"""Example: Repair missing or forbidden keywords."""
84+
print("\n" + "=" * 80)
85+
print("EXAMPLE: Repair Keyword Requirements")
86+
print("=" * 80)
87+
88+
session = start_session()
89+
90+
# Missing keywords - should add them
91+
result1 = session.instruct(
92+
"Explain web development",
93+
requirements=[
94+
contains_keywords(
95+
["HTML", "CSS", "JavaScript"], require_all=True, check_only=False
96+
)
97+
],
98+
strategy=RepairTemplateStrategy(loop_budget=3),
99+
)
100+
101+
print(f"\nOutput with required keywords:\n{result1.value}")
102+
103+
# Forbidden keywords - should remove them
104+
result2 = session.instruct(
105+
"Write professional documentation about the project",
106+
requirements=[excludes_keywords(["TODO", "FIXME", "hack"], check_only=False)],
107+
strategy=RepairTemplateStrategy(loop_budget=3),
108+
)
109+
110+
print(f"\nProfessional output (no forbidden keywords):\n{result2.value}")
111+
112+
113+
def example_combined_repair():
114+
"""Example: Multiple guardrails with repair."""
115+
print("\n" + "=" * 80)
116+
print("EXAMPLE: Combined Repair Strategies")
117+
print("=" * 80)
118+
119+
session = start_session()
120+
121+
# Multiple constraints that may need repair
122+
result = session.instruct(
123+
"Generate a JSON user profile",
124+
requirements=[
125+
json_valid(check_only=False),
126+
no_pii(check_only=False),
127+
max_length(300, check_only=False),
128+
contains_keywords(["username", "role"], check_only=False),
129+
],
130+
strategy=RepairTemplateStrategy(loop_budget=5),
131+
)
132+
133+
print(f"\nFinal output (meets all requirements):\n{result.value}")
134+
135+
136+
def example_check_only_vs_repair():
137+
"""Example: Comparing check_only=True vs check_only=False."""
138+
print("\n" + "=" * 80)
139+
print("EXAMPLE: Check-Only vs Repair Mode")
140+
print("=" * 80)
141+
142+
session = start_session()
143+
144+
# check_only=True: Brief reason, hard fail
145+
print("\nWith check_only=True (validation only):")
146+
try:
147+
result1 = session.instruct(
148+
"Write a 500-word essay",
149+
requirements=[max_length(50, check_only=True)],
150+
strategy=RepairTemplateStrategy(loop_budget=1),
151+
)
152+
print(f"Output: {result1.value}")
153+
except Exception as e:
154+
print(f"Failed: {e}")
155+
156+
# check_only=False: Detailed guidance, repair attempts
157+
print("\nWith check_only=False (repair enabled):")
158+
result2 = session.instruct(
159+
"Write a brief summary",
160+
requirements=[max_length(50, check_only=False)],
161+
strategy=RepairTemplateStrategy(loop_budget=3),
162+
)
163+
print(f"Output ({len(result2.value or '')} chars): {result2.value}")
164+
165+
166+
if __name__ == "__main__":
167+
# Run examples
168+
example_repair_json()
169+
example_repair_length()
170+
example_repair_keywords()
171+
example_combined_repair()
172+
example_check_only_vs_repair()
173+
174+
# Note: example_repair_pii() requires careful testing as it may
175+
# generate PII in the first attempt before repair
176+
177+
print("\n" + "=" * 80)
178+
print("ALL REPAIR EXAMPLES COMPLETE")
179+
print("=" * 80)

mellea/stdlib/requirements/__init__.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,44 @@
1414
simple_validate,
1515
)
1616
from .tool_reqs import tool_arg_validator, uses_tool
17+
from .guardrails import (
18+
contains_keywords,
19+
excludes_keywords,
20+
factual_grounding,
21+
is_code,
22+
json_valid,
23+
matches_schema,
24+
max_length,
25+
min_length,
26+
no_harmful_content,
27+
no_pii,
28+
)
29+
from .guardrail_profiles import GuardrailProfiles
30+
from .requirement_set import RequirementSet
1731

1832
__all__ = [
1933
"ALoraRequirement",
34+
"GuardrailProfiles",
2035
"LLMaJRequirement",
2136
"PythonExecutionReq",
2237
"Requirement",
38+
"RequirementSet",
2339
"ValidationResult",
2440
"as_markdown_list",
2541
"check",
42+
"contains_keywords",
2643
"default_output_to_bool",
44+
"excludes_keywords",
45+
"factual_grounding",
46+
"is_code",
2747
"is_markdown_list",
2848
"is_markdown_table",
49+
"json_valid",
50+
"matches_schema",
51+
"max_length",
52+
"min_length",
53+
"no_harmful_content",
54+
"no_pii",
2955
"req",
3056
"reqify",
3157
"requirement_check_to_bool",

0 commit comments

Comments
 (0)