接续 88dd570,保存 W20–W24 已实现的共享接口、业务入口、迁移、工作台、测试与文档。 W20/W22/W23 保持 in_progress,W21/W24 保持 verified;此提交不宣称方法或规则正式启用、多轮返修、真实角色评测完成。 W25 新增实验、标定、逐调用交付与角色执行及其迁移/测试/索引留在实施工作树,原有私人和旧实现保留项不纳入。 验证:离线 571、前端 33 通过;PG 469 项通过、2 项浏览器未启用,2 项误带入的 W25 用例已移出本提交;最终任务与交付边界 37 项通过。make 检查、最终类型、84 项资源及 diff 检查通过。未重跑浏览器或 Pi 宿主,不以合成调用认证外部模型效果。 独立整体审查四维通过;证据保存在 R2-20260909/提交W20-W24。
136 lines
5.0 KiB
Python
136 lines
5.0 KiB
Python
"""拆书分析:把参考作品逐窗拆为章节、阶段、实体与写法的版本化成果。
|
||
|
||
模型调用走 S02(extractor 角色、冻结配置、预算包络);字段结构是固定输出合同,
|
||
窗口结果绑定窗哈希,输入漂移时拒绝写入。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import asyncio
|
||
import hashlib
|
||
import json
|
||
from datetime import UTC, datetime, timedelta
|
||
from typing import Any
|
||
from uuid import uuid4
|
||
|
||
from muse.任务运行.接口 import (
|
||
原文服务,
|
||
执行上下文,
|
||
模型执行器,
|
||
模型请求,
|
||
组装角色请求,
|
||
角色策略目录,
|
||
请求字节,
|
||
)
|
||
from muse.共享.调用身份 import 内容用途
|
||
from muse.基础设施.数据库.连接 import 数据库工厂
|
||
from muse.资料研究.分章切窗 import 漂移检查, 窗口
|
||
from muse.资料研究.模型 import 资料错误
|
||
|
||
# 逐窗分析的输出合同:章节、阶段、实体(带证据)与写法;结构走 S04 固定合同。
|
||
窗口输出合同 = {
|
||
"type": "object",
|
||
"properties": {
|
||
"chapters": {
|
||
"type": "array",
|
||
"items": {
|
||
"type": "object",
|
||
"properties": {
|
||
"title": {"type": "string", "minLength": 1},
|
||
"beat": {"type": "string", "minLength": 1},
|
||
},
|
||
"required": ["title", "beat"],
|
||
"additionalProperties": False,
|
||
},
|
||
},
|
||
"phases": {"type": "array", "items": {"type": "string", "minLength": 1}},
|
||
"entities": {
|
||
"type": "array",
|
||
"items": {
|
||
"type": "object",
|
||
"properties": {
|
||
"name": {"type": "string", "minLength": 1},
|
||
"type": {"type": "string", "minLength": 1},
|
||
"aliases": {"type": "array", "items": {"type": "string"}},
|
||
"evidence": {"type": "array", "items": {"type": "string", "minLength": 1}},
|
||
},
|
||
"required": ["name", "type"],
|
||
"additionalProperties": False,
|
||
},
|
||
},
|
||
"techniques": {"type": "array", "items": {"type": "string", "minLength": 1}},
|
||
},
|
||
"required": ["chapters", "phases", "entities", "techniques"],
|
||
"additionalProperties": False,
|
||
}
|
||
|
||
系统提示 = (
|
||
"你是参考作品分析员,对给定窗口做拆书分析:"
|
||
"列出章节与情节节拍、叙事阶段、出现的人物/地点/事物实体(附原文引文证据)与可借鉴的写法。"
|
||
"只依据窗口原文,不补猜窗口外内容;输出一个 JSON 对象。"
|
||
)
|
||
|
||
|
||
def 执行窗口提取(
|
||
工厂: 数据库工厂,
|
||
原文: 原文服务,
|
||
执行器: 模型执行器,
|
||
上下文: 执行上下文,
|
||
窗: dict[str, Any],
|
||
文本: str,
|
||
) -> dict[str, Any]:
|
||
"""对单窗执行模型提取;输入漂移即失败,模型调用按 S02 证据合同授权留痕。"""
|
||
|
||
窗对象 = 窗口(**窗)
|
||
漂移检查(文本, 窗对象)
|
||
片段 = 文本[窗对象.起点 : 窗对象.终点]
|
||
拆书输入 = (上下文.任务.冻结输入.get("输入") or {}).get("拆书") or {}
|
||
from muse.任务运行.接口 import 配置版本管理
|
||
|
||
声明 = 配置版本管理(工厂).读取任务绑定(上下文.任务.任务ID).内容.角色配置["extractor"]
|
||
请求 = 模型请求(
|
||
调用ID=str(uuid4()),
|
||
provider=声明["provider"],
|
||
model=声明["model"],
|
||
thinking=声明.get("thinking"),
|
||
系统提示=系统提示,
|
||
用户输入=json.dumps(
|
||
{
|
||
"source_id": 拆书输入.get("source_id"),
|
||
"revision": 拆书输入.get("revision"),
|
||
"window_id": 窗对象.窗ID,
|
||
"起章": 窗对象.起章,
|
||
"止章": 窗对象.止章,
|
||
"窗口原文": 片段,
|
||
},
|
||
ensure_ascii=False,
|
||
),
|
||
输出合同=窗口输出合同,
|
||
最大输出token=8_000,
|
||
总期限秒=600.0,
|
||
)
|
||
请求 = 组装角色请求(角色策略目录.从发布包(), "extractor", 请求)
|
||
请求哈希 = hashlib.sha256(请求字节(请求)).hexdigest()
|
||
用途值 = 上下文.任务.冻结输入.get("内容用途", 内容用途.抽取.value)
|
||
授权 = 原文.批准保留(
|
||
上下文.任务.任务ID,
|
||
上下文.任务.作者,
|
||
"raw-" + 请求.调用ID,
|
||
来源版本=f"{拆书输入.get('source_id')}@r{拆书输入.get('revision')}",
|
||
哈希=(请求哈希,),
|
||
内容用途=用途值,
|
||
方式="persistent",
|
||
有效期=datetime.now(UTC) + timedelta(minutes=30),
|
||
调用ID=请求.调用ID,
|
||
调用请求哈希=请求哈希,
|
||
)
|
||
交付 = asyncio.run(执行器.执行(上下文, 请求, 阶段="拆书分析", 原文授权ID=授权))
|
||
内容 = dict(交付.内容)
|
||
for 项 in 内容["entities"]:
|
||
项.setdefault("aliases", [])
|
||
项.setdefault("evidence", [])
|
||
return 内容
|
||
|
||
|
||
__all__ = ["窗口输出合同", "系统提示", "执行窗口提取", "资料错误"]
|