☰
pollinations 社区模型监控 Agent 单周期运行机制全解:从探针选择到官方模型告警
2026/10/14 2:56:24 网站建设 项目流程
  • AI 应用
  • 媒体生成
  • 后端
  • 前端

【免费下载链接】pollinations

Your Friendly Open-Source Gen-AI Platform

项目地址:https://gitcode.com/gh_mirrors/po/pollinations
点击查看免费下载

导读

本文以 operations/community-monitor/CYCLE.md 为核心,系统讲解 pollinations 平台中负责守护社区模型(community/owner/model端点)的无头(headless)编码 Agent——"社区模型监控机器人"(Discord 身份el405b)的**单个运行周期(one cycle)**的完整工作方式。该 Agent 部署在独立的 EC2 监控机上,由 systemd 驱动,每轮周期结束后 30 分钟启动全新进程,只做规则文件规定的事然后退出。读完本文,你将掌握:探针候选的挑选逻辑与四小时退避调度、文本/图像探针的协议级校验标准、社区模型"只看不写"的可靠性观测原则、官方模型与 legacy 桥的告警-only 策略、Tinybird 健康数据的查询口径,以及两条消息预算与 ASCII 面板的消息规范——并能在仓库中逐行印证这些规则背后的源码实现。

一、运行框架:systemd 驱动的"一次周期 = 一个全新进程"

监控机器人的运行哲学是"一次新鲜进程、一个周期、做完全部职责、持久化状态、然后退出"。它永远不会阻塞等待人工回答:两轮周期之间没有任何人盯着终端,一个工具授权弹窗或澄清问题会让循环停滞数小时而非数秒。遇到规则内已授权的判断(发到哪个频道、模型是否不稳定、消息如何措辞)就直接做出合理决定继续执行;遇到真正模糊且超出授权的事项,则向#dev-community-models频道发送一条简短短信并@thomash(<@304378879705874432>),然后继续完成本周期剩余职责,而不是空转等待。

这一生命周期由两个仓库内文件直接实现:

  • loop.sh:每轮周期执行一次。先cd /home/ubuntu/monitor并 source.env,然后以claude -p "$(cat CYCLE.md)"将完整的CYCLE.md作为提示词喂给一个新 Claude 进程,固定--model claude-opus-5-5 --effort medium、--no-session-persistence,只允许 Bash/Read/Write 与 discord 读写工具。输出被丢弃,仅向loop.log记录周期起止时间与退出码——不保留任何 Discord 消息文本。
  • community-monitor.service:systemd 单元。ExecStart=/home/ubuntu/monitor/loop.sh、Restart=always、RestartSec=1800(即上一进程退出 30 分钟后启动下一轮)、RuntimeMaxSec=2700(单轮最长 45 分钟)、ExecStartPre为update-from-repo.sh,保证每轮周期前先同步仓库main上的最新规则与运行时文件。

另外,healthcheck.sh 由 cron 每小时独立运行,把服务状态与state.json的"进度年龄"写入health-status.json供外部告警读取:只要服务不健康、状态文件缺失或超过 5400 秒(90 分钟)未更新,就判定stalled=true——它是服务存活的外部探针,本身不向 Discord 发消息。

二、周期输入:四个数据源

一个周期开始后,Agent 依次读取四类输入,其中前两类决定"查谁",后两类决定"怎么称呼人、记住什么"。

2.1 probe-results.json:选择性例行检查的产物

/home/ubuntu/monitor/probe-results.json是上一轮例行探针的输出。选择探针对象前,Agent 先读它并结合各频道的新报告。选择标准是只挑"有问题"的模型,绝不为了凑样本去探测健康忙碌的模型:

  • 近四小时没有合格的非探针流量;
  • 该窗口内最终成功率 ≤ 80%;
  • 存在未解决的用户上报问题;
  • 或目录健康样本 ≤ 80%。

所有规则都排除监控器自己的探针账户pSuZFfxdFpRIDq0MJKwvT1y4LZ7cyA9n(这个账户只从真实流量角度剔除,不影响目录健康样本——样本是包含探针的)。绝不选择 agent 或私有模型。

选定后,把规范化 ID 写入probe-candidates.json:

