Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions libs/langchain_v1/langchain/agents/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
ProviderStrategy,
ProviderStrategyBinding,
ResponseFormat,
StructuredOutputError,
StructuredOutputValidationError,
ToolStrategy,
)
Expand Down Expand Up @@ -797,8 +798,16 @@ def _handle_model_output(
provider_strategy_binding = ProviderStrategyBinding.from_schema_spec(
effective_response_format.schema_spec
)
structured_response = provider_strategy_binding.parse(output)
return {"messages": [output], "structured_response": structured_response}
try:
structured_response = provider_strategy_binding.parse(output)
except Exception as exc: # noqa: BLE001
schema_name = getattr(
effective_response_format.schema_spec.schema, "__name__", "response_format"
)
validation_error = StructuredOutputValidationError(schema_name, exc, output)
raise validation_error
else:
return {"messages": [output], "structured_response": structured_response}
return {"messages": [output]}

# Handle structured output with tool strategy
Expand All @@ -812,11 +821,11 @@ def _handle_model_output(
]

if structured_tool_calls:
exception: Exception | None = None
exception: StructuredOutputError | None = None
if len(structured_tool_calls) > 1:
# Handle multiple structured outputs error
tool_names = [tc["name"] for tc in structured_tool_calls]
exception = MultipleStructuredOutputsError(tool_names)
exception = MultipleStructuredOutputsError(tool_names, output)
should_retry, error_message = _handle_structured_output_error(
exception, effective_response_format
)
Expand Down Expand Up @@ -858,7 +867,7 @@ def _handle_model_output(
"structured_response": structured_response,
}
except Exception as exc: # noqa: BLE001
exception = StructuredOutputValidationError(tool_call["name"], exc)
exception = StructuredOutputValidationError(tool_call["name"], exc, output)
should_retry, error_message = _handle_structured_output_error(
exception, effective_response_format
)
Expand Down
10 changes: 8 additions & 2 deletions libs/langchain_v1/langchain/agents/structured_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,21 @@
class StructuredOutputError(Exception):
"""Base class for structured output errors."""

ai_message: AIMessage


class MultipleStructuredOutputsError(StructuredOutputError):
"""Raised when model returns multiple structured output tool calls when only one is expected."""

def __init__(self, tool_names: list[str]) -> None:
def __init__(self, tool_names: list[str], ai_message: AIMessage) -> None:
"""Initialize `MultipleStructuredOutputsError`.

Args:
tool_names: The names of the tools called for structured output.
ai_message: The AI message that contained the invalid multiple tool calls.
"""
self.tool_names = tool_names
self.ai_message = ai_message

super().__init__(
"Model incorrectly returned multiple structured responses "
Expand All @@ -55,15 +59,17 @@ def __init__(self, tool_names: list[str]) -> None:
class StructuredOutputValidationError(StructuredOutputError):
"""Raised when structured output tool call arguments fail to parse according to the schema."""

def __init__(self, tool_name: str, source: Exception) -> None:
def __init__(self, tool_name: str, source: Exception, ai_message: AIMessage) -> None:
"""Initialize `StructuredOutputValidationError`.

Args:
tool_name: The name of the tool that failed.
source: The exception that occurred.
ai_message: The AI message that contained the invalid structured output.
"""
self.tool_name = tool_name
self.source = source
self.ai_message = ai_message
super().__init__(f"Failed to parse structured output for tool '{tool_name}': {source}.")


Expand Down
Loading