feat(server): add workbench API, DSH planner worker and RAG pipeline
This commit is contained in:
@@ -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"]
|
||||
Reference in New Issue
Block a user