[{ "name": "community/owner/model", "category": "text" | "image", "operation"?: "generate" | "edit" }]

然后只运行一次node probe.mjs --models-file /home/ubuntu/monitor/probe-candidates.json;无需检查时写入[](脚本会产出空结果但不探测任何东西)。命令失败时不得复用旧结果;即使本轮没有探针运行或分析不可用,也要继续阅读/回复频道——"分析不可用"不是全面扫描的许可。

2.2 模型目录与健康数据:可靠性的唯一事实来源

第二个输入是公开目录https://gen.pollinations.ai/models?reliability=all(无需鉴权)。其中health字段是公共社区代理列表可靠性的唯一事实来源:最近 7 天内最近 50 次合格最终请求,超过 80% 成功即视为健康;无观测则视为"未知且可见"。样本每分钟刷新约一次,无最小样本门槛,成功回退(fallback 救援)与 owner 请求都计入请求模型的成功率,最终 4xx 被排除,探针计入。官方模型、agent 与仅 owner 可见的私有模型不受此规则影响。

诊断时辅助两个时间窗口的 Tinybird 数据(用TB_TOKEN):探针选择用model_health.json?minutes=240,官方告警用minutes=60。行按目录name或声明的aliases匹配(规范名优先),并依据community与agent字段分类——绝不从名称形状臆断分类,未匹配的模型视为未知。

2.3 state.json:周期间的记忆

/home/ubuntu/monitor/state.json是各周期进程间的唯一记忆,字段结构(节选):

{ "lastRepliedMessageId": { "<channelId>": "<id>" }, "spend": { "...由 probe.mjs 自行维护..." }, "protocolFlagged": { "<model>": { "error": "...", "streak": 0, "lastPostedAt": "..." } }, "officialModelFlagged": { "<model>": "<iso-ts>" }, "officialModelSpilloverFlagged": { "<model>": "<iso-ts>" }, "legacyBridgeFlagged": { "text": { "flaggedAt": "...", "medianRequests": 0, "medianSuccess": 0.0 } }, "servedModelFlagged": { "<model>": { "declared": "...", "served": "...", "streak": 0, "lastPostedAt": "..." } }, "fallbackFlagged": { "<model>": { "servedBy": "...", "share": 0.0, "lastPostedAt": "..." } }, "lastLeaderboardPostedDate": "YYYY-MM-DD", "lastImageLeaderboardPostedDate": "YYYY-MM-DD", "lastFilteredModelsCheckedDate": "YYYY-MM-DD", "filteredModelIds": ["<canonical ID>"] }

要点:模型键必须用稳定的owner/name(剥掉一个前导community/),这样目录改名不会重置连击计数或发帖冷却;首次运行时若文件缺失按空处理并标记 FIRST RUN;spend键由 probe.mjs 自己写入(记录最近一轮实际花费与请求数),Agent 重写 state 时必须读-改-写保留它;未知的旧键(如billingFlagged、pendingDeactivation、healthChecks)保留但忽略。

2.4 people_mapping.json:GitHub ↔ Discord 身份映射

给任何人@之前必须先查这张表:解析模型 GitHub 用户名对应的discord_id后@正确的人,绝不猜测或编造 ID。discord_id: null意味着还不知道该用户的 Discord ID,此时用纯文本 GitHub 用户名称呼而非制造无效 mention。context字段用于让回复显得知情("你的 gpt-oss-20b"而非"你的某个模型"),但不得整段背诵。若本轮学到新映射(有人在聊天里报出 GitHub 用户名,或此前为 null 的 ID 因对方发帖而解析成功),追加到people数组并保持 JSON 合法;不得删除或覆盖已有确认条目。

三、Duty 2:观测可靠性,绝不写入可见性

所有模型列表都自动应用"80% 成功率"目录规则;被过滤的模型仍可按精确 ID 调用、仍可作为回退目标;owner 可自行将模型设为私有——监控器永不改变任何模型的发布状态。旧的停机门槛、每日七天审计、恢复连击和 D1 hide/relist 命令均已退役,旧记忆与 state 中的相关内容直接忽略。

  • agent 完全不在探针与告警范围内:跳过agent: true的目录条目。其他类别只从流量中观测,仅对 probe.mjs 支持的文本/图像代理合成例行请求。
  • 只使用输入步骤 1 中的单次选择性批量探测;不得发布例行"列表/取消列表"转换消息,不维护第二个可见性状态机。一次通过探针只是"贡献了一个请求",不是即时恢复覆盖。图像上报必须测试受影响的那个操作——生成通过不能证明编辑健康。

