259 lines
14 KiB
TypeScript
259 lines
14 KiB
TypeScript
import { useState } from "react";
|
||
|
||
// Mock 评测趋势数据
|
||
const QUALITY_TREND = [0.82, 0.84, 0.79, 0.81, 0.85, 0.88, 0.89, 0.87, 0.86, 0.91, 0.92, 0.88, 0.87, 0.88];
|
||
const HALLUCINATION_TREND = [18, 15, 22, 19, 14, 11, 10, 12, 13, 8, 7, 11, 12, 10]; // % 比例
|
||
const DATES = ["06-14", "06-15", "06-16", "06-17", "06-18", "06-19", "06-20", "06-21", "06-22", "06-23", "06-24", "06-25", "06-26", "06-27"];
|
||
|
||
// Mock 低分评测记录(错题本)与纠偏轨迹
|
||
const MOCK_POOR_RUNS = [
|
||
{
|
||
id: "task_e8f2a1b9",
|
||
time: "11:47:05",
|
||
user: "Bob",
|
||
agentName: "法律合同审查 Agent",
|
||
overall: 0.42,
|
||
ruleScore: 0.60,
|
||
llmScore: 0.50,
|
||
faithful: 0.15,
|
||
level: "poor",
|
||
reason: "幻觉严重。模型声称合同中包含‘三年内无条件退款限制条款’,但所附 RAG 参考材料中仅提及‘按比例折算退款规则’,属于严重的知识库脱轨和无中生有(无立足依据)。",
|
||
trace: {
|
||
initialAnswer: "根据合同第 4 条,本合同包含三年内无条件全额退款条款,客户可随时申请解除合作。",
|
||
critique: "【评测发现异常】RAG 知识块[文档: 退款政策_2026.pdf]中明确规定退款须‘按合作月份比例折算,扣除已产生渠道服务费后退还余款,且需提前30天书面申请’。模型回答‘无条件全额退款’属严重事实性捏造,忠实度(Faithful)分值判定为 0.15。",
|
||
refinePrompt: "你是一个严肃的合同审查纠偏助手。在前一次生成中,模型产生了事实性幻觉。请根据参考材料【退款政策_2026.pdf】:‘退款须按合作月份比例折算,扣除已产生渠道服务费后退还余款,且需提前30天书面申请’,对前次答案【根据合同第 4 条...】进行修改纠正,必须忠实于材料,杜绝捏造无条件条款。",
|
||
refinedAnswer: "根据退款政策附件规则,退款非无条件全额,而是必须按合作月份比例折算,且扣除已产生渠道服务费后退还余款。此外,客户申请退款需提前30天提交书面申请,合同第4条仅规定了申请路径,而非‘无条件退款’。",
|
||
newScore: 0.85
|
||
}
|
||
},
|
||
{
|
||
id: "task_ff3c0b12",
|
||
time: "10:12:30",
|
||
user: "Alice",
|
||
agentName: "医学文献总结 Agent",
|
||
overall: 0.55,
|
||
ruleScore: 0.50,
|
||
llmScore: 0.60,
|
||
faithful: 0.55,
|
||
level: "poor",
|
||
reason: "引用缺失。用户要求‘回答时必须在事实断言处标注 RAG 参考的文档来源’,但模型生成的总结文本中未包含任何形如 [1] 或 [doc_xxx] 的引用锚点,违反了输入 DSL 的强制规范规则。",
|
||
trace: {
|
||
initialAnswer: "该临床研究表明,使用该抗体偶联药物能提高 15% 的无进展生存期(PFS),且中位缓解期达到了 12.4 个月。",
|
||
critique: "【评测发现异常】模型得出了准确的结论,但未按照强制指令将数据来源指向知识块 [文献_ADC研究_Phase3.pdf]。违反强制引用约束,规则分降低为 0.50。",
|
||
refinePrompt: "前次生成中未包含数据来源引用。请在前次总结中,为‘提高 15% 的无进展生存期’与‘中位缓解期达到 12.4 个月’数据,在行内添加形如 [文献_ADC研究_Phase3.pdf] 的数据来源引用标签。",
|
||
refinedAnswer: "最新临床三期研究表明,使用该抗体偶联药物能提高 15% 的无进展生存期(PFS)[文献_ADC研究_Phase3.pdf],且中位缓解期达到了 12.4 个月[文献_ADC研究_Phase3.pdf]。",
|
||
newScore: 0.92
|
||
}
|
||
},
|
||
{
|
||
id: "task_a5fd2510",
|
||
time: "09:30:15",
|
||
user: "Alice",
|
||
agentName: "财务审计核对 Agent",
|
||
overall: 0.48,
|
||
ruleScore: 0.40,
|
||
llmScore: 0.55,
|
||
faithful: 0.50,
|
||
level: "poor",
|
||
reason: "计算口径不一致。知识库给出的 2025 Q4 营业收入为‘1.2 亿元(含未结算款项)’,但财务报表核查中模型漏计了未结算款,算出了 1.05 亿元,与账面发生额不符。",
|
||
trace: {
|
||
initialAnswer: "核对完毕,Q4 累计核算收入为 1.05 亿元,与系统申报一致。",
|
||
critique: "【评测发现异常】少计算了未结算款项 1500 万元。知识库规定必须将未结算款项计入 Q4 营业收入内。规则评分降为 0.40。",
|
||
refinePrompt: "计算遗漏。请把财务参考中的‘1500万未结算款项’加进 Q4 营业收入核对中,重新计算总营收并核对金额。",
|
||
refinedAnswer: "重新核算后,Q4 累计核算总收入为 1.2 亿元(已包含 1500 万元未结算款项),与系统申报发生额完全吻合。",
|
||
newScore: 0.89
|
||
}
|
||
}
|
||
];
|
||
|
||
export function EvalsPage() {
|
||
const [runs, setRuns] = useState(MOCK_POOR_RUNS);
|
||
const [expandedId, setExpandedId] = useState<string | null>(null);
|
||
|
||
const toggleExpand = (id: string) => {
|
||
setExpandedId((prev) => (prev === id ? null : id));
|
||
};
|
||
|
||
// SVG 趋势图宽高
|
||
const chartW = 260;
|
||
const chartH = 70;
|
||
const pad = 10;
|
||
|
||
// 1. 质量曲线点计算
|
||
const maxValQ = 1.0;
|
||
const pointsQ = QUALITY_TREND.map((val, idx) => {
|
||
const x = pad + (idx * (chartW - pad * 2)) / (QUALITY_TREND.length - 1);
|
||
const y = chartH - pad - (val * (chartH - pad * 2)) / maxValQ;
|
||
return { x, y };
|
||
});
|
||
const pathQ = pointsQ.reduce((p, pt, i) => p + `${i === 0 ? "M" : "L"} ${pt.x.toFixed(1)} ${pt.y.toFixed(1)}`, "");
|
||
|
||
// 2. 幻觉率曲线点计算
|
||
const maxValH = 30; // 最大 30% 刻度
|
||
const pointsH = HALLUCINATION_TREND.map((val, idx) => {
|
||
const x = pad + (idx * (chartW - pad * 2)) / (HALLUCINATION_TREND.length - 1);
|
||
const y = chartH - pad - (val * (chartH - pad * 2)) / maxValH;
|
||
return { x, y };
|
||
});
|
||
const pathH = pointsH.reduce((p, pt, i) => p + `${i === 0 ? "M" : "L"} ${pt.x.toFixed(1)} ${pt.y.toFixed(1)}`, "");
|
||
|
||
return (
|
||
<div className="space-y-6">
|
||
{/* 顶部大盘指标与微缩趋势图 */}
|
||
<div className="grid grid-cols-1 gap-6 md:grid-cols-3">
|
||
{/* 指标 1:综合评测均分 */}
|
||
<section className="rounded-xl border border-gray-100 bg-white p-4 shadow-sm flex items-center justify-between gap-4">
|
||
<div>
|
||
<span className="text-xs font-medium text-gray-400">自动化综合均分</span>
|
||
<h3 className="mt-1 text-2xl font-bold text-gray-800">0.88</h3>
|
||
<span className="text-[10px] text-emerald-600">本周均值较上周 ↑ 3%</span>
|
||
</div>
|
||
{/* 微型折线图 */}
|
||
<div className="w-36 h-12 bg-gray-50/50 rounded border p-1">
|
||
<svg viewBox={`0 0 ${chartW} ${chartH}`} className="w-full h-full overflow-visible">
|
||
<path d={pathQ} fill="none" stroke="#7c3aed" strokeWidth="2" strokeLinecap="round" />
|
||
</svg>
|
||
</div>
|
||
</section>
|
||
|
||
{/* 指标 2:忠实度评测与幻觉率 */}
|
||
<section className="rounded-xl border border-gray-100 bg-white p-4 shadow-sm flex items-center justify-between gap-4">
|
||
<div>
|
||
<span className="text-xs font-medium text-gray-400">平均幻觉发生率</span>
|
||
<h3 className="mt-1 text-2xl font-bold text-rose-600">10%</h3>
|
||
<span className="text-[10px] text-emerald-600">较本月初降低 ↓ 8%</span>
|
||
</div>
|
||
{/* 微型折线图 */}
|
||
<div className="w-36 h-12 bg-gray-50/50 rounded border p-1">
|
||
<svg viewBox={`0 0 ${chartW} ${chartH}`} className="w-full h-full overflow-visible">
|
||
<path d={pathH} fill="none" stroke="#f43f5e" strokeWidth="2" strokeLinecap="round" />
|
||
</svg>
|
||
</div>
|
||
</section>
|
||
|
||
{/* 指标 3:纠偏系统效能 */}
|
||
<section className="rounded-xl border border-gray-100 bg-white p-4 shadow-sm">
|
||
<span className="text-xs font-medium text-gray-400">低分纠偏成功率 (恒温器效能)</span>
|
||
<div className="mt-2 flex items-baseline gap-2">
|
||
<h3 className="text-2xl font-bold text-gray-800">84.2%</h3>
|
||
<span className="text-xs text-gray-500">纠偏重生成共计 228 次</span>
|
||
</div>
|
||
<div className="mt-2 h-1.5 w-full bg-gray-100 rounded-full overflow-hidden">
|
||
<div className="h-full bg-violet-600 rounded-full" style={{ width: "84.2%" }} />
|
||
</div>
|
||
</section>
|
||
</div>
|
||
|
||
{/* 自动纠偏错题本(失败记录) */}
|
||
<section className="rounded-xl border border-gray-100 bg-white p-5 shadow-sm">
|
||
<div className="mb-4">
|
||
<h3 className="text-sm font-semibold text-gray-700">自动纠偏错题本 (质量异常事件)</h3>
|
||
<p className="text-[11px] text-gray-400">罗列所有触发低分(poor)警告的请求,可点击展开查看系统对答案的自动纠正(Refinement)全轨迹</p>
|
||
</div>
|
||
|
||
<div className="space-y-3">
|
||
{runs.map((r) => {
|
||
const isExpanded = expandedId === r.id;
|
||
return (
|
||
<div key={r.id} className="rounded-lg border border-gray-100 overflow-hidden">
|
||
{/* 简要行 */}
|
||
<div
|
||
onClick={() => toggleExpand(r.id)}
|
||
className={`flex flex-col md:flex-row md:items-center justify-between gap-4 p-3.5 cursor-pointer hover:bg-gray-50/50 transition-colors ${
|
||
isExpanded ? "bg-violet-50/20 border-b border-violet-100" : ""
|
||
}`}
|
||
>
|
||
<div className="flex items-center gap-3">
|
||
<span className="text-xs font-mono font-bold text-gray-400">[{r.time}]</span>
|
||
<div>
|
||
<div className="text-xs font-semibold text-gray-800">{r.agentName}</div>
|
||
<div className="text-[10px] text-gray-400">提交者: {r.user} | ID: {r.id}</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 分数指标组 */}
|
||
<div className="flex items-center gap-3">
|
||
<div className="text-center">
|
||
<div className="text-[9px] text-gray-400">综合得分</div>
|
||
<div className="text-xs font-bold text-rose-600">{r.overall.toFixed(2)}</div>
|
||
</div>
|
||
<div className="text-center border-l pl-3">
|
||
<div className="text-[9px] text-gray-400">规则约束</div>
|
||
<div className="text-xs font-semibold text-gray-600">{r.ruleScore.toFixed(2)}</div>
|
||
</div>
|
||
<div className="text-center border-l pl-3">
|
||
<div className="text-[9px] text-gray-400">RAG忠实度</div>
|
||
<div className={`text-xs font-semibold ${r.faithful <= 0.3 ? "text-rose-600" : "text-gray-600"}`}>
|
||
{r.faithful.toFixed(2)}
|
||
</div>
|
||
</div>
|
||
<div className="text-center border-l pl-3">
|
||
<div className="text-[9px] text-gray-400">纠偏后分数</div>
|
||
<div className="text-xs font-bold text-emerald-600">↑ {r.trace.newScore.toFixed(2)}</div>
|
||
</div>
|
||
|
||
{/* 展开折叠箭头 */}
|
||
<span className="text-gray-400 text-xs pl-2 font-mono">{isExpanded ? "▲" : "▼"}</span>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 展开详细信息(纠偏对齐轨迹详情) */}
|
||
{isExpanded && (
|
||
<div className="p-4 bg-gray-50/30 text-xs space-y-4 animate-fadeIn">
|
||
{/* 1. 问题定位 */}
|
||
<div className="border-l-2 border-rose-500 pl-3">
|
||
<h5 className="font-bold text-gray-800">评测问题诊断 (Evaluator Diagnosis)</h5>
|
||
<p className="mt-1 text-gray-600 leading-snug">{r.reason}</p>
|
||
</div>
|
||
|
||
{/* 2. 纠偏流转卡片组 */}
|
||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
{/* 初次答案 */}
|
||
<div className="rounded border bg-white p-3">
|
||
<div className="text-[10px] font-bold text-rose-600 flex items-center gap-1.5">
|
||
<span className="h-1.5 w-1.5 rounded-full bg-rose-500" />
|
||
初次生成(存在幻觉/缺陷) Score: {r.overall.toFixed(2)}
|
||
</div>
|
||
<p className="mt-2 text-gray-500 font-mono leading-relaxed">{r.trace.initialAnswer}</p>
|
||
</div>
|
||
|
||
{/* 初次评测评语 */}
|
||
<div className="rounded border bg-white p-3">
|
||
<div className="text-[10px] font-bold text-amber-600 flex items-center gap-1.5">
|
||
<span className="h-1.5 w-1.5 rounded-full bg-amber-500" />
|
||
评测诊断意见 (Evaluator Critique)
|
||
</div>
|
||
<p className="mt-2 text-gray-500 leading-relaxed">{r.trace.critique}</p>
|
||
</div>
|
||
|
||
{/* 纠偏 Prompt 注入 */}
|
||
<div className="rounded border bg-white p-3 md:col-span-2">
|
||
<div className="text-[10px] font-bold text-violet-600 flex items-center gap-1.5">
|
||
<span className="h-1.5 w-1.5 rounded-full bg-violet-500 animate-pulse" />
|
||
纠偏重写指令 (Refinement Rewrite Prompt)
|
||
</div>
|
||
<p className="mt-2 text-gray-500 font-mono leading-relaxed bg-gray-50 p-2 rounded border border-gray-100">
|
||
{r.trace.refinePrompt}
|
||
</p>
|
||
</div>
|
||
|
||
{/* 纠偏后最终答案 */}
|
||
<div className="rounded border bg-white p-3 md:col-span-2 border-emerald-200 bg-emerald-50/10">
|
||
<div className="text-[10px] font-bold text-emerald-600 flex items-center gap-1.5">
|
||
<span className="h-1.5 w-1.5 rounded-full bg-emerald-500" />
|
||
纠偏重写采纳(纠偏成功) Score: {r.trace.newScore.toFixed(2)}
|
||
</div>
|
||
<p className="mt-2 text-gray-700 font-mono leading-relaxed">{r.trace.refinedAnswer}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
})}
|
||
</div>
|
||
</section>
|
||
</div>
|
||
);
|
||
}
|