Back to .md Directory

1. Clone repository

<img src="frontend/public/logo.svg" alt="FinSight AI Logo" width="80" height="80" />

May 2, 2026
0 downloads
0 views
ai agent llm rag
View source
<p align="center"> <img src="frontend/public/logo.svg" alt="FinSight AI Logo" width="80" height="80" /> </p> <h1 align="center">FinSight AI</h1> <p align="center"> <strong>Multi-Agent Financial Research Platform powered by LangGraph</strong> </p> <p align="center"> <a href="./README.md">English</a> | <a href="./readme_cn.md">中文</a> | <a href="./docs/DOCS_INDEX.md">Docs Index</a> </p> <p align="center"> 🌐 <strong>Live Demo:</strong> <a href="https://finsight-ai.chat">https://finsight-ai.chat</a> </p>

FinSight AI is a production-grade, multi-agent financial research system built on LangGraph. It unifies conversational AI analysis, a professional dashboard with 6 analytical tabs, autonomous task execution (Workbench), and proactive email alerts into one coherent platform.

7 Research Agents (autonomous, multi-tool) · 1 Synthesize Node (conflict detection + hallucination guard) · 5 Dashboard Scorers (per-tab AI cards) | Hybrid RAG (bge-m3) | Real-time ECharts | LLM-driven Smart Charts | Conflict detection across 8 agent pairs | Email subscription alerts


Table of Contents


✨ Key Features

CategoryHighlights
Multi-Agent Orchestration7 specialized research agents (Price, News, Fundamental, Technical, Macro, Risk, DeepSearch) running in parallel execution groups
LangGraph Pipeline18-node stateful graph handling chat, quick analysis, and deep investment reports with adaptive routing
Professional Dashboard6 analytical tabs (Overview, Financial, Technical, News, Research, Peers) with ECharts visualization
AI-Powered Insights5 Dashboard Scorers generate real-time AI analysis cards for each tab via single LLM call + deterministic fallback (1-3s each)
Hybrid RAG Enginebge-m3 (1024-dim Dense + Sparse) with bge-reranker-v2-m3 cross-encoder reranking
Smart ChartsDual-mode LLM-driven charts: <chart> (inline data) + <chart_ref> (real data reference)
Conflict DetectionAutomatic cross-agent conflict analysis across 8 comparable dimension pairs
Proactive Alerts3 alert schedulers (Price, News, Risk) with email notification via SMTP
WorkbenchAutonomous task execution, portfolio rebalancing with LLM enhancement, SSE streaming progress, report timeline, and quick analysis bar
"Ask About This"Context-aware follow-up on any news, insight, or risk item via MiniChat integration
ThinkingBubbleThree-layer execution display: thinking bubble (typewriter effect) → agent summary cards → detailed timeline
Morning Brief PipelineOne-click portfolio morning brief via LangGraph Pipeline with deterministic synthesis (zero LLM cost)
Rebalance LLM EnhancementAgent-backed LLM priority refinement for rebalance suggestions with evidence snapshots
Hallucination DefenseMulti-layer scrubbing: regex pattern matching + evidence cross-validation on LLM outputs
Conversational Price AlertsChat-driven alert setup — say "alert me when AAPL drops below $180" → auto-extracted, persisted, and triggered by scheduler (Phase 1)
Stock ScreenerNatural-language stock screening with multi-condition filters; capability_note boundary hints for CN/HK coverage (Phase 2)
A-Share Market DataNorthbound/Southbound capital flow, sector heat maps, concept board rankings for CN & HK markets (Phase 3)
Strategy BacktestingSMA crossover, MACD, RSI strategies with T+1 settlement, cost/slippage modeling, and look-ahead bias prevention (Phase 4)

📸 Platform Preview

<p align="center"> <img src="images/cb70fece-c319-4964-91fc-d7be91211b91.png" alt="FinSight AI Dashboard" width="100%"/> </p> <p align="center"> <img src="images/4dc0e95c-2963-4422-ba3e-d86a3788b4b1.png" alt="FinSight AI Dashboard" width="100%"/> </p> ### RAG Inspector <p align="center"> <img src="images/142bc537-d76f-4ab1-9a84-4d86a0db2af5.png" alt="RAG Inspector overview with run list, 24h counters, event payloads, and chunk previews" width="100%"/> </p> <p align="center"> <img src="images/6352da18-d7e9-418a-a219-15150cbeebcb.png" alt="RAG Inspector detail view with original source text and chunk metadata" width="100%"/> </p>

The RAG Inspector opens up the retrieval pipeline for direct inspection. It shows recent DeepSearch / hybrid RAG runs, 24-hour activity counters, event-by-event payloads, chunk slices, original source text, and chunk metadata so operators can verify exactly what was searched, chunked, retrieved, and stored.

<table> <tr> <td width="50%">

Overview Tab - AI Score Ring, Fear & Greed Gauge, Agent Coverage, Risk Metrics

</td> <td width="50%">

Financial Tab - 8Q Profitability Chart, EPS Surprise, Analyst Target Price

<img src="images/12e7daa8071f4983b85e578bbca7a0e1.png" width="100%"/> </td> </tr> <tr> <td width="50%">

Technical Tab - Candlestick K-line, RSI, MACD, Support/Resistance Levels

<img src="images/7dd48dd6d1d3b1aa6e7b3d33e1dcc492.png" width="100%"/> </td> <td width="50%">

News Tab - AI News Summary, Sentiment Bar, Tag Chips, Rich News Cards

<img src="images/48f1bedaef4381457d3ad98e5ae80201.png" width="100%"/> </td> </tr> <tr> <td width="50%">

Peers Tab - PE/Revenue Growth Comparison, Detailed Metrics Table

<img src="images/060fdf7b3d8f93ebda65cb3daaaacf21.png" width="100%"/> </td> <td width="50%">

Research Tab - Multi-Agent Deep Analysis with Conflict Matrix & Citations

<img src="images/3e47bb167c44c8f9cdcb23b20f905ada.png" width="100%"/> </td> </tr> <tr> <td width="50%">

Thinking Process - User View - Collapsible Reasoning Sections (Logic / Planning / Execution)

<img src="images/2b674275d75b4838f1e77de5d5980dfc.png" width="100%"/> </td> <td width="50%">

Execution Timeline + Agent Summary Cards - Per-Agent Step Tracking, 11-Agent Completion Grid

<img src="images/78247136de4dd9db0d96c6ca5f574e3f.png" width="100%"/> </td> </tr> <tr> <td width="50%">