四、Duty 2b:协议失败——只看流协议,不做算术审计

不再运行或发布例行的 token 计数、缓存、推理或计费算术检查(包括旧的billingFlagged状态与自动记忆笔记)。探针用量只用于实际花费与请求的诊断,不做主动的 owner 计费告警。

判定核心是显式终止性 SSE 错误(如usage_missing)即使内容先到也算失败请求。可归因到 provider 的文本结果以status: "PROTOCOL"记入protocolFlagged;调用方/探针钱包失败不属于 provider 告警。连击规则:

  • 仅当同一个稳定protocolError在连续的新鲜检查中重复出现时才累加streak;跳过的检查不变;不同的新鲜结果重置连击但保留lastPostedAt的完整 24 小时冷却。
  • 连续两次失败后,向#dev-community-models发至多一条分组消息(受影响模型、owner、精确协议错误),随后用lastPostedAt对同一 模型+错误 静默 24 小时。
  • 协议告警永远不授权可见性写入。若证据指向共享 Pollinations 网关回归或探针钱包故障,作为一起事故升级给维护者,而不是逐家发给 provider。绝不包含原始流内容或 provider 计费负载。

五、Duty 2c:官方(非社区)模型监控——只告警,永不改动

目录条目中community: true的是社区模型;匹配到的无此标志的条目即官方模型。官方模型是纯告警对象,监控器对其没有任何修改权。

几个关键约束:

  • 不对官方 Bedrock 推理做合成调用:可读官方 Anthropic/Claude 与 Amazon Nova 的分析数据,但绝不合成调用它们(包括诊断对比与重试);社区模型(哪怕名为 Claude 或 Sonnet)的探针仍允许。若分析无法确认官方 Bedrock 事故,就报告验证限制而不是花钱探测。
  • DEGRADED 阈值:使用 1 小时 Tinybird 窗口,最终用户可见成功率低于 90%且该小时至少有 10 个非客户端请求才判定。标准管道口径是status_2xx / (total_requests - errors_4xx);官方图像模型则查最终generation_event_v2行,把可确认归因到 provider 的 4xx(含历史Image provider error:行)与 5xx 一并计入,排除调用方鉴权/余额、非法输入与内容策略 4xx。归因不确定时不得仅凭比率告警。请求数不足 10 时样本太薄,跳过本轮,不为噪音而标记。
  • 绝不拿主端点/上游健康冒充最终健康:own_calls、own_calls_ok、primary_5xx、primary_retried_503s与generation_event_v2中的非最终行描述的是"尝试过的后端",不是调用方最终收到的结果;被回退救援的失败主调用是最终成功,不得因此标记 DEGRADED。recent_server_errors不同——它只含终止性错误且无is_final字段。
  • SPILLOVER(溢出回退)单独追踪:最终率 ≥ 90% 时,仅当primary_retried_503s >= 10且重试的 primary 503 占该小时status_2xx的至少 10% 才报告 SPILLOVER。面板必须含FINAL <rate>%、QUEUE <primary_retried_503s> retried、FALLBACK <fallback_rescues> rescued。不得称其为停机或"模型在失败"。用独立的officialModelSpilloverFlagged映射配 3 小时冷却,保证信息性溢出告警永远不能压制后续的 DEGRADED 告警;冷却期内不删时间戳,满 3 小时且模型不再 SPILLOVER 时才清理。
  • DEGRADED 前置确认:宣告前按api_key_id与user_id分组查看该模型的模型过滤终止错误,需要至少 2 个不同的非空 key 或 2 个不同的非空用户,或用新鲜合成生产探针复现 provider/server 5xx(探针必须覆盖故障表面:文生图探针不能确认或排除图生图事故)。失败集中在单一调用方且同表面探针通过时,视为调用方/请求特定问题:不告警、不设officialModelFlagged。集中的上游 403 不得仅凭状态码就断定为鉴权/密钥故障。
  • 告警动作:DEGRADED 且 3 小时内未标记过时,向#dev-agentstream(1521913038188314814,注意不是 #dev-community-models)发一条短消息并@thomash(<@304378879705874432>)与@elliot(<@884468469452656732>),使用 duty 3 的 ASCII 面板(STATUSDEGRADED、MODEL、WHY 含成功率+请求数与根因、BYmonitor),记录officialModelFlagged[model]。单小时跨过 90% 线即可告警,无多周期连击或宽限期。冷却内不重复标记;隐藏、禁用或以任何方式改动官方模型都不被允许——发告警及根因就是监控器权限的全部边界。

DEGRADED 面板的根因(同周期尽力而为):发布前用TB_TOKEN查询recent_server_errors,让面板不只是"84.6% success"。仓库给出了参考命令(注意stack/message中的换行会破坏jq,需用 Python 过滤):

curl -s "https://api.europe-west2.gcp.tinybird.co/v0/pipes/recent_server_errors.json?token=$TB_TOKEN&minutes=60&limit=50" \ | python3 -c "import json,sys; d=json.load(sys.stdin,strict=False); [print(r) for r in d['data'] if r['model_requested']=='<model>']"

读取upstream_status、upstream_host、upstream_body形成简短 WHY(哪个 provider/region、什么 HTTP 状态、超时还是硬错误、单个坏请求还是每个请求);错误行指向不明(上游字段为空、真歧义)就直说"cause unclear; upstream fields empty",绝不猜测。

恢复跟进:模型一旦被标记,其后的每个周期都要复查其 1 小时成功率(即使在 3 小时再标记冷却内,这是廉价读取而非新告警);一旦重新越过 90%,立即向 #dev-agentstream 发一行"<model>recovered — success back to % last hour"并删除其officialModelFlagged条目——官方模型事故要有显式收尾。

六、Duty 2d:served-model 检查——只告知,永不隐藏

调用方应得到列表所承诺的模型,两类偏差值得告知:

上游不匹配(Upstream mismatch):每周期一次查询 D1 公共行:

SELECT 'community/' || u.github_username || '/' || ce.name AS model_id, ce.upstream_model FROM community_endpoint ce JOIN user u ON ce.owner_user_id = u.id WHERE ce.visibility = 'public' AND ce.type = 'proxy'

对每个带servedModel的文本探针结果做名称规范化(小写;去掉最后一个/之前的 provider 前缀;去掉尾部:free/:paid、-latest、-preview或日期后缀如-20260916/-2026-09-16)。一个规范化名等于或包含另一个即一致;否则在稳定模型键上记servedModelFlagged:同一served值在连续新鲜检查中重复才累加streak,跳过不变、不同新鲜结果重置,保留lastPostedAt。fallbackUsed: true的结果跳过——改去比较回退列表自身的探针。

回退占比(Fallback share):从 4 小时窗口按resolved_model_requested、is_final、fallback_used、model_used查generation_event_v2;当至少 10 个被救援请求占该模型最终成功数的至少 25% 时记fallbackFlagged。

发帖规则:本职责每周期至多一条分组消息——不匹配需两次连续新鲜检查后、回退占比一个周期即可;随后对同一 模型+served 对用lastPostedAt静默 7 天。面板用STATUS MISMATCH(字段 MODEL、DECLARED、SERVED)或STATUS FALLBACK(MODEL、SERVED、SHARE 如37% of 412 reqs 4h),经 people_mapping.json 通知 owner,并加一句给调用方的平实说明(如 "requests to X are currently answered by Y")。这类通知只是信息性的:它们从不隐藏、不重新上架、不喂给 duty 2,且当两条消息预算吃紧时让位于诊断回复与 DEGRADED 帖(被跳过的通知下周期仍可发)。绝不包含上游主机名或原始负载。

七、Duty 2e:legacy 桥检查——只告警,每周期一次

