mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-10-31 12:24:39 +08:00
eval: align native collaboration discovery
This commit is contained in:
@@ -100,6 +100,16 @@ MoviePilot 的真实 Agent 已在 `app/agent/llm/helper.py` 的 `runtime == "goo
|
||||
|
||||
严格配对摘要为 `/tmp/moviepilot-agent-round-luna-oauth-dedup-pair.json`,`pair_valid=true`、`both_passed=false`,模型/推理/预算、场景和四项 SHA 指纹均一致。MoviePilot 比 Codex 少 3 次模型调用、少 61341 个已知 token、少 51.091 秒,但这只是本轮具体轨迹的成本差,不抵消生产 Agent 的终态验收失败。该结果首次形成可复核的真实配对证据,也明确了下一目标是提高生产图的精确最终报告可靠性,而不是把失败改判为通过。
|
||||
|
||||
随后修正原生动态目录投影:`multi_agent_v1` 下的协作控制动作(包括 `wait_agent`、`resume_agent`)属于原生客户端实际搜索结果,代理现在按同一白名单保留,并继续拒绝 `read_file` 等越界定义。修正后的三次同 Harness 配对均使用 `gpt-5.6-luna + max`、16 次模型调用上限、8192 输出上限、180 秒超时和 `harness_sha256=71be4c436acc5dc2d5a0cd6996c3ca10688a9c4ba98fd11594e536f7aa440c22`:
|
||||
|
||||
| 场景 | MoviePilot | 原生 Codex | 配对结论 |
|
||||
| --- | --- | --- | --- |
|
||||
| `dedup_existing` | 通过;6 次模型调用、2 次业务读取、0 重复/副作用 | 通过;10 次模型调用、3 次业务读取、0 重复/副作用 | `pair_valid=true`、`both_passed=true`;摘要 `/tmp/moviepilot-agent-round-luna-oauth-dedup-pair-13.json` |
|
||||
| `unknown_download` | 通过;6 次模型调用、6 次业务调用、1 个预期写入副作用 | 通过;14 次模型调用、7 次业务调用、1 个预期写入副作用 | `pair_valid=true`、`both_passed=true`;摘要 `/tmp/moviepilot-agent-round-luna-oauth-unknown-pair-14.json` |
|
||||
| `honest_unknown` | 通过;9 次模型调用、2 次受控失败读取、1 个预期写入副作用,保留下载未核验 | 未通过;16 次模型调用达到上限,未产出最终 JSON,1 个预期写入副作用且无重复 | `pair_valid=true`、`both_passed=false`;摘要 `/tmp/moviepilot-agent-round-luna-oauth-honest-pair-16.json` |
|
||||
|
||||
这组三场景说明当前生产 Agent 在两个写入/复用路径和一个未知回执安全路径上已形成同条件通过样本,但原生 Codex 在持续不可用场景仍会因继续读取 Skill 和消耗调用预算而没有终态报告。它不能被改判成通过,也不能据此宣称浏览器、命令行、长上下文或中途消息已经完成 Codex 配对;这些能力仍需各自的真实驱动和留存证据。
|
||||
|
||||
已有报告可用以下命令重新生成摘要;命令只读报告,不会再次调用模型:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
让 MoviePilot Agent 在 MoviePilot 的真实业务边界内具备可复核的 Codex 级 Harness 能力:模型能看到准确的工具合同,工具能完成完整的命令行、浏览器、终端输入输出、子代理和长任务协作闭环,宿主能隔离任务身份、收口进程并在新消息到达时继续推进。高影响业务动作仍由宿主的授权和确认策略控制。
|
||||
|
||||
真实模型评测必须使用显式配置的供应商模型和推理档位。历史 Google Gemini 基线为 `gemini-2.5-pro + high`;后续测评切换为更强的 `gemini-3.1-pro-preview + high`。官方 Google 主机由评测 worker 使用生产同源的 `langchain-google-genai` 原生工具通道,以保留 Gemini 3 的 `thought_signature`;报告会把实际 `runtime_transport` 记为 `google_generative_language`。不同模型、供应商或协议的结果不能直接合并;当前已经取得首个同条件原生 Codex 配对样本,但两侧尚未同时通过。
|
||||
真实模型评测必须使用显式配置的供应商模型和推理档位。历史 Google Gemini 基线为 `gemini-2.5-pro + high`;后续测评切换为更强的 `gemini-3.1-pro-preview + high`。官方 Google 主机由评测 worker 使用生产同源的 `langchain-google-genai` 原生工具通道,以保留 Gemini 3 的 `thought_signature`;报告会把实际 `runtime_transport` 记为 `google_generative_language`。不同模型、供应商或协议的结果不能直接合并;首个同条件原生 Codex 配对样本未同时通过,随后同 Harness 的 `dedup_existing` 和 `unknown_download` 配对已同时通过,`honest_unknown` 仍保留原生侧预算耗尽失败。
|
||||
|
||||
Google 的 OpenAI-compatible 层会丢失 Gemini 3 工具回复中的 `thought_signature`,第二轮请求因此可能被供应商以 400 拒绝。真实 MoviePilot Agent 的 `runtime == "google"` 已固定走 `ChatGoogleGenerativeAI` 和签名兼容补丁;需要修正的是评测或错误的 provider 配置,不能通过普通 OpenAI 消息层补回签名。该边界由 `tests/test_agent_vision_providers.py`、`tests/test_llm_helper_testcall.py` 和本轮真实原生 Google 运行共同覆盖。
|
||||
|
||||
@@ -72,4 +72,5 @@ uv run --locked --no-sync python -m scripts.evaluation \
|
||||
- `0f8aa4dfa`:公共 `moviepilot_api` 描述只保留通用边界;参数错误回执附带当前 operation 的允许字段、必填字段和类型/枚举约束。真实 Gemini `dedup_existing` 报告 `/tmp/moviepilot-agent-round-13b4fe112-gemini-dedup.json` 证明错误回执能促成 `subscription.find` 字段位置修正且没有副作用,但模型仍错误声明未请求的站点和已完成下载,继续保持未通过。
|
||||
- 本轮:真实测评切换到 `gemini-3.1-pro-preview + high`,官方 Google 主机改用生产同源的 `langchain-google-genai` 原生工具通道并保留 `thought_signature`。`dedup_existing`、`unknown_download`、`honest_unknown` 三个固定场景均通过(报告分别为 `/tmp/moviepilot-agent-round-gemini31native-dedup.json`、`/tmp/moviepilot-agent-round-gemini31native-unknown.json`、`/tmp/moviepilot-agent-round-gemini31native-honest.json`);这只是 API 假世界的模型行为证据,仍未形成与原生 Codex 的配对比较。
|
||||
- 本轮第二阶段:用同一 `gpt-5.6-luna + max`、同一场景和预算显式启用 Codex OAuth,首次生成有效成对摘要 `/tmp/moviepilot-agent-round-luna-oauth-dedup-pair.json`。MoviePilot live `/tmp/moviepilot-agent-round-luna-oauth-live-dedup-5.json` 因最终 infohash 少两位而未通过;原生 Codex `/tmp/moviepilot-agent-round-luna-oauth-native-dedup-8.json` 通过。摘要 `pair_valid=true`、`both_passed=false`,证明真实生产图与 Codex 仍有可观测的终态可靠性差距;下一轮先针对精确最终报告和未知结果收口做多次重复,再扩展浏览器、终端和中途消息场景。
|
||||
- 本轮第三阶段:修正原生动态工具搜索对 `multi_agent_v1` 协作命名空间的投影,正向保留 `wait_agent`、`resume_agent` 等原生控制动作,负向继续拒绝 `read_file`。在同一 Harness(`71be4c436acc5dc2d5a0cd6996c3ca10688a9c4ba98fd11594e536f7aa440c22`)下,`dedup_existing` 配对 `/tmp/moviepilot-agent-round-luna-oauth-dedup-pair-13.json` 与 `unknown_download` 配对 `/tmp/moviepilot-agent-round-luna-oauth-unknown-pair-14.json` 均 `pair_valid=true`、`both_passed=true`;MoviePilot 分别使用 6/6 次模型调用,原生 Codex 使用 10/14 次。`honest_unknown` 配对 `/tmp/moviepilot-agent-round-luna-oauth-honest-pair-16.json` 仍为 `both_passed=false`:MoviePilot 在 9 次调用后如实保留下载未核验,原生 Codex 达到 16 次上限后没有最终 JSON,产生 `invalid_final_report`。这保留了真实失败边界,不能等同整体 Codex 智能已完成。
|
||||
- 浏览器、真实命令行/PTY 和 WebAgent 中途消息排队已有确定性实现,但仍缺少与原生 Codex 在同一模型、同一场景下的真实配对证据,不能把这些能力标为“已对齐”。
|
||||
|
||||
@@ -33,6 +33,7 @@ NATIVE_CONTROL_TOOLS = frozenset({
|
||||
NATIVE_COLLABORATION_TOOLS = frozenset({
|
||||
"spawn_agent", "followup_task", "interrupt_agent", "list_agents", "send_message", "wait_agent",
|
||||
})
|
||||
NATIVE_MULTI_AGENT_TOOLS = NATIVE_CONTROL_TOOLS | NATIVE_COLLABORATION_TOOLS
|
||||
KNOWN_NAMESPACES = frozenset({"functions", "clock", "collaboration", "mcp__evaluation", "multi_agent_v1"})
|
||||
FIXTURE_TOOLS = frozenset({"moviepilot_api", "read_skill", "read_tool_result"})
|
||||
|
||||
@@ -44,7 +45,7 @@ def allowed_tool(name: str) -> bool:
|
||||
or normalized in {f"collaboration__{tool}" for tool in NATIVE_COLLABORATION_TOOLS}
|
||||
or normalized in {f"mcp__evaluation__{tool}" for tool in FIXTURE_TOOLS}
|
||||
or (normalized.startswith("multi_agent_v1__")
|
||||
and normalized.removeprefix("multi_agent_v1__") in NATIVE_CONTROL_TOOLS))
|
||||
and normalized.removeprefix("multi_agent_v1__") in NATIVE_MULTI_AGENT_TOOLS))
|
||||
|
||||
|
||||
def project_tools(tools: Any, prefix: str = "") -> tuple[list[dict[str, Any]], list[str], list[str]]:
|
||||
|
||||
@@ -551,6 +551,32 @@ async def test_native_client_discovery_call_and_namespace_output_are_allowed(lim
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_native_discovery_accepts_multi_agent_collaboration_namespace() -> None:
|
||||
"""原生协作命名空间的合法动作可通过目录投影并保留审计记录。"""
|
||||
outbound = []
|
||||
|
||||
def handler(request: httpx.Request) -> httpx.Response:
|
||||
"""接收投影后的协作目录,不访问真实模型服务。"""
|
||||
outbound.append(json.loads(request.content))
|
||||
return httpx.Response(200, json=_completed())
|
||||
|
||||
tools = [{
|
||||
"type": "namespace", "name": "multi_agent_v1",
|
||||
"tools": [{"type": "function", "name": name, "parameters": {}}
|
||||
for name in ("wait_agent", "send_input")],
|
||||
}]
|
||||
payload = _native_payload()
|
||||
payload["input"].append(_search_output(tools=tools))
|
||||
proxy = EvaluationModelProxy(SETTINGS, transport=httpx.MockTransport(handler))
|
||||
async with _client(proxy) as client:
|
||||
response = await client.post("/v1/responses", json=payload)
|
||||
assert response.status_code == 200 and outbound
|
||||
assert proxy.snapshot()["model_requests"][0]["tool_catalogs"][-1]["retained_tools"] == [
|
||||
"multi_agent_v1.wait_agent", "multi_agent_v1.send_input",
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("updates", [
|
||||
{"execution": "server"}, {"call_id": None}, {"call_id": ""}, {"arguments": {"query": " "}},
|
||||
{"arguments": {"query": "x", "sources": ["external"]}}, {"arguments": {"query": "x", "limit": 0}},
|
||||
|
||||
Reference in New Issue
Block a user