fix: Handle failed experiments in feedback step to prevent crashes

Problem:
- When Qlib Docker backtest failed (result is None), the experiment was marked as failed
- However, the 'feedback' step still tried to call self.factor_summarizer.generate_feedback()
- This caused an IndexError or KeyError because the experiment object was invalid
- Run #9 crashed with: 'None of [key] are in the [axis_name]'

Solution:
- In feedback() method, check if exp.failed is True before generating feedback
- If failed, create a simple HypothesisFeedback with decision=False
- This allows the loop to continue instead of crashing
- Log a warning message with the failure reason

This fix works together with the _evaluate_factor_directly() fix in factor_runner.py
to ensure that even when Docker fails, the loop continues smoothly.
This commit is contained in:
TPTBusiness
2026-04-05 12:58:41 +02:00
parent e31a2e5405
commit ae7e95cba6
+21 -4
View File
@@ -217,10 +217,27 @@ class QuantRDLoop(RDLoop):
decision=False,
)
else:
if prev_out["direct_exp_gen"]["propose"].action == "factor":
feedback = self.factor_summarizer.generate_feedback(prev_out["running"], self.trace)
elif prev_out["direct_exp_gen"]["propose"].action == "model":
feedback = self.model_summarizer.generate_feedback(prev_out["running"], self.trace)
# Handle cases where the experiment failed during execution (e.g., Docker error)
exp = prev_out.get("running")
if exp is not None and getattr(exp, "failed", False):
reason = getattr(exp, "failure_reason", "Unknown failure reason")
factor_name = "unknown"
if hasattr(exp, "hypothesis") and exp.hypothesis is not None:
factor_name = getattr(exp.hypothesis, "hypothesis", "unknown")
logger.warning(f"Skipping feedback for failed factor '{factor_name}'. Reason: {reason}")
feedback = HypothesisFeedback(
observations=f"Factor '{factor_name}' failed execution.",
hypothesis_evaluation="Failed",
new_hypothesis="Try a different approach.",
reason=reason,
decision=False,
)
else:
if prev_out["direct_exp_gen"]["propose"].action == "factor":
feedback = self.factor_summarizer.generate_feedback(prev_out["running"], self.trace)
elif prev_out["direct_exp_gen"]["propose"].action == "model":
feedback = self.model_summarizer.generate_feedback(prev_out["running"], self.trace)
# NOTE: DB save is handled by factor_runner.py _save_result_to_database()
# which runs immediately after Docker execution. No duplicate save needed here.