Structured output falls back to free text ~1x per run on DeepSeek thinking models
Problem
On DeepSeek thinking models, the free-text fallback in invoke_structured_or_freetext is
not a rare edge case — it fires once or twice in every run.
The comment at structured.py:77 already anticipates the shape ("a thinking model can answer in
plain text instead of calling the tool"). What this adds is the frequency, which seems high
enough to justify a retry policy rather than just a logged warning.
Measurement
v0.5.0, deep_think_llm=deepseek-v4-pro, quick_think_llm=deepseek-v4-flash, four analysts,
full research and risk debates, ~21 LLM calls per run. Over 10 consecutive runs:
structured-output invocation failed (structured output returned no parsed result);
retrying once as free text
Trader 6
Research Manager 4
Portfolio Manager 1
------------------------
total 11 across 10 runstool_choice was correctly suppressed throughout (both model IDs have capability rows), and
"does not support this tool_choice" occurred 0 times. So this is distinct from #1388 / #1389
and is not fixed by closing that naming gap.
Impact
- Schema enforcement is effectively not guaranteed — on average one agent per run produces unvalidated output.
- It is only a
logger.warning, invisible in the finished run summary, so it goes unnoticed unless you are watching stderr. - Ratings survive only because they are recovered from the
**Rating**:/**Recommendation**:/**Action**:labels rather than from the schema. Numeric schema fields (entry price, stop loss) have no such safety net.
Possible directions
- Retry the structured call once before falling back. The miss is a sampling artifact, so a retry will often succeed, at far lower cost than losing the schema.
- Use
json_modefor known thinking models (supports_json_modealready exists in the table). - At minimum, surface a fallback count in the run summary so users know how many agents skipped the schema.
Happy to send a PR for whichever direction you prefer.
Source: TauricResearch/TradingAgents