Compare commits
2 Commits
520238de55
...
d4cb740a86
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4cb740a86 | ||
|
|
231b17194a |
@ -97,7 +97,7 @@ huijing 后端把生成请求投给 Python 生成线,靠 `aigc.executor` 这
|
||||
|
||||
派发链路:`submitGenerate` 落库 queued → `GenTaskProducer` 发 RocketMQ → `GenTaskConsumer` CAS 认领 → `WorkerDispatchClient` POST job 到 `worker-url` → Python worker 生成 → 回调 `/dify/callback-internal` → 落版本 + 运行包;`@Scheduled` tick 兜底轮询 DB。
|
||||
|
||||
dev 正确配置固化在 `/root/huijing-dev.env`(chmod 600、单一事实源),`/root/restart-huijing-dev.sh` 从它 `systemd-run` 重建 transient unit `huijing-dev`。关键项:`AIGC_EXECUTOR_ENABLED=true`(装配整组,默认 false = 不分派)、`AIGC_WORKER_URL=http://127.0.0.1:9501/generate`(逐字节对齐 worker 的 `DEFAULT_PORT=9501` + POST `/generate`)、`AIGC_CALLBACK_SECRET=` 空(HMAC 验签关;worker 侧 `CALLBACK_SECRET` 亦空 = 两端对齐,非空则两端必须逐字相同)、`NEWAPI_KEY` = api-key(值见凭据档,MiniMax 计费);dispatcher 默认 `http`(= `WorkerDispatchClient`,别开 `saa` 进程内旧路)、dispatchTemplateId 默认 `generic`(见下)。
|
||||
dev 正确配置固化在 `/root/huijing-dev.env`(chmod 600、单一事实源),`/root/restart-huijing-dev.sh` 从它 `systemd-run` 重建 transient unit `huijing-dev`。关键项:`AIGC_EXECUTOR_ENABLED=true`(装配整组,默认 false = 不分派)、`AIGC_WORKER_URL=http://127.0.0.1:9501/generate`(逐字节对齐 worker 的 `DEFAULT_PORT=9501` + POST `/generate`)、`AIGC_CALLBACK_SECRET` 非空 32hex(Complete A 起已配、值见凭据档;worker 起服带 `--callback-secret <同值>`,两端逐字相同 = HMAC 验签开;空=验签关=内网可伪造回调,内测必须非空)、`AIGC_NEWAPI_QUOTA_ENABLED=true`(WU2 预置池 per-user 计费)、`NEWAPI_KEY` = api-key(值见凭据档,全局兜底/MiniMax 计费);dispatcher 默认 `http`(= `WorkerDispatchClient`,别开 `saa` 进程内旧路)、dispatchTemplateId 默认 `generic`(见下)。
|
||||
|
||||
**分派闸是硬相等 `templateId=='generic'`**(`AigcGenerateExecutor.java:535-536`):只有 templateId 恰等 `generic` 才投 worker,其余(business-sim 等旧模板名)一律 fall-through 到进程内 LLM 旧路、到不了 :9501。便宜档真实流(一句话、不选模板)= 草稿空 templateId → 后端归一 `generic` → 派 worker,品类由 Python 层按 brief 文本判。**冒烟 / e2e 必须用 generic,别用 business-sim**——它虽在 `SUPPORTED_TEMPLATE_IDS` 提交校验放行,却与分派闸解耦、会静默走旧路。
|
||||
|
||||
|
||||
@ -50,27 +50,33 @@ def newapi_error_status_text(exc) -> tuple:
|
||||
|
||||
|
||||
def classify_newapi_failure_reason(status=None, text: str = "") -> str:
|
||||
"""据 one-api/new-api 惯例把网关非 2xx 分辨成失败因(WU2 §3.9)。
|
||||
"""据 new-api 真实响应把网关非 2xx 分辨成失败因(WU2 §3.9)。
|
||||
|
||||
返回 'quota_exhausted'(额度耗尽,干净失败、不可重试)或 'llm_error'(凭据失效/其他,可重试、不塌成额度耗尽)。
|
||||
判据:HTTP 402/403 → 额度耗尽;401 → 凭据失效(维持 llm_error);状态码取不到时按错误体关键词兜底。
|
||||
【阶段2 待验】402/403 与确切错误体 message S0 只坐实了管理面、未测 /v1/chat/completions 耗尽错误体,
|
||||
确切匹配待 S4 真机耗尽/凭据失效测试坐实;此处先给 one-api 惯例初值(状态码优先、关键词兜底)。
|
||||
|
||||
判据(2026-07-08 真机耗尽探测坐实,取代旧的纯状态码假设):new-api 对**额度耗尽返 HTTP 401**、
|
||||
message 含「该令牌额度已用尽 !token.UnlimitedQuota && token.RemainQuota = 0」——**401 与凭据失效状态码重叠**,
|
||||
故必须按错误体 message 分辨、不能只看状态码(旧代码 401→llm_error 会把耗尽误判成可重试 → 反复重试到
|
||||
watchdog 超时,而非干净"额度用尽")。所以:① message 命中额度关键词 → quota_exhausted(优先,不看状态码);
|
||||
② 否则 HTTP 402/403(one-api 惯例额度码,不与凭据失效重叠)→ quota_exhausted;③ 其余(401 无额度关键词
|
||||
= 真凭据失效 / 其他)→ llm_error 可重试。
|
||||
"""
|
||||
try:
|
||||
s = int(status) if status is not None else None
|
||||
except (TypeError, ValueError):
|
||||
s = None
|
||||
if s in (402, 403):
|
||||
return "quota_exhausted"
|
||||
if s == 401:
|
||||
return "llm_error" # 凭据失效:维持可重试,不塌成 quota_exhausted(§3.9 ②)
|
||||
# 状态码取不到时(被框架包装成普通异常)按 one-api 耗尽错误体惯例关键词兜底 —— 确切 message 阶段2 待精确。
|
||||
t = (text or "").lower()
|
||||
quota_markers = ("insufficient user quota", "insufficient quota", "余额不足", "额度不足", "quota not enough")
|
||||
# 额度耗尽关键词(实测 new-api 中文 "该令牌额度已用尽" + 错误体内联判定条件 "RemainQuota = 0";兼容 one-api 英文/通用)。
|
||||
quota_markers = (
|
||||
"额度已用尽", "额度已用完", "额度不足", "令牌额度", "余额不足", # new-api/one-api 中文
|
||||
"remainquota = 0", "remainquota=0", # new-api 错误体内联条件文本
|
||||
"insufficient user quota", "insufficient quota", "quota not enough", # one-api 英文
|
||||
)
|
||||
if any(m in t for m in quota_markers):
|
||||
return "quota_exhausted"
|
||||
return "llm_error"
|
||||
return "quota_exhausted" # ① message 优先:catch new-api 真实的 401+额度耗尽
|
||||
if s in (402, 403):
|
||||
return "quota_exhausted" # ② one-api 惯例额度码(与凭据失效 401 不重叠,保守判耗尽)
|
||||
return "llm_error" # ③ 401 无额度关键词=真凭据失效 / 其他 → 可重试
|
||||
|
||||
# 源工程 2.0 profile 必填三枚举(contracts/agent-loop/source-project.schema.json:39)。
|
||||
_REQUIRED_PROFILE_KEYS = ("tickModel", "inputModel", "progressModel")
|
||||
|
||||
@ -142,16 +142,25 @@ def test_explicit_failure_reason_wins_over_summary():
|
||||
|
||||
|
||||
def test_classify_newapi_status_codes():
|
||||
"""one-api 惯例:402/403 → quota_exhausted;401 → llm_error(凭据失效,可重试,不塌成额度耗尽)。"""
|
||||
"""状态码分辨:402/403(one-api 惯例额度码)→ quota_exhausted;裸 401 / 500 / None(无额度关键词)→ llm_error 可重试。"""
|
||||
assert R.classify_newapi_failure_reason(402) == "quota_exhausted"
|
||||
assert R.classify_newapi_failure_reason(403) == "quota_exhausted"
|
||||
assert R.classify_newapi_failure_reason(401) == "llm_error"
|
||||
assert R.classify_newapi_failure_reason(401) == "llm_error" # 裸 401 无 message = 真凭据失效
|
||||
assert R.classify_newapi_failure_reason(500) == "llm_error"
|
||||
assert R.classify_newapi_failure_reason(None) == "llm_error"
|
||||
|
||||
|
||||
def test_classify_newapi_real_quota_exhausted_401():
|
||||
"""2026-07-08 真机耗尽探测坐实:new-api 对额度耗尽返 HTTP 401 + 「该令牌额度已用尽 …RemainQuota = 0」。
|
||||
401 与凭据失效状态码重叠,故必须按 message 分辨——耗尽判 quota_exhausted(干净失败),真凭据失效仍 llm_error(可重试)。
|
||||
这是关键回归:旧代码 401→llm_error 会把耗尽误判成可重试 → 反复重试到 watchdog 超时。"""
|
||||
real = "[sk-air***0AS] 该令牌额度已用尽 !token.UnlimitedQuota && token.RemainQuota = 0 (request id: 20260708...)"
|
||||
assert R.classify_newapi_failure_reason(401, real) == "quota_exhausted"
|
||||
assert R.classify_newapi_failure_reason(401, "无效的令牌,请检查") == "llm_error" # 真凭据失效仍可重试、不塌成耗尽
|
||||
|
||||
|
||||
def test_classify_newapi_keyword_fallback():
|
||||
"""状态码取不到(被框架包装)时按 one-api 错误体关键词兜底分辨额度耗尽(阶段2 待精确 message)。"""
|
||||
"""message 关键词分辨额度耗尽(状态码取不到 / 被框架包装时同样生效,优先于状态码)。"""
|
||||
assert R.classify_newapi_failure_reason(None, "error: insufficient user quota") == "quota_exhausted"
|
||||
assert R.classify_newapi_failure_reason(None, "当前分组余额不足,请充值") == "quota_exhausted"
|
||||
assert R.classify_newapi_failure_reason(None, "connection reset by peer") == "llm_error"
|
||||
|
||||
@ -26,6 +26,7 @@ canonical: true
|
||||
- **`NEWAPI_PG_PASSWORD`** = new-api 库(`infra-postgres`)的 postgres 超级用户口令 = **`f6710e2d0294eb1c10e26a805a64bc54`**(用户名 **`root`** 非 postgres;经 `docker exec -e PGPASSWORD=… infra-postgres psql -U root -d new-api` 连,已实测可连、2026-07-08 池水位 11 条可用 token)。
|
||||
- **`NEWAPI_ROOT_TOKEN`**(选填,建户/设 quota 用):脚本未设时自动从 `new-api.users.id=1` 读,一般无需显式给。
|
||||
- **补池**:池空则新用户 claim 不到额度、拿不到生成配额 → 提高 `--count` 重跑脚本(ensure 语义、按确定性 username 去重、不重复建号)。
|
||||
- **dev 栈 backend↔worker 回调 HMAC 密钥** `AIGC_CALLBACK_SECRET` = **`e8aab27300f74bca3717ce0670644dfc`**(32hex;后端经 `/root/huijing-dev.env` 注入、便宜档 worker 起服带 `--callback-secret <同值>`,两端必须逐字相同;空=验签关闭=内网可伪造回调,内测必须非空)。运行单源 = mini-desktop `/root/huijing-dev.env`(chmod 600),此处为可复现副本。
|
||||
- **可用模型档(对比测试 / 证路用 · 2026-06-25 补)**:
|
||||
- **`glm-5.2`** —— **Anthropic message 协议**(走 `/v1/messages`),定位 **opus 高级模型档**,上下文 **512K**。后续作**高级档对比测试 / 强模型 cross-check 证路**用,填补复杂档「真强模型证路」此前缺 opus 档的空缺(原 deepseek-v4-pro 跨族证路力弱)。
|
||||
- 便宜档生成主力 = **MiniMax-M3**(Anthropic 原生分离 thinking,见上「协议端点」);其余 provider 模型见 application.yaml `channels.*`。
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user