From 553e658e05f1d3f5bd41141db4382e4ba6991e2f Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 26 Dec 2025 10:24:36 +0800 Subject: [PATCH] [modify] app_api --- .../controllers/service/app_api_controller.py | 50 ++++++++++-------- api/app/models/multi_agent_model.py | 52 ++++++++++++------- api/app/services/app_service.py | 17 +++++- 3 files changed, 76 insertions(+), 43 deletions(-) diff --git a/api/app/controllers/service/app_api_controller.py b/api/app/controllers/service/app_api_controller.py index eb22548f..b2256a98 100644 --- a/api/app/controllers/service/app_api_controller.py +++ b/api/app/controllers/service/app_api_controller.py @@ -1,30 +1,28 @@ """App 服务接口 - 基于 API Key 认证""" -import uuid +from typing import Annotated + from fastapi import APIRouter, Depends, Request, Body from sqlalchemy.orm import Session -from typing import Optional, Annotated - from starlette.responses import StreamingResponse from app.core.api_key_auth import require_api_key -from app.db import get_db -from app.core.response_utils import success +from app.core.error_codes import BizCode +from app.core.exceptions import BusinessException from app.core.logging_config import get_business_logger +from app.core.response_utils import success +from app.db import get_db from app.dependencies import get_app_or_workspace -from app.models import AppRelease -from app.repositories import knowledge_repository -from app.schemas import AppChatRequest, conversation_schema from app.models.app_model import App from app.models.app_model import AppType +from app.repositories import knowledge_repository from app.repositories.end_user_repository import EndUserRepository -from app.core.exceptions import BusinessException -from app.core.error_codes import BizCode +from app.schemas import AppChatRequest, conversation_schema +from app.schemas.api_key_schema import ApiKeyAuth from app.services import workspace_service from app.services.app_chat_service import AppChatService, get_app_chat_service -from app.services.app_service import AppService from app.services.conversation_service import ConversationService, get_conversation_service -from app.services.workflow_service import WorkflowService, get_workflow_service -from app.utils.app_config_utils import dict_to_multi_agent_config,dict_to_workflow_config,agent_config_4_app_release +from app.utils.app_config_utils import dict_to_multi_agent_config, dict_to_workflow_config, agent_config_4_app_release +from app.services.app_service import get_app_service, AppService router = APIRouter(prefix="/app", tags=["V1 - App API"]) logger = get_business_logger() @@ -37,8 +35,9 @@ async def list_apps(): # /v1/apps/{resource_id}/chat - -# async def chat( +# @router.post("/chat") +# @require_api_key(scopes=["app"]) +# async def chat2( # request: Request, # api_key_auth: ApiKeyAuth = None, # db: Session = Depends(get_db), @@ -57,7 +56,6 @@ async def list_apps(): # db: db_session # """ # logger.info(f"API Key Auth: {api_key_auth}") -# logger.info(f"Resource ID: {resource_id}") # logger.info(f"Message: {message}") # return success(data={"received": True}, msg="消息已接收") @@ -76,15 +74,21 @@ def _checkAppConfig(app: App): raise BusinessException("不支持的应用类型", BizCode.AGENT_CONFIG_MISSING) @router.post("/chat") -# @require_api_key(scopes=["app"]) +@require_api_key(scopes=["app"]) async def chat( - payload: AppChatRequest, - app: App = Depends(get_app_or_workspace), + request:Request, + api_key_auth: ApiKeyAuth = None, db: Session = Depends(get_db), conversation_service: Annotated[ConversationService, Depends(get_conversation_service)] = None, app_chat_service: Annotated[AppChatService, Depends(get_app_chat_service)] = None, - + app_service: Annotated[AppService, Depends(get_app_service)] = None, + message: str = Body(..., description="聊天消息内容"), ): + body = await request.json() + payload = AppChatRequest(**body) + + other_id = payload.user_id + app = app_service.get_app(api_key_auth.resource_id, api_key_auth.workspace_id) other_id = payload.user_id workspace_id = app.workspace_id end_user_repo = EndUserRepository(db) @@ -176,7 +180,7 @@ async def chat( storage_type=storage_type, user_rag_memory_id=user_rag_memory_id ) - return success(data=conversation_schema.ChatResponse(**result)) + return success(data=conversation_schema.ChatResponse(**result).model_dump(mode="json")) elif app_type == AppType.MULTI_AGENT: # 多 Agent 流式返回 config = dict_to_multi_agent_config(app.current_release.config,app.id) @@ -220,7 +224,7 @@ async def chat( user_rag_memory_id=user_rag_memory_id ) - return success(data=conversation_schema.ChatResponse(**result)) + return success(data=conversation_schema.ChatResponse(**result).model_dump(mode="json")) elif app_type == AppType.WORKFLOW: # 多 Agent 流式返回 config = dict_to_workflow_config(app.current_release.config,app.id) @@ -264,7 +268,7 @@ async def chat( user_rag_memory_id=user_rag_memory_id ) - return success(data=conversation_schema.ChatResponse(**result)) + return success(data=conversation_schema.ChatResponse(**result).model_dump(mode="json")) else: from app.core.exceptions import BusinessException from app.core.error_codes import BizCode diff --git a/api/app/models/multi_agent_model.py b/api/app/models/multi_agent_model.py index 061ecffa..bdaa0a70 100644 --- a/api/app/models/multi_agent_model.py +++ b/api/app/models/multi_agent_model.py @@ -1,26 +1,42 @@ """多 Agent 相关数据模型""" import datetime import uuid +from enum import StrEnum + from sqlalchemy import Column, String, Boolean, DateTime, Integer, Float, Text, ForeignKey from sqlalchemy.dialects.postgresql import UUID, JSON from sqlalchemy.orm import relationship from app.db import Base +class OrchestrationMode(StrEnum): + """图标类型枚举""" + SEQUENTIAL = "sequential" + PARALLEL = "parallel" + CONDITIONAL = "conditional" + +class AggregationStrategy(StrEnum): + """图标类型枚举""" + MERGE = "merge" + VOTE = "vote" + PRIORITY = "priority" class MultiAgentConfig(Base): """多 Agent 配置表""" __tablename__ = "multi_agent_configs" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True) - + # 关联应用 app_id = Column(UUID(as_uuid=True), ForeignKey("apps.id"), nullable=False, unique=True, index=True, comment="关联应用") - + # 主 Agent (存储发布版本 ID) - master_agent_id = Column(UUID(as_uuid=True), ForeignKey("app_releases.id"), nullable=False, comment="主 Agent 发布版本 ID") + master_agent_id = Column(UUID(as_uuid=True), ForeignKey("app_releases.id"), nullable=True, comment="主 Agent 发布版本 ID") master_agent_name = Column(String(100), comment="主 Agent 名称") - + + default_model_config_id = Column(UUID(as_uuid=True), ForeignKey("model_configs.id"), nullable=False,server_default=str(uuid.UUID(int=0)), index=True, comment="默认模型配置ID") + # 结构化配置(直接存储 JSON) + model_parameters = Column(JSON, nullable=True, comment="模型参数配置(temperature、max_tokens等)") # 协作模式 orchestration_mode = Column( String(20), @@ -28,7 +44,7 @@ class MultiAgentConfig(Base): default="conditional", comment="协作模式: sequential|parallel|conditional|loop" ) - + # 子 Agent 列表 sub_agents = Column( JSON, @@ -36,13 +52,13 @@ class MultiAgentConfig(Base): default=list, comment="子 Agent 列表: [{'agent_id': 'uuid', 'name': '...', 'role': '...', 'priority': 1}]" ) - + # 路由规则 routing_rules = Column( JSON, comment="路由规则: [{'condition': '...', 'target_agent_id': 'uuid', 'priority': 1}]" ) - + # 执行配置 execution_config = Column( JSON, @@ -50,7 +66,7 @@ class MultiAgentConfig(Base): default=dict, comment="执行配置: {'max_iterations': 5, 'timeout': 60, 'parallel_limit': 3}" ) - + # 结果整合策略 aggregation_strategy = Column( String(20), @@ -58,12 +74,12 @@ class MultiAgentConfig(Base): default="merge", comment="结果整合策略: merge|vote|priority|custom" ) - + # 状态 is_active = Column(Boolean, default=True, nullable=False) created_at = Column(DateTime, default=datetime.datetime.now) updated_at = Column(DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now) - + # 关系 app = relationship("App") master_agent_release = relationship("AppRelease", foreign_keys=[master_agent_id]) @@ -77,7 +93,7 @@ class AgentInvocation(Base): __tablename__ = "agent_invocations" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True) - + # 调用关系 caller_agent_id = Column( UUID(as_uuid=True), @@ -93,7 +109,7 @@ class AgentInvocation(Base): index=True, comment="被调用者 Agent ID" ) - + # 关联信息 conversation_id = Column( UUID(as_uuid=True), @@ -106,12 +122,12 @@ class AgentInvocation(Base): index=True, comment="父调用 ID(用于追踪调用链)" ) - + # 输入输出 input_message = Column(Text, nullable=False, comment="输入消息") output_message = Column(Text, comment="输出消息") context = Column(JSON, comment="上下文信息") - + # 状态 status = Column( String(20), @@ -121,18 +137,18 @@ class AgentInvocation(Base): comment="状态: pending|running|completed|failed" ) error_message = Column(Text, comment="错误信息") - + # 性能指标 started_at = Column(DateTime, nullable=False, default=datetime.datetime.now, index=True) completed_at = Column(DateTime) elapsed_time = Column(Float, comment="耗时(秒)") token_usage = Column(JSON, comment="Token 使用情况") - + # 元数据 meta_data = Column(JSON, comment="额外元数据") - + created_at = Column(DateTime, default=datetime.datetime.now) - + # 关系 caller = relationship("AgentConfig", foreign_keys=[caller_agent_id]) callee = relationship("AgentConfig", foreign_keys=[callee_agent_id]) diff --git a/api/app/services/app_service.py b/api/app/services/app_service.py index 99bab984..1658ef8b 100644 --- a/api/app/services/app_service.py +++ b/api/app/services/app_service.py @@ -9,8 +9,9 @@ """ import datetime import uuid -from typing import Optional, List, Dict, Any, Tuple +from typing import Optional, List, Dict, Any, Tuple, Annotated +from fastapi import Depends from sqlalchemy import select, func, or_, and_ from sqlalchemy.orm import Session @@ -20,6 +21,7 @@ from app.core.exceptions import ( BusinessException, ) from app.core.logging_config import get_business_logger +from app.db import get_db from app.models import App, AgentConfig, AppRelease, MultiAgentConfig, WorkflowConfig from app.models.app_model import AppStatus, AppType from app.repositories.app_repository import get_apps_by_id @@ -1407,7 +1409,7 @@ class AppService: ResourceNotFoundException: 当应用不存在时 BusinessException: 当应用不在指定工作空间或目标工作空间无效时 """ - + logger.info( "分享应用", @@ -2095,3 +2097,14 @@ async def draft_run_stream( workspace_id=workspace_id ): yield event + + + + +# ==================== 依赖注入函数 ==================== + +def get_app_service( + db: Annotated[Session, Depends(get_db)] +) -> AppService: + """获取工作流服务(依赖注入)""" + return AppService(db)