- 章后处理:事实提案命令身份加入类型、批内去重改为先校验后去重(REPEAT_OBJECT_TYPE 记跳过、不再静默丢重复);查询章后状态回传事实跳过;可按需发布/核对可登记任务与 config_not_declared 语义收紧 - 模型治理:推理字符数计量(ChatCompletions/Messages/执行合同)、探针在声明关闭推理却仍有推理时拒绝、计价支持缓存协议与未知模型兜底 - 运行态:资源包重建(发布身份 21d850f7…),三处配置同步,post-extract v5 代次 5 启用,服务 PID 96675(health/ready 通过) - 门禁:make 检查通过;离线 1008 passed;定点数据库 101 passed;最终完整备份 bkp-1f5591d8… 与空库恢复演练 verified(152 表/158 关系/迁移 45,演练库已 DROP) - 文档与证据:运行手册、功能覆盖、工作包清单 W30 证据、测试用例清单(17 条 execution_evidence 回填 + 历史死指针说明)、目标文件清单 - 旧实现与旧库直连材料退出(含明文凭据文件移除);新配置 配置/本机正式.toml、配置/本机维护.toml、配置/计费/、配置/运行配置/ 入库,均只含受控引用 - R2 执行证据在 .agents.local/改造/R2-20260909/(不入库)
95 lines
3.9 KiB
Python
95 lines
3.9 KiB
Python
"""网关计价的线性公式、缓存口径与费率文件载入合同。"""
|
||
|
||
from decimal import Decimal
|
||
from pathlib import Path
|
||
|
||
import pytest
|
||
|
||
from muse.任务运行.接口 import 模型用量, 模型结果
|
||
from muse.共享.错误 import Muse错误
|
||
from muse.基础设施.模型.计价 import 模型费率, 网关计价, 载入费率文件
|
||
|
||
|
||
def _费率(输入="5", 输出="25", 读取="0.5", 写入="6.25") -> 模型费率:
|
||
return 模型费率(Decimal(输入), Decimal(输出), Decimal(读取), Decimal(写入))
|
||
|
||
|
||
def _结果(实际模型="claude-opus-4-8", 协议="chat-completions", **用量):
|
||
用量.setdefault("输入token", 0)
|
||
用量.setdefault("输出token", 0)
|
||
return 模型结果(
|
||
"completed",
|
||
"{}",
|
||
实际模型,
|
||
模型用量(**用量),
|
||
"resp-1",
|
||
回放协议=协议,
|
||
# 回放内容不属于计价输入,但合同要求终态完整。
|
||
回放内容=(),
|
||
)
|
||
|
||
|
||
def test_含缓存协议按未缓存输入加缓存读取计价__d9a001() -> None:
|
||
计价 = 网关计价("费率-1", {"claude-opus-4-8": _费率()}, "claude-opus-4-8")
|
||
# 输入10(含缓存4)+ 输出3:6×5/1M + 4×0.5/1M + 3×25/1M = 0.000107
|
||
金额 = 计价.金额(_结果(输入token=10, 输出token=3, 缓存读取token=4))
|
||
assert 金额 == Decimal("0.000107")
|
||
|
||
|
||
def test_独立缓存协议输入不含缓存读取__d9a002() -> None:
|
||
计价 = 网关计价("费率-1", {"claude-opus-4-8": _费率()}, "claude-opus-4-8")
|
||
# 输入2 + 读取4 + 写入6 + 输出1 = 10/1M + 2/1M + 37.5/1M + 25/1M = 0.0000745(半入进位)
|
||
金额 = 计价.金额(
|
||
_结果(协议="anthropic", 输入token=2, 输出token=1, 缓存读取token=4, 缓存写入token=6)
|
||
)
|
||
assert 金额 == Decimal("0.000075")
|
||
|
||
|
||
def test_缺用量或未知协议返回未知而不推定免费__d9a003() -> None:
|
||
计价 = 网关计价("费率-1", {"claude-opus-4-8": _费率()}, "claude-opus-4-8")
|
||
无用量 = 模型结果("completed", "{}", "claude-opus-4-8", None, None)
|
||
assert 计价.金额(无用量) is None
|
||
assert 计价.金额(_结果(协议="unknown")) is None
|
||
|
||
|
||
def test_未列模型按兜底模型高估__d9a004() -> None:
|
||
计价 = 网关计价(
|
||
"费率-1",
|
||
{"claude-opus-4-8": _费率(), "qwen3.8-flash": _费率("0.15", "0.47", "0.016", "0.2")},
|
||
"claude-opus-4-8",
|
||
)
|
||
未知 = 计价.金额(_结果(实际模型="另一个模型", 输入token=1, 输出token=0))
|
||
兜底 = 计价.金额(_结果(实际模型="claude-opus-4-8", 输入token=1, 输出token=0))
|
||
assert 未知 == 兜底 == Decimal("0.000005")
|
||
|
||
|
||
def test_费率文件载入并拒绝缺字段或非法金额__d9a005(tmp_path: Path) -> None:
|
||
文件 = tmp_path / "费率.toml"
|
||
文件.write_text(
|
||
'"版本" = "费率-1"\n'
|
||
'"兜底模型" = "模型甲"\n'
|
||
'["费率"."模型甲"]\n'
|
||
'"输入单价" = "1"\n"输出单价" = "2"\n"缓存读取单价" = "0.1"\n"缓存写入单价" = "1"\n',
|
||
encoding="utf-8",
|
||
)
|
||
计价 = 载入费率文件(文件)
|
||
assert 计价.版本 == "费率-1" and 计价.兜底模型 == "模型甲"
|
||
assert 计价.金额(_结果(实际模型="模型甲", 输入token=1)) == Decimal("0.000001")
|
||
|
||
缺字段 = tmp_path / "缺.toml"
|
||
缺字段.write_text('"版本" = "v"\n"兜底模型" = "甲"\n["费率"."甲"]\n"输入单价" = "1"\n')
|
||
with pytest.raises(Muse错误, match="不完整"):
|
||
载入费率文件(缺字段)
|
||
|
||
负价 = tmp_path / "负.toml"
|
||
负价.write_text(
|
||
'"版本" = "v"\n"兜底模型" = "甲"\n'
|
||
'["费率"."甲"]\n"输入单价" = "-1"\n"输出单价" = "2"\n'
|
||
'"缓存读取单价" = "0.1"\n"缓存写入单价" = "1"\n'
|
||
)
|
||
with pytest.raises(Muse错误, match="非负"):
|
||
载入费率文件(负价)
|
||
|
||
with pytest.raises(Muse错误):
|
||
载入费率文件(tmp_path / "不存在.toml")
|