多个链接不等于多份证据,新闻核验看板怎样合并来源 同一篇通稿被十个网站转载页面若只数链接会显示“10 个独立来源”可信指数也被虚高。新闻核验真正要统计的是相互独立的证据源以及这些来源分别支持或反驳了哪条陈述。新闻可信度看板已经展示可信指数、独立来源和待核事实场景页也区分官方发布、现场媒体和社交平台。我将页面数据拆成陈述、来源和证据三层使“来源数量”不再等于 URL 数量。一条新闻可以包含多条待核陈述整篇新闻只有一个真假值会丢失细节。同一报道中的时间可能已经证实伤亡数字仍在变化地点描述也可能有误。exporttypeClaimStatusunverified|supported|disputed|insufficientexporttypeEvidenceStancesupport|contradict|contextexportinterfaceClaim{id:stringtext:stringstatus:ClaimStatus updatedAt:number}exportinterfaceSource{id:stringpublisher:stringcanonicalUrl:stringoriginId:stringpublishedAt:numbersourceType:official|media|eyewitness|social}exportinterfaceEvidence{id:stringclaimId:stringsourceId:stringstance:EvidenceStance excerpt:stringcapturedAt:number}originId表示内容最初来源。转载站点可以拥有不同Source.id和网址但只要追溯到同一篇原稿它们就在独立性统计中归为一组。URL 先规范化再判断转载关系常见链接带有追踪参数和锚点。若不清理同一页面就可能被当成多个来源。exportfunctioncanonicalize(raw:string):string{try{consturlnewURL(raw)constremovable[utm_source,utm_medium,utm_campaign,from,share]removable.forEach((key:string)url.searchParams.delete(key))url.hashurl.hostnameurl.hostname.toLocaleLowerCase()if(url.pathname.length1url.pathname.endsWith(/)){url.pathnameurl.pathname.slice(0,-1)}returnurl.toString()}catch(_){returnraw.trim()}}exportfunctionuniqueOrigins(sources:Source[]):Source[]{constmapnewMapstring,Source()sources.forEach((source:Source){constkeysource.originId.length0?source.originId:canonicalize(source.canonicalUrl)constpreviousmap.get(key)if(!previous||source.publishedAtprevious.publishedAt){map.set(key,source)}})returnArray.from(map.values())}仅靠 URL 不能可靠识别所有转载。真实服务还需要内容指纹、引用链和人工确认本地界面先允许录入originId把独立性规则放在模型中而不是写死为域名数量。每条陈述独立计算状态来源可信度不能替代证据关系。官方来源可能只确认事件发生没有确认传播最广的数字。状态计算只看与当前陈述关联的证据。exportinterfaceClaimAssessment{claimId:stringstatus:ClaimStatus independentSupport:numberindependentContradiction:number}exportfunctionassessClaim(claim:Claim,evidence:Evidence[],sources:Source[]):ClaimAssessment{constsourceMapnewMap(sources.map((source:Source)[source.id,source]))constrelatedevidence.filter((item:Evidence)item.claimIdclaim.id)constsupportnewSetstring()constcontradictionnewSetstring()related.forEach((item:Evidence){constsourcesourceMap.get(item.sourceId)if(!source||item.stancecontext)returnconstoriginsource.originId||canonicalize(source.canonicalUrl)if(item.stancesupport)support.add(origin)if(item.stancecontradict)contradiction.add(origin)})letstatus:ClaimStatusunverifiedif(support.size2contradiction.size0)statussupportedelseif(contradiction.size0)statusdisputedelseif(support.size1)statusinsufficientreturn{claimId:claim.id,status,independentSupport:support.size,independentContradiction:contradiction.size}}这里设定“两份独立支持且无反证”为本地演示规则不代表新闻事实核验的通用结论。界面应把依据数量和冲突状态展示出来让读者知道评分如何形成。看板评分保留待核数量总分是导航信息不能覆盖明细。我根据已支持、存在争议和证据不足的陈述生成简单分数同时返回待核数量。exportinterfaceBoardSummary{score:numberindependentSources:numberpendingClaims:numberassessments:ClaimAssessment[]}exportfunctionsummarizeBoard(claims:Claim[],evidence:Evidence[],sources:Source[]):BoardSummary{constassessmentsclaims.map((claim:Claim)assessClaim(claim,evidence,sources))constrawassessments.reduce((sum:number,item:ClaimAssessment){if(item.statussupported)returnsum100if(item.statusinsufficient)returnsum55if(item.statusdisputed)returnsum25returnsum40},0)constscoreassessments.length0?0:Math.round(raw/assessments.length)constpendingClaimsassessments.filter((item:ClaimAssessment)item.status!supported).lengthreturn{score,independentSources:uniqueOrigins(sources).length,pendingClaims,assessments}}页面上的“可信指数 82”“独立来源 7”“待核事实 3”就可以从同一份BoardSummary读取。点击待核数量时列表过滤到status ! supported不用另外维护一套待办数组。晚到证据不覆盖人工结论证据抓取可能异步完成。自动评估结果到达时如果用户已经人工标记陈述需要保留人工版本。模型可以增加decisionSource和修订号。exportinterfaceClaimDecision{claimId:stringstatus:ClaimStatus decisionSource:automatic|manualrevision:number}exportfunctionapplyAutomaticDecision(current:ClaimDecision,next:ClaimDecision):ClaimDecision{if(current.decisionSourcemanual){returncurrent}returnnext.revisioncurrent.revision?next:current}报告页可以继续使用环形综合评分但“值得关注”区域应由争议项和待核项生成而不是固定文案。当前项目使用本地演示数据不会自动判断现实新闻真伪。后续接入抓取或检索服务时外部能力只负责产生来源与证据来源归并、陈述状态、人工覆盖和页面选择仍留在本地业务层。即使一下子导入几十个链接看板统计的也会是证据链而不是链接数量。