Chat + "Ask About This" - Conversational AI with Portfolio Panel

<img src="images/chat-report.png" width="100%"/> </td> <td width="50%">

Deep Research Report - Agent Confidence, Catalysts, Risk Alerts

<img src="images/report1.png" width="100%"/> </td> </tr> <tr> <td width="50%">

Workbench - Task Execution, Portfolio Rebalancing, Report Timeline

<img src="images/workbench.png" width="100%"/> </td> </tr> </table> <details> <summary>More Screenshots</summary>
Chat with Inline ChartsConsole & SSE Events
Chat ReportConsole
Research Report (Full)Commodity Analysis
ResearchGold Analysis
</details>

🏗️ System Architecture

graph TB
    subgraph "Frontend (React + Vite)"
        UI[Dashboard / Chat / Workbench]
        STORE[Zustand Stores<br/>dashboardStore · executionStore · useStore]
        API_CLIENT[API Client<br/>SSE parseSSEStream]
    end

    subgraph "Backend (FastAPI)"
        ROUTER[API Routers<br/>chat · dashboard · execute · alerts]
        GRAPH[LangGraph Pipeline<br/>18-node Stateful Graph]
        AGENTS[Agent Layer<br/>7 Research Agents + 5 Insight Scorers]
        TOOLS[Tool Layer<br/>32 Registered Tools]
        SYNTH[Synthesize Node<br/>Conflict Detection · Hallucination Scrub]
    end

    subgraph "Data Layer"
        RAG[Hybrid RAG<br/>bge-m3 · Reranker]
        CACHE[Dashboard Cache<br/>16 TTL Categories]
        MEMORY[Memory Store<br/>Per-user JSON]
        DB[(SQLite / PostgreSQL<br/>Checkpoints · Reports · Portfolio)]
    end

    subgraph "External"
        YFINANCE[yfinance]
        FMP[FMP API]
        FINNHUB[Finnhub]
        TAVILY[Tavily / Exa / DDG]
        FRED[FRED API]
        SEC[SEC EDGAR]
        LLM_API[LLM Provider<br/>OpenAI / Gemini / DeepSeek / Anthropic]
    end

    UI --> API_CLIENT --> ROUTER
    ROUTER --> GRAPH --> AGENTS --> TOOLS
    GRAPH --> SYNTH
    TOOLS --> YFINANCE & FMP & FINNHUB & TAVILY & FRED & SEC
    AGENTS --> LLM_API
    AGENTS --> RAG
    GRAPH --> CACHE & MEMORY & DB

🔄 LangGraph Pipeline (18 Nodes)

The core of FinSight is an 18-node LangGraph stateful graph that handles everything from casual chat to deep investment reports. Dashboard Scorers are served by /api/dashboard/insights and are not graph nodes in the 18-node pipeline.

flowchart TD
    START((Start)) --> INIT["① build_initial_state<br/><i>Parse input, load memory</i>"]
    INIT --> RESET["② reset_turn_state<br/><i>Clear ephemeral fields + trace runtime</i>"]
    RESET --> CTX["③ normalize_ui_context<br/><i>Merge UI hints, detect ticker</i>"]
    CTX --> MODE{"④ chat_respond<br/><i>Output mode?</i>"}

    MODE -->|"chat / qa"| CHAT_END["Direct LLM Response"]
    CHAT_END --> RENDER
    MODE -->|"needs analysis"| SUBJ["⑤ resolve_subject<br/><i>Ticker resolution + dedup</i>"]

    SUBJ --> CLARIFY{"⑥ clarify_gate<br/><i>Ambiguous?</i>"}
    CLARIFY -->|"Ambiguous"| ASK["Ask User for Clarification"]
    ASK --> RENDER
    CLARIFY -->|"Clear"| PARSE["⑦ parse_operation<br/><i>14-level intent classifier</i>"]

    PARSE -->|"alert_set"| ALERT_EX["⑦a alert_extractor<br/><i>Extract alert params</i>"]
    ALERT_EX -->|"valid"| ALERT_ACT["⑦b alert_action<br/><i>Save & schedule</i>"]
    ALERT_EX -->|"invalid"| RENDER
    ALERT_ACT --> RENDER
    PARSE -->|"other ops"| POLICY["⑧ policy_gate<br/><i>Capability scoring + budget</i>"]
    POLICY --> PLAN["⑨ planner_node<br/><i>LLM Planner or Stub Fallback</i>"]

    PLAN --> CONFIRM{"⑩ confirmation_gate<br/><i>HITL approval?</i>"}
    CONFIRM -->|"Rejected"| RENDER
    CONFIRM -->|"Approved"| EXEC["⑪ execute_plan<br/><i>Parallel agent groups</i>"]

    EXEC --> SYNTH["⑫ synthesize<br/><i>Merge outputs + compare_gate + Conflict check</i>"]
    SYNTH --> SCRUB["⑬ Hallucination Scrub<br/><i>Regex + Evidence validation</i>"]
    SCRUB --> BUILD["⑭ report_builder<br/><i>Build ReportIR structure</i>"]
    BUILD --> RENDER["⑮ render_response<br/><i>Format for frontend</i>"]
    RENDER --> SAVE["⑯ save_memory<br/><i>Persist to memory store</i>"]
    SAVE --> END((End))

    subgraph "Execution Engine (⑪)"
        direction LR
        EG1["Group 1<br/>price · news"] --> EG2["Group 2<br/>fundamental · technical"]
        EG2 --> EG3["Group 3<br/>macro · risk · deep_search"]
    end

    EXEC -.-> EG1

    style RESET fill:#a855f7,color:#fff
    style SYNTH fill:#ff9800,color:#000
    style SCRUB fill:#f44336,color:#fff
    style POLICY fill:#2196f3,color:#fff

Intent Classification (parse_operation)

The parse_operation node implements a rule-first intent classifier with 14 operation types, prioritized from highest to lowest:

PriorityOperationConfidenceTrigger Keywords
1compare0.85vs, versus, compare, 对比, 比较, 哪个更好
2analyze_impact0.75影响, 冲击, 利好, 利空, impact
3backtest0.86回测, 策略回测, ma cross, macd strategy (Phase 4)
4alert_set0.88提醒, 预警, alert, notify, remind me (Phase 1)
5screen0.86筛选, 选股, screener, stock screen (Phase 2)
6cn_market0.84资金流向, 北向, 龙虎榜, 概念股 (Phase 3)
7technical0.85技术面, macd, rsi, k线, 支撑阻力
8price0.80股价, 现价, price, quote
9summarize0.75总结, 摘要, tl;dr
10extract_metrics0.70提取指标, eps, 营收, guidance
11fetch0.65获取, 新闻, latest news
12morning_brief0.85晨报, 早报, morning brief
13(multi-ticker default)0.70Auto-triggered when len(tickers) >= 2 without guardrail hit
14qa0.40–0.55Fallback for general questions

