How to Debug Analysis Issues Using the Agent State Propagation System in TradingAgents-CN
Enable debug=True in TradingAgentsGraph and inspect performance_metrics in the returned state to trace exactly which analyst node failed or timed out during propagation.
The TradingAgents-CN repository implements a multi-agent analysis pipeline where the TradingAgentsGraph class orchestrates specialized analysts (market, social, news, fundamentals) through a state-propagation mechanism. When stock analysis results are missing, delayed, or incorrect, debugging the agent state propagation system is the most direct path to resolution.
Understanding the State-Propagation Architecture
Core Components
The propagation logic lives in tradingagents/graph/trading_graph.py. The TradingAgentsGraph class exposes the propagate() method, which is invoked by run_stock_analysis() in web/utils/analysis_runner.py.
When you call graph.propagate(company_name, trade_date), the system:
- Creates an initial agent state via
self.propagator.create_initial_state() - Sets up per-node timing dictionaries (
node_timings,total_start_time) - Selects stream mode (
updatesvsvalues) based on whether aprogress_callbackis provided - Executes the LangChain-style graph, optionally tracing LLM messages when
debug=True
The Propagation Pipeline
The propagate() method follows a strict sequence that provides natural debugging hooks:
| Step | Debugging Relevance | Source Location |
|---|---|---|
| Parameter logging | Verify company_name, trade_date, and task_id are correctly passed |
trading_graph.py lines 72-88 |
| Initial state creation | Inspect empty slots for all analysts before execution | trading_graph.py lines 92-98 |
| Debug/tracing branch | When self.debug is True, prints every LLM message via pretty_print() |
trading_graph.py lines 111-150 |
| Progress updates | Real-time UI feedback via _send_progress_update() |
trading_graph.py line 934 |
| Node timing | Captures elapsed time per node to identify bottlenecks | trading_graph.py lines 161-176 |
| Final state assembly | Attaches performance_metrics including node_timings and total duration |
trading_graph.py lines 211-232 |
| State persistence | Logs final state via _log_state() for post-hoc analysis |
trading_graph.py lines 236-242 |
Three Strategic Debugging Breakpoints
Input Validation
Before the graph executes, propagate() logs the raw input parameters. If your analysis returns data for the wrong symbol or date, check the logs at the start of propagate() to confirm the company_name and trade_date values match your request.
Node-Level Execution
Enable debug tracing by setting debug=True when constructing TradingAgentsGraph. This activates the trace branch that prints every LLM message using pretty_print(). When an analyst node fails or returns malformed JSON, the trace shows the exact prompt and response, making it trivial to spot API key errors, rate limits, or schema mismatches.
Performance and State Inspection
After propagate() returns, inspect graph.curr_state (or the returned state dictionary). This contains the complete agent state tree, including intermediate reports like market_report, fundamentals_report, and risk_assessment. The performance_metrics field provides per-node timings that pinpoint exactly which analyst is causing delays.
Common Debugging Scenarios and Fixes
Missing Analyst Output
If fundamentals_report is empty in the final state, examine the trace logs for the Fundamentals node. Verify that the FINNHUB_API_KEY environment variable is set and that the node's tool function succeeded. If the API call fails, add the required credential or replace the tool with a fallback defined in trading_graph.py.
Timeout or Long-Running Node
Check node_timings in performance_metrics. Nodes exceeding a few seconds indicate LLM timeouts. Increase the timeout value in quick_model_config or deep_model_config within your configuration, or switch to a faster model provider.
Incorrect Progress Display
If the UI shows stale progress bars, verify that progress_callback is being invoked for each chunk via _send_progress_update. Ensure the caller passes a valid callback function; the run_stock_analysis wrapper handles this automatically when called from the Streamlit UI.
Missing Performance Metrics
If the returned state lacks timing data, confirm you are reading from result['performance_metrics']. The timing logic executes regardless of the debug flag, so metrics are always available unless the graph execution itself crashes before completion.
Unexpected Model Info
When logs show "Unknown" for the model identifier, the LLM wrapper may not expose model_name. Verify that your provider's ChatOpenAI subclass implements this attribute, or manually set model_info in the configuration dictionary passed to TradingAgentsGraph.
Practical Debugging Code Examples
Enabling Full Debug Tracing
from tradingagents.graph.trading_graph import TradingAgentsGraph
from tradingagents.default_config import DEFAULT_CONFIG
import logging
# Turn on verbose logging for the web logger
logging.getLogger('web').setLevel(logging.DEBUG)
# Create the graph with debug tracing enabled
graph = TradingAgentsGraph(
selected_analysts=["market", "social", "news", "fundamentals"],
debug=True, # Activates pretty_print of every node
config=DEFAULT_CONFIG
)
# Run propagation without UI callback for cleaner logs
state, decision = graph.propagate(
company_name="AAPL",
trade_date="2024-08-01"
)
# Inspect performance bottlenecks
print("Node timings:")
for node, secs in state["performance_metrics"]["node_timings"].items():
print(f" {node:30s} → {secs:.2f}s")
Monitoring Live Progress with Callbacks
def my_progress(chunk, step=None, total=None):
# chunk is a dict {node_name: partial_state}
for node, update in chunk.items():
if not node.startswith("__"):
print(f"[{node}] updated – keys: {list(update.keys())}")
# Normal production run with progress tracking
graph = TradingAgentsGraph(debug=False, config=DEFAULT_CONFIG)
state, decision = graph.propagate(
company_name="TSLA",
trade_date="2024-08-01",
progress_callback=my_progress, # Receives updates from _send_progress_update
task_id="demo123"
)
Diagnosing Failed Analyst Nodes
# After a failed run, inspect graph.curr_state
failed_node = "Fundamentals Analyst"
state = graph.curr_state
if failed_node in state:
print(f"Output found:\n{state[failed_node]}")
else:
# Check if node was skipped due to missing API keys
timings = state.get("performance_metrics", {}).get("node_timings", {})
if failed_node not in timings:
print(f"{failed_node} did not execute – verify FINNHUB_API_KEY")
Key Files for Deep Debugging
| File | Purpose | Location |
|---|---|---|
tradingagents/graph/trading_graph.py |
Core graph definition, propagate() implementation, timing logic, and debug tracing |
View on GitHub |
web/utils/analysis_runner.py |
High-level wrapper run_stock_analysis() that instantiates the graph and handles UI integration |
View on GitHub |
tradingagents/default_config.py |
Default LLM configurations including timeout settings for quick_model_config and deep_model_config |
View on GitHub |
web/run_web.py |
Streamlit UI entry point that provides the progress_callback implementation |
View on GitHub |
tradingagents/utils/logging_manager.py |
Logging infrastructure used throughout the propagation system | View on GitHub |
Summary
- Enable
debug=Truewhen constructingTradingAgentsGraphto trace every LLM message and identify which analyst node produces malformed output or failures. - Inspect
performance_metricsin the returned state dictionary to pinpoint timeout bottlenecks via per-node timings stored innode_timings. - Validate inputs by checking the initial logs in
propagate()to confirmcompany_nameandtrade_datematch your request before the graph executes. - Use
progress_callbackto monitor real-time state updates during long-running analyses, ensuring the UI reflects actual node completion status. - Check
curr_stateafter execution to examine raw analyst outputs (e.g.,fundamentals_report) and verify API credentials when nodes are missing from the state tree.
Frequently Asked Questions
How do I enable detailed logging to see exactly what each analyst node is doing?
Set debug=True when creating the TradingAgentsGraph instance. This activates the trace branch in trading_graph.py (lines 111-150) which calls pretty_print() on every LLM message. You should also set logging.getLogger('web').setLevel(logging.DEBUG) to capture parameter logs at the start of propagate().
Where can I find timing information to identify slow analyst nodes?
The propagate() method automatically records execution times in the performance_metrics dictionary returned as part of the final state. Specifically, state["performance_metrics"]["node_timings"] contains a mapping of each analyst node name to its elapsed time in seconds. Check this dictionary after graph.propagate() returns to identify bottlenecks.
What should I check if a specific analyst report is missing from the final state?
First, verify that the analyst appears in state["performance_metrics"]["node_timings"]. If the node is absent from the timings dictionary, it likely failed to execute due to missing API credentials (e.g., FINNHUB_API_KEY for fundamentals) or an exception during tool invocation. Check the trace logs when debug=True to see the exact error message from the LLM or tool node.
How does the progress callback work for real-time UI updates?
The progress_callback parameter in propagate() receives chunks from the graph stream via _send_progress_update() (line 934 in trading_graph.py). Each chunk is a dictionary mapping node names to partial state updates. When debug=False and a callback is provided, the graph runs in updates mode, allowing the UI to render progress bars as each analyst completes its work.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →