| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- <!DOCTYPE html>
- <html lang="zh">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>施工方案RAG链路透视镜</title>
- <script src="https://unpkg.com/react@17/umd/react.development.js"></script>
- <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
- <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
- <script src="https://cdn.tailwindcss.com"></script>
- <style>
- .score-bar { transition: width 0.5s ease; }
- .lane-connector {
- position: absolute;
- left: 50%;
- border-left: 2px dashed #cbd5e1;
- z-index: 0;
- }
- </style>
- </head>
- <body class="bg-slate-50 text-slate-800">
- <div id="root"></div>
- <script type="text/babel">
- // 模拟你提供的日志数据
- const logData = {
- "stage": "rag_enhanced_check",
- "steps": {
- "1_query_extract": {
- "output": {
- "query_pairs": [
- {
- "entity": "T梁",
- "background": "安装作业,涉及外观检查、焊接连接...",
- "parameter": "梁端面平齐,梁缝符合要求..."
- },
- {
- "entity": "安全带",
- "background": "高处作业人员使用...",
- "parameter": "挂钩或绳子应挂在结实牢固的构件上..."
- }
- ]
- }
- },
- "2_entity_enhance_retrieval": {
- "output": {
- "results": [
- [ // T梁的结果
- {
- "metadata": { "title": "17.2.7 构件的存放" },
- "text_content": "构件应按其安装的先后顺序编号存放...",
- "hybrid_similarity": 0.78,
- "rerank_score": 0.96,
- "bfp_rerank_score": 0.09, // 低分致死原因
- "source_entity": "T梁"
- },
- {
- "metadata": { "title": "17.2.6 构件的场内移运" },
- "bfp_rerank_score": 0.02,
- "source_entity": "T梁"
- }
- ],
- [ // 安全带的结果
- {
- "metadata": { "title": "坠落防护 安全带" },
- "text_content": "坠落防护 安全带...",
- "hybrid_similarity": 0.65,
- "rerank_score": 0.92,
- "bfp_rerank_score": 0.97,
- "source_entity": "安全带"
- }
- ]
- ]
- }
- },
- "4_extract_query_pairs_results": {
- "output": {
- // 这里模拟那个 Bug:Entity是T梁,内容却是安全带
- "entity_results": [
- {
- "entity": "T梁",
- "query_index": 0,
- "metadata": { "title": "坠落防护 安全带" },
- "final_score": 0.97,
- "is_bug": true // 标记用于前端高亮
- }
- ]
- }
- }
- }
- };
- const ScoreBadge = ({ label, value, threshold = 0.5 }) => {
- const isLow = value < threshold;
- const colorClass = isLow ? "bg-red-100 text-red-700 border-red-200" : "bg-green-100 text-green-700 border-green-200";
- return (
- <div className={`flex flex-col border rounded px-2 py-1 text-xs ${colorClass} mb-1`}>
- <span className="opacity-70">{label}</span>
- <span className="font-bold text-sm">{value ? value.toFixed(2) : 'N/A'}</span>
- </div>
- );
- };
- const DocCard = ({ doc, isFinal = false, isBug = false }) => {
- return (
- <div className={`relative p-3 rounded-lg border-2 mb-2 bg-white shadow-sm ${isBug ? 'border-red-500 ring-2 ring-red-200' : 'border-slate-200'}`}>
- {isBug && (
- <div className="absolute -top-3 -right-3 bg-red-600 text-white text-xs font-bold px-2 py-1 rounded shadow animate-pulse">
- BUG DETECTED: 索引错位
- </div>
- )}
- <div className="font-semibold text-slate-700 text-sm truncate" title={doc.metadata?.title}>
- {doc.metadata?.title || doc.file_name || "Unknown Doc"}
- </div>
-
- {!isFinal && (
- <div className="grid grid-cols-3 gap-1 mt-2">
- <ScoreBadge label="混合检索" value={doc.hybrid_similarity} />
- <ScoreBadge label="粗排分数" value={doc.rerank_score} />
- <ScoreBadge label="背景重排" value={doc.bfp_rerank_score} threshold={0.5} />
- </div>
- )}
- {doc.bfp_rerank_score < 0.5 && !isFinal && (
- <div className="mt-1 text-xs text-red-500 font-bold text-center bg-red-50 py-1 rounded">
- {'[X] 因背景不匹配被过滤 (Score < 0.5)'}
- </div>
- )}
-
- <div className="mt-2 text-xs text-slate-500 line-clamp-2">
- {doc.text_content}
- </div>
- </div>
- );
- };
- const SwimLane = ({ queryPair, retrievalResults, finalResult, index }) => {
- const hasResults = retrievalResults && retrievalResults.length > 0;
- // 检查是否存在 Bug:Final result 的 entity 和 query 的 entity 不一致
- const isMismatchBug = finalResult && finalResult.entity !== queryPair.entity;
- const isContentMismatch = finalResult && finalResult.metadata?.title.includes("安全带") && queryPair.entity.includes("T梁");
- const bugDetected = isMismatchBug || isContentMismatch;
- return (
- <div className="flex flex-row gap-4 mb-8 min-w-[1000px]">
- {/* 1. 提取阶段 */}
- <div className="w-1/4 flex-shrink-0">
- <div className="bg-blue-50 border-l-4 border-blue-500 p-4 rounded shadow-sm h-full relative">
- <div className="absolute -left-3 -top-3 w-8 h-8 bg-blue-600 text-white rounded-full flex items-center justify-center font-bold">
- {index + 1}
- </div>
- <h3 className="font-bold text-lg text-blue-900">{queryPair.entity}</h3>
- <div className="mt-2 text-xs text-slate-600">
- <span className="font-semibold bg-blue-100 px-1 rounded">背景</span> {queryPair.background}
- </div>
- <div className="mt-2 text-xs text-slate-600">
- <span className="font-semibold bg-purple-100 px-1 rounded">参数</span> {queryPair.parameter}
- </div>
- </div>
- </div>
- {/* 箭头 */}
- <div className="flex flex-col justify-center items-center w-8 text-slate-300">
- →
- </div>
- {/* 2. 检索 & 排序阶段 */}
- <div className="w-1/3 flex-shrink-0 flex flex-col gap-2">
- {hasResults ? (
- retrievalResults.map((doc, idx) => (
- <DocCard key={idx} doc={doc} />
- ))
- ) : (
- <div className="text-center p-4 border-2 border-dashed border-gray-300 rounded text-gray-400">
- 未召回到相关文档
- </div>
- )}
- </div>
- {/* 箭头 */}
- <div className="flex flex-col justify-center items-center w-8 text-slate-300">
- →
- </div>
- {/* 3. 最终结果阶段 (展示 Bug) */}
- <div className="w-1/4 flex-shrink-0">
- {finalResult ? (
- <div className={`h-full ${bugDetected ? 'bg-red-50' : 'bg-green-50'} p-1 rounded`}>
- <DocCard doc={finalResult} isFinal={true} isBug={bugDetected} />
- {bugDetected && (
- <div className="text-xs text-red-600 mt-2 font-mono p-2 bg-red-100 rounded">
- 错误分析: <br/>
- Query: <strong>{queryPair.entity}</strong><br/>
- Result: <strong>{finalResult.metadata?.title}</strong><br/>
- <span className="font-bold">索引匹配错误!</span>
- </div>
- )}
- </div>
- ) : (
- <div className="h-full flex items-center justify-center border-2 border-dashed border-slate-200 rounded bg-slate-50 text-slate-400 text-sm">
- 此链路被过滤
- </div>
- )}
- </div>
- </div>
- );
- };
- const Dashboard = () => {
- const queryPairs = logData.steps["1_query_extract"].output.query_pairs;
- const retrievalOutputs = logData.steps["2_entity_enhance_retrieval"].output.results;
- const finalResults = logData.steps["4_extract_query_pairs_results"].output.entity_results;
- return (
- <div className="p-8 min-h-screen">
- <header className="mb-8 border-b pb-4">
- <h1 className="text-3xl font-bold text-slate-800">RAG 链路透视看板</h1>
- <p className="text-slate-500 mt-2">
- 针对 "T梁安装" 案例的执行轨迹回放与问题诊断
- </p>
- </header>
- <div className="flex flex-col">
- {/* 表头 */}
- <div className="flex flex-row gap-4 mb-4 text-sm font-bold text-slate-400 uppercase tracking-wider min-w-[1000px]">
- <div className="w-1/4">Step 1: 语义提取 (Query Construction)</div>
- <div className="w-8"></div>
- <div className="w-1/3">Step 2 & 3: 召回与重排序 (Recall & Rerank)</div>
- <div className="w-8"></div>
- <div className="w-1/4">Step 4: 最终映射 (Final Mapping)</div>
- </div>
- {/* 泳道 */}
- {queryPairs.map((pair, index) => {
- // 简单的按索引获取,模拟代码中的行为
- const results = retrievalOutputs[index] || [];
- // 模拟代码中的 Bug:这里强制让 index 0 的 T梁 显示 结果列表里的第 0 个 (其实是安全带,因为T梁被过滤了)
- // 在真实逻辑中,你需要根据 query_index 来 find
- const finalRes = finalResults.find(r => r.query_index === index) || (index === 0 && finalResults[0]);
-
- return (
- <SwimLane
- key={index}
- index={index}
- queryPair={pair}
- retrievalResults={results}
- finalResult={finalRes}
- />
- );
- })}
- </div>
-
- <div className="mt-12 bg-slate-800 text-slate-200 p-6 rounded-lg">
- <h3 className="text-xl font-bold mb-4 text-white">[工具] 修复建议 (基于日志分析)</h3>
- <ul className="list-disc pl-5 space-y-2">
- <li>
- <strong className="text-red-400">修复索引错位 Bug (Critical):</strong>
- 在 `extract_query_pairs_results` 函数中,不要假设 `enhanced_results` 的索引与 `query_pairs` 一一对应。
- 因为中间有过滤步骤,列表长度变了。应该使用 Map 或字典来通过 `query_index` 锚定结果。
- </li>
- <li>
- <strong className="text-yellow-400">解决 T梁 召回相关性低:</strong>
- 观察到 `bfp_rerank_score` 只有 0.09。这说明虽然召回了"T梁",但内容是关于"存放"的,而你需要"安装"。
- 建议在 Step 2 检索时,强制将 `background` 中的关键词(如"安装"、"焊接"、"支撑")加入到 Keyword Search 中,而不仅仅是搜索 Entity。
- </li>
- </ul>
- </div>
- </div>
- );
- };
- ReactDOM.render(<Dashboard />, document.getElementById('root'));
- </script>
- </body>
- </html>
|