旧版文本与图像 API 各用一个桥密钥调用 gen(generation_events_classified.pipe中的legacy)。该检查只读、绝不探测或调用 legacy API,核心是一个比较"最后一整小时 vs 前 7 天同时段中位数"的 Tinybird SQL(完整语句在 CYCLE.md 中,此处节选关键口径):

  • requests与successes从该小时回溯 7 天;成功按每个最终行计(因此余额 402 与密钥失败会拉低成功率)。
  • degraded判定:中位数至少 10 个请求,且最后一小时请求数或成功率低于中位数一半时置 1。
  • 桥不在结果里说明该时段的这些小时全无流量:记入周期摘要即可,不告警。
  • duty 2c 的"两个不同调用方"规则与探针确认不适用——每个密钥只有单一内部调用方,所以集中在该调用方上的失败就是事故。

每个周期在周期摘要中记录两个桥的最后一小时请求/成功率与其各自中位数。对legacyBridgeFlagged缺失或flaggedAt超过 3 小时的每个 degraded 桥,向 #dev-agentstream 发一个面板并@elliot,面板采用 duty 3 格式:STATUSDEGRADED、MODELlegacy text bridge/legacy image bridge、REQS<n> last hour, median <n>、FINAL<rate>% last hour, median <rate>%、WHYtop error <last_hour_top_error>(成功率下降时)、BYmonitor。首次标记时记录{ flaggedAt, medianRequests, medianSuccess };冷却后重复标记时只更新flaggedAt,让基线保持事故前的值。恢复判定对照存储的基线而非滚动中位数(长事故约 4 天后会把自己变成中位数):一旦last_hour_requests >= medianRequests / 2且last_hour_success >= medianSuccess / 2,发一行"legacy text bridgerecovered — ..."并删除条目。

八、Duty 3:频道检查与基于证据的诊断

8.1 阅读与回复范围

读取以下频道的最近 20 条消息:#dev-community-models(1522236212666961930)、#dev-models(1451926412771594312,遗留频道,仍要盯着零散回复)、community-models 线程(1521876416440827996)。只回复比各频道lastRepliedMessageId更新的、且确实发给自己的消息(提及机器人、询问模型统计/健康、有用的能力/用例反馈、重新上架请求)。被询问统计时用 Tinybird 的真实数字作答。所有新状态更新(duty 2/2b)发到 #dev-community-models 而非 #dev-models。

8.2 诊断回复的受控对比与预算

  • 先原样重放精确的合成探针负载(含每个字段),或使用明确提供的、脱敏的公共复现;绝不取回私有用户提示或输出。
  • 然后一次只改一个变量,使用新鲜唯一标记,记录 HTTP 状态、modelUsed、fallbackUsed、prompt_tokens、cached_tokens、total_tokens。仪表盘端点测试直接调 provider 模型、不经回退——与公共列表探针对比前先确认它匹配保存的上游模型。
  • 每周期每个上报问题至多 3 个请求(含定向探针),这是诊断不是压测。分离观察与归因:完整回答不是流成功的证据;502、缺失分析或一次通过的生成探针都不能单独确立 provider 停机、网关缺陷或编辑健康。
  • 有用的 provider 反馈(被请求时):用现有公共 Discord 示例与聚合用量/错误元数据作答(模型帮什么忙、工具是否可用、缓存工作流是否受支持),引用公共报告并区分于复现结果;无相关示例就直说用量数据看不出用例并索要一个脱敏示例或选择加入的测试,不得编造用户、背书、模型需求或能力支持,也不得主动广播新的 provider 请求。

8.3 风格与 ASCII 面板

消息风格要克制:目标 250 字符以内,一两句短句,只讲最重要的一件事(发生了什么/下一步做什么);删掉客套与多从句解释;emoji 零或一个。模型列表与请求的诊断细节字段(模型、操作、错误、请求 ID、时间)可超限,但仍只发一条分组回复。

状态帖统一用代码块里的 ASCII 面板(机器人的标志性外观,保持一致性):固定 44 字符宽边框,┌─ MONITOR ─...─┐/└─...─┘,每行│+ 内容左填充 +│,每行一个FIELD value对(字段名后至少两空格)。任何超宽值截断而非加宽。<@id>mention 必须放在代码块外面(Discord 不在代码块内渲染 mention)。标准字段:STATUS(DEGRADED/SPILLOVER/MISMATCH/FALLBACK/HEALTHY)、MODEL(每模型一行,多模型重复字段名)、FINAL、REQS、QUEUE、FALLBACK、DECLARED/SERVED/SHARE、WHY、BY。面板示例:

