Skip to content

Conversation

@dee-walia20
Copy link

Description

Summary of changes: Fix LiteLLM model to properly pass response_format to the underlying LiteLLM library when structured outputs are enabled.

Related issues: N/A (or link to any related issues)

Motivation and context:
When using LiteLLM model with output_schema, structured_outputs=True, and supports_native_structured_outputs=True, the agent was still falling back to JSON mode via prompt injection. This was because the response_format parameter was never passed to litellm.completion().

Environment or dependencies: No changes required

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Model update (Addition or modification of models)

Changes Made

  1. Added explicit structured output flags with documentation:

    • Flags remain False by default (safe for providers like Anthropic, Ollama)
    • Added clear comments explaining when/how users should enable them
    • Users explicitly enable for models that support it (OpenAI, Gemini, etc.)
  2. Added _get_response_format_param() helper method:

    • Converts Pydantic BaseModel classes to LiteLLM-compatible JSON schema format
    • Passes through dict formats unchanged
    • Returns None for None input
  3. Added _add_additional_properties_false() helper method:

    • Recursively adds additionalProperties: false to all object schemas
    • Required by OpenAI's strict mode (without this, API returns 400 error)
    • Handles nested objects, arrays, $defs, definitions, anyOf/oneOf/allOf
  4. Updated all invoke methods (invoke, invoke_stream, ainvoke, ainvoke_stream):

    • Added code to convert and add response_format to completion_kwargs
    • Only passes response_format when supports_native_structured_outputs=True
    • This prevents errors with providers like Anthropic that don't support it
  5. Added tests for structured output functionality

Important Design Decision

The supports_native_structured_outputs flag is kept as False by default because:

  • LiteLLM supports 100+ providers, not all support structured outputs
  • Anthropic models don't support response_format parameter (causes 400 error)
  • Ollama has limited/no structured output support
  • Safe default prevents breaking existing usage

The response_format parameter is only passed to the API when supports_native_structured_outputs=True.
This ensures providers like Anthropic continue to work (falling back to JSON mode via prompt).

Users enable it explicitly when they know their model supports it:

# For OpenAI/Gemini models - enable structured outputs
model = LiteLLM(
    id='gpt-4o',
    supports_native_structured_outputs=True,
)

# For Anthropic models - leave as default (uses prompt-based JSON mode)
model = LiteLLM(
    id='claude-sonnet-4-20250514',
    # supports_native_structured_outputs=False  # Default
)

Checklist

  • Adherence to standards: Code complies with Agno's style guidelines and best practices.
  • Formatting and validation: You have run ./scripts/format.sh and ./scripts/validate.sh
  • Self-review completed: A thorough review has been performed
  • Documentation: Docstrings added for the new helper method
  • Examples and guides: N/A (existing examples should now work correctly)
  • Tested in a clean environment: Changes tested and verified
  • Tests: Tests added for new functionality

Testing

Tested with:

  • OpenAI models via LiteLLM (gpt-4o)
  • Custom providers via SAP AI Core (sap/gpt-4o-mini)

Before fix:

LiteLLM: Params passed to completion() {..., 'response_format': None, ...}
WARNING  Failed to parse cleaned JSON: ...

After fix (with supports_native_structured_outputs=True):

LiteLLM: Params passed to completion() {..., 'response_format': {'type': 'json_schema', ...}, ...}

- Set supports_native_structured_outputs=True by default
- Set supports_json_schema_outputs=True by default
- Add _get_response_format_param() helper to convert Pydantic models
- Pass response_format to litellm.completion() in all invoke methods
- Add tests for structured output functionality

Fixes the issue where LiteLLM model was not passing response_format
to the underlying LiteLLM library, causing structured outputs to fail
even when output_schema and structured_outputs=True were set.
@dee-walia20 dee-walia20 requested a review from a team as a code owner December 31, 2025 12:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant