私有化 AI Agent 平台进阶指南:智能知识库、Skill 生态与自定义 Agent 实战

本文档是《本地部署全能 AI Agent 完整方案》的进阶篇,聚焦于知识库自动化运营、Skill 动态发现与注册、生产级稳定性保障、用户自定义 Agent 体系,以及完整的工程化落地方案。适合已完成基础部署、希望将 Agent 平台打造为可持续运营的生产力工具的读者。


第一部分:知识库内容自动获取与持续更新

1.1 核心问题

手动上传文档到知识库效率低、容易过时。需要一套自动化采集 → 清洗 → 入库 → 更新的流水线。

1.2 自动采集架构

text 复制代码
┌─────────────────────────────────────────────────────┐
│                知识库自动化流水线                       │
│                                                     │
│  ┌─────────┐   ┌─────────┐   ┌─────────┐           │
│  │ 数据源   │──▶│ 采集器   │──▶│ 清洗器   │           │
│  │ Sources  │   │ Scrapers│   │ Cleaners│           │
│  └─────────┘   └─────────┘   └─────────┘           │
│       │                            │                │
│       │                            ▼                │
│  ┌─────────┐   ┌─────────┐   ┌─────────┐           │
│  │ 变更检测  │──▶│ 增量更新  │──▶│ Dify    │           │
│  │ Monitor  │   │ Updater │   │ 知识库API│           │
│  └─────────┘   └─────────┘   └─────────┘           │
└─────────────────────────────────────────────────────┘

1.3 各领域知识源自动采集方案

1.3.1 编程开发知识

python 复制代码
# knowledge_scrapers/coding_scraper.py
import requests
import os
import json
from pathlib import Path

class CodingKnowledgeScraper:
    """自动采集编程领域知识"""

    def __init__(self, output_dir: str = "./knowledge/coding"):
        self.output_dir = Path(output_dir)
        self.output_dir.mkdir(parents=True, exist_ok=True)

    def scrape_github_awesome_lists(self):
        """从 GitHub Awesome 列表采集最佳实践"""
        awesome_repos = [
            "sindresorhus/awesome",
            "enaqx/awesome-react",
            "vinta/awesome-python",
            "avelino/awesome-go",
            "typescript-cheatsheets/react",
        ]
        for repo in awesome_repos:
            url = f"https://api.github.com/repos/{repo}/readme"
            resp = requests.get(url, headers={"Accept": "application/vnd.github.v3.raw"})
            if resp.status_code == 200:
                filename = repo.replace("/", "_") + ".md"
                (self.output_dir / filename).write_text(resp.text, encoding="utf-8")

    def scrape_official_docs(self):
        """采集官方文档(通过 Firecrawl / Crawl4AI)"""
        # Crawl4AI: 开源爬虫,专为 AI 知识采集设计
        # pip install crawl4ai
        from crawl4ai import WebCrawler

        crawler = WebCrawler()
        doc_sites = [
            {"url": "https://react.dev/learn", "name": "react_docs"},
            {"url": "https://www.typescriptlang.org/docs/", "name": "typescript_docs"},
            {"url": "https://docs.python.org/3/tutorial/", "name": "python_docs"},
        ]
        for site in doc_sites:
            result = crawler.run(url=site["url"])
            output_file = self.output_dir / f"{site['name']}.md"
            output_file.write_text(result.markdown, encoding="utf-8")

    def scrape_internal_api_docs(self, swagger_urls: list):
        """从 Swagger/OpenAPI 自动生成 API 知识文档"""
        for url in swagger_urls:
            resp = requests.get(url)
            spec = resp.json()
            markdown = self._openapi_to_markdown(spec)
            name = spec.get("info", {}).get("title", "api").replace(" ", "_")
            (self.output_dir / f"api_{name}.md").write_text(markdown, encoding="utf-8")

    def _openapi_to_markdown(self, spec: dict) -> str:
        """将 OpenAPI spec 转为可读的 Markdown 文档"""
        lines = [f"# {spec.get('info', {}).get('title', 'API Documentation')}\n"]
        for path, methods in spec.get("paths", {}).items():
            for method, detail in methods.items():
                if isinstance(detail, dict):
                    summary = detail.get("summary", "")
                    lines.append(f"## {method.upper()} {path}")
                    lines.append(f"{summary}\n")
                    # 参数
                    params = detail.get("parameters", [])
                    if params:
                        lines.append("**Parameters:**")
                        for p in params:
                            lines.append(f"- `{p.get('name')}` ({p.get('in')}): {p.get('description', '')}")
                    lines.append("")
        return "\n".join(lines)

    def scrape_stackoverflow_tags(self, tags: list, count: int = 50):
        """采集 StackOverflow 高票问答作为 FAQ 知识"""
        for tag in tags:
            url = f"https://api.stackexchange.com/2.3/questions"
            params = {
                "order": "desc", "sort": "votes",
                "tagged": tag, "site": "stackoverflow",
                "pagesize": count, "filter": "withbody"
            }
            resp = requests.get(url, params=params)
            if resp.status_code == 200:
                items = resp.json().get("items", [])
                content = f"# {tag} FAQ (Top {count})\n\n"
                for item in items:
                    content += f"## Q: {item['title']}\n"
                    content += f"Score: {item['score']} | Answers: {item['answer_count']}\n"
                    content += f"Link: {item['link']}\n\n"
                (self.output_dir / f"faq_{tag}.md").write_text(content, encoding="utf-8")

1.3.2 文案写作知识

python 复制代码
# knowledge_scrapers/writing_scraper.py
class WritingKnowledgeScraper:
    """自动采集文案写作知识"""

    def scrape_copywriting_templates(self):
        """采集营销文案模板库"""
        # 从开源文案库采集
        sources = [
            # 中文文案排版指南
            "https://raw.githubusercontent.com/sparanoid/chinese-copywriting-guidelines/master/README.zh-Hans.md",
        ]
        for url in sources:
            resp = requests.get(url)
            if resp.status_code == 200:
                filename = url.split("/")[-1]
                (self.output_dir / filename).write_text(resp.text, encoding="utf-8")

    def scrape_writing_guides_from_rss(self, rss_feeds: list):
        """从 RSS 订阅持续采集写作技巧文章"""
        import feedparser

        for feed_url in rss_feeds:
            feed = feedparser.parse(feed_url)
            for entry in feed.entries[:20]:  # 每个源取最新20篇
                content = entry.get("summary", entry.get("description", ""))
                title = entry.get("title", "untitled")
                filename = f"{title[:50].replace('/', '_')}.md"
                doc = f"# {title}\n\n{content}\n\nSource: {entry.get('link', '')}"
                (self.output_dir / filename).write_text(doc, encoding="utf-8")

    def generate_style_guide(self, brand_name: str, sample_texts: list):
        """用 LLM 从样本文本中提取品牌风格指南"""
        prompt = f"""分析以下 {brand_name} 的文案样本,提取品牌调性和写作风格指南:

样本:
{chr(10).join(sample_texts)}

请输出:
1. 品牌调性关键词(3-5个)
2. 语言风格特征
3. 常用句式模板
4. 禁用词/表达
5. 典型文案结构"""

        # 调用本地 Qwen 模型
        resp = requests.post("http://localhost:8000/v1/chat/completions", json={
            "model": "qwen2.5-72b",
            "messages": [{"role": "user", "content": prompt}]
        })
        guide = resp.json()["choices"][0]["message"]["content"]
        return guide

1.3.3 图像/视频知识

python 复制代码
# knowledge_scrapers/creative_scraper.py
class CreativeKnowledgeScraper:
    """采集图像和视频创作知识"""

    def scrape_prompt_databases(self):
        """采集高质量 Prompt 数据库"""
        # 从 CivitAI / PromptHero 等平台采集优质 prompt
        # 分类存储:人像、风景、产品、抽象等
        categories = {
            "portrait": "人像摄影 prompt 集合",
            "landscape": "风景 prompt 集合",
            "product": "产品图 prompt 集合",
            "illustration": "插画 prompt 集合",
            "ui_design": "UI 设计 prompt 集合",
        }
        for cat, desc in categories.items():
            # 生成分类 prompt 指南
            prompt = f"请为 FLUX/Stable Diffusion 模型生成 30 个高质量的{desc},每个包含正向和负向 prompt,标注推荐参数(步数、CFG、尺寸)"
            resp = requests.post("http://localhost:8000/v1/chat/completions", json={
                "model": "qwen2.5-72b",
                "messages": [{"role": "user", "content": prompt}]
            })
            content = resp.json()["choices"][0]["message"]["content"]
            (self.output_dir / f"prompts_{cat}.md").write_text(
                f"# {desc}\n\n{content}", encoding="utf-8"
            )

    def scrape_comfyui_workflows(self):
        """从社区采集 ComfyUI 工作流模板"""
        # OpenArt / Comfy.icu 等平台有大量共享工作流
        workflow_categories = [
            "text_to_image_basic",
            "image_to_image",
            "inpainting",
            "upscale",
            "text_to_video",
            "image_to_video",
            "style_transfer",
        ]
        # 将工作流 JSON + 说明文档存入知识库
        for cat in workflow_categories:
            doc = f"# ComfyUI Workflow: {cat}\n\n"
            doc += f"工作流文件: workflows/{cat}.json\n"
            doc += f"使用说明: ...\n"
            (self.output_dir / f"workflow_{cat}.md").write_text(doc, encoding="utf-8")

1.4 自动入库流水线

python 复制代码
# knowledge_pipeline.py --- 知识库自动更新流水线
import hashlib
import json
import requests
from pathlib import Path
from datetime import datetime

class DifyKnowledgeSync:
    """与 Dify 知识库 API 同步"""

    def __init__(self, dify_url: str, api_key: str):
        self.dify_url = dify_url.rstrip("/")
        self.api_key = api_key
        self.headers = {"Authorization": f"Bearer {api_key}"}
        self.state_file = Path("./knowledge_state.json")
        self.state = self._load_state()

    def _load_state(self) -> dict:
        if self.state_file.exists():
            return json.loads(self.state_file.read_text())
        return {"files": {}}

    def _save_state(self):
        self.state_file.write_text(json.dumps(self.state, indent=2, ensure_ascii=False))

    def _file_hash(self, filepath: Path) -> str:
        return hashlib.sha256(filepath.read_bytes()).hexdigest()

    def sync_directory(self, local_dir: str, dataset_id: str):
        """
        将本地目录与 Dify 知识库同步
        - 新文件 → 上传
        - 已修改文件 → 删除旧版本 + 重新上传
        - 已删除文件 → 从知识库删除
        """
        local_dir = Path(local_dir)
        current_files = {}

        # 扫描本地文件
        for f in local_dir.rglob("*"):
            if f.is_file() and f.suffix in (".md", ".txt", ".pdf", ".docx", ".html"):
                rel_path = str(f.relative_to(local_dir))
                file_hash = self._file_hash(f)
                current_files[rel_path] = {"hash": file_hash, "path": str(f)}

        # 对比变更
        old_files = self.state.get("files", {}).get(dataset_id, {})

        # 新增或修改的文件
        for rel_path, info in current_files.items():
            old_hash = old_files.get(rel_path, {}).get("hash")
            if old_hash != info["hash"]:
                print(f"[SYNC] Uploading: {rel_path}")
                # 如果是更新,先删除旧文档
                old_doc_id = old_files.get(rel_path, {}).get("doc_id")
                if old_doc_id:
                    self._delete_document(dataset_id, old_doc_id)
                # 上传新文档
                doc_id = self._upload_document(dataset_id, info["path"])
                current_files[rel_path]["doc_id"] = doc_id

        # 已删除的文件
        for rel_path in set(old_files.keys()) - set(current_files.keys()):
            old_doc_id = old_files[rel_path].get("doc_id")
            if old_doc_id:
                print(f"[SYNC] Deleting: {rel_path}")
                self._delete_document(dataset_id, old_doc_id)

        # 保存状态
        if "files" not in self.state:
            self.state["files"] = {}
        self.state["files"][dataset_id] = current_files
        self._save_state()

    def _upload_document(self, dataset_id: str, filepath: str) -> str:
        """上传文档到 Dify 知识库"""
        url = f"{self.dify_url}/v1/datasets/{dataset_id}/document/create_by_file"
        with open(filepath, "rb") as f:
            files = {"file": f}
            data = {
                "data": json.dumps({
                    "indexing_technique": "high_quality",
                    "process_rule": {
                        "mode": "automatic"
                    }
                })
            }
            resp = requests.post(url, headers=self.headers, files=files, data=data)
        if resp.status_code == 200:
            return resp.json().get("document", {}).get("id", "")
        return ""

    def _delete_document(self, dataset_id: str, document_id: str):
        """从知识库删除文档"""
        url = f"{self.dify_url}/v1/datasets/{dataset_id}/documents/{document_id}"
        requests.delete(url, headers=self.headers)


# ========== 定时任务:每日自动更新 ==========
# crontab: 0 3 * * * python knowledge_pipeline.py

if __name__ == "__main__":
    from knowledge_scrapers.coding_scraper import CodingKnowledgeScraper
    from knowledge_scrapers.writing_scraper import WritingKnowledgeScraper
    from knowledge_scrapers.creative_scraper import CreativeKnowledgeScraper

    # Step 1: 采集
    print(f"[{datetime.now()}] Starting knowledge scrape...")
    CodingKnowledgeScraper("./knowledge/coding").scrape_github_awesome_lists()
    CodingKnowledgeScraper("./knowledge/coding").scrape_official_docs()
    WritingKnowledgeScraper("./knowledge/writing").scrape_copywriting_templates()
    CreativeKnowledgeScraper("./knowledge/creative").scrape_prompt_databases()
    CreativeKnowledgeScraper("./knowledge/creative").scrape_comfyui_workflows()

    # Step 2: 同步到 Dify
    print(f"[{datetime.now()}] Syncing to Dify...")
    syncer = DifyKnowledgeSync(
        dify_url="http://localhost/api",
        api_key="your-dify-api-key"
    )

    # 每个领域对应一个 Dify dataset
    dataset_mapping = {
        "./knowledge/coding": "dataset-id-coding",
        "./knowledge/writing": "dataset-id-writing",
        "./knowledge/creative": "dataset-id-creative",
        "./knowledge/life": "dataset-id-life",
    }
    for local_dir, dataset_id in dataset_mapping.items():
        syncer.sync_directory(local_dir, dataset_id)

    print(f"[{datetime.now()}] Done!")

1.5 知识库质量保障

python 复制代码
# knowledge_quality.py --- 知识库质量检测
class KnowledgeQualityChecker:
    """定期检查知识库质量"""

    def check_freshness(self, knowledge_dir: str, max_age_days: int = 90):
        """检查文档时效性,标记过期内容"""
        stale_files = []
        for f in Path(knowledge_dir).rglob("*"):
            if f.is_file():
                age_days = (datetime.now() - datetime.fromtimestamp(f.stat().st_mtime)).days
                if age_days > max_age_days:
                    stale_files.append({"file": str(f), "age_days": age_days})
        return stale_files

    def check_retrieval_quality(self, dataset_id: str, test_queries: list):
        """用测试查询验证检索质量"""
        results = []
        for query in test_queries:
            # 调用 Dify 检索 API
            resp = requests.post(
                f"http://localhost/api/v1/datasets/{dataset_id}/retrieve",
                headers={"Authorization": "Bearer your-key"},
                json={"query": query, "top_k": 5}
            )
            records = resp.json().get("records", [])
            avg_score = sum(r.get("score", 0) for r in records) / max(len(records), 1)
            results.append({
                "query": query,
                "hit_count": len(records),
                "avg_score": round(avg_score, 3),
                "quality": "GOOD" if avg_score > 0.7 else "NEEDS_IMPROVEMENT"
            })
        return results

    def check_duplicates(self, knowledge_dir: str):
        """检测重复或高度相似的文档"""
        from difflib import SequenceMatcher

        files = list(Path(knowledge_dir).rglob("*.md"))
        duplicates = []
        for i, f1 in enumerate(files):
            for f2 in files[i + 1:]:
                text1 = f1.read_text(encoding="utf-8")[:2000]
                text2 = f2.read_text(encoding="utf-8")[:2000]
                similarity = SequenceMatcher(None, text1, text2).ratio()
                if similarity > 0.8:
                    duplicates.append({
                        "file1": str(f1), "file2": str(f2),
                        "similarity": round(similarity, 2)
                    })
        return duplicates

