实现侧: - 上下文:任务范围拆分为 范围校验/范围授权;索引按可发现口径重建、索引新鲜度改对称差;依赖校验统一快照漂移说明。 - 知识方法:方法与材料读取口径统一;超限方法材料按可选省略,核对路径不再二次计费;删除无合同的读时重算。 - 任务运行:新增 context.usage/tool.denied 事件类型;连接池常驻并在装配生命周期内开关;调用结算与核对分列。 - 效果评测/审校修订/交付连载/作者经验/作品规划:凭据冻结、标定消费、导出补证、事实引文核对等收尾修复。 - 资源加载:能力正文不再夹带索引用的导航注记(该注记此前进入角色与技能的模型提示)。 - 元数据:受保护骨架与代码保护属性对齐;字段校验与内置结构口径同步。 - 基础设施:环境预检进入装配生命周期;数据库连接运行期字段不参与相等比较;索引指纹归一化 jsonb 浮点。 - 删除被替代实现:7 份旧提示词模板与空壳 资料来源 读取器。 用例侧: - 用例身份与导航元信息迁移;夹具补生命周期、同库暴露与模板封存; - 本轮定向修复:方法材料省略、事实引文、迁移回执、额度与暂停用例、慢用例超时预算等。
208 lines
8.8 KiB
Python
208 lines
8.8 KiB
Python
"""S02核对结构化交付;不能用成功回执为任意审校字典背书。"""
|
||
|
||
import asyncio
|
||
import json
|
||
|
||
import pytest
|
||
import test_受控模型调用 as 模型测试
|
||
|
||
from muse.任务运行.接口 import 模型执行器, 证据服务
|
||
from muse.共享.错误 import Muse错误
|
||
from muse.基础设施.宿主.直接调用 import 直接宿主
|
||
from muse.基础设施.模型.HTTP传输 import HTTP传输
|
||
|
||
pytestmark = pytest.mark.数据库
|
||
模型环境 = 模型测试.模型环境
|
||
合成HTTP = 模型测试.合成HTTP
|
||
|
||
|
||
def 调用(env, tmp_path, http, *, 仅回合=False):
|
||
库, 运行, 策略, 请求, 原文, 授权, 预算, ctx = env
|
||
|
||
def 回复(_):
|
||
数据 = {
|
||
"type": "response.completed",
|
||
"response": {
|
||
"id": "structured-review",
|
||
"model": "claude-opus-4-8",
|
||
"status": "completed",
|
||
"output": [
|
||
{
|
||
"type": "message",
|
||
"content": [
|
||
{
|
||
"type": "output_text",
|
||
"text": json.dumps({"text": "结构化审校结果"}, ensure_ascii=False),
|
||
}
|
||
],
|
||
}
|
||
],
|
||
"usage": {"input_tokens": 1, "output_tokens": 1},
|
||
},
|
||
}
|
||
return ("data: " + json.dumps(数据) + "\n\n").encode()
|
||
|
||
key = tmp_path / "key"
|
||
key.write_text("synthetic-credential")
|
||
执行器 = 模型执行器(
|
||
运行,
|
||
预算,
|
||
原文,
|
||
证据服务(库),
|
||
策略,
|
||
直接宿主(HTTP传输(http(回复), "受控存储", str(key), "responses")),
|
||
模型测试.合成计价(),
|
||
)
|
||
fn = 执行器.执行回合 if 仅回合 else 执行器.执行
|
||
return asyncio.run(fn(ctx, 请求, 阶段="生成", 原文授权ID=授权))
|
||
|
||
|
||
@pytest.mark.case_id(
|
||
"NC-w22-22e001",
|
||
environment="隔离PG与合成HTTP提供方",
|
||
given="真实S02当前领取与未发送/已完成的模型调用",
|
||
when="调用登记的结构化交付核对或文学片/报告组装公共入口",
|
||
then=["只有完整派发和结构化响应才可核对,返回真实尝试与哈希"],
|
||
contract="docs/系统架构/新版设计/模块设计/S02-任务运行.md",
|
||
)
|
||
def test_只有完整结构化响应可核对且不改业务内容__22e001(模型环境, tmp_path, 合成HTTP):
|
||
库, 运行, _, 请求, _, _, _, ctx = 模型环境
|
||
with 库.连接() as 连, 连.transaction(), pytest.raises(Muse错误):
|
||
运行.核对结构化交付于(
|
||
连, ctx.领取, 请求.调用ID, 请求.用户输入, 请求.输出合同, {"text": "结构化审校结果"}
|
||
)
|
||
交付 = 调用(模型环境, tmp_path, 合成HTTP)
|
||
with 库.连接() as 连, 连.transaction():
|
||
依据 = 运行.核对结构化交付于(
|
||
连, ctx.领取, 请求.调用ID, 请求.用户输入, 请求.输出合同, 交付.内容
|
||
)
|
||
assert str(依据["attempt_id"]) == ctx.领取.尝试ID and 依据["call_state"] == "saved"
|
||
assert 依据["dispatch_hash"] == 依据["input_hash"]
|
||
assert 依据["response_metadata"]["structured_output_hash"]
|
||
|
||
|
||
@pytest.mark.case_id(
|
||
"NC-w22-22e002",
|
||
environment="隔离PG与合成HTTP提供方",
|
||
given="结构化交付后篡改输出/输入/合同/调用或结束尝试",
|
||
when="调用登记的结构化交付核对或文学片/报告组装公共入口",
|
||
then=["拒绝不匹配绑定与失效领取,不能为任意产物背书"],
|
||
contract="docs/系统架构/新版设计/模块设计/S02-任务运行.md",
|
||
)
|
||
@pytest.mark.parametrize("变动", ["输出", "输入", "合同", "调用", "失败"])
|
||
def test_结构化交付拒错绑定及失败后保存__22e002(模型环境, tmp_path, 合成HTTP, 变动):
|
||
库, 运行, _, 请求, _, _, _, ctx = 模型环境
|
||
交付 = 调用(模型环境, tmp_path, 合成HTTP)
|
||
输入, 合同, 输出, call = 请求.用户输入, 请求.输出合同, 交付.内容, 请求.调用ID
|
||
if 变动 == "输出":
|
||
输出 = {"text": "凭空更换结论"}
|
||
elif 变动 == "输入":
|
||
输入 = "不是模型实际收到的输入"
|
||
elif 变动 == "合同":
|
||
合同 = {"type": "object"}
|
||
elif 变动 == "调用":
|
||
call = "not-called"
|
||
else:
|
||
运行.失败步骤(ctx.领取, "SYNTHETIC_FAILURE")
|
||
with 库.连接() as 连, 连.transaction(), pytest.raises(Muse错误):
|
||
运行.核对结构化交付于(连, ctx.领取, call, 输入, 合同, 输出)
|
||
|
||
|
||
@pytest.mark.case_id(
|
||
"NC-w22-22e003",
|
||
environment="隔离PG与合成HTTP提供方",
|
||
given="只校验模型回合终态,没有最终结构化校验",
|
||
when="调用登记的结构化交付核对或文学片/报告组装公共入口",
|
||
then=["普通completed不能冒结构化最终交付"],
|
||
contract="docs/系统架构/新版设计/模块设计/S02-任务运行.md",
|
||
)
|
||
def test_只检终态的普通回合不冒结构化最终交付__22e003(模型环境, tmp_path, 合成HTTP):
|
||
库, 运行, _, 请求, _, _, _, ctx = 模型环境
|
||
调用(模型环境, tmp_path, 合成HTTP, 仅回合=True)
|
||
with 库.连接() as 连, 连.transaction(), pytest.raises(Muse错误):
|
||
运行.核对结构化交付于(
|
||
连, ctx.领取, 请求.调用ID, 请求.用户输入, 请求.输出合同, {"text": "结构化审校结果"}
|
||
)
|
||
|
||
|
||
@pytest.mark.case_id(
|
||
"NC-w25-25a001",
|
||
environment="隔离PG及受控合成HTTP",
|
||
given="同一S02尝试顺序执行两个真实模型回合",
|
||
when="第二次确认成功或确认前中断后查询首轮及次轮",
|
||
then=["第一轮仍按逐调用记录核验;当前入口不认旧轮,未确认次轮仍拒绝"],
|
||
contract="docs/系统架构/新版设计/模块设计/S02-任务运行.md",
|
||
)
|
||
@pytest.mark.parametrize("模型环境", [2], indirect=True)
|
||
@pytest.mark.parametrize("second_saved", [True, False])
|
||
def test_同尝试多回合历史独立核验但未确认回合仍拒绝__25a001(
|
||
模型环境, tmp_path, 合成HTTP, monkeypatch, second_saved
|
||
):
|
||
import hashlib
|
||
from dataclasses import replace
|
||
from datetime import UTC, datetime, timedelta
|
||
|
||
from muse.任务运行.接口 import 请求字节
|
||
|
||
库, 运行, 策略, request, raw, _, budget, ctx = 模型环境
|
||
first = 调用(模型环境, tmp_path, 合成HTTP)
|
||
request2 = replace(request, 调用ID="call-2", 用户输入="第二次独立合成输入")
|
||
digest = hashlib.sha256(请求字节(request2)).hexdigest()
|
||
auth2 = raw.批准保留(
|
||
ctx.任务.任务ID,
|
||
ctx.任务.作者,
|
||
"approve-second",
|
||
来源版本="synthetic-1",
|
||
哈希=(digest,),
|
||
内容用途="generation",
|
||
方式="persistent",
|
||
有效期=datetime.now(UTC) + timedelta(minutes=5),
|
||
调用ID=request2.调用ID,
|
||
调用请求哈希=digest,
|
||
)
|
||
second_env = (库, 运行, 策略, request2, raw, auth2, budget, ctx)
|
||
if second_saved:
|
||
second = 调用(second_env, tmp_path, 合成HTTP)
|
||
else:
|
||
|
||
def 不确认(self, *_args, **_kwargs):
|
||
raise Muse错误("合成确认前中断")
|
||
|
||
monkeypatch.setattr(模型执行器, "_确认保存", 不确认)
|
||
with pytest.raises(Muse错误, match="确认前中断"):
|
||
调用(second_env, tmp_path, 合成HTTP)
|
||
with 库.连接() as conn, conn.transaction():
|
||
historical = 运行.核对历史结构化交付于(
|
||
conn,
|
||
ctx.任务.作者,
|
||
ctx.任务.任务ID,
|
||
ctx.领取.尝试ID,
|
||
request.调用ID,
|
||
用户输入哈希=hashlib.sha256(request.用户输入.encode()).hexdigest(),
|
||
输出合同=request.输出合同,
|
||
输出=first.内容,
|
||
)
|
||
assert historical["response_metadata"]["call_id"] == request.调用ID
|
||
assert historical["call_state"] == "saved"
|
||
with pytest.raises(Muse错误):
|
||
运行.核对结构化交付于(
|
||
conn, ctx.领取, request.调用ID, request.用户输入, request.输出合同, first.内容
|
||
)
|
||
if second_saved:
|
||
current = 运行.核对结构化交付于(
|
||
conn, ctx.领取, request2.调用ID, request2.用户输入, request2.输出合同, second.内容
|
||
)
|
||
assert current["response_metadata"]["call_id"] == request2.调用ID
|
||
else:
|
||
with pytest.raises(Muse错误):
|
||
运行.核对历史结构化交付于(
|
||
conn,
|
||
ctx.任务.作者,
|
||
ctx.任务.任务ID,
|
||
ctx.领取.尝试ID,
|
||
request2.调用ID,
|
||
用户输入哈希=hashlib.sha256(request2.用户输入.encode()).hexdigest(),
|
||
输出合同=request2.输出合同,
|
||
输出={"text": "结构化审校结果"},
|
||
)
|