feat(tier2): 设计阶段接进服务路径(修服务态不收敛根因)
006 真跑实证:服务态 writer 拿空 design_text → 富游戏三门(tripleLink/economy/latch)全挂、 4 次 resume 不收敛(产物结构合法能渲染,但三系统联动没接对)。CLI 线 run_studio 先跑工作室设计 阶段再写、故更易过门;服务路径此前整段跳过设计(app.py 文件头标的 followup)。 修:bootstrap 加 _run_design_phase——在控制面进程内(有 agentscope+模型)复用 studio._design_stage (工作室星形多 agent 团队 + 失败 degrade 回单 agent)产出 design_text,喂进 AgentRecord.system_prompt (roles.writer_system 第二参)。每局建 agent 时跑一次,不随 resume 重跑。best-effort:设计失败返 "" 不阻断生成。do_design 经 drive_generation 透传(control_plane --no-design 可关,对照用)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
34b9ce3be0
commit
d0b30ddace
@ -137,6 +137,36 @@ async def _set_permission_bypass(client: Any, base: str, session_id: str, agent_
|
|||||||
print(f"[tier2-bootstrap] 会话 {session_id} 权限已设 BYPASS(跳过工具 ASK,无人值守自治)。", flush=True)
|
print(f"[tier2-bootstrap] 会话 {session_id} 权限已设 BYPASS(跳过工具 ASK,无人值守自治)。", flush=True)
|
||||||
|
|
||||||
|
|
||||||
|
async def _run_design_phase(brief: str, model_name: str, *, use_team: bool = True) -> str:
|
||||||
|
"""阶段 1 设计:在控制面进程内跑「工作室设计团队」产出富游戏 design_text,喂给服务态 writer 系统提示词。
|
||||||
|
|
||||||
|
为什么必须有(2026-06-24 cp-smoke-006 真跑实证):服务态此前 writer 拿【空 design_text】
|
||||||
|
(start_new_game 传 ""),M3 单写缺富游戏设计指引 → 富游戏三门(tripleLink/economy/latch)全挂、
|
||||||
|
4 次有界 resume 不收敛(产物结构合法、能渲染,但三系统联动没接对)。CLI 线 run_studio 先跑设计阶段
|
||||||
|
再写、故更易过门。本函数把【同一道设计阶段】接进服务路径:复用 studio._design_stage(工作室星形多 agent
|
||||||
|
团队 + 失败 degrade 回单 agent),在控制面进程内(有 agentscope + 模型)直接跑,产出 design_text 写进
|
||||||
|
AgentRecord.system_prompt(roles.writer_system 的第二参)。设计阶段每局只跑一次(建 agent 时),不随 resume 重跑。
|
||||||
|
|
||||||
|
best-effort:任何失败都返回 ""(绝不阻断生成——拿不到设计也让 writer 试,只是少指引),并记日志。
|
||||||
|
"""
|
||||||
|
import functools # noqa: PLC0415
|
||||||
|
from worker import config # noqa: PLC0415
|
||||||
|
from worker.agent_loop import studio as _studio # noqa: PLC0415 —— 牵出 agentscope,控制面进程内可用
|
||||||
|
|
||||||
|
try:
|
||||||
|
# model_factory:零参偏函数,每次返回新 M3 客户端(team 给 leader/各专家各取一个;degrade 单 agent 也取一个)。
|
||||||
|
model_factory = functools.partial(config.build_model, model_name)
|
||||||
|
models: list = [] # 设计阶段造的模型客户端(成本可在此汇总;服务态暂不并入 run 台账,列 followup)
|
||||||
|
design_text = await _studio._design_stage(brief, model_factory, model_sink=models, use_team=use_team)
|
||||||
|
print(f"[tier2-bootstrap] 设计阶段产出 design_text {len(design_text or '')} 字(喂服务态 writer)。",
|
||||||
|
flush=True)
|
||||||
|
return design_text or ""
|
||||||
|
except Exception as e: # noqa: BLE001 —— 设计阶段绝不阻断主链(拿不到设计也让 writer 试)
|
||||||
|
print(f"[tier2-bootstrap] ⚠ 设计阶段失败(writer 将拿空 design,降级继续):"
|
||||||
|
f"{type(e).__name__}: {e}", flush=True)
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
async def start_new_game(
|
async def start_new_game(
|
||||||
base_url: str,
|
base_url: str,
|
||||||
brief: str,
|
brief: str,
|
||||||
@ -145,6 +175,7 @@ async def start_new_game(
|
|||||||
model_name: str = "MiniMax-M3",
|
model_name: str = "MiniMax-M3",
|
||||||
writer_max_iters: int = 40,
|
writer_max_iters: int = 40,
|
||||||
credential_id: str | None = None,
|
credential_id: str | None = None,
|
||||||
|
do_design: bool = True,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
"""【路①】新建:注册凭据(若需)→ 建 agent → 建 session → 发 kick,启动一款新富游戏的生成。
|
"""【路①】新建:注册凭据(若需)→ 建 agent → 建 session → 发 kick,启动一款新富游戏的生成。
|
||||||
|
|
||||||
@ -173,13 +204,17 @@ async def start_new_game(
|
|||||||
user_header=user_id)
|
user_header=user_id)
|
||||||
credential_id = cred.get("credential_id") or cred.get("id")
|
credential_id = cred.get("credential_id") or cred.get("id")
|
||||||
|
|
||||||
# ② 建单写 agent:system_prompt=roles.writer_system(题面 + 空 design_text;设计阶段服务态落位见 followup),
|
# ②a 设计阶段(2026-06-24 接进服务路径修收敛):先在控制面进程内跑工作室设计团队产出 design_text,
|
||||||
|
# 喂给 writer 系统提示词——否则 writer 拿空 design、富游戏三门全挂不收敛(006 实证)。best-effort。
|
||||||
|
design_text = await _run_design_phase(brief, model_name) if do_design else ""
|
||||||
|
|
||||||
|
# ②b 建单写 agent:system_prompt=roles.writer_system(题面 + 富游戏 design_text),
|
||||||
# react_config 放开轮数,context_config=tier2 富游戏历史压缩(防长程多文件丢约定)。
|
# react_config 放开轮数,context_config=tier2 富游戏历史压缩(防长程多文件丢约定)。
|
||||||
# context_config / react_config 经 model_dump 转 JSON 传(端点 schema 收 ContextConfig/ReActConfig)。
|
# context_config / react_config 经 model_dump 转 JSON 传(端点 schema 收 ContextConfig/ReActConfig)。
|
||||||
ctx_cfg = config.build_context_config()
|
ctx_cfg = config.build_context_config()
|
||||||
agent_body = {
|
agent_body = {
|
||||||
"name": "tier2-writer",
|
"name": "tier2-writer",
|
||||||
"system_prompt": roles.writer_system(brief, "", fixture_hint=""),
|
"system_prompt": roles.writer_system(brief, design_text, fixture_hint=""),
|
||||||
"context_config": ctx_cfg.model_dump(mode="json"),
|
"context_config": ctx_cfg.model_dump(mode="json"),
|
||||||
"react_config": {"max_iters": writer_max_iters},
|
"react_config": {"max_iters": writer_max_iters},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -244,6 +244,7 @@ async def drive_generation(
|
|||||||
model_name: str = "MiniMax-M3",
|
model_name: str = "MiniMax-M3",
|
||||||
writer_max_iters: int | None = None,
|
writer_max_iters: int | None = None,
|
||||||
user_id: str = "tier2",
|
user_id: str = "tier2",
|
||||||
|
do_design: bool = True,
|
||||||
sse_turn_timeout_s: float = 1200.0,
|
sse_turn_timeout_s: float = 1200.0,
|
||||||
sse_idle_timeout_s: float = 300.0,
|
sse_idle_timeout_s: float = 300.0,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
@ -291,7 +292,7 @@ async def drive_generation(
|
|||||||
try:
|
try:
|
||||||
started = await bootstrap.start_new_game(
|
started = await bootstrap.start_new_game(
|
||||||
base_url, brief, user_id=user_id, model_name=model_name,
|
base_url, brief, user_id=user_id, model_name=model_name,
|
||||||
writer_max_iters=writer_max_iters)
|
writer_max_iters=writer_max_iters, do_design=do_design)
|
||||||
except Exception as e: # noqa: BLE001 —— 启动失败 best-effort 落结果、记日志,不静默吞
|
except Exception as e: # noqa: BLE001 —— 启动失败 best-effort 落结果、记日志,不静默吞
|
||||||
result["stopped_reason"] = f"start_failed:{type(e).__name__}: {e}"
|
result["stopped_reason"] = f"start_failed:{type(e).__name__}: {e}"
|
||||||
result["wall_s"] = round(time.perf_counter() - t0, 1)
|
result["wall_s"] = round(time.perf_counter() - t0, 1)
|
||||||
@ -407,12 +408,14 @@ def main(argv: list[str] | None = None) -> int:
|
|||||||
help="单写 ReAct 放开轮数(默认从 generation.yaml iteration.writer_max_iters 读)。")
|
help="单写 ReAct 放开轮数(默认从 generation.yaml iteration.writer_max_iters 读)。")
|
||||||
parser.add_argument("--model-name", default="MiniMax-M3", help="模型名(默认 MiniMax-M3)。")
|
parser.add_argument("--model-name", default="MiniMax-M3", help="模型名(默认 MiniMax-M3)。")
|
||||||
parser.add_argument("--user-id", default="tier2", help="多租户用户标识(默认 tier2)。")
|
parser.add_argument("--user-id", default="tier2", help="多租户用户标识(默认 tier2)。")
|
||||||
|
parser.add_argument("--no-design", action="store_true",
|
||||||
|
help="跳过阶段 1 工作室设计(writer 拿空 design_text;调试/对照用)。默认跑设计。")
|
||||||
args = parser.parse_args(argv)
|
args = parser.parse_args(argv)
|
||||||
|
|
||||||
res = asyncio.run(drive_generation(
|
res = asyncio.run(drive_generation(
|
||||||
args.base_url, args.game_id, args.brief,
|
args.base_url, args.game_id, args.brief,
|
||||||
max_resumes=args.max_resumes, writer_max_iters=args.writer_max_iters,
|
max_resumes=args.max_resumes, writer_max_iters=args.writer_max_iters,
|
||||||
model_name=args.model_name, user_id=args.user_id))
|
model_name=args.model_name, user_id=args.user_id, do_design=not args.no_design))
|
||||||
# 结构化结果打到 stdout(可被上层脚本捕获)。
|
# 结构化结果打到 stdout(可被上层脚本捕获)。
|
||||||
print(json.dumps(res, ensure_ascii=False, indent=2), flush=True)
|
print(json.dumps(res, ensure_ascii=False, indent=2), flush=True)
|
||||||
# 退出码:门绿落库成功 = 0,否则 1(供编排脚本判成败)。
|
# 退出码:门绿落库成功 = 0,否则 1(供编排脚本判成败)。
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user