第二部分:Skill 发现与动态注册

2.1 Skill 体系设计

text 复制代码
┌────────────────────────────────────────────────┐
│               Skill Registry                    │
│                                                │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐     │
│  │ 内置Skills│  │ 社区Skills│  │ 自定义    │     │
│  │ Built-in │  │ Community│  │ Skills   │     │
│  └─────┬────┘  └─────┬────┘  └─────┬────┘     │
│        └──────────┬──┘─────────────┘           │
│                   ▼                            │
│          ┌──────────────┐                      │
│          │ Skill Router │ ← 意图匹配 + 能力发现│
│          └──────┬───────┘                      │
│                 ▼                              │
│          ┌──────────────┐                      │
│          │ Skill Runner │ ← 执行 + 结果聚合    │
│          └──────────────┘                      │
└────────────────────────────────────────────────┘

2.2 Skill 定义标准

json 复制代码
// skills/text2ppt.skill.json
{
  "name": "text2ppt",
  "version": "1.0.0",
  "display_name": "文本转PPT",
  "description": "将文本内容或大纲自动生成专业 PPT 文件",
  "category": "document",
  "tags": ["ppt", "presentation", "office", "演示文稿"],

  "trigger_patterns": [
    "做(一个|份)?PPT",
    "制作演示文稿",
    "生成(PPT|幻灯片)",
    "text.*(to|转|变).*(ppt|slide)"
  ],

  "input_schema": {
    "type": "object",
    "properties": {
      "title": {"type": "string", "description": "PPT标题"},
      "outline": {"type": "string", "description": "内容大纲或主题"},
      "style": {
        "type": "string",
        "enum": ["business", "academic", "creative", "minimal"],
        "default": "business"
      },
      "slide_count": {"type": "integer", "default": 10}
    },
    "required": ["title"]
  },

  "output_schema": {
    "type": "object",
    "properties": {
      "file_path": {"type": "string"},
      "download_url": {"type": "string"},
      "slide_count": {"type": "integer"}
    }
  },

  "dependencies": {
    "tools": ["ppt_generator", "text2img"],
    "knowledge_bases": ["ppt_design"],
    "models": ["qwen2.5-72b"]
  },

  "execution": {
    "type": "workflow",
    "steps": [
      {"action": "llm_generate", "prompt_template": "ppt_outline"},
      {"action": "tool_call", "tool": "text2img", "for_each": "slides"},
      {"action": "tool_call", "tool": "ppt_generator"}
    ]
  }
}

2.3 Skill 自动发现引擎

python 复制代码
# skill_discovery.py --- Skill 自动发现与注册
import json
import re
from pathlib import Path
from typing import Optional

class SkillRegistry:
    """Skill 注册中心"""

    def __init__(self, skills_dir: str = "./skills"):
        self.skills_dir = Path(skills_dir)
        self.skills: dict = {}
        self._load_all_skills()

    def _load_all_skills(self):
        """启动时加载所有 Skill 定义"""
        for skill_file in self.skills_dir.rglob("*.skill.json"):
            with open(skill_file, "r", encoding="utf-8") as f:
                skill = json.load(f)
                self.skills[skill["name"]] = skill
                print(f"[SKILL] Loaded: {skill['name']} ({skill['display_name']})")

    def match_skill(self, user_input: str) -> Optional[dict]:
        """根据用户输入匹配最合适的 Skill"""
        matches = []
        for name, skill in self.skills.items():
            score = 0
            # 1. 正则 trigger 匹配
            for pattern in skill.get("trigger_patterns", []):
                if re.search(pattern, user_input, re.IGNORECASE):
                    score += 10
            # 2. tag 关键词匹配
            for tag in skill.get("tags", []):
                if tag.lower() in user_input.lower():
                    score += 3
            # 3. description 语义匹配(可用 Embedding 增强)
            if score > 0:
                matches.append({"skill": skill, "score": score})

        matches.sort(key=lambda x: x["score"], reverse=True)
        return matches[0]["skill"] if matches else None

    def register_skill(self, skill_definition: dict):
        """动态注册新 Skill"""
        name = skill_definition["name"]
        skill_file = self.skills_dir / f"{name}.skill.json"
        with open(skill_file, "w", encoding="utf-8") as f:
            json.dump(skill_definition, f, ensure_ascii=False, indent=2)
        self.skills[name] = skill_definition
        print(f"[SKILL] Registered: {name}")

    def list_skills(self, category: str = None) -> list:
        """列出所有可用 Skill"""
        skills = list(self.skills.values())
        if category:
            skills = [s for s in skills if s.get("category") == category]
        return [{"name": s["name"], "display_name": s["display_name"],
                 "description": s["description"]} for s in skills]


class SkillDiscoveryAgent:
    """
    Skill 发现 Agent ------ 当用户请求无法匹配现有 Skill 时,
    自动搜索社区/市场,下载并注册新 Skill
    """

    def __init__(self, registry: SkillRegistry):
        self.registry = registry
        # 社区 Skill 市场(可配置多个源)
        self.marketplaces = [
            "https://marketplace.dify.ai/api/skills",   # Dify 官方市场
            "https://registry.mcp.run/api/tools",        # MCP 社区
        ]

    def discover_and_install(self, user_need: str) -> Optional[dict]:
        """
        1. 先在本地匹配
        2. 匹配不到则搜索社区市场
        3. 下载、验证、注册
        """
        # 本地匹配
        skill = self.registry.match_skill(user_need)
        if skill:
            return skill

        # 搜索社区
        print(f"[DISCOVERY] No local skill found for: {user_need}")
        print(f"[DISCOVERY] Searching community marketplaces...")

        for marketplace_url in self.marketplaces:
            try:
                resp = requests.get(marketplace_url, params={"q": user_need}, timeout=10)
                if resp.status_code == 200:
                    results = resp.json().get("results", [])
                    if results:
                        best_match = results[0]
                        print(f"[DISCOVERY] Found: {best_match['name']} from {marketplace_url}")
                        # 下载 Skill 定义
                        skill_def = self._download_skill(best_match["download_url"])
                        if skill_def and self._validate_skill(skill_def):
                            self.registry.register_skill(skill_def)
                            return skill_def
            except Exception as e:
                print(f"[DISCOVERY] Marketplace error: {e}")

        return None

    def _download_skill(self, url: str) -> Optional[dict]:
        """下载 Skill 定义"""
        try:
            resp = requests.get(url, timeout=10)
            return resp.json()
        except Exception:
            return None

    def _validate_skill(self, skill_def: dict) -> bool:
        """验证 Skill 定义的完整性和安全性"""
        required_fields = ["name", "version", "description", "input_schema"]
        for field in required_fields:
            if field not in skill_def:
                print(f"[VALIDATION] Missing required field: {field}")
                return False

        # 安全检查:不允许执行任意代码的 Skill
        execution = skill_def.get("execution", {})
        if execution.get("type") == "code" and "eval" in json.dumps(execution):
            print("[VALIDATION] Rejected: contains unsafe code execution")
            return False

        return True