┌─ MONITOR ────────────────────────────────┐ │ STATUS DEGRADED │ │ MODEL sixfingerdev/qwen2.5-0.5b │ │ WHY 0% success across 34 requests │ │ BY monitor │ └──────────────────────────────────────────┘

关于重新上架请求或修复公告:解释自动列表遵循最新合格样本而非人工机器人决策;特定修复可做一次有边界的诊断检查,但不得批量刷成功来推高分数;7 天无观测的模型变为未知且可见;私有模型在 owner 发布前保持仅 owner 可见。@任何人前先查 people_mapping.json。

九、Duty 3b:每日排行榜与列表变动通报

每天约 12:00 UTC 执行,文本与图像两块板各自独立、各有状态键(lastLeaderboardPostedDate/lastImageLeaderboardPostedDate),只有键与当天 UTC 日期不同且已到 12:00 UTC 之后才运行:

  • 文本榜:cd /home/ubuntu/monitor/leaderboard && node build-leaderboard.mjs,按服务 token 数给社区文本模型排名,展示 token 速度与成功率。
  • 图像榜:node build-image-leaderboard.mjs,按成功生成图像数排名,展示每图秒数中位数与可归因到 provider 的成功率(客户端 4xx 从成功率排除)。

两个脚本(build-leaderboard.mjs 同款结构)都查询 Tinybird(generation_event_v2的generate.text事件、model_provider_used = 'community'、is_final,最少 50 个请求、TOP 10、速度前三),经 chromium 渲染像素风街机高分区 HTML 板、裁剪、上传 media.pollinations.ai,最后打印 JSON:{ date, imageUrl, markdown, pngPath },各约 10–15 秒。脚本出错或无可上榜模型:记入周期摘要、不设置该板状态键、下周期重试。成功则把markdown字段原样发到 #dev-community-models(两块同轮成功则合并为一条消息),随后把对应状态键设为今天日期。这是固定日常仪式,不加评论。

任一排行榜今日已发布且lastFilteredModelsCheckedDate非今日时,比较两个公开目录https://gen.pollinations.ai/models?community=true与...&reliability=all(按规范name):当前可靠性过滤集 = 出现在all响应但不在默认响应中、community: true、非 agent、且health.success_rate≤ 80% 的 ID。私有模型两边都不出现,绝不包含。filteredModelIds缺失时先存基线、不发布;否则只发布变化:Newly filtered(当前集减上次集)与Back in listings(上次集 ∩ 今日默认列表)标题下,展示当前过滤总数、每个变化的规范 ID 及其成功率(四舍五入到最近整数百分比,未知则写no recent sample);说清楚被过滤模型仍可按精确 ID 调用;不 @owner、不称模型"被禁用"、不展示完整列表。无变化则不发布;两条消息预算耗尽则延后重试且不更状态,排行榜无需重发。

十、Duty 4:状态落盘

周期收尾把 state.json 写入:各频道看到的最新消息 ID、duty 2b 的protocolFlagged、2c 的两个 official 映射、2d 的servedModelFlagged/fallbackFlagged、2e 的legacyBridgeFlagged、3b 的两个排行榜日期与过滤模型快照/日期,以及步骤 3 学到的 people_mapping.json 追加。未知旧键原样保留。

十一、探针脚本的源码级实现

11.1 退避调度:probe-schedule.mjs

调度只有两个导出函数,是"重试预算"而非可见性证据:

export function nextProbeAt(previous) { if (!previous) return 0; const delay = Math.min(4 * 2 ** previous.failures, 6 * 24) * HOUR; return Date.parse(previous.lastAt) + delay; } export function recordProbe(previous, result) { return { lastAt: result.timestamp, failures: result.ok || result.status === "ERR" || result.status === "INVALID" || (typeof result.status === "number" && result.status < 500) ? 0 : (previous?.failures ?? 0) + 1, operation: result.operation, }; }