Guardrail-A Mechanism: When a single-task keyword is detected (e.g., price), the classifier prevents multi-ticker queries from being forced into compare mode.

GraphState Fields

The pipeline maintains a rich state object (GraphState) across all nodes:

FieldTypeDescription
messagesAnnotated[list, add_messages]Conversation history (append-only via LangGraph reducer)
subjectdictResolved entity — {type, ticker, name, market}
output_modestr"chat" / "quick_report" / "investment_report"
plan_irdictExecution plan with steps, groups, dependencies, cost estimates
step_resultsdictRaw outputs from each agent/tool execution
evidence_poollist[dict]Collected evidence items with source attribution
rag_contextlist[dict]Retrieved documents from hybrid RAG search
artifactsdictSynthesized report, citations, charts
tracedictObservability: latencies, token counts, failures
agent_preferencesdictUI-injected agent toggles (on/off/deep) from AgentControlPanel
ui_contextdictFrontend hints: active_tab, selection_context, news_mode

LangChain / LangGraph APIs Used

APIUsage
langgraph.graph.MessagesStateBase state with add_messages reducer for conversation history
langgraph.checkpoint.sqlite.SqliteSaverPersistent conversation checkpoints (SQLite backend)
langgraph.checkpoint.postgres.PostgresSaverOptional PostgreSQL checkpoint backend
langgraph.types.interrupt()Human-in-the-loop pause at confirmation_gate
langgraph.types.Command(resume=)Resume execution after HITL approval
langchain_core.messages.HumanMessage / SystemMessage / RemoveMessageMessage type construction
langchain_core.messages.trim_messagesContext window management — trim old messages
langfuse.decorators.langfuse_observeDistributed tracing integration with Langfuse

🤖 Agent Ecosystem

Research Agents (7)

Each research agent inherits from BaseFinancialAgent and implements a research() method with reflection loops, tool calling, and evidence collection.

graph TB
    subgraph EXECUTOR["Execution Engine"]
        direction TB
        POLICY["Policy Gate<br/>Capability scoring"]
        PLANNER["Planner Node<br/>LLM / Stub"]
        PARALLEL["Parallel Groups"]
    end

    subgraph AGENTS["7 Research Agents"]
        direction TB

        subgraph PA["🏷️ PriceAgent"]
            PA_T1["get_stock_price"]
            PA_T2["get_option_chain_metrics"]
            PA_T3["search (Tavily)"]
            PA_CASCADE["11-source Price Cascade<br/>yfinance → FMP → Finnhub → ..."]
        end

        subgraph NA["📰 NewsAgent"]
            NA_T1["get_company_news"]
            NA_T2["get_news_sentiment"]
            NA_T3["get_event_calendar"]
            NA_T4["score_news_source_reliability"]
            NA_T5["search (Tavily)"]
        end

        subgraph FA["📊 FundamentalAgent"]
            FA_T1["get_financial_statements"]
            FA_T2["get_company_info"]
            FA_T3["get_earnings_estimates"]
            FA_T4["get_eps_revisions"]
            FA_T5["search (Tavily)"]
        end

        subgraph TA["📈 TechnicalAgent"]
            TA_T1["get_stock_historical_data"]
            TA_T2["search (Tavily)"]
            TA_CALC["Internal: RSI, MACD, BB<br/>MA, Stochastic, ADX, CCI"]
        end

        subgraph MA["🌍 MacroAgent"]
            MA_T1["get_fred_data"]
            MA_T2["get_market_sentiment"]
            MA_T3["get_economic_events"]
            MA_T4["search (Tavily)"]
        end

        subgraph RA["⚠️ RiskAgent"]
            RA_T1["evaluate_ticker_risk"]
            RA_T2["get_factor_exposure"]
            RA_T3["run_portfolio_stress_test"]
        end

        subgraph DS["🔍 DeepSearchAgent"]
            DS_T1["Tavily → Exa → DDG<br/>Multi-engine fallback"]
            DS_T2["Document Fetcher<br/>SSRF protection"]
            DS_T3["Self-RAG Loop<br/>SearchConvergence"]
        end
    end

    POLICY --> PLANNER --> PARALLEL
    PARALLEL --> PA & NA & FA & TA & MA & RA & DS

Agent Details

<details> <summary><b>PriceAgent</b> — Real-time & Historical Pricing</summary>
  • Tools: get_stock_price, get_option_chain_metrics, search
  • Specialty: 11-source price cascade fallback chain:
    yfinance → FMP quote → FMP historical → Finnhub quote →
    Finnhub candles → Alpha Vantage → Polygon → Twelve Data →
    MarketStack → web search → hardcoded fallback
    
  • Output: Current price, change %, volume, 52-week range, option metrics
  • Reflection: 2-round max with gap analysis
</details> <details> <summary><b>NewsAgent</b> — Market News & Sentiment</summary>
  • Tools: get_company_news, get_news_sentiment, get_event_calendar, score_news_source_reliability, search
  • Data Sources: Finnhub company news, Finnhub sentiment, economic calendar
  • Specialty: Source reliability scoring (domain whitelist + quality heuristics), breaking news detection
  • Output: Categorized news items with sentiment scores, impact tags, source reliability ratings
</details> <details> <summary><b>FundamentalAgent</b> — Financial Analysis</summary>
  • Tools: get_financial_statements, get_company_info, get_earnings_estimates, get_eps_revisions, search
  • Data Sources: yfinance (8 quarters), FMP (financials, profiles)
  • Specialty: Revenue/earnings trend analysis, margin decomposition, balance sheet health
  • Output: Quarterly financial data, valuation metrics, earnings surprise history
</details> <details> <summary><b>TechnicalAgent</b> — Technical Indicators & Signals</summary>
  • Tools: get_stock_historical_data, search
  • Internal Calculations: RSI(14), MACD(12,26,9), Bollinger Bands(20,2), Stochastic %K/%D, ADX(14), CCI(20), Williams %R, 8 Moving Averages (MA5/10/20/50/100/200, EMA12/26)
  • Output: Support/resistance levels, trend signals (bullish/bearish/neutral), indicator time series (120-day)
</details> <details> <summary><b>MacroAgent</b> — Macroeconomic Context</summary>
  • Tools: get_fred_data, get_market_sentiment, get_economic_events, search
  • Data Sources: FRED (GDP, CPI, unemployment, interest rates), CNN Fear & Greed Index
  • Specialty: Macro-micro linkage analysis (how macro trends affect specific sectors/stocks)
  • Output: Economic indicators, market sentiment score, upcoming economic events
</details> <details> <summary><b>RiskAgent</b> — Risk Assessment</summary>
  • Tools: evaluate_ticker_risk_lightweight, get_factor_exposure, run_portfolio_stress_test
  • Custom research(): Does not use standard BaseFinancialAgent.research() — implements direct tool calling
  • Calculations: Beta, VaR(95%), max drawdown, Sharpe ratio, sector exposure
  • Output: Risk score, factor exposures, stress test results, risk warnings
</details> <details> <summary><b>DeepSearchAgent</b> — Web Intelligence</summary>
  • Tools: Multi-engine search (Tavily → Exa → DuckDuckGo), document fetcher
  • Architecture: Self-RAG loop with SearchConvergence tracking
    Plan search → Execute search → Grade results →
    Identify gaps → Refine query → Re-search (max 3 rounds)
    
  • Security: SSRF protection (private IP blocking), domain whitelist for persistence
  • Quality Control: _doc_quality_score() = source_score * 0.5 + freshness * 0.25 + depth * 0.25
  • Output: Curated web findings with confidence scores, high-quality results (confidence ≥ 0.7) persisted to RAG
</details>

Dashboard Insight Scorers (5)

Lightweight scorers (not autonomous agents — no tool use, no planning, no reflection loops) that generate AI insight cards for each dashboard tab. They accept already-fetched API data (zero network calls) and produce structured JSON via a single LLM call, with deterministic rule-based fallback when LLM is unavailable. These run independently from the LangGraph research pipeline via /api/dashboard/insights.

ScorerTabInput DataAnalysis FocusLatency
OverviewDigestOverviewvaluation + technicals + newsComposite score, key insights, overall risk1-3s
FinancialDigestFinancialfinancials + valuationEarnings quality, financial health, valuation1-3s
TechnicalDigestTechnicaltechnicals + indicator_seriesTrend judgment, signal convergence, key levels1-3s
NewsDigestNewsmarket_news + impact_newsTopic extraction, sentiment analysis, risk events1-3s
PeersDigestPeerspeers + valuationCompetitive positioning, industry ranking1-3s

Each scorer has a deterministic fallback (rule-based) that activates when LLM is unavailable:

Score = Base(5) + RSI_normal(+1) + Trend_up(+2) + MACD_aligned(+1) + MA_bullish(+1) + Overbought(-1)

📊 Dashboard — 6 Analytical Tabs

Overview Tab

Composite AI analysis with ScoreRing, Fear & Greed Gauge, Agent Coverage Matrix, Dimension Radar, Risk Metrics, Highlights, and Analyst Target Price.

Overview

Financial Tab

8-quarter financial data table, Profitability ECharts combo chart (revenue bars + margin lines), EPS Surprise chart, Analyst Target Price gauge, Balance Sheet summary.

Technical Tab

Real ECharts candlestick K-line with support/resistance markLines, RSI(14) time-series chart, MACD(12,26,9) with histogram, Bollinger Bands position, moving average signals.

News Tab

Three sub-views (Stock-specific / Market 7x24 / Breaking Events), 7 topic filter chips, time range selector, sentiment stats bar, rich NewsCards with tags and impact badges.

Peers Tab

Peer score grid, PE/PB horizontal bar chart, revenue growth divergent bar chart, detailed comparison table with 10+ metrics.

Research Tab

Multi-agent deep analysis with per-agent sections (price, news, technical, fundamental, macro, deep_search), conflict matrix, citation tracking, confidence scoring.


🔍 RAG Engine — Hybrid Search Pipeline

FinSight uses a production-grade hybrid retrieval pipeline replacing the legacy SHA1 hash-based pseudo-embeddings.

flowchart LR
    QUERY["User Query"] --> ROUTER["RAG Router<br/><i>SKIP / SECONDARY / PRIMARY</i>"]

    ROUTER -->|PRIMARY| EMBED["bge-m3 Encode<br/><i>1024-dim Dense + Sparse lexical</i>"]
    ROUTER -->|SKIP| LIVE["Live Tools Only"]

    EMBED --> DENSE["Dense Search<br/><i>Cosine similarity</i>"]
    EMBED --> SPARSE["Sparse Search<br/><i>Lexical weight matching</i>"]

    DENSE --> RRF["RRF Fusion<br/><i>+ Scope Boost</i>"]
    SPARSE --> RRF

    RRF --> RERANK["Cross-Encoder Rerank<br/><i>bge-reranker-v2-m3</i><br/>Top-30 → Top-8"]

    RERANK --> OUTPUT["rag_context<br/><i>Injected into synthesize prompt</i>"]

    style EMBED fill:#4caf50,color:#fff
    style RERANK fill:#ff9800,color:#000

Key Components

ComponentFileModel / Algorithm
Embedderrag/embedder.pyBAAI/bge-m3 — 1024-dim Dense + Sparse (lexical weights)
Hybrid Searchrag/hybrid_service.pyRRF fusion with scope boosting: persistent +0.15, medium_ttl +0.05
Rerankerrag/reranker.pyBAAI/bge-reranker-v2-m3 Cross-Encoder, Top-30 → Top-8
Routerrag/rag_router.pyRule-based: SKIP (realtime quotes) / PRIMARY (historical) / PARALLEL (deep research)
Chunkerrag/chunker.pyPer-doc-type strategy: news (no split) / filings (1000/200) / transcripts (800/100)
Storerag/hybrid_service.pyIn-Memory or PostgreSQL (pgvector VECTOR(1024) + tsvector)

Document Lifecycle

SourceScopeTTLTrigger
Agent outputs (evidence)ephemeralRequest-scopedEvery analysis execution
News itemsmedium_ttl7 daysNewsAgent fetch
DeepSearch results (confidence ≥ 0.7)persistentPermanentAuto-persist on high quality
SEC filings (future)persistentPermanentScheduled ETL

Prompt Injection (synthesize.py)

RAG results and real-time evidence are injected as XML-tagged blocks:

<realtime_evidence>
  {evidence_pool from current execution}
</realtime_evidence>

<historical_knowledge>
  {rag_context from hybrid search}
</historical_knowledge>

<evidence_priority_rules>
  1. Real-time data overrides historical when conflicting
  2. Historical data must include date attribution
  3. Unverifiable data must be marked with date qualifier
</evidence_priority_rules>

Quality Benchmarks — RAG Quality V2

A 3-layer eval pyramid (tests/rag_qualityV2/) measuring retrieval and generation quality across 12 Chinese financial cases (filings, transcripts, news) with 6 diagnostic metrics:

LayerScopeKCKCRCSRUCR ↓CR ↓NCRGate
L1 Mock ContextLLM generation baseline0.87960.94790.94310.0570.00.9896✅ PASS
L2 Real RetrievalRetrieval + generation0.89600.96231.00000.0000.00.9861✅ PASS
L3 E2E PipelineFull LangGraph flow0.90720.96530.99240.0080.01.0000✅ PASS

CR = 0.0 across all layers — zero contradicted claims. NCR = 1.0 at E2E — numeric consistency is perfect end-to-end. *Based on 12 test cases; production results may vary.

Metrics: KC (Keypoint Coverage) · KCR (Keypoint Context Recall) · CSR (Claim Support Rate) · UCR (Unsupported Claim Rate) · CR (Contradiction Rate) · NCR (Numeric Consistency Rate)


📈 Smart Charts — LLM-Driven Visualization

FinSight supports dual-mode inline charts where the LLM autonomously decides when visualization aids understanding.

flowchart LR
    subgraph "Mode A: LLM-Generated Data"
        LLM1["LLM generates<br/>&lt;chart type='bar'&gt;<br/>{labels, values}"]
        LLM1 --> PARSE1["Frontend extracts<br/>before Markdown render"]
        PARSE1 --> ECHART1["ECharts renders<br/>bar / line / pie / scatter / gauge"]
    end

    subgraph "Mode B: Real Data Reference"
        LLM2["LLM generates<br/>&lt;chart_ref source='peers'<br/>fields='trailing_pe'/&gt;"]
        LLM2 --> PARSE2["Frontend reads<br/>dashboardStore data"]
        PARSE2 --> ECHART2["ECharts renders<br/>with real API values"]
    end
ModeTagData SourceUse CasePrecision
LLM Inline<chart>LLM fills JSON dataTrend overviews, qualitative comparisonsApproximate
API Reference<chart_ref>Frontend reads dashboardDataExact value charts, historical seriesPrecise

Processing: Chart tags are extracted from LLM output before Markdown rendering (same pattern as [CHART:TICKER:TYPE]), ensuring react-markdown never sees raw XML.


💬 "Ask About This" (问这条)

A context-aware follow-up feature allowing users to ask AI about any specific news item, AI insight, or risk warning directly from the dashboard.

sequenceDiagram
    participant User
    participant Card as NewsCard / AiInsightCard
    participant Store as dashboardStore
    participant Chat as MiniChat
    participant API as Backend SSE

    User->>Card: Click "问这条" button
    Card->>Store: setActiveSelection(SelectionItem)
    Store->>Chat: MiniChat reads activeSelection
    Chat->>Chat: Auto-populate context pill
    User->>Chat: Type follow-up question
    Chat->>API: POST /api/chat with selection_context
    API->>API: LangGraph pipeline processes with context
    API-->>Chat: SSE stream response

SelectionItem Types

TypeSource ComponentContext Sent to Backend
newsNewsCard{title, summary, source, ts, sentiment}
filingResearch citations{title, url, type}
docReport sections{title, content_snippet}
insightAiInsightCard{tab, score, summary, key_points}
riskRiskMetricsCard{risk_type, description, severity}

⚔️ Conflict Detection

When multiple agents analyze the same ticker, their conclusions may conflict. FinSight automatically detects and discloses these disagreements.

8 Comparable Agent Pairs

Agent AAgent BComparison Dimension
TechnicalFundamentalDirection judgment (signals vs. fundamentals)
TechnicalNewsPrice momentum vs. event impact
TechnicalPriceTechnical signals vs. actual price action
FundamentalNewsFundamentals vs. event-driven narrative
FundamentalMacroStock fundamentals vs. macro environment
NewsMacroEvent sentiment vs. macro cycle
PriceNewsPrice trend vs. news sentiment
MacroTechnicalMacro trend vs. technical signals

Trigger Formula

detect = deep_report OR (success_agents ≥ 2 AND comparable_claims ≥ 1)

Conflicts are surfaced both as structured JSON (for matrix visualization) and inline text (for report readability).


📧 Email Alerts & Subscriptions

<img src="images/ae7cbf42-a393-4ea8-bc75-ccf2d239e2c8.png" width="400" align="right"/>

FinSight includes 3 automated alert schedulers running via APScheduler:

SchedulerTriggerCheck Interval
PriceChangeSchedulerPrice moves beyond threshold (e.g., ±0.1%)15 min
NewsSchedulerHigh-impact news for watchlisted tickers30 min
RiskSchedulerRSI extreme / VaR breach / drawdown events60 min

Email Pipeline

Scheduler → Rule Engine → Alert Created →
HTML Template (Jinja2) → SMTP Send →
Delivery Tracking (transient vs permanent errors) →
Auto-disable after 3 permanent failures

Subscription Management

  • POST /api/subscriptions — Create subscription (email + tickers + alert types)
  • GET /api/subscriptions/{email} — List active subscriptions
  • DELETE /api/subscriptions/{id} — Remove subscription
  • Storage: data/subscriptions.json with per-user settings
<br clear="right"/>

💾 Data & Storage Architecture

graph TB
    subgraph "SQLite (Local)"
        CP[(checkpoints.sqlite<br/><i>LangGraph state snapshots</i>)]
        RI[(report_index.sqlite<br/><i>Report metadata + citations</i>)]
        PF[(portfolio.sqlite<br/><i>Holdings + transactions</i>)]
    end

    subgraph "JSON Files (data/)"
        MEM["memory/{user_id}.json<br/><i>User profiles + watchlists</i>"]
        SUB["subscriptions.json<br/><i>Email alert subscriptions</i>"]
        ALERTS["alerts/{user_id}.json<br/><i>Alert feed history</i>"]
    end

    subgraph "Optional PostgreSQL"
        PG_CP["langgraph_checkpoints<br/><i>Scalable checkpoint backend</i>"]
        PG_RAG["rag_documents_v2<br/><i>VECTOR(1024) + tsvector</i>"]
    end

    subgraph "In-Memory"
        DCACHE["DashboardCache<br/><i>16 TTL categories</i>"]
        ICACHE["InsightsCache<br/><i>1h TTL + stale-while-revalidate</i>"]
        RAGMEM["RAG InMemoryStore<br/><i>Fallback when no PostgreSQL</i>"]
    end

Database Schemas

<details> <summary><b>Report Index (SQLite)</b></summary>
CREATE TABLE report_index (
    report_id    TEXT PRIMARY KEY,
    session_id   TEXT NOT NULL,
    ticker       TEXT,
    title        TEXT,
    summary      TEXT,
    source_type  TEXT,          -- 'chat' | 'dashboard' | 'workbench'
    created_at   TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    metadata     TEXT           -- JSON blob
);

CREATE TABLE report_citations (
    id           INTEGER PRIMARY KEY AUTOINCREMENT,
    report_id    TEXT REFERENCES report_index(report_id),
    url          TEXT,
    title        TEXT,
    domain       TEXT,
    snippet      TEXT,
    accessed_at  TIMESTAMP
);
</details> <details> <summary><b>Portfolio (SQLite)</b></summary>
CREATE TABLE holdings (
    user_id    TEXT NOT NULL,
    ticker     TEXT NOT NULL,
    shares     REAL NOT NULL,
    avg_cost   REAL,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (user_id, ticker)
);
</details> <details> <summary><b>RAG Documents (PostgreSQL)</b></summary>
CREATE TABLE rag_documents_v2 (
    id          TEXT PRIMARY KEY,
    collection  TEXT NOT NULL,
    content     TEXT NOT NULL,
    embedding   VECTOR(1024),       -- bge-m3 dense vector
    ts_content  tsvector,           -- Chinese full-text search
    metadata    JSONB,
    scope       TEXT DEFAULT 'ephemeral',  -- ephemeral | medium_ttl | persistent
    created_at  TIMESTAMP DEFAULT NOW()
);
</details>

🗄️ Cache System

The DashboardCache manages 16 distinct TTL categories:

CategoryTTLDescription
quote30sReal-time price quotes
technical_snapshot60sTechnical indicator values
company_news300s (5m)Company-specific news
company_info600s (10m)Company profiles
sec_filings900s (15m)SEC filing data
market_chart300s (5m)OHLCV price data
financials600s (10m)Quarterly financial statements
peers600s (10m)Peer comparison data
earnings_history1800s (30m)EPS history
analyst_targets1800s (30m)Analyst price targets
recommendations1800s (30m)Buy/hold/sell ratings
indicator_series300s (5m)Technical indicator time series
insights3600s (1h)AI digest insights (stale-while-revalidate up to 4h)

Stale-While-Revalidate Pattern (Insights)

Fresh (< 1h)    → Return immediately, cached=true
Stale (1h-4h)   → Return stale data + background async refresh
Expired (> 4h)  → Wait for fresh generation

🧠 Memory & User Profiles

Per-user memory stored as JSON files in data/memory/{user_id}.json:

{
  "user_id": "abc123",
  "watchlist": ["AAPL", "GOOGL", "TSLA"],
  "preferences": {
    "language": "zh-CN",
    "risk_tolerance": "moderate",
    "default_depth": "report"
  },
  "interaction_history": [
    {"ticker": "AAPL", "action": "deep_research", "timestamp": "2026-02-18T10:30:00Z"}
  ]
}

The memory system integrates with:

  • Watchlist API: POST /api/user/watchlist/add / remove — persisted and used by alert schedulers
  • LangGraph Memory: Loaded at build_initial_state node, saved at save_memory node
  • Dashboard Store: Frontend dashboardStore syncs watchlist via API on init

🛡️ Resilience & Fallbacks

FinSight is designed for production reliability with multiple fallback layers:

ComponentPrimaryFallbackBehavior
PlannerLLM Planner (structured output)planner_stub (keyword → tool mapping)Auto-switch on LLM timeout (8s)
EmbeddingBAAI/bge-m3 (1024-dim)SHA1 hash embedding (96-dim)Graceful degradation if model not loaded
Rerankerbge-reranker-v2-m3Skip reranking, use RRF scores directlySilent passthrough
Price Datayfinance10 fallback sources (FMP → Finnhub → ...)11-level cascade
AI InsightsLLM Insight ScorersDeterministic rule-based scoringmodel_generated=false flag
Morning BriefLangGraph PipelineDirect data fetch (router fallback)Transparent to caller
Rebalance EnhancementAgent-backed LLMOriginal deterministic candidatesSafety fallback on any failure
Dashboard DataLive API fetchIn-memory cache (stale-while-revalidate)TTL-based freshness
CheckpointsPostgreSQLSQLite local fileAuto-detect on startup
RAG StorePostgreSQL + pgvectorIn-memory storeAuto-fallback
SearchTavilyExa → DuckDuckGoMulti-engine fallback chain

LLM Circuit Breaker

3 consecutive LLM failures → 15-min cooldown → Pure rule-based mode

🧹 Hallucination Mitigation

FinSight implements a multi-layer defense against LLM hallucinations, particularly targeting fabricated future events (e.g., "Company plans to launch X in 2026 Q3"):

LayerMethodStage
Prompt Constraints"Closed-book" instructions: only use provided evidence, never invent eventsSystem prompt
Regex Pattern Matching_HALLUCINATION_EVENT_PATTERNS — detect future event claimsPost-generation
Evidence Cross-Validation_claim_supported_by_evidence() — verify claims against evidence poolPost-generation
Placeholder ReplacementUnverified claims replaced with [此处信息未经证据验证,已移除]Post-generation
Time AnchoringForce date attribution on all data referencesPrompt + post-processing
DeduplicationCollapse consecutive placeholders into single markerCleanup

Full technical documentation: docs/HALLUCINATION_MITIGATION.md


🔧 Tech Stack

Backend

TechnologyVersionPurpose
Python3.11+Runtime
FastAPI0.100+REST API + SSE streaming
LangGraph0.2+Stateful agent orchestration
LangChain0.3+Tool framework, message types, text splitters
Langfuse2.xDistributed tracing & observability
yfinance0.2+Market data (quotes, financials, technicals)
FlagEmbeddinglatestbge-m3 embedding model
sentence-transformerslatestbge-reranker-v2-m3 cross-encoder
APScheduler3.xAlert scheduling (cron-based)
Pydantic2.xSchema validation

Frontend

TechnologyVersionPurpose
React19UI framework
Vite6.xBuild tooling
TypeScript5.xType safety
Zustand5.xState management (3 stores)
ECharts5.xChart visualization (via echarts-for-react)
TailwindCSS4.xStyling with CSS variables theming
react-markdownlatestMarkdown rendering in chat/reports

Models

ModelDimensionPurpose
LLM (configurable)create_llm() factory supports OpenAI, Gemini, DeepSeek, Anthropic, local
BAAI/bge-m31024Dense + Sparse embedding for RAG
BAAI/bge-reranker-v2-m3Cross-encoder reranking
paraphrase-multilingual-MiniLM-L12-v2384Legacy knowledge base (ChromaDB)

🚀 Getting Started

🐳 Docker One-Click Deployment (Recommended)

# 1. Clone repository
git clone https://github.com/kkkano/FinSight.git
cd FinSight

# 2. Configure environment
cp .env.example .env
# Edit .env with your API keys (see "API Keys" section below)

# 3. Start all services
docker compose up -d
# Frontend: http://localhost:5173
# Backend:  http://localhost:8000
# PostgreSQL: localhost:5432

💡 Docker deployment includes PostgreSQL with pgvector for production-grade RAG.

🔑 API Keys (Required vs Optional)

API KeyRequired?PurposeIf Not Configured
GEMINI_PROXY_API_KEY or OPENAI_API_KEYRequiredLLM for analysis & planningApp won't function
FMP_API_KEY⭐ RecommendedFinancial data (earnings, ratios)Falls back to yfinance
FINNHUB_API_KEYOptionalReal-time quotes, newsFalls back to other sources
TAVILY_API_KEYOptionalWeb searchFalls back to DuckDuckGo
FRED_API_KEYOptionalMacro economic dataLimited macro features
ALPHA_VANTAGE_API_KEYOptionalAdditional price dataUses other price sources

Minimum Setup: Only OPENAI_API_KEY (or equivalent LLM key) is required. All other APIs have automatic fallbacks.

💾 Database Initialization

SQLite tables (checkpoint, report, portfolio, subscriptions) are auto-created on first startup — no manual migration needed.

For PostgreSQL (optional), tables are created via SQLAlchemy models automatically.


Manual Setup (Alternative)

Prerequisites

  • Python 3.11+
  • Node.js 18+ with pnpm
  • At least one LLM API key (OpenAI / Gemini / DeepSeek)

Backend Setup

# 1. Create virtual environment
python -m venv .venv
# Windows
.venv\Scripts\activate
# Linux/Mac
source .venv/bin/activate

# 2. Install dependencies
pip install -r requirements.txt

# 3. Configure environment
copy .env.example .env
# Edit .env with your API keys:
#   OPENAI_API_KEY=sk-...
#   GOOGLE_API_KEY=...        (for Gemini)
#   FMP_API_KEY=...           (Financial Modeling Prep)
#   FINNHUB_API_KEY=...       (Finnhub)
#   TAVILY_API_KEY=...        (Tavily Search)
#   FRED_API_KEY=...          (FRED Economic Data)

# 4. Run Server
python -m uvicorn backend.api.main:app --host 0.0.0.0 --port 8000

Frontend Setup

cd frontend
pnpm install
pnpm dev
# Open http://localhost:5173

Optional: PostgreSQL for RAG

# Set environment variable to enable PostgreSQL backend
# RAG_BACKEND=postgres
# DATABASE_URL=postgresql://user:pass@localhost:5432/finsight

Optional: Email Alerts

# Enable alert schedulers
# ALERTS_ENABLED=true
# SMTP_HOST=smtp.gmail.com
# SMTP_PORT=587
# SMTP_USER=your-email@gmail.com
# SMTP_PASSWORD=your-app-password

📁 Project Structure

FinSight/
├── backend/
│   ├── api/                    # FastAPI routers
│   │   ├── main.py             # App entry point + CORS + lifespan
│   │   ├── chat_router.py      # POST /api/chat (SSE streaming)
│   │   ├── dashboard_router.py # GET /api/dashboard + /insights
│   │   ├── execution_router.py # POST /api/execute (workbench)
│   │   ├── alerts_router.py    # GET /api/alerts/feed
│   │   └── tools_router.py     # GET /api/tools (manifest)
│   ├── graph/                  # LangGraph pipeline
│   │   ├── builder.py          # Graph construction (16 nodes, edges)
│   │   ├── state.py            # GraphState definition
│   │   ├── report_builder.py   # ReportIR structure builder
│   │   └── nodes/              # Individual node implementations
│   │       ├── build_initial_state.py
│   │       ├── reset_turn_state.py  # Per-turn ephemeral field + trace cleanup
│   │       ├── chat_respond.py
│   │       ├── resolve_subject.py
│   │       ├── parse_operation.py   # 4-level priority chain (compare → guardrail → multi-ticker → qa)
│   │       ├── compare_gate.py      # Compare evidence gate (3 predicates)
│   │       ├── policy_gate.py
│   │       ├── planner.py
│   │       ├── execute_plan_stub.py
│   │       └── synthesize.py   # Conflict detection + hallucination scrub
│   ├── agents/                 # Agent implementations
│   │   ├── base_agent.py       # BaseFinancialAgent (reflection loops)
│   │   ├── price_agent.py
│   │   ├── news_agent.py
│   │   ├── fundamental_agent.py
│   │   ├── technical_agent.py
│   │   ├── macro_agent.py
│   │   ├── risk_agent.py
│   │   └── deep_search_agent.py
│   ├── dashboard/              # Dashboard data & AI insights
│   │   ├── data_service.py     # yfinance/FMP data fetching
│   │   ├── cache.py            # DashboardCache (16 TTL categories)
│   │   ├── insights_engine.py  # Insight Scorer orchestrator (single-LLM-call, not autonomous agents)
│   │   ├── insights_scorer.py  # Deterministic scoring fallback
│   │   ├── insights_prompts.py # LLM prompt templates
│   │   └── schemas.py          # Pydantic schemas
│   ├── rag/                    # Hybrid RAG engine
│   │   ├── hybrid_service.py   # InMemory + Postgres backends
│   │   ├── embedder.py         # bge-m3 embedding service
│   │   ├── reranker.py         # bge-reranker-v2-m3
│   │   ├── rag_router.py       # Query routing (SKIP/PRIMARY/PARALLEL)
│   │   └── chunker.py          # Document chunking strategies
│   ├── tools/                  # Tool implementations
│   │   ├── manifest.py         # 17 tools with metadata
│   │   ├── market.py           # Price data (11-source cascade)
│   │   ├── financial.py        # Financial statements
│   │   ├── technical.py        # Technical indicators
│   │   ├── macro.py            # FRED + sentiment
│   │   └── sec_tools.py        # SEC EDGAR filings
│   ├── services/               # Background services
│   │   ├── alert_scheduler.py  # 3 alert schedulers
│   │   ├── scheduler_runner.py # APScheduler wrapper
│   │   ├── subscription_service.py
│   │   └── memory.py           # Per-user memory store
│   └── tests/                  # 700+ tests
│       ├── test_graph_*.py
│       ├── test_agents_*.py
│       ├── test_dashboard_*.py
│       └── test_rag_*.py
├── frontend/
│   ├── src/
│   │   ├── api/client.ts       # API client + SSE parseSSEStream
│   │   ├── store/              # Zustand stores
│   │   │   ├── useStore.ts     # Global store (session, auth)
│   │   │   ├── dashboardStore.ts  # Dashboard state
│   │   │   └── executionStore.ts  # Workbench execution state
│   │   ├── components/
│   │   │   ├── dashboard/      # Dashboard UI
│   │   │   │   ├── tabs/       # 6 tab panels
│   │   │   │   │   ├── OverviewTab.tsx
│   │   │   │   │   ├── FinancialTab.tsx
│   │   │   │   │   ├── TechnicalTab.tsx
│   │   │   │   │   ├── NewsTab.tsx
│   │   │   │   │   ├── ResearchTab.tsx
│   │   │   │   │   └── PeersTab.tsx
│   │   │   │   └── StockHeader.tsx
│   │   │   ├── SmartChart.tsx  # LLM-driven dual-mode charts
│   │   │   ├── ChatList.tsx    # Chat + inline charts
│   │   │   └── workbench/      # Workbench components
│   │   ├── hooks/              # Custom React hooks
│   │   │   ├── useLatestReport.ts
│   │   │   ├── useDashboardData.ts
│   │   │   ├── useDashboardInsights.ts
│   │   │   └── useChartTheme.ts
│   │   └── types/dashboard.ts  # TypeScript type definitions
│   └── vite.config.ts
├── data/                       # Runtime data storage
│   ├── memory/                 # Per-user JSON profiles
│   ├── subscriptions.json      # Email alert subscriptions
│   └── *.sqlite                # SQLite databases
├── docs/                       # Technical documentation
└── images/                     # Screenshots

🧪 Phase Labs (Phase 1–4)

An experimental feature suite accessible at /phase-labs, built on top of the core platform:

PhaseFeatureDescription
Phase 1Conversational Price AlertsSay "alert me when TSLA hits $300" in chat → LangGraph extracts ticker/direction/threshold → scheduler fires email when triggered. Supports price_change_pct (cooldown window) and price_target (one-shot).
Phase 2Stock Screener MVPMulti-condition natural-language screener (PE < 20, revenue growth > 15%, etc.). Returns ranked results with a capability_note on CN/HK coverage limits.
Phase 3A-Share Market DataReal-time Northbound/Southbound capital flow (cn_market_flow), sector & concept board heat maps (cn_market_board), concept keyword map (concept_map). Covers both A-Share and HK markets.
Phase 4Strategy BacktestingSMA crossover, MACD signal, RSI mean-reversion strategies. Enforces A-Share T+1 settlement (no same-day round-trip), parameterized commission/slippage, and look-ahead bias prevention via t_plus_one bar offset.

🔬 RAG Quality V2 — 3-Layer Evaluation

A custom eval framework replacing RAGAS with 6 claim/keypoint-level metrics tailored for Chinese financial narratives. Full report: tests/rag_qualityV2/REPORT.md

Layer overview:

LayerWhat it testsInputKey insight
L1 Mock ContextLLM generation baseline — given perfect evidence, can the model answer correctly?Mock contexts → direct promptEstablishes the generation ceiling independent of retrieval
L2 Real RetrievalRetrieval + generation pipeline — does bge-m3 hybrid search surface the right chunks?Real embedding + Top-K → synthesize_agentIsolates retrieval quality from routing/orchestration noise
L3 E2E PipelineFull LangGraph end-to-end — exactly what a real user getsComplete LangGraph flowStrongest signal; validates production readiness

All 3 layers PASSED across 12 Chinese financial cases (filings, transcripts, news):

LayerKCKCRCSRUCR ↓CR ↓NCRGate
L1 Mock0.87960.94790.94310.0570.00.9896✅ PASS
L2 Retrieval0.89600.96231.00000.0000.00.9861✅ PASS
L3 E2E0.90720.96530.99240.0080.01.0000✅ PASS

Layer 3 per-case results (12/12 PASS):

#CaseTypeKCKCRCSRUCR ↓NCRResult
01Moutai 2024Q3 Revenuefiling/factoid1.01.01.00.01.0✅ Perfect
02CATL Gross Margin 2024filing/analysis1.01.01.00.01.0✅ Perfect
03BYD EV Sales 2024H1filing/factoid1.01.01.00.01.0✅ Perfect
04PICC Embedded Valuefiling/factoid1.01.01.00.01.0✅ Perfect
05Alibaba Cloud Guidancetranscript/analysis1.01.01.00.01.0✅ Perfect
06Tencent Gaming Recoverytranscript/analysis0.7141.01.00.01.0⚠️ KC
07Meituan Profitabilitytranscript/analysis0.8330.8331.00.01.0⚠️ KC
08JD Supply Chaintranscript/analysis0.7141.01.00.01.0⚠️ KC
09Fed Rate Cut → A-Sharenews/list1.01.01.00.01.0✅ Perfect
10China EV Export Controlsnews/list1.01.00.9090.0911.0⚠️ UCR
11iPhone 16 China Salesnews/analysis1.01.01.00.01.0✅ Perfect
12Semiconductor Export Bannews/analysis0.6250.751.00.01.0⚠️ KC

CR = 0.0 across all layers — zero contradicted claims. NCR = 1.0 at E2E — numeric consistency perfect end-to-end. ⚠️ KC gaps on transcript/analysis are generation-side (evidence exists, brief mode omits product-level detail). *Based on 12 test cases; production results may vary.


📄 License

This project is licensed under the MIT License.


<p align="center"> Built with LangGraph + React + ECharts </p>

Related Documents