2.4 内置 Skill 清单

text 复制代码
┌──────────────────────────────────────────────────────────────────┐
│                        内置 Skills 清单                          │
├──────────┬───────────────┬───────────────────────────────────────┤
│ 类别      │ Skill 名称     │ 功能描述                             │
├──────────┼───────────────┼───────────────────────────────────────┤
│ 文案      │ text_rewrite  │ 文案润色/改写/风格转换                 │
│          │ seo_optimize  │ SEO 关键词优化                         │
│          │ copywriting   │ 营销文案生成(多模板)                   │
│          │ summary       │ 长文摘要/提取要点                      │
│          │ translation   │ 中英文翻译(保持风格)                   │
├──────────┼───────────────┼───────────────────────────────────────┤
│ 文档      │ text2ppt      │ 文本/大纲 → PPT 生成                  │
│          │ text2doc      │ 结构化文档生成(Word)                  │
│          │ pdf_extract   │ PDF 解析 + 内容提取                    │
│          │ markdown2doc  │ Markdown → Word/PDF 转换              │
├──────────┼───────────────┼───────────────────────────────────────┤
│ 编码      │ code_generate │ 代码生成(多语言)                     │
│          │ code_review   │ 代码审查 + 改进建议                    │
│          │ code_explain  │ 代码逐行解释                          │
│          │ debug_assist  │ 错误诊断 + 修复建议                    │
│          │ test_generate │ 单元测试自动生成                       │
│          │ sql_generate  │ 自然语言 → SQL                        │
├──────────┼───────────────┼───────────────────────────────────────┤
│ 图像      │ text2img      │ 文本描述 → 图片生成                    │
│          │ img2img       │ 图片风格转换                           │
│          │ img_upscale   │ 图片超分辨率放大                       │
│          │ img_inpaint   │ 图片局部修改/擦除                      │
│          │ img_describe  │ 图片内容描述/分析                      │
│          │ remove_bg     │ 智能抠图/去背景                        │
├──────────┼───────────────┼───────────────────────────────────────┤
│ 视频      │ text2video    │ 文本描述 → 视频生成                    │
│          │ img2video     │ 静态图 → 动态视频                      │
│          │ video_trim    │ 视频裁剪/拼接                          │
│          │ video_caption │ 视频字幕生成                           │
│          │ video_bgm     │ 自动配乐/音频处理                      │
├──────────┼───────────────┼───────────────────────────────────────┤
│ 生活      │ weather       │ 天气查询 + 出行建议                    │
│          │ recipe        │ 菜谱推荐(按食材/口味)                  │
│          │ schedule      │ 日程管理/提醒                          │
│          │ health_tip    │ 健康建议/运动推荐                      │
│          │ web_search    │ 联网搜索 + 结果摘要                    │
└──────────┴───────────────┴───────────────────────────────────────┘

2.5 在 Dify 中配置 Skill → Tool 映射

python 复制代码
# skill_to_dify_tool.py --- 将 Skill 注册为 Dify 自定义工具
import requests
import json

class DifyToolRegistrar:
    """将 Skill 注册为 Dify 工具"""

    def __init__(self, dify_url: str, api_key: str):
        self.dify_url = dify_url
        self.headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}

    def register_skill_as_tool(self, skill: dict):
        """将 Skill 定义转换为 Dify OpenAPI Tool"""
        openapi_spec = {
            "openapi": "3.0.0",
            "info": {
                "title": skill["display_name"],
                "version": skill["version"]
            },
            "paths": {
                f"/skill/{skill['name']}": {
                    "post": {
                        "summary": skill["description"],
                        "operationId": skill["name"],
                        "requestBody": {
                            "content": {
                                "application/json": {
                                    "schema": skill["input_schema"]
                                }
                            }
                        },
                        "responses": {
                            "200": {
                                "content": {
                                    "application/json": {
                                        "schema": skill.get("output_schema", {})
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "servers": [{"url": "http://localhost:8600"}]
        }
        return openapi_spec

第三部分:可实施性与稳定性保障

3.1 分级部署策略(降低风险)

text 复制代码
Level 0: 最小可行版(1天搞定)
──────────────────────────────
✅ Ollama + Qwen2.5-14B(单机 8GB 显存即可)
✅ Dify 社区版(docker compose up -d)
✅ 手动上传 5-10 个文档到知识库
✅ 创建 1 个通用 Agent(纯对话 + 知识库检索)
❌ 暂无图像/视频生成
❌ 暂无自定义 Skill

→ 验证:能对话、能检索知识库 = 成功

Level 1: 基础多模态版(1周)
──────────────────────────────
✅ Level 0 全部
✅ 升级模型到 Qwen2.5-32B(24GB 显存)
✅ 部署 ComfyUI + SDXL/FLUX(文生图)
✅ 创建 3-4 个 SubAgent(文案、编码、图像、生活)
✅ 知识库扩展到 50+ 文档
❌ 暂无视频生成
❌ 暂无自动化采集

→ 验证:能分领域对话、能生成图片 = 成功

Level 2: 完整版(2-3周)
──────────────────────────────
✅ Level 1 全部
✅ 升级到 Qwen2.5-72B(双卡/A100)
✅ 视频生成(Wan2.1 / CogVideoX)
✅ PPT/视频剪辑微服务
✅ MCP Server 集成
✅ 知识库自动采集流水线
✅ 全部 6 个 SubAgent + 主 Orchestrator

→ 验证:端到端完成一个"从文案到PPT到配图"的完整任务 = 成功

Level 3: 生产级(4周+)
──────────────────────────────
✅ Level 2 全部
✅ Skill 注册中心 + 自动发现
✅ 用户自定义 Agent 界面
✅ 监控告警(Prometheus + Grafana)
✅ 自动扩缩容
✅ 安全加固(鉴权、审计日志)

→ 验证:多用户并发使用、7×24 稳定运行 = 成功

3.2 稳定性设计

3.2.1 模型服务高可用

yaml 复制代码
# docker-compose.ha.yml --- 高可用模型服务
version: '3.8'

services:
  # Nginx 负载均衡
  model-lb:
    image: nginx:alpine
    ports:
      - "8000:80"
    volumes:
      - ./nginx-model.conf:/etc/nginx/nginx.conf
    depends_on:
      - vllm-1
      - vllm-2

  # 模型服务实例 1
  vllm-1:
    image: vllm/vllm-openai:latest
    runtime: nvidia
    environment:
      - CUDA_VISIBLE_DEVICES=0
    command: >
      --model /models/qwen2.5-72b
      --served-model-name qwen2.5-72b
      --max-model-len 16384
      --port 8000

  # 模型服务实例 2(冗余)
  vllm-2:
    image: vllm/vllm-openai:latest
    runtime: nvidia
    environment:
      - CUDA_VISIBLE_DEVICES=1
    command: >
      --model /models/qwen2.5-72b
      --served-model-name qwen2.5-72b
      --max-model-len 16384
      --port 8000
nginx 复制代码
# nginx-model.conf
events { worker_connections 1024; }

http {
    upstream model_backend {
        least_conn;
        server vllm-1:8000 max_fails=3 fail_timeout=30s;
        server vllm-2:8000 max_fails=3 fail_timeout=30s;
    }

    server {
        listen 80;

        location / {
            proxy_pass http://model_backend;
            proxy_connect_timeout 60s;
            proxy_read_timeout 300s;  # LLM 生成可能较慢
            proxy_next_upstream error timeout http_502 http_503;
        }
    }
}

3.2.2 健康检查与自动恢复

python 复制代码
# health_monitor.py --- 服务健康监控
import requests
import subprocess
import time
import logging
from datetime import datetime

logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")

class HealthMonitor:
    """监控各服务健康状态,自动重启故障服务"""

    def __init__(self):
        self.services = {
            "vllm": {
                "url": "http://localhost:8000/v1/models",
                "container": "vllm",
                "critical": True,
                "fail_count": 0,
                "max_fails": 3,
            },
            "dify": {
                "url": "http://localhost/api/health",
                "container": "dify-api-1",
                "critical": True,
                "fail_count": 0,
                "max_fails": 3,
            },
            "comfyui": {
                "url": "http://localhost:8188/system_stats",
                "container": "comfyui",
                "critical": False,
                "fail_count": 0,
                "max_fails": 5,
            },
            "ollama": {
                "url": "http://localhost:11434/api/tags",
                "container": "ollama",
                "critical": False,
                "fail_count": 0,
                "max_fails": 3,
            },
        }

    def check_all(self):
        """检查所有服务"""
        for name, svc in self.services.items():
            try:
                resp = requests.get(svc["url"], timeout=10)
                if resp.status_code == 200:
                    svc["fail_count"] = 0
                    logging.debug(f"{name}: OK")
                else:
                    self._handle_failure(name, svc, f"HTTP {resp.status_code}")
            except requests.exceptions.RequestException as e:
                self._handle_failure(name, svc, str(e))

    def _handle_failure(self, name: str, svc: dict, error: str):
        svc["fail_count"] += 1
        logging.warning(f"{name}: FAIL ({svc['fail_count']}/{svc['max_fails']}) - {error}")

        if svc["fail_count"] >= svc["max_fails"]:
            logging.error(f"{name}: Max failures reached, restarting container...")
            self._restart_container(svc["container"])
            svc["fail_count"] = 0

    def _restart_container(self, container: str):
        try:
            subprocess.run(["docker", "restart", container], check=True, timeout=120)
            logging.info(f"Container {container} restarted successfully")
        except subprocess.CalledProcessError as e:
            logging.error(f"Failed to restart {container}: {e}")

    def run_loop(self, interval_seconds: int = 30):
        """持续监控循环"""
        logging.info("Health monitor started")
        while True:
            self.check_all()
            time.sleep(interval_seconds)

if __name__ == "__main__":
    monitor = HealthMonitor()
    monitor.run_loop(interval_seconds=30)

3.2.3 请求队列与限流

python 复制代码
# request_queue.py --- 防止模型过载
import asyncio
from collections import deque
from dataclasses import dataclass, field
from typing import Any
import time

@dataclass
class QueuedRequest:
    priority: int  # 0=highest
    timestamp: float = field(default_factory=time.time)
    payload: dict = field(default_factory=dict)
    future: asyncio.Future = field(default_factory=lambda: asyncio.get_event_loop().create_future())

class RequestQueue:
    """
    带优先级的请求队列,防止模型服务过载
    - 限制并发请求数
    - 超时自动取消
    - 优先级调度
    """

    def __init__(self, max_concurrent: int = 4, timeout: float = 120.0):
        self.max_concurrent = max_concurrent
        self.timeout = timeout
        self.active_count = 0
        self.queue: list = []  # 优先级队列

    async def submit(self, payload: dict, priority: int = 5) -> Any:
        req = QueuedRequest(priority=priority, payload=payload)
        self.queue.append(req)
        self.queue.sort(key=lambda r: (r.priority, r.timestamp))

        # 等待处理
        asyncio.create_task(self._process_queue())
        return await asyncio.wait_for(req.future, timeout=self.timeout)

    async def _process_queue(self):
        while self.queue and self.active_count < self.max_concurrent:
            req = self.queue.pop(0)
            self.active_count += 1
            try:
                result = await self._call_model(req.payload)
                req.future.set_result(result)
            except Exception as e:
                req.future.set_exception(e)
            finally:
                self.active_count -= 1

    async def _call_model(self, payload: dict) -> dict:
        """实际调用模型 API"""
        import aiohttp
        async with aiohttp.ClientSession() as session:
            async with session.post(
                "http://localhost:8000/v1/chat/completions",
                json=payload, timeout=aiohttp.ClientTimeout(total=120)
            ) as resp:
                return await resp.json()

3.2.4 监控看板

yaml 复制代码
# docker-compose.monitoring.yml
services:
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      GF_SECURITY_ADMIN_PASSWORD: admin123
    volumes:
      - ./grafana_data:/var/lib/grafana
yaml 复制代码
# prometheus.yml
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'vllm'
    static_configs:
      - targets: ['vllm:8000']
  - job_name: 'node'
    static_configs:
      - targets: ['node-exporter:9100']
  - job_name: 'nvidia-gpu'
    static_configs:
      - targets: ['nvidia-gpu-exporter:9400']

3.3 GPU 显存管理策略

python 复制代码
# gpu_manager.py --- 智能 GPU 显存调度
class GPUMemoryManager:
    """
    多模型共享 GPU 时的显存管理策略

    场景:单卡/双卡 4090 要同时跑 LLM + 图像 + 视频
    策略:分时复用 ------ 不同时加载所有模型
    """

    # 策略 1: 常驻 LLM + 按需加载多模态
    STRATEGY_LLM_RESIDENT = {
        "resident": ["qwen2.5-72b"],          # 常驻显存
        "on_demand": ["flux", "wan2.1"],       # 按需加载/卸载
        "preemption": True,                     # 允许抢占
    }

    # 策略 2: 分时段调度
    STRATEGY_TIME_BASED = {
        "schedules": [
            {"hours": "08:00-22:00", "models": ["qwen2.5-72b", "flux"]},    # 白天:对话 + 图像
            {"hours": "22:00-08:00", "models": ["wan2.1"]},                   # 夜间:批量视频生成
        ]
    }

    # 策略 3: 队列优先级
    STRATEGY_PRIORITY = {
        "priorities": {
            "chat": 1,          # 最高:实时对话
            "text2img": 2,      # 中等:图像生成
            "text2video": 3,    # 最低:视频生成(耗时长)
        }
    }

第四部分:用户自定义 Agent

4.1 Agent 创建工作流

text 复制代码
用户自定义 Agent 创建流程:

Step 1: 基本信息
┌─────────────────────────────────────────┐
│ Agent 名称:  [我的法律助手            ]  │
│ 头像:        [📚]                       │
│ 描述:        [专注劳动法咨询的AI助手   ]  │
│ 可见性:      ○ 仅自己  ● 团队  ○ 公开    │
└─────────────────────────────────────────┘

Step 2: 选择基础能力
┌─────────────────────────────────────────┐
│ ☑ 对话能力(必选)                       │
│ ☑ 知识库检索                            │
│ ☐ 文生图                               │
│ ☐ 代码执行                             │
│ ☑ 网页搜索                             │
│ ☐ 文件生成(PPT/Word/PDF)              │
└─────────────────────────────────────────┘

Step 3: 配置 Persona(系统提示词)
┌─────────────────────────────────────────┐
│ 你是一名资深劳动法律师,具有10年执业经验。│
│ 你需要:                                │
│ - 用通俗易懂的语言解释法律条文           │
│ - 给出具体可操作的建议                   │
│ - 引用相关法律条款和判例                 │
│ - 在不确定时明确告知需要线下咨询          │
│                                         │
│ [使用AI帮我生成提示词]                   │
└─────────────────────────────────────────┘

Step 4: 挂载知识库
┌─────────────────────────────────────────┐
│ ☑ 劳动法全文.pdf                        │
│ ☑ 劳动合同法.pdf                        │
│ ☑ 最新劳动争议司法解释.pdf               │
│ ☑ 典型劳动纠纷案例100例.pdf             │
│ [+ 上传新文档]  [+ 连接在线知识库]       │
└─────────────────────────────────────────┘

Step 5: 选择 Skills
┌─────────────────────────────────────────┐
│ ☑ web_search(联网搜索最新判例)         │
│ ☑ text2doc(生成法律文书模板)           │
│ ☑ summary(长文摘要)                   │
│ ☐ text2img                             │
│ ☐ code_generate                        │
│ [+ 浏览 Skill 市场]                     │
└─────────────────────────────────────────┘

Step 6: 测试 & 发布
┌─────────────────────────────────────────┐
│ [预览对话]  [运行测试集]  [发布]         │
└─────────────────────────────────────────┘

4.2 Agent 配置格式(YAML DSL)

yaml 复制代码
# agents/legal_assistant.agent.yaml
apiVersion: v1
kind: Agent
metadata:
  name: legal-assistant
  display_name: 法律助手
  description: 专注劳动法咨询的AI助手
  icon: "📚"
  author: user123
  visibility: team    # private | team | public
  tags: ["法律", "劳动法", "咨询"]

spec:
  # 使用的模型
  model:
    provider: local-vllm
    name: qwen2.5-72b
    temperature: 0.3          # 法律领域需要低温度,减少幻觉
    max_tokens: 4096

  # 系统提示词
  persona: |
    你是一名资深劳动法律师,具有10年执业经验。
    回答问题时:
    1. 先判断问题属于哪个法律领域
    2. 引用具体法律条款(如《劳动合同法》第XX条)
    3. 给出通俗易懂的解释
    4. 提供具体可操作的建议
    5. 在涉及复杂案件时,建议线下咨询专业律师

    禁止:
    - 给出明确的案件胜败判断
    - 替代律师做出法律决策
    - 编造不存在的法律条文

  # 知识库
  knowledge_bases:
    - dataset_id: kb-labor-law
      description: 劳动法全文及司法解释
      retrieval_mode: hybrid       # vector + keyword
      top_k: 5
      score_threshold: 0.6

    - dataset_id: kb-cases
      description: 典型劳动纠纷案例库
      retrieval_mode: vector
      top_k: 3
      score_threshold: 0.7

  # 挂载的 Skills / Tools
  skills:
    - name: web_search
      config:
        search_engine: bing
        max_results: 5
        domains: ["court.gov.cn", "law.cn"]    # 限制搜索域名

    - name: text2doc
      config:
        templates: ["labor_contract", "resignation_letter", "arbitration_application"]

    - name: summary
      config:
        max_length: 500

  # 对话设置
  conversation:
    opening_message: "你好!我是法律助手,专注于劳动法领域。请描述你的问题,我会尽力帮你分析。"
    suggested_questions:
      - "公司不签劳动合同怎么办?"
      - "被无故辞退可以要求哪些赔偿?"
      - "加班费怎么计算?"

    # 对话记忆
    memory:
      type: window          # window | summary | full
      window_size: 20       # 保留最近20轮对话

  # 工作流(可选,复杂 Agent 使用)
  workflow:
    - step: classify_intent
      type: llm
      prompt: "判断用户问题属于哪个法律类别:劳动合同、薪酬福利、工伤、离职、劳动仲裁、其他"

    - step: retrieve_knowledge
      type: knowledge_retrieval
      dataset: auto          # 根据分类自动选择知识库
      top_k: 5

    - step: generate_answer
      type: llm
      prompt: "根据检索到的法律知识,回答用户问题。必须引用具体法条。"

    - step: safety_check
      type: llm
      prompt: "检查回答是否包含不当法律建议。如有,添加免责声明。"

  # 安全防护
  guardrails:
    input_filters:
      - type: sensitive_words
        action: reject
        words: ["怎么钻法律空子", "如何逃避"]
    output_filters:
      - type: disclaimer
        trigger: "specific_legal_advice"
        message: "⚠️ 以上分析仅供参考,具体案件建议咨询专业律师。"

4.3 Agent 管理后台 API

python 复制代码
# agent_manager.py --- Agent 生命周期管理
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Optional
import yaml
import uuid
from pathlib import Path

app = FastAPI(title="Agent Manager")

AGENTS_DIR = Path("./agents")
AGENTS_DIR.mkdir(exist_ok=True)

class AgentCreateRequest(BaseModel):
    name: str
    display_name: str
    description: str
    model: str = "qwen2.5-72b"
    temperature: float = 0.7
    persona: str
    knowledge_base_ids: list[str] = []
    skill_names: list[str] = []
    visibility: str = "private"
    opening_message: Optional[str] = None
    suggested_questions: list[str] = []

class AgentResponse(BaseModel):
    id: str
    name: str
    display_name: str
    status: str

@app.post("/api/agents", response_model=AgentResponse)
async def create_agent(req: AgentCreateRequest):
    """创建新 Agent"""
    agent_id = f"agent-{uuid.uuid4().hex[:8]}"

    # 构建 Agent 配置
    config = {
        "apiVersion": "v1",
        "kind": "Agent",
        "metadata": {
            "id": agent_id,
            "name": req.name,
            "display_name": req.display_name,
            "description": req.description,
            "visibility": req.visibility,
        },
        "spec": {
            "model": {"name": req.model, "temperature": req.temperature},
            "persona": req.persona,
            "knowledge_bases": [{"dataset_id": kb_id} for kb_id in req.knowledge_base_ids],
            "skills": [{"name": s} for s in req.skill_names],
            "conversation": {
                "opening_message": req.opening_message or f"你好!我是{req.display_name},有什么可以帮你的?",
                "suggested_questions": req.suggested_questions,
            },
        },
    }

    # 保存配置
    config_file = AGENTS_DIR / f"{agent_id}.yaml"
    config_file.write_text(yaml.dump(config, allow_unicode=True, default_flow_style=False))

    # 同步注册到 Dify(通过 Dify API 创建应用)
    await _register_in_dify(config)

    return AgentResponse(id=agent_id, name=req.name,
                         display_name=req.display_name, status="active")

@app.get("/api/agents")
async def list_agents(visibility: Optional[str] = None):
    """列出所有 Agent"""
    agents = []
    for f in AGENTS_DIR.glob("*.yaml"):
        config = yaml.safe_load(f.read_text())
        meta = config.get("metadata", {})
        if visibility and meta.get("visibility") != visibility:
            continue
        agents.append({
            "id": meta.get("id"),
            "name": meta.get("name"),
            "display_name": meta.get("display_name"),
            "description": meta.get("description"),
            "visibility": meta.get("visibility"),
        })
    return {"agents": agents}

@app.put("/api/agents/{agent_id}")
async def update_agent(agent_id: str, req: AgentCreateRequest):
    """更新 Agent 配置"""
    config_file = AGENTS_DIR / f"{agent_id}.yaml"
    if not config_file.exists():
        raise HTTPException(status_code=404, detail="Agent not found")
    # ... 更新逻辑(类似 create)
    return {"status": "updated"}

@app.delete("/api/agents/{agent_id}")
async def delete_agent(agent_id: str):
    """删除 Agent"""
    config_file = AGENTS_DIR / f"{agent_id}.yaml"
    if config_file.exists():
        config_file.unlink()
    return {"status": "deleted"}

@app.post("/api/agents/{agent_id}/clone")
async def clone_agent(agent_id: str, new_name: str):
    """克隆现有 Agent 作为模板"""
    config_file = AGENTS_DIR / f"{agent_id}.yaml"
    if not config_file.exists():
        raise HTTPException(status_code=404, detail="Agent not found")

    config = yaml.safe_load(config_file.read_text())
    new_id = f"agent-{uuid.uuid4().hex[:8]}"
    config["metadata"]["id"] = new_id
    config["metadata"]["name"] = new_name

    new_file = AGENTS_DIR / f"{new_id}.yaml"
    new_file.write_text(yaml.dump(config, allow_unicode=True))
    return {"id": new_id, "status": "cloned"}

async def _register_in_dify(config: dict):
    """将 Agent 配置注册到 Dify 平台"""
    # 通过 Dify API 创建对应的应用
    # POST /api/v1/apps
    pass

# 启动: uvicorn agent_manager:app --host 0.0.0.0 --port 8700

4.4 Agent 模板市场

text 复制代码
┌─────────────────────────────────────────────────────────────┐
│                    Agent 模板市场                            │
├──────────────┬──────────────────────────────────────────────┤
│ 🔥 热门模板  │                                              │
│              │  📝 新媒体运营助手                            │
│              │     自动写推文、配图、排版,支持多平台风格     │
│              │     Skills: copywriting, text2img, seo        │
│              │     ⭐ 4.8 | 1.2k 使用                       │
│              │     [使用此模板]                              │
│              │                                              │
│              │  💻 全栈开发助手                              │
│              │     代码生成、Review、测试、Debug 全流程       │
│              │     Skills: code_generate, test_gen, debug    │
│              │     ⭐ 4.9 | 2.5k 使用                       │
│              │     [使用此模板]                              │
│              │                                              │
│              │  🎨 设计师助手                                │
│              │     UI设计、Logo生成、配色方案、原型图         │
│              │     Skills: text2img, img2img, remove_bg      │
│              │     ⭐ 4.6 | 800 使用                        │
│              │     [使用此模板]                              │
│              │                                              │
│              │  📊 数据分析师                                │
│              │     SQL生成、图表绘制、报告撰写               │
│              │     Skills: sql_gen, code_execute, text2doc   │
│              │     ⭐ 4.7 | 950 使用                        │
│              │     [使用此模板]                              │
│              │                                              │
│              │  📚 学术研究助手                              │
│              │     论文检索、文献综述、格式排版               │
│              │     Skills: web_search, summary, text2doc     │
│              │     ⭐ 4.5 | 600 使用                        │
│              │     [使用此模板]                              │
├──────────────┼──────────────────────────────────────────────┤
│ 📂 分类      │  🏢 办公效率  |  💻 软件开发  |  🎨 设计创意  │
│              │  📊 数据分析  |  📚 教育学习  |  🏥 健康医疗  │
│              │  ⚖️ 法律顾问  |  💰 财务税务  |  🎮 娱乐休闲  │
└──────────────┴──────────────────────────────────────────────┘

4.5 Agent 间协作(Team 模式)

yaml 复制代码
# teams/content_team.team.yaml
apiVersion: v1
kind: Team
metadata:
  name: content-production-team
  display_name: 内容生产团队
  description: 从选题到发布的全流程内容生产

spec:
  # 团队成员(都是 Agent)
  members:
    - agent: copywriter
      role: 文案撰写
      description: 负责撰写文章正文

    - agent: image-designer
      role: 配图设计
      description: 为文章生成配图

    - agent: video-creator
      role: 视频制作
      description: 将文章内容转为短视频

    - agent: editor
      role: 主编审核
      description: 审核内容质量,给出修改意见

  # 协作流程
  workflow:
    - phase: "1. 选题策划"
      agent: editor
      action: "根据用户需求,确定文章选题、角度和大纲"
      output: topic_outline

    - phase: "2. 文案撰写"
      agent: copywriter
      action: "根据大纲撰写完整文章"
      input: topic_outline
      output: draft_article

    - phase: "3. 内容审核"
      agent: editor
      action: "审核文章质量,给出修改意见"
      input: draft_article
      output: review_feedback
      loop_until: "approved"    # 循环直到审核通过

    - phase: "4. 配图生成"
      agent: image-designer
      action: "根据文章内容生成 3-5 张配图"
      input: draft_article
      output: images
      parallel: true            # 与下一步并行

    - phase: "5. 视频制作"
      agent: video-creator
      action: "将文章核心内容制作为 60 秒短视频"
      input: draft_article
      output: video
      parallel: true            # 与上一步并行

    - phase: "6. 最终整合"
      agent: editor
      action: "整合文章、配图、视频,输出最终成品"
      input: [draft_article, images, video]
      output: final_package

  # 协作规则
  rules:
    max_revision_rounds: 3      # 最多修改3轮
    timeout_per_phase: 300      # 每阶段最长5分钟
    fallback_on_failure: skip   # 某环节失败时跳过(而非中断)

4.6 用户自定义 Agent 的 Prompt 工程辅助

python 复制代码
# prompt_engineer.py --- 帮助用户生成高质量系统提示词
class PromptEngineer:
    """辅助用户创建 Agent 的系统提示词"""

    TEMPLATE = """请根据以下信息,生成一个专业的 AI Agent 系统提示词:

角色名称: {role_name}
领域: {domain}
目标用户: {target_users}
核心功能: {core_functions}
语气风格: {tone}
限制条件: {restrictions}

要求:
1. 明确角色定位和专业背景
2. 列出具体的行为准则(DO 和 DON'T)
3. 定义输出格式偏好
4. 包含错误处理策略(不确定时怎么做)
5. 加入安全防护指令(防止 prompt 注入、越权回答)
6. 总长度控制在 300-500 字"""

    def generate_persona(self, role_name: str, domain: str,
                         target_users: str, core_functions: str,
                         tone: str = "专业友好",
                         restrictions: str = "不编造信息") -> str:
        prompt = self.TEMPLATE.format(
            role_name=role_name, domain=domain,
            target_users=target_users, core_functions=core_functions,
            tone=tone, restrictions=restrictions
        )
        resp = requests.post("http://localhost:8000/v1/chat/completions", json={
            "model": "qwen2.5-72b",
            "messages": [{"role": "user", "content": prompt}],
            "temperature": 0.7
        })
        return resp.json()["choices"][0]["message"]["content"]

    def optimize_persona(self, current_persona: str,
                         user_feedback: str) -> str:
        """根据用户反馈优化提示词"""
        prompt = f"""当前系统提示词:
{current_persona}

用户反馈:
{user_feedback}

请优化系统提示词,解决用户反馈中提到的问题。保持原有优点,改进不足之处。"""

        resp = requests.post("http://localhost:8000/v1/chat/completions", json={
            "model": "qwen2.5-72b",
            "messages": [{"role": "user", "content": prompt}],
            "temperature": 0.5
        })
        return resp.json()["choices"][0]["message"]["content"]

第五部分:完整目录结构

text 复制代码
ai-agent-platform/
├── docker-compose.yml              # 主部署文件
├── docker-compose.ha.yml           # 高可用配置
├── docker-compose.monitoring.yml   # 监控配置
├── .env                            # 环境变量
│
├── models/                         # 模型文件
│   ├── qwen2.5-72b/
│   ├── qwen2.5-coder-32b/
│   └── bge-m3/
│
├── services/                       # 工具微服务
│   ├── ppt/
│   │   ├── Dockerfile
│   │   ├── requirements.txt
│   │   └── ppt_service.py
│   ├── video/
│   │   ├── Dockerfile
│   │   ├── requirements.txt
│   │   └── video_service.py
│   └── skill_runner/
│       ├── Dockerfile
│       └── skill_runner.py
│
├── mcp_servers/                    # MCP Server
│   ├── mcp_filesystem.py
│   ├── mcp_comfyui.py
│   └── mcp_tools.py
│
├── skills/                         # Skill 定义
│   ├── text2ppt.skill.json
│   ├── text2img.skill.json
│   ├── code_generate.skill.json
│   ├── web_search.skill.json
│   └── ...
│
├── agents/                         # Agent 配置
│   ├── copywriter.agent.yaml
│   ├── coder.agent.yaml
│   ├── designer.agent.yaml
│   └── ...
│
├── teams/                          # Team 配置
│   └── content_team.team.yaml
│
├── knowledge/                      # 知识库原始文件
│   ├── coding/
│   ├── writing/
│   ├── creative/
│   ├── life/
│   └── custom/                     # 用户自定义知识库
│
├── knowledge_scrapers/             # 知识采集器
│   ├── coding_scraper.py
│   ├── writing_scraper.py
│   ├── creative_scraper.py
│   └── __init__.py
│
├── core/                           # 核心模块
│   ├── knowledge_pipeline.py       # 知识库同步流水线
│   ├── knowledge_quality.py        # 质量检测
│   ├── skill_discovery.py          # Skill 发现引擎
│   ├── skill_to_dify_tool.py       # Skill → Dify 工具转换
│   ├── agent_manager.py            # Agent 管理 API
│   ├── prompt_engineer.py          # Prompt 工程辅助
│   ├── request_queue.py            # 请求队列
│   ├── gpu_manager.py              # GPU 调度
│   └── health_monitor.py           # 健康监控
│
├── nginx/
│   └── nginx-model.conf
│
├── prometheus/
│   └── prometheus.yml
│
├── comfyui_models/                 # ComfyUI 模型文件
│   ├── checkpoints/
│   ├── unet/
│   └── loras/
│
├── comfyui_workflows/              # ComfyUI 工作流模板
│   ├── text_to_image_flux.json
│   ├── image_to_video_wan21.json
│   └── ...
│
└── scripts/                        # 运维脚本
    ├── setup.sh                    # 一键安装
    ├── download_models.sh          # 模型下载
    ├── backup.sh                   # 备份
    └── update.sh                   # 更新

第六部分:一键启动脚本

bash 复制代码
#!/bin/bash
# scripts/setup.sh --- 一键安装部署脚本

set -e

echo "========================================="
echo "  AI Agent Platform - One-Click Setup"
echo "========================================="

# 检查前置条件
check_prerequisites() {
    echo "[1/8] Checking prerequisites..."

    # Docker
    if ! command -v docker &> /dev/null; then
        echo "Installing Docker..."
        curl -fsSL https://get.docker.com | sh
        sudo usermod -aG docker $USER
    fi
    echo "  ✅ Docker: $(docker --version)"

    # Docker Compose
    if ! command -v docker compose &> /dev/null; then
        echo "ERROR: Docker Compose not found"
        exit 1
    fi
    echo "  ✅ Docker Compose: available"

    # NVIDIA Driver
    if command -v nvidia-smi &> /dev/null; then
        echo "  ✅ NVIDIA Driver: $(nvidia-smi --query-gpu=driver_version --format=csv,noheader | head -1)"
        echo "  ✅ GPU: $(nvidia-smi --query-gpu=name --format=csv,noheader)"
        echo "  ✅ VRAM: $(nvidia-smi --query-gpu=memory.total --format=csv,noheader)"
    else
        echo "  ⚠️  No NVIDIA GPU detected, will use CPU mode (slow)"
    fi

    # NVIDIA Container Toolkit
    if docker run --rm --gpus all nvidia/cuda:12.0-base nvidia-smi &> /dev/null; then
        echo "  ✅ NVIDIA Container Toolkit: working"
    else
        echo "  Installing NVIDIA Container Toolkit..."
        distribution=$(. /etc/os-release; echo $ID$VERSION_ID)
        curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
        curl -s -L "https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list" | \
            sudo tee /etc/apt/sources.list.d/nvidia-docker.list
        sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit
        sudo systemctl restart docker
    fi
}

# 创建目录结构
create_directories() {
    echo "[2/8] Creating directory structure..."
    mkdir -p models services/ppt services/video mcp_servers skills agents teams
    mkdir -p knowledge/{coding,writing,creative,life,custom}
    mkdir -p knowledge_scrapers core scripts
    mkdir -p comfyui_models/{checkpoints,unet,loras}
    mkdir -p comfyui_workflows nginx prometheus
    mkdir -p ollama_data weaviate_data minio_data grafana_data outputs
    echo "  ✅ Directories created"
}

# 下载模型
download_models() {
    echo "[3/8] Downloading models (this may take a while)..."

    # 检测可用显存,选择合适的模型
    if command -v nvidia-smi &> /dev/null; then
        VRAM=$(nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits | head -1)
        GPU_COUNT=$(nvidia-smi --query-gpu=count --format=csv,noheader | head -1)
        TOTAL_VRAM=$((VRAM * GPU_COUNT))

        if [ "$TOTAL_VRAM" -ge 48000 ]; then
            MODEL="Qwen/Qwen2.5-72B-Instruct-GPTQ-Int4"
            echo "  Using Qwen2.5-72B (${TOTAL_VRAM}MB VRAM detected)"
        elif [ "$TOTAL_VRAM" -ge 24000 ]; then
            MODEL="Qwen/Qwen2.5-32B-Instruct-AWQ"
            echo "  Using Qwen2.5-32B (${TOTAL_VRAM}MB VRAM detected)"
        else
            MODEL="Qwen/Qwen2.5-14B-Instruct-AWQ"
            echo "  Using Qwen2.5-14B (${TOTAL_VRAM}MB VRAM detected)"
        fi
    else
        MODEL="Qwen/Qwen2.5-7B-Instruct"
        echo "  Using Qwen2.5-7B (CPU mode)"
    fi

    pip install modelscope -q
    modelscope download --model "$MODEL" --local_dir ./models/qwen2.5
    echo "  ✅ Language model downloaded"
}

# 启动核心服务
start_services() {
    echo "[4/8] Starting core services..."
    docker compose up -d
    echo "  ✅ Services starting..."

    # 等待服务就绪
    echo "  Waiting for services to be ready..."
    for i in {1..60}; do
        if curl -s http://localhost:8000/v1/models > /dev/null 2>&1; then
            echo "  ✅ Model service ready"
            break
        fi
        sleep 5
    done
}

# 初始化 Dify
init_dify() {
    echo "[5/8] Initializing Dify..."
    cd dify/docker && docker compose up -d && cd ../..
    echo "  ✅ Dify started at http://localhost"
    echo "  📌 Visit http://localhost/install to complete setup"
}

# 初始化知识库
init_knowledge() {
    echo "[6/8] Initializing knowledge base..."
    python core/knowledge_pipeline.py --init
    echo "  ✅ Knowledge base initialized"
}

# 注册 Skills
register_skills() {
    echo "[7/8] Registering skills..."
    for skill_file in skills/*.skill.json; do
        echo "  Registering: $skill_file"
    done
    echo "  ✅ Skills registered"
}

# 完成
finish() {
    echo "[8/8] Setup complete!"
    echo ""
    echo "========================================="
    echo "  🎉 AI Agent Platform is ready!"
    echo "========================================="
    echo ""
    echo "  Services:"
    echo "  - Dify Web UI:     http://localhost"
    echo "  - Model API:       http://localhost:8000"
    echo "  - ComfyUI:         http://localhost:8188"
    echo "  - Agent Manager:   http://localhost:8700"
    echo "  - MinIO Console:   http://localhost:9001"
    echo "  - Grafana:         http://localhost:3000"
    echo ""
    echo "  Next steps:"
    echo "  1. Visit http://localhost/install to set up Dify"
    echo "  2. Add your local model in Dify Settings"
    echo "  3. Create your first Agent!"
    echo ""
}

# 执行
check_prerequisites
create_directories
download_models
start_services
init_dify
init_knowledge
register_skills
finish
相关推荐
kyriewen1 天前
别再用AI debug了——这5种bug越修越烂
前端·javascript·ai编程
掉头发的王富贵1 天前
我来入职新公司两个月了,为什么只写了100行代码?
后端·ai编程
ZzT1 天前
别把锅甩给AI
ai编程
程序员老刘1 天前
腾讯混元Hy3在Flutter项目中的实战体验
flutter·ai编程
skiyee1 天前
换个底座的 Wot Starter 居然让 AI 更懂项目!
前端·ai编程
孟陬1 天前
高质量全方位的 AI 工具 sse-stuntman — Mock SSE 接口
前端·node.js·openai
阿新聊ai1 天前
死磕claude code-渐进式披露:别让 Skill 一上来就把上下文塞爆
ai编程
阿新聊ai1 天前
SKILL.md 结构详解:让 Skill 既会被触发、又能跑通的写法
ai编程
zxfeng~1 天前
伴眸-居家养老AI 眼镜智能体 技术方案
人工智能·agent·ai编程·智能眼镜
还有多久拿退休金1 天前
AI 写了代码,谁替你"试毒"?
前端·架构·ai编程