- Fix delete agent 500: clean up FK records (agent_llm_logs, permissions, schedules, executions, team_members) and unbind goals/tasks before delete - Remove hardcoded personality templates in Android, replace with dynamic system prompt generation from name + description - Set promptSectionsEnabled=false to bypass PromptComposer for personality - Add Tencent Cloud Linux deployment guide (Docker Compose) - Accumulated backend service updates, frontend UI fixes, Android app changes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
241 lines
12 KiB
Python
241 lines
12 KiB
Python
"""
|
||
模板市场预置模板引导
|
||
|
||
应用启动时自动检测并注入 8 个预置模板(若市场为空)。
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
import logging
|
||
import uuid
|
||
from datetime import datetime, timedelta
|
||
from typing import List, Dict, Any
|
||
|
||
from sqlalchemy.orm import Session
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
# 8 个预置模板定义
|
||
PRESET_TEMPLATES: List[Dict[str, Any]] = [
|
||
# ─── 1. 客服场景 ───
|
||
{
|
||
"name": "智能客服工作流",
|
||
"description": "通用客服问答场景,含问题分类与转人工逻辑,适合企业客服自动化。",
|
||
"category": "customer_service",
|
||
"tags": ["客服", "AI", "自动化", "FAQ"],
|
||
"is_featured": True,
|
||
"nodes": [
|
||
{"id": "start-1", "type": "start", "position": {"x": 80, "y": 120}, "data": {}},
|
||
{"id": "llm-1", "type": "llm", "position": {"x": 320, "y": 120},
|
||
"data": {"prompt": "你是企业客服场景 Agent。根据用户问题给出清晰、可执行的回答;不确定时先澄清。\n用户输入:{{input}}", "temperature": 0.35, "provider": "deepseek", "model": "deepseek-chat"}},
|
||
{"id": "end-1", "type": "end", "position": {"x": 560, "y": 120}, "data": {}},
|
||
],
|
||
"edges": [
|
||
{"id": "e_start_llm", "source": "start-1", "target": "llm-1", "sourceHandle": "right", "targetHandle": "left"},
|
||
{"id": "e_llm_end", "source": "llm-1", "target": "end-1", "sourceHandle": "right", "targetHandle": "left"},
|
||
],
|
||
},
|
||
# ─── 2. 研发/代码助手 ───
|
||
{
|
||
"name": "研发代码助手",
|
||
"description": "代码生成与设计说明辅助,优先给出可运行示例与步骤。",
|
||
"category": "dev",
|
||
"tags": ["代码", "开发", "LLM", "辅助"],
|
||
"is_featured": True,
|
||
"nodes": [
|
||
{"id": "start-1", "type": "start", "position": {"x": 80, "y": 120}, "data": {}},
|
||
{"id": "llm-1", "type": "llm", "position": {"x": 320, "y": 120},
|
||
"data": {"prompt": "你是研发辅助 Agent,负责代码与设计说明。优先给出可运行示例与步骤;涉及安全/生产变更时明确风险。\n用户诉求:{{input}}", "temperature": 0.25, "provider": "deepseek", "model": "deepseek-chat"}},
|
||
{"id": "end-1", "type": "end", "position": {"x": 560, "y": 120}, "data": {}},
|
||
],
|
||
"edges": [
|
||
{"id": "e_start_llm", "source": "start-1", "target": "llm-1", "sourceHandle": "right", "targetHandle": "left"},
|
||
{"id": "e_llm_end", "source": "llm-1", "target": "end-1", "sourceHandle": "right", "targetHandle": "left"},
|
||
],
|
||
},
|
||
# ─── 3. 运维/日志分析 ───
|
||
{
|
||
"name": "运维日志分析",
|
||
"description": "日志解读与排查建议,帮助快速定位线上问题根因。",
|
||
"category": "ops",
|
||
"tags": ["运维", "日志", "排查", "监控"],
|
||
"is_featured": True,
|
||
"nodes": [
|
||
{"id": "start-1", "type": "start", "position": {"x": 80, "y": 120}, "data": {}},
|
||
{"id": "llm-1", "type": "llm", "position": {"x": 320, "y": 120},
|
||
"data": {"prompt": "你是运维/日志分析场景 Agent。帮助用户解读日志片段、定位可能原因与下一步排查;不要编造未提供的日志内容。\n用户输入:{{input}}", "temperature": 0.3, "provider": "deepseek", "model": "deepseek-chat"}},
|
||
{"id": "end-1", "type": "end", "position": {"x": 560, "y": 120}, "data": {}},
|
||
],
|
||
"edges": [
|
||
{"id": "e_start_llm", "source": "start-1", "target": "llm-1", "sourceHandle": "right", "targetHandle": "left"},
|
||
{"id": "e_llm_end", "source": "llm-1", "target": "end-1", "sourceHandle": "right", "targetHandle": "left"},
|
||
],
|
||
},
|
||
# ─── 4. 简单LLM工作流 ───
|
||
{
|
||
"name": "简单LLM工作流",
|
||
"description": "最基础的三节点工作流(开始→LLM→结束),适合快速体验 Agent 编排。",
|
||
"category": "llm",
|
||
"tags": ["入门", "LLM", "基础"],
|
||
"is_featured": True,
|
||
"nodes": [
|
||
{"id": "start-1", "type": "start", "position": {"x": 100, "y": 100}, "data": {"label": "开始"}},
|
||
{"id": "llm-1", "type": "llm", "position": {"x": 100, "y": 250},
|
||
"data": {"label": "LLM处理", "prompt": "请处理以下输入:\n{{input}}", "provider": "deepseek", "model": "deepseek-chat", "temperature": 0.7}},
|
||
{"id": "end-1", "type": "end", "position": {"x": 100, "y": 400}, "data": {"label": "结束"}},
|
||
],
|
||
"edges": [
|
||
{"id": "e1", "source": "start-1", "target": "llm-1", "sourceHandle": "bottom", "targetHandle": "top"},
|
||
{"id": "e2", "source": "llm-1", "target": "end-1", "sourceHandle": "bottom", "targetHandle": "top"},
|
||
],
|
||
},
|
||
# ─── 5. 条件判断LLM工作流 ───
|
||
{
|
||
"name": "条件判断工作流",
|
||
"description": "含条件分支的 LLM 工作流,根据输入值走向不同处理路径。",
|
||
"category": "llm",
|
||
"tags": ["条件", "分支", "LLM", "中级"],
|
||
"is_featured": False,
|
||
"nodes": [
|
||
{"id": "start-1", "type": "start", "position": {"x": 100, "y": 100}, "data": {"label": "开始"}},
|
||
{"id": "condition-1", "type": "condition", "position": {"x": 100, "y": 200},
|
||
"data": {"label": "条件判断", "condition": "{{value}} > 10"}},
|
||
{"id": "llm-true", "type": "llm", "position": {"x": -100, "y": 350},
|
||
"data": {"label": "True分支LLM", "prompt": "值大于10,请分析:{{input}}", "provider": "deepseek", "model": "deepseek-chat"}},
|
||
{"id": "llm-false", "type": "llm", "position": {"x": 300, "y": 350},
|
||
"data": {"label": "False分支LLM", "prompt": "值小于等于10,请分析:{{input}}", "provider": "deepseek", "model": "deepseek-chat"}},
|
||
{"id": "end-1", "type": "end", "position": {"x": 100, "y": 500}, "data": {"label": "结束"}},
|
||
],
|
||
"edges": [
|
||
{"id": "e1", "source": "start-1", "target": "condition-1"},
|
||
{"id": "e2", "source": "condition-1", "target": "llm-true", "sourceHandle": "true"},
|
||
{"id": "e3", "source": "condition-1", "target": "llm-false", "sourceHandle": "false"},
|
||
{"id": "e4", "source": "llm-true", "target": "end-1"},
|
||
{"id": "e5", "source": "llm-false", "target": "end-1"},
|
||
],
|
||
},
|
||
# ─── 6. 数据转换+LLM ───
|
||
{
|
||
"name": "数据转换与LLM",
|
||
"description": "先进行数据映射转换,再将结果送入 LLM 处理,适合 ETL+AI 场景。",
|
||
"category": "data_processing",
|
||
"tags": ["数据", "转换", "ETL", "LLM"],
|
||
"is_featured": False,
|
||
"nodes": [
|
||
{"id": "start-1", "type": "start", "position": {"x": 100, "y": 100}, "data": {"label": "开始"}},
|
||
{"id": "transform-1", "type": "transform", "position": {"x": 100, "y": 200},
|
||
"data": {"label": "数据转换", "mode": "mapping", "mapping": {"input_text": "raw_input", "user_id": "id"}}},
|
||
{"id": "llm-1", "type": "llm", "position": {"x": 100, "y": 300},
|
||
"data": {"label": "LLM处理", "prompt": "处理转换后的数据:{{input_text}}", "provider": "deepseek", "model": "deepseek-chat"}},
|
||
{"id": "end-1", "type": "end", "position": {"x": 100, "y": 400}, "data": {"label": "结束"}},
|
||
],
|
||
"edges": [
|
||
{"id": "e1", "source": "start-1", "target": "transform-1"},
|
||
{"id": "e2", "source": "transform-1", "target": "llm-1"},
|
||
{"id": "e3", "source": "llm-1", "target": "end-1"},
|
||
],
|
||
},
|
||
# ─── 7. 多LLM链式工作流 ───
|
||
{
|
||
"name": "多LLM链式处理",
|
||
"description": "三个 LLM 节点链式串联:分析→处理→总结,实现复杂多步推理。",
|
||
"category": "llm",
|
||
"tags": ["链式", "多步", "LLM", "高级"],
|
||
"is_featured": True,
|
||
"nodes": [
|
||
{"id": "start-1", "type": "start", "position": {"x": 100, "y": 100}, "data": {"label": "开始"}},
|
||
{"id": "llm-1", "type": "llm", "position": {"x": 100, "y": 200},
|
||
"data": {"label": "第一步分析", "prompt": "第一步:分析输入数据:{{input}}", "provider": "deepseek", "model": "deepseek-chat"}},
|
||
{"id": "llm-2", "type": "llm", "position": {"x": 100, "y": 300},
|
||
"data": {"label": "第二步处理", "prompt": "第二步:基于第一步的结果进行处理:{{input}}", "provider": "deepseek", "model": "deepseek-chat"}},
|
||
{"id": "llm-3", "type": "llm", "position": {"x": 100, "y": 400},
|
||
"data": {"label": "第三步总结", "prompt": "第三步:总结最终结果:{{input}}", "provider": "deepseek", "model": "deepseek-chat"}},
|
||
{"id": "end-1", "type": "end", "position": {"x": 100, "y": 500}, "data": {"label": "结束"}},
|
||
],
|
||
"edges": [
|
||
{"id": "e1", "source": "start-1", "target": "llm-1"},
|
||
{"id": "e2", "source": "llm-1", "target": "llm-2"},
|
||
{"id": "e3", "source": "llm-2", "target": "llm-3"},
|
||
{"id": "e4", "source": "llm-3", "target": "end-1"},
|
||
],
|
||
},
|
||
# ─── 8. 定时自动化工作流 ───
|
||
{
|
||
"name": "定时自动化工作流",
|
||
"description": "含定时触发器的数据同步工作流,适合周期性批量任务。",
|
||
"category": "automation",
|
||
"tags": ["定时", "自动化", "同步", "批量"],
|
||
"is_featured": False,
|
||
"nodes": [
|
||
{"id": "start-1", "type": "start", "position": {"x": 100, "y": 100}, "data": {"label": "开始"}},
|
||
{"id": "schedule-1", "type": "schedule", "position": {"x": 100, "y": 200},
|
||
"data": {"label": "定时触发", "delay_type": "fixed", "delay_value": 3600, "delay_unit": "seconds"}},
|
||
{"id": "llm-1", "type": "llm", "position": {"x": 100, "y": 300},
|
||
"data": {"label": "任务处理", "prompt": "执行定时任务并生成报告:{{input}}", "provider": "deepseek", "model": "deepseek-chat"}},
|
||
{"id": "end-1", "type": "end", "position": {"x": 100, "y": 400}, "data": {"label": "结束"}},
|
||
],
|
||
"edges": [
|
||
{"id": "e1", "source": "start-1", "target": "schedule-1"},
|
||
{"id": "e2", "source": "schedule-1", "target": "llm-1"},
|
||
{"id": "e3", "source": "llm-1", "target": "end-1"},
|
||
],
|
||
},
|
||
]
|
||
|
||
|
||
def bootstrap_preset_templates(db: Session) -> int:
|
||
"""若模板市场为空,注入 8 个预置模板。返回注入数量。"""
|
||
from app.models.workflow_template import WorkflowTemplate
|
||
from app.models.user import User
|
||
|
||
# 检查是否已有模板
|
||
existing_count = db.query(WorkflowTemplate).count()
|
||
if existing_count >= 8:
|
||
logger.info("模板市场已有 %s 个模板,跳过预置注入", existing_count)
|
||
return 0
|
||
|
||
# 获取系统用户(优先 admin,否则第一个用户)
|
||
admin = db.query(User).filter(User.username == "admin").first()
|
||
if not admin:
|
||
admin = db.query(User).order_by(User.created_at.asc()).first()
|
||
if not admin:
|
||
logger.warning("无可用用户,跳过模板市场预置注入")
|
||
return 0
|
||
|
||
logger.info("模板市场仅 %s 个模板,开始注入 8 个预置模板 (用户=%s)...", existing_count, admin.username)
|
||
|
||
added = 0
|
||
now = datetime.utcnow()
|
||
for template_info in PRESET_TEMPLATES:
|
||
# 跳过已存在的同名模板
|
||
exists = db.query(WorkflowTemplate).filter(
|
||
WorkflowTemplate.name == template_info["name"]
|
||
).first()
|
||
if exists:
|
||
continue
|
||
|
||
template = WorkflowTemplate(
|
||
id=str(uuid.uuid4()),
|
||
name=template_info["name"],
|
||
description=template_info["description"],
|
||
category=template_info["category"],
|
||
tags=template_info["tags"],
|
||
nodes=template_info["nodes"],
|
||
edges=template_info["edges"],
|
||
is_public=True,
|
||
is_featured=template_info.get("is_featured", False),
|
||
view_count=0,
|
||
use_count=0,
|
||
rating_count=0,
|
||
rating_avg=0.0,
|
||
user_id=admin.id,
|
||
created_at=now - timedelta(days=30 - added), # 分散创建时间
|
||
updated_at=now,
|
||
)
|
||
db.add(template)
|
||
added += 1
|
||
logger.info(" 预置模板: %s", template_info["name"])
|
||
|
||
db.commit()
|
||
logger.info("模板市场预置注入完成,共注入 %s 个模板", added)
|
||
return added
|