feat(server): add workbench API, DSH planner worker and RAG pipeline

This commit is contained in:
yi
2026-09-16 19:06:20 +08:00
parent 72fc5b47c7
commit d4b5b3f43a
122 changed files with 31906 additions and 0 deletions
+104
View File
@@ -0,0 +1,104 @@
"""全局总监 Agent(画布级):每段生成后判断是否跑偏,跑偏则带指导重做。
- always:每段生成完必审
- on_drift:QC 有问题/质检反复(round>1)时才审(默认,省点数)
- off:不启用
总监不写内容,只输出 JSON:{"on_track": true} 或
{"on_track": false, "reason": "为什么偏了", "guidance": "怎么拉回来"}。
guidance 会注入该段下一轮生成提示,最多重做 1 次,防止无限循环烧点数。
"""
from __future__ import annotations
import json
from sqlmodel import Session
from ..models import Agent, Campaign, Canvas, Segment
SUPERVISOR_INSTRUCTIONS = (
"你是内容生产线的全局总监,负责保证每一段内容不跑偏。"
"给你任务目标、验收标准、本段应讲的主题和已生成的正文。"
"只判断:1) 正文是否围绕本段主题 2) 是否符合任务目标和验收标准 3) 是否夹带无关内容。"
"只输出 JSON:{\"on_track\": true} 或 {\"on_track\": false, \"reason\": \"跑偏原因(一句话)\", "
"\"guidance\": \"给写手的具体拉回指导(一两句话,怎么改)\"}"
)
def _canvas_for(campaign: Campaign, session: Session) -> Canvas | None:
"""任务运行时以画布快照为准;快照存了 supervisor 配置才能启用。"""
snap = campaign.canvas_snapshot or {}
if not isinstance(snap, dict):
return None
supervisor_id = snap.get("supervisor_agent_id")
mode = str(snap.get("supervisor_mode") or "on_drift")
if not supervisor_id or mode == "off":
return None
# 快照配置即可驱动审核;Canvas 实例仅用于传参,不落库
return Canvas(id=0, name="runtime", nodes=[], edges=[],
supervisor_agent_id=int(supervisor_id), supervisor_mode=mode,
organization_id=int(campaign.organization_id or 1))
def _segment_text(seg: Segment) -> str:
"""读取段落正文:优先产物文件,其次锚点卡标题。"""
from pathlib import Path
if seg.artifact_path and Path(seg.artifact_path).is_file():
try:
return Path(seg.artifact_path).read_text(encoding="utf-8")
except OSError:
pass
title = str((seg.anchor_card or {}).get("title") or seg.title or "")
return title
def supervisor_check(session: Session, seg: Segment, campaign: Campaign) -> dict:
"""总监审核一个刚生成完的段。返回 {"checked": bool, "on_track": bool, "guidance": str, "reason": str}。"""
canvas = _canvas_for(campaign, session)
if not canvas:
return {"checked": False}
supervisor = session.get(Agent, int(canvas.supervisor_agent_id or 0))
if not supervisor or supervisor.status != "active":
return {"checked": False}
mode = canvas.supervisor_mode
# on_drift 模式:只审可疑段(质检发现问题或已重做过一轮)
if mode == "on_drift" and seg.status == "approved" and int(seg.round or 1) <= 1:
return {"checked": False}
from ..llm import chat_json
prompt = (
f"任务目标:{campaign.objective}\n"
f"验收标准:{campaign.success_criteria}\n"
f"本段主题:{seg.title}\n"
f"已生成正文:\n{_segment_text(seg)[:4000]}"
)
try:
result = chat_json(
session,
[{"role": "system", "content": SUPERVISOR_INSTRUCTIONS},
{"role": "user", "content": prompt}],
provider_id=0, model="",
campaign_id=int(campaign.id or 0), segment_id=int(seg.id or 0),
agent_id=int(supervisor.id or 0), agent_name=f"{supervisor.name}(总监)",
user_id=int(campaign.owner_user_id or 0),
organization_id=int(campaign.organization_id or 1),
max_retries=1,
)
except Exception:
# 总监审核自身失败不阻断主流程
return {"checked": False}
if result.get("status") != "ok":
return {"checked": False}
try:
verdict = result.get("data") if isinstance(result.get("data"), dict) else json.loads(result.get("text") or "{}")
except (json.JSONDecodeError, TypeError):
verdict = {}
on_track = bool(verdict.get("on_track", True))
if on_track:
return {"checked": True, "on_track": True}
return {"checked": True, "on_track": False,
"reason": str(verdict.get("reason") or "内容偏离本段主题或任务目标")[:200],
"guidance": str(verdict.get("guidance") or "回到本段主题,紧扣任务目标与验收标准重写")[:300]}
__all__ = ["supervisor_check"]