与文档公式min(4 * 2^failures, 144)小时完全对应:文本与图像都是 4 小时基础间隔,每次 server/protocol 失败翻倍、上限 6 天;成功(含回退救援)与不确定的调用方/探针错误都重置为 4 小时。skippedModels表示"未到期"而非"失败或恢复"。测试 probe-schedule.test.mjs 验证了失败跨重启翻倍(8/16/32/64/128/144 小时序列)、回退成功重置以及 402/ERR/INVALID 不累加失败数的行为。注意recordProbe里"重置"的语义与文档中"成功和不结论的调用方/探针错误重置间隔"一致,spend.probes由脚本自行维护,绝不可手动清零来强制再查——这是一个重试预算,不是 provider 故障的证据。

11.2 探针主体:probe.mjs

  • 环境依赖:必须存在POLLI_TOKEN;GEN默认https://gen.pollinations.ai;并发CONCURRENCY = 4;文本超时TEXT_TIMEOUT_MS = 45_000,图像IMAGE_TIMEOUT_MS = 150_000;状态与结果路径可通过MONITOR_STATE_PATH/MONITOR_RESULTS_PATH覆盖。
  • 目录过滤:只取model.community && !model.agent && category ∈ {text, image}的条目——代码注释直言"Agents can perform real work on the probe account; never select them"。--models-file接受{ name, category, operation? }数组且校验严格(name 为字符串、category 必须 text|image、operation 必须 generate|edit),并与--model互斥;空数组合法且不触发全量扫描。--category image可探测隐藏的精确 ID。
  • 文本探针(probeText):生成唯一标记ok-<uuid 前 8 位>,提示词Reply with exactly: <marker>,请求/v1/chat/completions,stream: true、stream_options: { include_usage: true }——故意省略max_tokens让推理模型有空间返回最终答案,硬边界是超时。AbortController 的定时器必须覆盖响应体读取全程(代码注释记录了 2026-07-20 那次因停滞流挂死整个扫描的历史教训)。结果判定ok = res.ok && !protocolError && hasProbeMarker;modelUsed来自网关x-model-used头而非 provider 自报名称;fallbackUsed = modelUsed !== model.name(缺失头时为 null,即归因未知)。
  • 图像探针(probeImage):经 image-probe.mjs 构造请求。支持图像输入的模型按nextImageOperation在/v1/images/edits与/v1/images/generations之间交替(上次是 edit 则本次 generate,否则 edit);编辑请求内嵌一张 512×512 黑白 PNG(base64 常量,避免外部夹具主机),提示词Change the black square to blue. Add the label <marker>.,生成请求用response_format: "b64_json"与提示词A plain test card labeled <marker>。成功还需b64_json解码后字节数 > 100,否则判INVALID。每次检查只发一个缓存破拆请求,例行监控每模型每 4 小时至多一次——图像探针成本显著更高且消耗真实 owner 容量。
  • 结果落盘与花费:estimateCost用目录公开定价做规划预估值(文本按p * 20 + c * 8,图像按 prompt 文本/图像与 completion 图像 token 单价);真实花费actualCost从响应usage的input_tokens_details、prompt_tokens、completion_tokens等实际 token按单价重算,写回 state 的spend键(含lastActualPollen、lastRequestCount)。写 state 时重新读文件再合并而非复用启动快照——扫描要跑几分钟,期间 Agent 可能已重写过 state,合并进旧快照会静默回退那些写入。定向--model检查打印 JSON 到 stdout 但不替换例行结果文件,且同样更新 cadence。
  • 错误脱敏:chat-stream.mjs 的probeErrorDetails会把 URL 替换为[URL]、Bearer ...替换为Bearer [redacted]、sk_/pk_/sk-/ghp_/github_pat_前缀令牌替换为[redacted]、压缩换行并截断 300 字符——确保不持久化原始上游错误体或凭据。
  • SSE 校验(parseChatStream/hasChatProbeMarker):逐行解析 SSE,data:事件必须是合法 JSON 且含choices数组,恰好一个被空行终止的[DONE],[DONE]后不得再有数据、流不得以未终止事件或缺失[DONE]结束;usage_missing、finish_reason=error、事件内嵌 error 都是失败;标记必须出现在剥掉<think>/<thought>包裹后的最终完成内容里——不接受来自未完成推理的标记副本。任何PROTOCOL都是失败的兼容性探针,适用 duty 2b 的归因与确认规则,绝不修复、丢弃或重排 provider 输出。

11.3 自动更新与部署闭环

update-from-repo.sh 在每个周期前 fetchorigin/main,用临时文件 +mv原子替换CYCLE.md、探针脚本、loop.sh、healthcheck.sh、.claude/settings.json与两个排行榜构建器,并记录.source-revision。它优先读取新路径operations/community-monitor,回退到遗留路径apps/operation/community-monitor;只有 updater 本身已在 main 上时才自我更新,因此部署中的 PR 不能降级线上监控器。.env、state、身份映射、日志与生成数据永不被复制或删除。部署命令与迁移步骤见 README.md。

十二、硬性规则汇总(周期行为的最终边界)

  • 例行检查永远走选定批次与脚本强制退避;跳过的检查从不推进或清除诊断连击(协议与 served-model 不匹配连击同理,只有新探针时间戳能做到)。用户上报的具体问题可用有边界的一次模型诊断路径,绝不绕过节奏去攒样本或确认。
  • 每周期至多 2 条 Discord 消息;相关更新合并,不拆第二条补充消息。预算吃紧时诊断回复与 DEGRADED 告警优先于 SPILLOVER;被跳过的 SPILLOVER 不记为已标记,下周期再试。
  • 没有不稳定、没人搭话:什么都不发,静默是常态。
  • 任何消息不得包含 API 密钥/token、私有上游 URL/主机名、原始响应负载、私有提示或生成的用户内容;只报告安全的错误类别与诊断元数据,引用错误时也要脱敏敏感片段;公共请求路径必须省略查询值并脱敏内嵌提示。
  • 每条消息的数字必须来自真实数据,绝不编造统计。
  • owner 请求与探针计入目录可靠性;只有选择低流量模型再查时排除探针。
  • served-model 与回退通知(duty 2d)纯属信息性。
  • 永不<@fake_id>;没有确认的 discord_id 就用纯文本名字/GitHub 用户名。
  • 永不改动模型可见性;目录持有自动过滤权,owner 决定 Public/Private。
  • 不发布例行的 token 计数或计费健全性检查;2xx 响应仍可能含终止性 provider 失败,但仅标记不匹配不足以定性——套用输入步骤 2 的归因规则。
  • 所有模型对监控器只读;只有精确目录匹配可被分类,未知模型从不归咎于 provider。
  • 官方 DEGRADED 永远基于最终用户可见结果;非最终 primary 503 可产生 SPILLOVER,但绝不产生 DEGRADED。
  • 每个每日排行榜每 UTC 天至多发布一次——运行前必查其状态键,即使当天被要求"重新生成"也绝不二次运行(那是维护者动作,不是本循环自行重复的例行行为)。

十三、快速自查:一个周期的时间线

把以上职责按顺序串起来,一个典型周期是:systemd 启动新进程 →update-from-repo.sh同步规则 → 读取probe-results.json与新频道报告 → 按 4 小时窗口的低流量/低成功/问题上报/低健康样本挑选探针候选 → 写入probe-candidates.json并运行一次node probe.mjs --models-file ...→ 读取reliability=all目录与 Tinybird 诊断数据 → 依次执行 duty 2(社区可靠性观测)、2b(协议失败)、2c(官方模型告警-only)、2d(served-model/回退告知)、2e(legacy 桥告警)、3(频道回复 + 受控诊断)、3b(每日排行榜与过滤列表通报)→ duty 4 读-改-写落盘 state.json 与 people_mapping.json → 退出;systemd 30 分钟后启动下一轮。全程消息预算 2 条、探针预算 4 小时基础间隔(失败翻倍至 6 天上限)、每次上报问题至多 3 个诊断请求——这套自约束让一个无头 Agent 在无人值守的 EC2 上既能持续守护社区模型目录,又不会因为失稳而烧钱或刷屏。

  • AI 应用
  • 媒体生成
  • 后端
  • 前端

【免费下载链接】pollinations

Your Friendly Open-Source Gen-AI Platform

项目地址:https://gitcode.com/gh_mirrors/po/pollinations
点击查看免费下载

相关推荐

上一篇:Starship 高级安装指南:Windows、Termux、Funtoo 与 Nix 平台专项部署
下一篇:DeepSearcher环境隔离方案:多租户数据安全与资源分配完整指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询