Skip to content

Commit a010d01

Browse files
changed to only output validation summaries with failures
1 parent f43db05 commit a010d01

File tree

4 files changed

+43
-3
lines changed

4 files changed

+43
-3
lines changed

guardrails/classes/validation/validation_summary.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,15 @@ def from_validator_logs(
4040
):
4141
summaries.append(summary)
4242
return summaries
43+
44+
@staticmethod
45+
def from_validator_logs_only_fails(
46+
validator_logs: List[ValidatorLogs],
47+
) -> List["ValidationSummary"]:
48+
summaries = []
49+
for summary in ValidationSummary._generate_summaries_from_validator_logs(
50+
validator_logs
51+
):
52+
if summary.failure_reason:
53+
summaries.append(summary)
54+
return summaries

guardrails/classes/validation_outcome.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ def from_guard_history(cls, call: Call):
8282
)
8383
validation_passed = call.status == pass_status
8484
validator_logs = last_iteration.validator_logs or []
85-
validation_summaries = ValidationSummary.from_validator_logs(validator_logs)
85+
validation_summaries = ValidationSummary.from_validator_logs_only_fails(
86+
validator_logs
87+
)
8688
reask = last_output if isinstance(last_output, ReAsk) else None
8789
error = call.error
8890
output = cast(OT, call.guarded_output)

guardrails/run/async_stream_runner.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from guardrails.classes import ValidationOutcome
1414
from guardrails.classes.history import Call, Inputs, Iteration, Outputs
1515
from guardrails.classes.output_type import OutputTypes
16+
from guardrails.classes.validation.validation_summary import ValidationSummary
1617
from guardrails.constants import pass_status
1718
from guardrails.llm_providers import (
1819
AsyncLiteLLMCallable,
@@ -164,11 +165,16 @@ async def async_step(
164165
)
165166
validation_response += cast(str, validated_fragment)
166167
passed = call_log.status == pass_status
168+
validator_logs = iteration.validator_logs
169+
validation_summaries = ValidationSummary.from_validator_logs_only_fails(
170+
validator_logs
171+
)
167172
yield ValidationOutcome(
168173
call_id=call_log.id, # type: ignore
169174
raw_llm_output=chunk_text,
170175
validated_output=validated_fragment,
171176
validation_passed=passed,
177+
validation_summaries=validation_summaries,
172178
)
173179
else:
174180
async for chunk in stream_output:
@@ -204,11 +210,16 @@ async def async_step(
204210
validation_response = cast(list, validated_fragment)
205211
else:
206212
validation_response = cast(dict, validated_fragment)
213+
validator_logs = iteration.validator_logs
214+
validation_summaries = ValidationSummary.from_validator_logs_only_fails(
215+
validator_logs
216+
)
207217
yield ValidationOutcome(
208218
call_id=call_log.id, # type: ignore
209219
raw_llm_output=fragment,
210220
validated_output=chunk_text,
211221
validation_passed=validated_fragment is not None,
222+
validation_summaries=validation_summaries,
212223
)
213224

214225
iteration.outputs.raw_output = fragment

guardrails/run/stream_runner.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
from typing import Any, Dict, Generator, Iterable, List, Optional, Tuple, Union, cast
22

3+
34
from guardrails import validator_service
45
from guardrails.classes.history import Call, Inputs, Iteration, Outputs
56
from guardrails.classes.output_type import OT, OutputTypes
7+
from guardrails.classes.validation.validation_summary import ValidationSummary
68
from guardrails.classes.validation_outcome import ValidationOutcome
79
from guardrails.llm_providers import (
810
LiteLLMCallable,
@@ -176,8 +178,7 @@ def prepare_chunk_generator(stream) -> Iterable[Tuple[Any, bool]]:
176178
"$",
177179
validate_subschema=True,
178180
)
179-
180-
for res in gen:
181+
for chunk_index, res in enumerate(gen):
181182
chunk = res.chunk
182183
original_text = res.original_text
183184
if isinstance(chunk, SkeletonReAsk):
@@ -196,12 +197,20 @@ def prepare_chunk_generator(stream) -> Iterable[Tuple[Any, bool]]:
196197
# 5. Convert validated fragment to a pretty JSON string
197198
validation_response += cast(str, chunk)
198199
passed = call_log.status == pass_status
200+
201+
validator_logs = call_log.iterations.last.validator_logs
202+
203+
validation_summaries = ValidationSummary.from_validator_logs_only_fails(
204+
validator_logs
205+
)
206+
199207
yield ValidationOutcome(
200208
call_id=call_log.id, # type: ignore
201209
# The chunk or the whole output?
202210
raw_llm_output=original_text,
203211
validated_output=chunk,
204212
validation_passed=passed,
213+
validation_summaries=validation_summaries,
205214
)
206215

207216
# handle non string schema
@@ -246,11 +255,17 @@ def prepare_chunk_generator(stream) -> Iterable[Tuple[Any, bool]]:
246255
else:
247256
validation_response = cast(dict, validated_fragment)
248257
# 5. Convert validated fragment to a pretty JSON string
258+
259+
validator_logs = iteration.validator_logs
260+
validation_summaries = ValidationSummary.from_validator_logs_only_fails(
261+
validator_logs
262+
)
249263
yield ValidationOutcome(
250264
call_id=call_log.id, # type: ignore
251265
raw_llm_output=fragment,
252266
validated_output=validated_fragment,
253267
validation_passed=validated_fragment is not None,
268+
validation_summaries=validation_summaries,
254269
)
255270

256271
# # Finally, add to logs

0 commit comments

Comments
 (0)