Add tool-based structured output to bypass Bedrock schema limits#22
Conversation
Replace ProviderStrategy with a custom structured_response tool to work around AWS Bedrock constraints (16 anyOf max, 24 optionals max, grammar size limits). Extract the structured response from tool_calls in messages rather than relying on the native provider mechanism. Update stream_message to capture the structured event in a variable before yielding, aligning with the new extraction flow.
- Rename factory test to reflect structured_response tool injection - Update route tests to assert on new "structured" event type instead of "message" with nested structured_response - Verify content events and separate structured events in stream output
Kaiohz
left a comment
There was a problem hiding this comment.
📊 Review de la PR #22
Contexte
AWS Bedrock impose des limitations strictes sur les schémas JSON (max 16 anyOf, max 24 optionals, max grammar size). Cette PR contourne ces limites en remplaçant ProviderStrategy par un tool structured_response injecté dynamiquement.
✅ Points positifs
1. Solution élégante et bien intégrée
- Réutilisation intelligente de
_create_response_toolqui existait déjà pour les subagents - L'instruction système
STRUCTURED_OUTPUT_INSTRUCTIONguide le LLM vers le bon comportement
2. Logique de fallback solide
# 1. tool_calls (ToolStrategy mode)
# 2. result.structured_response (fallback natif)
# 3. JSON parsing du contenu (dernier recours)Cette hiérarchie de fallback gère élégamment les différents scénarios.
3. Comments explicatifs clairs
Les commentaires dans factory.py expliquent bien le pourquoi:
Use tool-based structured output instead of ProviderStrategy to bypass Bedrock schema limitations
4. Bug fix dans stream_message.py
Le changement yield StreamEvent → event = StreamEvent puis yield corrige un bug potentiel où l'event pouvait être yieldé avant d'être complètement construit.
5. Tests cohérents
Les tests reflètent correctement le nouveau comportement (events structured vs message).
🔍 Points à améliorer
1. Méthode statique
_extract_structured_response ne dépend pas de self → devrait être @staticmethod:
@staticmethod
def _extract_structured_response(messages: list) -> dict | None:2. Nommage
_create_response_tool pourrait être plus explicite:
_create_structured_output_tool() # plus clair3. Couverture de test - Cas edge
Manque un test pour le cas où structured_response apparaît à la fois dans tool_calls ET result. La priorité actuelle (tool_calls d'abord) est-elle correcte?
4. Test du prompt
Dans test_factory.py:
assert 'structured_response' in kwargs.get('system_prompt', '') Ce test vérifie juste la présence du mot, pas que l'instruction complète est bien ajoutée. Suggérer:
from src.infrastructure.deepagent.factory import STRUCTURED_OUTPUT_INSTRUCTION
assert STRUCTURED_OUTPUT_INSTRUCTION in kwargs.get('system_prompt', '')📈 Score qualité: 7/10
| Critère | Note |
|---|---|
| Solution technique | 8/10 |
| Intégration codebase | 8/10 |
| Tests | 6/10 |
| Documentation/comments | 7/10 |
| Bonnes pratiques | 7/10 |
🎯 Suggestions
- Ajouter
@staticmethodsur_extract_structured_response - Ajouter un test pour le cas
tool_calls+resultsimultané - Renforcer le test du prompt avec l'instruction complète
- Documenter la priorité des fallbacks dans un docstring ou commentaire
✅ Verdict
La solution est correcte et bien intégrée. Les améliorations suggérées sont mineures et n'empêchent pas le merge. 👍
Approve pour merge après corrections mineures optionnelles.
Replace ProviderStrategy with a custom structured_response tool to work around AWS Bedrock constraints (16 anyOf max, 24 optionals max, grammar size limits). Extract the structured response from tool_calls in messages rather than relying on the native provider mechanism.
Update stream_message to capture the structured event in a variable before yielding, aligning with the new extraction flow.