- TypeScript 86.2%
- HTML 13.8%
| data | ||
| src | ||
| test | ||
| .gitignore | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| server.ts | ||
| tsconfig.json | ||
EVA:多评价器在线反馈实验
运行:
npm start
浏览器打开 http://127.0.0.1:4173。如端口被占用,可设置 PORT,例如:$env:PORT='4174'; npm start。
数据文件
data/cases.json:200 条案例库。每条含标题、评论正文、类别与初始参考分数;其中 100 条带uci-sms-*ID 的样本来自公开语料。data/feedback.json:按 case ID 保存当前有效的人工反馈;再次点击同一个 case 时覆盖旧记录。data/evaluation-cases.json:不由页面加载、也不参与 profile 学习的 32 条冻结评测样本;含 20 条与训练文本不重复的 UCI holdout,以及 12 条人工编写的边界样本。data/provenance.json:外部语料的 URL、许可、获取日期、原始文件 SHA-256、行号范围、抽样与脱敏约定。
代码边界
src/index.html:页面源码。src/app.ts:页面状态、渲染与案例/反馈 API 调用。src/core.ts:领域无关的 evaluator 执行、贡献折扣、聚合与反馈学习。src/evaluators/:独立的 spam 应用 evaluator;当前输入模型为title与content,可替换成 ASCII 比例、内容质量或其他目标领域的实现。test/:核心行为测试与 80/20 训练/验证实验;每次测试都从默认 profile 开始,不持久化实验 profile。
服务加载 case 时,会以该 case 最近一次人工反馈的 correctedScore 覆盖其初始参考分数;所以后续实验会直接使用积累后的人工判断。所有 evaluator 输出都在浏览器会话中根据 content 重新计算,随机评价器也不会污染案例源文件。
核心算法原理
flowchart LR
input[领域输入对象<br/>title、content]
subgraph application[应用层:可替换的评价器]
spam[Spam 指标<br/>语种、链接、关键词、格式、推广]
ascii[ASCII 比例等<br/>一般内容特征]
inverse[方向相反的指标]
noise[随机噪声指标]
end
run[runEvaluators<br/>逐个执行]
evaluations[评价结果集合<br/>score + confidence]
profiles[评价器元数据<br/>weight、reliability、alignment、身份保障]
aggregate[aggregate<br/>校准分数、计算新颖度并聚合]
result[聚合结果<br/>score、evidence、agreement、contributions]
human[人工反馈<br/>correctedScore + confidence]
store[(feedback.json<br/>每个 case 仅保留当前反馈)]
learn[applyFeedback<br/>按信心学习可靠度与方向]
input --> spam
input --> ascii
input --> inverse
input --> noise
spam --> run
ascii --> run
inverse --> run
noise --> run
run --> evaluations
evaluations --> aggregate
profiles --> aggregate
aggregate --> result
result --> human
human --> store
human --> learn
evaluations --> learn
profiles --> learn
learn --> profiles
核心只处理通用的 score 与 confidence,不认识 spam、ASCII 或内容质量等业务概念。confidence 是评价器对本次判断投入的信心:为 0 时退出本次评价;越高时,对聚合的影响和反馈后的 profile 变化都越大。
每个 profile 的 weight 与 reliability 都由人工反馈学习,但职责不同:weight 是长期实际影响力,reliability 是历史表现的浓缩,并决定 weight 的更新速度。历史可靠度越高,weight 改变越慢,但不会冻结。alignment 校准评分方向:正值表示同向,负值表示稳定的反向指标。有效权重为:
weight × confidence × |alignment| × novelty
novelty 只根据当前 case 的全部结果计算,不保存原始评价历史,也不要求人工给评价器静态分组。每个稳定 evaluatorId 在一批中只能提交一次结果;身份保障较低且本次给出相似校准分数的评价器,会因冗余而降低有效影响力。人工反馈后,每个评价器先按自身评分和本次 confidence 更新可靠度与权重;高可靠度会让 weight 上升更快、下降更慢。weight 的正向奖励按身份保障与边际贡献混合折扣:内部或已认证来源保留大部分奖励,低保障且低贡献的外部来源则被显著折扣。高信心错误不按人数稀释惩罚。
链接评价器只在检测到链接时给出非零信心;格式异常与推广意图评价器在没有对应信号时同样弃权。中文、英文、越南文评价器按语种分别输出,未覆盖的语种不会强行给高信心评分。
公开语料与规则依据
uci-sms-001 至 uci-sms-100 来自 UCI SMS Spam Collection(Almeida 与 Hidalgo,DOI: 10.24432/C5CC84,CC BY 4.0)。该集是短信而不是评论,因此只用于扩充英文真实文本、号码、短码、行动指令与正常口语的覆盖;不能把它的离线分数外推为本站评论的生产指标。导入时按语料原始标签设置 0.05 或 0.95,每条均保留 UCI 行号;连续六位以上的号码会替换为 [number]。短信没有伪造标题,title 保持空字符串,因此输入给评价器的仍是原始短信正文。选择 50 条 spam(链接、中奖/奖品、短信/拨号、紧迫性四类各先抽取,再补足不同文本)与 50 条 ham,并交错放入案例库,避免在线回放连续面对同一标签。
评价器没有把第三方声誉库或网络查询塞进核心聚合层。链接实现只判断本地可解释的结构信号:短链、IP 主机、Punycode、异常端口/用户信息、深层域名、百分号编码与重定向参数。这与 SpamAssassin 的 URI 解析接口 和其 短链解码插件 的边界一致:若生产环境需要跟随跳转或查域名黑名单,应当另写一个可超时、可审计的 evaluator 包装器,而不是修改 core.ts。
格式异常评价器会识别不可见字符、双向控制符、数值 HTML 实体、拉丁字母和常见希腊/西里尔同形字混用,以及少量被插入标点的风险词。它只是轻量近似实现,并不声称完整实现 Unicode UTS #39 的 skeleton/confusable 数据表;如果生产需求是标识符级别的同形字判定,应使用该规范的完整、版本化数据。
新增的“账号诱导”评价器要求同时出现账号/身份凭据主题与交付动作(链接、点击、回复或拨打),因而普通的“如何重置密码”讨论会弃权;紧迫性只在这个组合成立后加强分数和本次信心。
聚合结果不把支持度伪装成概率置信度,而是分别返回:score(聚合分数)、evidence(有效投入总量)和 agreement(结果一致程度)。页面显示后两者,应用层可按业务需要决定如何解释或展示它们。
反馈使用显式的 reliabilityLearningRate、weightLearningRate 与 alignmentLearningRate;没有基于样本量的自动降速。旧评价器在高信心作恶时,仍会快速失去可靠度与权重。页面在人工反馈成功写入前不会变更 profile 或进入下一条;保存失败会保留当前案例并提示重试。覆盖已有反馈也不会虚增反馈计数。
npm test 会用 cases.json 学习临时 profile,并仅在 evaluation-cases.json 的冻结、文本不重复样本上报告 MAE、MSE、ROC-AUC、平均精确率、阈值 precision/recall,以及语言和风险类型分桶。MSE 是当前反馈规则的优化目标,因此它下降不表示 AUC 或召回率必然同步提高;测试故意把这些指标全部输出,以暴露而不是掩盖这种取舍。所有实验 profile 都只存在于测试进程中。