fix(platform): 能力误判根治三层——提取提示词能力判定铁律(按正文模态声明禁照示例);apply能力一致性守卫(描述模态vs capability矛盾代码级纠正t2v→r2v);overrides.model_capability白名单(用户口头纠正能落进规格,禁重提取死循环);check_model_accounting区分failed调用行/充值行非待记账

This commit is contained in:
yumoqing 2026-09-06 14:56:34 +08:00
parent a24a2320de
commit b2ecf54f43

View File

@ -136,12 +136,35 @@ def _spec_overlay(base, overrides):
"""覆盖项合并仅允许少量标量覆盖vendor_name 等),不做大 JSON 搬运。
overrides 只认白名单键防止 LLM 借覆盖项塞回编造结构
model_capability2026-09-06 wan3.0 教训{vendor_model_id: capability}
按模型纠正能力用户提醒这是参考生视频后助手必须有工具路径把纠正
落进规格否则只能重跑 extract同样提示词同样误判提醒无效的死循环
纠正值仍要过能力字典校验下游 unknown 拒绝落库不会被塞私货
"""
allowed = {'vendor_name', 'base_url', 'protocol', 'doc_url', 'doc_notes'}
out = dict(base or {})
for k in allowed:
if k in (overrides or {}) and str(overrides.get(k) or '').strip():
out[k] = str(overrides[k]).strip()
mc = (overrides or {}).get('model_capability')
if isinstance(mc, str):
try:
mc = json.loads(mc)
except Exception:
mc = None
if isinstance(mc, dict) and mc:
fixed = []
models = list(out.get('models') or [])
for m in models:
vmid = m.get('vendor_model_id') or m.get('name') or ''
newcap = str(mc.get(vmid) or '').strip()
if vmid and newcap and newcap != m.get('capability'):
fixed.append('%s: %s%s' % (vmid, m.get('capability'), newcap))
m['capability'] = newcap
out['models'] = models
if fixed:
out['doc_notes'] = ((out.get('doc_notes') or '') +
' [能力已按人工纠正: %s]' % ''.join(fixed)).strip()
return out
@ -335,7 +358,7 @@ _EXTRACT_PROMPT = """你是大模型 API 配置专家。通读下面这份模型
"response_format": "响应格式说明content 字段路径 + usage 字段路径)",
"response_example": {"说明": "文档中的响应示例 JSON或结果字段说明逐字照抄无则 null"},
"async_steps": [{"purpose": "query|download", "path": "该步骤接口路径", "method": "GET|POST", "request_fields": ["请求字段名列表"], "response_format": "该步骤响应格式说明"}],
"models": [{"vendor_model_id": "供应商侧模型ID", "capability": "t2t|t2i|i2t|t2v|i2v|r2v|i2i|embedding|rerank|tts|asr",
"models": [{"vendor_model_id": "供应商侧模型ID", "capability": "t2t|t2i|i2t|t2v|i2v|r2v|i2i|embedding|rerank|tts|asr|mm-embedding|mm-rerank",
"sync_mode": "sync|async提交后需轮询查询结果的填 async",
"description": "一句话说明"}],
"pricing": {
@ -358,6 +381,16 @@ _EXTRACT_PROMPT = """你是大模型 API 配置专家。通读下面这份模型
path 照文档逐字抄同供应商多个模型会复用同一份查询模板不要因模型而异
- 同步模型 async_steps 填空数组 []
能力判定铁律2026-09-06 wan3.0-video-prime 误判教训概述明写"四模态全能参考"
输入=音频/图像/文本/视频却因调用示例只有 prompt 被判成 t2v
- capability 必须以文档**概述正文 + 输入/输出模态声明**为准禁止以调用示例为准
示例常只演示最简形态纯文本 prompt照示例判会把多媒体参考模型误判成纯文本模型
- 判定表输入模态 输出模态 能力
多种媒体输入或正文含参考/reference/全能参考/多图/多模态输入 r2v即使示例只有文本
图像+文本 视频 i2v仅文本 视频 t2v仅文本 图像 t2i图像 图像 i2i
视频 视频 v2v 类按字典就近文本 音频 tts音频 文本 asr
- description 里必须保留正文的模态声明原文关键词"支持四模态全能参考"供下游一致性校验
定价规则
- pricing.items 每条必须带 doc_quote文档原文定价句逐字照抄定价只允许来自文档原文
- 价格/单位按文档原文记录禁止自行换算推导或统一单位
@ -411,9 +444,20 @@ async def _h_extract_llm_api_spec(sor, params, ctx):
if anchored:
out["__anchored__"] = ("规格已锚定到本会话缓存。下一步调用 apply_llm_config 与 "
"apply_model_pricing 时传 {\"use_last_extract\": true}"
"需改动只传覆盖项overrides,仅 vendor_name/base_url/"
"protocol/doc_url/doc_notes 白名单键)。"
"需改动只传覆盖项overrides 白名单:vendor_name/base_url/"
"protocol/doc_url/doc_notes/model_capability)。"
"禁止把本规格复制进 spec 参数——复制即编造。")
# 能力一致性告警2026-09-06 wan3.0 教训):提取完当场校验描述模态声明 vs
# capability矛盾信息直接回给助手用户纠正时传 overrides.model_capability 重 apply
cap_alerts = []
for _m in (spec.get("models") or []):
_fix, _warn = _capability_guard(_m.get("capability", ""), _m.get("description", ""))
if _warn:
cap_alerts.append("%s: %s" % (_m.get("vendor_model_id", "?"), _warn))
if cap_alerts:
out["__capability_alert__"] = ("能力分类与文档描述矛盾(按示例误判的典型信号),"
"apply 时会自动纠正,也可用 overrides.model_capability "
"人工指定:" + "".join(cap_alerts))
return json.dumps(out, ensure_ascii=False)
@ -426,6 +470,52 @@ def _f(v, default=0.0):
return default
# 描述里的媒体输入声明词(能力一致性守卫用)
_DESC_MEDIA_WORDS = {
'image': ('图像', '图片', '多图'),
'video': ('视频',),
'audio': ('音频', '声音'),
}
_DESC_REF_WORDS = ('参考生', '全能参考', '参考图', '参考视频', '参考音频', '四模态', '多模态参考')
def _capability_guard(capability, description):
"""描述模态声明 vs capability 一致性守卫2026-09-06 wan3.0-video-prime 实测:
描述自带"支持四模态全能参考"capability 却是 t2v提取 LLM 照调用示例判能力
示例只演示最简形态就误判提示词加铁律后仍需代码级兜底LLM 不保证遵守
保守策略只在纯文本能力t2v/t2i/t2t+ 描述含媒体输入/参考声明这种
铁证矛盾时纠正其他不一致只警告不改避免误伤描述措辞不规范的正确配置
返回 (corrected_cap None, warning None)
"""
desc = description or ''
if not desc or capability not in ('t2v', 't2i', 't2t'):
return None, None
has_ref = any(w in desc for w in _DESC_REF_WORDS)
kinds = [k for k, words in _DESC_MEDIA_WORDS.items() if any(w in desc for w in words)]
# 「输出 视频」的"视频"不算输入声明——t2v 描述几乎都带"视频"二字。
# 输入声明判据:参考词,或图像/音频词(这两个不会出现在纯文本生成的描述里),
# 或"视频"以外多模态组合。
input_kinds = [k for k in kinds if k != 'video']
if has_ref or len(input_kinds) >= 1 or (has_ref is False and len(kinds) >= 2 and 'video' in kinds and input_kinds):
out_word = '视频' if capability == 't2v' else ('图像' if capability == 't2i' else '')
if capability == 't2t':
return None, ("描述含媒体输入声明(%s)但能力是 t2t——请人工核对能力分类"
% '/'.join(kinds))
expected = 'r2v' if (has_ref or len(kinds) >= 2) else (
'i2v' if 'image' in input_kinds and out_word == '视频' else
('i2i' if 'image' in input_kinds and out_word == '图像' else None))
if expected and expected != capability:
return expected, ("能力自动纠正 %s%s:描述声明媒体输入(%s%s"
"纯文本能力与之矛盾(提取照示例误判,守卫按正文模态纠正)"
% (capability, expected, '/'.join(kinds),
',含参考声明' if has_ref else ''))
return None, ("描述含媒体输入声明(%s)但能力是 %s——无法确定目标能力,"
"请人工核对(可用 overrides.model_capability 纠正)"
% ('/'.join(kinds), capability))
return None, None
async def _h_apply_llm_config(sor, params, ctx):
"""按提取的规格写库:供应商(复用/新建)+ 适配模板 + 模型。
@ -649,6 +739,15 @@ async def _h_apply_llm_config(sor, params, ctx):
cap = m.get("capability") or "t2t"
sync_mode = "async" if str(m.get("sync_mode") or "").strip() == "async" else "sync"
desc = (m.get("description", "") or "").strip()
# 能力一致性守卫2026-09-06 wan3.0 实测):描述模态声明 vs capability
# 铁证矛盾时代码级纠正——提取 LLM 照示例误判,提示词铁律不保证遵守
cap_fix, cap_warn = _capability_guard(cap, desc)
if cap_fix:
tpl_notes.append("%s: %s" % (vmid, cap_warn))
cap = cap_fix
m["capability"] = cap_fix
elif cap_warn:
tpl_notes.append("%s: %s" % (vmid, cap_warn))
# 出处标注2026-09-05 用户规则):模型注册表描述字段必须保存文档 URL
if doc_url and ("[出处:" + doc_url + "]") not in desc:
desc = (desc + " " if desc else "") + "[出处:%s]" % doc_url
@ -1731,7 +1830,17 @@ async def _h_check_model_accounting(sor, params, ctx):
"模型未映射产品→产品管理导入产线模型;"
"定价无匹配档位→核对usages维度值与定价YAML是否一致")
elif st == "created":
item["verdict"] = "待记账出账循环60秒一轮稍后复查持续不变查记账worker进程"
# m0011 设计accounting_status 只对 status='ok' 行有意义——
# failed 调用行/recharge 充值行挂 created 是被出账循环天然排除(不计费),
# 不是「待记账」2026-09-06 实测:助手把 21 条 failed 行误报成待记账)
call_st = row.get("status", "")
if call_st == "recharge":
item["verdict"] = "充值对账流水(非计费用量,不参与出账)"
elif call_st != "ok":
item["verdict"] = "调用失败行(不计费,出账循环天然排除)"
item["reason"] = (row.get("note") or "")[:200]
else:
item["verdict"] = "待记账出账循环60秒一轮稍后复查持续不变查记账worker进程"
elif st == "accounted":
# 独立复算:用 usages 因子过定价引擎,对比 charge
item["verdict"] = "已记账"
@ -1813,10 +1922,10 @@ PLATFORM_TOOLS = [
),
ToolDefinition(
name="apply_llm_config",
description="按提取的规格写入模型治理配置:供应商/端点/适配模板/模型。幂等。推荐 use_last_extract=true 取本会话锚定规格(禁止把规格复制进 spec——复制即编造需改动加 overridesvendor_name/base_url/protocol/doc_url/doc_notes。仅owner组织角色可用。",
description="按提取的规格写入模型治理配置:供应商/端点/适配模板/模型。幂等。推荐 use_last_extract=true 取本会话锚定规格(禁止把规格复制进 spec——复制即编造需改动加 overridesvendor_name/base_url/protocol/doc_url/doc_notes/model_capability——用户纠正能力分类时传 model_capability 而非重提取。仅owner组织角色可用。",
parameters={
"use_last_extract": "true=用本会话 extract_llm_api_spec 锚定的规格(推荐,会话级隔离)",
"overrides": "覆盖项 JSON白名单vendor_name/base_url/protocol/doc_url/doc_notes,如用户要求改供应商名",
"overrides": "覆盖项 JSON白名单vendor_name/base_url/protocol/doc_url/doc_notes/model_capability。model_capability={模型ID:能力} 如 {\\\"wan3.0-video-prime\\\": \\\"r2v\\\"}——用户纠正能力分类时传它+use_last_extract 重新 apply不要重提取模板会按新能力重建",
"spec": "仅无锚定时的兜底extract 返回的 JSON 规格原文",
},
category="platform",
@ -1904,6 +2013,11 @@ PLATFORM_PROMPT = """
- **定价只允许来自文档原文**doc_quote 强制禁止编造/换算/推导
- **出处必留**模型注册表描述字段与定价方案描述字段都必须保存文档 URL
- 能力分类不存在 先加分类字典/种子/提示词/端点注释四处同步再配模型禁止塞近似分类
- 能力分类铁律按文档正文的输入/输出模态声明判定禁止照调用示例判示例常只演示
最简形态wan3.0 实测四模态全能参考被示例判成 t2vextract 返回
__capability_alert__ 说明描述与能力矛盾apply 会自动纠正用户口头纠正能力时
overrides={"model_capability": {"模型ID": "能力"}} + use_last_extract 重新 apply
禁止重提取同样的提示词只会同样误判
- 生成类模型媒体铁律上行统一三数组契约 image_files/audio_files/video_files
字符串或数组均可 b64media2url 转公网 URL下行产物用
downloadfile2url(request, url) 落地apply 返回的 media_audit 警告必须如实转告