关于 classifier.dev
classifier.dev 是零样本文本分类服务,输入文本与自定义标签,返回标签及校准后的置信度,无需 API key。它面向需要快速批量分类的开发者与 Agent,提供 HTTP 接口与命令行工具 classify。
主要功能
- 01零样本分类,标签由用户自定义
- 02每个结果附带校准后的置信度
- 03单次请求最多处理 1,000 条文本
- 04支持多标签分类
- 05提供 curl 与 classify 命令行接口
适用场景
- 01对用户反馈按类别(如 bug、feature)分类
- 02过滤垃圾信息等文本内容
- 03在脚本或 Agent 中批量调用文本分类
MCP 相关
输入中未提及 MCP。
配置
远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。
https://classifier.dev/mcpclaude mcp add --transport http dev-classifier-classifier https://classifier.dev/mcp{"mcpServers":{"dev-classifier-classifier":{"type":"http","url":"https://classifier.dev/mcp"}}}在 Cursor 中打开{"servers":{"dev-classifier-classifier":{"type":"http","url":"https://classifier.dev/mcp"}}}在 VS Code 中打开{"mcpServers":{"dev-classifier-classifier":{"type":"http","url":"https://classifier.dev/mcp"}}}{"mcpServers":{"dev-classifier-classifier":{"serverUrl":"https://classifier.dev/mcp"}}}命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。
工具
5| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| url | string | 否 | 使用一个公开 URL 抓取内容,而不是使用 inputs/items。需要工作区有可用余额。Context.dev 每次计费尝试收费 $0.0022,另加分类费用;长文章需要 Fast。错误信息会披露已产生的费用。不会自动重试抓取。 |
| tier | enum | 否 | fast(默认)或 smart;后者会将置信度低于 0.7 的答案交由推理模型重新判定(速度较慢,且仅支持单标签)。与 Laya 处理通道相互独立。fast | smart |
| model | enum | 否 | 默认使用 Jev。默认或显式指定 jev 时,输入超过 32,000 个字符将使用付费的 Fast-only 长上下文:总计最多 250,000 个原始 cl100k_base 上下文 token、20 个文档、32 次判定和 1 MB 请求正文。需要付费工作区余额或有效的付费订阅,不可使用注册赠金。每 100 万个原始上下文 token 收费 $0.084,跨所有输入仅计一次,与维度数量无关。最终的 Jev 会使用所选证据;符合条件的分块可能被省略,并在 usage.long_context 中披露。没有证据时会返回 422 long_context_no_evidence,且不收费。显式指定 'chunklaya' 会保留旧版的选择加入行为(每个输入最多 4,000,000 个字符、20 个输入,并受请求正文大小限制)。'laya'(512-token 上下文)和 'kev'(8K 上下文)仍为实验性选项。jev | laya | kev | chunklaya |
| inputs | array | 否 | 要分类的文本,数量为 1 至 1,000 条。结果按相同顺序返回。 |
| labels | array | 是 | 2 至 100 个类别名称。描述性名称的分类效果更好:"urgent bug" 比 "p0" 更好。若“以上皆非”确实是可能结果,请添加类似 "none of these" 的标签。 |
| include | array | 否 | 与 url 一起使用:返回 article.markdown 和/或 article.html,不额外收取抓取费用。省略则返回精简输出。 |
| processing | enum | 否 | 可选。若省略 model,则隐含使用 Laya;显式指定 Jev 时无效。使用 Laya 时,省略此项可根据情况自动为单次判定选择 fast,或为批次选择 bulk。显式指定 fast 时仅接受单次判定。共享容量限制可能导致返回 429。fast | bulk |
| share_data | boolean | 否 | 默认情况下,同步分类请求中的文本、标签、指令和模型结果会保留在 Cloudflare 私有存储中,用于模型训练和运营人员审核。共享请求的每分钟及每日分类配额均为双倍。设置 share_data: false 或 X-Classifier-Share-Data: false 可选择退出并使用标准限额。仅共享你有权提供的数据;请勿包含机密或个人信息。尽力进行内容脱敏。计费、支出上限和输入大小限制仍然适用。 |
| instructions | string | 否 | 可选的附加标准,例如 "judge only the service, ignore the food"。 |
详细介绍
classifier.dev
零样本文本分类。输入纯文本,输出标签和经过校准的置信度。无需密钥,无需注册。每个请求最多可处理一千条文本。
curl https://classifier.dev/spam,not+spam/Win+a+free+iPhone
spam
curl "https://classifier.dev/?labels=spam,not+spam&text=Win+a+free+iPhone" # 同一调用,查询参数形式
spam
单个 Cloudflare Worker。没有数据库,没有框架,除 esbuild 外无需构建步骤。
CLI
npm i -g classifier-dev
classify bug,feature,praise < feedback.txt
cli/ 是独立的 npm 包(classifier-dev,二进制文件为 classify):单个无依赖的 Node 文件,针对模拟 API 运行测试(npm test),使用 semver 并有自己的 CHANGELOG,通过 npm run release patch|minor|major 发布;该命令会创建 cli-v<version> 标签,并由 .github/workflows/publish-cli.yml 负责发布(需要设置 NPM_TOKEN 仓库密钥)。它与 API 的交互方式和 curl 完全相同。
目录结构
src/index.ts 路由、验证、层级、LLM 回退链、分析
src/query.ts GET 查询形式,使用 nuqs 读写;错误信息会建议使用的 URL
src/jev.ts TypeSafe 的 Jev:将输入打包为请求,并读取概率
src/limiter.ts Durable Object:按 IP 限流
src/report.ts 摘要 — Analytics Engine SQL -> Resend,标记模型回退
src/alerts.ts 每 15 分钟运行一次;仅在出现问题时发送邮件
src/feedback.ts Agent 反馈,feedback.now 协议 -> 电子邮件
src/privacy.ts 带密钥的假名:保留的信息不会指向调用者
src/cost.ts 每个请求的上游支出,来自各提供商自己的记账数据
src/docs.ts 网站(GET / 和 GET /benchmark),纯文本
src/home.ts 同样的两份文档,仅为浏览器渲染
src/ui.ts 统一外观:终端中的 Markdown
cli/ `classify` 命令,以 classifier-dev 为名发布到 npm
eval/ 基准测试;引用数据前请先阅读 eval/README.md
finish-dns.sh 一次性 DNS 配置,见下文
wrangler.example.toml Worker 配置,不含特定账户的 ID
网站
curl classifier.dev 会输出纯文本,一如既往。浏览器会发送 Accept: text/html 并获取同一份渲染后的文档 — 包含标题、括号中的链接和复制按钮 — 由 src/home.ts 提供。内容不会重复:页面会在收到请求时根据 DOCS 和 BENCHMARK 生成,因此文本保持统一,两个版本不会出现偏差。可手动使用 ?format=text 选择纯文本,两种响应都会携带 Vary: accept。
Agent 反馈
实现了 feedback.now 协议(schema 1.1),任何支持该协议的 Agent 都可以直接报告问题,无需说明操作方式:
GET /.well-known/agent-feedback.json 此主机接受的内容
GET /api/v1/policy 类别、严重程度、限制
POST /api/v1/feedback 完整的结构化报告
POST /api/v1/observations 更简短的信号
POST /api/v1/feedback/{id}/attachments 稍后补充更多证据
GET /api/v1/receipts/{id} 是否已收到,以及内容是否有效
已接受的提交会发送到 REPORT_TO 指定的邮箱。报告会在 KV 中保留 90 天。同一 domain + surface + category + title 的重复报告会被存储并确认为重复项,但不会再次发送邮件,因此循环运行的单个 Agent 无法把收件箱塞满;每个 IP 每小时限额为 100,剩余限额会在每张回执中返回。
推荐使用 signal.category: "testimonial"。这类推荐必须包含 reporter.agent_type 和 reporter.agent_description,确保推荐附带足够的背景信息,说明受益的 Agent 类型及其工作方式。
quality_score 是根据报告完整度计算的确定性函数 — Agent 可以查看规则,下次写出更好的报告。这里不会调用分类器或 Analytics Engine:这里接收的是报告这些服务故障的消息,因此即使它们无法工作,这里也必须正常运行。
部署
合并到 main 即会触发部署。.github/workflows/deploy.yml 会进行类型检查、运行 Worker 和 CLI 测试、执行 wrangler deploy,然后请求线上服务的 /v1/health 和一次分类,因此,如果上传的 Worker 有问题,部署会在 CI 中失败,而不是等到有人在终端中发现。
手动尝试尚未合并的改动:
cp wrangler.example.toml wrangler.toml # 只需执行一次,然后填入你自己的 ID
npx wrangler deploy
wrangler.toml 已加入 gitignore,其中保存了特定于某个 Cloudflare 账户的两个值:account_id,以及通过 npx wrangler kv namespace create STATS 返回的 STATS KV 命名空间 ID。已纳入版本控制的 wrangler.example.toml 包含其他所有内容——cron、绑定和迁移——因此部署配置保存在仓库中,只有标识符例外。
CI 没有 wrangler.toml,因此 .github/render-wrangler.mjs 会根据示例文件和三个仓库密钥生成一个文件。这样,示例文件就是实际部署配置的来源,而不是它的副本:如果只修改 wrangler.toml 中的绑定,CI 仍会部署旧配置。
部署所需的仓库密钥:
CLOUDFLARE_API_TOKEN dash.cloudflare.com > My Profile > API Tokens >
Create Token > "Edit Cloudflare Workers"
CLOUDFLARE_ACCOUNT_ID wrangler.toml 中的 account_id
STATS_KV_ID wrangler.toml 中的 STATS 命名空间 ID
REPORT_TO 每日摘要的接收地址
通过 wrangler secret put 设置的密钥保存在 Worker 上,不会打包进脚本中,因此部署不会改动它们,CI 也无需知道这些密钥。
Worker 读取的密钥:TYPESAFE_API_KEY、AI_GATEWAY_API_KEY(Vercel 的 AI Gateway,每月提供免费额度供 Jev 使用;设置后会优先调用它,遇到拒绝请求时再由 TypeSafe 处理)、OPENROUTER_API_KEY、CONTEXT_API_KEY(context.dev,用于聊天中的网页搜索和页面读取)、RESEND_API_KEY、CF_ANALYTICS_TOKEN、REPORT_KEY、PRIVACY_SALT。使用 npx wrangler secret put NAME 添加密钥;这些密钥都不会从仓库中读取。其余密钥列在 src/index.ts 的 Env 接口中。
比较密钥时会使用 secretEquals(src/secrets.ts),绝不使用 ===:普通比较会在遇到第一个错误字节时返回,并泄露猜测正确了多少。
模型
两个层级都基于 TypeSafe's Jev 作答。它是一种决策模型,而非语言模型:接收状态和带类型的问题,并在约 150ms 内为每个选项返回校准后的概率。这种设计让 API 能做到 LLM 版本无法做到的三件事。
每次请求处理一千条输入。 状态是一个由 {id, text} 组成的数组,每条输入都有自己的问题,因此整个批次只需调用一次上游服务。文档中规定的限制是每次请求 64k 个 token;jev.ts 会按保守的预算打包,并让生成的请求一次并行运行八个。实测:端到端分类 400 条新闻标题耗时 650ms;打包 100 条输入得到的评分,与逐条发送相同。
有意义的置信度。 在 400 条六分类情绪数据中,置信度 >= 0.9 的答案有 82% 正确,而置信度低于 0.5 的答案有 29% 正确。此前模型的 logprob“置信度”将 87% 的新闻条目评为高于 0.9,其中只有 68% 答对。因此,tier: "smart" 现在的含义是:对于快速推理模型给出的单标签答案,若置信度低于 0.7,就重新提问并替换答案,同时标记 escalated: true。其他一切保持不变。模型的选择很重要:在 Jev 不确定的那些条目上,deepseek-v4-flash、qwen3.7-flash 和 mercury-2.5 的表现都不如 Jev;gemini-3.8-flash 将新闻主题准确率从 87.5% 提升到 90.0%,将情绪准确率从 61.8% 提升到 63.7%,因此采用了这条链路。前沿模型(claude-fable-5.1)的准确率为 72.3% / 90.7%,价格约为 3 倍;如果觉得这笔权衡值得,相关数据见 /benchmark。
一次完成多标签分类。 每个标签对应一个是/否问题,返回分数 >= 0.7 的标签,按最可能到最不可能排序,并附上完整的分数映射。在七案例数据集上的 F1 为 0.887,而它取代的“扫描并验证”LLM 级联为 0.799;耗时 230ms,而非 1.5s。使用推理模型重新判断候选结果反而降低了表现(且耗时 23s),因此多标签分类不受层级设置影响。
index.ts 中的 LLM 链路仍作为 TypeSafe 不可用时的回退方案;由于每条输入都需要单独调用一次,因此限制为二十条输入。摘要会报告实际作答的模型,并标记 FALLBACK;此前的主模型被上游下架后,其备用模型在数周内持续提供 F1 为 0.546 的结果,却没有任何提示。
更新列表
表单和 POST /subscribe 会通过 Resend 发送确认邮件。
API 返回 202 {"ok":true,"status":"pending_confirmation"}。在将邮件中的令牌提交到
POST /subscribe/confirm,作为 {"token":"..."}(或通过确认表单提交)之前,
不会向 newsletter 数据库写入任何内容。GET 只会呈现表单,因此邮件扫描器无法确认订阅。
令牌使用 NEWSLETTER_CONFIRMATION_SECRET 签名,有效期不超过 24 小时,
注册时绝不会返回令牌。Resend 的幂等键会在每个整点时段内对来自同一邮箱的重复请求进行去重。现有的每 IP 限制也继续适用。轮换签名密钥会使尚未过期的链接失效。
部署前请使用 npm run db:migrate 应用 migrations/postgres/。订阅者表与应用数据库共用。
现有未确认的订阅者仍保持未确认状态;不要回填 confirmed_at,也不要在他们确认前向其发送更新。确认操作或重放旧令牌都不会清除现有的退订状态。
必需的 Worker 密钥:DATABASE_URL、NEWSLETTER_RESEND_API_KEY,以及至少 32 字节的随机 NEWSLETTER_CONFIRMATION_SECRET。wrangler.example.toml 中的 NEWSLETTER_FROM 必须使用已验证的 Resend 发件域名。REPORT_TO 是回复地址,仅会在新记录确认时收到通知。
订阅者表保存邮箱、来源、注册/确认/退订日期、勾选的路线图项目(wants text[],存储 ROADMAP 键;勾选项会随确认令牌传递,并在确认时写入)、选择更快推理时请求的延迟,以及内部 ID。表中不保存 IP、请求 ID 或分类流量。待确认的注册不会被存储。不得记录令牌和邮件服务提供商的错误响应正文。
migrations/postgres/0007_newsletter.sql 定义了该表;重复确认仅在勾选了项目时才会替换勾选项,且绝不会清除退订状态或更改首次确认日期。
发送更新时,只读取已确认且仍在订阅的收件人:
SELECT email, wants, desired_latency_ms FROM subscriber
WHERE confirmed_at IS NOT NULL AND unsubscribed_at IS NULL;
人们最先请求的内容,用于安排工作顺序:
SELECT unnest(wants) AS item, count(*) FROM subscriber
WHERE unsubscribed_at IS NULL GROUP BY 1 ORDER BY 2 DESC;
Worker 使用应用的 DATABASE_URL 存储 newsletter 和账户数据。
订阅者记录没有账户外键或 API 流量标识;共用存储不会让账户持有人自动订阅,也不会更改现有的同意状态。旧 newsletter 项目作为只读迁移存档保留。经验证的切换和恢复流程请参阅
docs/postgres-setup.md。
文案由一个常量提供——src/newsletter.ts 中的 ROADMAP。curl classifier.dev 输出的纯文本、渲染页面上的表单和 index.md 都读取该常量,因此路线图变更会同时影响这三处,或都不受影响。
Jev 长上下文
默认 Jev 和显式设置 model: "jev" 的输入如果超过 32,000 个字符,则会使用 Chonkie RecursiveChunker,将内容切分为 600 个 token 的 cl100k_base 分块;随后并行调用 Jev,筛查相关或不确定的证据(包括相反证据和例外情况);最后按来源顺序,将所有符合条件的分块交由 Jev 处理。最终证据预算为 20,000 个 cl100k_base token,并会进行保守的提供商上下文检查。预算用尽时,符合条件的分块可能会被省略;usage.long_context 会报告筛选数量、token 数、调用次数和耗时。
这并不保证最终处理会阅读完整文档,也不保证结果始终准确。
请使用由付费余额或有效付费订阅支持的 Fast 工作区密钥;匿名访问和注册赠金不符合条件。同步限制:
所有输入的原始上下文 token 总数不超过 250,000 个,文档不超过 20 份,判定不超过 32 项,正文不超过 1 MB。零售价为每百万个原始 cl100k_base 上下文 token 收取 $0.084;无论维度或实际推理用量如何,所有输入只计费一次。
连续的空白字符或非空白字符序列长度上限为 8,192 个 UTF-16 代码单元。超长序列会在文档 token 化或分块之前返回 400 long_context_input,以限制病态输入导致的分词器工作量。
没有符合条件的证据时,会返回 422 long_context_no_evidence,且不收费。
显式设置 model: "chunklaya" 会保留其独立的旧版选择启用行为。
使用已充值的工作区密钥,通过 POST /v1/classify 发送一份完整文档,最多可包含 1,000 万个输入 token(100 MB)。使用常规 JSON 输入和标签,或发送 text/plain,并通过 labels 查询参数指定标签。大文件上传会返回 202 和 status_url;较小文档也支持 Prefer: respond-async。服务端会自动拆分、筛查、重试并完成处理。
仓库 CLI 可通过 node cli/classify.js a,b --document document.txt --json 处理上传和轮询。
完整文档的精确 token 数用于设置预留金额和 $0.084/M 费用。排队期间,源文本会以私密方式存储,并在筛查过程中逐步删除。最终由 Jev 阅读的已选证据不超过 20,000 个 token。任务完成、失败、取消或满 24 小时后,剩余源文本和证据都会被删除;失败或取消的任务会退款。结果在过期前仍可获取。
分析
每个请求都会写入一条 Analytics Engine 数据点(层级、标签集指纹、国家/地区、状态、数量、延迟)。分析数据中不会写入请求文本。
长上下文聚合数据也会写入 classifier_long_context_events,其中包含上下文/文档总数、分块筛查/选中/省略数量、各阶段输入 token 数(包括数量未知标记)、已回答的调用次数和各阶段耗时。账户事件会追加相应字段;其有序列契约见 src/server/analytics/schema.ts。
文档数和原始上下文 token 数只计一次;分块和阶段计数器会在不同维度的处理过程中累加。专用数据集中不会写入文档文本或调用方标识符。
每个请求也会记录我们的成本:OpenRouter 在收到询问时会返回调用费用;Jev 则按其报告的输入 token 数,并按照 eval/bench.py 为基准测试定价的费率计费。支出会累计在每请求计量器(src/cost.ts)中,并写入 double3。该列在上线后才添加,因此在该次部署之前的数据中显示为 0。
cron 会在 15:00 UTC 查询该数据,并通过 Resend 发送摘要。
告警
一个独立的 cron 每十五分钟运行一次,除非触发告警,否则不会发出通知。它只监控关联了操作的条件:Jev 密钥被拒绝、Jev 无响应(备用链会静默接手,这种情况确实发生过)、5xx 比率、智能层级升级失败(耗尽的 OPENROUTER_API_KEY 会出现这种情况)、平均延迟、相较于过去一天的支出激增,以及流量完全停止。4xx 会被忽略——那是扫描器在探测 /wp-admin,不属于故障。
Jev 额度。 TypeSafe 不提供余额端点——它的 API 只有 /v1/systemone 和 /v1/models,没有其他端点——因此没有可供监控的余额数字。作为替代,检查程序每十五分钟使用密钥调用 /v1/models,并报告 TypeSafe 返回的内容:如果该端点返回 401、402 或 403,就表示额度用尽、密钥已撤销或密钥错误,并会发出严重告警,引用 TypeSafe 自身的消息,而不是猜测每种状态码代表什么。由于它会主动探测,而不是等待流量到来,因此即使主机处于空闲状态,也能在任何调用者遇到备用链之前触发;即使 Analytics Engine 宕机,它也会继续运行。
每种情况开始时发送一封邮件,持续期间每六小时再发送一次,解除时再发送一次;状态存储在 KV 的 alert: 下。阈值位于 src/alerts.ts 顶部的 T 对象中。
curl -H "authorization: Bearer $REPORT_KEY" https://classifier.dev/alerts
curl -H "authorization: Bearer $REPORT_KEY" "https://classifier.dev/alerts?demo=1&send=1"
第一条命令会预览,不发送邮件,也不更改状态;第二条命令会通过实际流程发送一封示例邮件,以验证投递正常。
随时预览摘要,不发送邮件:
curl -H "authorization: Bearer $REPORT_KEY" https://classifier.dev/report
Jev 提供商的尝试记录会通过 JEV_AE 单独存储在 classifier_jev_attempts 中,包括已恢复的故障、重试和网关冷却期间的跳过记录。报告会列出每个提供商的状态、原因、次数和平均延迟;即使通知被抑制,/alerts 仍会显示当前事件。现有的 15 分钟告警检查会在任一提供商至少有三次尝试失败,且失败率超过 5% 时发出警告。次数会考虑 Analytics Engine 的采样。不会存储任何输入文本、调用者标识符或上游消息。成功的简单分类器和多标签分类器名称会在单独的聚合 KV 记录中保留 90 天,其中不含调用者或源文本字段。其带密钥的指纹也会出现在每次请求的分析数据中,使运维人员能够在这些假名化记录中查询标签名称。
wrangler.example.toml 中的 AI_GATEWAY_DISABLED = "true" 会让生产环境直接使用 TypeSafe;这是因为网关在 9 月 19 日反复返回 429。网关密钥会保留。若要恢复优先使用网关的路由,请确认网关容量正常,在示例配置和本地配置中将此变量改为 "false",然后部署。重新启用后,请检查提供商尝试记录和实时 API 测试。
请求头是唯一的访问入口。查询字符串会进入访问日志、浏览器历史记录,以及之后点击的任何链接的 Referer 请求头中,因此已移除 ?key=。添加 ?send=1 才会真正发送邮件。
Cloudflare 的 Analytics Engine SQL 是 ClickHouse 的精简子集——不支持 uniq()、SELECT DISTINCT,而单独使用 SELECT col ... GROUP BY col 也会被拒绝。因此,去重计数会使用 SELECT col, count() ... GROUP BY col,并对返回的行计数。每条查询都会单独执行,因此单条查询失败不会导致整份报告空白。
隐私
该数据集中的两列曾用于标识调用方:IP 地址,以及合并并转换为小写的标签集。现在这两列都经过密钥哈希处理(src/privacy.ts),因此统计数据仍能计算不同调用方和不同分类器的数量,但无法反推出地址或某人的措辞。调用方哈希还会使用 UTC 日期,因此明天就会变成不同的值——这就是为什么 7d 或 30d 内的独立调用方数量实际上统计的是调用方日数。
设置一次密钥,并像对待其他密钥一样将其保密:
npx wrangler secret put PRIVACY_SALT # 32 random bytes
轮换密钥会重新编号所有指纹,因此轮换前后的独立计数会重复计算。密钥会依次回退到 ADMIN_SIGNING_KEY、REPORT_KEY,然后是每个 isolate 随机生成的值,因为对 IPv4 地址或常见标签集进行无密钥哈希,几秒钟内就能反推出原值。
评估
npm run bench # 多标签,7 个用例:jev 与任意 OpenRouter 模型
npm run single -- --dataset emotion --backend jev
npm run single -- --dataset ag_news --backend openrouter:qwen/qwen3.7-flash
python3 eval/escalate.py --dataset emotion # 智能层带来的收益
single.py 首次运行时会下载 AG News 和 dair-ai/emotion 的测试行,并将原始结果缓存到 eval/data/results/,以便 escalate.py 合并后端结果,而不必再次付费。eval/README.md 列出了注意事项。
速率限制
按 Durable Object 中的 IP 地址限流,按分类次数计数:fast 为每分钟 3,000 次、每天 20,000 次;smart 为每分钟 200 次、每天 2,000 次。
我们尝试并否决了另外两种方案:
- Cloudflare 的原生
ratelimit绑定可以正常注册,但计数从未递减(对 60 次的限制发起 70 次调用,全部返回success: true)。 - KV 会在边缘缓存且最终一致,因此这一秒写入的计数器对下一次读取不可见——每个请求都看到
remaining: 59。
Durable Object 是单线程且强一致的,这正是计数器所需要的。已在原本每分钟 60 次的限制下验证:75 个请求 -> 60 个返回 200,15 个返回 429。
DNS
域名在 Porkbun 注册;Worker 部署在 Cloudflare 上。Cloudflare Workers 自定义域名要求区域托管在 Cloudflare,而这里的两个 API 令牌都没有 zone.create 权限,因此其中一步需要手动完成:
- https://dash.cloudflare.com -> 添加域名 ->
classifier.dev-> Free 套餐 ./finish-dns.sh— 读取分配的名称服务器,通过 Porkbun API 将 Porkbun 指向这些服务器,并将 Worker 绑定到根域名和www。
Agent 技能
npx skills add https://classifier.dev
该技能通过 RFC 8615 well-known 发现机制从此域名提供,因此无需经由代码仓库:
src/SKILL.md 技能文件,以 Text 模块打包
GET /skill.md 资源文件
GET /.well-known/agent-skills/index.json 发现入口,schema v0.2.0
索引必须包含资源文件的 sha256 值,而索引与文件内容不一致会导致技能无法安装。为了避免提交的摘要在之后编辑时被悄悄作废,src/skill.ts 会在每个 isolate 中对实际提供的字节计算一次哈希。因此,编辑 SKILL.md 就够了,无需更新其他内容。
该技能讲解了 API 宣传中容易忽略的一点:你本身已经是模型,可以对所有可见内容进行分类,因此调用该工具的理由不是能力,而是上下文——无需阅读 40 条搜索结果,就能将其筛选到 6 条。
测试中碰到两个问题,因此文档特别说明了它们。Cloudflare 会在请求到达 Worker 之前拦截 Python 标准库 urllib 的 User-Agent 并返回 403,因此示例会显式设置 User-Agent。此外,应告诉筛选器“拿不准时就保留”:在一个包含 10 条片段的研究筛选测试中,这让保留的有效信息从 4/6 提升到 6/6,且没有增加噪声;添加第三个“可能相关”标签则毫无作用。
发现入口
GET /openapi.json OpenAPI 3.1,也可通过 /.well-known/openapi.json 访问
GET /llms.txt 面向 Agent 的简短索引,由 robots.txt 链接
GET /benchmark 准确率、成本和延迟的实测数据
GET / 的第三段中链接到了这两者,因此 Agent 阅读着陆页时就能立即找到它们。
已知问题:Cloudflare 托管的 robots.txt
启用该区域后,Cloudflare AI Crawl Control 会在 /robots.txt 前置一个托管规则,禁止 GPTBot、ClaudeBot、CCBot、Google-Extended、Bytespider、Amazonbot 和 meta-externalagent 抓取。Worker 自身的 robots.txt 会附加在其后,无法覆盖该规则。
这会阻止用于训练的爬虫,而不会阻止运行时 API 使用者——任何 Agent 仍然可以调用 API。但这确实会让文档无法进入未来模型的训练数据,不利于被发现。更改 dash.cloudflare.com -> classifier.dev -> AI Crawl Control -> Security 中的开关后,设置并未保留,因此可能需要在套餐级别进行更改或联系支持团队。
运营方 Agent 访问权限
对于运营方自有的大批量 Agent 任务,请设置专用的 AGENT_API_KEY Worker 密钥,并通过 Authorization: Bearer ... 发送。分类配额不设上限,但推理使用独立的运营方每日 $2 额度(OPERATOR_DAILY_USD),由多个 IP 共享,并采用与免费使用相同的请求和并发限制。它既不消耗也不会扩大匿名额度,也不能替代 ENTERPRISE_API_KEY。CLI 可通过 CLASSIFY_API_KEY 或 CLASSIFIER_API_KEY 接受该密钥。此密钥不能用于访问私有报告或管理功能。请将其保存在被忽略的密钥文件中;切勿交给公共客户端。未进行身份验证的流量仍受匿名配额限制。
对于已安排大批量配额的预付费工作区密钥,请将 API_KEY_RATE_LIMIT_MULTIPLIERS Worker 密钥设置为一个 JSON 对象,其中将每个密钥的 SHA-256 十六进制摘要映射到一个整数倍数(1–1,000)。覆盖设置只会提高该密钥的准入配额;账户计数器、余额扣费、模型容量限制和其他密钥均保持不变。移除对应条目即可恢复套餐配额。
查找分类代码
领域术语定义见 CONTEXT.md。
| 模块 | 职责 |
|---|---|
src/index.ts | HTTP 验证、配额、模型选择、智能升级、回退和响应格式化。 |
src/jev.ts | Jev 问题与答案、共享批次预算和恢复机制、网关/直连传输以及提供方验证。 |
src/dimensions.ts | 维度定义,以及输入–维度决策与 Jev 问题之间的双向映射。 |
普通分类和维度分类都使用相同的 Jev 批处理模块。 问题组是恢复机制会整体保留的最小请求单元: 普通分类中,一个输入的问题;维度分类中,一个决策。 批次准备会将共享输入文本只计算一次,检查两个提供方的预算,并在维度分类扣除配额前运行。执行过程会限制并发请求,并在问题组之间拆分超大批次。
在 src/jev.ts 中更改提供方预算和恢复机制;在 src/dimensions.ts 中维护维度含义。通过 jevClassify 和 Worker HTTP 接口测试提交的请求和返回的分类结果,不要依赖内部打包实现。
多维度
POST /v1/classify 也接受 items 和 dimensions:
{
"items": ["Checkout charges me twice"],
"dimensions": {
"team": ["billing", "identity", "platform"],
"urgency": {
"labels": ["immediate", "normal", "low"],
"instructions": "Active financial harm is immediate."
},
"kind": ["bug", "request", "question"]
}
}
每个 results[i].dimensions[name] 都包含自己的标签、置信度、分数、模型和延迟。Jev 会在条目与维度问题之间共享状态,同时兼顾两者的上下文限制。智能升级针对每个字段单独执行,并会清除原始分数;Jev 不可用时,仅对最多 20 个决策进行回退。API 最多接受 20 个维度和 1,000 个决策,每个决策都会计入配额。classify_dimensions MCP 工具使用相同路径。
分析数据新增了 blob9(单项/多项/多维度)、double6(成功处理的输入条目数)、double7(维度数)、double8(不确定或未评分的字段数)和 double9(由回退处理的字段数)。double1 统计成功决策数。维度配置使用键控指纹,不会逐字存储。管理面板会单独查询维度流量,包括失败和调用方天数。现有的告警 cron 会在一小时内维度请求中 5xx 错误达到 3 次或以上、且占维度请求的比例超过 10% 时发出告警;任何维度回退使用也会触发告警。
使用 Node 22.18+ 运行 npm run test:e2e,并连接真实生产 API;也可以将 CLASSIFIER_BASE_URL 设为预发布环境的源站。这些是使用 node:test 编写的具名 TypeScript 测试,会发起真实的 HTTP 请求并调用模型,不使用 fetch 或推理模拟。共享 IP 配额用尽时,可将 CLASSIFIER_API_KEY 设为已授权的密钥;该设置为可选项。测试套件会使用推理,并计入常规配额。
测试会检查 300 个决策的确切结果和排序、每个字段允许的标签与概率分布、真实的智能升级、提供方分数保留情况、别名、验证错误、MCP、OpenAPI 和旧版调用。
响应最初被视为 unknown,经过验证后才会转换为类型化矩阵。
智能测试要求确实发生升级;如果模型漂移导致所有测试样例都被判定为高置信度,测试会失败,而不会静默跳过推理提供方。
npm run typecheck 会检查 Worker 和 TypeScript 实时测试。部署 CI 会在发布后运行实时测试套件;npm test 仍保持离线运行。故障注入测试仍位于 test/dimensions.test.ts 和 test/dimensions-observability.test.ts。
可从 GitHub Actions 手动运行 live API tests 工作流(或运行 gh workflow run e2e.yml),在不部署 Worker 的情况下检查生产环境。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。