fix(llm): _pick_candidate协议感知选端点(404根因)——按模型profile.protocol过滤端点标签,不匹配报真实可行动错误;无标签端点视为通用(向后兼容)

This commit is contained in:
yumoqing 2026-09-05 23:08:17 +08:00
parent 7b6b74646d
commit 51d1e4ccdd

View File

@ -260,8 +260,19 @@ def _filter_by_pref(candidates_with_ep, pref: str):
return matched + rest
async def _model_protocol(sor, model: dict) -> str:
"""模型适配模板的协议2026-09-05 端点协议感知选择用)。查不到返回空串。"""
pid = (model.get('profile_id') or '').strip()
if not pid:
return ''
recs = await sor.sqlExe(
"SELECT protocol FROM llm_api_profile WHERE id=${i}$ LIMIT 1", {"i": pid})
await sor.sqlExe("COMMIT", {})
return (getattr(recs[0], 'protocol', '') or '').strip() if recs else ''
async def _pick_candidate(sor, model: dict, pref: str):
"""构建候选并选一个:区域偏好过滤 → 冷却避让 → 余额加权。
"""构建候选并选一个:协议过滤 → 区域偏好过滤 → 冷却避让 → 余额加权。
返回 (ok, result)ok result=(account_dict, endpoint_dict)否则 result=错误信息
"""
@ -274,6 +285,27 @@ async def _pick_candidate(sor, model: dict, pref: str):
accounts = await _account_candidates(sor, model)
if not accounts:
return False, '模型「%s」的供应商下无启用账号(或账号余额状态异常)' % model.get('name', '')
# 协议感知2026-09-05 404 教训):模型模板协议与端点标签匹配才可用。
# 端点无标签(历史数据)视为通用——同供应商混布 compatible-mode/api/v1
# 两类端点时,无标签过滤会把原生异步模型拼到 openai_compat 前缀下 404。
mproto = await _model_protocol(sor, model)
if mproto:
tagged = [(i, e) for i, e in enumerate(endpoints) if (e.get('protocol') or '').strip()]
if tagged:
matched = {i for i, e in tagged if (e.get('protocol') or '').strip() == mproto}
untagged = {i for i, e in enumerate(endpoints)
if not (e.get('protocol') or '').strip()}
usable = matched | untagged
if not matched:
return False, ('供应商端点均为其他协议(模型模板协议 %s,端点协议 %s)——'
'原生异步(openai_compat 之外)与兼容模式端点 base_url 不同,'
'混用必 404。请在供应商端点目录添加协议 %s 的端点'
% (mproto, sorted({(e.get('protocol') or '') for _, e in tagged}),
mproto))
else:
usable = set(range(len(endpoints)))
else:
usable = set(range(len(endpoints)))
# 展开 (账号, 端点) 对:账号选用的端点下标
pairs = []
for acc in accounts:
@ -285,10 +317,11 @@ async def _pick_candidate(sor, model: dict, pref: str):
i = int(i)
except (TypeError, ValueError):
continue
if 0 <= i < len(endpoints):
if i in usable:
pairs.append((acc, endpoints[i], i))
if not pairs:
return False, '所有账号都未选用端点(模型治理→供应商账号→选用端点),请配置'
return False, ('所有账号都未选用可用端点(模型治理→供应商账号→选用端点)。'
'模型模板协议 %s——请把该协议端点加入账号的选用端点' % (mproto or '未知'))
pairs = _filter_by_pref(pairs, pref)
if not pairs:
return False, ('端点偏好为「仅 %s」,但没有可用的该区域端点。按合规要求不跨端点降级——'