feat(workflow): add per-agent vision configuration
This commit is contained in:
@@ -16,6 +16,7 @@ from schemas import AssistantOut, AssistantUpsert
|
||||
from services.auth import require_admin
|
||||
from services.masking import mask, resolve_incoming_key
|
||||
from services.node_specs import graph_references, normalize_graph, validate_graph
|
||||
from services.workflow_engine import WorkflowEngine
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
@@ -35,6 +36,10 @@ def _validate_workflow(body: AssistantUpsert) -> None:
|
||||
errors = validate_graph(body.graph)
|
||||
if errors:
|
||||
raise HTTPException(400, "工作流校验失败:" + ";".join(errors))
|
||||
# Graph settings are the source of truth. The flat flag is only a session
|
||||
# capability summary used by clients to decide whether to open the camera.
|
||||
body.vision_enabled = WorkflowEngine(body.graph).uses_vision()
|
||||
body.vision_model_resource_id = None
|
||||
refs = graph_references(body.graph)
|
||||
body.tool_ids = list(dict.fromkeys([*body.tool_ids, *sorted(refs["tools"])]))
|
||||
|
||||
@@ -45,8 +50,10 @@ async def _validate_workflow_references(
|
||||
if body.type != "workflow" or not body.graph.get("nodes"):
|
||||
return
|
||||
graph = body.graph
|
||||
engine = WorkflowEngine(graph)
|
||||
settings = graph.get("settings") or {}
|
||||
resource_expectations: dict[str, str] = {}
|
||||
vision_resource_ids: set[str] = set()
|
||||
for key, capability in (
|
||||
("defaultLlmResourceId", "LLM"),
|
||||
("defaultAsrResourceId", "ASR"),
|
||||
@@ -71,10 +78,32 @@ async def _validate_workflow_references(
|
||||
resource_expectations[str(data["ttsResourceId"])] = "TTS"
|
||||
if data.get("knowledgeBaseId"):
|
||||
knowledge_ids.add(str(data["knowledgeBaseId"]))
|
||||
for node_id, node in engine.nodes.items():
|
||||
if node.get("type") != "agent":
|
||||
continue
|
||||
stage = engine.agent_stage_config(node_id)
|
||||
if not stage.vision_enabled:
|
||||
continue
|
||||
resource_id = (
|
||||
stage.vision_model_resource_id or stage.llm_resource_id
|
||||
)
|
||||
if not resource_id:
|
||||
raise HTTPException(
|
||||
400,
|
||||
f"Agent 节点 {node_id} 开启视觉理解时必须选择"
|
||||
"支持图片输入的大语言模型或视觉模型",
|
||||
)
|
||||
resource_expectations[resource_id] = "LLM"
|
||||
vision_resource_ids.add(resource_id)
|
||||
for resource_id, capability in resource_expectations.items():
|
||||
resource = await session.get(ModelResource, resource_id)
|
||||
if not resource or not resource.enabled or resource.capability != capability:
|
||||
raise HTTPException(400, f"Workflow 引用了无效的 {capability} 资源:{resource_id}")
|
||||
if resource_id in vision_resource_ids and not resource.support_image_input:
|
||||
raise HTTPException(
|
||||
400,
|
||||
f"Workflow 视觉模型必须支持图片输入:{resource_id}",
|
||||
)
|
||||
for knowledge_id in knowledge_ids:
|
||||
knowledge = await session.get(KnowledgeBase, knowledge_id)
|
||||
if not knowledge or knowledge.status != "active":
|
||||
@@ -84,6 +113,9 @@ async def _validate_workflow_references(
|
||||
async def _validate_vision_model(
|
||||
session: AsyncSession, body: AssistantUpsert
|
||||
) -> None:
|
||||
# Workflow 的视觉模型属于图中的全局/Agent 配置,由上面的图引用校验处理。
|
||||
if body.type == "workflow":
|
||||
return
|
||||
if body.vision_enabled:
|
||||
if body.vision_model_resource_id:
|
||||
resource = await session.get(ModelResource, body.vision_model_resource_id)
|
||||
|
||||
@@ -163,8 +163,13 @@ async def _handle_offer_payload(payload, peers):
|
||||
else:
|
||||
cfg = await _resolve_config(offer) # 解析放在建连前,配置错就别建连
|
||||
# 服务端助手配置是视觉理解的唯一授权来源;客户端 offer 只负责携带媒体轨。
|
||||
vision_enabled = cfg.vision_enabled
|
||||
if vision_enabled:
|
||||
if cfg.type == "workflow":
|
||||
from services.workflow_engine import WorkflowEngine
|
||||
|
||||
vision_enabled = WorkflowEngine(cfg.graph).uses_vision()
|
||||
else:
|
||||
vision_enabled = cfg.vision_enabled
|
||||
if vision_enabled and cfg.type != "workflow":
|
||||
has_native_vision = (
|
||||
not cfg.vision_model_resource_id and cfg.llm_support_image_input
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user