diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..37292a7 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,60 @@ +# Sample workflow for building and deploying a VitePress site to GitHub Pages +name: Deploy VitePress site to Pages + +on: + # Runs on pushes targeting the `main` branch. Change this to `master` if you're using `master` branch. + push: + branches: [main, master, version2] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: pages + cancel-in-progress: false + +jobs: + # Build job + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Not needed if lastUpdated is not enabled + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + - name: Setup Pages + uses: actions/configure-pages@v4 + - name: Install dependencies + run: npm ci + - name: Build with VitePress + run: npm run build + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: docs/.vitepress/dist + + # Deployment job + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + needs: build + runs-on: ubuntu-latest + name: Deploy + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 8222584..a37a882 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ .DS_Store -node_modules/* -tools/* \ No newline at end of file +node_modules +tools/* +docs/.vitepress/dist +docs/.vitepress/cache diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..49955e2 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "semi": false, + "singleQuote": true, + "trailingComma": "none" +} diff --git a/.vscode/settings.json b/.vscode/settings.json index a127e95..22af89e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,13 @@ { - "cSpell.words": [] -} \ No newline at end of file + "cSpell.words": [], + "pasteImage.path": "${currentFileDir}/images", + "pasteImage.defaultName": "${currentFileNameWithoutExt}-YYYY-MM-DD-HH-mm-ss", + "pasteImage.prefix": "images/", + "pasteImage.insertPattern": "![](${imageFilePath})", + "pasteImage.basePath": "${currentFileDir}/images", + "markdown.copyFiles.destination": { + "*.md": "images/${fileName}" + }, + "markdown.editor.drop.enabled": false, + "markdown.editor.pasteUrlAsFormattedLink.enabled": false +} diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..19fd595 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,153 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +This is **Easy-Vibe**, an educational curriculum for learning AI Vibe Coding from zero to advanced levels. It's a documentation-based project using Docsify to serve educational content about AI-assisted software development. + +The curriculum follows a progressive four-stage structure: + +- **Stage 0 (幼儿园)**: Introduction to AI programming through games +- **Stage 1 (AI 产品经理)**: Building AI-powered web application prototypes +- **Stage 2 (初中级开发工程师)**: Full-stack development with databases and deployment +- **Stage 3 (高级开发工程师)**: Cross-platform development (WeChat mini-programs, Android apps, MCP) + +## Development Commands + +### Start Local Documentation Server + +```bash +npm install # Install dependencies (first time only) +npm run dev # Start docsify server on port 3000 +# or +npm start # Same as npm run dev +``` + +The documentation will be available at `http://localhost:3000` + +### Build/Run Commands + +- `npm run dev` - Serves the documentation using docsify-cli on port 3000 +- No build step required - docsify serves markdown files directly + +## Project Architecture + +### Directory Structure + +``` +easy-vibe/ +├── docs/ # Main documentation content (served by docsify) +│ ├── index.html # Docsify configuration and plugins +│ ├── _sidebar.md # Sidebar navigation structure +│ ├── README.md # Homepage (symlink to root README.md) +│ ├── stage-0/ # Stage 0 content (幼儿园) +│ ├── stage-1/ # Stage 1 content (AI 产品经理) +│ ├── stage-2/ # Stage 2 content (初中级开发工程师) +│ ├── stage-3/ # Stage 3 content (高级开发工程师) +│ ├── appendix/ # Reference materials (AI capability dictionary) +│ ├── examples/ # Practical examples and tutorials +│ ├── extra/ # Additional knowledge (Git, API, RAG, etc.) +│ └── project/ # Legacy project documentation +├── assets/ # Images and static assets (symlinked in docs/) +├── package.json # Project dependencies and scripts +└── README.md # Project overview and contribution guide +``` + +### Content Organization + +Each stage follows a numbered chapter structure: + +``` +stage-{N}/ +└── {N}.{M}-{chapter-name}/ + ├── index.md # Main content file + └── images/ # Chapter-specific images +``` + +Example: `stage-1/1.1-introduction-to-ai-ide/index.md` + +### Documentation System (Docsify) + +The project uses **Docsify** with the following key configuration in `docs/index.html`: + +- **Single Sidebar**: `loadSidebar: true` with `/_sidebar.md` alias for all routes +- **Search**: Full-text search across all documentation +- **Dark Mode**: Theme toggle with localStorage persistence +- **Image Viewer**: Viewer.js for image zoom/rotate/flip +- **Code Copy**: Copy code button on all code blocks +- **Pagination**: Previous/Next navigation between chapters +- **Word Count**: Chinese word count display on each page + +### Sidebar Management + +The sidebar is defined in `docs/_sidebar.md`. When adding new chapters: + +1. Add the chapter entry to the appropriate stage section +2. Follow the existing pattern: `* [Chapter Title](stage-{N}/{chapter-dir}/index.md)` +3. Ensure relative paths match the actual directory structure + +### Asset Management + +- Static assets are in `/assets/` at the root level +- Chapter-specific images go in `stage-{N}/{chapter-dir}/images/` +- Images are referenced with relative paths from the markdown file location +- Global CSS limits image display to max 80% width, 300px height with centered alignment + +### Legacy Content Structure + +The project maintains three legacy sections in the sidebar for backward compatibility: + +1. **Project 文档** (`project/`): Older chapter-based tutorials +2. **Extra 扩展知识** (`extra/`): Supplementary topics (Git, APIs, RAG, deployment) +3. **Examples 实战案例** (`examples/`): Practical tutorials (some moved to stage-3) + +When updating content, prefer integrating into the stage structure over adding to legacy sections. + +## Content Guidelines + +### Writing New Chapters + +1. Create directory: `docs/stage-{N}/{N}.{M}-{chapter-name}/` +2. Create `index.md` with chapter content +3. Add images subdirectory if needed: `images/` +4. Update `docs/_sidebar.md` with the new entry +5. Follow Chinese language conventions (this is a Chinese curriculum) + +### Content Status Markers + +In README.md, use these status indicators: + +- ✅ Completed +- 🚧 In progress/Under construction + +### File Naming Conventions + +- Use kebab-case for directories: `1.1-introduction-to-ai-ide` +- Use `index.md` for primary content files +- Images use descriptive names in their respective chapter directories + +## Permissions + +The project has configured bash permissions in `.claude/settings.local.json`: + +- File operations: `which`, `find`, `mv`, `tree`, `cat`, `curl`, `lsof` +- Process management: `xargs ps`, `kill` +- Development: `npm run dev` + +## Key Context for Development + +- **Educational Focus**: This is curriculum content, not application code +- **Target Audience**: Beginners to advanced developers learning AI-assisted programming +- **Language**: Primary content is in Chinese +- **No Build Pipeline**: Docsify serves markdown directly, no compilation needed +- **Git Workflow**: Content changes should preserve formatting and structure +- **Asset Paths**: Always use relative paths from markdown file location + +When making changes: + +- Preserve the Docsify configuration in `docs/index.html` +- Maintain sidebar structure consistency +- Test locally with `npm run dev` before committing +- Check that image links work correctly +- Ensure dark mode styles are not broken diff --git a/README.md b/README.md index 2716947..fb2c057 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ easy-vibe
-

Easy-Vibe : Learn Vibe Coding from 0 to 1

+

Easy-Vibe : Learn Vibe Coding from 0 to 1

GitHub stars GitHub forks Language @@ -24,11 +24,11 @@ 2025年,被很多人视为AI编程的元年。越来越多的人开始用AI写代码,但往往做出来的还停留在玩具层面——不知道如何用Vibe Coding组织开发流程,不知道该选哪些工具,更不清楚从原型到上线中间还差哪些关键步骤。 -我们采用循序渐进的**三阶段实战路径**:第一阶段掌握Vibe Coding工作方式并完成Web应用原型,第二阶段学习全栈开发与部署上线,第三阶段构建跨平台复杂应用。 +我们采用循序渐进的**三阶段实战路径**:第零阶段通过小游戏快速上手AI编程,第一阶段掌握Vibe Coding工作方式并完成Web应用原型,第二阶段学习全栈开发与部署上线,第三阶段构建跨平台复杂应用。 每个阶段都配有完整项目实战,让你在真实挑战中从玩具走向产品,最终具备**将任何想法落地为可用应用**的能力。 -我们相信,掌握Vibe Coding并配合系统化训练,你一个人就能成为**集前后端开发、AI能力集成、产品设计于一身的全能开发者**。 +我们相信,掌握Vibe Coding并配合系统化训练,你一个人就能成为**集前后端开发、AI 能力集成、产品设计于一身的全能开发者**。 本项目主要面向三类学习者: @@ -36,90 +36,91 @@ - **初中级开发者(有一定基础的学生和开发者)**:系统掌握 vibe coding 与原生 AI 应用开发。 - **高级开发者(公司与初创、开源与独立开发者)**:支持团队和个人快速搭建、验证与迭代原生 AI 应用。 -### 你将收获什么? - -- 理解什么是 vibe coding 以及它的一般做法,掌握实现原生 AI 应用的基本路径 -- 通过多个完整项目,熟悉游戏、工具类、产品原型等不同形态的 AI 应用开发 -- 了解并实践 Git、API、RAG、AI IDE、Zeabur 等关键工具与基础设施 -- 掌握产品思维,学会构建符合用户需求的产品 - ## 📖 内容导航 -**注: 本项目快速更新中,第二次更新在[分支 verison2](https://github.com/datawhalechina/easy-vibe/tree/version2)预计将于 1 月 20 日之前合并替换主分支,尽请期待** +### 总附录 -### Project 部分 +[AI 能力词典:常见 AI 核心概念与名词、场景解释](docs/appendix/ai-capability-dictionary.md) -本教程将 Project 分为三个阶段,帮助你从零开始掌握 Vibe Coding: +### 零、幼儿园 -| 章节 | 关键内容 | 难度 | 状态 | -| :--- | :--- | :--- | :--- | -| **第一阶段:本地基础开发** | | | | -| [前言:课程学习地图](https://github.com/datawhalechina/easy-vibe/blob/main/docs/project/chapter0-learning-map/chapter0-learning-map.md) | 课程学习地图、学习目标、常见问题解答 | 初 | ✅ | -| [Project 1: 如何构建贪吃蛇游戏](https://github.com/datawhalechina/easy-vibe/blob/main/docs/project/chapter1/chapter1-how-to-build-a-snake-game.md) | 网页端 AI 编程入门、实现贪吃蛇、文字和生图 API 调用、制作小游戏 | 初 | ✅ | -| [Project 2: 探索 AI 工具的能力边界](https://github.com/datawhalechina/easy-vibe/blob/main/docs/project/chapter2/chapter2-reach-the-capability-boundaries-of-ai-tools.md) | 提示词工程练习、AI 编程入门进阶、图片视频生成 API 进阶、理解 AI 能力边界 | 初 | ✅ | -| [Project 3: Dify 入门与知识库集成](https://github.com/datawhalechina/easy-vibe/blob/main/docs/project/chapter3/chapter3-getting-started-with-dify-and-its-knowledge-base-integration.md) | Dify 平台实战、RAG 检索增强生成、Workflow 编排、Dify API 调用 | 初 | ✅ | -| **第二阶段:数据库与全栈部署** | | | | -| [Project 4: 一起做霍格沃茨画像](https://github.com/datawhalechina/easy-vibe/blob/main/docs/project/chapter4/chapter4-lets-build-hogwarts-portraits.md) | 前端原型设计、前端原型转代码、AI IDE 入门、Dify API 集成、网页部署 | 中 | ✅ | -| [Project 5: 从数据库到 Supabase](https://github.com/datawhalechina/easy-vibe/blob/main/docs/project/chapter5/chapter5-from-database-to-supabase.md) | 数据库与 JSON 入门、Supabase 后端服务、用户鉴权系统、边缘函数、鉴权、存储桶 | 中 | ✅ | -| [Project 6: 别急着写代码,先想一个好点子](https://github.com/datawhalechina/easy-vibe/blob/main/docs/project/chapter6/chapter6-no-code-without-an-idea.md) | 产品思维、学会抽象思路变具体、如何制作好应用、用户需求与增长 | 中 | ✅ | -| **第三阶段:现代全栈网页应用实战** | | | | -| Project 7: 构建第一个现代应用程序-UI设计 | 现代前端组件库、前端编辑工具进阶、UI 设计规范 | 高 | 🚧 | -| Project 8: 构建第一个现代应用程序-功能设计 | 市场调研、产品 PRD 构建、原型设计深度解析、多页面架构设计 | 高 | 🚧 | -| Project 9: 构建第一个现代应用程序-全栈应用 | 全栈应用构建方案、独立后端鉴权、设计到上线开发闭环 | 高 | 🚧 | +| 章节 | 关键内容 | 状态 | +| :----------------------------------------------------------------------------------------- | :------------------------------------- | :--- | +| [前言:学习地图](docs/stage-0/0.1-learning-map/index.md) | 整体学习路径导览 | ✅ | +| [初级一:AI 时代,会说话就会编程](docs/stage-0/0.2-ai-capabilities-through-games/index.md) | 通过贪吃蛇等案例初步感受 AI 编程的能力 | ✅ | -### 扩展知识部分 +### 一、AI 产品经理 -| 章节 | 关键内容 | 难度 | 状态 | -| :--- | :--- | :--- | :--- | -| [扩展知识 1: 什么是 Git 和 GitHub](https://github.com/datawhalechina/easy-vibe/blob/main/docs/extra/extra1/extra1-what-is-git-and-what-is-github.md) | Git 版本控制、GitHub 协作流程、代码仓库管理、SSH 配置 | 初 | ✅ | -| [扩展知识 2: 什么是 API](https://github.com/datawhalechina/easy-vibe/blob/main/docs/extra/extra2/extra2-what-is-api.md) | API 原理与机制、接口请求/响应、第三方服务集成、HTTP 基础 | 初 | ✅ | -| [扩展知识 3: AI 词典](https://github.com/datawhalechina/easy-vibe/blob/main/docs/extra/extra3/extra3-ai-capability-starter-handbook.md) | AI 能力全景图、主流模型选型 (LLM/图像/语音/视频/时间序列)、AI 工程能力全景图 | 初 | ✅ | -| [扩展知识 4: 什么是 AI IDE 和 Trae](https://github.com/datawhalechina/easy-vibe/blob/main/docs/extra/extra4/extra4-what-is-ai-ide-and-trae.md) | IDE 与 AI IDE 概念、Trae 工具实战入门 | 初 | ✅ | -| [扩展知识 5: 什么是 RAG 以及它如何工作](https://github.com/datawhalechina/easy-vibe/blob/main/docs/extra/extra5/extra5-what-is-rag-and-how-does-it-work-and-future.md) | RAG 技术原理、文档切片与索引、RAG 进阶方案、RAG 企业方案 | 中 | ✅ | -| [扩展知识 6: Zeabur 与 Web 应用部署](https://github.com/datawhalechina/easy-vibe/blob/main/docs/extra/extra6/extra6-zeabur-what-is-it-and-how-to-deploy-web-applications.md) | Web 应用部署、Zeabur 平台使用方法 | 中 | ✅ | -| [扩展知识 7: CLI AI 编程工具](https://github.com/datawhalechina/easy-vibe/blob/main/docs/extra/extra7/extra7-cli-ai-coding-tools-and-the-principles-of-test-driven-development.md) | 终端介绍、CLI AI 编程工具、Claude Code/Codex | 中 | ✅ | -| 扩展知识 8: MCP 与 ClaudeCode skills | MCP 协议、ClaudeCode Skills、工具扩展机制 | 中 | 🚧 | -| 扩展知识 9: 使用 Trae SOLO 模式深度开发 | PRD 生成、需求驱动开发、前后端集成 | 中 | 🚧 | -| 扩展知识 10: 尝试提高 vibe coding 的品味 | 测试驱动开发、设立中间检查点、约束条件 | 高 | 🚧 | -| 扩展知识 11: 如何让 Coding Tools 长时间工作 | 自动化开发配置、长时间任务管理、CLI 工具稳定性优化 | 高 | 🚧 | +| 章节 | 关键内容 | 状态 | +| :---------------------------------------------------------------------------------- | :------------------------------------------------ | :--- | +| [初级二:认识 AI IDE 工具](docs/stage-1/1.1-introduction-to-ai-ide/index.md) | 学会使用 IDE,掌握界面结构和高效提示方式 | ✅ | +| [初级三:动手做出原型](docs/stage-1/1.2-building-prototype/index.md) | 从产品分析拆解,到多页面产品原型实现的完整闭环 | ✅ | +| [初级四:给原型加上 AI 能力](docs/stage-1/1.3-integrating-ai-capabilities/index.md) | 理解并完成常见 AI 能力(文本图片视频)的 API 接入 | ✅ | +| [初级五:完整项目实战](docs/stage-1/1.4-complete-project-practice/index.md) | 模拟真实场景、接受用户反馈迭代并完成项目展示 | ✅ | +| [大作业:做一个完整的 Web 应用原型并展示](docs/stage-1/1.5-final-project/index.md) | 独立用 AI IDE 落地并演示一个可用 Web 应用 | ✅ | -### 实践项目部分 +#### 附录 -| 章节 | 关键内容 | 难度 | 状态 | -| :--- | :--- | :--- | :--- | -| [Example 0-1: 使用 Vibe Coding 工具完成贪吃蛇教程](https://github.com/datawhalechina/easy-vibe/blob/main/docs/examples/example0/vibe-coding-tools-snake-game-tutorial/README.md) | 基于 Vibe Coding 工具复现与扩展贪吃蛇游戏的补充文章与实践记录 | 中 | 🚧 | -| [Example 0-2: 使用 Vibe Coding 工具与设计智能体搭建网站](https://github.com/datawhalechina/easy-vibe/blob/main/docs/examples/example0/vibe-coding-tools-build-website-with-ai-coding-and-design-agents/README.md) | 结合 Vibe Coding 工具与设计智能体从 0 到 1 搭建网站的补充文章与实践记录 | 中 | 🚧 | -| [Example 1: 如何构建微信小程序](https://github.com/datawhalechina/easy-vibe/blob/main/docs/examples/example1/example1-how-to-build-a-wechat-miniprogram.md) | 了解微信小程序生态与开发链路,结合 Trae + HBuilderX + 微信开发者工具,全流程开发贪吃蛇小程序 | 中 | ✅ | -| Example 2: 如何构建微信小程序-包含后端 | 使用 vibe coding 从 0 到 1 构建具有后端数据库的微信小程序 | 中 | 🚧 | -| Example 3: 如何构建安卓程序 | 结合 Expo,使用 vibe coding 从 0 到 1 构建安卓应用并上架 | 高 | 🚧 | +| 章节 | 关键内容 | 状态 | +| :-------------------------------------------------------------------------- | :---------------------------------------- | :--- | +| [附录A:产品思维补充](docs/stage-1/appendix-a-product-thinking/index.md) | 从想法评估到需求拆解与 MVP 的产品思维框架 | ✅ | +| [附录B:常见报错及解决方案](docs/stage-1/appendix-b-common-errors/index.md) | vibe coding 中的常见错误及排查方法 | ✅ | +### 二、初中级开发工程师 -### 路线图 +#### 前端部分 -- [ ] 1 月 11 日前实现大纲更新,更符合逻辑和学习习惯。 +| 章节 | 关键内容 | 状态 | +| :------------------------------------------------------------------------------------------------------------------------------------ | :--------------------------------------------------------------------------- | :--- | +| [前端零:使用 lovart 生产素材](docs/stage-2/frontend/2.0-lovart-assets/) | 学会用 lovart 批量生成人物、场景等视觉素材,为 UI 设计和前端开发提供素材基础 | 🚧 | +| [前端一:Figma 与 MasterGo 入门](docs/stage-2/frontend/2.1-figma-mastergo/) | 用设计工具梳理信息架构和页面结构,为前端实现打基础 | 🚧 | +| [前端二:构建第一个现代应用程序-UI 设计](docs/stage-2/frontend/2.2-ui-design/) | 基于设计稿完成组件化界面,实现从设计到代码的第一条链路 | 🚧 | +| [前端三:参考 UI 设计规范与多产品 UI 设计](docs/stage-2/frontend/2.3-multi-product-ui/) | 围绕统一主视觉扩展多产品界面,练习系统化设计能力 | 🚧 | +| [前端四:一起做霍格沃茨画像](docs/stage-2/frontend/2.4-hogwarts-portraits/chapter4-lets-build-hogwarts-portraits) | 从 0 到 1 做出接入 AI 能力的前端应用,串联设计与开发 | 🚧 | -#### 更新 +#### 后端与全栈部分 -- [ ] 补全未完成的 project extra 文档 -- [ ] 补充关于 IOS 平台 vibecoding 文档 -- [ ] 补充关于更多开发基础知识的 vibe coding 理解方案 +| 章节 | 关键内容 | 状态 | +| :------------------------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------ | :--- | +| [后端一:什么是 API](docs/stage-2/backend/2.1-what-is-api/extra2/extra2-what-is-api) | 理解 HTTP 接口与请求响应模型,为后端集成与联调做准备 | 🚧 | +| [后端二:从数据库到 Supabase](docs/stage-2/backend/2.2-database-supabase/chapter5/chapter5-from-database-to-supabase) | 在 Supabase 上落地数据库和 API,打通数据模型与前端页面 | 🚧 | +| [后端三:大模型辅助编写接口代码与接口文档](docs/stage-2/backend/2.3-ai-interface-code/) | 用大模型协助生成接口与数据库文档及代码,实现可读可测的后端 | 🚧 | +| [后端四:Git 工作流](docs/stage-2/backend/2.4-git-workflow/extra1/extra1-what-is-git-and-what-is-github) | 在 Git 工作流中管理代码,进行版本控制和协作 | 🚧 | +| [后端五:Zeabur 部署](docs/stage-2/backend/2.5-zeabur-deployment/extra6/extra6-zeabur-what-is-it-and-how-to-deploy-web-applications) | 将应用部署到 Zeabur 上线 | 🚧 | +| [后端六:现代 CLI 开发工具](docs/stage-2/backend/2.6-modern-cli/extra7/extra7-cli-ai-coding-tools-and-the-principles-of-test-driven-development) | 使用 CLI 类 AI 编程工具加速开发与调试,形成个人工程化工作流 | 🚧 | +| [后端七:如何集成 Stripe 等收费系统](docs/stage-2/backend/2.7-stripe-payment/) | 接入支付系统,完成收费链路与基础结算流程 | 🚧 | +| [大作业 1:构建第一个现代应用程序-全栈应用](docs/stage-2/assignments/2.1-fullstack-app/) | 综合前端、后端与支付模块,完成可上线的全栈 Web 应用 | 🚧 | +| [大作业 2:现代前端组件库 + Trae 实战](docs/stage-2/assignments/2.2-modern-frontend-trae/) | 使用现代前端组件库与 Trae,独立完成可登录注册并支持收费的产品 | 🚧 | -#### 修复 +#### AI 能力附录 -- [ ] 根据内测内容反馈补充润色 project 1 与 2 、extra 2 的内容,修复不自然的语言转换部分 -- [ ] 修复 extra 失效部分内容 -- [ ] 将未推送的教程补充推送,同时优化在线阅读体验 -- [ ] 修复英文版仓库不自然的部分 +| 章节 | 关键内容 | 状态 | +| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------- | :--- | +| [AI 一:Dify 入门与知识库集成](docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/chapter3-getting-started-with-dify-and-its-knowledge-base-integration) | 用 Dify Workflow 与基础 RAG 搭建工具类产品,为后续应用升级打样 | 🚧 | +| [AI 二:学会查询 AI 词典与集成多模态 API](docs/stage-2/ai-capabilities/2.2-multimodal-api/extra3/extra3-ai-capability-starter-handbook) | 学会查找合适的模型与 API,并把文本、图像等多模态能力接入产品 | 🚧 | +### 三、高级开发工程师 + +| 章节 | 关键内容 | 状态 | +| :-------------------------------------------------------------------- | :----------------------------------------------------------- | :--- | +| [高级一:MCP 与 ClaudeCode Skills](docs/stage-3/core-skills/3.1-mcp-claudecode-skills/) | 通过 MCP 与 Skills 扩展 IDE 能力,把外部服务接成工具 | 🚧 | +| [高级二:如何让 Coding Tools 长时间工作](docs/stage-3/core-skills/3.2-long-running-tasks/) | 设计和配置长时间运行的任务,让 Coding Tools 更稳定可靠 | 🚧 | +| [高级三:多平台开发:如何构建微信小程序](docs/stage-3/cross-platform/3.3-wechat-miniprogram/) | 了解微信小程序生态,从官方模板到上线完成一个前端小程序 | 🚧 | +| [高级四:多平台开发:如何构建微信小程序-包含后端](docs/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) | 在小程序中接入数据库与后端逻辑,打通完整业务闭环 | 🚧 | +| [高级五:多平台开发:如何构建安卓程序](docs/stage-3/cross-platform/3.5-android-app/) | 使用 Expo 等工具,完成 Web/原生一体化的安卓应用开发 | 🚧 | +| [高级六:多平台开发:如何构建 iOS 程序](docs/stage-3/cross-platform/3.6-ios-app/) | 使用 Expo 等工具,完成 Web/原生一体化的 iOS 应用开发 | 🚧 | +| [高级七:如何构建属于自己的个人网页与学术博客](docs/stage-3/personal-brand/3.7-personal-website-blog/) | 从选型、搭建到部署,构建展示个人项目与学术成果的长久在线主页 | 🚧 | + +#### AI 能力附录 + +| 章节 | 关键内容 | 状态 | +| :-------------------------------------------------------------------- | :------------------------------------------------------ | :--- | +| [高级 AI 一:什么是 RAG 以及它如何工作](docs/stage-3/ai-advanced/3.a1-rag-introduction/extra5/extra5-what-is-rag-and-how-does-it-work-and-future) | 系统理解 RAG 原理与常见架构,为复杂应用提供知识检索基础 | 🚧 | +| [高级 AI 二:中高级 RAG 与工作流编排:以 LangGraph 为例](docs/stage-3/ai-advanced/3.a2-langgraph-advanced-rag/) | 使用 LangGraph 等工具设计多步工作流与中高级 RAG 系统 | 🚧 | ## 如何学习 -- 建议具备基本编程经验(任意一门语言均可),并对 AI 与产品开发有兴趣 -- 按照 Project 模块从 0 到 6 依次实践,完成从小游戏到完整应用原型的进阶 -- 在 Extra 模块中补充 Git、API、RAG、部署等通识知识,完善你的 AI 开发知识图谱 -- 遇到问题时优先尝试自己排查与检索,再对照教程与源码进行比对和反思 - -你可以根据个人时间与需求,选择性地阅读和实践相关章节,但推荐至少完成全部 Project,以形成一套完整的实践闭环。 +- 根据个人能力,选择性地阅读和实践相关章节,如果有问题欢迎 issue 提问。 ## 本地启动本课件 diff --git a/docs/.nojekyll b/docs/.nojekyll deleted file mode 100644 index e69de29..0000000 diff --git a/docs/.vitepress/config.mjs b/docs/.vitepress/config.mjs new file mode 100644 index 0000000..8a145fc --- /dev/null +++ b/docs/.vitepress/config.mjs @@ -0,0 +1,301 @@ +import { defineConfig } from 'vitepress' + +export default defineConfig({ + base: '/', + title: 'Easy-Vibe Tutorial', + description: 'Easy-Vibe 中文实战课 - 零基础学会用 AI 干实际工作', + head: [['link', { rel: 'icon', href: '/logo.png' }]], + themeConfig: { + logo: '/logo.png', + search: { + provider: 'local' + }, + outline: { + level: 'deep', + label: '页面导航' + }, + nav: [ + { text: '首页', link: '/' }, + { text: '纯新手', link: '/stage-0/0.1-learning-map/' }, + { text: '产品经理', link: '/stage-1/1.1-introduction-to-ai-ide/' }, + { + text: '初中级开发', + link: '/stage-2/frontend/2.0-lovart-assets/' + }, + { + text: '高级开发', + link: '/stage-3/core-skills/3.1-mcp-claudecode-skills/' + }, + { text: '附录', link: '/appendix/ai-capability-dictionary' } + ], + sidebar: { + '/stage-0/': [ + { text: '0.1 学习地图', link: '/stage-0/0.1-learning-map/' }, + { + text: '0.2 AI 时代,会说话就会编程', + link: '/stage-0/0.2-ai-capabilities-through-games/' + } + ], + '/stage-1/': [ + { + text: '1.1 认识 AI IDE 工具', + link: '/stage-1/1.1-introduction-to-ai-ide/' + }, + { + text: '1.2 动手做出原型', + link: '/stage-1/1.2-building-prototype/' + }, + { + text: '1.3 给原型加上 AI 能力', + link: '/stage-1/1.3-integrating-ai-capabilities/' + }, + { + text: '1.4 完整项目实战', + link: '/stage-1/1.4-complete-project-practice/' + }, + { + text: '1.5 大作业:完成一个 Web 应用原型', + link: '/stage-1/1.5-final-project/' + }, + { + text: '附录 A:产品思维补充', + link: '/stage-1/appendix-a-product-thinking/' + }, + { + text: '附录 B:常见报错及解决方案', + link: '/stage-1/appendix-b-common-errors/' + } + ], + '/stage-2/': [ + { + text: '前端开发', + collapsed: false, + items: [ + { + text: '前端零:使用 Lovart 生产素材', + link: '/stage-2/frontend/2.0-lovart-assets/' + }, + { + text: '前端一:Figma 与 MasterGo 入门', + link: '/stage-2/frontend/2.1-figma-mastergo/' + }, + { + text: '前端二:构建第一个现代应用程序 - UI 设计', + link: '/stage-2/frontend/2.2-ui-design/' + }, + { + text: '前端三:参考 UI 设计规范与多产品 UI 设计', + link: '/stage-2/frontend/2.3-multi-product-ui/' + }, + { + text: '前端四:一起做霍格沃茨画像', + link: '/stage-2/frontend/2.4-hogwarts-portraits/chapter4-lets-build-hogwarts-portraits' + } + ] + }, + { + text: '后端与全栈', + collapsed: false, + items: [ + { + text: '后端一:什么是 API', + link: '/stage-2/backend/2.1-what-is-api/extra2/extra2-what-is-api' + }, + { + text: '后端二:从数据库到 Supabase', + link: '/stage-2/backend/2.2-database-supabase/chapter5/chapter5-from-database-to-supabase' + }, + { + text: '后端三:大模型辅助编写接口代码与接口文档', + link: '/stage-2/backend/2.3-ai-interface-code/' + }, + { + text: '后端四:Git 工作流', + link: '/stage-2/backend/2.4-git-workflow/extra1/extra1-what-is-git-and-what-is-github' + }, + { + text: '后端五:Zeabur 部署', + link: '/stage-2/backend/2.5-zeabur-deployment/extra6/extra6-zeabur-what-is-it-and-how-to-deploy-web-applications' + }, + { + text: '后端六:现代 CLI 开发工具', + link: '/stage-2/backend/2.6-modern-cli/extra7/extra7-cli-ai-coding-tools-and-the-principles-of-test-driven-development' + }, + { + text: '后端七:如何集成 Stripe 等收费系统', + link: '/stage-2/backend/2.7-stripe-payment/' + } + ] + }, + { + text: '大作业', + collapsed: false, + items: [ + { + text: '大作业 1:构建第一个现代应用程序 - 全栈应用', + link: '/stage-2/assignments/2.1-fullstack-app/' + }, + { + text: '大作业 2:现代前端组件库 + Trae 实战', + link: '/stage-2/assignments/2.2-modern-frontend-trae/' + } + ] + }, + { + text: 'AI 能力附录', + collapsed: false, + items: [ + { + text: 'AI 一:Dify 入门与知识库集成', + link: '/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/chapter3-getting-started-with-dify-and-its-knowledge-base-integration' + }, + { + text: 'AI 二:学会查询 AI 词典与集成多模态 API', + link: '/stage-2/ai-capabilities/2.2-multimodal-api/extra3/extra3-ai-capability-starter-handbook' + } + ] + } + ], + '/stage-3/': [ + { + text: '核心技能', + collapsed: false, + items: [ + { + text: '高级一:MCP 与 ClaudeCode Skills', + link: '/stage-3/core-skills/3.1-mcp-claudecode-skills/' + }, + { + text: '高级二:如何让 Coding Tools 长时间工作', + link: '/stage-3/core-skills/3.2-long-running-tasks/' + } + ] + }, + { + text: '多平台开发', + collapsed: false, + items: [ + { + text: '高级三:如何构建微信小程序', + link: '/stage-3/cross-platform/3.3-wechat-miniprogram/example1/index' + }, + { + text: '高级四:如何构建微信小程序(包含后端)', + link: '/stage-3/cross-platform/3.4-wechat-miniprogram-backend/' + }, + { + text: '高级五:如何构建安卓程序', + link: '/stage-3/cross-platform/3.5-android-app/' + }, + { + text: '高级六:如何构建 iOS 程序', + link: '/stage-3/cross-platform/3.6-ios-app/' + } + ] + }, + { + text: '个人品牌', + collapsed: false, + items: [ + { + text: '高级七:如何构建属于自己的个人网页与学术博客', + link: '/stage-3/personal-brand/3.7-personal-website-blog/' + } + ] + }, + { + text: 'AI 能力附录', + collapsed: false, + items: [ + { + text: '高级 AI 一:什么是 RAG 以及它如何工作', + link: '/stage-3/ai-advanced/3.a1-rag-introduction/extra5/extra5-what-is-rag-and-how-does-it-work-and-future' + }, + { + text: '高级 AI 二:中高级 RAG 与工作流编排 - 以 LangGraph 为例', + link: '/stage-3/ai-advanced/3.a2-langgraph-advanced-rag/' + } + ] + } + ], + '/guide/': [ + { + text: '课程指南', + items: [{ text: '课程介绍', link: '/guide/introduction' }] + } + ], + '/extra/': [ + { + text: 'Extra 扩展知识(旧版,已迁移到 Stage 2/3)', + items: [ + { + text: 'Extra 1: Git & GitHub', + link: '/extra/extra1/extra1-what-is-git-and-what-is-github' + }, + { + text: 'Extra 2: What is API', + link: '/extra/extra2/extra2-what-is-api' + }, + { + text: 'Extra 5: What is RAG', + link: '/extra/extra5/extra5-what-is-rag-and-how-does-it-work-and-future' + }, + { + text: 'Extra 6: Zeabur Deployment', + link: '/extra/extra6/extra6-zeabur-what-is-it-and-how-to-deploy-web-applications' + }, + { + text: 'Extra 7: CLI AI Tools & TDD', + link: '/extra/extra7/extra7-cli-ai-coding-tools-and-the-principles-of-test-driven-development' + } + ] + } + ], + '/examples/': [ + { + text: 'Examples 实战案例(旧版,已迁移到 Stage 0/3)', + items: [ + { + text: 'Ex 0.1: Snake Game', + link: '/examples/example0/example0-1/vibe-coding-tools-snake-game-tutorial' + }, + { + text: 'Ex 0.2: Build Website with AI', + link: '/examples/example0/example0-2/vibe-coding-tools-build-website-with-ai-coding-and-design-agents' + } + ] + } + ], + '/project/': [ + { + text: 'Project 文档(旧版,已迁移到 Stage 2)', + items: [ + { + text: '前端四:霍格沃茨画像', + link: '/project/chapter4/chapter4-lets-build-hogwarts-portraits' + }, + { + text: '后端二:Supabase 数据库', + link: '/project/chapter5/chapter5-from-database-to-supabase' + }, + { + text: 'AI 一:Dify & Knowledge Base', + link: '/project/chapter3/chapter3-getting-started-with-dify-and-its-knowledge-base-integration' + } + ] + } + ], + '/appendix/': [ + { + text: '附录', + items: [ + { text: 'AI 能力词典', link: '/appendix/ai-capability-dictionary' } + ] + } + ] + }, + socialLinks: [ + { icon: 'github', link: 'https://github.com/datawhalechina/easy-vibe' } + ] + } +}) diff --git a/docs/.vitepress/theme/Layout.vue b/docs/.vitepress/theme/Layout.vue new file mode 100644 index 0000000..47a9d47 --- /dev/null +++ b/docs/.vitepress/theme/Layout.vue @@ -0,0 +1,27 @@ + + + diff --git a/docs/.vitepress/theme/components/TextType.vue b/docs/.vitepress/theme/components/TextType.vue new file mode 100644 index 0000000..139e527 --- /dev/null +++ b/docs/.vitepress/theme/components/TextType.vue @@ -0,0 +1,260 @@ + + + + + diff --git a/docs/.vitepress/theme/index.js b/docs/.vitepress/theme/index.js new file mode 100644 index 0000000..ddde568 --- /dev/null +++ b/docs/.vitepress/theme/index.js @@ -0,0 +1,119 @@ +import DefaultTheme from 'vitepress/theme' +import Viewer from 'viewerjs' +import 'viewerjs/dist/viewer.css' +import TypeIt from 'typeit' +import { onMounted, watch, nextTick } from 'vue' +import { useRoute, useData } from 'vitepress' +import './style.css' + +export default { + extends: DefaultTheme, + setup() { + const route = useRoute() + const { frontmatter } = useData() + let viewer = null + + const initViewer = () => { + // 销毁旧实例 + if (viewer) { + viewer.destroy() + viewer = null + } + + // 找到文章内容容器 + const doc = document.querySelector('.vp-doc') + if (doc) { + // 初始化 Viewer,配置一些常用选项 + viewer = new Viewer(doc, { + button: true, // 显示右上角关闭按钮 + navbar: true, // 显示底部缩略图导航 + title: true, // 显示图片标题(alt 属性) + toolbar: true, // 显示工具栏(缩放、旋转等) + tooltip: true, // 显示缩放百分比 + movable: true, // 允许拖拽 + zoomable: true, // 允许缩放 + rotatable: true, // 允许旋转 + scalable: true, // 允许翻转 + transition: false, // 禁用自带动画,确保打开瞬间无飞入 + fullscreen: true, // 允许全屏播放 + shown() { + // 打开完成后,标记为 ready,CSS 此时才会介入 transition + document.body.classList.add('viewer-ready') + }, + hide() { + // 关闭前移除标记,确保关闭瞬间无动画 + document.body.classList.remove('viewer-ready') + }, + keyboard: true, // 允许键盘控制 + url: 'src', // 图片源 + // 过滤掉不想查看的图片(比如表情包等小图标,如果需要的话) + filter(image) { + return !image.classList.contains('no-viewer') + } + }) + } + } + + const initTypewriter = () => { + const taglineData = frontmatter.value.hero?.tagline + if (Array.isArray(taglineData) && taglineData.length > 0) { + const taglineEl = document.querySelector('.VPHomeHero .tagline') + if (taglineEl) { + taglineEl.innerHTML = '' + + const typeIt = new TypeIt(taglineEl, { + speed: 50, + startDelay: 500, + loop: true + }) + + taglineData.forEach((text) => { + typeIt.type(text).pause(2000).delete().pause(500) + }) + + typeIt.go() + } + } + } + + const optimizeImages = () => { + const images = document.querySelectorAll('.vp-doc img') + images.forEach(img => { + if (img.complete) { + applyImageStyle(img) + } else { + img.onload = () => applyImageStyle(img) + } + }) + } + + const applyImageStyle = (img) => { + const { naturalWidth, naturalHeight } = img + if (!naturalWidth || !naturalHeight) return + + const ratio = naturalHeight / naturalWidth + img.classList.remove('img-tall', 'img-very-tall') + + if (ratio > 2) { + img.classList.add('img-very-tall') + } else if (ratio > 1.2) { + img.classList.add('img-tall') + } + } + + onMounted(() => { + initViewer() + initTypewriter() + optimizeImages() + }) + + watch( + () => route.path, + () => nextTick(() => { + initViewer() + initTypewriter() + optimizeImages() + }) + ) + } +} diff --git a/docs/.vitepress/theme/style.css b/docs/.vitepress/theme/style.css new file mode 100644 index 0000000..913f127 --- /dev/null +++ b/docs/.vitepress/theme/style.css @@ -0,0 +1,38 @@ +/* Custom styles for viewerjs */ +.viewer-container { + z-index: 9999 !important; /* Ensure it's above everything including navbar */ +} + +/* Optional: Adjust backdrop opacity if needed */ +.viewer-backdrop { + background-color: rgba(0, 0, 0, 0.9); /* Darker backdrop for better focus */ +} + +/* + Core Logic: + 1. Default (opening/closing): No transition -> Instant. + 2. body.viewer-ready (viewing): Force transition -> Smooth Zoom. +*/ +body.viewer-ready .viewer-canvas > img { + transition: transform 0.2s ease-out !important; +} + +/* Limit image max height in document content */ +.vp-doc img { + max-height: 500px; + width: auto; + margin: 16px auto; /* Center with spacing */ + display: block; + border-radius: 8px; /* Optional: Rounded corners */ + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); /* Optional: Shadow */ +} + +/* Tall images (e.g. mobile screenshots) - ratio > 1.2 */ +.vp-doc img.img-tall { + max-height: 400px; +} + +/* Very tall images (e.g. long screenshots) - ratio > 2 */ +.vp-doc img.img-very-tall { + max-height: 300px; +} diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index d455589..0000000 --- a/docs/README.md +++ /dev/null @@ -1,132 +0,0 @@ -# Vibe Coding 101 课件 - -
-

Easy-Vibe

- GitHub stars - GitHub forks - Language - GitHub Project -
- -
- -[中文](https://github.com/datawhalechina/easy-vibe/blob/main/README.md) | [English](https://github.com/THU-SIGS-AIID/ai-vibe-coding-101/blob/main/README.md) - -
- -
-

📚 AI Vibe Coding 101 教程

-

零基础,在项目制学习中掌握 Vibe Coding 与 AI 技能,构建第一个 AI 原生产品

-
- -## 项目介绍 - -2025 年,被很多人视为 AI 编程的元年。越来越多的人已经开始用 AI 写代码,但做出来的东西往往还停留在玩具层面。且一到真正动手,大家常常会被各种门槛劝退: -- 不知道用什么 AI 编程工具写代码比较好; -- 不知道怎么把大模型的能力应用到具体产品上; -- 不清楚 AI 写出的代码,距离真实能上线运行还差多远。 - -通过这个项目,我们希望帮你掌握和 AI 搭档写代码的最佳实践。你将学会借助 AI 的力量,在一个又一个的项目制学习挑战中,独立完成游戏、实用工具、产品原型的实现,最后制作一款属于自己的产品。 - -我们相信,你一个人就可以成为前后端开发、AI 算法开发、产品经理。 - -### 项目受众 - -本项目主要面向希望系统学习 vibe coding 与原生 AI 应用开发的学习者,包括但不限于: - -- 计算机科学、人工智能及相关或跨学科专业的学生,希望通过实践经验系统地介绍 vibe coding 和原生 AI 开发 -- 具有基本编程技能的初中级开发人员,希望学习 vibe coding 并构建原生 AI 应用程序 -- 开源爱好者和独立开发者,希望降低 AI 原生开发的门槛,并利用免费资源创建衍生作品 -- 旨在快速制作原生 AI 应用程序原型的企业技术团队和 AI 初创公司 -- 非开发人员角色(如产品经理),希望掌握基本开发任务并为 AI 计划提供技术支持 - -### 你将收获什么? - -- 理解什么是 vibe coding 以及它的一般做法 -- 掌握从零到一设计和实现原生 AI 应用的基本路径 -- 通过多个完整项目,熟悉游戏、工具类、产品原型等不同形态的 AI 应用开发 -- 了解并实践 Git、API、RAG、AI IDE、Zeabur 等关键工具与基础设施 -- 掌握产品思维,学会构建符合用户需求的产品 -- 在实践中形成一套可复用的 AI 原生产品开发工作流 - -### 路线图 - -- [ ] 修复 extra 失效部分内容 -- [ ] 补全未完成的 project extra 文档 -- [ ] 根据内测内容反馈补充润色 project 1 与 2 、extra 2 的内容 -- [ ] 将未推送的教程补充推送,同时优化在线阅读体验 -- [ ] 修复英文版仓库不自然的部分 - -## 内容导航 - -本教程将内容分为三个难度等级,供不同阶段的学习者参考: - -- **初级**:适合 AI 编程新手,侧重于工具的基础使用与简单应用体验。 -- **中级**:适合具备一定基础的开发者,涉及前后端交互、数据库集成及多模态能力。 -- **高级**:适合进阶学习者,涵盖全栈开发、系统架构设计及复杂的工程化配置。 - -### Project 部分 - -| 难度 | 章节 | 关键内容 | 状态 | -| ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------- | ---- | -| 初 | [前言:课程学习地图](https://github.com/datawhalechina/easy-vibe/blob/main/docs/project/chapter0-learning-map/chapter0-learning-map.md) | 课程学习地图、学习目标、常见问题解答 | ✅ | -| 初 | [Project 1: 如何构建贪吃蛇游戏](https://github.com/datawhalechina/easy-vibe/blob/main/docs/project/chapter1/chapter1-how-to-build-a-snake-game.md) | 网页 AI 编程基础、实现贪吃蛇、集成文字、生图 API | ✅ | -| 初 | [Project 2: 探索 AI 工具的能力边界](https://github.com/datawhalechina/easy-vibe/blob/main/docs/project/chapter2/chapter2-reach-the-capability-boundaries-of-ai-tools.md) | 提示词工程练习、AI 编程基础、图片视频生成 API、理解 AI 能力边界 | ✅ | -| 初 | [Project 3: Dify 入门与知识库集成](https://github.com/datawhalechina/easy-vibe/blob/main/docs/project/chapter3/chapter3-getting-started-with-dify-and-its-knowledge-base-integration.md) | Dify 平台实战、RAG 检索增强生成、Workflow 编排 | ✅ | -| 中 | [Project 4: 一起做霍格沃茨画像](https://github.com/datawhalechina/easy-vibe/blob/main/docs/project/chapter4/chapter4-lets-build-hogwarts-portraits.md) | 前端原型设计、前端原型转代码、AI IDE 入门、Dify API 集成、网页部署 | ✅ | -| 中 | [Project 5: 从数据库到 Supabase](https://github.com/datawhalechina/easy-vibe/blob/main/docs/project/chapter5/chapter5-from-database-to-supabase.md) | 数据库与 JSON 入门、Supabase 后端服务、用户鉴权系统、边缘函数、鉴权、存储桶 | ✅ | -| 中 | [Project 6: 别急着写代码,先想一个好点子](https://github.com/datawhalechina/easy-vibe/blob/main/docs/project/chapter6/chapter6-no-code-without-an-idea.md) | 产品思维、学会抽象思路变具体、如何制作好应用、用户需求与增长 | ✅ | -| 高 | Project 7: 构建第一个现代应用程序-UI设计 | 现代前端组件库、前端编辑工具进阶、UI 设计规范 | 🚧 | -| 高 | Project 8: 构建第一个现代应用程序-功能设计 | 市场调研、产品 PRD 构建、原型设计深度解析、多页面架构设计 | 🚧 | -| 高 | Project 9: 构建第一个现代应用程序-全栈应用 | 全栈应用构建方案、独立后端鉴权、设计到上线开发闭环 | 🚧 | - -### 扩展知识部分 - -| 难度 | 章节 | 关键内容 | 状态 | -| ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | ---- | -| 初 | [扩展知识 1: 什么是 Git 和 GitHub](https://github.com/datawhalechina/easy-vibe/blob/main/docs/extra/extra1/extra1-what-is-git-and-what-is-github.md) | Git 版本控制、GitHub 协作流程、代码仓库管理、SSH 配置 | ✅ | -| 初 | [扩展知识 2: 什么是 API](https://github.com/datawhalechina/easy-vibe/blob/main/docs/extra/extra2/extra2-what-is-api.md) | API 原理与机制、接口请求/响应、第三方服务集成、HTTP 基础 | ✅ | -| 初 | [扩展知识 3: AI 能力入门手册](https://github.com/datawhalechina/easy-vibe/blob/main/docs/extra/extra3/extra3-ai-capability-starter-handbook.md) | AI 能力全景图、主流模型选型 (LLM/图像/语音/视频/时间序列)、AI 工程能力全景图 | ✅ | -| 初 | [扩展知识 4: 什么是 AI IDE 和 Trae](https://github.com/datawhalechina/easy-vibe/blob/main/docs/extra/extra4/extra4-what-is-ai-ide-and-trae.md) | IDE 与 AI IDE 概念、Trae 工具实战入门 | ✅ | -| 中 | [扩展知识 5: 什么是 RAG 以及它如何工作](https://github.com/datawhalechina/easy-vibe/blob/main/docs/extra/extra5/extra5-what-is-rag-and-how-does-it-work-and-future.md) | RAG 技术原理、文档切片与索引、RAG 进阶方案、RAG 企业方案 | ✅ | -| 中 | [扩展知识 6: Zeabur 与 Web 应用部署](https://github.com/datawhalechina/easy-vibe/blob/main/docs/extra/extra6/extra6-zeabur-what-is-it-and-how-to-deploy-web-applications.md) | Web 应用部署、Zeabur 平台使用方法 | ✅ | -| 中 | [扩展知识 7: CLI AI 编程工具](https://github.com/datawhalechina/easy-vibe/blob/main/docs/extra/extra7/extra9-cli-ai-coding-tools-and-the-principles-of-test-driven-development.md) | 终端介绍、CLI AI 编程工具、Claude Code/Codex | ✅ | -| 中 | 扩展知识 8: MCP 与 ClaudeCode skills | MCP 协议、ClaudeCode Skills、工具扩展机制 | 🚧 | -| 高 | 扩展知识 9: 如何让 Coding Tools 长时间工作 | 自动化开发配置、长时间任务管理、CLI 工具稳定性优化 | 🚧 | - -### 实践项目部分 - -该部分将会覆盖常见电脑应用形式的 0-1 Vibe Coding 开发过程。 - -| 难度 | 章节 | 关键内容 | 状态 | -| ---- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---- | -| 初 | [Example 0-1: Vibe Coding 入门与贪吃蛇游戏实战](https://github.com/datawhalechina/easy-vibe/blob/main/docs/examples/example0/example0-1/vibe-coding-tools-snake-game-tutorial.md) | 认识 Vibe Coding 与在线 AI Agent 编码平台,学习提示词编写方法,对比不同平台 vibe coding 贪吃蛇游戏的效果。 | ✅ | -| 初 | [Example 0-2: 使用 AI 设计与编码 Agent 搭建网站](https://github.com/datawhalechina/easy-vibe/blob/main/docs/examples/example0/example0-2/vibe-coding-tools-build-website-with-ai-coding-and-design-agents.md) | 使用设计 Agent + 编码 Agent,从零完成 Logo 设计、网站结构规划与单页网站搭建全流程。 | ✅ | -| 中 | [Example 1: 如何构建微信小程序](https://github.com/datawhalechina/easy-vibe/blob/main/docs/examples/example1/example1-how-to-build-a-wechat-miniprogram.md) | 了解微信小程序生态与开发链路,结合 **Trae** + **HBuilderX** + **微信开发者工具**,通过 AI 辅助从环境搭建到代码生成,全流程开发**贪吃蛇小程序**。 | ✅ | -| 中 | Example 2: 如何构建微信小程序-包含后端 | 使用 vibe coding 从 0 到 1 构建具有后端数据库的微信小程序 | 🚧 | -| 高 | Example 3: 如何构建安卓程序 | 结合 Expo,使用 vibe coding 从 0 到 1 构建安卓应用并上架 | 🚧 | - -## 如何学习 - -- 建议具备基本编程经验(任意一门语言均可),并对 AI 与产品开发有兴趣 -- 按照 Project 模块从 0 到 6 依次实践,完成从小游戏到完整应用原型的进阶 -- 在 Extra 模块中补充 Git、API、RAG、部署等通识知识,完善你的 AI 开发知识图谱 -- 遇到问题时优先尝试自己排查与检索,再对照教程与源码进行比对和反思 - -你可以根据个人时间与需求,选择性地阅读和实践相关章节,但推荐至少完成全部 Project,以形成一套完整的实践闭环。 - -## 本地启动本课件 - -### 现代方案 - -在 AI IDE 对话框(vscode、cursor、trae 等)中,输入下列提示词启动本课件: - -``` -请你帮我运行这个项目的本地服务 -``` - -### 旧方案 - -1. npm install -2. npm run dev -3. 打开浏览器访问 `http://localhost:3000` 即可查看。 diff --git a/docs/_sidebar.md b/docs/_sidebar.md deleted file mode 100644 index 9ede1d5..0000000 --- a/docs/_sidebar.md +++ /dev/null @@ -1,24 +0,0 @@ -* [首页](README.md) - -* Project - * [学习地图](project/chapter0-learning-map/chapter0-learning-map.md) - * [Project 1: 如何构建贪吃蛇游戏](project/chapter1/chapter1-how-to-build-a-snake-game.md) - * [Project 2: 探索 AI 工具的能力边界](project/chapter2/chapter2-reach-the-capability-boundaries-of-ai-tools.md) - * [Project 3: Dify 入门与知识库集成](project/chapter3/chapter3-getting-started-with-dify-and-its-knowledge-base-integration.md) - * [Project 4: 一起做霍格沃茨画像](project/chapter4/chapter4-lets-build-hogwarts-portraits.md) - * [Project 5: 从数据库到 Supabase](project/chapter5/chapter5-from-database-to-supabase.md) - * [Project 6: 没有 idea 就没有代码](project/chapter6/chapter6-no-code-without-an-idea.md) - -* Extra - * [扩展知识 1: 什么是 Git 和 GitHub](extra/extra1/extra1-what-is-git-and-what-is-github.md) - * [扩展知识 2: 什么是 API](extra/extra2/extra2-what-is-api.md) - * [扩展知识 3: AI 能力入门手册](extra/extra3/extra3-ai-capability-starter-handbook.md) - * [扩展知识 4: 什么是 AI IDE 和 Trae](extra/extra4/extra4-what-is-ai-ide-and-trae.md) - * [扩展知识 5: 什么是 RAG 以及它如何工作](extra/extra5/extra5-what-is-rag-and-how-does-it-work-and-future.md) - * [扩展知识 6: Zeabur 与 Web 应用部署](extra/extra6/extra6-zeabur-what-is-it-and-how-to-deploy-web-applications.md) - * [扩展知识 7: 命令行 AI 编程工具介绍](extra/extra7/extra7-cli-ai-coding-tools-and-the-principles-of-test-driven-development.md) - -* Examples -* * [完整实战 0-1: Vibe Coding 入门与贪吃蛇游戏实战](examples/example0/example0-1/vibe-coding-tools-snake-game-tutorial.md) -* * [完整实战 0-2: 使用 AI 设计与编码 Agent 搭建网站](examples/example0/example0-2/vibe-coding-tools-build-website-with-ai-coding-and-design-agents.md) -* * [完整实战项目 1: 如何写一个微信小程序](examples/example1/example1-how-to-build-a-wechat-miniprogram.md) diff --git a/docs/appendix/ai-capability-dictionary.md b/docs/appendix/ai-capability-dictionary.md new file mode 100644 index 0000000..6f8ab8c --- /dev/null +++ b/docs/appendix/ai-capability-dictionary.md @@ -0,0 +1,3267 @@ +# AI 词典:主流模型、产品形态与应用场景一览 + +随着生成式 AI 技术在各类产品和业务场景中的广泛落地,一个越来越现实的问题摆在每个我们面前: **到底有哪些 AI 能力可以用?** 在具体的需求里,又 **该选择哪一种能力、哪一类模型或哪一个产品来承载?** + +面对这种困惑,最直观的做法或许是 “临时抱佛脚”:**遇到需求再搜索市面上云服务厂商的产品 API,或者是对应模型,搜索市面上的商业级解决方案对照文档与 Demo进行处理** 。看到图片需求就想到图像生成,碰到文本任务就找来大模型,涉及语音交互就想起 ASR 和 TTS,再在海量 API 与服务中货比三家。然而,把零散的产品堆在一起,与在企业级场景中系统性地规划、选型和组合 AI 能力,是两件截然不同的事情。仅靠临时查资料与经验判断,会带来能力认知碎片化、方案设计随意、能力复用困难等一系列严峻挑战。 + +为了解决这些痛点,本文以“AI 能力全景图”为核心的整理思路应运而生。在这本手册里,我们想做的不是堆名词,而是帮你快速搞清楚三件事:**"这件事可以用什么 AI 能力做?大概该选哪一类模型或产品?接下来用哪些关键词去找 API、项目或服务来试?"** 通过从模态(文字、图像、音频、视频、3D、多模态)到架构层(模型、检索、Agent、平台工程)的系统梳理, **我们可以为每一类典型需求和场景找到对应的 AI 能力、代表性模型/产品,以及在真实业务中的常见用途** ,帮助团队以更低试错成本、更高决策效率和更强可复用性来建设 AI 体系。 + +在本篇手册中,我们将系统介绍当下主流的 AI 能力版图,从单一模态到多模态融合、从单点模型到平台与工程的整体框架,结合常见产品形态与应用场景,给出面向实践的能力选型参考。 + +> 由于 **内容较多** ,你可以在实践过程中遇到场景不知道如何选型的问题再查阅手册寻找参考;推荐你**根据具体应用方向,让 AI 参考该手册,给出可参考的模型选型建议、方案 API 调用建议即可。** + +如果你只想了解对应的类别,不想看具体内容,只需要看每个大章节的初始段内容即可,例如 1.1 、1.2 的内容,但不需要看 1.1.1 或者 1.1.2 的内容。 + +**推荐本手册只在需要时查阅对应部分或只浏览一级目录部分,若有兴趣再浏览全文。** + +**之后更新会在每个章节部分,推荐可尝试使用的模型 API 服务地址。** + +# 本节课你将学到 + +- AI 能力全景:从文本、图像、音频、视频、3D 到多模态、Agent、RAG、安全与平台工程的整体能力划分思路 +- 各能力对应的模型与产品:了解 Embedding、OCR、ASR、TTS、VLM、RAG 等关键能力背后的代表性模型与服务 +- 能力到场景的映射方法:掌握如何将“能力清单”转化为产品内容、搜索问答、智能客服、自动化运营等具体应用 + +完成本手册的学习后,你将对主流 AI 能力建立起入门级的系统化认知,不仅知道“市面上有哪些能力、常配哪些产品”,更能理解它们在整体架构中的位置和相互关系。知道在面对具体业务需求时,如何快速定位所需能力、做出有依据的选型,为构建 AI 能力体系打下坚实基础。 + +## 手册中涉及的模型参数 + +在进入具体能力地图之前,先澄清一个经常被提到、但又有点抽象的概念:到底什么算大模型?什么算小模型? + +**从学术上看** ,大模型通常指参数量在几十亿、上百亿乃至万亿级别的通用模型,小模型则是针对特定任务或场景、参数量更小(几千万到几亿级)的专用模型。 + +**从价格上看** ,如果一个模型的 API 调用非常便宜,比如按调用计费几厘钱、几分钱,或者只按每千 tokens 几厘到几分,而且没有特别强调通用大模型,那通常要么是典型的小模型(例如专门做 OCR、ASR、图片分类、内容审核的模型),要么是参数量较小的轻量版大模型(专门为了高并发、低成本做了压缩或蒸馏)。 如果单次调用价格明显偏高,比如一次调用就要几角甚至 1 元起步,那么大概率是大模型。 + +此外,如果产品文案里面会明确强调使用了大语言模型 LLM、通用大模型、多模态大模型,或提到端到端地完成从输入到输出的复杂任务(比如端到端对话机器人、端到端检索问答、端到端视频生成),那通常就可以把它视作是大模型。 + +相反,如果宣传重点在于某一个垂直能力,比如银行卡识别、发票识别、车牌识别、广告点击率预测、语音转写、内容安全审核,说明这个产品底层更可能是一个或一组小模型。 + +因此,在本文接下来的叙述中可以做个务实的约定: + +- 大模型更多指那类通用、可对话、可编程、往往价格略高的模型(包括它们的多模态版本,比如 GPT-4o、Gemini 1.5 Pro、Claude 3.5 Sonnet 等),它们能覆盖大部分通用文本、代码以及图像、音频、视频等多模态任务; +- 小模型则指那些为某个特定任务精调或定制的模型,通常价格更便宜、性能更稳定可控,但适用范围更窄,需要你在系统里主动组合与编排。 + +这里不妨补充一个关键的行业变化:手册中提到的很多模型能力,在 2021 年之前其实都是由 “小模型” 来承接的。针对特定场景、特定数据训练专属模型,以此满足精准需求。而**如今,绝大多数通用场景和任务已经可以直接调用大模型来解决** 。 + +从**精度与成本**的极致追求来看,小模型的训练与应用依然有其不可替代的价值;但**对于入门者而言,我们完全可以从学会找到并调用大模型 API 开始** ,再逐步深入高阶玩法。你只需要在成本、精度和延迟之间做权衡,再决定哪里要用通用大模型,哪里继续保留或引入专用小模型。 + +> **从一些常见产品认识**常用的文本和多模态通用大模型: +> +> - OpenAI 系列:GPT-4、GPT-4.1、GPT-4o、GPT-5.1 等 +> - Google 系列:Gemini 1.5 Pro、Gemini 1.5 Flash 等 +> - Anthropic 系列:Claude 3.5 Sonnet、Claude 3.5 Haiku 等 +> - 国内模型:通义千问 Qwen 系列、文心一言 ERNIE Bot 系列、GLM/智谱清言、百度的文心大模型家族、腾讯混元、讯飞星火、月之暗面的 Kimi 背后的大模型等 +> +> 更偏视觉和视频方向的大模型和服务,包括: +> +> - 图像生成:DALL·E、Midjourney、Stable Diffusion、SDXL、Flux 等 +> - 多模态视觉理解:GPT-4o、GPT-4.1 with Vision、Gemini 1.5(图文多模态)、Claude 3.5 Sonnet Vision、LLaVA 等 +> - 视频生成:Sora、Kling、Runway Gen-2、Pika、Luma、Veo 等 +> +> 语音和音频方向的大模型,包括: +> +> - 语音识别 ASR:Whisper 系列(Whisper、Whisper-large-v3 等)、Deepgram、各家云厂商的端到端 ASR 大模型(如讯飞、百度、火山、阿里等) +> - 语音多模态与语音对话:GPT-4o(端到端语音对话)、OpenAI Realtime、Gemini 1.5 的音频理解能力等 +> - TTS / 音频与音乐生成:OpenAI TTS、ElevenLabs、Suno、Udio、MusicGen 等 +> +> 3D / 空间方向的生成与理解模型,包括: +> +> - 文生 3D 和图生 3D:DreamFusion、Shap-E、GET3D、Zero-1-to-3、TripoSR 等 +> - NeRF / 神经渲染家族:Instant-NGP、NeRF 系列、Gaussian Splatting 相关模型等 + +# 1. 文本任务 (Text / NLP / LLM) + +在 AI 能力中,文字任务是最基础的功能。无论我们最终想做的是内容审核、搜索推荐、知识问答,还是写作助手、代码 Copilot,本质上都绕不开一个问题:机器如何真正看懂文字。 + +## 1.1 基础语言建模与表示 + +让我们从最底层的基础语言建模与表示讲起。它的作用是让机器先在统计意义上熟悉语言,并在此基础上为词、句子、文档找到一个稳定的向量矩阵表示,以便于后面的分类、匹配、抽取、生成等任务。不管未来要做什么文本相关任务,都或多或少需要先回答同一个问题:我怎么用一串数字,把这一段话表示出来? + +我们可以简单从场景、原理、模型三个角度来看这个问题的相关内容: + +- **场景** + - **检索搜索相关** + - 通用搜索引擎:用户随便输入一句话,得到含义相关的文档,而不是只做关键词精确匹配。 + - 站内搜索 / 电商搜索:用户用口语化的描述(比如“适合夏天通勤的白衬衫”),找到含义对应的商品。 + - 文档库 / 知识库检索:在技术文档、政策法规、企业知识库里,直接输入一句话获得相关条目。 + - **推荐排序相关** + - 信息流 / 内容推荐:根据用户最近看过、点过的内容,自动找出内容相近的其他内容继续推荐,而不是只靠人工规则或标签。 + - 电商 / 商品推荐:根据用户看过、买过、收藏过的商品描述,找到风格或用途相近的商品,做个性化推荐。 + - 用户兴趣建模:根据用户看过的标题、搜索过的词等,总结出几个主要兴趣方向,用来提升推荐和排序效果。 + - **问答助手相关** + - FAQ 问答:用户用不同说法问同一个问题(“怎么开发票?” vs “发票在哪里开?”),系统能跳到同一个答案。 + - 知识库问答 / 企业助手:用户用自然语言提问,系统到内部文档里按含义去匹配,找出最相关的段落回答。 + - **文本理解分析相关** + - 评论舆情分析:把大量评论、帖子按“在说什么 / 情绪怎样”大致分成几类。 + - 文本去重 / 相似检测:用于发现改写稿、伪原创文章。 + - 文档聚类 / 分组:把很多文章、报告按照内容相近分成几组,方便做导航、推荐或抽样检查。 + - **作为下游任务通用特征 (下游任务指的是用模型的基础能力,去实现更具体的文字处理任务)** + - 文本分类:情感分类、意图识别、垃圾内容识别等下游模型直接复用这一层的表示。 + - 信息抽取:实体识别、关系抽取在词 / 句子表示的基础上进行微调,而不是从头训练。 + - 文本生成:为摘要、改写、续写等生成任务提供语义表征输入,提升生成质量与可控性。 +- **原理** + 学习词、句子、文档的表示,为后续更复杂的任务作为基底。 + - 语言建模 + - 自回归语言模型:预测下一个 token(GPT 系列、LLaMA、Qwen 等) + - 掩码语言模型 (Masked LM):预测被遮盖 token(BERT、RoBERTa、ERNIE) + - 词 / 句子 / 段落表示 + - 静态词向量:Word2Vec、GloVe、FastText + - 上下文表征:BERT embedding、Sentence‑BERT 等 + - 文档级向量:用于语义检索、相似度匹配 +- **模型** + BERT / RoBERTa / ERNIE、GPT 家族、LLaMA / Qwen / Yi 等 LLM;各类 Embedding 模型(OpenAI text‑embedding‑3 系列、bge、E5、SimCSE 等)。 + +### **1.1.1 语言建模:通过“猜下一个词”学会语言** + +这一层的第一步,是先让模型在大量文本里 **熟悉语言规律** 。做法可以简单理解为:给模型出无数道“猜词题”,在看到一段话的上下文后,让它填上最合理的词(token)。练习题足够多、语料足够广,模型就会逐渐学会:一句自然的句子长什么样,哪些词经常一起出现,什么表达读起来别扭。这个过程叫“语言建模”,本质就是一套统一的 **猜词训练机制** 。 + +常见有两种出题方式,每种用一句话举个简单例子: + +1. **往后接(自回归)** :只给前面的内容,让模型猜“后面会怎么说”。 +2. 输入前缀:`今天下雨了,所以我` +3. 模型任务:猜下一个词,比如“ **带** (伞)”“ **没** (出去)”“ **打算** (在家)”等,然后再继续往后接。 + 这种方式主要锻炼模型对**续写、连贯性、常见表达**的把握。 +4. **挖空填词(掩码)** :把中间挖个洞,让模型利用前后文一起填空。 +5. 原句:`今天下雨了,所以我带了雨伞` +6. 训练句:`今天 [MASK] 了,所以我带了雨伞` +7. 模型任务:把 `[MASK]` 补成“ **下雨** ”这类合理的词。 + 这里模型必须同时看左边的“今天”“了”和右边的“所以我带了雨伞”,才能决定该填什么,更有利于学习 **整句语义** 。 + +通过在海量语料上反复做这两类“猜词题”,模型会逐渐积累起对语言的 **语感和统计常识** 。在此基础上,下一步我们再把这种能力显式地变成 **词、句子和文档的向量表示** ,为后续的检索、推荐和问答等任务打底。 + +### 1.1.2 词、句子与文档表示:把离散符号映射到语义空间 + +构建文本向量最早一代的方法是**静态词向量** :为每个词分配一份固定向量,训练好后不随上下文变化,直观、简单,但 **无法区分多义词在不同语境下的含义。** 为了解决这个问题,后来出现了基于上下文的动态表示方法:同一个词在不同句子中会生成不同的向量,完全由它所在的上下文决定。比如“苹果”在“苹果发布了新手机”中会更靠近“科技公司”的语义方向,而在“苹果富含维生素”中则更接近“水果”概念。 + +这种机制不仅提升了词层面的表达能力,也为句子和文档的向量化铺平了道路。对于句子,可以生成句向量;对于文档,可以整篇输入编码(如果长度允许),或分段编码后再通过注意力机制、层次化池化、对比学习等方式聚合出一个全局向量。近年来的专用 embedding 模型(如 bge、E5、text-embedding 系列)正是围绕“让语义相近的文本在向量空间中更近”这一目标持续优化,尤其在语义检索、相似匹配等任务上表现突出。 + +这套从上下文建模到句/文档向量生成的流程,已经成为搜索、推荐、问答等系统背后的核心基础设施,让我们回到前面提到的各类场景: + +- 检索搜索场景(通用搜索、电商搜索、知识库检索)都需要把用户输入和候选文档都编码成向量,然后在向量空间里做相似度匹配,找出语义最接近的结果,而不是只靠关键词精确匹配。 +- 推荐排序场景(信息流推荐、商品推荐、用户兴趣建模)需要把用户历史行为对应的内容转成向量,然后找到向量相近的新内容推荐给用户,实现"看过 A 推荐 B"的个性化效果。 +- 问答助手场景(FAQ 问答、知识库问答)需要把用户的提问和知识库里的问题或段落都编码成向量,通过向量相似度找到最匹配的答案。 +- 文本理解分析场景(评论舆情、去重、聚类)需要先把每条文本转成向量,再基于向量做聚类、相似度计算或分类。 +- 下游任务场景(文本分类、信息抽取、文本生成)则是直接把这一层的向量表示作为输入特征,喂给后续的分类器、抽取器或生成器,避免从头学习语义。 + +工程上,常见做法是封装成统一的"文本向量服务":输入任意一段文本,输出一串固定维度的向量,供搜索、推荐、问答等多个系统共享使用。在产品层面,这一层的能力主要体现在:搜索和推荐中的语义召回(不再只依赖关键词,而是通过向量相似度召回"说法不同但意思相近"的内容),以及面向企业知识库、FAQ、案例库的统一 embedding / 向量检索服务。 + +## 1.2 文本分类与文本匹配(Classification & Matching) + +在上一节中,我们通过基础语言建模与表示,为每一段文本找到了在语义空间中的“坐标”。但仅有坐标还不够,业务真正关心的问题往往是:这段文本属于哪一类?和另一段文本是不是讲同一件事?两句话之间在逻辑上是相互支持还是互相矛盾?你可以把它理解为:用分类和匹配这两个能力,把底层的向量表示转化为可以直接驱动业务决策的标签与相关性信号。我们仍然从场景、原理和模型三个角度来梳理这一层: + +- **场景** + - 内容理解与审核:给评论、帖子、文章打上主题、情感、风险等标签,用于审核、推荐、统计分析。 + - 推荐与排序:根据“用户兴趣标签”和“内容标签”的匹配程度,决定展示哪些内容、排在多前。 + - 搜索与 FAQ:用户随便输入一句自然语言问题,系统能够自动找到最相关的问题‑答案对或文档片段。 + - 相似内容识别:在大量文本中找到“内容相近”的条目,用于去重、合并统计、推荐“相关内容”。 + - 逻辑关系判断:判断两句话之间是互相支持、互相矛盾,还是无关,用于事实核查、多轮对话一致性检查等。 +- **原理** + 在语义表示的基础上,对整段文本或文本对进行整体判断: + - 文本分类:给单条文本打标签(如情感、主题、风险类型等); + - 文本匹配:判断两段文本之间的相似度、相关性,或“问题–答案”是否匹配; +- **模型** + 以预训练 encoder 为基础,接上简单的分类 / 匹配结构: + - 单文本分类:BERT / RoBERTa / DeBERTa + 全连接分类层; + - 文本匹配:Sentence‑BERT、SimCSE、双塔(Bi‑Encoder)、交叉编码器(Cross‑Encoder); + - 复杂判断:在 LLM 上通过指令微调,让模型直接输出标签或逻辑关系。 + +### 1.2.1 文本分类:从“懂内容”到“给内容定性” + +借助上一层的语义表示,我们可以非常自然地在其上方接一个简单的分类头,通过少量标注数据,让模型学会回答一个问题: **“这段文本属于哪一类?”** 。 + +最经典的是 **情感分类** 。用户的一句评价,可能是认可、抱怨,也可能只是陈述事实。模型在拿到这句话的向量表示之后,只需要再接一个 softmax 分类层,就能输出“正向 / 负向 / 中立”的概率。这类能力在电商、社交平台、应用市场等场景中,都已经非常成熟。 + +另一大类是 **主题 / 行业分类** 。新闻推荐里,我们希望知道一篇文章是体育、财经还是娱乐;企业内部的客服 / 工单系统,则更关心这是产品咨询、功能异常还是投诉建议。这些标签既可以帮助内容被更精准地路由到合适的流程中,也可以作为推荐排序阶段的重要特征。 + +更进一步,**风险 / 合规分类**则直接与平台安全相关。我们会针对广告导流、谩骂攻击、涉政敏感、低俗色情等类别设置专门的分类模型,配合人工审核,对高风险内容进行拦截或降权。可以说,绝大部分内容安全策略的第一道闸门,都是由这类分类器构成的。 + +可以看到,到这一层为止,我们已经能够把“抽象的语义表示”转化为若干业务可用的标签。接下来,我们要讨论的是:当文本之间产生关系时,我们又如何进行 **匹配与推断** 。 + +### 1.2.2 文本匹配:为一句话“找到最合适的另一句” + +与分类对“单个文本定性”不同,**文本匹配**关注的是“两段文本之间的相关性”。在很多产品里,这往往是实现“智能”的关键一环:用户说了一句话,系统能不能找到知识库里最合适的一条进行回应,完全取决于匹配质量。 + +最基础的是 **语义相似度计算** 。我们会先用上一层的 embedding 模型,把两个句子编码成向量,再通过余弦相似度、点积等方式,判断它们在语义空间里的距离。像 SimCSE、Sentence‑BERT 这类模型,就是通过对比学习的方式,专门把“相似的句子对”拉近,把“不相似的句子对”推远。 + +在此之上,**复述检测**和**抄袭检测**只是特定应用场景的匹配任务。前者用于内容去重,避免平台充斥着重复表达;后者则在教育、知识社区等场景中,用来识别高度相似的回答或文章。技术上,它们本质都是根据文本相似度来做二分类或排序。 + +一个非常重要的下游应用是 **问答匹配** 。当用户提出一个自然语言问题时,我们不会直接用关键词去匹配 FAQ,而是通过语义向量先做召回,再用更精细的匹配模型(如交叉编码器 Cross‑Encoder)对若干候选进行重排序,选出最可能对应的那一条。这一链路构成了 FAQ 机器人和文档问答系统的基础。 + +在这一层,我们已经具备了对“整段文本”进行分类和关系判断的能力。但在很多场景里,业务并不满足于此,而是进一步希望知道: **这段文本中具体提到了哪些实体、发生了什么事件** 。这就自然引出了下一节的主题—— **序列标注与信息抽取** 。 + +## 1.3 序列标注与信息抽取(Sequence Labeling & Information Extraction) + +在完成了对文本整体的分类和匹配之后,我们往往会遇到一个更细致的诉求:不仅要知道“这篇文章是关于什么的、风险高不高”,还要进一步知道“它具体提到了谁、在哪儿、什么时候、金额是多少”。这一节,就是在整体判断之上向“细粒度结构化”迈出的关键一步。你可以把它理解为:在已经知道“应该看哪一类文本、它大概讲什么”的前提下,从文本内部挖掘实体、关系、事件和各类字段,让非结构化文本可以直接被业务系统消费。我们同样从目标、原理、模型和产品四个方面来看这一层: + +- **场景** + - 行业文本结构化:从合同、报告、公告、病历、政策等文档中,抽取出人名、机构、金额、时间、条款等关键字段,用于入库和检索。 + - 知识图谱与关系网:从新闻、论文、问答中识别实体及其关系,构建“谁和谁有什么关系”的图谱,用于搜索、推荐和分析。 + - 票据与单据处理:对发票、对账单、报销单等,自动提取抬头、税号、金额、日期等字段,减少人工录入。 + - 舆情与事件分析:从海量文本中抽取“谁在什么时候在哪儿做了什么”,用于事件跟踪、风险预警与统计报表。 + - 日志与工单结构化:把客服对话、工单、系统日志等非结构化文本里的关键信息抽出来,方便统计、监控和自动化处理。 +- **原理** + 在 token / 短语层面,对文本进行细粒度标注与结构化: + - 序列标注:对每个 token 贴标签(如人名、地名、机构名、产品名等),实现命名实体识别、词性标注、短语切分等; + - 关系与事件抽取:在实体之上识别“实体‑实体”之间的关系,以及“谁在何时何地做了什么”的事件结构; + - 业务字段抽取:围绕具体业务 schema(如合同字段、票据字段),将长文档转成标准化的 key‑value 或记录表。 +- **模型** + 在预训练表示的基础上,通过序列标注或 span 抽取等结构完成信息提取: + - 序列标注模型:BiLSTM‑CRF、BERT + CRF / Softmax 等; + - Span‑based 抽取:直接预测实体 / 关系片段的起止位置; + - 文档级抽取:结合版式、布局的 DocIE 类模型; + - 基于 LLM 的抽取:通过 Prompt / Few‑shot,让大模型按指定格式抽取所需字段。 + +### 1.3.1 序列标注:给每个 token 和短语贴上语义“标签” + +在文本分类阶段,我们只关心整段文本属于哪一类;而在序列标注阶段,我们要对文本中的每一个 token、每一段短语进行标记。最典型的任务是命名实体识别(NER):识别人名、机构名、地名、产品名、疾病名等特定类型的实体。 + +- 例如,在句子“张三在北京加入某科技公司”中,把“张三”标为人名、“北京”标为地名、“某科技公司”标为机构。 + +从建模方式上看,传统的做法是使用 BiLSTM + CRF 这类序列标注结构,后续则更多采用 BERT + CRF 或 BERT + Softmax,利用预训练 encoder 的上下文表征能力,来判断每个 token 的标签(如 B‑ORG、I‑ORG、O 等)。在实践中,NER 模型往往是后续知识图谱、关系抽取的第一道“预处理”。 + +除了 NER 外,词性标注、短语切分也属于典型的序列标注任务。它们更多服务于底层语言分析,为后续更复杂的语法 / 语义任务提供基础结构。 + +- 比如对“快速 提升 模型 性能”标出“快速”为副词,“提升”为动词,“性能”为名词,用于下游分析。 + +### 1.3.2 关系与事件抽取:把“点”连成“线”和“故事” + +当我们通过序列标注识别出文本中的实体之后,一个顺理成章的问题是:这些实体之间到底是什么关系,它们共同构成了什么样的事件? + +关系抽取关注的是“实体对 + 关系类型”。例如,在一句“张三于 2024 年加入某科技公司担任 CTO”中,我们不仅要识别“张三”和“某科技公司”这两个实体,还要抽取它们之间的“就职于”关系。 + +- 简单来说,就是从“张三 – 某科技公司”这对实体上,贴上“任职”这类关系标签。 + +在关系之上,事件抽取则试图重建“谁在什么时候、什么地点,做了什么事情”。以一则新闻为例,一个标准的事件模板可能包含:事件类型(收购、合作、事故)、时间、地点、参与方、金额、后果等多个槽位。事件抽取模型需要从冗长的文本中自动填充这些槽位,从而构建出可被检索、统计和推理的“事件表”。 + +- 比如从“某公司以 5 亿元收购另一家公司”中抽出:事件类型=收购,金额=5 亿元,参与方=两家公司。 + +在建模方法上,除了传统的序列标注式抽取,我们还会采用 Span‑based IE(直接预测实体 / 关系 span 的起止位置)以及近年来兴起的 Prompt‑based IE 和基于 LLM 的 Few‑shot 抽取。后者的优势在于可以通过自然语言提示,快速适配新的 schema,减少大量重新标注和训练的成本。 + +从工程角度看,成熟的抽取系统往往会形成一条管线: + +- 上游 NER / 序列标注识别实体; +- 中间层做关系和事件结构建模; +- 下游把结果写入数据库或知识图谱,供搜索、分析和风控系统消费。 + +## 1.4 文本生成与编辑(Text Generation & Editing) + +在前面几节中,我们已经依次构建了“表示 → 分类匹配 → 序列标注与抽取”这条理解链路:模型不仅能把文本映射到语义空间,还能对整段文本做判断,并从中抽取出结构化信息。这一节要做的,是把这条理解链路“反向”再走一遍:在充分理解的基础上,让模型主动去生产、改写、压缩和润色文本。你可以把它理解为:在语义空间中进行“反向编码”,把内部表示重新变成高质量的自然语言输出,是整条文字模态能力链里最贴近用户感知的一层。我们依旧从目标、原理、模型和产品四个维度来拆解: + +- **场景** + - 日常写作与办公:生成邮件、通知、方案初稿,或对现有文本进行扩写、改写和润色。 + - 知识管理与总结:对长文档、报告、会议记录进行自动摘要,帮助快速抓住重点。 + - 客服与问答:根据用户问题和检索到的资料,自动生成结构清晰、口吻统一的回答。 + - 营销与创意内容:生成广告文案、社交媒体帖子、活动介绍、脚本等。 + - 多语言场景:在保持原意的基础上,完成翻译、本地化改写,适配不同语言和场景。 +- **原理** + 在语言建模的基础上,对文本进行“从无到有”和“基于已有内容的修改”: + - 自由生成:根据意图、提示词或大纲,从头生成一段完整的文本; + - 受控改写:在保持核心信息不变的前提下,调整风格、长度、结构(如摘要、扩写、风格转换); + - 纠错与润色:修正错别字、语法问题,优化表达顺序和逻辑结构。 +- **模型** + 以大规模预训练 + 指令微调的生成模型为主: + - 指令微调 LLM:GPT 系列、LLaMA / Qwen / GLM 等,用于通用生成与编辑; + - Seq2Seq 模型:T5、BART、mT5 等,用于摘要、翻译、格式转换等任务; + - 对齐与安全:通过 RLHF / RLAIF 等手段,让生成内容更加符合指令和安全要求。 + +由于这个部分基本等于提示词工程,故不再过多阐述,可以自行查看提示词工程部分的教程。 + +# 2. 图像模态(Image / Vision) + +在 AI 能力中,图像模态负责“用视觉理解世界”。不管最终想做的是安防监控、自动驾驶、短视频特效、电商智能修图,还是多模态问答、AI 画画,本质上都离不开一条路径:从原始像素出发,逐步获得对画面的结构化理解与可控生成能力。 + +## 2.1 底层视觉(Low‑Level Vision) + +在上一节中,我们从整体上介绍了视觉模态在多模态系统中的角色,以及它与语言、语音之间的衔接方式。但在真正进入目标检测、图像理解、视觉问答这些“高层语义任务”之前,还有一个往往被忽略、却至关重要的基础能力层——底层视觉。你可以把它理解为:在“看懂图里是什么”之前,系统需要先解决“这张图本身质量如何”“有哪些稳定的局部结构可以被上层复用”这两个问题,用一层通用的复原、增强和结构抽取,将原始像素转化为更干净、更稳定的图像表示。 + +从工程角度看,底层视觉既直接影响用户肉眼看到的“画质体验”,也决定了上层检测、识别、分割等任务的输入分布是否健康。如果这一层做得不好,后面所有模型都要在“噪声大、畸变重、光照极端”的环境下硬扛;相反,如果在这一层就把图像尽可能修好、结构信息提炼好,高层任务就可以在一个更友好的基座上发挥能力。下面我们同样从场景、原理和模型三个角度来梳理这一层: + +- **场景** + - 相机与拍摄设备:手机/相机的自动去噪、HDR、夜景模式、防抖,多帧融合提升细节和动态范围。 + - 内容平台与短视频:上传图片/视频的一键画质增强,去压缩块、提高清晰度和对比度,提升主观观感。 + - 老照片与文档修复:老照片的去噪、上色、超分辨率;拍歪、拍暗的票据、合同、书页自动拉正、增强,方便 OCR。 + - 监控与安防:低照度监控画面的降噪、去雾、防雨滴、提升分辨率,为后续人脸/车牌识别打基础。 + - AR/VR 与三维重建:为 SLAM、全景拼接、三维重建提供稳定的角点、边缘和局部描述子,保证跟踪与配准鲁棒性。 +- **原理** + 围绕“图像质量”和“局部结构”两个核心目标,对像素级信息进行物理与统计建模: + - 图像复原与增强:假设观测图像是理想图像经过噪声、模糊核、压缩和成像非线性等退化后得到,在这一假设下进行去噪、去模糊、去压缩伪影、低光照增强和超分辨率重建,使输出更接近真实场景成像,同时符合人眼感知习惯。 + - 结构特征抽取:在不引入具体语义标签的前提下,从像素梯度和纹理统计中提取边缘、角点、局部纹理、显著区域等特征,为后续的检测、配准、跟踪、分割提供“几何骨架”。 + - 几何与光照预处理:基于相机模型和简单几何线索(直线、消失点、对称性等)估计畸变与透视关系,通过去畸变、拉正、对比度与光照归一化等操作,将原始图像对齐到一个更标准、更稳定的输入空间。 +- **模型** + 综合使用经典图像处理方法和深度学习模型,在效率与效果之间做权衡: + - 传统图像处理:双边滤波、非局部均值、引导滤波、Retinex、直方图均衡、Canny/LoG 边缘检测、Harris/FAST 角点、SIFT/SURF/ORB 描述子、Hough 变换、相机标定与几何校正等。 + - 深度复原与增强模型:基于 CNN 或视觉 Transformer 的去噪、去模糊、超分辨率、去雨/去雾/去压缩伪影模型(如 EDSR、RCAN、SwinIR、ESRGAN 等),以及多帧/视频增强网络,用端到端方式学习从退化图到高质量图的映射,或使用现代的图像编辑模型实现例如即梦和 qwen 编辑模型。 + +### 2.1.1 图像复原与增强:从“看得见”到“看得清” + +在底层视觉里,图像复原与增强首先面对的是各种退化:噪声、模糊、压缩失真、低光照、动态范围不足等。很多真实场景下的原始图像并不“干净”:夜景和室内弱光会让画面布满颗粒和色斑,抓拍和监控画面常常因为运动、对焦不准而发虚,视频压缩会带来一块一块的方块噪声。复原与增强的目标,就是在不改变图像语义内容的前提下,尽可能恢复清晰的细节和自然的观感,把“模糊、灰暗、脏”的输入变得“清楚、明亮、舒适”。 + +典型任务包括去噪、去模糊、低光照增强和超分辨率等。去噪和去模糊需要在局部纹理和整体结构之间权衡:既要压制高频噪声、反卷积掉模糊核的影响,又不能把真实细节一起抹平;低光照增强则要在提升亮度与对比度的同时,避免暗部噪声被一并拉起,并校正偏色、压住过曝区域;超分辨率则侧重在放大的同时补出合理的高频信息,让放大后的图像既不显得“糊”和“塑料感严重”,又不过度“凭空捏造”细节。现代方法大多采用深度网络(CNN 或视觉 Transformer),在大量“退化–清晰”成对数据上学习从观测图像 y 到理想图像 x 的映射,同时使用包含像素误差、感知损失和对抗损失的组合目标,在“指标好看”和“人眼好看”之间取得平衡。 + +这些能力在产品中的呈现往往是隐性的:手机相机的夜景模式和 HDR 拍照、短视频平台的一键画质增强、老照片修复工具、监控系统的云端增强服务,本质上都依赖这一层的复原与增强模块。对业务而言,它们既直接影响用户对“画质”的主观感受,也间接决定了上层检测、识别、分割等算法的输入质量。可以说,越是复杂的上层视觉任务,越依赖底层有一个高质量、分布稳定的“图像地基”。 + +### 2.1.2 结构特征与预处理:为高层理解搭好“脚手架” + +当图像质量被修复到一个可用水平之后,底层视觉的第二项关键工作,是从像素中抽取出与具体语义暂时无关、但对几何结构和视觉感知非常重要的特征,并对几何和光照进行统一。这一步不会直接告诉你“这里是一辆车”或“这是某个人的脸”,但会回答“哪里有清晰的轮廓和拐角”“哪些区域纹理结构显著”“图像是否发生畸变或倾斜”等问题,为上层模型提供可靠的结构性输入。 + +在特征提取方面,边缘和角点是最基础的元素。通过 Canny、Sobel 等算子,系统可以在整张图上标出灰度或颜色变化最剧烈的“边缘”,这些往往对应物体轮廓、部件分界和纹理走向;角点检测(如 Harris、FAST)则找到局部梯度在多个方向上都变化显著的“拐角”,通常出现在物体的角、线条交汇处。进一步地,像 SIFT、SURF、ORB 这样的局部描述子,会在这些关键点周围编码一小片区域的纹理模式,使得同一物理点在不同视角、尺度和一定光照变化下仍然可以被匹配出来,这为图像配准、全景拼接、SLAM、AR 跟踪和三维重建提供了基础支撑。 + +与特征提取并行的,是各种几何和光照预处理操作。广角镜头带来的桶形/枕形畸变、拍摄文档时的倾斜和透视拉伸,都会通过直线检测、消失点估计等底层几何线索被识别出来,并通过去畸变、拉正、透视矫正等步骤被“拉回正常”;全局或自适应直方图均衡、对比度拉伸和光照归一化,则在保证细节不丢失的前提下,提升局部对比度、减弱光照不均和阴影的影响。颜色空间变换(RGB→HSV/Lab)与颜色直方图统计,为简单的基于颜色的分割、显著性区域检测、色偏校正等任务提供直接可用的输入。 + +在端到端深度学习成为主流之后,这些结构特征和预处理有一部分被“内化”到了网络前几层的卷积核和归一化策略中,不再以显式算子的形式出现在系统架构图上。但从功能上看,它们依然扮演着同样的角色:先用一层相对通用的、与具体类别无关的底层处理,把原始像素整理成在几何形态、光照条件和局部结构上更稳定的表示,再交给上层的分类、检测、分割和多模态模块去完成“理解这是什么”的任务。没有这层“脚手架”,上层模型就不得不在噪声大、畸变重、结构模糊的原始图上硬扛,整体系统的鲁棒性和泛化能力都会显著下降。 + +## 2.2 图像分类与识别(Image Classification & Recognition) + +在大部分图像任务中,业务方真正关心的问题是:**这张图整体属于哪一类?图里的这个人是谁?这名行人在不同摄像头下是不是同一个?** 你可以把这一层理解为:在一个统一、干净的输入空间上,为整张图像或者整个人/目标打上“类别标签”或“身份标签”,把视觉信号转化为最直接可用的识别结果。 + +从产品视角看,图像分类与识别是最早大规模落地的一批视觉能力,也是很多上层应用的“入口模块”。电商和内容平台用它来自动给图片打标签、识别主体品类;安防和门禁系统用它来确认“是不是同一个人”;行人重识别系统则在多路摄像头之间抽丝剥茧,找出同一目标的跨场景轨迹。下面我们同样从场景、原理和模型三个角度来梳理这一层: + +- **场景** + - 通用图片理解:为用户上传的图片自动打上“风景 / 美食 / 宠物 / 文档”等主题标签,用于检索、推荐、内容审核。 + - 人脸识别与门禁:在人脸门禁、考勤系统中,根据人脸图像识别个人身份,实现“刷脸通行”“刷脸打卡”。 + - 行人/人员重识别:在不同摄像头画面中判断是否为同一行人或同一人员,用于安防检索、轨迹分析。 + - 人体属性识别:在不直接确认身份的前提下,识别性别、年龄段、是否戴帽子/背包/穿制服等属性,为检索和行为分析提供线索。 +- **原理** + 在统一的视觉特征空间中,对整张图或整个人/目标进行判别式建模: + - 图像分类:以整张图像为输入,通过卷积网络或视觉 Transformer 提取全局特征,并在特征顶层接一个分类头,输出单标签或多标签的类别概率,用于回答“这是一张什么类型的图片”。 + - 身份/实例识别:将“是谁”的问题转化为特征空间中的度量学习问题,即学习一个嵌入空间,使同一身份的图像特征彼此接近,不同身份的特征彼此远离,然后用最近邻搜索或聚类完成识别与检索。 + - 属性识别:在共享的行人/人体特征之上,增加多任务输出头,预测性别、年龄段、衣着颜色、是否携带物品等属性标签,使得同一特征可以服务于多种下游检索与分析需求。 +- **模型** + 以深度卷积网络和视觉 Transformer 为主干,结合分类头或度量学习头实现不同类型的识别任务: + - 图像分类 Backbone:ResNet、DenseNet、EfficientNet、ConvNeXt、Vision Transformer (ViT)、Swin Transformer 等,通常在 ImageNet 等大规模数据集上进行预训练,再在具体业务数据上微调。 + - 通用分类结构:Backbone + 全连接分类层(Softmax / Sigmoid),用于单标签或多标签图像分类任务,可通过类别重加权、focal loss 等应对长尾分布。 + - 身份/实例识别:在 Backbone 的特征输出之上,使用 ArcFace、CosFace、SphereFace 等带角度约束的损失函数,显式拉大不同身份之间的类间间隔,提升在特征空间中的可分性,并通过向量检索(ANN)完成大规模库上的比对。 + - 行人/属性识别结构:针对行人 Re-ID 和人体属性识别,常见做法是采用共享 Backbone 提取行人特征,再在顶层分出“身份分支”和“属性分支”,既优化跨摄像头的身份区分能力,又兼顾多属性预测。 + +对应到具体产品形态,这一层的能力常以“图片内容识别 / 分类 API”“人脸识别 SDK / SaaS”“行人重识别平台”等方式对外提供。它们往往既直接驱动业务决策(如门禁放行、内容标签写入),又作为上游,为后续的检索、推荐、行为分析和多模态理解提供结构化标签与稳定的身份表征。下面,我们分别从图像分类和身份/属性识别两个角度展开。 + +### 2.2.1 图像分类:回答“这是一张什么图?” + +在最基础的图像分类任务中,系统面对的是整张图片,目标是给它贴上一个或若干个语义类别标签。最常见的是单标签分类,例如在 ImageNet 这样的数据集中,每张图被标注为“狗”“猫”“汽车”“飞机”等一个主类别;在业务场景中,这类能力被广泛用于给用户上传的图片加上“风景 / 美食 / 宠物 / 人像 / 文档”等主题标签,支持检索、推荐和内容审核。与文本分类类似,模型会在预训练 Backbone 提取的全局视觉特征之上接一个全连接 + Softmax 层,对所有候选类别输出一个概率分布。 + +在很多实际应用中,一张图往往同时属于多个类别,比如一张“海边日落自拍”图片,既可以是“风景”,也是“人像”,还可能被标注为“旅行”“海边”。这时就需要多标签分类(Multi‑label Classification):模型依然从整图特征出发,但输出层不再是互斥的 Softmax,而是对每个标签单独预测有/无的概率(Sigmoid),并采用多标签损失函数来训练。为了应对现实数据中大量“长尾类别”(冷门标签样本极少),多标签分类模型常会加入类别重加权、难例挖掘或标签结构建模等机制,提升对小众类别的召回。 + +在人机接口层面,图像分类通常以“图片内容识别 API”的形式对外提供。上游业务只需上传一张图片,即可获得一组类别标签及其置信度,用于后续的策略判断:比如广告投放系统可以根据图片内容限制某些敏感类目,电商平台可以利用图片分类辅助商品类目纠错,内容平台则用来丰富推荐特征和审核信号。虽然从技术上看,这类能力相对成熟,但它仍然是后续目标检测、实例分割、视觉问答等更复杂能力的基石。 + +### 2.2.2 图像识别与属性识别:回答“这是谁 / 这是什么实例?” + +与“这是一张什么类型的图”不同,图像识别更关心的是“图中的这个人/目标是谁”,也就是身份级、实例级的区分。典型代表是人脸识别和行人重识别:前者在门禁、考勤、支付等场景中判断“当前人脸与库中哪一个身份最接近”;后者则在多路摄像头与不同时间段的监控画面中,寻找是否存在同一行人,辅助案件回溯和轨迹分析。这类任务的核心,不再是简单的多分类,而是如何在特征空间中学习到一个“类内紧凑、类间分离”的嵌入,使同一身份在不同姿态、光照、摄像头下拍摄的图像仍能被聚到一起。 + +在模型设计上,人脸识别和行人重识别通常采用类似的范式:先用 ResNet、ConvNeXt、ViT、Swin 等 Backbone 提取以人脸/行人为中心的特征,再接上专门为度量学习设计的损失函数,如 ArcFace、CosFace 等。与普通分类损失不同,这些损失直接在角度空间或特征空间上约束类间边界,显式拉大不同身份特征之间的间隔,从而使得训练好之后的特征可以拿来做大规模向量检索,而不必局限于训练时见过的固定类别。在线服务时,系统会先对图库中每个身份的特征进行预计算和索引,再对上线查询的人脸/行人特征进行近似最近邻搜索,找到最相似的若干候选,并结合业务阈值和多模态信息做最终决策。 + +与“直接身份识别”相对应的,是不指向具体人的 **属性识别** 。在很多安防和零售场景下,系统只需要知道“是男性还是女性”“大概年龄段”“是否戴帽子/口罩”“衣服颜色和款式”“是否背包/拉行李”等属性,用于快速筛选目标,而不必、也不适合直接输出个人身份。这类任务通常在共享的行人/人体特征之上,接多个并行的属性头(头的意思是输出概率的位置,可以多几个概率输出的结果用于判断类别),每个头负责预测一个或一组属性标签,形成一个多任务学习框架。一方面,多任务训练可以让特征更加丰富、泛化更好;另一方面,属性本身也可以作为 Re-ID 或检索的辅助条件,提升系统在复杂场景下的可用性。 + +在产品形态上,这一类能力通常打包为“人脸识别 SDK/云服务”“行人重识别平台”“人体属性识别 API”等,被集成进门禁闸机、考勤机、安防平台和视频结构化系统。与通用图像分类相比,它们对数据安全和隐私保护要求更高,对误识率和召回率的权衡也更敏感,因此在算法之外,还会辅以质量检测(如是否为真人、是否为遮挡/翻拍)、活体检测、多模态交叉验证等机制,构成更完整、更负责任的身份识别方案。 + +## 2.3 目标检测(Object Detection) + +在前面的图像分类与识别中,我们只对“整张图”或“整个人”给出一个整体标签,而忽略了它在图中出现的位置和大小。然而,真实业务更常见的问题是:**这张图里有哪些物体?它们分别在什么位置?** 比如一张街景图中,我们希望同时标出所有的行人、车辆、交通标志牌;在工业产线上,需要在同一画面中标出所有瑕疵区域、零件位置。目标检测就是为这些需求而生的:它在单张图像或视频帧中,同时预测每一个物体的 **位置(bounding box)和类别** ,是众多下游视觉任务(跟踪、分割、行为分析、多目标计数等)的基础能力。 + +从工程使用角度看,目标检测是很多视觉系统的“第一步结构化”,把一张原始图分解为若干个带标签的矩形框,每个框都可以进一步送到其他模块做识别、跟踪、属性分析乃至语义生成。安防摄像头中行人/车辆的检测、无人零售货架上商品的检测、工业质检中缺陷/异物的检测、以及云厂商提供的「目标检测 / 物体检测」API,本质上都依赖这一层能力。下面我们从 **场景** 、**原理**和**模型**三个角度来梳理目标检测,并在后续小节中分别展开关键方向。 + +- **场景** + - 安防与交通监控:在摄像头画面中实时检测行人、车辆、非机动车、交通标志、逆行/占道目标等,为后续的行为分析和告警提供基础。 + - 工业质检与制造:在生产线上检测产品缺陷(划痕、破损、异物)、零部件位置、装配是否缺失,支持自动剔除与机器人定位。 + - 零售与物流:无人零售货架商品检测、结算;仓储中包裹、托盘、码垛的目标检测与定位,辅助库存盘点和机器人抓取。 + - 内容理解与审核:在图像/视频中检测人、logo、武器、敏感物品等,为内容审核、广告合规和品牌识别提供结构化信号。 +- **原理** + 目标检测的核心,是在图像上构建一个密集预测机制: + - 将输入图像通过 Backbone 提取为多尺度特征图,在这些特征图上,对每个“位置”(或候选区域)同时预测“是否有目标”“是什么类别”“对应的 bbox 参数”。 + - 按照架构划分,有先生成候选框再精修的 **双阶段检测(Two‑stage)** ,以及直接在特征图上做分类+回归的一体化 **单阶段检测(One‑stage)** ,两者在精度与速度上各有侧重。 + - 按候选框设计划分,有依赖预定义锚框(anchor)的 **anchor‑based** 方法,也有直接预测中心点/边界的 **anchor‑free** 与基于集合匹配的 **DETR 家族** 。 + - 为应对现实数据中的小目标、密集目标、遮挡和尺度变化,检测器通常会结合多尺度特征(FPN)、更高分辨率输入、特定损失函数与后处理策略(如 NMS 变体、多尺度测试)进行优化。 +- **模型** + 检测模型大体由**骨干网络 + 特征金字塔 / 头部结构 + 损失与后处理**三部分构成: + - 经典双阶段检测器:Faster R‑CNN、Mask R‑CNN 等,先通过 RPN 产生候选框,再对每个候选区域做精细分类与回归,精度高、结构清晰,适合对精度要求极高的场景。 + - 单阶段检测器:SSD、RetinaNet、YOLO 系列(YOLOv5/6/7/8、YOLOX、YOLOv10 等)等,在一个统一的网络中完成检测,结构紧凑、延迟低,是工业界实时检测的主力。 + - Anchor‑free / Transformer 检测器:FCOS、CenterNet、ATSS 等以像素点为中心直接预测框;DETR / Deformable DETR 等通过 Transformer 和集合匹配,将检测视为“从一组查询中生成一组目标”的问题,简化多种手工设计。 + - 视频检测与跟踪:在图像检测器的基础上,引入时序信息与关联策略(如跟踪头、光流、轨迹匹配),形成 Detection + Tracking 的统一框架,支撑长时间、多目标的行为分析。 + +综合来看,目标检测处于视觉能力谱系的“中枢位置”——它一方面承接底层视觉提供的干净图像输入,另一方面把图像解构成可供识别、跟踪、分割和多模态理解使用的“目标级”元素。下面,我们分别从 **单/双阶段检测架构** 、**Anchor‑based / Anchor‑free / Transformer 检测**以及**小目标与视频检测**三个方向展开。 + +### 2.3.1 单阶段与双阶段检测:精度–速度的结构权衡 + +从架构上看,目标检测最经典的划分是 **双阶段(Two‑stage)与单阶段(One‑stage)** 。二者的主要区别在于:是先“粗选一批候选框,再进行精修”,还是在特征图上“一次性预测完所有框和类别”。 + +双阶段检测以 Faster R‑CNN 为代表。它首先在 Backbone 特征图上通过 RPN(Region Proposal Network)生成一批“高概率包含目标”的候选框(第一阶段),然后对每个候选区域进行 RoI 对齐与特征提取,再做更精细的分类与边框回归(第二阶段)。这种设计的好处是:大量负样本在 RPN 阶段就被过滤掉,第二阶段可以集中精力在少数候选区域上做高质量的判别,因此在精度上往往更有优势,也更容易扩展到实例分割(Mask R‑CNN)、关键点检测(Keypoint R‑CNN)等任务。不过,多阶段结构带来的计算与实现复杂度相对较高,更适合对实时性要求不那么苛刻、但强调精度和可扩展性的离线或准实时场景。 + +单阶段检测则力图打通整个流程,在一个统一的网络中同时完成类别分类和边框回归。代表模型包括 SSD、RetinaNet 和 YOLO 系列等:它们直接在多尺度特征图的每个位置上预测若干候选框的“前景/背景 + 类别 + bbox”,省去了显式 proposal 阶段,更适合做端到端加速与部署。早期的单阶段检测器相对双阶段在精度上有一定差距,但凭借结构简单、速度快,在工业界迅速占据主导;随着 FPN、focal loss、IoU‑aware loss,以及更强 Backbone 和 Neck 的引入,RetinaNet、YOLOX、YOLOv7/8/10 等新一代模型已经在很多任务上实现了“接近甚至赶超双阶段”的精度–速度平衡。 + +在应用层面,工程上通常会根据需求在这两类架构间做取舍:对于云端批量离线分析、需要较高精度和可扩展性(如同时做检测+分割+关键点)的任务,双阶段检测仍然是一个稳定可靠的选择;而对于边缘设备、移动端应用、摄像头实时检测等延迟敏感场景,YOLO 系列等单阶段检测器几乎是默认首选,并且往往会结合量化、剪枝、蒸馏等技巧,以进一步压缩模型和提升吞吐。 + +### 2.3.2 Anchor‑based 与 Anchor‑free:从手工设定到端到端学习 + +在如何定义“候选框”这一问题上,检测方法又可以分为 **Anchor‑based 和 Anchor‑free** 两大类。早期主流方法(如 Faster R‑CNN、SSD、RetinaNet、YOLOv3/v4/v5 等)采用 Anchor‑based 思路:在特征图的每个位置预先定义若干具有不同尺度和长宽比的锚框(anchor),然后学习每个 anchor 对应的前景概率和 bbox 偏移量。这种方式实现简单、效果好,但需要人工对 anchor 的尺寸和比例进行较多调参,且在小目标、密集目标场景下容易出现 anchor 数量庞大、正负样本极度不平衡的问题。 + +Anchor‑free 方法则尝试摆脱对预定义 anchor 的依赖。以 FCOS、CenterNet、ATSS 等为代表,它们通常直接在特征图的每个像素点上预测“这里是否是某个目标的中心(或属于该目标)”以及对应的边界距离,从而完全避免了预设 anchor 的复杂性。这样的好处是:模型结构更简洁,训练样本分配策略可以更加自然,尤其在面对尺度变化大、目标形状复杂的真实场景时,具有更好的泛化和可扩展性。与此同时,Anchor‑free 检测器也推动了更多基于像素/点的统一框架,使得检测与关键点、分割等任务更易共同建模。 + +更进一步,DETR / Deformable DETR 等 Transformer‑based 检测器从另一个维度重新思考了检测问题:它们不在特征图上密集铺设 anchor,而是引入一组固定数量的“查询向量”(object queries),通过 Transformer 的自注意力和交叉注意力机制,从全局特征中“生成”一组目标预测,并通过匈牙利匹配(Hungarian Matching)实现一一对齐。这种集合预测(set prediction)的思路彻底消除了 NMS 和手工样本分配等传统组件,在概念上非常简洁,但在早期实现中存在收敛慢、对小目标不友好等问题;后续的 Deformable DETR 通过引入可变形注意力和多尺度机制,在收敛速度和性能上都有明显提升,逐渐在检测与多任务场景中获得更多应用。 + +对于工程实践而言,Anchor‑based、Anchor‑free 与 Transformer 检测并不是互斥的选择,而更像是一条演化链:从 heavily engineered 的 anchor 设计,到更为端到端的点/中心预测,再到完全基于集合预测与注意力的统一框架。当前工业落地中,YOLO 系列等成熟 Anchor‑based 模型依然是主力,Anchor‑free 和 DETR 家族则更多出现在对结构简洁性、多任务统一性、可扩展性要求较高的系统中。 + +### 2.3.3 小目标与视频检测:走向真实场景的鲁棒性 + +在公开数据集上的目标检测往往给人一种“问题已经基本解决”的错觉,但一旦进入真实场景,就会立刻遇到两类棘手问题:**小目标/密集目标**与 **视频中的稳健检测与跟踪** 。 + +小目标检测中,目标在原图中往往只占极少的像素区域,例如远处的行人、遥远的车辆、空中无人机,或者高分辨率工业图像上的微小瑕疵。随着 Backbone 下采样和特征图分辨率的降低,这些小目标在高层特征中很容易被“淹没”,导致漏检。为此,检测器通常会采用多尺度特征金字塔(FPN/PAFPN 等)、提高输入分辨率、在浅层特征图上增加检测头,甚至专门设计针对小目标的分支和损失加权策略。同时,在数据层面也需要通过裁剪、放大、小目标重采样等方式,提升模型对小尺度目标的感知与记忆能力。 + +密集目标(如拥挤人群、密集停车场、排列紧凑的商品/零件)则会暴露出锚框重叠、NMS 误杀、遮挡严重等问题。改进策略包括更精细的标签分配(如 ATSS 等自适应分配方法)、软 NMS 或基于学习的去重策略、以及通过中心点/密度图建模等方式缓解框间竞争。在工业质检中,许多系统还会结合检测与像素级分割,实现更精确的缺陷定位,以便后续自动处理。 + +当检测从单帧扩展到视频时,另一个挑战是 **时间连续性与目标稳定性** 。单帧检测器在每一帧上独立做出预测,难以避免短时丢检、ID 抖动和虚警,而现实应用中的告警、计数、轨迹分析往往需要跨帧一致的目标轨迹。为此,视频目标检测通常会叠加一个 Tracking 模块,把“检测 + 目标跟踪”打通:经典做法是以图像检测器为前端,在后端利用卡尔曼滤波、匈牙利匹配、外观特征相似度等实现多目标跟踪(如 SORT、DeepSORT 等);更进一步的做法是将跟踪头直接整合到检测网络中,联合学习检测与跨帧关联,提高短时遮挡、快速运动等场景下的鲁棒性。 + +在实际系统中,小目标、密集目标和视频检测往往不是孤立的问题,而是同时出现:例如城市道路监控中的远处行人/车辆、车站广场中的密集人群、产线视频中的高速运动零件。这也决定了,高质量的目标检测模块,除了在标准 benchmark 上有亮眼指标外,更需要在多尺度、多密度、长时间视频等真实条件下,经受住各种复杂因素的考验,才能真正支撑上层的行为分析、智能告警和多模态理解。 + +## 2.4 图像分割(Image Segmentation) + +有了目标检测,我们已经可以知道“图里有哪些物体、它们大致在哪里”,但很多任务还需要更精细的结构化理解:**精确到每一个像素,判断它属于哪一类、属于哪个实例** 。例如自动驾驶中要知道哪些像素是路、哪些是人和车;抠图工具要把头发丝和背景分得干干净净;医学图像里要精确描出肿瘤和器官的边界。这类任务统称为图像分割,它直接在像素层面输出语义或实例标签,相比检测提供了更细粒度的空间结构信息。 + +从产品角度看,图像分割是“像素级结构化”的核心能力:抠图和背景替换工具依赖它决定哪些像素需要保留;自动驾驶的感知模块依赖它构建精细的“可行驶区域 + 障碍物”地图;医学影像软件依赖它测量病灶大小、形状和体积;遥感平台依赖它区分农田、水体、建筑、道路等地物。下面我们从 **场景** 、**原理**和**模型**三个角度来梳理图像分割,并在后续子项中展开语义/实例/全景/大模型分割等方向。 + +- **场景** + - 内容编辑与抠图:人像抠图、头发丝级别的背景替换、物体抠出和分层编辑,用于图片美化、短视频特效、广告创意制作。 + - 自动驾驶与机器人:对每个像素标注路面、车道线、行人、车辆、护栏、建筑、天空等,用于路径规划、碰撞预警和环境建模。 + - 医学影像分析:在 CT、MRI、超声等图像中精确分割器官、肿瘤、病灶区域,支持辅助诊断、手术规划和疗效评估。 + - 遥感与地理信息:在卫星/航拍图中分割农田、水体、道路、建筑、林地等地物,支持国土规划、土地利用监测和灾害评估。 +- **原理** + 图像分割本质上是“密集预测”,对输入图像通过编码器(Backbone)提取多尺度特征,再通过解码器或上采样模块,将特征图逐步还原到与输入同尺寸的分割图,在每个像素位置上输出一个语义或实例标签。 + - **语义分割(Semantic Segmentation)** :为每个像素分配一个语义类别(如路、人、车、天空),不区分同类的不同个体,适合描述“场景组成”。 + - **实例分割(Instance Segmentation)** :在语义信息之上进一步区分同类不同实例,为“每一辆车、每一个人”生成独立掩膜,是检测与分割的结合。 + - **全景分割(Panoptic Segmentation)** :统一处理“可数的物体(thing,如人、车)”与“不可数的背景(stuff,如路、天空)”,为每个像素同时给出语义标签和实例 ID。 + 与检测相比,分割对空间细节与边界质量更加敏感,需要更丰富的多尺度上下文信息和更精细的上采样/融合策略。 +- **模型** + 经典到最新的分割模型大致沿着“FCN → 编码器–解码器 → 多尺度上下文 → 检测+分割一体化 → 大模型分割”的路线演化: + - 语义分割:FCN、U‑Net 及其变体、DeepLab 系列(DeepLabv3/v3+)、PSPNet 等,通过空洞卷积、金字塔池化、跳跃连接等方式获取多尺度上下文和精细边界。 + - 实例/全景分割:Mask R‑CNN、Panoptic FPN、Mask2Former 等,将检测头与分割头结合,实现目标级分割和全景分割。 + - 大模型与通用分割:Segment Anything Model (SAM) 等基础分割模型,将分割从“每个任务单独训练”提升为“一个模型适配多数分割场景”,支持交互式、提示驱动(prompt‑based)的分割。 + +总体而言,图像分割相比目标检测提供了更精细的空间结构表达,是构建高可靠感知系统和高级编辑工具时不可或缺的一环。下面,我们从 **语义分割与实例分割**, **全景分割与检测一体化**, 以及**通用分割**, **大模型**, **与无监督分割**三个方向展开。 + +### 2.4.1 语义分割与实例分割:从“像素类别”到“像素实例” + +**语义分割(Semantic Segmentation)** 的目标,是为图像中的每一个像素指定一个语义类别,使得网络学会“这片区域是路,那片区域是车,这里是人,那边是天空和建筑”。经典做法通常采用编码器–解码器结构:编码器(如 ResNet、EfficientNet、Swin Transformer 等)提取逐渐下采样的高层特征,解码器通过上采样、跳跃连接(skip connection)和多尺度融合,将粗糙的高层语义特征与底层细节结合,还原到原始分辨率。FCN 首次将这种密集预测形式系统化,U‑Net 通过对称的 U 型结构与大量 skip connection 在医学影像中取得了巨大成功;DeepLab 系列通过空洞卷积(dilated convolution)和 ASPP(金字塔空洞池化)在不降低分辨率的情况下扩大感受野;PSPNet 则通过金字塔池化获取全局上下文信息。这些模型共同推动了在道路场景、遥感、医学等领域的大规模应用。 + +**实例分割(Instance Segmentation)** 进一步在像素语义标签的基础上区分同类不同个体:不只要知道哪些像素是“车”,还要知道这些像素分别属于哪一辆车。最具代表性的模型是 Mask R‑CNN,它在 Faster R‑CNN 的检测框架上增加了一个并行的分割分支:先通过检测头预测每个候选框的类别和位置,再在每个框内生成一个二值掩膜,从而得到“框 + 掩膜”的目标级分割结果。与纯语义分割相比,这种方法能够很好地处理物体重叠和遮挡,是人像/商品抠图、多目标计数、细粒度编辑等任务的基础。后续的实例分割方法在 mask 质量、多尺度与速度上不断改进,也出现了基于 anchor‑free 和 Transformer 的新架构,但“检测 + 局部分割”的思路仍然非常主流。 + +在产品层面,语义分割通常出现在“场景级”的应用中,例如自动驾驶道路分割、遥感地物识别、医学器官分割等;实例分割则更常用于“物体级”抠图、计数和编辑,例如一键选中并分离每一辆车、每一个人、每一件商品。两者结合,可以为上层任务提供既精细又结构化的空间信息。 + +仅做语义分割会把同类对象混在一起(所有“车”像素都属于同一个类);仅做实例分割又往往只关注可数的“东西”(things,如人、车、动物),而忽视大面积的不可数“背景”(stuff,如路、草地、天空)。在很多场景中,我们既需要知道**每一个对象的实例级掩膜** ,又想了解 **整体场景构成** 。这就催生了**全景分割(Panoptic Segmentation)** :为每一个像素同时给出语义类和实例 ID,实现对 thing + stuff 的统一建模。 + +早期的全景分割系统通常通过“语义分割模型 + 实例分割模型 + 后处理合成”的方式实现:先用一个网络预测每个像素的语义类别,再用另一个网络输出各个实例的掩膜与类别,最后通过一套规则(如优先级、重叠处理)将两者合并为一个一致的全景分割结果。Panoptic FPN 代表了一条工程上更优雅的路径:在一个共享 Backbone 与特征金字塔(FPN)上,分别挂载语义分割头和实例分割头,通过联合训练与特征共享,同时得到两种输出,再通过轻量的后处理将它们融合。这样不仅提高了效率,也增强了语义和实例之间的一致性。 + +在模型层面,随着检测/分割一体化与 Transformer 架构的发展,出现了如 Mask2Former 等统一的全景分割框架:它们倾向于使用一套通用的“query + mask decoder”结构,在同一网络中同时预测语义、实例乃至其他下游任务的掩膜,从而在架构上大幅简化系统、方便多任务扩展。对于自动驾驶、机器人导航、AR 场景理解等复杂任务来说,全景分割提供了一种更接近“人眼主观感受”的完整场景描述,让上层决策和规划可以在更准确的空间语义上进行。 + +在产品形态上,全景分割往往内嵌在自动驾驶、机器人系统和高端视觉分析平台中,用户未必直接感知到“全景分割”这个概念,但会真实受益于更稳健的场景理解和更自然的交互体验。 + +### 2.4.2 通用分割与无监督分割:从任务定制到“Segment Anything” + +传统分割模型往往围绕特定数据集和任务训练:比如“道路场景 19 类语义分割”“某种肿瘤分割”“某几类商品分割”等,每换一个任务就要重新标注、重新训练。在实际业务中,这种强依赖精标数据的方式代价巨大,并且难以覆盖长尾类别和不断涌现的新场景。近年来,随着大规模预训练视觉模型和提示驱动(prompt‑based)范式的发展,出现了以 **Segment Anything Model (SAM)** 为代表的**通用分割大模型** ,试图把分割能力从“任务定制”提升为“基础设施”。 + +以 SAM 为例,它通过一个强大的图像编码器(通常是大规模预训练的 ViT)学习全图的通用特征,再通过轻量的提示编码器和掩膜解码器,将用户给出的点、框、文本提示等转化为分割结果。在训练阶段,SAM 利用了海量、多源、多任务的掩膜标注,使得模型学到的是一种“泛化的分割能力”,而不是对某个数据集标签的死记硬背;在使用阶段,用户只需给出极少量提示(一个点或者一个粗框),就能在各种未见过的图像类型和物体类别上得到质量较高的掩膜。这种范式大大降低了构建新分割应用的门槛,也为无监督/弱监督场景提供了强有力的工具。 + +与之相关的,是更广义的**无监督 / 自监督分割**方向:不依赖或极少依赖人工掩膜,通过图像内部的相似性、时序一致性、多视角约束等信号,自动将图像划分为若干有意义的区域。早期工作多侧重于“视觉聚类”和区域提议(proposal generation),如今则更多地被大模型内化为一种表征学习方式,为下游的分割任务提供良好的初始化。结合 CLIP 等文本–图像对比学习模型,越来越多的方法能够在“只给文本类别名称、不提供掩膜标注”的条件下,进行零样本或少样本分割,为冷启动场景和长尾类提供新解法。 + +在实际产品中,通用分割大模型往往以“交互式抠图工具”“智能选区”“一键抠背景”等形式出现,也逐步被整合进医学、遥感、工业等领域的专业软件中,作为半自动标注与辅助分割的加速器。与传统定制模型相比,它们不一定在某个特定任务上达到极致,但在“什么都能做一点、多场景快速落地”上有显著优势,也为后续构建真正的多模态基础视觉模型打下了基础。 + +## 2.5 关键点检测与动作识别(Keypoint Detection & Action Recognition) + +在分类、检测、分割之后,我们已经可以知道“图里有什么、在哪儿、每个像素属于什么”。但在很多真实任务中,业务关心的不仅是“物体存在与位置”,而是**姿态和动作** :一个人是在走路还是在奔跑?这只手是否举起、是否做出某个手势?工人是否正确佩戴安全设备、执行规范动作?运动员的技术动作是否标准?这些问题需要我们进一步理解 **物体内部的结构与时序变化** 。 + +关键点检测与动作识别就是面向这一需求的两层能力: + +- **关键点检测(Keypoint Detection)** :在图像或视频帧上,预测目标(通常是人体、手部、面部或特定机械结构)的若干“骨架点”(如关节、指尖、五官),得到一个精细的结构化姿态表示(pose)。 +- **动作识别(Action Recognition)** :在时序上分析这些关键点或外观特征随时间的变化,判断“这个人/这群人正在做什么动作或行为”。 + +从产品视角看,这一能力广泛服务于:人机交互(手势控制)、体育分析(技术动作评估)、安防(跌倒检测、打架/奔跑等异常行为识别)、工业安全(违规动作检测)、虚拟人驱动(依靠人体/面部关键点驱动 3D 骨骼与动画)等场景。下面我们从 **场景** 、**原理**和**模型**三个角度梳理这一层能力,并在子节中分别展开关键点检测与动作识别。 + +- **场景** + - 人机交互与 AR/VR:通过手势识别、身体姿态检测,实现“比划一下就能控制”的自然交互,或在 AR/VR 中实时驱动虚拟形象。 + - 体育训练与运动分析:对跑步、跳高、投篮、举重等动作进行关键点追踪与角度分析,给出技术动作评估与纠错建议。 + - 安防与公共安全:检测跌倒、打架、剧烈奔跑、翻越护栏等异常行为,用于及时告警;在工地、厂区中识别是否规范操作。 + - 工业与人机协作:检测工人是否按规范姿态操作、与机器人协作时的安全距离、是否出现危险动作。 + - 面部/表情驱动与虚拟人:通过面部关键点捕捉表情细节,用于表情迁移、数字人驱动、视频会议虚拟形象等。 +- **原理** + 两类任务分别侧重空间结构与时序变化,但本质上都是在高维特征空间中做结构化预测: + - 关键点检测:在图像上定位一组预定义关键点(如 17/25 个人体关节、21 个手部关节、68/106 个面部关键点),常用方式是在特征图上预测每个关键点的热力图(heatmap),再通过峰值位置反推坐标;多人的场景下,还需要进行“关节到人的组装”。 + - 单帧/短时动作识别:基于单张图或短时间窗口,通过人体姿态(关键点)和外观特征,判断该帧/该片段中发生的动作类别(如走、跑、举手、挥手、坐下等)。 + - 时序动作识别:在更长的时间尺度上,分析特征序列(图像特征、关键点序列或光流等),建模动作的起始、持续与结束,识别“正在打电话”“正在做俯卧撑”“两人互相推搡”等复杂行为。 + - 结构化表示:关键点序列提供了一种比原始像素更紧凑、更稳定的结构化表示,便于在动作识别中处理视角变化、背景干扰和外观差异。 +- **模型** + 常见模型大致沿着“卷积/Transformer 特征提取 + 关键点/时序头”这一统一范式发展: + - 关键点检测:OpenPose 系列、Hourglass Network、HRNet、基于自顶向下(先检测人再估计姿态)和自底向上(先检测关节再组装)两大分支;近年来也有基于 Transformer 的姿态估计器。 + - 视频动作识别:基于 2D/3D CNN 的视频模型(I3D、SlowFast 等)、基于骨架的 GCN 模型(ST‑GCN 等,直接在关键点图上建模时空关系)、以及基于视频 Transformer(Video Swin、TimeSformer 等)的端到端方案。 + - 统一多任务与大模型:在通用视觉 Backbone 上同时输出检测、分割、关键点和动作标签,或利用多模态大模型通过文本提示直接理解“这个人在做什么动作”,将结构化预测与语义理解连接起来。 + +下面我们分别从**关键点检测与姿态估计**以及**动作识别与行为理解**两个方向展开。 + +### 2.5.1 关键点检测与姿态估计:给人和物“画骨架” + +关键点检测(也常被称为姿态估计,Pose Estimation)关注的是 **单帧或单幅图像中的空间结构** :在二维图像中找到一组具有语义意义的关键点,并将它们连接成骨架。例如,在人体姿态估计中,我们通常需要检测头部、肩膀、肘、腕、髋、膝、踝等关节;在面部姿态中则是眼角、嘴角、鼻尖、脸廓等;在手部姿态中则是指根、指关节、指尖。对于机械臂、关节结构件等非人体对象,也可以同样定义一套关键点体系。 + +在模型设计上,关键点检测常用的是 **“特征提取 + 热力图预测”**范式: + +- 首先使用 CNN 或视觉 Transformer(如 ResNet、HRNet、Swin 等)对输入图像提取多尺度特征。 +- 然后通过一个解码头或多层卷积,为每一个关键点类型输出一张热力图(heatmap),其中每个像素值表示“该位置是该关键点的可能性”。 +- 推理阶段,通常取每张热力图的峰值位置作为关键点坐标,并通过双线性插值、局部拟合等方式进行亚像素级优化。 + +针对多人场景,姿态估计方法大致分为两路: + +- **自顶向下(Top‑down)** :先使用行人检测器在图中找到每个人的边界框,再对每个框内的图像分别做单人姿态估计。这种方式对单人精度高、框架简单,但在多人密集场景中计算代价大、对检测质量敏感。代表系统包括许多基于 Faster R‑CNN/YOLO + Hourglass/HRNet 的组合。 +- **自底向上(Bottom‑up)** :不先区分每个人,而是在全图上直接预测所有潜在关键点(及其类型),同时预测关键点之间的连接关系或亲和场(如 OpenPose 的 PAF)。然后通过图匹配/聚类算法,将关键点组装成多个独立的人体骨架。这类方法在多人密集场景中更高效、对人数规模更鲁棒,但组装过程复杂,对连接质量敏感。 + +近年来,基于 Transformer 的姿态估计模型也逐渐出现,将关键点检测看作一组“查询–响应”任务,与 DETR 类似,可以在架构上统一对象检测与姿态估计。在工程应用中,关键点检测能力通常被封装为“人体/手势/面部关键点 SDK 或 API”,上游应用只需传入图像或视频帧,即可获取结构化的骨架坐标,用于后续的动作识别、交互控制或动画驱动。 + +### 2.5.2 动作识别与行为理解:让“骨架”动起来 + +在得到关键点或高层视觉特征之后,下一步就是理解 **时间维度上的变化** ——也就是动作识别(Action Recognition)和行为分析(Behavior Understanding)。与关键点检测不同,动作识别不再局限于单帧;它关心的是一段时间内特征的演化模式:从“抬手”到“挥手”,从“走路”到“奔跑”,从“站立”到“跌倒”。 + +在输入表示上,大致有三条路线: + +- **基于原始** **视频帧** **/光流** :直接对视频帧序列建模,或额外引入光流(描述局部运动速度的场)作为输入,让模型从外观 + 运动信息中联合学习。 +- **基于骨架/关键点序列** :先用姿态估计得到人体关键点坐标序列,再在“时空骨架图”上建模,弱化背景与光照干扰,更关注人体结构与运动模式。 +- **多模态融合** :将视频特征、关键点序列、甚至音频、文本等多模态一起纳入,处理复杂行为场景(如多人互动、事件级动作)。 + +对应地,模型结构也呈现出多样化发展: + +- 早期的动作识别主要依赖 **2D CNN + 时间 n 池化** 或 **3D CNN** (如 I3D、C3D):前者对每一帧提特征再在时间维上做池化或 RNN;后者直接在空间和时间上做三维卷积,捕捉短时运动模式。 +- 针对骨架序列,典型方法是 **时空图卷积网络(ST ‑ GCN)** :把人体关键点看作图结构节点,关节之间的连接是边,在时间维上也连边,通过图卷积在时空图上传播信息,从而学习动作模式。这类方法轻量、对背景鲁棒,适合在资源有限的设备上部署。 +- 近年来, **视频 Transformer** (如 TimeSformer、Video Swin)在动作识别中表现突出,它们将视频切分为时空 patch,通过自注意力机制建模长时间依赖,能够更好地捕捉复杂动作与多目标交互。 + +在业务侧,动作识别往往会与检测、跟踪、关键点检测结合,形成端到端的行为分析系统: + +- 在安防中,先检测并跟踪人员,再对每条轨迹的关键点序列进行动作分类,实现跌倒检测、打架/奔跑识别等; +- 在体育和健身应用中,通过关键点序列分析动作是否标准、幅度是否合适,并给出纠正建议; +- 在人机交互场景中,对实时姿态流进行轻量级动作分类,实现挥手、比心、手势指令等交互; +- 在工业安全中,对工人操作动作进行持续监测,识别危险姿态(如俯身进入危险区、越过安全线等)。 + +面向未来,多模态大模型正在将“动作识别”提升为更高层的“事件与意图理解”:模型不仅可以标注“走路、跑步、打电话”,还能够回答“这个人似乎在示意招呼某人”“这两人正在发生争执”等更接近日常语言的描述。关键点检测和动作识别在其中,作为重要的结构化运动线索,与外观特征和语言提示一起,共同支撑更复杂的时空理解能力。 + +## 2.6 开放词汇 / 开放世界 / 开放域检测 + +(Open‑Vocabulary / Open‑World / Open‑Domain Detection) + +前面的检测与分割能力,基本都默认一个前提: **训练和推理时的类别集合是固定的** 。也就是说,模型在训练阶段就完整地见过“所有要识别的类别”,推理时只需要在这套封闭标签里做选择。但真实世界远比数据集复杂:新商品、新品牌、新路牌、新物种、新场景随时出现,不可能为每个新类都准备充足的标注数据重新训练检测器。这就催生了 **开放词汇 / 开放世界 / 开放域检测** :在训练数据只覆盖有限“已知类”的情况下,让模型在推理时仍然能够感知、定位和识别 **未见的新类** ,并且在视觉风格和拍摄域(domain)变化时保持鲁棒性。 + +你可以把这一层理解为:在传统检测之上,加入“对语言空间与开放世界的对齐和泛化能力”。模型不再只会说“这是 80 类 COCO 之一”,而是可以在任意文本描述的空间里理解和检索目标,例如“检测图里所有‘红色运动鞋’”“标出所有‘疑似小型飞行器’”,即便这些精细类别在训练集中从未显式出现。下面我们从 **场景** 、**原理**和**模型**三个角度来梳理这一层,并在子小节中分别展开开放词汇检测、开放世界检测和开放域泛化。 + +- **场景** + - 通用场景理解 API:用户给出任意自然语言描述(类别词或短句),系统在任意风格的图像中返回对应目标的检测框或分割掩膜,例如“图中所有安全帽”“所有疑似品牌 logo”“所有带轮子的物体”。 + - 大规模商品 / 物种识别:电商中不断上新的长尾商品、自然界中数量巨大的动植物物种,训练数据只能覆盖一部分已知类,但系统需要对海量新类进行定位与粗识别,并支持通过文本或图像检索。 + - 跨域安防 / 自动驾驶感知:训练数据多来自白天城市道路/少数摄像头视角,实际部署却面临不同城市、乡村、高速、极端天气、红外/鱼眼摄像头等“新域”,其中还会出现训练集中从未标注过的新型目标(新款车型、新交通设施、新类型障碍物)。 +- **原理** + 这类方法的核心,是用**视觉–语言对齐的嵌入空间**替代传统的“固定 one‑hot 类别头”,并通过多种机制处理“未见类”和“新域”: + - 开放词汇检测(Open‑Vocabulary Detection):在训练阶段,利用大规模图文对(image–text pairs)预训练得到类似 CLIP 的对齐空间,使得图像区域和文本嵌入可以直接在同一语义空间中做相似度匹配;检测头不再输出固定的类别 logit,而是输出一个区域特征向量,与任意文本描述向量进行对比,从而支持“训练只见部分类别,推理可指定任意文本类别”。 + - 开放世界检测(Open‑World Detection):进一步处理“训练集中完全没有标注的新类”,要求模型可以将这类目标检测为“未知类(unknown)”,并在后续通过交互标注或持续学习,把这些未知类逐步纳入已知类别集合,形成一个可以不断扩充类目的在线学习系统。 + - 开放域 / 跨域检测(Open‑Domain Detection):面对图像风格、成像设备、环境条件等大幅变化(domain shift),通过领域自适应(Domain Adaptation)、领域泛化(Domain Generalization)等技术,让检测器在未见过的新域中保持稳定检测性能;常见手段包括对抗性域对齐、多域训练、风格随机化、元学习等。 + - 分割与检测一体的开放词汇:将上述思路扩展到像素级,对任意文本描述生成分割掩膜(open‑vocabulary segmentation),通过 Region–Word 或 Mask–Word 对齐损失,实现“用自然语言描述一个区域/物体,就能得到对应 mask 或框”。 +- **模型** + 当前开放词汇 / 开放世界 / 开放域检测的主流技术路线,基本围绕“大规模视觉–语言预训练 + 检测头适配 + 域泛化机制”展开: + - CLIP‑based 检测器:以 CLIP 风格的图像编码器和文本编码器为基础,在区域级特征(ROI、特征图 patch、mask 区域)与文本嵌入之间应用对比学习和 Region–Word 对齐损失;典型实现包括在 Faster R‑CNN / RetinaNet / YOLO / DETR 等架构上替换或扩展分类头,使其以“cosine 相似度 + 文本嵌入”方式输出类别分数。 + - Caption‑driven / Prompt‑based Detection:利用大规模图文描述(caption)数据,为图像中的区域或 mask 自动生成文字描述,再用这些自动生成的文字与检测/分割区域对齐训练,从而减少对人工类别标签的依赖;推理时则通过自然语言 prompt(如“所有穿红色衣服的人”“所有电动车”)驱动检测/分割。 + - Open‑World Detection 系列工作:在传统检测框架中显式引入“未知类(unknown)”建模、渐进式类别扩展和增量学习机制,一部分方法通过度量空间的距离与不确定性估计来判断“是否为未知类”,另一部分引入记忆库与在线重训练,使系统能随时间积累新类别知识。 + - 域自适应 / 域泛化检测:在 Backbone 和检测头层面增加域判别器、对抗性损失、多域 batch normalization、风格随机化增强等模块,使检测器在不同域之间学习到更域不变的表示;也有工作在 Transformer 检测框架(如 Deformable DETR)上引入多源域训练和元学习策略,提升跨域泛化能力。 + - 通用 / Foundation 检测模型:把检测问题上升到“基础模型”层面,预训练一个在类别和域上都尽可能通用的 Detection Foundation Model,再通过轻量微调或文本 prompt 适配特定场景;这类模型通常结合大规模检测标注、多源图文对、甚至视频数据,目标是让“任意文本 + 任意风格图像”的通用理解成为可能。 + +在具体产品形态上,开放词汇/开放世界/开放域检测往往体现为“更自然、更少限制”的视觉接口:用户不必提前约定一小撮固定标签,而是可以用自然语言描述想找的目标;系统也不需要为每个业务场景从零开始重训检测器,而是基于统一的通用模型,通过 prompt 或少量样本快速适配。对于大规模商品 / 物种识别、全球化部署的安防与自动驾驶感知系统而言,这一层能力正在成为从“封闭数据集性能”走向“真实开放世界可用性”的关键跳板。 + +### 2.6.1 开放词汇检测:从固定类别头到文本驱动类别空间 + +**开放词汇检测(Open‑Vocabulary Detection)的出发点,是突破传统检测中“固定类别头”的限制。以往的检测器在顶层接一个大小固定的分类层(对应训练集中的 N 个类别),训练完成后只能在这 N 个类别中选择;而开放词汇检测则通过引入文本**, **编码器**, **和共享的语义嵌入空间,让检测头输出的区域特征可以与任意文本描述**进行相似度对比,从而在推理时接纳未见过的新类别。 + +典型做法是使用类似 CLIP 的视觉–语言预训练模型: + +- 文本端:对类别名称或自然语言描述(如“person”、“red sports car”、“yellow construction helmet”)进行编码,得到文本向量。 +- 视觉端:在检测框架(Faster R‑CNN、RetinaNet、YOLO、DETR 等)中,对每个候选区域或特征点提取区域特征向量。 +- 对齐训练:通过对比损失、Region–Word 对齐损失,使同一语义的文本和区域特征在嵌入空间中靠近,不同语义的向量远离。训练时即便只对一部分类别提供显式框标注,也可以利用图文对或图像 caption 扩展语义覆盖。 + +推理阶段,系统不再依赖训练时固定的一组类名,而是允许用户在线提供任意类别词或自然语言描述,通过文本编码器转为嵌入,再与区域特征做相似度匹配。这使得检测器可以在不重新训练的前提下,支持诸如“检测所有滑板”“检测所有绿植”“检测所有安全相关设备”等灵活需求,即便某些具体类目在训练集中从未出现过完整标注,只要语义上与预训练的图文空间有重叠,就能被一定程度地识别和定位。 + +在工程实践中,开放词汇检测需要在效果与效率之间平衡:一方面,保持与大规模预训练的视觉–语言 Backbone 的语义对齐;另一方面,又要承载检测任务对多尺度、实时性的要求。主流 CLIP‑based 检测器往往采用“预计算文本嵌入 + 高效向量相似度计算”的方式,避免在在线服务中反复编码文本,同时对区域特征进行量化或蒸馏,兼顾精度和推理速度。 + +### 2.6.2 开放世界检测:从“未见类”到“可学习的未知” + +**开放世界检测(Open‑World Detection)在开放词汇的基础上,进一步要求模型显式处理“未知类”** :训练数据中只标注了部分类别,其余物体要么未被标注,要么被统称为背景;推理时,这些“未被标注的真实物体”既不应该被简单视为背景,也不应被错误归入已知类别,而应作为“未知类(unknown)”被检测出来,并具备后续转化为“新已知类”的可能。 + +在建模上,开放世界检测通常需要解决三个问题: + +1. **未知类感知** :如何在训练阶段避免将所有未标注目标都学成“背景”?常见做法包括:引入显式“未知类”槽位,通过负例挖掘和不确定性建模让模型学会在低置信度区域输出“unknown”;或者利用无标注数据和自监督机制,对高置信度的潜在目标区域进行聚类和伪标签生成。 +2. **错误归类控制** :模型需要在“宁可判为 unknown,也不要错误归入错误已知类”之间做权衡,这涉及到损失设计(如 margin、开放集判别)、决策阈值和后处理策略。 +3. **渐进式类别扩展** :当业务方对一批“unknown”目标人工标注出新类别后,模型应能够通过增量学习将这些新类别纳入“已知类”集合,而不显著遗忘旧类。为此,很多工作引入了记忆库、蒸馏损失、参数隔离或重放机制,实现对新类别的稳定吸收。 + +从产品视角看,开放世界检测特别适合那些**类目不断增长、长尾极度严重**的场景,例如自然物种识别、新品快速上新的商品识别、复杂安防场景中的异常目标检测等。系统可以先用开放世界检测将“任何非背景的可疑目标”标出,并逐步通过人工或半自动标注,将其中有价值的聚类升级为正式类目,从而形成一个“类目可持续生长”的检测系统,而不是被固定数据集束缚。 + +### 2.6.3 开放域 / 开放分布检测:跨风格、跨设备、跨场景的鲁棒性 + +即使类别集合保持不变,检测器仍然会在现实部署中遭遇严重的 **域偏移(Domain Shift)** :训练数据可能来自少数城市的白天高清摄像头,而部署环境却包含不同国家、乡村、高速路、隧道、夜间、雨雪、低分辨率摄像头、鱼眼镜头甚至红外成像;电商商品摄影与用户实拍、广告图/插画/动漫风格之间也存在巨大差异。**开放域检测(Open‑Domain Detection)**关注的正是:在图像分布发生显著变化的条件下,保持检测性能的稳定与可靠。 + +典型的技术路径包括: + +- **领域自适应(Domain Adaptation)** :在拥有目标域无标注数据或少量标注数据的前提下,通过对抗性域对齐(在特征空间上混淆源域/目标域)、多级域对齐(图像风格、特征、检测头输出)、风格迁移(如将源域图像风格迁移到目标域)等方式,让模型学到对域不敏感的特征。 +- **领域泛化(Domain Generalization)** :在仅有多个源域数据、没有目标域数据的前提下,利用多域训练、风格随机化、特征扰动、元学习等手段,使模型在训练阶段就尽可能暴露于多样化分布,提升对未知新域的泛化能力。 +- **通用 / Foundation 检测模型** :通过在极大规模、多源、多风格数据上预训练检测 Backbone 和头部结构(包括自然图像、视频帧、合成数据、跨模态数据等),再在特定业务场景轻量微调,从而获得比“单域训练”更强的开放域鲁棒性。 + +这些开放域机制往往与开放词汇/开放世界能力相互叠加:一个面向真实世界的通用检测系统,既要能听懂用户的自然语言类别描述(开放词汇),又要能对新出现的目标给出合理的“未知”判断和渐进吸收(开放世界),还要能在不同国家、不同设备、不同天气和风格下保持性能(开放域)。在工程落地中,这三者并不是彼此孤立的研究方向,而是共同构成了从“封闭 benchmark”迈向“开放世界可用”的关键能力组合。 + +## 2.7 视觉–语言任务(Vision–Language Tasks) + +前面的章节主要围绕“单模态视觉”展开:输入是一张图像,输出是检测框、分割掩膜、类别标签或质量分数。而在很多真实应用中,视觉信息并不是孤立存在的——一张图往往伴随标题、说明文字、对话或搜索查询;用户想问的是“图里在讲什么”“这张图和这句话匹不匹配”。**视觉–语言任务**正是解决这类问题:它们以图像 + 文本为输入或输出,通过 **跨模态对齐与联合建模** ,让系统能够“看图说话”“看图回答问题”“用文字找图 / 用图找文”。 + +从产品视角看,视觉–语言模型(VLM)是多模态系统的中枢能力:搜索引擎依赖它实现“以文搜图 / 以图搜文”;内容平台用它做智能配图、广告审核、图文一致性检查;多模态助手则将其作为基础能力,实现“看图聊天”“对文档/截图提问”等功能。下面我们从 **场景** 、**原理**和**模型**三个角度梳理这一层,并在后续小节中分别展开图像描述、视觉问答与图文检索。 + +- **场景** + - 图像描述(Image Captioning):为图片自动生成一两句自然语言描述,用于无障碍辅助阅读、智能相册说明、搜索索引丰富。 + - 图像问答(VQA):用户针对图片提出自然语言问题(“这个人拿着什么?”“车牌号是多少?”),系统给出精准回答,可用于教育、辅助决策和多模态助手。 + - 图文检索(Cross‑modal Retrieval):以文本检索相关图片(Text‑to‑Image)、以图片检索相关文本(Image‑to‑Text),支撑“以文搜图 / 以图搜文”搜索、创意选图和广告投放审核。 + - 图文一致性与审核:判断图片与标题/广告语是否相符,有没有“图文不符”“诱导性描述”等风险,用于内容审核和品牌安全。 +- **原理** + 核心问题是:如何把图像和文本映射到 **同一个语义空间** ,并在这个空间内进行对齐与推理: + - 跨模态对齐:通过联合训练的图像编码器和文本编码器,让对应的“图–文对”在表示空间中彼此靠近,不相关对彼此远离(典型如 CLIP);这为检索、匹配提供了基础。 + - 联合理解与生成:在对齐的表示基础上,引入跨模态注意力,让语言模型在“看着图像特征”的前提下生成文本(图像描述)、推理和回答问题(VQA)。 + - 提示化与指令化:用自然语言指令统一描述多种视觉–语言任务(“为这张图写标题”“回答关于这张图的问题”“判断这段文字是否描述了图片”),让一个模型通过不同提示完成多种任务。 +- **模型** + 主流视觉–语言模型大致演化为两类:**对比学习型 VLM** 与 **生成式多模态** **大模型** : + - 对比学习型:CLIP、ALIGN 等,将图像和文本分别编码成向量,通过大规模图–文配对训练,使其在检索和匹配任务上表现出色,是“以文搜图 / 以图搜文”的基础。 + - 视觉–语言生成模型:BLIP / BLIP‑2、Flamingo、Kosmos、LLaVA 等,将视觉编码器与大语言模型(LLM)衔接,通过跨模态注意力和指令微调,支持图像描述、VQA、多轮对话等复杂任务。 + - 通用多模态大模型:如 GPT‑4.1 with Vision、Gemini 1.5 等,进一步将视觉与更多模态(语音、代码等)统一在一个大模型中,通过统一的接口完成检索、问答、推理和生成。 + +总体而言,视觉–语言任务标志着“视觉不再是一个单独的感知通道”,而是与语言共同参与到更高层的知识表达和推理之中。下面,我们从 **图像描述与视觉问答** 、**图文检索与跨模态对齐**两个方向展开(这里按内容合并为两小节)。 + +### 2.7.1 图像描述与视觉问答:从“看图说话”到“看图推理” + +**图像描述(Image Captioning)**的目标,是输入一张图像,输出一段自然语言描述,比如“一个小女孩在草地上放风筝”。传统做法通常采用“CNN + RNN”结构:用卷积网络提取整图特征,再用 LSTM/GRU 逐词生成描述;随着 Transformer 和预训练 VLM 的出现,主流范式逐渐转向“图像编码器 + 文本解码器”结构,如 BLIP / BLIP‑2、ViT + GPT 等。训练上,模型通常在大量图–文对上进行自回归训练,有时还会采用强化学习或对比损失,优化描述的多样性与正确性。在产品层面,图像描述被广泛用于无障碍阅读(为盲人读屏软件生成图片说明)、智能相册自动加标题,以及为搜索系统提供更多文本索引。 + +**视觉问答(VQA)则进一步把人类交互引入进来:模型的输入不再是“图 + 空白提示”,而是“图 + 问题”,输出一个简短答案或者自然语言解释。与图像描述相比,VQA 更强调可控性与推理能力** :问题可以关注局部细节(“男人的帽子是什么颜色?”)、关系(“哪辆车离路口更近?”)、计数(“有几只狗?”),甚至需要外部知识(“这道菜属于哪种菜系?”)。早期 VQA 模型通常使用图像编码器 + 问题编码器 + 融合模块(如双线性池化、注意力)+ 分类头,输出一个有限词表中的答案;现代多模态大模型则直接用图像编码器 + LLM,在“看图”的基础上进行自然语言生成,在开放式回答和多轮对话上有明显优势。 + +两者在统一的 VLM 框架下可以被视为不同的“提示模板”: + +- Captioning:`<图像> + "Describe this image in one sentence."` → 文本; +- VQA:`<图像> + "Q: ... A:"` → 文本。 + +通过指令微调(Instruction Tuning),同一个多模态大模型可以兼容描述、问答、解释、打标签等多种任务,这也是现代 VLM 产品(多模态助手、图像问答机器人等)的基础工程思路。 + +### 2.7.2 图文检索与跨模态对齐:以文搜图 & 以图搜文 + +**图文检索(Cross‑modal Retrieval)**解决的是另一个高频需求:给定一段文本,找到匹配的图片(Text‑to‑Image Retrieval);或给定一张图,找到相关的文字描述、商品信息、新闻报道等(Image‑to‑Text Retrieval)。这些能力构成了“以文搜图 / 以图搜文”“看图找商品”“给新闻配图”等产品的核心。 + +核心技术是 **跨模态对齐** :以 CLIP 为代表的模型,对图像和文本分别使用各自的编码器(如 ViT 和 Transformer 文本编码器),在大规模图–文配对数据上使用对比学习训练: + +- 对于同一对(图像,文本),让它们的向量在嵌入空间中彼此靠近; +- 对于不匹配的图–文对,则推远它们的向量。 + +训练完成后,只需将所有图片和文本编码成向量,就可以通过向量检索(最近邻搜索)在共享空间中进行快速匹配: + +- Text‑to‑Image:文本 → 文本向量 → 最近的图像向量; +- Image‑to‑Text:图像 → 图像向量 → 最近的文本向量。 + +在工程实践中,这类模型通常采用两阶段结构: + +- 第一阶段用轻量快速的双编码器(Bi‑Encoder,如 CLIP)做粗检索,在亿级图像库中快速筛选出一小部分候选; +- 第二阶段可选用更强的交叉编码器(Cross‑Encoder)或多模态大模型对候选进行精排与重排序,以提升相关性和鲁棒性。 + +在产品侧,图文检索与跨模态对齐被广泛用于:图片搜索、广告检索(根据广告文案找到合适图片)、合规审核(检查广告图文是否一致)、内容推荐(基于用户阅读文本历史向其推荐相关图片/视频)等。随着多模态大模型的兴起,这类检索能力也逐渐被统一进更大的多模态框架中,以“自然语言指令 + 多模态记忆/向量库”的形式,对外提供统一接口。 + +## 2.8 光学字符识别(OCR) + +在很多业务中,最重要的信息既不体现在“画面里的物体和场景”,也不在自然语言对图像的描述里,而是直接写在图像上的 **文字** :合同条款、发票金额、路牌名称、仪表读数、屏幕截图上的错误信息等。**光学字符识别(OCR)**就是围绕“图像 + 文档版式”的结构化理解任务:从复杂的视觉输入中,自动检测并识别文字内容,理解文档的布局和结构,进而支持搜索、统计、自动录入和智能问答。 + +从产品视角看,OCR 是“把纸质/图像信息变成可计算文本”的关键桥梁,是电子化、自动化与智能化办公的基础设施:合同审阅、票据入账、政企档案数字化、办公软件中的 PDF 转 Word、文档问答助手等,都建立在 OCR 能力之上。下面从 **场景** 、**原理**和**模型**三个角度梳理 OCR 体系,并在后续小节中展开核心方向。 + +- **场景** + - 场景文本识别:街景中店铺招牌、路牌、广告牌、包装盒文案等,用于导航、搜索、零售洞察和合规审核。 + - 文档 OCR:扫描件、传真件、PDF、照片版合同/发票/报告等的文字识别与结构化,还原成可编辑文本。 + - 专用场景:车牌识别、仪表盘读数(电表、水表、气表)、屏幕截图文字提取、试卷/表单识别等。 + - 文档理解:在布局复杂的长文档中,抽取标题、段落、表格、注释等结构,为搜索、摘要、问答奠定基础。 +- **原理** + OCR 体系通常分成几个关键步骤: + - 文本检测:在图像上检测出所有文字区域(文本行或文本块),输出定位框(水平或四点多边形),这是后续识别的输入。 + - 文本识别:对每个检测到的文字区域进行序列识别,将像素序列转化为字符序列(如中文、英文、数字、符号等)。 + - 版式分析(Layout Analysis):在文档场景中,识别各区域的角色(标题、正文、图片、表格、页眉页脚等),恢复阅读顺序和层次结构。 + - 表格结构识别:对表格区域进行行列划分、单元格边界解析、合并单元格恢复,重建逻辑表格结构。 + - 文档问答(DocVQA):在 OCR 和版式理解的基础上,让模型能够回答“这份合同的付款日期是什么?”“发票的金额是多少?”这类跨区域、多步骤推理的问题。 +- **模型** + 工程上常见的是“专用 OCR 模块 + 文档理解模型 + 多模态大模型”组合: + - 文本检测与识别: + - 检测:EAST、DBNet/DBNet++ 等基于分割或边缘学习的方法,擅长处理弯曲文本和复杂背景; + - 识别:CRNN、RARE、SAR 等序列模型(CNN + RNN/Attention + CTC 或自回归解码),支持多语种和多字体。 + - 文档版式与结构理解: + - LayoutLM / LayoutLMv2/v3、DocFormer 等,将文本内容(token)、位置信息(bounding box)和视觉特征联合编码; + - Donut 等“端到端文档理解”模型,直接从图像到结构化输出(如 JSON / Markdown),弱化传统 OCR 的边界。 + - 文档问答与多模态理解: + - 在布局模型基础上,叠加任务头进行 DocVQA; + - 或直接使用多模态大模型(VLM)读取文档图像,在自然语言层面完成问答和摘要,同时隐式利用 OCR 能力。 + +综合来看,OCR 已经从早期“简单的字符识别”发展为涵盖**文字 + 版式 + 结构 + 问答**的整体文档理解体系,是企业数字化、政务档案管理和智能办公的关键支柱。下面,我们从 **文本检测与识别** 、 **文档版式与表格结构分析** 、**文档问答与多模态 DocVQA**三个方向展开。 + +### 2.8.1 文本检测与识别:从像素到可用文本 + +OCR 的第一步是 **文本检测** :在输入图像中找到所有包含文字的区域。街景/场景文本面临字体多样、倾斜扭曲、光照复杂、背景干扰严重等挑战;文档场景则强调对密集文本和多栏排版的鲁棒支持。EAST、DBNet 等方法通过将检测问题转化为“像素级分割 + 边缘学习”,在特征图上预测文本概率和几何参数,再通过后处理获得精确的文本框(可为水平框或任意四边形/多边形),兼顾精度和速度。 + +**文本识别**则把每个检测出的文本区域切下来,转化为字符序列。经典做法以 CRNN 为代表:先用 CNN 提取特征,再通过 RNN 或 Transformer 进行序列建模,最后使用 CTC 或注意力解码输出字符序列。对于不定长文本、弯曲文字和复杂语言(中英文混排、多语种),识别模型需要在视觉特征建模和字符语言建模上同时发力。诸如 RARE、SAR 等方法会引入空间变换网络(STN)或注意力对齐机制,以纠正几何畸变、提升对复杂布局的适应能力。 + +在工程系统中,检测与识别通常作为两个解耦的服务组成一条 OCR pipeline:前端检测将图像拆成若干文本行/块,后端识别对每个块做字符识别,并可叠加语言模型做错误纠正(如拼写修复、数字/金额校验)。对于车牌、仪表读数等特定场景,还会使用专门微调的检测/识别模型,以利用场景先验(固定字体、有限字符集)换取更高精度和更低延迟。 + +### 2.8.2 文档版式与表格结构分析:还原“文档的形状” + +单纯把文字识别出来还不够,尤其在长文档、报告、合同和票据等场景中,**版式结构**往往决定了信息的含义和重要性:标题与正文的层级关系、图表与配文的位置、页眉页脚的作用、表格内外文段的逻辑顺序等。**文档版式分析(Document Layout Analysis)**的目标,就是在二维页面上识别出不同区域的角色和边界,并恢复出合理的阅读顺序与层级结构。 + +LayoutLM / LayoutLMv2/v3、DocFormer 等模型,将每个文本 token 的内容(文本 embedding)、空间位置(bounding box 坐标)以及局部视觉特征(来自 CNN/ViT)联合编码,通过 Transformer 建模 token 间的语义–空间关系。通过在带版式标注的数据集上训练,模型可以学会区分“标题/段落/列表/表格/图片说明/页眉页脚”等多种区域类型,并在输出中给出对应标签和层级。这类模型通常作为“中间层”,为合同审阅系统、报告解析、档案数字化平台提供结构化的文档骨架。 + +**表格结构识别(Table Structure Recognition)** 是版式分析中特别关键的一支:它不仅要检测出表格区域,还要进一步解析行列边界、单元格坐标和合并单元格,最终重建一份逻辑表格(通常表示为 HTML、Markdown 表、或带坐标的结构化 JSON)。实现方法包括: + +- 基于规则/视觉:使用线检测、分割网络、对象检测等手段提取表格线和单元格区域,再进行拓扑建图; +- 基于 Transformer:将表格区域的文本块与几何信息编码成序列,直接预测单元格结构和关联关系。 + +在产品上,这些能力支撑了“PDF 转 Word/Excel”“票据/发票结构化录入”“报表解析与指标抽取”等高价值场景,是政企办公自动化的关键组件。 + +### 2.8.3 文档问答与 DocVQA:从“读文档”到“问文档” + +当 OCR 与版式分析能力足够强时,下一步自然需求就是: **不再让人自己翻阅文档,而是直接“问文档”** 。这就是 **文档问答(DocVQA)** :模型在合同、报告、票据、说明书等复杂文档上回答问题,比如“这份合同的生效日期是什么时候?”“这页报表中 2023 年 Q4 的净利润是多少?”“发票上的购方名称是谁?”。 + +传统 DocVQA 系统通常以“OCR + 版式模型 + QA 头”的方式构建: + +- 先使用 OCR 提取文本及坐标; +- 用 LayoutLM / DocFormer 等建模文本–版式–视觉三模态关系; +- 最后在这个表示上叠加任务头(分类 / 抽取 / span 预测),根据问题在文档中定位答案或相关片段。 + +随着多模态大模型的发展,越来越多系统开始直接使用“文档图像 + 问题”作为输入,让一个 VLM 或多模态 LLM 直接生成答案或带引用的解释。在这种架构下,OCR、版式、语义理解和推理能力在模型内部以端到端的方式协同工作:模型既能看到原始版式和视觉线索,又能利用语言世界知识和推理模式完成复杂问题的解答。 + +在产品形态上,DocVQA 通常以“合同审阅助手”“发票/报表问答”“长文档智能问答”形式出现,帮助用户从大量文档中快速定位关键信息、自动生成摘要、进行条款比对等,大幅减轻人工审阅和信息检索的负担。 + +## 2.9 图像生成与编辑(Image Generation & Editing) + +前面介绍的视觉能力大多是“判别式”的:输入图像,输出标签、框、掩膜或文本;而近年来快速发展的另一条主线是 **生成式视觉** :模型不再只是理解图像,而是 **创造或修改图像** ,在给定文本/图像条件下生成高质量、多风格的视觉内容。**图像生成与编辑**正是这一方向的核心能力,支撑了从 AIGC 绘图平台到智能修图/特效工具的大量产品。 + +从业务视角看,生成式视觉已经从“技术演示”变成切实可用的生产力工具:设计师用它做灵感草图和细化稿;营销团队用它批量生成海报和广告素材;普通用户用它制作头像、插画、壁纸;视频创作者用它做抠图、背景替换和特效。下面我们从 **场景** 、**原理**和**模型**三个角度梳理这一层,并在后续小节中展开文本生成图像、图像到图像与编辑能力。 + +- **场景** + - 文本生成图像:用户输入一段描述(“赛博朋克风的夜景城市”),系统自动生成符合描述的多张图片,支持选图与迭代修改。 + - 风格迁移与图像翻译:将真实照片转换为动漫/素描/油画/水彩风格,或在不同领域间做映射(白天 ↔ 夜晚、夏天 ↔ 冬天)。 + - 条件重绘与扩展:在原图的局部进行重绘(Inpainting)、对画面外扩(Outpainting),用于修补瑕疵、移除/添加对象、扩展构图。 + - 文本驱动编辑:用自然语言指令修改图像(“把天空改成日落”“让这辆车变成红色跑车”),用户无需掌握复杂的图像编辑软件。 +- **原理** + 生成式视觉模型主要通过学习“图像分布”和“条件控制”来完成生成与编辑: + - 分布建模:GAN、扩散模型(Diffusion)、Flow Matching 等从大量图像中学习高维分布,使得模型能从随机噪声中逐步“采样”出逼真的图像。 + - 条件生成:在纯图像分布建模基础上,引入文本/草图/分割图/关键点/深度图等条件,使生成过程受到外部信号约束(Text‑to‑Image、Image‑to‑Image、ControlNet 等)。 + - 可控编辑:在已有图像的潜在空间中,通过文本或局部 mask 对局部特征进行引导和修改,实现局部重绘、风格变化、构图调整等。 +- **模型** + 当前主流图像生成与编辑模型以**扩散模型 + 条件控制**为主: + - GAN 系列:StyleGAN 等在高分辨率人脸和样式控制方面表现突出;但训练不稳定、难以覆盖复杂多模态分布。 + - 扩散模型:Stable Diffusion、Imagen、DALL·E 系列等,通过“正向加噪 + 反向去噪”的过程进行采样,兼具质量和多样性,是当前 Text‑to‑Image 的主力方向。 + - 可控生成与编辑:ControlNet、T2I‑Adapter 等,在基础扩散模型上叠加条件通道(边缘、姿态、分割等),实现精确控制;结合文本引导的 Inpainting/Outpainting 实现局部编辑和画面扩展。 + - Flow Matching 与新一代生成模型:通过学习连续流场将噪声分布变换到图像分布,在效率、可控性与稳定性上探索新的平衡。 + +在产品层面,这些技术以即梦、阿里 qwen 图像模型、FLUX、OpenAI 或者 Gemini nanobanana、Stable Diffusion 生态、Photoshop Generative Fill、Canva AI、剪映/CapCut 智能抠图与特效等形态面向用户,逐步从“玩具”演进为内容生产链条中的正式环节。下面,我们从 **文本生成图像** 、**图像到图像翻译**和**文本驱动编辑**三个方向展开。 + +### 2.9.1 文本生成图像(Text‑to‑Image):从一句话到一张画 + +**文本生成图像(Text‑to‑Image)** 的核心任务是:给定一段自然语言描述,生成一张尽可能匹配其语义和风格的图像。现代 Text‑to‑Image 模型主要基于扩散架构: + +- 首先使用文本编码器(如 CLIP Text Encoder 或 T5/LLM)将输入文本编码为条件向量; +- 然后在图像潜空间中,从高噪声状态开始,通过多步反向去噪采样,在每一步都利用文本条件引导生成方向; +- 最终得到符合描述的高分辨率图像,可进一步放大或后处理。 + +Stable Diffusion、Imagen、DALL·E 系列等方法在大规模图–文对上进行训练,使模型既掌握视觉谱系(形状、纹理、构图、光影),又获得一定程度的语言–视觉对齐能力(理解“风格”“材质”“构图”等复杂描述)。在产品层面,这种能力让“不会画画的人也能画图”:用户只需用自然语言描述想法,系统就能给出多种视觉实现,支持迭代试探和细化。 + +Text‑to‑Image 模型通常同时支持多风格、多分辨率输出:通过在训练或推理时加入风格 token、尺寸条件等,使同一个模型在“写实照片风、扁平插画风、3D 渲染风”等不同风格之间切换。工程上常用的技巧包括: + +- 文本提示工程(Prompt Engineering),用于细化和稳定输出风格; +- LoRA / DreamBooth 等轻量微调技术,在通用模型上快速适配特定人物、IP 或品牌风格。 + +### 2.9.2 图像到图像(Image‑to‑Image):翻译、风格迁移与局部重绘 + +**Image‑to‑Image** 任务在给定输入图像的基础上,生成另一个“受其约束”的图像版本:既保留原图的整体结构或内容,又实现某种转换或增强。典型形态包括: + +- 图像翻译 / 风格迁移:在不同视觉域之间进行映射,如“照片 → 动漫”“夏天 → 冬天”“白天 → 夜晚”“素描 → 彩色图像”。早期多基于 GAN(CycleGAN、Pix2Pix 等),现在也可以用扩散模型在条件控制下完成。 +- 条件生成:以草图、分割图、深度图、边缘图等为条件,通过 ControlNet、T2I‑Adapter 等模块引导扩散过程,让生成图严格遵守几何/布局条件,同时在纹理、光影、风格上自由发挥。 +- Inpainting / Outpainting:在原图上划定某个区域,将其视为待重绘部分(inpainting),或在画面外延展生成新内容(outpainting),实现“填坑”“扩图”等操作。 + +这类任务的关键是 **在保留约束的前提下创造新内容** 。扩散模型在这方面表现突出:在 inpainting 中,模型只对 mask 区域进行采样,而在未被遮挡的区域保持原图不变,通过语义理解与上下文信息,使新内容与周围区域在风格与光影上自然融合。对于风格迁移,模型在保留输入结构的同时,从目标风格分布中采样纹理和颜色,实现“换壳不换骨”。 + +在产品里,Image‑to‑Image 能力支撑了大量创意工具:风格滤镜、漫画化、一键天空替换、自动美颜、旧照修复、局部修图等,通常以高度可视化的界面呈现给用户。 + +### 2.9.3 文本驱动图像编辑:自然语言当“画笔” + +在传统图像编辑软件中,用户需要掌握图层、蒙版、选区、滤镜等一整套专业概念;而**文本驱动图像编辑(Text‑guided Editing)** 尝试用自然语言替代大部分专业操作: + +- “把背景换成夜晚城市天际线”; +- “让这个人穿黑色西装”; +- “把这辆车变成蓝色跑车,增加运动模糊效果”。 + +技术上,文本驱动编辑通常建立在 Text‑to‑Image 扩散模型之上,通过几种方式实现: + +- 在原图附近的潜空间中搜索或采样,使编辑后的图与原图保持高相似度,只在受文本影响的局部发生变化; +- 使用显式 mask(用户圈定区域),将编辑范围限制在特定区域(这就是许多工具中的“选中区域后输入文本指令”); +- 引入“指令控制”模块(如 ControlNet、可学习控制 token),增强模型对编辑请求的可控性与稳定性。 + +即梦、FLUX、阿里 qwen 图像模型、Stable Diffusion 生态、Canva AI 等产品都提供了类似能力:用户通过简单文字和少量交互即可完成复杂编辑。对专业用户而言,这成为加速创作流程的“智能助手”;对普通用户而言,则极大降低了图像编辑的门槛。 + +## 2.10 图像质量评估(Image Quality Assessment, IQA) + +在底层视觉增强、压缩编码、图像生成与编辑等任务中,我们经常需要回答一个看似主观的问题: **“这张图看起来好不好?”** 。手工检查显然无法规模化,而像 PSNR 这类传统指标又常常与人眼主观感受不一致。**图像质量评估(Image Quality Assessment, IQA)** 的目标,就是建立一套自动化机制,对图像的主观/客观质量进行评分或排序,成为连接“底层算法输出”和“用户真实体验”的关键环节。 + +从系统角度看,IQA 是很多流水线中的“看门人”和“调参参考”:电商/内容平台用它筛掉模糊、噪声重、压缩过度的上传图片;手机相机/相册用它在连拍中挑出“最好的一张”;云端增强和压缩服务用它进行前后对比评估,以指导模型迭代。下面从 **场景** 、**原理**和**模型**三个维度梳理 IQA,并在后续小节中展开评估类型与指标/学习范式。 + +- **场景** + - 上传质检与审核:对用户上传的图片/视频做质量评分,过滤严重模糊、曝光异常、噪声明显和压缩伪影严重的内容。 + - 智能选片与去重:在手机相册、相机应用中,从多张相似照片中选择清晰度、表情、构图更好的版本,同时识别质量差或冗余图片用于清理。 + - 增强/压缩算法评估:在图像增强、降噪、超分辨率、编解码等算法 A/B 测试中,用 IQA 指标客观衡量“哪种策略更好”,辅助参数搜索与模型选择。 + - 海报/缩略图自动选取:在视频或多图集合中自动选择视觉质量和吸引力更高的帧作为封面或海报候选。 +- **原理** + IQA 的核心是从两个维度刻画图像质量:**相对于参考图的失真程度**与 **人眼主观感知的好坏** : + - 全参考 IQA(FR‑IQA):在有高质量参考图的前提下,将待评估图与参考图进行逐像素或特征对比,衡量失真程度,用于算法研发和实验评估。 + - 无参考 IQA(NR‑IQA / Blind IQA):实际场景中更常见,没有参考图,只能从单张图的统计特征或深度特征中推断质量,需要模型从大量图像与主观评分中学习到“人眼喜欢什么样的图”。 + - 伪参考 / 降采样参考:在某些场景中,可以使用压缩前的低分辨率版本、模型预测的“理想图”等作为近似参考,兼顾可实现性与评估精度。 +- **模型** + IQA 模型大致分为**传统手工特征指标**与**深度学习\*\***式质量预测\*\*两大类: + - 传统指标: + - FR‑IQA:PSNR、SSIM、MS‑SSIM、FSIM 等,侧重结构、对比度和相位信息,对简单退化(如加噪、模糊)较敏感。 + - 感知指标:LPIPS、DISTS 等,在深度特征空间衡量图像间感知差异,与人眼主观感受有更高相关性。 + - 无参考 / 学习式 IQA: + - 早期方法:BRISQUE、NIQE、BLIINDS 系列等,从自然场景统计(NSS)和手工特征出发,训练浅层模型预测质量分数。 + - 深度 NR‑IQA:RankIQA、DBCNN、HyperIQA、MUSIQ 等,直接用 CNN / ViT 从图像中抽取特征,并在 MOS(Mean Opinion Score,主观评分均值)数据上监督训练,使输出质量分数尽可能拟合人眼评价。 + - 预训练表征:利用 CLIP、ViT 等大模型的特征,作为质量预测网络的输入或 backbone,在有限 MOS 数据上微调,提升对复杂失真类型的泛化能力。 + +整体来看,IQA 并不是“越高越好”的单一指标,而是一套与具体业务目标相关的评估体系:在某些场景(如监控增强)中,保留细节和可识别性比视觉自然更重要;在内容创作平台中,主观观感和审美标准则占主导。因此,工业界常见做法是:在通用 IQA 模型基础上,通过少量业务数据微调或学习加权,构建“任务感知”的质量评估器。 + +### 2.10.1 评估类型:有参考、无参考与伪参考 + +按照是否存在高质量参考图,IQA 可以分为三类: **全参考(FR‑IQA)** 、 **无参考(NR‑IQA)和伪参考** 。 + +在 **全参考 IQA** 中,我们假设存在一张理想的高质量参考图像,待评估图是其经过压缩、传输或处理后的退化版本。模型通过对两者进行逐像素或特征级比较,量化失真程度。PSNR 是最简单的度量(基于均方误差),SSIM/MS‑SSIM/FSIM 等进一步考虑亮度、对比度、结构或相位信息,在一定程度上更接近人眼感受。这类指标非常适合在算法开发阶段评估编解码、超分辨率、去噪等方法,但在真实业务中往往缺乏参考图,应用场景有限。 + +**无参考 IQA(Blind IQA)** 是实际系统中更常见的设定:只有待评估图像本身,没有任何参考。早期无参考方法(如 BRISQUE、NIQE、BLIINDS 等)主要基于自然场景统计:假设高质量自然图像在某些统计分布上有稳定形态,失真会引起统计特征变化,从而可以训练模型根据这些特征预测质量分数。深度学习时代,NR‑IQA 模型通常直接利用 CNN / ViT 提取特征,并在带有人眼主观评分(MOS)的数据集上回归质量分数或学习排序关系,使其能够覆盖噪声、模糊、压缩伪影、曝光异常等多种失真类型。 + +**伪参考 / 降采样参考 IQA** 介于两者之间:在没有真正高质量参考的情况下,使用某种可获得的近似版本(如压缩前低分辨率图、模型预测的“干净图”)作为参考,对退化程度进行估计。这种方式常见于在线视频质量监控、编解码优化任务中,可以在成本与精度之间取得平衡。 + +### 2.10.2 指标与学习范式:从 PSNR 到感知质量预测 + +在具体实现层面,IQA 采用多种指标和学习范式来逼近人眼主观感受。 + +**传统指标**方面: + +- PSNR 直接基于像素级误差,简单高效,但对人眼不敏感的变化(如轻微平移、结构保持的滤波)也会给出较大惩罚; +- SSIM、MS‑SSIM、FSIM 等从亮度、对比度、结构、相位等多个维度建模图像相似性,对结构性失真更敏感,也一定程度反映人眼对结构信息的偏好。 + +**感知指标**方面:LPIPS、DISTS 等通过在预训练深度网络(VGG、AlexNet、ViT 等)内部特征层计算向量差异,并按照不同层的重要性加权,得到一种“特征空间中的距离”,与主观感知相似性有更高相关性。它们特别适合作为生成式任务(超分、生成、编辑)的训练目标或评估指标,用来衡量“看起来像不像”。 + +**学习式质量预测**方面,深度 NR‑IQA 模型(如 RankIQA、DBCNN、HyperIQA、MUSIQ 等)直接对图像打分或排序: + +- 训练数据中,每张图像附带一组主观评分(MOS),模型以此为监督训练质量回归或排序网络; +- 模型结构上,多采用 CNN/ViT + 全局池化 + MLP 输出质量分数,或输出一组质量分布再取期望; +- 有些方法还利用对比学习或排序学习(pairwise ranking),让模型更关注“相对好/坏”的关系,而不是绝对分数。 + +随着大规模预训练视觉模型的普及,越来越多 IQA 方法采用“预训练 Backbone + 轻量头”的范式:利用 CLIP、ViT 等丰富的视觉表征,在较少 MOS 数据上进行微调,从而在跨失真类型、跨场景上保持良好的泛化。 + +在工程落地中,通常会将上述多种指标组合使用:例如 FR‑IQA 指标用于实验阶段评估算法改进;深度 NR‑IQA 模型用于线上实时质检;感知指标用于生成任务的内部优化。通过 A/B 实验将这些自动指标与真实用户数据(点击率、完播率、投诉率等)对齐,逐步构建起与业务目标高度相关的“感知质量度量体系”。 + +# 3. 3D / 空间模态(3D / Spatial / XR) + +随着应用从“平面图像/视频”走向自动驾驶、机器人、AR/VR/XR 等场景,系统不再满足于只看“2D 像素”,而是需要理解 **真实世界的三维结构、尺度和位姿关系** 。这类任务统称为 3D / 空间模态:既包括对几何与拓扑的精确建模,也包括在 3D 空间中的语义理解、定位导航与内容生成。它一端连接 LiDAR、RGB‑D、IMU 等多种传感器,另一端连接自动驾驶感知模块、机器人导航系统、ARKit/ARCore 环境模型、手机 3D 扫描建模应用以及数字孪生平台等。 + +## 3.1 3D 感知与重建(3D Perception & Reconstruction) + +在 2D 视觉里,我们只看到了“拍成照片后的世界”;而在自动驾驶、机器人、AR/VR 等场景中,更关键的是: **真实世界在 3D 空间中的位置、形状和结构** 。3D 感知与重建就是要从多种传感器(相机、LiDAR、深度相机等)出发,恢复环境的三维几何信息,并以点云、体素、网格(Mesh)、隐式场等形式表达出来,为路径规划、物理仿真、数字孪生和 3D 内容生成提供基础。 + +在工程实践中,这一层涵盖从**点云处理**到**多视角几何重建**再到**神经辐射场 / 神经场渲染**等多个技术方向,对应着自动驾驶 3D 感知模块、ARKit/ARCore 环境建模、手机 3D 扫描/建模应用以及数字孪生城市/园区建模平台等产品形态。下面从 **场景** 、 **原理** 、**模型**三个角度展开,并进一步细分几个关键子方向。 + +- **场景** + - 自动驾驶与辅助驾驶:从车载 LiDAR 点云和多摄像头图像中感知车辆、行人、路沿、车道线、交通设施等 3D 结构,用于路径规划和安全决策。 + - 室内/室外环境扫描:利用手机/平板(结构光 / ToF / 双目)或手持扫描仪采集多视角数据,实时构建房间、楼宇、街区的 3D 模型,用于 AR 建模、家装设计、数字孪生。 + - 数字孪生与 BIM:将实际工厂、园区、城市通过多视角影像和点云重建成高精度 3D 模型,用于运维管理、仿真与可视化。 + - 消费级 3D 扫描:手机 3D 扫描 App、一键“拍照变 3D 模型”工具,为 3D 打印、虚拟试穿、游戏/影视资产制作提供原始几何。 +- **原理** + - 点云处理:将 LiDAR 或多视角重建得到的稀疏/稠密点集合视作 3D 采样点集,对其进行滤波、配准、下采样和特征学习,再做分类、语义/实例分割或 3D 目标检测。 + - 多视角几何与三维重建:通过 SfM(Structure‑from‑Motion)估计多张图像之间的相机位姿和稀疏 3D 点云,再通过 MVS(Multi‑View Stereo)生成稠密点云,随后进行网格重建与纹理贴图。 + - 神经辐射场 / 神经隐式场:使用 NeRF、Instant‑NGP、Gaussian Splatting 等方法,把 3D 场景表示为连续的体密度/颜色场或高斯粒子集合,通过体渲染或光栅化生成图像,从多视图监督中学习;训练好后可以进行新视角渲染和几何提取。 +- **模型** + - 点云网络:PointNet / PointNet++、PointCNN、DGCNN、MinkowskiNet 等直接在点或稀疏体素上学习特征,用于点云分类、分割与 3D 检测。自动驾驶中常用 VoxelNet、SECOND、CenterPoint 等 3D 检测框架,将点云转换为体素或 BEV(鸟瞰图)特征后进行检测。 + - 几何重建工具链:COLMAP、OpenMVG / OpenMVS 等传统 SfM/MVS 系统,可从多视角照片恢复相机位姿和稠密点云,构建出高质量 Mesh。 + - 神经场重建与渲染:NeRF / Instant‑NGP、Gaussian Splatting 及大量改进模型,把场景编码在神经网络或高斯云中,实现高保真的新视角合成与 3D 场景重建,并逐步形成工程化产品。业界也出现了如「混元 3D」「Tripo」这类面向开发者和内容生产的 3D AI 服务,将 NeRF/高斯等技术封装成云端 API 或交互工具。 + +从这一层开始,传统几何与深度学习、隐式表示与显式网格密切交织,既要解决「如何准确还原真实世界」的问题,又要兼顾实时性和可用性,服务更上层的 3D 场景理解、3D 生成与编辑。 + +### 3.1.1 点云处理与 3D 目标检测 + +对于自动驾驶、机器人和高精度测绘而言,LiDAR 点云是最关键的 3D 传感信息之一。点云是一组三维坐标(有时附带反射强度、时间戳等)构成的稀疏点集,没有规则的栅格结构,给传统卷积带来了挑战。点云处理的目标,是从这些非结构化的点中提取有用的几何与语义信息,例如“这里是一辆车”“这里是路沿/地面”“这里是一栋建筑物”。 + +在**点云分类与分割**任务中,我们往往关注:某个点(或点簇)属于哪一类结构,如车、行人、地面、路沿、建筑、植被等,或者对场景做语义/实例分割。从建模方式看,可以粗略分为三类: + +1. 直接点云网络:PointNet / PointNet++、PointCNN、DGCNN 等直接在点集上定义“对点集排列不敏感”的运算,通过局部邻域聚合构建层级特征,适合中小规模点云的分类与分割。 +2. 体素与稀疏卷积:将点云栅格化为 3D 体素,再用稀疏 3D CNN(如 VoxelNet、MinkowskiNet)进行卷积,兼顾结构规整性与空间稀疏性,在自动驾驶 3D 检测中应用广泛。 +3. 投影与多视图:将点云投影到 BEV(鸟瞰图)、前视深度图或多视角视图,再用 2D CNN 提取特征,相对易于与成熟的 2D 检测网络结合。 + +在**3D 目标检测**中,目标不再是单纯地给点打标签,而是要预测 3D 边界框(位置、尺寸、朝向)及其类别,这是自动驾驶环境感知的核心。典型方法如 VoxelNet、SECOND、PointPillars 和 CenterPoint 等,它们通常将点云转换为体素或柱状表示,在 BEV 或 3D 空间上进行检测回归。CenterPoint 等方法通过“中心点检测”范式,直接在 BEV 上检测目标中心及其尺寸/方向,兼具精度和速度。随着深度学习与传感器硬件的演进,3D 检测已能在车规级芯片上实现实时推理,成为自动驾驶感知栈的基础模块之一。 + +### 3.1.2 多视角几何与三维重建:从照片到 Mesh + +如果没有 LiDAR,是否仍能“看懂”3D?答案是可以的——多视角几何与三维重建依赖的是“多张照片 + 摄像机运动”。通过在不同视角拍摄同一场景,我们可以利用几何约束恢复相机位姿和空间结构,这就是经典的 SfM/MVS 管线。 + +**SfM(Structure‑from‑Motion)** 主要解决两个问题: + +1. 从多张成对或多视角图像中,估计每一张图像的相机外参(位置和朝向); +2. 在统一坐标系下恢复一组稀疏 3D 特征点。 + +典型工具如 COLMAP、OpenMVG,通过特征提取与匹配(SIFT/ORB 等)、增量或全局 BA(Bundle Adjustment),可以从无标定图像集合中自动恢复稀疏点云和相机位姿。 +在此基础上,**MVS(Multi‑View Stereo)** 会利用多视角的光度一致性,生成稠密点云:对每个像素/视线进行深度估计,逐步填充场景的几何细节。 + +获得稠密点云后,下一步是 **网格重建(Mesh Reconstruction)** : + +- 通过 Poisson Surface Reconstruction、Marching Cubes 或基于学习的方法,将散乱的点云“包裹”成连续曲面,形成带拓扑结构的 Mesh。 +- 后续通常还会进行孔洞填补、平滑、边界优化,并进行纹理贴图(Texture Mapping),得到可直接用于渲染和编辑的 3D 模型。 + +在产品形态上,这一整套管线已通过桌面软件、云服务和 SDK 的形式下沉。例如:手机上的 3D 扫描应用,会在后台调用类似 SfM/MVS 的流程,给用户“绕一圈拍照”或“扫一圈视频”之后自动输出一个可导入到游戏引擎的网格模型;数字孪生平台则在城市/园区尺度上,用航摄影像 + 街景数据跑大规模重建,生成可交互的 3D 场景。 + +### 3.1.3 神经辐射场与体渲染:NeRF、Gaussian 与新一代 3D 重建 + +传统的 SfM/MVS/网格重建,可以得到结构良好的显式几何,但在渲染质量、视角连续性和细节表现上仍有局限;而神经辐射场(NeRF)及其后续工作则以**隐式场 + 体渲染**的方式重新定义了 3D 重建和新视角合成。 + +在 NeRF 中,整个 3D 场景被建模为一个连续函数: + +![](https://ecn00p15ubf1.feishu.cn/space/api/box/stream/download/asynccode/?code=ZjYyZTc5MWFhY2QxM2FjNTI1MDFhNDM5NTEwNTBkNGFfM3RvSngwZnhwc1hMRFQxaXVXMkFNem5RSFFqUkppdkdfVG9rZW46TVltUGJUUWRib1NGV2V4dklHZ2NYandjbkJlXzE3NjcxMDU4ODM6MTc2NzEwOTQ4M19WNA) + +给定三维空间中的一个点位置 x 和观察方向 d,网络会输出该点对应的体密度 σ 与颜色 c。沿着相机视线方向对这个映射函数做体渲染积分运算,我们就能得到该相机位姿下的像素颜色;反过来,只要给定一组多视角照片及其相机参数,我们就能通过最小化渲染结果与真实图像的误差,求解出模型的参数 θ。待模型训练完成后,只需改变相机位姿,就能合成那些 “从未被真实拍摄过” 的新视角图像(Novel View Synthesis)。 + +传统 NeRF 训练和渲染速度都偏慢,后续如 **Instant‑NGP** 通过多分辨率哈希网格编码等手段,大幅加快了收敛与推理速度;**Gaussian Splatting** 则用 3D 高斯粒子替代表达场景,通过高效的光栅化策略,实现了高质量、实时的新视角渲染。与此同时,大量工作还围绕 NeRF/高斯做了可编辑、多模态、可组合等扩展,使其逐渐从研究原型走向工程体系。 + +在产品化层面,NeRF/高斯类技术已经嵌入到多种 3D AI 产品中: + +- 手机/PC 端的“多视角视频 → 3D 场景”工具,底层往往基于神经场或高斯粒子完成重建和渲染; +- 游戏/影视资产管线中,利用神经场进行快速场景捕捉和光照还原,再导出为 Mesh + 纹理供传统 DCC 工具使用; +- 各大云厂商和内容平台推出的 3D AI 服务,如腾讯系的「混元 3D」、Tripo 等,通常支持“多视图照片/短视频 → 可编辑 3D 模型/场景”,在内部则综合运用神经辐射场、SDF/Gaussian 表示与后续显式重建,把高质量 3D 结果打包为对开发者友好的 API 或交互式产品。 + +## 3.2 3D 场景理解与定位(3D Scene Understanding & SLAM) + +如果说 3D 感知与重建回答的是“这个世界长什么样”,那么 3D 场景理解与定位则进一步回答:“ **我在这个世界的哪里?这个世界中哪些地方可以走,哪些是障碍?** ” 对于扫地机器人、AGV 机器人、无人机、AR 导航和室内定位系统来说,能够在 3D 环境中自定位、自建图、自主规划路径,是生存的前提。 + +这部分工作主要围绕**3D 语义理解**与**SLAM(Simultaneous Localization and Mapping)**展开:前者在重建的 3D 场景中进行语义分割和可通行区域识别,后者则利用视觉/IMU/LiDAR 等传感器进行相机/机器人位姿估计与地图构建。在工程上,这一层通常以 SDK 或算法模块的形式嵌入到机器人底盘、无人机飞控或移动端 AR 引擎中。 + +- **场景** + - 家用与服务机器人:扫地机器人、送餐/巡检机器人在室内环境中构建地图、识别房间类型和障碍物,实现自动规划清扫或巡逻路径。 + - 仓储与物流:AGV/AMR 机器人在仓库中进行自主导航,识别货架、通道与禁入区域,完成搬运和盘点任务。 + - 无人机与户外机器人:在室外环境中构建 3D 地图,避开建筑、树木、电线等障碍,执行巡检、测绘与安防任务。 + - AR 导航与室内定位:手机/AR 眼镜通过 SLAM 获取相机位姿,并在语义地图上叠加导航箭头、房间信息和 POI,实现沉浸式导览与导航。 +- **原理** + - 3D 语义分割与场景理解:在点云或体素表示上进行语义分割,区分墙壁、地面、桌椅、货架、门窗等结构,同时识别可通行区域和障碍物,为导航和行为决策提供语义层信息。 + - 位姿估计与 SLAM:通过 Visual SLAM(单目/双目 / RGB‑D)或 LiDAR‑SLAM,从连续传感数据中估计相机/机器人的 6D 位姿,处理回环检测与地图优化,必要时融合 IMU、轮速、GNSS 等多源信息提高鲁棒性。 + - 地图构建与导航:在局部/全局地图上叠加几何和语义信息,形成 2D/3D/拓扑/语义地图,并在此基础上进行路径规划、避障和任务分配。 +- **模型** + - SLAM 系统:经典的特征点法 ORB‑SLAM 系列、直接法 DSO,以及融合惯导的 VINS‑Mono / VINS‑Fusion,通过前端特征跟踪 + 后端优化实现精确位姿估计与稠密/半稠密地图。LiDAR/视觉‑LiDAR 融合中常见 LIO‑SAM 等框架。 + - 3D 语义分割网络:3D U‑Net、MinkowskiNet 等 3D CNN,以及基于点云的 PointNet++ / KPConv / SparseConv 系列,用于点云/体素的语义分割与实例分割。 + - 多传感器融合定位:基于图优化或滤波(EKF/UKF)的方法,将视觉、IMU、LiDAR、里程计等多源信息在统一状态空间中融合,提升在恶劣光照、纹理缺失或动态环境中的定位稳定性。 + +整体上,3D 场景理解与定位构成了机器人“能动起来”的基础:既要在复杂三维世界中构建可靠的自我定位框架,又要让地图变得“有意义”,从而支持高层任务规划与人机交互。 + +### 3.2.1 3D 语义分割与可通行区域理解 + +在纯几何地图中,所有结构只是无差别的点/体素;而在真实应用中,我们关心的是:哪里是地面、哪里是墙、哪里有桌子或货架、哪里可以通行。**3D 语义分割**就是要为每一个点或体素赋予语义标签,将“纯几何”转化为“几何 + 语义”。 + +在室内/室外场景中,典型目标包括: + +- 固定结构:墙、地面、天花板、楼梯、柱子、道路、路沿等; +- 家具与设施:桌椅、柜子、货架、门窗、扶手等; +- 可通行/不可通行区域:机器人可行走区域、需绕行的障碍物、禁入区域等。 + +建模上,3D 语义分割常采用: + +- 体素/稀疏卷积方案:把点云体素化后,用 3D U‑Net、MinkowskiNet 等稀疏 CNN 学习体素级特征,兼顾局部细节和全局结构。 +- 点云直接方案:PointNet++、KPConv 等点云网络,对局部邻域做特征聚合,实现点级别的语义预测。 + +在扫地机器人、AGV 机器人等应用中,语义分割的结果会被进一步抽象成 **语义地图** :例如把房间划分为卧室/客厅/厨房,把仓库内空间划分为货架区域/通道/禁行区。机器人不仅知道“哪里可以走”,还可以根据房间类型定制不同策略(如卧室避开地毯区域、仓库中优先覆盖某些货区)。 + +### 3.2.2 位姿估计、SLAM 与多传感器融合定位 + +**SLAM(Simultaneous Localization and Mapping)** 的目标是:在未知环境中,一边移动一边估计自身轨迹,同时构建环境地图。对于没有高精度外部定位(如 RTK‑GNSS)支持的室内环境来说,SLAM 是绝大多数机器人和 AR 引擎的首选方案。 + +在视觉 SLAM 中,以 ORB‑SLAM、DSO、VINS‑Mono/VINS‑Fusion 为代表的方法,通常分为几个关键模块: + +- 前端:从连续图像中提取和跟踪关键点/图像块,估计相邻帧之间的相对位姿。 +- 后端:在滑动窗口或全局图中进行 BA 或图优化,处理漂移、回环检测与重定位。 +- 地图:根据位姿和深度信息构建稠密或半稠密地图,为后续导航或渲染提供基础。 + +纯视觉在纹理缺失、光照剧烈变化时容易失效,因此实践中一般会采用 **多传感器融合定位** : + +- 视觉 + IMU:VINS‑Mono/VINS‑Fusion 等框架将 IMU 的高频短时精度与视觉的尺度和几何约束结合,大幅提高短时和急转弯场景的稳定性。 +- LiDAR + IMU + 视觉:如 LIO‑SAM 等里程计框架在 LiDAR‑SLAM 中引入惯导与可选视觉信息,利用三者互补的特性实现鲁棒定位,在自动驾驶和高精度测绘中广泛使用。 + +在产品层面,这些方法通常被封装为机器人底盘控制器、无人机飞控、AR 引擎(如 ARKit/ARCore 中的 Visual‑Inertial SLAM)或室内定位 SDK 的一部分,对上层应用屏蔽了复杂的状态估计和图优化逻辑,让开发者可以直接拿到“实时位姿 + 地图”。 + +### 3.2.3 语义地图、导航与避障 + +有了稳定的位姿估计和几何/语义地图,下一步是让机器人“聪明地动起来”。这部分主要涉及 **语义地图构建、路径规划和避障** 。 + +- **语义地图构建** :在几何地图上叠加语义信息(房间类型、POI、区域标签),形成适合高层决策的地图表征。例如: +- 家庭场景中,将地图划分为卧室、客厅、厨房、卫生间等区域; +- 仓储场景中,标注货架位置、装卸区、危险区域等; +- 大型商场/展馆中,标注店铺、服务台、洗手间等 POI,用于 AR 导航和导览。 +- **路径规划与避障** :在地图上构建栅格图或拓扑图,利用 A*、D* Lite、RRT 等规划算法为机器人找到从起点到目标点的可行路径;同时结合实时感知(前方障碍物、动态行人/车辆),进行局部重规划和避障,保证运行安全与效率。 +- **导航行为与任务调度** :在 AGV 机器人和无人机中,还会在导航之上叠加任务调度与多机协同模块:分配任务、避免拥堵、优化整体路径与能耗。 + +AR 导航与室内定位系统本质上也依赖类似的语义地图和路径规划,只不过“执行者”从机器人变成了人:系统通过 SLAM 获取用户设备的位姿,在语义地图上规划行走路径,再以增强现实的形式把路径可视化叠加到真实世界视图中。 + +## 3.3 3D 生成与编辑(3D Generation & Editing) + +如果说 3D 感知和 SLAM 是从真实世界“采集并理解”几何,那么 3D 生成与编辑则是站在内容生产的角度: **如何用 AI 自动生产和改造 3D 资产** 。这直接面向游戏、影视、数字人、虚拟空间、电商展示、3D 打印等巨大的内容需求。 + +最近两三年,随着 NeRF/Gaussian、SDF 表示、多模态扩散模型等技术的突破,3D 生成进入快速发展期:从文本、图像、视频一键生成 3D 模型或场景已经成为现实,各大云厂商和创业团队推出了如「混元 3D」、Tripo、DreamFusion / Magic3D 系列方法落地为在线工具,使 3D 生产逐渐向“人人可用”的方向演进。3D 生成与编辑大致可以拆成四类能力:文生 3D、图/视频生 3D、模型优化与编辑,以及绑定与动画。 + +- **场景** + - 游戏 / 影视资产制作:为角色、道具、建筑、场景快速生成可用的 3D 模型,大幅降低美术工作量。 + - 电商与产品展示:根据产品文案或照片自动生成 3D 展示模型,用于 3D 看样、AR 试摆、交互式广告。 + - 数字人与虚拟内容:快速生成虚拟人、虚拟试衣模特、虚拟主播场景等 3D 资产,支持直播、短视频和互动应用。 + - 3D 打印与个性化建模:从草图/照片/文本生成可打印模型,实现个性化礼品、原型设计与教育场景应用。 +- **原理** + - 文生 3D(Text‑to‑3D):将文本描述编码为语义向量,再通过多阶段优化或扩散过程生成 3D 表示(NeRF/SDF/Gaussian/Mesh),通常借助强大的 2D 文生图模型做“评分器”或先验。 + - 图 / 视频生 3D:利用单张或多张图像、多视角视频作为监督,结合 NeRF、SDF 或隐式/显式混合表示,重建出带几何和纹理的 3D 模型。 + - 3D 模型优化与编辑:对已有模型进行重拓扑、简模、细节增强、LOD 生成、UV 展开和贴图生成,以及基于语言/图像的形变与风格化。 + - 绑定与动画:为 3D 角色自动推断骨骼结构并完成 Rigging,支持骨骼动画和物理模拟(布料、软体、刚体),形成可驱动的动态资产。 +- **模型** + - 3D 生成基础表示:NeRF / Instant‑NGP、SDF(隐式表面)、Gaussian Splatting 以及 Mesh‑based 生成网络,构成 3D 数据的表达空间。 + - Text‑to‑3D 方法:DreamFusion、Magic3D、Fantasia3D 等典型路线,通过“2D 文生图模型 + 3D 优化”或“3D 扩散模型”完成从文本到 3D 的端到端生成,为后来的混元 3D、Tripo 等产品奠定技术基础。 + - 图/视频生 3D 模型:基于 NeRF/SDF/Gaussian 的重建与优化框架,从多视图一致性和单视图先验中恢复稳定的 3D 几何与纹理。 + - 绑定与动画算法:自动骨骼提取、骨骼权重预测、基于深度学习的 Retargeting 与运动生成,为虚拟人/角色动画提供一键化工具。 + +在这一层,传统 3D DCC(Maya/Blender/3ds Max 等)与 AI 工具链逐步融合:许多 3D AI 服务以插件或云端接口的形式嵌入现有生产流程,让建模师/美术可以在人机协作中迅速迭代资产。 + +### 3.3.1 文生 3D 与场景草模 + +**文生 3D(Text‑to‑3D)** 的目标是:给出一句自然语言描述,例如“一个卡通风格的黄色小鸭玩具,带有蓝色围巾,适合儿童玩具展示”,系统自动生成一个可编辑的 3D 模型(Mesh/NeRF/SDF/Gaussian 等)。这是将大语言模型/多模态模型与 3D 表示结合的典型应用。 + +典型技术路径包括: + +1. **基于 2D 文生图模型的优化** (如 DreamFusion、Magic3D): +2. 使用强大的 Text‑to‑Image 模型(如扩散模型)作为“评估器”,给定 3D 表示在某一视角下渲染出的图像,评估它与文本描述的匹配程度。 +3. 通过梯度优化或扩散过程,迭代调整 3D 表示(NeRF/SDF/Mesh),使得从多个视角渲染出的图像都符合文本语义。 +4. **3D 扩散模型 / 直接生成** : +5. 将 3D 数据(点云、体素、隐式场参数、Gaussian 粒子等)作为扩散模型的生成目标,在大规模 3D 数据集上预训练; +6. 通过文本条件控制,实现端到端的 Text‑to‑3D 采样。 + +在场景级别,**场景草模**能力允许用户用自然语言或粗略草图描述空间布局,例如“一个带落地窗的客厅,左边一张 L 型沙发,中间一张茶几,右侧有书架和电视柜”,系统自动搭建出一个几何和语义合理的 3D 布局草图。后续可以在 DCC 工具中细化模型与材质,或直接通过混元 3D、Tripo 等工具中的“场景生成”能力快速产出可用的场景原型。 + +当前,多家平台已经推出面向设计师和开发者的 Text‑to‑3D 产品: + +- 「混元 3D」等将文生 3D、多视图生成与重建能力整合进统一界面,支持从文本快速生成角色、道具和场景再导出到游戏引擎; +- Tripo 类产品则强调“多模态输入 + 一键 3D 输出”,支持简单文本和参考图像混合,引导生成满足风格与结构需求的 3D 资产。 + +### 3.3.2 图 / 视频生 3D 与模型优化编辑 + +与纯文本相比,从图像或视频生成 3D 模型对几何约束更强,在视觉上一致性也更好。因此,大量 3D AI 产品支持 **图生 3D / 视频生 3D** : + +- 单张照片 → 粗 3D:利用单视图先验(如人脸、人体、常见物体类别的形状先验),推断大致的 3D 几何,生成可用于预览或简单交互的 3D 模型。 +- 多张照片 / 短视频 → 高质量 3D:综合使用 NeRF/SDF/Gaussian 重建、多视角几何和后处理,将数十张照片或几秒钟视频转换为高保真的 3D 模型,适合游戏/影视资产或高质量电商展示。 + +生成出 3D 几何只是第一步,后续还需要大量**模型优化与编辑**工作: + +- 重拓扑与简模:将隐式场或高多边形 Mesh 转换为结构规整、面数可控的拓扑,以便于绑定、动画和实时渲染。 +- LOD 生成:自动生成多级细节模型(Level of Detail),在远处用低模、近处用高模,兼顾画质与性能。 +- UV 展开与贴图生成:自动为模型展开 UV、生成或优化法线贴图、位移贴图、粗糙度/金属度贴图等 PBR 材质;有些模型还支持从文本或参考图自动生成风格化纹理。 +- 几何与风格编辑:基于语言或示例图进行局部修改,如“让这个椅子腿变短一点”“把这栋楼改成赛博朋克风格”,底层通常通过形状潜空间操作或神经场编辑实现。 + +混元 3D、Tripo 等产品往往将上述流程打通:用户从照片/视频或简单文本出发,系统内部完成重建、重拓扑、贴图与导出,让非专业用户也能在几分钟内获得“即插即用”的 3D 模型,大幅缩短从概念到资产的时间。 + +### 3.3.3 绑定、动画与动态 3D 资产 + +静态模型只是内容的一半,“能动起来”的 3D 资产在游戏、影视、虚拟人和交互应用中更为关键。这涉及**骨骼绑定(Rigging)、权重绘制、动画与物理模拟**等环节,传统上都是高门槛的专业工作,如今也逐渐被 AI 工具辅助甚至半自动完成。 + +- **自动 Rigging** :给定一个角色 Mesh,系统自动推断骨骼层级结构(脊柱、四肢、手指等)和骨骼在模型中的位置,并预测每个顶点相对于各个骨骼的权重。近年来的深度学习方法可以在大规模带骨骼标注的角色数据集上学习这一映射,实现一键骨骼绑定。 +- **动画与动作生成** :在已有骨骼上叠加动作数据(Mocap 或 AI 生成),完成走路、跑步、表情、手势等动画;基于深度学习的动作生成与 Retargeting 可以将视频中的人体动作或其他角色的动作迁移到新角色上。 +- **物理模拟** :对布料、软体、刚体等进行物理模拟,使头发、衣服、旗帜、柔软物体的运动更自然。有些系统利用神经网络加速或近似物理,使实时引擎中的物理效果更逼真。 + +在产品与生态上,这些能力常常内嵌于: + +- 游戏 / 影视资产工具链:为建模师提供一键 Rigging、自动权重分配和基础动作库,大幅减少重复劳动; +- 虚拟人 / 数字资产制作平台:从人物照片或扫描开始,经由 3D 重建 + 自动 Rigging + 动作驱动,输出可在直播、短视频、互动应用中驱动的虚拟人; +- 3D AI 平台(如混元 3D、Tripo 及同类产品):在 3D 生成之后,进一步增加绑定与简单动画功能,让用户“生成的角色可以立刻动起来”,而不需要复杂的 DCC 工具操作。 + +随着 3D 生成与编辑技术的成熟,整个 3D 内容生产流程正在从“以专业 DCC 工具为中心”演化为“AI 驱动的人机协作”:AI 负责生成与大量基础工作,人类更多在风格定义、品控和关键设计节点上做决策。混元 3D、Tripo 等新一代 3D AI 产品正是这一趋势的集中体现,为上层的游戏、影视、AR/VR、数字孪生和虚拟人应用提供了更快、更易用的 3D 基础设施。 + +# 4. 音频(Audio / Speech) + +在整体技术栈中,“音频”对应的是对声学信号的感知与生成:既包括对原始波形和频谱的处理,也包括把语音转为文字、理解“谁在说”“说了什么”,以及进一步对声音、音乐进行创作和合成。与视觉类似,音频也可以被拆成多层:底层的**波形与频谱处理**负责“听清楚”;中层的**语音识别与说话人技术**负责“听懂是谁在说什么”;在此之上,是更抽象的**音频/音乐理解**与 **语音、音乐生成** 。这一整块能力共同支撑了会议实时字幕、语音助手、播客后期修音、智能音箱、声学安防监控、音乐推荐与生成等产品。 + +## 4.1 波形层面音频处理:从“听得清”开始 + +在音频技术的最底层,我们首先关心的并不是“说了什么”“是谁在说”“音乐是什么风格”,而是 **这个声音本身干不干净、听不听得清** 。这一层主要在波形和频谱层面工作,通过重采样、增强、降噪、分离等操作,把嘈杂、失真、混在一起的原始声音加工成更适合后续识别、分析和生成的“干净信号”。可以把它类比到视觉里的“图像增强 + 去噪 +分离前景/背景”,更多是在做声学层面的清理,而不直接处理语义。 + +从产品角度看,这一层几乎“隐身”在所有音频产品背后:会议软件的实时降噪、播客/短视频后期修音、录音笔和手机里的“语音增强模式”、直播平台里的“美声开关”,以及给 ASR/声纹模型做的前端预处理,都是波形层面音频处理的直接体现。下面依旧从 **场景** 、**原理**和**模型**三个角度来梳理,并在后续小节具体展开预处理 & 特征提取、增强与降噪、声源分离三个关键方向。 + +- **场景** + - 在线沟通与会议:Zoom、腾讯会议等在嘈杂办公室、开放工位、家中环境下,实时压制键盘声、敲击声、街噪、回声,让语音更清晰。 + - 内容创作与后期修音:播客、短视频、直播后期中,自动消除底噪、电流声、房间混响,修补录音爆音和频段缺失,提高整体听感。 + - 录音与转写前端:录音笔、智能字幕、会议转写服务在进入 ASR 之前,通过 VAD、降噪、响度归一等处理,提升后端识别鲁棒性。 + - 终端与 IoT:智能音箱、车机、摄像头等设备上的“远场拾音”与“降噪模式”,在复杂声场中尽量捕获到主说话人或关键声源。 +- **原理** + 波形层面处理通常不直接理解语义,而是围绕频谱结构和统计特性做信号优化: + - 在时间域和频率域之间来回变换(如 STFT → 频谱/梅尔频谱 → iSTFT),对噪声频带、混响特征或背景声进行抑制或建模。 + - 通过 VAD 和能量/谱特征,区分“有语音的片段”和“静音/噪声片段”,减少无效片段对后端的影响。 + - 使用深度学习或经典滤波方法估计“干净语音谱”和“噪声谱”的掩码或增益函数,对频谱进行加权,达到增强与降噪的目的。 + - 在多声源混合的场景中,通过端到端分离网络或稀疏表示,将不同说话人、人声与伴奏、前景与背景环境声解混到独立的轨道。 +- **模型** + 波形/频谱层面的模型大致可分为两类:**频谱域模型**和 **时域端到端模型** : + - 频谱/梅尔频谱上的 U‑Net 系列:Spectrogram‑based U‑Net、DCCRN 等,在时–频平面上做“图像式”的卷积与编码–解码,是语音增强、歌声分离等任务的常用方案。 + - 波形端到端模型:Wave‑U‑Net、Conv‑TasNet、Demucs 等,直接在时域波形上建模,避免显式 STFT/ISTFT,往往在主观听感和时域保真度上效果更好。 + - 经典信号处理方法:谱减、Wiener 滤波等传统频域方法,在轻量级设备或对延迟极敏感的场景中仍然广泛存在,常与深度增强网络结合形成“混合方案”。 + +### 4.1.1 预处理与特征提取:为后端“清场搭台” + +任何后续的 ASR、声纹识别、事件检测、TTS 等模型,都需要一个尽量统一、干净、结构化的音频输入,这就是预处理与特征提取层的职责。它负责做最基础却又极其关键的“清场”和“格式统一”,为上游音频模型搭好舞台。 + +在预处理阶段,首先会对采集到的音频做 **采样率转换和声道转换** :比如把 48kHz 立体声转换为 16kHz 单声道,以满足下游模型的输入规格,并降低计算成本。随后,会对响度进行归一化、去直流分量、简单滤波等,使不同设备、不同场景下录得的音频在能量尺度上更加一致。 + +**语音端点检测(VAD)** 则是预处理中的另一个关键环节。它尝试在音频流中自动划分“有语音的片段”和“静音/纯噪声片段”,常基于帧能量、谱熵、零交叉率或小型神经网络判别。VAD 的好处是:可以显著减少送入 ASR/声纹模型的无效数据,降低计算量,同时避免静音段干扰识别(例如误识为长串空格或奇怪字符)。在实时通信中,VAD 还可以驱动“语音活动指示灯”和自动静音逻辑。 + +在特征提取层面,最常见的是将时域波形转为**频谱**或 **梅尔频谱** 。通过短时傅里叶变换(STFT),音频被分解为随时间变化的频率分布;再通过梅尔滤波器组,可以得到更符合人耳感知的梅尔频谱或梅尔倒谱特征(如 log Mel‑spectrogram、MFCC)。这些时–频特征为后续的识别、分离与生成提供了一种“二维表示”,类似视觉里的灰度图或多通道特征图,便于卷积、注意力等结构处理。随着端到端建模的发展,也有越来越多模型直接在波形上学习特征(如 Wav2Vec 2.0 ),但在工程实践中,STFT + 梅尔特征的组合仍然是最普遍、最稳妥的前端。 + +### 4.1.2 增强与降噪:把“糊音”修成“干声” + +在真实环境中,声音几乎总是在噪声和混响中传播:空调声、键盘敲击、路噪、人群嘈杂、房间回声,都在不同程度上降低了语音和音乐的可懂度与主观质量。**语音增强与降噪**的目标,就是在尽量保持语音自然度和完整度的前提下,抑制这些背景干扰,把“糊掉”的声音尽可能修成“干净”的声音。 + +在传统方法中,这一任务主要通过谱减、Wiener 滤波等频域技术实现:先估计噪声谱,然后在频谱上按一定规则“减去”噪声或进行频带增益调整。虽然实现简单、实时性好,但在强噪声、非平稳噪声和复杂混响场景下容易产生明显的“音乐噪声”和伪影。 + +深度学习方法则通过在频谱或波形上学习一个 **映射** :给定带噪语音,预测一个时间–频率掩码或直接预测干净波形。常见方案包括在梅尔/线性频谱上使用 **Spectrogram‑based U‑Net、DCCRN** 等编码–解码结构,对每一帧的频谱进行细致修复;也有直接在时域波形上用 **Conv‑TasNet、Demucs、Wave‑U‑Net** 等模型进行端到端的波形增强。这些方法在语音电话、在线会议、录音修复等场景中,能显著提高语音清晰度和主观听感。 + +在内容创作和后期制作中,“录音修复”往往还涉及减少爆音(plosives)、削减齿音(sibilance)、补偿频段缺失以及均衡(EQ)和动态处理(压缩器/限幅器)等更“音频工程师味”的操作。越来越多的工具将这些传统处理与深度模型结合,提供一键“修音”和“音频美化”能力,服务播客、视频创作者和直播平台。 + +### 4.1.3 声源分离:把“混音”拆开 + +如果说增强与降噪是“让主声更突出、背景更安静”,那么**声源分离**则进一步尝试将混合在一起的多个声源完全拆分成独立轨道。例如:会议录音中多位说话人同时讲话;音乐中人声与伴奏混在一起;环境录音中主事件(如警报、喊叫)掩埋在背景噪声里。声源分离的目标,是从单条或多条混合信号中,恢复出每个独立声源的波形或频谱。 + +在语音领域,**多说话人分离**是一个核心应用:模型需要在没有单独麦克风分轨的情况下,根据声纹、时频结构和说话人特征,将多个重叠语音分到不同通道。这类能力不仅能提升多说话人 ASR 的表现,还可为说话人分离与标注(Diarization)提供更干净的输入。在音乐领域,**人声/伴奏分离(歌声分离)**则可以从一首混音好的歌曲中分离出清晰的人声轨和纯伴奏轨,用于翻唱、Remix、卡拉 OK、音乐分析等。类似地,**环境音/前景声分离**可用于安防与 IoT 场景,从复杂背景中提取关键事件声(如玻璃破碎、冲突声)。 + +在模型层面,声源分离通常采用比普通增强更强的建模能力和更复杂的架构。**Conv‑TasNet、Demucs、Wave‑U‑Net** 等端到端网络可以直接在时域进行多声源分解;在频谱域上,则常见多分支 U‑Net、注意力、掩码估计等结构,分别为不同声源预测专门的掩码或频谱。随着训练数据和计算资源的增长,现代声源分离模型已经能在相当复杂的混响和噪声环境下,输出可用于实际创作与分析的高质量分轨,为直播美声、多说话人会议、音乐制作和音频检索提供了坚实基础。 + +## 4.2 语音识别与说话人技术(ASR & Speaker) + +在波形层面完成了预处理、增强和分离之后,我们终于可以开始问更高层的问题:**“音频里说了什么?”“是谁在说?”“什么时候谁在说?”** 这一层聚焦的是各种围绕语音本身的“理解与标注”任务:自动语音识别(ASR)、说话人识别与验证、说话人分离与标注(Diarization),以及面向交互的热词与关键词检测(KWS)。 + +从产品形态看,这一层是绝大多数“语音产品”的核心:语音输入法、会议转写、客户服务录音分析、智能客服质检、智能音箱和车机语音交互、电话机器人、金融场景声纹验证等,几乎都直接依赖这些技术。它们把前一层“干净的声音”转化为文字序列、说话人标签或关键词事件,是音频到语义世界的最重要桥梁之一。 + +- **场景** + - 自动语音识别(ASR):实时字幕、语音输入法、会议与课堂记录、客服通话转写,为用户提供“听觉到文本”的即时通道。 + - 说话人识别与验证:手机/银行/呼叫中心中的“声纹解锁”“声纹验证”,以及在海量录音中检索某一特定说话人。 + - 说话人分离与标注(Diarization):在会议、访谈、圆桌讨论中,自动回答“谁在什么时候说话”,实现“分说话人转写”。 + - 热词与关键词检测(KWS):智能音箱/车机唤醒词检测(“Hey Siri”“OK Google”),以及在客服录音、质检中捕捉关键短语(如“投诉”“退款”“要升级”等)。 +- **原理** + 这一层的大部分任务都可以被统一视为对音频序列进行 **时间对齐与序列标注** : + - ASR:给定一段语音,学习从声学特征到文本序列的映射,常使用 CTC、RNN‑Transducer(RNN‑T)或基于注意力的端到端结构;现代模型多采用大规模预训练(如 Wav2Vec 2.0、Whisper 等)再微调。 + - 说话人识别:从音频中提取一个固定维度的 **说话人嵌入** (speaker embedding,如 x‑vector、ECAPA‑TDNN),在这个嵌入空间中,同一人的语音彼此接近,不同人的语音彼此远离,再结合度量或分类模型完成识别与验证。 + - 说话人分离与标注(Diarization):综合利用声纹嵌入、VAD、分段聚类或端到端网络(EEND),为每一段时间片分配说话人标签,从而拼出“时间轴上的多说话人时间线”。 + - KWS:在连续音频流上进行低延迟的小模型检测,对预定义的唤醒词或关键词进行局部模式匹配和置信度评估,兼顾低算力与高召回。 +- **模型** + ASR 与说话人技术的模型谱系既包括端到端架构,也包括专门的嵌入模型与聚类方法: + - ASR:Wav2Vec 2.0、Conformer、Whisper、RNN‑T、Citrinet 等,大多采用卷积 + 自注意力或纯自注意力结构,支持多语种、大词表和长上下文。 + - 说话人嵌入:ECAPA‑TDNN、x‑vector、i‑vector 等,通过对大量说话人数据进行分类训练或度量学习,得到稳健的说话人特征空间。 + - Diarization:从 VAD + 分段 + 聚类的传统流程,到 End‑to‑End Diarization(EEND)这类直接输出“时刻 × 说话人”矩阵的端到端方法。 + - 热词/关键词检测:轻量级 CNN/RNN/Transformer 前端组合 CTC 或门控机制,嵌入在设备本地,以超低算力、低延迟实现常开监听。 + +### 4.2.1 自动语音识别(ASR):把“声音”变成“文字” + +**自动语音识别(ASR)是“音频→文本”的主通路:无论是语音输入法,还是会议转写、智能字幕、客服录音分析,第一步都是要把用户说的话准确地转成文字。现代 ASR 系统多采用端到端架构** :从声学特征(如梅尔频谱或直接波形)出发,经过一系列深度网络(如 Conformer、Citrinet、基于 Transformer 的 Encoder),直接输出文字序列或对应的 token 序列。 + +在建模上,ASR 的难点主要包括长时依赖、多语种与方言、口音变化、重叠语音、背景噪声以及领域内专有名词。为此,当前主流方向是利用大规模无标注音频做自监督预训练(如 Wav2Vec 2.0、HuBERT),或在多语种、多任务数据上做大规模监督训练(如 Whisper),再通过相对少量的领域数据进行微调,从而在不同语言、口音和场景下达到较好的鲁棒性。 + +在产品层面,ASR 通常被打包为“语音输入法 SDK”“云端语音识别 API”“会议转写服务”等能力输出:前端可以是实时流式识别(RNN‑T、流式 Transformer 等),后端可通过热词注入、自定义词表、上下文约束来强化对特定人名、地名、品牌名和业务术语的识别。这些识别结果往往是后续 NLP、对话系统和数据分析的基础。 + +### 4.2.2 说话人识别与分离标注:回答“是谁”与“何时在说话” + +与“说了什么”相比,**“是谁在说”在很多应用中同样重要:金融、政务、客服、安防等场景需要通过声纹识别**来验证身份或排查风险;而会议与访谈场景则需要知道“每一句是谁说的”,以支持分说话人转写、发言统计和行为分析。 + +在**说话人识别/验证(Speaker Recognition)** 任务中,系统的目标是:给定一段语音,判断说话人是谁,或者判断是否与某个注册说话人属于同一人。现代系统通常通过 ECAPA‑TDNN、x‑vector 等模型,从语音段中提取一个固定维度的说话人嵌入向量。在训练阶段,以说话人分类与度量学习的组合,保证同一人的嵌入更为聚集、不同人之间的嵌入距离更大;在推理阶段,再采取最近邻或后端判别器(如 PLDA、Cosine scoring with margin)进行验证与识别。这样,系统就能在电话、麦克风、噪声环境下,以一定置信度回答“是不是同一个人”。 + +**说话人分离与标注(Diarization)** 则进一步回答“谁在什么时候说话”。传统方案通常包含三个步骤:先用 VAD 找出有语音的片段,再将长音频切成短 segments,为每个 segment 提取说话人嵌入,最后在嵌入空间中做聚类和时间拼接,得到一条多说话人时间轴。更先进的 **End‑to‑End Diarization (EEND)** 类方法则尝试直接从音频特征输出“时间 × 说话人”布尔矩阵,端到端学习重叠语音、说话人切换等复杂模式。Diarization 在会议、访谈节目、法庭记录、电话客服等场景中极具价值,常与 ASR 结合形成“带说话人标签的文字记录”。 + +### 4.2.3 热词与关键词检测:面向交互和监控的“耳朵” + +在持续的音频流中,不是每一秒都值得被完整识别和存储。**热词与关键词检测(KWS)**的角色,就是一个始终在线的“守门员”: + +- 在智能音箱、车机、手机助手中,KWS 模块负责检测唤醒词(如“Hey Siri”“OK Google”“小爱同学”),一旦检测到唤醒词,就把音频流交给更昂贵的 ASR 与对话系统处理。 +- 在智能客服、质检和合规场景中,KWS 会对录音或实时通话中出现的关键短语(如“投诉”“退货”“维权”“欺诈”)进行标记和告警,为后端分析和质检策略提供触发点。 + +在技术实现上,KWS 通常需要在**极低算力和低延迟**的约束下运行,尤其是本地设备上的唤醒词检测:模型往往是一个小型 CNN/RNN/Transformer 前端,接 CTC 或门控判别头,对特定词的声学模式进行检测,并利用滑动窗口和置信度平滑避免误唤醒。对于关键词质检场景,则可以采用更强的 ASR + 关键词匹配/正则 + 统计分析,或者直接训练端到端关键词 tagging 模型。无论哪种形态,KWS 本质上是在语音流上加了一层“事件级”的语义筛选,是连接音频世界与交互逻辑的重要接口。 + +## 4.3 音频/音乐理解(Audio Event & Music Understanding) + +并非所有音频都以“语音”为中心。现实中有大量与环境声、事件声、音乐相关的场景,它们更关注的是:**“发生了什么声音事件?”“当前环境是什么声景?”“这首歌是什么风格、用了哪些乐器、节奏和调是什么?”** 这部分能力统称为音频/音乐理解,主要围绕声音事件检测、环境/场景分类和音乐属性理解展开。 + +从产品视角看,音频理解技术支撑了安防声学监控、IoT 声学传感器、智能设备的环境自适应、音乐推荐与分类、音乐版权识别、音乐检索和创作辅助等广泛应用。与图像中的“图像分类 + 细粒度分类”类似,这一层把原本连续、复杂的声音空间结构化成离散的事件标签、多维属性向量和风格描述。 + +- **场景** + - 声音事件检测:检测警报声、玻璃破碎、婴儿哭声、撞击声等,用于安防监控、智慧楼宇、车辆安全系统和工业告警。 + - 环境/场景分类:识别“室内/室外”“办公室/车内/街道/地铁”等声景,为智能设备的降噪策略、自适应增益、模式切换提供依据。 + - 音乐理解与音乐信息检索(MIR):曲风分类、乐器识别、节奏与调性分析,支撑音乐推荐、歌单生成、音乐检索、版权识别和创作助手。 +- **原理** + 音频/音乐理解大多基于**时–频特征 + 深度神经网络**进行分类或多标签标注: + - 使用 log Mel‑spectrogram 等特征,将音频转化为“声学图像”,再利用 CNN、CRNN 或 Transformer 等结构进行时–频模式识别。 + - 对于声音事件检测,往往采用多标签、多时序输出,对每种事件在时间轴上进行存在性预测,有时还会结合弱监督标签和多实例学习。 + - 对环境/场景分类,则更注重长时间统计特征和背景格局,往往需要在较长窗口上建模。 + - 音乐理解任务则结合音乐理论知识,对节奏(BPM)、拍点、调性、和弦和结构进行建模,部分任务通过自监督或对比学习预训练音乐嵌入,再做下游微调。 +- **模型** + 常见的音频理解模型多在公开数据集(如 AudioSet)上预训练,再迁移到具体任务: + - VGGish、YAMNet、PANNs 等 CNN/CRNN 模型,在大规模有声数据上预训练后,可用于多种音频事件与声景任务。 + - AST(Audio Spectrogram Transformer)等 Transformer‑based 模型,直接在频谱图上使用自注意力,获得更强的全局时–频建模能力。 + - 针对音乐的 MusicTagging / MIR 模型,会在百万级歌曲上预训练标签模型或嵌入模型,用于风格/情感/乐器标签、音乐检索和推荐。 + +### 4.3.1 声音事件与环境声景:让设备“听得懂环境” + +在安防、IoT、智慧城市、车载系统中,光靠摄像头并不足以全面理解环境状态。**声音事件检测**的目标,就是让系统“听得懂”关键事件:当发生玻璃破碎、警报拉响、婴儿哭泣、碰撞、尖叫、打斗、破坏行为时,系统能够在音频信号中识别并发出告警。与语音识别不同,这类事件往往是短促、非语言的,频率范围和能量形态各异,且可能和背景噪声高度重叠。 + +**环境/场景分类**则更关注持续性的声景(acoustic scene):是安静办公室、热闹街道、车内、高铁站还是咖啡馆?系统可以根据声景自动调整降噪强度、回声抵消参数、麦克风阵列波束指向,甚至改变交互策略(例如在车内通过更简短的反馈交互,在嘈杂街道上提高输出音量)。在 IoT 场景中,多个声音传感器组成的“声学网络”可用于对环境状态进行长期监控和统计分析。 + +在技术实现上,这两类任务都大多采用**多标签分类 + 时序建模**方案:将音频转换为梅尔频谱,使用 VGGish、PANNs、AST 或类似模型进行特征抽取,再用时序池化或序列模型输出每个标签在时间轴上的激活情况。由于很多数据集只提供“片段级标签”(weak labels),模型常需通过多实例学习、自注意力池化等方式,在弱监督下学习事件的时间定位。 + +### 4.3.2 音乐理解与标签:从“歌单标签”到“结构分析” + +在音乐领域,音频理解的目标不仅仅是“这是一首什么歌”,更是要回答:**“这首歌什么风格?用到了哪些乐器?节奏快慢如何?调性与大致和声结构是什么?”** 这些信息一方面支撑音乐推荐与歌单编排,另一方面也为创作者和生成模型提供结构化“音乐元数据”。 + +**曲风分类**任务会根据歌曲整体声学特征与结构,将其归入流行、摇滚、古典、嘻哈、电子、Lo‑Fi 等不同风格;**乐器识别**则在时–频特征上区分鼓、贝斯、吉他、钢琴、弦乐等不同乐器的声学指纹,可用于乐器统计、音乐检索和混音分析。**节奏/调性分析**则是对 BPM、拍点位置、拍号、主调(Key)等进行估计,为节奏匹配、自动和声、DJ 混音、游戏音轨同步等任务提供基础。 + +在模型上,音乐理解多沿用通用音频模型(如 PANNs、AST),但也有大量专门面向音乐信息检索(MIR)的模型与预训练嵌入。典型做法是在大规模音乐数据集上进行 **多标签音乐标签学习** (genre、mood、instrument、era 等),得到音乐嵌入空间,再在上述具体任务上微调或做零样本推断。结合这些模型,音乐平台可以更智能地完成音乐分类与推荐,版权平台可以强化音乐指纹与相似性检索,而创作工具则可以利用这些理解能力,为用户推荐合适的伴奏、扩展相似风格或自动生成音乐结构。 + +## 4.4 语音与音频生成(TTS / VC / Music Generation) + +在完成了对音频的“清理”“识别”和“理解”之后,下一层自然的问题是:**“我们能否直接让机器‘说话’、‘唱歌’甚至‘作曲’?”** 这就是语音与音频生成的世界:从文本到语音(TTS),从一种声音到另一种声音(VC / Voice Cloning),到更大范围的音乐与音效生成,再到可以演唱歌词和旋律的歌声合成。与图像生成类似,这一层不再只是在已有数据上打标签或提取结构,而是主动“创造”新的声音内容。 + +在产品层面,这一层能力已经渗透到各类应用:OpenAI TTS、ElevenLabs、火山引擎、minimax等语音产品线为应用提供高质量合成语音;Suno、Udio 等音乐生成平台为创作者甚至普通用户提供从文案到完整音乐的能力;游戏、视频、虚拟主播和数字人依赖这些模型进行配音和歌唱,极大降低了内容制作的门槛。 + +- **场景** + - 文本转语音(TTS):新闻播报、导航播报、智能客服语音回复、学习类 App 朗读内容、无障碍读屏等,需要将任意文本转换为自然、清晰、可控的语音。 + - 语音转换 / 语音克隆(VC / Voice Cloning):在保持语义和韵律的前提下,改变说话人音色,实现“换声说话”或“少样本声纹克隆”(在严格合规条件下)。 + - 音乐与音效生成:为短视频、游戏、广告、播客等生成合适的背景音乐与音效(环境声、UI 声效、过场音)。 + - 歌声合成与翻唱:给定旋律与歌词,让虚拟歌手演唱,或在合规前提下生成某种风格/音色的翻唱版本。 +- **原理** + 语音与音频生成通常采用**“高层表示 → 低层波形”** 的分层建模思路: + - TTS 中,先将文本转为音素/音节/字级序列,再通过序列到声学特征(如梅尔谱)的模型(Tacotron、FastSpeech、VITS 等),最后用神经声码器(WaveNet、WaveRNN、HiFi‑GAN 等)从特征生成高保真波形。 + - Voice Conversion 中,通过解耦“说什么(内容)”与“谁在说(音色)”,从源语音提取内容表示,再与目标说话人嵌入或声码条件结合,生成新的语音波形。 + - 音乐与音效生成可基于 token 化的表示(如音符、MIDI、编码后的频谱/codec token),采用自回归、扩散(Diffusion)或神经 codec 生成模型,从文本、参考音频或结构参数中采样出新音频。 + - 歌声合成在 TTS 的基础上引入更精细的韵律、音高轨迹和歌唱控制,通常对音高、时值、连音、颤音等有显式或隐式建模。 +- **模型** + 当前语音与音频生成的主流技术路线包括: + - TTS:Tacotron / Tacotron2、FastSpeech 系列(非自回归 TTS)、VITS 等负责从文本到梅尔谱或 codec token;WaveNet、WaveRNN、HiFi‑GAN、WaveGlow 等作为 vocoder 或解码器负责从特征到波形。最近的 Diffusion‑based TTS 和 Neural Codec 模型在自然度和多样性上进一步提升。 + - Voice Conversion / Cloning:基于 speaker embedding + content encoder 的 VC 框架,以及利用神经 codec 的语音转换模型,支持少样本音色克隆和跨语言说话人迁移。这类技术目前已被多家平台商用落地,提供便捷的语音克隆调用服务,国内常见平台包括火山引擎、minimax、科大讯飞开放平台、百度智能云千帆大模型平台、阿里云智能语音交互平台等;海外则有 ElevenLabs、Resemble.ai、Play.ht 等主流平台。其中,火山引擎的语音克隆能力支持少量音频样本快速训练,适配智能客服、有声读物等多场景的商用调用;minimax 则依托其大模型技术优势,实现了克隆音色与文本内容的自然适配,同时支持跨语言的说话人音色迁移;科大讯飞开放平台的语音克隆在中文发音的清晰度和情感表现力上具备显著优势,广泛服务于教育、广电等领域。 + - 音乐与音效生成:MusicLM、MusicGen、以及 Suno / Udio 类模型,通常基于文本和/或参考音频条件,使用自回归或扩散架构在离散 codec token 上生成长时音频。 + +### 4.4.1 文本转语音(TTS):让机器“自然开口说话” + +**文本转语音(TTS)**是最直观的语音生成任务:输入一段文本,输出一段自然流畅的语音,理想状态下可以与人声几乎难以区分。现代 TTS 系统通常分为两个主要阶段:文本到声学特征(如梅尔频谱),以及声学特征到波形。 + +在第一个阶段,模型需要处理分词、音素化、多音字消歧、标点与停顿、韵律预测等问题。典型模型包括基于注意力的 Tacotron 系列和基于长度预测的 FastSpeech 系列,后者通过非自回归架构显著加速合成、提升稳定性。近年来,VITS 等端到端模型将声学建模和声码器融合在一个统一框架中,进一步简化了系统。 + +在第二个阶段,神经声码器(Neural Vocoder)如 WaveNet、WaveRNN、HiFi‑GAN、WaveGlow 等负责将梅尔谱或其他中间表示转换为高保真波形。训练良好的声码器不仅可以生成自然清晰的语音,还能很好地还原不同音色、情感和风格。现代 TTS 系统还支持 **多说话人建模** (通过 speaker embedding)、音色/语速/情绪控制(如“兴奋”“平静”“播音腔”),以及跨语种 TTS,为各类应用提供高度定制化的声音能力。 + +### 4.4.2 语音转换与声纹克隆:改变“谁在说” + +在很多创作和辅助场景中,我们希望在**不改变内容与韵律**的前提下,改变说话人的音色或风格,这就是**语音转换(VC)**和**语音克隆(Voice Cloning)**的任务。前者主要解决“把 A 的话变成 B 的声音”;后者则进一步强调“少样本甚至几句语音就能学到新的音色”。 + +技术上,VC 通常采用“内容–音色解耦”的思路:通过一个内容编码器提取说话内容与韵律信息(可以是基于 ASR 的离散单位,也可以是自监督的连续表示),再通过一个条件生成器结合目标说话人嵌入或 codec 条件,生成目标音色但语义与节奏基本不变的新语音。如引入神经 codec,则可以在编解码空间直接编辑语音,实现高保真转换。 + +**语音克隆**在 VC 的基础上强调少样本与泛化能力:模型需要从几个样本甚至几秒音频中提取稳定的说话人表示,并据此生成风格一致、音色接近的合成语音。这一能力在虚拟人设、个性化助手、游戏角色定制、配音加速等方面非常有用,但也需要严格遵守法律与伦理规范,确保只在合规授权、充分知情和安全控制的前提下使用,避免滥用或身份冒充风险。 + +### 4.4.3 音乐与音效生成:从提示到完整声景 + +相比语音生成,**音乐与音效生成**在结构与时间尺度上更为复杂:音乐往往持续时间更长,内部结构(段落、旋律、和声、节奏)更加丰富;音效则种类繁多,从自然环境(雨声、风声、海浪)到拟声(UI 点击、提示音、游戏技能音效)都有各自模式。近年来,基于神经 codec、序列建模和扩散的模型使得“从文本生成完整音乐/音效”成为现实。 + +在音乐生成中,像 MusicLM、MusicGen、Suno、Udio 等模型通常将音频编码为离散的 codec token 序列,再在这一离散空间上训练文本条件或多模态条件的生成模型。用户只需提供一段文本描述(如“节奏适中、温暖治愈的 Lo‑Fi 背景音乐,适合学习专注”“紧张的电子管弦配乐,适合科幻预告片”),或上传一段参考音乐片段,模型就能生成长度达几十秒甚至数分钟的高质量音乐。对于创作者,这既是灵感来源,也是快速打样和背景音乐生成的利器。 + +在音效生成上,类似的技术可以根据文本提示生成 UI 声效、通知音、游戏环境声等,帮助产品与游戏团队快速迭代声音设计。结合前一层的音频理解能力,还可以做到风格对齐与场景自适应,例如根据画面或游戏关卡自动匹配音效风格。 + +无论是语音还是音乐与音效生成,这一层能力都在快速演进:从早期合成味浓重的机器音,到现在与人声、专业音乐难以区分的高保真内容。与此同时,围绕版权、合规、溯源和可控性的问题也变得尤为重要——如何在提供强大创作工具的同时,保护创作者和使用者的合法权益,将是这一层技术持续需要面对的关键议题。 + +# 5. 视频(Video) + +在多模态 AI 体系中,**视频模态**负责理解和生成“随时间变化的视觉信号”。相比单帧图像,视频不仅包含空间维度上的纹理、形状和布局信息,还携带丰富的 **时间维度线索** :动作的起落、物体的运动轨迹、镜头的切换节奏等。无论是安防监控中的行为识别、体育训练中的动作分析,还是短视频平台的一键剪辑、长视频的智能解析,本质上都依赖于一整套围绕“帧序列”展开的理解与生成能力。 + +从工程视角看,视频能力大体可以分为几层:**底层的视频增强与复原**负责保证“能看清”;**视频理解与结构分析**负责回答“发生了什么”;在此基础上,**视频 + 语言多模态任务**将视频内容转化为文本可用的结构化描述和检索接口;进一步的,**视频生成与编辑**则反过来从文本或示例视频出发,用可控的方式生成或重组视频内容;而以**数字人 / 虚拟人**为代表的一类应用,则将语音、语言、动作和视频渲染综合在一起,构成面向交互与内容生产的新形态。 + +下面我们同样从分层能力出发,对视频相关能力进行梳理。 + +## 5.1 传统视频处理:从“能播”到“好看、好用” + +在视频技术的最底层,我们首先关心的,并不是“画面里是谁”“发生了什么事件”,而是这段视频本身是否稳定、清晰、舒适:画面抖不抖、糊不糊、噪点多不多、比例是否适合目标终端播放。**传统视频处理**这一层,主要在帧序列和时空像素层面工作,通过增强、修复、超分辨率、插帧和重定帧等操作,把嘈杂、抖动、分辨率不足或比例不合适的原始视频,转换为更适合观看和后续分析的“高质量时序信号”。可以把它类比为图像模态中的“图像复原与增强 + 几何校正”,只不过这里额外引入了时间维度上的平滑与一致性。 + +从产品角度看,这一层能力几乎“隐身”在所有视频产品背后:剪辑软件的一键画质增强、短视频平台的自动画质升级、电视盒子和播放器的智能超分与插帧、老影片修复服务,以及给上游检测/识别模型做的多帧预处理,都是传统视频处理的直接体现。下面依然从 **场景** 、**原理**和**模型**三个角度来梳理,并在后续小节中展开视频增强与修复、超分与插帧几个关键方向。 + +- **场景** + 在线视频平台、剪辑工具、监控系统和终端设备中,传统视频处理主要出现在以下典型场景: + - 内容平台与剪辑工具:短视频、长视频在上传或编辑时,通过一键画质增强、稳像、防抖、降噪,让用户“拿起手机就能拍、拍完就能用”;老视频素材在导入剪辑工程时,通过修复和补帧,使其与新素材在观感上更一致。 + - 影视与老影片修复:对历史胶片、早期电视节目和标清素材进行数字修复,去除划痕、噪点和抖动,恢复色彩和细节,为重映、再发行和数字档案保存提供更高质量的版本。 + - 视频监控与行车记录:对弱光、雨雾、压缩严重的监控画面进行降噪、去雾、增强对比度和稳像,提升后续检测和识别模块的鲁棒性,便于取证和溯源。 + - 终端播放与设备侧增强:电视、机顶盒、手机播放器本地集成超分和插帧功能,将存量的 720p/1080p、24/30fps 内容在播放端“升级”为近似 4K、60/120fps 的视觉效果。 + - 多终端适配与分发:为同时覆盖手机竖屏、平板横屏和大屏电视,对同一视频进行横竖屏适配、智能裁剪和多比例重定帧,减少手工剪辑和多版本维护成本。 +- **原理** + 传统视频处理通常不直接理解语义类别,而是围绕画质、稳定性和时间一致性在时空信号层面做建模和优化: + - 时空联合建模:在单帧图像增强的基础上,引入时间维度的信息,通过光流估计、相机运动建模或时空卷积,把前后帧作为额外“观测”,在时间轴上做多帧融合与噪声抑制。 + - 稳像与防抖:将相机抖动建模为一段时间上的几何变换序列(平移、旋转、缩放等),通过估计全局或局部运动轨迹,将其平滑后重新投影到输出视频中,从而达到去抖和稳定的效果。 + - 视频超分与插帧:视频超分通过多帧对齐和细节重建,在提升空间分辨率的同时保持时间一致性;插帧则通过光流估计或时空生成网络,在两帧之间合成中间帧,用更高帧率呈现运动,提高流畅度。 + - 重定帧与自动构图:通过检测和追踪视频中的主体(人物、物体),在时间轴上估计主体轨迹,再结合目标分辨率的长宽比,为每一帧选择合适的裁剪窗口,并对裁剪窗口的运动进行时间平滑,保证观感自然。 + - 质量与效率权衡:在云端离线处理可以追求最优画质和复杂模型,而在手机、播放器和实时场景中则需要控制模型参数量、计算复杂度和延迟,在算法结构和推理框架上做精细折中。 +- **模型** + 在具体实现上,传统视频处理综合使用经典视频信号处理方法和深度学习模型,在效果、效率与部署形态之间寻找平衡: + - 经典视频处理方法:基于光流的稳像与插帧、时域滤波与多帧融合、基于块匹配的去噪和去压缩伪影等,仍然广泛应用于算力受限或对可解释性有要求的场景。 + - 深度视频复原与增强模型:以 EDVR、BasicVSR / BasicVSR++、Real‑ESRGAN 视频版等为代表的多帧超分与增强网络,通过对齐与时空特征聚合,在去噪、去模糊、细节恢复和去压缩伪影方面显著优于传统方法。 + - 深度插帧模型:如 DAIN、RIFE、FILM 等插帧网络,通过显式或隐式光流估计与中间特征融合生成中间帧,相比传统光流 + 重采样方法在复杂运动和遮挡场景中更稳定。 + - 基于 Transformer 的视频复原:利用时空注意力统一处理空间纹理与时间依赖,在复杂镜头运动、多物体场景下具备更强的建模能力,同时在推理时通过稀疏注意力、滑动窗口等机制控制计算量。 + - 实际产品与系统:剪映 / CapCut 的智能增强、Topaz Video Enhance 等商用增强软件,B 站及各短视频平台的画质增强管线、老影片修复 SaaS 服务等,通常会将多种模型与策略级联,按素材类型和终端条件动态选择最优处理路径。 + +综合来看,这一层更多是在“语义之前”为视频打好物理与感知基础:既帮助用户获得更舒适的观感,也为上游检测、识别和生成模型提供更干净、更稳定的输入。下面,我们分别从 **视频增强与修复** 、**超分辨率与插帧等**子方向展开。 + +### 5.1.1 视频增强与修复:把“能看”打磨到“好看” + +在真实拍摄条件下,视频往往并不“干净”:手持设备造成的剧烈抖动、弱光下的高噪点和涂抹感、网络压缩带来的块状伪影和色带、老旧设备录制的褪色和划痕,都让视频质量明显低于理想状态。视频增强与修复的目标,就是在不改变视频语义内容的前提下,最大程度恢复稳定、清晰、自然的观感,把“勉强能看”的素材打磨到“看起来顺眼甚至好看”的水准。 + +在时域上,增强与修复首先要解决的是稳定性问题。通过对连续帧进行特征匹配或光流估计,可以分离出全局相机运动和局部物体运动,再利用平滑后的相机轨迹重新渲染输出帧,从而抑制快速抖动与微小晃动,避免观众在观看过程中产生眩晕感。在此基础上,画面级的去噪、去模糊和去伪影则更多集中在空间–时间联合建模:多帧联合去噪利用前后帧冗余信息,在时间方向上进行类似“多曝光融合”的处理,在保留细节纹理的同时有效抑制高 ISO 噪声和压缩噪声;对轻微运动模糊,则通过估计模糊核或使用端到端深度网络,在帧序列上进行反卷积式的清晰化处理,使静态背景和运动主体都更锐利。 + +对于老影片和低质量素材,修复还涉及色彩和结构层面的“重建”。胶片老化会导致画面泛黄、对比度下降、局部划痕和污点显著,早期数字视频则常见分辨率低、压缩严重和边缘锯齿等问题。现代修复流程往往采用多步协同:先利用检测和分割模型定位划痕、污点等局部损坏区域,再通过时空补全网络在邻近帧和邻近空间像素中“借料填坑”;同时进行色彩还原和对比度重塑,使整体色调接近原始拍摄或设定的风格参考。对于严重压缩的视频,还会引入针对块效应和振铃伪影的专用去伪影网络,在不过度平滑的前提下改善边缘和细节。 + +这些增强与修复能力在产品中的体现往往是“一键式”的:用户只需勾选“稳像”“画质增强”或“老视频修复”,系统便会在后台自动选择合适的模型和参数组合,对视频帧序列做多阶段处理。对业务而言,这一层既直接决定了观众对画质的主观评价,也间接影响上游分析模型的表现:更干净、更稳定的视频输入,往往意味着更可靠的人脸/车牌识别、更准确的行为检测和更少的误报。 + +### 5.1.2 超分辨率与插帧:从“能看清”到“更流畅” + +在显示设备不断升级、用户对细节和流畅度要求不断提高的背景下,大量存量视频内容在分辨率和帧率上显得“先天不足”:1080p 在 4K 屏幕上显得不够锐利,24/30fps 在大屏和快速运动场景中容易出现拖影或卡顿感。超分辨率与插帧技术正是为了解决这两个问题:前者在空间维度上“补细节”,后者在时间维度上“补过程”,共同把“勉强能看清”的视频提升为“细节丰富、播放顺滑”的观感。 + +视频超分辨率相比单帧图像超分多了一个关键维度:时间。简单的逐帧放大容易导致相邻帧细节不一致,出现闪烁和纹理抖动。因此,主流方法都会利用前后多帧的信息,通过光流估计或特征级对齐,将邻近帧中的细节对齐到目标帧上,再在对齐后进行细节重建。像 EDVR、BasicVSR / BasicVSR++、Real‑ESRGAN 视频版等模型,会先在特征空间对多帧进行对齐和聚合,再用深度网络推断高分辨率细节,避免简单插值带来的“糊”和“塑料感”。在这一过程中,如何在“物理合理”和“感官好看”之间平衡,是损失设计和训练策略的核心:既要提升客观指标(如 PSNR、SSIM),也要保证主观观感自然,没有过度锐化和伪细节。 + +插帧则聚焦在时间轴上的“补帧”。传统方法依赖光流估计,先预测前后两帧之间每个像素的运动,再按照一定规则在中间位置插值生成新帧。然而在快速运动、多物体遮挡或纹理复杂区域,光流往往不够准确,容易出现拖影、重影或局部形变。深度插帧模型如 DAIN、RIFE、FILM 等,通过端到端网络同时学习光流、深度或中间特征的融合策略,直接输出插值帧,在复杂场景下的稳定性和视觉质量明显提升。对于体育赛事、动作游戏录屏和慢动作创作,插帧可以将 24/30fps 的原始视频平滑提升到 60/120fps,既保留运动细节,又减少卡顿和残影。 + +在工程实践中,超分和插帧常常结合使用:对低分辨率、低帧率的存量内容先做时序插帧,再进行空间超分,或两者在统一的时空网络中一体化实现。部署形态上,云端离线处理适合对画质要求极高的影视修复和平台级“画质升级”服务,而端侧实时推理则更多见于电视盒子、播放器 App 和游戏/运动相机中,需要通过模型压缩和硬件加速保证低延迟。无论以何种形态呈现,超分与插帧已经成为“高清/超高清体验”的重要基建,使旧内容在新终端上焕发“第二春”。 + +## 5.2 视频理解与结构分析(Video Understanding) + +如果说传统视频处理更多停留在“画质与稳定性”层面,那么**视频理解与结构分析**则开始回答“视频里在发生什么”这一类语义问题:谁在做什么、在哪里做、持续了多久、是否存在异常行为等。这里的目标,是在时间轴上对视频进行结构化拆解:识别动作与行为、检测与跟踪目标、分割前景与背景、划分场景与镜头,并抽取出可供下游决策、检索与告警使用的高层语义信号。 + +从产品视角看,这一层能力已经深入到各类智慧安防平台、运动训练分析系统、智能行车记录仪和工业质检视频分析系统中:在监控中识别打架、摔倒、徘徊等异常;在体育和健身场景中分析动作规范性和技术细节;在交通与工业环境下追踪车辆和人员轨迹、监控生产流程是否正常。下面依然从 **场景** 、**原理**和**模型**三个角度梳理这类能力,并在后续小节中重点展开几个代表性方向。 + +- **场景** + - 安防与公共安全:在城市监控、园区和楼宇中,识别打架、摔倒、聚集、奔跑、翻越围栏等行为,对徘徊、深夜逗留等异常模式提前告警。 + - 交通与出行:对行人、车辆、自行车在路口、隧道和高速上的轨迹进行检测和追踪,分析闯红灯、逆行、占道、超速等行为,为交管和事故溯源提供依据。 + - 体育与运动训练:分析篮球投篮、网球发球、瑜伽体式等动作的关键阶段与姿态质量,为运动员和大众用户提供技术分析和纠错建议。 + - 工业生产与质检:监控生产线上的作业步骤是否规范,检测装配过程中是否存在漏装、错装或异常动作,为安全生产和良率提升提供基础数据。 + - 内容结构化与检索:对长视频进行镜头拆分、场景分类和重要片段标记,为后续检索、推荐和剪辑提供结构化索引。 +- **原理** + 视频理解与结构分析的关键,是在时间维度上对空间目标和语义进行联合建模: + - 动作识别与行为分析:基于 2D/3D 卷积、时序池化或 Transformer,对一段视频片段进行整体编码,识别其中发生的动作类别;进阶方法结合人体关键点序列与骨架拓扑,更细粒度地分析动作质量与模式。 + - 目标检测与追踪:在每一帧上做检测的同时,引入跨帧关联机制(外观特征、运动轨迹等),将同一目标在不同时刻的检测框串联为连续轨迹,得到多目标跟踪结果。 + - 视频语义分割与场景分析:在像素级别上对视频中的每一帧进行语义分割或实例分割,并利用时间连续性平滑预测;同时对镜头切换和场景边界进行检测,实现长视频的结构拆解。 + - 高层事件与异常检测:在基础的动作与轨迹特征之上,利用时序建模和模式识别方法,对罕见事件和异常模式进行检测,往往结合无监督或弱监督学习缓解标注稀缺问题。 +- **模型** + 在模型选择上,视频理解与结构分析通常采用“空间特征 + 时间建模”的组合架构: + - 基于 3D 卷积和 Two‑Stream 的经典模型,如 I3D 等,通过在空间和时间维度同时卷积,对短视频片段进行端到端动作识别。 + - 基于多路径与多时间尺度的 SlowFast 系列模型,通过慢路径捕捉语义、快路径捕捉运动细节,在计算量和精度之间取得更好平衡。 + - 基于 Transformer 的视频模型,如 TimeSformer、Video Swin Transformer 等,利用时空注意力机制对长时间范围的视频进行建模,更适合捕捉复杂事件和多主体互动。 + - Tube‑based 检测器与时空卷积 / Transformer 模型,将检测框在时间上扩展为“tube”,在空间–时间联合特征上做行为检测与时空分割。 + - 多目标跟踪(MOT)方法,如 DeepSORT 等,将帧级检测结果与外观嵌入、运动预测结合,在视频中稳定关联目标身份。 + +整体上,这一层能力把视频从“高质量像素流”进一步抽象为“行为与事件流”,为上游的多模态理解、检索与决策奠定结构基础。下面,我们从 **动作识别与行为分析** 、 **目标检测与追踪** 、**事件与异常检测**三个方向展开。 + +### 5.2.1 动作识别与行为分析:从帧序列到“谁在做什么” + +动作识别与行为分析关注的是“在一段时间窗口内,主体在做什么事”。在安防场景中,这意味着从视频中识别出“走路、奔跑、摔倒、打架”等行为;在体育和健身中,则对应“投篮、发球、深蹲是否标准”“瑜伽体式是否到位”等更细粒度动作。技术上,早期方法主要依赖 2D 卷积 + 光流或手工特征,将若干帧堆叠后整体分类;现代方法则更多采用 3D 卷积(I3D、一系列 3D ResNet 变体)、SlowFast 这类多时间尺度结构,或 TimeSformer、Video Swin Transformer 等基于时空注意力的模型,对空间纹理与时间变化进行联合建模。 + +在许多需要高精度姿态分析的场景中,直接对 RGB 片段分类并不足够,还会结合人体姿态估计和骨架序列建模:先从每一帧中提取 2D/3D 关键点,再将关键点序列送入 RNN、时序卷积或 GCN/Transformer 网络,分析动作的时序结构和空间协调性。这种“姿态先验 + 时序建模”的方式,对背景、光照和服装变化更鲁棒,适合瑜伽、健身、工业操作规范性评估等对动作细节要求较高的应用。 + +### 5.2.2 目标检测与追踪:从“这一帧在哪”到“整段轨迹” + +单帧目标检测可以告诉我们“这一帧里有哪些目标、在哪儿”,而现实中的许多任务需要的是“这辆车 / 这个人从哪里来、到哪里去、中间做了什么”。目标检测与追踪模块正是为了把帧级检测串成时间上的连续轨迹:一方面在每一帧上运行检测器,给出候选目标框;另一方面基于外观特征(ReID 嵌入)、运动预测(卡尔曼滤波)和空间重叠等线索,将相邻帧上的框进行匹配与关联,得到多目标跟踪(MOT)结果。 + +在工程实践中,一个典型的流水线是:“强健的行人 / 车辆检测 + DeepSORT 一类的关联算法”,部署在监控或行车记录仪上,实时输出每个 ID 的运动轨迹。在更复杂的系统中,这些轨迹还会结合区域语义(车道、区域划分)与业务逻辑规则,进一步推断逆行、长时间逗留、频繁进出等高层行为模式,为上游安防、交通流量分析和工业流程监控提供连续时序信号。 + +### 5.2.3 事件与异常检测:从“常态模式”中找出“不对劲” + +在大部分业务场景中,真正需要重点关注的往往是“少数异常”和“关键事件”:例如安防中的打架、摔倒、聚集,工业生产中的异常停机或违规操作,交通中的危险驾驶行为等。这类事件相对罕见,标注成本高、样本极不平衡,给模型建构带来了额外挑战。 + +常见的做法,是在基础的动作识别、目标跟踪和场景分割之上,构建一个时序异常检测模块:要么通过有监督方式直接学习少量已标注的异常样本;要么采用无监督/弱监督方法,对“正常模式”的运动与行为分布进行建模,一旦新观测与历史分布明显偏离,就发出告警。在模型层面,会结合时序自编码器、对比学习、图神经网络或时序 Transformer,将空间关系和时间依赖统一编码,从而捕捉更复杂的群体行为模式和长程依赖。 + +## 5.3 视频 + 语言多模态任务(Video‑Language) + +如果说视频理解解决的是“视频本身理解清楚了”,那么**视频 + 语言多模态任务**关注的是“如何用自然语言去描述、问答、检索视频内容”,以及“如何在长视频时间轴上,围绕文本需求快速定位关键信息”。这类任务需要同时处理视觉、语音与文本信号:一方面提取视频中的画面与声音特征,另一方面对接语言模型的推理与生成能力,把时空内容压缩成适合人类消费和机器调用的文本摘要、问答结果与语义索引。 + +从产品视角看,这一层能力已经深入长视频自动生成字幕与时间轴、短视频剪辑平台的“智能打点 / 关键片段抽取”、企业培训和会议视频的问答助手等场景:用户不必再“从头看到尾”,而是可以通过自然语言直接对视频内容进行检索、提问和重组。下面依然从 **场景** 、**原理**和**模型**三个角度展开。 + +- **场景** + - 字幕与摘要生成:对课程、演讲、会议和长视频内容自动生成多语言字幕,并在此基础上生成章节级摘要、看点列表与时间轴。 + - 视频问答与知识访问:对教学视频、操作演示、企业培训内容构建“视频问答助手”,支持用户用自然语言提问,如“这个步骤怎么做”“这个人最后把手机放哪了”。 + - 视频内容检索与片段定位:在大规模视频库中支持“文字 → 视频片段”的精确检索,例如“找出提到价格的部分”“找到讲解某个公式的片段”;在单个长视频内自动打点标注精彩片段与关键信息。 + - 内容生产与编辑辅助:结合视频内容理解与语言生成功能,自动生成标题、文案、分镜脚本,辅助创作者快速剪辑和重组素材。 +- **原理** + 视频–语言多模态系统的核心,是在统一嵌入空间中对齐时序视觉特征与文本表示,并在这一基础上进行检索、生成与推理: + - 多模态特征抽取与对齐:对视频帧/片段提取时空特征(CNN/ViT/Video Transformer),对文本提取语言嵌入(预训练 LLM 或文本编码器),通过对比学习或多模态预训练对齐两种模态。 + - 语音与文本管线:对包含语音的内容,通常先用 ASR 生成时间戳对齐的转写文本,再与视觉特征联合建模,既可以用文本直接驱动检索,也可以做跨模态对照与纠错。 + - 时间建模与片段定位:对于长视频,需要在时间轴上学习“片段级”表示,通过注意力或时序 RAG 在局部片段和全局上下文之间动态切换,实现对问题相关区间的精确定位。 + - 生成与推理:在对齐后的多模态表示上接入大语言模型,进行自然语言生成(字幕、摘要、解释),或进行多轮问答与逻辑推理。 +- **模型** + 在模型形态上,视频–语言多模态任务经历了从“专用编码器 + 简单头”到“统一多模态大模型”的演进: + - 早期视频–语言模型:如 VideoBERT 等,在预训练阶段联合建模视觉与文本 token,通过掩码预测和对比学习获得可迁移的视频–语言表征。 + - All‑in‑One Video‑Language Models:将视频、文本(及语音)统一纳入一个多模态 Transformer 中,通过共享或部分共享参数,实现描述生成、检索、QA 等多任务统一处理。 + - 长视频多模态模型:如具备视频能力的 Gemini、Claude、GPT 等,通过长上下文与分层时序建模,对数十分钟乃至数小时视频进行整体理解,支持时间轴级别的摘要与问答。 + - 时序 RAG + VLM:在视频上构建“时序向量索引”,先用 VLM 对视频片段进行编码建立数据库,再在查询时检索相关片段,结合 LLM 进行答案综合与可解释推理。 + +总体来看,这一层将视频从“机器理解”进一步提升到“人机对话与协作”层面:用户可以像问人一样向视频提问,系统则在背后完成复杂的视觉、语音与语言对齐与推理。 + +### 5.3.1 字幕、摘要与时间轴:把长视频压缩成可浏览文本 + +对于课程、讲座、会议和长内容视频,最迫切的需求往往是“快速知道讲了什么、哪里是重点”,而不是从头到尾完整观看。自动字幕与摘要系统通过“ASR + 文本处理 + 视觉辅助”的组合,将音频内容转写为时间戳对齐的文本,再在此基础上生成结构化大纲与精简摘要,实现从“小时级视频”到“分钟级阅读”的信息压缩。 + +在实现层面,ASR 模块负责稳定、高质量地给出多语言转写和时间轴对齐;文本侧则利用大语言模型对原始转写进行纠错、分句和语义重整,提取章节标题、关键信息和问题–答案对。在一些场景中,还会结合视觉线索(如 PPT 页面变化、场景切换)来辅助划分章节边界与重点片段,保证摘要结构与真实内容节奏更加一致。 + +### 5.3.2 视频问答与语义检索:用自然语言“操纵”视频 + +在字幕与摘要之上,更进一步的需求是能够针对特定视频内容进行问答和检索:例如“这个人最后把手机放在哪里”“哪一段讲到了价格策略”“演示这个步骤的是第几分钟”。这类任务需要在时间轴上对问题进行语义定位:既要理解问题本身涉及的人物、物体和动作,也要在视频时序表示中找到对应的片段。 + +具体做法上,通常会先离线为视频构建多粒度索引:对固定长度的片段提取多模态表示(画面 + 文本/语音),建立向量索引或图结构。在在线交互时,将用户问题编码为文本向量,与索引中的片段表征进行匹配,找出最相关的时间区间;随后,将这些片段的内容(关键帧截图描述、转写文本等)与问题一起送入 LLM,由模型生成自然语言答案或返回对应时间点。对于大规模视频库,可以在相同机制下支持“跨视频检索”,例如在企业培训知识库或电商商品视频中跨集合查找相关片段。 + +### 5.3.3 多模态编辑辅助:从理解到“帮你剪好” + +当系统能够稳定地理解视频中的内容和语义结构后,自然的下一步就是反向利用这些理解结果来辅助创作与编辑。视频–语言多模态模型可以根据创作者提供的脚本或提示词,在现有素材中自动选取符合语义的片段,生成粗剪时间线;也可以根据视频内容自动生成标题、封面文案、章节标签,甚至对镜头节奏和配乐提出建议。 + +在工作流中,这类能力通常以“智能推荐”和“自动粗剪”的形式出现:创作者上传素材后,系统自动完成分析、分镜、打点,并给出若干候选版本(如不同节奏、不同时长的剪辑方案);创作者可以在此基础上微调,而无需从零开始逐帧筛选。对于企业级应用,系统还可以结合知识库和品牌规范,确保生成的文案、字幕和剪辑风格符合既定的业务要求和合规标准。 + +## 5.4 视频生成与编辑(Video Generation & Editing) + +在拥有了稳定的理解和结构分析能力之后,**视频生成与编辑**则迈向了“主动创造内容”的阶段:不再只是提升画质或做结构化分析,而是根据文本脚本、参考图像或已有视频,生成全新的镜头,或对原始视频进行结构化编辑与重组。这里既包括从无到有的文生视频(Text‑to‑Video),也包括基于已有图像/视频的风格迁移、扩展与重排,以及面向对象级别的精细编辑与替换。 + +产品上,这一层能力已经通过即梦视频、 minimax 视频、Sora、Runway Gen‑2、Pika、Kling 等一系列产品进入内容创作主流:广告片、概念片、动画、剧情分镜可以在不依赖大型拍摄团队和复杂后期的情况下快速生成;创作者可以通过自然语言脚本驱动镜头和风格;传统的视频剪辑流程则开始与结构化生成工具深度融合。下面依然从 **场景** 、**原理**和**模型**的角度进行梳理。 + +- **场景** + - 文案、剧本到短视频:品牌广告、小剧场、剧情片段和概念动画,根据脚本自动生成或半自动生成可播放的视频草稿。 + - 图像 / 视频到视频:为插画或角色设计生成动态版本,为现实拍摄素材进行风格迁移(现实 → 动漫 / 插画),或在时间与空间上扩展/重组已有视频。 + - 结构化编辑与后期:在不改变整体内容语义的前提下,实现人物换脸、口型同步、对象擦除与替换、文本驱动的剪辑重排等精细操作。 +- **原理** + 当前主流视频生成与编辑方法多以扩散模型(Diffusion)或其变体为核心,在高维的时空潜空间中逐步“去噪”生成视频: + - 文本条件建模:通过文本编码器(如 T5/CLIP 文本塔或专用语言模型)将脚本映射为条件向量,引导视频解码器在风格、内容和运动模式上对齐文本描述。 + - 时空一致性与运动控制:在扩散过程或后验优化中加入时空卷积、时序注意力或 4D 表达(NeRF/GS 等),保证视频在时间轴上的连贯性与物理合理性。 + - 图 / 视频条件生成:在输入图像或视频的特征空间上启动扩散过程,通过控制噪声注入、遮罩区域和条件通道,实现“保留已给部分 + 生成新内容”的受控编辑或扩展。 + - 结构化控制信号:结合姿态骨架、分割掩膜、深度图、相机轨迹等结构信息,使生成视频在主体动作和视角变化上更可控。 +- **模型** + 代表性的模型与方向包括: + - Diffusion‑based Text‑to‑Video 模型(Sora、Runway Gen‑2、Pika、Kling 等),通过大规模视频–文本对进行预训练,在复杂场景、多镜头运动和多样风格上具备较强生成能力。 + - Image‑to‑Video 扩散模型:以单帧图像为条件,预测后续帧的动态演化,实现“单图 → 动画 / 动效”;或对短视频进行续写、扩展、旋转视角等操作。 + - NeRF / 4D 表达与关键帧 + 插值方法:利用 3D 场景表示或关键帧 + 时序插值,将生成与几何、一致性建模结合,实现更稳定的视角漫游与复杂运动。 + +这些能力并非孤立存在,而是逐步渗入剪辑与后期流水线:文案到分镜、分镜到粗剪、粗剪到风格化与局部编辑,越来越多环节被“文本 + 结构化控制”所驱动。 + +### 5.4.1 文生视频:从脚本到“可看”的镜头序列 + +文生视频(Text‑to‑Video)希望实现的是:用户用自然语言描述一个场景、镜头或故事片段,系统自动生成一段连贯的视频。与图像生成相比,文生视频增加了时间维度的难题:不仅要在单帧层面保持画面质量和风格一致,还要保证跨帧的主体身份、光照、背景和运动轨迹的连贯性。 + +典型的扩散式文生视频模型会先在大规模视频–文本配对数据上预训练:文本编码器提取语义条件,视频解码器在潜空间中对一段“噪声视频”反复去噪,逐渐收敛到与文本一致的时空信号。在此过程中,会通过时序注意力、3D 卷积或 4D 表达等结构,将时间依赖显式建入网络,以避免出现“帧间跳变”“角色重置”等问题。部分系统还支持对镜头运动(推拉摇移)和构图节奏进行控制,使生成结果更接近真实拍摄语言。 + +### 5.4.2 图 / 视频到视频:在已有内容上“生长”与“变形” + +另一条重要路线是基于已有图像或视频进行生成与编辑:例如,将一张插画或概念设定图“动起来”,将真人视频风格化为动漫,或在保持结构不变的前提下更换背景、调整天气和时间。技术上,这类方法往往在扩散过程上增加“参考通道”:将输入图像或视频编码为特征,作为条件或初始状态参与去噪,同时通过遮罩、显式几何约束等机制控制“哪些区域可以被改变、哪些必须保持”。 + +对于风格迁移场景,模型会在保留原始运动和构图的前提下,重绘纹理和光影,使其匹配目标风格;对于视频扩展与重组,则通过在时间两端或中间“续写”新帧,实现水平/垂直场景扩展、视角绕行或情节补充。这类能力非常适合与传统剪辑流程结合:剪辑师先给出关键镜头和节奏,模型再在这些“锚点”之间自动生成过渡和变体。 + +### 5.4.3 结构化视频编辑:对象级的精细控制 + +在许多业务场景中,完全重生视频并非刚需,更关键的是对已有画面进行精细、可控的结构化编辑:比如换脸、改口型、擦除不需要的物体、替换广告位内容,或者根据文本脚本重排镜头顺序。结构化视频编辑正是沿着这一思路发展:在视频理解的基础上,引入对象级分割、跟踪和参数化表示,使编辑操作可以稳定绑定到特定目标和时间段。 + +人物换脸和口型同步(Lip‑sync)是这一方向中最典型的应用:模型需要在保证头部姿态与整体表情自然连贯的前提下,将目标人物的身份映射到原视频的表演上,并根据新语音信号精确控制口型运动。对象擦除 / 替换则依赖高质量的分割和时空补全:先在每一帧中分割并移除目标对象,再利用邻近帧与上下文纹理填补空洞,避免出现明显“打补丁”的痕迹。文本驱动剪辑则通过将“脚本结构”与视频时间轴对齐,自动选取和拼接符合脚本语义的片段,实现更高层的自动化编辑。 + +## 5.5 数字人 / 虚拟人(Digital Human / Avatar) + +**数字人 / 虚拟人(Digital Human / Avatar)** 可以看作是视频生成、语音合成、多模态理解和图形渲染的一次“系统级整合”:它不只是生成一段视频,而是基于文本或语音输入,持续、可控地驱动一个虚拟形象“开口说话、做表情、摆动作”,并在越来越多场景下实现准实时甚至实时的交互。相比一般的视频生成,数字人更强调三点: **身份与形象的长期一致性、语音—表情—动作的精细对齐、以及端到端系统的实时性与稳定性** 。 + +从产品视角看,数字人已经广泛出现在**内容生产平台、虚拟客服 / 智能前台 / 虚拟导览、教育培训与在线课堂、品牌虚拟 IP / 虚拟偶像、为创作者提供的虚拟主播 / 数字分身工具**等场景:企业可以批量生产带有固定形象和风格的视频内容,政府和企业服务可以用虚拟前台 7×24 小时接待用户,个人创作者可以完全不露脸但持续产出“有人出镜”的视频。下面依然从 **场景** 、**原理**和**模型**三个维度来梳理,并在后续小节展开驱动与表达、形象与视频生成、实时交互与系统集成三个方向。 + +- **场景** + - 内容生产与在线传播:企业宣传片、产品功能讲解、课程录制、新闻播报,使用数字人替代真人上镜,大量减少拍摄场地、灯光设备和人力成本。 + - 虚拟客服与导览:在银行网点、政务大厅、景区、博物馆等场所,用数字人承担迎宾、问询、业务咨询和路线指引,兼顾形象统一与 7×24 小时服务。 + - 品牌虚拟 IP / 虚拟偶像:围绕某一虚拟形象长期运营短视频、直播、电商内容,在不同平台上保持统一人设和视觉风格。 + - 虚拟主播与数字分身:为不愿出镜或需要多身份运营的创作者,提供可配置的虚拟主播 / 数字分身,与真实声音或合成声音绑定,实现“只用说话 / 打字,就能稳定出镜”。 +- **原理** + 数字人系统本质上是一个“语音 / 文本驱动 + 形象建模 + 视频 / 渲染输出”的多模态流水线,在离线与实时场景下略有差异,但核心组件相似: + - 语音与语言驱动:根据脚本直接用 TTS 合成语音,或接入 ASR + LLM,从用户语音 / 文本中生成回复文本,再用 TTS 输出语音;语音特征(如 mel 频谱)作为驱动信号控制嘴型与表情时间轴。 + - 形象与动作空间建模:为虚拟形象构建可控的几何与外观表示,例如 2D 人像 / 插画、基于骨骼和 Blendshape 的 3D Avatar、或基于 NeRF / 4D 高斯的可渲染体积表示;并定义一组“驱动参数”(如关键点、姿态骨架、Blendshape 系数),用来编码表情与姿态。 + - 语音 → 表情 / 动作映射:通过专门的“语音驱动”模型,将语音特征映射为人脸和上半身的驱动参数,实现口型同步(Lip‑sync)、表情细节和头肩动作;实时数字人会要求这一映射端到端低延迟且稳定。 + - 渲染与合成:根据当前帧驱动参数,对虚拟形象进行图像或 3D 渲染,输出连续视频流或实时画面;可叠加背景、道具、字幕等元素,与传统视频剪辑流程结合。 +- **模型** + 在具体模型上,数字人系统往往综合使用多类专用模型与通用多模态模型: + - Audio‑driven Talking Head 模型:如 Wav2Lip 一类的口型同步模型,通过学习语音与口腔区域像素 / 几何之间的对齐关系,在保证身份一致的前提下生成自然的嘴部运动。 + - 实时 / 轻量级数字人模型:如 Ultralight‑Digital‑Human、轻量级 Talking Head 模型等,在结构上大幅压缩参数与计算量,使得在 CPU / 移动端 / WebGPU 上也能实现接近实时的驱动与渲染。 + - NeRF / 4D 表达模型:如 ER‑NeRF(Explicit / Efficient / Editable 方向的数字人 NeRF 方案)等,通过在 3D 空间中建模人物形象与表情变化,使视角、光照和动作更自然连贯,适合高保真和多机位场景。 + - 语音驱动与多模态对齐模型:如 MuseTalk 一类“语音 → 面部表情 / 说话头”模型,将音频特征和视觉特征对齐,在不依赖大量 3D 标注的情况下实现逼真的讲话表情与头部动作。 + - 语音与对话模型:高自然度多说话人 TTS、端到端语音对话模型(ASR + LLM + TTS 一体化),为数字人提供多风格、多语种的声音和对话能力。 + +综合来看,数字人既是一组模型,也是一套完整系统:它将语言理解、语音、视觉生成与实时推理整合起来,从而在“屏幕前”呈现出一个可交互的虚拟角色。下面,我们从 **驱动与表达** 、**形象与视频生成**和**实时交互与系统集成**三个方向展开。 + +### 5.5.1 驱动与表达:从脚本 / 语音到“会说话、会表情”的人 + +在数字人流水线中,**驱动与表达**负责回答一个核心问题:在给定脚本或语音的前提下,虚拟形象在每一帧应该呈现什么样的嘴型、表情和头肩动作。这里既包括离线批量生产的场景,也包括对实时对话的响应。 + +在离线内容生产中,常见链路是“文本脚本 → TTS → 语音驱动”:业务侧提供播报文案,TTS 模块生成目标音色(如品牌虚拟代言人)的语音,再将语音特征输入到“语音 → 动作”模型。**Wav2Lip 类模型**就是这一环节的重要代表: + +- 它以参考人像帧和对应语音片段为输入,通过一个卷积 / 注意力网络预测出与语音精细对齐的嘴部区域,再与原始人像进行融合,从而在保持身份和大部分表情不变的前提下,精确修改嘴型。 +- 训练时,通过语音–视频对齐数据监督网络学会不同音素对应的口腔形态,并在时间上保持连续性,避免嘴型跳变或延迟感。 + +相比早期纯口型同步方案,新一代的语音驱动模型(如 MuseTalk 一类的方法)进一步扩展到了 **全脸表情和头部姿态** : + +- 这类模型通常将语音特征映射到一个低维的“情绪 / 表达潜空间”,再通过解码器生成关键点、Blendshape 系数或直接生成图像特征,带动眉毛、眼睛、颊部等区域的细微变化,使“说话表情”更生动。 +- 有的模型还会将语音内容的语义信息(如疑问、强调、感叹)编码进去,结合 LLM 分析的句法 / 语用信号,在语调变化处增加点头、皱眉、手势等动作,提升表达的自然度和感染力。 + +在更高维度上,**驱动与表达**也可以结合外部控制信号:例如将姿态骨架、手势轨迹、视线方向等作为附加输入,使数字人可以模仿特定演讲者的风格,或根据脚本中的“指示动作”(如“指向屏幕”“双手张开”)执行预定义的动作模板。无论是 Wav2Lip 这样的局部口型驱动,还是 MuseTalk / 实时骨架驱动等更全身的表达建模,它们共同实现了从语音 / 文本到面部与上半身动作的连续映射,是数字人“看起来像在认真说话”的关键一环。 + +### 5.5.2 形象与视频生成:从“一个模型”到“一个可塑的角色” + +驱动链路解决了“怎么动”,而**形象与视频生成**则决定了“谁在动、在哪里动、以什么风格动”。这里既包含高保真写实数字人,也包含二次元、卡通和低多边形 Avatar 等风格化形象,以及面向实时和离线渲染的不同技术选型。 + +在 2D 人像与插画场景中,典型做法是基于少量参考图像和短视频训练一个 **Talking Head 生成模型** : + +- 模型将人物的身份信息编码为一个“外观向量”或风格特征,将驱动参数(如语音隐向量、关键点、表情编码)作为条件输入,在图像空间中合成新的帧。 +- 与纯 Wav2Lip 只改口型不同,这类模型可以在姿态上做小幅度摆动、在表情上叠加情绪变化,从而让数字人看起来不那么“僵硬”。 + +在追求更高真实感、更自由视角和多机位切换的场景中,越来越多方案采用基于 **NeRF / 4D 表达**的数字人建模(如 ER‑NeRF 一类方法): + +- 通过多视角拍摄或视频,先重建人物头部 / 上半身的 3D 体积或高斯场,将不同表情和嘴型对应的状态编码为可插值的隐空间; +- 驱动时,将语音 / 表情参数映射到这一隐空间,在 3D 中进行体积渲染或高斯渲染,再投影到屏幕上。 +- 这种做法的优势在于:视角、光照和背景更自然,可以支持“环绕视角”“虚拟摄影机”运动,对 VR/AR、虚拟直播间和高端广告制作尤为友好。 + +在强调跨端部署与实时性的业务中,还会采用 **Ultralight‑Digital‑Human** 这类轻量化方案: + +- 通过结构剪枝、算子重构和模型蒸馏,将 Talking Head 或 Avatar 渲染网络压缩到移动端 / WebGPU 也能运行的规模; +- 在几毫秒级别完成从驱动参数到一帧图像的生成,与实时语音流或控制信号对齐,实现“低延迟数字人”,适合互动终端、自助机和 Web 前端应用。 + +在完整视频生产层面,形象与视频生成还要与背景、道具和镜头语言结合:一个常见的工作流是: + +- 先为品牌或个人定制一个数字人形象(2D 或 3D); +- 预设若干虚拟场景(演播厅、办公室、教室、展厅等); +- 在生产内容时,系统根据脚本自动选择合适场景和机位,生成数字人画面,并与 PPT、演示视频、产品画面进行多画面编排。 + 这使得数字人不只是一个“说话头”,而是可以自然融入各种节目和内容形态的“角色”。 + +### 5.5.3 实时数字人与系统集成:从离线视频到“屏幕里的同事” + +随着 ASR、TTS、LLM 和轻量级视频生成模型的成熟,越来越多数字人系统开始从**离线批量出片**走向 **实时交互** :用户在终端开口说话或输入文本,屏幕上的数字人在几百毫秒到几秒内“听懂—思考—回应—开口说话”,形成类似真人客服 / 导览 / 主持的体验。这里的关键不只是模型本身,还包括如何把多模态链路 **压缩到可接受的端到端延迟** 。 + +在一个典型的实时数字人闭环中: + +- **前端输入** :ASR 模块将用户语音实时转为文本,或直接接收用户文本输入。 +- **语义理解与决策** :LLM 结合业务知识库和工具(RAG、数据库查询、流程编排)生成回复文本,以及必要的结构化指令(如需要展示哪一页 PPT、播放哪个视频片段)。 +- **语音与驱动** :TTS 将回复文本转换为目标音色的语音,语音流一边生成、一边被 Wav2Lip / MuseTalk / 实时骨架驱动模型消费,逐段输出对应的口型与表情参数。 +- **渲染输出** :Ultralight‑Digital‑Human 类型的轻量渲染网络或基于 GPU 的 NeRF / Avatar 渲染引擎,将驱动参数实时转换成视频帧,通过 WebRTC、RTMP 或本地渲染直接输出到屏幕。 + +为了在多终端上提供一致体验,系统还需要在**延迟、带宽与算力**之间做细致权衡: + +- 在云端渲染方案中,绝大部分计算(LLM、TTS、驱动与渲染)在服务器完成,终端只负责播放视频流,适合算力有限的 Web / App 和线下大屏,但对网络稳定性有依赖; +- 在“云 + 端混合”方案中,ASR 和部分 LLM 推理在云端完成,轻量化驱动与渲染在本地进行,可以显著降低音画交互延迟,适合移动设备与自助终端; +- 在强算力终端(如高性能 PC、专用工作站)上,还可以将大部分链路下沉本地,实现弱网环境下的稳定互动。 + +在模型侧,**实时数字人**也对结构设计提出了额外要求: + +- 语音驱动模型需要具备流式推理能力,能够在获得一小段语音后就给出口型与表情预测,而不是等整句结束; +- 渲染网络需要尽可能减少依赖大卷积核和全局注意力,采用局部卷积、轻量自注意力、分辨率金字塔等结构控制计算量; +- 对于基于 NeRF / 4D 的高保真方案,则需要通过网格缓存、视锥裁剪、稀疏体积和 GPU 优化等手段,把每帧渲染控制在几毫秒到几十毫秒内。 + +在系统集成层面,实时数字人往往还要与**业务知识、人格设定与对话策略**紧密绑定: + +- 通过知识库和 RAG 管理行业知识、业务流程和 FAQ,确保“说得对、说得全”; +- 通过人设配置和话术模板控制说话风格和表达边界,确保“说得像这个人(或这个品牌)”; +- 通过多轮对话策略与会话状态管理,使数字人可以记住用户上下文、在合适时机确认和追问,呈现出“像一个真正的同事 / 导游 / 讲师”的交互感。 + +总体而言,加入了 Wav2Lip、MuseTalk、ER‑NeRF、Ultralight‑Digital‑Human 等专门为口型同步、表情驱动与实时渲染设计的模型之后,数字人正从“离线视频模板工具”加速演化为 **可实时响应、有稳定人格和专业知识的虚拟实体** ,成为视频技术体系中最具综合性和应用张力的一环。 + +# 6. 时间序列与时序决策(Time Series & Sequential Decision) + +在前面的视觉和结构化建模中,我们更多是在“静态”空间下思考问题:一张图、一条记录、一段文本。而在真实业务中,极大一部分核心指标都是随时间演化的:销售量和流量每天在波动,服务器负载和传感器读数每秒在变化,金融价格与宏观指标则在政策和事件驱动下不断调整。**时间序列与时序决策**这层,关注的就是:在时间轴上预测未来、识别异常、刻画结构突变,并在此基础上做出有前瞻性的决策与控制。 + +从产品视角看,这类能力贯穿运营、规划、风控和调度等关键环节:传统 BI / 报表系统中嵌入的指标预测模块、财务与供应链规划工具中的需求预测和安全库存建议、量化研究分析软件中的宏观关联分析和因果关系挖掘、电商和出行平台上的流量与运力预测、运维 AIOps 中的指标异常检测与告警,都是这一层的典型落地形态。下面我们从 **经典统计方法** 、 **深度学习时间序列建模** 、**异常与变点检测**以及**时空序列建模**四个方向展开。 + +## 6.1 经典时间序列建模(Statistical TS Modeling) + +在很多业务里,“时间”是天然的主线:销售量按日/周变化、网站流量随活动波动、设备负载跟着用户行为起伏、传感器读数反映着系统状态的细微变化。**经典统计时间序列建模**就是在这种时序结构上,利用相对可解释、可分析的统计模型去回答三个核心问题:**未来会怎样?变量之间如何关联?系统当前所处的状态是什么?** 尽管深度学习已经在许多场景中崭露头角,但 ARIMA、协整分析、卡尔曼滤波等传统方法,仍然在金融、供应链、运营、风控等领域长期服役,并常常作为更复杂系统的“基线”和解释工具。 + +从应用视角看,经典时间序列模型广泛存在于传统 BI/报表系统的指标预测模块、财务与供应链规划工具、以及各类量化研究软件中。它们可以直接对单个或多个时间序列给出未来预测区间,也可以用来分析宏观指标之间的协同变化与长期均衡关系,并通过状态空间建模对轨迹和隐藏状态进行估计。下面,我们从 **场景** 、**原理**和**模型**三个维度来梳理这类方法的典型用法,再分别展开具体方向。 + +- **场景** + - 指标预测:对销售量、网站流量、CPU 负载、传感器读数等按时间变化的数值进行短期或中期预测,用于库存备货、产能安排、运维调度等决策。 + - 宏观经济与金融分析:研究 GDP、通胀率、利率、汇率、资产价格等宏观和市场指标之间的长期关联和短期动态,辅助政策研究与量化策略开发。 + - 过程与轨迹估计:在定位、导航、目标跟踪和设备监控中,对随时间变化的轨迹、速度、状态进行估计与平滑,并在噪声环境中尽可能还原“真实过程”。 +- **原理** + 经典时间序列方法普遍基于“ **统计假设 + 参数化结构** ”的思路: + - 假定时间序列满足一定的平稳性或弱平稳性条件,通过自相关结构(自相关函数 ACF、偏自相关函数 PACF)刻画“当前值由过去多少阶的历史决定”。 + - 在多变量情形中,通过协整与向量自回归(VAR)模型,刻画多个时间序列之间的长期均衡关系与短期偏离修正。 + - 对于噪声严重、状态不可直接观测的系统,引入隐含状态(latent state)与观测方程组成状态空间模型,用贝叶斯推断或递推滤波(如卡尔曼滤波)进行在线估计与预测。 +- **模型** + 这类方法的模型族相对明确、结构清晰,便于解释和调参: + - 单变量与多变量 AR/MA/ARIMA/SARIMA 系列,用于平稳/季节性时间序列建模,是 BI 系统和传统预测模块的“常驻成员”。 + - VAR/协整模型,用于多维宏观和金融时间序列的联合建模和因果关系检验,适合政策和策略层面的关联分析。 + - 状态空间模型与卡尔曼滤波、隐马尔可夫模型(HMM)等,用于轨迹估计、设备状态估计以及隐藏状态的推断,是工程控制与信号处理中的基础工具。 + +综合来看,经典时间序列建模的优势在于 **可解释性、可诊断性和工程可控性** :建模流程、假设检验、残差分析都有成熟规范,很容易融入现有 BI 与规划系统。下面,我们从单/多变量预测、协整与因果、状态空间三个方向展开。 + +### 6.1.1 单变量/多变量时间序列预测:从 ARIMA 到 VAR + +在最典型的业务场景中,我们首先面对的是一条或若干条按时间排序的指标曲线:例如某商品每日销量、站点每小时 PV、机房每分钟 CPU 使用率、设备传感器每秒读数。目标是根据历史走势对未来的短期或中期区间给出预测,并给出合理的置信区间。**AR/MA/ARMA/ARIMA/SARIMA** 系列模型正是为此设计的标准工具。 + +对单变量序列来说,ARIMA 类模型假设“当前值由过去若干期的历史值和随机扰动线性决定”,通过对序列做差分、季节差分来消除趋势和季节性,使其趋于平稳: + +- AR(自回归)部分刻画“自身滞后对当前值的影响”; +- MA(滑动平均)部分捕捉“历史误差项对当前值的影响”; +- I(差分)部分负责去除趋势; +- 加上季节项后得到 SARIMA,可以显式描述周度、月度等周期性结构。 + +在工程使用中,通常会先做平稳性检验(如 ADF)、观察 ACF/PACF 图,再通过信息准则(AIC/BIC)和残差诊断选取合理的阶数。对于具有明显季节性的指标(如电商日销量、节假日流量)尤其适合 SARIMA 建模,配合假日特征或外生变量可以进一步改善预测性能。 + +当我们希望一次性建模多条相关时间序列时,可以引入 **多变量时间序列模型** 。代表方法是 VAR(向量自回归)与其变体。VAR 将多个序列视为一个联合向量,用自身及彼此的滞后项共同解释当前值,从而捕捉不同指标之间的相互影响。例如,在宏观经济分析中,可以将 GDP 增速、通胀率、利率、汇率等纳入同一个 VAR 模型,研究冲击响应和传导路径;在业务运营中,也可以用 VAR 描述“一个渠道的流量变化如何影响其他渠道”“促销强度与销量之间的动态关系”,为资源调配提供参考。 + +在产品化形态上,这一类单/多变量预测能力通常嵌入在**传统 BI / 报表系统的预测功能、财务与供应链规划工具**中:用户选定某条或若干条时间序列,系统自动完成建模与预测,并提供预测区间、残差分析和模型诊断报告,用于辅助决策,而不必深入理解决策背后的所有数学细节。 + +### 6.1.2 协整与因果关系:宏观指标之间的长期均衡 + +在经济与金融领域,很多时间序列表面看似随机游走,但在更长的时间尺度上存在某种 **稳定的长期均衡关系** 。典型例子包括汇率与利差、股指与宏观盈利、商品价格与成本指数等。单独看每条序列,可能都是非平稳的;但某种线性组合却在长期内围绕一个稳定水平波动。这种现象被称为 **协整(cointegration)** ,它为我们理解宏观指标之间的结构性关系提供了重要线索。 + +在工程实践中,协整分析通常包括几个步骤: + +1. 对各个时间序列进行单位根检验,确认其为同阶单整(例如都为 I(1)); +2. 进行协整检验(如 Engle-Granger 两步法、Johansen 检验等),判断是否存在非平凡的线性组合使得该组合平稳; +3. 若发现协整关系,可以构建误差修正模型(ECM),刻画“短期偏离长期均衡时,系统如何逐步修正回到平衡状态”。 + +与协整相关的,是 **Granger 因果关系检验** 。它并不是严格意义上的哲学“因果”,而是一种基于预测能力的统计定义:如果变量 X 的历史信息可以显著提高对变量 Y 的预测精度,则称“X Granger 导致 Y”。通过在 VAR 或回归框架下比较有/无某个变量滞后项时的预测误差,可以评估不同宏观或市场指标之间的方向性影响。在量化研究和宏观分析中,这种检验常用于甄别潜在的领先指标、构建因子、或者验证策略假说。 + +从产品视角看,协整与因果分析更多出现在**量化研究分析软件、宏观经济分析平台和金融研究工具**中。它们帮助研究者从成堆的时间序列中抽取出相对稳健的结构关系,并将这些关系映射到更高层次的业务概念(如“利率对汇率的长期约束”“不同资产之间的价差回归”),成为策略设计与风险管理的重要依据。 + +### 6.1.3 状态空间模型与隐状态估计:卡尔曼滤波与 HMM + +在许多真实系统中,我们观测到的时间序列只是 **噪声污染后的表象** ,而真正感兴趣的是背后随时间演化的“系统状态”:例如车辆的真实位置和速度、设备的健康状态、用户的潜在行为模式等。此时,如果仍然只在观测序列上做 ARIMA 式建模,就很难充分利用对系统结构的理解。**状态空间模型(State Space Models)**正是为这种“隐状态 + 噪声观测”的问题而提出。 + +状态空间模型通常由两部分构成: + +- 状态转移方程:描述隐藏状态如何随时间演化,可以是线性的也可以是非线性的; +- 观测方程:描述隐藏状态如何生成带噪声的观测值。 + +在线性高斯假设下,这个框架可以通过**卡尔曼滤波(Kalman Filter)和平滑器(Smoother)** 实现对状态的递推估计与预测:每一步分为“预测”和“更新”两大阶段,将上一时刻的状态分布与当前观测结合,得到新的状态估计。这在导航与定位(如轨迹估计、目标跟踪)、金融时间序列(如波动率估计)、设备状态估计(如健康监控、剩余寿命预测)中极其常见。 + +与连续状态空间模型相邻的,是 **隐马尔可夫模型(HMM)** 。HMM 假设系统在若干个离散的隐状态之间随时间转移,每个隐状态下生成观测数据的概率分布不同。通过前向–后向算法和 Viterbi 算法,HMM 可以估计隐状态序列、计算观察序列概率,并对下一步状态与观测做预测。HMM 早期广泛用于语音识别、文本标注,也常用于简单的行为模式识别与事件序列建模,在某些工业与金融场景中仍有其优势——结构可解释、训练稳定、与领域经验易于结合。 + +在系统层面,状态空间建模、卡尔曼滤波和 HMM 常作为**轨迹估计、设备状态估计、金融与工程控制系统**的底层模块,被封装在更大的工具链中。它们不一定直接暴露给终端用户,但在导航、目标跟踪、工业控制、风险计量等产品背后,长期扮演着“隐形引擎”的角色。 + +## 6.2 深度学习时间序列建模(Deep TS Forecasting) + +随着数据规模和场景复杂度的持续上升,单纯依赖线性、平稳性假设的经典模型在很多应用中开始显得“力不从心”:大量非线性模式、长跨度依赖、复杂的多变量交互、突发行为与周期叠加等特点,使得我们需要更灵活、更高容量的模型结构。**深度学习时间序列建模**正是在这一背景下发展起来的:从 RNN/LSTM/GRU,到 Temporal CNN/TCN,再到时序专用 Transformer、混合与分层模型,它们共同构成了现代时序预测与建模的主力工具箱。 + +从应用视角来看,深度时序模型已经广泛部署在**电商流量 & 销量预测平台、供需/运力/排班预测系统、云资源负载预测与容量规划工具**中,用于在多品类、多门店、多城市、甚至多业务线的复杂结构下,给出统一而灵活的预测方案。与经典模型相比,它们更强调“端到端表示学习”和“全局模式建模”,更擅长处理长序列、高维、多变量场景。下面,我们同样从 **场景** 、**原理**和**模型**三个维度展开。 + +- **场景** + - 大规模多序列预测:成千上万条商品、门店、城市维度的销量/流量序列,需要在一个统一模型下同时建模,并支持冷启动与长尾序列。 + - 复杂运营与调度:供电/供水/运力/排班等系统中,需求受多维特征影响(天气、节假日、价格、活动),且存在多层级结构(门店/城市/全国),需要同时兼顾全局模式与局部差异。 + - 云资源与基础设施:大规模服务器集群、容器平台、网络与存储负载,呈现高度非线性和多峰结构,需要高频预测与容量规划支撑 SLO。 +- **原理** + 深度时序模型的核心在于 **自动从历史序列与协变量中学习多尺度模式与长期依赖** : + - RNN/LSTM/GRU 通过循环结构显式地在时间维度上传递“记忆”,适合捕获顺序依赖与局部时间结构。 + - Temporal CNN / TCN 使用一维卷积和膨胀卷积,在保证因果性的前提下扩大感受野,实现并行训练与稳定梯度传播。 + - 时序 Transformer 与专门设计的变体(Informer、Autoformer、TimesNet 等)利用自注意力机制,在长序列、多变量设置下建模复杂依赖和周期性模式。 + - 混合与分层模型进一步引入“全局 + 局部”“多层级时间序列”的结构假设,在统一框架中同时学习全局模式与个体特征。 +- **模型** + 在具体实现上,深度时序建模涌现出一系列具有代表性的架构: + - 经典深度序列模型:RNN/LSTM/GRU 以及基于它们的 DeepAR 等自回归概率预测模型。 + - 分解与预测一体化模型:N‑BEATS 等通过显式趋势/季节分解模块增强可解释性。 + - 基于注意力的时序模型:Temporal Fusion Transformer(TFT)等结合注意力、门控、变量选择,适用于多变量、有丰富协变量的业务场景。 + - 长序列 Transformer 模型:Informer、Autoformer、TimesNet、PatchTST 等,围绕长序列效率与多尺度建模做出专门设计。 + +下面,我们从深度序列模型、卷积与 Transformer、以及混合与分层建模三个方向展开。 + +### 6.2.1 深度 RNN/LSTM/GRU:从单序列到 DeepAR + +在深度学习进入时间序列领域初期,**RNN/LSTM/GRU** 是最自然的选择。与文本和语音建模类似,它们通过在时间步之间传递隐状态来“记忆”历史信息,允许捕捉比传统线性模型更复杂的非线性和长期依赖。对于单条或少量时间序列,简单的 LSTM/GRU 在有足够数据时就可以取得不错的预测效果;而在大规模多序列场景中,则可以采用 **共享参数的 RNN/LSTM/GRU 模型** ,在所有序列上进行联合训练,从而学习到通用的时序模式。 + +在此基础上,类似 **DeepAR** 的自回归概率模型为深度时序建模提供了一个标准框架:它将历史观测和协变量输入一个共享的 RNN/LSTM/GRU 网络,在每个时间步上输出序列值的条件分布参数(如高斯、负二项分布等),并通过最大似然训练实现端到端的概率预测。这样的设计使模型能够自然生成预测区间、处理不规则的尺度和多序列混合,有利于在电商销量、需求预测等场景中落地。 + +然而,RNN 类模型存在典型问题:长序列上的梯度衰减,以及在训练阶段无法完全并行化。虽然门控机制(LSTM/GRU)缓解了部分问题,但在特别长的时间跨度和高频数据下,训练与推理效率仍然是需要权衡的因素。这也促使业界和学术界探索更加并行友好的结构,如 TCN 和 Transformer。 + +### 6.2.2 Temporal CNN 与 Transformer:从局部卷积到长序列注意力 + +为了解决 RNN 在长序列上的效率和稳定性问题,**Temporal CNN / TCN** 引入了一维卷积和膨胀卷积来建模时间依赖:通过堆叠多层因果卷积、逐层扩大感受野,它在不破坏时间因果性的前提下,实现了对远距离历史的建模。相比 RNN,TCN 在训练时可以高度并行,梯度传播路径更短,因此在训练稳定性和效率上表现突出,适合用在高频数据、需要较大感受野的工业时序预测场景中。 + +在更高的复杂度层级上,**Transformer 与时序专用结构**成为近年来长序列、多变量时间序列建模的主角。直接使用标准 Transformer 会遇到计算复杂度随序列长度平方级增长的问题,因此涌现出一系列面向时序的改造方案: + +- **Informer** 通过概率稀疏自注意力等机制,降低长序列上的计算负担,并针对预测任务优化结构。 +- **Autoformer** 将趋势与季节性分解融入自注意力框架,试图在保持长序列建模能力的同时提升可解释性和稳定性。 +- **TimesNet** 通过在时间–频率域或多尺度展开中增强对周期与模式的感知,更好地处理复杂、多周期的长序列。 +- **PatchTST** 借鉴 Vision Transformer 的“patch”思想,将连续子序列视作补丁,提高长序列时的建模效率与泛化能力。 + +这类模型往往特别适合**长序列、多变量、高维协变量**的复杂时序场景,如大规模云资源负载、多区域能源需求、多渠道流量预测等。它们可以在一个统一架构中同时建模多维输入、静态特征和时间相关变量,并通过注意力权重为后续解释与诊断提供一定线索。 + +### 6.2.3 混合与分层模型:全局 + 局部、多层级时间序列 + +在实际业务中,时间序列很少是“孤立”的:它们往往具有明显的 **层级结构与共享模式** ——例如门店/城市/区域/全国的销售层级,SKU/品类/品牌的商品层级,或业务线/产品/渠道的组织结构。如果简单地为每条序列单独建模,很难利用到这一层次结构;而直接把所有序列混在一起,又会忽略各自的个性化差异。**混合与分层模型**正是为解决这类问题而设计。 + +一类常见思路是 **全局 + 局部模型** :通过一个共享的“全局模型”学习所有序列的共性模式(如总体趋势、节假日效应、季节性),同时为每条序列或每个子群体引入局部参数或嵌入向量,捕捉个体特性。这种结构既避免了为长尾序列单独训练模型导致的数据稀疏问题,又保留了在热门序列上进行精细建模的能力。 + +另一类是 **多层级时间序列(hierarchical TS)建模** :在预测过程中显式考虑层级约束(如子层级之和需要与上层级预测一致),通过自顶向下、自底向上或中间层级的联合优化,使各层级预测在数值和结构上保持一致。在深度时序框架下,这通常表现为在输入编码中加入层级特征、为不同层级设计多头输出,或使用分层损失函数进行训练。 + +从产品视角看,这类混合与分层建模广泛应用于**电商销量预测平台、供需/运力/排班预测系统**等场景:系统需要同时给出“单店单品”“城市级别”“全国总量”等不同粒度的预测,并在资源规划和 KPI 拆解过程中保持上下层的一致性。深度模型的灵活结构,使得这类约束可以通过端到端方式嵌入建模过程,而不必完全依赖事后修正。 + +## 6.3 异常检测与变点检测(Anomaly & Change Point Detection) + +在时间序列场景中,“预测未来”只是问题的一部分,另一部分同样关键的是: **实时发现异常与结构变化** 。无论是设备运行、业务指标、交易行为,还是运维监控,异常检测与变点检测都是保障系统稳定、识别风险机会的核心能力。传统上,统计阈值法、EWMA、CUSUM 等方法广泛使用;随着数据维度和复杂度提升,各类机器学习与深度学习方法(孤立森林、One‑Class SVM、AutoEncoder/VAE、时序 GAN、GNN + 时序模型)也开始扮演重要角色。 + +从产品形态来看,这类能力往往内嵌在**设备故障预警系统、业务指标异常报警平台(如转化率突降)、安全攻击与欺诈检测系统、运维 AIOps 告警引擎**中,通过实时监控多维时序信号,自动标记可疑点和结构变更,并与规则、知识库和人工决策流程结合。下面继续从 **场景** 、**原理**和**模型**三个角度展开。 + +- **场景** + - 设备与工业系统:监控温度、振动、电流、压力等传感器数据,提前发现故障与退化趋势,减少停机和损失。 + - 业务与运营指标:监控 PV/UV、转化率、订单量、延迟、错误率等关键指标,快速发现突降、突升、异常波动,为运营和技术团队提供告警。 + - 安全与风控:分析登录行为、交易序列、访问模式等时间序列,识别潜在攻击、作弊和欺诈行为。 +- **原理** + 异常与变点检测本质上是在“正常模式”上寻找显著偏离和结构突变: + - 对于点异常和序列异常,可以通过统计分布拟合、密度估计或边界学习,判断当前观测是否落在“正常区域”之外。 + - 对于变点,则关注时间序列统计特性(均值、方差、相关结构、分布等)在时间轴上的突变,并尝试定位变化发生的时间位置。 + - 在高维和多点网络中,需要将多条时间序列之间的依赖结构(如拓扑、相关性)纳入建模,避免将局部异常与整体趋势混淆。 +- **模型** + 从方法族来看,可以大致分为统计方法、单类/孤立学习方法、重构式深度模型和图 + 时序组合模型: + - 统计异常检测:阈值、EWMA、CUSUM 等,对单变量或简单场景极其高效,是传统监控系统的基础。 + - 机器学习方法:Isolation Forest、One‑Class SVM 等,用于在多维特征空间中刻画“正常区域”,对异常样本进行孤立。 + - 深度重构模型:AutoEncoder / VAE / 时序 GAN,通过学习重构正常序列,在重构误差较大时标记异常。 + - 图神经网络 + 时序模型:在传感器网络、微服务指标等场景中,引入图结构和时序模型共同学习正常模式,强化对拓扑相关异常的识别。 + +下面,我们围绕点/序列异常、变点检测、多维与图结构三个方向展开。 + +### 6.3.1 点异常与序列异常:从统计阈值到重构式模型 + +最直观的异常检测形式是 **点异常** :某个时间点的观测值远离历史正常范围(如 CPU 使用率突然飙到 100%、交易金额异常增大、传感器读数瞬间跳变)。传统方法中,最常见的做法是对历史正常数据拟合一个统计分布或滑动统计量(均值、方差、分位数),在此基础上设定阈值或控制图(如 EWMA、CUSUM),当当前观测超出可接受区间时发出告警。优点是实现简单、计算代价低、易于解释,因此在大量运维监控和工业系统中仍然广泛使用。 + +当维度提升或模式变得更复杂时,可以引入**孤立森林(Isolation Forest)、One‑Class SVM** 等单类/孤立学习方法:它们通过在“正常样本”上学习一个聚合区域(或边界),将落在该区域之外的点视为异常。通过在序列的滑动窗口上提取统计特征(如窗口均值、方差、频域特征等),这类方法也可以用于识别局部“序列异常”(即一段时间内行为偏离正常模式),适用于多维指标和难以精确定义分布形态的场景。 + +在深度学习框架下,**基于重构误差的 AutoEncoder / VAE / 时序 GAN** 等方法则提供了更灵活的选择: + +- 使用 AutoEncoder 或 VAE 在大量正常序列上训练“压缩–重建”模型,使其学会重构正常模式; +- 在在线监控时,将新的时间窗口输入模型,如果重构误差显著增大,则认为该区间存在异常; +- 时序 GAN 类方法则通过学习生成正常序列,在判别器的判定结果或生成误差中寻找异常信号。 + +这些方法可以适应高度非线性的模式和复杂的协变量结构,特别适合在**多维业务指标、复杂设备传感器数据**上构建统一异常检测引擎。 + +### 6.3.2 变点检测:结构突变与事件生效 + +与点异常和局部异常不同,**变点检测(Change Point Detection)**关注的是时间序列在结构上的突变:例如均值从一个水平跃迁到另一个水平、波动率发生改变、周期和相关结构出现调整。这类变化往往对应现实世界中的某种事件或状态切换,如配置变更、生效新策略、政策调整、生产工艺改变、市场 regime 切换等,对业务诊断和因果分析极为关键。 + +传统统计方法中,变点检测常借助似然比检验、CUSUM、Bayesian Online Change Point Detection(BOCPD)等技术: + +- 通过在不同时间点前后拟合不同参数的模型(如不同均值/方差),比较“无变点假设”和“有变点假设”的拟合优度; +- 在在线场景中,对每个时间点递推更新“当前段落为止是否出现变点”的后验概率,一旦超过设定阈值则触发告警。 + +在更复杂的设置下,可以结合深度表示学习与分段模型,将变点检测视作 **序列分段问题** :用神经网络提取特征,再在特征空间中寻找段落边界,或者直接训练模型预测某一时间点属于“变点”的概率。这对于存在多种形态变化(不仅是均值/方差变化)、且难以用简单统计假设刻画的业务指标尤其有用。 + +在产品体系中,变点检测通常被集成在**业务指标分析平台、A/B 实验分析系统、配置与策略变更监控工具**中:当关键指标呈现结构性变化时,系统可以自动标记潜在变点,并关联相应的变更事件(如版本发布、参数调整、政策落地),为后续根因分析提供线索。 + +### 6.3.3 多维时序与图结构:GNN + 时序模型的联合建模 + +在现代分布式系统和物联网场景中,我们往往面对的是 **多点、多维、具有关联拓扑结构的时间序列** :例如传感器网络中的多个测点、微服务架构中的各个服务指标、配电网/交通网中的多个节点和边。此时,单独、逐条地对每个时间序列做异常检测,很容易误判局部波动或忽略整体模式——真正的异常往往是“局部–整体不一致”或“拓扑结构中不协调”的表现。 + +为此,近年来出现了大量**图神经网络(GNN) + 时序模型**的组合方法: + +- 首先根据现实拓扑(物理连接、网络拓扑)或基于数据估计出的相关图,构建一个表示多点之间关系的图结构; +- 在每个时间步上,用 GNN 对节点特征(各点的时序值及其局部上下文)进行消息传递,学习空间关联特征; +- 再将图编码后的表示输入 RNN、TCN 或 Transformer 等时序模型,捕捉时间维度上的动态模式; +- 最终在联合表示上进行异常评分或变点检测,实现 **时空联合的异常识别** 。 + +这种框架在**传感器网络监控、微服务指标异常检测、城市计算中的时空异常检测**等场景中尤其适用:它能够分辨“全局性变化”(如整个系统负载上升)与“局部异常”(如某个节点异常拥塞),也能更好地识别拓扑结构相关的异常模式(如链路级问题、区域性网络故障)。 + +在工程层面,这类方法通常作为**运维 AIOps 告警系统、安全与风控平台、设备群监控系统**的高阶能力出现,结合基础统计监控、规则系统和专家知识,为复杂系统提供更智能、更上下文感知的异常发现机制。 + +## 6.4 时空序列(Spatio-Temporal Modeling) + +在很多关键业务场景里,仅仅建模“时间”是不够的: **“什么时候”与“在哪里”并行存在** ,而且二者高度耦合。城市交通流量受路网结构和时间规律共同影响,气象与空气质量既依赖时间演化,也依赖地理邻近与大气流场;物流、共享单车与网约车调度则需要同时考虑需求的时空分布和道路/区域结构。**时空序列建模(Spatio‑Temporal Modeling)** 正是针对这类“时间 + 空间”联合建模问题的系统方法。 + +与纯时间序列模型相比,时空模型需要显式把**空间依赖结构**纳入考虑:相邻路段的交通流量、邻近监测站的空气质量、相连节点的负载与状态,通常比相隔较远的点更具相关性。为此,图神经网络(GNN)、卷积 LSTM(ConvLSTM)等结构被广泛用于结合空间与时间两个维度的特征学习。对应到产品层面,这类能力支撑着**城市计算平台(交通/人流预测)、气象/环境预测系统、物流路径规划与共享单车/网约车调度平台**等大量关键应用。 + +- **场景** + - 交通流量与人流预测:在路网或地铁网结构上,对不同时段的车流、人流进行预测,辅助信号灯优化、拥堵管理和调度决策。 + - 气象与环境监测:在地理网格或监测站网络上,预测未来的温度、降雨、风力、空气质量等时空分布,为预报和决策提供支撑。 + - 物流与出行调度:在城市区域或路网结构上预测订单需求、车辆分布、仓库/站点的负载情况,为路径规划、车辆调度和运力分配提供依据。 +- **原理** + 时空序列建模的核心是 **在统一框架中同时学习空间相关性与时间动态** : + - 在空间维度上,通过图结构或卷积结构刻画“谁与谁相关”,并基于此进行消息传递与特征聚合; + - 在时间维度上,利用 RNN、TCN、Transformer 或特化的时序结构刻画动态变化; + - 两者可以串联(先做空间,再做时间),也可以交织或同时作用(如时空卷积、时空注意力)。 +- **模型** + 典型时空模型大多采用“GNN + 时序模型”或“卷积 + LSTM”的组合形态: + - 图神经网络 + 时序模型:ST‑GCN、DCRNN、Graph WaveNet、ST‑Transformer 等,通过图卷积或图注意力捕捉空间依赖,再用时序结构捕捉时间动态。 + - 卷积 LSTM 类模型:ConvLSTM、Conv‑TT‑LSTM 等,在时序递推中嵌入空间卷积门控,实现对时空局部特征的联合建模。 + +下面,我们从时空任务与数据表示、GNN + 时序模型、卷积 LSTM 与时空卷积三个方向展开。 + +### 6.5.1 时空任务与数据表示:从路网到地理网格 + +在进入具体模型之前,时空序列建模首先要解决的是 **如何表示空间结构** 。与一维时间轴不同,空间结构可以是规则网格(grid)、不规则图(graph)、或者混合形式。 + +- 在交通场景中,道路与交叉口天然构成一个有向或无向图:节点表示路段或路口,边表示道路连接与行驶方向;每个节点在每个时间步上有一组特征,如车流量、平均速度、拥堵指数等。 +- 在气象与空气质量预测中,可以使用规则地理网格(如经纬度网格),或将监测站点之间的邻接关系构建为图结构,基于地理距离、风向或相关性定义边权。 +- 在物流与共享出行场景中,可以将城市划分为网格或区域单元,每个单元在时间上具有订单量、活跃车辆数等特征,同时在空间上通过邻接关系或实际道路距离相连。 + +这种“ **空间结构 + 时间序列** ”的统一表示,使得很多不同场景可以被建模为类似的问题:给定历史时空序列,预测未来若干时间步上每个节点或网格的状态。后续模型设计(无论是 GNN + 时序模型,还是 ConvLSTM)都是在这一统一视角上展开。 + +在产品层面,这一层的抽象往往封装在**城市计算平台、气象/环境预测系统、路径规划与调度平台**的数据层与建模层:业务方只需要知道“我们在路网/网格上预测未来流量/需求如何”,而底层的数据表达与时空融合由建模框架统一处理。 + +### 6.5.2 图神经网络 + 时序模型:ST‑GCN、DCRNN、Graph WaveNet 等 + +在图结构上建模时空序列,目前最主流的路线是“ **图神经网络(GNN) + 时序模型** ”的组合。代表模型包括 **ST‑GCN、DCRNN、Graph WaveNet、ST‑Transformer** 等,它们的共同特点是: + +- 在空间维度上使用图卷积(GCN)、图注意力(GAT)或谱域卷积等方法,对每个时间步的节点特征进行“邻域聚合”,从而捕捉空间依赖与拓扑结构的影响; +- 在时间维度上,通过 RNN(如 GRU/LSTM)、TCN、或 Transformer 对节点级特征进行序列建模,捕捉时间趋势和周期性; +- 通过交替堆叠或联合设计,使得模型能够在多个时空尺度上学习局部与全局模式。 + +例如,**DCRNN(Diffusion Convolutional RNN)** 将图卷积与门控循环单元结合起来,使用扩散卷积来模拟信息在路网上的传播,再通过 RNN 捕捉时间维度的动态,非常适合交通流量预测等任务。**Graph WaveNet** 则在图卷积和时间卷积的基础上,引入自适应图结构学习和多尺度建模,提高对复杂路网和非规则拓扑的适应性。**ST‑Transformer** 等模型则把自注意力机制引入时空建模,通过时空注意力模块同时考虑不同时间和空间位置之间的相关性。 + +在实际系统中,这一类 GNN + 时序模型广泛部署在**城市交通与人流预测平台、共享出行调度系统、复杂 IoT 网络监控**等产品中。它们通常作为核心预测引擎之一,与规则系统、仿真模型和业务策略共同组成闭环,使得调度与规划既能考虑全局结构,又能响应局部变化。 + +### 6.5.3 卷积 LSTM 与时空卷积:ConvLSTM、Conv‑TT‑LSTM 等 + +另一条重要路线是基于**卷积 LSTM(ConvLSTM)**及其变体的时空建模。与标准 LSTM 在时间步之间传递一维向量不同,ConvLSTM 在门控结构中使用卷积算子,使得隐藏状态和输入都保持为多维张量(如空间网格上的特征图)。这样,在每个时间步的状态更新中,既包含了时间上的递推,也在空间维度上进行了局部卷积聚合,实现了对时空局部模式的自然建模。 + +在此基础上,**Conv‑TT‑LSTM 等改进模型**尝试通过张量分解、参数分享、多尺度卷积等机制,提升模型的表达能力和效率,适应更大规模、更复杂的时空数据。例如,在气象预测中,可以使用 ConvLSTM 堆叠多层,对多通道气象要素图(温度、湿度、风向等)进行时空递推,从历史若干帧预测未来几小时或数天的空间分布;在交通和环境监测中,也可以将路网或监测点映射到规则网格上,使用 ConvLSTM 等模型进行预测。 + +与 GNN + 时序模型相比,ConvLSTM 系列在**规则网格结构、局部空间平滑性明显**的场景中使用较多,如气象雷达回波预测、空气质量网格预报、视频帧级预测等。其优势在于实现相对直接、易于利用现有卷积网络基础设施进行加速和部署,也容易与 CNN/ViT 等视觉模型协同使用,如在遥感影像时空建模中结合卷积特征和时序递推。 + +在产品形态上,这一方向的模型多用于**气象/环境预测系统、遥感时空分析平台、视频与影像时空预测**等,常常以“未来时空场景预测图”的形式向上游暴露能力,成为业务决策与可视化分析的重要输入。 + +# 7. Agent 与工具调用层(Agents & Tool Use) + +在前面的视觉、语言等能力层中,模型大多还是“被动回答”的形态——接收输入、给出输出。而在很多真实业务里,我们需要的是一个 **可以主动规划、调用外部工具、串联工作流的智能体(Agent)** :它不仅能看懂/读懂/听懂,还能自己“决定下一步做什么”,比如去查资料、跑代码、读写文件、调用内部系统,然后再把结果整合、解释并反馈给用户。 + +这一层可以被理解为“把基础模型变成可行动系统”的关键粘合层:通过 **结构化工具调用接口、工作流编排、多 Agent 协作以及人类在环机制** ,把 LLM 从一个强大的“认知内核”扩展为能够完成端到端任务的“数字员工”。 + +## 7.1 工具调用与执行(Tool Calling / Function Calling) + +在只读不写、只说不做的纯文本时代,LLM 更像一个“超级对话者”:可以理解问题、给出建议、写代码、列方案,但所有“真正执行”的工作——查数据库、跑脚本、生成文件、调云服务——仍然要人工接手完成。而**工具调用 / Function Calling** 的出现,让模型第一次可以在安全边界内“动手”:根据自然语言自动生成结构化参数,去调用搜索引擎、数据库、计算引擎、图像/音频/视频生成服务等外部能力,再把执行结果整理返回,从而形成“理解 → 决策 → 执行”的闭环。 + +从产品角度看,工具调用是绝大多数 Agent 系统的“底盘能力”:OpenAI Assistants API、LangChain、LlamaIndex、AutoGen、各类云厂商的 Agent 平台,实质上都是在 LLM 之上,围绕**如何定义工具、如何让模型正确选工具、如何处理出错与重试**搭建一层运行时。下面同样从 **场景** 、**原理**和**模型**三个角度梳理这一层能力,并在后续小节中分别展开“工具调用接口设计”“工具选择与策略”“典型工具类型”三个方向。 + +- **场景** + - 智能问答与检索增强:模型根据用户问题自动决定是否调用检索工具(向量/关键词搜索)、查企业内部知识库或公网搜索,并将查到的文档、FAQ 整合进最终回答。 + - 数据与报表自动化:面对“帮我查这段时间的销售额并画图”“给我算一下这个投资组合的风险指标”之类请求,模型自动生成 SQL 或分析参数,调用数据库和计算引擎,返回图表与结论。 + - 文档与文件操作:自动读取 PDF/Word/Excel/数据库表,抽取和汇总关键信息,或按指令生成新文件(如报表、合同、方案),并通过工具上传/存储到指定位置。 + - 媒体生成与处理:根据文本指令调用图像/音频/视频/3D 生成服务,或对现有媒体做剪辑、压缩、转码、水印等操作,形成一键“文案 + 设计 + 导出”的内容流水线。 +- **原理** + 工具调用的核心是: **用自然语言驱动结构化函数调用** 。 + - 首先以 JSON Schema 或函数签名的形式,将外部工具的名称、说明、参数结构(类型、必填项、枚举值等)暴露给 LLM。 + - 当用户发出请求时,LLM 不仅要理解语义,还要判断“是否需要调用某个工具”“需要哪个(些)工具”“这些工具的参数应该怎么填”。 + - 一旦模型决定调用某个工具,就生成一段结构化参数(通常是 JSON),由运行时去真正执行外部 API / 程序,并把执行结果以结构化形式返回给模型,让模型基于结果继续推理或生成最终回答。 + - 为保证安全与鲁棒性,系统需要在这一过程中处理参数校验、超时、错误返回、重试与回退,并对可能涉及安全/隐私的调用做权限与审计控制。 +- **模型** + 支撑这一能力的模型与框架主要包括三类: + - 支持 Function Calling 的 LLM:如 GPT‑4.1 / o 系列等,原生在解码层面理解“工具签名 + JSON Schema”,能够在合适时机主动或被动地产生结构化调用参数。 + - 工具增强推理范式:如 ReAct、Toolformer,将“思考 + 工具调用”编织进同一推理链条,将工具使用视作中间步骤的一部分,而不是简单的前/后处理。 + - 工程框架与运行时:OpenAI Assistants API、LangChain、LlamaIndex、AutoGen、各云厂商 Agent 平台等,为工具定义、调用路由、状态管理、错误处理与日志审计提供基础设施,让开发者可以聚焦在“暴露哪些工具”和“抽象怎样的业务 API”上,而不必从零搭建运行时。 + +### 7.1.1 工具调用接口:从自然语言到结构化函数调用 + +一个可用的工具调用系统,首先需要一个清晰、规范、对 LLM 友好的“工具接口层”。它承担着把外部世界的 API、脚本、服务包装成模型可理解、可安全调用的“函数”的职责,让模型可以像写伪代码一样“说出”自己希望调用的工具及其参数。 + +- **工具定义与参数模式** + 在接口层,通常会用类似 JSON Schema 或函数签名的结构定义每个工具:包括名称(name)、说明(description)、参数字段(properties)、类型(string / number / boolean / array / object)、是否必填(required)、取值范围或枚举等。 + 这些信息一方面被用来驱动前端/SDK 的类型检查,另一方面也直接提供给 LLM,帮助模型“学会”如何正确填写参数。描述越清晰、约束越合理,模型生成的调用就越规范,出错率越低。 +- **LLM 生成结构化参数** + 当用户提出“帮我查 2024 年 Q3 的营收并画一张按地区拆分的柱状图”这类请求时,模型需要先推理出:这至少需要一个“报表查询工具”(访问数据)、可能还需要一个“图表生成工具”(画图)。对每个工具,它要从原始语言中抽取并映射结构化参数,如时间范围(start_date/end_date)、维度(region)、指标(revenue)、图表类型(bar)、输出格式等,然后以 JSON 输出交给运行时。 + 这个过程中,模型本质上在做“自然语言 → 任务规划 → 参数抽取 / 填充”的一体化推理,因此工具描述的自然语言提示、参数示例和 few‑shot 样例都非常关键。 +- **工具执行与结果回传** + 运行时接收到模型产出的 JSON 调用后,会先进行参数校验与安全检查,再去真正调用后端 API 或程序。执行完成之后,将结果封装为结构化对象(如查询结果表格、文件 URL、媒体资源 ID 等)返回给模型。 + 随后,模型会把这些原始结果转化为用户可读的解释或进一步加工,如总结报表、生成自然语言分析、嵌入图表标注说明等。对于模型而言,工具结果只是中间信息的一部分,它仍然要负责“理解结果 + 解释结果”。 + +### 7.1.2 工具选择与策略:在多工具世界里做决策 + +当系统中只有一个工具时,“要不要用工具”是唯一的问题。但在现实 Agent 应用中,往往会有几十甚至上百个工具:不同数据源的检索、不同部门的业务 API、不同技术域的生成/分析能力,这就引出了一个新的挑战: **模型如何在多工具环境下做合理的选择和编排** 。 + +- **工具选择与路由** + 首先,模型需要判断“当前请求是否需要调用工具”,以及“需要调用哪一个(或哪几个)工具”。这通常通过在系统提示中列出可用工具的说明,并提供典型示例,让模型学会根据用户意图选择合适工具。 + 对于工具数量较多、描述相似度较高的场景,很多框架会引入“工具路由器”(如基于向量检索或规则的前置筛选),先从大列表中筛出若干候选工具,再暴露给 LLM 选择,从而降低模型负担和误选概率。 +- **多工具顺序与组合** + 复杂任务往往需要多个工具协同完成。例如“调研某行业主要上市公司,并生成一份包含财务对比图表的报告”,可能涉及搜索引擎、财报数据库、计算引擎、图表生成工具、文档导出工具等。 + 在这种情况下,模型需要做一个轻量级的任务规划:先用哪个工具获取列表,再对列表逐个查询详细信息,之后合并数据、做计算与可视化,最后调用导出工具生成报告。典型实践包括 ReAct/Planner‑Executor 思路,让模型在“思考(Plan)—调用(Act)—反思(Reflect)”的循环中,逐步完成工具组合调用。 + +### 7.1.3 典型工具类型:从检索到媒体生成的能力拼图 + +不同类型的工具,为 Agent 系统提供了不同维度的“外接大脑”。从工程实践来看,以下几类工具几乎是所有复杂应用的“标配”。 + +- **检索工具:向量与关键词搜索** + 检索工具负责把“记忆”扩展到外部世界: + - 关键词搜索适合结构化较好、字段清晰的传统文档和业务数据库。 + - 向量搜索则通过嵌入(embedding)为非结构化文本、代码、对话记录、甚至多模态数据建立语义索引,支持“模糊但语义相关”的检索。 + 在 RAG 场景中,LLM 通过检索工具拉取与用户问题相关的上下文,再在此基础上进行推理与生成,大幅提升回答的时效性和准确性。 +- **代码执行与计算引擎** + 代码执行类工具(如 Python/JS 沙箱、Notebook 执行器)让 LLM 可以“写一段代码并立即跑起来”,解决复杂计算、数据处理、数值模拟、可视化等问题。 + 模型负责产出代码与输入参数,执行环境负责安全隔离、资源限制与结果收集。这类工具在数据分析、量化研究、自动化报表、科学计算以及 Agent 自我验证(模型生成答案后用代码校验)等场景中非常关键。 +- **文件与数据源访问** + 文件读写工具负责将外部文件系统和数据源引入到 Agent 视野中:读取 PDF/Word/Excel、访问数据库表、调用内部业务 API 等。模型通过这些工具获取真实业务数据,再进行归纳、对比和报告生成。 + 与之配套的还有文件写入与管理工具:将生成的报告、图表、PPT、代码等持久化存储,并返回链接或 ID,方便用户后续访问与集成。 +- **媒体生成与处理工具** + 媒体生成工具则为 Agent 增添了“创作”和“设计”的手臂: + - 图像/视频生成与编辑:根据文案自动生成配图、海报、分镜,或对已有媒体进行裁剪、上字幕、加水印等。 + - 音频生成与处理:TTS、配音、音乐生成、音频增强与剪辑。 + - 3D / 工程类工具:生成简单 3D 场景、CAD 草图、UI 原型等。 + 在内容生产、营销设计、教育培训、游戏与多媒体应用中,这类工具让“从想法到成品”更接近一条自动化流水线。 + +综合来看,工具调用与执行把 LLM 从“语言模型”扩展为“具备行动接口的通用控制器”:模型通过语言理解需求与环境,通过工具执行真实操作,通过反馈不断修正策略。搭配合适的工作流编排与多 Agent 协作(见 7.2),就构成了新一代智能应用的基础架构。 + +## 7.2 工作流编排与多 Agent 协作(Workflow & Orchestration) + +有了工具调用能力,LLM 不再只是一个“回答问题的人”,而可以成为面向具体任务的“执行单元”。但现实业务往往远比单次对话复杂:一个完整的诉讼分析、一次市场调研、一轮 A/B 实验配置、一次端到端运维处理流程,通常都需要多步操作、多种工具、甚至多方角色长期参与。这时,单一 LLM + 工具的模式就显得吃力,需要进一步的 **工作流编排与多 Agent 协作** 。 + +从系统视角看,这一层的职责是: **把一个复杂的、多步骤、多参与方的业务流程,抽象成可被 LLM 理解与操控的工作流图** ,然后在这个图上调度一个或多个 Agent,配合人类干预,共同完成任务。典型实现包括 Planner‑Executor 型 Agent 架构、具备反思 / 自我修正能力的 Agent、以及基于图结构的 Workflow Orchestrator;相应的产品形态则是各类自动报告生成与运营自动化平台、低代码工作流 + LLM 集成、复杂业务流程机器人、自动运维系统等。 + +- **场景** + - 报告与内容流水线:从“接收需求 → 检索与数据拉取 → 分析和可视化 → 撰写报告 → 审核修改 → 导出与分发”,将多步内容生产流程自动化或半自动化。 + - 业务流程自动化:如电商运营中的“商品分析 → 竞品监控 → 活动策略生成 → 落地配置”,运维场景中的“监控告警 → 根因分析 → 缓解措施执行 → 复盘报告”等。 + - 跨角色协作:让不同领域 Agent(法律、财务、技术、运营)围绕一个复杂项目协同工作,例如并购尽调、投融资材料准备、大型项目标书编制。 +- **原理** + 工作流与多 Agent 协作的核心,是在 LLM 之上再加一层 **结构化控制与状态管理** : + - 将复杂任务拆分为若干有依赖关系的子任务,用 DAG / 状态机 / 有向图等结构表示,并为每个节点配置触发条件、输入输出和所需 Agent/工具。 + - 由 Planner 型 Agent 或上层 orchestrator 决定何时触发哪个节点、用哪个 Agent 或工具,并根据执行结果动态调整后续路径(条件分支、循环、错误回退)。 + - 在关键环节引入人类在环(Human‑in‑the‑loop),对高风险决策和关键输出进行人工确认与编辑,并将人类反馈回流到系统,用于更新策略或微调模型。 +- **模型** + 支撑这一层的主要技术方向包括: + - Planner‑Executor 型 Agent 架构:由一个“规划 Agent”负责任务分解与路径设计,一个或多个“执行 Agent”负责具体步骤的落地实施。 + - 反思 / 自我修正 Agent:在执行过程中不断回顾自己的表现,对不合理的中间结果进行反思和修正,减少“自信错误”的静默扩散。 + - Graph‑based Workflow Orchestrator:将整个任务流程建模为图结构,引入节点状态、边条件、并行/串行控制等机制,使 LLM 调用变成图中的一个或多个节点,而不是唯一的控制中心。 + +### 7.2.1 任务分解与规划:从“一句话需求”到可执行流程 + +用户给 Agent 的通常是一句高度压缩的自然语言需求,例如“帮我做一个关于新能源车行业的市场调研并输出 PPT”,背后实际包含了检索、筛选、分析、可视化、排版、多轮修改等大量步骤。如何从这句话出发,自动构建一条清晰、可执行的工作流,是工作流编排的第一步。 + +- **从自然语言到子任务图** + Planner 型 Agent 首先需要把需求“展开”:结合内置模板、历史案例、以及工具清单,识别出关键阶段(如信息收集、数据分析、结构设计、内容撰写、审校与导出),并进一步细化为可执行子任务(如“检索 5 篇近一年权威行业报告”“拉取近 3 年销量数据并按车型细分”“生成 3 张对比图表”等)。 + 这些子任务之间的依赖关系和调度逻辑,会被显式表示为一张图或一个状态机:哪些可以并行、哪些必须顺序执行、在哪些节点需要人工确认、在什么条件下需要回退或重试。 +- **条件分支、循环与异常路径** + 真实流程往往并不是线性流水线,而是包含 **条件分支** (如“如果检索不到足够高质量报告则换关键词或换数据源”)、 **循环** (如“持续尝试改写和压缩,直到报告长度满足限制”)和 **异常路径** (如“某个数据源不可达时,切换到备选源或采用估算方法”)。 + 这要求工作流编排层能够在图结构上表达 if/else、while/for、try/catch 等控制流语义,并允许 Planner Agent 或上层 orchestrator 在运行过程中根据实时结果做决策,而不仅仅在开始时一次性规划好所有步骤。 +- **与工具调用的衔接** + 任务分解与规划与 7.1 中的工具调用是紧密相连的:Planner 在生成子任务时,往往会同时指定“该任务需要用到哪些工具/Agent”和“该节点的输入输出格式”,为后续自动参数填充和工具执行打基础。 + 一些系统会采用“Plan + Execute”显式两阶段:先由 Planner 输出一个机器可读的计划(如 JSON 工作流描述),再由 Executor 严格按计划调用工具与 Agent;也有系统采用 ReAct 风格,将“思考–工具调用–观察–再思考”编织在同一对话中,以获得更灵活的自适应执行。 + +### 7.2.2 多 Agent 协作:让“虚拟团队”各司其职 + +单个大模型固然强大,但在复杂业务场景中,不同领域往往需要不同的知识结构、风格偏好和安全策略。**多 Agent 协作**的思路,是把一个“大而全”的智能拆解为多个“专而精”的角色:有人负责规划,有人负责执行,有人负责审校,有人负责领域专业判断,形成一个由 Agent + 工具 + 人类共同组成的虚拟团队。 + +- **角色分工:规划、执行与审校** + 在一个典型的多 Agent 流程中,常见角色包括: + - 规划 Agent:负责理解用户需求、设计整体计划、拆分子任务,并在执行过程中根据结果动态调整路径。 + - 执行 Agent:围绕某些工具或子领域进行深度优化(如检索 Agent、数据分析 Agent、内容撰写 Agent),按规划要求完成具体步骤。 + - 审校 Agent:从结构性、逻辑性、风格一致性和风险控制等角度,对中间和最终产出进行检查和修订,类似“虚拟编辑/Reviewer”。 +- **领域专家 Agent 协同** + 对于法律、金融、技术、运营等专业性极强的领域,可以进一步细分出领域专家 Agent:如“法律顾问 Agent”“投研分析 Agent”“云原生运维 Agent”“广告投放优化 Agent”等。 + 它们可以基于领域专用知识库、工具、甚至专门微调模型,参与项目式协作:例如在一份投融资材料中,由技术 Agent 负责技术可行性部分,财务 Agent 负责财务模型与估值,法律 Agent 负责合规与风险披露,运营 Agent 负责市场与增长策略,再由总控 Agent 汇总和统一风格。 +- **协作协议与消息路由** + 多 Agent 协作的关键,还在于“谁在什么时候跟谁说话”。系统需要一个消息路由与协调机制: + - 决定某条用户请求或中间结果应当被哪个 Agent 处理。 + - 维护共享上下文与各自的私有记忆。 + - 控制并行与串行执行,以及冲突解决(如不同 Agent 提出相互矛盾的建议时如何仲裁)。 + 这类能力通常由上层 orchestrator 或“管理 Agent”提供,而 LangChain、AutoGen 等框架则在工程层面提供了对话路由、多 Agent 会话、角色设定等基础设施。 + +### 7.2.3 人类在环(Human‑in‑the‑loop):把风险关口握在手里 + +即便工作流与多 Agent 协作再智能,真实业务中仍然无法完全脱离人类判断,尤其在**高风险、高成本、高敏感度**的场景下,如法律合规、金融决策、医疗建议、大规模生产变更、舆情响应等。**人类在环(Human‑in‑the‑loop)** 的设计,正是要在自动化与可控性之间找到平衡:该自动的自动,该人工确认的一定要停下来让人看一眼。 + +- **关键步骤人工确认** + 在工作流图中,通常会显式标记若干“人工审批/确认节点”: + - 例如在自动生成合同时,在签发前需要法务和业务负责人双重确认; + - 在自动运维系统中,对涉及生产环境变更、批量重启、配置修改的操作,必须有值班工程师点击确认; + - 在内容生成场景中,对大量公开发布或品牌敏感的内容,需要人工审稿。 + Orchestrator 会在这些节点暂停自动执行,将中间结果发送给对应人类角色,并在收到反馈后再继续后续流程。 +- **反馈驱动的策略更新** + 人类不仅在某一时刻“按下通过或驳回”,更重要的是反馈的内容可以被系统吸收: + - 将人工修改后的版本与原始输出对比,作为“正负样例”记录下来,用于后续的提示优化或模型微调。 + - 基于统计分析,识别出哪些类型的任务/步骤最容易被人工反复修改,进而优化对应 Agent 的提示词、工具组合或工作流设计。 + - 在极端或异常案例中,人工可以添加“黑名单 / 白名单 / 特殊规则”,直接影响系统在类似情况中的策略选择。 +- **风险分级与可观测性** + 最后,人类在环还需要一套清晰的风险分级和可观测性机制: + - 根据任务类型、影响面、金额规模、涉及的敏感信息等维度,将流程分为不同风险等级,对应不同强度的人类介入(如只读审阅、强制审批、多级审批)。 + - 通过日志、审计、可视化看板等方式,让运营/管理人员能够随时追踪哪些任务在跑、跑到哪一步了、哪些地方触发了人工介入、历史上出现过哪些失败与人工修正。 + 这些能力不仅提高了系统在企业内的可接受度,也为后续的合规审查和责任划分提供了基础。 + +综合来看,工具调用与执行(7.1)解决的是“单步行动”的问题,而工作流编排与多 Agent 协作(7.2)则试图回答“如何把很多步串起来,让不同角色长期协作并可控运行”。两者叠加,再加上人类在环与良好的工程实践,构成了面向真实业务场景的新一代智能应用底座。 + +# 8. 检索增强与知识层(Retrieval & Knowledge) + +在前面的视觉与理解层中,模型主要依赖“自身参数里学到的知识”来理解和生成内容。但在真实业务里,很多问题并不能只靠“记忆”解决:企业内部制度每天在变、法规和行业标准持续更新、某个客户的历史记录只存在于内部数据库。这时,仅靠模型“背过”的知识远远不够,更关键的是能否在 **外部知识库、结构化数据和图谱上进行高效检索与推理** 。 + +可以把这一层理解为:在模型能力之上,再加一层“会查资料、会用数据库的外脑”。当用户提出问题时,系统不再直接生成答案,而是先去合适的数据源里“翻资料”:文档库、数据库、搜索引擎、知识图谱、日志与业务系统……然后再让模型基于真实检索到的内容来给出回答与决策。这样不仅能显著提升准确性和时效性,还能在很大程度上提升可解释性和合规性(例如可引用出处、保留执行 SQL 记录等)。 + +围绕这一层,常见能力大致可以分为两个方向:一是 **检索增强生成(RAG)** ,主要面向“自然语言问答 + 文档/知识库检索”;二是 **结构化数据与知识图谱(Structured Data & KG)** ,负责对数据库、图数据库和领域知识中台进行更精准、可控的访问与推理。下面分别展开。 + +## 8.1 检索增强生成(RAG) + +RAG(Retrieval‑Augmented Generation)可以看作是“会查资料的 LLM”。与纯粹依赖模型内部参数不同,RAG 在回答每一个问题前,都会先去外部知识库做检索,把与问题最相关的若干段文档片段(chunk)找出来,然后再把这些检索到的内容作为“上下文”喂给 LLM,让它在“看过资料”的基础上生成答案。对于企业知识库问答、行业报告搜索、法律/医疗/金融专业问答、内部文档搜索机器人等场景,RAG 已经成为默认范式。 + +在系统架构上,典型 RAG 可以拆解为三层: **索引构建层、检索层、生成层** 。前两层主要是“查得准”,后一层则负责“说得清”。下面从这三层来展开,并在二级小节中进一步细化核心设计与实践。 + +- **场景** + - 企业内部知识问答:员工用自然语言提问制度流程、技术文档、项目资料,系统基于内部文档与 Wiki 检索相关内容后,由 LLM 生成清晰回答并附带引用。 + - 行业报告与研究搜索:在大量 PDF、报告和论文中检索某个行业问题的相关内容(如“新能源车补贴政策变化”),并自动总结、对比和列出处。 + - 法律 / 医疗 / 金融领域问答:基于法规条文、判决文书、临床指南、产品说明书等权威材料进行检索增强,降低“胡编乱造”的风险。 + - 内部文档 / 工单搜索机器人:帮助运营、客服、研发快速在知识库、工单和变更记录中定位答案,并以自然语言总结结果。 +- **原理** + RAG 的核心思想是把“知识存贮在外部,推理交给模型”: + - 将非结构化文档(PDF、网页、Word、技术文档等)拆成适合检索的文档块(chunk),用 Embedding 模型将其映射到向量空间,并构建向量索引(如 FAISS、Milvus、PGVector 等)。 + - 在用户查询时,同时利用语义向量检索与关键词检索(Hybrid Search),找到与问题最相关的若干文档块,并根据相关性和覆盖度做重排序(Re‑ranking)。 + - 将检索到的上下文、用户提问、以及必要的系统指令/格式约束一起输入 LLM,由模型在“可见证据”的约束下进行回答,并在输出中引用出处(source citation),以提升可解释性和可审计性。 +- **模型** + 典型 RAG 系统往往是一个 **模型组合架构** : + - Embedding 模型:用于将查询和文档块编码到同一个语义空间,是向量检索效果的关键(包括通用 Embedding 和领域定制 Embedding)。 + - 检索与重排模型:Hybrid Search(如 BM25 + Vector)负责第一轮召回,Cross‑Encoder Re‑ranker 或 LLM 本身用于对召回结果做更精细的重排序。 + - 生成模型:LLM 在给定检索上下文的前提下进行回答;在更复杂的 RAG / HyDE / ReAct + RAG 中,LLM 还会参与“伪文档生成”“多轮工具调用”“思考 + 检索交替”等过程,以提高召回、减少遗忘和增强推理能力。 + +### 8.1.1 索引构建与知识资产整理 + +在任何 RAG 系统中,索引构建都是基础。没有高质量的索引,后续再强大的 LLM 也只是“巧妇难为无米之炊”。索引构建的目标,是把杂乱无章的文档资源转化为“可检索、可维护、可扩展的知识资产”。 + +从流程上看,典型索引构建包括以下几个关键步骤: + +1. **文档分块与预处理** + 文档往往是长篇 PDF、PPT、Word 或网页,如果直接对整篇文档做向量化,既容易造成“稀释”(一篇文档包含多个主题),也不利于高效检索。因此需要: + 1. 按段落、标题、页码、章节结构进行分块,平衡“语义完整度”和“块大小”; + 2. 处理格式问题(表格、公式、图片中的文字 OCR)、去噪(页眉页脚、目录、版权信息等); + 3. 为每个块生成“上下文标签”(如所属文档、章节标题、页码),为后续解释与引用做好准备。 +2. **Embedding 与向量索引** + 在分块基础上,对每个文档块生成语义向量: + 1. 选择合适的 Embedding 模型(如通用语义 Embedding、领域微调模型),确保对目标语言和领域术语有良好表达能力; + 2. 使用 FAISS、Milvus、PGVector 等构建高维向量索引,支持大规模数据下的近似最近邻检索; + 3. 处理多版本与增量更新:当文档更新时,需要支持增量重建索引、版本记录和旧版本清理策略。 +3. **元信息索引与过滤** + 单纯的语义向量并不足以应对复杂过滤需求,通常还需要构建 **元信息索引** : + 1. 为每个文档块补充时间、作者、来源、文档类型、业务线、敏感级别等元数据; + 2. 支持在检索时基于元信息进行预过滤(如时间范围、部门、权限等级),减少无关结果; + 3. 为权限控制与审计打下基础,避免 RAG 在回答中泄露用户无权访问的内容。 + +### 8.1.2 检索与重排序:从“召回相关”到“找到最合适的证据” + +在索引构建完成后,当用户发起查询,就进入检索与重排序阶段。这里的关键不只是“找一些相关文档”,而是要尽可能找到 **既相关又覆盖充分、且支持推理的证据组合** 。 + +1. **Hybrid 检索:向量 + 关键词的互补** + 纯向量检索擅长捕捉语义相似度,但对于精确术语、代号、表格字段等,关键词检索(如 BM25)往往更稳健。因此工程实践中普遍采用 Hybrid Search: + 1. 首先对查询分别进行向量检索和关键词检索,得到两组候选文档块; + 2. 使用加权打分或学习到的融合策略,将两路候选合并; + 3. 在一些场景中,可根据查询类型(FAQ 问答 vs. 法条定位)动态调节向量与关键词检索的权重。 +2. **重排序(Re‑ranking):更精细地挑选“证据集”** + 初始检索结果往往包含不少“边缘相关”或“冗余”文档块,需要重排序来提升最终 Top‑K 的质量: + 1. 使用 Cross‑Encoder(交叉编码器)对“查询–文档块”对进行双向编码和相关性打分,相比双塔 Embedding 模型精度更高,但开销较大,适合作为二阶段重排; + 2. 在性能允许时,引入 LLM 进行轻量级重排,让模型基于更丰富的语义和上下文信息来判断哪些块真正“有用”; + 3. 同时考虑覆盖度与多样性,避免所有检索块都集中在同一文档或同一段落,从而导致回答视野过窄。 +3. **检索–生成闭环优化** + 更高级的实践中,检索和生成不再是单向流程,而是形成闭环: + 1. 利用 LLM 对检索结果的“使用情况”进行分析(哪些块被引用、哪些块总是被忽略),反向指导索引和分块策略的优化; + 2. 利用对话日志中的“追问/纠错”信号,对召回失败、误召回的样本进行标注和再训练,提高系统对模糊查询、长尾问题的鲁棒性。 + +### 8.1.3 生成与引用:在“证据约束下”回答问题 + +最后一环是生成层,它直接决定了用户体验。这里的目标不是让模型“随心所欲”地发挥,而是让它在 **检索证据的约束下,给出清晰、有边界、有引用的回答** 。 + +1. **基于检索上下文的受控生成** + 在 RAG 架构中,LLM 接收到的不只是用户问题,还包括多段检索到的文档块以及系统指令。系统通常会: + 1. 通过 Prompt 约束模型“只根据给定文档回答”“如果文档中找不到答案就明确说明缺失”; + 2. 对检索上下文进行结构化组织(分段、编号、标注来源),方便模型理解与引用; + 3. 控制输出格式(列表、表格、分点说明等),适配下游系统或前端展示。 +2. **引用与可解释性(Source Citation)** + 为了便于审计与追溯,尤其在法律、医疗、金融、企业内部制度等高风险领域,回答中往往需要附带明确引用: + 1. 在输出中标注引用来源,如“[文档 A,第 3 章,第 2 节]”“[法规 X 第 12 条]”; + 2. 在前端界面中支持一键跳转到原文位置,便于用户核查和进一步阅读; + 3. 在后台保存“问题–检索结果–引用块–最终回答”的完整链路日志,为后续风控和模型改进提供数据。 +3. **先进 RAG 变体:HyDE / ReAct + RAG 等** + 为进一步提升难题场景下的效果,实践中还会使用更复杂的 RAG 变体: + 1. HyDE:由 LLM 先根据问题生成一个“假想答案文档”,再用该文档向量去检索真实文档,从而提高召回质量; + 2. ReAct + RAG:LLM 以“思考(Reasoning)+ 行动(Action)”的方式,在推理中多次调用检索工具,逐步细化问题、补充证据,类似“边思考边查资料”; + 3. 多轮 RAG:在对话过程中,保留历史检索结果和回答,形成上下文感知的长期知识会话,而不仅是“单问单检索”。 + +## 8.2 结构化数据与知识图谱(Structured Data & KG) + +如果说 RAG 主要解决“如何在大规模非结构化文档中查资料”,那么结构化数据与知识图谱这一层,则更多面向“如何优雅地用好数据库、报表系统和图数据库中的结构化知识”。 + +在企业环境中,真正关键的业务数据——订单、客户、合同、库存、行为日志——往往以关系数据库、数据仓库、OLAP 引擎或图数据库的形式存在。这些系统在查询能力、计算效率和审计方面已经非常成熟,但对于业务人员而言,直接写 SQL / DSL 仍然门槛较高。**Text‑to‑SQL / Text‑to‑DSL** 与 **知识图谱问答与推理** ,就是要让 LLM 在不破坏这些系统稳定性的前提下,作为“自然语言界面”和“推理协作伙伴”插入进来。 + +- **场景** + - BI 智能问答与自助分析:业务人员用自然语言发问(如“帮我看看最近 3 个月华东地区新客的复购率趋势”),系统自动生成 SQL,查询数据仓库,然后用自然语言和可视化图表返回结果。 + - 运营 / 销售分析助手:运营同学可以用对话的方式探索数据(“这个活动转化率为什么下降”“哪些渠道贡献了最多高价值用户”),在多轮对话中逐步细化条件和维度。 + - 领域知识中台:将实体、概念、规则和案例组织为知识图谱,支持围绕某个实体进行上下游关系探索和合规性检查。 + - 图数据库问答与推理系统:在风险控制、反洗钱、供应链分析等场景中,通过图数据库与 LLM 联合,对“关系链条”和“多跳推理”类问题进行回答与解释。 +- **原理** + 这一层的核心,是把 LLM 从“直接给答案的人”变成“会调用数据库与图数据库的助手”: + - 在数据库问答中,模型需要理解用户的自然语言意图,结合数据库 schema(表结构、字段含义、约束等),生成正确的 SQL / GraphQL / 内部 DSL,再对执行结果进行解释与可视化。 + - 在知识图谱场景中,系统需要先从文档和日志中抽取实体和关系,构建结构化图谱;然后在问答时由 LLM 负责把自然语言问题转译为图查询(如 Cypher),并基于查询结果进行多跳推理和解释。 + - 与 RAG 不同,这里强调的是 **对结构化数据与图结构的精确访问** ,一方面要保证语义正确、语法严谨,另一方面要控制侧写攻击、敏感数据暴露和高成本查询。 +- **模型** + 典型方案通常是“LLM + 专用组件”的多模块架构: + - Text‑to‑SQL 模型:在大规模 SQL 语料上预训练或微调的模型(如 PICARD、DIN‑SQL 等),侧重语法正确性与 schema 对齐,有时会搭配执行反馈进行自我修正。 + - 信息抽取与图谱构建 pipeline:通过实体识别(NER)、关系抽取、事件抽取等模块,从文本和日志中构建和更新知识图谱;LLM 可以参与难例抽取、边界模糊关系的辅助判断。 + - LLM + 图数据库联合问答:LLM 负责问题解析、查询生成与结果解释,图数据库(如 Neo4j 等)负责高效执行与多跳关系搜索,两者通过工具调用协议或中间 DSL 对接。 + +### 8.2.1 数据库问答(Text‑to‑SQL / DSL)实践 + +数据库问答的目标,是让业务人员“用自然语言问数据”,而系统在背后自动完成查询语句生成、执行与解释。要把这件事做好,关键在于兼顾 **语义准确性、语法正确性和执行安全性** 。 + +1. **自然语言到 SQL / DSL 的转换** + 在最基础的链路中,系统需要: + 1. 解析用户意图:识别出查询对象(如“华东地区新客”)、过滤条件(时间、地区、渠道)、聚合方式(总数、平均值、同比/环比)和展示需求(趋势、排行、Top‑N); + 2. 结合数据库 schema:理解哪些表与字段可以表达上述概念,如何进行关联(join)、分组(group by)和排序; + 3. 生成可执行的 SQL / GraphQL / 内部 DSL,并通过语法校验器或专门的 Text2SQL 模型(PICARD、DIN‑SQL 等)确保结构合法。 +2. **执行结果的自然语言解释与可视化** + 查询执行后,系统还需把“冷冰冰的结果集”变成“可理解的洞察”: + 1. 对简单结果进行文本解释,如“过去 3 个月华东地区新客的复购率整体呈上升趋势,从 15% 提升到 21%”; + 2. 对复杂结果选择合适的可视化形式(折线图、柱状图、饼图、分布图等),并给出简要分析; + 3. 支持用户基于当前结果继续追问(如“这波增长主要来自哪些渠道?”),自动在历史 SQL 和上下文的基础上构造新的查询。 +3. **安全与控制:防止“乱查”和“越权”** + 由于 LLM 生成的 SQL 具有高度灵活性,必须有一层安全与治理机制: + 1. 基于用户角色与权限,对可查询的库、表、字段和时间范围做严格限制; + 2. 为模型生成的 SQL 配备静态/动态审查规则,过滤危险操作(如大范围扫描、高成本 join、跨租户查询等); + 3. 将“自然语言问题–生成 SQL–执行结果–最终回答”完整记录,用于审计与异常分析。 + +### 8.2.2 知识图谱构建与查询 + +知识图谱试图把散落在文本、表格、日志中的知识,组织成“实体–关系–属性–事件”的结构化网络,从而更好地支持 **关系探索、多跳推理和复杂问答** 。在这一方向上,LLM 与传统信息抽取、图数据库形成了良好的互补。 + +1. **从文档中抽取实体和关系构建图谱** + 构建知识图谱通常采用多阶段 pipeline: + 1. 信息抽取:利用 NER、关系抽取、事件抽取等模型,从文本中识别实体(人、机构、产品、地名、概念等)、它们之间的关系(隶属、合作、依赖、因果)以及关键事件(交易、风险、变更); + 2. 规范化与对齐:将同一实体的不同表述(简称、别名、拼写变体)进行归一,对齐到统一 ID; + 3. 图谱更新与版本管理:支持增量更新、冲突解决和错误纠正,确保图谱在长期演化中保持质量与一致性。LLM 可以在歧义消解、关系类型细化、规则归纳等环节辅助传统算法。 +2. **LLM + 图数据库(Neo4j 等)的查询与推理** + 当图谱构建完毕,图数据库负责高效存储和检索,而 LLM 则可以扮演“自然语言入口 + 推理控制器”的角色: + 1. 问题解析与图查询生成:将自然语言问题转译为图查询语句(如 Neo4j 的 Cypher),包括确定起点实体、关系类型、路径长度与过滤条件; + 2. 多跳推理:通过图查询得到的路径和局部子图,再由 LLM 进行解释与归纳,如“客户 A 与高风险实体 B 之间通过三家公司间接相连”; + 3. 结果可视化与可解释性:将图查询结果以可视化网络形式呈现,同时由 LLM 给出口头说明,帮助用户理解复杂关系结构。 +3. **领域知识中台与统一服务** + 在更大规模的企业或行业级应用中,知识图谱往往作为“领域知识中台”存在: + 1. 为上层业务系统(风控、合规、客户 360 视图、供应链分析等)提供统一的实体和关系视角; + 2. 与 RAG、数据库问答共同构成统一的知识服务层,由统一的 LLM 编排逻辑决定当前问题该访问文档索引、关系数据库还是图数据库; + 3. 在安全和合规要求下,通过图谱层面的访问控制和脱敏策略,进一步降低敏感信息泄露的风险。 + +这一层的共同目标,是把“模型会说话”升级为“模型既会说话,又真正接上了企业的真实数据与知识资产”。当 RAG、Text‑to‑SQL、知识图谱与传统数据基础设施有效结合之后,AI 系统才能在复杂业务环境中既保持智能和灵活性,又具备可控性、可解释性和长期演化能力。 + +# 9. 安全、对齐与评估(Safety / Alignment / Evaluation) + +在前面的章节里,我们更多从“模型能做什么”出发:能看图、能写代码、能和用户对话。但在真实的大模型系统中,仅仅“有能力”远远不够:**怎么证明这些能力是稳定、可靠、可控的?怎么确保输出符合价值观和合规要求?在长周期运营中如何持续监控、迭代与回归?** +这一层关注的就是: **能力评估与基准测试、价值对齐与训练、内容安全与合规、以及鲁棒性与幻觉控制** ,共同构成一个可持续运营的大模型“基础设施层”。 + +从产品视角看,这些能力贯穿模型全生命周期:模型在实验室阶段需要标准 Benchmark 与专业评估;上线前要通过对齐训练与安全审查;上线后依赖内容安全网关、日志审计与 A/B 测试持续监控;面对新场景与新威胁时,又要回到评估与对齐环节重新训练和验证。下面我们从**能力评估与基准测试、价值对齐与训练、内容安全与合规、鲁棒性与幻觉控制**四个方向展开。 + +## 9.1 能力评估与基准测试(Capability Evaluation & Benchmarks) + +在大模型研发和落地过程中,**能力评估与基准测试**是把“模型能力”转化为“可观测信号”的关键一环:既要回答“这个模型总体水平怎么样”,也要回答“在某个专业领域、某种真实业务场景下表现如何”。一方面,我们通过标准化的基准集与自动评测体系,去衡量模型在**语言理解与生成、推理与数学、知识与事实性**等通用维度上的表现;另一方面,还需要针对**医疗、法律、金融、教育**等专业领域构建专门评测,并在**真实用户对话、AB 测试和业务指标(Task Success Rate、CSAT、工单关闭率等)中不断验证与修正。整体上,这一层最终会沉淀为内部的能力评估平台**与对外的“ **能力说明书** ”,并为多版本、多租户、多场景的模型选型提供统一决策依据。下面从 **场景** 、 **原理** 、**模型**三个角度展开。 + +- **场景** + - **通用能力评估场景** :在基础模型或大版本更新时,需要系统性地评估其在阅读理解、摘要、翻译、对话质量等**语言理解与生成**任务上的表现,以及在算术、多步推理、代码/逻辑题等**推理与数学**任务中的能力,同时通过事实问答、开放域 QA、知识覆盖度任务衡量其**知识与事实性**水平,用于判断“新模型是否整体抬升”。 + - **专业领域评估场景** :对于医疗、法律、金融、教育等细分领域,需要设计专业问答与决策模拟,比如疾病问答与分诊建议、法律条文理解与案例归类、投融资分析与风控判断、教学答疑与作业辅导,并在**多语言、多文化环境**下测试模型的一致性与稳定性,确认其能否在高风险环境中“说对话、说适当的话”。 + - **真实场景与业务指标评估场景** :在产品上线和持续运营阶段,通过用户对话日志回放、线上 AB 测试等方式,将模型表现映射到 **任务完成率(Task Success Rate)** 、 **用户满意度(CSAT)** 、**工单关闭率**等业务指标;此时评估对象实际是“模型 + 策略 + 产品流程”的整体系统,用于指导版本回滚、策略调优和新功能放量。 +- **原理** + 能力评估体系可以看作一个分层的“测量系统工程”,其核心原理包括: + - **标准基准集:公共刻度与可复现实验** + - 语言 / 推理:使用 **MMLU** 、**BIG-Bench** 等综合性任务,配合 **GSM8K** 、**MATH** 等数学与逻辑题目,构建对语言理解、知识掌握、多步推理的统一刻度。 + - 编程:通过 **HumanEval** 、 **MBPP** 、**Codeforces** 题库等,量化代码生成、程序修复与问题求解能力。 + - 多模态:利用 **VQA** 、 **MMBench** 、 **ScienceQA** 、**MathVista** 等基准测试图文理解、视觉问答和图像中的数学推理。 + 这些基准强调 **标准化、可复现、可对比** ,便于跨模型、跨机构进行横向对比和对外披露。 + - **自动评测:规模化与持续回归** + - **LLM-as-a-Judge** :用更强或专门训练的模型对回答进行打分/排序,评价正确性、完整性、风格和安全性,实现大规模自动主观评测。 + - **基于规则的度量** :如 BLEU / ROUGE / BERTScore 衡量文本相似度,Pass@k 衡量代码题通过率等,使得在固定数据集上可以快速比较不同版本的差异。 + 自动评测的关键在于 **稳定性与一致性** ,即便不完美,只要“偏差一致”,就可以在持续集成(CI)中可靠地反映模型相对变化。 + - **人工评测:对齐人类感知与业务目标** + - **Pairwise 对比与打分标注** :由标注员对 A/B 两个模型回答做 pairwise 选择或多维度打分(helpful / honest / harmless 等),是训练 RLHF / RLAIF 奖励模型的重要数据来源。 + - **线上用户实验** :通过对话助手、搜索/推荐等落地场景做 AB 测试,直接观察不同模型 / 策略对用户满意度、转化率等指标的影响。 + 人工评测既用于 **校准自动评测** ,也是对外“解释模型行为”时的重要依据。 +- **模型** + 在工程实践中,能力评估会沉淀为一套相对完整的“平台 + 流程 + 指标体系”: + - **内部能力评估平台与 CI 流水线** :统一管理各类基准集、评测脚本、LLM-as-a-Judge 配置与人工标注工具,支持新模型或新策略提交后一键触发 Benchmark 回归;自动汇总不同任务和维度的指标变化,提供可视化 Dashboard 与回归告警。 + - **对外“能力说明书”与模型画像** :将内部评估结果整理为对外可消费的“能力说明书”,包括代表性基准成绩、推荐适用场景(如通用对话、代码辅助、多模态理解等)、已知局限与不适用场景,帮助客户形成正确预期,也为合规和责任划分提供依据。 + - **多租户 / 多版本模型统一评测与选型工具** :在同一套评估体系下,统一比较不同尺寸、不同对齐策略或不同架构的模型,支持按行业、地区、SLA 要求配置权重,自动生成“性能–成本–延迟”综合评分,帮助产品和业务方做模型选型与灰度发布决策。 + +### 9.1.1 通用与专业能力评估:从 Benchmark 到场景验证 + +通用与专业能力评估是整个评估体系的“第一层地基”,重点在于:先用统一刻度衡量模型的 **基础能力** ,再在专业场景中验证其 **可用性与风险** 。 + +在通用能力评估中,通常会将任务拆分为语言理解与生成、推理与数学、知识与事实性三个维度:前者通过阅读理解、摘要、翻译、对话质量任务,检查模型是否能准确理解上下文、控制风格并输出连贯文本;中者通过算术、多步推理、代码 / 逻辑题,评估模型在复杂推理链和程序结构上的能力;后者则通过事实问答和开放域 QA 度量知识覆盖度和事实性水平。在专业领域评估中,则需要邀请行业专家参与数据设计:如医疗问答中设定病史、化验结果等上下文,要求模型在回答中给出风险提示和就医建议边界;法律任务中设计条文检索、案例比对、法律适用分析;金融与教育中则聚焦合规披露与教学引导。这一层评估往往结合标准基准集与自建数据集,既追求可对比性,也兼顾业务相关性。 + +### 9.1.2 自动评测与 LLM-as-a-Judge:让评估可扩展 + +当任务规模和模型版本数迅速增长后,仅依赖人工已经难以支撑评估需求,此时需要通过自动评测体系实现 **规模化与高频回归** 。 + +一类做法是利用传统的基于规则度量:在翻译、摘要等任务上,用 BLEU / ROUGE / BERTScore 与参考答案对比,在代码任务上用 Pass@k 测试在多个生成样本中是否至少有一个通过单测。这类指标实现简单、可高度自动化,但对答案多样性与风格细节不敏感。另一类更具代表性的做法是 **LLM-as-a-Judge** :将更强或专门训练的模型用作“打分裁判”,根据预定义的评分 Rubric,对被测模型输出进行维度化打分或 Pairwise 排序。这允许我们在没有标准答案、回答多样的开放问答和对话任务中也进行高效自动评估。实际工程中,LLM-as-a-Judge 的评分标准和 Prompt 需要经过人工标注数据校准与迭代,以确保其与人类评委的一致性。 + +### 9.1.3 人工评测与业务指标:闭环到真实用户体验 + +再完备的离线指标,也只能近似真实用户体验。为了把能力评估闭环到业务,需要引入人工评测与线上实验两类手段。 + +人工评测侧,常见的是 Pairwise 对比:让标注员在看不到模型身份的前提下,基于 helpful / honest / harmless 等维度,对 A/B 两个回答做偏好选择或打分,从而得到高质量偏好数据,一方面用于直接评估,另一方面可以为 RLHF / RLAIF 训练奖励模型提供数据。在业务侧,则通过线上 AB 测试,对比不同模型、提示词、策略配置版本对任务完成率、用户满意度(CSAT)、工单关闭率等关键指标的影响,辅以用户对话日志回放和人工抽检,持续监控模型上线后的真实表现。这一层评估的输出又会反过来指导能力评估平台的重点方向和权重调整,形成“离线指标—人工评测—线上指标”的闭环。 + +## 9.2 价值对齐与训练(Value Alignment & Training) + +在拥有强大基础能力之后,大模型要成为“安全、可靠、可控”的产品,还必须经历 **价值对齐与训练** 。这一层关注的不再是模型“能不能回答”,而是“ **回答得是否有用、诚实、无害** ”以及“在不同角色和行业中应该如何说话”。从工程角度看,对齐过程大致包括三步:首先通过文档与规范明确 **对齐目标定义(What to Align)** ,将有用(Helpful)、诚实(Honest)、无害(Harmless)拆解为可标注、可训练的标准;其次构建覆盖广泛的 **指令数据与安全数据** ,涵盖正常任务、灰区案例与不合适回答;最后通过 **SFT、RLHF / RLAIF、拒答/重定向策略建模** 等方法,将这些偏好与规则“写进”模型行为中,并辅以上游对话管理与策略引擎,实现端到端的安全对齐。下面同样从 **场景** 、 **原理** 、**模型**三个角度展开。 + +- **场景** + - **通用 C 端助手场景** :面向大众用户的聊天助手、信息检索助手,需要在广谱话题下保持“ **友好、有帮助、不越界** ”:既要回答得专业、聚焦任务,又要在不确定时坦诚表达局限,对明显不当需求进行拒答或柔性引导。 + - **专业行业助手场景** :在医疗、法律、金融、教育等领域,除了基础安全,还要叠加行业规范:例如医疗助手需要反复强调“非诊断性质 + 风险提示 + 建议就医”,法律助手要避免提供违法规避建议,金融助手要遵守投资合规披露要求,教育助手要考虑未成年保护与适龄内容。 + - **B 端可配置对齐层场景** :企业往往希望在通用安全基线之上,进一步嵌入自身的行业要求、品牌语气和内部政策,因此需要一个 **可配置的对齐层** ,允许客户自行配置安全阈值、敏感类别和话术风格,而不必重训底层大模型。 +- **原理** + 价值对齐可以理解为“用人类和组织的价值观约束模型的行为空间”,其核心原理包括: + - **对齐目标定义(What to Align)** + - **有用(Helpful)** :回答应高质量、专业、结构清晰、聚焦任务目标,不过度发散和闲聊。 + - **诚实(Honest)** :尽量不胡编乱造,在知识缺失或理解不清时主动承认不确定性、给出估计范围或建议查证渠道。 + - **无害(Harmless)** :遵守法律与平台政策,避免生成仇恨、歧视、自残鼓励、违法犯罪指导等内容,并尊重用户的尊严与边界。 + 这些目标会被写入标注指南与策略文档,成为后续数据构建、奖励建模和评测的统一标准。 + - **对齐训练数据构建** + - **指令数据(Instruction)** :设计覆盖广泛的任务指令与理想回答,涵盖问答、写作、总结、代码、规划等多种场景,教会模型在“正常请求”下的最佳行为。 + - **安全数据(Safety)** :构建“好的回答 vs 不合适回答”对照样本,特别注重灰色边界(gray zone),如科普信息 vs 具体操作、情绪支持 vs 自残鼓励、合法辩论 vs 仇恨煽动等,为模型提供细粒度的边界示例。 + - **对齐训练方法** + - **SFT(Supervised Fine-Tuning)** :在高质量对话 / 指令数据上进行有监督微调,是塑造模型基准行为和语气的第一步。 + - **RLHF / RLAIF** :通过人类或模型打分构建偏好数据,训练奖励模型,然后进行策略优化,让模型在生成时倾向于被“偏好”的回答(更有用、更安全、更诚实)。 + - **拒答 / 重定向策略建模** :针对高风险或不适当请求,训练模型不仅会拒答,还能给出合理解释并引导用户到安全替代方案(例如提供求助资源、鼓励咨询专业人士等)。 +- **模型** + 在系统设计上,价值对齐通常体现为“ **底层对齐训练 + 上层策略护栏** ”的组合: + - **SFT + RLHF / RLAIF 对齐模型** :SFT 阶段让模型学会理想回答的基本模式;RLHF / RLAIF 阶段则通过偏好学习进一步“收紧”行为,使其更贴近人类偏好与安全标准。在安全维度上,可以单独为有害性构建奖励头或分类器,用于在策略优化中施加惩罚。 + - **Constitutional AI / Policy-based Alignment** :通过先撰写一套“宪法(Constitution)”或 Policy 文档,再让模型根据这套规则进行自我批评与重写,生成大量“自监督批改数据”,在减少人工成本的同时强化模型对规则的内化。 + - **对话管理与意图检测协同** :在产品管线中,将安全 / 对齐逻辑部分上移到对话管理层,通过意图识别、槽位填充、任务路由决定请求是否交给大模型、是否需要额外的安全过滤或模板化回复。这样可以形成“模型对齐 + 策略护栏”的双重保险。 + - **内部对齐平台与角色配置** :建设内部对齐平台,提供标注 / 打分工具、策略版本管理和训练流水线;同时支持为不同角色(客服、医疗建议、教育辅导等)配置差异化对齐目标和话术风格,使同一底座模型在不同产品中展现出截然不同但可控的一致人格。 + +### 9.2.1 对齐目标与训练数据:把价值变成可学习信号 + +价值对齐的第一步,是把“抽象价值观”转译成模型可以学习的信号,而这离不开对齐目标定义和训练数据构建。 + +在对齐目标层面,团队通常会输出一套详细的行为规范文档,将 Helpful / Honest / Harmless 拆解为具体条款,如:禁止给出某类高危操作的具体步骤、对于医疗/法律建议必须附带免责声明和风险提示、在涉及争议话题时保持中立与多视角呈现等。接着,在指令数据阶段,会围绕这些指标构建多样化任务与理想回答,涵盖聊天、写作、代码、问答等场景,并融合多语言、多文化背景;在安全数据阶段,则针对有害内容、高风险领域与灰色地带,构建成对的“好 / 坏回答”示例,为后续偏好学习和安全分类器提供训练素材。通过这种方式,价值目标被“翻译”为实际数据分布,成为模型训练可以直接感知的信号。 + +### 9.2.2 SFT、RLHF / RLAIF 与拒答策略:塑形模型行为 + +有了对齐目标和数据之后,下一步是通过多阶段训练过程将这些目标写入模型行为。 + +在 SFT 阶段,模型在高质量人类示范数据上进行有监督微调,这类似于“教科书式学习”:它决定了模型在绝大多数正常请求下的语气、结构和解决问题的标准范式。随后,通过 **RLHF\*\*** / RLAIF** 进行偏好优化:先利用人类标注或更大 LLM 产生的偏好标签训练奖励模型,再使用策略优化算法(如 PPO 等)调整模型,使其在生成中倾向于获得更高奖励。这样,模型不仅“知道正确答案长什么样”,还知道“哪种答案更符合人类偏好和安全要求”。在此基础上,还会专门建模各种 **拒答与重定向策略\*\* :对于明显违法、极高风险或不适合由 AI 回答的问题,模型应该学会给出清晰的拒绝与解释,并提供安全的替代路径(如求助热线、专业咨询等),而不是简单沉默或随意搪塞。 + +### 9.2.3 策略层与对齐平台:让对齐可配置、可演进 + +即便底层模型已经进行了充分对齐训练,在实际系统中仍需要**策略层与对齐平台**来实现更细粒度的可控性和可演进性。 + +策略层通常包含意图识别、风险评估与路由逻辑:当用户输入到达系统时,先由轻量模型判断其意图、领域和风险等级,再决定是否直接调用大模型、是否需要额外安全过滤、是否落入模板回复或转人工渠道。对于不同行业和客户,策略层可以加载不同的 Policy 配置,实现对敏感类别、拒答风格和品牌语气的定制。与此同时,内部对齐平台会管理所有对齐相关资产:标注/打分工具、奖励模型版本、策略变更记录、在线 A/B 结果等,使团队可以在不频繁重训底座模型的前提下,对对齐策略进行快速迭代和灰度发布,从而保持对模型行为的持续掌控。 + +## 9.3 内容安全与合规(Content Safety & Compliance) + +随着大模型被嵌入到搜索、对话、内容创作、社交平台乃至企业内部系统中,**内容安全与合规**从“附加功能”变成了“准入门槛”。这一层关注的是:模型在生成文本、图像、音视频时,是否会产生违法有害内容;系统在处理用户数据时,是否符合所在国家/地区和所属行业的法律法规;以及在面对审计与监管时,能否给出清晰可追溯的证据链。为此,我们需要构建覆盖**多模态内容审核、区域与行业合规、本地隐私与数据保护**的完整技术与治理体系,并将其封装为 SaaS 内容安全服务、企业合规中台和行业安全网关等产品形态。下面同样从 **场景** 、 **原理** 、**模型**三个角度展开。 + +- **场景** + - **多模态内容审核与过滤场景** :在对话产品、UGC 平台、社区与社交应用中,大模型会生成或接收大量文本、图像、音视频内容,需要通过统一的**多模态审核**能力,实时识别并拦截涉及个人隐私、违法犯罪指导、仇恨煽动、极端暴力、色情与未成年人不当内容等高风险输出。 + - **合规约束与本地化场景** :不同国家/地区的法律法规对数据保护、未成年人保护、内容监管等有不同要求;不同行业(医疗、金融、教育、广告等)也有细化的合规规范。因此系统必须支持按**地区与行业**加载不同策略模板,以符合当地监管要求。 + - **用户隐私与数据保护场景** :在模型训练和在线服务过程中,需要处理大量用户对话和业务数据,如何实现数据匿名化、脱敏和最小采集,同时在训练和推理阶段通过技术和制度手段保护隐私,是内容安全与合规体系的另一根支柱,尤其在金融、医疗等高敏感行业。 +- **原理** + 内容安全与合规的底层原理可以分为策略、过滤和隐私三个层面: + - **安全策略系统(Policy Engine)** + - 将法律法规、平台规则、行业规范 **形式化为可执行策略** ,通过规则引擎结合模型打分,对内容进行风险分级(安全 / 灰区 / 高危)。 + - 支持按场景和客户选择不同策略模板,例如为青少年产品、专业社区或跨国企业配置不同的敏感类别与阈值。 + - **多级内容过滤:事前–事中–事后** + - **事前** :对用户 Prompt 做拦截与重写(Prompt Shielding),在请求进入大模型前阻断明显违法或高度敏感的意图,或将其引导为较为安全的表达方式。 + - **事中** :在模型生成输出时,利用安全分类模型与规则对内容进行实时审查(Real-time Safety Filter),对高风险内容进行截断、替换、打码或触发拒答。 + - **事后** :对对话和生成日志做抽样审计与人审复核,对发现的问题进行溯源分析,进而更新策略和模型,并为外部监管提供可追溯的记录。 + - **隐私保护技术与\*\***数据治理\*\* + - 在数据存储和训练前,对用户对话数据进行 **匿名化与脱敏处理** ,移除或替换姓名、身份证号、手机号、地址等敏感字段,并遵循**最小采集原则**只保留必要信息。 + - 在某些场景中采用**差分隐私(DP)**限制单个样本对模型参数的影响,或者通过**联邦学习(FL)**将训练留在本地数据域,避免原始数据上云。 + - 利用 **RBAC\*\*** / \***\*ABAC** 等访问控制机制,严格限制谁可以访问什么级别的日志与敏感数据,并配合审计日志保证访问路径可追踪。 +- **模型** + 从产品与系统设计角度看,内容安全与合规最终会演化为一系列可复用的“安全服务与中台”: + - **SaaS 内容安全服务** :将文本 / 图像 / 音视频审核能力封装为统一 API,对接上游应用;输入内容,输出风险类型、分级和处理建议(放行、拦截、人审),帮助开发者快速集成安全模块。 + - **企业内部合规中台** :为大型企业提供集中管理的合规策略配置、审计报表和风险告警能力,对接内部的业务系统和人审团队,使各业务线在统一策略下执行自定义规则,并满足外部监管报告需求。 + - **高风险行业专用安全网关与日志审计系统** :在金融、医疗等高风险行业,通过专用安全网关代理所有大模型调用,对流量进行实时检查与脱敏,将关键日志留存在本地或合规区域,提供详尽的访问审计和事件追溯能力,满足严格的监管要求。 + +### 9.3.1 多模态审核与策略引擎:把规则变成“可执行的代码” + +实际的内容安全系统,首先要能“看懂”来自不同渠道与模态的内容,然后才能将策略落地到每一次请求与响应上。 + +在多模态审核方面,系统通常会构建文本、图像、视频等多种检测模型:文本侧模型识别敏感关键词、上下文语境和隐晦表达;图像和视频侧则检测暴力、色情、未成年人、仇恨符号和违法物品等内容,并在必要时结合 OCR、ASR 和视觉特征进行联合判断。策略引擎则把这些模型输出与法规要求绑定在一起:例如,在某一地区对赌博或政治内容有更严格限制,就可以在对应策略模板中提高相关检测类别的敏感度,或对命中这些分类的内容强制转人工复核。通过把抽象规则转化为规则链、阈值和动作(放行/拦截/人审/打码),Policy Engine 让合规要求真正“跑起来”。 + +### 9.3.2 多级过滤与日志审计:构建端到端安全闭环 + +单一环节的拦截很难覆盖所有风险,因此内容安全体系普遍采用**事前–事中–事后**三层防线的设计。 + +在事前阶段,系统会对用户输入进行快速检测,对明显违规或高度敏感的 Prompt 直接拒绝或重写,引导用户以安全方式提问;对于边界尝试和模糊请求,也可以主动补充声明和风险提示。在事中阶段,模型输出会经过实时安全过滤组件:该组件会利用文本分类和规则匹配,对潜在高危输出进行剪裁、替换或触发拒答流程,确保最终呈现给用户的内容落在可接受范围内。事后阶段,则通过日志审计与抽检机制,由安全团队或可信的自动系统定期回放与检查会话,分析误判、漏判和新型风险样式,并据此更新策略、训练数据和检测模型。这样形成一个持续演进的安全闭环,而不是“一次性配置”。 + +### 9.3.3 隐私保护与行业安全网关:让数据安全“可证明” + +在高敏感行业中,仅仅“不输出有害内容”还远远不够,还要证明“内部对用户数据的使用同样安全、合规、可追踪”。 + +隐私保护从数据进入系统开始:在采集和存储阶段就尽量进行匿名化和脱敏,确保即使日志泄露也难以直接关联到具体个人;在训练阶段,则通过差分隐私、采样策略或联邦学习减少单个用户数据对最终模型的影响和外泄风险。对于模型推理流量,则通过**安全网关**进行统一接入管控:所有请求与响应都要经过网关的内容检查、权限校验和审计记录,必要时根据业务线和用户角色应用不同的访问策略与数据视图。最终,这些日志和策略变更记录会沉淀为可供内部审计和外部监管查看的“证据链”,使企业不仅在事实上合规,而且在形式上“可证明自己合规”。 + +# 10. AI for Science(AI4Science) + +当深度学习和大模型从“推荐广告、理解自然语言”走向 **科学问题本身** ,目标不再只是预测一个指标或做一个分类,而是要真正参与到**发现规律、设计实验、加速仿真与推理**之中。AI4Science 试图把“统计模式识别”与“物理定律 / 生物化学规律 / 数学结构”结合起来,让模型在分子设计、蛋白工程、材料发现、物理仿真、数学推理等环节中充当“可编程的科学助手”。 + +在工程实践中,这一层一端连接量子化学软件、分子动力学(MD)、CFD/FEA 仿真器、自动定理证明器、文献数据库和自动化实验室(Robotic Lab)等“传统科学基础设施”,另一端连接制药公司、材料企业、能源公司、科研机构的真实科研工作流。下面从 **场景** 、 **原理** 、**模型**三个角度展开,并在若干关键方向上进一步细分。 + +- **场景** + - 分子与药物设计:从海量小分子 / 片段出发,预测性质与 ADMET,设计针对特定靶点的候选药物,并通过虚拟筛选和多目标优化缩小实验空间。 + - 蛋白质与生物结构建模:预测蛋白及复合物的三维结构,辅助抗体、酶、蛋白药物设计,评估突变对功能与稳定性的影响。 + - 物理仿真与工程设计:用深度替代模型加速 CFD / FEA / 分子动力学等高成本仿真,为航空航天、汽车、能源等领域提供快速评估与优化工具。 + - 材料发现与晶体设计:在庞大化学 / 材料空间中进行虚拟筛选和逆设计,加速电池、光伏、催化剂、合金等关键材料的研发。 + - 数学与符号推理:在形式系统中做自动定理证明、符号计算和方程求解,增强大模型在数学题、工程推导中的严谨推理能力。 + - 科学工作流与自动化实验:对接文献、数据库与自动化实验平台,构建“自驱动实验室(Self‑Driving Lab)”,让模型参与实验设计、执行与结果分析。 +- **原理** + - 结构化表示与图建模:用图(Graph)、晶体图(Crystal Graph)、分子图等结构表征复杂对象,在图神经网络或 E(3)-等变网络上建模几何与拓扑关系。 + - 物理 / 化学归纳偏置:通过守恒定律、对称性(平移 / 旋转 / 反射)、PDE 约束(PINN)、能量势函数等方式,将物理先验融入模型结构与损失函数。 + - 生成与逆设计:利用 VAE、GAN、Diffusion、RL 等生成式建模方法,支持从“目标性质 / 约束条件”反推结构,实现分子 / 材料 / 结构的逆设计。 + - 代理模型与多尺度耦合:用深度代理模型近似昂贵的量子化学 / 连续介质 / 结构力学仿真,并将微观–中观–宏观模型拼接起来,实现多尺度建模。 + - 工具增强与 Agent 工作流:将 LLM 与模拟器、符号计算器、自动定理证明器、文献检索系统和实验机器人组合,构建可自动规划和执行科学任务的 Agent。 +- **模型** + - 分子与材料表征模型:SchNet、DimeNet、PhysNet、CGCNN、MEGNet、ALIGNN 等 E(3)-等变网络与图网络,ChemBERTa、MolBERT、MoleculeSTM 等分子语言模型。 + - 结构生物学模型:AlphaFold / AlphaFold2 / AlphaFold3、RoseTTAFold、OpenFold、ProteinMPNN、ESM‑IF、ESM 系列蛋白语言模型与结构生成模型。 + - 物理仿真与算子学习:PINN、DeepONet、Fourier Neural Operator (FNO) 及 Neural Operator 家族、DeepMD、NequIP 等势能面与算子学习模型。 + - 数学与符号推理模型:Minerva、Gödel、GPT‑f、Lean‑Dojo 等数学 / 证明专用模型,以及 LLM + SymPy/Mathematica/Lean/Coq 的工具增强系统。 + - 科学 Agent 与工作流系统:结合检索、代码生成、仿真调用与实验控制接口,为制药、材料、物理、化学等领域封装的“AI 科学助手”和自驱动实验平台。 + +从这一层开始,传统科学计算与深度学习、大模型深度交织:既要尊重物理 / 化学 / 生物 / 数学的严格约束,又要利用数据驱动的强拟合能力提升效率,最终目标是让 AI 成为科研中的“合作者”,而不仅仅是一个预测黑盒。 + +--- + +## 10.1 分子与药物设计(Molecular Modeling & Drug Discovery) + +在传统药物研发中,从靶点发现到临床试验往往需要 10+ 年和数十亿美元成本,而极大一部分时间与资金耗费在早期的分子设计、性质预测和虚拟筛选阶段。AI 驱动的分子建模与药物设计,旨在用**数据驱动 + 生成式建模**加速这一过程:从结构或文本描述出发,预测分子性质与 ADMET,设计针对特定靶点的候选化合物,并通过多目标优化与虚拟筛选显著减少湿实验负担。 + +这一方向一端连接量子化学软件(DFT、ab initio)、生物活性实验、HTS(High‑Throughput Screening)等数据来源,另一端连接药企内部的 Small Molecule Design 平台、性质预测 SaaS、材料 / 化学品设计工具。下面从 **场景** 、 **原理** 、**模型**三个维度展开。 + +- **场景** + - 早期虚拟筛选与 Hit 发现:面对数百万到数十亿规模的虚拟分子库,通过 AI 快速预测活性 / ADMET,对候选分子排序,筛出少量高价值 Hit 进入实验环节。 + - 分子性质与 ADMET 评估:在先导化合物优化(Lead Optimization)阶段,持续预测溶解度、毒性、代谢稳定性以及口服生物利用度等指标,为药代动力学和安全性评估提供参考。 + - 靶点导向分子生成:给定蛋白靶点信息(口袋特征、已知配体)或目标性质约束,自动生成结构多样、具有高活性且可合成的候选小分子。 + - 材料与化学品分子设计:面向非药物场景,如涂料、溶剂、电解液、界面活性剂等分子,设计满足特定物性(黏度、极性、界面能等)的配方分子。 +- **原理** + - 分子表征与性质预测: + - **结构表示** :常见有 SMILES 序列、分子图(原子为节点、键为边)、3D 坐标及量子特征等;模型需要从这些表示中抽取可泛化的语义与几何信息。 + - **性质预测** :通过 GNN(GCN、GAT、MPNN)或 3D‑等变网络(SchNet、DimeNet、PhysNet 等),从分子图或 3D 结构中学习到能量、偶极矩、轨道能级等量子性质,以及溶解度、LogP、毒性、代谢稳定性等 ADMET 属性。 + - **表征学习与预训练** :基于大规模分子库(如 ZINC、ChEMBL、PubChem)进行掩码预测、对比学习或自回归预训练,得到可迁移的通用分子表示,为下游 QSAR / ADMET 提供特征。 + - 结构生成与分子优化: + - **生成建模** :利用 VAE、GAN、Flow、Diffusion 等生成式模型,在 SMILES 或分子图空间中采样新分子,要求保证化学结构合法性(价态、环结构等)与多样性。 + - **条件生成** :引入条件向量(目标活性、理化性质、结构片段、靶点口袋描述等),在给定约束下生成候选分子,实现性质导向或片段补全式的设计。 + - **多目标优化与 RL** :通过强化学习(如 MolDQN 等)在分子空间中进行“编辑”操作(加原子、改键、替换片段),从而在活性、毒性、合成可行性、专利避让等多个目标之间权衡。 + - 蛋白 – 小分子相互作用建模: + - **结合位点与打分函数** :通过 3D 卷积 / 图网络 / 互作图建模蛋白口袋与配体的空间关系,预测结合位点及结合亲和力(Binding Affinity)。 + - **对接与 Binding Pose 预测** :将 Docking 中的构象搜索与深度模型结合,用深度打分函数或 Diffusion 式生成预测稳定构象,提高对接准确率并降低计算成本。 +- **模型** + - 分子表征模型: + - **GNN 与 3D 网络** :DimeNet / DimeNet++、SchNet、PhysNet 等考虑角度 / 距离的 3D 等变模型,GCN/GAT/MPNN 等通用图神经网络,适用于性质预测与 QSAR。 + - **基于 SMILES 的 Transformer** :将分子视为“化学语言句子”,用 Transformer 做自回归或掩码语言建模,为生成与性质预测提供序列表示。 + - 生成与优化模型: + - 图生成模型:GraphVAE、Junction Tree VAE、GraphAF 等在图 / 片段空间生成分子,强调结构合法性与可解释性(片段级构造)。 + - 扩散模型:Diffusion for Molecules 通过在图或 3D 结构空间添加 / 去除噪声生成新分子或构象,可与条件向量结合实现定制生成。 + - 强化学习优化:MolDQN 等基于 RL 的方法,将分子优化视作在“分子编辑”状态空间中的序列决策问题,用奖励函数编码多目标指标。 + - 分子大模型与多模态方向: + - **分子语言模型** :ChemBERTa、MolBERT 等在大规模 SMILES 语料上预训练,支持零样本或小样本转移至下游任务。 + - **多模态分子模型** :MoleculeSTM 等整合结构(图 / 3D)、文本描述(合成路线、文献摘要)、分子属性,实现跨模态检索与联合预测。 + - 产品与应用形态: + - 面向药企的早期药物筛选平台与内部 Small Molecule Design 平台,提供虚拟筛选、分子生成、ADMET 预测等一体化能力。 + - 面向研发人员的性质预测 SaaS:通过 Web 或 API 方式快速查询分子性质、ADMET、分子相似度等。 + - 面向材料与化学品设计的分子级设计工具,用于涂料、溶剂、电解液等分子体系的定制开发。 + +从这一子方向开始,药物设计流程正在从“专家 + 高通量实验”走向“专家 + 模型 + 自动化实验”的闭环,AI 不只是给出分数,而是逐渐参与从“提出想法”到“生成候选”再到“筛选与优化”的完整环节。 + +### 10.1.1 分子表征与性质 / ADMET 预测 + +在药物与材料研发中,一个基础能力是: **给定一个分子,快速且准确地预测其性质与行为** ,包括量子化学性质(能量、轨道、偶极矩)、理化性质(溶解度、LogP)、以及药代 / 毒性相关的 ADMET 指标。这一问题的本质,是如何从不同形式的分子表示中学习到 **既符合化学规律,又具备泛化能力的表征** 。 + +- 在**分子表征**层面,常见的表示包括: + - **SMILES / SELFIES 等字符串** :把分子视为序列,天然适合用 RNN / Transformer 进行语言建模。 + - **分子图表示** :原子为节点、键为边,节点和边带有类型、价态、芳香性等特征;适合用 GNN、MPNN 等建模邻域与拓扑。 + - **3D 几何表示** :基于量子化学或力场优化得到的 3D 坐标、键角、二面角等信息,为 E(3)-等变网络捕捉空间结构提供基础。 +- 在**性质与 ADMET 预测**层面,目标任务包括: + - 小分子量子性质预测:能量、偶极矩、HOMO/LUMO 能级等,用以替代昂贵的 DFT / ab initio 计算。 + - QSAR / 活性预测:给出化合物对特定靶点的活性(IC50、Ki)、选择性等,用于筛选潜在候选。 + - ADMET 相关指标:溶解度、渗透性、毒性、代谢稳定性、CYP 抑制等,是药物可成药性评估的关键。 + +典型模型路径为:用 DimeNet / SchNet / PhysNet / GNN 等在分子结构上提取高维表征,再通过多任务学习同时预测多种性质;在大规模公开或企业内部数据上进行预训练,提高小数据场景的建模能力。对外则以 ADMET 预测 SaaS 或内部平台 API 的形式提供服务,为项目组提供快速的“虚拟实验”能力。 + +### 10.1.2 结构生成与分子优化:从 SMILES / Graph 到候选药物 + +在具备了可靠的分子表征与性质预测模型之后,更进一步的目标是 **主动生成“更好”的分子** :不再只是评估给定化合物,而是围绕靶点与性质约束,直接设计出新的候选分子。这一方向通常被称为 **分子生成与分子优化** 。 + +在**结构生成**方面,研究与工程实践主要围绕三类路径: + +1. **基于 SMILES 的序列生成** + 将分子视作字符串,使用 VAE、GAN 或自回归 Transformer 在 SMILES 空间中采样新结构;通过语法约束(如 SELFIES)或后处理保证化学有效性。 +2. **基于图 / 片段的生成** + GraphVAE、Junction Tree VAE、GraphAF 等模型直接在分子图或基元片段(Fragement / Motif)层面构造结构,更贴近化学合成思维,有利于控制环、基团与骨架结构。 +3. **基于扩散与 3D 生成** + Diffusion for Molecules 等方法在图或 3D 坐标空间进行扩散与去噪,可同时考虑空间构象,适用于生成对 3D 形状敏感的配体或材料单元。 + +在**分子优化**方面,关键是引入 **目标与约束** : + +- **条件生成** :把目标活性、理化性质或片段锚定作为条件向量输入模型,使其在生成时偏向满足这些条件。 +- **强化学习与多目标优化** :以性质预测模型为“环境”,用 RL 在分子空间中做序列决策(如 MolDQN),在活性、毒性、合成可行性、专利风险等多维指标上设置奖励与惩罚,实现多目标权衡。 +- **合成可行性与化学先验** :在生成与优化过程中融入合成路径预测模型、合成复杂度指标(如 SA score),避免产生难以合成或不稳定的结构。 + +在产品化上,这一类模型常被封装进药企内部的“AI 药物设计平台”中:给定靶点、已知先导结构和优化方向,平台自动提出若干批次候选分子,项目组再结合实验、专利和商业考量逐步筛选与迭代,实现“模型–实验–模型”的闭环优化。 + +## 10.2 蛋白质与生物结构建模(Protein & Structural Biology) + +在生命科学中,**结构决定功能** 是一条近乎教条的原则:蛋白质如何折叠成三维结构、如何与其他分子装配成复合物,直接决定了其在细胞中的功能表现。传统结构解析依赖 X‑ray 晶体学、NMR、冷冻电镜等实验手段,周期长、成本高且存在“难结晶、难解析”的巨大盲区。以 AlphaFold 为代表的深度学习模型,把“从序列直接到结构”的能力大幅推前,使得在全基因组尺度上获得高质量结构成为可能。 + +这一方向一端连接 UniProt / PDB 等序列与结构数据库、组学实验与结构组学项目,另一端连接生物制药、合成生物学、酶工程等产业界的结构设计与分析平台。下面同样从 **场景** 、 **原理** 、**模型** 三个角度展开,并进一步拆分关键子方向。 + +- **场景** + - 靶点结构注释与筛选:在基因组层面预测大量蛋白的结构,辅助靶点发现、功能注释与通路分析;结合变异信息评估潜在致病机理。 + - 抗体 / 蛋白药物设计:对抗体可变区(CDR)、受体结合结构域等关键区域进行精细建模与设计,优化亲和力、特异性和免疫原性。 + - 酶与生物催化设计:基于酶三维结构和活性位点环境,设计突变与变体库,提升催化效率、底物范围与稳定性。 + - 复合物与相互作用研究:预测蛋白–蛋白、蛋白–核酸、蛋白–小分子复合物结构,解析界面互作模式,为药物设计与信号通路建模提供基础。 + - 突变效应与耐药性分析:评估自然变异或人工突变对结构稳定性、功能和配体结合的影响,分析耐药突变的结构基础。 +- **原理** + - 蛋白质结构预测: + - **序列 → 结构** :从氨基酸序列(单序列或包含多序列对齐 MSA)出发,建模残基两两之间的几何约束(距离、角度、接触图),再通过几何重建模块生成全原子 3D 结构。 + - **协同进化信号** :利用同源序列之间的协同突变模式(co‑evolution),推断潜在的残基接触关系,为折叠约束提供强先验。 + - **结构精修与不确定性估计** :对预测结构进行局部精修(relax、repack),并输出置信度评分(如 pLDDT、PAE),指导后续应用中的“可信区域”选择。 + - 复合物与分子装配建模: + - **多链联合建模** :将多个蛋白链或蛋白 + 核酸序列作为输入,引入链识别与接口约束,直接输出完整复合物结构。 + - **界面预测与装配** :基于已知单体结构,通过图模型或扩散模型预测最可能的界面构型与装配方式。 + - 蛋白设计与突变效应预测: + - **反向折叠(Inverse Folding)** :给定三维骨架结构或拓扑约束,生成能稳定折叠成该结构的氨基酸序列,实现 de novo 蛋白设计。 + - **突变效应建模** :结合蛋白语言模型与结构模型,预测特定突变对稳定性(ΔΔG)、活性或结合亲和力的影响,辅助定向进化与变体筛选。 +- **模型** + - 结构预测: + - AlphaFold / AlphaFold2 / AlphaFold3:以注意力机制和几何模块为核心,从 MSA、模板结构与序列特征中预测高精度蛋白结构,并输出不确定性估计。 + - RoseTTAFold、OpenFold:采用多轨道(sequence / pair / structure)表示与多尺度注意力机制,为开源与产业化落地提供基础实现。 + - 复合物与界面建模: + - AlphaFold‑Multimer:在多链场景下直接建模蛋白–蛋白复合物结构,兼顾单体折叠与界面互作。 + - RFdiffusion:基于扩散模型在 3D 空间生成或优化蛋白骨架与复合物接口,实现复杂装配与对称体设计。 + - DiffDock 等方法:在蛋白–小分子系统中,用扩散或深度打分函数预测 Binding Pose 与结合模式。 + - 设计与突变模型: + - ProteinMPNN:在给定结构的条件下生成兼容的序列,用于稳定骨架与界面设计。 + - ESM‑IF、ESMFold / ESM‑2 系列:基于大规模蛋白序列预训练的语言模型,具备从序列推断结构、功能与突变效应的能力。 + - 产品与应用: + - 公有云上的蛋白结构预测服务与数据库(如 AlphaFold DB),为科研提供大规模结构注释与下载接口。 + - 生物制药公司内部结构设计平台:集成蛋白结构预测、抗体设计、酶工程、蛋白–配体对接等模块。 + - 生物技术 SaaS:提供结合位点预测、界面热力学评估、亲和力与免疫原性评估工具,服务于抗体药物、生物制剂开发。 + +从这一子方向开始,AI 不仅在“解读”自然存在的蛋白结构,更在“创造”全新的蛋白与复合物架构,使结构生物学从“被动测量时代”进入“主动设计时代”。 + +### 10.2.1 蛋白质结构预测与复合物装配 + +蛋白质结构预测是结构生物学与 AI 结合最具代表性的突破之一。其核心问题是:**能否从序列出发,在不依赖或少依赖实验数据的情况下,预测出接近实验分辨率的 3D 结构?** 而在真实应用中,单体结构往往只是起点,更关键的是蛋白如何与其他分子装配成复合物。 + +在 **单体结构预测** 中,典型流程包括: + +1. **序列 / MSA 编码** :通过序列特征提取和多序列对齐挖掘协同进化信号。 +2. **几何约束推断** :预测残基对之间的距离分布、接触概率与相对取向,形成“伪测量”的几何场。 +3. **结构构建与迭代精修** :在几何约束下用结构模块(如旋转平移不变块、内坐标更新)构建 3D 结构,并多次迭代 refinement 以降低几何违背。 +4. **不确定性与质量评估** :输出逐残基置信度(pLDDT)、残基对误差估计(PAE)等指标,为后续建模与筛选提供参考。 + +在 **复合物与装配预测** 中,问题进一步扩展为“多条链如何在空间中组织与相互作用”: + +- 对于 **蛋白–蛋白复合物** ,通常在多链输入的基础上,使用专门的多链建模策略(如 AlphaFold‑Multimer)直接输出装配结构。 +- 对于 **蛋白–核酸 / 蛋白–小分子体系** ,一类路径是先预测各自结构,再通过对接与界面打分函数预测装配方式;另一类则是用扩散模型或联合建模在 3D 空间内直接生成复合物构象。 +- 在多亚基、大型装配体场景中,还需要结合对称性约束、低分辨率 EM 密度图等信息,进行分层与多尺度装配。 + +在产品实践中,结构预测与装配常被封装为云端服务或本地工具链,为蛋白功能注释、相互作用网络建模、药物靶点验证提供基础结构信息。 + +### 10.2.2 蛋白设计与突变效应预测:从结构到功能调控 + +在掌握“序列 → 结构”的映射之后,下一步是反向问题:**如何在给定结构或功能需求的情况下,设计出合适的蛋白序列与突变方案?** 这就是蛋白设计与突变效应预测的核心。 + +在 **蛋白设计** 中,关键任务包括: + +- **反向折叠(Inverse Folding)** :给定目标骨架(backbone)或整体拓扑结构,生成能够稳定折叠成该结构的氨基酸序列,这一过程可通过 ProteinMPNN、ESM‑IF 等结构条件生成模型实现。 +- **功能导向设计** :在保持整体结构稳定的前提下,针对活性位点、结合口袋、界面区域进行定向设计,优化亲和力、特异性与催化效率。 +- **可制造性与免疫原性约束** :在序列设计过程中,引入表达可行性、翻译后修饰、免疫原性风险等约束,保证候选序列在生物制剂开发中的可落地性。 + +在 **突变效应预测** 中,关注的是: + +- **稳定性变化(ΔΔG)** :给定野生型结构与突变位点,预测单点或多点突变对折叠稳定性的影响,用于定向进化和耐药突变分析。 +- **活性与亲和力变化** :结合结构与蛋白语言模型,评估突变对酶学活性、配体亲和力与信号通路调控的影响。 +- **大规模变体库设计** :在体内 / 体外筛选实验之前,用模型对庞大突变空间进行预筛选,保留高潜力变体,降低实验成本。 + +在工程与产品层面,蛋白设计与突变效应预测常被集成为生物制药 / 合成生物学公司内部的“结构设计与优化模块”:从候选骨架结构出发,自动提出多轮突变与变体库设计方案,与高通量筛选实验形成数据驱动的闭环。 + +## 10.3 物理仿真与加速计算(Physics Simulation & Surrogate Modeling) + +在航空航天、汽车、土木工程、能源、化工等领域, **高精度仿真是设计与验证的核心环节** 。然而 CFD(计算流体力学)、FEA(有限元分析)、分子动力学(MD)以及各类 PDE 求解往往计算昂贵,难以支持大规模参数扫描、实时控制或在线优化。AI 驱动的物理仿真与代理建模,试图用深度网络来近似数值求解器或算子本身,在保证物理一致性和可解释性的前提下,实现数量级的加速。 + +这一方向一端连接传统仿真软件(ANSYS、Fluent、COMSOL、自研求解器)、实验测量与传感器数据,另一端连接工程设计平台、自动驾驶与航天气动设计、化工过程模拟与优化系统。下面从 **场景** 、 **原理** 、**模型** 三个角度展开。 + +- **场景** + - 工程仿真加速:在给定几何与工况下,用深度代理模型快速预测压力场、速度场、温度场、应力 / 应变分布等,为多轮设计迭代和优化提供支持。 + - 复杂过程模拟与工艺优化:在化工、能源等流程工业中,通过 ML 近似机理模型或黑箱过程模型,实现快速评估与实时控制。 + - 分子 / 材料尺度模拟:用 ML 势能面(Neural Network Potential)替代高成本的 ab initio 势能与力计算,加速分子动力学与材料相行为模拟。 + - 多尺度与跨学科耦合:通过深度代理模型把微观–中观–宏观模型拼接起来,构建端到端的多尺度仿真与优化链路。 +- **原理** + - 替代模型 / 代理模型(Surrogate Models): + - 从数值仿真或实验数据中学习“输入参数 → 输出场 / 指标”的映射,作为高保真求解器的近似。 + - 在高维参数空间下,结合主动学习与贝叶斯优化,自动选择最有信息量的样本点进行高保真仿真或实验,持续提高代理模型质量。 + - 物理知晓神经网络(PINN): + - 将 PDE、初始 / 边界条件与物理守恒定律写入损失函数,利用自动微分技术在连续空间上求解物理场。 + - 支持正向问题(求解状态场)与逆问题(由稀疏观测反推源项、材料参数等),特别适用于传统数值方法难以处理的复杂几何与边界。 + - 算子学习与 Neural Operator: + - 不只拟合“具体条件下的解”,而是学习从函数到函数的映射(算子),如“边界条件 / 源项 → 整个解场”。 + - 代表方法如 Fourier Neural Operator (FNO)、DeepONet 等,通过频域变换或特定网络架构,提升对不同网格密度与几何形状的泛化能力。 + - 多尺度建模: + - 在微观模拟数据上训练中观 / 宏观层级的有效参数或本构关系,由深度代理模型承担“尺度桥接层”角色。 + - 对复杂材料、流固耦合与多相流等问题,用深度模型在不同尺度与物理模块间传递信息。 +- **模型** + - 通用物理神经网络: + - PINN 系列:通过在时空域采样点上最小化 PDE 残差来求解,适用于 Navier‑Stokes、Maxwell、弹性力学等方程。 + - DeepONet、FNO、Neural Operator 家族:直接学习 PDE 求解器的“算子级”近似,在多工况、多几何下快速推理。 + - 分子 / 材料尺度势能模型: + - DeepMD、SchNet、NequIP、SpookyNet 等:构建高精度 ML 势能面,在接近 ab initio 准确度的前提下,大幅加速力与能量计算。 + - 与传统 MD 引擎耦合,实现大体系、长时间尺度的高精度分子动力学。 + - CFD / 结构力学代理模型: + - U‑Net / UNet++ 等 Encoder‑Decoder 网络:在规则网格上从几何 / 边界条件预测流场或温度场。 + - 图神经网络 on Mesh:在非结构化网格上对节点 / 单元进行消息传递与更新,适合复杂几何和多物理场耦合场景。 + - Neural Operator for CFD:在不同雷诺数、来流条件、几何参数下泛化流场预测。 + - 产品与应用: + - 工业仿真软件中的 AI 加速模块:在传统求解器外层提供快速预估和敏感性分析功能。 + - 化工 / 能源过程模拟与优化平台:把机理模型 + 代理模型 + 优化算法组合成一体化工艺优化工具。 + - 自动驾驶 / 航空航天气动设计:在气动外形设计中进行大规模设计变量扫描与自动形状优化。 + +### 10.3.1 替代模型与物理知晓神经网络(PINN) + +**替代模型(Surrogate Models)** 与 **物理知晓** **神经网络** **(PINN)** 是物理仿真 AI 化的两条互补路径:前者从数据出发近似仿真映射,后者从物理出发构造学习目标。 + +在 **替代模型** 场景中,典型流程是: + +1. 通过高保真数值仿真或实验采集一批样本数据(输入参数、边界条件、几何 → 输出物理量)。 +2. 训练深度网络(如 MLP、卷积网络、GNN、Neural Operator)近似这一映射函数。 +3. 在设计优化、参数扫描或实时控制中,用代理模型替代昂贵的求解器进行快速评估。 + +在 **PINN** 场景中,模型不再以大量监督标签为主,而是通过最小化 PDE 残差与边界条件违背构建损失函数: + +- 在空间 / 时间采样点上,用神经网络输出物理量(如速度、压力、位移场等),自动微分得到梯度与导数。 +- 将这些导数代入 PDE 中,形成残差,并与边界条件、初始条件的误差一起构成总损失。 +- 通过优化使 PDE 残差与边界误差尽可能接近 0,从而得到满足物理方程的近似解。 + +两者可以结合使用:在有部分高保真数据时,用数据误差 + 物理残差共同约束训练,提高精度与泛化能力。在工程应用中,PINN 特别适合处理逆问题与数据驱动建模,如从传感器观测反推材料参数、源项或缺陷位置。 + +### 10.3.2 Neural Operator 与多尺度物理建模 + +**Neural Operator** 将物理建模从“点到点 / 参数到解”的映射提升到“函数到函数”的层面:它学习的是“给定一类 PDE 与边界条件,求解其解场”的统一算子近似,而非单一工况下的特定解。这为多工况、多几何与跨网格分辨率的泛化提供了新的可能。 + +在 **算子学习** 中,典型做法是: + +- 以函数(如源项、边界条件、材料参数场等)作为输入,用网络(如 FNO、DeepONet)输出整个解场函数。 +- 通过在不同网格、不同参数与不同几何上的样本训练,让模型学习到 PDE 求解器的“公共模式”。 +- 部署时,只需给出新的输入函数(如新的边界条件、几何),就能快速推理得到近似解场。 + +在 **多尺度建模** 场景中: + +- 在微观尺度(如分子动力学、晶体塑性)产生的大量数据上训练 Neural Operator,学习微观结构与宏观响应之间的映射。 +- 在宏观连续介质模型中,用这一映射作为本构关系或有效参数计算模块,实现微–宏耦合。 +- 对于流固耦合、多相流、反应流等复杂系统,可以对不同物理场分别建模并通过共享接口变量(如通量、界面力等)耦合。 + +在工程实践中,Neural Operator 逐渐从研究原型走向应用,成为 CFD、地球物理、气候建模等场景中“加速求解器 + 多尺度桥接”的重要技术方向。 + +## 10.4 材料发现与晶体设计(Materials Science & Crystal Design) + +在材料科学中,一个核心矛盾是: **设计空间几乎无穷大,而实验与高精度计算成本极高** 。如何在巨大的化学与结构组合空间中高效地找到满足特定性能要求的候选材料,是新能源、电子、结构、功能材料等领域的关键问题。AI 驱动的材料发现与晶体设计,通过图神经网络、生成模型与高通量虚拟筛选,将“试错式”研发逐步转向“数据驱动 + 逆设计”。 + +这一方向一端连接 Materials Project、OQMD、AFLOW 等材料数据库与 DFT / MD 计算结果,另一端连接电池、光伏、催化、半导体、合金等应用场景的材料研发平台。下面从 **场景** 、 **原理** 、**模型** 三个角度展开。 + +- **场景** + - 性能导向的材料筛选:给定晶体结构或化学式,预测能带结构、带隙、载流子迁移率、热 / 电 / 磁性质等,为材料筛选与组合优化提供依据。 + - 新能源材料研发:面向电池电解质、电极材料、固态离子导体、光伏吸收层与催化剂等体系,预测离子电导率、稳定性、电化学窗口与活性等。 + - 高通量虚拟筛选(HTVS):在构建的大规模候选库中,通过 ML 模型快速评估,筛出潜力材料,再用少量 DFT / 实验验证与校准。 + - 晶体结构与成分逆设计:从目标性质出发,反向搜索满足性能与工艺约束的晶体结构 / 成分组合。 +- **原理** + - 材料与晶体表示: + - 将周期性晶体结构表示为晶体图(Crystal Graph):节点为原子,边为原子间近邻关系,结合晶格参数与空间群信息。 + - 对于非晶或复杂多相材料,可通过局部环境描述符(如 SOAP)、Voronoi 特征或多尺度图结构表示其微结构。 + - 性质预测: + - 在 CGCNN、MEGNet、ALIGNN 等 GNN 模型上对晶体图进行卷积 / 消息传递,预测能量、带隙、弹性模量、热导等。 + - 利用 Mat2Vec 等基于文献和化学式的嵌入,在低数据场景下实现迁移学习与零样本估计。 + - 高通量虚拟筛选: + - 构建候选库(通过组合枚举、结构生成、经验规则等) → 使用 ML 模型快速预测性质 → 筛选出少量 Top 候选进行 DFT 或实验校准 → 更新模型与筛选策略,形成主动学习闭环。 + - 生成与逆设计: + - 利用扩散模型、VAE 或 GNN 生成模型在晶体结构空间采样新结构,可施加成分、空间群、密度等约束。 + - 结合代理模型与贝叶斯优化,从目标性质出发搜索合适的结构 / 成分组合,实现 inverse design。 +- **模型** + - 表征与预测: + - CGCNN(Crystal Graph Convolutional Neural Network):在晶体图上进行卷积,用于能量、带隙等无机材料性质预测。 + - MEGNet、ALIGNN:融合图结构与边 / 角度信息,在多种材料家族上具备更强的泛化与精度。 + - Mat2Vec + 轻量 ML:通过对化学式和元素信息的向量化,快速训练用于特定性质预测的小模型。 + - 生成与逆设计: + - Diffusion for Crystals:在晶格参数与原子位置组成的高维空间中进行扩散 / 去噪,生成满足一定约束的晶体结构。 + - GNN‑based Generative Models:通过逐步添加 / 修改原子和键或操作晶格,实现从随机初始化到目标性质附近的结构搜索。 + - Surrogate + Bayesian Optimization:用 ML 模型作为“结构 → 性质”的近似黑箱,在其上做贝叶斯优化,寻找最优结构或成分。 + - 数据平台与工具链: + - Materials Project、OQMD、AFLOW:提供大量结构与 DFT 计算数据,是训练与评估材料 ML 模型的基础。 + - 企业内部材料数据库与模型:结合公司实验数据与工艺信息,构建领域特化的材料 AI 设计平台。 + - 产品与应用: + - 新能源材料研发加速平台:为电池、电催化、光伏等团队提供一体化的性质预测、HTVS 与 inverse design 能力。 + - 虚拟筛选软件与 SaaS:为合金、半导体、功能陶瓷等提供数字化筛选工具,减少早期试错成本。 + - 材料公司内部的 AI 设计工具:与实验室信息管理系统(LIMS)与生产线数据对接,形成从“模型 → 实验 → 生产”的闭环。 + +### 10.4.1 材料性质预测与高通量虚拟筛选(HTVS) + +在材料研发流程中,**快速而可靠的性质预测** 是一项基础能力:给定一个候选结构或成分,能否在不做昂贵 DFT / 实验的情况下,大致判断其是否值得深入探索。基于 GNN 与材料数据库的性质预测模型,为高通量虚拟筛选提供了可能。 + +在 **性质预测** 层面: + +- 使用晶体图表示周期性结构,通过 CGCNN、MEGNet、ALIGNN 等模型学习原子与邻域间的相互作用。 +- 针对不同任务(能量、带隙、弹性常数、热导、电导、磁性等)进行单任务或多任务训练,在 Materials Project 等数据集上达到接近 DFT 精度的预测性能。 +- 在工业场景中,常结合内部实验数据进行再训练或领域自适应,以提升对特定材料家族与工艺条件的适配度。 + +在 **高通量虚拟筛选(HTVS)** 场景中,典型流程为: + +1. 构建大规模候选库(组合枚举、结构生成或从现有数据库扩展)。 +2. 使用 ML 模型快速预测每个候选的目标性质与辅助性质(稳定性、安全性、成本相关指标等)。 +3. 按目标性质与多约束条件筛选排名,选出 Top‑K 候选进行高保真 DFT 计算或实验验证。 +4. 将验证结果反哺模型,更新参数与不确定性估计,形成“筛选–验证–再筛选”的主动学习闭环。 + +这一工作流在电池材料、光伏吸收层、催化剂与结构材料等多个领域已进入实用阶段,成为材料研发团队的“前置筛选引擎”。 + +### 10.4.2 晶体生成与逆设计:从目标性质到候选结构 + +在具备了可靠的性质预测与 HTVS 能力之后,更进一步的目标是 **直接从目标性质与约束出发,提出新的晶体结构与成分候选** ,即材料的逆设计与生成。 + +在 **晶体生成** 中,关键问题包括: + +- 如何在周期性约束下生成物理合理的晶格与原子排列? +- 如何在生成过程中显式或隐式地施加成分、对称性与密度等约束? +- 如何保证生成结构在经过简单松弛后依然稳定? + +为此,研究与工程实践常采用: + +- **Diffusion for Crystals** :在晶格参数 + 原子位置的联合空间中添加 / 去除噪声,实现从随机初始到结构样本的渐进生成,可在噪声过程或条件向量中融入目标性质与成分约束。 +- **GNN** **‑based Generative Models** :在图结构上逐步添加原子与连接关系,或对已有结构进行编辑,生成满足约束的候选结构。 + +在 **逆设计** 中,通常与代理模型与优化方法结合: + +- 将性质预测模型视作“结构 → 性质”的黑箱函数。 +- 通过贝叶斯优化、进化算法或 RL 在结构空间中探索,使预测性质逐步逼近目标值,同时满足稳定性、安全性、成本等约束。 +- 对搜索得到的候选结构进行 DFT / 实验验证,并将结果用于更新代理模型与搜索策略。 + +在工程应用中,逆设计模块往往被集成到材料 AI 平台中,为研发人员提供“设定目标性质 → 系统自动提出候选结构”的交互界面,显著提升新材料探索的效率。 + +## 10.5 数学与符号推理(Mathematics & Symbolic Reasoning) + +数学是高度形式化、可精确验证的语言,这让它在 AI 时代同时具备“难度极高”和“潜在回报巨大”两种属性。一方面,复杂的定理证明与高阶推理对模型能力提出了极高要求;另一方面,数学推理与符号计算的结果可以被严格验证,天然适合与程序化工具协同。AI 在数学与符号推理方向的目标,是构建能够在形式系统中**进行可靠推理与计算**的模型,并将其融入教育、科研与工程应用。 + +这一方向一端连接 Lean / Coq / Isabelle 等交互式定理证明器,SymPy / Mathematica / Maple 等计算机代数系统(CAS),以及大型数学题库与文献语料;另一端连接数学教育产品、辅助研究工具与工程 / 金融等领域的公式推导与风险分析需求。下面从 **场景** 、 **原理** 、**模型** 三个角度展开。 + +- **场景** + - 自动定理证明与辅助证明:在形式化系统中自动给出定理证明,或生成可读的证明草稿,由人类进一步审阅与完善。 + - 表达式操作与符号计算:自动化简表达式、求导、积分、级数展开、变换与方程求解,为工程建模与金融风险分析提供符号工具。 + - 数学题理解与解题步骤生成:从自然语言或图片中的题目提取结构化表示,给出严谨、可检查的解题步骤,服务于教育与训练场景。 + - 数学推理能力增强:通过数学专向微调与工具增强,提高大模型在算术、代数、几何、组合等领域的多步推理与严谨性。 +- **原理** + - 形式系统与搜索: + - 在 Lean / Coq / Isabelle 等系统内,数学对象与定理被形式化为项与类型,证明过程对应于在规则约束下构建证明树。 + - 证明搜索可以视为“在极大状态空间中寻找满足约束的路径”,适合采用强化学习、MCTS(蒙特卡洛树搜索)与策略网络 / 价值网络等方法。 + - 神经 – 符号协同: + - LLM 负责从自然语言或非结构化输入中提取问题结构与求解思路,将其翻译为符号表达(如 SymPy 代码、Lean 证明脚本)。 + - 计算机代数系统与定理证明器负责执行严格的符号计算与形式验证,对 LLM 输出进行校验与纠错。 + - 数学推理能力提升: + - 通过在大规模数学文本与题库上做专向预训练或微调(如 Minerva、Gödel),提升模型对数学语言的理解与推理风格的掌握。 + - 采用 Tool‑Augmented LLM 框架,将符号求解器、数值计算库、绘图工具与证明器作为外部工具,让模型在复杂推理中学会“调用工具”而非“死记结果”。 +- **模型** + - 自动定理证明: + - AlphaZero‑style 证明器:将证明进程视为博弈过程,使用策略网络和价值网络引导搜索,逐步构造形式证明。 + - GPT‑f、Lean‑Dojo 等:在大规模形式化定理与证明语料上训练,用于在 Lean 等系统中自动生成证明。 + - 数学大模型与工具增强: + - Minerva、Gödel 等:在数学教材、论文、题库等语料上微调的大模型,在证明题、竞赛题和高阶推理任务上表现更强。 + - LLM + SymPy / Mathematica / Lean / Coq:由 LLM 做问题解析与策略规划,调用符号计算与证明工具做精确操作与验证。 + - 产品与应用: + - 教育产品中的“数学助教 / 解题助手”,提供个性化讲解与多种解法路径。 + - 辅助研究工具:帮助研究者构造猜想、生成证明草稿、搜索相关定理与引理,加速理论探索。 + - 工程 / 金融领域的公式推导与风险模型分析:将复杂模型形式化,进行符号敏感性分析与合规性审查。 + +### 10.5.1 自动定理证明与形式化推理 + +**自动定理证明(ATP)与交互式定理证明(ITP)** 是数学与计算机科学交叉的重要方向。AI 介入这一领域的核心任务,是在形式系统中自动构造或辅助构造证明,减少人类在低层次细节上的负担,使其更多地专注于高层次思路。 + +在 **形式化系统** 中: + +- 定理被编码为需要构造的目标类型(goal),证明对应为构造某个项,使其类型为该目标类型。 +- 证明过程由一系列战术(tactics)或推理步骤组成,每一步都在严格的逻辑规则下推进。 + +AI 在其中可以承担多种角色: + +1. **战术选择与参数推荐** :在当前证明状态下,预测下一步应使用的战术及其参数,减少人工尝试与回溯。 +2. **引理与定理检索** :从庞大的库中检索与当前目标最相关的引理 / 定理,缩小搜索空间。 +3. **端到端证明生成** :在给定定理与上下文的情况下,直接生成完整或局部证明脚本,再由证明器验证其正确性。 + +AlphaZero‑style 证明器、GPT‑f、Lean‑Dojo 等工作,通过在大规模形式化语料上训练策略与价值网络或语言模型,实现了在 Lean / Coq 等系统上自动完成相当比例定理的证明。在产品方向上,这类能力有望演化为“形式化验证助手”,用于软件 / 硬件验证、加密协议分析和高可靠系统设计。 + +### 10.5.2 符号计算与数学问题求解:LLM + CAS + +相比定理证明,**符号计算与数学问题求解** 更贴近工程与教育场景。其目标是: **从自然语言问题出发,自动构造符号表达、执行计算并给出可解释的解题步骤** 。 + +在这一方向上,典型的神经 – 符号协作流程为: + +1. **问题理解与抽象** :LLM 将自然语言或图片中的题目解析为结构化数学表达(方程、约束、目标函数等)。 +2. **符号表达生成** :将抽象结果翻译为 CAS 代码(如 SymPy 表达式、Mathematica 命令)。 +3. **调用 \*\***CAS\*\* ** 执行** :使用 CAS 进行精确的代数运算、求导、积分、求解方程组、极限等。 +4. **结果解释与步骤生成** :LLM 基于 CAS 的计算结果,生成符合人类习惯的解题步骤与解释。 + +这一模式有几个关键优势: + +- 通过 CAS 保障计算的正确性,避免 LLM 在长算式上的“错位运算”与累积错误。 +- 通过 LLM 提供自然语言理解与表达,降低 CAS 的使用门槛,使非专业用户也能调用强大的符号工具。 +- 在教育场景中,可以控制解题的详细程度与风格,生成适合不同学习阶段的讲解。 + +在工程 / 金融场景中,这一能力可以扩展到复杂模型的公式化与分析:自动从文档与代码中提取模型结构,构造符号表示,并进行敏感性分析、边界情况分析与风险识别。 + +## 10.6 科学工作流与自动化实验(Scientific Workflow & Lab Automation) + +前面的子方向大多聚焦于“单点能力”:预测一个性质、生成一个结构、证明一个定理。然而在真实的科研与工业研发中,更关键的是如何把这些能力**串联成完整的** **工作流** ,并与文献、数据库、仿真平台与自动化实验设备打通。科学工作流与自动化实验方向,旨在构建面向科学场景的 **Agent + 工具 + 机器人** 一体化系统,让 AI 从“会算”进化到“会做实验、会做研究”。 + +这一方向一端连接论文与专利数据库(如 PubMed、arXiv)、科学数据仓库、领域知识图谱与仿真平台,另一端连接自动化实验室(Robotic Lab)、高通量筛选设备与科研流程管理系统。下面从 **场景** 、 **原理** 、**模型** 三个角度展开。 + +- **场景** + - 科学文献挖掘与知识库构建:从海量论文中自动提取化合物、蛋白、材料、反应条件、实验结果等信息,构建结构化知识库与知识图谱。 + - 实验设计与 Self‑Driving Lab:在 AI 提出的实验计划指导下,由机器人实验平台自动执行配制、反应、测量与数据采集,实现“闭环”优化。 + - 科学数据管理与可重复性保障:自动整理仿真与实验数据、元数据与代码脚本,生成标准化实验记录与报告,提高可追溯性与复现性。 + - 领域“AI 实验助手”:为药企、材料公司与科研机构提供一站式的文献检索、方案设计、实验规划与结果分析支持。 +- **原理** + - 文献挖掘与领域 LLM: + - 利用 SciBERT、BioBERT、PubMedBERT 等领域预训练模型进行命名实体识别、关系抽取、反应式解析与实验条件抽取。 + - 在此基础上训练 Bio‑LM、Chem‑LM、Materials‑LM 等领域 LLM,提升对专业术语、实验语句与隐含假设的理解与推理能力。 + - 实验设计与 Self‑Driving Lab: + - 将实验空间(配方、温度、时间、添加顺序等)视为优化变量,由 LLM + RL 或贝叶斯优化策略提出下一组实验条件。 + - 实验机器人与仪器按照计划执行,采集数据并实时回传,由模型更新参数与不确定性估计,形成主动学习闭环。 + - 工作流编排与 Agent: + - 在 Agent & Tool Use 框架下,将文献检索、代码生成、仿真调用、数据分析、可视化与报告生成工具统一纳入。 + - Agent 根据任务目标(如“寻找高导电电解质配方”),自动规划任务分解、调用工具顺序与结果整合。 +- **模型** + - 文献与知识挖掘模型: + - SciBERT、BioBERT、PubMedBERT 等:针对科学与生医文献进行预训练的模型,用于实体 / 关系抽取、分类与问答。 + - Galactica、领域特化 LLM:以科学语料为主进行训练,支持综述生成、代码草稿、实验设计建议等。 + - 实验规划与控制模型: + - LLM + RL / Bayesian Optimization:结合领域先验、模型不确定性与实验成本,对实验空间进行高效探索与 exploitation。 + - 与 Robotic Lab 控制接口集成的 Agent:将自然语言实验描述转换为结构化实验步骤与仪器控制命令。 + - 科学 Agent 与工作流系统: + - 在 7 章 Agent & Tool Use 能力基础上,构建面向科学场景的“多工具 Agent”:能够检索文献、生成代码、调用仿真、处理数据、绘制图表并写出报告初稿。 + - 产品与应用: + - 药企 / 材料公司内部的“AI 实验助手”与自动化实验台:用于加速配方开发、工艺优化与候选筛选。 + - 领域科学搜索引擎与知识图谱(Bio / Chem / Materials / Physics Knowledge Graph):支持语义检索、交互式探索与知识推理。 + - 科研流程管理平台:集成实验规划、数据记录、版本管理、可视化与报告自动生成,提高科研团队的效率与结果的可复现性。 + +### 10.6.1 科学文献挖掘与领域知识库构建 + +科学知识的绝大部分首先以论文与报告的形式出现。要让 AI 真正参与科研,就必须让其“读得懂论文,并从中提炼结构化知识”。 **科学文献挖掘与知识库构建** ,正是从非结构化文本出发,构建可查询、可推理的知识基础设施。 + +在这一方向中,核心任务包括: + +- **实体识别与标准化** :识别文献中的化合物、蛋白、材料、反应物、产物、实验设备与条件等实体,并与标准数据库(如 ChEMBL、Uniprot、Materials Project)对齐。 +- **关系与事件抽取** :从文本中抽取“谁与谁如何相互作用”“什么条件下产生了什么结果”等关系与事件,例如反应方程、配方–性能对应关系等。 +- **知识图谱** **构建** :将实体与关系组织为图结构,支持复杂查询(如“在某条件下提高某性能的所有已报道方法”)与路径推理。 + +为实现上述目标,常采用: + +- SciBERT、BioBERT、PubMedBERT 等预训练模型进行 NER(实体识别)、RE(关系抽取)与文档级事件抽取。 +- 在此基础上构建领域特化 LLM(Bio‑LM、Chem‑LM、Materials‑LM),用于进行更复杂的问题回答、综述生成与知识补全。 + +构建好的领域知识库与知识图谱不仅可以为研发人员提供更智能的检索与推荐服务,也为后续的实验设计、材料 / 药物逆设计提供数据与先验支撑。 + +### 10.6.2 Self‑Driving Lab 与科学工作流 Agent:从“读论文”到“做实验” + +在具备文献挖掘、建模与优化能力之后,下一步就是把这些能力与 **自动化实验平台** 结合,构建真正意义上的 **Self‑Driving Lab(自驱动实验室)** 与科学工作流 Agent。 + +在 Self‑Driving Lab 中,典型工作闭环为: + +1. **目标设定** :研究者给出宏观目标(如“提高某材料在特定条件下的导电率”)与约束条件(成本、安全性、工艺限制等)。 +2. **文献与知识检索** :Agent 调用文献检索与知识图谱,了解现有工作与经验规律,形成初始假设与实验设计空间。 +3. **实验规划与优化策略** :基于 LLM + RL / 贝叶斯优化策略,提出首批实验条件(配方、温度、时间、环境等)。 +4. **机器人执行与数据采集** :自动化实验台(Robotic Lab)执行实验,实时采集结果并回传。 +5. **模型更新与下一轮设计** :代理模型根据新数据更新参数与不确定性估计,再提出下一轮更有信息量或更有潜力的实验条件。 + +在更广义的 **科学\*\***工作流\***\* Agent** 中,这一闭环会扩展到仿真、数据分析与报告生成等环节: + +- Agent 可以自动生成仿真代码或调用现有仿真工具,对某些实验条件进行前置评估; +- 在数据分析阶段,自动完成数据清洗、可视化与统计检验; +- 在项目阶段总结时,生成结构化的实验记录与报告草稿,附带图表与参考文献。 + +在产品形态上,这类系统往往以平台形式落地:提供一套统一的界面与 API,对接文献库、仿真引擎与实验设备,让科学家和工程师在高层用自然语言与可视化界面制定目标,其余环节由 Agent + 工具链自动编排与执行。 + +从这一子方向开始,AI 在科学中的角色真正从“离线分析工具”转向“在线科研合作者”:不仅能读论文、写代码、算模型,更能与机器人一起,完成一项项真实的实验与发现。 + +# 11. 平台与工程能力(MLOps / Infra) + +大模型从实验室走向企业生产,绝不仅是“模型本身足够好”就可以,而是要依托一整套稳定、可扩展、可运维的 **平台与工程体系** 。这套体系需要贯穿模型的**训练与微调、部署与推理优化、数据与模型运维、监控与成本管理、安全与合规、以及中台与应用支撑能力**等环节,把原本零散的技术点串成一个可持续运转的闭环。 + +从业务视角看,平台与工程能力往往决定了一个组织是否能“规模化地、安全且低成本地”使用大模型:同样的底层模型,如果没有良好的 MLOps 体系,很可能只能停留在 Demo 与试点阶段;而一旦具备完善的平台,企业就能在多个 BU、多个国家 / 区域、多个行业场景中快速复制与演进高质量应用。下面我们将分别从**模型训练与微调平台、部署与推理优化、数据与模型运维、监控与成本可靠性、安全与合规基础设施、以及上层应用与中台能力**六个方向展开阐述 + +## 11.1 模型训练与微调(Training & Fine-tuning) + +在基础模型层面,大部分组织不会从零开始训练千亿参数模型,而是基于开源或商用基座做 **继续预训练 + 微调** 。这一层的核心问题是:如何高效利用算力和数据,把通用大模型“拉近”到具体行业、企业和任务上,同时又要保证多模型、多版本的工程可管理性。 + +从工程视角看,这一层通常包含三块: **预训练与继续预训练** 、**微调\*\***范式\***\*与工具链**以及**大规模\*\***分布式\*\* **训练基础设施** 。 + +- **场景** + - 通用大模型底座研发:云厂商 / 大厂自研通用语言 / 多模态基座模型,用于对外 API 和内部多业务共享。 + - 行业大模型与专有模型:围绕金融、医疗、法律、制造、能源、游戏等特定领域,构建行业基座模型或“企业自有大模型”。 + - 企业级模型定制:为单一大客户(银行、保险、政府、制造集团等)基于其内部数据定制专属微调模型或 LoRA 权重。 + - 多租户模型市场:SaaS / 云平台为众多中小客户提供“一客一模型”的微调与托管能力,每个租户一套权重或适配层。 + - 一键微调平台:对非算法团队开放的“上传数据 → 选择底座模型 → 自动微调 → 一键部署”全托管产品。 +- **原理** + - 预训练与继续预训练: + - 在海量通用文本、代码、多模态数据上进行大规模预训练,使模型获得 **通用语言理解、世界知识与基本推理能力** 。 + - 对于特定行业,通过 **Domain‑adaptive Pretraining(DAPT)** 在通用模型之上继续预训练,引入行业专有术语、写作风格和知识分布。 + - 多语言 / 多模态预训练通过共享语义空间与联合训练,使模型具备**跨语言迁移**与**图文 / 语音 / 结构化数据融合**能力。 + - 微调范式: + - **全参数微调** :在目标任务与预训练分布差异极大、且有充足算力和数据时,直接更新全部参数,获得最高上限性能。 + - **参数高效微调(PEFT)** :通过 Adapter、LoRA / QLoRA、Prefix / P‑Tuning 等方式,仅训练极少量“增量参数”,适合多任务、多客户、频繁更新场景。 + - **指令** **微调与任务微调** :用“指令 + 示例”的方式让模型学会理解自然语言任务描述;既可以面向单一垂直任务,也可以在统一模型上承载多任务。 + - **RLHF** ** / RLAIF** :通过人类或 AI 反馈训练奖励模型,进一步用强化学习对齐模型行为(礼貌性、安全性、拒答策略、价值观)。 + - 分布式训练与工程体系: + - 使用 **数据并行、模型并行、流水线** **并行** **、** **张量\*\***并行\*\*等策略,将超大模型和大规模数据拆分至集群多节点、多卡协同训练。 + - 通过 ZeRO / FSDP 等技术**降低\*\***显存\*\* **占用、提升训练吞吐** ,配合高效调度(Kubernetes + Slurm / Ray)实现大规模集群训练。 + - 依托标准化的数据 pipeline(数据集加载、清洗、去重、分片、缓存)与微调框架(Transformers Trainer、DeepSpeed、Lightning 等)减少重复造轮子。 +- **模型** + - 预训练与继续预训练工具链: + - 训练框架:PyTorch、TensorFlow、JAX。 + - 大规模训练加速:DeepSpeed、Megatron‑LM、Colossal‑AI、Fairscale。 + - 分布式训练策略:数据并行(DP)、模型并行(MP)、流水线并行(PP)、张量并行;ZeRO / FSDP、Megatron(TP+PP)、DeepSpeed ZeRO。 + - 集群调度与管理:Kubernetes + Slurm / Ray / Horovod / TorchElastic。 + - 数据 pipeline:Hugging Face Datasets、WebDataset、Petastorm、tf.data、Arrow;对象存储(S3 / OSS / GCS)+ 本地 cache;数据清洗与去重工具。 + - 微调与 PEFT 工具: + - 微调框架:Hugging Face Transformers + Trainer / Accelerate、PyTorch Lightning、DeepSpeed、Colossal‑AI。 + - PEFT 工具集:PEFT(LoRA / QLoRA / Prefix Tuning / Prompt Tuning 等)、LLaMA‑Adapter 及各类 LoRA 工具链。 + - 指令与数据构建:Self‑Instruct、Alpaca / Dolly 风格 pipeline,各类数据增强与对话重写工具。 + - RLHF / RLAIF 工具链: + - TRL(Transformers Reinforcement Learning)、trlx、DeepSpeed‑RLHF、自研 RLHF pipeline。 + - 奖励模型训练、排序 / 评分模型、拒答策略与对齐策略模板。 + +在产品形态上,这一层往往体现为: **模型底座研发平台、企业级“代训+定制”服务、一键微调平台与模型市场(Model Hub / Model Store)** ,支撑从“通用模型”到“千企千模”的生产化路径。 + +### 11.1.1 预训练与继续预训练:从通用能力到行业基座 + +预训练是现代大模型能力的“源头工程”:通过对海量未标注文本、代码和多模态数据的自监督学习,模型逐渐获得语言建模、世界知识、基本推理与表示学习能力。在此基础上,继续预训练(特别是 **Domain‑adaptive Pretraining, DAPT** )则承担了“把模型拉向某个垂直领域”的任务。 + +在**通用预训练**阶段,核心关注点包括: + +1. **语料规模与多样性** :混合网页文本、书籍、代码、对话、多语种内容以及图文对等多模态数据,尽可能覆盖广泛的知识与表达形式。 +2. **训练目标与多任务混合** :除了经典的自回归语言建模外,有时会加入填空、下一句预测、对比学习、图文对齐等目标,提升模型的语义对齐与多模态理解。 +3. **多语言与对齐** :通过共享词表或子词编码,以及跨语种平行语料或对齐任务,使模型在统一向量空间中对不同语言进行建模,实现 **跨语言迁移与翻译** 。 + +在**行业继续预训练(DAPT)** 阶段,重点转向: + +1. **行业语料构建** :从医疗病历与指南、法律判决书与法规条文、金融研报与交易数据、制造 / 能源 / 游戏设计文档等渠道构建专有语料。 +2. **风格与术语适配** :通过大量领域内语料的继续预训练,使模型自然掌握行业术语、固定表达、专业写作风格与隐性知识(如临床表述习惯、法律措辞)。 +3. **企业级专有知识注入** :对于大型企业或机构,可在通用 + 行业语料之外进一步加入企业内部文档、知识库、工单记录等,训练“企业专有大模型”作为统一智能底座。 + +在工程实践中,预训练与继续预训练会配合大规模分布式框架(Megatron‑LM、DeepSpeed ZeRO 等)以及高效的数据 pipeline(WebDataset / HF Datasets + 对象存储)运行,形成 **稳定可复用的训练流水线** 。对于云厂商或大厂,这一流水线往往会被封装为内部平台,支持周期性增量预训练和多行业基座并行迭代。 + +### 11.1.2 微调范式与 RLHF:从“能说话”到“懂业务、守边界” + +在拥有强大的预训练基座之后,如何让模型“对业务有用”并“行为可控”,关键在于微调与对齐阶段。这里既包括传统意义上的监督微调(SFT),也包括指令微调、多任务微调和基于反馈的强化学习(RLHF / RLAIF)。 + +在**微调范式**层面,可以大致分为: + +1. **全参数微调(Full Fine‑tuning)** + 在任务分布与预训练差异很大,或对极致性能有刚性要求且算力充足的场景(如特定编程语言模型、特定语言 / 行业对话模型)中,直接更新全部参数可以获得最大性能上限。但其成本高、版本管理复杂,一般只在少数核心模型上使用。 +2. **参数高效微调(PEFT)** + 通过 Adapter、LoRA / QLoRA、Prefix / P‑Tuning 等方法,仅对插入的“小块增量参数”或权重低秩增量进行训练,原始大模型权重保持冻结。这带来了三点工程优势: + 1. 多任务 / 多客户可以共享同一基座,只切换不同的 Adapter / LoRA 权重。 + 2. 显著降低显存与算力需求,支持在中小型 GPU 集群或单机环境中完成微调。 + 3. 更新频繁、回滚简单,便于快速试错与 A/B 实验。 +3. **指令微调与任务微调** + 1. **指令微调(Instruction Tuning)** :通过“自然语言指令 + 输入 + 期望输出”的样本,让模型学会理解“帮我…”“请解释…”等人类指令形式,从而摆脱任务特定模板。 + 2. **单任务微调** :如仅针对客服问答、代码补全、法律咨询等垂直任务进行微调,最大化该任务表现。 + 3. **多任务微调** :在统一模型上同时承载多种任务(问答、摘要、翻译、代码、推荐理由生成等),提升模型通用性和资源利用率。 + +在**行为对齐与安全性**层面,**RLHF / RLAIF** 起到关键作用: + +1. **奖励模型(Reward Model)训练** :收集人类或 AI 对模型多种候选回答的偏好(排序 / 打分),训练一个能评估“回答好坏”的奖励模型。 +2. **强化学习(如 PPO)优化基座模型** :在奖励模型的指导下,通过强化学习调整模型参数,使其更符合人类偏好和平台价值观,例如: +3. 更礼貌、中立、专业; +4. 对危险、违规、隐私相关请求进行拒答或安全改写; +5. 在有不确定性时表明不确定,而非虚构事实。 +6. **RLAIF 与自监督对齐** :在部分场景下,使用强基座模型作为反馈者,或结合规则与自动化评估,对微调过程进行半自动对齐,降低人工标注成本。 + +工具链方面,Hugging Face Transformers + PEFT、TRL / trlx、DeepSpeed‑RLHF 等框架,已经基本形成了从 SFT → RM 训练 → RLHF 的**标准工业工作流** 。在产品定义上,这一层典型落地为:**模型定制 / 代训服务、一键微调平台、多租户模型市场与行业 / 企业专有大模型工程平台** 。 + +## 11.2 模型部署与推理(Serving & Optimization) + +在训练好大模型之后,如何以 **高可用、** **低延迟** **、可扩展、可降本**的方式提供推理服务,是 AI 工程体系的第二根支柱。部署与推理层一端连接 GPU / NPU 等算力集群,另一端连接 API 网关、企业应用和对外开放平台,其核心职责包括: **部署架构设计、模型路由策略、推理性能优化与硬件利用** 。 + +从整体来看,这一层要解决三个问题: **用什么架构对外服务** 、 **如何让推理更快更便宜** 、 **如何在多模型、多地域、多租户环境下保持高可用与可治理** 。 + +- **场景** + - 企业内部 AI 中台 / 模型服务总线:统一为各业务线提供大模型 API,屏蔽底层模型和硬件差异。 + - 对外开放云 API:向外部开发者与生态伙伴提供标准化的推理接口,支持多模型选择与版本管理。 + - 高 QPS 在线业务:客服助手、搜索、推荐、办公助手等对延迟和稳定性要求极高的场景。 + - 低成本离线生成:广告 / 游戏文案、知识库生成、代码批量重构等以吞吐与成本为主、对实时性要求不高的批处理任务。 + - 跨地域、多集群部署:为全球或多区域用户提供就近访问,同时支持多云或混合云形态。 +- **原理** + - 部署架构与模型路由: + - **单模型服务** :在早期或简单场景下,以一个主模型对外提供统一服务,架构简单,但难以兼顾延迟与成本。 + - **多模型服务与路由** :针对不同任务、延迟要求、成本约束、用户等级等维度,配置不同大小或不同专长的模型,并通过规则或 Meta‑model 进行请求路由(包括 A/B 测试、多臂老虎机 / Bandit 策略等)。 + - **多租户隔离与 \*\***SLA\*\* ** 管理** :在多客户场景中,通过资源配额、QPS 限制、访问鉴权和 SLA 分级确保不同租户之间在性能与安全上的隔离。 + - **弹性扩容与高可用** :借助 Kubernetes / Service Mesh 等基础设施,实现自动扩缩容、多副本部署、灰度发布、蓝绿部署和跨区域容灾。 + - 推理性能优化: + - **模型压缩与加速** :通过量化(INT8 / INT4 / NF4 / GPTQ / AWQ)、剪枝 / 稀疏化、知识蒸馏等手段减少模型计算量与显存占用。 + - **系统级优化** :利用 KV Cache 缓存注意力键值,加速长对话与连续推理;通过批处理(Batching)、并行 token 生成和流式输出平衡吞吐与延迟;通过算子融合和图优化减少内存访问和内核启动开销。 + - **异构硬件利用** :针对 GPU、CPU、NPU、FPGA、ASIC 等不同硬件构建适配的 Runtime 与调度策略,在单机多卡、多机多卡场景下通过 NVLink / RDMA 等高速互联提升整体效率。 + - 工程与运维: + - 使用 vLLM、TGI、Triton 等专用推理框架,显著降低自研成本。 + - 通过 ONNX Runtime、TensorRT、TVM、OpenVINO 等编译器与 Runtime 进行跨平台部署与算子级优化。 + - 借助 Kubernetes、Ray、Service Mesh 和 API 网关构建统一的 **在线推理集群与流量调度层** 。 +- **模型** + - Serving 框架与推理服务: + - vLLM、TGI(Text Generation Inference)、Triton Inference Server。 + - Ray Serve、KServe、TorchServe、SageMaker Endpoint、Vertex AI Endpoint 等。 + - 集群与调度: + - Kubernetes(K8s)、Kubeflow、Ray、Slurm。 + - Service Mesh:Istio / Linkerd(支持灰度、限流、熔断、回退等流量治理)。 + - API 网关与鉴权: + - Kong、NGINX / APISIX / Envoy。 + - IAM / Keycloak / Auth0、云厂商 API Gateway、OAuth2 / OIDC 等。 + - 模型压缩与性能库: + - 量化:NVIDIA TensorRT‑LLM / TensorRT、Intel Neural Compressor、OpenVINO(PTQ / QAT)、BitsAndBytes、GPTQ、AWQ、AutoGPTQ。 + - 剪枝 / 稀疏:PyTorch Sparse、TensorFlow Model Optimization Toolkit、SparseML、Neural Magic。 + - 蒸馏:DistilBERT / TinyBERT 等参考方案,或基于 Hugging Face Trainer + 自定义 distillation loss 的蒸馏 pipeline。 + - 推理引擎 / Runtime 与图优化: + - ONNX Runtime、TensorRT、OpenVINO Runtime、TVM、MNN、NCNN。 + - 大模型专用推理引擎:Sglang、vLLM、FasterTransformer、TGI、LMDeploy、DeepSpeed‑Inference。 + - 编译与图优化:TVM、XLA(JAX/TF)、TensorRT Graph Optimizer、TorchDynamo / TorchInductor、MLIR、Glow、ONNX Graph Optimizer、Intel NNCF 等。 + - 硬件与异构支持: + - GPU:CUDA / cuDNN / cuBLAS、ROCm(AMD)。 + - CPU:oneDNN(MKL‑DNN)、OpenBLAS、Eigen。 + - NPU / 专用加速卡:Ascend CANN、Habana Gaudi、Graphcore IPU 等 SDK。 + +在产品侧,这一层常以 **企业 AI 中台 / 模型服务总线、对外云 ** **API** **、统一推理** **网关** **、高 \*\***QPS\***\* 在线推理集群、低成本\*\***批处理\***\*平台与\*\***算力\***\*利用率优化方案** 的形态出现,是支撑大模型能力规模化落地的运行时“操作系统”。 + +### 11.2.1 部署架构与模型路由:从单模型到多模型服务网格 + +在早期尝试阶段,很多团队会选择以一个“大而全”的模型作为**单一入口**提供服务:所有请求都经由同一个模型处理。这种模式架构简单、维护成本低,适合 POC 与低流量场景。但随着业务扩展和成本压力上升,单模型架构的不足会迅速暴露: + +1. 不同任务对延迟 / 成本 / 质量的要求并不相同,用同一个大模型处理所有请求会造成**算力** **浪费** 。 +2. 面向不同行业、不同客户需要提供差异化能力,例如行业专有模型、客户专属微调权重,很难在“单模型”模式下统一管理。 +3. 灰度发布、A/B 测试、跨地域灾备等场景要求能够在多个模型版本之间灵活调度。 + +因此,成熟的大模型服务体系往往会演进为**多模型服务与智能路由**架构: + +1. **多模型池与模型目录** :同时维护多种大小(small / base / large / ultra)、多种专长(通用 / 代码 / 多模态 / 行业专用)、多种版本(v1 / v1.1 / 客户定制等)的模型,并在服务层对其进行统一注册与管理。 +2. **路由策略** : +3. **规则路由** :基于请求参数(任务类型、用户等级、延迟 / 成本偏好等)以及业务规则(某行业某区域强制使用特定模型)进行显式选择。 +4. **模型选择器(** **Meta** **‑model)** :使用一个轻量级模型根据输入内容、历史效果、实时指标自动选择最优模型(如快速小模型 vs. 慢速大模型)。 +5. **A/B / Bandit 路由** :在新旧模型或不同配置之间进行在线实验,根据 CTR、用户满意度、任务成功率等指标自动收敛到更优方案。 +6. **多租户隔离与配额管理** : +7. 在模型路由之上叠加租户维度的配额控制、QPS 限制、访问鉴权与 SLA 分级,确保不同客户之间的资源与数据隔离。 +8. 通过**逻辑隔离 + 物理隔离(独占集群或专用节点)** n应对金融 / 医疗 / 政务等高合规场景。 +9. **弹性扩缩容与高可用** : +10. 基于 Kubernetes HPA / VPA、Cluster Autoscaler 实现按流量自动扩缩容。 +11. 通过多副本部署、负载均衡、灰度发布、蓝绿部署和多区域容灾保证服务稳定性。 + +技术上,往往会采用 **Kubernetes + Service Mesh(Istio / Linkerd)+ \*\***API\*\* **网关** **(Kong / APISIX / ** **Envoy** **)+ 模型服务框架(vLLM / TGI / Triton / Ray Serve / KServe)** 的组合,形成一个既支持多模型、多租户,又支持流量治理与灰度发布的 **服务网格化推理平台** 。 + +### 11.2.2 推理性能优化与硬件加速:把“推理一次多少钱”压到最低 + +在大模型大规模商用场景中,推理成本往往是最大的持续支出之一。如何在保证体验的前提下,将**单位请求成本(Cost per Request / per Token)和端到端延迟**压缩到可接受范围,是部署层的核心技术挑战。 + +在 **模型侧** ,常见手段包括: + +1. **量化(Quantization)** + 通过将权重和激活从 FP16 / BF16 压缩到 INT8 / INT4 / NF4 等低比特格式,显著降低显存占用和带宽开销。 + 1. 训练后量化(PTQ):如 GPTQ、AWQ、BitsAndBytes 等,对已有模型进行离线量化。 + 2. 量化感知训练(QAT):在训练 / 微调阶段考虑量化误差,提升量化后精度。 +2. **剪枝** **与稀疏化(** **Pruning\*\*** & Sparsity)\*\* + 通过结构化 / 非结构化剪枝去除不重要的权重或通道,使模型稀疏化,并结合硬件友好的稀疏算子(如 NVIDIA 稀疏矩阵加速)提高推理速度。 +3. **蒸馏(Distillation)** + 使用大模型作为教师,将知识蒸馏到更小的学生模型或任务特定模型上,在大幅降低参数规模的同时保持接近的任务性能,适合对延迟极敏感的在线业务或边缘部署。 + +在 **系统与 Runtime 侧** ,关键优化点包括: + +1. **KV** ** Cache 与长上下文优化** : + 在自回归生成中缓存历史 token 的注意力键值,避免重复计算,从而提高长对话与多轮请求的效率;结合分块计算和动态裁剪策略控制显存开销。 +2. **批处理\*\***与\***\*并行** **生成** : + 通过对多个请求进行动态批处理、分组调度和并行 token 生成,在不显著增加 P95 延迟的前提下提高整体吞吐;结合流式输出(Streaming)改善前端交互体验。 +3. **算子与图优化** : + 使用编译器和 Runtime(如 TensorRT、TVM、ONNX Runtime、TorchInductor)进行算子融合、内存布局优化、静态图编译,减少 kernel 启动和内存访问开销。 +4. **异构硬件调度** : + 根据不同任务的计算特性与延迟要求,在 GPU、CPU、NPU、FPGA 等异构资源之间做合理分配: +5. 极度延迟敏感和高并发的对话 / 搜索请求优先调度到 GPU / NPU。 +6. 批量生成、离线评估、日志回放等任务可以调度到 CPU 或低成本 GPU / NPU。 + +工具与框架上,TensorRT‑LLM、SgLang、vLLM、FasterTransformer、LMDeploy、DeepSpeed‑Inference 等已经形成了一套相对成熟的**大模型** **推理加速生态** 。在业务侧,这些优化最终体现为:**高 ** **QPS** **、** **低延迟** **的在线推理集群、低成本批量生成平台、** **算力\*\***利用率优化方案与 MaaS / \***\*API** ** 计费和成本核算系统** 。 + +## 11.3 数据与模型运维(Data / Model Ops) + +大模型一旦进入生产环境,就不再是“一次性交付”的静态资产,而是需要在**数据、模型、配置、版本和实验**五个维度持续迭代的动态系统。数据与模型运维层(Data / Model Ops)就是围绕这一现实构建的工程范式:从数据飞轮、模型生命周期管理到在线实验和自动化发布,为模型能力的**可持续提升与可控演进**提供基础。 + +这一层一端连接数据湖 / 数仓、日志与采集系统,另一端连接训练平台、评估体系和在线服务网关,是打通“数据–模型–业务反馈”闭环的中枢。 + +- **场景** + - 企业级数据中台 + 模型训练一体化平台:打通数据采集、清洗、标注、管理到训练 / 微调的全链路,支撑多模型持续迭代。 + - 面向 C 端 / B 端 AI 应用的“效果持续提升机制”:依赖用户反馈和使用数据驱动的数据飞轮。 + - 标注团队与算法团队共用的数据管理与标注工作台:支持任务分配、质检、版本回溯。 + - 集团级 ModelOps 平台:统一记录和管理所有模型版本、评估结果与发布状态。 + - 在线业务实验与灰度体系:支持 A/B 测试、多模型小流量试运行和自动择优放量。 + - 模型托管服务:为合作伙伴 / 客户提供“一处上传,多环境部署,多版本管理”的模型管理能力。 +- **原理** + - 数据管理与数据飞轮: + - **数据采集与治理** :从业务日志、用户对话、公开数据、合作方数据中采集样本,对其进行去重、降噪、脱敏、格式统一和质量评估。 + - **标注与反馈闭环** :通过专家标注与众包结合、配合质检机制构建高质量标注数据;将用户的点赞 / 点踩、纠错、人工复核等反馈回流至训练样本池。 + - **数据飞轮(Data Flywheel)** :模型上线后,持续收集真实使用数据 → 从中挑选高价值样本(如模型错误、低信度、高收益任务)→ 再训练或微调 → 模型效果提升 → 新一轮使用,形成正反馈循环。 + - 模型生命周期与发布: + - **模型版本管理** :为每个模型维护清晰的版本号(大小版本)、训练数据版本、配置参数、评估结果、安全报告与变更记录。 + - **CI/CD** ** 与自动化流水线** :训练完成后自动触发评估与安全检查,通过回归测试和阈值门控,只有在关键指标不过度退化的情况下才允许灰度发布与全量上线。 + - **实验与流量分配** :使用 A/B 测试、多臂老虎机等在线实验方法,对多版本模型进行对比,按实时业务指标(例如任务成功率、工单解决率、用户满意度)自动择优。 +- **模型** + - 数据湖与数仓: + - Delta Lake、Apache Hudi、Iceberg、Hive、BigQuery、Snowflake 等,用于统一存储与管理大规模结构化 / 非结构化数据。 + - 流式数据处理: + - Kafka、Pulsar、Flink、Spark Streaming 等,用于实时日志、用户对话和事件流接入。 + - 特征与样本管理: + - Feast 等 Feature Store、自研样本仓、ML Metadata Store,用于记录样本、特征和训练元数据。 + - 标注与质检平台: + - Label Studio、Scale‑like 平台、自研标注系统,支持多任务标注、质检与人员管理。 + - MLOps / ModelOps 平台: + - MLflow、Kubeflow、SageMaker、Vertex AI、Azure ML、Weights & Biases 等,用于管理训练实验、参数、指标和模型 artifact。 + - 模型注册与版本管理: + - MLflow Model Registry、SageMaker Model Registry、W&B Artifacts 等。 + - CI/CD 工具: + - GitHub Actions、GitLab CI、Jenkins、Argo CD、Flux 等,用于构建模型持续交付管线。 + +### 11.3.1 数据飞轮与训练闭环:让模型“越用越聪明” + +在传统软件开发中,版本升级往往由开发计划驱动;而在大模型时代,**数据与反馈**成为迭代的主要驱动力。数据飞轮的目标,就是把“模型使用 → 数据沉淀 → 再训练 → 模型升级”变成一条自动滚动的闭环,让模型在实际业务中 **越用越好用** 。 + +核心环节包括: + +1. **在线数据采集与筛选** + 在对话机器人、Copilot、搜索问答、代码助手等应用中,每一次用户交互都是潜在的高价值训练样本。通过日志系统和事件追踪,将请求、模型回答、用户行为(点击、采纳与否)结构化采集下来,并在采集端就进行隐私脱敏与字段裁剪,确保不额外引入合规风险。 +2. **高价值样本挖掘** + 在海量日志中筛选出对训练最有价值的一小部分样本,例如: + 1. 明显错误或被用户点踩的回答,用于“纠错式”再训练。 + 2. 高难度长问题、复杂工作流任务样本,用于提升模型在“长链推理 / 多步工具调用”上的能力。 + 3. 典型业务案例、高价值工单,用于构建行业 / 企业专有能力。 +3. **标注与质量控制** + 对候选样本进行人工或半自动标注(包括期望回答、优劣排序、安全性标签等),并通过多轮质检、复核和抽检手段确保标注质量,为后续 SFT 或 RLHF 提供可靠数据。 +4. **持续\*\***再\***\*训练与评估上线** + 周期性地将新样本加入训练集,进行 SFT / DAPT / RLHF 等再训练操作,并通过标准评测集和在线 A/B 实验同时评估“离线指标 + 线上效果”,确保新版本在总体上优于旧版本,避免数据飞轮“拐到错误方向”。 + +在成熟形态下,数据飞轮的绝大部分操作会被自动化封装进 **Data / Model Ops 平台** :从数据采集、样本筛选、标注任务派发,到模型再训练触发、评估结果收集和上线决策,尽量减少人工操作,使模型迭代成为一个稳定可控的工程流程。 + +### 11.3.2 模型生命周期与 ModelOps:从实验模型到生产资产 + +随着模型数量与版本的指数级增长,如果缺乏严谨的生命周期管理,很容易出现“模型散落各处、版本混乱、回滚困难”等问题。ModelOps 的目标,就是把模型当作**一等公民的工程资产**来管理,全程可追溯、可比较、可回滚。 + +关键要点包括: + +1. **版本化与\*\***元数据管理\*\* + 为每个模型分配明确的版本号(如 `industry-legal-base-v1.2.3`),并记录: + 1. 训练数据版本与时间范围; + 2. 训练配置(超参数、训练脚本版本、使用的代码 Commit); + 3. 评估指标(通用基准 + 业务特定基准); + 4. 安全评估与对齐策略(如敏感话题回答策略版本); + 5. 上线 / 下线 / 回滚历史记录。 +2. **端到端自动化流水线(** **CI/CD\*\*** for Models)\*\* + 将“模型训练完成 → 自动评估 → 安全与偏见检查 → 灰度发布 → 全量发布”的流程封装进 CI/CD 管线。 +3. 若离线评估指标未达到预设门槛,则自动阻断上线。 +4. 若在线 A/B 实验表现不佳,则自动降低流量或回滚到上一版本。 +5. **多版本共存与流量调度** + 在生产环境中,往往会同时存在多个模型版本(如 `stable` / `canary` / `experimental`),通过流量分配策略(固定比例、用户维度、特征维度)对其进行在线对比。 + 1. A/B 测试更关注稳定统计结论; + 2. 多臂老虎机(Multi‑armed Bandit)在探索与利用之间自动折中,加速收敛到效果更好的版本。 +6. **合规与审计支持** + 对于金融、医疗、政务等行业,需要对每一次模型版本变更保持可追溯记录:谁在何时基于什么数据把模型从哪个版本升级到哪个版本,以及升级后的影响评估如何。这部分通常与第 11.5 节中的**安全与合规基础设施**联动。 + +工程实现上,MLflow / SageMaker / Vertex AI / W&B 等工具已经提供了相对成熟的 ModelOps 能力,多数企业会在其基础上结合自身流程做二次封装,构建统一的 **内部模型注册中心与发布平台** 。 + +## 11.4 监控、成本与可靠性(Monitoring, Cost & Reliability) + +当大模型成为业务核心基础设施时,如何保证其 **可观测、可预警、可扩缩、** **可控成本** ,就成为 SRE 和平台团队的核心职责。监控、成本与可靠性层将传统可观测性体系与大模型特有指标结合,构建面向运维、算法与管理层的多维度视图。 + +这一层一端连接监控采集、日志 / 链路追踪系统,另一端连接业务 KPI 与成本分析平台,是保证模型服务“稳、快、省”的关键支柱。 + +- **场景** + - 面向运维 / SRE 的运行监控大盘:统一展示 CPU / GPU 利用率、QPS、延迟、错误率、告警等。 + - 面向算法团队的数据与模型质量监控平台:监控输入数据分布、模型漂移、提示工程效果与 RAG 命中率等。 + - 面向管理层的服务健康看板:将业务 KPI(转化率、满意度、任务完成率)与模型指标绑定展示。 + - AI 成本分析与优化平台:按模型、项目、业务线拆解算力成本,支持预算管理与成本优化策略。 + - 智能调度与弹性伸缩系统:根据负载与预算自动扩缩容或切换模型规格。 + - 对外 MaaS / API 计费与成本核算系统:支撑按调用量、token 数、算力使用量等维度计费。 +- **原理** + - 监控与可观测性: + - **多层监控** :从基础设施层(CPU / GPU / 内存 / 网络 / 存储)到服务层(QPS、P50 / P95 / P99 延迟、错误率、超时重试),再到模型层(token 使用量、上下文长度分布、响应长度、常见错误类型)。 + - **日志与链路追踪** :通过结构化日志记录请求 / 响应(在脱敏前提下),并携带模型版本、路由决策、租户信息;使用分布式追踪工具记录请求从 API 网关 → 模型服务 → 下游系统的完整链路。 + - **告警与分析** :设置阈值告警、异常检测和趋势分析,并与业务指标、成本和安全事件联动,实现快速定位与恢复。 + - 成本控制与弹性调度: + - **成本分析** :按模型、项目、业务线维度拆解 GPU / CPU / 存储 / 带宽成本,计算单请求平均成本和不同任务 / 客户的边际成本。 + - **弹性调度** :运用峰谷分时策略,在高峰期自动扩容、低谷期自动缩容;将离线批量任务错峰到夜间或低负载时段。 + - **策略性降级与按需加速** :在资源紧张时自动切换到小模型、更短上下文或更保守的推理配置;对高价值请求自动使用更大模型或更长上下文。 +- **模型** + - 监控与可视化: + - Prometheus + Grafana、VictoriaMetrics、Thanos 等指标采集与可视化方案。 + - 日志系统: + - ELK(Elasticsearch + Logstash + Kibana)、EFK(Fluentd / Fluent Bit)、OpenSearch 等。 + - 链路追踪: + - OpenTelemetry、Jaeger、Zipkin 等。 + - 模型特定监控: + - WhyLabs、Arize AI、Fiddler、Evidently AI 等,用于数据 / 模型漂移监控与输出质量评估。 + - 成本统计与分摊: + - K8s Metrics / Cost Exporter、Kubecost,以及各云厂商 Cost Management 工具(AWS Cost Explorer / GCP Billing / Azure Cost Management)。 + - 资源调度与弹性伸缩: + - K8s HPA / VPA、Cluster Autoscaler、Volcano、Ray Cluster Autoscaler。 + - 任务编排: + - Argo Workflows、Airflow、Prefect、Dagster 等。 + +### 11.4.1 监控与可观测性:从基础设施到模型行为 + +在大模型系统中,传统的 CPU / 内存 / QPS 指标已经不够,需要叠加一层“模型视角”的监控,才能真正看清系统健康状况。一个完整的可观测性体系通常包含: + +1. **基础设施与服务层监控** + 通过 Prometheus / Grafana、VictoriaMetrics 等采集并可视化: + 1. 节点 / Pod 级别的 CPU、GPU、内存、磁盘、网络使用情况; + 2. 服务级别的 QPS、P50 / P95 / P99 延迟、错误率、超时重试比例、连接数; + 3. 集群级别的资源使用率与容量预警。 +2. **模型层指标监控** + 针对大模型服务,除了常规性能指标外,还需要专项监控: + 1. 每次请求的 token 消耗(输入 / 输出)、上下文长度分布; + 2. 响应长度与截断比例,以排查因上下文 / 输出长度限制导致的质量问题; + 3. 常见错误类型统计(如超长输入、模型超时、工具调用失败等)。 +3. **日志与\*\***分布式\***\*链路追踪** + 1. 使用结构化日志记录请求参数(脱敏后)、模型版本、路由决策、租户标识、返回代码等信息。 + 2. 借助 OpenTelemetry、Jaeger、Zipkin 等追踪一次请求在 API 网关 → 模型服务 → 下游系统 → 回调链路中的全程,便于定位延迟瓶颈和故障点。 +4. **异常检测与智能告警** + 在传统阈值告警基础上,可以引入简单的统计监控或机器学习模型,对 QPS、延迟、错误率、token 分布等进行异常检测,当出现突变时自动报警,并联动自愈策略(如自动扩容、流量切换、服务降级)。 + +对于算法团队,还可以在这一层接入 WhyLabs、Arize、Evidently AI 等工具,对输入分布、模型输出特征、漂移情况进行长期跟踪,为后续数据飞轮与再训练提供信号。 + +### 11.4.2 成本分析与弹性调度:在“体验”和“预算”之间找平衡点 + +大模型服务最显著的运维挑战之一就是 **成本高且波动大** 。缺乏精细化的成本分析与弹性调度,很容易在业务增长时看不到“钱烧在哪儿”,也难以及时做出调整。一个成熟的成本和资源调度体系通常包括: + +1. **成本归因\*\***与\***\*分摊** + 利用 Kubecost、云厂商 Billing 工具以及自研账本,将 GPU / CPU / 存储 / 带宽成本按模型、项目、业务线、租户等维度拆解,让每个团队和客户都能看到自己对应的真实资源消耗与费用。 +2. **单位请求成本与\*\***边际成本\***\*分析** + 1. 计算每个模型 / 任务的单请求平均成本(Cost per 1k tokens / per request),对比不同模型和配置下的性价比。 + 2. 分析不同客户、不同业务场景的边际成本,为定价策略(API 计费)、SLA 分级和产品打包提供依据。 +3. **弹性扩缩容与峰谷利用** + 1. 通过 K8s HPA / VPA、Cluster Autoscaler、Ray Autoscaler 等机制实现自动扩缩容,保证在高峰期不炸服、在低谷期不闲置。 + 2. 将离线任务(如批量内容生成、日志重放、离线评估)安排在夜间或非高峰时段,以提高整体 GPU 利用率,平滑成本曲线。 +4. **策略性降级与按需加速** + 1. 在资源紧张或成本超预算时自动触发降级策略:使用更小模型、缩短上下文或输出、降低并行度。 + 2. 对高价值请求(如付费高等级用户、关键业务流程)自动使用更大模型、更长上下文或更丰富的工具调用能力,实现“按价值分配算力”。 + +在对外 API 场景,这一层还会与计费系统深度绑定,形成 **MaaS / API 计费与成本核算平台** :根据 token 使用量、调用次数、模型规格和请求类型进行计费,并为运营 / 销售提供成本与毛利分析。 + +## 11.5 安全、权限与合规基础设施(Security, Access Control & Compliance Infra) + +大模型能力一旦进入金融、医疗、政务等高敏感行业,安全与合规不再是“附加价值”,而是进入场景的前置门槛。安全、权限与合规基础设施层负责从**访问控制、数据安全、隐私保护到合规审计**构建系统级防线,保证模型服务在法律与监管框架内可靠运行。 + +这一层一端连接身份认证、权限管理、密钥与加密系统,另一端连接模型服务和日志 / 审计平台,是把“能用的模型”变成“敢用的模型”的关键。 + +- **场景** + - 金融 / 医疗 / 政务等高合规行业的本地化大模型平台:要求数据不出域、可审计、可追溯。 + - 企业统一 AI 访问控制与审计网关:对所有模型调用进行统一鉴权、权限管理和审计记录。 + - 多租户 SaaS / 云平台:需要在逻辑和物理层面为不同客户提供严格的安全隔离与合规支撑。 + - 面向合作伙伴 / 生态的开放接口:要求对 API 调用进行精细化权限控制和配额限制,并满足合规要求(如 GDPR 等)。 +- **原理** + - 访问控制与租户隔离: + - 使用 API Key / Token / OAuth / SSO 等方式进行身份认证。 + - 通过 RBAC(基于角色的访问控制)和 ABAC(基于属性的访问控制)在模型、功能、调用频率和数据范围等维度进行精细化权限管理。 + - 在多租户环境中实现**数据、日志、配置和模型权重**的隔离,防止跨租户访问与信息泄露。 + - 数据安全与隐私保护: + - 采用 TLS 加密传输、存储加密和集中式密钥管理(KMS)保障数据在传输与存储环节的安全。 + - 实施日志脱敏和数据最小化策略,仅保留业务与优化所必需的信息,并对访问行为进行审计。 + - 在必要场景中引入隐私增强技术(如数据匿名化、差分隐私、联邦学习)进一步降低隐私风险。 + - 合规与审计: + - 对模型发布、配置变更、权限变更、路由策略调整等关键操作进行全程留痕与审批。 + - 为每一个请求记录可追溯的元数据:请求来源、模型版本、决策依据(如使用的知识库 / 工具调用情况)。 + - 确保系统设计和运行符合金融、医疗、政务等行业监管要求以及本地与跨境数据合规规范。 +- **模型** + - 身份认证与权限管理: + - Keycloak、Auth0、Okta、各云厂商 IAM(AWS IAM / GCP IAM / Azure AD)。 + - OPA(Open Policy Agent)+ Rego Policy 等策略引擎,用于统一策略管理与执行。 + - API 安全网关: + - Kong、Apigee、Envoy、云厂商 API Gateway 等。 + - 数据与密钥安全: + - KMS(Key Management Service)、HashiCorp Vault。 + - TLS 终端、机密计算(Confidential Computing)等。 + +### 11.5.1 访问控制与租户隔离:保证“谁能用、能用什么、能用多少” + +在多业务线、多客户、多角色共同使用的大模型平台中,若没有细粒度访问控制和租户隔离,很容易出现权限滥用、数据泄露和资源争抢等严重问题。一个完善的访问与隔离体系需要在以下几个维度配合: + +1. **身份认证与\*\***单点登录\*\* + 通过 API Key / Token、OAuth2 / OIDC、企业 SSO 等方式,对内部员工、外部合作伙伴、第三方应用进行统一身份认证。对企业用户,可与现有身份系统(如 AD / LDAP / 企业 IAM)打通,避免重复账号体系。 +2. **细粒度权限控制(** **RBAC\*\*** / \*\* **ABAC** **)** +3. RBAC:为管理员、算法工程师、业务运营、普通用户、合作伙伴等角色分别配置可访问的模型、环境(测试 / 生产)、操作(调用 / 配置 / 发布)与额度。 +4. ABAC:在角色基础上,引入租户 ID、项目 ID、数据域、时间段等属性,实现更灵活的策略(如“仅允许政务租户 A 在本地域调用本地化模型集群”)。 +5. **多租户隔离与配额管理** + 1. 在逻辑层面,通过租户 ID 隔离不同客户的调用、数据与日志; + 2. 在物理层面,对高合规客户(如银行 / 政府)提供专用集群或专用节点,实现更高等级的隔离; + 3. 配置不同租户的 QPS 限制、并发连接数和 token 配额,防止“某一租户暴冲拖垮全场”。 +6. **访问审计与策略评估** + 1. 对关键操作(如创建 / 删除 API Key、调整权限、修改配额)进行审计记录; + 2. 借助 OPA / Rego 等策略引擎,在执行前对复杂访问策略进行统一评估与解释,减少“策略散落代码中”的风险。 + +通过这层机制,平台可以在保证资源和数据安全的前提下,对内外部用户开放大模型能力,同时为后续合规审计和问题追责提供基础数据。 + +### 11.5.2 数据安全、隐私与合规审计:让模型“好用又合规” + +大模型往往会接触到大量敏感数据(用户对话、业务文档、交易记录等),一旦安全或合规出现问题,后果将极其严重。因此,需要在数据全生命周期和模型调用全链路上“多层防护”。 + +1. **数据传输与存储安全** + 1. 对所有外部和内部接口统一启用 TLS 加密,防止传输中被窃听或篡改; + 2. 对敏感数据采用静态加密存储,配合云厂商或自建的 KMS 管理密钥生命周期; + 3. 使用 Vault 等工具集中管理访问数据库、对象存储、第三方 API 所需的密钥和凭证。 +2. **最小化原则与脱敏** + 1. 只采集业务所必需的数据字段,并在日志与训练样本中尽量移除个人身份信息(PII)与敏感字段; + 2. 对不可避免要保留的标识符进行哈希或匿名化处理,降低泄露风险; + 3. 在 RAG / 知识库场景,对文档访问做权限分级,确保模型不会从“不该看的文档”中检索信息。 +3. **隐私增强技术与边缘约束** + 1. 在需要共享模型而不共享原始数据的场景中,引入差分隐私或联邦学习等方式,兼顾隐私与效能; + 2. 对政务、金融、医疗等场景,采用“数据不出域,模型下沉 or 本地部署”的模式,将训练 / 推理能力部署在合规域内。 +4. **合规与审计机制** + 1. 对模型发布、配置变更、权限调整等操作进行审批流与留痕,方便事后追溯; + 2. 对每次请求记录模型版本、调用方、路由决策、数据访问范围等元信息,在出现争议或调查需求时可以复盘; + 3. 定期输出合规报表(如数据访问审计、权限使用记录、异常事件报告),对接内部风控与外部监管要求。 + +这部分能力与 11.3、11.4 的 Data / Model Ops 和监控平台相互配合,共同构成一个“既能持续迭代,又能安全合规”的模型运行环境。 + +## 11.6 上层应用与中台能力(Application Enablers) + +有了从训练到推理、安全与运维的完整基础设施,还需要一层面向业务与开发者的“能力层”,将底层大模型抽象成更易用、更贴近业务语义的组件与服务。这一层通常被称为 **AI 中台、应用使能层或 Copilot 平台** ,其职责是:把大模型 + RAG + Agent + 工作流封装成标准化能力,让业务团队与生态伙伴可以快速搭建 AI 应用。 + +这一层一端连接模型 API、RAG 引擎与 Agent Orchestrator,另一端连接 CRM / ERP / OA / 工单等业务系统,是“从模型能力到业务场景”的关键桥梁。 + +- **场景** + - 企业 AI 中台 / Copilot 平台:为 CRM、ERP、OA、客服、营销、研发等内部系统统一提供对话、RAG、Agent 等智能能力。 + - 面向开发者与生态伙伴的应用开发平台:通过 SDK、模板工程、可视化编排工具,让第三方快速构建和部署 AI 应用。 + - 行业 SaaS 产品的 AI 后端:如智能客服云、营销云、办公协同云、研发管理云等,将 AI 能力嵌入原有产品体系。 + - 垂直场景助手:代码 Copilot、销售助手、运营助手、法务助手、医生助理等,通过中台能力迅速组合出场景化解决方案。 +- **原理** + - 对话与 Agent 能力: + - **会话管理与记忆** :维护多轮对话状态与长期记忆,支持话题切换、上下文压缩和个性化画像。 + - **工具调用(Tool Use)与\*\***工作流\*\* **编排** :通过函数调用或插件机制,将模型与外部系统(数据库、搜索、业务 API、第三方服务)连接起来;在复杂任务中使用 Workflow / Orchestrator 将多步操作串联起来。 + - **多 Agent 协作** :为复杂任务拆分出不同角色(如规划者、执行者、审阅者),以协作方式完成任务分解与结果聚合。 + - RAG 与知识库: + - **文档解析与预处理** :对 PDF、Word、网页、扫描件等文档进行解析、切块、结构化。 + - **向量化与检索** :使用 Embedding 模型对文本 / 表格 / 代码等内容进行向量化,构建向量索引;结合关键字检索与向量检索实现高召回。 + - **检索 + 生成(RAG)与证据链** :在推理时先从知识库检索相关内容,再由大模型基于检索结果生成回答,并输出引用与证据链,提高准确性与可解释性。 + - **知识图谱** **与结构化知识融合** :将领域知识图谱、业务数据表、规则系统与 LLM 结合,提高对结构化查询与复杂约束的处理能力。 + - 开发者接入与二次开发: + - **多语言 SDK 与 \*\***API\*\* ** 设计** :提供 Python / JS / Java / Go 等语言的 SDK,封装调用模式、重试与幂等处理。 + - **模板与\*\***低代码\*\* ** / 无代码搭建** :通过预制模板工程与可视化“搭积木”式工具,让非专业开发者也能搭建 RAG / Agent / Workflow。 + - **插件与中间件** :提供与常见业务系统(CRM / ERP / OA / 工单系统等)的插件或中间件,降低系统集成成本。 +- **模型** + - 对话 / Agent 框架: + - LangChain、LlamaIndex、Haystack、Semantic Kernel 等。 + - 自研 Orchestration 层:通常包含 Workflow Engine、Tool Router、Memory 管理模块。 + - RAG 与向量检索: + - 向量数据库:FAISS、Milvus、Qdrant、Weaviate、Pinecone 等。 + - 文档解析:unstructured、Textract、pdfplumber、Apache Tika 等。 + - SDK / 接入层: + - 官方或自研 SDK、前端组件库(聊天组件、提示模板管理、对话记录视图)。 + - 与业务系统(CRM / ERP / OA / 工单等)的中间件 / 插件。 + +### 11.6.1 对话与 Agent 编排:从“问答机器人”到“任务协作体” + +相比早期的 FAQ 式问答机器人,现代大模型驱动的应用更像是“会用工具的智能协作者”。对话与 Agent 编排的目标,是把大模型从“语言生成器”升级为能够**调用工具、执行计划、协调多角色**的智能体。 + +1. **对话管理与记忆机制** + 1. 维护对话上下文、用户画像和长周期记忆,在多轮交互中保持一致性与连贯性; + 2. 对超长对话采用摘要、检索式记忆等方式进行压缩,避免上下文“爆表”; + 3. 在企业内应用中,引入身份与权限信息到对话上下文中,使回答与操作符合用户在业务系统中的权限。 +2. **工具调用(Tool Use)与\*\***工作流\***\*编排** + 1. 为模型提供结构化工具列表(如“查订单”“创建工单”“查询库存”“调用搜索引擎”等),并通过函数调用接口让模型在需要时主动调用; + 2. 使用 Orchestrator 根据模型提出的计划,协调多个工具调用的顺序、数据流与错误处理; + 3. 对复杂业务流程(如审批流、报销、售后处理)进行工作流建模,让 Agent 可以扮演“流程协调者”的角色。 +3. **多 Agent 协作模式** + 1. 将复杂任务拆成多个角色:如“任务规划 Agent”“信息检索 Agent”“执行 Agent”“质检 / 审核 Agent”; + 2. 通过消息通道或共享内存实现 Agent 间协作,提升复杂任务的鲁棒性与可解释性; + 3. 在企业环境中,可以将人类角色也纳入协作环中,如“AI 起草–人类审核–AI 修改–系统执行”。 + +这一层通常借助 LangChain、Semantic Kernel、LlamaIndex 等现成框架,并配合自研的 Orchestration 服务,将对话、工具、工作流、权限和审计统一在一套“Agent 平台”内。 + +### 11.6.2 RAG、知识库与开发者平台:把企业知识“接到模型脑子里” + +大模型再强,也不可能天然掌握每一家企业的私有知识,更无法实时知道最新的政策、产品和业务规则。RAG + 知识库 + 开发者平台,就是把这些**企业知识、行业知识和实时数据**以工程化方式接入模型能力的关键路径。 + +1. **文档解析与知识入库** + 1. 通过 unstructured、Textract、pdfplumber、Tika 等组件,将 PDF、Office 文档、网页、图片扫描件解析为结构化文本; + 2. 按章节、标题、语义块等进行“切块”,为后续向量化与检索提供合适粒度; + 3. 对于表格数据、业务数据库、API 文档等结构化信息,构建对应的 schema 映射和访问接口。 +2. **向量化、索引与检索重排** + 1. 使用 Embedding 模型将文本 / 代码 / 多模态内容转换为向量,存入 FAISS、Milvus、Qdrant、Weaviate、Pinecone 等向量数据库; + 2. 同时保留关键词索引与元数据过滤能力(如按租户、部门、文档类型过滤),组合出高精度的“检索前过滤 + 语义检索 + 重排”流程; + 3. 在查询时,将检索结果与原始问题一起喂入大模型,实现“检索增强生成(RAG)”,并返回引用与证据链。 +3. **RAG 应用模板与\*\***低代码\***\*搭建** + 1. 为常见场景(知识问答、政策解读、产品说明、内部文档助手等)提供预制 RAG 模板; + 2. 通过可视化配置界面(选择知识源、设置切块规则、选定向量模型与大模型)快速搭建专属知识助手; + 3. 将这些能力以 SDK 形式暴露给开发者,支持在 Web、移动端、桌面端或业务系统插件中快速嵌入。 +4. **开发者平台与生态集成** + 1. 提供 Python / JS / Java / Go 等语言 SDK,以及前端组件(聊天气泡、文档引用区、反馈按钮等),降低集成门槛; + 2. 为主流业务系统(CRM / ERP / OA / 工单)提供插件或中间件,使其可以“勾选几项配置”就接入 AI 能力; + 3. 对外开放应用开发平台,让生态伙伴基于底座模型、RAG 与 Agent 能力构建自己的行业应用,形成“平台–生态–终端客户”的正循环。 + +这一层最终将复杂的模型与基础设施能力封装成“可复用、可拼装的业务组件”,帮助企业在**安全、合规、成本可控**的前提下,以更低门槛、更快速度,把大模型真正变成推动业务创新的生产力工具。 diff --git a/docs/assets b/docs/assets new file mode 120000 index 0000000..ec2e4be --- /dev/null +++ b/docs/assets @@ -0,0 +1 @@ +../assets \ No newline at end of file diff --git a/docs/demo.md b/docs/demo.md new file mode 100644 index 0000000..91aeaad --- /dev/null +++ b/docs/demo.md @@ -0,0 +1,63 @@ +# 组件库演示 (Element Plus) + +Easy-Vibe 已经集成了 [Element Plus](https://element-plus.org/),你可以在 Markdown 中直接使用 Vue 组件。 + +## 按钮示例 + + + Default + Primary + Success + Info + Warning + Danger + + +## 图标示例 + + + + + + + + + + + + + + +::: tip +要使用图标,你可能需要手动导入具体的图标组件,或者配置自动导入。上面的示例假设你已经配置好了或使用了简单的图标。 +::: + +## 卡片示例 + + + +
+ {{'List item ' + o }} +
+
+ + diff --git a/docs/examples/README.md b/docs/examples/README.md new file mode 100644 index 0000000..bf92f9b --- /dev/null +++ b/docs/examples/README.md @@ -0,0 +1,7 @@ +# Examples 实战案例 + +这里包含了实战案例的文档: + +- [Example 0.1: Snake Game Tutorial](example0/example0-1/vibe-coding-tools-snake-game-tutorial.md) +- [Example 0.2: Build Website with AI](example0/example0-2/vibe-coding-tools-build-website-with-ai-coding-and-design-agents.md) +- [Example 1: Build WeChat MiniProgram](example1/example1-how-to-build-a-wechat-miniprogram.md) diff --git a/docs/examples/example0/example0-1/vibe-coding-tools-snake-game-tutorial.md b/docs/examples/example0/example0-1/vibe-coding-tools-snake-game-tutorial.md index 84e5b3c..9382659 100644 --- a/docs/examples/example0/example0-1/vibe-coding-tools-snake-game-tutorial.md +++ b/docs/examples/example0/example0-1/vibe-coding-tools-snake-game-tutorial.md @@ -4,12 +4,12 @@ ### **你将学到:** -* **什么是 Vibe Coding:** 了解它的定义、工作流和关键优势。 -* **AI Agent 的角色:** 理解 AI Agent 的工作方式,以及它与传统程序的差异。 -* **如何写好提示词:** 掌握清晰、具体的提示词写法,以获得更好的结果。 -* **Vibe Coding 工具:** 认识一批主流的 AI 编程与设计平台。 -* **平台对比:** 从初学者视角出发,对 7 个不同 AI Agent 平台的优劣势进行评测与对比。 -* **UI / UX 工具:** 学会如何将 Figma、Mastergo 等 UI/UX 工具融入到整体工作流中。 +- **什么是 Vibe Coding:** 了解它的定义、工作流和关键优势。 +- **AI Agent 的角色:** 理解 AI Agent 的工作方式,以及它与传统程序的差异。 +- **如何写好提示词:** 掌握清晰、具体的提示词写法,以获得更好的结果。 +- **Vibe Coding 工具:** 认识一批主流的 AI 编程与设计平台。 +- **平台对比:** 从初学者视角出发,对 7 个不同 AI Agent 平台的优劣势进行评测与对比。 +- **UI / UX 工具:** 学会如何将 Figma、Mastergo 等 UI/UX 工具融入到整体工作流中。 # 1. 引言 @@ -25,18 +25,18 @@ Vibe Coding 的核心思想,是从 **“以代码为中心(code-first)”* 典型的 Vibe Coding 工作流程是一个不断迭代的循环: -* **描述目标:** 先用一句话或一段话描述你想要实现的功能,例如:“做一个带有 Python 后端、可以生成诗歌的简单贪吃蛇游戏。” -* **AI 生成代码:** AI Agent 解析你的需求,生成初版代码,包括基本结构、前端页面和后端逻辑。 -* **运行并观察:** 运行生成的代码,检查其是否按预期工作,同时发现 bug 或不足之处。 -* **反馈并迭代:** 如果有错误或效果不理想,就在对话中继续下指令,例如:“蛇移动太慢了,把速度调快些”,或者“现在 `.env` 文件里的 API Key 没被正确读取,请修复后端代码。” -* **重复上述步骤:** 不断在“描述 → 生成 → 运行 → 反馈”的循环中迭代,直到应用达到满意的状态。 +- **描述目标:** 先用一句话或一段话描述你想要实现的功能,例如:“做一个带有 Python 后端、可以生成诗歌的简单贪吃蛇游戏。” +- **AI 生成代码:** AI Agent 解析你的需求,生成初版代码,包括基本结构、前端页面和后端逻辑。 +- **运行并观察:** 运行生成的代码,检查其是否按预期工作,同时发现 bug 或不足之处。 +- **反馈并迭代:** 如果有错误或效果不理想,就在对话中继续下指令,例如:“蛇移动太慢了,把速度调快些”,或者“现在 `.env` 文件里的 API Key 没被正确读取,请修复后端代码。” +- **重复上述步骤:** 不断在“描述 → 生成 → 运行 → 反馈”的循环中迭代,直到应用达到满意的状态。 ### Vibe Coding 的主要优势: -* **降低门槛:** 让缺乏编程经验的设计师、创业者、学生等,也可以通过自然语言参与应用开发。 -* **快速原型:** 从想法到最小可行产品(MVP)的时间大幅缩短。 -* **提高效率:** 自动处理大量重复、机械的编码工作(如模板代码),让开发者可以把精力放在架构设计和问题抽象上。 -* **利于试验:** 鼓励先快速产出,再不断完善的方式,更便于尝试新点子和新功能。 +- **降低门槛:** 让缺乏编程经验的设计师、创业者、学生等,也可以通过自然语言参与应用开发。 +- **快速原型:** 从想法到最小可行产品(MVP)的时间大幅缩短。 +- **提高效率:** 自动处理大量重复、机械的编码工作(如模板代码),让开发者可以把精力放在架构设计和问题抽象上。 +- **利于试验:** 鼓励先快速产出,再不断完善的方式,更便于尝试新点子和新功能。 --- @@ -48,20 +48,21 @@ AI Agent 是一种软件系统,它能够感知环境、做出决策,并自 下面是一些将 AI Agent 与传统程序区分开的关键特征: -* **自主性(Autonomy):** AI Agent 具有较高的独立性。传统程序通常需要人一步一步触发,而 Agent 可以根据目标自主决定下一步要做什么。 -* **感知与记忆(Perception & Memory):** Agent 会从环境中收集数据(例如 API 响应、传感器数据、用户输入等),并通过“记忆”保留上下文,从而在后续行动中复用经验、持续改进效果。 -* **理性与目标导向(Rationality & Goal-Orientation):** Agent 会围绕给定的目标进行分析与规划,选择最合适的行动序列来追求更高的“绩效指标”。 -* **工具使用(Tool Use):** 现代 AI Agent 的一大特征,是可以调用外部工具,不再局限于“生成文字”。例如,它可以浏览网页、运行代码、查询数据库、发送邮件等,是一个会“调度工具”的大脑。 +- **自主性(Autonomy):** AI Agent 具有较高的独立性。传统程序通常需要人一步一步触发,而 Agent 可以根据目标自主决定下一步要做什么。 +- **感知与记忆(Perception & Memory):** Agent 会从环境中收集数据(例如 API 响应、传感器数据、用户输入等),并通过“记忆”保留上下文,从而在后续行动中复用经验、持续改进效果。 +- **理性与目标导向(Rationality & Goal-Orientation):** Agent 会围绕给定的目标进行分析与规划,选择最合适的行动序列来追求更高的“绩效指标”。 +- **工具使用(Tool Use):** 现代 AI Agent 的一大特征,是可以调用外部工具,不再局限于“生成文字”。例如,它可以浏览网页、运行代码、查询数据库、发送邮件等,是一个会“调度工具”的大脑。 可以这样类比理解: -* 一个 **传统程序** 像是计算器。你给它输入数字和运算符,它只在你按下按钮时执行计算。 -* 一个 **AI 助手** 像是人类助理。你让它“帮我找附近的餐馆”,它会给你搜索结果并列出选项,但最后还是由你做决策。 -* 一个 **AI Agent** 则更像是一支自动化研究团队。你只需要给出高层目标(比如“帮我规划一次日本旅行”),它就会分解任务、上网查资料、预定机票酒店(通过 API)、整理日程,最终把结果交付给你,全程几乎不需要你干预细节。 +- 一个 **传统程序** 像是计算器。你给它输入数字和运算符,它只在你按下按钮时执行计算。 +- 一个 **AI 助手** 像是人类助理。你让它“帮我找附近的餐馆”,它会给你搜索结果并列出选项,但最后还是由你做决策。 +- 一个 **AI Agent** 则更像是一支自动化研究团队。你只需要给出高层目标(比如“帮我规划一次日本旅行”),它就会分解任务、上网查资料、预定机票酒店(通过 API)、整理日程,最终把结果交付给你,全程几乎不需要你干预细节。 --- # 2. 关于提示词编写 + ## 1. 提示词一次写完好,还是拆成多步更好? 很多人会忍不住想直接在一个提示词里,把“做一个完整的全栈应用”一次性说清楚。事实上,当前工具已经足够强大,确实有机会一次性给出一个看上去还不错的结果。但从整体体验和成功率来看,把工作拆成小步骤、按阶段迭代,效果往往会更好,也更不容易陷入“改不动”的死胡同。 @@ -75,91 +76,92 @@ AI Agent 是一种软件系统,它能够感知环境、做出决策,并自 ## 2. 越清晰,越好 -* 在 Vibe Coding 中,你写的提示词和你写的代码一样重要。提示越清晰、越具体,结果就越接近你心中所想。 -* 一开始就把目标与约束条件说清楚,可以减少后续反复修改的次数,这不仅省时间,也能节省使用额度和成本。 +- 在 Vibe Coding 中,你写的提示词和你写的代码一样重要。提示越清晰、越具体,结果就越接近你心中所想。 +- 一开始就把目标与约束条件说清楚,可以减少后续反复修改的次数,这不仅省时间,也能节省使用额度和成本。 --- # 3. 工具总览(Vibe Coding / UIUX 工具) + ## 1. AI Agent 平台 - | **Name** | **Platform** | - | --------------------------------------------- | ------------------ | - | **[Lovable](https://lovable.dev/)** | Web-based | - | **[Cursor](https://cursor.com/cn/agents)** | PC | - | **[Z.ai](https://chat.z.ai/)** | Web-based | - | **[Replit](https://replit.com/~)** | Web-based | - | **[Minimax](https://agent.minimaxi.com/)** | Web-based | - | **[Trae](https://www.trae.ai/)** | PC | - | **[V0](https://v0.app/)** | Web-based | +| **Name** | **Platform** | +| ------------------------------------------ | ------------ | +| **[Lovable](https://lovable.dev/)** | Web-based | +| **[Cursor](https://cursor.com/cn/agents)** | PC | +| **[Z.ai](https://chat.z.ai/)** | Web-based | +| **[Replit](https://replit.com/~)** | Web-based | +| **[Minimax](https://agent.minimaxi.com/)** | Web-based | +| **[Trae](https://www.trae.ai/)** | PC | +| **[V0](https://v0.app/)** | Web-based | + ## 2. AI UIUX 平台 - | **Name** | **Platform** | - | ---------------------------------------- | -------------------- | - | **[Mastergo](https://mastergo.com/)** | Web-based | - | **[FIgma](https://www.figma.com/)** | Web-based, PC Plugin | +| **Name** | **Platform** | +| ------------------------------------- | -------------------- | +| **[Mastergo](https://mastergo.com/)** | Web-based | +| **[FIgma](https://www.figma.com/)** | Web-based, PC Plugin | --- # 4. 实战教程(Vibe Coding + UI 结合) + 1. 在你准备进行 Vibe Coding 的平台聊天窗口中,输入你想要的程序描述。 示例: - > 请构建一个带前端和后端的简单贪吃蛇(Snake)网页应用。 + > 请构建一个带前端和后端的简单贪吃蛇(Snake)网页应用。 > - > 1. 前端 + > 1. 前端 > - > - 页面 1:游戏页面 + > - 页面 1:游戏页面 + > - 使用键盘控制蛇的移动。 + > - 蛇吃掉的不是食物,而是英文单词。 + > - 页面侧边栏展示已收集单词及其数量。 + > - 游戏结束后,已收集的单词仍然保留,并在新一局中延续。 > - > * 使用键盘控制蛇的移动。 - > * 蛇吃掉的不是食物,而是英文单词。 - > * 页面侧边栏展示已收集单词及其数量。 - > * 游戏结束后,已收集的单词仍然保留,并在新一局中延续。 - > - 页面 2:写诗页面(Make Poem) + > - 页面 2:写诗页面(Make Poem) + > - 展示与游戏页面相同的单词列表(数据一致)。 + > - 提供一个按钮,将当前收集的单词发送给后端生成一首诗。 + > - 生成诗歌后,将被使用到的单词从列表中移除或递减计数。 > - > * 展示与游戏页面相同的单词列表(数据一致)。 - > * 提供一个按钮,将当前收集的单词发送给后端生成一首诗。 - > * 生成诗歌后,将被使用到的单词从列表中移除或递减计数。 + > * 添加简单的导航,在 Game 和 Make Poem 两个页面之间切换。 + > * 确保收集到的单词在两个页面中都能看到。 > - > * 添加简单的导航,在 Game 和 Make Poem 两个页面之间切换。 - > * 确保收集到的单词在两个页面中都能看到。 + > 2. 后端 > - > 2. 后端 - > - > * 提供一个后端接口,接收收集到的单词并返回一首诗。 - > * 使用 DeepSeek API 生成诗歌。 - > * 将 API Key 存放在 `.env` 文件中,并在 `.gitignore` 中忽略该文件。 - > -2. 输入你的 DeepSeek API Key。(可以在 [https://platform.deepseek.com/](https://platform.deepseek.com/) 获取) + > - 提供一个后端接口,接收收集到的单词并返回一首诗。 + > - 使用 DeepSeek API 生成诗歌。 + > - 将 API Key 存放在 `.env` 文件中,并在 `.gitignore` 中忽略该文件。 +2. 输入你的 DeepSeek API Key。(可以在 [https://platform.deepseek.com/](https://platform.deepseek.com/) 获取) 1. LLM 的 API Key 用于在你自己的项目中调用大模型。由于这是敏感信息,不能公开,因此需要单独写在配置文件里。 **为什么要用 `.env` 文件,并且不要把它上传到 GitHub?** + - `.env` 文件专门用来存放 **密钥或密码**(例如 DeepSeek API Key)。 + - 如果这个文件被上传到 GitHub,全世界的人都能看到你的密钥并盗用它。 + - 为了安全起见,我们需要在 `.gitignore` 文件中声明忽略 `.env`,让 Git 不跟踪它。 + - 这样一来,你的项目仍然可以在本机正常使用这些密钥,但不会在仓库中泄露。 - * `.env` 文件专门用来存放 **密钥或密码**(例如 DeepSeek API Key)。 - * 如果这个文件被上传到 GitHub,全世界的人都能看到你的密钥并盗用它。 - * 为了安全起见,我们需要在 `.gitignore` 文件中声明忽略 `.env`,让 Git 不跟踪它。 - * 这样一来,你的项目仍然可以在本机正常使用这些密钥,但不会在仓库中泄露。 3. 查看生成结果后,如果发现错误或有需要修改的地方,可以直接在聊天窗口中输入你的修改请求。 4. 如果你对页面设计不满意,也可以选择在 Figma 或 Mastergo 中重新设计界面,再把设计思路反馈给 Agent。 -* **示例** +- **示例** -> 请设计一个名为 *Word-Snake* 的 **双页面 Web 应用**。 +> 请设计一个名为 _Word-Snake_ 的 **双页面 Web 应用**。 > -> * **Game 页面:** -> * 蛇通过键盘控制移动。 -> * 蛇吃掉的是英文单词,而不是普通食物。 -> * 右侧面板展示已收集单词及数量。 -> * 游戏结束后,单词库存不会清空,在新一轮中继续使用。 -> * **Make Poem 页面:** -> * 展示同一份共享单词库存。 -> * 用户选择部分单词并点击 **Generate Poem** 按钮。 -> * 将这些单词发送给后端,由 DeepSeek API 生成一首诗。 -> * 生成诗歌后,从库存中删除或减少被使用的单词。 -> * **导航:** 通过简单的 Tab 或顶部菜单在两个页面之间切换。 -> * **共享状态:** 确保收集到的单词在两个页面始终保持同步可见。 +> - **Game 页面:** +> - 蛇通过键盘控制移动。 +> - 蛇吃掉的是英文单词,而不是普通食物。 +> - 右侧面板展示已收集单词及数量。 +> - 游戏结束后,单词库存不会清空,在新一轮中继续使用。 +> - **Make Poem 页面:** +> - 展示同一份共享单词库存。 +> - 用户选择部分单词并点击 **Generate Poem** 按钮。 +> - 将这些单词发送给后端,由 DeepSeek API 生成一首诗。 +> - 生成诗歌后,从库存中删除或减少被使用的单词。 +> - **导航:** 通过简单的 Tab 或顶部菜单在两个页面之间切换。 +> - **共享状态:** 确保收集到的单词在两个页面始终保持同步可见。 -* **效果示例** +- **效果示例** ![](images/image1.png)![](images/image2.png) @@ -170,137 +172,141 @@ AI Agent 是一种软件系统,它能够感知环境、做出决策,并自 不同的 Vibe Coding 平台各有特色和工作流。我们使用同一套“带 DeepSeek API 的贪吃蛇游戏”需求,在多个平台上进行实测,从初学者的角度评估它们的优劣。以下是总结。 ## 1. 对比标准 + 1. **目标(Goal)** 构建一个接入 DeepSeek API 的贪吃蛇(Snake)网页应用。 2. **游戏细节(Game Details)** - 1. 游戏通过 DeepSeek LLM API 生成诗歌。 2. 蛇吃掉的是英文单词,收集到的单词会在游戏结束后保留,并在新一局中继续使用。相同单词可以被多次收集,并分别计数。 3. 当生成一首诗后,被使用到的单词会从库存中移除。 -3. **必备功能(Must-Haves)** +3. **必备功能(Must-Haves)** 1. 一个可运行的前端页面,包含贪吃蛇游戏(键盘控制、Canvas 渲染)。 2. 单词收集机制(单词出现在棋盘上,蛇吃掉单词后,侧栏列表更新)。 3. 在多轮游戏之间保持单词库存的持久化。 4. 使用 DeepSeek API 的后端(如果没有 API Key,可以先返回模拟诗歌)。 5. “生成诗歌”按钮:点击后调用后端,显示诗歌,并根据使用情况更新单词库存。 6. 对 API Key 的 `.env` 支持,以及通过 `.gitignore` 避免密钥泄漏。 -4. **加分项(Nice-to-Haves)** +4. **加分项(Nice-to-Haves)** 1. 用户可以选择要用哪些词来生成诗歌。 2. 用户体验友好(例如侧边栏清晰展示单词列表、诗歌展示区布局合理)。 3. 为初学者在代码中加入注释,解释关键逻辑。 + ## 2. 编码输出对比 + ### 1. Lovable(Web-based) -* **平台类型:** Web 端 -* **主要特性与工作流:** Lovable 在集成与协作方面做得很好,它自动完成诸如连接 Supabase 数据库等初始化工作,使项目搭建过程非常顺畅。你只需描述项目需求,Agent 就会帮你把各类服务串联起来,构建好基本结构。 -* **适合的用户:** 对于第一次尝试 Vibe Coding 的新手来说,Lovable 是非常友好的选择。它简化了多服务联动的复杂度,让你可以把注意力集中在提示词与迭代上,而不是环境配置。得益于高度自动化,你能很快得到一个可运行的原型。 -* **提示词过程:** +- **平台类型:** Web 端 +- **主要特性与工作流:** Lovable 在集成与协作方面做得很好,它自动完成诸如连接 Supabase 数据库等初始化工作,使项目搭建过程非常顺畅。你只需描述项目需求,Agent 就会帮你把各类服务串联起来,构建好基本结构。 +- **适合的用户:** 对于第一次尝试 Vibe Coding 的新手来说,Lovable 是非常友好的选择。它简化了多服务联动的复杂度,让你可以把注意力集中在提示词与迭代上,而不是环境配置。得益于高度自动化,你能很快得到一个可运行的原型。 +- **提示词过程:** ![](images/image3.png) -* **贪吃蛇游戏效果:** +- **贪吃蛇游戏效果:** ![](images/image4.png)![](images/image5.png) -* **价格:** 相对偏贵,但如果你有学校邮箱,可以通过学生验证以半价使用。 +- **价格:** 相对偏贵,但如果你有学校邮箱,可以通过学生验证以半价使用。 ![](images/image6.png) ### 2. Cursor(IDE) -* **平台类型:** 桌面应用(PC) -* **主要特性与工作流:** Cursor 是一款集成了 AI 能力的专有 IDE,支持 Windows、macOS 和 Linux。它把代码生成、智能重写、代码库查询等功能直接嵌入在开发环境中。与 Web 工具相比,它更接近传统本地开发体验。由于是本地环境,不同电脑的配置各异,偶尔会遇到环境相关问题。好处是项目就在本机,无需再额外下载或配置运行环境,Cursor 会帮你处理很多繁琐步骤。 -* **适合的用户:** 对已有一定编程基础的用户,Cursor 是一个非常强大又熟悉的环境。但对完全零基础的新手来说,需要自己理解项目结构、依赖管理和文件组织等概念,学习曲线会更陡一些。更适合想在传统编码流程中加入 AI 助手的开发者。 -* **提示词过程:** +- **平台类型:** 桌面应用(PC) +- **主要特性与工作流:** Cursor 是一款集成了 AI 能力的专有 IDE,支持 Windows、macOS 和 Linux。它把代码生成、智能重写、代码库查询等功能直接嵌入在开发环境中。与 Web 工具相比,它更接近传统本地开发体验。由于是本地环境,不同电脑的配置各异,偶尔会遇到环境相关问题。好处是项目就在本机,无需再额外下载或配置运行环境,Cursor 会帮你处理很多繁琐步骤。 +- **适合的用户:** 对已有一定编程基础的用户,Cursor 是一个非常强大又熟悉的环境。但对完全零基础的新手来说,需要自己理解项目结构、依赖管理和文件组织等概念,学习曲线会更陡一些。更适合想在传统编码流程中加入 AI 助手的开发者。 +- **提示词过程:** ![](images/image7.png) -* **贪吃蛇游戏效果:** +- **贪吃蛇游戏效果:** ![](images/image8.png)![](images/image9.png) -* **价格:** +- **价格:** ![](images/image10.png) ### 3. Z.ai(Web-based) -* **平台类型:** Web 端 -* **主要特性与工作流:** Z.ai 的使用方式比较直接,但一个明显的挑战在于:你需要 **手动复制粘贴生成的代码**。平台本身缺少实时预览窗口,因此很难第一时间看到代码运行效果。 -* **适合的用户:** 这个平台要求比较“动手”的使用方式。缺少自动化意味着你必须与代码直接打交道,这对想深入理解 AI 输出内容的人来说反而是种训练。但频繁的复制粘贴会带来效率问题和出错风险。更适合想看“原生 AI 输出代码”的同学,而不是追求一键式体验的人。 -* **提示词过程:** +- **平台类型:** Web 端 +- **主要特性与工作流:** Z.ai 的使用方式比较直接,但一个明显的挑战在于:你需要 **手动复制粘贴生成的代码**。平台本身缺少实时预览窗口,因此很难第一时间看到代码运行效果。 +- **适合的用户:** 这个平台要求比较“动手”的使用方式。缺少自动化意味着你必须与代码直接打交道,这对想深入理解 AI 输出内容的人来说反而是种训练。但频繁的复制粘贴会带来效率问题和出错风险。更适合想看“原生 AI 输出代码”的同学,而不是追求一键式体验的人。 +- **提示词过程:** ![](images/image11.png) -* **贪吃蛇游戏效果:** +- **贪吃蛇游戏效果:** ![](images/image12.png)![](images/image13.png) -* **价格:** +- **价格:** ![](images/image14.png) ### 4. Replit(Web-based) -* **平台类型:** Web 端 -* **主要特性与工作流:** Replit 是一体化的在线开发与部署环境,浏览器里就可以写代码、运行程序、生成线上访问地址。开始编码前,它会给出清晰的行动计划;同时还提供可视化编辑器,你可以在预览窗口里直接改 UI,源码会自动同步更新。这样可以让你随时校验 AI 的输出是否符合预期,大幅减少来回修改的次数。 +- **平台类型:** Web 端 +- **主要特性与工作流:** Replit 是一体化的在线开发与部署环境,浏览器里就可以写代码、运行程序、生成线上访问地址。开始编码前,它会给出清晰的行动计划;同时还提供可视化编辑器,你可以在预览窗口里直接改 UI,源码会自动同步更新。这样可以让你随时校验 AI 的输出是否符合预期,大幅减少来回修改的次数。 ![](images/image15.png) -* **适合的用户:** Replit 对新手十分友好。它简化了从编码到部署的完整闭环,无需自己额外配置服务器或托管服务。协作功能也很强,适合同学之间一起做项目或请他人远程帮忙查看代码。 -* **提示词过程:** 在构建过程中,AI 并不是一开始就完全理解需求,中间经历了大约 3 轮迭代,最终输出才达到了理想效果。 + +- **适合的用户:** Replit 对新手十分友好。它简化了从编码到部署的完整闭环,无需自己额外配置服务器或托管服务。协作功能也很强,适合同学之间一起做项目或请他人远程帮忙查看代码。 +- **提示词过程:** 在构建过程中,AI 并不是一开始就完全理解需求,中间经历了大约 3 轮迭代,最终输出才达到了理想效果。 ![](images/image16.png) -* **贪吃蛇游戏效果:** +- **贪吃蛇游戏效果:** ![](images/image17.png)![](images/image18.png) -* **价格:** +- **价格:** ![](images/image19.png) ### 5. Minimax(Web-based) -* **平台类型:** Web 端 -* **主要特性与工作流:** Minimax 在执行任务时通常比较耗时。其流程往往包括:AI 自动发现并修复错误,因此整个过程可能较慢、甚至略显折腾。以本项目为例,Agent 一般会先生成一个详细计划,然后一步步搭建后端、数据库和前端逻辑。 -* **适合的用户:** 由于它会自动运行测试和修复错误,时间与 Token 消耗都比较大,但你可以清楚看到 AI 如何定位并解决问题,从学习角度看很有价值。 -* **提示词过程:** +- **平台类型:** Web 端 +- **主要特性与工作流:** Minimax 在执行任务时通常比较耗时。其流程往往包括:AI 自动发现并修复错误,因此整个过程可能较慢、甚至略显折腾。以本项目为例,Agent 一般会先生成一个详细计划,然后一步步搭建后端、数据库和前端逻辑。 +- **适合的用户:** 由于它会自动运行测试和修复错误,时间与 Token 消耗都比较大,但你可以清楚看到 AI 如何定位并解决问题,从学习角度看很有价值。 +- **提示词过程:** ![](images/image20.png)![](images/image21.png)![](images/image22.png)![](images/image23.png) -* **贪吃蛇游戏效果:** +- **贪吃蛇游戏效果:** ![](images/image24.png)![](images/image25.png) -* **价格:** 免费版在复杂项目中很可能无法顺利从头跑到尾,因此更推荐付费升级,以确保项目可以完整构建。 +- **价格:** 免费版在复杂项目中很可能无法顺利从头跑到尾,因此更推荐付费升级,以确保项目可以完整构建。 ![](images/image26.png) ### 6. Trae(IDE) -* **平台类型:** 桌面应用(PC) -* **主要特性与工作流:** 作为桌面应用,Trae 相比 Web 工具在性能和响应速度上通常更有优势。但它需要下载安装,对一些用户来说入门门槛稍高。同样地,由于是本地环境,不同电脑配置和依赖环境的差异,会带来一定的不确定性。优势在于,Trae 会帮助你在本地完成项目创建与运行配置,你可以直接在本机开发与调试。 -* **适合的用户:** 更适合计划长期进行 Vibe Coding 项目、并希望使用专门桌面工具的用户。对于只想“偶尔玩一下”的同学,可能不是最轻量的选择。 -* **提示词过程:** +- **平台类型:** 桌面应用(PC) +- **主要特性与工作流:** 作为桌面应用,Trae 相比 Web 工具在性能和响应速度上通常更有优势。但它需要下载安装,对一些用户来说入门门槛稍高。同样地,由于是本地环境,不同电脑配置和依赖环境的差异,会带来一定的不确定性。优势在于,Trae 会帮助你在本地完成项目创建与运行配置,你可以直接在本机开发与调试。 +- **适合的用户:** 更适合计划长期进行 Vibe Coding 项目、并希望使用专门桌面工具的用户。对于只想“偶尔玩一下”的同学,可能不是最轻量的选择。 +- **提示词过程:** ![](images/image27.png) -* **贪吃蛇游戏效果:** +- **贪吃蛇游戏效果:** ![](images/image28.png)![](images/image29.png) -* **价格:** 价格相对亲民,即便是免费版本,也足以完成质量不错的小项目。 +- **价格:** 价格相对亲民,即便是免费版本,也足以完成质量不错的小项目。 ![](images/image30.png) ### 7. V0(Web-based) -* **平台类型:** Web 端 -* **主要特性与工作流:** V0 是一个专注于生成 React UI 组件的工具,由 Vercel 提供。它在生成高质量、可用于生产环境的界面方面表现出色。但在实际使用中,会遇到诸如“难以找到代码视图”、“没有清晰说明 API Key 应该配置在何处”等问题。 -* **适合的用户:** V0 非常适合专注前端和 UI/UX 设计的学生或设计师。但它并不是完整的全栈解决方案,你仍然需要使用其他平台来实现后端逻辑与 API 集成,因此如果你的目标是“一站式搭建完整应用”,它可能不是最佳首选。 -* **提示词过程:** +- **平台类型:** Web 端 +- **主要特性与工作流:** V0 是一个专注于生成 React UI 组件的工具,由 Vercel 提供。它在生成高质量、可用于生产环境的界面方面表现出色。但在实际使用中,会遇到诸如“难以找到代码视图”、“没有清晰说明 API Key 应该配置在何处”等问题。 +- **适合的用户:** V0 非常适合专注前端和 UI/UX 设计的学生或设计师。但它并不是完整的全栈解决方案,你仍然需要使用其他平台来实现后端逻辑与 API 集成,因此如果你的目标是“一站式搭建完整应用”,它可能不是最佳首选。 +- **提示词过程:** ![](images/image31.png) ![](images/image32.png) -* **贪吃蛇游戏效果:** + +- **贪吃蛇游戏效果:** ![](images/image33.png)![](images/image34.png) -* **价格:** 免费用户大约可以构建 4–5 个简单项目。 +- **价格:** 免费用户大约可以构建 4–5 个简单项目。 ![](images/image35.png) ## 3. 平台总结对比 -| **平台** | **Review** | **Platform** | **Notes** | -| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **[Lovable](https://lovable.dev/)** | 对 AI 编程新手非常友好,上手简单、体验顺滑,是理想的入门选择。 | Web-based | 自动完成 Supabase 等服务连接,减少配置成本。 | -| **[Cursor](https://cursor.com/cn/agents)** | 适合已有开发经验的用户,大幅提升生产力与代码质量。 | PC | 需要一定编程基础,本地环境中需自己理解项目结构和依赖。 | -| **[Z.ai](https://chat.z.ai/)** | 更适合有编程基础、想直接研究 AI 输出代码细节的用户。 | Web-based | 无预览窗口,检查结果较麻烦;需要手动粘贴代码、创建文件夹和文件并手动运行服务。 | -| **[Replit](https://replit.com/~)** | 推荐给想快速把点子变成可访问在线服务的用户。 | Web-based | 一体化在线开发与部署,支持协作并提供可视化编辑器。 | -| **[Minimax](https://agent.minimaxi.com/)** | 适合希望看到 AI 自动查错与修复全过程、并从中学习的人,但整体较慢且耗费 Token。 | Web-based | 整个过程较长,AI 会多次自动运行测试并修复错误。 | -| **[Trae](https://www.trae.ai/)** | 针对有编程经验、希望使用桌面 IDE + AI Agent 组合的用户,是提升效率的有力工具。 | PC | 需本地安装与环境配置,但性能更好,适合长期进行 Vibe Coding 项目。 | -| **[V0](https://v0.app/)** | 为想快速做出 React UI 视觉效果的非开发者进行了优化,适合前端 / 设计向的学生。 | Web-based | 专注生成 React UI,需要与其他平台配合完成后端和完整应用搭建。 | +| **平台** | **Review** | **Platform** | **Notes** | +| ------------------------------------------ | ------------------------------------------------------------------------------ | ------------ | ------------------------------------------------------------------------------ | +| **[Lovable](https://lovable.dev/)** | 对 AI 编程新手非常友好,上手简单、体验顺滑,是理想的入门选择。 | Web-based | 自动完成 Supabase 等服务连接,减少配置成本。 | +| **[Cursor](https://cursor.com/cn/agents)** | 适合已有开发经验的用户,大幅提升生产力与代码质量。 | PC | 需要一定编程基础,本地环境中需自己理解项目结构和依赖。 | +| **[Z.ai](https://chat.z.ai/)** | 更适合有编程基础、想直接研究 AI 输出代码细节的用户。 | Web-based | 无预览窗口,检查结果较麻烦;需要手动粘贴代码、创建文件夹和文件并手动运行服务。 | +| **[Replit](https://replit.com/~)** | 推荐给想快速把点子变成可访问在线服务的用户。 | Web-based | 一体化在线开发与部署,支持协作并提供可视化编辑器。 | +| **[Minimax](https://agent.minimaxi.com/)** | 适合希望看到 AI 自动查错与修复全过程、并从中学习的人,但整体较慢且耗费 Token。 | Web-based | 整个过程较长,AI 会多次自动运行测试并修复错误。 | +| **[Trae](https://www.trae.ai/)** | 针对有编程经验、希望使用桌面 IDE + AI Agent 组合的用户,是提升效率的有力工具。 | PC | 需本地安装与环境配置,但性能更好,适合长期进行 Vibe Coding 项目。 | +| **[V0](https://v0.app/)** | 为想快速做出 React UI 视觉效果的非开发者进行了优化,适合前端 / 设计向的学生。 | Web-based | 专注生成 React UI,需要与其他平台配合完成后端和完整应用搭建。 | diff --git a/docs/examples/example0/example0-2/vibe-coding-tools-build-website-with-ai-coding-and-design-agents.md b/docs/examples/example0/example0-2/vibe-coding-tools-build-website-with-ai-coding-and-design-agents.md index f48b158..0c66344 100644 --- a/docs/examples/example0/example0-2/vibe-coding-tools-build-website-with-ai-coding-and-design-agents.md +++ b/docs/examples/example0/example0-2/vibe-coding-tools-build-website-with-ai-coding-and-design-agents.md @@ -1,83 +1,86 @@ # 1. 入门指南 + ## 1. 教程简介 让我们使用 AI 设计 Agent 和编码 Agent,从零开始搭建一个完整的网站。 -* **设计 Agent**:负责创建 logo、网页布局、配色方案和其他视觉元素 -* **编码 Agent**:根据你在提示中提出的需求与布局,编写 HTML/CSS/JS 等实际代码,构建可运行的网站 +- **设计 Agent**:负责创建 logo、网页布局、配色方案和其他视觉元素 +- **编码 Agent**:根据你在提示中提出的需求与布局,编写 HTML/CSS/JS 等实际代码,构建可运行的网站 ## 2. 设计 Agent 与编码 Agent -* **设计 Agent**:根据你提供的提示,生成图片、页面模型或设计风格的 AI。 -* Mastergo -* Lovart -* Figma MCP -* **编码 Agent**:根据你在提示中请求的功能与布局,编写实际的代码(HTML/CSS/JS 等)的 AI。 -* Z.AI -* Trae -* Cursor -* Lovable +- **设计 Agent**:根据你提供的提示,生成图片、页面模型或设计风格的 AI。 +- Mastergo +- Lovart +- Figma MCP +- **编码 Agent**:根据你在提示中请求的功能与布局,编写实际的代码(HTML/CSS/JS 等)的 AI。 +- Z.AI +- Trae +- Cursor +- Lovable --- # 2. 使用设计 Agent 创建 Logo + ## 1. 设计 Logo 时需要考虑的关键要素 Logo 是决定你网站第一印象的关键元素之一。想要从 AI 设计 Agent 那里获得满意的结果,你需要在提示中清楚地描述你想要的 Logo 类型。 1. **品牌名称 / 文本** -* 必须出现在 Logo 中的文字(例如:网站标题、品牌名称等)。 +- 必须出现在 Logo 中的文字(例如:网站标题、品牌名称等)。 2. **风格(情绪 / 气氛)** -* Logo 想要传达的整体感觉或氛围。 -* *示例:极简、可爱、简洁、现代、复古、未来感等。* +- Logo 想要传达的整体感觉或氛围。 +- _示例:极简、可爱、简洁、现代、复古、未来感等。_ 3. **配色方案**(可选) -* 最好让 Logo 的配色与整个网站的整体基调相匹配。 -* 可以指定具体的十六进制色号,或大致的色调(冷色、暖色等)。 -* *示例:**`#171721`**(黑色)、**`#FF7130`**(橙色)。* +- 最好让 Logo 的配色与整个网站的整体基调相匹配。 +- 可以指定具体的十六进制色号,或大致的色调(冷色、暖色等)。 +- _示例:**`#171721`**(黑色)、**`#FF7130`**(橙色)。_ 4. **形式(形状 / 结构)** -* 明确 Logo 是否需要特定的形状或构图。 -* *示例:文字在圆形内部、图标 + 文字组合、以图标为主的 Logo 等。* +- 明确 Logo 是否需要特定的形状或构图。 +- _示例:文字在圆形内部、图标 + 文字组合、以图标为主的 Logo 等。_ 5. **图标 / 符号元素**(可选) -* 希望出现在 Logo 中的图形或符号。 -* *示例:书本图标、闪电符号、与 AI 相关的图形、抽象几何图形等。* +- 希望出现在 Logo 中的图形或符号。 +- _示例:书本图标、闪电符号、与 AI 相关的图形、抽象几何图形等。_ ## 2. 编写 Logo 设计提示词 **示例提示词** ```Plain -"请为我设计一个极简风格的 Logo,品牌名称是 ‘My First Website’。 +"请为我设计一个极简风格的 Logo,品牌名称是 ‘My First Website’。 使用黑色 (#171721) 和橙色 (#FF7130),并将文字放在一个圆形内部。" ``` ```Plain -"请设计一个以 ‘AIID’ 为品牌名的 Logo。 -整体风格要未来感、干净简洁,主色为蓝色与白色。 +"请设计一个以 ‘AIID’ 为品牌名的 Logo。 +整体风格要未来感、干净简洁,主色为蓝色与白色。 将象征 AI 的抽象图形与文字相结合,并导出为带透明背景的 PNG。" ``` ## 3. 向 Agent 请求设计 -* 输入上述提示词 → 比对 Agent 生成的多个设计稿。 +- 输入上述提示词 → 比对 Agent 生成的多个设计稿。 ![](images/image1.png)![](images/image2.png) ## 4. 确定最终 Logo -* 从草稿中选择你最喜欢的版本并下载。 +- 从草稿中选择你最喜欢的版本并下载。 --- # 3. 规划你的网站结构 + ## 1. 了解基础版块 在真正开始制作网站前,先规划好要包含哪些菜单(版块)非常重要。菜单的设计取决于你希望访客看到什么、以及你希望他们采取什么行动。 @@ -103,18 +106,18 @@ Logo 是决定你网站第一印象的关键元素之一。想要从 AI 设计 A ### 可选菜单 4. **Services / Projects** - 1. 展示你提供的服务,或你的项目 / 作品集 2. 通常以列表或卡片形式展示 + 5. **Gallery** - 1. 用于展示图片、照片或设计作品 + 6. **Blog / News** - 1. 用于发布文章、动态或日志 -7. **FAQ** +7. **FAQ** 1. 整理访客经常会问的问题及解答 + ## 3. 选择配色方案(可选) 如果你已经有了 Logo,或者想用特定的颜色搭配来设计网站,也可以直接在提示词中写上你想使用的颜色代码。 @@ -123,13 +126,13 @@ Logo 是决定你网站第一印象的关键元素之一。想要从 AI 设计 A 即使你暂时想不到配色方案,也可以通过配色网站或搜索关键词来找到灵感。 -* **配色参考网站** - * https://colorhunt.co/ - * https://coolors.co/ +- **配色参考网站** + - https://colorhunt.co/ + - https://coolors.co/ ![](images/image3.png)![](images/image4.png) -* **在 Google 上通过关键词搜索配色** +- **在 Google 上通过关键词搜索配色** ![](images/image5.png) @@ -138,17 +141,18 @@ Logo 是决定你网站第一印象的关键元素之一。想要从 AI 设计 A **示例提示词** ```Plain -"请设计一个由 Home、About、Contact 三个版块构成的单页网站。 -使用配色 #171721、#FF7130 和 #FF3C68。 +"请设计一个由 Home、About、Contact 三个版块构成的单页网站。 +使用配色 #171721、#FF7130 和 #FF3C68。 整体风格要现代、简洁。" ``` --- # 4. 使用设计 Agent 设计网站 + ## 1. 输入提示词 → 生成设计稿 -* 在提示词中写出你规划好的结构以及选定的配色。 +- 在提示词中写出你规划好的结构以及选定的配色。 **Mastergo 提示词示例** @@ -158,10 +162,10 @@ Logo 是决定你网站第一印象的关键元素之一。想要从 AI 设计 A 你可以根据自己的需求,向 Agent 提出反馈,例如: -* “太花哨了,整体风格改得更简洁一些。” -* “换一种字体。” -* “调整一下颜色搭配。” -* “把这里这一块删掉。” +- “太花哨了,整体风格改得更简洁一些。” +- “换一种字体。” +- “调整一下颜色搭配。” +- “把这里这一块删掉。” ![](images/image8.png) @@ -188,21 +192,22 @@ Logo 是决定你网站第一印象的关键元素之一。想要从 AI 设计 A --- # 5. 使用编码 Agent 搭建网站 + ## 1. 理解 HTML/CSS/JS 的基础概念 一个网站本质上由三种语言构成: -* **HTML(HyperText Markup Language)** → 结构(骨架) -* **CSS(Cascading Style Sheets)** → 样式(外观) -* **JavaScript(JS)** → 功能(交互) +- **HTML(HyperText Markup Language)** → 结构(骨架) +- **CSS(Cascading Style Sheets)** → 样式(外观) +- **JavaScript(JS)** → 功能(交互) 这三者配合在一起,构成我们看到的完整网页。 1. **🏗️ HTML(结构)** -* 定义页面中“展示什么” -* 用来放置文本、图片、按钮、链接等元素 -* 类似于建筑物的 **墙体和框架** +- 定义页面中“展示什么” +- 用来放置文本、图片、按钮、链接等元素 +- 类似于建筑物的 **墙体和框架** **示例** @@ -214,9 +219,9 @@ Logo 是决定你网站第一印象的关键元素之一。想要从 AI 设计 A 2. **🎨 CSS(样式)** -* 决定“内容怎样展示” -* 控制文字大小、颜色、间距、背景、按钮形状等 -* 让 HTML 有了“衣服”和视觉风格 +- 决定“内容怎样展示” +- 控制文字大小、颜色、间距、背景、按钮形状等 +- 让 HTML 有了“衣服”和视觉风格 **示例** @@ -235,9 +240,9 @@ body { 3. **⚙️ JavaScript(JS)(功能)** -* 让网页能够和用户互动 -* 可以实现按钮点击、菜单展开、图片轮播、表单提交等动态效果 -* 如果说 HTML/CSS 是静态的骨架和外观,那么 JS 就是让网页“活起来”的 **大脑** +- 让网页能够和用户互动 +- 可以实现按钮点击、菜单展开、图片轮播、表单提交等动态效果 +- 如果说 HTML/CSS 是静态的骨架和外观,那么 JS 就是让网页“活起来”的 **大脑** **示例** @@ -256,8 +261,8 @@ function showAlert() { **示例提示词** ```Plain -"请为一个包含 Home、About 和 Contact 版块的单页网站编写 HTML 和 CSS。 -使用配色 #171721、#FF7130、#FF3C68。 +"请为一个包含 Home、About 和 Contact 版块的单页网站编写 HTML 和 CSS。 +使用配色 #171721、#FF7130、#FF3C68。 背景为黑色,文字为白色。" ``` @@ -279,8 +284,8 @@ function showAlert() { 你可以继续通过自然语言对草稿进行微调,例如: -* “把按钮做大一点。” -* “字体粗一点。” +- “把按钮做大一点。” +- “字体粗一点。” ![](images/image13.png)![](images/image14.png) @@ -306,25 +311,26 @@ Agent 生成的初版网站,通常会包含一些自动生成的占位文本 如果你想加入特定图片(例如 Logo、背景图等),可以先把图片上传到项目文件夹中,然后在提示词里说明要在页面的什么位置使用这些图片。 -* **示例:** +- **示例:** ![](images/image18.png)![](images/image19.png)![](images/image20.png) -* **结果:** +- **结果:** ![](images/image21.png) --- # 6. 将设计与代码整合 + ## 1. 将设计文件与网站代码整合(可选) 当你从设计 Agent 那里下载到了代码文件后,可以把它们移动到当前项目目录中,然后请编码 Agent 帮你将这些设计代码与现有项目进行合并。 -* **示例:** +- **示例:** ![](images/image22.png) -* **结果:** +- **结果:** ![](images/image23.png) diff --git a/docs/examples/example1/example1-how-to-build-a-wechat-miniprogram.md b/docs/examples/example1/example1-how-to-build-a-wechat-miniprogram.md index 3ccfc42..de58f52 100644 --- a/docs/examples/example1/example1-how-to-build-a-wechat-miniprogram.md +++ b/docs/examples/example1/example1-how-to-build-a-wechat-miniprogram.md @@ -1,447 +1,3 @@ -# 如何构建一个最简单的微信小程序 -# 1. 什么是微信小程序和微信小程序开发 +# 微信小程序开发实战 -在这篇教程中,我们将完整跑通一条闭环:从脑海中的一个想法,到在微信里可以搜索、可以扫码打开的真实小程序。 - -开始动手之前,我们需要先建立两个基本认知。 - -第一个是 **本质**:微信小程序到底是什么?它和普通 App、网页有什么不同?为什么这么多产品会选择用小程序这种形态?只有理解了小程序的底层逻辑,你才能判断自己的想法是否适合用小程序来实现。 - -第二个是 **路径**:当你说「我要做一个小程序」时,从零到上线的完整路径是什么样的?这条路上有哪些关键节点——构思阶段要考虑什么、开发环境怎么搭建、如何用 AI 辅助开发提高效率、模拟器调试有哪些坑、测试号和正式发布各自解决什么问题。把整个流程在脑子里先跑一遍,后面实操时才不会迷路。 - -搞清楚这两个问题之后,我们就可以正式进入开发环节了。接下来,让我们先从第一个问题开始:微信小程序究竟是什么。 - -## 1.1 微信小程序 - -微信小程序可以看成藏在微信里的应用。它不需要你去应用商店搜索、下载、安装,只要在微信里搜名字、扫码,或者点开别人分享的卡片,就能马上使用。用完直接关掉,下次需要再打开即可,不会长期占据你的手机桌面和存储空间。 - -对普通用户来说,小程序解决的是很多「一件小事」:查快递、点咖啡、看订单、玩一局小游戏。打开速度快、入口统一在微信里,这是它最大的体验特征。 - -对企业和开发者来说,小程序是一种可以被搜索、被分享的「小应用形态」。只要在微信公众平台上注册、配置好信息,通过审核,小程序就能对所有微信用户开放。和传统 App 相比,它更容易获得第一批用户,因为大家已经习惯在微信里完成很多事情。 - -在本教程里,我们不会做复杂的业务系统,而是选一个很经典的例子——贪吃蛇小游戏。它体量小、逻辑清晰,却又包含了一个完整小程序需要具备的元素:多个页面、简单交互、状态变化、分数记录等,非常适合作为你的第一个作品。 - -## 1.2 微信小程序开发 - -理解了「小程序是什么」,接下来要回答的问题是:那开发一个小程序,到底要做什么? - -你需要有一个清晰的目标(例如:做一个可以随时玩一局的贪吃蛇),设计出用户会看到的界面,告诉系统在不同操作下应该发生什么,并最终把这个作品发布出去。 - -在传统的开发流程里,上面这些步骤往往都由程序员主导,需要写大量代码。而在 AI 辅助开发的场景下,这件事可以拆得更细:你负责讲清楚想做什么,AI 帮你完成大部分具体怎么写。 这也意味着,对于刚入门的人来说,最重要的能力不再是背多少语法,而是能不能把需求描述清楚、能不能读懂 AI 给出的结果。 - -## 1.3 微信小程序开发的几种方法 - -真正做小程序时,大家采用的技术路线并不完全一样。为了避免你一上来就被各种名词淹没,我们只做一个粗略分类,让你知道常见的几条路分别长什么样。 - -第一种方式,是直接使用微信官方提供的原生能力。在微信开发者工具中创建项目后,你会看到一组固定的文件类型,用它们来描述页面结构、样式和逻辑。这种方式贴近官方文档,控制力强,但对第一次接触前端的人来说,学习曲线会稍微曲折一些。 - -第二种方式,是利用多端框架,比如 uni-app 等。你在本地主要是写类似网页的代码(例如 .vue 文件),然后通过框架把这套代码转换成微信小程序可以识别的形式。这样的好处是:结构更统一,以后如果想把产品发布到其他平台(比如 H5、App),改动会相对少一些。 - -基于以上两种方式,本教程会重点讲述使用 AI 辅助开发工具的小程序开发SOP。比如把整个项目在 Trae 里打开,然后直接对内置的 AI 助手说: 请帮我在这个文件里加一个首页,有标题和按钮——请帮我写一个游戏页面,可以显示贪吃蛇和分数,AI 会在理解现有代码的基础上,为你生成新的代码片段,或者帮你修改、重构。 - -这三种方式并不是互斥的。你完全可以在一个 uni-app 项目里,借助 Trae 的 AI 功能来完成大部分编码工作。关键不是选哪一个方法,而是知道:自己现在处在什么位置,以及有哪些工具可以用。 - -## 1.4 本文介绍的微信小程序开发步骤(粗略预览) - -本教程会带着**从环境到成品**的节奏,专门围绕贪吃蛇这个例子,结合 Trae 的 vibecoding 方式,把整个过程拆成一条你可以反复复用的路线。整体上,你将在后面的章节里经历这样几个阶段: - -1. 先搭建认知地基:弄清楚什么是微信小程序、常见的开发方式有哪些,以及我们要做的这款贪吃蛇小程序面向谁、在什么场景被使用。 -2. 然后完成环境准备:注册小程序账号,安装 HBuilderX、Trae 和微信开发者工具,并用 HBuilderX 创建一个可以在微信开发者工具中跑起来的基础项目骨架,让屏幕上先出现一个最简单的页面。 -3. 接下来进入正式开发:在 Trae 中打开这个项目,用 vibecoding 的方式和 AI 对话,一步步生成首页和游戏页的布局,实现蛇移动、吃食物、游戏结束等核心玩法。 -4. 在功能跑通之后,学会把 AI 当成「调试和重构伙伴」:遇到 bug 时请它一起排查,觉得结构乱时让它帮忙整理,并逐渐加上开始 / 暂停、最高分记录、界面微调等细节体验。 -5. 最后进入发布环节:把项目构建成微信可识别的版本,在微信开发者工具中做预览和真机测试,先以测试号和体验版的形式上线验证流程,完成备案和审核后,再把小程序正式发布出去,让别人也能在微信里搜索到、玩到你的作品。 - -这一节只负责把全景图画出来,不展开具体命令和代码。你现在需要做的只是先大致记住这 5 步: **理解 → 搭环境 → vibecoding 开发 → 调试打磨 → 构建发布** 。后面的章节会在每一步上慢慢放大,告诉你要准备什么、要和 AI 说什么,以及在每个阶段你应该在屏幕上看到怎样的结果。 - -# 2. 环境准备 - -在开始写任何一行代码之前,我们先把开发环境准备好。 这一部分的目标,是让你在后面的章节里不再纠结 **去哪儿下载软件、为什么运行不了** ,而是可以直接把注意力放在和 AI 对话、实现需求上。 - -你只需要会打开浏览器、下载文件、双击安装程序,就可以完成本节全部步骤。 - -## 2.1 本教程会用到的三个工具 - -整个贪吃蛇小程序的开发,我们会同时用到三个工具,它们各自负责不同的环节: - -1. 第一个是 Trae。你可以把它理解为一款集成了 AI 的代码编辑器,既能像普通 IDE 一样打开项目文件,又能让你直接用自然语言和 AI 交流,请它帮你写代码、改代码、解释代码。本教程里,大部分「和 AI 一起写小程序」的操作,都会在 Trae 里完成。你可以在浏览器中访问 https://www.trae.cn 获取最新版本。 -2. 第二个是 HBuilderX。它是一款对 Vue 和 uni-app 支持特别好的编辑器,官方提供了很多现成的小程序项目模板。我们会用它来「一键生成」一个基础的小程序项目,相当于先打好地基,再把地基交给 Trae 和 AI 去改造。HBuilderX 的下载地址是 https://www.dcloud.io/hbuilderx.html 。 -3. 第三个是微信开发者工具。这是微信官方提供的专门用来开发和预览小程序的工具。它负责把你写好的项目在电脑上跑起来,并支持在手机上进行真机调试。你可以从 https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html 下载适合你操作系统的版本。 - -简单总结一下:HBuilderX 帮你快速建一个小程序项目,Trae 帮你和 AI 一起写代码,微信开发者工具帮你看到真正运行中的小程序。 - -## 2.2 注册微信公众平台账号并获取 AppID - -有了工具,还需要一个 **小程序身份** ,这一步在微信公众平台上完成。 如果你之前从来没有注册过微信小程序,可以按照下面的顺序来做: - -1. 在浏览器地址栏输入 https://mp.weixin.qq.com ,打开微信公众平台网页,用你的微信扫码登录。 - -![](images/image1.png) - -2. 在首页选择「小程序」,按照页面提示完成注册流程,填写邮箱、手机号以及主体类型(个人或企业)。 - ![](images/image2.png) -3. 注册成功并进入后台后,找到「开发管理」或「开发设置」页面,就能看到一个唯一的编号,名字叫 AppID 。这个编号后面会用在项目配置里,相当于你这个小程序在微信里的身份证。 - -![](images/image3.png) - -建议你把 AppID 记录在一个方便找到的地方。后续章节在配置项目时,我们会直接把这个值填进去,让本地项目和线上小程序对应起来。 - -## 2.3 安装微信开发者工具 - -接下来,我们需要一个地方实际运行和预览小程序,这就是微信开发者工具存在的意义。 - -1. 访问下载页面 https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html 。 在这个页面上,你会看到针对不同操作系统的多个版本,通常选择与你电脑系统匹配的稳定版即可,比如 Windows 64 位或 macOS 版本。 -2. 下载完成后,双击安装包,按照安装向导一步步点击下一步。如果你不清楚要改什么设置,保持默认选项就可以。 -3. 安装结束后,从桌面或开始菜单启动微信开发者工具。首次启动时,它会在屏幕上显示一个二维码,提示你用手机微信扫码登录。用自己的微信扫码并确认授权后,就可以进入主界面。 - -![](images/image4.png)![](images/image5.png) - -后面当我们在 Trae 中准备好项目文件之后,就会把构建好的小程序导入到微信开发者工具里,在这里看到真实的运行效果。 - -## 2.4 准备 Trae 和 HBuilderX - -最后,我们把真正负责写项目的两个工具安装好:Trae 和 HBuilderX。 - -你可以 **先安装 Trae** 。打开浏览器访问 https://www.trae.cn ,根据页面提示下载适合你系统的版本。安装过程和普通软件一样,双击安装包,按提示完成即可。安装完成后,你会得到一个可以打开本地文件夹、查看代码、和 AI 对话的 IDE,后续所有 vibecoding 步骤都会在这里进行。 - -![](images/image6.png) - - **接着安装 HBuilderX** 。访问 https://www.dcloud.io/hbuilderx.html ,选择对应操作系统的发行包下载。HBuilderX 的包体非常小,启动速度也很快。安装完成后,你可以先熟悉一下它的界面,不需要深入研究功能;在后面的章节中,我们会用它来创建一个 uni-app 小程序模板,作为整个项目的起点。 - -![](images/image7.png) - -完成本节的所有步骤之后,你已经具备了完整的开发环境:有微信小程序的账号和 AppID,有可以预览的小程序运行环境,也有可以和 AI 一起写代码的 IDE。在接下来的部分,我们会从**创建第一个小程序项目骨架**开始,让这些工具真正跑起来。 - -## 2.5基础文件准备 - -1. 点击新建项目 - -![](images/image8.png) - -2. 选择默认模板,给小程序起名,选择存放路径,带你及右下角的创建: - -![](images/image9.png) - -3. 显示创建成功! - -![](images/image10.png) - -4. 接着可以在对应的文件夹中找到该文件夹,在Trae里面打开该文件夹,可以看到地基文件已经全部建造好: - -![](images/image11.png) - -# 3. 小程序开发 - -前面两部分,我们已经搞清楚了「小程序是什么」、以及「环境怎么配、工具怎么装」。 从这一节开始,正式进入实战:不再停留在概念层面,而是让 AI 真正帮你把贪吃蛇小程序从无到有做出来。 - -这一节,你会完整走完一次「开发环节」的 SOP,大致包括几步: - -1. 在 Trae 里把当前项目打开,给 AI 下第一条完整指令,让它基于现有骨架设计并实现一个可运行的贪吃蛇版本。 -2. 让 Trae 直接改动真实项目文件,而不是只给你“示例代码”,并学会用回退功能在需要时恢复到修改前的状态。 -3. 回到 HBuilderX 和微信开发者工具,通过「运行到小程序模拟器」的方式在模拟器里试玩这一版,实现从“代码视角”到“用户视角”的切换。 -4. 根据试玩结果,用自然语言持续提出修改需求,让 AI 帮你从按键控制迭代到摇杆控制,顺便体验一次「发现问题 → 描述问题 → AI 修复 → 再次验证」的闭环。 - -你当然可以选择先在开发前,把每个页面、每个按钮都想得一清二楚,再交给 AI。 但对完全小白来说,小程序的界面和交互设计本身也是一个全新的领域(后面我们会教你怎么用 AI 帮忙做设计),所以在这一次,我们刻意采用另一种方式: 先开干 ——让 AI 先生成一个能跑起来的版本,再一边看效果、一边用自然语言慢慢打磨和调整。 - -## 3.1 把需求一次性说清楚:给 Trae 下第一条“总指令” - -打开 Trae,载入前面已经准备好的小程序项目之后,我先没有急着改某一行代码,而是对内置的 AI 助手说了这样一件事: - -**我向AI“发号施令”,说我现在需要基于现在的框架写一个贪吃蛇小程序,请给设计此小程序并我写一个prompt。** - -也就是说,我不是「一点点要求它写某个函数」,而是先抛出一个完整目标,让 AI 帮我规划,但是AI不仅帮我做了计划,还直接落地第一版实现。 - -Trae 收到这条指令之后,会自动阅读当前项目结构,判断应该在哪些文件里增加页面、在哪些地方补充逻辑,然后直接对项目中的文件或代码做出修改,而不需要你自己去手搓代码或者增删改查文件/文件夹。 - -## 3.2 让 AI 自动修改代码,而不是“手搓” - -当你在 Trae 中点击执行这条指令时,AI 会进入一个「帮你改工程」的流程。 在这个过程中,你可以看到几个关键点: - -1. 它会在对话区解释自己的思路,比如会在哪个目录下新增页面、打算如何组织游戏逻辑。 - -![](images/image12.png)![](images/image13.png) - -2. 它会直接对真实项目文件做增删改,而不是只给你一段「示例代码」让你自己拷贝。 -3. 修改完成后,Trae 会生成一个简短的小结,告诉你:这次它改了哪些文件,大致做了哪些事情。 - -如果你对这一轮修改不满意(或者觉得某一步有问题),也不用紧张。Trae 在你发出对话的对话框外的左上角提供了「回退」能力,你可以一键把工程恢复到本次指令执行之前的状态,相当于给这次操作加了一个安全的撤销键。 - -![](images/image14.png) - -![](images/image15.png) - -## 3.3 在 HBuilderX 和微信开发者工具中查看效果 - -AI 完成第一轮开发之后,代码已经落在项目里了,但这时候你还没有看到玩家视角的效果。 下一步,我们需要把它跑起来。 - -具体做法是:回到 HBuilderX,找到顶部菜单的「运行」选项,选择「运行到小程序模拟器」中的「微信开发者工具」。这一操作会触发项目编译,并将结果交给微信开发者工具打开。 - -![](images/image16.png) - -底部的输出窗口会显示编译的过程。如果最终状态是「ready」且没有报错,就说明构建成功,你可以切到微信开发者工具里查看这一版小程序的界面和功能。 - -![](images/image17.png) - -在大多数情况下,HBuilderX 会自动帮你打开微信开发者工具,让你直接看到新的小程序。如果没有自动打开,你可以按下面的方式处理: - -1. 先在 HBuilderX 中停止当前运行。 -2. 手动启动微信开发者工具,让它处于打开状态。 -3. 回到 HBuilderX,再次点击「运行 → 运行到小程序模拟器 → 微信开发者工具」。 - -这样我们就可以微信小程序开发者工具中看到我们Vibecoding的小程序: - -![](images/image18.png) - -## 3.4 用自然语言反复调整和完善小程序,直到我们满意 - -在这次实践中,AI 一开始给我生成的是按键控制方向的贪吃蛇:屏幕上有四个方向按钮,点击不同方向,蛇就会改变运动方向。 功能上完全可以玩,但我个人更喜欢用摇杆控制。对于你的调整需求(不仅限于功能、UI设计、界面,等你熟练后,你甚至可以用自然语言让AI帮你接入其他大模型的API或接入数据库)——再强调一遍,你只需要用自然语言告诉大模型即可。 - -这就是 vibecoding 的优势所在:你不必自己去翻代码,查找事件绑定的位置、计算坐标的逻辑,而是直接把想法告诉 AI。例如,你可以在 Trae 的对话框里这样描述: - - 把按键换成摇杆控制,并且用户松开摇杆时蛇保持同方向移动,直到用户再次松开摇杆。 - -只要你把需求讲得足够清楚,AI 会自动定位到对应界面和逻辑文件,替你完成控件样式、交互绑定和方向处理等改动。 - -![](images/image19.png) - -修改完成后,再回到微信开发者工具中查看。 如果没有立刻看到变化,可以尝试点击开发者工具上的「运行」按钮,或者刷新小程序预览窗口,让最新的构建结果生效。 仍然没有更新时,可以在 HBuilderX 中先停止运行,再重新执行一次「运行到小程序模拟器」,即可看到调整之后的小程序: - -![](images/image20.png) - -## 3.5 出现问题怎么办:继续用自然语言沟通 - -AI 生成的版本不一定一开始就完美。有时候你会遇到这些情况: - -* 运行时报错,小程序无法正常打开; -* 功能大致正确,但细节和你想象的不太一样; -* 界面可以用,但你觉得还可以更好看或更顺手。 - -在这些时候,不需要自己钻进代码里盲改,而是可以把遇到的问题直接用自然语言重新描述给 Trae 中的 AI 助手,例如: - - 现在摇杆控制已经生效了,但有时候蛇会突然停止不动,请帮我检查当前实现哪里有问题。 或者: 现在游戏可以玩,但界面有点拥挤,我希望在手机上显示时上下留出更多空白。请你帮我调整布局。 - -AI 会根据你当前的项目状态和描述,给出修改建议并直接应用在代码里。如果修改之后结果更糟或方向不对,你依然可以使用回退,把工程恢复到前一个稳定版本,再换一种说法尝试。 - -通过这几轮往返,你会从最初的“毛坯版本”,逐步打磨出一个更贴近自己喜好的摇杆版贪吃蛇小程序。例如我给出了一种图画风格,让AI根据此风格来调整小程序的UI风格: - -![](images/image21.png) - -## 3.6 最终成品与本节小结 - -经过一轮又一轮的 **自然语言叙述 → AI 修改 → 在微信开发者工具中预览 → 继续对话微调** ,我最终得到的是这样一个成品: - -* 有完整的游戏页面; -* 蛇可以顺畅移动并吃到食物; -* 支持摇杆控制; -* 在小程序模拟器中可以顺利运行。 - -最终开发成品如下: - -![](images/image22.png)![](images/image23.png)![](images/image24.png) - -在这一节里,你已经看到了一个完整的闭环: - -1. 在 Trae 中用一句清晰的指令,让 AI 搭出第一版贪吃蛇小程序; -2. 借助 HBuilderX 和微信开发者工具,从用户视角检查实际效果; -3. 用自然语言反复向 AI 提出修改需求,让它替你完成功能调整和界面优化; -4. 在任何一步出现问题时,都可以通过回退和重新运行来保证安全。 - -接下来,你可以按照同样的节奏去尝试自己的想法:不一定非要是贪吃蛇,也可以是一个工具小程序、一个活动页,甚至是你工作中真正需要的业务原型。你的主要任务,是把需求想清楚、说清楚,其余的交给 AI 和这些工具来配合完成。 - -# 4.小程序发布 - -前面三章,我们已经完成了从 **搭环境** ——**和 AI 一起开发**到**在本地模拟器里跑通贪吃蛇**的整个流程。 - -从这一章开始,我们关心的问题变成了:**怎样把这个作品真正挂到微信上,不只是一个小玩具,而是所有人都可以使用的微信小程序呢?** - -为了降低门槛,我们先走一条 **最短闭环** :只让它以**测试号**的形式上线,先自己和少数同学体验;等到你觉得功能和体验都足够稳定,再走正式上线流程。 - -本章先讲到 4.1,帮你完成**测试号上线**这条最短路径;关于面向所有用户的正式上线,会在 4.2 中再展开。 - -## 4.1 最短 SOP —— 测试号上线 - -这一小节的目标只有一个:让你在微信里,真的能以**体验版**的形式打开自己的贪吃蛇小程序。 - -整个流程可以理解为四件事: - -1. 在微信公众平台找到并确认自己的 AppID。 -2. 在项目里把这个 AppID 配置好。 -3. 用微信开发者工具上传当前版本。 -4. 回到公众平台,把这次上传的版本设置为「体验版」。 - -下面我们按照这个顺序来走一遍。 - -### 4.1.1 在微信公众平台确认 AppID - -第一步,是在微信公众平台上确认你的小程序 AppID。 - -这一步你之前在**2.环境准备**时已经做过一次,这里是把它真正用起来。 - -1. 打开浏览器,访问 `https://mp.weixin.qq.com`,登录你的小程序后台。 -2. 在左侧菜单中找到「开发管理」,进入其中的「开发设置」。 -3. 在页面上方,你会看到一块叫做「开发者 ID」的区域,里面有一行「AppID(小程序 ID)」——这就是你的小程序唯一编号。 - -这串编号需要和项目中的配置一一对应,否则微信会认为你上传的是「别人的小程序」,自然无法正常预览和发布。 - -![](images/image25.png) - -### 4.1.2 在项目中填写 AppID - -第二步是把这个 AppID 写进你的项目配置里,让本地构建出来的小程序和公众平台上的这个「账号」对应上。 - -如果你是用 uni-app 模板来做的项目,可以按照下面的方式操作: - -1. 打开 HBuilderX,载入你的贪吃蛇项目。 -2. 在左侧文件树中找到 `manifest.json`,双击打开。 -3. 下拉到「微信小程序配置」这一栏,你会看到一个输入框,提示类似「微信小程序 AppID(请在微信开发者工具中获取)」。 -4. 把刚才在公众平台上看到的 AppID 原样粘贴进来,保存文件。 - ![](images/image26.png) - -到这里为止,你的本地项目就已经认领了这个小程序身份。接下来,只要通过微信开发者工具上传版本,它就会被记在这个 AppID 名下。 - -### 4.1.3 在微信开发者工具中上传一个版本 - -前面我们已经用 HBuilderX 把项目运行到微信开发者工具里,看过模拟器中的效果。 - -现在要做的是:在开发者工具中,把当前这份代码“”打一个版本包”上传到服务器上。 - -大致步骤如下: - -1. 在微信开发者工具顶部工具栏的右侧,你会看到一个「上传」按钮,点击它。 -2. 弹出的窗口中,需要填写两个关键字段: - 1. 版本号:例如 `1.0.0`,只允许数字和小数点。 - 2. 项目备注:写一段简短说明,比如「完成基本功能的开发」。 -3. 检查无误后,点击「上传」按钮。下面的输出区域会显示编译过程,所有步骤变成绿色并提示上传完成,就说明这一版已经成功提交到了微信服务器。 - -![](images/image27.png) - -![](images/image28.png) - -![](images/image29.png)![](images/image30.png) - -### 4.1.4 在管理后台中把版本设为体验版 - -上传只是把代码送到了微信这边,还没告诉系统“这是一版可以试用的体验版本”。 - -最后一步,我们回到公众平台的小程序后台,完成这个闭环。 - -1. 再次打开 `https://mp.weixin.qq.com`,进入你的小程序后台。 -2. 在左侧找到「管理」下面的「版本管理」,点击进入。 -3. 在页面的「开发版本」一栏,你应该能看到刚刚上传的那个版本:版本号是 `1.0.0`,备注是你写的那一段说明,时间是刚刚的上传时间。 -4. 在这一行的右侧,会有一个下拉按钮或操作按钮,可以选择「设为体验版」,点击之后,确认操作,注意在这一步之前请确保你已经在首页-小程序类目设置好了你的主营类目。 - - ![](images/image31.png) - - ![](images/image32.png) - -完成之后,这个版本就变成了你的小程序「体验版」。你可以在后台生成体验版二维码,也可以把自己和同事加入「体验成员」,让大家用微信扫描后,在真机上体验这款贪吃蛇小程序。 - -到这里,我们就完成了从本地项目到测试号上线的最短闭环: - -你不需要一开始就面向所有微信用户开放,只是在一个安全的范围内,让真实的小程序跑在真实的微信环境里。这足够你用来测试功能、收集反馈、继续迭代。 - -## 4.2 小程序正式上线 - -体验版跑通之后,你已经可以在自己的微信里玩到这款贪吃蛇小程序了。 接下来要做的,就是把它从只有少数体验成员能用的状态,推进到全民可用正式微信小程序。 - -把这件事拆成几步:先补充信息,再选择类目,然后完成备案,最后提交审核。下面按照这个顺序走一遍。 - -### 4.2.1 进入小程序发布流程 - -首先回到微信公众平台后台,登录你的小程序账号。 在左侧导航里找到与「版本管理 / 发布」相关的入口(不同时间界面可能略有调整),展开后会看到「小程序发布流程」这一项。 - -点击进入之后,界面上方会显示一个进度条,下面依次列出几个步骤,例如: - -1. 小程序信息 -2. 小程序类目 -3. 运营信息 / 小程序备案 -4. 微信认证(视你的主体而定) - -一开始进度会显示 0%,随着你完成每一步,系统会自动把进度向前推进。 - -![](images/image33.png) - -### 4.2.2 填写小程序基本信息 - -第一步是把小程序的「名片」补充完整,这也是用户在微信里第一次看到你的时候会接触到的内容。 - -在「小程序信息」页面,你通常需要填写和确认以下内容: - -1. 小程序名称 这个名字会出现在搜索结果和小程序顶部,有长度限制,同时需要符合微信的命名规范。建议选择既能表达功能,又方便记忆的名称,例如「贪吃蛇 vibecoding 版」这一类。 -2. 功能介绍 / 简介 用一两句话说明这个小程序是做什么的,例如:「一款用 AI 辅助开发完成的贪吃蛇小游戏,适合在碎片时间玩一局。」 注意简介要和实际功能一致,避免使用夸张宣传语。 -3. 图标和展示图片 - 1. 图标一般要求为正方形图片,支持 PNG/JPG 等格式,大小和像素有明确限制(以页面说明为准),建议提供一张简洁、对比度高的图。 - 2. 展示图片可以上传几张小程序页面的截图,例如首页、游戏页面、设置界面等,这些会出现在详情页中,帮助用户了解内容。 -4. 其他必要信息 例如标签、服务区域等,根据页面提示填写即可。 原则只有一个:所有填写的内容都要和这款贪吃蛇小程序真实功能相符。 - -![](images/image34.png) - -全部填写完毕后,点击保存或下一步,发布流程中的第一步就完成了。 - -### 4.2.3 选择小程序服务类目 - -完成基本信息后,向导会引导你进入「小程序类目」步骤。 类目可以理解为小程序在微信里的「归属分类」,决定它在审核时会被归入哪一类应用,也会影响后续展示和运营。 - -![](images/image35.png) - -在这个页面,你会看到「添加类目」按钮。点击后,可以从系统提供的分类树中选择适合你小程序的方向,例如: - -![](images/image36.png) - -1. 先选择「教育」这一大类; -2. 再在下面选择「教育工具 / 教学辅助」等更具体的子类,本次我选择了教育器具,当做大家学习Vibecoding的教具吧~ - -你在自己的项目里,只需要根据实际用途选择最贴切的一项即可。 - -![](images/image37.png) - -![](images/image38.png) - -确认类目后,点击保存。如果页面提示「创建类目成功」,并在列表中显示你刚刚添加的那一项,就说明这一步已经完成。 - -### 4.2.4 完成小程序备案信息 - -接下来,发布流程会要求你完成「运营信息 / 小程序备案」部分。这一步是为了验证小程序的主体身份,确保上线的应用有明确责任人。 - -![](images/image39.png) - -在个人主体的示例下,大致会经历这样几个动作: - -1. 选择备案类型 页面会让你在不同主体类型之间进行选择,例如「个人」「企业」等。根据你注册小程序时的主体保持一致即可。 -2. 填写主体信息 包括姓名、证件类型、证件号码等基本信息。 这一部分需要与注册信息保持一致,否则可能会在审核时被退回。 -3. 上传证明材料 页面通常会要求你上传身份证照片或其他证明文件,具体格式、清晰度和大小要求会写在说明里。 按提示准备好图片后上传,确保内容清晰可辨。 - ![](images/image40.png) - -提交之后,系统会进入「审核中」状态,页面上会显示类似「信息已提交,请耐心等待」的提示。这个过程可能需要一定时间,你可以在后台随时查看备案进度。 - -![](images/image41.png) - -### 4.2.5 提交审核并等待正式发布 - -当「小程序信息」「小程序类目」「运营信息 / 备案」等步骤全部被勾选完成后,你就可以进行最后一个动作:提交审核。 - -1. 回到「小程序发布流程」总览页面,确认每一项都显示为已完成,进度条接近 100%。 -2. 根据页面提示,点击「提交审核」或类似按钮,把当前开发版本送交微信团队审核。 -3. 在「版本管理」中,你会看到这次提交的版本状态变为「审核中」。通过后,会变成「已发布」或可选择「上线」的状态。 - -备案审核不通过会打电话给开发者,提示不通过的部分。 - -备案会收到“工业和信息化部”发来的验证码,和核验链接,点击进入把验证码和个人信息填入就行(核验有效期是1天)备案通过会收到“工业和信息化部”发送的邮件和短信通知,并且告知备案号。微信认证:个人缴纳30元,公司企业貌似是300元,不管认证是否通过都钱都不退回,会收到认证通知,并且接到电话确认信息 - -提交进行审核,要上传操作视频和页面,填好信息提交即可 ,点击“提交发布”,就正式发布了 - -![](images/image42.png) - -# 5.总结 - -到这里,你已经完整跑完了一次**从0到1**的小程序开发闭环: 从认识微信小程序,到装好 Trae、HBuilderX 和微信开发者工具;从把想法丢给 AI,让它在代码里替你“搬砖”,到在模拟器里试玩第一版贪吃蛇;再到把作品打成体验版、走完备案和审核,真正在微信里让人使用——这条链路你已经亲手走通了一遍。 - -更重要的是,你不是靠死记硬背语法做到这一点的,而是靠清楚地表达需求 + 和 AI 有效沟通来实现的 。你已经体验过 **:一句自然语言指令,可以让AI完美满足你的开发要求** 。这种能力不会只停留在贪吃蛇上,它可以迁移到你以后想做的任何小程序——工具、活动页、教学应用,甚至是你工作中的真实项目。 - -如果要给你一个 **通用SOP** ,其实只有五步:** 想清楚一个小需求 → 在 Trae 里搭好项目骨架 → 用 vibecoding 和 AI 搭出第一版 → 在微信开发者工具里不断试玩和改进 → 上传、备案、审核、上线。** 每次你重复这五步,就会多一个真正能被人打开、能被分享的小程序,也会多一份「我可以用 AI 把点子变成产品」的信心。 - -接下来,你可以继续打磨这款贪吃蛇,也可以关掉它,重新起一个空项目,从你自己的想法出发。无论做什么,只要记住一点: 你不再只是一个「想做点东西」的人,而是已经跑通了全流程的 vibecoding 开发者。剩下的,就是多做几次,把这种能力变成习惯。 - -# 参考资料: - -- https://zhuanlan.zhihu.com/p/1889401120939567074 -- https://blog.csdn.net/2401_87407347/article/details/155193007 +> 本章节正在编写中,敬请期待... diff --git a/docs/extra/README.md b/docs/extra/README.md new file mode 100644 index 0000000..f171364 --- /dev/null +++ b/docs/extra/README.md @@ -0,0 +1,10 @@ +# Extra 扩展知识 + +这里包含了额外的扩展知识文档: + +- [Extra 1: Git and GitHub](extra1/extra1-what-is-git-and-what-is-github.md) +- [Extra 2: What is API](extra2/extra2-what-is-api.md) +- [Extra 3: AI Capability Starter Handbook](extra3/extra3-ai-capability-starter-handbook.md) +- [Extra 5: What is RAG](extra5/extra5-what-is-rag-and-how-does-it-work-and-future.md) +- [Extra 6: Zeabur Deployment](extra6/extra6-zeabur-what-is-it-and-how-to-deploy-web-applications.md) +- [Extra 7: CLI AI Coding Tools](extra7/extra7-cli-ai-coding-tools-and-the-principles-of-test-driven-development.md) diff --git a/docs/extra/extra1/extra1-what-is-git-and-what-is-github.md b/docs/extra/extra1/extra1-what-is-git-and-what-is-github.md index e602ceb..6587681 100644 --- a/docs/extra/extra1/extra1-what-is-git-and-what-is-github.md +++ b/docs/extra/extra1/extra1-what-is-git-and-what-is-github.md @@ -44,13 +44,13 @@ Git 是由 Linux 内核开发者 Linus Torvalds 于 2005 年创建的分布式 1. 前往 [Git 官方下载页面](https://git-scm.com/download/win) 并下载适合你系统的安装程序:[安装包](https://github.com/git-for-windows/git/releases/download/v2.51.0.windows.1/Git-2.51.0-64-bit.exe)。默认情况下,推荐使用 x64 安装程序。 2. 双击安装程序并按照安装向导说明进行操作: - ![](images/image5.png) - + ![](images/image5.png) 1. 建议保持默认选项。如果你需要自定义,请注意以下几点:(在大多数情况下,你可以一直点击“Next”) - * 选择 Git 使用的默认编辑器:选择你喜欢的编辑器(如 VS Code)。你可以默认选择第一个选项,即 Vim(一个文本编辑器),或选择“Visual Studio Code as Git's default editor”选项(需要预先安装 VS Code)。你可以保持默认选择并点击“Next”继续。 - ![](images/image6.png) - * 选择如何使用 Git:这三个选项控制 Git 在系统中的可访问性。建议选择选项 2(“from command line and 3rd-party software”)——它将基本的 Git 工具添加到 PATH 中,让你可以在 Git Bash、命令提示符、PowerShell 和 IDE 中使用 Git,而不会使系统混乱。 - ![](images/image7.png) + - 选择 Git 使用的默认编辑器:选择你喜欢的编辑器(如 VS Code)。你可以默认选择第一个选项,即 Vim(一个文本编辑器),或选择“Visual Studio Code as Git's default editor”选项(需要预先安装 VS Code)。你可以保持默认选择并点击“Next”继续。 + ![](images/image6.png) + - 选择如何使用 Git:这三个选项控制 Git 在系统中的可访问性。建议选择选项 2(“from command line and 3rd-party software”)——它将基本的 Git 工具添加到 PATH 中,让你可以在 Git Bash、命令提示符、PowerShell 和 IDE 中使用 Git,而不会使系统混乱。 + ![](images/image7.png) + 3. 安装后,在桌面上右键单击。如果在菜单中看到“Git Bash Here”,则安装成功。 ![](images/image8.png) @@ -70,20 +70,20 @@ Git 是由 Linux 内核开发者 Linus Torvalds 于 2005 年创建的分布式 大多数 Linux 发行版可以通过其包管理器安装 Git: -* Ubuntu/Debian: +- Ubuntu/Debian: ```Bash sudo apt update sudo apt install git ``` -* CentOS/RHEL: +- CentOS/RHEL: ```Bash sudo yum install git ``` -* 验证安装:在终端中输入 git --version。如果显示版本号,则安装成功。 +- 验证安装:在终端中输入 git --version。如果显示版本号,则安装成功。 ## Git 初始化 @@ -118,7 +118,7 @@ GitHub 不仅是世界上最大的代码托管平台,也是全球最活跃、 ## 注册 GitHub 账号 1. 访问 [GitHub 官网](https://github.com/) 并点击右上角的“Sign up”。 - ![](images/image11.png) + ![](images/image11.png) 2. 输入你的电子邮件地址(建议使用常用邮箱,因为验证和通知将发送到那里),设置密码(必须包含字母、数字和特殊字符)。 3. 完成人工验证,按照提示验证邮箱,你的账号就创建好了。 @@ -166,8 +166,8 @@ GitHub 不仅是世界上最大的代码托管平台,也是全球最活跃、 GitHub 支持两种主要的仓库操作协议:HTTPS 协议和 SSH 协议: -* HTTPS 协议:每次操作(如 push)都需要输入 GitHub 账号密码(或个人访问令牌 PAT)。验证过程繁琐,且存在密码泄露风险。 -* SSH 协议:身份验证通过“密钥对”完成,因此不需要重复输入密码,且加密传输更加安全。 +- HTTPS 协议:每次操作(如 push)都需要输入 GitHub 账号密码(或个人访问令牌 PAT)。验证过程繁琐,且存在密码泄露风险。 +- SSH 协议:身份验证通过“密钥对”完成,因此不需要重复输入密码,且加密传输更加安全。 “SSH 协议绑定”是启用 GitHub SSH 认证的前提步骤——只有将本地 SSH 公钥“绑定”到 GitHub 账号后,GitHub 才能识别你的设备并允许对仓库进行 SSH 操作。 @@ -180,9 +180,9 @@ SSH 认证依赖于密钥对(公钥 + 私钥),它们是匹配的加密文 当你通过 SSH 操作 GitHub 仓库时(例如 git push git@github.com:xxx/xxx.git): -* 你的本地设备使用私钥加密“操作请求”并发送给 GitHub; -* 收到请求后,GitHub 尝试使用你之前绑定的公钥进行解密; -* 如果解密成功,你的设备被确认为已授权,操作被允许;否则,访问被拒绝。 +- 你的本地设备使用私钥加密“操作请求”并发送给 GitHub; +- 收到请求后,GitHub 尝试使用你之前绑定的公钥进行解密; +- 如果解密成功,你的设备被确认为已授权,操作被允许;否则,访问被拒绝。 ### “绑定”的具体步骤(核心流程) @@ -192,23 +192,23 @@ SSH 认证依赖于密钥对(公钥 + 私钥),它们是匹配的加密文 1. 使用 Trae 获取公钥(推荐) 提示词:`Help me create the SSH key needed for GitHub login. My email is your_email@gmail.com , Please return the public key for me to copy` - ![](images/image18.png) + ![](images/image18.png) - 输入提示词后,你还需要在左侧终端按 Enter 键,否则命令会一直等待而不执行。由于 Trae 无法帮你执行任何条件判断,我们只需要一直按 Enter 即可。 + 输入提示词后,你还需要在左侧终端按 Enter 键,否则命令会一直等待而不执行。由于 Trae 无法帮你执行任何条件判断,我们只需要一直按 Enter 即可。 - 最后,你会看到右侧的 Trae 返回了它读取的公钥。你只需复制它并准备在下一步中粘贴。 + 最后,你会看到右侧的 Trae 返回了它读取的公钥。你只需复制它并准备在下一步中粘贴。 - ![](images/image19.png) - 2. 手动获取公钥 - 打开你的本地终端(在 Windows 上使用 Git Bash 或 PowerShell;在 macOS/Linux 上使用终端),输入以下命令(将 your_email@example.com 替换为你注册 GitHub 账号时使用的邮箱): + ![](images/image19.png) 2. 手动获取公钥 + 打开你的本地终端(在 Windows 上使用 Git Bash 或 PowerShell;在 macOS/Linux 上使用终端),输入以下命令(将 your_email@example.com 替换为你注册 GitHub 账号时使用的邮箱): - ```Bash - ssh-keygen -t ed25519 -C "your_email@example.com" - ``` + ```Bash + ssh-keygen -t ed25519 -C "your_email@example.com" + ``` + + 1. 按 Enter 接受默认值(默认文件路径,无密码,或根据需要设置密码)。这将在 ~/.ssh/ 目录中生成两个文件: + - id_ed25519:私钥(本地保存,**绝不分享**); + - id_ed25519.pub:公钥(需要上传到 GitHub)。 - 1. 按 Enter 接受默认值(默认文件路径,无密码,或根据需要设置密码)。这将在 ~/.ssh/ 目录中生成两个文件: - * id_ed25519:私钥(本地保存,**绝不分享**); - * id_ed25519.pub:公钥(需要上传到 GitHub)。 2. 将公钥“绑定”到你的 GitHub 账号 这是核心绑定步骤——将本地公钥添加到 GitHub 账号的“SSH keys list”中: @@ -219,7 +219,7 @@ SSH 认证依赖于密钥对(公钥 + 私钥),它们是匹配的加密文 3. macOS/Linux:在终端运行 cat ~/.ssh/id_ed25519.pub 并复制所有输出(从开头的 SSH-ed25519 到结尾的邮箱)。 2. 登录 GitHub 并进入“SSH Key Management”页面: 1. 点击右上角头像 → Settings → 左侧菜单 SSH and GPG keys → 点击 New SSH key。 - ![](images/image20.png)![](images/image21.png) + ![](images/image20.png)![](images/image21.png) 2. 输入任何标题(例如,your local computer's SSH),然后将你刚刚获取的 SSH 公钥粘贴到这里。 ![](images/image22.png) @@ -234,8 +234,8 @@ SSH 认证依赖于密钥对(公钥 + 私钥),它们是匹配的加密文 ssh -T git@github.com ``` -* 如果你看到类似 Hi [your GitHub username]! You've successfully authenticated... 的内容,说明你已成功绑定密钥; -* 如果遇到错误,通常是因为公钥复制不完整、私钥权限过高(你的本地 ~/.ssh/ 目录应仅由你读写)等。根据需要检查这些问题。 +- 如果你看到类似 Hi [your GitHub username]! You've successfully authenticated... 的内容,说明你已成功绑定密钥; +- 如果遇到错误,通常是因为公钥复制不完整、私钥权限过高(你的本地 ~/.ssh/ 目录应仅由你读写)等。根据需要检查这些问题。 ### 重要注意事项 @@ -275,5 +275,5 @@ prompt:`I finished. Commit and push to the repository AIID-TEST in ./AIID-TEST.` # 参考资料 -* Pro Git book https://git-scm.com/book/en/v2 -* GitHub Docs https://docs.github.com/en +- Pro Git book https://git-scm.com/book/en/v2 +- GitHub Docs https://docs.github.com/en diff --git a/docs/extra/extra2/extra2-what-is-api.md b/docs/extra/extra2/extra2-what-is-api.md index 413616e..fc1d437 100644 --- a/docs/extra/extra2/extra2-what-is-api.md +++ b/docs/extra/extra2/extra2-what-is-api.md @@ -6,19 +6,19 @@ 为了解决这些痛点,本篇手册以“API 核心逻辑”为整理思路。在这本手册里,我们想做的不是堆名词,而是帮你快速搞清楚三件事:**“这件事可以用什么 API 做?它的本质逻辑是什么?接下来该怎么安全地调用它?”** 通过从生活类比到代码实践的系统梳理,我们将为你揭开 API 的神秘面纱,帮你建立起从“逻辑认知”到“场景映射”再到“代码实现”的完整链路。 -> 由于 **内容较多** ,你可以在实践过程中遇到场景不知道如何选型的问题再查阅手册寻找参考;推荐你**根据具体应用方向,让 AI 参考该手册,给出可参考的模型选型建议、方案 API 调用建议即可。** -> -> 如果你只想了解对应的类别,不想看具体内容,只需要看每个大章节的初始段内容即可,例如 1 、2 的内容,但不需要看 5.1 或者 5.2 的代码细节。 -> -> **推荐本手册只在需要时查阅对应部分或只浏览一级目录部分,若有兴趣再浏览全文。** -> -> **之后更新会在每个章节部分,推荐可尝试使用的模型 API 服务地址。** +> 由于 **内容较多** ,你可以在实践过程中遇到场景不知道如何选型的问题再查阅手册寻找参考;推荐你**根据具体应用方向,让 AI 参考该手册,给出可参考的模型选型建议、方案 API 调用建议即可。** +> +> 如果你只想了解对应的类别,不想看具体内容,只需要看每个大章节的初始段内容即可,例如 1 、2 的内容,但不需要看 5.1 或者 5.2 的代码细节。 +> +> **推荐本手册只在需要时查阅对应部分或只浏览一级目录部分,若有兴趣再浏览全文。** +> +> **之后更新会在每个章节部分,推荐可尝试使用的模型 API 服务地址。** # 本节课你将学到 -* **核心概念映射**:通过“电源插座”与“餐厅点餐”等经典类比,建立对 API 请求与响应循环的直观理解。 -* **现实场景解析**:了解天气、地图、社交登录及大语言模型等主流 API 的工作原理,掌握从“功能”到“接口”的映射方法。 -* **代码实践与安全**:掌握 Python 环境下 AI API 的调用方式,并理解前端开发中后端代理等安全工程实践的重要性。 +- **核心概念映射**:通过“电源插座”与“餐厅点餐”等经典类比,建立对 API 请求与响应循环的直观理解。 +- **现实场景解析**:了解天气、地图、社交登录及大语言模型等主流 API 的工作原理,掌握从“功能”到“接口”的映射方法。 +- **代码实践与安全**:掌握 Python 环境下 AI API 的调用方式,并理解前端开发中后端代理等安全工程实践的重要性。 完成本手册的学习后,你将对主流 API 能力建立起入门级的系统化认知,不仅知道“市面上有哪些接口、常配哪些产品”,更能理解它们在整体架构中的位置和相互关系。知道在面对具体业务需求时,如何快速定位所需能力、做出有依据的选型,为构建 AI 应用体系打下坚实基础。 @@ -51,28 +51,28 @@ API 无处不在,在后台默默工作。 **天气预报 API** 它就像一个专门提供气象信息的窗口。你的天气应用向它发送坐标和密钥,它就回传一串 JSON 数据。 -* **一个简单的“请求”示例:** - * **Endpoint:** `/current-weather` - * **Parameters:** `city=London` & `apiKey=your_access_key` -* **“响应”(回传的数据):** - ```json +- **一个简单的“请求”示例:** + - **Endpoint:** `/current-weather` + - **Parameters:** `city=London` & `apiKey=your_access_key` +- **“响应”(回传的数据):** + `json { "city": "London", "temperature": "15°C", "condition": "Cloudy", "humidity": "70%" } - ``` -应用拿到这些数据后,再把它们漂亮地展示在你的手机屏幕上。 + ` + 应用拿到这些数据后,再把它们漂亮地展示在你的手机屏幕上。 **地图服务 API** 不管是外卖平台还是打车软件,它们本身并不生产地图。它们通过调用高德或 Google Maps 的 API,就能获得精准的路线规划和导航功能。 -* **一个简单的“请求”示例:** - * **Endpoint:** `/directions` - * **Parameters:** `origin=Eiffel Tower` & `destination=Louvre Museum` & `mode=driving` -* **“响应”(回传的数据):** - ```json +- **一个简单的“请求”示例:** + - **Endpoint:** `/directions` + - **Parameters:** `origin=Eiffel Tower` & `destination=Louvre Museum` & `mode=driving` +- **“响应”(回传的数据):** + `json { "total_distance": "4.5 kilometers", "estimated_time": "15 minutes", @@ -82,8 +82,8 @@ API 无处不在,在后台默默工作。 "..." ] } - ``` -通过这些数据,应用就能在地图上绘制路线并提供导航指令。 + ` + 通过这些数据,应用就能在地图上绘制路线并提供导航指令。 **社交媒体登录 API** 当你点击“使用 Google 登录"时,购物应用会问 Google API:“这个用户是谁?”Google 验证后告诉应用:“他是 John Doe”。这样,你不用输入密码就能安全登录。 @@ -96,6 +96,7 @@ API 无处不在,在后台默默工作。 当你真正开始动手写代码时,会遇到一些技术名词。别担心,你不需要现在就记住所有细节,只需要看看它们在代码里是怎么“呼吸”的。 ### 5.1 Python 中的 AI 调用 + 在 Python 中调用 OpenAI 的 API 非常直观。你可以通过设置 `base_url` 来指定服务器地址。 ```python @@ -119,37 +120,39 @@ print(response.choices[0].message["content"]) 许多模型(如 DeepSeek)都兼容 OpenAI 的格式。你只需要更换 API 密钥和地址,就能无缝切换。 ### 5.2 前端开发中的安全实践 + 如果你在做网页,切记不要在浏览器代码里直接写 API 密钥,否则会被人偷走。通常的做法是写一个**后端代理**,让服务器去替你完成调用。 ```javascript // 后端 Node.js 示例 -const express = require("express"); -const axios = require("axios"); -const app = express(); -app.use(express.json()); +const express = require('express') +const axios = require('axios') +const app = express() +app.use(express.json()) -app.post("/api/chat", async (req, res) => { +app.post('/api/chat', async (req, res) => { try { const response = await axios.post( - "https://api.openai.com/v1/chat/completions", + 'https://api.openai.com/v1/chat/completions', { - model: "gpt-3.5-turbo", - messages: [{ role: "user", content: req.body.message }] + model: 'gpt-3.5-turbo', + messages: [{ role: 'user', content: req.body.message }] }, { - headers: { "Authorization": `Bearer ${process.env.OPENAI_API_KEY}` } + headers: { Authorization: `Bearer ${process.env.OPENAI_API_KEY}` } } - ); - res.json({ reply: response.data.choices[0].message.content }); + ) + res.json({ reply: response.data.choices[0].message.content }) } catch (error) { - res.status(500).json({ error: error.message }); + res.status(500).json({ error: error.message }) } -}); +}) -app.listen(3001, () => console.log("服务器运行在 3001 端口")); +app.listen(3001, () => console.log('服务器运行在 3001 端口')) ``` 你可以使用 `curl` 命令来测试这个接口: + ```bash curl -X POST http://localhost:3001/api/chat \ -H "Content-Type: application/json" \ @@ -161,5 +164,7 @@ curl -X POST http://localhost:3001/api/chat \ API 是现代数字世界的基石。通过理解“请求与响应”这个简单的逻辑,你已经迈出了通往软件开发广阔世界的第一步。在接下来的 Z.ai 探索中,我们将亲手尝试这些调用,感受 AI API 的魅力。 --- + **参考资料** -* [Postman: What is an API?](https://www.postman.com/what-is-an-api/) + +- [Postman: What is an API?](https://www.postman.com/what-is-an-api/) diff --git a/docs/extra/extra3/extra3-ai-capability-starter-handbook.md b/docs/extra/extra3/extra3-ai-capability-starter-handbook.md index 8fa1ba5..95ab095 100644 --- a/docs/extra/extra3/extra3-ai-capability-starter-handbook.md +++ b/docs/extra/extra3/extra3-ai-capability-starter-handbook.md @@ -1,3267 +1,3 @@ -# AI 词典:主流模型、产品形态与应用场景一览 +# AI 能力入门手册 -随着生成式 AI 技术在各类产品和业务场景中的广泛落地,一个越来越现实的问题摆在每个我们面前: **到底有哪些 AI 能力可以用?** 在具体的需求里,又 **该选择哪一种能力、哪一类模型或哪一个产品来承载?** - -面对这种困惑,最直观的做法或许是 “临时抱佛脚”:**遇到需求再搜索市面上云服务厂商的产品 API,或者是对应模型,搜索市面上的商业级解决方案对照文档与 Demo进行处理** 。看到图片需求就想到图像生成,碰到文本任务就找来大模型,涉及语音交互就想起 ASR 和 TTS,再在海量 API 与服务中货比三家。然而,把零散的产品堆在一起,与在企业级场景中系统性地规划、选型和组合 AI 能力,是两件截然不同的事情。仅靠临时查资料与经验判断,会带来能力认知碎片化、方案设计随意、能力复用困难等一系列严峻挑战。 - -为了解决这些痛点,本文以“AI 能力全景图”为核心的整理思路应运而生。在这本手册里,我们想做的不是堆名词,而是帮你快速搞清楚三件事:**"这件事可以用什么 AI 能力做?大概该选哪一类模型或产品?接下来用哪些关键词去找 API、项目或服务来试?"** 通过从模态(文字、图像、音频、视频、3D、多模态)到架构层(模型、检索、Agent、平台工程)的系统梳理, **我们可以为每一类典型需求和场景找到对应的 AI 能力、代表性模型/产品,以及在真实业务中的常见用途** ,帮助团队以更低试错成本、更高决策效率和更强可复用性来建设 AI 体系。 - -在本篇手册中,我们将系统介绍当下主流的 AI 能力版图,从单一模态到多模态融合、从单点模型到平台与工程的整体框架,结合常见产品形态与应用场景,给出面向实践的能力选型参考。 - -> 由于 **内容较多** ,你可以在实践过程中遇到场景不知道如何选型的问题再查阅手册寻找参考;推荐你**根据具体应用方向,让 AI 参考该手册,给出可参考的模型选型建议、方案 API 调用建议即可。** - -如果你只想了解对应的类别,不想看具体内容,只需要看每个大章节的初始段内容即可,例如 1.1 、1.2 的内容,但不需要看 1.1.1 或者 1.1.2 的内容。 - -**推荐本手册只在需要时查阅对应部分或只浏览一级目录部分,若有兴趣再浏览全文。** - -**之后更新会在每个章节部分,推荐可尝试使用的模型 API 服务地址。** - -# 本节课你将学到 - -* AI 能力全景:从文本、图像、音频、视频、3D 到多模态、Agent、RAG、安全与平台工程的整体能力划分思路 -* 各能力对应的模型与产品:了解 Embedding、OCR、ASR、TTS、VLM、RAG 等关键能力背后的代表性模型与服务 -* 能力到场景的映射方法:掌握如何将“能力清单”转化为产品内容、搜索问答、智能客服、自动化运营等具体应用 - -完成本手册的学习后,你将对主流 AI 能力建立起入门级的系统化认知,不仅知道“市面上有哪些能力、常配哪些产品”,更能理解它们在整体架构中的位置和相互关系。知道在面对具体业务需求时,如何快速定位所需能力、做出有依据的选型,为构建 AI 能力体系打下坚实基础。 - -## 手册中涉及的模型参数 - -在进入具体能力地图之前,先澄清一个经常被提到、但又有点抽象的概念:到底什么算大模型?什么算小模型? - - **从学术上看** ,大模型通常指参数量在几十亿、上百亿乃至万亿级别的通用模型,小模型则是针对特定任务或场景、参数量更小(几千万到几亿级)的专用模型。 - - **从价格上看** ,如果一个模型的 API 调用非常便宜,比如按调用计费几厘钱、几分钱,或者只按每千 tokens 几厘到几分,而且没有特别强调通用大模型,那通常要么是典型的小模型(例如专门做 OCR、ASR、图片分类、内容审核的模型),要么是参数量较小的轻量版大模型(专门为了高并发、低成本做了压缩或蒸馏)。 如果单次调用价格明显偏高,比如一次调用就要几角甚至 1 元起步,那么大概率是大模型。 - -此外,如果产品文案里面会明确强调使用了大语言模型 LLM、通用大模型、多模态大模型,或提到端到端地完成从输入到输出的复杂任务(比如端到端对话机器人、端到端检索问答、端到端视频生成),那通常就可以把它视作是大模型。 - -相反,如果宣传重点在于某一个垂直能力,比如银行卡识别、发票识别、车牌识别、广告点击率预测、语音转写、内容安全审核,说明这个产品底层更可能是一个或一组小模型。 - -因此,在本文接下来的叙述中可以做个务实的约定: - -* 大模型更多指那类通用、可对话、可编程、往往价格略高的模型(包括它们的多模态版本,比如 GPT-4o、Gemini 1.5 Pro、Claude 3.5 Sonnet 等),它们能覆盖大部分通用文本、代码以及图像、音频、视频等多模态任务; -* 小模型则指那些为某个特定任务精调或定制的模型,通常价格更便宜、性能更稳定可控,但适用范围更窄,需要你在系统里主动组合与编排。 - -这里不妨补充一个关键的行业变化:手册中提到的很多模型能力,在 2021 年之前其实都是由 “小模型” 来承接的。针对特定场景、特定数据训练专属模型,以此满足精准需求。而**如今,绝大多数通用场景和任务已经可以直接调用大模型来解决** 。 - -从**精度与成本**的极致追求来看,小模型的训练与应用依然有其不可替代的价值;但**对于入门者而言,我们完全可以从学会找到并调用大模型 API 开始** ,再逐步深入高阶玩法。你只需要在成本、精度和延迟之间做权衡,再决定哪里要用通用大模型,哪里继续保留或引入专用小模型。 - -> **从一些常见产品认识**常用的文本和多模态通用大模型: -> -> * OpenAI 系列:GPT-4、GPT-4.1、GPT-4o、GPT-5.1 等 -> * Google 系列:Gemini 1.5 Pro、Gemini 1.5 Flash 等 -> * Anthropic 系列:Claude 3.5 Sonnet、Claude 3.5 Haiku 等 -> * 国内模型:通义千问 Qwen 系列、文心一言 ERNIE Bot 系列、GLM/智谱清言、百度的文心大模型家族、腾讯混元、讯飞星火、月之暗面的 Kimi 背后的大模型等 -> -> 更偏视觉和视频方向的大模型和服务,包括: -> -> * 图像生成:DALL·E、Midjourney、Stable Diffusion、SDXL、Flux 等 -> * 多模态视觉理解:GPT-4o、GPT-4.1 with Vision、Gemini 1.5(图文多模态)、Claude 3.5 Sonnet Vision、LLaVA 等 -> * 视频生成:Sora、Kling、Runway Gen-2、Pika、Luma、Veo 等 -> -> 语音和音频方向的大模型,包括: -> -> * 语音识别 ASR:Whisper 系列(Whisper、Whisper-large-v3 等)、Deepgram、各家云厂商的端到端 ASR 大模型(如讯飞、百度、火山、阿里等) -> * 语音多模态与语音对话:GPT-4o(端到端语音对话)、OpenAI Realtime、Gemini 1.5 的音频理解能力等 -> * TTS / 音频与音乐生成:OpenAI TTS、ElevenLabs、Suno、Udio、MusicGen 等 -> -> 3D / 空间方向的生成与理解模型,包括: -> -> * 文生 3D 和图生 3D:DreamFusion、Shap-E、GET3D、Zero-1-to-3、TripoSR 等 -> * NeRF / 神经渲染家族:Instant-NGP、NeRF 系列、Gaussian Splatting 相关模型等 - -# 1. 文本任务 (Text / NLP / LLM) - -在 AI 能力中,文字任务是最基础的功能。无论我们最终想做的是内容审核、搜索推荐、知识问答,还是写作助手、代码 Copilot,本质上都绕不开一个问题:机器如何真正看懂文字。 - -## 1.1 基础语言建模与表示 - -让我们从最底层的基础语言建模与表示讲起。它的作用是让机器先在统计意义上熟悉语言,并在此基础上为词、句子、文档找到一个稳定的向量矩阵表示,以便于后面的分类、匹配、抽取、生成等任务。不管未来要做什么文本相关任务,都或多或少需要先回答同一个问题:我怎么用一串数字,把这一段话表示出来? - -我们可以简单从场景、原理、模型三个角度来看这个问题的相关内容: - -* **场景** - * **检索搜索相关** - * 通用搜索引擎:用户随便输入一句话,得到含义相关的文档,而不是只做关键词精确匹配。 - * 站内搜索 / 电商搜索:用户用口语化的描述(比如“适合夏天通勤的白衬衫”),找到含义对应的商品。 - * 文档库 / 知识库检索:在技术文档、政策法规、企业知识库里,直接输入一句话获得相关条目。 - * **推荐排序相关** - * 信息流 / 内容推荐:根据用户最近看过、点过的内容,自动找出内容相近的其他内容继续推荐,而不是只靠人工规则或标签。 - * 电商 / 商品推荐:根据用户看过、买过、收藏过的商品描述,找到风格或用途相近的商品,做个性化推荐。 - * 用户兴趣建模:根据用户看过的标题、搜索过的词等,总结出几个主要兴趣方向,用来提升推荐和排序效果。 - * **问答助手相关** - * FAQ 问答:用户用不同说法问同一个问题(“怎么开发票?” vs “发票在哪里开?”),系统能跳到同一个答案。 - * 知识库问答 / 企业助手:用户用自然语言提问,系统到内部文档里按含义去匹配,找出最相关的段落回答。 - * **文本理解分析相关** - * 评论舆情分析:把大量评论、帖子按“在说什么 / 情绪怎样”大致分成几类。 - * 文本去重 / 相似检测:用于发现改写稿、伪原创文章。 - * 文档聚类 / 分组:把很多文章、报告按照内容相近分成几组,方便做导航、推荐或抽样检查。 - * **作为下游任务通用特征 (下游任务指的是用模型的基础能力,去实现更具体的文字处理任务)** - * 文本分类:情感分类、意图识别、垃圾内容识别等下游模型直接复用这一层的表示。 - * 信息抽取:实体识别、关系抽取在词 / 句子表示的基础上进行微调,而不是从头训练。 - * 文本生成:为摘要、改写、续写等生成任务提供语义表征输入,提升生成质量与可控性。 -* **原理** - 学习词、句子、文档的表示,为后续更复杂的任务作为基底。 - * 语言建模 - * 自回归语言模型:预测下一个 token(GPT 系列、LLaMA、Qwen 等) - * 掩码语言模型 (Masked LM):预测被遮盖 token(BERT、RoBERTa、ERNIE) - * 词 / 句子 / 段落表示 - * 静态词向量:Word2Vec、GloVe、FastText - * 上下文表征:BERT embedding、Sentence‑BERT 等 - * 文档级向量:用于语义检索、相似度匹配 -* **模型** - BERT / RoBERTa / ERNIE、GPT 家族、LLaMA / Qwen / Yi 等 LLM;各类 Embedding 模型(OpenAI text‑embedding‑3 系列、bge、E5、SimCSE 等)。 - -### **1.1.1 语言建模:通过“猜下一个词”学会语言** - -这一层的第一步,是先让模型在大量文本里 **熟悉语言规律** 。做法可以简单理解为:给模型出无数道“猜词题”,在看到一段话的上下文后,让它填上最合理的词(token)。练习题足够多、语料足够广,模型就会逐渐学会:一句自然的句子长什么样,哪些词经常一起出现,什么表达读起来别扭。这个过程叫“语言建模”,本质就是一套统一的 **猜词训练机制** 。 - -常见有两种出题方式,每种用一句话举个简单例子: - -1. **往后接(自回归)** :只给前面的内容,让模型猜“后面会怎么说”。 -2. 输入前缀:`今天下雨了,所以我` -3. 模型任务:猜下一个词,比如“ **带** (伞)”“ **没** (出去)”“ **打算** (在家)”等,然后再继续往后接。 - 这种方式主要锻炼模型对**续写、连贯性、常见表达**的把握。 -4. **挖空填词(掩码)** :把中间挖个洞,让模型利用前后文一起填空。 -5. 原句:`今天下雨了,所以我带了雨伞` -6. 训练句:`今天 [MASK] 了,所以我带了雨伞` -7. 模型任务:把 `[MASK]` 补成“ **下雨** ”这类合理的词。 - 这里模型必须同时看左边的“今天”“了”和右边的“所以我带了雨伞”,才能决定该填什么,更有利于学习 **整句语义** 。 - -通过在海量语料上反复做这两类“猜词题”,模型会逐渐积累起对语言的 **语感和统计常识** 。在此基础上,下一步我们再把这种能力显式地变成 **词、句子和文档的向量表示** ,为后续的检索、推荐和问答等任务打底。 - -### 1.1.2 词、句子与文档表示:把离散符号映射到语义空间 - -构建文本向量最早一代的方法是**静态词向量** :为每个词分配一份固定向量,训练好后不随上下文变化,直观、简单,但 **无法区分多义词在不同语境下的含义。** 为了解决这个问题,后来出现了基于上下文的动态表示方法:同一个词在不同句子中会生成不同的向量,完全由它所在的上下文决定。比如“苹果”在“苹果发布了新手机”中会更靠近“科技公司”的语义方向,而在“苹果富含维生素”中则更接近“水果”概念。 - -这种机制不仅提升了词层面的表达能力,也为句子和文档的向量化铺平了道路。对于句子,可以生成句向量;对于文档,可以整篇输入编码(如果长度允许),或分段编码后再通过注意力机制、层次化池化、对比学习等方式聚合出一个全局向量。近年来的专用 embedding 模型(如 bge、E5、text-embedding 系列)正是围绕“让语义相近的文本在向量空间中更近”这一目标持续优化,尤其在语义检索、相似匹配等任务上表现突出。 - -这套从上下文建模到句/文档向量生成的流程,已经成为搜索、推荐、问答等系统背后的核心基础设施,让我们回到前面提到的各类场景: - -* 检索搜索场景(通用搜索、电商搜索、知识库检索)都需要把用户输入和候选文档都编码成向量,然后在向量空间里做相似度匹配,找出语义最接近的结果,而不是只靠关键词精确匹配。 -* 推荐排序场景(信息流推荐、商品推荐、用户兴趣建模)需要把用户历史行为对应的内容转成向量,然后找到向量相近的新内容推荐给用户,实现"看过 A 推荐 B"的个性化效果。 -* 问答助手场景(FAQ 问答、知识库问答)需要把用户的提问和知识库里的问题或段落都编码成向量,通过向量相似度找到最匹配的答案。 -* 文本理解分析场景(评论舆情、去重、聚类)需要先把每条文本转成向量,再基于向量做聚类、相似度计算或分类。 -* 下游任务场景(文本分类、信息抽取、文本生成)则是直接把这一层的向量表示作为输入特征,喂给后续的分类器、抽取器或生成器,避免从头学习语义。 - -工程上,常见做法是封装成统一的"文本向量服务":输入任意一段文本,输出一串固定维度的向量,供搜索、推荐、问答等多个系统共享使用。在产品层面,这一层的能力主要体现在:搜索和推荐中的语义召回(不再只依赖关键词,而是通过向量相似度召回"说法不同但意思相近"的内容),以及面向企业知识库、FAQ、案例库的统一 embedding / 向量检索服务。 - -## 1.2 文本分类与文本匹配(Classification & Matching) - -在上一节中,我们通过基础语言建模与表示,为每一段文本找到了在语义空间中的“坐标”。但仅有坐标还不够,业务真正关心的问题往往是:这段文本属于哪一类?和另一段文本是不是讲同一件事?两句话之间在逻辑上是相互支持还是互相矛盾?你可以把它理解为:用分类和匹配这两个能力,把底层的向量表示转化为可以直接驱动业务决策的标签与相关性信号。我们仍然从场景、原理和模型三个角度来梳理这一层: - -* **场景** - * 内容理解与审核:给评论、帖子、文章打上主题、情感、风险等标签,用于审核、推荐、统计分析。 - * 推荐与排序:根据“用户兴趣标签”和“内容标签”的匹配程度,决定展示哪些内容、排在多前。 - * 搜索与 FAQ:用户随便输入一句自然语言问题,系统能够自动找到最相关的问题‑答案对或文档片段。 - * 相似内容识别:在大量文本中找到“内容相近”的条目,用于去重、合并统计、推荐“相关内容”。 - * 逻辑关系判断:判断两句话之间是互相支持、互相矛盾,还是无关,用于事实核查、多轮对话一致性检查等。 -* **原理** - 在语义表示的基础上,对整段文本或文本对进行整体判断: - * 文本分类:给单条文本打标签(如情感、主题、风险类型等); - * 文本匹配:判断两段文本之间的相似度、相关性,或“问题–答案”是否匹配; -* **模型** - 以预训练 encoder 为基础,接上简单的分类 / 匹配结构: - * 单文本分类:BERT / RoBERTa / DeBERTa + 全连接分类层; - * 文本匹配:Sentence‑BERT、SimCSE、双塔(Bi‑Encoder)、交叉编码器(Cross‑Encoder); - * 复杂判断:在 LLM 上通过指令微调,让模型直接输出标签或逻辑关系。 - -### 1.2.1 文本分类:从“懂内容”到“给内容定性” - -借助上一层的语义表示,我们可以非常自然地在其上方接一个简单的分类头,通过少量标注数据,让模型学会回答一个问题: **“这段文本属于哪一类?”** 。 - -最经典的是 **情感分类** 。用户的一句评价,可能是认可、抱怨,也可能只是陈述事实。模型在拿到这句话的向量表示之后,只需要再接一个 softmax 分类层,就能输出“正向 / 负向 / 中立”的概率。这类能力在电商、社交平台、应用市场等场景中,都已经非常成熟。 - -另一大类是 **主题 / 行业分类** 。新闻推荐里,我们希望知道一篇文章是体育、财经还是娱乐;企业内部的客服 / 工单系统,则更关心这是产品咨询、功能异常还是投诉建议。这些标签既可以帮助内容被更精准地路由到合适的流程中,也可以作为推荐排序阶段的重要特征。 - -更进一步,**风险 / 合规分类**则直接与平台安全相关。我们会针对广告导流、谩骂攻击、涉政敏感、低俗色情等类别设置专门的分类模型,配合人工审核,对高风险内容进行拦截或降权。可以说,绝大部分内容安全策略的第一道闸门,都是由这类分类器构成的。 - -可以看到,到这一层为止,我们已经能够把“抽象的语义表示”转化为若干业务可用的标签。接下来,我们要讨论的是:当文本之间产生关系时,我们又如何进行 **匹配与推断** 。 - -### 1.2.2 文本匹配:为一句话“找到最合适的另一句” - -与分类对“单个文本定性”不同,**文本匹配**关注的是“两段文本之间的相关性”。在很多产品里,这往往是实现“智能”的关键一环:用户说了一句话,系统能不能找到知识库里最合适的一条进行回应,完全取决于匹配质量。 - -最基础的是 **语义相似度计算** 。我们会先用上一层的 embedding 模型,把两个句子编码成向量,再通过余弦相似度、点积等方式,判断它们在语义空间里的距离。像 SimCSE、Sentence‑BERT 这类模型,就是通过对比学习的方式,专门把“相似的句子对”拉近,把“不相似的句子对”推远。 - -在此之上,**复述检测**和**抄袭检测**只是特定应用场景的匹配任务。前者用于内容去重,避免平台充斥着重复表达;后者则在教育、知识社区等场景中,用来识别高度相似的回答或文章。技术上,它们本质都是根据文本相似度来做二分类或排序。 - -一个非常重要的下游应用是 **问答匹配** 。当用户提出一个自然语言问题时,我们不会直接用关键词去匹配 FAQ,而是通过语义向量先做召回,再用更精细的匹配模型(如交叉编码器 Cross‑Encoder)对若干候选进行重排序,选出最可能对应的那一条。这一链路构成了 FAQ 机器人和文档问答系统的基础。 - -在这一层,我们已经具备了对“整段文本”进行分类和关系判断的能力。但在很多场景里,业务并不满足于此,而是进一步希望知道: **这段文本中具体提到了哪些实体、发生了什么事件** 。这就自然引出了下一节的主题—— **序列标注与信息抽取** 。 - -## 1.3 序列标注与信息抽取(Sequence Labeling & Information Extraction) - -在完成了对文本整体的分类和匹配之后,我们往往会遇到一个更细致的诉求:不仅要知道“这篇文章是关于什么的、风险高不高”,还要进一步知道“它具体提到了谁、在哪儿、什么时候、金额是多少”。这一节,就是在整体判断之上向“细粒度结构化”迈出的关键一步。你可以把它理解为:在已经知道“应该看哪一类文本、它大概讲什么”的前提下,从文本内部挖掘实体、关系、事件和各类字段,让非结构化文本可以直接被业务系统消费。我们同样从目标、原理、模型和产品四个方面来看这一层: - -* **场景** - * 行业文本结构化:从合同、报告、公告、病历、政策等文档中,抽取出人名、机构、金额、时间、条款等关键字段,用于入库和检索。 - * 知识图谱与关系网:从新闻、论文、问答中识别实体及其关系,构建“谁和谁有什么关系”的图谱,用于搜索、推荐和分析。 - * 票据与单据处理:对发票、对账单、报销单等,自动提取抬头、税号、金额、日期等字段,减少人工录入。 - * 舆情与事件分析:从海量文本中抽取“谁在什么时候在哪儿做了什么”,用于事件跟踪、风险预警与统计报表。 - * 日志与工单结构化:把客服对话、工单、系统日志等非结构化文本里的关键信息抽出来,方便统计、监控和自动化处理。 -* **原理** - 在 token / 短语层面,对文本进行细粒度标注与结构化: - * 序列标注:对每个 token 贴标签(如人名、地名、机构名、产品名等),实现命名实体识别、词性标注、短语切分等; - * 关系与事件抽取:在实体之上识别“实体‑实体”之间的关系,以及“谁在何时何地做了什么”的事件结构; - * 业务字段抽取:围绕具体业务 schema(如合同字段、票据字段),将长文档转成标准化的 key‑value 或记录表。 -* **模型** - 在预训练表示的基础上,通过序列标注或 span 抽取等结构完成信息提取: - * 序列标注模型:BiLSTM‑CRF、BERT + CRF / Softmax 等; - * Span‑based 抽取:直接预测实体 / 关系片段的起止位置; - * 文档级抽取:结合版式、布局的 DocIE 类模型; - * 基于 LLM 的抽取:通过 Prompt / Few‑shot,让大模型按指定格式抽取所需字段。 - -### 1.3.1 序列标注:给每个 token 和短语贴上语义“标签” - -在文本分类阶段,我们只关心整段文本属于哪一类;而在序列标注阶段,我们要对文本中的每一个 token、每一段短语进行标记。最典型的任务是命名实体识别(NER):识别人名、机构名、地名、产品名、疾病名等特定类型的实体。 - -* 例如,在句子“张三在北京加入某科技公司”中,把“张三”标为人名、“北京”标为地名、“某科技公司”标为机构。 - -从建模方式上看,传统的做法是使用 BiLSTM + CRF 这类序列标注结构,后续则更多采用 BERT + CRF 或 BERT + Softmax,利用预训练 encoder 的上下文表征能力,来判断每个 token 的标签(如 B‑ORG、I‑ORG、O 等)。在实践中,NER 模型往往是后续知识图谱、关系抽取的第一道“预处理”。 - -除了 NER 外,词性标注、短语切分也属于典型的序列标注任务。它们更多服务于底层语言分析,为后续更复杂的语法 / 语义任务提供基础结构。 - -* 比如对“快速 提升 模型 性能”标出“快速”为副词,“提升”为动词,“性能”为名词,用于下游分析。 - -### 1.3.2 关系与事件抽取:把“点”连成“线”和“故事” - -当我们通过序列标注识别出文本中的实体之后,一个顺理成章的问题是:这些实体之间到底是什么关系,它们共同构成了什么样的事件? - -关系抽取关注的是“实体对 + 关系类型”。例如,在一句“张三于 2024 年加入某科技公司担任 CTO”中,我们不仅要识别“张三”和“某科技公司”这两个实体,还要抽取它们之间的“就职于”关系。 - -* 简单来说,就是从“张三 – 某科技公司”这对实体上,贴上“任职”这类关系标签。 - -在关系之上,事件抽取则试图重建“谁在什么时候、什么地点,做了什么事情”。以一则新闻为例,一个标准的事件模板可能包含:事件类型(收购、合作、事故)、时间、地点、参与方、金额、后果等多个槽位。事件抽取模型需要从冗长的文本中自动填充这些槽位,从而构建出可被检索、统计和推理的“事件表”。 - -* 比如从“某公司以 5 亿元收购另一家公司”中抽出:事件类型=收购,金额=5 亿元,参与方=两家公司。 - -在建模方法上,除了传统的序列标注式抽取,我们还会采用 Span‑based IE(直接预测实体 / 关系 span 的起止位置)以及近年来兴起的 Prompt‑based IE 和基于 LLM 的 Few‑shot 抽取。后者的优势在于可以通过自然语言提示,快速适配新的 schema,减少大量重新标注和训练的成本。 - -从工程角度看,成熟的抽取系统往往会形成一条管线: - -* 上游 NER / 序列标注识别实体; -* 中间层做关系和事件结构建模; -* 下游把结果写入数据库或知识图谱,供搜索、分析和风控系统消费。 - -## 1.4 文本生成与编辑(Text Generation & Editing) - -在前面几节中,我们已经依次构建了“表示 → 分类匹配 → 序列标注与抽取”这条理解链路:模型不仅能把文本映射到语义空间,还能对整段文本做判断,并从中抽取出结构化信息。这一节要做的,是把这条理解链路“反向”再走一遍:在充分理解的基础上,让模型主动去生产、改写、压缩和润色文本。你可以把它理解为:在语义空间中进行“反向编码”,把内部表示重新变成高质量的自然语言输出,是整条文字模态能力链里最贴近用户感知的一层。我们依旧从目标、原理、模型和产品四个维度来拆解: - -* **场景** - * 日常写作与办公:生成邮件、通知、方案初稿,或对现有文本进行扩写、改写和润色。 - * 知识管理与总结:对长文档、报告、会议记录进行自动摘要,帮助快速抓住重点。 - * 客服与问答:根据用户问题和检索到的资料,自动生成结构清晰、口吻统一的回答。 - * 营销与创意内容:生成广告文案、社交媒体帖子、活动介绍、脚本等。 - * 多语言场景:在保持原意的基础上,完成翻译、本地化改写,适配不同语言和场景。 -* **原理** - 在语言建模的基础上,对文本进行“从无到有”和“基于已有内容的修改”: - * 自由生成:根据意图、提示词或大纲,从头生成一段完整的文本; - * 受控改写:在保持核心信息不变的前提下,调整风格、长度、结构(如摘要、扩写、风格转换); - * 纠错与润色:修正错别字、语法问题,优化表达顺序和逻辑结构。 -* **模型** - 以大规模预训练 + 指令微调的生成模型为主: - * 指令微调 LLM:GPT 系列、LLaMA / Qwen / GLM 等,用于通用生成与编辑; - * Seq2Seq 模型:T5、BART、mT5 等,用于摘要、翻译、格式转换等任务; - * 对齐与安全:通过 RLHF / RLAIF 等手段,让生成内容更加符合指令和安全要求。 - -由于这个部分基本等于提示词工程,故不再过多阐述,可以自行查看提示词工程部分的教程。 - -# 2. 图像模态(Image / Vision) - -在 AI 能力中,图像模态负责“用视觉理解世界”。不管最终想做的是安防监控、自动驾驶、短视频特效、电商智能修图,还是多模态问答、AI 画画,本质上都离不开一条路径:从原始像素出发,逐步获得对画面的结构化理解与可控生成能力。 - -## 2.1 底层视觉(Low‑Level Vision) - -在上一节中,我们从整体上介绍了视觉模态在多模态系统中的角色,以及它与语言、语音之间的衔接方式。但在真正进入目标检测、图像理解、视觉问答这些“高层语义任务”之前,还有一个往往被忽略、却至关重要的基础能力层——底层视觉。你可以把它理解为:在“看懂图里是什么”之前,系统需要先解决“这张图本身质量如何”“有哪些稳定的局部结构可以被上层复用”这两个问题,用一层通用的复原、增强和结构抽取,将原始像素转化为更干净、更稳定的图像表示。 - -从工程角度看,底层视觉既直接影响用户肉眼看到的“画质体验”,也决定了上层检测、识别、分割等任务的输入分布是否健康。如果这一层做得不好,后面所有模型都要在“噪声大、畸变重、光照极端”的环境下硬扛;相反,如果在这一层就把图像尽可能修好、结构信息提炼好,高层任务就可以在一个更友好的基座上发挥能力。下面我们同样从场景、原理和模型三个角度来梳理这一层: - -* **场景** - * 相机与拍摄设备:手机/相机的自动去噪、HDR、夜景模式、防抖,多帧融合提升细节和动态范围。 - * 内容平台与短视频:上传图片/视频的一键画质增强,去压缩块、提高清晰度和对比度,提升主观观感。 - * 老照片与文档修复:老照片的去噪、上色、超分辨率;拍歪、拍暗的票据、合同、书页自动拉正、增强,方便 OCR。 - * 监控与安防:低照度监控画面的降噪、去雾、防雨滴、提升分辨率,为后续人脸/车牌识别打基础。 - * AR/VR 与三维重建:为 SLAM、全景拼接、三维重建提供稳定的角点、边缘和局部描述子,保证跟踪与配准鲁棒性。 -* **原理** - 围绕“图像质量”和“局部结构”两个核心目标,对像素级信息进行物理与统计建模: - * 图像复原与增强:假设观测图像是理想图像经过噪声、模糊核、压缩和成像非线性等退化后得到,在这一假设下进行去噪、去模糊、去压缩伪影、低光照增强和超分辨率重建,使输出更接近真实场景成像,同时符合人眼感知习惯。 - * 结构特征抽取:在不引入具体语义标签的前提下,从像素梯度和纹理统计中提取边缘、角点、局部纹理、显著区域等特征,为后续的检测、配准、跟踪、分割提供“几何骨架”。 - * 几何与光照预处理:基于相机模型和简单几何线索(直线、消失点、对称性等)估计畸变与透视关系,通过去畸变、拉正、对比度与光照归一化等操作,将原始图像对齐到一个更标准、更稳定的输入空间。 -* **模型** - 综合使用经典图像处理方法和深度学习模型,在效率与效果之间做权衡: - * 传统图像处理:双边滤波、非局部均值、引导滤波、Retinex、直方图均衡、Canny/LoG 边缘检测、Harris/FAST 角点、SIFT/SURF/ORB 描述子、Hough 变换、相机标定与几何校正等。 - * 深度复原与增强模型:基于 CNN 或视觉 Transformer 的去噪、去模糊、超分辨率、去雨/去雾/去压缩伪影模型(如 EDSR、RCAN、SwinIR、ESRGAN 等),以及多帧/视频增强网络,用端到端方式学习从退化图到高质量图的映射,或使用现代的图像编辑模型实现例如即梦和 qwen 编辑模型。 - -### 2.1.1 图像复原与增强:从“看得见”到“看得清” - -在底层视觉里,图像复原与增强首先面对的是各种退化:噪声、模糊、压缩失真、低光照、动态范围不足等。很多真实场景下的原始图像并不“干净”:夜景和室内弱光会让画面布满颗粒和色斑,抓拍和监控画面常常因为运动、对焦不准而发虚,视频压缩会带来一块一块的方块噪声。复原与增强的目标,就是在不改变图像语义内容的前提下,尽可能恢复清晰的细节和自然的观感,把“模糊、灰暗、脏”的输入变得“清楚、明亮、舒适”。 - -典型任务包括去噪、去模糊、低光照增强和超分辨率等。去噪和去模糊需要在局部纹理和整体结构之间权衡:既要压制高频噪声、反卷积掉模糊核的影响,又不能把真实细节一起抹平;低光照增强则要在提升亮度与对比度的同时,避免暗部噪声被一并拉起,并校正偏色、压住过曝区域;超分辨率则侧重在放大的同时补出合理的高频信息,让放大后的图像既不显得“糊”和“塑料感严重”,又不过度“凭空捏造”细节。现代方法大多采用深度网络(CNN 或视觉 Transformer),在大量“退化–清晰”成对数据上学习从观测图像 y 到理想图像 x 的映射,同时使用包含像素误差、感知损失和对抗损失的组合目标,在“指标好看”和“人眼好看”之间取得平衡。 - -这些能力在产品中的呈现往往是隐性的:手机相机的夜景模式和 HDR 拍照、短视频平台的一键画质增强、老照片修复工具、监控系统的云端增强服务,本质上都依赖这一层的复原与增强模块。对业务而言,它们既直接影响用户对“画质”的主观感受,也间接决定了上层检测、识别、分割等算法的输入质量。可以说,越是复杂的上层视觉任务,越依赖底层有一个高质量、分布稳定的“图像地基”。 - -### 2.1.2 结构特征与预处理:为高层理解搭好“脚手架” - -当图像质量被修复到一个可用水平之后,底层视觉的第二项关键工作,是从像素中抽取出与具体语义暂时无关、但对几何结构和视觉感知非常重要的特征,并对几何和光照进行统一。这一步不会直接告诉你“这里是一辆车”或“这是某个人的脸”,但会回答“哪里有清晰的轮廓和拐角”“哪些区域纹理结构显著”“图像是否发生畸变或倾斜”等问题,为上层模型提供可靠的结构性输入。 - -在特征提取方面,边缘和角点是最基础的元素。通过 Canny、Sobel 等算子,系统可以在整张图上标出灰度或颜色变化最剧烈的“边缘”,这些往往对应物体轮廓、部件分界和纹理走向;角点检测(如 Harris、FAST)则找到局部梯度在多个方向上都变化显著的“拐角”,通常出现在物体的角、线条交汇处。进一步地,像 SIFT、SURF、ORB 这样的局部描述子,会在这些关键点周围编码一小片区域的纹理模式,使得同一物理点在不同视角、尺度和一定光照变化下仍然可以被匹配出来,这为图像配准、全景拼接、SLAM、AR 跟踪和三维重建提供了基础支撑。 - -与特征提取并行的,是各种几何和光照预处理操作。广角镜头带来的桶形/枕形畸变、拍摄文档时的倾斜和透视拉伸,都会通过直线检测、消失点估计等底层几何线索被识别出来,并通过去畸变、拉正、透视矫正等步骤被“拉回正常”;全局或自适应直方图均衡、对比度拉伸和光照归一化,则在保证细节不丢失的前提下,提升局部对比度、减弱光照不均和阴影的影响。颜色空间变换(RGB→HSV/Lab)与颜色直方图统计,为简单的基于颜色的分割、显著性区域检测、色偏校正等任务提供直接可用的输入。 - -在端到端深度学习成为主流之后,这些结构特征和预处理有一部分被“内化”到了网络前几层的卷积核和归一化策略中,不再以显式算子的形式出现在系统架构图上。但从功能上看,它们依然扮演着同样的角色:先用一层相对通用的、与具体类别无关的底层处理,把原始像素整理成在几何形态、光照条件和局部结构上更稳定的表示,再交给上层的分类、检测、分割和多模态模块去完成“理解这是什么”的任务。没有这层“脚手架”,上层模型就不得不在噪声大、畸变重、结构模糊的原始图上硬扛,整体系统的鲁棒性和泛化能力都会显著下降。 - -## 2.2 图像分类与识别(Image Classification & Recognition) - -在大部分图像任务中,业务方真正关心的问题是:**这张图整体属于哪一类?图里的这个人是谁?这名行人在不同摄像头下是不是同一个?** 你可以把这一层理解为:在一个统一、干净的输入空间上,为整张图像或者整个人/目标打上“类别标签”或“身份标签”,把视觉信号转化为最直接可用的识别结果。 - -从产品视角看,图像分类与识别是最早大规模落地的一批视觉能力,也是很多上层应用的“入口模块”。电商和内容平台用它来自动给图片打标签、识别主体品类;安防和门禁系统用它来确认“是不是同一个人”;行人重识别系统则在多路摄像头之间抽丝剥茧,找出同一目标的跨场景轨迹。下面我们同样从场景、原理和模型三个角度来梳理这一层: - -* **场景** - * 通用图片理解:为用户上传的图片自动打上“风景 / 美食 / 宠物 / 文档”等主题标签,用于检索、推荐、内容审核。 - * 人脸识别与门禁:在人脸门禁、考勤系统中,根据人脸图像识别个人身份,实现“刷脸通行”“刷脸打卡”。 - * 行人/人员重识别:在不同摄像头画面中判断是否为同一行人或同一人员,用于安防检索、轨迹分析。 - * 人体属性识别:在不直接确认身份的前提下,识别性别、年龄段、是否戴帽子/背包/穿制服等属性,为检索和行为分析提供线索。 -* **原理** - 在统一的视觉特征空间中,对整张图或整个人/目标进行判别式建模: - * 图像分类:以整张图像为输入,通过卷积网络或视觉 Transformer 提取全局特征,并在特征顶层接一个分类头,输出单标签或多标签的类别概率,用于回答“这是一张什么类型的图片”。 - * 身份/实例识别:将“是谁”的问题转化为特征空间中的度量学习问题,即学习一个嵌入空间,使同一身份的图像特征彼此接近,不同身份的特征彼此远离,然后用最近邻搜索或聚类完成识别与检索。 - * 属性识别:在共享的行人/人体特征之上,增加多任务输出头,预测性别、年龄段、衣着颜色、是否携带物品等属性标签,使得同一特征可以服务于多种下游检索与分析需求。 -* **模型** - 以深度卷积网络和视觉 Transformer 为主干,结合分类头或度量学习头实现不同类型的识别任务: - * 图像分类 Backbone:ResNet、DenseNet、EfficientNet、ConvNeXt、Vision Transformer (ViT)、Swin Transformer 等,通常在 ImageNet 等大规模数据集上进行预训练,再在具体业务数据上微调。 - * 通用分类结构:Backbone + 全连接分类层(Softmax / Sigmoid),用于单标签或多标签图像分类任务,可通过类别重加权、focal loss 等应对长尾分布。 - * 身份/实例识别:在 Backbone 的特征输出之上,使用 ArcFace、CosFace、SphereFace 等带角度约束的损失函数,显式拉大不同身份之间的类间间隔,提升在特征空间中的可分性,并通过向量检索(ANN)完成大规模库上的比对。 - * 行人/属性识别结构:针对行人 Re-ID 和人体属性识别,常见做法是采用共享 Backbone 提取行人特征,再在顶层分出“身份分支”和“属性分支”,既优化跨摄像头的身份区分能力,又兼顾多属性预测。 - -对应到具体产品形态,这一层的能力常以“图片内容识别 / 分类 API”“人脸识别 SDK / SaaS”“行人重识别平台”等方式对外提供。它们往往既直接驱动业务决策(如门禁放行、内容标签写入),又作为上游,为后续的检索、推荐、行为分析和多模态理解提供结构化标签与稳定的身份表征。下面,我们分别从图像分类和身份/属性识别两个角度展开。 - -### 2.2.1 图像分类:回答“这是一张什么图?” - -在最基础的图像分类任务中,系统面对的是整张图片,目标是给它贴上一个或若干个语义类别标签。最常见的是单标签分类,例如在 ImageNet 这样的数据集中,每张图被标注为“狗”“猫”“汽车”“飞机”等一个主类别;在业务场景中,这类能力被广泛用于给用户上传的图片加上“风景 / 美食 / 宠物 / 人像 / 文档”等主题标签,支持检索、推荐和内容审核。与文本分类类似,模型会在预训练 Backbone 提取的全局视觉特征之上接一个全连接 + Softmax 层,对所有候选类别输出一个概率分布。 - -在很多实际应用中,一张图往往同时属于多个类别,比如一张“海边日落自拍”图片,既可以是“风景”,也是“人像”,还可能被标注为“旅行”“海边”。这时就需要多标签分类(Multi‑label Classification):模型依然从整图特征出发,但输出层不再是互斥的 Softmax,而是对每个标签单独预测有/无的概率(Sigmoid),并采用多标签损失函数来训练。为了应对现实数据中大量“长尾类别”(冷门标签样本极少),多标签分类模型常会加入类别重加权、难例挖掘或标签结构建模等机制,提升对小众类别的召回。 - -在人机接口层面,图像分类通常以“图片内容识别 API”的形式对外提供。上游业务只需上传一张图片,即可获得一组类别标签及其置信度,用于后续的策略判断:比如广告投放系统可以根据图片内容限制某些敏感类目,电商平台可以利用图片分类辅助商品类目纠错,内容平台则用来丰富推荐特征和审核信号。虽然从技术上看,这类能力相对成熟,但它仍然是后续目标检测、实例分割、视觉问答等更复杂能力的基石。 - -### 2.2.2 图像识别与属性识别:回答“这是谁 / 这是什么实例?” - -与“这是一张什么类型的图”不同,图像识别更关心的是“图中的这个人/目标是谁”,也就是身份级、实例级的区分。典型代表是人脸识别和行人重识别:前者在门禁、考勤、支付等场景中判断“当前人脸与库中哪一个身份最接近”;后者则在多路摄像头与不同时间段的监控画面中,寻找是否存在同一行人,辅助案件回溯和轨迹分析。这类任务的核心,不再是简单的多分类,而是如何在特征空间中学习到一个“类内紧凑、类间分离”的嵌入,使同一身份在不同姿态、光照、摄像头下拍摄的图像仍能被聚到一起。 - -在模型设计上,人脸识别和行人重识别通常采用类似的范式:先用 ResNet、ConvNeXt、ViT、Swin 等 Backbone 提取以人脸/行人为中心的特征,再接上专门为度量学习设计的损失函数,如 ArcFace、CosFace 等。与普通分类损失不同,这些损失直接在角度空间或特征空间上约束类间边界,显式拉大不同身份特征之间的间隔,从而使得训练好之后的特征可以拿来做大规模向量检索,而不必局限于训练时见过的固定类别。在线服务时,系统会先对图库中每个身份的特征进行预计算和索引,再对上线查询的人脸/行人特征进行近似最近邻搜索,找到最相似的若干候选,并结合业务阈值和多模态信息做最终决策。 - -与“直接身份识别”相对应的,是不指向具体人的 **属性识别** 。在很多安防和零售场景下,系统只需要知道“是男性还是女性”“大概年龄段”“是否戴帽子/口罩”“衣服颜色和款式”“是否背包/拉行李”等属性,用于快速筛选目标,而不必、也不适合直接输出个人身份。这类任务通常在共享的行人/人体特征之上,接多个并行的属性头(头的意思是输出概率的位置,可以多几个概率输出的结果用于判断类别),每个头负责预测一个或一组属性标签,形成一个多任务学习框架。一方面,多任务训练可以让特征更加丰富、泛化更好;另一方面,属性本身也可以作为 Re-ID 或检索的辅助条件,提升系统在复杂场景下的可用性。 - -在产品形态上,这一类能力通常打包为“人脸识别 SDK/云服务”“行人重识别平台”“人体属性识别 API”等,被集成进门禁闸机、考勤机、安防平台和视频结构化系统。与通用图像分类相比,它们对数据安全和隐私保护要求更高,对误识率和召回率的权衡也更敏感,因此在算法之外,还会辅以质量检测(如是否为真人、是否为遮挡/翻拍)、活体检测、多模态交叉验证等机制,构成更完整、更负责任的身份识别方案。 - -## 2.3 目标检测(Object Detection) - -在前面的图像分类与识别中,我们只对“整张图”或“整个人”给出一个整体标签,而忽略了它在图中出现的位置和大小。然而,真实业务更常见的问题是:**这张图里有哪些物体?它们分别在什么位置?** 比如一张街景图中,我们希望同时标出所有的行人、车辆、交通标志牌;在工业产线上,需要在同一画面中标出所有瑕疵区域、零件位置。目标检测就是为这些需求而生的:它在单张图像或视频帧中,同时预测每一个物体的 **位置(bounding box)和类别** ,是众多下游视觉任务(跟踪、分割、行为分析、多目标计数等)的基础能力。 - -从工程使用角度看,目标检测是很多视觉系统的“第一步结构化”,把一张原始图分解为若干个带标签的矩形框,每个框都可以进一步送到其他模块做识别、跟踪、属性分析乃至语义生成。安防摄像头中行人/车辆的检测、无人零售货架上商品的检测、工业质检中缺陷/异物的检测、以及云厂商提供的「目标检测 / 物体检测」API,本质上都依赖这一层能力。下面我们从 **场景** 、**原理**和**模型**三个角度来梳理目标检测,并在后续小节中分别展开关键方向。 - -* **场景** - * 安防与交通监控:在摄像头画面中实时检测行人、车辆、非机动车、交通标志、逆行/占道目标等,为后续的行为分析和告警提供基础。 - * 工业质检与制造:在生产线上检测产品缺陷(划痕、破损、异物)、零部件位置、装配是否缺失,支持自动剔除与机器人定位。 - * 零售与物流:无人零售货架商品检测、结算;仓储中包裹、托盘、码垛的目标检测与定位,辅助库存盘点和机器人抓取。 - * 内容理解与审核:在图像/视频中检测人、logo、武器、敏感物品等,为内容审核、广告合规和品牌识别提供结构化信号。 -* **原理** - 目标检测的核心,是在图像上构建一个密集预测机制: - * 将输入图像通过 Backbone 提取为多尺度特征图,在这些特征图上,对每个“位置”(或候选区域)同时预测“是否有目标”“是什么类别”“对应的 bbox 参数”。 - * 按照架构划分,有先生成候选框再精修的 **双阶段检测(Two‑stage)** ,以及直接在特征图上做分类+回归的一体化 **单阶段检测(One‑stage)** ,两者在精度与速度上各有侧重。 - * 按候选框设计划分,有依赖预定义锚框(anchor)的 **anchor‑based** 方法,也有直接预测中心点/边界的 **anchor‑free** 与基于集合匹配的 **DETR 家族** 。 - * 为应对现实数据中的小目标、密集目标、遮挡和尺度变化,检测器通常会结合多尺度特征(FPN)、更高分辨率输入、特定损失函数与后处理策略(如 NMS 变体、多尺度测试)进行优化。 -* **模型** - 检测模型大体由**骨干网络 + 特征金字塔 / 头部结构 + 损失与后处理**三部分构成: - * 经典双阶段检测器:Faster R‑CNN、Mask R‑CNN 等,先通过 RPN 产生候选框,再对每个候选区域做精细分类与回归,精度高、结构清晰,适合对精度要求极高的场景。 - * 单阶段检测器:SSD、RetinaNet、YOLO 系列(YOLOv5/6/7/8、YOLOX、YOLOv10 等)等,在一个统一的网络中完成检测,结构紧凑、延迟低,是工业界实时检测的主力。 - * Anchor‑free / Transformer 检测器:FCOS、CenterNet、ATSS 等以像素点为中心直接预测框;DETR / Deformable DETR 等通过 Transformer 和集合匹配,将检测视为“从一组查询中生成一组目标”的问题,简化多种手工设计。 - * 视频检测与跟踪:在图像检测器的基础上,引入时序信息与关联策略(如跟踪头、光流、轨迹匹配),形成 Detection + Tracking 的统一框架,支撑长时间、多目标的行为分析。 - -综合来看,目标检测处于视觉能力谱系的“中枢位置”——它一方面承接底层视觉提供的干净图像输入,另一方面把图像解构成可供识别、跟踪、分割和多模态理解使用的“目标级”元素。下面,我们分别从 **单/双阶段检测架构** 、**Anchor‑based / Anchor‑free / Transformer 检测**以及**小目标与视频检测**三个方向展开。 - -### 2.3.1 单阶段与双阶段检测:精度–速度的结构权衡 - -从架构上看,目标检测最经典的划分是 **双阶段(Two‑stage)与单阶段(One‑stage)** 。二者的主要区别在于:是先“粗选一批候选框,再进行精修”,还是在特征图上“一次性预测完所有框和类别”。 - -双阶段检测以 Faster R‑CNN 为代表。它首先在 Backbone 特征图上通过 RPN(Region Proposal Network)生成一批“高概率包含目标”的候选框(第一阶段),然后对每个候选区域进行 RoI 对齐与特征提取,再做更精细的分类与边框回归(第二阶段)。这种设计的好处是:大量负样本在 RPN 阶段就被过滤掉,第二阶段可以集中精力在少数候选区域上做高质量的判别,因此在精度上往往更有优势,也更容易扩展到实例分割(Mask R‑CNN)、关键点检测(Keypoint R‑CNN)等任务。不过,多阶段结构带来的计算与实现复杂度相对较高,更适合对实时性要求不那么苛刻、但强调精度和可扩展性的离线或准实时场景。 - -单阶段检测则力图打通整个流程,在一个统一的网络中同时完成类别分类和边框回归。代表模型包括 SSD、RetinaNet 和 YOLO 系列等:它们直接在多尺度特征图的每个位置上预测若干候选框的“前景/背景 + 类别 + bbox”,省去了显式 proposal 阶段,更适合做端到端加速与部署。早期的单阶段检测器相对双阶段在精度上有一定差距,但凭借结构简单、速度快,在工业界迅速占据主导;随着 FPN、focal loss、IoU‑aware loss,以及更强 Backbone 和 Neck 的引入,RetinaNet、YOLOX、YOLOv7/8/10 等新一代模型已经在很多任务上实现了“接近甚至赶超双阶段”的精度–速度平衡。 - -在应用层面,工程上通常会根据需求在这两类架构间做取舍:对于云端批量离线分析、需要较高精度和可扩展性(如同时做检测+分割+关键点)的任务,双阶段检测仍然是一个稳定可靠的选择;而对于边缘设备、移动端应用、摄像头实时检测等延迟敏感场景,YOLO 系列等单阶段检测器几乎是默认首选,并且往往会结合量化、剪枝、蒸馏等技巧,以进一步压缩模型和提升吞吐。 - -### 2.3.2 Anchor‑based 与 Anchor‑free:从手工设定到端到端学习 - -在如何定义“候选框”这一问题上,检测方法又可以分为 **Anchor‑based 和 Anchor‑free** 两大类。早期主流方法(如 Faster R‑CNN、SSD、RetinaNet、YOLOv3/v4/v5 等)采用 Anchor‑based 思路:在特征图的每个位置预先定义若干具有不同尺度和长宽比的锚框(anchor),然后学习每个 anchor 对应的前景概率和 bbox 偏移量。这种方式实现简单、效果好,但需要人工对 anchor 的尺寸和比例进行较多调参,且在小目标、密集目标场景下容易出现 anchor 数量庞大、正负样本极度不平衡的问题。 - -Anchor‑free 方法则尝试摆脱对预定义 anchor 的依赖。以 FCOS、CenterNet、ATSS 等为代表,它们通常直接在特征图的每个像素点上预测“这里是否是某个目标的中心(或属于该目标)”以及对应的边界距离,从而完全避免了预设 anchor 的复杂性。这样的好处是:模型结构更简洁,训练样本分配策略可以更加自然,尤其在面对尺度变化大、目标形状复杂的真实场景时,具有更好的泛化和可扩展性。与此同时,Anchor‑free 检测器也推动了更多基于像素/点的统一框架,使得检测与关键点、分割等任务更易共同建模。 - -更进一步,DETR / Deformable DETR 等 Transformer‑based 检测器从另一个维度重新思考了检测问题:它们不在特征图上密集铺设 anchor,而是引入一组固定数量的“查询向量”(object queries),通过 Transformer 的自注意力和交叉注意力机制,从全局特征中“生成”一组目标预测,并通过匈牙利匹配(Hungarian Matching)实现一一对齐。这种集合预测(set prediction)的思路彻底消除了 NMS 和手工样本分配等传统组件,在概念上非常简洁,但在早期实现中存在收敛慢、对小目标不友好等问题;后续的 Deformable DETR 通过引入可变形注意力和多尺度机制,在收敛速度和性能上都有明显提升,逐渐在检测与多任务场景中获得更多应用。 - -对于工程实践而言,Anchor‑based、Anchor‑free 与 Transformer 检测并不是互斥的选择,而更像是一条演化链:从 heavily engineered 的 anchor 设计,到更为端到端的点/中心预测,再到完全基于集合预测与注意力的统一框架。当前工业落地中,YOLO 系列等成熟 Anchor‑based 模型依然是主力,Anchor‑free 和 DETR 家族则更多出现在对结构简洁性、多任务统一性、可扩展性要求较高的系统中。 - -### 2.3.3 小目标与视频检测:走向真实场景的鲁棒性 - -在公开数据集上的目标检测往往给人一种“问题已经基本解决”的错觉,但一旦进入真实场景,就会立刻遇到两类棘手问题:**小目标/密集目标**与 **视频中的稳健检测与跟踪** 。 - -小目标检测中,目标在原图中往往只占极少的像素区域,例如远处的行人、遥远的车辆、空中无人机,或者高分辨率工业图像上的微小瑕疵。随着 Backbone 下采样和特征图分辨率的降低,这些小目标在高层特征中很容易被“淹没”,导致漏检。为此,检测器通常会采用多尺度特征金字塔(FPN/PAFPN 等)、提高输入分辨率、在浅层特征图上增加检测头,甚至专门设计针对小目标的分支和损失加权策略。同时,在数据层面也需要通过裁剪、放大、小目标重采样等方式,提升模型对小尺度目标的感知与记忆能力。 - -密集目标(如拥挤人群、密集停车场、排列紧凑的商品/零件)则会暴露出锚框重叠、NMS 误杀、遮挡严重等问题。改进策略包括更精细的标签分配(如 ATSS 等自适应分配方法)、软 NMS 或基于学习的去重策略、以及通过中心点/密度图建模等方式缓解框间竞争。在工业质检中,许多系统还会结合检测与像素级分割,实现更精确的缺陷定位,以便后续自动处理。 - -当检测从单帧扩展到视频时,另一个挑战是 **时间连续性与目标稳定性** 。单帧检测器在每一帧上独立做出预测,难以避免短时丢检、ID 抖动和虚警,而现实应用中的告警、计数、轨迹分析往往需要跨帧一致的目标轨迹。为此,视频目标检测通常会叠加一个 Tracking 模块,把“检测 + 目标跟踪”打通:经典做法是以图像检测器为前端,在后端利用卡尔曼滤波、匈牙利匹配、外观特征相似度等实现多目标跟踪(如 SORT、DeepSORT 等);更进一步的做法是将跟踪头直接整合到检测网络中,联合学习检测与跨帧关联,提高短时遮挡、快速运动等场景下的鲁棒性。 - -在实际系统中,小目标、密集目标和视频检测往往不是孤立的问题,而是同时出现:例如城市道路监控中的远处行人/车辆、车站广场中的密集人群、产线视频中的高速运动零件。这也决定了,高质量的目标检测模块,除了在标准 benchmark 上有亮眼指标外,更需要在多尺度、多密度、长时间视频等真实条件下,经受住各种复杂因素的考验,才能真正支撑上层的行为分析、智能告警和多模态理解。 - -## 2.4 图像分割(Image Segmentation) - -有了目标检测,我们已经可以知道“图里有哪些物体、它们大致在哪里”,但很多任务还需要更精细的结构化理解:**精确到每一个像素,判断它属于哪一类、属于哪个实例** 。例如自动驾驶中要知道哪些像素是路、哪些是人和车;抠图工具要把头发丝和背景分得干干净净;医学图像里要精确描出肿瘤和器官的边界。这类任务统称为图像分割,它直接在像素层面输出语义或实例标签,相比检测提供了更细粒度的空间结构信息。 - -从产品角度看,图像分割是“像素级结构化”的核心能力:抠图和背景替换工具依赖它决定哪些像素需要保留;自动驾驶的感知模块依赖它构建精细的“可行驶区域 + 障碍物”地图;医学影像软件依赖它测量病灶大小、形状和体积;遥感平台依赖它区分农田、水体、建筑、道路等地物。下面我们从 **场景** 、**原理**和**模型**三个角度来梳理图像分割,并在后续子项中展开语义/实例/全景/大模型分割等方向。 - -* **场景** - * 内容编辑与抠图:人像抠图、头发丝级别的背景替换、物体抠出和分层编辑,用于图片美化、短视频特效、广告创意制作。 - * 自动驾驶与机器人:对每个像素标注路面、车道线、行人、车辆、护栏、建筑、天空等,用于路径规划、碰撞预警和环境建模。 - * 医学影像分析:在 CT、MRI、超声等图像中精确分割器官、肿瘤、病灶区域,支持辅助诊断、手术规划和疗效评估。 - * 遥感与地理信息:在卫星/航拍图中分割农田、水体、道路、建筑、林地等地物,支持国土规划、土地利用监测和灾害评估。 -* **原理** - 图像分割本质上是“密集预测”,对输入图像通过编码器(Backbone)提取多尺度特征,再通过解码器或上采样模块,将特征图逐步还原到与输入同尺寸的分割图,在每个像素位置上输出一个语义或实例标签。 - * **语义分割(Semantic Segmentation)** :为每个像素分配一个语义类别(如路、人、车、天空),不区分同类的不同个体,适合描述“场景组成”。 - * **实例分割(Instance Segmentation)** :在语义信息之上进一步区分同类不同实例,为“每一辆车、每一个人”生成独立掩膜,是检测与分割的结合。 - * **全景分割(Panoptic Segmentation)** :统一处理“可数的物体(thing,如人、车)”与“不可数的背景(stuff,如路、天空)”,为每个像素同时给出语义标签和实例 ID。 - 与检测相比,分割对空间细节与边界质量更加敏感,需要更丰富的多尺度上下文信息和更精细的上采样/融合策略。 -* **模型** - 经典到最新的分割模型大致沿着“FCN → 编码器–解码器 → 多尺度上下文 → 检测+分割一体化 → 大模型分割”的路线演化: - * 语义分割:FCN、U‑Net 及其变体、DeepLab 系列(DeepLabv3/v3+)、PSPNet 等,通过空洞卷积、金字塔池化、跳跃连接等方式获取多尺度上下文和精细边界。 - * 实例/全景分割:Mask R‑CNN、Panoptic FPN、Mask2Former 等,将检测头与分割头结合,实现目标级分割和全景分割。 - * 大模型与通用分割:Segment Anything Model (SAM) 等基础分割模型,将分割从“每个任务单独训练”提升为“一个模型适配多数分割场景”,支持交互式、提示驱动(prompt‑based)的分割。 - -总体而言,图像分割相比目标检测提供了更精细的空间结构表达,是构建高可靠感知系统和高级编辑工具时不可或缺的一环。下面,我们从 **语义分割与实例分割**, **全景分割与检测一体化**, 以及**通用分割**, **大模型**, **与无监督分割**三个方向展开。 - -### 2.4.1 语义分割与实例分割:从“像素类别”到“像素实例” - -**语义分割(Semantic Segmentation)** 的目标,是为图像中的每一个像素指定一个语义类别,使得网络学会“这片区域是路,那片区域是车,这里是人,那边是天空和建筑”。经典做法通常采用编码器–解码器结构:编码器(如 ResNet、EfficientNet、Swin Transformer 等)提取逐渐下采样的高层特征,解码器通过上采样、跳跃连接(skip connection)和多尺度融合,将粗糙的高层语义特征与底层细节结合,还原到原始分辨率。FCN 首次将这种密集预测形式系统化,U‑Net 通过对称的 U 型结构与大量 skip connection 在医学影像中取得了巨大成功;DeepLab 系列通过空洞卷积(dilated convolution)和 ASPP(金字塔空洞池化)在不降低分辨率的情况下扩大感受野;PSPNet 则通过金字塔池化获取全局上下文信息。这些模型共同推动了在道路场景、遥感、医学等领域的大规模应用。 - -**实例分割(Instance Segmentation)** 进一步在像素语义标签的基础上区分同类不同个体:不只要知道哪些像素是“车”,还要知道这些像素分别属于哪一辆车。最具代表性的模型是 Mask R‑CNN,它在 Faster R‑CNN 的检测框架上增加了一个并行的分割分支:先通过检测头预测每个候选框的类别和位置,再在每个框内生成一个二值掩膜,从而得到“框 + 掩膜”的目标级分割结果。与纯语义分割相比,这种方法能够很好地处理物体重叠和遮挡,是人像/商品抠图、多目标计数、细粒度编辑等任务的基础。后续的实例分割方法在 mask 质量、多尺度与速度上不断改进,也出现了基于 anchor‑free 和 Transformer 的新架构,但“检测 + 局部分割”的思路仍然非常主流。 - -在产品层面,语义分割通常出现在“场景级”的应用中,例如自动驾驶道路分割、遥感地物识别、医学器官分割等;实例分割则更常用于“物体级”抠图、计数和编辑,例如一键选中并分离每一辆车、每一个人、每一件商品。两者结合,可以为上层任务提供既精细又结构化的空间信息。 - -仅做语义分割会把同类对象混在一起(所有“车”像素都属于同一个类);仅做实例分割又往往只关注可数的“东西”(things,如人、车、动物),而忽视大面积的不可数“背景”(stuff,如路、草地、天空)。在很多场景中,我们既需要知道**每一个对象的实例级掩膜** ,又想了解 **整体场景构成** 。这就催生了**全景分割(Panoptic Segmentation)** :为每一个像素同时给出语义类和实例 ID,实现对 thing + stuff 的统一建模。 - -早期的全景分割系统通常通过“语义分割模型 + 实例分割模型 + 后处理合成”的方式实现:先用一个网络预测每个像素的语义类别,再用另一个网络输出各个实例的掩膜与类别,最后通过一套规则(如优先级、重叠处理)将两者合并为一个一致的全景分割结果。Panoptic FPN 代表了一条工程上更优雅的路径:在一个共享 Backbone 与特征金字塔(FPN)上,分别挂载语义分割头和实例分割头,通过联合训练与特征共享,同时得到两种输出,再通过轻量的后处理将它们融合。这样不仅提高了效率,也增强了语义和实例之间的一致性。 - -在模型层面,随着检测/分割一体化与 Transformer 架构的发展,出现了如 Mask2Former 等统一的全景分割框架:它们倾向于使用一套通用的“query + mask decoder”结构,在同一网络中同时预测语义、实例乃至其他下游任务的掩膜,从而在架构上大幅简化系统、方便多任务扩展。对于自动驾驶、机器人导航、AR 场景理解等复杂任务来说,全景分割提供了一种更接近“人眼主观感受”的完整场景描述,让上层决策和规划可以在更准确的空间语义上进行。 - -在产品形态上,全景分割往往内嵌在自动驾驶、机器人系统和高端视觉分析平台中,用户未必直接感知到“全景分割”这个概念,但会真实受益于更稳健的场景理解和更自然的交互体验。 - -### 2.4.2 通用分割与无监督分割:从任务定制到“Segment Anything” - -传统分割模型往往围绕特定数据集和任务训练:比如“道路场景 19 类语义分割”“某种肿瘤分割”“某几类商品分割”等,每换一个任务就要重新标注、重新训练。在实际业务中,这种强依赖精标数据的方式代价巨大,并且难以覆盖长尾类别和不断涌现的新场景。近年来,随着大规模预训练视觉模型和提示驱动(prompt‑based)范式的发展,出现了以 **Segment Anything Model (SAM)** 为代表的**通用分割大模型** ,试图把分割能力从“任务定制”提升为“基础设施”。 - -以 SAM 为例,它通过一个强大的图像编码器(通常是大规模预训练的 ViT)学习全图的通用特征,再通过轻量的提示编码器和掩膜解码器,将用户给出的点、框、文本提示等转化为分割结果。在训练阶段,SAM 利用了海量、多源、多任务的掩膜标注,使得模型学到的是一种“泛化的分割能力”,而不是对某个数据集标签的死记硬背;在使用阶段,用户只需给出极少量提示(一个点或者一个粗框),就能在各种未见过的图像类型和物体类别上得到质量较高的掩膜。这种范式大大降低了构建新分割应用的门槛,也为无监督/弱监督场景提供了强有力的工具。 - -与之相关的,是更广义的**无监督 / 自监督分割**方向:不依赖或极少依赖人工掩膜,通过图像内部的相似性、时序一致性、多视角约束等信号,自动将图像划分为若干有意义的区域。早期工作多侧重于“视觉聚类”和区域提议(proposal generation),如今则更多地被大模型内化为一种表征学习方式,为下游的分割任务提供良好的初始化。结合 CLIP 等文本–图像对比学习模型,越来越多的方法能够在“只给文本类别名称、不提供掩膜标注”的条件下,进行零样本或少样本分割,为冷启动场景和长尾类提供新解法。 - -在实际产品中,通用分割大模型往往以“交互式抠图工具”“智能选区”“一键抠背景”等形式出现,也逐步被整合进医学、遥感、工业等领域的专业软件中,作为半自动标注与辅助分割的加速器。与传统定制模型相比,它们不一定在某个特定任务上达到极致,但在“什么都能做一点、多场景快速落地”上有显著优势,也为后续构建真正的多模态基础视觉模型打下了基础。 - -## 2.5 关键点检测与动作识别(Keypoint Detection & Action Recognition) - -在分类、检测、分割之后,我们已经可以知道“图里有什么、在哪儿、每个像素属于什么”。但在很多真实任务中,业务关心的不仅是“物体存在与位置”,而是**姿态和动作** :一个人是在走路还是在奔跑?这只手是否举起、是否做出某个手势?工人是否正确佩戴安全设备、执行规范动作?运动员的技术动作是否标准?这些问题需要我们进一步理解 **物体内部的结构与时序变化** 。 - -关键点检测与动作识别就是面向这一需求的两层能力: - -* **关键点检测(Keypoint Detection)** :在图像或视频帧上,预测目标(通常是人体、手部、面部或特定机械结构)的若干“骨架点”(如关节、指尖、五官),得到一个精细的结构化姿态表示(pose)。 -* **动作识别(Action Recognition)** :在时序上分析这些关键点或外观特征随时间的变化,判断“这个人/这群人正在做什么动作或行为”。 - -从产品视角看,这一能力广泛服务于:人机交互(手势控制)、体育分析(技术动作评估)、安防(跌倒检测、打架/奔跑等异常行为识别)、工业安全(违规动作检测)、虚拟人驱动(依靠人体/面部关键点驱动 3D 骨骼与动画)等场景。下面我们从 **场景** 、**原理**和**模型**三个角度梳理这一层能力,并在子节中分别展开关键点检测与动作识别。 - -* **场景** - * 人机交互与 AR/VR:通过手势识别、身体姿态检测,实现“比划一下就能控制”的自然交互,或在 AR/VR 中实时驱动虚拟形象。 - * 体育训练与运动分析:对跑步、跳高、投篮、举重等动作进行关键点追踪与角度分析,给出技术动作评估与纠错建议。 - * 安防与公共安全:检测跌倒、打架、剧烈奔跑、翻越护栏等异常行为,用于及时告警;在工地、厂区中识别是否规范操作。 - * 工业与人机协作:检测工人是否按规范姿态操作、与机器人协作时的安全距离、是否出现危险动作。 - * 面部/表情驱动与虚拟人:通过面部关键点捕捉表情细节,用于表情迁移、数字人驱动、视频会议虚拟形象等。 -* **原理** - 两类任务分别侧重空间结构与时序变化,但本质上都是在高维特征空间中做结构化预测: - * 关键点检测:在图像上定位一组预定义关键点(如 17/25 个人体关节、21 个手部关节、68/106 个面部关键点),常用方式是在特征图上预测每个关键点的热力图(heatmap),再通过峰值位置反推坐标;多人的场景下,还需要进行“关节到人的组装”。 - * 单帧/短时动作识别:基于单张图或短时间窗口,通过人体姿态(关键点)和外观特征,判断该帧/该片段中发生的动作类别(如走、跑、举手、挥手、坐下等)。 - * 时序动作识别:在更长的时间尺度上,分析特征序列(图像特征、关键点序列或光流等),建模动作的起始、持续与结束,识别“正在打电话”“正在做俯卧撑”“两人互相推搡”等复杂行为。 - * 结构化表示:关键点序列提供了一种比原始像素更紧凑、更稳定的结构化表示,便于在动作识别中处理视角变化、背景干扰和外观差异。 -* **模型** - 常见模型大致沿着“卷积/Transformer 特征提取 + 关键点/时序头”这一统一范式发展: - * 关键点检测:OpenPose 系列、Hourglass Network、HRNet、基于自顶向下(先检测人再估计姿态)和自底向上(先检测关节再组装)两大分支;近年来也有基于 Transformer 的姿态估计器。 - * 视频动作识别:基于 2D/3D CNN 的视频模型(I3D、SlowFast 等)、基于骨架的 GCN 模型(ST‑GCN 等,直接在关键点图上建模时空关系)、以及基于视频 Transformer(Video Swin、TimeSformer 等)的端到端方案。 - * 统一多任务与大模型:在通用视觉 Backbone 上同时输出检测、分割、关键点和动作标签,或利用多模态大模型通过文本提示直接理解“这个人在做什么动作”,将结构化预测与语义理解连接起来。 - -下面我们分别从**关键点检测与姿态估计**以及**动作识别与行为理解**两个方向展开。 - -### 2.5.1 关键点检测与姿态估计:给人和物“画骨架” - -关键点检测(也常被称为姿态估计,Pose Estimation)关注的是 **单帧或单幅图像中的空间结构** :在二维图像中找到一组具有语义意义的关键点,并将它们连接成骨架。例如,在人体姿态估计中,我们通常需要检测头部、肩膀、肘、腕、髋、膝、踝等关节;在面部姿态中则是眼角、嘴角、鼻尖、脸廓等;在手部姿态中则是指根、指关节、指尖。对于机械臂、关节结构件等非人体对象,也可以同样定义一套关键点体系。 - -在模型设计上,关键点检测常用的是 **“特征提取 + 热力图预测”**范式: - -* 首先使用 CNN 或视觉 Transformer(如 ResNet、HRNet、Swin 等)对输入图像提取多尺度特征。 -* 然后通过一个解码头或多层卷积,为每一个关键点类型输出一张热力图(heatmap),其中每个像素值表示“该位置是该关键点的可能性”。 -* 推理阶段,通常取每张热力图的峰值位置作为关键点坐标,并通过双线性插值、局部拟合等方式进行亚像素级优化。 - -针对多人场景,姿态估计方法大致分为两路: - -* **自顶向下(Top‑down)** :先使用行人检测器在图中找到每个人的边界框,再对每个框内的图像分别做单人姿态估计。这种方式对单人精度高、框架简单,但在多人密集场景中计算代价大、对检测质量敏感。代表系统包括许多基于 Faster R‑CNN/YOLO + Hourglass/HRNet 的组合。 -* **自底向上(Bottom‑up)** :不先区分每个人,而是在全图上直接预测所有潜在关键点(及其类型),同时预测关键点之间的连接关系或亲和场(如 OpenPose 的 PAF)。然后通过图匹配/聚类算法,将关键点组装成多个独立的人体骨架。这类方法在多人密集场景中更高效、对人数规模更鲁棒,但组装过程复杂,对连接质量敏感。 - -近年来,基于 Transformer 的姿态估计模型也逐渐出现,将关键点检测看作一组“查询–响应”任务,与 DETR 类似,可以在架构上统一对象检测与姿态估计。在工程应用中,关键点检测能力通常被封装为“人体/手势/面部关键点 SDK 或 API”,上游应用只需传入图像或视频帧,即可获取结构化的骨架坐标,用于后续的动作识别、交互控制或动画驱动。 - -### 2.5.2 动作识别与行为理解:让“骨架”动起来 - -在得到关键点或高层视觉特征之后,下一步就是理解 **时间维度上的变化** ——也就是动作识别(Action Recognition)和行为分析(Behavior Understanding)。与关键点检测不同,动作识别不再局限于单帧;它关心的是一段时间内特征的演化模式:从“抬手”到“挥手”,从“走路”到“奔跑”,从“站立”到“跌倒”。 - -在输入表示上,大致有三条路线: - -* **基于原始** **视频帧** **/光流** :直接对视频帧序列建模,或额外引入光流(描述局部运动速度的场)作为输入,让模型从外观 + 运动信息中联合学习。 -* **基于骨架/关键点序列** :先用姿态估计得到人体关键点坐标序列,再在“时空骨架图”上建模,弱化背景与光照干扰,更关注人体结构与运动模式。 -* **多模态融合** :将视频特征、关键点序列、甚至音频、文本等多模态一起纳入,处理复杂行为场景(如多人互动、事件级动作)。 - -对应地,模型结构也呈现出多样化发展: - -* 早期的动作识别主要依赖 **2D CNN + 时间 n 池化** 或 **3D CNN** (如 I3D、C3D):前者对每一帧提特征再在时间维上做池化或 RNN;后者直接在空间和时间上做三维卷积,捕捉短时运动模式。 -* 针对骨架序列,典型方法是 **时空图卷积网络(ST ‑ GCN)** :把人体关键点看作图结构节点,关节之间的连接是边,在时间维上也连边,通过图卷积在时空图上传播信息,从而学习动作模式。这类方法轻量、对背景鲁棒,适合在资源有限的设备上部署。 -* 近年来, **视频 Transformer** (如 TimeSformer、Video Swin)在动作识别中表现突出,它们将视频切分为时空 patch,通过自注意力机制建模长时间依赖,能够更好地捕捉复杂动作与多目标交互。 - -在业务侧,动作识别往往会与检测、跟踪、关键点检测结合,形成端到端的行为分析系统: - -* 在安防中,先检测并跟踪人员,再对每条轨迹的关键点序列进行动作分类,实现跌倒检测、打架/奔跑识别等; -* 在体育和健身应用中,通过关键点序列分析动作是否标准、幅度是否合适,并给出纠正建议; -* 在人机交互场景中,对实时姿态流进行轻量级动作分类,实现挥手、比心、手势指令等交互; -* 在工业安全中,对工人操作动作进行持续监测,识别危险姿态(如俯身进入危险区、越过安全线等)。 - -面向未来,多模态大模型正在将“动作识别”提升为更高层的“事件与意图理解”:模型不仅可以标注“走路、跑步、打电话”,还能够回答“这个人似乎在示意招呼某人”“这两人正在发生争执”等更接近日常语言的描述。关键点检测和动作识别在其中,作为重要的结构化运动线索,与外观特征和语言提示一起,共同支撑更复杂的时空理解能力。 - -## 2.6 开放词汇 / 开放世界 / 开放域检测 - -(Open‑Vocabulary / Open‑World / Open‑Domain Detection) - -前面的检测与分割能力,基本都默认一个前提: **训练和推理时的类别集合是固定的** 。也就是说,模型在训练阶段就完整地见过“所有要识别的类别”,推理时只需要在这套封闭标签里做选择。但真实世界远比数据集复杂:新商品、新品牌、新路牌、新物种、新场景随时出现,不可能为每个新类都准备充足的标注数据重新训练检测器。这就催生了 **开放词汇 / 开放世界 / 开放域检测** :在训练数据只覆盖有限“已知类”的情况下,让模型在推理时仍然能够感知、定位和识别 **未见的新类** ,并且在视觉风格和拍摄域(domain)变化时保持鲁棒性。 - -你可以把这一层理解为:在传统检测之上,加入“对语言空间与开放世界的对齐和泛化能力”。模型不再只会说“这是 80 类 COCO 之一”,而是可以在任意文本描述的空间里理解和检索目标,例如“检测图里所有‘红色运动鞋’”“标出所有‘疑似小型飞行器’”,即便这些精细类别在训练集中从未显式出现。下面我们从 **场景** 、**原理**和**模型**三个角度来梳理这一层,并在子小节中分别展开开放词汇检测、开放世界检测和开放域泛化。 - -* **场景** - * 通用场景理解 API:用户给出任意自然语言描述(类别词或短句),系统在任意风格的图像中返回对应目标的检测框或分割掩膜,例如“图中所有安全帽”“所有疑似品牌 logo”“所有带轮子的物体”。 - * 大规模商品 / 物种识别:电商中不断上新的长尾商品、自然界中数量巨大的动植物物种,训练数据只能覆盖一部分已知类,但系统需要对海量新类进行定位与粗识别,并支持通过文本或图像检索。 - * 跨域安防 / 自动驾驶感知:训练数据多来自白天城市道路/少数摄像头视角,实际部署却面临不同城市、乡村、高速、极端天气、红外/鱼眼摄像头等“新域”,其中还会出现训练集中从未标注过的新型目标(新款车型、新交通设施、新类型障碍物)。 -* **原理** - 这类方法的核心,是用**视觉–语言对齐的嵌入空间**替代传统的“固定 one‑hot 类别头”,并通过多种机制处理“未见类”和“新域”: - * 开放词汇检测(Open‑Vocabulary Detection):在训练阶段,利用大规模图文对(image–text pairs)预训练得到类似 CLIP 的对齐空间,使得图像区域和文本嵌入可以直接在同一语义空间中做相似度匹配;检测头不再输出固定的类别 logit,而是输出一个区域特征向量,与任意文本描述向量进行对比,从而支持“训练只见部分类别,推理可指定任意文本类别”。 - * 开放世界检测(Open‑World Detection):进一步处理“训练集中完全没有标注的新类”,要求模型可以将这类目标检测为“未知类(unknown)”,并在后续通过交互标注或持续学习,把这些未知类逐步纳入已知类别集合,形成一个可以不断扩充类目的在线学习系统。 - * 开放域 / 跨域检测(Open‑Domain Detection):面对图像风格、成像设备、环境条件等大幅变化(domain shift),通过领域自适应(Domain Adaptation)、领域泛化(Domain Generalization)等技术,让检测器在未见过的新域中保持稳定检测性能;常见手段包括对抗性域对齐、多域训练、风格随机化、元学习等。 - * 分割与检测一体的开放词汇:将上述思路扩展到像素级,对任意文本描述生成分割掩膜(open‑vocabulary segmentation),通过 Region–Word 或 Mask–Word 对齐损失,实现“用自然语言描述一个区域/物体,就能得到对应 mask 或框”。 -* **模型** - 当前开放词汇 / 开放世界 / 开放域检测的主流技术路线,基本围绕“大规模视觉–语言预训练 + 检测头适配 + 域泛化机制”展开: - * CLIP‑based 检测器:以 CLIP 风格的图像编码器和文本编码器为基础,在区域级特征(ROI、特征图 patch、mask 区域)与文本嵌入之间应用对比学习和 Region–Word 对齐损失;典型实现包括在 Faster R‑CNN / RetinaNet / YOLO / DETR 等架构上替换或扩展分类头,使其以“cosine 相似度 + 文本嵌入”方式输出类别分数。 - * Caption‑driven / Prompt‑based Detection:利用大规模图文描述(caption)数据,为图像中的区域或 mask 自动生成文字描述,再用这些自动生成的文字与检测/分割区域对齐训练,从而减少对人工类别标签的依赖;推理时则通过自然语言 prompt(如“所有穿红色衣服的人”“所有电动车”)驱动检测/分割。 - * Open‑World Detection 系列工作:在传统检测框架中显式引入“未知类(unknown)”建模、渐进式类别扩展和增量学习机制,一部分方法通过度量空间的距离与不确定性估计来判断“是否为未知类”,另一部分引入记忆库与在线重训练,使系统能随时间积累新类别知识。 - * 域自适应 / 域泛化检测:在 Backbone 和检测头层面增加域判别器、对抗性损失、多域 batch normalization、风格随机化增强等模块,使检测器在不同域之间学习到更域不变的表示;也有工作在 Transformer 检测框架(如 Deformable DETR)上引入多源域训练和元学习策略,提升跨域泛化能力。 - * 通用 / Foundation 检测模型:把检测问题上升到“基础模型”层面,预训练一个在类别和域上都尽可能通用的 Detection Foundation Model,再通过轻量微调或文本 prompt 适配特定场景;这类模型通常结合大规模检测标注、多源图文对、甚至视频数据,目标是让“任意文本 + 任意风格图像”的通用理解成为可能。 - -在具体产品形态上,开放词汇/开放世界/开放域检测往往体现为“更自然、更少限制”的视觉接口:用户不必提前约定一小撮固定标签,而是可以用自然语言描述想找的目标;系统也不需要为每个业务场景从零开始重训检测器,而是基于统一的通用模型,通过 prompt 或少量样本快速适配。对于大规模商品 / 物种识别、全球化部署的安防与自动驾驶感知系统而言,这一层能力正在成为从“封闭数据集性能”走向“真实开放世界可用性”的关键跳板。 - -### 2.6.1 开放词汇检测:从固定类别头到文本驱动类别空间 - -**开放词汇检测(Open‑Vocabulary Detection)的出发点,是突破传统检测中“固定类别头”的限制。以往的检测器在顶层接一个大小固定的分类层(对应训练集中的 N 个类别),训练完成后只能在这 N 个类别中选择;而开放词汇检测则通过引入文本**, **编码器**, **和共享的语义嵌入空间,让检测头输出的区域特征可以与任意文本描述**进行相似度对比,从而在推理时接纳未见过的新类别。 - -典型做法是使用类似 CLIP 的视觉–语言预训练模型: - -* 文本端:对类别名称或自然语言描述(如“person”、“red sports car”、“yellow construction helmet”)进行编码,得到文本向量。 -* 视觉端:在检测框架(Faster R‑CNN、RetinaNet、YOLO、DETR 等)中,对每个候选区域或特征点提取区域特征向量。 -* 对齐训练:通过对比损失、Region–Word 对齐损失,使同一语义的文本和区域特征在嵌入空间中靠近,不同语义的向量远离。训练时即便只对一部分类别提供显式框标注,也可以利用图文对或图像 caption 扩展语义覆盖。 - -推理阶段,系统不再依赖训练时固定的一组类名,而是允许用户在线提供任意类别词或自然语言描述,通过文本编码器转为嵌入,再与区域特征做相似度匹配。这使得检测器可以在不重新训练的前提下,支持诸如“检测所有滑板”“检测所有绿植”“检测所有安全相关设备”等灵活需求,即便某些具体类目在训练集中从未出现过完整标注,只要语义上与预训练的图文空间有重叠,就能被一定程度地识别和定位。 - -在工程实践中,开放词汇检测需要在效果与效率之间平衡:一方面,保持与大规模预训练的视觉–语言 Backbone 的语义对齐;另一方面,又要承载检测任务对多尺度、实时性的要求。主流 CLIP‑based 检测器往往采用“预计算文本嵌入 + 高效向量相似度计算”的方式,避免在在线服务中反复编码文本,同时对区域特征进行量化或蒸馏,兼顾精度和推理速度。 - -### 2.6.2 开放世界检测:从“未见类”到“可学习的未知” - - **开放世界检测(Open‑World Detection)在开放词汇的基础上,进一步要求模型显式处理“未知类”** :训练数据中只标注了部分类别,其余物体要么未被标注,要么被统称为背景;推理时,这些“未被标注的真实物体”既不应该被简单视为背景,也不应被错误归入已知类别,而应作为“未知类(unknown)”被检测出来,并具备后续转化为“新已知类”的可能。 - -在建模上,开放世界检测通常需要解决三个问题: - -1. **未知类感知** :如何在训练阶段避免将所有未标注目标都学成“背景”?常见做法包括:引入显式“未知类”槽位,通过负例挖掘和不确定性建模让模型学会在低置信度区域输出“unknown”;或者利用无标注数据和自监督机制,对高置信度的潜在目标区域进行聚类和伪标签生成。 -2. **错误归类控制** :模型需要在“宁可判为 unknown,也不要错误归入错误已知类”之间做权衡,这涉及到损失设计(如 margin、开放集判别)、决策阈值和后处理策略。 -3. **渐进式类别扩展** :当业务方对一批“unknown”目标人工标注出新类别后,模型应能够通过增量学习将这些新类别纳入“已知类”集合,而不显著遗忘旧类。为此,很多工作引入了记忆库、蒸馏损失、参数隔离或重放机制,实现对新类别的稳定吸收。 - -从产品视角看,开放世界检测特别适合那些**类目不断增长、长尾极度严重**的场景,例如自然物种识别、新品快速上新的商品识别、复杂安防场景中的异常目标检测等。系统可以先用开放世界检测将“任何非背景的可疑目标”标出,并逐步通过人工或半自动标注,将其中有价值的聚类升级为正式类目,从而形成一个“类目可持续生长”的检测系统,而不是被固定数据集束缚。 - -### 2.6.3 开放域 / 开放分布检测:跨风格、跨设备、跨场景的鲁棒性 - -即使类别集合保持不变,检测器仍然会在现实部署中遭遇严重的 **域偏移(Domain Shift)** :训练数据可能来自少数城市的白天高清摄像头,而部署环境却包含不同国家、乡村、高速路、隧道、夜间、雨雪、低分辨率摄像头、鱼眼镜头甚至红外成像;电商商品摄影与用户实拍、广告图/插画/动漫风格之间也存在巨大差异。**开放域检测(Open‑Domain Detection)**关注的正是:在图像分布发生显著变化的条件下,保持检测性能的稳定与可靠。 - -典型的技术路径包括: - -* **领域自适应(Domain Adaptation)** :在拥有目标域无标注数据或少量标注数据的前提下,通过对抗性域对齐(在特征空间上混淆源域/目标域)、多级域对齐(图像风格、特征、检测头输出)、风格迁移(如将源域图像风格迁移到目标域)等方式,让模型学到对域不敏感的特征。 -* **领域泛化(Domain Generalization)** :在仅有多个源域数据、没有目标域数据的前提下,利用多域训练、风格随机化、特征扰动、元学习等手段,使模型在训练阶段就尽可能暴露于多样化分布,提升对未知新域的泛化能力。 -* **通用 / Foundation 检测模型** :通过在极大规模、多源、多风格数据上预训练检测 Backbone 和头部结构(包括自然图像、视频帧、合成数据、跨模态数据等),再在特定业务场景轻量微调,从而获得比“单域训练”更强的开放域鲁棒性。 - -这些开放域机制往往与开放词汇/开放世界能力相互叠加:一个面向真实世界的通用检测系统,既要能听懂用户的自然语言类别描述(开放词汇),又要能对新出现的目标给出合理的“未知”判断和渐进吸收(开放世界),还要能在不同国家、不同设备、不同天气和风格下保持性能(开放域)。在工程落地中,这三者并不是彼此孤立的研究方向,而是共同构成了从“封闭 benchmark”迈向“开放世界可用”的关键能力组合。 - -## 2.7 视觉–语言任务(Vision–Language Tasks) - -前面的章节主要围绕“单模态视觉”展开:输入是一张图像,输出是检测框、分割掩膜、类别标签或质量分数。而在很多真实应用中,视觉信息并不是孤立存在的——一张图往往伴随标题、说明文字、对话或搜索查询;用户想问的是“图里在讲什么”“这张图和这句话匹不匹配”。**视觉–语言任务**正是解决这类问题:它们以图像 + 文本为输入或输出,通过 **跨模态对齐与联合建模** ,让系统能够“看图说话”“看图回答问题”“用文字找图 / 用图找文”。 - -从产品视角看,视觉–语言模型(VLM)是多模态系统的中枢能力:搜索引擎依赖它实现“以文搜图 / 以图搜文”;内容平台用它做智能配图、广告审核、图文一致性检查;多模态助手则将其作为基础能力,实现“看图聊天”“对文档/截图提问”等功能。下面我们从 **场景** 、**原理**和**模型**三个角度梳理这一层,并在后续小节中分别展开图像描述、视觉问答与图文检索。 - -* **场景** - * 图像描述(Image Captioning):为图片自动生成一两句自然语言描述,用于无障碍辅助阅读、智能相册说明、搜索索引丰富。 - * 图像问答(VQA):用户针对图片提出自然语言问题(“这个人拿着什么?”“车牌号是多少?”),系统给出精准回答,可用于教育、辅助决策和多模态助手。 - * 图文检索(Cross‑modal Retrieval):以文本检索相关图片(Text‑to‑Image)、以图片检索相关文本(Image‑to‑Text),支撑“以文搜图 / 以图搜文”搜索、创意选图和广告投放审核。 - * 图文一致性与审核:判断图片与标题/广告语是否相符,有没有“图文不符”“诱导性描述”等风险,用于内容审核和品牌安全。 -* **原理** - 核心问题是:如何把图像和文本映射到 **同一个语义空间** ,并在这个空间内进行对齐与推理: - * 跨模态对齐:通过联合训练的图像编码器和文本编码器,让对应的“图–文对”在表示空间中彼此靠近,不相关对彼此远离(典型如 CLIP);这为检索、匹配提供了基础。 - * 联合理解与生成:在对齐的表示基础上,引入跨模态注意力,让语言模型在“看着图像特征”的前提下生成文本(图像描述)、推理和回答问题(VQA)。 - * 提示化与指令化:用自然语言指令统一描述多种视觉–语言任务(“为这张图写标题”“回答关于这张图的问题”“判断这段文字是否描述了图片”),让一个模型通过不同提示完成多种任务。 -* **模型** - 主流视觉–语言模型大致演化为两类:**对比学习型 VLM** 与 **生成式多模态** **大模型** : - * 对比学习型:CLIP、ALIGN 等,将图像和文本分别编码成向量,通过大规模图–文配对训练,使其在检索和匹配任务上表现出色,是“以文搜图 / 以图搜文”的基础。 - * 视觉–语言生成模型:BLIP / BLIP‑2、Flamingo、Kosmos、LLaVA 等,将视觉编码器与大语言模型(LLM)衔接,通过跨模态注意力和指令微调,支持图像描述、VQA、多轮对话等复杂任务。 - * 通用多模态大模型:如 GPT‑4.1 with Vision、Gemini 1.5 等,进一步将视觉与更多模态(语音、代码等)统一在一个大模型中,通过统一的接口完成检索、问答、推理和生成。 - -总体而言,视觉–语言任务标志着“视觉不再是一个单独的感知通道”,而是与语言共同参与到更高层的知识表达和推理之中。下面,我们从 **图像描述与视觉问答** 、**图文检索与跨模态对齐**两个方向展开(这里按内容合并为两小节)。 - -### 2.7.1 图像描述与视觉问答:从“看图说话”到“看图推理” - -**图像描述(Image Captioning)**的目标,是输入一张图像,输出一段自然语言描述,比如“一个小女孩在草地上放风筝”。传统做法通常采用“CNN + RNN”结构:用卷积网络提取整图特征,再用 LSTM/GRU 逐词生成描述;随着 Transformer 和预训练 VLM 的出现,主流范式逐渐转向“图像编码器 + 文本解码器”结构,如 BLIP / BLIP‑2、ViT + GPT 等。训练上,模型通常在大量图–文对上进行自回归训练,有时还会采用强化学习或对比损失,优化描述的多样性与正确性。在产品层面,图像描述被广泛用于无障碍阅读(为盲人读屏软件生成图片说明)、智能相册自动加标题,以及为搜索系统提供更多文本索引。 - - **视觉问答(VQA)则进一步把人类交互引入进来:模型的输入不再是“图 + 空白提示”,而是“图 + 问题”,输出一个简短答案或者自然语言解释。与图像描述相比,VQA 更强调可控性与推理能力** :问题可以关注局部细节(“男人的帽子是什么颜色?”)、关系(“哪辆车离路口更近?”)、计数(“有几只狗?”),甚至需要外部知识(“这道菜属于哪种菜系?”)。早期 VQA 模型通常使用图像编码器 + 问题编码器 + 融合模块(如双线性池化、注意力)+ 分类头,输出一个有限词表中的答案;现代多模态大模型则直接用图像编码器 + LLM,在“看图”的基础上进行自然语言生成,在开放式回答和多轮对话上有明显优势。 - -两者在统一的 VLM 框架下可以被视为不同的“提示模板”: - -* Captioning:`<图像> + "Describe this image in one sentence."` → 文本; -* VQA:`<图像> + "Q: ... A:"` → 文本。 - -通过指令微调(Instruction Tuning),同一个多模态大模型可以兼容描述、问答、解释、打标签等多种任务,这也是现代 VLM 产品(多模态助手、图像问答机器人等)的基础工程思路。 - -### 2.7.2 图文检索与跨模态对齐:以文搜图 & 以图搜文 - -**图文检索(Cross‑modal Retrieval)**解决的是另一个高频需求:给定一段文本,找到匹配的图片(Text‑to‑Image Retrieval);或给定一张图,找到相关的文字描述、商品信息、新闻报道等(Image‑to‑Text Retrieval)。这些能力构成了“以文搜图 / 以图搜文”“看图找商品”“给新闻配图”等产品的核心。 - -核心技术是 **跨模态对齐** :以 CLIP 为代表的模型,对图像和文本分别使用各自的编码器(如 ViT 和 Transformer 文本编码器),在大规模图–文配对数据上使用对比学习训练: - -* 对于同一对(图像,文本),让它们的向量在嵌入空间中彼此靠近; -* 对于不匹配的图–文对,则推远它们的向量。 - -训练完成后,只需将所有图片和文本编码成向量,就可以通过向量检索(最近邻搜索)在共享空间中进行快速匹配: - -* Text‑to‑Image:文本 → 文本向量 → 最近的图像向量; -* Image‑to‑Text:图像 → 图像向量 → 最近的文本向量。 - -在工程实践中,这类模型通常采用两阶段结构: - -* 第一阶段用轻量快速的双编码器(Bi‑Encoder,如 CLIP)做粗检索,在亿级图像库中快速筛选出一小部分候选; -* 第二阶段可选用更强的交叉编码器(Cross‑Encoder)或多模态大模型对候选进行精排与重排序,以提升相关性和鲁棒性。 - -在产品侧,图文检索与跨模态对齐被广泛用于:图片搜索、广告检索(根据广告文案找到合适图片)、合规审核(检查广告图文是否一致)、内容推荐(基于用户阅读文本历史向其推荐相关图片/视频)等。随着多模态大模型的兴起,这类检索能力也逐渐被统一进更大的多模态框架中,以“自然语言指令 + 多模态记忆/向量库”的形式,对外提供统一接口。 - -## 2.8 光学字符识别(OCR) - -在很多业务中,最重要的信息既不体现在“画面里的物体和场景”,也不在自然语言对图像的描述里,而是直接写在图像上的 **文字** :合同条款、发票金额、路牌名称、仪表读数、屏幕截图上的错误信息等。**光学字符识别(OCR)**就是围绕“图像 + 文档版式”的结构化理解任务:从复杂的视觉输入中,自动检测并识别文字内容,理解文档的布局和结构,进而支持搜索、统计、自动录入和智能问答。 - -从产品视角看,OCR 是“把纸质/图像信息变成可计算文本”的关键桥梁,是电子化、自动化与智能化办公的基础设施:合同审阅、票据入账、政企档案数字化、办公软件中的 PDF 转 Word、文档问答助手等,都建立在 OCR 能力之上。下面从 **场景** 、**原理**和**模型**三个角度梳理 OCR 体系,并在后续小节中展开核心方向。 - -* **场景** - * 场景文本识别:街景中店铺招牌、路牌、广告牌、包装盒文案等,用于导航、搜索、零售洞察和合规审核。 - * 文档 OCR:扫描件、传真件、PDF、照片版合同/发票/报告等的文字识别与结构化,还原成可编辑文本。 - * 专用场景:车牌识别、仪表盘读数(电表、水表、气表)、屏幕截图文字提取、试卷/表单识别等。 - * 文档理解:在布局复杂的长文档中,抽取标题、段落、表格、注释等结构,为搜索、摘要、问答奠定基础。 -* **原理** - OCR 体系通常分成几个关键步骤: - * 文本检测:在图像上检测出所有文字区域(文本行或文本块),输出定位框(水平或四点多边形),这是后续识别的输入。 - * 文本识别:对每个检测到的文字区域进行序列识别,将像素序列转化为字符序列(如中文、英文、数字、符号等)。 - * 版式分析(Layout Analysis):在文档场景中,识别各区域的角色(标题、正文、图片、表格、页眉页脚等),恢复阅读顺序和层次结构。 - * 表格结构识别:对表格区域进行行列划分、单元格边界解析、合并单元格恢复,重建逻辑表格结构。 - * 文档问答(DocVQA):在 OCR 和版式理解的基础上,让模型能够回答“这份合同的付款日期是什么?”“发票的金额是多少?”这类跨区域、多步骤推理的问题。 -* **模型** - 工程上常见的是“专用 OCR 模块 + 文档理解模型 + 多模态大模型”组合: - * 文本检测与识别: - * 检测:EAST、DBNet/DBNet++ 等基于分割或边缘学习的方法,擅长处理弯曲文本和复杂背景; - * 识别:CRNN、RARE、SAR 等序列模型(CNN + RNN/Attention + CTC 或自回归解码),支持多语种和多字体。 - * 文档版式与结构理解: - * LayoutLM / LayoutLMv2/v3、DocFormer 等,将文本内容(token)、位置信息(bounding box)和视觉特征联合编码; - * Donut 等“端到端文档理解”模型,直接从图像到结构化输出(如 JSON / Markdown),弱化传统 OCR 的边界。 - * 文档问答与多模态理解: - * 在布局模型基础上,叠加任务头进行 DocVQA; - * 或直接使用多模态大模型(VLM)读取文档图像,在自然语言层面完成问答和摘要,同时隐式利用 OCR 能力。 - -综合来看,OCR 已经从早期“简单的字符识别”发展为涵盖**文字 + 版式 + 结构 + 问答**的整体文档理解体系,是企业数字化、政务档案管理和智能办公的关键支柱。下面,我们从 **文本检测与识别** 、 **文档版式与表格结构分析** 、**文档问答与多模态 DocVQA**三个方向展开。 - -### 2.8.1 文本检测与识别:从像素到可用文本 - -OCR 的第一步是 **文本检测** :在输入图像中找到所有包含文字的区域。街景/场景文本面临字体多样、倾斜扭曲、光照复杂、背景干扰严重等挑战;文档场景则强调对密集文本和多栏排版的鲁棒支持。EAST、DBNet 等方法通过将检测问题转化为“像素级分割 + 边缘学习”,在特征图上预测文本概率和几何参数,再通过后处理获得精确的文本框(可为水平框或任意四边形/多边形),兼顾精度和速度。 - -**文本识别**则把每个检测出的文本区域切下来,转化为字符序列。经典做法以 CRNN 为代表:先用 CNN 提取特征,再通过 RNN 或 Transformer 进行序列建模,最后使用 CTC 或注意力解码输出字符序列。对于不定长文本、弯曲文字和复杂语言(中英文混排、多语种),识别模型需要在视觉特征建模和字符语言建模上同时发力。诸如 RARE、SAR 等方法会引入空间变换网络(STN)或注意力对齐机制,以纠正几何畸变、提升对复杂布局的适应能力。 - -在工程系统中,检测与识别通常作为两个解耦的服务组成一条 OCR pipeline:前端检测将图像拆成若干文本行/块,后端识别对每个块做字符识别,并可叠加语言模型做错误纠正(如拼写修复、数字/金额校验)。对于车牌、仪表读数等特定场景,还会使用专门微调的检测/识别模型,以利用场景先验(固定字体、有限字符集)换取更高精度和更低延迟。 - -### 2.8.2 文档版式与表格结构分析:还原“文档的形状” - -单纯把文字识别出来还不够,尤其在长文档、报告、合同和票据等场景中,**版式结构**往往决定了信息的含义和重要性:标题与正文的层级关系、图表与配文的位置、页眉页脚的作用、表格内外文段的逻辑顺序等。**文档版式分析(Document Layout Analysis)**的目标,就是在二维页面上识别出不同区域的角色和边界,并恢复出合理的阅读顺序与层级结构。 - -LayoutLM / LayoutLMv2/v3、DocFormer 等模型,将每个文本 token 的内容(文本 embedding)、空间位置(bounding box 坐标)以及局部视觉特征(来自 CNN/ViT)联合编码,通过 Transformer 建模 token 间的语义–空间关系。通过在带版式标注的数据集上训练,模型可以学会区分“标题/段落/列表/表格/图片说明/页眉页脚”等多种区域类型,并在输出中给出对应标签和层级。这类模型通常作为“中间层”,为合同审阅系统、报告解析、档案数字化平台提供结构化的文档骨架。 - -**表格结构识别(Table Structure Recognition)** 是版式分析中特别关键的一支:它不仅要检测出表格区域,还要进一步解析行列边界、单元格坐标和合并单元格,最终重建一份逻辑表格(通常表示为 HTML、Markdown 表、或带坐标的结构化 JSON)。实现方法包括: - -* 基于规则/视觉:使用线检测、分割网络、对象检测等手段提取表格线和单元格区域,再进行拓扑建图; -* 基于 Transformer:将表格区域的文本块与几何信息编码成序列,直接预测单元格结构和关联关系。 - -在产品上,这些能力支撑了“PDF 转 Word/Excel”“票据/发票结构化录入”“报表解析与指标抽取”等高价值场景,是政企办公自动化的关键组件。 - -### 2.8.3 文档问答与 DocVQA:从“读文档”到“问文档” - -当 OCR 与版式分析能力足够强时,下一步自然需求就是: **不再让人自己翻阅文档,而是直接“问文档”** 。这就是 **文档问答(DocVQA)** :模型在合同、报告、票据、说明书等复杂文档上回答问题,比如“这份合同的生效日期是什么时候?”“这页报表中 2023 年 Q4 的净利润是多少?”“发票上的购方名称是谁?”。 - -传统 DocVQA 系统通常以“OCR + 版式模型 + QA 头”的方式构建: - -* 先使用 OCR 提取文本及坐标; -* 用 LayoutLM / DocFormer 等建模文本–版式–视觉三模态关系; -* 最后在这个表示上叠加任务头(分类 / 抽取 / span 预测),根据问题在文档中定位答案或相关片段。 - -随着多模态大模型的发展,越来越多系统开始直接使用“文档图像 + 问题”作为输入,让一个 VLM 或多模态 LLM 直接生成答案或带引用的解释。在这种架构下,OCR、版式、语义理解和推理能力在模型内部以端到端的方式协同工作:模型既能看到原始版式和视觉线索,又能利用语言世界知识和推理模式完成复杂问题的解答。 - -在产品形态上,DocVQA 通常以“合同审阅助手”“发票/报表问答”“长文档智能问答”形式出现,帮助用户从大量文档中快速定位关键信息、自动生成摘要、进行条款比对等,大幅减轻人工审阅和信息检索的负担。 - -## 2.9 图像生成与编辑(Image Generation & Editing) - -前面介绍的视觉能力大多是“判别式”的:输入图像,输出标签、框、掩膜或文本;而近年来快速发展的另一条主线是 **生成式视觉** :模型不再只是理解图像,而是 **创造或修改图像** ,在给定文本/图像条件下生成高质量、多风格的视觉内容。**图像生成与编辑**正是这一方向的核心能力,支撑了从 AIGC 绘图平台到智能修图/特效工具的大量产品。 - -从业务视角看,生成式视觉已经从“技术演示”变成切实可用的生产力工具:设计师用它做灵感草图和细化稿;营销团队用它批量生成海报和广告素材;普通用户用它制作头像、插画、壁纸;视频创作者用它做抠图、背景替换和特效。下面我们从 **场景** 、**原理**和**模型**三个角度梳理这一层,并在后续小节中展开文本生成图像、图像到图像与编辑能力。 - -* **场景** - * 文本生成图像:用户输入一段描述(“赛博朋克风的夜景城市”),系统自动生成符合描述的多张图片,支持选图与迭代修改。 - * 风格迁移与图像翻译:将真实照片转换为动漫/素描/油画/水彩风格,或在不同领域间做映射(白天 ↔ 夜晚、夏天 ↔ 冬天)。 - * 条件重绘与扩展:在原图的局部进行重绘(Inpainting)、对画面外扩(Outpainting),用于修补瑕疵、移除/添加对象、扩展构图。 - * 文本驱动编辑:用自然语言指令修改图像(“把天空改成日落”“让这辆车变成红色跑车”),用户无需掌握复杂的图像编辑软件。 -* **原理** - 生成式视觉模型主要通过学习“图像分布”和“条件控制”来完成生成与编辑: - * 分布建模:GAN、扩散模型(Diffusion)、Flow Matching 等从大量图像中学习高维分布,使得模型能从随机噪声中逐步“采样”出逼真的图像。 - * 条件生成:在纯图像分布建模基础上,引入文本/草图/分割图/关键点/深度图等条件,使生成过程受到外部信号约束(Text‑to‑Image、Image‑to‑Image、ControlNet 等)。 - * 可控编辑:在已有图像的潜在空间中,通过文本或局部 mask 对局部特征进行引导和修改,实现局部重绘、风格变化、构图调整等。 -* **模型** - 当前主流图像生成与编辑模型以**扩散模型 + 条件控制**为主: - * GAN 系列:StyleGAN 等在高分辨率人脸和样式控制方面表现突出;但训练不稳定、难以覆盖复杂多模态分布。 - * 扩散模型:Stable Diffusion、Imagen、DALL·E 系列等,通过“正向加噪 + 反向去噪”的过程进行采样,兼具质量和多样性,是当前 Text‑to‑Image 的主力方向。 - * 可控生成与编辑:ControlNet、T2I‑Adapter 等,在基础扩散模型上叠加条件通道(边缘、姿态、分割等),实现精确控制;结合文本引导的 Inpainting/Outpainting 实现局部编辑和画面扩展。 - * Flow Matching 与新一代生成模型:通过学习连续流场将噪声分布变换到图像分布,在效率、可控性与稳定性上探索新的平衡。 - -在产品层面,这些技术以即梦、阿里 qwen 图像模型、FLUX、OpenAI 或者 Gemini nanobanana、Stable Diffusion 生态、Photoshop Generative Fill、Canva AI、剪映/CapCut 智能抠图与特效等形态面向用户,逐步从“玩具”演进为内容生产链条中的正式环节。下面,我们从 **文本生成图像** 、**图像到图像翻译**和**文本驱动编辑**三个方向展开。 - -### 2.9.1 文本生成图像(Text‑to‑Image):从一句话到一张画 - -**文本生成图像(Text‑to‑Image)** 的核心任务是:给定一段自然语言描述,生成一张尽可能匹配其语义和风格的图像。现代 Text‑to‑Image 模型主要基于扩散架构: - -* 首先使用文本编码器(如 CLIP Text Encoder 或 T5/LLM)将输入文本编码为条件向量; -* 然后在图像潜空间中,从高噪声状态开始,通过多步反向去噪采样,在每一步都利用文本条件引导生成方向; -* 最终得到符合描述的高分辨率图像,可进一步放大或后处理。 - -Stable Diffusion、Imagen、DALL·E 系列等方法在大规模图–文对上进行训练,使模型既掌握视觉谱系(形状、纹理、构图、光影),又获得一定程度的语言–视觉对齐能力(理解“风格”“材质”“构图”等复杂描述)。在产品层面,这种能力让“不会画画的人也能画图”:用户只需用自然语言描述想法,系统就能给出多种视觉实现,支持迭代试探和细化。 - -Text‑to‑Image 模型通常同时支持多风格、多分辨率输出:通过在训练或推理时加入风格 token、尺寸条件等,使同一个模型在“写实照片风、扁平插画风、3D 渲染风”等不同风格之间切换。工程上常用的技巧包括: - -* 文本提示工程(Prompt Engineering),用于细化和稳定输出风格; -* LoRA / DreamBooth 等轻量微调技术,在通用模型上快速适配特定人物、IP 或品牌风格。 - -### 2.9.2 图像到图像(Image‑to‑Image):翻译、风格迁移与局部重绘 - -**Image‑to‑Image** 任务在给定输入图像的基础上,生成另一个“受其约束”的图像版本:既保留原图的整体结构或内容,又实现某种转换或增强。典型形态包括: - -* 图像翻译 / 风格迁移:在不同视觉域之间进行映射,如“照片 → 动漫”“夏天 → 冬天”“白天 → 夜晚”“素描 → 彩色图像”。早期多基于 GAN(CycleGAN、Pix2Pix 等),现在也可以用扩散模型在条件控制下完成。 -* 条件生成:以草图、分割图、深度图、边缘图等为条件,通过 ControlNet、T2I‑Adapter 等模块引导扩散过程,让生成图严格遵守几何/布局条件,同时在纹理、光影、风格上自由发挥。 -* Inpainting / Outpainting:在原图上划定某个区域,将其视为待重绘部分(inpainting),或在画面外延展生成新内容(outpainting),实现“填坑”“扩图”等操作。 - -这类任务的关键是 **在保留约束的前提下创造新内容** 。扩散模型在这方面表现突出:在 inpainting 中,模型只对 mask 区域进行采样,而在未被遮挡的区域保持原图不变,通过语义理解与上下文信息,使新内容与周围区域在风格与光影上自然融合。对于风格迁移,模型在保留输入结构的同时,从目标风格分布中采样纹理和颜色,实现“换壳不换骨”。 - -在产品里,Image‑to‑Image 能力支撑了大量创意工具:风格滤镜、漫画化、一键天空替换、自动美颜、旧照修复、局部修图等,通常以高度可视化的界面呈现给用户。 - -### 2.9.3 文本驱动图像编辑:自然语言当“画笔” - -在传统图像编辑软件中,用户需要掌握图层、蒙版、选区、滤镜等一整套专业概念;而**文本驱动图像编辑(Text‑guided Editing)** 尝试用自然语言替代大部分专业操作: - -* “把背景换成夜晚城市天际线”; -* “让这个人穿黑色西装”; -* “把这辆车变成蓝色跑车,增加运动模糊效果”。 - -技术上,文本驱动编辑通常建立在 Text‑to‑Image 扩散模型之上,通过几种方式实现: - -* 在原图附近的潜空间中搜索或采样,使编辑后的图与原图保持高相似度,只在受文本影响的局部发生变化; -* 使用显式 mask(用户圈定区域),将编辑范围限制在特定区域(这就是许多工具中的“选中区域后输入文本指令”); -* 引入“指令控制”模块(如 ControlNet、可学习控制 token),增强模型对编辑请求的可控性与稳定性。 - -即梦、FLUX、阿里 qwen 图像模型、Stable Diffusion 生态、Canva AI 等产品都提供了类似能力:用户通过简单文字和少量交互即可完成复杂编辑。对专业用户而言,这成为加速创作流程的“智能助手”;对普通用户而言,则极大降低了图像编辑的门槛。 - -## 2.10 图像质量评估(Image Quality Assessment, IQA) - -在底层视觉增强、压缩编码、图像生成与编辑等任务中,我们经常需要回答一个看似主观的问题: **“这张图看起来好不好?”** 。手工检查显然无法规模化,而像 PSNR 这类传统指标又常常与人眼主观感受不一致。**图像质量评估(Image Quality Assessment, IQA)** 的目标,就是建立一套自动化机制,对图像的主观/客观质量进行评分或排序,成为连接“底层算法输出”和“用户真实体验”的关键环节。 - -从系统角度看,IQA 是很多流水线中的“看门人”和“调参参考”:电商/内容平台用它筛掉模糊、噪声重、压缩过度的上传图片;手机相机/相册用它在连拍中挑出“最好的一张”;云端增强和压缩服务用它进行前后对比评估,以指导模型迭代。下面从 **场景** 、**原理**和**模型**三个维度梳理 IQA,并在后续小节中展开评估类型与指标/学习范式。 - -* **场景** - * 上传质检与审核:对用户上传的图片/视频做质量评分,过滤严重模糊、曝光异常、噪声明显和压缩伪影严重的内容。 - * 智能选片与去重:在手机相册、相机应用中,从多张相似照片中选择清晰度、表情、构图更好的版本,同时识别质量差或冗余图片用于清理。 - * 增强/压缩算法评估:在图像增强、降噪、超分辨率、编解码等算法 A/B 测试中,用 IQA 指标客观衡量“哪种策略更好”,辅助参数搜索与模型选择。 - * 海报/缩略图自动选取:在视频或多图集合中自动选择视觉质量和吸引力更高的帧作为封面或海报候选。 -* **原理** - IQA 的核心是从两个维度刻画图像质量:**相对于参考图的失真程度**与 **人眼主观感知的好坏** : - * 全参考 IQA(FR‑IQA):在有高质量参考图的前提下,将待评估图与参考图进行逐像素或特征对比,衡量失真程度,用于算法研发和实验评估。 - * 无参考 IQA(NR‑IQA / Blind IQA):实际场景中更常见,没有参考图,只能从单张图的统计特征或深度特征中推断质量,需要模型从大量图像与主观评分中学习到“人眼喜欢什么样的图”。 - * 伪参考 / 降采样参考:在某些场景中,可以使用压缩前的低分辨率版本、模型预测的“理想图”等作为近似参考,兼顾可实现性与评估精度。 -* **模型** - IQA 模型大致分为**传统手工特征指标**与**深度学习****式质量预测**两大类: - * 传统指标: - * FR‑IQA:PSNR、SSIM、MS‑SSIM、FSIM 等,侧重结构、对比度和相位信息,对简单退化(如加噪、模糊)较敏感。 - * 感知指标:LPIPS、DISTS 等,在深度特征空间衡量图像间感知差异,与人眼主观感受有更高相关性。 - * 无参考 / 学习式 IQA: - * 早期方法:BRISQUE、NIQE、BLIINDS 系列等,从自然场景统计(NSS)和手工特征出发,训练浅层模型预测质量分数。 - * 深度 NR‑IQA:RankIQA、DBCNN、HyperIQA、MUSIQ 等,直接用 CNN / ViT 从图像中抽取特征,并在 MOS(Mean Opinion Score,主观评分均值)数据上监督训练,使输出质量分数尽可能拟合人眼评价。 - * 预训练表征:利用 CLIP、ViT 等大模型的特征,作为质量预测网络的输入或 backbone,在有限 MOS 数据上微调,提升对复杂失真类型的泛化能力。 - -整体来看,IQA 并不是“越高越好”的单一指标,而是一套与具体业务目标相关的评估体系:在某些场景(如监控增强)中,保留细节和可识别性比视觉自然更重要;在内容创作平台中,主观观感和审美标准则占主导。因此,工业界常见做法是:在通用 IQA 模型基础上,通过少量业务数据微调或学习加权,构建“任务感知”的质量评估器。 - -### 2.10.1 评估类型:有参考、无参考与伪参考 - -按照是否存在高质量参考图,IQA 可以分为三类: **全参考(FR‑IQA)** 、 **无参考(NR‑IQA)和伪参考** 。 - -在 **全参考 IQA** 中,我们假设存在一张理想的高质量参考图像,待评估图是其经过压缩、传输或处理后的退化版本。模型通过对两者进行逐像素或特征级比较,量化失真程度。PSNR 是最简单的度量(基于均方误差),SSIM/MS‑SSIM/FSIM 等进一步考虑亮度、对比度、结构或相位信息,在一定程度上更接近人眼感受。这类指标非常适合在算法开发阶段评估编解码、超分辨率、去噪等方法,但在真实业务中往往缺乏参考图,应用场景有限。 - -**无参考 IQA(Blind IQA)** 是实际系统中更常见的设定:只有待评估图像本身,没有任何参考。早期无参考方法(如 BRISQUE、NIQE、BLIINDS 等)主要基于自然场景统计:假设高质量自然图像在某些统计分布上有稳定形态,失真会引起统计特征变化,从而可以训练模型根据这些特征预测质量分数。深度学习时代,NR‑IQA 模型通常直接利用 CNN / ViT 提取特征,并在带有人眼主观评分(MOS)的数据集上回归质量分数或学习排序关系,使其能够覆盖噪声、模糊、压缩伪影、曝光异常等多种失真类型。 - -**伪参考 / 降采样参考 IQA** 介于两者之间:在没有真正高质量参考的情况下,使用某种可获得的近似版本(如压缩前低分辨率图、模型预测的“干净图”)作为参考,对退化程度进行估计。这种方式常见于在线视频质量监控、编解码优化任务中,可以在成本与精度之间取得平衡。 - -### 2.10.2 指标与学习范式:从 PSNR 到感知质量预测 - -在具体实现层面,IQA 采用多种指标和学习范式来逼近人眼主观感受。 - -**传统指标**方面: - -* PSNR 直接基于像素级误差,简单高效,但对人眼不敏感的变化(如轻微平移、结构保持的滤波)也会给出较大惩罚; -* SSIM、MS‑SSIM、FSIM 等从亮度、对比度、结构、相位等多个维度建模图像相似性,对结构性失真更敏感,也一定程度反映人眼对结构信息的偏好。 - -**感知指标**方面:LPIPS、DISTS 等通过在预训练深度网络(VGG、AlexNet、ViT 等)内部特征层计算向量差异,并按照不同层的重要性加权,得到一种“特征空间中的距离”,与主观感知相似性有更高相关性。它们特别适合作为生成式任务(超分、生成、编辑)的训练目标或评估指标,用来衡量“看起来像不像”。 - -**学习式质量预测**方面,深度 NR‑IQA 模型(如 RankIQA、DBCNN、HyperIQA、MUSIQ 等)直接对图像打分或排序: - -* 训练数据中,每张图像附带一组主观评分(MOS),模型以此为监督训练质量回归或排序网络; -* 模型结构上,多采用 CNN/ViT + 全局池化 + MLP 输出质量分数,或输出一组质量分布再取期望; -* 有些方法还利用对比学习或排序学习(pairwise ranking),让模型更关注“相对好/坏”的关系,而不是绝对分数。 - -随着大规模预训练视觉模型的普及,越来越多 IQA 方法采用“预训练 Backbone + 轻量头”的范式:利用 CLIP、ViT 等丰富的视觉表征,在较少 MOS 数据上进行微调,从而在跨失真类型、跨场景上保持良好的泛化。 - -在工程落地中,通常会将上述多种指标组合使用:例如 FR‑IQA 指标用于实验阶段评估算法改进;深度 NR‑IQA 模型用于线上实时质检;感知指标用于生成任务的内部优化。通过 A/B 实验将这些自动指标与真实用户数据(点击率、完播率、投诉率等)对齐,逐步构建起与业务目标高度相关的“感知质量度量体系”。 - -# 3. 3D / 空间模态(3D / Spatial / XR) - -随着应用从“平面图像/视频”走向自动驾驶、机器人、AR/VR/XR 等场景,系统不再满足于只看“2D 像素”,而是需要理解 **真实世界的三维结构、尺度和位姿关系** 。这类任务统称为 3D / 空间模态:既包括对几何与拓扑的精确建模,也包括在 3D 空间中的语义理解、定位导航与内容生成。它一端连接 LiDAR、RGB‑D、IMU 等多种传感器,另一端连接自动驾驶感知模块、机器人导航系统、ARKit/ARCore 环境模型、手机 3D 扫描建模应用以及数字孪生平台等。 - -## 3.1 3D 感知与重建(3D Perception & Reconstruction) - -在 2D 视觉里,我们只看到了“拍成照片后的世界”;而在自动驾驶、机器人、AR/VR 等场景中,更关键的是: **真实世界在 3D 空间中的位置、形状和结构** 。3D 感知与重建就是要从多种传感器(相机、LiDAR、深度相机等)出发,恢复环境的三维几何信息,并以点云、体素、网格(Mesh)、隐式场等形式表达出来,为路径规划、物理仿真、数字孪生和 3D 内容生成提供基础。 - -在工程实践中,这一层涵盖从**点云处理**到**多视角几何重建**再到**神经辐射场 / 神经场渲染**等多个技术方向,对应着自动驾驶 3D 感知模块、ARKit/ARCore 环境建模、手机 3D 扫描/建模应用以及数字孪生城市/园区建模平台等产品形态。下面从 **场景** 、 **原理** 、**模型**三个角度展开,并进一步细分几个关键子方向。 - -* **场景** - * 自动驾驶与辅助驾驶:从车载 LiDAR 点云和多摄像头图像中感知车辆、行人、路沿、车道线、交通设施等 3D 结构,用于路径规划和安全决策。 - * 室内/室外环境扫描:利用手机/平板(结构光 / ToF / 双目)或手持扫描仪采集多视角数据,实时构建房间、楼宇、街区的 3D 模型,用于 AR 建模、家装设计、数字孪生。 - * 数字孪生与 BIM:将实际工厂、园区、城市通过多视角影像和点云重建成高精度 3D 模型,用于运维管理、仿真与可视化。 - * 消费级 3D 扫描:手机 3D 扫描 App、一键“拍照变 3D 模型”工具,为 3D 打印、虚拟试穿、游戏/影视资产制作提供原始几何。 -* **原理** - * 点云处理:将 LiDAR 或多视角重建得到的稀疏/稠密点集合视作 3D 采样点集,对其进行滤波、配准、下采样和特征学习,再做分类、语义/实例分割或 3D 目标检测。 - * 多视角几何与三维重建:通过 SfM(Structure‑from‑Motion)估计多张图像之间的相机位姿和稀疏 3D 点云,再通过 MVS(Multi‑View Stereo)生成稠密点云,随后进行网格重建与纹理贴图。 - * 神经辐射场 / 神经隐式场:使用 NeRF、Instant‑NGP、Gaussian Splatting 等方法,把 3D 场景表示为连续的体密度/颜色场或高斯粒子集合,通过体渲染或光栅化生成图像,从多视图监督中学习;训练好后可以进行新视角渲染和几何提取。 -* **模型** - * 点云网络:PointNet / PointNet++、PointCNN、DGCNN、MinkowskiNet 等直接在点或稀疏体素上学习特征,用于点云分类、分割与 3D 检测。自动驾驶中常用 VoxelNet、SECOND、CenterPoint 等 3D 检测框架,将点云转换为体素或 BEV(鸟瞰图)特征后进行检测。 - * 几何重建工具链:COLMAP、OpenMVG / OpenMVS 等传统 SfM/MVS 系统,可从多视角照片恢复相机位姿和稠密点云,构建出高质量 Mesh。 - * 神经场重建与渲染:NeRF / Instant‑NGP、Gaussian Splatting 及大量改进模型,把场景编码在神经网络或高斯云中,实现高保真的新视角合成与 3D 场景重建,并逐步形成工程化产品。业界也出现了如「混元 3D」「Tripo」这类面向开发者和内容生产的 3D AI 服务,将 NeRF/高斯等技术封装成云端 API 或交互工具。 - -从这一层开始,传统几何与深度学习、隐式表示与显式网格密切交织,既要解决「如何准确还原真实世界」的问题,又要兼顾实时性和可用性,服务更上层的 3D 场景理解、3D 生成与编辑。 - -### 3.1.1 点云处理与 3D 目标检测 - -对于自动驾驶、机器人和高精度测绘而言,LiDAR 点云是最关键的 3D 传感信息之一。点云是一组三维坐标(有时附带反射强度、时间戳等)构成的稀疏点集,没有规则的栅格结构,给传统卷积带来了挑战。点云处理的目标,是从这些非结构化的点中提取有用的几何与语义信息,例如“这里是一辆车”“这里是路沿/地面”“这里是一栋建筑物”。 - -在**点云分类与分割**任务中,我们往往关注:某个点(或点簇)属于哪一类结构,如车、行人、地面、路沿、建筑、植被等,或者对场景做语义/实例分割。从建模方式看,可以粗略分为三类: - -1. 直接点云网络:PointNet / PointNet++、PointCNN、DGCNN 等直接在点集上定义“对点集排列不敏感”的运算,通过局部邻域聚合构建层级特征,适合中小规模点云的分类与分割。 -2. 体素与稀疏卷积:将点云栅格化为 3D 体素,再用稀疏 3D CNN(如 VoxelNet、MinkowskiNet)进行卷积,兼顾结构规整性与空间稀疏性,在自动驾驶 3D 检测中应用广泛。 -3. 投影与多视图:将点云投影到 BEV(鸟瞰图)、前视深度图或多视角视图,再用 2D CNN 提取特征,相对易于与成熟的 2D 检测网络结合。 - -在**3D 目标检测**中,目标不再是单纯地给点打标签,而是要预测 3D 边界框(位置、尺寸、朝向)及其类别,这是自动驾驶环境感知的核心。典型方法如 VoxelNet、SECOND、PointPillars 和 CenterPoint 等,它们通常将点云转换为体素或柱状表示,在 BEV 或 3D 空间上进行检测回归。CenterPoint 等方法通过“中心点检测”范式,直接在 BEV 上检测目标中心及其尺寸/方向,兼具精度和速度。随着深度学习与传感器硬件的演进,3D 检测已能在车规级芯片上实现实时推理,成为自动驾驶感知栈的基础模块之一。 - -### 3.1.2 多视角几何与三维重建:从照片到 Mesh - -如果没有 LiDAR,是否仍能“看懂”3D?答案是可以的——多视角几何与三维重建依赖的是“多张照片 + 摄像机运动”。通过在不同视角拍摄同一场景,我们可以利用几何约束恢复相机位姿和空间结构,这就是经典的 SfM/MVS 管线。 - -**SfM(Structure‑from‑Motion)** 主要解决两个问题: - -1. 从多张成对或多视角图像中,估计每一张图像的相机外参(位置和朝向); -2. 在统一坐标系下恢复一组稀疏 3D 特征点。 - -典型工具如 COLMAP、OpenMVG,通过特征提取与匹配(SIFT/ORB 等)、增量或全局 BA(Bundle Adjustment),可以从无标定图像集合中自动恢复稀疏点云和相机位姿。 - 在此基础上,**MVS(Multi‑View Stereo)** 会利用多视角的光度一致性,生成稠密点云:对每个像素/视线进行深度估计,逐步填充场景的几何细节。 - -获得稠密点云后,下一步是 **网格重建(Mesh Reconstruction)** : - -* 通过 Poisson Surface Reconstruction、Marching Cubes 或基于学习的方法,将散乱的点云“包裹”成连续曲面,形成带拓扑结构的 Mesh。 -* 后续通常还会进行孔洞填补、平滑、边界优化,并进行纹理贴图(Texture Mapping),得到可直接用于渲染和编辑的 3D 模型。 - -在产品形态上,这一整套管线已通过桌面软件、云服务和 SDK 的形式下沉。例如:手机上的 3D 扫描应用,会在后台调用类似 SfM/MVS 的流程,给用户“绕一圈拍照”或“扫一圈视频”之后自动输出一个可导入到游戏引擎的网格模型;数字孪生平台则在城市/园区尺度上,用航摄影像 + 街景数据跑大规模重建,生成可交互的 3D 场景。 - -### 3.1.3 神经辐射场与体渲染:NeRF、Gaussian 与新一代 3D 重建 - -传统的 SfM/MVS/网格重建,可以得到结构良好的显式几何,但在渲染质量、视角连续性和细节表现上仍有局限;而神经辐射场(NeRF)及其后续工作则以**隐式场 + 体渲染**的方式重新定义了 3D 重建和新视角合成。 - -在 NeRF 中,整个 3D 场景被建模为一个连续函数: - -![](https://ecn00p15ubf1.feishu.cn/space/api/box/stream/download/asynccode/?code=ZjYyZTc5MWFhY2QxM2FjNTI1MDFhNDM5NTEwNTBkNGFfM3RvSngwZnhwc1hMRFQxaXVXMkFNem5RSFFqUkppdkdfVG9rZW46TVltUGJUUWRib1NGV2V4dklHZ2NYandjbkJlXzE3NjcxMDU4ODM6MTc2NzEwOTQ4M19WNA) - -给定三维空间中的一个点位置 x 和观察方向 d,网络会输出该点对应的体密度 σ 与颜色 c。沿着相机视线方向对这个映射函数做体渲染积分运算,我们就能得到该相机位姿下的像素颜色;反过来,只要给定一组多视角照片及其相机参数,我们就能通过最小化渲染结果与真实图像的误差,求解出模型的参数 θ。待模型训练完成后,只需改变相机位姿,就能合成那些 “从未被真实拍摄过” 的新视角图像(Novel View Synthesis)。 - -传统 NeRF 训练和渲染速度都偏慢,后续如 **Instant‑NGP** 通过多分辨率哈希网格编码等手段,大幅加快了收敛与推理速度;**Gaussian Splatting** 则用 3D 高斯粒子替代表达场景,通过高效的光栅化策略,实现了高质量、实时的新视角渲染。与此同时,大量工作还围绕 NeRF/高斯做了可编辑、多模态、可组合等扩展,使其逐渐从研究原型走向工程体系。 - -在产品化层面,NeRF/高斯类技术已经嵌入到多种 3D AI 产品中: - -* 手机/PC 端的“多视角视频 → 3D 场景”工具,底层往往基于神经场或高斯粒子完成重建和渲染; -* 游戏/影视资产管线中,利用神经场进行快速场景捕捉和光照还原,再导出为 Mesh + 纹理供传统 DCC 工具使用; -* 各大云厂商和内容平台推出的 3D AI 服务,如腾讯系的「混元 3D」、Tripo 等,通常支持“多视图照片/短视频 → 可编辑 3D 模型/场景”,在内部则综合运用神经辐射场、SDF/Gaussian 表示与后续显式重建,把高质量 3D 结果打包为对开发者友好的 API 或交互式产品。 - -## 3.2 3D 场景理解与定位(3D Scene Understanding & SLAM) - -如果说 3D 感知与重建回答的是“这个世界长什么样”,那么 3D 场景理解与定位则进一步回答:“ **我在这个世界的哪里?这个世界中哪些地方可以走,哪些是障碍?** ” 对于扫地机器人、AGV 机器人、无人机、AR 导航和室内定位系统来说,能够在 3D 环境中自定位、自建图、自主规划路径,是生存的前提。 - -这部分工作主要围绕**3D 语义理解**与**SLAM(Simultaneous Localization and Mapping)**展开:前者在重建的 3D 场景中进行语义分割和可通行区域识别,后者则利用视觉/IMU/LiDAR 等传感器进行相机/机器人位姿估计与地图构建。在工程上,这一层通常以 SDK 或算法模块的形式嵌入到机器人底盘、无人机飞控或移动端 AR 引擎中。 - -* **场景** - * 家用与服务机器人:扫地机器人、送餐/巡检机器人在室内环境中构建地图、识别房间类型和障碍物,实现自动规划清扫或巡逻路径。 - * 仓储与物流:AGV/AMR 机器人在仓库中进行自主导航,识别货架、通道与禁入区域,完成搬运和盘点任务。 - * 无人机与户外机器人:在室外环境中构建 3D 地图,避开建筑、树木、电线等障碍,执行巡检、测绘与安防任务。 - * AR 导航与室内定位:手机/AR 眼镜通过 SLAM 获取相机位姿,并在语义地图上叠加导航箭头、房间信息和 POI,实现沉浸式导览与导航。 -* **原理** - * 3D 语义分割与场景理解:在点云或体素表示上进行语义分割,区分墙壁、地面、桌椅、货架、门窗等结构,同时识别可通行区域和障碍物,为导航和行为决策提供语义层信息。 - * 位姿估计与 SLAM:通过 Visual SLAM(单目/双目 / RGB‑D)或 LiDAR‑SLAM,从连续传感数据中估计相机/机器人的 6D 位姿,处理回环检测与地图优化,必要时融合 IMU、轮速、GNSS 等多源信息提高鲁棒性。 - * 地图构建与导航:在局部/全局地图上叠加几何和语义信息,形成 2D/3D/拓扑/语义地图,并在此基础上进行路径规划、避障和任务分配。 -* **模型** - * SLAM 系统:经典的特征点法 ORB‑SLAM 系列、直接法 DSO,以及融合惯导的 VINS‑Mono / VINS‑Fusion,通过前端特征跟踪 + 后端优化实现精确位姿估计与稠密/半稠密地图。LiDAR/视觉‑LiDAR 融合中常见 LIO‑SAM 等框架。 - * 3D 语义分割网络:3D U‑Net、MinkowskiNet 等 3D CNN,以及基于点云的 PointNet++ / KPConv / SparseConv 系列,用于点云/体素的语义分割与实例分割。 - * 多传感器融合定位:基于图优化或滤波(EKF/UKF)的方法,将视觉、IMU、LiDAR、里程计等多源信息在统一状态空间中融合,提升在恶劣光照、纹理缺失或动态环境中的定位稳定性。 - -整体上,3D 场景理解与定位构成了机器人“能动起来”的基础:既要在复杂三维世界中构建可靠的自我定位框架,又要让地图变得“有意义”,从而支持高层任务规划与人机交互。 - -### 3.2.1 3D 语义分割与可通行区域理解 - -在纯几何地图中,所有结构只是无差别的点/体素;而在真实应用中,我们关心的是:哪里是地面、哪里是墙、哪里有桌子或货架、哪里可以通行。**3D 语义分割**就是要为每一个点或体素赋予语义标签,将“纯几何”转化为“几何 + 语义”。 - -在室内/室外场景中,典型目标包括: - -* 固定结构:墙、地面、天花板、楼梯、柱子、道路、路沿等; -* 家具与设施:桌椅、柜子、货架、门窗、扶手等; -* 可通行/不可通行区域:机器人可行走区域、需绕行的障碍物、禁入区域等。 - -建模上,3D 语义分割常采用: - -* 体素/稀疏卷积方案:把点云体素化后,用 3D U‑Net、MinkowskiNet 等稀疏 CNN 学习体素级特征,兼顾局部细节和全局结构。 -* 点云直接方案:PointNet++、KPConv 等点云网络,对局部邻域做特征聚合,实现点级别的语义预测。 - -在扫地机器人、AGV 机器人等应用中,语义分割的结果会被进一步抽象成 **语义地图** :例如把房间划分为卧室/客厅/厨房,把仓库内空间划分为货架区域/通道/禁行区。机器人不仅知道“哪里可以走”,还可以根据房间类型定制不同策略(如卧室避开地毯区域、仓库中优先覆盖某些货区)。 - -### 3.2.2 位姿估计、SLAM 与多传感器融合定位 - -**SLAM(Simultaneous Localization and Mapping)** 的目标是:在未知环境中,一边移动一边估计自身轨迹,同时构建环境地图。对于没有高精度外部定位(如 RTK‑GNSS)支持的室内环境来说,SLAM 是绝大多数机器人和 AR 引擎的首选方案。 - -在视觉 SLAM 中,以 ORB‑SLAM、DSO、VINS‑Mono/VINS‑Fusion 为代表的方法,通常分为几个关键模块: - -* 前端:从连续图像中提取和跟踪关键点/图像块,估计相邻帧之间的相对位姿。 -* 后端:在滑动窗口或全局图中进行 BA 或图优化,处理漂移、回环检测与重定位。 -* 地图:根据位姿和深度信息构建稠密或半稠密地图,为后续导航或渲染提供基础。 - -纯视觉在纹理缺失、光照剧烈变化时容易失效,因此实践中一般会采用 **多传感器融合定位** : - -* 视觉 + IMU:VINS‑Mono/VINS‑Fusion 等框架将 IMU 的高频短时精度与视觉的尺度和几何约束结合,大幅提高短时和急转弯场景的稳定性。 -* LiDAR + IMU + 视觉:如 LIO‑SAM 等里程计框架在 LiDAR‑SLAM 中引入惯导与可选视觉信息,利用三者互补的特性实现鲁棒定位,在自动驾驶和高精度测绘中广泛使用。 - -在产品层面,这些方法通常被封装为机器人底盘控制器、无人机飞控、AR 引擎(如 ARKit/ARCore 中的 Visual‑Inertial SLAM)或室内定位 SDK 的一部分,对上层应用屏蔽了复杂的状态估计和图优化逻辑,让开发者可以直接拿到“实时位姿 + 地图”。 - -### 3.2.3 语义地图、导航与避障 - -有了稳定的位姿估计和几何/语义地图,下一步是让机器人“聪明地动起来”。这部分主要涉及 **语义地图构建、路径规划和避障** 。 - -* **语义地图构建** :在几何地图上叠加语义信息(房间类型、POI、区域标签),形成适合高层决策的地图表征。例如: -* 家庭场景中,将地图划分为卧室、客厅、厨房、卫生间等区域; -* 仓储场景中,标注货架位置、装卸区、危险区域等; -* 大型商场/展馆中,标注店铺、服务台、洗手间等 POI,用于 AR 导航和导览。 -* **路径规划与避障** :在地图上构建栅格图或拓扑图,利用 A*、D* Lite、RRT 等规划算法为机器人找到从起点到目标点的可行路径;同时结合实时感知(前方障碍物、动态行人/车辆),进行局部重规划和避障,保证运行安全与效率。 -* **导航行为与任务调度** :在 AGV 机器人和无人机中,还会在导航之上叠加任务调度与多机协同模块:分配任务、避免拥堵、优化整体路径与能耗。 - -AR 导航与室内定位系统本质上也依赖类似的语义地图和路径规划,只不过“执行者”从机器人变成了人:系统通过 SLAM 获取用户设备的位姿,在语义地图上规划行走路径,再以增强现实的形式把路径可视化叠加到真实世界视图中。 - -## 3.3 3D 生成与编辑(3D Generation & Editing) - -如果说 3D 感知和 SLAM 是从真实世界“采集并理解”几何,那么 3D 生成与编辑则是站在内容生产的角度: **如何用 AI 自动生产和改造 3D 资产** 。这直接面向游戏、影视、数字人、虚拟空间、电商展示、3D 打印等巨大的内容需求。 - -最近两三年,随着 NeRF/Gaussian、SDF 表示、多模态扩散模型等技术的突破,3D 生成进入快速发展期:从文本、图像、视频一键生成 3D 模型或场景已经成为现实,各大云厂商和创业团队推出了如「混元 3D」、Tripo、DreamFusion / Magic3D 系列方法落地为在线工具,使 3D 生产逐渐向“人人可用”的方向演进。3D 生成与编辑大致可以拆成四类能力:文生 3D、图/视频生 3D、模型优化与编辑,以及绑定与动画。 - -* **场景** - * 游戏 / 影视资产制作:为角色、道具、建筑、场景快速生成可用的 3D 模型,大幅降低美术工作量。 - * 电商与产品展示:根据产品文案或照片自动生成 3D 展示模型,用于 3D 看样、AR 试摆、交互式广告。 - * 数字人与虚拟内容:快速生成虚拟人、虚拟试衣模特、虚拟主播场景等 3D 资产,支持直播、短视频和互动应用。 - * 3D 打印与个性化建模:从草图/照片/文本生成可打印模型,实现个性化礼品、原型设计与教育场景应用。 -* **原理** - * 文生 3D(Text‑to‑3D):将文本描述编码为语义向量,再通过多阶段优化或扩散过程生成 3D 表示(NeRF/SDF/Gaussian/Mesh),通常借助强大的 2D 文生图模型做“评分器”或先验。 - * 图 / 视频生 3D:利用单张或多张图像、多视角视频作为监督,结合 NeRF、SDF 或隐式/显式混合表示,重建出带几何和纹理的 3D 模型。 - * 3D 模型优化与编辑:对已有模型进行重拓扑、简模、细节增强、LOD 生成、UV 展开和贴图生成,以及基于语言/图像的形变与风格化。 - * 绑定与动画:为 3D 角色自动推断骨骼结构并完成 Rigging,支持骨骼动画和物理模拟(布料、软体、刚体),形成可驱动的动态资产。 -* **模型** - * 3D 生成基础表示:NeRF / Instant‑NGP、SDF(隐式表面)、Gaussian Splatting 以及 Mesh‑based 生成网络,构成 3D 数据的表达空间。 - * Text‑to‑3D 方法:DreamFusion、Magic3D、Fantasia3D 等典型路线,通过“2D 文生图模型 + 3D 优化”或“3D 扩散模型”完成从文本到 3D 的端到端生成,为后来的混元 3D、Tripo 等产品奠定技术基础。 - * 图/视频生 3D 模型:基于 NeRF/SDF/Gaussian 的重建与优化框架,从多视图一致性和单视图先验中恢复稳定的 3D 几何与纹理。 - * 绑定与动画算法:自动骨骼提取、骨骼权重预测、基于深度学习的 Retargeting 与运动生成,为虚拟人/角色动画提供一键化工具。 - -在这一层,传统 3D DCC(Maya/Blender/3ds Max 等)与 AI 工具链逐步融合:许多 3D AI 服务以插件或云端接口的形式嵌入现有生产流程,让建模师/美术可以在人机协作中迅速迭代资产。 - -### 3.3.1 文生 3D 与场景草模 - -**文生 3D(Text‑to‑3D)** 的目标是:给出一句自然语言描述,例如“一个卡通风格的黄色小鸭玩具,带有蓝色围巾,适合儿童玩具展示”,系统自动生成一个可编辑的 3D 模型(Mesh/NeRF/SDF/Gaussian 等)。这是将大语言模型/多模态模型与 3D 表示结合的典型应用。 - -典型技术路径包括: - -1. **基于 2D 文生图模型的优化** (如 DreamFusion、Magic3D): -2. 使用强大的 Text‑to‑Image 模型(如扩散模型)作为“评估器”,给定 3D 表示在某一视角下渲染出的图像,评估它与文本描述的匹配程度。 -3. 通过梯度优化或扩散过程,迭代调整 3D 表示(NeRF/SDF/Mesh),使得从多个视角渲染出的图像都符合文本语义。 -4. **3D 扩散模型 / 直接生成** : -5. 将 3D 数据(点云、体素、隐式场参数、Gaussian 粒子等)作为扩散模型的生成目标,在大规模 3D 数据集上预训练; -6. 通过文本条件控制,实现端到端的 Text‑to‑3D 采样。 - -在场景级别,**场景草模**能力允许用户用自然语言或粗略草图描述空间布局,例如“一个带落地窗的客厅,左边一张 L 型沙发,中间一张茶几,右侧有书架和电视柜”,系统自动搭建出一个几何和语义合理的 3D 布局草图。后续可以在 DCC 工具中细化模型与材质,或直接通过混元 3D、Tripo 等工具中的“场景生成”能力快速产出可用的场景原型。 - -当前,多家平台已经推出面向设计师和开发者的 Text‑to‑3D 产品: - -* 「混元 3D」等将文生 3D、多视图生成与重建能力整合进统一界面,支持从文本快速生成角色、道具和场景再导出到游戏引擎; -* Tripo 类产品则强调“多模态输入 + 一键 3D 输出”,支持简单文本和参考图像混合,引导生成满足风格与结构需求的 3D 资产。 - -### 3.3.2 图 / 视频生 3D 与模型优化编辑 - -与纯文本相比,从图像或视频生成 3D 模型对几何约束更强,在视觉上一致性也更好。因此,大量 3D AI 产品支持 **图生 3D / 视频生 3D** : - -* 单张照片 → 粗 3D:利用单视图先验(如人脸、人体、常见物体类别的形状先验),推断大致的 3D 几何,生成可用于预览或简单交互的 3D 模型。 -* 多张照片 / 短视频 → 高质量 3D:综合使用 NeRF/SDF/Gaussian 重建、多视角几何和后处理,将数十张照片或几秒钟视频转换为高保真的 3D 模型,适合游戏/影视资产或高质量电商展示。 - -生成出 3D 几何只是第一步,后续还需要大量**模型优化与编辑**工作: - -* 重拓扑与简模:将隐式场或高多边形 Mesh 转换为结构规整、面数可控的拓扑,以便于绑定、动画和实时渲染。 -* LOD 生成:自动生成多级细节模型(Level of Detail),在远处用低模、近处用高模,兼顾画质与性能。 -* UV 展开与贴图生成:自动为模型展开 UV、生成或优化法线贴图、位移贴图、粗糙度/金属度贴图等 PBR 材质;有些模型还支持从文本或参考图自动生成风格化纹理。 -* 几何与风格编辑:基于语言或示例图进行局部修改,如“让这个椅子腿变短一点”“把这栋楼改成赛博朋克风格”,底层通常通过形状潜空间操作或神经场编辑实现。 - -混元 3D、Tripo 等产品往往将上述流程打通:用户从照片/视频或简单文本出发,系统内部完成重建、重拓扑、贴图与导出,让非专业用户也能在几分钟内获得“即插即用”的 3D 模型,大幅缩短从概念到资产的时间。 - -### 3.3.3 绑定、动画与动态 3D 资产 - -静态模型只是内容的一半,“能动起来”的 3D 资产在游戏、影视、虚拟人和交互应用中更为关键。这涉及**骨骼绑定(Rigging)、权重绘制、动画与物理模拟**等环节,传统上都是高门槛的专业工作,如今也逐渐被 AI 工具辅助甚至半自动完成。 - -* **自动 Rigging** :给定一个角色 Mesh,系统自动推断骨骼层级结构(脊柱、四肢、手指等)和骨骼在模型中的位置,并预测每个顶点相对于各个骨骼的权重。近年来的深度学习方法可以在大规模带骨骼标注的角色数据集上学习这一映射,实现一键骨骼绑定。 -* **动画与动作生成** :在已有骨骼上叠加动作数据(Mocap 或 AI 生成),完成走路、跑步、表情、手势等动画;基于深度学习的动作生成与 Retargeting 可以将视频中的人体动作或其他角色的动作迁移到新角色上。 -* **物理模拟** :对布料、软体、刚体等进行物理模拟,使头发、衣服、旗帜、柔软物体的运动更自然。有些系统利用神经网络加速或近似物理,使实时引擎中的物理效果更逼真。 - -在产品与生态上,这些能力常常内嵌于: - -* 游戏 / 影视资产工具链:为建模师提供一键 Rigging、自动权重分配和基础动作库,大幅减少重复劳动; -* 虚拟人 / 数字资产制作平台:从人物照片或扫描开始,经由 3D 重建 + 自动 Rigging + 动作驱动,输出可在直播、短视频、互动应用中驱动的虚拟人; -* 3D AI 平台(如混元 3D、Tripo 及同类产品):在 3D 生成之后,进一步增加绑定与简单动画功能,让用户“生成的角色可以立刻动起来”,而不需要复杂的 DCC 工具操作。 - -随着 3D 生成与编辑技术的成熟,整个 3D 内容生产流程正在从“以专业 DCC 工具为中心”演化为“AI 驱动的人机协作”:AI 负责生成与大量基础工作,人类更多在风格定义、品控和关键设计节点上做决策。混元 3D、Tripo 等新一代 3D AI 产品正是这一趋势的集中体现,为上层的游戏、影视、AR/VR、数字孪生和虚拟人应用提供了更快、更易用的 3D 基础设施。 - -# 4. 音频(Audio / Speech) - -在整体技术栈中,“音频”对应的是对声学信号的感知与生成:既包括对原始波形和频谱的处理,也包括把语音转为文字、理解“谁在说”“说了什么”,以及进一步对声音、音乐进行创作和合成。与视觉类似,音频也可以被拆成多层:底层的**波形与频谱处理**负责“听清楚”;中层的**语音识别与说话人技术**负责“听懂是谁在说什么”;在此之上,是更抽象的**音频/音乐理解**与 **语音、音乐生成** 。这一整块能力共同支撑了会议实时字幕、语音助手、播客后期修音、智能音箱、声学安防监控、音乐推荐与生成等产品。 - -## 4.1 波形层面音频处理:从“听得清”开始 - -在音频技术的最底层,我们首先关心的并不是“说了什么”“是谁在说”“音乐是什么风格”,而是 **这个声音本身干不干净、听不听得清** 。这一层主要在波形和频谱层面工作,通过重采样、增强、降噪、分离等操作,把嘈杂、失真、混在一起的原始声音加工成更适合后续识别、分析和生成的“干净信号”。可以把它类比到视觉里的“图像增强 + 去噪 +分离前景/背景”,更多是在做声学层面的清理,而不直接处理语义。 - -从产品角度看,这一层几乎“隐身”在所有音频产品背后:会议软件的实时降噪、播客/短视频后期修音、录音笔和手机里的“语音增强模式”、直播平台里的“美声开关”,以及给 ASR/声纹模型做的前端预处理,都是波形层面音频处理的直接体现。下面依旧从 **场景** 、**原理**和**模型**三个角度来梳理,并在后续小节具体展开预处理 & 特征提取、增强与降噪、声源分离三个关键方向。 - -* **场景** - * 在线沟通与会议:Zoom、腾讯会议等在嘈杂办公室、开放工位、家中环境下,实时压制键盘声、敲击声、街噪、回声,让语音更清晰。 - * 内容创作与后期修音:播客、短视频、直播后期中,自动消除底噪、电流声、房间混响,修补录音爆音和频段缺失,提高整体听感。 - * 录音与转写前端:录音笔、智能字幕、会议转写服务在进入 ASR 之前,通过 VAD、降噪、响度归一等处理,提升后端识别鲁棒性。 - * 终端与 IoT:智能音箱、车机、摄像头等设备上的“远场拾音”与“降噪模式”,在复杂声场中尽量捕获到主说话人或关键声源。 -* **原理** - 波形层面处理通常不直接理解语义,而是围绕频谱结构和统计特性做信号优化: - * 在时间域和频率域之间来回变换(如 STFT → 频谱/梅尔频谱 → iSTFT),对噪声频带、混响特征或背景声进行抑制或建模。 - * 通过 VAD 和能量/谱特征,区分“有语音的片段”和“静音/噪声片段”,减少无效片段对后端的影响。 - * 使用深度学习或经典滤波方法估计“干净语音谱”和“噪声谱”的掩码或增益函数,对频谱进行加权,达到增强与降噪的目的。 - * 在多声源混合的场景中,通过端到端分离网络或稀疏表示,将不同说话人、人声与伴奏、前景与背景环境声解混到独立的轨道。 -* **模型** - 波形/频谱层面的模型大致可分为两类:**频谱域模型**和 **时域端到端模型** : - * 频谱/梅尔频谱上的 U‑Net 系列:Spectrogram‑based U‑Net、DCCRN 等,在时–频平面上做“图像式”的卷积与编码–解码,是语音增强、歌声分离等任务的常用方案。 - * 波形端到端模型:Wave‑U‑Net、Conv‑TasNet、Demucs 等,直接在时域波形上建模,避免显式 STFT/ISTFT,往往在主观听感和时域保真度上效果更好。 - * 经典信号处理方法:谱减、Wiener 滤波等传统频域方法,在轻量级设备或对延迟极敏感的场景中仍然广泛存在,常与深度增强网络结合形成“混合方案”。 - -### 4.1.1 预处理与特征提取:为后端“清场搭台” - -任何后续的 ASR、声纹识别、事件检测、TTS 等模型,都需要一个尽量统一、干净、结构化的音频输入,这就是预处理与特征提取层的职责。它负责做最基础却又极其关键的“清场”和“格式统一”,为上游音频模型搭好舞台。 - -在预处理阶段,首先会对采集到的音频做 **采样率转换和声道转换** :比如把 48kHz 立体声转换为 16kHz 单声道,以满足下游模型的输入规格,并降低计算成本。随后,会对响度进行归一化、去直流分量、简单滤波等,使不同设备、不同场景下录得的音频在能量尺度上更加一致。 - -**语音端点检测(VAD)** 则是预处理中的另一个关键环节。它尝试在音频流中自动划分“有语音的片段”和“静音/纯噪声片段”,常基于帧能量、谱熵、零交叉率或小型神经网络判别。VAD 的好处是:可以显著减少送入 ASR/声纹模型的无效数据,降低计算量,同时避免静音段干扰识别(例如误识为长串空格或奇怪字符)。在实时通信中,VAD 还可以驱动“语音活动指示灯”和自动静音逻辑。 - -在特征提取层面,最常见的是将时域波形转为**频谱**或 **梅尔频谱** 。通过短时傅里叶变换(STFT),音频被分解为随时间变化的频率分布;再通过梅尔滤波器组,可以得到更符合人耳感知的梅尔频谱或梅尔倒谱特征(如 log Mel‑spectrogram、MFCC)。这些时–频特征为后续的识别、分离与生成提供了一种“二维表示”,类似视觉里的灰度图或多通道特征图,便于卷积、注意力等结构处理。随着端到端建模的发展,也有越来越多模型直接在波形上学习特征(如 Wav2Vec 2.0 ),但在工程实践中,STFT + 梅尔特征的组合仍然是最普遍、最稳妥的前端。 - -### 4.1.2 增强与降噪:把“糊音”修成“干声” - -在真实环境中,声音几乎总是在噪声和混响中传播:空调声、键盘敲击、路噪、人群嘈杂、房间回声,都在不同程度上降低了语音和音乐的可懂度与主观质量。**语音增强与降噪**的目标,就是在尽量保持语音自然度和完整度的前提下,抑制这些背景干扰,把“糊掉”的声音尽可能修成“干净”的声音。 - -在传统方法中,这一任务主要通过谱减、Wiener 滤波等频域技术实现:先估计噪声谱,然后在频谱上按一定规则“减去”噪声或进行频带增益调整。虽然实现简单、实时性好,但在强噪声、非平稳噪声和复杂混响场景下容易产生明显的“音乐噪声”和伪影。 - -深度学习方法则通过在频谱或波形上学习一个 **映射** :给定带噪语音,预测一个时间–频率掩码或直接预测干净波形。常见方案包括在梅尔/线性频谱上使用 **Spectrogram‑based U‑Net、DCCRN** 等编码–解码结构,对每一帧的频谱进行细致修复;也有直接在时域波形上用 **Conv‑TasNet、Demucs、Wave‑U‑Net** 等模型进行端到端的波形增强。这些方法在语音电话、在线会议、录音修复等场景中,能显著提高语音清晰度和主观听感。 - -在内容创作和后期制作中,“录音修复”往往还涉及减少爆音(plosives)、削减齿音(sibilance)、补偿频段缺失以及均衡(EQ)和动态处理(压缩器/限幅器)等更“音频工程师味”的操作。越来越多的工具将这些传统处理与深度模型结合,提供一键“修音”和“音频美化”能力,服务播客、视频创作者和直播平台。 - -### 4.1.3 声源分离:把“混音”拆开 - -如果说增强与降噪是“让主声更突出、背景更安静”,那么**声源分离**则进一步尝试将混合在一起的多个声源完全拆分成独立轨道。例如:会议录音中多位说话人同时讲话;音乐中人声与伴奏混在一起;环境录音中主事件(如警报、喊叫)掩埋在背景噪声里。声源分离的目标,是从单条或多条混合信号中,恢复出每个独立声源的波形或频谱。 - -在语音领域,**多说话人分离**是一个核心应用:模型需要在没有单独麦克风分轨的情况下,根据声纹、时频结构和说话人特征,将多个重叠语音分到不同通道。这类能力不仅能提升多说话人 ASR 的表现,还可为说话人分离与标注(Diarization)提供更干净的输入。在音乐领域,**人声/伴奏分离(歌声分离)**则可以从一首混音好的歌曲中分离出清晰的人声轨和纯伴奏轨,用于翻唱、Remix、卡拉 OK、音乐分析等。类似地,**环境音/前景声分离**可用于安防与 IoT 场景,从复杂背景中提取关键事件声(如玻璃破碎、冲突声)。 - -在模型层面,声源分离通常采用比普通增强更强的建模能力和更复杂的架构。**Conv‑TasNet、Demucs、Wave‑U‑Net** 等端到端网络可以直接在时域进行多声源分解;在频谱域上,则常见多分支 U‑Net、注意力、掩码估计等结构,分别为不同声源预测专门的掩码或频谱。随着训练数据和计算资源的增长,现代声源分离模型已经能在相当复杂的混响和噪声环境下,输出可用于实际创作与分析的高质量分轨,为直播美声、多说话人会议、音乐制作和音频检索提供了坚实基础。 - -## 4.2 语音识别与说话人技术(ASR & Speaker) - -在波形层面完成了预处理、增强和分离之后,我们终于可以开始问更高层的问题:**“音频里说了什么?”“是谁在说?”“什么时候谁在说?”** 这一层聚焦的是各种围绕语音本身的“理解与标注”任务:自动语音识别(ASR)、说话人识别与验证、说话人分离与标注(Diarization),以及面向交互的热词与关键词检测(KWS)。 - -从产品形态看,这一层是绝大多数“语音产品”的核心:语音输入法、会议转写、客户服务录音分析、智能客服质检、智能音箱和车机语音交互、电话机器人、金融场景声纹验证等,几乎都直接依赖这些技术。它们把前一层“干净的声音”转化为文字序列、说话人标签或关键词事件,是音频到语义世界的最重要桥梁之一。 - -* **场景** - * 自动语音识别(ASR):实时字幕、语音输入法、会议与课堂记录、客服通话转写,为用户提供“听觉到文本”的即时通道。 - * 说话人识别与验证:手机/银行/呼叫中心中的“声纹解锁”“声纹验证”,以及在海量录音中检索某一特定说话人。 - * 说话人分离与标注(Diarization):在会议、访谈、圆桌讨论中,自动回答“谁在什么时候说话”,实现“分说话人转写”。 - * 热词与关键词检测(KWS):智能音箱/车机唤醒词检测(“Hey Siri”“OK Google”),以及在客服录音、质检中捕捉关键短语(如“投诉”“退款”“要升级”等)。 -* **原理** - 这一层的大部分任务都可以被统一视为对音频序列进行 **时间对齐与序列标注** : - * ASR:给定一段语音,学习从声学特征到文本序列的映射,常使用 CTC、RNN‑Transducer(RNN‑T)或基于注意力的端到端结构;现代模型多采用大规模预训练(如 Wav2Vec 2.0、Whisper 等)再微调。 - * 说话人识别:从音频中提取一个固定维度的 **说话人嵌入** (speaker embedding,如 x‑vector、ECAPA‑TDNN),在这个嵌入空间中,同一人的语音彼此接近,不同人的语音彼此远离,再结合度量或分类模型完成识别与验证。 - * 说话人分离与标注(Diarization):综合利用声纹嵌入、VAD、分段聚类或端到端网络(EEND),为每一段时间片分配说话人标签,从而拼出“时间轴上的多说话人时间线”。 - * KWS:在连续音频流上进行低延迟的小模型检测,对预定义的唤醒词或关键词进行局部模式匹配和置信度评估,兼顾低算力与高召回。 -* **模型** - ASR 与说话人技术的模型谱系既包括端到端架构,也包括专门的嵌入模型与聚类方法: - * ASR:Wav2Vec 2.0、Conformer、Whisper、RNN‑T、Citrinet 等,大多采用卷积 + 自注意力或纯自注意力结构,支持多语种、大词表和长上下文。 - * 说话人嵌入:ECAPA‑TDNN、x‑vector、i‑vector 等,通过对大量说话人数据进行分类训练或度量学习,得到稳健的说话人特征空间。 - * Diarization:从 VAD + 分段 + 聚类的传统流程,到 End‑to‑End Diarization(EEND)这类直接输出“时刻 × 说话人”矩阵的端到端方法。 - * 热词/关键词检测:轻量级 CNN/RNN/Transformer 前端组合 CTC 或门控机制,嵌入在设备本地,以超低算力、低延迟实现常开监听。 - -### 4.2.1 自动语音识别(ASR):把“声音”变成“文字” - - **自动语音识别(ASR)是“音频→文本”的主通路:无论是语音输入法,还是会议转写、智能字幕、客服录音分析,第一步都是要把用户说的话准确地转成文字。现代 ASR 系统多采用端到端架构** :从声学特征(如梅尔频谱或直接波形)出发,经过一系列深度网络(如 Conformer、Citrinet、基于 Transformer 的 Encoder),直接输出文字序列或对应的 token 序列。 - -在建模上,ASR 的难点主要包括长时依赖、多语种与方言、口音变化、重叠语音、背景噪声以及领域内专有名词。为此,当前主流方向是利用大规模无标注音频做自监督预训练(如 Wav2Vec 2.0、HuBERT),或在多语种、多任务数据上做大规模监督训练(如 Whisper),再通过相对少量的领域数据进行微调,从而在不同语言、口音和场景下达到较好的鲁棒性。 - -在产品层面,ASR 通常被打包为“语音输入法 SDK”“云端语音识别 API”“会议转写服务”等能力输出:前端可以是实时流式识别(RNN‑T、流式 Transformer 等),后端可通过热词注入、自定义词表、上下文约束来强化对特定人名、地名、品牌名和业务术语的识别。这些识别结果往往是后续 NLP、对话系统和数据分析的基础。 - -### 4.2.2 说话人识别与分离标注:回答“是谁”与“何时在说话” - -与“说了什么”相比,**“是谁在说”在很多应用中同样重要:金融、政务、客服、安防等场景需要通过声纹识别**来验证身份或排查风险;而会议与访谈场景则需要知道“每一句是谁说的”,以支持分说话人转写、发言统计和行为分析。 - -在**说话人识别/验证(Speaker Recognition)** 任务中,系统的目标是:给定一段语音,判断说话人是谁,或者判断是否与某个注册说话人属于同一人。现代系统通常通过 ECAPA‑TDNN、x‑vector 等模型,从语音段中提取一个固定维度的说话人嵌入向量。在训练阶段,以说话人分类与度量学习的组合,保证同一人的嵌入更为聚集、不同人之间的嵌入距离更大;在推理阶段,再采取最近邻或后端判别器(如 PLDA、Cosine scoring with margin)进行验证与识别。这样,系统就能在电话、麦克风、噪声环境下,以一定置信度回答“是不是同一个人”。 - -**说话人分离与标注(Diarization)** 则进一步回答“谁在什么时候说话”。传统方案通常包含三个步骤:先用 VAD 找出有语音的片段,再将长音频切成短 segments,为每个 segment 提取说话人嵌入,最后在嵌入空间中做聚类和时间拼接,得到一条多说话人时间轴。更先进的 **End‑to‑End Diarization (EEND)** 类方法则尝试直接从音频特征输出“时间 × 说话人”布尔矩阵,端到端学习重叠语音、说话人切换等复杂模式。Diarization 在会议、访谈节目、法庭记录、电话客服等场景中极具价值,常与 ASR 结合形成“带说话人标签的文字记录”。 - -### 4.2.3 热词与关键词检测:面向交互和监控的“耳朵” - -在持续的音频流中,不是每一秒都值得被完整识别和存储。**热词与关键词检测(KWS)**的角色,就是一个始终在线的“守门员”: - -* 在智能音箱、车机、手机助手中,KWS 模块负责检测唤醒词(如“Hey Siri”“OK Google”“小爱同学”),一旦检测到唤醒词,就把音频流交给更昂贵的 ASR 与对话系统处理。 -* 在智能客服、质检和合规场景中,KWS 会对录音或实时通话中出现的关键短语(如“投诉”“退货”“维权”“欺诈”)进行标记和告警,为后端分析和质检策略提供触发点。 - -在技术实现上,KWS 通常需要在**极低算力和低延迟**的约束下运行,尤其是本地设备上的唤醒词检测:模型往往是一个小型 CNN/RNN/Transformer 前端,接 CTC 或门控判别头,对特定词的声学模式进行检测,并利用滑动窗口和置信度平滑避免误唤醒。对于关键词质检场景,则可以采用更强的 ASR + 关键词匹配/正则 + 统计分析,或者直接训练端到端关键词 tagging 模型。无论哪种形态,KWS 本质上是在语音流上加了一层“事件级”的语义筛选,是连接音频世界与交互逻辑的重要接口。 - -## 4.3 音频/音乐理解(Audio Event & Music Understanding) - -并非所有音频都以“语音”为中心。现实中有大量与环境声、事件声、音乐相关的场景,它们更关注的是:**“发生了什么声音事件?”“当前环境是什么声景?”“这首歌是什么风格、用了哪些乐器、节奏和调是什么?”** 这部分能力统称为音频/音乐理解,主要围绕声音事件检测、环境/场景分类和音乐属性理解展开。 - -从产品视角看,音频理解技术支撑了安防声学监控、IoT 声学传感器、智能设备的环境自适应、音乐推荐与分类、音乐版权识别、音乐检索和创作辅助等广泛应用。与图像中的“图像分类 + 细粒度分类”类似,这一层把原本连续、复杂的声音空间结构化成离散的事件标签、多维属性向量和风格描述。 - -* **场景** - * 声音事件检测:检测警报声、玻璃破碎、婴儿哭声、撞击声等,用于安防监控、智慧楼宇、车辆安全系统和工业告警。 - * 环境/场景分类:识别“室内/室外”“办公室/车内/街道/地铁”等声景,为智能设备的降噪策略、自适应增益、模式切换提供依据。 - * 音乐理解与音乐信息检索(MIR):曲风分类、乐器识别、节奏与调性分析,支撑音乐推荐、歌单生成、音乐检索、版权识别和创作助手。 -* **原理** - 音频/音乐理解大多基于**时–频特征 + 深度神经网络**进行分类或多标签标注: - * 使用 log Mel‑spectrogram 等特征,将音频转化为“声学图像”,再利用 CNN、CRNN 或 Transformer 等结构进行时–频模式识别。 - * 对于声音事件检测,往往采用多标签、多时序输出,对每种事件在时间轴上进行存在性预测,有时还会结合弱监督标签和多实例学习。 - * 对环境/场景分类,则更注重长时间统计特征和背景格局,往往需要在较长窗口上建模。 - * 音乐理解任务则结合音乐理论知识,对节奏(BPM)、拍点、调性、和弦和结构进行建模,部分任务通过自监督或对比学习预训练音乐嵌入,再做下游微调。 -* **模型** - 常见的音频理解模型多在公开数据集(如 AudioSet)上预训练,再迁移到具体任务: - * VGGish、YAMNet、PANNs 等 CNN/CRNN 模型,在大规模有声数据上预训练后,可用于多种音频事件与声景任务。 - * AST(Audio Spectrogram Transformer)等 Transformer‑based 模型,直接在频谱图上使用自注意力,获得更强的全局时–频建模能力。 - * 针对音乐的 MusicTagging / MIR 模型,会在百万级歌曲上预训练标签模型或嵌入模型,用于风格/情感/乐器标签、音乐检索和推荐。 - -### 4.3.1 声音事件与环境声景:让设备“听得懂环境” - -在安防、IoT、智慧城市、车载系统中,光靠摄像头并不足以全面理解环境状态。**声音事件检测**的目标,就是让系统“听得懂”关键事件:当发生玻璃破碎、警报拉响、婴儿哭泣、碰撞、尖叫、打斗、破坏行为时,系统能够在音频信号中识别并发出告警。与语音识别不同,这类事件往往是短促、非语言的,频率范围和能量形态各异,且可能和背景噪声高度重叠。 - -**环境/场景分类**则更关注持续性的声景(acoustic scene):是安静办公室、热闹街道、车内、高铁站还是咖啡馆?系统可以根据声景自动调整降噪强度、回声抵消参数、麦克风阵列波束指向,甚至改变交互策略(例如在车内通过更简短的反馈交互,在嘈杂街道上提高输出音量)。在 IoT 场景中,多个声音传感器组成的“声学网络”可用于对环境状态进行长期监控和统计分析。 - -在技术实现上,这两类任务都大多采用**多标签分类 + 时序建模**方案:将音频转换为梅尔频谱,使用 VGGish、PANNs、AST 或类似模型进行特征抽取,再用时序池化或序列模型输出每个标签在时间轴上的激活情况。由于很多数据集只提供“片段级标签”(weak labels),模型常需通过多实例学习、自注意力池化等方式,在弱监督下学习事件的时间定位。 - -### 4.3.2 音乐理解与标签:从“歌单标签”到“结构分析” - -在音乐领域,音频理解的目标不仅仅是“这是一首什么歌”,更是要回答:**“这首歌什么风格?用到了哪些乐器?节奏快慢如何?调性与大致和声结构是什么?”** 这些信息一方面支撑音乐推荐与歌单编排,另一方面也为创作者和生成模型提供结构化“音乐元数据”。 - -**曲风分类**任务会根据歌曲整体声学特征与结构,将其归入流行、摇滚、古典、嘻哈、电子、Lo‑Fi 等不同风格;**乐器识别**则在时–频特征上区分鼓、贝斯、吉他、钢琴、弦乐等不同乐器的声学指纹,可用于乐器统计、音乐检索和混音分析。**节奏/调性分析**则是对 BPM、拍点位置、拍号、主调(Key)等进行估计,为节奏匹配、自动和声、DJ 混音、游戏音轨同步等任务提供基础。 - -在模型上,音乐理解多沿用通用音频模型(如 PANNs、AST),但也有大量专门面向音乐信息检索(MIR)的模型与预训练嵌入。典型做法是在大规模音乐数据集上进行 **多标签音乐标签学习** (genre、mood、instrument、era 等),得到音乐嵌入空间,再在上述具体任务上微调或做零样本推断。结合这些模型,音乐平台可以更智能地完成音乐分类与推荐,版权平台可以强化音乐指纹与相似性检索,而创作工具则可以利用这些理解能力,为用户推荐合适的伴奏、扩展相似风格或自动生成音乐结构。 - -## 4.4 语音与音频生成(TTS / VC / Music Generation) - -在完成了对音频的“清理”“识别”和“理解”之后,下一层自然的问题是:**“我们能否直接让机器‘说话’、‘唱歌’甚至‘作曲’?”** 这就是语音与音频生成的世界:从文本到语音(TTS),从一种声音到另一种声音(VC / Voice Cloning),到更大范围的音乐与音效生成,再到可以演唱歌词和旋律的歌声合成。与图像生成类似,这一层不再只是在已有数据上打标签或提取结构,而是主动“创造”新的声音内容。 - -在产品层面,这一层能力已经渗透到各类应用:OpenAI TTS、ElevenLabs、火山引擎、minimax等语音产品线为应用提供高质量合成语音;Suno、Udio 等音乐生成平台为创作者甚至普通用户提供从文案到完整音乐的能力;游戏、视频、虚拟主播和数字人依赖这些模型进行配音和歌唱,极大降低了内容制作的门槛。 - -* **场景** - * 文本转语音(TTS):新闻播报、导航播报、智能客服语音回复、学习类 App 朗读内容、无障碍读屏等,需要将任意文本转换为自然、清晰、可控的语音。 - * 语音转换 / 语音克隆(VC / Voice Cloning):在保持语义和韵律的前提下,改变说话人音色,实现“换声说话”或“少样本声纹克隆”(在严格合规条件下)。 - * 音乐与音效生成:为短视频、游戏、广告、播客等生成合适的背景音乐与音效(环境声、UI 声效、过场音)。 - * 歌声合成与翻唱:给定旋律与歌词,让虚拟歌手演唱,或在合规前提下生成某种风格/音色的翻唱版本。 -* **原理** - 语音与音频生成通常采用**“高层表示 → 低层波形”** 的分层建模思路: - * TTS 中,先将文本转为音素/音节/字级序列,再通过序列到声学特征(如梅尔谱)的模型(Tacotron、FastSpeech、VITS 等),最后用神经声码器(WaveNet、WaveRNN、HiFi‑GAN 等)从特征生成高保真波形。 - * Voice Conversion 中,通过解耦“说什么(内容)”与“谁在说(音色)”,从源语音提取内容表示,再与目标说话人嵌入或声码条件结合,生成新的语音波形。 - * 音乐与音效生成可基于 token 化的表示(如音符、MIDI、编码后的频谱/codec token),采用自回归、扩散(Diffusion)或神经 codec 生成模型,从文本、参考音频或结构参数中采样出新音频。 - * 歌声合成在 TTS 的基础上引入更精细的韵律、音高轨迹和歌唱控制,通常对音高、时值、连音、颤音等有显式或隐式建模。 -* **模型** - 当前语音与音频生成的主流技术路线包括: - * TTS:Tacotron / Tacotron2、FastSpeech 系列(非自回归 TTS)、VITS 等负责从文本到梅尔谱或 codec token;WaveNet、WaveRNN、HiFi‑GAN、WaveGlow 等作为 vocoder 或解码器负责从特征到波形。最近的 Diffusion‑based TTS 和 Neural Codec 模型在自然度和多样性上进一步提升。 - * Voice Conversion / Cloning:基于 speaker embedding + content encoder 的 VC 框架,以及利用神经 codec 的语音转换模型,支持少样本音色克隆和跨语言说话人迁移。这类技术目前已被多家平台商用落地,提供便捷的语音克隆调用服务,国内常见平台包括火山引擎、minimax、科大讯飞开放平台、百度智能云千帆大模型平台、阿里云智能语音交互平台等;海外则有 ElevenLabs、Resemble.ai、Play.ht 等主流平台。其中,火山引擎的语音克隆能力支持少量音频样本快速训练,适配智能客服、有声读物等多场景的商用调用;minimax 则依托其大模型技术优势,实现了克隆音色与文本内容的自然适配,同时支持跨语言的说话人音色迁移;科大讯飞开放平台的语音克隆在中文发音的清晰度和情感表现力上具备显著优势,广泛服务于教育、广电等领域。 - * 音乐与音效生成:MusicLM、MusicGen、以及 Suno / Udio 类模型,通常基于文本和/或参考音频条件,使用自回归或扩散架构在离散 codec token 上生成长时音频。 - -### 4.4.1 文本转语音(TTS):让机器“自然开口说话” - -**文本转语音(TTS)**是最直观的语音生成任务:输入一段文本,输出一段自然流畅的语音,理想状态下可以与人声几乎难以区分。现代 TTS 系统通常分为两个主要阶段:文本到声学特征(如梅尔频谱),以及声学特征到波形。 - -在第一个阶段,模型需要处理分词、音素化、多音字消歧、标点与停顿、韵律预测等问题。典型模型包括基于注意力的 Tacotron 系列和基于长度预测的 FastSpeech 系列,后者通过非自回归架构显著加速合成、提升稳定性。近年来,VITS 等端到端模型将声学建模和声码器融合在一个统一框架中,进一步简化了系统。 - -在第二个阶段,神经声码器(Neural Vocoder)如 WaveNet、WaveRNN、HiFi‑GAN、WaveGlow 等负责将梅尔谱或其他中间表示转换为高保真波形。训练良好的声码器不仅可以生成自然清晰的语音,还能很好地还原不同音色、情感和风格。现代 TTS 系统还支持 **多说话人建模** (通过 speaker embedding)、音色/语速/情绪控制(如“兴奋”“平静”“播音腔”),以及跨语种 TTS,为各类应用提供高度定制化的声音能力。 - -### 4.4.2 语音转换与声纹克隆:改变“谁在说” - -在很多创作和辅助场景中,我们希望在**不改变内容与韵律**的前提下,改变说话人的音色或风格,这就是**语音转换(VC)**和**语音克隆(Voice Cloning)**的任务。前者主要解决“把 A 的话变成 B 的声音”;后者则进一步强调“少样本甚至几句语音就能学到新的音色”。 - -技术上,VC 通常采用“内容–音色解耦”的思路:通过一个内容编码器提取说话内容与韵律信息(可以是基于 ASR 的离散单位,也可以是自监督的连续表示),再通过一个条件生成器结合目标说话人嵌入或 codec 条件,生成目标音色但语义与节奏基本不变的新语音。如引入神经 codec,则可以在编解码空间直接编辑语音,实现高保真转换。 - -**语音克隆**在 VC 的基础上强调少样本与泛化能力:模型需要从几个样本甚至几秒音频中提取稳定的说话人表示,并据此生成风格一致、音色接近的合成语音。这一能力在虚拟人设、个性化助手、游戏角色定制、配音加速等方面非常有用,但也需要严格遵守法律与伦理规范,确保只在合规授权、充分知情和安全控制的前提下使用,避免滥用或身份冒充风险。 - -### 4.4.3 音乐与音效生成:从提示到完整声景 - -相比语音生成,**音乐与音效生成**在结构与时间尺度上更为复杂:音乐往往持续时间更长,内部结构(段落、旋律、和声、节奏)更加丰富;音效则种类繁多,从自然环境(雨声、风声、海浪)到拟声(UI 点击、提示音、游戏技能音效)都有各自模式。近年来,基于神经 codec、序列建模和扩散的模型使得“从文本生成完整音乐/音效”成为现实。 - -在音乐生成中,像 MusicLM、MusicGen、Suno、Udio 等模型通常将音频编码为离散的 codec token 序列,再在这一离散空间上训练文本条件或多模态条件的生成模型。用户只需提供一段文本描述(如“节奏适中、温暖治愈的 Lo‑Fi 背景音乐,适合学习专注”“紧张的电子管弦配乐,适合科幻预告片”),或上传一段参考音乐片段,模型就能生成长度达几十秒甚至数分钟的高质量音乐。对于创作者,这既是灵感来源,也是快速打样和背景音乐生成的利器。 - -在音效生成上,类似的技术可以根据文本提示生成 UI 声效、通知音、游戏环境声等,帮助产品与游戏团队快速迭代声音设计。结合前一层的音频理解能力,还可以做到风格对齐与场景自适应,例如根据画面或游戏关卡自动匹配音效风格。 - -无论是语音还是音乐与音效生成,这一层能力都在快速演进:从早期合成味浓重的机器音,到现在与人声、专业音乐难以区分的高保真内容。与此同时,围绕版权、合规、溯源和可控性的问题也变得尤为重要——如何在提供强大创作工具的同时,保护创作者和使用者的合法权益,将是这一层技术持续需要面对的关键议题。 - -# 5. 视频(Video) - -在多模态 AI 体系中,**视频模态**负责理解和生成“随时间变化的视觉信号”。相比单帧图像,视频不仅包含空间维度上的纹理、形状和布局信息,还携带丰富的 **时间维度线索** :动作的起落、物体的运动轨迹、镜头的切换节奏等。无论是安防监控中的行为识别、体育训练中的动作分析,还是短视频平台的一键剪辑、长视频的智能解析,本质上都依赖于一整套围绕“帧序列”展开的理解与生成能力。 - -从工程视角看,视频能力大体可以分为几层:**底层的视频增强与复原**负责保证“能看清”;**视频理解与结构分析**负责回答“发生了什么”;在此基础上,**视频 + 语言多模态任务**将视频内容转化为文本可用的结构化描述和检索接口;进一步的,**视频生成与编辑**则反过来从文本或示例视频出发,用可控的方式生成或重组视频内容;而以**数字人 / 虚拟人**为代表的一类应用,则将语音、语言、动作和视频渲染综合在一起,构成面向交互与内容生产的新形态。 - -下面我们同样从分层能力出发,对视频相关能力进行梳理。 - -## 5.1 传统视频处理:从“能播”到“好看、好用” - -在视频技术的最底层,我们首先关心的,并不是“画面里是谁”“发生了什么事件”,而是这段视频本身是否稳定、清晰、舒适:画面抖不抖、糊不糊、噪点多不多、比例是否适合目标终端播放。**传统视频处理**这一层,主要在帧序列和时空像素层面工作,通过增强、修复、超分辨率、插帧和重定帧等操作,把嘈杂、抖动、分辨率不足或比例不合适的原始视频,转换为更适合观看和后续分析的“高质量时序信号”。可以把它类比为图像模态中的“图像复原与增强 + 几何校正”,只不过这里额外引入了时间维度上的平滑与一致性。 - -从产品角度看,这一层能力几乎“隐身”在所有视频产品背后:剪辑软件的一键画质增强、短视频平台的自动画质升级、电视盒子和播放器的智能超分与插帧、老影片修复服务,以及给上游检测/识别模型做的多帧预处理,都是传统视频处理的直接体现。下面依然从 **场景** 、**原理**和**模型**三个角度来梳理,并在后续小节中展开视频增强与修复、超分与插帧几个关键方向。 - -* **场景** - 在线视频平台、剪辑工具、监控系统和终端设备中,传统视频处理主要出现在以下典型场景: - * 内容平台与剪辑工具:短视频、长视频在上传或编辑时,通过一键画质增强、稳像、防抖、降噪,让用户“拿起手机就能拍、拍完就能用”;老视频素材在导入剪辑工程时,通过修复和补帧,使其与新素材在观感上更一致。 - * 影视与老影片修复:对历史胶片、早期电视节目和标清素材进行数字修复,去除划痕、噪点和抖动,恢复色彩和细节,为重映、再发行和数字档案保存提供更高质量的版本。 - * 视频监控与行车记录:对弱光、雨雾、压缩严重的监控画面进行降噪、去雾、增强对比度和稳像,提升后续检测和识别模块的鲁棒性,便于取证和溯源。 - * 终端播放与设备侧增强:电视、机顶盒、手机播放器本地集成超分和插帧功能,将存量的 720p/1080p、24/30fps 内容在播放端“升级”为近似 4K、60/120fps 的视觉效果。 - * 多终端适配与分发:为同时覆盖手机竖屏、平板横屏和大屏电视,对同一视频进行横竖屏适配、智能裁剪和多比例重定帧,减少手工剪辑和多版本维护成本。 -* **原理** - 传统视频处理通常不直接理解语义类别,而是围绕画质、稳定性和时间一致性在时空信号层面做建模和优化: - * 时空联合建模:在单帧图像增强的基础上,引入时间维度的信息,通过光流估计、相机运动建模或时空卷积,把前后帧作为额外“观测”,在时间轴上做多帧融合与噪声抑制。 - * 稳像与防抖:将相机抖动建模为一段时间上的几何变换序列(平移、旋转、缩放等),通过估计全局或局部运动轨迹,将其平滑后重新投影到输出视频中,从而达到去抖和稳定的效果。 - * 视频超分与插帧:视频超分通过多帧对齐和细节重建,在提升空间分辨率的同时保持时间一致性;插帧则通过光流估计或时空生成网络,在两帧之间合成中间帧,用更高帧率呈现运动,提高流畅度。 - * 重定帧与自动构图:通过检测和追踪视频中的主体(人物、物体),在时间轴上估计主体轨迹,再结合目标分辨率的长宽比,为每一帧选择合适的裁剪窗口,并对裁剪窗口的运动进行时间平滑,保证观感自然。 - * 质量与效率权衡:在云端离线处理可以追求最优画质和复杂模型,而在手机、播放器和实时场景中则需要控制模型参数量、计算复杂度和延迟,在算法结构和推理框架上做精细折中。 -* **模型** - 在具体实现上,传统视频处理综合使用经典视频信号处理方法和深度学习模型,在效果、效率与部署形态之间寻找平衡: - * 经典视频处理方法:基于光流的稳像与插帧、时域滤波与多帧融合、基于块匹配的去噪和去压缩伪影等,仍然广泛应用于算力受限或对可解释性有要求的场景。 - * 深度视频复原与增强模型:以 EDVR、BasicVSR / BasicVSR++、Real‑ESRGAN 视频版等为代表的多帧超分与增强网络,通过对齐与时空特征聚合,在去噪、去模糊、细节恢复和去压缩伪影方面显著优于传统方法。 - * 深度插帧模型:如 DAIN、RIFE、FILM 等插帧网络,通过显式或隐式光流估计与中间特征融合生成中间帧,相比传统光流 + 重采样方法在复杂运动和遮挡场景中更稳定。 - * 基于 Transformer 的视频复原:利用时空注意力统一处理空间纹理与时间依赖,在复杂镜头运动、多物体场景下具备更强的建模能力,同时在推理时通过稀疏注意力、滑动窗口等机制控制计算量。 - * 实际产品与系统:剪映 / CapCut 的智能增强、Topaz Video Enhance 等商用增强软件,B 站及各短视频平台的画质增强管线、老影片修复 SaaS 服务等,通常会将多种模型与策略级联,按素材类型和终端条件动态选择最优处理路径。 - -综合来看,这一层更多是在“语义之前”为视频打好物理与感知基础:既帮助用户获得更舒适的观感,也为上游检测、识别和生成模型提供更干净、更稳定的输入。下面,我们分别从 **视频增强与修复** 、**超分辨率与插帧等**子方向展开。 - -### 5.1.1 视频增强与修复:把“能看”打磨到“好看” - -在真实拍摄条件下,视频往往并不“干净”:手持设备造成的剧烈抖动、弱光下的高噪点和涂抹感、网络压缩带来的块状伪影和色带、老旧设备录制的褪色和划痕,都让视频质量明显低于理想状态。视频增强与修复的目标,就是在不改变视频语义内容的前提下,最大程度恢复稳定、清晰、自然的观感,把“勉强能看”的素材打磨到“看起来顺眼甚至好看”的水准。 - -在时域上,增强与修复首先要解决的是稳定性问题。通过对连续帧进行特征匹配或光流估计,可以分离出全局相机运动和局部物体运动,再利用平滑后的相机轨迹重新渲染输出帧,从而抑制快速抖动与微小晃动,避免观众在观看过程中产生眩晕感。在此基础上,画面级的去噪、去模糊和去伪影则更多集中在空间–时间联合建模:多帧联合去噪利用前后帧冗余信息,在时间方向上进行类似“多曝光融合”的处理,在保留细节纹理的同时有效抑制高 ISO 噪声和压缩噪声;对轻微运动模糊,则通过估计模糊核或使用端到端深度网络,在帧序列上进行反卷积式的清晰化处理,使静态背景和运动主体都更锐利。 - -对于老影片和低质量素材,修复还涉及色彩和结构层面的“重建”。胶片老化会导致画面泛黄、对比度下降、局部划痕和污点显著,早期数字视频则常见分辨率低、压缩严重和边缘锯齿等问题。现代修复流程往往采用多步协同:先利用检测和分割模型定位划痕、污点等局部损坏区域,再通过时空补全网络在邻近帧和邻近空间像素中“借料填坑”;同时进行色彩还原和对比度重塑,使整体色调接近原始拍摄或设定的风格参考。对于严重压缩的视频,还会引入针对块效应和振铃伪影的专用去伪影网络,在不过度平滑的前提下改善边缘和细节。 - -这些增强与修复能力在产品中的体现往往是“一键式”的:用户只需勾选“稳像”“画质增强”或“老视频修复”,系统便会在后台自动选择合适的模型和参数组合,对视频帧序列做多阶段处理。对业务而言,这一层既直接决定了观众对画质的主观评价,也间接影响上游分析模型的表现:更干净、更稳定的视频输入,往往意味着更可靠的人脸/车牌识别、更准确的行为检测和更少的误报。 - -### 5.1.2 超分辨率与插帧:从“能看清”到“更流畅” - -在显示设备不断升级、用户对细节和流畅度要求不断提高的背景下,大量存量视频内容在分辨率和帧率上显得“先天不足”:1080p 在 4K 屏幕上显得不够锐利,24/30fps 在大屏和快速运动场景中容易出现拖影或卡顿感。超分辨率与插帧技术正是为了解决这两个问题:前者在空间维度上“补细节”,后者在时间维度上“补过程”,共同把“勉强能看清”的视频提升为“细节丰富、播放顺滑”的观感。 - -视频超分辨率相比单帧图像超分多了一个关键维度:时间。简单的逐帧放大容易导致相邻帧细节不一致,出现闪烁和纹理抖动。因此,主流方法都会利用前后多帧的信息,通过光流估计或特征级对齐,将邻近帧中的细节对齐到目标帧上,再在对齐后进行细节重建。像 EDVR、BasicVSR / BasicVSR++、Real‑ESRGAN 视频版等模型,会先在特征空间对多帧进行对齐和聚合,再用深度网络推断高分辨率细节,避免简单插值带来的“糊”和“塑料感”。在这一过程中,如何在“物理合理”和“感官好看”之间平衡,是损失设计和训练策略的核心:既要提升客观指标(如 PSNR、SSIM),也要保证主观观感自然,没有过度锐化和伪细节。 - -插帧则聚焦在时间轴上的“补帧”。传统方法依赖光流估计,先预测前后两帧之间每个像素的运动,再按照一定规则在中间位置插值生成新帧。然而在快速运动、多物体遮挡或纹理复杂区域,光流往往不够准确,容易出现拖影、重影或局部形变。深度插帧模型如 DAIN、RIFE、FILM 等,通过端到端网络同时学习光流、深度或中间特征的融合策略,直接输出插值帧,在复杂场景下的稳定性和视觉质量明显提升。对于体育赛事、动作游戏录屏和慢动作创作,插帧可以将 24/30fps 的原始视频平滑提升到 60/120fps,既保留运动细节,又减少卡顿和残影。 - -在工程实践中,超分和插帧常常结合使用:对低分辨率、低帧率的存量内容先做时序插帧,再进行空间超分,或两者在统一的时空网络中一体化实现。部署形态上,云端离线处理适合对画质要求极高的影视修复和平台级“画质升级”服务,而端侧实时推理则更多见于电视盒子、播放器 App 和游戏/运动相机中,需要通过模型压缩和硬件加速保证低延迟。无论以何种形态呈现,超分与插帧已经成为“高清/超高清体验”的重要基建,使旧内容在新终端上焕发“第二春”。 - -## 5.2 视频理解与结构分析(Video Understanding) - -如果说传统视频处理更多停留在“画质与稳定性”层面,那么**视频理解与结构分析**则开始回答“视频里在发生什么”这一类语义问题:谁在做什么、在哪里做、持续了多久、是否存在异常行为等。这里的目标,是在时间轴上对视频进行结构化拆解:识别动作与行为、检测与跟踪目标、分割前景与背景、划分场景与镜头,并抽取出可供下游决策、检索与告警使用的高层语义信号。 - -从产品视角看,这一层能力已经深入到各类智慧安防平台、运动训练分析系统、智能行车记录仪和工业质检视频分析系统中:在监控中识别打架、摔倒、徘徊等异常;在体育和健身场景中分析动作规范性和技术细节;在交通与工业环境下追踪车辆和人员轨迹、监控生产流程是否正常。下面依然从 **场景** 、**原理**和**模型**三个角度梳理这类能力,并在后续小节中重点展开几个代表性方向。 - -* **场景** - * 安防与公共安全:在城市监控、园区和楼宇中,识别打架、摔倒、聚集、奔跑、翻越围栏等行为,对徘徊、深夜逗留等异常模式提前告警。 - * 交通与出行:对行人、车辆、自行车在路口、隧道和高速上的轨迹进行检测和追踪,分析闯红灯、逆行、占道、超速等行为,为交管和事故溯源提供依据。 - * 体育与运动训练:分析篮球投篮、网球发球、瑜伽体式等动作的关键阶段与姿态质量,为运动员和大众用户提供技术分析和纠错建议。 - * 工业生产与质检:监控生产线上的作业步骤是否规范,检测装配过程中是否存在漏装、错装或异常动作,为安全生产和良率提升提供基础数据。 - * 内容结构化与检索:对长视频进行镜头拆分、场景分类和重要片段标记,为后续检索、推荐和剪辑提供结构化索引。 -* **原理** - 视频理解与结构分析的关键,是在时间维度上对空间目标和语义进行联合建模: - * 动作识别与行为分析:基于 2D/3D 卷积、时序池化或 Transformer,对一段视频片段进行整体编码,识别其中发生的动作类别;进阶方法结合人体关键点序列与骨架拓扑,更细粒度地分析动作质量与模式。 - * 目标检测与追踪:在每一帧上做检测的同时,引入跨帧关联机制(外观特征、运动轨迹等),将同一目标在不同时刻的检测框串联为连续轨迹,得到多目标跟踪结果。 - * 视频语义分割与场景分析:在像素级别上对视频中的每一帧进行语义分割或实例分割,并利用时间连续性平滑预测;同时对镜头切换和场景边界进行检测,实现长视频的结构拆解。 - * 高层事件与异常检测:在基础的动作与轨迹特征之上,利用时序建模和模式识别方法,对罕见事件和异常模式进行检测,往往结合无监督或弱监督学习缓解标注稀缺问题。 -* **模型** - 在模型选择上,视频理解与结构分析通常采用“空间特征 + 时间建模”的组合架构: - * 基于 3D 卷积和 Two‑Stream 的经典模型,如 I3D 等,通过在空间和时间维度同时卷积,对短视频片段进行端到端动作识别。 - * 基于多路径与多时间尺度的 SlowFast 系列模型,通过慢路径捕捉语义、快路径捕捉运动细节,在计算量和精度之间取得更好平衡。 - * 基于 Transformer 的视频模型,如 TimeSformer、Video Swin Transformer 等,利用时空注意力机制对长时间范围的视频进行建模,更适合捕捉复杂事件和多主体互动。 - * Tube‑based 检测器与时空卷积 / Transformer 模型,将检测框在时间上扩展为“tube”,在空间–时间联合特征上做行为检测与时空分割。 - * 多目标跟踪(MOT)方法,如 DeepSORT 等,将帧级检测结果与外观嵌入、运动预测结合,在视频中稳定关联目标身份。 - -整体上,这一层能力把视频从“高质量像素流”进一步抽象为“行为与事件流”,为上游的多模态理解、检索与决策奠定结构基础。下面,我们从 **动作识别与行为分析** 、 **目标检测与追踪** 、**事件与异常检测**三个方向展开。 - -### 5.2.1 动作识别与行为分析:从帧序列到“谁在做什么” - -动作识别与行为分析关注的是“在一段时间窗口内,主体在做什么事”。在安防场景中,这意味着从视频中识别出“走路、奔跑、摔倒、打架”等行为;在体育和健身中,则对应“投篮、发球、深蹲是否标准”“瑜伽体式是否到位”等更细粒度动作。技术上,早期方法主要依赖 2D 卷积 + 光流或手工特征,将若干帧堆叠后整体分类;现代方法则更多采用 3D 卷积(I3D、一系列 3D ResNet 变体)、SlowFast 这类多时间尺度结构,或 TimeSformer、Video Swin Transformer 等基于时空注意力的模型,对空间纹理与时间变化进行联合建模。 - -在许多需要高精度姿态分析的场景中,直接对 RGB 片段分类并不足够,还会结合人体姿态估计和骨架序列建模:先从每一帧中提取 2D/3D 关键点,再将关键点序列送入 RNN、时序卷积或 GCN/Transformer 网络,分析动作的时序结构和空间协调性。这种“姿态先验 + 时序建模”的方式,对背景、光照和服装变化更鲁棒,适合瑜伽、健身、工业操作规范性评估等对动作细节要求较高的应用。 - -### 5.2.2 目标检测与追踪:从“这一帧在哪”到“整段轨迹” - -单帧目标检测可以告诉我们“这一帧里有哪些目标、在哪儿”,而现实中的许多任务需要的是“这辆车 / 这个人从哪里来、到哪里去、中间做了什么”。目标检测与追踪模块正是为了把帧级检测串成时间上的连续轨迹:一方面在每一帧上运行检测器,给出候选目标框;另一方面基于外观特征(ReID 嵌入)、运动预测(卡尔曼滤波)和空间重叠等线索,将相邻帧上的框进行匹配与关联,得到多目标跟踪(MOT)结果。 - -在工程实践中,一个典型的流水线是:“强健的行人 / 车辆检测 + DeepSORT 一类的关联算法”,部署在监控或行车记录仪上,实时输出每个 ID 的运动轨迹。在更复杂的系统中,这些轨迹还会结合区域语义(车道、区域划分)与业务逻辑规则,进一步推断逆行、长时间逗留、频繁进出等高层行为模式,为上游安防、交通流量分析和工业流程监控提供连续时序信号。 - -### 5.2.3 事件与异常检测:从“常态模式”中找出“不对劲” - -在大部分业务场景中,真正需要重点关注的往往是“少数异常”和“关键事件”:例如安防中的打架、摔倒、聚集,工业生产中的异常停机或违规操作,交通中的危险驾驶行为等。这类事件相对罕见,标注成本高、样本极不平衡,给模型建构带来了额外挑战。 - -常见的做法,是在基础的动作识别、目标跟踪和场景分割之上,构建一个时序异常检测模块:要么通过有监督方式直接学习少量已标注的异常样本;要么采用无监督/弱监督方法,对“正常模式”的运动与行为分布进行建模,一旦新观测与历史分布明显偏离,就发出告警。在模型层面,会结合时序自编码器、对比学习、图神经网络或时序 Transformer,将空间关系和时间依赖统一编码,从而捕捉更复杂的群体行为模式和长程依赖。 - -## 5.3 视频 + 语言多模态任务(Video‑Language) - -如果说视频理解解决的是“视频本身理解清楚了”,那么**视频 + 语言多模态任务**关注的是“如何用自然语言去描述、问答、检索视频内容”,以及“如何在长视频时间轴上,围绕文本需求快速定位关键信息”。这类任务需要同时处理视觉、语音与文本信号:一方面提取视频中的画面与声音特征,另一方面对接语言模型的推理与生成能力,把时空内容压缩成适合人类消费和机器调用的文本摘要、问答结果与语义索引。 - -从产品视角看,这一层能力已经深入长视频自动生成字幕与时间轴、短视频剪辑平台的“智能打点 / 关键片段抽取”、企业培训和会议视频的问答助手等场景:用户不必再“从头看到尾”,而是可以通过自然语言直接对视频内容进行检索、提问和重组。下面依然从 **场景** 、**原理**和**模型**三个角度展开。 - -* **场景** - * 字幕与摘要生成:对课程、演讲、会议和长视频内容自动生成多语言字幕,并在此基础上生成章节级摘要、看点列表与时间轴。 - * 视频问答与知识访问:对教学视频、操作演示、企业培训内容构建“视频问答助手”,支持用户用自然语言提问,如“这个步骤怎么做”“这个人最后把手机放哪了”。 - * 视频内容检索与片段定位:在大规模视频库中支持“文字 → 视频片段”的精确检索,例如“找出提到价格的部分”“找到讲解某个公式的片段”;在单个长视频内自动打点标注精彩片段与关键信息。 - * 内容生产与编辑辅助:结合视频内容理解与语言生成功能,自动生成标题、文案、分镜脚本,辅助创作者快速剪辑和重组素材。 -* **原理** - 视频–语言多模态系统的核心,是在统一嵌入空间中对齐时序视觉特征与文本表示,并在这一基础上进行检索、生成与推理: - * 多模态特征抽取与对齐:对视频帧/片段提取时空特征(CNN/ViT/Video Transformer),对文本提取语言嵌入(预训练 LLM 或文本编码器),通过对比学习或多模态预训练对齐两种模态。 - * 语音与文本管线:对包含语音的内容,通常先用 ASR 生成时间戳对齐的转写文本,再与视觉特征联合建模,既可以用文本直接驱动检索,也可以做跨模态对照与纠错。 - * 时间建模与片段定位:对于长视频,需要在时间轴上学习“片段级”表示,通过注意力或时序 RAG 在局部片段和全局上下文之间动态切换,实现对问题相关区间的精确定位。 - * 生成与推理:在对齐后的多模态表示上接入大语言模型,进行自然语言生成(字幕、摘要、解释),或进行多轮问答与逻辑推理。 -* **模型** - 在模型形态上,视频–语言多模态任务经历了从“专用编码器 + 简单头”到“统一多模态大模型”的演进: - * 早期视频–语言模型:如 VideoBERT 等,在预训练阶段联合建模视觉与文本 token,通过掩码预测和对比学习获得可迁移的视频–语言表征。 - * All‑in‑One Video‑Language Models:将视频、文本(及语音)统一纳入一个多模态 Transformer 中,通过共享或部分共享参数,实现描述生成、检索、QA 等多任务统一处理。 - * 长视频多模态模型:如具备视频能力的 Gemini、Claude、GPT 等,通过长上下文与分层时序建模,对数十分钟乃至数小时视频进行整体理解,支持时间轴级别的摘要与问答。 - * 时序 RAG + VLM:在视频上构建“时序向量索引”,先用 VLM 对视频片段进行编码建立数据库,再在查询时检索相关片段,结合 LLM 进行答案综合与可解释推理。 - -总体来看,这一层将视频从“机器理解”进一步提升到“人机对话与协作”层面:用户可以像问人一样向视频提问,系统则在背后完成复杂的视觉、语音与语言对齐与推理。 - -### 5.3.1 字幕、摘要与时间轴:把长视频压缩成可浏览文本 - -对于课程、讲座、会议和长内容视频,最迫切的需求往往是“快速知道讲了什么、哪里是重点”,而不是从头到尾完整观看。自动字幕与摘要系统通过“ASR + 文本处理 + 视觉辅助”的组合,将音频内容转写为时间戳对齐的文本,再在此基础上生成结构化大纲与精简摘要,实现从“小时级视频”到“分钟级阅读”的信息压缩。 - -在实现层面,ASR 模块负责稳定、高质量地给出多语言转写和时间轴对齐;文本侧则利用大语言模型对原始转写进行纠错、分句和语义重整,提取章节标题、关键信息和问题–答案对。在一些场景中,还会结合视觉线索(如 PPT 页面变化、场景切换)来辅助划分章节边界与重点片段,保证摘要结构与真实内容节奏更加一致。 - -### 5.3.2 视频问答与语义检索:用自然语言“操纵”视频 - -在字幕与摘要之上,更进一步的需求是能够针对特定视频内容进行问答和检索:例如“这个人最后把手机放在哪里”“哪一段讲到了价格策略”“演示这个步骤的是第几分钟”。这类任务需要在时间轴上对问题进行语义定位:既要理解问题本身涉及的人物、物体和动作,也要在视频时序表示中找到对应的片段。 - -具体做法上,通常会先离线为视频构建多粒度索引:对固定长度的片段提取多模态表示(画面 + 文本/语音),建立向量索引或图结构。在在线交互时,将用户问题编码为文本向量,与索引中的片段表征进行匹配,找出最相关的时间区间;随后,将这些片段的内容(关键帧截图描述、转写文本等)与问题一起送入 LLM,由模型生成自然语言答案或返回对应时间点。对于大规模视频库,可以在相同机制下支持“跨视频检索”,例如在企业培训知识库或电商商品视频中跨集合查找相关片段。 - -### 5.3.3 多模态编辑辅助:从理解到“帮你剪好” - -当系统能够稳定地理解视频中的内容和语义结构后,自然的下一步就是反向利用这些理解结果来辅助创作与编辑。视频–语言多模态模型可以根据创作者提供的脚本或提示词,在现有素材中自动选取符合语义的片段,生成粗剪时间线;也可以根据视频内容自动生成标题、封面文案、章节标签,甚至对镜头节奏和配乐提出建议。 - -在工作流中,这类能力通常以“智能推荐”和“自动粗剪”的形式出现:创作者上传素材后,系统自动完成分析、分镜、打点,并给出若干候选版本(如不同节奏、不同时长的剪辑方案);创作者可以在此基础上微调,而无需从零开始逐帧筛选。对于企业级应用,系统还可以结合知识库和品牌规范,确保生成的文案、字幕和剪辑风格符合既定的业务要求和合规标准。 - -## 5.4 视频生成与编辑(Video Generation & Editing) - -在拥有了稳定的理解和结构分析能力之后,**视频生成与编辑**则迈向了“主动创造内容”的阶段:不再只是提升画质或做结构化分析,而是根据文本脚本、参考图像或已有视频,生成全新的镜头,或对原始视频进行结构化编辑与重组。这里既包括从无到有的文生视频(Text‑to‑Video),也包括基于已有图像/视频的风格迁移、扩展与重排,以及面向对象级别的精细编辑与替换。 - -产品上,这一层能力已经通过即梦视频、 minimax 视频、Sora、Runway Gen‑2、Pika、Kling 等一系列产品进入内容创作主流:广告片、概念片、动画、剧情分镜可以在不依赖大型拍摄团队和复杂后期的情况下快速生成;创作者可以通过自然语言脚本驱动镜头和风格;传统的视频剪辑流程则开始与结构化生成工具深度融合。下面依然从 **场景** 、**原理**和**模型**的角度进行梳理。 - -* **场景** - * 文案、剧本到短视频:品牌广告、小剧场、剧情片段和概念动画,根据脚本自动生成或半自动生成可播放的视频草稿。 - * 图像 / 视频到视频:为插画或角色设计生成动态版本,为现实拍摄素材进行风格迁移(现实 → 动漫 / 插画),或在时间与空间上扩展/重组已有视频。 - * 结构化编辑与后期:在不改变整体内容语义的前提下,实现人物换脸、口型同步、对象擦除与替换、文本驱动的剪辑重排等精细操作。 -* **原理** - 当前主流视频生成与编辑方法多以扩散模型(Diffusion)或其变体为核心,在高维的时空潜空间中逐步“去噪”生成视频: - * 文本条件建模:通过文本编码器(如 T5/CLIP 文本塔或专用语言模型)将脚本映射为条件向量,引导视频解码器在风格、内容和运动模式上对齐文本描述。 - * 时空一致性与运动控制:在扩散过程或后验优化中加入时空卷积、时序注意力或 4D 表达(NeRF/GS 等),保证视频在时间轴上的连贯性与物理合理性。 - * 图 / 视频条件生成:在输入图像或视频的特征空间上启动扩散过程,通过控制噪声注入、遮罩区域和条件通道,实现“保留已给部分 + 生成新内容”的受控编辑或扩展。 - * 结构化控制信号:结合姿态骨架、分割掩膜、深度图、相机轨迹等结构信息,使生成视频在主体动作和视角变化上更可控。 -* **模型** - 代表性的模型与方向包括: - * Diffusion‑based Text‑to‑Video 模型(Sora、Runway Gen‑2、Pika、Kling 等),通过大规模视频–文本对进行预训练,在复杂场景、多镜头运动和多样风格上具备较强生成能力。 - * Image‑to‑Video 扩散模型:以单帧图像为条件,预测后续帧的动态演化,实现“单图 → 动画 / 动效”;或对短视频进行续写、扩展、旋转视角等操作。 - * NeRF / 4D 表达与关键帧 + 插值方法:利用 3D 场景表示或关键帧 + 时序插值,将生成与几何、一致性建模结合,实现更稳定的视角漫游与复杂运动。 - -这些能力并非孤立存在,而是逐步渗入剪辑与后期流水线:文案到分镜、分镜到粗剪、粗剪到风格化与局部编辑,越来越多环节被“文本 + 结构化控制”所驱动。 - -### 5.4.1 文生视频:从脚本到“可看”的镜头序列 - -文生视频(Text‑to‑Video)希望实现的是:用户用自然语言描述一个场景、镜头或故事片段,系统自动生成一段连贯的视频。与图像生成相比,文生视频增加了时间维度的难题:不仅要在单帧层面保持画面质量和风格一致,还要保证跨帧的主体身份、光照、背景和运动轨迹的连贯性。 - -典型的扩散式文生视频模型会先在大规模视频–文本配对数据上预训练:文本编码器提取语义条件,视频解码器在潜空间中对一段“噪声视频”反复去噪,逐渐收敛到与文本一致的时空信号。在此过程中,会通过时序注意力、3D 卷积或 4D 表达等结构,将时间依赖显式建入网络,以避免出现“帧间跳变”“角色重置”等问题。部分系统还支持对镜头运动(推拉摇移)和构图节奏进行控制,使生成结果更接近真实拍摄语言。 - -### 5.4.2 图 / 视频到视频:在已有内容上“生长”与“变形” - -另一条重要路线是基于已有图像或视频进行生成与编辑:例如,将一张插画或概念设定图“动起来”,将真人视频风格化为动漫,或在保持结构不变的前提下更换背景、调整天气和时间。技术上,这类方法往往在扩散过程上增加“参考通道”:将输入图像或视频编码为特征,作为条件或初始状态参与去噪,同时通过遮罩、显式几何约束等机制控制“哪些区域可以被改变、哪些必须保持”。 - -对于风格迁移场景,模型会在保留原始运动和构图的前提下,重绘纹理和光影,使其匹配目标风格;对于视频扩展与重组,则通过在时间两端或中间“续写”新帧,实现水平/垂直场景扩展、视角绕行或情节补充。这类能力非常适合与传统剪辑流程结合:剪辑师先给出关键镜头和节奏,模型再在这些“锚点”之间自动生成过渡和变体。 - -### 5.4.3 结构化视频编辑:对象级的精细控制 - -在许多业务场景中,完全重生视频并非刚需,更关键的是对已有画面进行精细、可控的结构化编辑:比如换脸、改口型、擦除不需要的物体、替换广告位内容,或者根据文本脚本重排镜头顺序。结构化视频编辑正是沿着这一思路发展:在视频理解的基础上,引入对象级分割、跟踪和参数化表示,使编辑操作可以稳定绑定到特定目标和时间段。 - -人物换脸和口型同步(Lip‑sync)是这一方向中最典型的应用:模型需要在保证头部姿态与整体表情自然连贯的前提下,将目标人物的身份映射到原视频的表演上,并根据新语音信号精确控制口型运动。对象擦除 / 替换则依赖高质量的分割和时空补全:先在每一帧中分割并移除目标对象,再利用邻近帧与上下文纹理填补空洞,避免出现明显“打补丁”的痕迹。文本驱动剪辑则通过将“脚本结构”与视频时间轴对齐,自动选取和拼接符合脚本语义的片段,实现更高层的自动化编辑。 - -## 5.5 数字人 / 虚拟人(Digital Human / Avatar) - -**数字人 / 虚拟人(Digital Human / Avatar)** 可以看作是视频生成、语音合成、多模态理解和图形渲染的一次“系统级整合”:它不只是生成一段视频,而是基于文本或语音输入,持续、可控地驱动一个虚拟形象“开口说话、做表情、摆动作”,并在越来越多场景下实现准实时甚至实时的交互。相比一般的视频生成,数字人更强调三点: **身份与形象的长期一致性、语音—表情—动作的精细对齐、以及端到端系统的实时性与稳定性** 。 - -从产品视角看,数字人已经广泛出现在**内容生产平台、虚拟客服 / 智能前台 / 虚拟导览、教育培训与在线课堂、品牌虚拟 IP / 虚拟偶像、为创作者提供的虚拟主播 / 数字分身工具**等场景:企业可以批量生产带有固定形象和风格的视频内容,政府和企业服务可以用虚拟前台 7×24 小时接待用户,个人创作者可以完全不露脸但持续产出“有人出镜”的视频。下面依然从 **场景** 、**原理**和**模型**三个维度来梳理,并在后续小节展开驱动与表达、形象与视频生成、实时交互与系统集成三个方向。 - -* **场景** - * 内容生产与在线传播:企业宣传片、产品功能讲解、课程录制、新闻播报,使用数字人替代真人上镜,大量减少拍摄场地、灯光设备和人力成本。 - * 虚拟客服与导览:在银行网点、政务大厅、景区、博物馆等场所,用数字人承担迎宾、问询、业务咨询和路线指引,兼顾形象统一与 7×24 小时服务。 - * 品牌虚拟 IP / 虚拟偶像:围绕某一虚拟形象长期运营短视频、直播、电商内容,在不同平台上保持统一人设和视觉风格。 - * 虚拟主播与数字分身:为不愿出镜或需要多身份运营的创作者,提供可配置的虚拟主播 / 数字分身,与真实声音或合成声音绑定,实现“只用说话 / 打字,就能稳定出镜”。 -* **原理** - 数字人系统本质上是一个“语音 / 文本驱动 + 形象建模 + 视频 / 渲染输出”的多模态流水线,在离线与实时场景下略有差异,但核心组件相似: - * 语音与语言驱动:根据脚本直接用 TTS 合成语音,或接入 ASR + LLM,从用户语音 / 文本中生成回复文本,再用 TTS 输出语音;语音特征(如 mel 频谱)作为驱动信号控制嘴型与表情时间轴。 - * 形象与动作空间建模:为虚拟形象构建可控的几何与外观表示,例如 2D 人像 / 插画、基于骨骼和 Blendshape 的 3D Avatar、或基于 NeRF / 4D 高斯的可渲染体积表示;并定义一组“驱动参数”(如关键点、姿态骨架、Blendshape 系数),用来编码表情与姿态。 - * 语音 → 表情 / 动作映射:通过专门的“语音驱动”模型,将语音特征映射为人脸和上半身的驱动参数,实现口型同步(Lip‑sync)、表情细节和头肩动作;实时数字人会要求这一映射端到端低延迟且稳定。 - * 渲染与合成:根据当前帧驱动参数,对虚拟形象进行图像或 3D 渲染,输出连续视频流或实时画面;可叠加背景、道具、字幕等元素,与传统视频剪辑流程结合。 -* **模型** - 在具体模型上,数字人系统往往综合使用多类专用模型与通用多模态模型: - * Audio‑driven Talking Head 模型:如 Wav2Lip 一类的口型同步模型,通过学习语音与口腔区域像素 / 几何之间的对齐关系,在保证身份一致的前提下生成自然的嘴部运动。 - * 实时 / 轻量级数字人模型:如 Ultralight‑Digital‑Human、轻量级 Talking Head 模型等,在结构上大幅压缩参数与计算量,使得在 CPU / 移动端 / WebGPU 上也能实现接近实时的驱动与渲染。 - * NeRF / 4D 表达模型:如 ER‑NeRF(Explicit / Efficient / Editable 方向的数字人 NeRF 方案)等,通过在 3D 空间中建模人物形象与表情变化,使视角、光照和动作更自然连贯,适合高保真和多机位场景。 - * 语音驱动与多模态对齐模型:如 MuseTalk 一类“语音 → 面部表情 / 说话头”模型,将音频特征和视觉特征对齐,在不依赖大量 3D 标注的情况下实现逼真的讲话表情与头部动作。 - * 语音与对话模型:高自然度多说话人 TTS、端到端语音对话模型(ASR + LLM + TTS 一体化),为数字人提供多风格、多语种的声音和对话能力。 - -综合来看,数字人既是一组模型,也是一套完整系统:它将语言理解、语音、视觉生成与实时推理整合起来,从而在“屏幕前”呈现出一个可交互的虚拟角色。下面,我们从 **驱动与表达** 、**形象与视频生成**和**实时交互与系统集成**三个方向展开。 - -### 5.5.1 驱动与表达:从脚本 / 语音到“会说话、会表情”的人 - -在数字人流水线中,**驱动与表达**负责回答一个核心问题:在给定脚本或语音的前提下,虚拟形象在每一帧应该呈现什么样的嘴型、表情和头肩动作。这里既包括离线批量生产的场景,也包括对实时对话的响应。 - -在离线内容生产中,常见链路是“文本脚本 → TTS → 语音驱动”:业务侧提供播报文案,TTS 模块生成目标音色(如品牌虚拟代言人)的语音,再将语音特征输入到“语音 → 动作”模型。**Wav2Lip 类模型**就是这一环节的重要代表: - -* 它以参考人像帧和对应语音片段为输入,通过一个卷积 / 注意力网络预测出与语音精细对齐的嘴部区域,再与原始人像进行融合,从而在保持身份和大部分表情不变的前提下,精确修改嘴型。 -* 训练时,通过语音–视频对齐数据监督网络学会不同音素对应的口腔形态,并在时间上保持连续性,避免嘴型跳变或延迟感。 - -相比早期纯口型同步方案,新一代的语音驱动模型(如 MuseTalk 一类的方法)进一步扩展到了 **全脸表情和头部姿态** : - -* 这类模型通常将语音特征映射到一个低维的“情绪 / 表达潜空间”,再通过解码器生成关键点、Blendshape 系数或直接生成图像特征,带动眉毛、眼睛、颊部等区域的细微变化,使“说话表情”更生动。 -* 有的模型还会将语音内容的语义信息(如疑问、强调、感叹)编码进去,结合 LLM 分析的句法 / 语用信号,在语调变化处增加点头、皱眉、手势等动作,提升表达的自然度和感染力。 - -在更高维度上,**驱动与表达**也可以结合外部控制信号:例如将姿态骨架、手势轨迹、视线方向等作为附加输入,使数字人可以模仿特定演讲者的风格,或根据脚本中的“指示动作”(如“指向屏幕”“双手张开”)执行预定义的动作模板。无论是 Wav2Lip 这样的局部口型驱动,还是 MuseTalk / 实时骨架驱动等更全身的表达建模,它们共同实现了从语音 / 文本到面部与上半身动作的连续映射,是数字人“看起来像在认真说话”的关键一环。 - -### 5.5.2 形象与视频生成:从“一个模型”到“一个可塑的角色” - -驱动链路解决了“怎么动”,而**形象与视频生成**则决定了“谁在动、在哪里动、以什么风格动”。这里既包含高保真写实数字人,也包含二次元、卡通和低多边形 Avatar 等风格化形象,以及面向实时和离线渲染的不同技术选型。 - -在 2D 人像与插画场景中,典型做法是基于少量参考图像和短视频训练一个 **Talking Head 生成模型** : - -* 模型将人物的身份信息编码为一个“外观向量”或风格特征,将驱动参数(如语音隐向量、关键点、表情编码)作为条件输入,在图像空间中合成新的帧。 -* 与纯 Wav2Lip 只改口型不同,这类模型可以在姿态上做小幅度摆动、在表情上叠加情绪变化,从而让数字人看起来不那么“僵硬”。 - -在追求更高真实感、更自由视角和多机位切换的场景中,越来越多方案采用基于 **NeRF / 4D 表达**的数字人建模(如 ER‑NeRF 一类方法): - -* 通过多视角拍摄或视频,先重建人物头部 / 上半身的 3D 体积或高斯场,将不同表情和嘴型对应的状态编码为可插值的隐空间; -* 驱动时,将语音 / 表情参数映射到这一隐空间,在 3D 中进行体积渲染或高斯渲染,再投影到屏幕上。 -* 这种做法的优势在于:视角、光照和背景更自然,可以支持“环绕视角”“虚拟摄影机”运动,对 VR/AR、虚拟直播间和高端广告制作尤为友好。 - -在强调跨端部署与实时性的业务中,还会采用 **Ultralight‑Digital‑Human** 这类轻量化方案: - -* 通过结构剪枝、算子重构和模型蒸馏,将 Talking Head 或 Avatar 渲染网络压缩到移动端 / WebGPU 也能运行的规模; -* 在几毫秒级别完成从驱动参数到一帧图像的生成,与实时语音流或控制信号对齐,实现“低延迟数字人”,适合互动终端、自助机和 Web 前端应用。 - -在完整视频生产层面,形象与视频生成还要与背景、道具和镜头语言结合:一个常见的工作流是: - -* 先为品牌或个人定制一个数字人形象(2D 或 3D); -* 预设若干虚拟场景(演播厅、办公室、教室、展厅等); -* 在生产内容时,系统根据脚本自动选择合适场景和机位,生成数字人画面,并与 PPT、演示视频、产品画面进行多画面编排。 - 这使得数字人不只是一个“说话头”,而是可以自然融入各种节目和内容形态的“角色”。 - -### 5.5.3 实时数字人与系统集成:从离线视频到“屏幕里的同事” - -随着 ASR、TTS、LLM 和轻量级视频生成模型的成熟,越来越多数字人系统开始从**离线批量出片**走向 **实时交互** :用户在终端开口说话或输入文本,屏幕上的数字人在几百毫秒到几秒内“听懂—思考—回应—开口说话”,形成类似真人客服 / 导览 / 主持的体验。这里的关键不只是模型本身,还包括如何把多模态链路 **压缩到可接受的端到端延迟** 。 - -在一个典型的实时数字人闭环中: - -* **前端输入** :ASR 模块将用户语音实时转为文本,或直接接收用户文本输入。 -* **语义理解与决策** :LLM 结合业务知识库和工具(RAG、数据库查询、流程编排)生成回复文本,以及必要的结构化指令(如需要展示哪一页 PPT、播放哪个视频片段)。 -* **语音与驱动** :TTS 将回复文本转换为目标音色的语音,语音流一边生成、一边被 Wav2Lip / MuseTalk / 实时骨架驱动模型消费,逐段输出对应的口型与表情参数。 -* **渲染输出** :Ultralight‑Digital‑Human 类型的轻量渲染网络或基于 GPU 的 NeRF / Avatar 渲染引擎,将驱动参数实时转换成视频帧,通过 WebRTC、RTMP 或本地渲染直接输出到屏幕。 - -为了在多终端上提供一致体验,系统还需要在**延迟、带宽与算力**之间做细致权衡: - -* 在云端渲染方案中,绝大部分计算(LLM、TTS、驱动与渲染)在服务器完成,终端只负责播放视频流,适合算力有限的 Web / App 和线下大屏,但对网络稳定性有依赖; -* 在“云 + 端混合”方案中,ASR 和部分 LLM 推理在云端完成,轻量化驱动与渲染在本地进行,可以显著降低音画交互延迟,适合移动设备与自助终端; -* 在强算力终端(如高性能 PC、专用工作站)上,还可以将大部分链路下沉本地,实现弱网环境下的稳定互动。 - -在模型侧,**实时数字人**也对结构设计提出了额外要求: - -* 语音驱动模型需要具备流式推理能力,能够在获得一小段语音后就给出口型与表情预测,而不是等整句结束; -* 渲染网络需要尽可能减少依赖大卷积核和全局注意力,采用局部卷积、轻量自注意力、分辨率金字塔等结构控制计算量; -* 对于基于 NeRF / 4D 的高保真方案,则需要通过网格缓存、视锥裁剪、稀疏体积和 GPU 优化等手段,把每帧渲染控制在几毫秒到几十毫秒内。 - -在系统集成层面,实时数字人往往还要与**业务知识、人格设定与对话策略**紧密绑定: - -* 通过知识库和 RAG 管理行业知识、业务流程和 FAQ,确保“说得对、说得全”; -* 通过人设配置和话术模板控制说话风格和表达边界,确保“说得像这个人(或这个品牌)”; -* 通过多轮对话策略与会话状态管理,使数字人可以记住用户上下文、在合适时机确认和追问,呈现出“像一个真正的同事 / 导游 / 讲师”的交互感。 - -总体而言,加入了 Wav2Lip、MuseTalk、ER‑NeRF、Ultralight‑Digital‑Human 等专门为口型同步、表情驱动与实时渲染设计的模型之后,数字人正从“离线视频模板工具”加速演化为 **可实时响应、有稳定人格和专业知识的虚拟实体** ,成为视频技术体系中最具综合性和应用张力的一环。 - -# 6. 时间序列与时序决策(Time Series & Sequential Decision) - -在前面的视觉和结构化建模中,我们更多是在“静态”空间下思考问题:一张图、一条记录、一段文本。而在真实业务中,极大一部分核心指标都是随时间演化的:销售量和流量每天在波动,服务器负载和传感器读数每秒在变化,金融价格与宏观指标则在政策和事件驱动下不断调整。**时间序列与时序决策**这层,关注的就是:在时间轴上预测未来、识别异常、刻画结构突变,并在此基础上做出有前瞻性的决策与控制。 - -从产品视角看,这类能力贯穿运营、规划、风控和调度等关键环节:传统 BI / 报表系统中嵌入的指标预测模块、财务与供应链规划工具中的需求预测和安全库存建议、量化研究分析软件中的宏观关联分析和因果关系挖掘、电商和出行平台上的流量与运力预测、运维 AIOps 中的指标异常检测与告警,都是这一层的典型落地形态。下面我们从 **经典统计方法** 、 **深度学习时间序列建模** 、**异常与变点检测**以及**时空序列建模**四个方向展开。 - -## 6.1 经典时间序列建模(Statistical TS Modeling) - -在很多业务里,“时间”是天然的主线:销售量按日/周变化、网站流量随活动波动、设备负载跟着用户行为起伏、传感器读数反映着系统状态的细微变化。**经典统计时间序列建模**就是在这种时序结构上,利用相对可解释、可分析的统计模型去回答三个核心问题:**未来会怎样?变量之间如何关联?系统当前所处的状态是什么?** 尽管深度学习已经在许多场景中崭露头角,但 ARIMA、协整分析、卡尔曼滤波等传统方法,仍然在金融、供应链、运营、风控等领域长期服役,并常常作为更复杂系统的“基线”和解释工具。 - -从应用视角看,经典时间序列模型广泛存在于传统 BI/报表系统的指标预测模块、财务与供应链规划工具、以及各类量化研究软件中。它们可以直接对单个或多个时间序列给出未来预测区间,也可以用来分析宏观指标之间的协同变化与长期均衡关系,并通过状态空间建模对轨迹和隐藏状态进行估计。下面,我们从 **场景** 、**原理**和**模型**三个维度来梳理这类方法的典型用法,再分别展开具体方向。 - -* **场景** - * 指标预测:对销售量、网站流量、CPU 负载、传感器读数等按时间变化的数值进行短期或中期预测,用于库存备货、产能安排、运维调度等决策。 - * 宏观经济与金融分析:研究 GDP、通胀率、利率、汇率、资产价格等宏观和市场指标之间的长期关联和短期动态,辅助政策研究与量化策略开发。 - * 过程与轨迹估计:在定位、导航、目标跟踪和设备监控中,对随时间变化的轨迹、速度、状态进行估计与平滑,并在噪声环境中尽可能还原“真实过程”。 -* **原理** - 经典时间序列方法普遍基于“ **统计假设 + 参数化结构** ”的思路: - * 假定时间序列满足一定的平稳性或弱平稳性条件,通过自相关结构(自相关函数 ACF、偏自相关函数 PACF)刻画“当前值由过去多少阶的历史决定”。 - * 在多变量情形中,通过协整与向量自回归(VAR)模型,刻画多个时间序列之间的长期均衡关系与短期偏离修正。 - * 对于噪声严重、状态不可直接观测的系统,引入隐含状态(latent state)与观测方程组成状态空间模型,用贝叶斯推断或递推滤波(如卡尔曼滤波)进行在线估计与预测。 -* **模型** - 这类方法的模型族相对明确、结构清晰,便于解释和调参: - * 单变量与多变量 AR/MA/ARIMA/SARIMA 系列,用于平稳/季节性时间序列建模,是 BI 系统和传统预测模块的“常驻成员”。 - * VAR/协整模型,用于多维宏观和金融时间序列的联合建模和因果关系检验,适合政策和策略层面的关联分析。 - * 状态空间模型与卡尔曼滤波、隐马尔可夫模型(HMM)等,用于轨迹估计、设备状态估计以及隐藏状态的推断,是工程控制与信号处理中的基础工具。 - -综合来看,经典时间序列建模的优势在于 **可解释性、可诊断性和工程可控性** :建模流程、假设检验、残差分析都有成熟规范,很容易融入现有 BI 与规划系统。下面,我们从单/多变量预测、协整与因果、状态空间三个方向展开。 - -### 6.1.1 单变量/多变量时间序列预测:从 ARIMA 到 VAR - -在最典型的业务场景中,我们首先面对的是一条或若干条按时间排序的指标曲线:例如某商品每日销量、站点每小时 PV、机房每分钟 CPU 使用率、设备传感器每秒读数。目标是根据历史走势对未来的短期或中期区间给出预测,并给出合理的置信区间。**AR/MA/ARMA/ARIMA/SARIMA** 系列模型正是为此设计的标准工具。 - -对单变量序列来说,ARIMA 类模型假设“当前值由过去若干期的历史值和随机扰动线性决定”,通过对序列做差分、季节差分来消除趋势和季节性,使其趋于平稳: - -* AR(自回归)部分刻画“自身滞后对当前值的影响”; -* MA(滑动平均)部分捕捉“历史误差项对当前值的影响”; -* I(差分)部分负责去除趋势; -* 加上季节项后得到 SARIMA,可以显式描述周度、月度等周期性结构。 - -在工程使用中,通常会先做平稳性检验(如 ADF)、观察 ACF/PACF 图,再通过信息准则(AIC/BIC)和残差诊断选取合理的阶数。对于具有明显季节性的指标(如电商日销量、节假日流量)尤其适合 SARIMA 建模,配合假日特征或外生变量可以进一步改善预测性能。 - -当我们希望一次性建模多条相关时间序列时,可以引入 **多变量时间序列模型** 。代表方法是 VAR(向量自回归)与其变体。VAR 将多个序列视为一个联合向量,用自身及彼此的滞后项共同解释当前值,从而捕捉不同指标之间的相互影响。例如,在宏观经济分析中,可以将 GDP 增速、通胀率、利率、汇率等纳入同一个 VAR 模型,研究冲击响应和传导路径;在业务运营中,也可以用 VAR 描述“一个渠道的流量变化如何影响其他渠道”“促销强度与销量之间的动态关系”,为资源调配提供参考。 - -在产品化形态上,这一类单/多变量预测能力通常嵌入在**传统 BI / 报表系统的预测功能、财务与供应链规划工具**中:用户选定某条或若干条时间序列,系统自动完成建模与预测,并提供预测区间、残差分析和模型诊断报告,用于辅助决策,而不必深入理解决策背后的所有数学细节。 - -### 6.1.2 协整与因果关系:宏观指标之间的长期均衡 - -在经济与金融领域,很多时间序列表面看似随机游走,但在更长的时间尺度上存在某种 **稳定的长期均衡关系** 。典型例子包括汇率与利差、股指与宏观盈利、商品价格与成本指数等。单独看每条序列,可能都是非平稳的;但某种线性组合却在长期内围绕一个稳定水平波动。这种现象被称为 **协整(cointegration)** ,它为我们理解宏观指标之间的结构性关系提供了重要线索。 - -在工程实践中,协整分析通常包括几个步骤: - -1. 对各个时间序列进行单位根检验,确认其为同阶单整(例如都为 I(1)); -2. 进行协整检验(如 Engle-Granger 两步法、Johansen 检验等),判断是否存在非平凡的线性组合使得该组合平稳; -3. 若发现协整关系,可以构建误差修正模型(ECM),刻画“短期偏离长期均衡时,系统如何逐步修正回到平衡状态”。 - -与协整相关的,是 **Granger 因果关系检验** 。它并不是严格意义上的哲学“因果”,而是一种基于预测能力的统计定义:如果变量 X 的历史信息可以显著提高对变量 Y 的预测精度,则称“X Granger 导致 Y”。通过在 VAR 或回归框架下比较有/无某个变量滞后项时的预测误差,可以评估不同宏观或市场指标之间的方向性影响。在量化研究和宏观分析中,这种检验常用于甄别潜在的领先指标、构建因子、或者验证策略假说。 - -从产品视角看,协整与因果分析更多出现在**量化研究分析软件、宏观经济分析平台和金融研究工具**中。它们帮助研究者从成堆的时间序列中抽取出相对稳健的结构关系,并将这些关系映射到更高层次的业务概念(如“利率对汇率的长期约束”“不同资产之间的价差回归”),成为策略设计与风险管理的重要依据。 - -### 6.1.3 状态空间模型与隐状态估计:卡尔曼滤波与 HMM - -在许多真实系统中,我们观测到的时间序列只是 **噪声污染后的表象** ,而真正感兴趣的是背后随时间演化的“系统状态”:例如车辆的真实位置和速度、设备的健康状态、用户的潜在行为模式等。此时,如果仍然只在观测序列上做 ARIMA 式建模,就很难充分利用对系统结构的理解。**状态空间模型(State Space Models)**正是为这种“隐状态 + 噪声观测”的问题而提出。 - -状态空间模型通常由两部分构成: - -* 状态转移方程:描述隐藏状态如何随时间演化,可以是线性的也可以是非线性的; -* 观测方程:描述隐藏状态如何生成带噪声的观测值。 - -在线性高斯假设下,这个框架可以通过**卡尔曼滤波(Kalman Filter)和平滑器(Smoother)** 实现对状态的递推估计与预测:每一步分为“预测”和“更新”两大阶段,将上一时刻的状态分布与当前观测结合,得到新的状态估计。这在导航与定位(如轨迹估计、目标跟踪)、金融时间序列(如波动率估计)、设备状态估计(如健康监控、剩余寿命预测)中极其常见。 - -与连续状态空间模型相邻的,是 **隐马尔可夫模型(HMM)** 。HMM 假设系统在若干个离散的隐状态之间随时间转移,每个隐状态下生成观测数据的概率分布不同。通过前向–后向算法和 Viterbi 算法,HMM 可以估计隐状态序列、计算观察序列概率,并对下一步状态与观测做预测。HMM 早期广泛用于语音识别、文本标注,也常用于简单的行为模式识别与事件序列建模,在某些工业与金融场景中仍有其优势——结构可解释、训练稳定、与领域经验易于结合。 - -在系统层面,状态空间建模、卡尔曼滤波和 HMM 常作为**轨迹估计、设备状态估计、金融与工程控制系统**的底层模块,被封装在更大的工具链中。它们不一定直接暴露给终端用户,但在导航、目标跟踪、工业控制、风险计量等产品背后,长期扮演着“隐形引擎”的角色。 - -## 6.2 深度学习时间序列建模(Deep TS Forecasting) - -随着数据规模和场景复杂度的持续上升,单纯依赖线性、平稳性假设的经典模型在很多应用中开始显得“力不从心”:大量非线性模式、长跨度依赖、复杂的多变量交互、突发行为与周期叠加等特点,使得我们需要更灵活、更高容量的模型结构。**深度学习时间序列建模**正是在这一背景下发展起来的:从 RNN/LSTM/GRU,到 Temporal CNN/TCN,再到时序专用 Transformer、混合与分层模型,它们共同构成了现代时序预测与建模的主力工具箱。 - -从应用视角来看,深度时序模型已经广泛部署在**电商流量 & 销量预测平台、供需/运力/排班预测系统、云资源负载预测与容量规划工具**中,用于在多品类、多门店、多城市、甚至多业务线的复杂结构下,给出统一而灵活的预测方案。与经典模型相比,它们更强调“端到端表示学习”和“全局模式建模”,更擅长处理长序列、高维、多变量场景。下面,我们同样从 **场景** 、**原理**和**模型**三个维度展开。 - -* **场景** - * 大规模多序列预测:成千上万条商品、门店、城市维度的销量/流量序列,需要在一个统一模型下同时建模,并支持冷启动与长尾序列。 - * 复杂运营与调度:供电/供水/运力/排班等系统中,需求受多维特征影响(天气、节假日、价格、活动),且存在多层级结构(门店/城市/全国),需要同时兼顾全局模式与局部差异。 - * 云资源与基础设施:大规模服务器集群、容器平台、网络与存储负载,呈现高度非线性和多峰结构,需要高频预测与容量规划支撑 SLO。 -* **原理** - 深度时序模型的核心在于 **自动从历史序列与协变量中学习多尺度模式与长期依赖** : - * RNN/LSTM/GRU 通过循环结构显式地在时间维度上传递“记忆”,适合捕获顺序依赖与局部时间结构。 - * Temporal CNN / TCN 使用一维卷积和膨胀卷积,在保证因果性的前提下扩大感受野,实现并行训练与稳定梯度传播。 - * 时序 Transformer 与专门设计的变体(Informer、Autoformer、TimesNet 等)利用自注意力机制,在长序列、多变量设置下建模复杂依赖和周期性模式。 - * 混合与分层模型进一步引入“全局 + 局部”“多层级时间序列”的结构假设,在统一框架中同时学习全局模式与个体特征。 -* **模型** - 在具体实现上,深度时序建模涌现出一系列具有代表性的架构: - * 经典深度序列模型:RNN/LSTM/GRU 以及基于它们的 DeepAR 等自回归概率预测模型。 - * 分解与预测一体化模型:N‑BEATS 等通过显式趋势/季节分解模块增强可解释性。 - * 基于注意力的时序模型:Temporal Fusion Transformer(TFT)等结合注意力、门控、变量选择,适用于多变量、有丰富协变量的业务场景。 - * 长序列 Transformer 模型:Informer、Autoformer、TimesNet、PatchTST 等,围绕长序列效率与多尺度建模做出专门设计。 - -下面,我们从深度序列模型、卷积与 Transformer、以及混合与分层建模三个方向展开。 - -### 6.2.1 深度 RNN/LSTM/GRU:从单序列到 DeepAR - -在深度学习进入时间序列领域初期,**RNN/LSTM/GRU** 是最自然的选择。与文本和语音建模类似,它们通过在时间步之间传递隐状态来“记忆”历史信息,允许捕捉比传统线性模型更复杂的非线性和长期依赖。对于单条或少量时间序列,简单的 LSTM/GRU 在有足够数据时就可以取得不错的预测效果;而在大规模多序列场景中,则可以采用 **共享参数的 RNN/LSTM/GRU 模型** ,在所有序列上进行联合训练,从而学习到通用的时序模式。 - -在此基础上,类似 **DeepAR** 的自回归概率模型为深度时序建模提供了一个标准框架:它将历史观测和协变量输入一个共享的 RNN/LSTM/GRU 网络,在每个时间步上输出序列值的条件分布参数(如高斯、负二项分布等),并通过最大似然训练实现端到端的概率预测。这样的设计使模型能够自然生成预测区间、处理不规则的尺度和多序列混合,有利于在电商销量、需求预测等场景中落地。 - -然而,RNN 类模型存在典型问题:长序列上的梯度衰减,以及在训练阶段无法完全并行化。虽然门控机制(LSTM/GRU)缓解了部分问题,但在特别长的时间跨度和高频数据下,训练与推理效率仍然是需要权衡的因素。这也促使业界和学术界探索更加并行友好的结构,如 TCN 和 Transformer。 - -### 6.2.2 Temporal CNN 与 Transformer:从局部卷积到长序列注意力 - -为了解决 RNN 在长序列上的效率和稳定性问题,**Temporal CNN / TCN** 引入了一维卷积和膨胀卷积来建模时间依赖:通过堆叠多层因果卷积、逐层扩大感受野,它在不破坏时间因果性的前提下,实现了对远距离历史的建模。相比 RNN,TCN 在训练时可以高度并行,梯度传播路径更短,因此在训练稳定性和效率上表现突出,适合用在高频数据、需要较大感受野的工业时序预测场景中。 - -在更高的复杂度层级上,**Transformer 与时序专用结构**成为近年来长序列、多变量时间序列建模的主角。直接使用标准 Transformer 会遇到计算复杂度随序列长度平方级增长的问题,因此涌现出一系列面向时序的改造方案: - -* **Informer** 通过概率稀疏自注意力等机制,降低长序列上的计算负担,并针对预测任务优化结构。 -* **Autoformer** 将趋势与季节性分解融入自注意力框架,试图在保持长序列建模能力的同时提升可解释性和稳定性。 -* **TimesNet** 通过在时间–频率域或多尺度展开中增强对周期与模式的感知,更好地处理复杂、多周期的长序列。 -* **PatchTST** 借鉴 Vision Transformer 的“patch”思想,将连续子序列视作补丁,提高长序列时的建模效率与泛化能力。 - -这类模型往往特别适合**长序列、多变量、高维协变量**的复杂时序场景,如大规模云资源负载、多区域能源需求、多渠道流量预测等。它们可以在一个统一架构中同时建模多维输入、静态特征和时间相关变量,并通过注意力权重为后续解释与诊断提供一定线索。 - -### 6.2.3 混合与分层模型:全局 + 局部、多层级时间序列 - -在实际业务中,时间序列很少是“孤立”的:它们往往具有明显的 **层级结构与共享模式** ——例如门店/城市/区域/全国的销售层级,SKU/品类/品牌的商品层级,或业务线/产品/渠道的组织结构。如果简单地为每条序列单独建模,很难利用到这一层次结构;而直接把所有序列混在一起,又会忽略各自的个性化差异。**混合与分层模型**正是为解决这类问题而设计。 - -一类常见思路是 **全局 + 局部模型** :通过一个共享的“全局模型”学习所有序列的共性模式(如总体趋势、节假日效应、季节性),同时为每条序列或每个子群体引入局部参数或嵌入向量,捕捉个体特性。这种结构既避免了为长尾序列单独训练模型导致的数据稀疏问题,又保留了在热门序列上进行精细建模的能力。 - -另一类是 **多层级时间序列(hierarchical TS)建模** :在预测过程中显式考虑层级约束(如子层级之和需要与上层级预测一致),通过自顶向下、自底向上或中间层级的联合优化,使各层级预测在数值和结构上保持一致。在深度时序框架下,这通常表现为在输入编码中加入层级特征、为不同层级设计多头输出,或使用分层损失函数进行训练。 - -从产品视角看,这类混合与分层建模广泛应用于**电商销量预测平台、供需/运力/排班预测系统**等场景:系统需要同时给出“单店单品”“城市级别”“全国总量”等不同粒度的预测,并在资源规划和 KPI 拆解过程中保持上下层的一致性。深度模型的灵活结构,使得这类约束可以通过端到端方式嵌入建模过程,而不必完全依赖事后修正。 - -## 6.3 异常检测与变点检测(Anomaly & Change Point Detection) - -在时间序列场景中,“预测未来”只是问题的一部分,另一部分同样关键的是: **实时发现异常与结构变化** 。无论是设备运行、业务指标、交易行为,还是运维监控,异常检测与变点检测都是保障系统稳定、识别风险机会的核心能力。传统上,统计阈值法、EWMA、CUSUM 等方法广泛使用;随着数据维度和复杂度提升,各类机器学习与深度学习方法(孤立森林、One‑Class SVM、AutoEncoder/VAE、时序 GAN、GNN + 时序模型)也开始扮演重要角色。 - -从产品形态来看,这类能力往往内嵌在**设备故障预警系统、业务指标异常报警平台(如转化率突降)、安全攻击与欺诈检测系统、运维 AIOps 告警引擎**中,通过实时监控多维时序信号,自动标记可疑点和结构变更,并与规则、知识库和人工决策流程结合。下面继续从 **场景** 、**原理**和**模型**三个角度展开。 - -* **场景** - * 设备与工业系统:监控温度、振动、电流、压力等传感器数据,提前发现故障与退化趋势,减少停机和损失。 - * 业务与运营指标:监控 PV/UV、转化率、订单量、延迟、错误率等关键指标,快速发现突降、突升、异常波动,为运营和技术团队提供告警。 - * 安全与风控:分析登录行为、交易序列、访问模式等时间序列,识别潜在攻击、作弊和欺诈行为。 -* **原理** - 异常与变点检测本质上是在“正常模式”上寻找显著偏离和结构突变: - * 对于点异常和序列异常,可以通过统计分布拟合、密度估计或边界学习,判断当前观测是否落在“正常区域”之外。 - * 对于变点,则关注时间序列统计特性(均值、方差、相关结构、分布等)在时间轴上的突变,并尝试定位变化发生的时间位置。 - * 在高维和多点网络中,需要将多条时间序列之间的依赖结构(如拓扑、相关性)纳入建模,避免将局部异常与整体趋势混淆。 -* **模型** - 从方法族来看,可以大致分为统计方法、单类/孤立学习方法、重构式深度模型和图 + 时序组合模型: - * 统计异常检测:阈值、EWMA、CUSUM 等,对单变量或简单场景极其高效,是传统监控系统的基础。 - * 机器学习方法:Isolation Forest、One‑Class SVM 等,用于在多维特征空间中刻画“正常区域”,对异常样本进行孤立。 - * 深度重构模型:AutoEncoder / VAE / 时序 GAN,通过学习重构正常序列,在重构误差较大时标记异常。 - * 图神经网络 + 时序模型:在传感器网络、微服务指标等场景中,引入图结构和时序模型共同学习正常模式,强化对拓扑相关异常的识别。 - -下面,我们围绕点/序列异常、变点检测、多维与图结构三个方向展开。 - -### 6.3.1 点异常与序列异常:从统计阈值到重构式模型 - -最直观的异常检测形式是 **点异常** :某个时间点的观测值远离历史正常范围(如 CPU 使用率突然飙到 100%、交易金额异常增大、传感器读数瞬间跳变)。传统方法中,最常见的做法是对历史正常数据拟合一个统计分布或滑动统计量(均值、方差、分位数),在此基础上设定阈值或控制图(如 EWMA、CUSUM),当当前观测超出可接受区间时发出告警。优点是实现简单、计算代价低、易于解释,因此在大量运维监控和工业系统中仍然广泛使用。 - -当维度提升或模式变得更复杂时,可以引入**孤立森林(Isolation Forest)、One‑Class SVM** 等单类/孤立学习方法:它们通过在“正常样本”上学习一个聚合区域(或边界),将落在该区域之外的点视为异常。通过在序列的滑动窗口上提取统计特征(如窗口均值、方差、频域特征等),这类方法也可以用于识别局部“序列异常”(即一段时间内行为偏离正常模式),适用于多维指标和难以精确定义分布形态的场景。 - -在深度学习框架下,**基于重构误差的 AutoEncoder / VAE / 时序 GAN** 等方法则提供了更灵活的选择: - -* 使用 AutoEncoder 或 VAE 在大量正常序列上训练“压缩–重建”模型,使其学会重构正常模式; -* 在在线监控时,将新的时间窗口输入模型,如果重构误差显著增大,则认为该区间存在异常; -* 时序 GAN 类方法则通过学习生成正常序列,在判别器的判定结果或生成误差中寻找异常信号。 - -这些方法可以适应高度非线性的模式和复杂的协变量结构,特别适合在**多维业务指标、复杂设备传感器数据**上构建统一异常检测引擎。 - -### 6.3.2 变点检测:结构突变与事件生效 - -与点异常和局部异常不同,**变点检测(Change Point Detection)**关注的是时间序列在结构上的突变:例如均值从一个水平跃迁到另一个水平、波动率发生改变、周期和相关结构出现调整。这类变化往往对应现实世界中的某种事件或状态切换,如配置变更、生效新策略、政策调整、生产工艺改变、市场 regime 切换等,对业务诊断和因果分析极为关键。 - -传统统计方法中,变点检测常借助似然比检验、CUSUM、Bayesian Online Change Point Detection(BOCPD)等技术: - -* 通过在不同时间点前后拟合不同参数的模型(如不同均值/方差),比较“无变点假设”和“有变点假设”的拟合优度; -* 在在线场景中,对每个时间点递推更新“当前段落为止是否出现变点”的后验概率,一旦超过设定阈值则触发告警。 - -在更复杂的设置下,可以结合深度表示学习与分段模型,将变点检测视作 **序列分段问题** :用神经网络提取特征,再在特征空间中寻找段落边界,或者直接训练模型预测某一时间点属于“变点”的概率。这对于存在多种形态变化(不仅是均值/方差变化)、且难以用简单统计假设刻画的业务指标尤其有用。 - -在产品体系中,变点检测通常被集成在**业务指标分析平台、A/B 实验分析系统、配置与策略变更监控工具**中:当关键指标呈现结构性变化时,系统可以自动标记潜在变点,并关联相应的变更事件(如版本发布、参数调整、政策落地),为后续根因分析提供线索。 - -### 6.3.3 多维时序与图结构:GNN + 时序模型的联合建模 - -在现代分布式系统和物联网场景中,我们往往面对的是 **多点、多维、具有关联拓扑结构的时间序列** :例如传感器网络中的多个测点、微服务架构中的各个服务指标、配电网/交通网中的多个节点和边。此时,单独、逐条地对每个时间序列做异常检测,很容易误判局部波动或忽略整体模式——真正的异常往往是“局部–整体不一致”或“拓扑结构中不协调”的表现。 - -为此,近年来出现了大量**图神经网络(GNN) + 时序模型**的组合方法: - -* 首先根据现实拓扑(物理连接、网络拓扑)或基于数据估计出的相关图,构建一个表示多点之间关系的图结构; -* 在每个时间步上,用 GNN 对节点特征(各点的时序值及其局部上下文)进行消息传递,学习空间关联特征; -* 再将图编码后的表示输入 RNN、TCN 或 Transformer 等时序模型,捕捉时间维度上的动态模式; -* 最终在联合表示上进行异常评分或变点检测,实现 **时空联合的异常识别** 。 - -这种框架在**传感器网络监控、微服务指标异常检测、城市计算中的时空异常检测**等场景中尤其适用:它能够分辨“全局性变化”(如整个系统负载上升)与“局部异常”(如某个节点异常拥塞),也能更好地识别拓扑结构相关的异常模式(如链路级问题、区域性网络故障)。 - -在工程层面,这类方法通常作为**运维 AIOps 告警系统、安全与风控平台、设备群监控系统**的高阶能力出现,结合基础统计监控、规则系统和专家知识,为复杂系统提供更智能、更上下文感知的异常发现机制。 - -## 6.4 时空序列(Spatio-Temporal Modeling) - -在很多关键业务场景里,仅仅建模“时间”是不够的: **“什么时候”与“在哪里”并行存在** ,而且二者高度耦合。城市交通流量受路网结构和时间规律共同影响,气象与空气质量既依赖时间演化,也依赖地理邻近与大气流场;物流、共享单车与网约车调度则需要同时考虑需求的时空分布和道路/区域结构。**时空序列建模(Spatio‑Temporal Modeling)** 正是针对这类“时间 + 空间”联合建模问题的系统方法。 - -与纯时间序列模型相比,时空模型需要显式把**空间依赖结构**纳入考虑:相邻路段的交通流量、邻近监测站的空气质量、相连节点的负载与状态,通常比相隔较远的点更具相关性。为此,图神经网络(GNN)、卷积 LSTM(ConvLSTM)等结构被广泛用于结合空间与时间两个维度的特征学习。对应到产品层面,这类能力支撑着**城市计算平台(交通/人流预测)、气象/环境预测系统、物流路径规划与共享单车/网约车调度平台**等大量关键应用。 - -* **场景** - * 交通流量与人流预测:在路网或地铁网结构上,对不同时段的车流、人流进行预测,辅助信号灯优化、拥堵管理和调度决策。 - * 气象与环境监测:在地理网格或监测站网络上,预测未来的温度、降雨、风力、空气质量等时空分布,为预报和决策提供支撑。 - * 物流与出行调度:在城市区域或路网结构上预测订单需求、车辆分布、仓库/站点的负载情况,为路径规划、车辆调度和运力分配提供依据。 -* **原理** - 时空序列建模的核心是 **在统一框架中同时学习空间相关性与时间动态** : - * 在空间维度上,通过图结构或卷积结构刻画“谁与谁相关”,并基于此进行消息传递与特征聚合; - * 在时间维度上,利用 RNN、TCN、Transformer 或特化的时序结构刻画动态变化; - * 两者可以串联(先做空间,再做时间),也可以交织或同时作用(如时空卷积、时空注意力)。 -* **模型** - 典型时空模型大多采用“GNN + 时序模型”或“卷积 + LSTM”的组合形态: - * 图神经网络 + 时序模型:ST‑GCN、DCRNN、Graph WaveNet、ST‑Transformer 等,通过图卷积或图注意力捕捉空间依赖,再用时序结构捕捉时间动态。 - * 卷积 LSTM 类模型:ConvLSTM、Conv‑TT‑LSTM 等,在时序递推中嵌入空间卷积门控,实现对时空局部特征的联合建模。 - -下面,我们从时空任务与数据表示、GNN + 时序模型、卷积 LSTM 与时空卷积三个方向展开。 - -### 6.5.1 时空任务与数据表示:从路网到地理网格 - -在进入具体模型之前,时空序列建模首先要解决的是 **如何表示空间结构** 。与一维时间轴不同,空间结构可以是规则网格(grid)、不规则图(graph)、或者混合形式。 - -* 在交通场景中,道路与交叉口天然构成一个有向或无向图:节点表示路段或路口,边表示道路连接与行驶方向;每个节点在每个时间步上有一组特征,如车流量、平均速度、拥堵指数等。 -* 在气象与空气质量预测中,可以使用规则地理网格(如经纬度网格),或将监测站点之间的邻接关系构建为图结构,基于地理距离、风向或相关性定义边权。 -* 在物流与共享出行场景中,可以将城市划分为网格或区域单元,每个单元在时间上具有订单量、活跃车辆数等特征,同时在空间上通过邻接关系或实际道路距离相连。 - -这种“ **空间结构 + 时间序列** ”的统一表示,使得很多不同场景可以被建模为类似的问题:给定历史时空序列,预测未来若干时间步上每个节点或网格的状态。后续模型设计(无论是 GNN + 时序模型,还是 ConvLSTM)都是在这一统一视角上展开。 - -在产品层面,这一层的抽象往往封装在**城市计算平台、气象/环境预测系统、路径规划与调度平台**的数据层与建模层:业务方只需要知道“我们在路网/网格上预测未来流量/需求如何”,而底层的数据表达与时空融合由建模框架统一处理。 - -### 6.5.2 图神经网络 + 时序模型:ST‑GCN、DCRNN、Graph WaveNet 等 - -在图结构上建模时空序列,目前最主流的路线是“ **图神经网络(GNN) + 时序模型** ”的组合。代表模型包括 **ST‑GCN、DCRNN、Graph WaveNet、ST‑Transformer** 等,它们的共同特点是: - -* 在空间维度上使用图卷积(GCN)、图注意力(GAT)或谱域卷积等方法,对每个时间步的节点特征进行“邻域聚合”,从而捕捉空间依赖与拓扑结构的影响; -* 在时间维度上,通过 RNN(如 GRU/LSTM)、TCN、或 Transformer 对节点级特征进行序列建模,捕捉时间趋势和周期性; -* 通过交替堆叠或联合设计,使得模型能够在多个时空尺度上学习局部与全局模式。 - -例如,**DCRNN(Diffusion Convolutional RNN)** 将图卷积与门控循环单元结合起来,使用扩散卷积来模拟信息在路网上的传播,再通过 RNN 捕捉时间维度的动态,非常适合交通流量预测等任务。**Graph WaveNet** 则在图卷积和时间卷积的基础上,引入自适应图结构学习和多尺度建模,提高对复杂路网和非规则拓扑的适应性。**ST‑Transformer** 等模型则把自注意力机制引入时空建模,通过时空注意力模块同时考虑不同时间和空间位置之间的相关性。 - -在实际系统中,这一类 GNN + 时序模型广泛部署在**城市交通与人流预测平台、共享出行调度系统、复杂 IoT 网络监控**等产品中。它们通常作为核心预测引擎之一,与规则系统、仿真模型和业务策略共同组成闭环,使得调度与规划既能考虑全局结构,又能响应局部变化。 - -### 6.5.3 卷积 LSTM 与时空卷积:ConvLSTM、Conv‑TT‑LSTM 等 - -另一条重要路线是基于**卷积 LSTM(ConvLSTM)**及其变体的时空建模。与标准 LSTM 在时间步之间传递一维向量不同,ConvLSTM 在门控结构中使用卷积算子,使得隐藏状态和输入都保持为多维张量(如空间网格上的特征图)。这样,在每个时间步的状态更新中,既包含了时间上的递推,也在空间维度上进行了局部卷积聚合,实现了对时空局部模式的自然建模。 - -在此基础上,**Conv‑TT‑LSTM 等改进模型**尝试通过张量分解、参数分享、多尺度卷积等机制,提升模型的表达能力和效率,适应更大规模、更复杂的时空数据。例如,在气象预测中,可以使用 ConvLSTM 堆叠多层,对多通道气象要素图(温度、湿度、风向等)进行时空递推,从历史若干帧预测未来几小时或数天的空间分布;在交通和环境监测中,也可以将路网或监测点映射到规则网格上,使用 ConvLSTM 等模型进行预测。 - -与 GNN + 时序模型相比,ConvLSTM 系列在**规则网格结构、局部空间平滑性明显**的场景中使用较多,如气象雷达回波预测、空气质量网格预报、视频帧级预测等。其优势在于实现相对直接、易于利用现有卷积网络基础设施进行加速和部署,也容易与 CNN/ViT 等视觉模型协同使用,如在遥感影像时空建模中结合卷积特征和时序递推。 - -在产品形态上,这一方向的模型多用于**气象/环境预测系统、遥感时空分析平台、视频与影像时空预测**等,常常以“未来时空场景预测图”的形式向上游暴露能力,成为业务决策与可视化分析的重要输入。 - -# 7. Agent 与工具调用层(Agents & Tool Use) - -在前面的视觉、语言等能力层中,模型大多还是“被动回答”的形态——接收输入、给出输出。而在很多真实业务里,我们需要的是一个 **可以主动规划、调用外部工具、串联工作流的智能体(Agent)** :它不仅能看懂/读懂/听懂,还能自己“决定下一步做什么”,比如去查资料、跑代码、读写文件、调用内部系统,然后再把结果整合、解释并反馈给用户。 - -这一层可以被理解为“把基础模型变成可行动系统”的关键粘合层:通过 **结构化工具调用接口、工作流编排、多 Agent 协作以及人类在环机制** ,把 LLM 从一个强大的“认知内核”扩展为能够完成端到端任务的“数字员工”。 - -## 7.1 工具调用与执行(Tool Calling / Function Calling) - -在只读不写、只说不做的纯文本时代,LLM 更像一个“超级对话者”:可以理解问题、给出建议、写代码、列方案,但所有“真正执行”的工作——查数据库、跑脚本、生成文件、调云服务——仍然要人工接手完成。而**工具调用 / Function Calling** 的出现,让模型第一次可以在安全边界内“动手”:根据自然语言自动生成结构化参数,去调用搜索引擎、数据库、计算引擎、图像/音频/视频生成服务等外部能力,再把执行结果整理返回,从而形成“理解 → 决策 → 执行”的闭环。 - -从产品角度看,工具调用是绝大多数 Agent 系统的“底盘能力”:OpenAI Assistants API、LangChain、LlamaIndex、AutoGen、各类云厂商的 Agent 平台,实质上都是在 LLM 之上,围绕**如何定义工具、如何让模型正确选工具、如何处理出错与重试**搭建一层运行时。下面同样从 **场景** 、**原理**和**模型**三个角度梳理这一层能力,并在后续小节中分别展开“工具调用接口设计”“工具选择与策略”“典型工具类型”三个方向。 - -* **场景** - * 智能问答与检索增强:模型根据用户问题自动决定是否调用检索工具(向量/关键词搜索)、查企业内部知识库或公网搜索,并将查到的文档、FAQ 整合进最终回答。 - * 数据与报表自动化:面对“帮我查这段时间的销售额并画图”“给我算一下这个投资组合的风险指标”之类请求,模型自动生成 SQL 或分析参数,调用数据库和计算引擎,返回图表与结论。 - * 文档与文件操作:自动读取 PDF/Word/Excel/数据库表,抽取和汇总关键信息,或按指令生成新文件(如报表、合同、方案),并通过工具上传/存储到指定位置。 - * 媒体生成与处理:根据文本指令调用图像/音频/视频/3D 生成服务,或对现有媒体做剪辑、压缩、转码、水印等操作,形成一键“文案 + 设计 + 导出”的内容流水线。 -* **原理** - 工具调用的核心是: **用自然语言驱动结构化函数调用** 。 - * 首先以 JSON Schema 或函数签名的形式,将外部工具的名称、说明、参数结构(类型、必填项、枚举值等)暴露给 LLM。 - * 当用户发出请求时,LLM 不仅要理解语义,还要判断“是否需要调用某个工具”“需要哪个(些)工具”“这些工具的参数应该怎么填”。 - * 一旦模型决定调用某个工具,就生成一段结构化参数(通常是 JSON),由运行时去真正执行外部 API / 程序,并把执行结果以结构化形式返回给模型,让模型基于结果继续推理或生成最终回答。 - * 为保证安全与鲁棒性,系统需要在这一过程中处理参数校验、超时、错误返回、重试与回退,并对可能涉及安全/隐私的调用做权限与审计控制。 -* **模型** - 支撑这一能力的模型与框架主要包括三类: - * 支持 Function Calling 的 LLM:如 GPT‑4.1 / o 系列等,原生在解码层面理解“工具签名 + JSON Schema”,能够在合适时机主动或被动地产生结构化调用参数。 - * 工具增强推理范式:如 ReAct、Toolformer,将“思考 + 工具调用”编织进同一推理链条,将工具使用视作中间步骤的一部分,而不是简单的前/后处理。 - * 工程框架与运行时:OpenAI Assistants API、LangChain、LlamaIndex、AutoGen、各云厂商 Agent 平台等,为工具定义、调用路由、状态管理、错误处理与日志审计提供基础设施,让开发者可以聚焦在“暴露哪些工具”和“抽象怎样的业务 API”上,而不必从零搭建运行时。 - -### 7.1.1 工具调用接口:从自然语言到结构化函数调用 - -一个可用的工具调用系统,首先需要一个清晰、规范、对 LLM 友好的“工具接口层”。它承担着把外部世界的 API、脚本、服务包装成模型可理解、可安全调用的“函数”的职责,让模型可以像写伪代码一样“说出”自己希望调用的工具及其参数。 - -* **工具定义与参数模式** - 在接口层,通常会用类似 JSON Schema 或函数签名的结构定义每个工具:包括名称(name)、说明(description)、参数字段(properties)、类型(string / number / boolean / array / object)、是否必填(required)、取值范围或枚举等。 - 这些信息一方面被用来驱动前端/SDK 的类型检查,另一方面也直接提供给 LLM,帮助模型“学会”如何正确填写参数。描述越清晰、约束越合理,模型生成的调用就越规范,出错率越低。 -* **LLM 生成结构化参数** - 当用户提出“帮我查 2024 年 Q3 的营收并画一张按地区拆分的柱状图”这类请求时,模型需要先推理出:这至少需要一个“报表查询工具”(访问数据)、可能还需要一个“图表生成工具”(画图)。对每个工具,它要从原始语言中抽取并映射结构化参数,如时间范围(start_date/end_date)、维度(region)、指标(revenue)、图表类型(bar)、输出格式等,然后以 JSON 输出交给运行时。 - 这个过程中,模型本质上在做“自然语言 → 任务规划 → 参数抽取 / 填充”的一体化推理,因此工具描述的自然语言提示、参数示例和 few‑shot 样例都非常关键。 -* **工具执行与结果回传** - 运行时接收到模型产出的 JSON 调用后,会先进行参数校验与安全检查,再去真正调用后端 API 或程序。执行完成之后,将结果封装为结构化对象(如查询结果表格、文件 URL、媒体资源 ID 等)返回给模型。 - 随后,模型会把这些原始结果转化为用户可读的解释或进一步加工,如总结报表、生成自然语言分析、嵌入图表标注说明等。对于模型而言,工具结果只是中间信息的一部分,它仍然要负责“理解结果 + 解释结果”。 - -### 7.1.2 工具选择与策略:在多工具世界里做决策 - -当系统中只有一个工具时,“要不要用工具”是唯一的问题。但在现实 Agent 应用中,往往会有几十甚至上百个工具:不同数据源的检索、不同部门的业务 API、不同技术域的生成/分析能力,这就引出了一个新的挑战: **模型如何在多工具环境下做合理的选择和编排** 。 - -* **工具选择与路由** - 首先,模型需要判断“当前请求是否需要调用工具”,以及“需要调用哪一个(或哪几个)工具”。这通常通过在系统提示中列出可用工具的说明,并提供典型示例,让模型学会根据用户意图选择合适工具。 - 对于工具数量较多、描述相似度较高的场景,很多框架会引入“工具路由器”(如基于向量检索或规则的前置筛选),先从大列表中筛出若干候选工具,再暴露给 LLM 选择,从而降低模型负担和误选概率。 -* **多工具顺序与组合** - 复杂任务往往需要多个工具协同完成。例如“调研某行业主要上市公司,并生成一份包含财务对比图表的报告”,可能涉及搜索引擎、财报数据库、计算引擎、图表生成工具、文档导出工具等。 - 在这种情况下,模型需要做一个轻量级的任务规划:先用哪个工具获取列表,再对列表逐个查询详细信息,之后合并数据、做计算与可视化,最后调用导出工具生成报告。典型实践包括 ReAct/Planner‑Executor 思路,让模型在“思考(Plan)—调用(Act)—反思(Reflect)”的循环中,逐步完成工具组合调用。 - -### 7.1.3 典型工具类型:从检索到媒体生成的能力拼图 - -不同类型的工具,为 Agent 系统提供了不同维度的“外接大脑”。从工程实践来看,以下几类工具几乎是所有复杂应用的“标配”。 - -* **检索工具:向量与关键词搜索** - 检索工具负责把“记忆”扩展到外部世界: - * 关键词搜索适合结构化较好、字段清晰的传统文档和业务数据库。 - * 向量搜索则通过嵌入(embedding)为非结构化文本、代码、对话记录、甚至多模态数据建立语义索引,支持“模糊但语义相关”的检索。 - 在 RAG 场景中,LLM 通过检索工具拉取与用户问题相关的上下文,再在此基础上进行推理与生成,大幅提升回答的时效性和准确性。 -* **代码执行与计算引擎** - 代码执行类工具(如 Python/JS 沙箱、Notebook 执行器)让 LLM 可以“写一段代码并立即跑起来”,解决复杂计算、数据处理、数值模拟、可视化等问题。 - 模型负责产出代码与输入参数,执行环境负责安全隔离、资源限制与结果收集。这类工具在数据分析、量化研究、自动化报表、科学计算以及 Agent 自我验证(模型生成答案后用代码校验)等场景中非常关键。 -* **文件与数据源访问** - 文件读写工具负责将外部文件系统和数据源引入到 Agent 视野中:读取 PDF/Word/Excel、访问数据库表、调用内部业务 API 等。模型通过这些工具获取真实业务数据,再进行归纳、对比和报告生成。 - 与之配套的还有文件写入与管理工具:将生成的报告、图表、PPT、代码等持久化存储,并返回链接或 ID,方便用户后续访问与集成。 -* **媒体生成与处理工具** - 媒体生成工具则为 Agent 增添了“创作”和“设计”的手臂: - * 图像/视频生成与编辑:根据文案自动生成配图、海报、分镜,或对已有媒体进行裁剪、上字幕、加水印等。 - * 音频生成与处理:TTS、配音、音乐生成、音频增强与剪辑。 - * 3D / 工程类工具:生成简单 3D 场景、CAD 草图、UI 原型等。 - 在内容生产、营销设计、教育培训、游戏与多媒体应用中,这类工具让“从想法到成品”更接近一条自动化流水线。 - -综合来看,工具调用与执行把 LLM 从“语言模型”扩展为“具备行动接口的通用控制器”:模型通过语言理解需求与环境,通过工具执行真实操作,通过反馈不断修正策略。搭配合适的工作流编排与多 Agent 协作(见 7.2),就构成了新一代智能应用的基础架构。 - -## 7.2 工作流编排与多 Agent 协作(Workflow & Orchestration) - -有了工具调用能力,LLM 不再只是一个“回答问题的人”,而可以成为面向具体任务的“执行单元”。但现实业务往往远比单次对话复杂:一个完整的诉讼分析、一次市场调研、一轮 A/B 实验配置、一次端到端运维处理流程,通常都需要多步操作、多种工具、甚至多方角色长期参与。这时,单一 LLM + 工具的模式就显得吃力,需要进一步的 **工作流编排与多 Agent 协作** 。 - -从系统视角看,这一层的职责是: **把一个复杂的、多步骤、多参与方的业务流程,抽象成可被 LLM 理解与操控的工作流图** ,然后在这个图上调度一个或多个 Agent,配合人类干预,共同完成任务。典型实现包括 Planner‑Executor 型 Agent 架构、具备反思 / 自我修正能力的 Agent、以及基于图结构的 Workflow Orchestrator;相应的产品形态则是各类自动报告生成与运营自动化平台、低代码工作流 + LLM 集成、复杂业务流程机器人、自动运维系统等。 - -* **场景** - * 报告与内容流水线:从“接收需求 → 检索与数据拉取 → 分析和可视化 → 撰写报告 → 审核修改 → 导出与分发”,将多步内容生产流程自动化或半自动化。 - * 业务流程自动化:如电商运营中的“商品分析 → 竞品监控 → 活动策略生成 → 落地配置”,运维场景中的“监控告警 → 根因分析 → 缓解措施执行 → 复盘报告”等。 - * 跨角色协作:让不同领域 Agent(法律、财务、技术、运营)围绕一个复杂项目协同工作,例如并购尽调、投融资材料准备、大型项目标书编制。 -* **原理** - 工作流与多 Agent 协作的核心,是在 LLM 之上再加一层 **结构化控制与状态管理** : - * 将复杂任务拆分为若干有依赖关系的子任务,用 DAG / 状态机 / 有向图等结构表示,并为每个节点配置触发条件、输入输出和所需 Agent/工具。 - * 由 Planner 型 Agent 或上层 orchestrator 决定何时触发哪个节点、用哪个 Agent 或工具,并根据执行结果动态调整后续路径(条件分支、循环、错误回退)。 - * 在关键环节引入人类在环(Human‑in‑the‑loop),对高风险决策和关键输出进行人工确认与编辑,并将人类反馈回流到系统,用于更新策略或微调模型。 -* **模型** - 支撑这一层的主要技术方向包括: - * Planner‑Executor 型 Agent 架构:由一个“规划 Agent”负责任务分解与路径设计,一个或多个“执行 Agent”负责具体步骤的落地实施。 - * 反思 / 自我修正 Agent:在执行过程中不断回顾自己的表现,对不合理的中间结果进行反思和修正,减少“自信错误”的静默扩散。 - * Graph‑based Workflow Orchestrator:将整个任务流程建模为图结构,引入节点状态、边条件、并行/串行控制等机制,使 LLM 调用变成图中的一个或多个节点,而不是唯一的控制中心。 - -### 7.2.1 任务分解与规划:从“一句话需求”到可执行流程 - -用户给 Agent 的通常是一句高度压缩的自然语言需求,例如“帮我做一个关于新能源车行业的市场调研并输出 PPT”,背后实际包含了检索、筛选、分析、可视化、排版、多轮修改等大量步骤。如何从这句话出发,自动构建一条清晰、可执行的工作流,是工作流编排的第一步。 - -* **从自然语言到子任务图** - Planner 型 Agent 首先需要把需求“展开”:结合内置模板、历史案例、以及工具清单,识别出关键阶段(如信息收集、数据分析、结构设计、内容撰写、审校与导出),并进一步细化为可执行子任务(如“检索 5 篇近一年权威行业报告”“拉取近 3 年销量数据并按车型细分”“生成 3 张对比图表”等)。 - 这些子任务之间的依赖关系和调度逻辑,会被显式表示为一张图或一个状态机:哪些可以并行、哪些必须顺序执行、在哪些节点需要人工确认、在什么条件下需要回退或重试。 -* **条件分支、循环与异常路径** - 真实流程往往并不是线性流水线,而是包含 **条件分支** (如“如果检索不到足够高质量报告则换关键词或换数据源”)、 **循环** (如“持续尝试改写和压缩,直到报告长度满足限制”)和 **异常路径** (如“某个数据源不可达时,切换到备选源或采用估算方法”)。 - 这要求工作流编排层能够在图结构上表达 if/else、while/for、try/catch 等控制流语义,并允许 Planner Agent 或上层 orchestrator 在运行过程中根据实时结果做决策,而不仅仅在开始时一次性规划好所有步骤。 -* **与工具调用的衔接** - 任务分解与规划与 7.1 中的工具调用是紧密相连的:Planner 在生成子任务时,往往会同时指定“该任务需要用到哪些工具/Agent”和“该节点的输入输出格式”,为后续自动参数填充和工具执行打基础。 - 一些系统会采用“Plan + Execute”显式两阶段:先由 Planner 输出一个机器可读的计划(如 JSON 工作流描述),再由 Executor 严格按计划调用工具与 Agent;也有系统采用 ReAct 风格,将“思考–工具调用–观察–再思考”编织在同一对话中,以获得更灵活的自适应执行。 - -### 7.2.2 多 Agent 协作:让“虚拟团队”各司其职 - -单个大模型固然强大,但在复杂业务场景中,不同领域往往需要不同的知识结构、风格偏好和安全策略。**多 Agent 协作**的思路,是把一个“大而全”的智能拆解为多个“专而精”的角色:有人负责规划,有人负责执行,有人负责审校,有人负责领域专业判断,形成一个由 Agent + 工具 + 人类共同组成的虚拟团队。 - -* **角色分工:规划、执行与审校** - 在一个典型的多 Agent 流程中,常见角色包括: - * 规划 Agent:负责理解用户需求、设计整体计划、拆分子任务,并在执行过程中根据结果动态调整路径。 - * 执行 Agent:围绕某些工具或子领域进行深度优化(如检索 Agent、数据分析 Agent、内容撰写 Agent),按规划要求完成具体步骤。 - * 审校 Agent:从结构性、逻辑性、风格一致性和风险控制等角度,对中间和最终产出进行检查和修订,类似“虚拟编辑/Reviewer”。 -* **领域专家 Agent 协同** - 对于法律、金融、技术、运营等专业性极强的领域,可以进一步细分出领域专家 Agent:如“法律顾问 Agent”“投研分析 Agent”“云原生运维 Agent”“广告投放优化 Agent”等。 - 它们可以基于领域专用知识库、工具、甚至专门微调模型,参与项目式协作:例如在一份投融资材料中,由技术 Agent 负责技术可行性部分,财务 Agent 负责财务模型与估值,法律 Agent 负责合规与风险披露,运营 Agent 负责市场与增长策略,再由总控 Agent 汇总和统一风格。 -* **协作协议与消息路由** - 多 Agent 协作的关键,还在于“谁在什么时候跟谁说话”。系统需要一个消息路由与协调机制: - * 决定某条用户请求或中间结果应当被哪个 Agent 处理。 - * 维护共享上下文与各自的私有记忆。 - * 控制并行与串行执行,以及冲突解决(如不同 Agent 提出相互矛盾的建议时如何仲裁)。 - 这类能力通常由上层 orchestrator 或“管理 Agent”提供,而 LangChain、AutoGen 等框架则在工程层面提供了对话路由、多 Agent 会话、角色设定等基础设施。 - -### 7.2.3 人类在环(Human‑in‑the‑loop):把风险关口握在手里 - -即便工作流与多 Agent 协作再智能,真实业务中仍然无法完全脱离人类判断,尤其在**高风险、高成本、高敏感度**的场景下,如法律合规、金融决策、医疗建议、大规模生产变更、舆情响应等。**人类在环(Human‑in‑the‑loop)** 的设计,正是要在自动化与可控性之间找到平衡:该自动的自动,该人工确认的一定要停下来让人看一眼。 - -* **关键步骤人工确认** - 在工作流图中,通常会显式标记若干“人工审批/确认节点”: - * 例如在自动生成合同时,在签发前需要法务和业务负责人双重确认; - * 在自动运维系统中,对涉及生产环境变更、批量重启、配置修改的操作,必须有值班工程师点击确认; - * 在内容生成场景中,对大量公开发布或品牌敏感的内容,需要人工审稿。 - Orchestrator 会在这些节点暂停自动执行,将中间结果发送给对应人类角色,并在收到反馈后再继续后续流程。 -* **反馈驱动的策略更新** - 人类不仅在某一时刻“按下通过或驳回”,更重要的是反馈的内容可以被系统吸收: - * 将人工修改后的版本与原始输出对比,作为“正负样例”记录下来,用于后续的提示优化或模型微调。 - * 基于统计分析,识别出哪些类型的任务/步骤最容易被人工反复修改,进而优化对应 Agent 的提示词、工具组合或工作流设计。 - * 在极端或异常案例中,人工可以添加“黑名单 / 白名单 / 特殊规则”,直接影响系统在类似情况中的策略选择。 -* **风险分级与可观测性** - 最后,人类在环还需要一套清晰的风险分级和可观测性机制: - * 根据任务类型、影响面、金额规模、涉及的敏感信息等维度,将流程分为不同风险等级,对应不同强度的人类介入(如只读审阅、强制审批、多级审批)。 - * 通过日志、审计、可视化看板等方式,让运营/管理人员能够随时追踪哪些任务在跑、跑到哪一步了、哪些地方触发了人工介入、历史上出现过哪些失败与人工修正。 - 这些能力不仅提高了系统在企业内的可接受度,也为后续的合规审查和责任划分提供了基础。 - -综合来看,工具调用与执行(7.1)解决的是“单步行动”的问题,而工作流编排与多 Agent 协作(7.2)则试图回答“如何把很多步串起来,让不同角色长期协作并可控运行”。两者叠加,再加上人类在环与良好的工程实践,构成了面向真实业务场景的新一代智能应用底座。 - -# 8. 检索增强与知识层(Retrieval & Knowledge) - -在前面的视觉与理解层中,模型主要依赖“自身参数里学到的知识”来理解和生成内容。但在真实业务里,很多问题并不能只靠“记忆”解决:企业内部制度每天在变、法规和行业标准持续更新、某个客户的历史记录只存在于内部数据库。这时,仅靠模型“背过”的知识远远不够,更关键的是能否在 **外部知识库、结构化数据和图谱上进行高效检索与推理** 。 - -可以把这一层理解为:在模型能力之上,再加一层“会查资料、会用数据库的外脑”。当用户提出问题时,系统不再直接生成答案,而是先去合适的数据源里“翻资料”:文档库、数据库、搜索引擎、知识图谱、日志与业务系统……然后再让模型基于真实检索到的内容来给出回答与决策。这样不仅能显著提升准确性和时效性,还能在很大程度上提升可解释性和合规性(例如可引用出处、保留执行 SQL 记录等)。 - -围绕这一层,常见能力大致可以分为两个方向:一是 **检索增强生成(RAG)** ,主要面向“自然语言问答 + 文档/知识库检索”;二是 **结构化数据与知识图谱(Structured Data & KG)** ,负责对数据库、图数据库和领域知识中台进行更精准、可控的访问与推理。下面分别展开。 - -## 8.1 检索增强生成(RAG) - -RAG(Retrieval‑Augmented Generation)可以看作是“会查资料的 LLM”。与纯粹依赖模型内部参数不同,RAG 在回答每一个问题前,都会先去外部知识库做检索,把与问题最相关的若干段文档片段(chunk)找出来,然后再把这些检索到的内容作为“上下文”喂给 LLM,让它在“看过资料”的基础上生成答案。对于企业知识库问答、行业报告搜索、法律/医疗/金融专业问答、内部文档搜索机器人等场景,RAG 已经成为默认范式。 - -在系统架构上,典型 RAG 可以拆解为三层: **索引构建层、检索层、生成层** 。前两层主要是“查得准”,后一层则负责“说得清”。下面从这三层来展开,并在二级小节中进一步细化核心设计与实践。 - -* **场景** - * 企业内部知识问答:员工用自然语言提问制度流程、技术文档、项目资料,系统基于内部文档与 Wiki 检索相关内容后,由 LLM 生成清晰回答并附带引用。 - * 行业报告与研究搜索:在大量 PDF、报告和论文中检索某个行业问题的相关内容(如“新能源车补贴政策变化”),并自动总结、对比和列出处。 - * 法律 / 医疗 / 金融领域问答:基于法规条文、判决文书、临床指南、产品说明书等权威材料进行检索增强,降低“胡编乱造”的风险。 - * 内部文档 / 工单搜索机器人:帮助运营、客服、研发快速在知识库、工单和变更记录中定位答案,并以自然语言总结结果。 -* **原理** - RAG 的核心思想是把“知识存贮在外部,推理交给模型”: - * 将非结构化文档(PDF、网页、Word、技术文档等)拆成适合检索的文档块(chunk),用 Embedding 模型将其映射到向量空间,并构建向量索引(如 FAISS、Milvus、PGVector 等)。 - * 在用户查询时,同时利用语义向量检索与关键词检索(Hybrid Search),找到与问题最相关的若干文档块,并根据相关性和覆盖度做重排序(Re‑ranking)。 - * 将检索到的上下文、用户提问、以及必要的系统指令/格式约束一起输入 LLM,由模型在“可见证据”的约束下进行回答,并在输出中引用出处(source citation),以提升可解释性和可审计性。 -* **模型** - 典型 RAG 系统往往是一个 **模型组合架构** : - * Embedding 模型:用于将查询和文档块编码到同一个语义空间,是向量检索效果的关键(包括通用 Embedding 和领域定制 Embedding)。 - * 检索与重排模型:Hybrid Search(如 BM25 + Vector)负责第一轮召回,Cross‑Encoder Re‑ranker 或 LLM 本身用于对召回结果做更精细的重排序。 - * 生成模型:LLM 在给定检索上下文的前提下进行回答;在更复杂的 RAG / HyDE / ReAct + RAG 中,LLM 还会参与“伪文档生成”“多轮工具调用”“思考 + 检索交替”等过程,以提高召回、减少遗忘和增强推理能力。 - -### 8.1.1 索引构建与知识资产整理 - -在任何 RAG 系统中,索引构建都是基础。没有高质量的索引,后续再强大的 LLM 也只是“巧妇难为无米之炊”。索引构建的目标,是把杂乱无章的文档资源转化为“可检索、可维护、可扩展的知识资产”。 - -从流程上看,典型索引构建包括以下几个关键步骤: - -1. **文档分块与预处理** - 文档往往是长篇 PDF、PPT、Word 或网页,如果直接对整篇文档做向量化,既容易造成“稀释”(一篇文档包含多个主题),也不利于高效检索。因此需要: - 1. 按段落、标题、页码、章节结构进行分块,平衡“语义完整度”和“块大小”; - 2. 处理格式问题(表格、公式、图片中的文字 OCR)、去噪(页眉页脚、目录、版权信息等); - 3. 为每个块生成“上下文标签”(如所属文档、章节标题、页码),为后续解释与引用做好准备。 -2. **Embedding 与向量索引** - 在分块基础上,对每个文档块生成语义向量: - 1. 选择合适的 Embedding 模型(如通用语义 Embedding、领域微调模型),确保对目标语言和领域术语有良好表达能力; - 2. 使用 FAISS、Milvus、PGVector 等构建高维向量索引,支持大规模数据下的近似最近邻检索; - 3. 处理多版本与增量更新:当文档更新时,需要支持增量重建索引、版本记录和旧版本清理策略。 -3. **元信息索引与过滤** - 单纯的语义向量并不足以应对复杂过滤需求,通常还需要构建 **元信息索引** : - 1. 为每个文档块补充时间、作者、来源、文档类型、业务线、敏感级别等元数据; - 2. 支持在检索时基于元信息进行预过滤(如时间范围、部门、权限等级),减少无关结果; - 3. 为权限控制与审计打下基础,避免 RAG 在回答中泄露用户无权访问的内容。 - -### 8.1.2 检索与重排序:从“召回相关”到“找到最合适的证据” - -在索引构建完成后,当用户发起查询,就进入检索与重排序阶段。这里的关键不只是“找一些相关文档”,而是要尽可能找到 **既相关又覆盖充分、且支持推理的证据组合** 。 - -1. **Hybrid 检索:向量 + 关键词的互补** - 纯向量检索擅长捕捉语义相似度,但对于精确术语、代号、表格字段等,关键词检索(如 BM25)往往更稳健。因此工程实践中普遍采用 Hybrid Search: - 1. 首先对查询分别进行向量检索和关键词检索,得到两组候选文档块; - 2. 使用加权打分或学习到的融合策略,将两路候选合并; - 3. 在一些场景中,可根据查询类型(FAQ 问答 vs. 法条定位)动态调节向量与关键词检索的权重。 -2. **重排序(Re‑ranking):更精细地挑选“证据集”** - 初始检索结果往往包含不少“边缘相关”或“冗余”文档块,需要重排序来提升最终 Top‑K 的质量: - 1. 使用 Cross‑Encoder(交叉编码器)对“查询–文档块”对进行双向编码和相关性打分,相比双塔 Embedding 模型精度更高,但开销较大,适合作为二阶段重排; - 2. 在性能允许时,引入 LLM 进行轻量级重排,让模型基于更丰富的语义和上下文信息来判断哪些块真正“有用”; - 3. 同时考虑覆盖度与多样性,避免所有检索块都集中在同一文档或同一段落,从而导致回答视野过窄。 -3. **检索–生成闭环优化** - 更高级的实践中,检索和生成不再是单向流程,而是形成闭环: - 1. 利用 LLM 对检索结果的“使用情况”进行分析(哪些块被引用、哪些块总是被忽略),反向指导索引和分块策略的优化; - 2. 利用对话日志中的“追问/纠错”信号,对召回失败、误召回的样本进行标注和再训练,提高系统对模糊查询、长尾问题的鲁棒性。 - -### 8.1.3 生成与引用:在“证据约束下”回答问题 - -最后一环是生成层,它直接决定了用户体验。这里的目标不是让模型“随心所欲”地发挥,而是让它在 **检索证据的约束下,给出清晰、有边界、有引用的回答** 。 - -1. **基于检索上下文的受控生成** - 在 RAG 架构中,LLM 接收到的不只是用户问题,还包括多段检索到的文档块以及系统指令。系统通常会: - 1. 通过 Prompt 约束模型“只根据给定文档回答”“如果文档中找不到答案就明确说明缺失”; - 2. 对检索上下文进行结构化组织(分段、编号、标注来源),方便模型理解与引用; - 3. 控制输出格式(列表、表格、分点说明等),适配下游系统或前端展示。 -2. **引用与可解释性(Source Citation)** - 为了便于审计与追溯,尤其在法律、医疗、金融、企业内部制度等高风险领域,回答中往往需要附带明确引用: - 1. 在输出中标注引用来源,如“[文档 A,第 3 章,第 2 节]”“[法规 X 第 12 条]”; - 2. 在前端界面中支持一键跳转到原文位置,便于用户核查和进一步阅读; - 3. 在后台保存“问题–检索结果–引用块–最终回答”的完整链路日志,为后续风控和模型改进提供数据。 -3. **先进 RAG 变体:HyDE / ReAct + RAG 等** - 为进一步提升难题场景下的效果,实践中还会使用更复杂的 RAG 变体: - 1. HyDE:由 LLM 先根据问题生成一个“假想答案文档”,再用该文档向量去检索真实文档,从而提高召回质量; - 2. ReAct + RAG:LLM 以“思考(Reasoning)+ 行动(Action)”的方式,在推理中多次调用检索工具,逐步细化问题、补充证据,类似“边思考边查资料”; - 3. 多轮 RAG:在对话过程中,保留历史检索结果和回答,形成上下文感知的长期知识会话,而不仅是“单问单检索”。 - -## 8.2 结构化数据与知识图谱(Structured Data & KG) - -如果说 RAG 主要解决“如何在大规模非结构化文档中查资料”,那么结构化数据与知识图谱这一层,则更多面向“如何优雅地用好数据库、报表系统和图数据库中的结构化知识”。 - -在企业环境中,真正关键的业务数据——订单、客户、合同、库存、行为日志——往往以关系数据库、数据仓库、OLAP 引擎或图数据库的形式存在。这些系统在查询能力、计算效率和审计方面已经非常成熟,但对于业务人员而言,直接写 SQL / DSL 仍然门槛较高。**Text‑to‑SQL / Text‑to‑DSL** 与 **知识图谱问答与推理** ,就是要让 LLM 在不破坏这些系统稳定性的前提下,作为“自然语言界面”和“推理协作伙伴”插入进来。 - -* **场景** - * BI 智能问答与自助分析:业务人员用自然语言发问(如“帮我看看最近 3 个月华东地区新客的复购率趋势”),系统自动生成 SQL,查询数据仓库,然后用自然语言和可视化图表返回结果。 - * 运营 / 销售分析助手:运营同学可以用对话的方式探索数据(“这个活动转化率为什么下降”“哪些渠道贡献了最多高价值用户”),在多轮对话中逐步细化条件和维度。 - * 领域知识中台:将实体、概念、规则和案例组织为知识图谱,支持围绕某个实体进行上下游关系探索和合规性检查。 - * 图数据库问答与推理系统:在风险控制、反洗钱、供应链分析等场景中,通过图数据库与 LLM 联合,对“关系链条”和“多跳推理”类问题进行回答与解释。 -* **原理** - 这一层的核心,是把 LLM 从“直接给答案的人”变成“会调用数据库与图数据库的助手”: - * 在数据库问答中,模型需要理解用户的自然语言意图,结合数据库 schema(表结构、字段含义、约束等),生成正确的 SQL / GraphQL / 内部 DSL,再对执行结果进行解释与可视化。 - * 在知识图谱场景中,系统需要先从文档和日志中抽取实体和关系,构建结构化图谱;然后在问答时由 LLM 负责把自然语言问题转译为图查询(如 Cypher),并基于查询结果进行多跳推理和解释。 - * 与 RAG 不同,这里强调的是 **对结构化数据与图结构的精确访问** ,一方面要保证语义正确、语法严谨,另一方面要控制侧写攻击、敏感数据暴露和高成本查询。 -* **模型** - 典型方案通常是“LLM + 专用组件”的多模块架构: - * Text‑to‑SQL 模型:在大规模 SQL 语料上预训练或微调的模型(如 PICARD、DIN‑SQL 等),侧重语法正确性与 schema 对齐,有时会搭配执行反馈进行自我修正。 - * 信息抽取与图谱构建 pipeline:通过实体识别(NER)、关系抽取、事件抽取等模块,从文本和日志中构建和更新知识图谱;LLM 可以参与难例抽取、边界模糊关系的辅助判断。 - * LLM + 图数据库联合问答:LLM 负责问题解析、查询生成与结果解释,图数据库(如 Neo4j 等)负责高效执行与多跳关系搜索,两者通过工具调用协议或中间 DSL 对接。 - -### 8.2.1 数据库问答(Text‑to‑SQL / DSL)实践 - -数据库问答的目标,是让业务人员“用自然语言问数据”,而系统在背后自动完成查询语句生成、执行与解释。要把这件事做好,关键在于兼顾 **语义准确性、语法正确性和执行安全性** 。 - -1. **自然语言到 SQL / DSL 的转换** - 在最基础的链路中,系统需要: - 1. 解析用户意图:识别出查询对象(如“华东地区新客”)、过滤条件(时间、地区、渠道)、聚合方式(总数、平均值、同比/环比)和展示需求(趋势、排行、Top‑N); - 2. 结合数据库 schema:理解哪些表与字段可以表达上述概念,如何进行关联(join)、分组(group by)和排序; - 3. 生成可执行的 SQL / GraphQL / 内部 DSL,并通过语法校验器或专门的 Text2SQL 模型(PICARD、DIN‑SQL 等)确保结构合法。 -2. **执行结果的自然语言解释与可视化** - 查询执行后,系统还需把“冷冰冰的结果集”变成“可理解的洞察”: - 1. 对简单结果进行文本解释,如“过去 3 个月华东地区新客的复购率整体呈上升趋势,从 15% 提升到 21%”; - 2. 对复杂结果选择合适的可视化形式(折线图、柱状图、饼图、分布图等),并给出简要分析; - 3. 支持用户基于当前结果继续追问(如“这波增长主要来自哪些渠道?”),自动在历史 SQL 和上下文的基础上构造新的查询。 -3. **安全与控制:防止“乱查”和“越权”** - 由于 LLM 生成的 SQL 具有高度灵活性,必须有一层安全与治理机制: - 1. 基于用户角色与权限,对可查询的库、表、字段和时间范围做严格限制; - 2. 为模型生成的 SQL 配备静态/动态审查规则,过滤危险操作(如大范围扫描、高成本 join、跨租户查询等); - 3. 将“自然语言问题–生成 SQL–执行结果–最终回答”完整记录,用于审计与异常分析。 - -### 8.2.2 知识图谱构建与查询 - -知识图谱试图把散落在文本、表格、日志中的知识,组织成“实体–关系–属性–事件”的结构化网络,从而更好地支持 **关系探索、多跳推理和复杂问答** 。在这一方向上,LLM 与传统信息抽取、图数据库形成了良好的互补。 - -1. **从文档中抽取实体和关系构建图谱** - 构建知识图谱通常采用多阶段 pipeline: - 1. 信息抽取:利用 NER、关系抽取、事件抽取等模型,从文本中识别实体(人、机构、产品、地名、概念等)、它们之间的关系(隶属、合作、依赖、因果)以及关键事件(交易、风险、变更); - 2. 规范化与对齐:将同一实体的不同表述(简称、别名、拼写变体)进行归一,对齐到统一 ID; - 3. 图谱更新与版本管理:支持增量更新、冲突解决和错误纠正,确保图谱在长期演化中保持质量与一致性。LLM 可以在歧义消解、关系类型细化、规则归纳等环节辅助传统算法。 -2. **LLM + 图数据库(Neo4j 等)的查询与推理** - 当图谱构建完毕,图数据库负责高效存储和检索,而 LLM 则可以扮演“自然语言入口 + 推理控制器”的角色: - 1. 问题解析与图查询生成:将自然语言问题转译为图查询语句(如 Neo4j 的 Cypher),包括确定起点实体、关系类型、路径长度与过滤条件; - 2. 多跳推理:通过图查询得到的路径和局部子图,再由 LLM 进行解释与归纳,如“客户 A 与高风险实体 B 之间通过三家公司间接相连”; - 3. 结果可视化与可解释性:将图查询结果以可视化网络形式呈现,同时由 LLM 给出口头说明,帮助用户理解复杂关系结构。 -3. **领域知识中台与统一服务** - 在更大规模的企业或行业级应用中,知识图谱往往作为“领域知识中台”存在: - 1. 为上层业务系统(风控、合规、客户 360 视图、供应链分析等)提供统一的实体和关系视角; - 2. 与 RAG、数据库问答共同构成统一的知识服务层,由统一的 LLM 编排逻辑决定当前问题该访问文档索引、关系数据库还是图数据库; - 3. 在安全和合规要求下,通过图谱层面的访问控制和脱敏策略,进一步降低敏感信息泄露的风险。 - -这一层的共同目标,是把“模型会说话”升级为“模型既会说话,又真正接上了企业的真实数据与知识资产”。当 RAG、Text‑to‑SQL、知识图谱与传统数据基础设施有效结合之后,AI 系统才能在复杂业务环境中既保持智能和灵活性,又具备可控性、可解释性和长期演化能力。 - -# 9. 安全、对齐与评估(Safety / Alignment / Evaluation) - -在前面的章节里,我们更多从“模型能做什么”出发:能看图、能写代码、能和用户对话。但在真实的大模型系统中,仅仅“有能力”远远不够:**怎么证明这些能力是稳定、可靠、可控的?怎么确保输出符合价值观和合规要求?在长周期运营中如何持续监控、迭代与回归?** - 这一层关注的就是: **能力评估与基准测试、价值对齐与训练、内容安全与合规、以及鲁棒性与幻觉控制** ,共同构成一个可持续运营的大模型“基础设施层”。 - -从产品视角看,这些能力贯穿模型全生命周期:模型在实验室阶段需要标准 Benchmark 与专业评估;上线前要通过对齐训练与安全审查;上线后依赖内容安全网关、日志审计与 A/B 测试持续监控;面对新场景与新威胁时,又要回到评估与对齐环节重新训练和验证。下面我们从**能力评估与基准测试、价值对齐与训练、内容安全与合规、鲁棒性与幻觉控制**四个方向展开。 - -## 9.1 能力评估与基准测试(Capability Evaluation & Benchmarks) - -在大模型研发和落地过程中,**能力评估与基准测试**是把“模型能力”转化为“可观测信号”的关键一环:既要回答“这个模型总体水平怎么样”,也要回答“在某个专业领域、某种真实业务场景下表现如何”。一方面,我们通过标准化的基准集与自动评测体系,去衡量模型在**语言理解与生成、推理与数学、知识与事实性**等通用维度上的表现;另一方面,还需要针对**医疗、法律、金融、教育**等专业领域构建专门评测,并在**真实用户对话、AB 测试和业务指标(Task Success Rate、CSAT、工单关闭率等)中不断验证与修正。整体上,这一层最终会沉淀为内部的能力评估平台**与对外的“ **能力说明书** ”,并为多版本、多租户、多场景的模型选型提供统一决策依据。下面从 **场景** 、 **原理** 、**模型**三个角度展开。 - -* **场景** - * **通用能力评估场景** :在基础模型或大版本更新时,需要系统性地评估其在阅读理解、摘要、翻译、对话质量等**语言理解与生成**任务上的表现,以及在算术、多步推理、代码/逻辑题等**推理与数学**任务中的能力,同时通过事实问答、开放域 QA、知识覆盖度任务衡量其**知识与事实性**水平,用于判断“新模型是否整体抬升”。 - * **专业领域评估场景** :对于医疗、法律、金融、教育等细分领域,需要设计专业问答与决策模拟,比如疾病问答与分诊建议、法律条文理解与案例归类、投融资分析与风控判断、教学答疑与作业辅导,并在**多语言、多文化环境**下测试模型的一致性与稳定性,确认其能否在高风险环境中“说对话、说适当的话”。 - * **真实场景与业务指标评估场景** :在产品上线和持续运营阶段,通过用户对话日志回放、线上 AB 测试等方式,将模型表现映射到 **任务完成率(Task Success Rate)** 、 **用户满意度(CSAT)** 、**工单关闭率**等业务指标;此时评估对象实际是“模型 + 策略 + 产品流程”的整体系统,用于指导版本回滚、策略调优和新功能放量。 -* **原理** - 能力评估体系可以看作一个分层的“测量系统工程”,其核心原理包括: - * **标准基准集:公共刻度与可复现实验** - * 语言 / 推理:使用 **MMLU** 、**BIG-Bench** 等综合性任务,配合 **GSM8K** 、**MATH** 等数学与逻辑题目,构建对语言理解、知识掌握、多步推理的统一刻度。 - * 编程:通过 **HumanEval** 、 **MBPP** 、**Codeforces** 题库等,量化代码生成、程序修复与问题求解能力。 - * 多模态:利用 **VQA** 、 **MMBench** 、 **ScienceQA** 、**MathVista** 等基准测试图文理解、视觉问答和图像中的数学推理。 - 这些基准强调 **标准化、可复现、可对比** ,便于跨模型、跨机构进行横向对比和对外披露。 - * **自动评测:规模化与持续回归** - * **LLM-as-a-Judge** :用更强或专门训练的模型对回答进行打分/排序,评价正确性、完整性、风格和安全性,实现大规模自动主观评测。 - * **基于规则的度量** :如 BLEU / ROUGE / BERTScore 衡量文本相似度,Pass@k 衡量代码题通过率等,使得在固定数据集上可以快速比较不同版本的差异。 - 自动评测的关键在于 **稳定性与一致性** ,即便不完美,只要“偏差一致”,就可以在持续集成(CI)中可靠地反映模型相对变化。 - * **人工评测:对齐人类感知与业务目标** - * **Pairwise 对比与打分标注** :由标注员对 A/B 两个模型回答做 pairwise 选择或多维度打分(helpful / honest / harmless 等),是训练 RLHF / RLAIF 奖励模型的重要数据来源。 - * **线上用户实验** :通过对话助手、搜索/推荐等落地场景做 AB 测试,直接观察不同模型 / 策略对用户满意度、转化率等指标的影响。 - 人工评测既用于 **校准自动评测** ,也是对外“解释模型行为”时的重要依据。 -* **模型** - 在工程实践中,能力评估会沉淀为一套相对完整的“平台 + 流程 + 指标体系”: - * **内部能力评估平台与 CI 流水线** :统一管理各类基准集、评测脚本、LLM-as-a-Judge 配置与人工标注工具,支持新模型或新策略提交后一键触发 Benchmark 回归;自动汇总不同任务和维度的指标变化,提供可视化 Dashboard 与回归告警。 - * **对外“能力说明书”与模型画像** :将内部评估结果整理为对外可消费的“能力说明书”,包括代表性基准成绩、推荐适用场景(如通用对话、代码辅助、多模态理解等)、已知局限与不适用场景,帮助客户形成正确预期,也为合规和责任划分提供依据。 - * **多租户 / 多版本模型统一评测与选型工具** :在同一套评估体系下,统一比较不同尺寸、不同对齐策略或不同架构的模型,支持按行业、地区、SLA 要求配置权重,自动生成“性能–成本–延迟”综合评分,帮助产品和业务方做模型选型与灰度发布决策。 - -### 9.1.1 通用与专业能力评估:从 Benchmark 到场景验证 - -通用与专业能力评估是整个评估体系的“第一层地基”,重点在于:先用统一刻度衡量模型的 **基础能力** ,再在专业场景中验证其 **可用性与风险** 。 - -在通用能力评估中,通常会将任务拆分为语言理解与生成、推理与数学、知识与事实性三个维度:前者通过阅读理解、摘要、翻译、对话质量任务,检查模型是否能准确理解上下文、控制风格并输出连贯文本;中者通过算术、多步推理、代码 / 逻辑题,评估模型在复杂推理链和程序结构上的能力;后者则通过事实问答和开放域 QA 度量知识覆盖度和事实性水平。在专业领域评估中,则需要邀请行业专家参与数据设计:如医疗问答中设定病史、化验结果等上下文,要求模型在回答中给出风险提示和就医建议边界;法律任务中设计条文检索、案例比对、法律适用分析;金融与教育中则聚焦合规披露与教学引导。这一层评估往往结合标准基准集与自建数据集,既追求可对比性,也兼顾业务相关性。 - -### 9.1.2 自动评测与 LLM-as-a-Judge:让评估可扩展 - -当任务规模和模型版本数迅速增长后,仅依赖人工已经难以支撑评估需求,此时需要通过自动评测体系实现 **规模化与高频回归** 。 - -一类做法是利用传统的基于规则度量:在翻译、摘要等任务上,用 BLEU / ROUGE / BERTScore 与参考答案对比,在代码任务上用 Pass@k 测试在多个生成样本中是否至少有一个通过单测。这类指标实现简单、可高度自动化,但对答案多样性与风格细节不敏感。另一类更具代表性的做法是 **LLM-as-a-Judge** :将更强或专门训练的模型用作“打分裁判”,根据预定义的评分 Rubric,对被测模型输出进行维度化打分或 Pairwise 排序。这允许我们在没有标准答案、回答多样的开放问答和对话任务中也进行高效自动评估。实际工程中,LLM-as-a-Judge 的评分标准和 Prompt 需要经过人工标注数据校准与迭代,以确保其与人类评委的一致性。 - -### 9.1.3 人工评测与业务指标:闭环到真实用户体验 - -再完备的离线指标,也只能近似真实用户体验。为了把能力评估闭环到业务,需要引入人工评测与线上实验两类手段。 - -人工评测侧,常见的是 Pairwise 对比:让标注员在看不到模型身份的前提下,基于 helpful / honest / harmless 等维度,对 A/B 两个回答做偏好选择或打分,从而得到高质量偏好数据,一方面用于直接评估,另一方面可以为 RLHF / RLAIF 训练奖励模型提供数据。在业务侧,则通过线上 AB 测试,对比不同模型、提示词、策略配置版本对任务完成率、用户满意度(CSAT)、工单关闭率等关键指标的影响,辅以用户对话日志回放和人工抽检,持续监控模型上线后的真实表现。这一层评估的输出又会反过来指导能力评估平台的重点方向和权重调整,形成“离线指标—人工评测—线上指标”的闭环。 - -## 9.2 价值对齐与训练(Value Alignment & Training) - -在拥有强大基础能力之后,大模型要成为“安全、可靠、可控”的产品,还必须经历 **价值对齐与训练** 。这一层关注的不再是模型“能不能回答”,而是“ **回答得是否有用、诚实、无害** ”以及“在不同角色和行业中应该如何说话”。从工程角度看,对齐过程大致包括三步:首先通过文档与规范明确 **对齐目标定义(What to Align)** ,将有用(Helpful)、诚实(Honest)、无害(Harmless)拆解为可标注、可训练的标准;其次构建覆盖广泛的 **指令数据与安全数据** ,涵盖正常任务、灰区案例与不合适回答;最后通过 **SFT、RLHF / RLAIF、拒答/重定向策略建模** 等方法,将这些偏好与规则“写进”模型行为中,并辅以上游对话管理与策略引擎,实现端到端的安全对齐。下面同样从 **场景** 、 **原理** 、**模型**三个角度展开。 - -* **场景** - * **通用 C 端助手场景** :面向大众用户的聊天助手、信息检索助手,需要在广谱话题下保持“ **友好、有帮助、不越界** ”:既要回答得专业、聚焦任务,又要在不确定时坦诚表达局限,对明显不当需求进行拒答或柔性引导。 - * **专业行业助手场景** :在医疗、法律、金融、教育等领域,除了基础安全,还要叠加行业规范:例如医疗助手需要反复强调“非诊断性质 + 风险提示 + 建议就医”,法律助手要避免提供违法规避建议,金融助手要遵守投资合规披露要求,教育助手要考虑未成年保护与适龄内容。 - * **B 端可配置对齐层场景** :企业往往希望在通用安全基线之上,进一步嵌入自身的行业要求、品牌语气和内部政策,因此需要一个 **可配置的对齐层** ,允许客户自行配置安全阈值、敏感类别和话术风格,而不必重训底层大模型。 -* **原理** - 价值对齐可以理解为“用人类和组织的价值观约束模型的行为空间”,其核心原理包括: - * **对齐目标定义(What to Align)** - * **有用(Helpful)** :回答应高质量、专业、结构清晰、聚焦任务目标,不过度发散和闲聊。 - * **诚实(Honest)** :尽量不胡编乱造,在知识缺失或理解不清时主动承认不确定性、给出估计范围或建议查证渠道。 - * **无害(Harmless)** :遵守法律与平台政策,避免生成仇恨、歧视、自残鼓励、违法犯罪指导等内容,并尊重用户的尊严与边界。 - 这些目标会被写入标注指南与策略文档,成为后续数据构建、奖励建模和评测的统一标准。 - * **对齐训练数据构建** - * **指令数据(Instruction)** :设计覆盖广泛的任务指令与理想回答,涵盖问答、写作、总结、代码、规划等多种场景,教会模型在“正常请求”下的最佳行为。 - * **安全数据(Safety)** :构建“好的回答 vs 不合适回答”对照样本,特别注重灰色边界(gray zone),如科普信息 vs 具体操作、情绪支持 vs 自残鼓励、合法辩论 vs 仇恨煽动等,为模型提供细粒度的边界示例。 - * **对齐训练方法** - * **SFT(Supervised Fine-Tuning)** :在高质量对话 / 指令数据上进行有监督微调,是塑造模型基准行为和语气的第一步。 - * **RLHF / RLAIF** :通过人类或模型打分构建偏好数据,训练奖励模型,然后进行策略优化,让模型在生成时倾向于被“偏好”的回答(更有用、更安全、更诚实)。 - * **拒答 / 重定向策略建模** :针对高风险或不适当请求,训练模型不仅会拒答,还能给出合理解释并引导用户到安全替代方案(例如提供求助资源、鼓励咨询专业人士等)。 -* **模型** - 在系统设计上,价值对齐通常体现为“ **底层对齐训练 + 上层策略护栏** ”的组合: - * **SFT + RLHF / RLAIF 对齐模型** :SFT 阶段让模型学会理想回答的基本模式;RLHF / RLAIF 阶段则通过偏好学习进一步“收紧”行为,使其更贴近人类偏好与安全标准。在安全维度上,可以单独为有害性构建奖励头或分类器,用于在策略优化中施加惩罚。 - * **Constitutional AI / Policy-based Alignment** :通过先撰写一套“宪法(Constitution)”或 Policy 文档,再让模型根据这套规则进行自我批评与重写,生成大量“自监督批改数据”,在减少人工成本的同时强化模型对规则的内化。 - * **对话管理与意图检测协同** :在产品管线中,将安全 / 对齐逻辑部分上移到对话管理层,通过意图识别、槽位填充、任务路由决定请求是否交给大模型、是否需要额外的安全过滤或模板化回复。这样可以形成“模型对齐 + 策略护栏”的双重保险。 - * **内部对齐平台与角色配置** :建设内部对齐平台,提供标注 / 打分工具、策略版本管理和训练流水线;同时支持为不同角色(客服、医疗建议、教育辅导等)配置差异化对齐目标和话术风格,使同一底座模型在不同产品中展现出截然不同但可控的一致人格。 - -### 9.2.1 对齐目标与训练数据:把价值变成可学习信号 - -价值对齐的第一步,是把“抽象价值观”转译成模型可以学习的信号,而这离不开对齐目标定义和训练数据构建。 - -在对齐目标层面,团队通常会输出一套详细的行为规范文档,将 Helpful / Honest / Harmless 拆解为具体条款,如:禁止给出某类高危操作的具体步骤、对于医疗/法律建议必须附带免责声明和风险提示、在涉及争议话题时保持中立与多视角呈现等。接着,在指令数据阶段,会围绕这些指标构建多样化任务与理想回答,涵盖聊天、写作、代码、问答等场景,并融合多语言、多文化背景;在安全数据阶段,则针对有害内容、高风险领域与灰色地带,构建成对的“好 / 坏回答”示例,为后续偏好学习和安全分类器提供训练素材。通过这种方式,价值目标被“翻译”为实际数据分布,成为模型训练可以直接感知的信号。 - -### 9.2.2 SFT、RLHF / RLAIF 与拒答策略:塑形模型行为 - -有了对齐目标和数据之后,下一步是通过多阶段训练过程将这些目标写入模型行为。 - -在 SFT 阶段,模型在高质量人类示范数据上进行有监督微调,这类似于“教科书式学习”:它决定了模型在绝大多数正常请求下的语气、结构和解决问题的标准范式。随后,通过 **RLHF**** / RLAIF** 进行偏好优化:先利用人类标注或更大 LLM 产生的偏好标签训练奖励模型,再使用策略优化算法(如 PPO 等)调整模型,使其在生成中倾向于获得更高奖励。这样,模型不仅“知道正确答案长什么样”,还知道“哪种答案更符合人类偏好和安全要求”。在此基础上,还会专门建模各种 **拒答与重定向策略** :对于明显违法、极高风险或不适合由 AI 回答的问题,模型应该学会给出清晰的拒绝与解释,并提供安全的替代路径(如求助热线、专业咨询等),而不是简单沉默或随意搪塞。 - -### 9.2.3 策略层与对齐平台:让对齐可配置、可演进 - -即便底层模型已经进行了充分对齐训练,在实际系统中仍需要**策略层与对齐平台**来实现更细粒度的可控性和可演进性。 - -策略层通常包含意图识别、风险评估与路由逻辑:当用户输入到达系统时,先由轻量模型判断其意图、领域和风险等级,再决定是否直接调用大模型、是否需要额外安全过滤、是否落入模板回复或转人工渠道。对于不同行业和客户,策略层可以加载不同的 Policy 配置,实现对敏感类别、拒答风格和品牌语气的定制。与此同时,内部对齐平台会管理所有对齐相关资产:标注/打分工具、奖励模型版本、策略变更记录、在线 A/B 结果等,使团队可以在不频繁重训底座模型的前提下,对对齐策略进行快速迭代和灰度发布,从而保持对模型行为的持续掌控。 - -## 9.3 内容安全与合规(Content Safety & Compliance) - -随着大模型被嵌入到搜索、对话、内容创作、社交平台乃至企业内部系统中,**内容安全与合规**从“附加功能”变成了“准入门槛”。这一层关注的是:模型在生成文本、图像、音视频时,是否会产生违法有害内容;系统在处理用户数据时,是否符合所在国家/地区和所属行业的法律法规;以及在面对审计与监管时,能否给出清晰可追溯的证据链。为此,我们需要构建覆盖**多模态内容审核、区域与行业合规、本地隐私与数据保护**的完整技术与治理体系,并将其封装为 SaaS 内容安全服务、企业合规中台和行业安全网关等产品形态。下面同样从 **场景** 、 **原理** 、**模型**三个角度展开。 - -* **场景** - * **多模态内容审核与过滤场景** :在对话产品、UGC 平台、社区与社交应用中,大模型会生成或接收大量文本、图像、音视频内容,需要通过统一的**多模态审核**能力,实时识别并拦截涉及个人隐私、违法犯罪指导、仇恨煽动、极端暴力、色情与未成年人不当内容等高风险输出。 - * **合规约束与本地化场景** :不同国家/地区的法律法规对数据保护、未成年人保护、内容监管等有不同要求;不同行业(医疗、金融、教育、广告等)也有细化的合规规范。因此系统必须支持按**地区与行业**加载不同策略模板,以符合当地监管要求。 - * **用户隐私与数据保护场景** :在模型训练和在线服务过程中,需要处理大量用户对话和业务数据,如何实现数据匿名化、脱敏和最小采集,同时在训练和推理阶段通过技术和制度手段保护隐私,是内容安全与合规体系的另一根支柱,尤其在金融、医疗等高敏感行业。 -* **原理** - 内容安全与合规的底层原理可以分为策略、过滤和隐私三个层面: - * **安全策略系统(Policy Engine)** - * 将法律法规、平台规则、行业规范 **形式化为可执行策略** ,通过规则引擎结合模型打分,对内容进行风险分级(安全 / 灰区 / 高危)。 - * 支持按场景和客户选择不同策略模板,例如为青少年产品、专业社区或跨国企业配置不同的敏感类别与阈值。 - * **多级内容过滤:事前–事中–事后** - * **事前** :对用户 Prompt 做拦截与重写(Prompt Shielding),在请求进入大模型前阻断明显违法或高度敏感的意图,或将其引导为较为安全的表达方式。 - * **事中** :在模型生成输出时,利用安全分类模型与规则对内容进行实时审查(Real-time Safety Filter),对高风险内容进行截断、替换、打码或触发拒答。 - * **事后** :对对话和生成日志做抽样审计与人审复核,对发现的问题进行溯源分析,进而更新策略和模型,并为外部监管提供可追溯的记录。 - * **隐私保护技术与****数据治理** - * 在数据存储和训练前,对用户对话数据进行 **匿名化与脱敏处理** ,移除或替换姓名、身份证号、手机号、地址等敏感字段,并遵循**最小采集原则**只保留必要信息。 - * 在某些场景中采用**差分隐私(DP)**限制单个样本对模型参数的影响,或者通过**联邦学习(FL)**将训练留在本地数据域,避免原始数据上云。 - * 利用 **RBAC**** / ****ABAC** 等访问控制机制,严格限制谁可以访问什么级别的日志与敏感数据,并配合审计日志保证访问路径可追踪。 -* **模型** - 从产品与系统设计角度看,内容安全与合规最终会演化为一系列可复用的“安全服务与中台”: - * **SaaS 内容安全服务** :将文本 / 图像 / 音视频审核能力封装为统一 API,对接上游应用;输入内容,输出风险类型、分级和处理建议(放行、拦截、人审),帮助开发者快速集成安全模块。 - * **企业内部合规中台** :为大型企业提供集中管理的合规策略配置、审计报表和风险告警能力,对接内部的业务系统和人审团队,使各业务线在统一策略下执行自定义规则,并满足外部监管报告需求。 - * **高风险行业专用安全网关与日志审计系统** :在金融、医疗等高风险行业,通过专用安全网关代理所有大模型调用,对流量进行实时检查与脱敏,将关键日志留存在本地或合规区域,提供详尽的访问审计和事件追溯能力,满足严格的监管要求。 - -### 9.3.1 多模态审核与策略引擎:把规则变成“可执行的代码” - -实际的内容安全系统,首先要能“看懂”来自不同渠道与模态的内容,然后才能将策略落地到每一次请求与响应上。 - -在多模态审核方面,系统通常会构建文本、图像、视频等多种检测模型:文本侧模型识别敏感关键词、上下文语境和隐晦表达;图像和视频侧则检测暴力、色情、未成年人、仇恨符号和违法物品等内容,并在必要时结合 OCR、ASR 和视觉特征进行联合判断。策略引擎则把这些模型输出与法规要求绑定在一起:例如,在某一地区对赌博或政治内容有更严格限制,就可以在对应策略模板中提高相关检测类别的敏感度,或对命中这些分类的内容强制转人工复核。通过把抽象规则转化为规则链、阈值和动作(放行/拦截/人审/打码),Policy Engine 让合规要求真正“跑起来”。 - -### 9.3.2 多级过滤与日志审计:构建端到端安全闭环 - -单一环节的拦截很难覆盖所有风险,因此内容安全体系普遍采用**事前–事中–事后**三层防线的设计。 - -在事前阶段,系统会对用户输入进行快速检测,对明显违规或高度敏感的 Prompt 直接拒绝或重写,引导用户以安全方式提问;对于边界尝试和模糊请求,也可以主动补充声明和风险提示。在事中阶段,模型输出会经过实时安全过滤组件:该组件会利用文本分类和规则匹配,对潜在高危输出进行剪裁、替换或触发拒答流程,确保最终呈现给用户的内容落在可接受范围内。事后阶段,则通过日志审计与抽检机制,由安全团队或可信的自动系统定期回放与检查会话,分析误判、漏判和新型风险样式,并据此更新策略、训练数据和检测模型。这样形成一个持续演进的安全闭环,而不是“一次性配置”。 - -### 9.3.3 隐私保护与行业安全网关:让数据安全“可证明” - -在高敏感行业中,仅仅“不输出有害内容”还远远不够,还要证明“内部对用户数据的使用同样安全、合规、可追踪”。 - -隐私保护从数据进入系统开始:在采集和存储阶段就尽量进行匿名化和脱敏,确保即使日志泄露也难以直接关联到具体个人;在训练阶段,则通过差分隐私、采样策略或联邦学习减少单个用户数据对最终模型的影响和外泄风险。对于模型推理流量,则通过**安全网关**进行统一接入管控:所有请求与响应都要经过网关的内容检查、权限校验和审计记录,必要时根据业务线和用户角色应用不同的访问策略与数据视图。最终,这些日志和策略变更记录会沉淀为可供内部审计和外部监管查看的“证据链”,使企业不仅在事实上合规,而且在形式上“可证明自己合规”。 - -# 10. AI for Science(AI4Science) - -当深度学习和大模型从“推荐广告、理解自然语言”走向 **科学问题本身** ,目标不再只是预测一个指标或做一个分类,而是要真正参与到**发现规律、设计实验、加速仿真与推理**之中。AI4Science 试图把“统计模式识别”与“物理定律 / 生物化学规律 / 数学结构”结合起来,让模型在分子设计、蛋白工程、材料发现、物理仿真、数学推理等环节中充当“可编程的科学助手”。 - -在工程实践中,这一层一端连接量子化学软件、分子动力学(MD)、CFD/FEA 仿真器、自动定理证明器、文献数据库和自动化实验室(Robotic Lab)等“传统科学基础设施”,另一端连接制药公司、材料企业、能源公司、科研机构的真实科研工作流。下面从 **场景** 、 **原理** 、**模型**三个角度展开,并在若干关键方向上进一步细分。 - -* **场景** - * 分子与药物设计:从海量小分子 / 片段出发,预测性质与 ADMET,设计针对特定靶点的候选药物,并通过虚拟筛选和多目标优化缩小实验空间。 - * 蛋白质与生物结构建模:预测蛋白及复合物的三维结构,辅助抗体、酶、蛋白药物设计,评估突变对功能与稳定性的影响。 - * 物理仿真与工程设计:用深度替代模型加速 CFD / FEA / 分子动力学等高成本仿真,为航空航天、汽车、能源等领域提供快速评估与优化工具。 - * 材料发现与晶体设计:在庞大化学 / 材料空间中进行虚拟筛选和逆设计,加速电池、光伏、催化剂、合金等关键材料的研发。 - * 数学与符号推理:在形式系统中做自动定理证明、符号计算和方程求解,增强大模型在数学题、工程推导中的严谨推理能力。 - * 科学工作流与自动化实验:对接文献、数据库与自动化实验平台,构建“自驱动实验室(Self‑Driving Lab)”,让模型参与实验设计、执行与结果分析。 -* **原理** - * 结构化表示与图建模:用图(Graph)、晶体图(Crystal Graph)、分子图等结构表征复杂对象,在图神经网络或 E(3)-等变网络上建模几何与拓扑关系。 - * 物理 / 化学归纳偏置:通过守恒定律、对称性(平移 / 旋转 / 反射)、PDE 约束(PINN)、能量势函数等方式,将物理先验融入模型结构与损失函数。 - * 生成与逆设计:利用 VAE、GAN、Diffusion、RL 等生成式建模方法,支持从“目标性质 / 约束条件”反推结构,实现分子 / 材料 / 结构的逆设计。 - * 代理模型与多尺度耦合:用深度代理模型近似昂贵的量子化学 / 连续介质 / 结构力学仿真,并将微观–中观–宏观模型拼接起来,实现多尺度建模。 - * 工具增强与 Agent 工作流:将 LLM 与模拟器、符号计算器、自动定理证明器、文献检索系统和实验机器人组合,构建可自动规划和执行科学任务的 Agent。 -* **模型** - * 分子与材料表征模型:SchNet、DimeNet、PhysNet、CGCNN、MEGNet、ALIGNN 等 E(3)-等变网络与图网络,ChemBERTa、MolBERT、MoleculeSTM 等分子语言模型。 - * 结构生物学模型:AlphaFold / AlphaFold2 / AlphaFold3、RoseTTAFold、OpenFold、ProteinMPNN、ESM‑IF、ESM 系列蛋白语言模型与结构生成模型。 - * 物理仿真与算子学习:PINN、DeepONet、Fourier Neural Operator (FNO) 及 Neural Operator 家族、DeepMD、NequIP 等势能面与算子学习模型。 - * 数学与符号推理模型:Minerva、Gödel、GPT‑f、Lean‑Dojo 等数学 / 证明专用模型,以及 LLM + SymPy/Mathematica/Lean/Coq 的工具增强系统。 - * 科学 Agent 与工作流系统:结合检索、代码生成、仿真调用与实验控制接口,为制药、材料、物理、化学等领域封装的“AI 科学助手”和自驱动实验平台。 - -从这一层开始,传统科学计算与深度学习、大模型深度交织:既要尊重物理 / 化学 / 生物 / 数学的严格约束,又要利用数据驱动的强拟合能力提升效率,最终目标是让 AI 成为科研中的“合作者”,而不仅仅是一个预测黑盒。 - ---- - -## 10.1 分子与药物设计(Molecular Modeling & Drug Discovery) - -在传统药物研发中,从靶点发现到临床试验往往需要 10+ 年和数十亿美元成本,而极大一部分时间与资金耗费在早期的分子设计、性质预测和虚拟筛选阶段。AI 驱动的分子建模与药物设计,旨在用**数据驱动 + 生成式建模**加速这一过程:从结构或文本描述出发,预测分子性质与 ADMET,设计针对特定靶点的候选化合物,并通过多目标优化与虚拟筛选显著减少湿实验负担。 - -这一方向一端连接量子化学软件(DFT、ab initio)、生物活性实验、HTS(High‑Throughput Screening)等数据来源,另一端连接药企内部的 Small Molecule Design 平台、性质预测 SaaS、材料 / 化学品设计工具。下面从 **场景** 、 **原理** 、**模型**三个维度展开。 - -* **场景** - * 早期虚拟筛选与 Hit 发现:面对数百万到数十亿规模的虚拟分子库,通过 AI 快速预测活性 / ADMET,对候选分子排序,筛出少量高价值 Hit 进入实验环节。 - * 分子性质与 ADMET 评估:在先导化合物优化(Lead Optimization)阶段,持续预测溶解度、毒性、代谢稳定性以及口服生物利用度等指标,为药代动力学和安全性评估提供参考。 - * 靶点导向分子生成:给定蛋白靶点信息(口袋特征、已知配体)或目标性质约束,自动生成结构多样、具有高活性且可合成的候选小分子。 - * 材料与化学品分子设计:面向非药物场景,如涂料、溶剂、电解液、界面活性剂等分子,设计满足特定物性(黏度、极性、界面能等)的配方分子。 -* **原理** - * 分子表征与性质预测: - * **结构表示** :常见有 SMILES 序列、分子图(原子为节点、键为边)、3D 坐标及量子特征等;模型需要从这些表示中抽取可泛化的语义与几何信息。 - * **性质预测** :通过 GNN(GCN、GAT、MPNN)或 3D‑等变网络(SchNet、DimeNet、PhysNet 等),从分子图或 3D 结构中学习到能量、偶极矩、轨道能级等量子性质,以及溶解度、LogP、毒性、代谢稳定性等 ADMET 属性。 - * **表征学习与预训练** :基于大规模分子库(如 ZINC、ChEMBL、PubChem)进行掩码预测、对比学习或自回归预训练,得到可迁移的通用分子表示,为下游 QSAR / ADMET 提供特征。 - * 结构生成与分子优化: - * **生成建模** :利用 VAE、GAN、Flow、Diffusion 等生成式模型,在 SMILES 或分子图空间中采样新分子,要求保证化学结构合法性(价态、环结构等)与多样性。 - * **条件生成** :引入条件向量(目标活性、理化性质、结构片段、靶点口袋描述等),在给定约束下生成候选分子,实现性质导向或片段补全式的设计。 - * **多目标优化与 RL** :通过强化学习(如 MolDQN 等)在分子空间中进行“编辑”操作(加原子、改键、替换片段),从而在活性、毒性、合成可行性、专利避让等多个目标之间权衡。 - * 蛋白 – 小分子相互作用建模: - * **结合位点与打分函数** :通过 3D 卷积 / 图网络 / 互作图建模蛋白口袋与配体的空间关系,预测结合位点及结合亲和力(Binding Affinity)。 - * **对接与 Binding Pose 预测** :将 Docking 中的构象搜索与深度模型结合,用深度打分函数或 Diffusion 式生成预测稳定构象,提高对接准确率并降低计算成本。 -* **模型** - * 分子表征模型: - * **GNN 与 3D 网络** :DimeNet / DimeNet++、SchNet、PhysNet 等考虑角度 / 距离的 3D 等变模型,GCN/GAT/MPNN 等通用图神经网络,适用于性质预测与 QSAR。 - * **基于 SMILES 的 Transformer** :将分子视为“化学语言句子”,用 Transformer 做自回归或掩码语言建模,为生成与性质预测提供序列表示。 - * 生成与优化模型: - * 图生成模型:GraphVAE、Junction Tree VAE、GraphAF 等在图 / 片段空间生成分子,强调结构合法性与可解释性(片段级构造)。 - * 扩散模型:Diffusion for Molecules 通过在图或 3D 结构空间添加 / 去除噪声生成新分子或构象,可与条件向量结合实现定制生成。 - * 强化学习优化:MolDQN 等基于 RL 的方法,将分子优化视作在“分子编辑”状态空间中的序列决策问题,用奖励函数编码多目标指标。 - * 分子大模型与多模态方向: - * **分子语言模型** :ChemBERTa、MolBERT 等在大规模 SMILES 语料上预训练,支持零样本或小样本转移至下游任务。 - * **多模态分子模型** :MoleculeSTM 等整合结构(图 / 3D)、文本描述(合成路线、文献摘要)、分子属性,实现跨模态检索与联合预测。 - * 产品与应用形态: - * 面向药企的早期药物筛选平台与内部 Small Molecule Design 平台,提供虚拟筛选、分子生成、ADMET 预测等一体化能力。 - * 面向研发人员的性质预测 SaaS:通过 Web 或 API 方式快速查询分子性质、ADMET、分子相似度等。 - * 面向材料与化学品设计的分子级设计工具,用于涂料、溶剂、电解液等分子体系的定制开发。 - -从这一子方向开始,药物设计流程正在从“专家 + 高通量实验”走向“专家 + 模型 + 自动化实验”的闭环,AI 不只是给出分数,而是逐渐参与从“提出想法”到“生成候选”再到“筛选与优化”的完整环节。 - -### 10.1.1 分子表征与性质 / ADMET 预测 - -在药物与材料研发中,一个基础能力是: **给定一个分子,快速且准确地预测其性质与行为** ,包括量子化学性质(能量、轨道、偶极矩)、理化性质(溶解度、LogP)、以及药代 / 毒性相关的 ADMET 指标。这一问题的本质,是如何从不同形式的分子表示中学习到 **既符合化学规律,又具备泛化能力的表征** 。 - -* 在**分子表征**层面,常见的表示包括: - * **SMILES / SELFIES 等字符串** :把分子视为序列,天然适合用 RNN / Transformer 进行语言建模。 - * **分子图表示** :原子为节点、键为边,节点和边带有类型、价态、芳香性等特征;适合用 GNN、MPNN 等建模邻域与拓扑。 - * **3D 几何表示** :基于量子化学或力场优化得到的 3D 坐标、键角、二面角等信息,为 E(3)-等变网络捕捉空间结构提供基础。 -* 在**性质与 ADMET 预测**层面,目标任务包括: - * 小分子量子性质预测:能量、偶极矩、HOMO/LUMO 能级等,用以替代昂贵的 DFT / ab initio 计算。 - * QSAR / 活性预测:给出化合物对特定靶点的活性(IC50、Ki)、选择性等,用于筛选潜在候选。 - * ADMET 相关指标:溶解度、渗透性、毒性、代谢稳定性、CYP 抑制等,是药物可成药性评估的关键。 - -典型模型路径为:用 DimeNet / SchNet / PhysNet / GNN 等在分子结构上提取高维表征,再通过多任务学习同时预测多种性质;在大规模公开或企业内部数据上进行预训练,提高小数据场景的建模能力。对外则以 ADMET 预测 SaaS 或内部平台 API 的形式提供服务,为项目组提供快速的“虚拟实验”能力。 - -### 10.1.2 结构生成与分子优化:从 SMILES / Graph 到候选药物 - -在具备了可靠的分子表征与性质预测模型之后,更进一步的目标是 **主动生成“更好”的分子** :不再只是评估给定化合物,而是围绕靶点与性质约束,直接设计出新的候选分子。这一方向通常被称为 **分子生成与分子优化** 。 - -在**结构生成**方面,研究与工程实践主要围绕三类路径: - -1. **基于 SMILES 的序列生成** - 将分子视作字符串,使用 VAE、GAN 或自回归 Transformer 在 SMILES 空间中采样新结构;通过语法约束(如 SELFIES)或后处理保证化学有效性。 -2. **基于图 / 片段的生成** - GraphVAE、Junction Tree VAE、GraphAF 等模型直接在分子图或基元片段(Fragement / Motif)层面构造结构,更贴近化学合成思维,有利于控制环、基团与骨架结构。 -3. **基于扩散与 3D 生成** - Diffusion for Molecules 等方法在图或 3D 坐标空间进行扩散与去噪,可同时考虑空间构象,适用于生成对 3D 形状敏感的配体或材料单元。 - -在**分子优化**方面,关键是引入 **目标与约束** : - -* **条件生成** :把目标活性、理化性质或片段锚定作为条件向量输入模型,使其在生成时偏向满足这些条件。 -* **强化学习与多目标优化** :以性质预测模型为“环境”,用 RL 在分子空间中做序列决策(如 MolDQN),在活性、毒性、合成可行性、专利风险等多维指标上设置奖励与惩罚,实现多目标权衡。 -* **合成可行性与化学先验** :在生成与优化过程中融入合成路径预测模型、合成复杂度指标(如 SA score),避免产生难以合成或不稳定的结构。 - -在产品化上,这一类模型常被封装进药企内部的“AI 药物设计平台”中:给定靶点、已知先导结构和优化方向,平台自动提出若干批次候选分子,项目组再结合实验、专利和商业考量逐步筛选与迭代,实现“模型–实验–模型”的闭环优化。 - -## 10.2 蛋白质与生物结构建模(Protein & Structural Biology) - -在生命科学中,**结构决定功能** 是一条近乎教条的原则:蛋白质如何折叠成三维结构、如何与其他分子装配成复合物,直接决定了其在细胞中的功能表现。传统结构解析依赖 X‑ray 晶体学、NMR、冷冻电镜等实验手段,周期长、成本高且存在“难结晶、难解析”的巨大盲区。以 AlphaFold 为代表的深度学习模型,把“从序列直接到结构”的能力大幅推前,使得在全基因组尺度上获得高质量结构成为可能。 - -这一方向一端连接 UniProt / PDB 等序列与结构数据库、组学实验与结构组学项目,另一端连接生物制药、合成生物学、酶工程等产业界的结构设计与分析平台。下面同样从 **场景** 、 **原理** 、**模型** 三个角度展开,并进一步拆分关键子方向。 - -* **场景** - * 靶点结构注释与筛选:在基因组层面预测大量蛋白的结构,辅助靶点发现、功能注释与通路分析;结合变异信息评估潜在致病机理。 - * 抗体 / 蛋白药物设计:对抗体可变区(CDR)、受体结合结构域等关键区域进行精细建模与设计,优化亲和力、特异性和免疫原性。 - * 酶与生物催化设计:基于酶三维结构和活性位点环境,设计突变与变体库,提升催化效率、底物范围与稳定性。 - * 复合物与相互作用研究:预测蛋白–蛋白、蛋白–核酸、蛋白–小分子复合物结构,解析界面互作模式,为药物设计与信号通路建模提供基础。 - * 突变效应与耐药性分析:评估自然变异或人工突变对结构稳定性、功能和配体结合的影响,分析耐药突变的结构基础。 -* **原理** - * 蛋白质结构预测: - * **序列 → 结构** :从氨基酸序列(单序列或包含多序列对齐 MSA)出发,建模残基两两之间的几何约束(距离、角度、接触图),再通过几何重建模块生成全原子 3D 结构。 - * **协同进化信号** :利用同源序列之间的协同突变模式(co‑evolution),推断潜在的残基接触关系,为折叠约束提供强先验。 - * **结构精修与不确定性估计** :对预测结构进行局部精修(relax、repack),并输出置信度评分(如 pLDDT、PAE),指导后续应用中的“可信区域”选择。 - * 复合物与分子装配建模: - * **多链联合建模** :将多个蛋白链或蛋白 + 核酸序列作为输入,引入链识别与接口约束,直接输出完整复合物结构。 - * **界面预测与装配** :基于已知单体结构,通过图模型或扩散模型预测最可能的界面构型与装配方式。 - * 蛋白设计与突变效应预测: - * **反向折叠(Inverse Folding)** :给定三维骨架结构或拓扑约束,生成能稳定折叠成该结构的氨基酸序列,实现 de novo 蛋白设计。 - * **突变效应建模** :结合蛋白语言模型与结构模型,预测特定突变对稳定性(ΔΔG)、活性或结合亲和力的影响,辅助定向进化与变体筛选。 -* **模型** - * 结构预测: - * AlphaFold / AlphaFold2 / AlphaFold3:以注意力机制和几何模块为核心,从 MSA、模板结构与序列特征中预测高精度蛋白结构,并输出不确定性估计。 - * RoseTTAFold、OpenFold:采用多轨道(sequence / pair / structure)表示与多尺度注意力机制,为开源与产业化落地提供基础实现。 - * 复合物与界面建模: - * AlphaFold‑Multimer:在多链场景下直接建模蛋白–蛋白复合物结构,兼顾单体折叠与界面互作。 - * RFdiffusion:基于扩散模型在 3D 空间生成或优化蛋白骨架与复合物接口,实现复杂装配与对称体设计。 - * DiffDock 等方法:在蛋白–小分子系统中,用扩散或深度打分函数预测 Binding Pose 与结合模式。 - * 设计与突变模型: - * ProteinMPNN:在给定结构的条件下生成兼容的序列,用于稳定骨架与界面设计。 - * ESM‑IF、ESMFold / ESM‑2 系列:基于大规模蛋白序列预训练的语言模型,具备从序列推断结构、功能与突变效应的能力。 - * 产品与应用: - * 公有云上的蛋白结构预测服务与数据库(如 AlphaFold DB),为科研提供大规模结构注释与下载接口。 - * 生物制药公司内部结构设计平台:集成蛋白结构预测、抗体设计、酶工程、蛋白–配体对接等模块。 - * 生物技术 SaaS:提供结合位点预测、界面热力学评估、亲和力与免疫原性评估工具,服务于抗体药物、生物制剂开发。 - -从这一子方向开始,AI 不仅在“解读”自然存在的蛋白结构,更在“创造”全新的蛋白与复合物架构,使结构生物学从“被动测量时代”进入“主动设计时代”。 - -### 10.2.1 蛋白质结构预测与复合物装配 - -蛋白质结构预测是结构生物学与 AI 结合最具代表性的突破之一。其核心问题是:**能否从序列出发,在不依赖或少依赖实验数据的情况下,预测出接近实验分辨率的 3D 结构?** 而在真实应用中,单体结构往往只是起点,更关键的是蛋白如何与其他分子装配成复合物。 - -在 **单体结构预测** 中,典型流程包括: - -1. **序列 / MSA 编码** :通过序列特征提取和多序列对齐挖掘协同进化信号。 -2. **几何约束推断** :预测残基对之间的距离分布、接触概率与相对取向,形成“伪测量”的几何场。 -3. **结构构建与迭代精修** :在几何约束下用结构模块(如旋转平移不变块、内坐标更新)构建 3D 结构,并多次迭代 refinement 以降低几何违背。 -4. **不确定性与质量评估** :输出逐残基置信度(pLDDT)、残基对误差估计(PAE)等指标,为后续建模与筛选提供参考。 - -在 **复合物与装配预测** 中,问题进一步扩展为“多条链如何在空间中组织与相互作用”: - -* 对于 **蛋白–蛋白复合物** ,通常在多链输入的基础上,使用专门的多链建模策略(如 AlphaFold‑Multimer)直接输出装配结构。 -* 对于 **蛋白–核酸 / 蛋白–小分子体系** ,一类路径是先预测各自结构,再通过对接与界面打分函数预测装配方式;另一类则是用扩散模型或联合建模在 3D 空间内直接生成复合物构象。 -* 在多亚基、大型装配体场景中,还需要结合对称性约束、低分辨率 EM 密度图等信息,进行分层与多尺度装配。 - -在产品实践中,结构预测与装配常被封装为云端服务或本地工具链,为蛋白功能注释、相互作用网络建模、药物靶点验证提供基础结构信息。 - -### 10.2.2 蛋白设计与突变效应预测:从结构到功能调控 - -在掌握“序列 → 结构”的映射之后,下一步是反向问题:**如何在给定结构或功能需求的情况下,设计出合适的蛋白序列与突变方案?** 这就是蛋白设计与突变效应预测的核心。 - -在 **蛋白设计** 中,关键任务包括: - -* **反向折叠(Inverse Folding)** :给定目标骨架(backbone)或整体拓扑结构,生成能够稳定折叠成该结构的氨基酸序列,这一过程可通过 ProteinMPNN、ESM‑IF 等结构条件生成模型实现。 -* **功能导向设计** :在保持整体结构稳定的前提下,针对活性位点、结合口袋、界面区域进行定向设计,优化亲和力、特异性与催化效率。 -* **可制造性与免疫原性约束** :在序列设计过程中,引入表达可行性、翻译后修饰、免疫原性风险等约束,保证候选序列在生物制剂开发中的可落地性。 - -在 **突变效应预测** 中,关注的是: - -* **稳定性变化(ΔΔG)** :给定野生型结构与突变位点,预测单点或多点突变对折叠稳定性的影响,用于定向进化和耐药突变分析。 -* **活性与亲和力变化** :结合结构与蛋白语言模型,评估突变对酶学活性、配体亲和力与信号通路调控的影响。 -* **大规模变体库设计** :在体内 / 体外筛选实验之前,用模型对庞大突变空间进行预筛选,保留高潜力变体,降低实验成本。 - -在工程与产品层面,蛋白设计与突变效应预测常被集成为生物制药 / 合成生物学公司内部的“结构设计与优化模块”:从候选骨架结构出发,自动提出多轮突变与变体库设计方案,与高通量筛选实验形成数据驱动的闭环。 - -## 10.3 物理仿真与加速计算(Physics Simulation & Surrogate Modeling) - -在航空航天、汽车、土木工程、能源、化工等领域, **高精度仿真是设计与验证的核心环节** 。然而 CFD(计算流体力学)、FEA(有限元分析)、分子动力学(MD)以及各类 PDE 求解往往计算昂贵,难以支持大规模参数扫描、实时控制或在线优化。AI 驱动的物理仿真与代理建模,试图用深度网络来近似数值求解器或算子本身,在保证物理一致性和可解释性的前提下,实现数量级的加速。 - -这一方向一端连接传统仿真软件(ANSYS、Fluent、COMSOL、自研求解器)、实验测量与传感器数据,另一端连接工程设计平台、自动驾驶与航天气动设计、化工过程模拟与优化系统。下面从 **场景** 、 **原理** 、**模型** 三个角度展开。 - -* **场景** - * 工程仿真加速:在给定几何与工况下,用深度代理模型快速预测压力场、速度场、温度场、应力 / 应变分布等,为多轮设计迭代和优化提供支持。 - * 复杂过程模拟与工艺优化:在化工、能源等流程工业中,通过 ML 近似机理模型或黑箱过程模型,实现快速评估与实时控制。 - * 分子 / 材料尺度模拟:用 ML 势能面(Neural Network Potential)替代高成本的 ab initio 势能与力计算,加速分子动力学与材料相行为模拟。 - * 多尺度与跨学科耦合:通过深度代理模型把微观–中观–宏观模型拼接起来,构建端到端的多尺度仿真与优化链路。 -* **原理** - * 替代模型 / 代理模型(Surrogate Models): - * 从数值仿真或实验数据中学习“输入参数 → 输出场 / 指标”的映射,作为高保真求解器的近似。 - * 在高维参数空间下,结合主动学习与贝叶斯优化,自动选择最有信息量的样本点进行高保真仿真或实验,持续提高代理模型质量。 - * 物理知晓神经网络(PINN): - * 将 PDE、初始 / 边界条件与物理守恒定律写入损失函数,利用自动微分技术在连续空间上求解物理场。 - * 支持正向问题(求解状态场)与逆问题(由稀疏观测反推源项、材料参数等),特别适用于传统数值方法难以处理的复杂几何与边界。 - * 算子学习与 Neural Operator: - * 不只拟合“具体条件下的解”,而是学习从函数到函数的映射(算子),如“边界条件 / 源项 → 整个解场”。 - * 代表方法如 Fourier Neural Operator (FNO)、DeepONet 等,通过频域变换或特定网络架构,提升对不同网格密度与几何形状的泛化能力。 - * 多尺度建模: - * 在微观模拟数据上训练中观 / 宏观层级的有效参数或本构关系,由深度代理模型承担“尺度桥接层”角色。 - * 对复杂材料、流固耦合与多相流等问题,用深度模型在不同尺度与物理模块间传递信息。 -* **模型** - * 通用物理神经网络: - * PINN 系列:通过在时空域采样点上最小化 PDE 残差来求解,适用于 Navier‑Stokes、Maxwell、弹性力学等方程。 - * DeepONet、FNO、Neural Operator 家族:直接学习 PDE 求解器的“算子级”近似,在多工况、多几何下快速推理。 - * 分子 / 材料尺度势能模型: - * DeepMD、SchNet、NequIP、SpookyNet 等:构建高精度 ML 势能面,在接近 ab initio 准确度的前提下,大幅加速力与能量计算。 - * 与传统 MD 引擎耦合,实现大体系、长时间尺度的高精度分子动力学。 - * CFD / 结构力学代理模型: - * U‑Net / UNet++ 等 Encoder‑Decoder 网络:在规则网格上从几何 / 边界条件预测流场或温度场。 - * 图神经网络 on Mesh:在非结构化网格上对节点 / 单元进行消息传递与更新,适合复杂几何和多物理场耦合场景。 - * Neural Operator for CFD:在不同雷诺数、来流条件、几何参数下泛化流场预测。 - * 产品与应用: - * 工业仿真软件中的 AI 加速模块:在传统求解器外层提供快速预估和敏感性分析功能。 - * 化工 / 能源过程模拟与优化平台:把机理模型 + 代理模型 + 优化算法组合成一体化工艺优化工具。 - * 自动驾驶 / 航空航天气动设计:在气动外形设计中进行大规模设计变量扫描与自动形状优化。 - -### 10.3.1 替代模型与物理知晓神经网络(PINN) - -**替代模型(Surrogate Models)** 与 **物理知晓** **神经网络** **(PINN)** 是物理仿真 AI 化的两条互补路径:前者从数据出发近似仿真映射,后者从物理出发构造学习目标。 - -在 **替代模型** 场景中,典型流程是: - -1. 通过高保真数值仿真或实验采集一批样本数据(输入参数、边界条件、几何 → 输出物理量)。 -2. 训练深度网络(如 MLP、卷积网络、GNN、Neural Operator)近似这一映射函数。 -3. 在设计优化、参数扫描或实时控制中,用代理模型替代昂贵的求解器进行快速评估。 - -在 **PINN** 场景中,模型不再以大量监督标签为主,而是通过最小化 PDE 残差与边界条件违背构建损失函数: - -* 在空间 / 时间采样点上,用神经网络输出物理量(如速度、压力、位移场等),自动微分得到梯度与导数。 -* 将这些导数代入 PDE 中,形成残差,并与边界条件、初始条件的误差一起构成总损失。 -* 通过优化使 PDE 残差与边界误差尽可能接近 0,从而得到满足物理方程的近似解。 - -两者可以结合使用:在有部分高保真数据时,用数据误差 + 物理残差共同约束训练,提高精度与泛化能力。在工程应用中,PINN 特别适合处理逆问题与数据驱动建模,如从传感器观测反推材料参数、源项或缺陷位置。 - -### 10.3.2 Neural Operator 与多尺度物理建模 - -**Neural Operator** 将物理建模从“点到点 / 参数到解”的映射提升到“函数到函数”的层面:它学习的是“给定一类 PDE 与边界条件,求解其解场”的统一算子近似,而非单一工况下的特定解。这为多工况、多几何与跨网格分辨率的泛化提供了新的可能。 - -在 **算子学习** 中,典型做法是: - -* 以函数(如源项、边界条件、材料参数场等)作为输入,用网络(如 FNO、DeepONet)输出整个解场函数。 -* 通过在不同网格、不同参数与不同几何上的样本训练,让模型学习到 PDE 求解器的“公共模式”。 -* 部署时,只需给出新的输入函数(如新的边界条件、几何),就能快速推理得到近似解场。 - -在 **多尺度建模** 场景中: - -* 在微观尺度(如分子动力学、晶体塑性)产生的大量数据上训练 Neural Operator,学习微观结构与宏观响应之间的映射。 -* 在宏观连续介质模型中,用这一映射作为本构关系或有效参数计算模块,实现微–宏耦合。 -* 对于流固耦合、多相流、反应流等复杂系统,可以对不同物理场分别建模并通过共享接口变量(如通量、界面力等)耦合。 - -在工程实践中,Neural Operator 逐渐从研究原型走向应用,成为 CFD、地球物理、气候建模等场景中“加速求解器 + 多尺度桥接”的重要技术方向。 - -## 10.4 材料发现与晶体设计(Materials Science & Crystal Design) - -在材料科学中,一个核心矛盾是: **设计空间几乎无穷大,而实验与高精度计算成本极高** 。如何在巨大的化学与结构组合空间中高效地找到满足特定性能要求的候选材料,是新能源、电子、结构、功能材料等领域的关键问题。AI 驱动的材料发现与晶体设计,通过图神经网络、生成模型与高通量虚拟筛选,将“试错式”研发逐步转向“数据驱动 + 逆设计”。 - -这一方向一端连接 Materials Project、OQMD、AFLOW 等材料数据库与 DFT / MD 计算结果,另一端连接电池、光伏、催化、半导体、合金等应用场景的材料研发平台。下面从 **场景** 、 **原理** 、**模型** 三个角度展开。 - -* **场景** - * 性能导向的材料筛选:给定晶体结构或化学式,预测能带结构、带隙、载流子迁移率、热 / 电 / 磁性质等,为材料筛选与组合优化提供依据。 - * 新能源材料研发:面向电池电解质、电极材料、固态离子导体、光伏吸收层与催化剂等体系,预测离子电导率、稳定性、电化学窗口与活性等。 - * 高通量虚拟筛选(HTVS):在构建的大规模候选库中,通过 ML 模型快速评估,筛出潜力材料,再用少量 DFT / 实验验证与校准。 - * 晶体结构与成分逆设计:从目标性质出发,反向搜索满足性能与工艺约束的晶体结构 / 成分组合。 -* **原理** - * 材料与晶体表示: - * 将周期性晶体结构表示为晶体图(Crystal Graph):节点为原子,边为原子间近邻关系,结合晶格参数与空间群信息。 - * 对于非晶或复杂多相材料,可通过局部环境描述符(如 SOAP)、Voronoi 特征或多尺度图结构表示其微结构。 - * 性质预测: - * 在 CGCNN、MEGNet、ALIGNN 等 GNN 模型上对晶体图进行卷积 / 消息传递,预测能量、带隙、弹性模量、热导等。 - * 利用 Mat2Vec 等基于文献和化学式的嵌入,在低数据场景下实现迁移学习与零样本估计。 - * 高通量虚拟筛选: - * 构建候选库(通过组合枚举、结构生成、经验规则等) → 使用 ML 模型快速预测性质 → 筛选出少量 Top 候选进行 DFT 或实验校准 → 更新模型与筛选策略,形成主动学习闭环。 - * 生成与逆设计: - * 利用扩散模型、VAE 或 GNN 生成模型在晶体结构空间采样新结构,可施加成分、空间群、密度等约束。 - * 结合代理模型与贝叶斯优化,从目标性质出发搜索合适的结构 / 成分组合,实现 inverse design。 -* **模型** - * 表征与预测: - * CGCNN(Crystal Graph Convolutional Neural Network):在晶体图上进行卷积,用于能量、带隙等无机材料性质预测。 - * MEGNet、ALIGNN:融合图结构与边 / 角度信息,在多种材料家族上具备更强的泛化与精度。 - * Mat2Vec + 轻量 ML:通过对化学式和元素信息的向量化,快速训练用于特定性质预测的小模型。 - * 生成与逆设计: - * Diffusion for Crystals:在晶格参数与原子位置组成的高维空间中进行扩散 / 去噪,生成满足一定约束的晶体结构。 - * GNN‑based Generative Models:通过逐步添加 / 修改原子和键或操作晶格,实现从随机初始化到目标性质附近的结构搜索。 - * Surrogate + Bayesian Optimization:用 ML 模型作为“结构 → 性质”的近似黑箱,在其上做贝叶斯优化,寻找最优结构或成分。 - * 数据平台与工具链: - * Materials Project、OQMD、AFLOW:提供大量结构与 DFT 计算数据,是训练与评估材料 ML 模型的基础。 - * 企业内部材料数据库与模型:结合公司实验数据与工艺信息,构建领域特化的材料 AI 设计平台。 - * 产品与应用: - * 新能源材料研发加速平台:为电池、电催化、光伏等团队提供一体化的性质预测、HTVS 与 inverse design 能力。 - * 虚拟筛选软件与 SaaS:为合金、半导体、功能陶瓷等提供数字化筛选工具,减少早期试错成本。 - * 材料公司内部的 AI 设计工具:与实验室信息管理系统(LIMS)与生产线数据对接,形成从“模型 → 实验 → 生产”的闭环。 - -### 10.4.1 材料性质预测与高通量虚拟筛选(HTVS) - -在材料研发流程中,**快速而可靠的性质预测** 是一项基础能力:给定一个候选结构或成分,能否在不做昂贵 DFT / 实验的情况下,大致判断其是否值得深入探索。基于 GNN 与材料数据库的性质预测模型,为高通量虚拟筛选提供了可能。 - -在 **性质预测** 层面: - -* 使用晶体图表示周期性结构,通过 CGCNN、MEGNet、ALIGNN 等模型学习原子与邻域间的相互作用。 -* 针对不同任务(能量、带隙、弹性常数、热导、电导、磁性等)进行单任务或多任务训练,在 Materials Project 等数据集上达到接近 DFT 精度的预测性能。 -* 在工业场景中,常结合内部实验数据进行再训练或领域自适应,以提升对特定材料家族与工艺条件的适配度。 - -在 **高通量虚拟筛选(HTVS)** 场景中,典型流程为: - -1. 构建大规模候选库(组合枚举、结构生成或从现有数据库扩展)。 -2. 使用 ML 模型快速预测每个候选的目标性质与辅助性质(稳定性、安全性、成本相关指标等)。 -3. 按目标性质与多约束条件筛选排名,选出 Top‑K 候选进行高保真 DFT 计算或实验验证。 -4. 将验证结果反哺模型,更新参数与不确定性估计,形成“筛选–验证–再筛选”的主动学习闭环。 - -这一工作流在电池材料、光伏吸收层、催化剂与结构材料等多个领域已进入实用阶段,成为材料研发团队的“前置筛选引擎”。 - -### 10.4.2 晶体生成与逆设计:从目标性质到候选结构 - -在具备了可靠的性质预测与 HTVS 能力之后,更进一步的目标是 **直接从目标性质与约束出发,提出新的晶体结构与成分候选** ,即材料的逆设计与生成。 - -在 **晶体生成** 中,关键问题包括: - -* 如何在周期性约束下生成物理合理的晶格与原子排列? -* 如何在生成过程中显式或隐式地施加成分、对称性与密度等约束? -* 如何保证生成结构在经过简单松弛后依然稳定? - -为此,研究与工程实践常采用: - -* **Diffusion for Crystals** :在晶格参数 + 原子位置的联合空间中添加 / 去除噪声,实现从随机初始到结构样本的渐进生成,可在噪声过程或条件向量中融入目标性质与成分约束。 -* **GNN** **‑based Generative Models** :在图结构上逐步添加原子与连接关系,或对已有结构进行编辑,生成满足约束的候选结构。 - -在 **逆设计** 中,通常与代理模型与优化方法结合: - -* 将性质预测模型视作“结构 → 性质”的黑箱函数。 -* 通过贝叶斯优化、进化算法或 RL 在结构空间中探索,使预测性质逐步逼近目标值,同时满足稳定性、安全性、成本等约束。 -* 对搜索得到的候选结构进行 DFT / 实验验证,并将结果用于更新代理模型与搜索策略。 - -在工程应用中,逆设计模块往往被集成到材料 AI 平台中,为研发人员提供“设定目标性质 → 系统自动提出候选结构”的交互界面,显著提升新材料探索的效率。 - -## 10.5 数学与符号推理(Mathematics & Symbolic Reasoning) - -数学是高度形式化、可精确验证的语言,这让它在 AI 时代同时具备“难度极高”和“潜在回报巨大”两种属性。一方面,复杂的定理证明与高阶推理对模型能力提出了极高要求;另一方面,数学推理与符号计算的结果可以被严格验证,天然适合与程序化工具协同。AI 在数学与符号推理方向的目标,是构建能够在形式系统中**进行可靠推理与计算**的模型,并将其融入教育、科研与工程应用。 - -这一方向一端连接 Lean / Coq / Isabelle 等交互式定理证明器,SymPy / Mathematica / Maple 等计算机代数系统(CAS),以及大型数学题库与文献语料;另一端连接数学教育产品、辅助研究工具与工程 / 金融等领域的公式推导与风险分析需求。下面从 **场景** 、 **原理** 、**模型** 三个角度展开。 - -* **场景** - * 自动定理证明与辅助证明:在形式化系统中自动给出定理证明,或生成可读的证明草稿,由人类进一步审阅与完善。 - * 表达式操作与符号计算:自动化简表达式、求导、积分、级数展开、变换与方程求解,为工程建模与金融风险分析提供符号工具。 - * 数学题理解与解题步骤生成:从自然语言或图片中的题目提取结构化表示,给出严谨、可检查的解题步骤,服务于教育与训练场景。 - * 数学推理能力增强:通过数学专向微调与工具增强,提高大模型在算术、代数、几何、组合等领域的多步推理与严谨性。 -* **原理** - * 形式系统与搜索: - * 在 Lean / Coq / Isabelle 等系统内,数学对象与定理被形式化为项与类型,证明过程对应于在规则约束下构建证明树。 - * 证明搜索可以视为“在极大状态空间中寻找满足约束的路径”,适合采用强化学习、MCTS(蒙特卡洛树搜索)与策略网络 / 价值网络等方法。 - * 神经 – 符号协同: - * LLM 负责从自然语言或非结构化输入中提取问题结构与求解思路,将其翻译为符号表达(如 SymPy 代码、Lean 证明脚本)。 - * 计算机代数系统与定理证明器负责执行严格的符号计算与形式验证,对 LLM 输出进行校验与纠错。 - * 数学推理能力提升: - * 通过在大规模数学文本与题库上做专向预训练或微调(如 Minerva、Gödel),提升模型对数学语言的理解与推理风格的掌握。 - * 采用 Tool‑Augmented LLM 框架,将符号求解器、数值计算库、绘图工具与证明器作为外部工具,让模型在复杂推理中学会“调用工具”而非“死记结果”。 -* **模型** - * 自动定理证明: - * AlphaZero‑style 证明器:将证明进程视为博弈过程,使用策略网络和价值网络引导搜索,逐步构造形式证明。 - * GPT‑f、Lean‑Dojo 等:在大规模形式化定理与证明语料上训练,用于在 Lean 等系统中自动生成证明。 - * 数学大模型与工具增强: - * Minerva、Gödel 等:在数学教材、论文、题库等语料上微调的大模型,在证明题、竞赛题和高阶推理任务上表现更强。 - * LLM + SymPy / Mathematica / Lean / Coq:由 LLM 做问题解析与策略规划,调用符号计算与证明工具做精确操作与验证。 - * 产品与应用: - * 教育产品中的“数学助教 / 解题助手”,提供个性化讲解与多种解法路径。 - * 辅助研究工具:帮助研究者构造猜想、生成证明草稿、搜索相关定理与引理,加速理论探索。 - * 工程 / 金融领域的公式推导与风险模型分析:将复杂模型形式化,进行符号敏感性分析与合规性审查。 - -### 10.5.1 自动定理证明与形式化推理 - -**自动定理证明(ATP)与交互式定理证明(ITP)** 是数学与计算机科学交叉的重要方向。AI 介入这一领域的核心任务,是在形式系统中自动构造或辅助构造证明,减少人类在低层次细节上的负担,使其更多地专注于高层次思路。 - -在 **形式化系统** 中: - -* 定理被编码为需要构造的目标类型(goal),证明对应为构造某个项,使其类型为该目标类型。 -* 证明过程由一系列战术(tactics)或推理步骤组成,每一步都在严格的逻辑规则下推进。 - -AI 在其中可以承担多种角色: - -1. **战术选择与参数推荐** :在当前证明状态下,预测下一步应使用的战术及其参数,减少人工尝试与回溯。 -2. **引理与定理检索** :从庞大的库中检索与当前目标最相关的引理 / 定理,缩小搜索空间。 -3. **端到端证明生成** :在给定定理与上下文的情况下,直接生成完整或局部证明脚本,再由证明器验证其正确性。 - -AlphaZero‑style 证明器、GPT‑f、Lean‑Dojo 等工作,通过在大规模形式化语料上训练策略与价值网络或语言模型,实现了在 Lean / Coq 等系统上自动完成相当比例定理的证明。在产品方向上,这类能力有望演化为“形式化验证助手”,用于软件 / 硬件验证、加密协议分析和高可靠系统设计。 - -### 10.5.2 符号计算与数学问题求解:LLM + CAS - -相比定理证明,**符号计算与数学问题求解** 更贴近工程与教育场景。其目标是: **从自然语言问题出发,自动构造符号表达、执行计算并给出可解释的解题步骤** 。 - -在这一方向上,典型的神经 – 符号协作流程为: - -1. **问题理解与抽象** :LLM 将自然语言或图片中的题目解析为结构化数学表达(方程、约束、目标函数等)。 -2. **符号表达生成** :将抽象结果翻译为 CAS 代码(如 SymPy 表达式、Mathematica 命令)。 -3. **调用 ****CAS** ** 执行** :使用 CAS 进行精确的代数运算、求导、积分、求解方程组、极限等。 -4. **结果解释与步骤生成** :LLM 基于 CAS 的计算结果,生成符合人类习惯的解题步骤与解释。 - -这一模式有几个关键优势: - -* 通过 CAS 保障计算的正确性,避免 LLM 在长算式上的“错位运算”与累积错误。 -* 通过 LLM 提供自然语言理解与表达,降低 CAS 的使用门槛,使非专业用户也能调用强大的符号工具。 -* 在教育场景中,可以控制解题的详细程度与风格,生成适合不同学习阶段的讲解。 - -在工程 / 金融场景中,这一能力可以扩展到复杂模型的公式化与分析:自动从文档与代码中提取模型结构,构造符号表示,并进行敏感性分析、边界情况分析与风险识别。 - -## 10.6 科学工作流与自动化实验(Scientific Workflow & Lab Automation) - -前面的子方向大多聚焦于“单点能力”:预测一个性质、生成一个结构、证明一个定理。然而在真实的科研与工业研发中,更关键的是如何把这些能力**串联成完整的** **工作流** ,并与文献、数据库、仿真平台与自动化实验设备打通。科学工作流与自动化实验方向,旨在构建面向科学场景的 **Agent + 工具 + 机器人** 一体化系统,让 AI 从“会算”进化到“会做实验、会做研究”。 - -这一方向一端连接论文与专利数据库(如 PubMed、arXiv)、科学数据仓库、领域知识图谱与仿真平台,另一端连接自动化实验室(Robotic Lab)、高通量筛选设备与科研流程管理系统。下面从 **场景** 、 **原理** 、**模型** 三个角度展开。 - -* **场景** - * 科学文献挖掘与知识库构建:从海量论文中自动提取化合物、蛋白、材料、反应条件、实验结果等信息,构建结构化知识库与知识图谱。 - * 实验设计与 Self‑Driving Lab:在 AI 提出的实验计划指导下,由机器人实验平台自动执行配制、反应、测量与数据采集,实现“闭环”优化。 - * 科学数据管理与可重复性保障:自动整理仿真与实验数据、元数据与代码脚本,生成标准化实验记录与报告,提高可追溯性与复现性。 - * 领域“AI 实验助手”:为药企、材料公司与科研机构提供一站式的文献检索、方案设计、实验规划与结果分析支持。 -* **原理** - * 文献挖掘与领域 LLM: - * 利用 SciBERT、BioBERT、PubMedBERT 等领域预训练模型进行命名实体识别、关系抽取、反应式解析与实验条件抽取。 - * 在此基础上训练 Bio‑LM、Chem‑LM、Materials‑LM 等领域 LLM,提升对专业术语、实验语句与隐含假设的理解与推理能力。 - * 实验设计与 Self‑Driving Lab: - * 将实验空间(配方、温度、时间、添加顺序等)视为优化变量,由 LLM + RL 或贝叶斯优化策略提出下一组实验条件。 - * 实验机器人与仪器按照计划执行,采集数据并实时回传,由模型更新参数与不确定性估计,形成主动学习闭环。 - * 工作流编排与 Agent: - * 在 Agent & Tool Use 框架下,将文献检索、代码生成、仿真调用、数据分析、可视化与报告生成工具统一纳入。 - * Agent 根据任务目标(如“寻找高导电电解质配方”),自动规划任务分解、调用工具顺序与结果整合。 -* **模型** - * 文献与知识挖掘模型: - * SciBERT、BioBERT、PubMedBERT 等:针对科学与生医文献进行预训练的模型,用于实体 / 关系抽取、分类与问答。 - * Galactica、领域特化 LLM:以科学语料为主进行训练,支持综述生成、代码草稿、实验设计建议等。 - * 实验规划与控制模型: - * LLM + RL / Bayesian Optimization:结合领域先验、模型不确定性与实验成本,对实验空间进行高效探索与 exploitation。 - * 与 Robotic Lab 控制接口集成的 Agent:将自然语言实验描述转换为结构化实验步骤与仪器控制命令。 - * 科学 Agent 与工作流系统: - * 在 7 章 Agent & Tool Use 能力基础上,构建面向科学场景的“多工具 Agent”:能够检索文献、生成代码、调用仿真、处理数据、绘制图表并写出报告初稿。 - * 产品与应用: - * 药企 / 材料公司内部的“AI 实验助手”与自动化实验台:用于加速配方开发、工艺优化与候选筛选。 - * 领域科学搜索引擎与知识图谱(Bio / Chem / Materials / Physics Knowledge Graph):支持语义检索、交互式探索与知识推理。 - * 科研流程管理平台:集成实验规划、数据记录、版本管理、可视化与报告自动生成,提高科研团队的效率与结果的可复现性。 - -### 10.6.1 科学文献挖掘与领域知识库构建 - -科学知识的绝大部分首先以论文与报告的形式出现。要让 AI 真正参与科研,就必须让其“读得懂论文,并从中提炼结构化知识”。 **科学文献挖掘与知识库构建** ,正是从非结构化文本出发,构建可查询、可推理的知识基础设施。 - -在这一方向中,核心任务包括: - -* **实体识别与标准化** :识别文献中的化合物、蛋白、材料、反应物、产物、实验设备与条件等实体,并与标准数据库(如 ChEMBL、Uniprot、Materials Project)对齐。 -* **关系与事件抽取** :从文本中抽取“谁与谁如何相互作用”“什么条件下产生了什么结果”等关系与事件,例如反应方程、配方–性能对应关系等。 -* **知识图谱** **构建** :将实体与关系组织为图结构,支持复杂查询(如“在某条件下提高某性能的所有已报道方法”)与路径推理。 - -为实现上述目标,常采用: - -* SciBERT、BioBERT、PubMedBERT 等预训练模型进行 NER(实体识别)、RE(关系抽取)与文档级事件抽取。 -* 在此基础上构建领域特化 LLM(Bio‑LM、Chem‑LM、Materials‑LM),用于进行更复杂的问题回答、综述生成与知识补全。 - -构建好的领域知识库与知识图谱不仅可以为研发人员提供更智能的检索与推荐服务,也为后续的实验设计、材料 / 药物逆设计提供数据与先验支撑。 - -### 10.6.2 Self‑Driving Lab 与科学工作流 Agent:从“读论文”到“做实验” - -在具备文献挖掘、建模与优化能力之后,下一步就是把这些能力与 **自动化实验平台** 结合,构建真正意义上的 **Self‑Driving Lab(自驱动实验室)** 与科学工作流 Agent。 - -在 Self‑Driving Lab 中,典型工作闭环为: - -1. **目标设定** :研究者给出宏观目标(如“提高某材料在特定条件下的导电率”)与约束条件(成本、安全性、工艺限制等)。 -2. **文献与知识检索** :Agent 调用文献检索与知识图谱,了解现有工作与经验规律,形成初始假设与实验设计空间。 -3. **实验规划与优化策略** :基于 LLM + RL / 贝叶斯优化策略,提出首批实验条件(配方、温度、时间、环境等)。 -4. **机器人执行与数据采集** :自动化实验台(Robotic Lab)执行实验,实时采集结果并回传。 -5. **模型更新与下一轮设计** :代理模型根据新数据更新参数与不确定性估计,再提出下一轮更有信息量或更有潜力的实验条件。 - -在更广义的 **科学****工作流**** Agent** 中,这一闭环会扩展到仿真、数据分析与报告生成等环节: - -* Agent 可以自动生成仿真代码或调用现有仿真工具,对某些实验条件进行前置评估; -* 在数据分析阶段,自动完成数据清洗、可视化与统计检验; -* 在项目阶段总结时,生成结构化的实验记录与报告草稿,附带图表与参考文献。 - -在产品形态上,这类系统往往以平台形式落地:提供一套统一的界面与 API,对接文献库、仿真引擎与实验设备,让科学家和工程师在高层用自然语言与可视化界面制定目标,其余环节由 Agent + 工具链自动编排与执行。 - -从这一子方向开始,AI 在科学中的角色真正从“离线分析工具”转向“在线科研合作者”:不仅能读论文、写代码、算模型,更能与机器人一起,完成一项项真实的实验与发现。 - -# 11. 平台与工程能力(MLOps / Infra) - -大模型从实验室走向企业生产,绝不仅是“模型本身足够好”就可以,而是要依托一整套稳定、可扩展、可运维的 **平台与工程体系** 。这套体系需要贯穿模型的**训练与微调、部署与推理优化、数据与模型运维、监控与成本管理、安全与合规、以及中台与应用支撑能力**等环节,把原本零散的技术点串成一个可持续运转的闭环。 - -从业务视角看,平台与工程能力往往决定了一个组织是否能“规模化地、安全且低成本地”使用大模型:同样的底层模型,如果没有良好的 MLOps 体系,很可能只能停留在 Demo 与试点阶段;而一旦具备完善的平台,企业就能在多个 BU、多个国家 / 区域、多个行业场景中快速复制与演进高质量应用。下面我们将分别从**模型训练与微调平台、部署与推理优化、数据与模型运维、监控与成本可靠性、安全与合规基础设施、以及上层应用与中台能力**六个方向展开阐述 - -## 11.1 模型训练与微调(Training & Fine-tuning) - -在基础模型层面,大部分组织不会从零开始训练千亿参数模型,而是基于开源或商用基座做 **继续预训练 + 微调** 。这一层的核心问题是:如何高效利用算力和数据,把通用大模型“拉近”到具体行业、企业和任务上,同时又要保证多模型、多版本的工程可管理性。 - -从工程视角看,这一层通常包含三块: **预训练与继续预训练** 、**微调****范式****与工具链**以及**大规模****分布式** **训练基础设施** 。 - -* **场景** - * 通用大模型底座研发:云厂商 / 大厂自研通用语言 / 多模态基座模型,用于对外 API 和内部多业务共享。 - * 行业大模型与专有模型:围绕金融、医疗、法律、制造、能源、游戏等特定领域,构建行业基座模型或“企业自有大模型”。 - * 企业级模型定制:为单一大客户(银行、保险、政府、制造集团等)基于其内部数据定制专属微调模型或 LoRA 权重。 - * 多租户模型市场:SaaS / 云平台为众多中小客户提供“一客一模型”的微调与托管能力,每个租户一套权重或适配层。 - * 一键微调平台:对非算法团队开放的“上传数据 → 选择底座模型 → 自动微调 → 一键部署”全托管产品。 -* **原理** - * 预训练与继续预训练: - * 在海量通用文本、代码、多模态数据上进行大规模预训练,使模型获得 **通用语言理解、世界知识与基本推理能力** 。 - * 对于特定行业,通过 **Domain‑adaptive Pretraining(DAPT)** 在通用模型之上继续预训练,引入行业专有术语、写作风格和知识分布。 - * 多语言 / 多模态预训练通过共享语义空间与联合训练,使模型具备**跨语言迁移**与**图文 / 语音 / 结构化数据融合**能力。 - * 微调范式: - * **全参数微调** :在目标任务与预训练分布差异极大、且有充足算力和数据时,直接更新全部参数,获得最高上限性能。 - * **参数高效微调(PEFT)** :通过 Adapter、LoRA / QLoRA、Prefix / P‑Tuning 等方式,仅训练极少量“增量参数”,适合多任务、多客户、频繁更新场景。 - * **指令** **微调与任务微调** :用“指令 + 示例”的方式让模型学会理解自然语言任务描述;既可以面向单一垂直任务,也可以在统一模型上承载多任务。 - * **RLHF** ** / RLAIF** :通过人类或 AI 反馈训练奖励模型,进一步用强化学习对齐模型行为(礼貌性、安全性、拒答策略、价值观)。 - * 分布式训练与工程体系: - * 使用 **数据并行、模型并行、流水线** **并行** **、** **张量****并行**等策略,将超大模型和大规模数据拆分至集群多节点、多卡协同训练。 - * 通过 ZeRO / FSDP 等技术**降低****显存** **占用、提升训练吞吐** ,配合高效调度(Kubernetes + Slurm / Ray)实现大规模集群训练。 - * 依托标准化的数据 pipeline(数据集加载、清洗、去重、分片、缓存)与微调框架(Transformers Trainer、DeepSpeed、Lightning 等)减少重复造轮子。 -* **模型** - * 预训练与继续预训练工具链: - * 训练框架:PyTorch、TensorFlow、JAX。 - * 大规模训练加速:DeepSpeed、Megatron‑LM、Colossal‑AI、Fairscale。 - * 分布式训练策略:数据并行(DP)、模型并行(MP)、流水线并行(PP)、张量并行;ZeRO / FSDP、Megatron(TP+PP)、DeepSpeed ZeRO。 - * 集群调度与管理:Kubernetes + Slurm / Ray / Horovod / TorchElastic。 - * 数据 pipeline:Hugging Face Datasets、WebDataset、Petastorm、tf.data、Arrow;对象存储(S3 / OSS / GCS)+ 本地 cache;数据清洗与去重工具。 - * 微调与 PEFT 工具: - * 微调框架:Hugging Face Transformers + Trainer / Accelerate、PyTorch Lightning、DeepSpeed、Colossal‑AI。 - * PEFT 工具集:PEFT(LoRA / QLoRA / Prefix Tuning / Prompt Tuning 等)、LLaMA‑Adapter 及各类 LoRA 工具链。 - * 指令与数据构建:Self‑Instruct、Alpaca / Dolly 风格 pipeline,各类数据增强与对话重写工具。 - * RLHF / RLAIF 工具链: - * TRL(Transformers Reinforcement Learning)、trlx、DeepSpeed‑RLHF、自研 RLHF pipeline。 - * 奖励模型训练、排序 / 评分模型、拒答策略与对齐策略模板。 - -在产品形态上,这一层往往体现为: **模型底座研发平台、企业级“代训+定制”服务、一键微调平台与模型市场(Model Hub / Model Store)** ,支撑从“通用模型”到“千企千模”的生产化路径。 - -### 11.1.1 预训练与继续预训练:从通用能力到行业基座 - -预训练是现代大模型能力的“源头工程”:通过对海量未标注文本、代码和多模态数据的自监督学习,模型逐渐获得语言建模、世界知识、基本推理与表示学习能力。在此基础上,继续预训练(特别是 **Domain‑adaptive Pretraining, DAPT** )则承担了“把模型拉向某个垂直领域”的任务。 - -在**通用预训练**阶段,核心关注点包括: - -1. **语料规模与多样性** :混合网页文本、书籍、代码、对话、多语种内容以及图文对等多模态数据,尽可能覆盖广泛的知识与表达形式。 -2. **训练目标与多任务混合** :除了经典的自回归语言建模外,有时会加入填空、下一句预测、对比学习、图文对齐等目标,提升模型的语义对齐与多模态理解。 -3. **多语言与对齐** :通过共享词表或子词编码,以及跨语种平行语料或对齐任务,使模型在统一向量空间中对不同语言进行建模,实现 **跨语言迁移与翻译** 。 - -在**行业继续预训练(DAPT)** 阶段,重点转向: - -1. **行业语料构建** :从医疗病历与指南、法律判决书与法规条文、金融研报与交易数据、制造 / 能源 / 游戏设计文档等渠道构建专有语料。 -2. **风格与术语适配** :通过大量领域内语料的继续预训练,使模型自然掌握行业术语、固定表达、专业写作风格与隐性知识(如临床表述习惯、法律措辞)。 -3. **企业级专有知识注入** :对于大型企业或机构,可在通用 + 行业语料之外进一步加入企业内部文档、知识库、工单记录等,训练“企业专有大模型”作为统一智能底座。 - -在工程实践中,预训练与继续预训练会配合大规模分布式框架(Megatron‑LM、DeepSpeed ZeRO 等)以及高效的数据 pipeline(WebDataset / HF Datasets + 对象存储)运行,形成 **稳定可复用的训练流水线** 。对于云厂商或大厂,这一流水线往往会被封装为内部平台,支持周期性增量预训练和多行业基座并行迭代。 - -### 11.1.2 微调范式与 RLHF:从“能说话”到“懂业务、守边界” - -在拥有强大的预训练基座之后,如何让模型“对业务有用”并“行为可控”,关键在于微调与对齐阶段。这里既包括传统意义上的监督微调(SFT),也包括指令微调、多任务微调和基于反馈的强化学习(RLHF / RLAIF)。 - -在**微调范式**层面,可以大致分为: - -1. **全参数微调(Full Fine‑tuning)** - 在任务分布与预训练差异很大,或对极致性能有刚性要求且算力充足的场景(如特定编程语言模型、特定语言 / 行业对话模型)中,直接更新全部参数可以获得最大性能上限。但其成本高、版本管理复杂,一般只在少数核心模型上使用。 -2. **参数高效微调(PEFT)** - 通过 Adapter、LoRA / QLoRA、Prefix / P‑Tuning 等方法,仅对插入的“小块增量参数”或权重低秩增量进行训练,原始大模型权重保持冻结。这带来了三点工程优势: - 1. 多任务 / 多客户可以共享同一基座,只切换不同的 Adapter / LoRA 权重。 - 2. 显著降低显存与算力需求,支持在中小型 GPU 集群或单机环境中完成微调。 - 3. 更新频繁、回滚简单,便于快速试错与 A/B 实验。 -3. **指令微调与任务微调** - 1. **指令微调(Instruction Tuning)** :通过“自然语言指令 + 输入 + 期望输出”的样本,让模型学会理解“帮我…”“请解释…”等人类指令形式,从而摆脱任务特定模板。 - 2. **单任务微调** :如仅针对客服问答、代码补全、法律咨询等垂直任务进行微调,最大化该任务表现。 - 3. **多任务微调** :在统一模型上同时承载多种任务(问答、摘要、翻译、代码、推荐理由生成等),提升模型通用性和资源利用率。 - -在**行为对齐与安全性**层面,**RLHF / RLAIF** 起到关键作用: - -1. **奖励模型(Reward Model)训练** :收集人类或 AI 对模型多种候选回答的偏好(排序 / 打分),训练一个能评估“回答好坏”的奖励模型。 -2. **强化学习(如 PPO)优化基座模型** :在奖励模型的指导下,通过强化学习调整模型参数,使其更符合人类偏好和平台价值观,例如: -3. 更礼貌、中立、专业; -4. 对危险、违规、隐私相关请求进行拒答或安全改写; -5. 在有不确定性时表明不确定,而非虚构事实。 -6. **RLAIF 与自监督对齐** :在部分场景下,使用强基座模型作为反馈者,或结合规则与自动化评估,对微调过程进行半自动对齐,降低人工标注成本。 - -工具链方面,Hugging Face Transformers + PEFT、TRL / trlx、DeepSpeed‑RLHF 等框架,已经基本形成了从 SFT → RM 训练 → RLHF 的**标准工业工作流** 。在产品定义上,这一层典型落地为:**模型定制 / 代训服务、一键微调平台、多租户模型市场与行业 / 企业专有大模型工程平台** 。 - -## 11.2 模型部署与推理(Serving & Optimization) - -在训练好大模型之后,如何以 **高可用、** **低延迟** **、可扩展、可降本**的方式提供推理服务,是 AI 工程体系的第二根支柱。部署与推理层一端连接 GPU / NPU 等算力集群,另一端连接 API 网关、企业应用和对外开放平台,其核心职责包括: **部署架构设计、模型路由策略、推理性能优化与硬件利用** 。 - -从整体来看,这一层要解决三个问题: **用什么架构对外服务** 、 **如何让推理更快更便宜** 、 **如何在多模型、多地域、多租户环境下保持高可用与可治理** 。 - -* **场景** - * 企业内部 AI 中台 / 模型服务总线:统一为各业务线提供大模型 API,屏蔽底层模型和硬件差异。 - * 对外开放云 API:向外部开发者与生态伙伴提供标准化的推理接口,支持多模型选择与版本管理。 - * 高 QPS 在线业务:客服助手、搜索、推荐、办公助手等对延迟和稳定性要求极高的场景。 - * 低成本离线生成:广告 / 游戏文案、知识库生成、代码批量重构等以吞吐与成本为主、对实时性要求不高的批处理任务。 - * 跨地域、多集群部署:为全球或多区域用户提供就近访问,同时支持多云或混合云形态。 -* **原理** - * 部署架构与模型路由: - * **单模型服务** :在早期或简单场景下,以一个主模型对外提供统一服务,架构简单,但难以兼顾延迟与成本。 - * **多模型服务与路由** :针对不同任务、延迟要求、成本约束、用户等级等维度,配置不同大小或不同专长的模型,并通过规则或 Meta‑model 进行请求路由(包括 A/B 测试、多臂老虎机 / Bandit 策略等)。 - * **多租户隔离与 ****SLA** ** 管理** :在多客户场景中,通过资源配额、QPS 限制、访问鉴权和 SLA 分级确保不同租户之间在性能与安全上的隔离。 - * **弹性扩容与高可用** :借助 Kubernetes / Service Mesh 等基础设施,实现自动扩缩容、多副本部署、灰度发布、蓝绿部署和跨区域容灾。 - * 推理性能优化: - * **模型压缩与加速** :通过量化(INT8 / INT4 / NF4 / GPTQ / AWQ)、剪枝 / 稀疏化、知识蒸馏等手段减少模型计算量与显存占用。 - * **系统级优化** :利用 KV Cache 缓存注意力键值,加速长对话与连续推理;通过批处理(Batching)、并行 token 生成和流式输出平衡吞吐与延迟;通过算子融合和图优化减少内存访问和内核启动开销。 - * **异构硬件利用** :针对 GPU、CPU、NPU、FPGA、ASIC 等不同硬件构建适配的 Runtime 与调度策略,在单机多卡、多机多卡场景下通过 NVLink / RDMA 等高速互联提升整体效率。 - * 工程与运维: - * 使用 vLLM、TGI、Triton 等专用推理框架,显著降低自研成本。 - * 通过 ONNX Runtime、TensorRT、TVM、OpenVINO 等编译器与 Runtime 进行跨平台部署与算子级优化。 - * 借助 Kubernetes、Ray、Service Mesh 和 API 网关构建统一的 **在线推理集群与流量调度层** 。 -* **模型** - * Serving 框架与推理服务: - * vLLM、TGI(Text Generation Inference)、Triton Inference Server。 - * Ray Serve、KServe、TorchServe、SageMaker Endpoint、Vertex AI Endpoint 等。 - * 集群与调度: - * Kubernetes(K8s)、Kubeflow、Ray、Slurm。 - * Service Mesh:Istio / Linkerd(支持灰度、限流、熔断、回退等流量治理)。 - * API 网关与鉴权: - * Kong、NGINX / APISIX / Envoy。 - * IAM / Keycloak / Auth0、云厂商 API Gateway、OAuth2 / OIDC 等。 - * 模型压缩与性能库: - * 量化:NVIDIA TensorRT‑LLM / TensorRT、Intel Neural Compressor、OpenVINO(PTQ / QAT)、BitsAndBytes、GPTQ、AWQ、AutoGPTQ。 - * 剪枝 / 稀疏:PyTorch Sparse、TensorFlow Model Optimization Toolkit、SparseML、Neural Magic。 - * 蒸馏:DistilBERT / TinyBERT 等参考方案,或基于 Hugging Face Trainer + 自定义 distillation loss 的蒸馏 pipeline。 - * 推理引擎 / Runtime 与图优化: - * ONNX Runtime、TensorRT、OpenVINO Runtime、TVM、MNN、NCNN。 - * 大模型专用推理引擎:Sglang、vLLM、FasterTransformer、TGI、LMDeploy、DeepSpeed‑Inference。 - * 编译与图优化:TVM、XLA(JAX/TF)、TensorRT Graph Optimizer、TorchDynamo / TorchInductor、MLIR、Glow、ONNX Graph Optimizer、Intel NNCF 等。 - * 硬件与异构支持: - * GPU:CUDA / cuDNN / cuBLAS、ROCm(AMD)。 - * CPU:oneDNN(MKL‑DNN)、OpenBLAS、Eigen。 - * NPU / 专用加速卡:Ascend CANN、Habana Gaudi、Graphcore IPU 等 SDK。 - -在产品侧,这一层常以 **企业 AI 中台 / 模型服务总线、对外云 ** **API** **、统一推理** **网关** **、高 ****QPS**** 在线推理集群、低成本****批处理****平台与****算力****利用率优化方案** 的形态出现,是支撑大模型能力规模化落地的运行时“操作系统”。 - -### 11.2.1 部署架构与模型路由:从单模型到多模型服务网格 - -在早期尝试阶段,很多团队会选择以一个“大而全”的模型作为**单一入口**提供服务:所有请求都经由同一个模型处理。这种模式架构简单、维护成本低,适合 POC 与低流量场景。但随着业务扩展和成本压力上升,单模型架构的不足会迅速暴露: - -1. 不同任务对延迟 / 成本 / 质量的要求并不相同,用同一个大模型处理所有请求会造成**算力** **浪费** 。 -2. 面向不同行业、不同客户需要提供差异化能力,例如行业专有模型、客户专属微调权重,很难在“单模型”模式下统一管理。 -3. 灰度发布、A/B 测试、跨地域灾备等场景要求能够在多个模型版本之间灵活调度。 - -因此,成熟的大模型服务体系往往会演进为**多模型服务与智能路由**架构: - -1. **多模型池与模型目录** :同时维护多种大小(small / base / large / ultra)、多种专长(通用 / 代码 / 多模态 / 行业专用)、多种版本(v1 / v1.1 / 客户定制等)的模型,并在服务层对其进行统一注册与管理。 -2. **路由策略** : -3. **规则路由** :基于请求参数(任务类型、用户等级、延迟 / 成本偏好等)以及业务规则(某行业某区域强制使用特定模型)进行显式选择。 -4. **模型选择器(** **Meta** **‑model)** :使用一个轻量级模型根据输入内容、历史效果、实时指标自动选择最优模型(如快速小模型 vs. 慢速大模型)。 -5. **A/B / Bandit 路由** :在新旧模型或不同配置之间进行在线实验,根据 CTR、用户满意度、任务成功率等指标自动收敛到更优方案。 -6. **多租户隔离与配额管理** : -7. 在模型路由之上叠加租户维度的配额控制、QPS 限制、访问鉴权与 SLA 分级,确保不同客户之间的资源与数据隔离。 -8. 通过**逻辑隔离 + 物理隔离(独占集群或专用节点)** n应对金融 / 医疗 / 政务等高合规场景。 -9. **弹性扩缩容与高可用** : -10. 基于 Kubernetes HPA / VPA、Cluster Autoscaler 实现按流量自动扩缩容。 -11. 通过多副本部署、负载均衡、灰度发布、蓝绿部署和多区域容灾保证服务稳定性。 - -技术上,往往会采用 **Kubernetes + Service Mesh(Istio / Linkerd)+ ****API** **网关** **(Kong / APISIX / ** **Envoy** **)+ 模型服务框架(vLLM / TGI / Triton / Ray Serve / KServe)** 的组合,形成一个既支持多模型、多租户,又支持流量治理与灰度发布的 **服务网格化推理平台** 。 - -### 11.2.2 推理性能优化与硬件加速:把“推理一次多少钱”压到最低 - -在大模型大规模商用场景中,推理成本往往是最大的持续支出之一。如何在保证体验的前提下,将**单位请求成本(Cost per Request / per Token)和端到端延迟**压缩到可接受范围,是部署层的核心技术挑战。 - -在 **模型侧** ,常见手段包括: - -1. **量化(Quantization)** - 通过将权重和激活从 FP16 / BF16 压缩到 INT8 / INT4 / NF4 等低比特格式,显著降低显存占用和带宽开销。 - 1. 训练后量化(PTQ):如 GPTQ、AWQ、BitsAndBytes 等,对已有模型进行离线量化。 - 2. 量化感知训练(QAT):在训练 / 微调阶段考虑量化误差,提升量化后精度。 -2. **剪枝** **与稀疏化(** **Pruning**** & Sparsity)** - 通过结构化 / 非结构化剪枝去除不重要的权重或通道,使模型稀疏化,并结合硬件友好的稀疏算子(如 NVIDIA 稀疏矩阵加速)提高推理速度。 -3. **蒸馏(Distillation)** - 使用大模型作为教师,将知识蒸馏到更小的学生模型或任务特定模型上,在大幅降低参数规模的同时保持接近的任务性能,适合对延迟极敏感的在线业务或边缘部署。 - -在 **系统与 Runtime 侧** ,关键优化点包括: - -1. **KV** ** Cache 与长上下文优化** : - 在自回归生成中缓存历史 token 的注意力键值,避免重复计算,从而提高长对话与多轮请求的效率;结合分块计算和动态裁剪策略控制显存开销。 -2. **批处理****与****并行** **生成** : - 通过对多个请求进行动态批处理、分组调度和并行 token 生成,在不显著增加 P95 延迟的前提下提高整体吞吐;结合流式输出(Streaming)改善前端交互体验。 -3. **算子与图优化** : - 使用编译器和 Runtime(如 TensorRT、TVM、ONNX Runtime、TorchInductor)进行算子融合、内存布局优化、静态图编译,减少 kernel 启动和内存访问开销。 -4. **异构硬件调度** : - 根据不同任务的计算特性与延迟要求,在 GPU、CPU、NPU、FPGA 等异构资源之间做合理分配: -5. 极度延迟敏感和高并发的对话 / 搜索请求优先调度到 GPU / NPU。 -6. 批量生成、离线评估、日志回放等任务可以调度到 CPU 或低成本 GPU / NPU。 - -工具与框架上,TensorRT‑LLM、SgLang、vLLM、FasterTransformer、LMDeploy、DeepSpeed‑Inference 等已经形成了一套相对成熟的**大模型** **推理加速生态** 。在业务侧,这些优化最终体现为:**高 ** **QPS** **、** **低延迟** **的在线推理集群、低成本批量生成平台、** **算力****利用率优化方案与 MaaS / ****API** ** 计费和成本核算系统** 。 - -## 11.3 数据与模型运维(Data / Model Ops) - -大模型一旦进入生产环境,就不再是“一次性交付”的静态资产,而是需要在**数据、模型、配置、版本和实验**五个维度持续迭代的动态系统。数据与模型运维层(Data / Model Ops)就是围绕这一现实构建的工程范式:从数据飞轮、模型生命周期管理到在线实验和自动化发布,为模型能力的**可持续提升与可控演进**提供基础。 - -这一层一端连接数据湖 / 数仓、日志与采集系统,另一端连接训练平台、评估体系和在线服务网关,是打通“数据–模型–业务反馈”闭环的中枢。 - -* **场景** - * 企业级数据中台 + 模型训练一体化平台:打通数据采集、清洗、标注、管理到训练 / 微调的全链路,支撑多模型持续迭代。 - * 面向 C 端 / B 端 AI 应用的“效果持续提升机制”:依赖用户反馈和使用数据驱动的数据飞轮。 - * 标注团队与算法团队共用的数据管理与标注工作台:支持任务分配、质检、版本回溯。 - * 集团级 ModelOps 平台:统一记录和管理所有模型版本、评估结果与发布状态。 - * 在线业务实验与灰度体系:支持 A/B 测试、多模型小流量试运行和自动择优放量。 - * 模型托管服务:为合作伙伴 / 客户提供“一处上传,多环境部署,多版本管理”的模型管理能力。 -* **原理** - * 数据管理与数据飞轮: - * **数据采集与治理** :从业务日志、用户对话、公开数据、合作方数据中采集样本,对其进行去重、降噪、脱敏、格式统一和质量评估。 - * **标注与反馈闭环** :通过专家标注与众包结合、配合质检机制构建高质量标注数据;将用户的点赞 / 点踩、纠错、人工复核等反馈回流至训练样本池。 - * **数据飞轮(Data Flywheel)** :模型上线后,持续收集真实使用数据 → 从中挑选高价值样本(如模型错误、低信度、高收益任务)→ 再训练或微调 → 模型效果提升 → 新一轮使用,形成正反馈循环。 - * 模型生命周期与发布: - * **模型版本管理** :为每个模型维护清晰的版本号(大小版本)、训练数据版本、配置参数、评估结果、安全报告与变更记录。 - * **CI/CD** ** 与自动化流水线** :训练完成后自动触发评估与安全检查,通过回归测试和阈值门控,只有在关键指标不过度退化的情况下才允许灰度发布与全量上线。 - * **实验与流量分配** :使用 A/B 测试、多臂老虎机等在线实验方法,对多版本模型进行对比,按实时业务指标(例如任务成功率、工单解决率、用户满意度)自动择优。 -* **模型** - * 数据湖与数仓: - * Delta Lake、Apache Hudi、Iceberg、Hive、BigQuery、Snowflake 等,用于统一存储与管理大规模结构化 / 非结构化数据。 - * 流式数据处理: - * Kafka、Pulsar、Flink、Spark Streaming 等,用于实时日志、用户对话和事件流接入。 - * 特征与样本管理: - * Feast 等 Feature Store、自研样本仓、ML Metadata Store,用于记录样本、特征和训练元数据。 - * 标注与质检平台: - * Label Studio、Scale‑like 平台、自研标注系统,支持多任务标注、质检与人员管理。 - * MLOps / ModelOps 平台: - * MLflow、Kubeflow、SageMaker、Vertex AI、Azure ML、Weights & Biases 等,用于管理训练实验、参数、指标和模型 artifact。 - * 模型注册与版本管理: - * MLflow Model Registry、SageMaker Model Registry、W&B Artifacts 等。 - * CI/CD 工具: - * GitHub Actions、GitLab CI、Jenkins、Argo CD、Flux 等,用于构建模型持续交付管线。 - -### 11.3.1 数据飞轮与训练闭环:让模型“越用越聪明” - -在传统软件开发中,版本升级往往由开发计划驱动;而在大模型时代,**数据与反馈**成为迭代的主要驱动力。数据飞轮的目标,就是把“模型使用 → 数据沉淀 → 再训练 → 模型升级”变成一条自动滚动的闭环,让模型在实际业务中 **越用越好用** 。 - -核心环节包括: - -1. **在线数据采集与筛选** - 在对话机器人、Copilot、搜索问答、代码助手等应用中,每一次用户交互都是潜在的高价值训练样本。通过日志系统和事件追踪,将请求、模型回答、用户行为(点击、采纳与否)结构化采集下来,并在采集端就进行隐私脱敏与字段裁剪,确保不额外引入合规风险。 -2. **高价值样本挖掘** - 在海量日志中筛选出对训练最有价值的一小部分样本,例如: - 1. 明显错误或被用户点踩的回答,用于“纠错式”再训练。 - 2. 高难度长问题、复杂工作流任务样本,用于提升模型在“长链推理 / 多步工具调用”上的能力。 - 3. 典型业务案例、高价值工单,用于构建行业 / 企业专有能力。 -3. **标注与质量控制** - 对候选样本进行人工或半自动标注(包括期望回答、优劣排序、安全性标签等),并通过多轮质检、复核和抽检手段确保标注质量,为后续 SFT 或 RLHF 提供可靠数据。 -4. **持续****再****训练与评估上线** - 周期性地将新样本加入训练集,进行 SFT / DAPT / RLHF 等再训练操作,并通过标准评测集和在线 A/B 实验同时评估“离线指标 + 线上效果”,确保新版本在总体上优于旧版本,避免数据飞轮“拐到错误方向”。 - -在成熟形态下,数据飞轮的绝大部分操作会被自动化封装进 **Data / Model Ops 平台** :从数据采集、样本筛选、标注任务派发,到模型再训练触发、评估结果收集和上线决策,尽量减少人工操作,使模型迭代成为一个稳定可控的工程流程。 - -### 11.3.2 模型生命周期与 ModelOps:从实验模型到生产资产 - -随着模型数量与版本的指数级增长,如果缺乏严谨的生命周期管理,很容易出现“模型散落各处、版本混乱、回滚困难”等问题。ModelOps 的目标,就是把模型当作**一等公民的工程资产**来管理,全程可追溯、可比较、可回滚。 - -关键要点包括: - -1. **版本化与****元数据管理** - 为每个模型分配明确的版本号(如 `industry-legal-base-v1.2.3`),并记录: - 1. 训练数据版本与时间范围; - 2. 训练配置(超参数、训练脚本版本、使用的代码 Commit); - 3. 评估指标(通用基准 + 业务特定基准); - 4. 安全评估与对齐策略(如敏感话题回答策略版本); - 5. 上线 / 下线 / 回滚历史记录。 -2. **端到端自动化流水线(** **CI/CD**** for Models)** - 将“模型训练完成 → 自动评估 → 安全与偏见检查 → 灰度发布 → 全量发布”的流程封装进 CI/CD 管线。 -3. 若离线评估指标未达到预设门槛,则自动阻断上线。 -4. 若在线 A/B 实验表现不佳,则自动降低流量或回滚到上一版本。 -5. **多版本共存与流量调度** - 在生产环境中,往往会同时存在多个模型版本(如 `stable` / `canary` / `experimental`),通过流量分配策略(固定比例、用户维度、特征维度)对其进行在线对比。 - 1. A/B 测试更关注稳定统计结论; - 2. 多臂老虎机(Multi‑armed Bandit)在探索与利用之间自动折中,加速收敛到效果更好的版本。 -6. **合规与审计支持** - 对于金融、医疗、政务等行业,需要对每一次模型版本变更保持可追溯记录:谁在何时基于什么数据把模型从哪个版本升级到哪个版本,以及升级后的影响评估如何。这部分通常与第 11.5 节中的**安全与合规基础设施**联动。 - -工程实现上,MLflow / SageMaker / Vertex AI / W&B 等工具已经提供了相对成熟的 ModelOps 能力,多数企业会在其基础上结合自身流程做二次封装,构建统一的 **内部模型注册中心与发布平台** 。 - -## 11.4 监控、成本与可靠性(Monitoring, Cost & Reliability) - -当大模型成为业务核心基础设施时,如何保证其 **可观测、可预警、可扩缩、** **可控成本** ,就成为 SRE 和平台团队的核心职责。监控、成本与可靠性层将传统可观测性体系与大模型特有指标结合,构建面向运维、算法与管理层的多维度视图。 - -这一层一端连接监控采集、日志 / 链路追踪系统,另一端连接业务 KPI 与成本分析平台,是保证模型服务“稳、快、省”的关键支柱。 - -* **场景** - * 面向运维 / SRE 的运行监控大盘:统一展示 CPU / GPU 利用率、QPS、延迟、错误率、告警等。 - * 面向算法团队的数据与模型质量监控平台:监控输入数据分布、模型漂移、提示工程效果与 RAG 命中率等。 - * 面向管理层的服务健康看板:将业务 KPI(转化率、满意度、任务完成率)与模型指标绑定展示。 - * AI 成本分析与优化平台:按模型、项目、业务线拆解算力成本,支持预算管理与成本优化策略。 - * 智能调度与弹性伸缩系统:根据负载与预算自动扩缩容或切换模型规格。 - * 对外 MaaS / API 计费与成本核算系统:支撑按调用量、token 数、算力使用量等维度计费。 -* **原理** - * 监控与可观测性: - * **多层监控** :从基础设施层(CPU / GPU / 内存 / 网络 / 存储)到服务层(QPS、P50 / P95 / P99 延迟、错误率、超时重试),再到模型层(token 使用量、上下文长度分布、响应长度、常见错误类型)。 - * **日志与链路追踪** :通过结构化日志记录请求 / 响应(在脱敏前提下),并携带模型版本、路由决策、租户信息;使用分布式追踪工具记录请求从 API 网关 → 模型服务 → 下游系统的完整链路。 - * **告警与分析** :设置阈值告警、异常检测和趋势分析,并与业务指标、成本和安全事件联动,实现快速定位与恢复。 - * 成本控制与弹性调度: - * **成本分析** :按模型、项目、业务线维度拆解 GPU / CPU / 存储 / 带宽成本,计算单请求平均成本和不同任务 / 客户的边际成本。 - * **弹性调度** :运用峰谷分时策略,在高峰期自动扩容、低谷期自动缩容;将离线批量任务错峰到夜间或低负载时段。 - * **策略性降级与按需加速** :在资源紧张时自动切换到小模型、更短上下文或更保守的推理配置;对高价值请求自动使用更大模型或更长上下文。 -* **模型** - * 监控与可视化: - * Prometheus + Grafana、VictoriaMetrics、Thanos 等指标采集与可视化方案。 - * 日志系统: - * ELK(Elasticsearch + Logstash + Kibana)、EFK(Fluentd / Fluent Bit)、OpenSearch 等。 - * 链路追踪: - * OpenTelemetry、Jaeger、Zipkin 等。 - * 模型特定监控: - * WhyLabs、Arize AI、Fiddler、Evidently AI 等,用于数据 / 模型漂移监控与输出质量评估。 - * 成本统计与分摊: - * K8s Metrics / Cost Exporter、Kubecost,以及各云厂商 Cost Management 工具(AWS Cost Explorer / GCP Billing / Azure Cost Management)。 - * 资源调度与弹性伸缩: - * K8s HPA / VPA、Cluster Autoscaler、Volcano、Ray Cluster Autoscaler。 - * 任务编排: - * Argo Workflows、Airflow、Prefect、Dagster 等。 - -### 11.4.1 监控与可观测性:从基础设施到模型行为 - -在大模型系统中,传统的 CPU / 内存 / QPS 指标已经不够,需要叠加一层“模型视角”的监控,才能真正看清系统健康状况。一个完整的可观测性体系通常包含: - -1. **基础设施与服务层监控** - 通过 Prometheus / Grafana、VictoriaMetrics 等采集并可视化: - 1. 节点 / Pod 级别的 CPU、GPU、内存、磁盘、网络使用情况; - 2. 服务级别的 QPS、P50 / P95 / P99 延迟、错误率、超时重试比例、连接数; - 3. 集群级别的资源使用率与容量预警。 -2. **模型层指标监控** - 针对大模型服务,除了常规性能指标外,还需要专项监控: - 1. 每次请求的 token 消耗(输入 / 输出)、上下文长度分布; - 2. 响应长度与截断比例,以排查因上下文 / 输出长度限制导致的质量问题; - 3. 常见错误类型统计(如超长输入、模型超时、工具调用失败等)。 -3. **日志与****分布式****链路追踪** - 1. 使用结构化日志记录请求参数(脱敏后)、模型版本、路由决策、租户标识、返回代码等信息。 - 2. 借助 OpenTelemetry、Jaeger、Zipkin 等追踪一次请求在 API 网关 → 模型服务 → 下游系统 → 回调链路中的全程,便于定位延迟瓶颈和故障点。 -4. **异常检测与智能告警** - 在传统阈值告警基础上,可以引入简单的统计监控或机器学习模型,对 QPS、延迟、错误率、token 分布等进行异常检测,当出现突变时自动报警,并联动自愈策略(如自动扩容、流量切换、服务降级)。 - -对于算法团队,还可以在这一层接入 WhyLabs、Arize、Evidently AI 等工具,对输入分布、模型输出特征、漂移情况进行长期跟踪,为后续数据飞轮与再训练提供信号。 - -### 11.4.2 成本分析与弹性调度:在“体验”和“预算”之间找平衡点 - -大模型服务最显著的运维挑战之一就是 **成本高且波动大** 。缺乏精细化的成本分析与弹性调度,很容易在业务增长时看不到“钱烧在哪儿”,也难以及时做出调整。一个成熟的成本和资源调度体系通常包括: - -1. **成本归因****与****分摊** - 利用 Kubecost、云厂商 Billing 工具以及自研账本,将 GPU / CPU / 存储 / 带宽成本按模型、项目、业务线、租户等维度拆解,让每个团队和客户都能看到自己对应的真实资源消耗与费用。 -2. **单位请求成本与****边际成本****分析** - 1. 计算每个模型 / 任务的单请求平均成本(Cost per 1k tokens / per request),对比不同模型和配置下的性价比。 - 2. 分析不同客户、不同业务场景的边际成本,为定价策略(API 计费)、SLA 分级和产品打包提供依据。 -3. **弹性扩缩容与峰谷利用** - 1. 通过 K8s HPA / VPA、Cluster Autoscaler、Ray Autoscaler 等机制实现自动扩缩容,保证在高峰期不炸服、在低谷期不闲置。 - 2. 将离线任务(如批量内容生成、日志重放、离线评估)安排在夜间或非高峰时段,以提高整体 GPU 利用率,平滑成本曲线。 -4. **策略性降级与按需加速** - 1. 在资源紧张或成本超预算时自动触发降级策略:使用更小模型、缩短上下文或输出、降低并行度。 - 2. 对高价值请求(如付费高等级用户、关键业务流程)自动使用更大模型、更长上下文或更丰富的工具调用能力,实现“按价值分配算力”。 - -在对外 API 场景,这一层还会与计费系统深度绑定,形成 **MaaS / API 计费与成本核算平台** :根据 token 使用量、调用次数、模型规格和请求类型进行计费,并为运营 / 销售提供成本与毛利分析。 - -## 11.5 安全、权限与合规基础设施(Security, Access Control & Compliance Infra) - -大模型能力一旦进入金融、医疗、政务等高敏感行业,安全与合规不再是“附加价值”,而是进入场景的前置门槛。安全、权限与合规基础设施层负责从**访问控制、数据安全、隐私保护到合规审计**构建系统级防线,保证模型服务在法律与监管框架内可靠运行。 - -这一层一端连接身份认证、权限管理、密钥与加密系统,另一端连接模型服务和日志 / 审计平台,是把“能用的模型”变成“敢用的模型”的关键。 - -* **场景** - * 金融 / 医疗 / 政务等高合规行业的本地化大模型平台:要求数据不出域、可审计、可追溯。 - * 企业统一 AI 访问控制与审计网关:对所有模型调用进行统一鉴权、权限管理和审计记录。 - * 多租户 SaaS / 云平台:需要在逻辑和物理层面为不同客户提供严格的安全隔离与合规支撑。 - * 面向合作伙伴 / 生态的开放接口:要求对 API 调用进行精细化权限控制和配额限制,并满足合规要求(如 GDPR 等)。 -* **原理** - * 访问控制与租户隔离: - * 使用 API Key / Token / OAuth / SSO 等方式进行身份认证。 - * 通过 RBAC(基于角色的访问控制)和 ABAC(基于属性的访问控制)在模型、功能、调用频率和数据范围等维度进行精细化权限管理。 - * 在多租户环境中实现**数据、日志、配置和模型权重**的隔离,防止跨租户访问与信息泄露。 - * 数据安全与隐私保护: - * 采用 TLS 加密传输、存储加密和集中式密钥管理(KMS)保障数据在传输与存储环节的安全。 - * 实施日志脱敏和数据最小化策略,仅保留业务与优化所必需的信息,并对访问行为进行审计。 - * 在必要场景中引入隐私增强技术(如数据匿名化、差分隐私、联邦学习)进一步降低隐私风险。 - * 合规与审计: - * 对模型发布、配置变更、权限变更、路由策略调整等关键操作进行全程留痕与审批。 - * 为每一个请求记录可追溯的元数据:请求来源、模型版本、决策依据(如使用的知识库 / 工具调用情况)。 - * 确保系统设计和运行符合金融、医疗、政务等行业监管要求以及本地与跨境数据合规规范。 -* **模型** - * 身份认证与权限管理: - * Keycloak、Auth0、Okta、各云厂商 IAM(AWS IAM / GCP IAM / Azure AD)。 - * OPA(Open Policy Agent)+ Rego Policy 等策略引擎,用于统一策略管理与执行。 - * API 安全网关: - * Kong、Apigee、Envoy、云厂商 API Gateway 等。 - * 数据与密钥安全: - * KMS(Key Management Service)、HashiCorp Vault。 - * TLS 终端、机密计算(Confidential Computing)等。 - -### 11.5.1 访问控制与租户隔离:保证“谁能用、能用什么、能用多少” - -在多业务线、多客户、多角色共同使用的大模型平台中,若没有细粒度访问控制和租户隔离,很容易出现权限滥用、数据泄露和资源争抢等严重问题。一个完善的访问与隔离体系需要在以下几个维度配合: - -1. **身份认证与****单点登录** - 通过 API Key / Token、OAuth2 / OIDC、企业 SSO 等方式,对内部员工、外部合作伙伴、第三方应用进行统一身份认证。对企业用户,可与现有身份系统(如 AD / LDAP / 企业 IAM)打通,避免重复账号体系。 -2. **细粒度权限控制(** **RBAC**** / ** **ABAC** **)** -3. RBAC:为管理员、算法工程师、业务运营、普通用户、合作伙伴等角色分别配置可访问的模型、环境(测试 / 生产)、操作(调用 / 配置 / 发布)与额度。 -4. ABAC:在角色基础上,引入租户 ID、项目 ID、数据域、时间段等属性,实现更灵活的策略(如“仅允许政务租户 A 在本地域调用本地化模型集群”)。 -5. **多租户隔离与配额管理** - 1. 在逻辑层面,通过租户 ID 隔离不同客户的调用、数据与日志; - 2. 在物理层面,对高合规客户(如银行 / 政府)提供专用集群或专用节点,实现更高等级的隔离; - 3. 配置不同租户的 QPS 限制、并发连接数和 token 配额,防止“某一租户暴冲拖垮全场”。 -6. **访问审计与策略评估** - 1. 对关键操作(如创建 / 删除 API Key、调整权限、修改配额)进行审计记录; - 2. 借助 OPA / Rego 等策略引擎,在执行前对复杂访问策略进行统一评估与解释,减少“策略散落代码中”的风险。 - -通过这层机制,平台可以在保证资源和数据安全的前提下,对内外部用户开放大模型能力,同时为后续合规审计和问题追责提供基础数据。 - -### 11.5.2 数据安全、隐私与合规审计:让模型“好用又合规” - -大模型往往会接触到大量敏感数据(用户对话、业务文档、交易记录等),一旦安全或合规出现问题,后果将极其严重。因此,需要在数据全生命周期和模型调用全链路上“多层防护”。 - -1. **数据传输与存储安全** - 1. 对所有外部和内部接口统一启用 TLS 加密,防止传输中被窃听或篡改; - 2. 对敏感数据采用静态加密存储,配合云厂商或自建的 KMS 管理密钥生命周期; - 3. 使用 Vault 等工具集中管理访问数据库、对象存储、第三方 API 所需的密钥和凭证。 -2. **最小化原则与脱敏** - 1. 只采集业务所必需的数据字段,并在日志与训练样本中尽量移除个人身份信息(PII)与敏感字段; - 2. 对不可避免要保留的标识符进行哈希或匿名化处理,降低泄露风险; - 3. 在 RAG / 知识库场景,对文档访问做权限分级,确保模型不会从“不该看的文档”中检索信息。 -3. **隐私增强技术与边缘约束** - 1. 在需要共享模型而不共享原始数据的场景中,引入差分隐私或联邦学习等方式,兼顾隐私与效能; - 2. 对政务、金融、医疗等场景,采用“数据不出域,模型下沉 or 本地部署”的模式,将训练 / 推理能力部署在合规域内。 -4. **合规与审计机制** - 1. 对模型发布、配置变更、权限调整等操作进行审批流与留痕,方便事后追溯; - 2. 对每次请求记录模型版本、调用方、路由决策、数据访问范围等元信息,在出现争议或调查需求时可以复盘; - 3. 定期输出合规报表(如数据访问审计、权限使用记录、异常事件报告),对接内部风控与外部监管要求。 - -这部分能力与 11.3、11.4 的 Data / Model Ops 和监控平台相互配合,共同构成一个“既能持续迭代,又能安全合规”的模型运行环境。 - -## 11.6 上层应用与中台能力(Application Enablers) - -有了从训练到推理、安全与运维的完整基础设施,还需要一层面向业务与开发者的“能力层”,将底层大模型抽象成更易用、更贴近业务语义的组件与服务。这一层通常被称为 **AI 中台、应用使能层或 Copilot 平台** ,其职责是:把大模型 + RAG + Agent + 工作流封装成标准化能力,让业务团队与生态伙伴可以快速搭建 AI 应用。 - -这一层一端连接模型 API、RAG 引擎与 Agent Orchestrator,另一端连接 CRM / ERP / OA / 工单等业务系统,是“从模型能力到业务场景”的关键桥梁。 - -* **场景** - * 企业 AI 中台 / Copilot 平台:为 CRM、ERP、OA、客服、营销、研发等内部系统统一提供对话、RAG、Agent 等智能能力。 - * 面向开发者与生态伙伴的应用开发平台:通过 SDK、模板工程、可视化编排工具,让第三方快速构建和部署 AI 应用。 - * 行业 SaaS 产品的 AI 后端:如智能客服云、营销云、办公协同云、研发管理云等,将 AI 能力嵌入原有产品体系。 - * 垂直场景助手:代码 Copilot、销售助手、运营助手、法务助手、医生助理等,通过中台能力迅速组合出场景化解决方案。 -* **原理** - * 对话与 Agent 能力: - * **会话管理与记忆** :维护多轮对话状态与长期记忆,支持话题切换、上下文压缩和个性化画像。 - * **工具调用(Tool Use)与****工作流** **编排** :通过函数调用或插件机制,将模型与外部系统(数据库、搜索、业务 API、第三方服务)连接起来;在复杂任务中使用 Workflow / Orchestrator 将多步操作串联起来。 - * **多 Agent 协作** :为复杂任务拆分出不同角色(如规划者、执行者、审阅者),以协作方式完成任务分解与结果聚合。 - * RAG 与知识库: - * **文档解析与预处理** :对 PDF、Word、网页、扫描件等文档进行解析、切块、结构化。 - * **向量化与检索** :使用 Embedding 模型对文本 / 表格 / 代码等内容进行向量化,构建向量索引;结合关键字检索与向量检索实现高召回。 - * **检索 + 生成(RAG)与证据链** :在推理时先从知识库检索相关内容,再由大模型基于检索结果生成回答,并输出引用与证据链,提高准确性与可解释性。 - * **知识图谱** **与结构化知识融合** :将领域知识图谱、业务数据表、规则系统与 LLM 结合,提高对结构化查询与复杂约束的处理能力。 - * 开发者接入与二次开发: - * **多语言 SDK 与 ****API** ** 设计** :提供 Python / JS / Java / Go 等语言的 SDK,封装调用模式、重试与幂等处理。 - * **模板与****低代码** ** / 无代码搭建** :通过预制模板工程与可视化“搭积木”式工具,让非专业开发者也能搭建 RAG / Agent / Workflow。 - * **插件与中间件** :提供与常见业务系统(CRM / ERP / OA / 工单系统等)的插件或中间件,降低系统集成成本。 -* **模型** - * 对话 / Agent 框架: - * LangChain、LlamaIndex、Haystack、Semantic Kernel 等。 - * 自研 Orchestration 层:通常包含 Workflow Engine、Tool Router、Memory 管理模块。 - * RAG 与向量检索: - * 向量数据库:FAISS、Milvus、Qdrant、Weaviate、Pinecone 等。 - * 文档解析:unstructured、Textract、pdfplumber、Apache Tika 等。 - * SDK / 接入层: - * 官方或自研 SDK、前端组件库(聊天组件、提示模板管理、对话记录视图)。 - * 与业务系统(CRM / ERP / OA / 工单等)的中间件 / 插件。 - -### 11.6.1 对话与 Agent 编排:从“问答机器人”到“任务协作体” - -相比早期的 FAQ 式问答机器人,现代大模型驱动的应用更像是“会用工具的智能协作者”。对话与 Agent 编排的目标,是把大模型从“语言生成器”升级为能够**调用工具、执行计划、协调多角色**的智能体。 - -1. **对话管理与记忆机制** - 1. 维护对话上下文、用户画像和长周期记忆,在多轮交互中保持一致性与连贯性; - 2. 对超长对话采用摘要、检索式记忆等方式进行压缩,避免上下文“爆表”; - 3. 在企业内应用中,引入身份与权限信息到对话上下文中,使回答与操作符合用户在业务系统中的权限。 -2. **工具调用(Tool Use)与****工作流****编排** - 1. 为模型提供结构化工具列表(如“查订单”“创建工单”“查询库存”“调用搜索引擎”等),并通过函数调用接口让模型在需要时主动调用; - 2. 使用 Orchestrator 根据模型提出的计划,协调多个工具调用的顺序、数据流与错误处理; - 3. 对复杂业务流程(如审批流、报销、售后处理)进行工作流建模,让 Agent 可以扮演“流程协调者”的角色。 -3. **多 Agent 协作模式** - 1. 将复杂任务拆成多个角色:如“任务规划 Agent”“信息检索 Agent”“执行 Agent”“质检 / 审核 Agent”; - 2. 通过消息通道或共享内存实现 Agent 间协作,提升复杂任务的鲁棒性与可解释性; - 3. 在企业环境中,可以将人类角色也纳入协作环中,如“AI 起草–人类审核–AI 修改–系统执行”。 - -这一层通常借助 LangChain、Semantic Kernel、LlamaIndex 等现成框架,并配合自研的 Orchestration 服务,将对话、工具、工作流、权限和审计统一在一套“Agent 平台”内。 - -### 11.6.2 RAG、知识库与开发者平台:把企业知识“接到模型脑子里” - -大模型再强,也不可能天然掌握每一家企业的私有知识,更无法实时知道最新的政策、产品和业务规则。RAG + 知识库 + 开发者平台,就是把这些**企业知识、行业知识和实时数据**以工程化方式接入模型能力的关键路径。 - -1. **文档解析与知识入库** - 1. 通过 unstructured、Textract、pdfplumber、Tika 等组件,将 PDF、Office 文档、网页、图片扫描件解析为结构化文本; - 2. 按章节、标题、语义块等进行“切块”,为后续向量化与检索提供合适粒度; - 3. 对于表格数据、业务数据库、API 文档等结构化信息,构建对应的 schema 映射和访问接口。 -2. **向量化、索引与检索重排** - 1. 使用 Embedding 模型将文本 / 代码 / 多模态内容转换为向量,存入 FAISS、Milvus、Qdrant、Weaviate、Pinecone 等向量数据库; - 2. 同时保留关键词索引与元数据过滤能力(如按租户、部门、文档类型过滤),组合出高精度的“检索前过滤 + 语义检索 + 重排”流程; - 3. 在查询时,将检索结果与原始问题一起喂入大模型,实现“检索增强生成(RAG)”,并返回引用与证据链。 -3. **RAG 应用模板与****低代码****搭建** - 1. 为常见场景(知识问答、政策解读、产品说明、内部文档助手等)提供预制 RAG 模板; - 2. 通过可视化配置界面(选择知识源、设置切块规则、选定向量模型与大模型)快速搭建专属知识助手; - 3. 将这些能力以 SDK 形式暴露给开发者,支持在 Web、移动端、桌面端或业务系统插件中快速嵌入。 -4. **开发者平台与生态集成** - 1. 提供 Python / JS / Java / Go 等语言 SDK,以及前端组件(聊天气泡、文档引用区、反馈按钮等),降低集成门槛; - 2. 为主流业务系统(CRM / ERP / OA / 工单)提供插件或中间件,使其可以“勾选几项配置”就接入 AI 能力; - 3. 对外开放应用开发平台,让生态伙伴基于底座模型、RAG 与 Agent 能力构建自己的行业应用,形成“平台–生态–终端客户”的正循环。 - -这一层最终将复杂的模型与基础设施能力封装成“可复用、可拼装的业务组件”,帮助企业在**安全、合规、成本可控**的前提下,以更低门槛、更快速度,把大模型真正变成推动业务创新的生产力工具。 +> 本章节正在编写中,敬请期待... diff --git a/docs/extra/extra4/extra4-what-is-ai-ide-and-trae.md b/docs/extra/extra4/extra4-what-is-ai-ide-and-trae.md deleted file mode 100644 index 5810f3e..0000000 --- a/docs/extra/extra4/extra4-what-is-ai-ide-and-trae.md +++ /dev/null @@ -1,168 +0,0 @@ -# 扩展知识 4 - 什么是 AI IDE 和 Trae - -在之前的学习阶段,我们使用 z.ai 搭建了最简单的 Web 程序和网页小游戏。但如果我们想要构建更复杂的应用——比如功能更完善的网站、桌面程序,甚至是手机应用——就必须在自己的电脑上使用专业的编程软件来编写代码。 - -最早的时候,只需要在一个简单的文本文件里写好程序,再用专门的语言处理器去读取并打包执行就够了。但随着代码量越来越大、项目结构越来越复杂,人工管理大量文件、手动编辑庞大的项目变得越来越困难。开发者因此迫切需要一种工具,能够高效管理和切换大量代码文件,支持多种编程语言的语法高亮,并可以快速定位和调试问题。于是,集成开发环境(IDE,Integrated Development Environment)就应运而生了。 - -你可以把 IDE 理解成一种专门用来“编辑、管理、运行和调试”各种应用源代码的程序。在真正打包发布之前,不同语言写出来的程序本质上只是特定格式的代码文件而已,你可以用普通文本编辑器打开它们,也可以用 IDE 打开。早期的计算机几乎完全通过终端来操作(只用键盘就能完成所有操作,几乎不需要鼠标),所以早期的 IDE 外观也非常“原始”——除非你额外安装插件来实现简单的交互式界面。 - -![](images/image1.png)![](images/image2.png) - -终端界面(Terminal) - -图片来源:https://en.wikipedia.org/wiki/File:Emacs-screenshot.png - -一个非常知名、功能成熟的“内置 IDE”叫做 `Vim`。在很多服务器上,你都可以直接用它来编辑文件(服务器通常没有显示屏,只能通过键盘远程操作)。 - -![](images/image3.png) - -现代 IDE 通常具有更加美观直观的图形界面,并提供更强大的编辑、运行和调试能力。一个典型的 IDE 通常包含以下核心组件: - -* **源代码编辑器(Source Code Editor)**:专门用于编写和编辑代码的文本编辑器,一般具备语法高亮、代码自动补全、实时错误提示等功能。 -* **构建与运行工具(编译器 / 解释器)**:IDE 内置编译器或解释器,可以将开发者写好的源代码转换成计算机可以执行的机器代码。 -* **调试器(Debugger)**:用于测试和排查代码错误的工具。它支持逐行执行代码、查看变量状态、设置断点等,帮助开发者定位并修复程序中的问题。 - -除此之外,现代 IDE 往往还内置版本控制工具(如 Git)和项目管理工具等实用功能。当下最流行的 IDE 之一是微软出品的 **[Visual Studio Code (VS Code)](https://code.visualstudio.com/)**。它轻量、可扩展性极强,因此被广泛使用。当然,也有很多开发者推荐 JetBrains 家的专业 IDE,比如用于 Python 的 PyCharm、用于 C/C++ 的 CLion 等,它们对特定语言提供了更深入、更完整的支持。但从入门友好度和通用性角度出发,我们更推荐初学者优先选择 VS Code 作为主要开发工具。 - -![](images/image4.png) - -# 现代 IDE:VS Code - -Visual Studio Code(简称 VS Code)是由微软开发的一款免费、开源且功能强大的现代代码编辑器。自 2015 年发布以来,凭借优异的性能和灵活性,它迅速成为全球最受欢迎的开发工具之一。 - -VS Code 的核心理念之一是“一切皆插件”。不同编程语言可以用来编写不同类型的程序,而每种语言都有自己独特的语法高亮规则和导航能力(比如“跳转到定义”“查找引用”等)。要让一个 IDE 原生支持所有语言几乎是不可能的——从逻辑上讲,你会需要为每一种语言单独准备一个 IDE 才行。 - -VS Code 巧妙地通过“插件机制”解决了这一问题。比如,如果你要写 Python,就安装 Python 插件,它会提供 Python 专属的语法高亮、自动补全和代码导航功能;如果你要写 C/C++,则可以安装对应的 C/C++ 插件来获得相应支持。在不安装任何插件的情况下,VS Code 本质上只是一个“高级的文本文件管理器”;当你为某种语言安装了对应插件之后,它就会“变身”成该语言的理想开发工具。 - -![](images/image5.png) - -除了编写代码以外,你甚至可以把 VS Code 当作编辑 Markdown 文档的工具来使用。 - -![](images/image6.png) - -总之,你可以在 VS Code 的扩展市场中浏览和下载各类扩展,为不同类型的文件提供更好用的编辑体验,也可以根据需要搜索不同语言和调试工具的插件,尝试它们如何提升你的工作效率。 - -# 现代 AI IDE - -上面介绍的都属于“传统意义上的现代 IDE”。但随着人工智能时代的到来,越来越多的代码开始由大语言模型来自动生成,这自然催生出一种新的开发工具形态——AI IDE,也就是可以利用大语言模型自动写代码的 IDE。 - -在最新版 VS Code 中,已经内置了一个大语言模型助手。你可以直接针对整个代码仓库、某个文件,甚至某个函数与模型对话。 - -你也可以像之前在 Web 端使用自动写代码工具一样,将需求以提示词的形式发给内置的编码 Agent,让它自动帮你实现所需功能、创建文件、修改代码、配置环境等。 - -典型的 AI IDE 一般具备以下核心能力: - -* 智能代码生成与补全:在传统 IDE 中,我们通常是输入几个字符来补全变量名或函数名;在现代 AI IDE 中,你可以写几行伪代码或者简单说明需求,让 IDE 自动补全完整的逻辑,甚至根据指令直接生成一大段甚至整块代码。 -* 代码理解与问答:IDE 能够理解并回答关于某段代码、某个文件,甚至整个工程目录结构的问题。 -* 代码重构与优化:IDE 可以根据你的意图,重写或优化指定代码片段的实现逻辑。 -* 自动生成测试:IDE 可以自动生成针对不同函数和模块的测试代码,方便你进行有针对性的测试。 -* Agent 式任务执行:智能 Agent 可以自动生成、打包、安装、运行和修改代码,在很多任务上可以部分替代初级软件工程师的工作。 - -在最新版 VS Code 中,你可以点击右上角的侧边栏入口,打开 AI 功能区域,体验这些能力。 - -![](images/image7.png) - -不过,VS Code 并不是 AI 能力最强的 IDE。对于需要大量 AI 辅助编码的场景,我们往往希望使用“更聪明、效率更高”的工具——好的 AI IDE 能显著节省写代码和改 Bug 的时间。下面我们会介绍几款目前比较流行的 AI IDE,重点讲解 Trae IDE。你可以根据个人喜好选择任意一款 AI IDE 使用。 - -由于 VS Code 是开源的(任何人都可以下载源码并自行编译),目前市面上绝大多数 AI IDE 都是在 VS Code 基础上二次开发而来。所以你不必担心要“学习很多种 IDE”——一旦你熟悉了 VS Code 的基本用法,迁移到这些 AI IDE 基本不需要重新学习。 - -如果要简单概括这些 AI IDE 之间的差异,主要集中在四个方面:价格;可使用的模型种类(部分高级模型在某些地区可能受限);Agent 的能力(在协助写代码时的智能程度和执行能力);以及运行速度与性能。 - -## Trae - -![](images/image8.png) - -Trae 是字节跳动推出的一款 AI 编程助手,支持 100 多种编程语言,并能集成到主流 IDE 中。它的功能包括:用自然语言生成代码、自动调试、把设计稿转换为 React/Vue 组件等。在 2025 年 8 月的更新之后,Trae 新增了智能依赖导入、重命名建议、任务清单管理等功能;SOLO 模式也开始支持后端代码生成和技术架构文档编辑。 - -## Cursor - -Cursor 是 Anysphere 开发的一款 AI 代码编辑器,基于 VS Code 定制,重点优化了大规模代码仓库和多文件协同的场景。它支持 GPT-4o、Claude 3.7 等模型;2025 年推出的 Claude Max 模式可以处理数百万行代码级别的项目。专业版取消了请求次数限制,非常适合复杂的企业级项目。 - -目前,Cursor 可以说是“带前端界面的 AI IDE”中综合体验最好的一款之一,用户数量庞大,功能迭代频率也很高。它最大的缺点是价格较高——专业版大约需要每月 20 美元。 - -![](images/image9.png) - -## Qoder - -Qoder 是阿里巴巴推出的一款强调“透明协作”和“增强上下文工程能力”的 AI IDE。它通过 Action Flow 支持把任务拆解成多个步骤,并实时跟踪 AI 的执行过程;还支持多模型动态路由和任务状态机管理,非常适合在中大型项目中做架构治理和对遗留系统进行“反向工程”分析。 - -![](images/image10.png) - -## CodeBuddy - -CodeBuddy 是腾讯云推出的一款 AI 编程工具,强调对中文指令的支持以及企业级合规能力。它提供代码补全、批量代码审查和多模型切换等功能;其中的 Craft 智能体可以实现多文件代码生成和 API 集成。企业版支持私有化部署,并通过了三级等保认证,适合金融、医疗等对数据安全要求较高的行业。 - -![](images/image11.png) - -## windsurf(已不推荐) - -Windsurf 最初因其基于 Agent 的 AI 编程能力而受到关注。但由于 2024 年团队调整以及模型权限问题,它的稳定性大幅下降,目前已经不再推荐使用。尽管在前一年它还可以与 Cursor 分庭抗礼,但现在基本可以视为“被淘汰”的工具。 - -![](images/image12.png) - -## VS Code + Cline - -Cline 是 VS Code(Visual Studio Code)的一款 AI 编程 Agent 插件,可以通过配置不同的 API 端点来灵活切换所使用的大模型。Cline 支持多模态输入、MCP 工具扩展以及成本监控,所有操作都需要用户确认后才会执行。它非常适合用于快速验证想法,或与现有开发流程集成。基础功能是免费的,企业版则支持在私有环境中部署模型。 - -![](images/image13.png) - -![](images/image14.png) - -# 什么是 Trae - -Trae 的全称可以理解为 “The Real AI Engineer”,是一款由字节跳动开发的自适应 AI 集成开发环境(IDE)。它是在流行的 VS Code 基础之上构建的,这意味着,如果你之前已经习惯了 VS Code,那么在使用 Trae 时,无论是界面布局还是基础操作都会感到非常熟悉、舒适。 - -Trae 的核心目标是成为开发者的“智能编程伙伴”。通过深度集成 AI 能力,它可以自动处理大量重复性工作,为你提供更直观、更高效的开发体验。它并不仅仅是一个“代码补全工具”,而是希望贯穿整个开发工作流,从创建项目、编写代码、调试、测试到部署都提供帮助。 - -## 安装 Trae - -Trae 分为国际版和中国版。国际版需要能够访问海外网络,但可以使用 GPT-5、Claude 4 等最新的海外模型;中国版则主要支持国内最新的大模型,例如 GLM、Qwen、Kimi 等。 - -国际版下载地址: - -https://www.trae.ai/ - -![](images/image15.png) - -中国版下载地址: - -https://www.trae.cn/ - -![](images/image16.png) - -## Trae 界面简介 - -简单来说,Trae 和 VS Code 看起来几乎一模一样。 - -![](images/image17.png) - -右侧的侧边栏就是 Copilot 交互窗口,也可以理解为 Agent 窗口。如果你暂时看不到它,可以点击 Trae 右上角的侧边栏图标将其打开。 - -![](images/image18.png) - -打开侧边栏之后,你会看到一个 `Builder` 选项,这就是 Agent 模式。简单理解,它相当于 z.ai 的“本地版”,可以帮你操作本机环境,安装运行环境、打开网页等。 - -![](images/image19.png) - -点击 “Builder” 后,你会看到 “Chat” 模式和 “Builder with MCP” 模式: - -* **Chat 模式**:主要用于和当前文件夹里的代码对话,或者当作普通聊天模型来使用。(你可以通过左上角的 “File” 菜单打开一个文件夹,在这个文件夹中进行编辑操作。在这种情况下,Builder 创建或修改的文件都只会发生在这个文件夹内部。) -* **Builder with MCP 模式**:为 Agent 提供了更多可用工具(例如把语言模型和其他软件联通起来、查询天气等)。你可以简单理解为:MCP 能让语言模型更方便地调用各种外部工具。 - -![](images/image20.png) - -在下面的区域,你还会看到模型选择选项,点击即可修改当前使用的大模型。在中国版中,你可以选择使用 Kimi k2 或 GLM 等国内模型;如果你使用的是国际版 Trae,还可以选择 ChatGPT 或 Claude 等海外模型。不过,由于国内大模型发展非常快,Kimi、Qwen、GLM 等在很多任务上的实际体验已经接近 Claude 3.5 或 3.7,对日常开发来说已经完全够用。 - -![](images/image21.png) - -以上就是对 Trae 的一个简单介绍。接下来,我们可以回顾一下之前在 z.ai 中做过的操作,并尝试在 Trae 中做同样的事情。 - -## 使用 Trae 安装 Python 和前端环境 - -大多数情况下,我们的 Windows 笔记本电脑默认不会预装前端开发所需的 Node.js 环境,或用于后端 / 通用开发的 Python 环境。我们可以尝试直接在 Trae 的 Agent 模式中跟它对话,让它帮我们安装 Python 环境或 Node.js 环境。 - -![](images/image22.png) - -## 📚 作业:用 Trae 写你的第一个程序 - -接下来,请尝试用 Trae 来完成你的第一个程序!你还记得之前的 AI 贪吃蛇游戏吗?把当时在 z.ai 中使用的那条提示词原封不动地输入到 Trae 的 Agent 模式中,看看会发生什么吧! diff --git a/docs/extra/extra5/extra5-what-is-rag-and-how-does-it-work-and-future.md b/docs/extra/extra5/extra5-what-is-rag-and-how-does-it-work-and-future.md index b469e8c..530c8ac 100644 --- a/docs/extra/extra5/extra5-what-is-rag-and-how-does-it-work-and-future.md +++ b/docs/extra/extra5/extra5-what-is-rag-and-how-does-it-work-and-future.md @@ -10,13 +10,13 @@ # 本节课你将学到 -* RAG的核心价值:深入理解它如何解决长上下文在成本、注意力、知识更新上的核心难题 -* RAG的工作原理:通过具体案例看它如何完成从检索到生成的闭环 -* RAG的技术演进脉络:从基础的Naive RAG到Advanced RAG再到模块化的Modular RAG -* RAG的模型选型建议:掌握Embedding、Rerank和LLM三大关键模型的评估与选择策略 -* RAG的企业级实践:学习从数据预处理到系统上线评估的全链路构建指南 -* RAG的效果评估与调优:了解核心评测指标、主流框架与持续优化的方法 -* RAG的前沿趋势:探索其与智能体、多模态等技术融合的未来方向 +- RAG的核心价值:深入理解它如何解决长上下文在成本、注意力、知识更新上的核心难题 +- RAG的工作原理:通过具体案例看它如何完成从检索到生成的闭环 +- RAG的技术演进脉络:从基础的Naive RAG到Advanced RAG再到模块化的Modular RAG +- RAG的模型选型建议:掌握Embedding、Rerank和LLM三大关键模型的评估与选择策略 +- RAG的企业级实践:学习从数据预处理到系统上线评估的全链路构建指南 +- RAG的效果评估与调优:了解核心评测指标、主流框架与持续优化的方法 +- RAG的前沿趋势:探索其与智能体、多模态等技术融合的未来方向 # 本节课你将收获 @@ -40,7 +40,7 @@ > 上下文(context)从意义上指模型在回答当前问题时所“参考”的背景信息与对话历史;从技术上则是指一次推理时输入给模型的 Token 序列(如 system/user 指令、历史消息、检索片段等)的总和。 > > “上下文窗口”是这批输入内容的 **容量上限** :模型一次最多只能“看到”这么多 Token。在当前主流的大模型架构(例如 Transformer)中,这些 Token 会在模型的每一层里彼此做注意力计算、反复参与运算,因此一旦窗口变长、Token 变多,计算量和成本都会成倍甚至指数级增加。 - > + 3. 计算资源存在大量浪费:绝大多数任务仅需极少量与当前问题高度相关的信息,将全量文档塞入上下文,会造成严重的计算资源闲置与浪费,进而降低系统吞吐量,拖慢响应速度,最终影响用户体验。 4. **注意力与聚焦的问题** : 大模型虽能 “覆盖” 超长上下文,却无法对每一段信息都实现同等质量的利用。当上下文长度达到一定阈值时,模型会出现明显的 “注意力偏差”: @@ -83,9 +83,9 @@ RAG(Retrieval-Augmented Generation,检索增强生成)的核心思路是 在图中,这一阶段对应右上角紫色区域 “Indexing”。从 “Documents” 出发,经由 “Chunks / Vectors” 到 “embeddings” 的那一部分,就是在说明文档被切块并转换为向量、写入索引的过程。具体过程如下: -* 文档被划分为若干个语义相对完整的 chunks,每个 chunk 可能对应一小段新闻、一段说明或一段分析。 -* 每个 chunk 会通过 embedding 模型转换成高维向量,并存入向量索引中。 -* 这个索引支持后续基于相似度的检索,为回答问题提前准备好“可被查阅的知识库”。 +- 文档被划分为若干个语义相对完整的 chunks,每个 chunk 可能对应一小段新闻、一段说明或一段分析。 +- 每个 chunk 会通过 embedding 模型转换成高维向量,并存入向量索引中。 +- 这个索引支持后续基于相似度的检索,为回答问题提前准备好“可被查阅的知识库”。 2. **检索阶段 + 基于检索结果生成答案** @@ -166,9 +166,9 @@ RAG(Retrieval-Augmented Generation,检索增强生成)的核心思路是 简化示例(实际向量维度高得多,这里仅示意): -* 文档A向量(关于苹果公司创立):`[0.85, -0.23, 0.41, -0.56, 0.12, 0.78, ...]` -* 文档B向量(关于水果苹果):`[-0.12, 0.95, -0.34, 0.67, -0.89, 0.05, ...]` -* 文档C向量(关于iPhone发布):`[0.79, -0.18, 0.52, -0.61, 0.23, 0.81, ...]` +- 文档A向量(关于苹果公司创立):`[0.85, -0.23, 0.41, -0.56, 0.12, 0.78, ...]` +- 文档B向量(关于水果苹果):`[-0.12, 0.95, -0.34, 0.67, -0.89, 0.05, ...]` +- 文档C向量(关于iPhone发布):`[0.79, -0.18, 0.52, -0.61, 0.23, 0.81, ...]` 相关向量需存入向量数据库(如 Pinecone、Weaviate、FAISS)用于之后的检索召回工作。 @@ -186,9 +186,9 @@ RAG(Retrieval-Augmented Generation,检索增强生成)的核心思路是 接下来系统将进行相似度检索 (Top-K, K=2)操作,计算该查询向量与知识库中所有文档向量的余弦相似度(一种衡量向量方向接近程度的指标)。结果如下: -* 与文档A(公司创立)相似度:0.97(高度相关) -* 与文档C(iPhone发布)相似度:0.88(相关,同属公司主题) -* 与文档B(水果营养)相似度:0.12(几乎不相关) +- 与文档A(公司创立)相似度:0.97(高度相关) +- 与文档C(iPhone发布)相似度:0.88(相关,同属公司主题) +- 与文档B(水果营养)相似度:0.12(几乎不相关) > Top-K 是向量检索场景中常用的筛选策略,核心含义是 “从所有匹配结果中,按相似度从高到低排序后,选取排名前 K 个的结果”;而 K=2 则是对该策略的具体数值定义,即明确要求系统仅保留相似度排名前 2 的文档向量,过滤掉其余相似度更低的结果,以确保后续仅基于最相关的 2 个文档片段生成答案。 @@ -220,9 +220,9 @@ LLM接收到上述结构化输入后,会遵循系统指令,将“参考信 接下来系统将进行相似度检索 (Top-K, K=2) 操作,计算该查询向量与知识库中所有文档向量的余弦相似度。结果如下: -* 与文档B(水果营养)相似度:0.95(高度相关) -* 与文档C(iPhone发布)相似度:0.18(几乎不相关) -* 与文档A(公司创立)相似度:0.15(几乎不相关) +- 与文档B(水果营养)相似度:0.95(高度相关) +- 与文档C(iPhone发布)相似度:0.18(几乎不相关) +- 与文档A(公司创立)相似度:0.15(几乎不相关) 系统根据相似度分数从高到低,返回 Top‑2 的文档片段作为证据: @@ -254,9 +254,9 @@ LLM接收到上述结构化输入后,其最终回复将类似: 接下来系统将进行相似度检索 (Top-K, K=2) 操作,计算余弦相似度。由于问题主题与知识库内容无关,整体相似度得分都很低。结果如下: -* 与文档B(水果营养)相似度:0.18(极低) -* 与文档C(iPhone发布)相似度:0.10(几乎不相关) -* 与文档A(公司创立)相似度:0.08(几乎不相关) +- 与文档B(水果营养)相似度:0.18(极低) +- 与文档C(iPhone发布)相似度:0.10(几乎不相关) +- 与文档A(公司创立)相似度:0.08(几乎不相关) Top-K 仍会返回相似度排名前 K 个结果,但在该场景下,这些结果并不能提供有效证据。实际系统常会结合“最低相似度阈值”直接返回空召回,即没有任何召回的结果,参考信息为 0,以减少无关信息干扰。 @@ -310,48 +310,46 @@ Naive RAG可以理解为基础的 RAG 形态,它在工程上非常直接,典 在检索前,重点是把“存什么”和“怎么问”处理好: -* 在索引端,从固定长度切分演进到语义感知分块与分层索引,例如按章节、小节、段落或句子边界进行切分,辅以滑动窗口和多粒度索引结构。 -* 为每个文档块附加丰富的元数据,例如来源、时间、作者、主题、文档类型等,为后续的过滤和排序提供更多维度。 -* 在查询端,对用户原始问题进行重写、扩展和拆分,例如通过 Query Rewrite、多路查询(Multi-Query)、子问题分解(Sub-Query)、Step-back Prompting 等方式,将含糊或口语化的问题转换为更利于检索理解的表达。 +- 在索引端,从固定长度切分演进到语义感知分块与分层索引,例如按章节、小节、段落或句子边界进行切分,辅以滑动窗口和多粒度索引结构。 +- 为每个文档块附加丰富的元数据,例如来源、时间、作者、主题、文档类型等,为后续的过滤和排序提供更多维度。 +- 在查询端,对用户原始问题进行重写、扩展和拆分,例如通过 Query Rewrite、多路查询(Multi-Query)、子问题分解(Sub-Query)、Step-back Prompting 等方式,将含糊或口语化的问题转换为更利于检索理解的表达。 > 1. Query Rewrite(查询重写) > > 核心是将用户模糊、口语化或不规范的原始查询,转化为检索系统更易理解的标准化表述,补充关键信息、修正歧义。 > - > * 用户原始问题为 “咋查明天北京的天气啊”,会去除 “咋”“啊” 等口语化词汇,补充 “实时”“全天” 等关键限定,重写为 “查询北京市明日全天实时天气”; - > * 用户原始问题为 “推荐好看的电影”,若结合用户历史行为发现其常看悬疑片,会补充 “2024 年高分”“悬疑题材” 等信息,重写为 “推荐 2024 年高分悬疑题材电影”。 + > - 用户原始问题为 “咋查明天北京的天气啊”,会去除 “咋”“啊” 等口语化词汇,补充 “实时”“全天” 等关键限定,重写为 “查询北京市明日全天实时天气”; + > - 用户原始问题为 “推荐好看的电影”,若结合用户历史行为发现其常看悬疑片,会补充 “2024 年高分”“悬疑题材” 等信息,重写为 “推荐 2024 年高分悬疑题材电影”。 > > 2. Multi-Query(多路查询) > > 基于原始问题生成多个 “语义相关但角度不同” 的查询语句,避免单一查询遗漏潜在结果,覆盖用户未明确的潜在需求。 > - > * 用户原始问题为 “如何给刚满月的宝宝拍嗝”,会生成聚焦 “姿势” 的查询:“新生儿拍嗝的正确姿势”; - > * 生成聚焦 “防吐奶” 的查询:“满月宝宝拍嗝避免吐奶的方法”; - > * 生成聚焦 “月龄适配” 的查询:“婴儿拍嗝的步骤(0-1 个月)”; - > * 生成聚焦 “新手场景” 的查询:“新手爸妈给满月宝宝拍嗝技巧”。 + > - 用户原始问题为 “如何给刚满月的宝宝拍嗝”,会生成聚焦 “姿势” 的查询:“新生儿拍嗝的正确姿势”; + > - 生成聚焦 “防吐奶” 的查询:“满月宝宝拍嗝避免吐奶的方法”; + > - 生成聚焦 “月龄适配” 的查询:“婴儿拍嗝的步骤(0-1 个月)”; + > - 生成聚焦 “新手场景” 的查询:“新手爸妈给满月宝宝拍嗝技巧”。 > > 3. Sub-Query(子问题分解) > > 针对包含多个诉求的复合问题,拆分为独立、简单的子查询,让检索系统针对单一诉求精准匹配数据,避免信息混杂缺失。 > - > * 用户原始复合问题为 “北京到上海的高铁,明天有哪些班次?票价多少?需要坐多久?”,会拆解出聚焦 “班次” 的子查询:“北京市至上海市 明日高铁班次表”; - > * 拆解出聚焦 “票价” 的子查询:“北京到上海高铁 二等座 / 一等座票价”; - > * 拆解出聚焦 “时长” 的子查询:“北京到上海高铁 行驶时长(最快 / 平均)”。 + > - 用户原始复合问题为 “北京到上海的高铁,明天有哪些班次?票价多少?需要坐多久?”,会拆解出聚焦 “班次” 的子查询:“北京市至上海市 明日高铁班次表”; + > - 拆解出聚焦 “票价” 的子查询:“北京到上海高铁 二等座 / 一等座票价”; + > - 拆解出聚焦 “时长” 的子查询:“北京到上海高铁 行驶时长(最快 / 平均)”。 > > 4. Step-back Prompting(回溯提示) > > 先生成 “比原始问题更宏观的上位问题”,再基于上位逻辑回推检索方向,解决原始问题因聚焦细节导致的理解偏差。 > - > * 用户原始问题为 “为什么 2024 年某国产新能源汽车品牌的销量突然下降?”,第一步生成宏观上位问题:“影响新能源汽车品牌短期销量波动的核心因素有哪些?”(如产品迭代、竞品动作、政策变化、市场需求等); - > * 第二步基于上位问题逻辑,生成具体检索方向:“2024 年某国产新能源品牌 产品更新情况”“2024 年新能源汽车市场 竞品定价策略”“2024 年新能源汽车补贴政策调整”。 - > + > - 用户原始问题为 “为什么 2024 年某国产新能源汽车品牌的销量突然下降?”,第一步生成宏观上位问题:“影响新能源汽车品牌短期销量波动的核心因素有哪些?”(如产品迭代、竞品动作、政策变化、市场需求等); + > - 第二步基于上位问题逻辑,生成具体检索方向:“2024 年某国产新能源品牌 产品更新情况”“2024 年新能源汽车市场 竞品定价策略”“2024 年新能源汽车补贴政策调整”。 在检索后,重点是把“取回来的内容”治理好: -* 使用专门的 Rerank 模型或 LLM 对候选文档进行重新排序,确保最关键、最贴近问题的内容优先进入上下文。 +- 使用专门的 Rerank 模型或 LLM 对候选文档进行重新排序,确保最关键、最贴近问题的内容优先进入上下文。 > Rerank 模型是信息检索流程中的关键组件,主要用于对 “召回阶段” 初步筛选出的候选结果进行二次排序 —— 它会借助更复杂的语义理解能力(常基于 Transformer 等深度学习架构),分析用户需求与候选结果的深层关联,修正初步排序中可能存在的语义偏差,最终让更贴合用户需求的结果排在更靠前的位置,提升用户获取有效信息的效率。 - > -* 对检索结果进行筛选、去重与压缩,去掉明显无关或高度重复的片段,缓解长上下文中部信息被忽略的问题。 -* 在必要时,结合轻量的模型微调,使 LLM 更倾向于依据检索证据作答,并在回答中附带引用或出处信息。 +- 对检索结果进行筛选、去重与压缩,去掉明显无关或高度重复的片段,缓解长上下文中部信息被忽略的问题。 +- 在必要时,结合轻量的模型微调,使 LLM 更倾向于依据检索证据作答,并在回答中附带引用或出处信息。 总体来看,第二代检索增强生成技术其关注点不再局限于 “是否需要检索”“能否检索到信息” 这两个基础问题,而是进一步聚焦于三个更大的挑战:“能否精准定位到真正关键的段落内容”“传递给大模型的上下文是否简洁有序、具备清晰结构且易于高效利用”“当面临信息噪音、内容冲突或多资料源查找需求时,系统整体性能是否依然稳健可靠”。 @@ -452,8 +450,8 @@ MTEB为各类Embedding模型提供了一个统一、客观的评估框架。它 在选择 Embedding 模型时,我们可以用 MTEB 这样的 benchmark。而对于 Rerank 模型我们可以参考 Agentset 的 [Reranker Leaderboard](https://agentset.ai/rerankers),该网站针对 RAG 场景下的重排能力做了系统测试。 -| Model Name↑ | ELO | nDCG@10 | Latency (ms) | Price / 1M | License | -| --------------------------------------------------------------------------------------------------- | ---- | ------- | ------------ | ---------- | ------------ | +| Model Name↑ | ELO | nDCG@10 | Latency (ms) | Price / 1M | License | +| ------------------------------------------------------------------------------------------------------ | ---- | ------- | ------------ | ---------- | ------------ | | [BAAI/BGE Reranker v2 M3](https://agentset.ai/rerankers/baaibge-reranker-v2-m3) | 1314 | 0.201 | 2383 | $0.02 | Apache 2.0 | | [Cohere Rerank 3.5](https://agentset.ai/rerankers/cohere-rerank-35) | 1452 | 0.2 | 392 | $0.05 | Proprietary | | [Cohere Rerank 4 Fast](https://agentset.ai/rerankers/cohere-rerank-4-fast) | 1506 | 0.216 | 447 | $0.05 | Proprietary | @@ -472,8 +470,8 @@ MTEB为各类Embedding模型提供了一个统一、客观的评估框架。它 在此基础上,基准测试还设计了两组互补性指标,用于对模型进行多维度综合评估: -* nDCG@5/10:聚焦排序精准度,重点衡量相关文档是否被合理置于结果前列,直接反映 “排得准” 的能力; -* Recall@5/10:侧重结果覆盖面,核心评估系统能否识别出所有与查询相关的文档,对应 “找得全” 的能力。 +- nDCG@5/10:聚焦排序精准度,重点衡量相关文档是否被合理置于结果前列,直接反映 “排得准” 的能力; +- Recall@5/10:侧重结果覆盖面,核心评估系统能否识别出所有与查询相关的文档,对应 “找得全” 的能力。 这两组指标相辅相成,共同构建起对 Rerank 模型的完整评估体系,确保评估结果更具全面性与参考价值。 @@ -493,8 +491,8 @@ MTEB为各类Embedding模型提供了一个统一、客观的评估框架。它 以下是竞技场排名的示例(截止至 2025 年 12 月 15 日) -| Rank | Model | Score | Votes | Organization | License | -| ---- | ---------------------------------------------------------------------------------------- | ----- | ------ | ------------ | ----------- | +| Rank | Model | Score | Votes | Organization | License | +| ---- | ------------------------------------------------------------------------------------------- | ----- | ------ | ------------ | ----------- | | 1 | [gemini-3-pro](http://aistudio.google.com/app/prompts/new_chat?model=gemini-3-pro-preview) | 1492 | 15,871 | Google | Proprietary | | 2 | [grok-4.1-thinking](https://x.ai/news/grok-4-1) | 1478 | 16,660 | xAI | Proprietary | | 3 | [claude-opus-4-5-20251101-thinking-32k](https://www.anthropic.com/news/claude-opus-4-5) | 1470 | 9,879 | Anthropic | Proprietary | @@ -516,20 +514,20 @@ LMArena的独特价值在于其评估方式更贴近真实用户体验,而非 在实际工程实践中,通常不需要从零开始构建整个 RAG 系统。目前业界已有多个成熟的开源框架可供选择,它们在架构设计、模块集成和开发效率等方面各有特色。企业可以根据自身的技术储备和业务场景,选择合适的框架快速搭建系统。常见的框架类型包括: - **低代码** **/可视化平台** +**低代码** **/可视化平台** -* [Dify](https://dify.ai):提供直观的可视化界面,支持快速搭建 RAG 应用,适合非技术团队或快速原型验证场景。内置多模型接入、工作流编排和 prompt 管理功能。 -* [Coze](https://www.coze.com/):字节跳动推出的 AI Bot 开发平台,提供零代码的可视化搭建能力。特色在于与豆包等字节系大模型深度集成,支持插件市场、定时任务和多渠道发布(飞书、微信等),适合快速构建面向 C 端用户的对话应用或企业内部智能助手。 -* [n8n](https://n8n.io/):一个开源的、基于节点的工作流自动化平台。它通过可视化的方式连接各类应用、API和数据源。在RAG场景中,可以利用n8n编排复杂的业务逻辑,将数据预处理、向量数据库操作、大模型调用以及后续动作(如发送邮件、更新工单)串联成一个自动化流程。 -* [RAGFlow](https://ragflow.io/):专注于深度版面分析和知识抽取能力,对复杂文档(如多栏 PDF、表格密集型文档)的处理效果较好,适合文档结构复杂的企业知识库场景。 -* [FastGPT](https://fastgpt.io/en):中国国内开源方案,集成了知识库管理、对话流程编排和应用发布功能,中文文档完善,适合快速部署中文 RAG 应用。 +- [Dify](https://dify.ai):提供直观的可视化界面,支持快速搭建 RAG 应用,适合非技术团队或快速原型验证场景。内置多模型接入、工作流编排和 prompt 管理功能。 +- [Coze](https://www.coze.com/):字节跳动推出的 AI Bot 开发平台,提供零代码的可视化搭建能力。特色在于与豆包等字节系大模型深度集成,支持插件市场、定时任务和多渠道发布(飞书、微信等),适合快速构建面向 C 端用户的对话应用或企业内部智能助手。 +- [n8n](https://n8n.io/):一个开源的、基于节点的工作流自动化平台。它通过可视化的方式连接各类应用、API和数据源。在RAG场景中,可以利用n8n编排复杂的业务逻辑,将数据预处理、向量数据库操作、大模型调用以及后续动作(如发送邮件、更新工单)串联成一个自动化流程。 +- [RAGFlow](https://ragflow.io/):专注于深度版面分析和知识抽取能力,对复杂文档(如多栏 PDF、表格密集型文档)的处理效果较好,适合文档结构复杂的企业知识库场景。 +- [FastGPT](https://fastgpt.io/en):中国国内开源方案,集成了知识库管理、对话流程编排和应用发布功能,中文文档完善,适合快速部署中文 RAG 应用。 **代码框架/开发库** 以下介绍的软件通常都有不同平台(前后端)语言的实现方式,你可以根据当前应用的语言选择下列对应软件的语言版本(例如 Python 或 Java 版)。 -* [LlamaIndex](https://www.llamaindex.ai/):专为 RAG 场景设计的 Python 框架,提供丰富的数据连接器(Connector)、索引结构和查询引擎,模块化程度高,适合需要深度定制检索策略或集成多种数据源的场景。 -* [LangChain](https://www.langchain.com/):通用 LLM 应用开发框架,RAG 只是其中一个应用方向。优势在于生态丰富、组件齐全,支持复杂的 Agent 和工作流编排,但学习曲线相对陡峭,适合构建复杂的多模块 LLM 应用。 +- [LlamaIndex](https://www.llamaindex.ai/):专为 RAG 场景设计的 Python 框架,提供丰富的数据连接器(Connector)、索引结构和查询引擎,模块化程度高,适合需要深度定制检索策略或集成多种数据源的场景。 +- [LangChain](https://www.langchain.com/):通用 LLM 应用开发框架,RAG 只是其中一个应用方向。优势在于生态丰富、组件齐全,支持复杂的 Agent 和工作流编排,但学习曲线相对陡峭,适合构建复杂的多模块 LLM 应用。 如果团队技术储备有限、追求快速上线,可优先考虑 Dify 、Coze 或 FastGPT 等低代码平台;如果需要深度定制检索框架、对接特殊数据源或优化性能细节,LlamaIndex 和 LangChain 提供了更大的灵活性。实际项目中,也可以采用"混合方案":用低代码平台快速验证可行性,再用代码框架实现生产级部署和性能优化。此外,这些框架大多支持主流 Embedding、Rerank 和 LLM 模型的快速接入,可以基于前文提到的模型选型标准灵活组合最后使用的模型型号。 @@ -543,9 +541,9 @@ LMArena的独特价值在于其评估方式更贴近真实用户体验,而非 具体而言,该流程通常包含三个关键步骤: -* 首先合成评测数据集,我们需要从知识库中采样文档,并指令 LLM 生成与之对应的、高质量的“问题-参考答案”对,再经过相关性、事实 groundedness 等过滤,形成基准测试集; -* 其次,运行 RAG 系统并收集答案,让待评估的系统处理测试集中的每个问题,得到其生成的答案; -* 最后,进行自动化判分,调用另一个作为“裁判”的 LLM,将系统生成的答案与参考答案进行对比,从准确性、完整性等维度给出量化评分。 +- 首先合成评测数据集,我们需要从知识库中采样文档,并指令 LLM 生成与之对应的、高质量的“问题-参考答案”对,再经过相关性、事实 groundedness 等过滤,形成基准测试集; +- 其次,运行 RAG 系统并收集答案,让待评估的系统处理测试集中的每个问题,得到其生成的答案; +- 最后,进行自动化判分,调用另一个作为“裁判”的 LLM,将系统生成的答案与参考答案进行对比,从准确性、完整性等维度给出量化评分。 可以用一个简单的例子展示其过程: @@ -559,8 +557,8 @@ LMArena的独特价值在于其评估方式更贴近真实用户体验,而非 若你需要深入掌握具体细节(如指标的数学计算逻辑、框架的实操部署步骤、不同基准数据集的适用场景等),建议参考以下两篇 RAG 评测领域的论文: -* [https://arxiv.org/pdf/2504.14891](https://arxiv.org/pdf/2504.14891)(《Retrieval Augmented Generation Evaluation in the Era of Large Language Models: A Comprehensive Survey》):系统梳理了 LLM 时代 RAG 的内外部评测方法,涵盖组件级与系统级评估,还汇总了海量评测数据集与框架,并分析了当前研究趋势与挑战。 -* [https://arxiv.org/pdf/2405.07437](https://arxiv.org/pdf/2405.07437)(《Evaluation of Retrieval-Augmented Generation: A Survey》):提出了统一的 RAG 评测流程(Auepora),从 “评测目标、数据集、指标” 三维度拆解评测逻辑,同时对比了不同基准的优劣,为实践提供了清晰指引。 +- [https://arxiv.org/pdf/2504.14891](https://arxiv.org/pdf/2504.14891)(《Retrieval Augmented Generation Evaluation in the Era of Large Language Models: A Comprehensive Survey》):系统梳理了 LLM 时代 RAG 的内外部评测方法,涵盖组件级与系统级评估,还汇总了海量评测数据集与框架,并分析了当前研究趋势与挑战。 +- [https://arxiv.org/pdf/2405.07437](https://arxiv.org/pdf/2405.07437)(《Evaluation of Retrieval-Augmented Generation: A Survey》):提出了统一的 RAG 评测流程(Auepora),从 “评测目标、数据集、指标” 三维度拆解评测逻辑,同时对比了不同基准的优劣,为实践提供了清晰指引。 ### 5.3.2 评测指标 @@ -574,9 +572,9 @@ RAG系统的评估本质上围绕两个核心问题:检索模块能否准确 首先是一组衡量召回基本质量的经典指标:Recall@K、Precision@K和F1。 -* **Recall@K** 衡量在前K条检索结果中,相关文档被找回的比例。比如知识库中有5篇相关文档,前10条结果找回了3篇,则Recall@10为60%。这个指标告诉我们检索的"覆盖面"如何。 -* **Precision** **@K** 衡量前K条结果中真正相关文档的占比。同样是前10条结果,如果其中有3篇相关、7篇不相关,则Precision@10为30%。这个指标反映检索的"准确度"。 -* **F1** 则是Recall和Precision的调和平均,在两者间寻求平衡。 +- **Recall@K** 衡量在前K条检索结果中,相关文档被找回的比例。比如知识库中有5篇相关文档,前10条结果找回了3篇,则Recall@10为60%。这个指标告诉我们检索的"覆盖面"如何。 +- **Precision** **@K** 衡量前K条结果中真正相关文档的占比。同样是前10条结果,如果其中有3篇相关、7篇不相关,则Precision@10为30%。这个指标反映检索的"准确度"。 +- **F1** 则是Recall和Precision的调和平均,在两者间寻求平衡。 这组指标适合快速发现召回阶段的基础问题,比如向量化模型是否有效、检索策略是否合理、Query改写是否到位等。如果Recall很低,说明相关文档根本没被找到;如果Precision很低,说明检索噪声太大。 @@ -584,9 +582,9 @@ RAG系统的评估本质上围绕两个核心问题:检索模块能否准确 找到相关文档只是第一步,更重要的是把最相关的文档排在前面。这就需要关注排序质量的指标:MRR、NDCG@K和MAP。 -* **MRR** **(** **Mean Reciprocal Rank** **)** 计算第一个相关文档出现位置的倒数均值。如果第一个相关文档出现在第3位,该条查询的RR就是1/3。MRR适合那些只需要一个正确答案的场景,比如问答系统。 -* **NDCG@K(Normalized Discounted Cumulative Gain)** 考虑了相关性分级和位置衰减两个因素。它不仅关注文档是否相关,还关注相关程度;同时,越相关的文档排在越前面,得分越高。这使得NDCG成为衡量排序质量最全面的指标之一。 -* **MAP(Mean ** **Average Precision** **)** 综合考虑所有相关文档的位置,对整体排序质量更为敏感。 +- **MRR** **(** **Mean Reciprocal Rank** **)** 计算第一个相关文档出现位置的倒数均值。如果第一个相关文档出现在第3位,该条查询的RR就是1/3。MRR适合那些只需要一个正确答案的场景,比如问答系统。 +- **NDCG@K(Normalized Discounted Cumulative Gain)** 考虑了相关性分级和位置衰减两个因素。它不仅关注文档是否相关,还关注相关程度;同时,越相关的文档排在越前面,得分越高。这使得NDCG成为衡量排序质量最全面的指标之一。 +- **MAP(Mean ** **Average Precision** **)** 综合考虑所有相关文档的位置,对整体排序质量更为敏感。 在实际工程中,我们通常采用 Recall@K + MRR@K 的组合,既保证召回覆盖面又约束排序质量。举个例子,如果发现Recall@10达到80%但MRR@10只有0.3,说明相关文档虽然被找到了但都埋在后面,这时就需要优化重排序策略,比如引入交叉编码器或调整多路召回的权重分配。 @@ -598,11 +596,11 @@ RAG系统的评估本质上围绕两个核心问题:检索模块能否准确 **精确匹配与文本相似度** -最直接的评估方式是 **EM(Exact Match)** ,要求生成答案与参考答案完全一致。这个指标适合答案唯一、形式固定的场景,比如"成立日期是什么时候?""总部在哪里?"这类事实性问答。但EM过于严格,同样正确的"2020年1月1日"和"2020-01-01"会被判为不匹配。 +最直接的评估方式是 **EM(Exact Match)** ,要求生成答案与参考答案完全一致。这个指标适合答案唯一、形式固定的场景,比如"成立日期是什么时候?""总部在哪里?"这类事实性问答。但EM过于严格,同样正确的"2020年1月1日"和"2020-01-01"会被判为不匹配。 -因此,更常用的是基于n-gram重叠的相似度指标: **ROUGE** **、** **BLEU** **、METEOR** 。它们通过计算生成内容与参考答案的词汇重叠程度来打分。其中,ROUGE-L关注最长公共子序列,对答案的流畅性更敏感;BLEU源自机器翻译领域,注重精确匹配;METEOR则加入了同义词和词干的考量。这些指标的优势是计算简单、易于理解,但也有明显局限——它们只看表面词汇匹配,对语义理解不够深入。 +因此,更常用的是基于n-gram重叠的相似度指标: **ROUGE** **、** **BLEU** **、METEOR** 。它们通过计算生成内容与参考答案的词汇重叠程度来打分。其中,ROUGE-L关注最长公共子序列,对答案的流畅性更敏感;BLEU源自机器翻译领域,注重精确匹配;METEOR则加入了同义词和词干的考量。这些指标的优势是计算简单、易于理解,但也有明显局限——它们只看表面词汇匹配,对语义理解不够深入。 -为了弥补这一不足,我们可以引入 **BertScore** 或直接的 **向量相似度** 。它们利用预训练模型的向量表示来计算语义相似度,更能容忍表述差异。比如"这款产品很受欢迎"和"该设备广受好评"在词汇上几乎没有重叠,但向量相似度会很高。这对于需要改写、总结、解释的生成任务特别有效。 +为了弥补这一不足,我们可以引入 **BertScore** 或直接的 **向量相似度** 。它们利用预训练模型的向量表示来计算语义相似度,更能容忍表述差异。比如"这款产品很受欢迎"和"该设备广受好评"在词汇上几乎没有重叠,但向量相似度会很高。这对于需要改写、总结、解释的生成任务特别有效。 **事实忠实度与幻觉检测** @@ -618,10 +616,10 @@ RAG系统的评估本质上围绕两个核心问题:检索模块能否准确 具体做法是:将问题、检索文档、系统回答、参考答案一并输入一个独立的大模型(通常选择能力较强的模型如GPT-4或Claude),让它按多个维度进行综合评分: -* **问题相关性** :答案是否真正回应了用户问题,有没有答非所问? -* **信息完整性** :该涵盖的要点是否都说到了,有没有遗漏关键信息? -* **事实忠实性** :答案是否出现了检索文档中不存在的内容,有没有幻觉? -* **整体正确性** :与参考答案相比,生成答案的质量如何? +- **问题相关性** :答案是否真正回应了用户问题,有没有答非所问? +- **信息完整性** :该涵盖的要点是否都说到了,有没有遗漏关键信息? +- **事实忠实性** :答案是否出现了检索文档中不存在的内容,有没有幻觉? +- **整体正确性** :与参考答案相比,生成答案的质量如何? LLM裁判的优势在于能进行更接近人类的整体性判断——它可以理解上下文、把握语义、识别逻辑,甚至能发现一些自动化指标捕捉不到的细微问题,比如语气不当、逻辑矛盾、表述含糊等。当然,裁判本身也需要精心设计prompt,并用人工标注样本进行校准,确保评分标准的一致性和可靠性。 @@ -631,9 +629,9 @@ LLM裁判的优势在于能进行更接近人类的整体性判断——它可 一个务实的建议是 **从精简组合开始,逐步完善** : -* **检索评估** :采用 Recall@K + MRR@K 的核心组合,快速把握召回覆盖和排序质量 -* **生成评估** :根据任务特点,从 EM、ROUGE-L、BertScore 中选择一到两个作为基线 -* **综合评估** :引入 LLM裁判,重点关注相关性、完整性、忠实性三个维度 +- **检索评估** :采用 Recall@K + MRR@K 的核心组合,快速把握召回覆盖和排序质量 +- **生成评估** :根据任务特点,从 EM、ROUGE-L、BertScore 中选择一到两个作为基线 +- **综合评估** :引入 LLM裁判,重点关注相关性、完整性、忠实性三个维度 在此基础上,采用"评测→发现问题→调整策略→再评测"的循环迭代。比如,发现召回率不错但MRR很低,就重点优化重排序;发现幻觉率偏高,就加强对检索文档的忠实度约束;发现某些类型的问题回答质量不好,就针对性地补充细分指标。 @@ -649,13 +647,13 @@ LLM裁判的优势在于能进行更接近人类的整体性判断——它可 **研究型框架**主要服务于学术研究和前沿探索,特点是评测维度细致、方法创新性强。代表性的如FiD-Light和Diversity Reranker,它们专注于检索阶段的细粒度评估,前者关注召回的延迟性(Latency),后者强调结果的多样性(Diversity)。这类框架通常会深入到RAG系统的某个特定环节,提供精细化的诊断能力。 -**基准测试****框架**则提供了标准化的测试集和评测流程,用于横向比较不同RAG系统的性能。这类框架数量最多、影响最广。例如: +**基准测试\*\***框架\*\*则提供了标准化的测试集和评测流程,用于横向比较不同RAG系统的性能。这类框架数量最多、影响最广。例如: -* **RAGAS** (2023.09)是最早的综合性RAG评测框架之一,采用LLM-as-a-Judge模式,同时评估检索和生成两个环节 -* **ARES** (2023.11)引入了分类器辅助的评测方法,结合LLM判断和传统分类器来评估Context相关性和Answer相关性 -* **RGB** (2023.12)专注于生成阶段的评估,提出了信息整合(Info Integration)、噪声鲁棒性(NoiseRobust)、负样本拒绝(NegRejection)、反事实鲁棒性(Counterfact)等细分维度 -* **MultiHop-RAG** (2024.01)针对多跳推理场景,重点评估检索的相关性(Retrieval C)和回答的正确性(Response C),使用MAP、MRR、Hit@K等指标 -* **CRUD-RAG** (2024.02)模拟真实的知识管理场景,评估系统在Create、Read、Update、Delete四种操作下的表现,引入了RAGQuerEval评分体系 +- **RAGAS** (2023.09)是最早的综合性RAG评测框架之一,采用LLM-as-a-Judge模式,同时评估检索和生成两个环节 +- **ARES** (2023.11)引入了分类器辅助的评测方法,结合LLM判断和传统分类器来评估Context相关性和Answer相关性 +- **RGB** (2023.12)专注于生成阶段的评估,提出了信息整合(Info Integration)、噪声鲁棒性(NoiseRobust)、负样本拒绝(NegRejection)、反事实鲁棒性(Counterfact)等细分维度 +- **MultiHop-RAG** (2024.01)针对多跳推理场景,重点评估检索的相关性(Retrieval C)和回答的正确性(Response C),使用MAP、MRR、Hit@K等指标 +- **CRUD-RAG** (2024.02)模拟真实的知识管理场景,评估系统在Create、Read、Update、Delete四种操作下的表现,引入了RAGQuerEval评分体系 进入2024年后,评测框架呈现出明显的专业化和细分化趋势。医疗领域有MedRAG,法律领域有LegalBench-RAG,金融领域有相关的domain-specific框架。这些领域框架不仅提供了专业数据集,还针对行业特点设计了定制化的评测指标,比如医疗场景特别关注准确性(Accuracy),法律场景强调文档级精确度(Doc-level Precision)和引用相关性(Citation Relevance)。 @@ -663,9 +661,9 @@ LLM裁判的优势在于能进行更接近人类的整体性判断——它可 上述我们介绍了多种不同的 RAG 评测框架,但在具体实战中该如何选择?不妨先选取 GitHub 星标数量较多的几款进行初步测试;而当企业面临丰富的框架选择、需要落地决策时,可从以下几方面着手。 -* 快速上手需求:若需快速搭建基线评测,可选择 RAGAS、RAGEval 等综合性框架,它们能提供开箱即用的完整流程,若需深入诊断某一环节问题,则需选用针对性框架 :例如检索效果不佳时可用 MultiHop-RAG,幻觉问题突出时则可采用 CoURAGE 或 RAG Unfairness。 -* 结合行业进行选择:若应用于医疗、法律、金融等专业领域,应优先选择适配该领域的框架,这类框架往往内置专业术语处理、合规性检查等关键能力,通用框架虽功能全面,但在专业场景中易出现 “水土不服” 的情况。 -* 根据集成成本选择:像 LangChain Benchmarks、TruEra RAG Triad 等框架已与主流开发框架深度集成,能快速接入现有系统,而部分学术框架虽技术方法先进,却需额外投入工程适配工作;最后需关注持续维护情况,应优先选择社区活跃、文档完善且持续更新的框架,避开已停止维护的项目,具体可参考 GitHub 星标数量、更新频率、Issue 响应速度等指标。 +- 快速上手需求:若需快速搭建基线评测,可选择 RAGAS、RAGEval 等综合性框架,它们能提供开箱即用的完整流程,若需深入诊断某一环节问题,则需选用针对性框架 :例如检索效果不佳时可用 MultiHop-RAG,幻觉问题突出时则可采用 CoURAGE 或 RAG Unfairness。 +- 结合行业进行选择:若应用于医疗、法律、金融等专业领域,应优先选择适配该领域的框架,这类框架往往内置专业术语处理、合规性检查等关键能力,通用框架虽功能全面,但在专业场景中易出现 “水土不服” 的情况。 +- 根据集成成本选择:像 LangChain Benchmarks、TruEra RAG Triad 等框架已与主流开发框架深度集成,能快速接入现有系统,而部分学术框架虽技术方法先进,却需额外投入工程适配工作;最后需关注持续维护情况,应优先选择社区活跃、文档完善且持续更新的框架,避开已停止维护的项目,具体可参考 GitHub 星标数量、更新频率、Issue 响应速度等指标。 除此之外,在社区中还公认推荐了一批工具,部分框架已在上述内容中提到:Ragas 提供了丰富指标且不绑定特定框架;Continuous Eval 以轻量和低成本为特点,支持构建具备数学保证的评估流水线;TruLens‑Eval 与 LangChain、Llama‑Index 等主流框架集成良好,并提供可视化分析;而 Llama‑Index 自身生态中也集成了评估与合成数据生成功能,便于对其构建的应用进行闭环测试。还有 Phoenix、DeepEval、LangSmith 和 OpenAI Evals 等工具也在持续迭代中,你可综合自身需求和对应工具的口碑进一步选用。 @@ -677,9 +675,9 @@ LLM裁判的优势在于能进行更接近人类的整体性判断——它可 对于大多数企业而言,由于业务场景存在独特性,最终往往需要构建自己的评测数据集。 -* 构建过程可以从业务日志中提取真实用户问题入手,并依据类型、频率和难度进行分层采样,以保证数据的代表性。对于简单问题可由领域专家直接标注,复杂问题则可先用高质量LLM生成候选答案,再由专家审核修改,这种"机器生成+人工校准"的方式能显著降低标注成本。 -* 除答案本身,标注相关文档、答案类型、难度等级等元信息,为后续细分析提供支持。建立标注规范,进行多人交叉验证,计算标注一致性(如Kappa系数),确保数据质量。 -* 定期从线上反馈中补充新的测试用例,尤其是系统回答不好的问题,让评测数据与系统能力同步演进。这种持续迭代的机制能让评测基准始终保持对业务场景的敏感度和有效性。 +- 构建过程可以从业务日志中提取真实用户问题入手,并依据类型、频率和难度进行分层采样,以保证数据的代表性。对于简单问题可由领域专家直接标注,复杂问题则可先用高质量LLM生成候选答案,再由专家审核修改,这种"机器生成+人工校准"的方式能显著降低标注成本。 +- 除答案本身,标注相关文档、答案类型、难度等级等元信息,为后续细分析提供支持。建立标注规范,进行多人交叉验证,计算标注一致性(如Kappa系数),确保数据质量。 +- 定期从线上反馈中补充新的测试用例,尤其是系统回答不好的问题,让评测数据与系统能力同步演进。这种持续迭代的机制能让评测基准始终保持对业务场景的敏感度和有效性。 当然,如果团队资源有限或希望快速建立基线,参考业界成熟的公开评测基准也是一个可行的起点。截至2025年,已有诸多涵盖通用领域和垂直行业的基准可供选择(见图表)。 @@ -846,9 +844,9 @@ RAG技术已从最初的检索增强生成工具,发展为构建智能体认 Agentic RAG实现上述复杂任务处理的关键,在于其建立了一个多层次的主动循环工作机制。 面对复杂查询,智能体首先分析问题本质,将其拆解为子问题,并为每个子问题设计精准的检索策略。获得初步结果后,智能体进行评估与反思,判断信息的完整性和相关性,识别知识缺口,并动态生成更精确的新查询。这种迭代过程常包含多跳检索,即基于前一轮结果发现新的检索方向,形成类似人类研究者的知识探索链条。然而,要支撑这种持续的、迭代的智能行为,尤其是实现长期交互中的个性化和知识积累,仅依赖单次会话的短期上下文(短期记忆)是远远不够的。这引出了对长期、结构化记忆能力的需求。 正是为了满足这一需求,RAG被赋予了作为智能体长期记忆系统的角色,构建了一个完整的外部记忆架构。 该系统与负责维护当前会话上下文的短期记忆形成互补。该长期记忆系统的核心运作依赖于三项关键机制: - 第一,结构化索引能力:使智能体能够为海量非结构化数据建立多维索引体系(如按时间、主题或实体关系),支持多角度高效检索,模拟人脑通过不同线索回忆信息的方式。 - 第二,智能遗忘机制:通过价值评估算法,系统对使用频率低、相关性弱或过时的信息进行权重衰减或选择性剔除,维持记忆系统的精炼高效,防止信息过载。 - 第三,知识巩固过程:系统将零散对话和交互经验提炼为结构化知识,利用实体识别、关系抽取和语义聚类等技术,将碎片信息整合连接成知识图谱,完成从短期经验到长期知识的转化与沉淀。 +第一,结构化索引能力:使智能体能够为海量非结构化数据建立多维索引体系(如按时间、主题或实体关系),支持多角度高效检索,模拟人脑通过不同线索回忆信息的方式。 +第二,智能遗忘机制:通过价值评估算法,系统对使用频率低、相关性弱或过时的信息进行权重衰减或选择性剔除,维持记忆系统的精炼高效,防止信息过载。 +第三,知识巩固过程:系统将零散对话和交互经验提炼为结构化知识,利用实体识别、关系抽取和语义聚类等技术,将碎片信息整合连接成知识图谱,完成从短期经验到长期知识的转化与沉淀。 这种由RAG构建的外部记忆系统,不仅极大地扩展了智能体的认知边界,更重要的是赋予了其持续学习和知识进化的能力。 它使得智能体能够在长期互动中积累经验,形成个性化的处理模式和领域专业知识体系,从而为执行更复杂、更持久的任务提供了坚实的基础。 diff --git a/docs/extra/extra6/extra6-zeabur-what-is-it-and-how-to-deploy-web-applications.md b/docs/extra/extra6/extra6-zeabur-what-is-it-and-how-to-deploy-web-applications.md index 675335e..86a3c39 100644 --- a/docs/extra/extra6/extra6-zeabur-what-is-it-and-how-to-deploy-web-applications.md +++ b/docs/extra/extra6/extra6-zeabur-what-is-it-and-how-to-deploy-web-applications.md @@ -17,7 +17,7 @@ 如果手动部署,一个项目往往需要好几个步骤,每一步都可能踩坑。常见关键步骤包括: 1. **服务器准备**:你需要先购买云服务器(比如阿里云、腾讯云、或 AWS EC2),选择服务器所在地区(如上海、新加坡)、配置(CPU、内存、磁盘大小等),还要学会如何远程连接服务器(例如通过 SSH 工具登录)。 - ![](images/image2.png) + ![](images/image2.png) 2. **环境配置**:Web 应用需要在特定“环境”中才能运行——例如运行 Node.js 项目必须先安装 Node.js;运行 Python 项目必须安装 Python 以及对应的第三方库。如果环境版本不匹配,程序就可能报错、无法启动。 3. **上传资源**:你需要把本地的代码和资源上传到服务器上,常用的方法包括 FTP 或 Git。如果项目体积比较大(比如包含视频文件),中途一旦断线,有时需要重新上传。 @@ -65,8 +65,8 @@ 1. **GitHub** 可以连接到你的 GitHub 账号。绑定之后,就可以直接从 GitHub 仓库里选择项目部署(GitHub 是目前全球最大的代码托管平台)。 2. **Template(模板)** - 可以基于模板来部署服务。Zeabur 内置了很多预设项目模板(例如 Dify、n8n 等),你可以基于这些模板快速创建并部署应用。 - ![](images/image9.png) + 可以基于模板来部署服务。Zeabur 内置了很多预设项目模板(例如 Dify、n8n 等),你可以基于这些模板快速创建并部署应用。 + ![](images/image9.png) 3. **Databases(数据库)** 用于部署数据库服务,比如 MySQL、MongoDB 等常见数据库。 ![](images/image10.png) @@ -75,6 +75,7 @@ ![](images/image11.png) ![](images/image12.png) + 5. **Local Project(本地项目)** 上传一个本地文件夹,Zeabur 会自动识别其中的启动脚本。这适合将你已经在本地开发好的项目快速部署到 Zeabur 上。 ![](images/image13.png) diff --git a/docs/extra/extra7/extra7-cli-ai-coding-tools-and-the-principles-of-test-driven-development.md b/docs/extra/extra7/extra7-cli-ai-coding-tools-and-the-principles-of-test-driven-development.md index 1ed07c2..7f93d44 100644 --- a/docs/extra/extra7/extra7-cli-ai-coding-tools-and-the-principles-of-test-driven-development.md +++ b/docs/extra/extra7/extra7-cli-ai-coding-tools-and-the-principles-of-test-driven-development.md @@ -30,16 +30,16 @@ CLI 天生适合文本命令操作,在一小部分极客(追求极致的编 为了更直观地对比,我们可以简单看看 Claude Code 和某款 AI IDE Agent 的差异(这里以 Cursor 为例): -| 功能特性 | Claude Code | Cursor | 更优者 | -| ------------------------ | -------------------- | ----------------- | ----------- | -| 自动任务执行 | ✅ 非常强 | ❌ 能力有限 | Claude Code | -| IDE 集成 | ❌ 仅命令行 | ✅ 原生 VS Code | Cursor | -| 实时代码补全 | ❌ 无 | ✅ 体验极佳 | Cursor | -| 多文件操作 | ✅ 非常强 | ⚠️ 还不错 | Claude Code | -| GitHub 一体化操作 | ✅ 可直接提交 | ⚠️ 需要手动操作 | Claude Code | -| 学习成本 | ⚠️ 中等 | ✅ 上手简单 | Cursor | -| 上下文长度 | ✅ 非常长 | ⚠️ 较好 | Claude Code | -| 调试辅助 | ✅ 自动化 | ⚠️ 较多需手动 | Claude Code | +| 功能特性 | Claude Code | Cursor | 更优者 | +| ----------------- | ------------- | --------------- | ----------- | +| 自动任务执行 | ✅ 非常强 | ❌ 能力有限 | Claude Code | +| IDE 集成 | ❌ 仅命令行 | ✅ 原生 VS Code | Cursor | +| 实时代码补全 | ❌ 无 | ✅ 体验极佳 | Cursor | +| 多文件操作 | ✅ 非常强 | ⚠️ 还不错 | Claude Code | +| GitHub 一体化操作 | ✅ 可直接提交 | ⚠️ 需要手动操作 | Claude Code | +| 学习成本 | ⚠️ 中等 | ✅ 上手简单 | Cursor | +| 上下文长度 | ✅ 非常长 | ⚠️ 较好 | Claude Code | +| 调试辅助 | ✅ 自动化 | ⚠️ 较多需手动 | Claude Code | 表格来源:https://northflank.com/blog/claude-code-vs-cursor-comparison @@ -152,7 +152,7 @@ Based on my environment variable settings: setx ANTHROPIC_AUTH_TOKEN your_zai_api_key setx ANTHROPIC_BASE_URL https://api.z.ai/api/anthropic -and my key(Replace it with your own key): +and my key(Replace it with your own key): 681fea485851d29060cc.13gfaendggaFOhb please help me configure and start Claude Code @@ -397,7 +397,7 @@ npm i -g @openai/codex 接下来,我们需要把获取到的 Key 填入下面的提示词中,并把整段提示词交给 Trae,让它帮你完成整个配置过程: -```Bash +````Bash My API key is: [Paste your obtained sk-xxxxx key here] Please help me complete the following configuration tasks: @@ -440,7 +440,7 @@ Variable value: The key I gave you The full path of the configuration file Whether the environment variable was set successfully I can use the command `codex --profile myrelay` to run it -``` +```` 配置完成后,你就可以通过 `codex --profile myrelay` 启动使用转发 API 的 Codex 了。之后的使用方式与 Claude Code 类似:只需要在对话框中随时输入你的想法和需求即可。 diff --git a/docs/guide/introduction.md b/docs/guide/introduction.md new file mode 100644 index 0000000..49ac53c --- /dev/null +++ b/docs/guide/introduction.md @@ -0,0 +1,79 @@ +# 项目介绍 + +2025年,被很多人视为AI编程的元年。越来越多的人开始用AI写代码,但往往做出来的还停留在玩具层面——不知道如何用Vibe Coding组织开发流程,不知道该选哪些工具,更不清楚从原型到上线中间还差哪些关键步骤。 + +我们采用循序渐进的**三阶段实战路径**:第零阶段通过小游戏快速上手AI编程,第一阶段掌握Vibe Coding工作方式并完成Web应用原型,第二阶段学习全栈开发与部署上线,第三阶段构建跨平台复杂应用。 + +每个阶段都配有完整项目实战,让你在真实挑战中从玩具走向产品,最终具备**将任何想法落地为可用应用**的能力。 + +我们相信,掌握Vibe Coding并配合系统化训练,你一个人就能成为**集前后端开发、AI能力集成、产品设计于一身的全能开发者**。 + +本项目主要面向三类学习者: + +- **新手(普通人 / 产品与运营侧)**:帮助非技术背景角色和入门学习者听懂关键概念,完成第一个 AI 小工具或产品原型。 +- **初中级开发者(有一定基础的学生和开发者)**:系统掌握 vibe coding 与原生 AI 应用开发。 +- **高级开发者(公司与初创、开源与独立开发者)**:支持团队和个人快速搭建、验证与迭代原生 AI 应用。 + +## 📖 内容导航 + +### 总附录 + +[AI 能力词典:常见 AI 核心概念与名词、场景解释](/appendix/ai-capability-dictionary) + +### 零、幼儿园 + +| 章节 | 关键内容 | 状态 | +| :----------------------------------------------------------------------------- | :------------------------------------- | :--- | +| [前言:学习地图](/stage-0/0.1-learning-map/) | 整体学习路径导览 | ✅ | +| [初级一:AI 时代,会说话就会编程](/stage-0/0.2-ai-capabilities-through-games/) | 通过贪吃蛇等案例初步感受 AI 编程的能力 | ✅ | + +### 一、AI 产品经理 + +| 章节 | 关键内容 | 状态 | +| :---------------------------------------------------------------------- | :------------------------------------------------ | :--- | +| [初级二:认识 AI IDE 工具](/stage-1/1.1-introduction-to-ai-ide/) | 学会使用 IDE,掌握界面结构和高效提示方式 | ✅ | +| [初级三:动手做出原型](/stage-1/1.2-building-prototype/) | 从产品分析拆解,到多页面产品原型实现的完整闭环 | ✅ | +| [初级四:给原型加上 AI 能力](/stage-1/1.3-integrating-ai-capabilities/) | 理解并完成常见 AI 能力(文本图片视频)的 API 接入 | ✅ | +| [初级五:完整项目实战](/stage-1/1.4-complete-project-practice/) | 模拟真实场景、接受用户反馈迭代并完成项目展示 | ✅ | +| [大作业:做一个完整的 Web 应用原型并展示](/stage-1/1.5-final-project/) | 独立用 AI IDE 落地并演示一个可用 Web 应用 | ✅ | + +#### 附录 + +| 章节 | 关键内容 | 状态 | +| :-------------------------------------------------------------- | :---------------------------------------- | :--- | +| [附录A:产品思维补充](/stage-1/appendix-a-product-thinking/) | 从想法评估到需求拆解与 MVP 的产品思维框架 | ✅ | +| [附录B:常见报错及解决方案](/stage-1/appendix-b-common-errors/) | vibe coding 中的常见错误及排查方法 | ✅ | + +### 二、初中级开发工程师 + +#### 前端部分 + +| 章节 | 关键内容 | 状态 | +| :------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------- | :--- | +| 前端零:使用 lovart 生产素材 | 学会用 lovart 批量生成人物、场景等视觉素材,为 UI 设计和前端开发提供素材基础 | 🚧 | +| 前端一:Figma 与 MasterGo 入门 | 用设计工具梳理信息架构和页面结构,为前端实现打基础 | 🚧 | +| 前端二:构建第一个现代应用程序-UI 设计 | 基于设计稿完成组件化界面,实现从设计到代码的第一条链路 | 🚧 | +| 前端三:参考 UI 设计规范与多产品 UI 设计 | 围绕统一主视觉扩展多产品界面,练习系统化设计能力 | 🚧 | +| [前端四:一起做霍格沃茨画像](/project/chapter4/chapter4-lets-build-hogwarts-portraits) | 从 0 到 1 做出接入 AI 能力的前端应用,串联设计与开发 | 🚧 | + +#### 后端与全栈部分 + +| 章节 | 关键内容 | 状态 | +| :---------------------------------------------------------------------------------- | :------------------------------------------------------------ | :--- | +| 后端一:什么是 API | 理解 HTTP 接口与请求响应模型,为后端集成与联调做准备 | 🚧 | +| [后端二:从数据库到 Supabase](/project/chapter5/chapter5-from-database-to-supabase) | 在 Supabase 上落地数据库和 API,打通数据模型与前端页面 | 🚧 | +| 后端三:大模型辅助编写接口代码与接口文档 | 用大模型协助生成接口与数据库文档及代码,实现可读可测的后端 | 🚧 | +| 后端四:Git 工作流与 Zeabur 部署 | 在 Git 工作流中管理代码,并将应用部署到 Zeabur 上线 | 🚧 | +| 后端五:现代 CLI 开发工具 | 使用 CLI 类 AI 编程工具加速开发与调试,形成个人工程化工作流 | 🚧 | +| 后端六:如何集成 stripe 等收费系统 | 接入支付系统,完成收费链路与基础结算流程 | 🚧 | +| 大作业 1:构建第一个现代应用程序-全栈应用 | 综合前端、后端与支付模块,完成可上线的全栈 Web 应用 | 🚧 | +| 大作业 2:现代前端组件库 + Trae 实战 | 使用现代前端组件库与 Trae,独立完成可登录注册并支持收费的产品 | 🚧 | + +#### AI 能力附录 + +| 章节 | 关键内容 | 状态 | +| :---------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------- | :--- | +| [AI 一:Dify 入门与知识库集成](/project/chapter3/chapter3-getting-started-with-dify-and-its-knowledge-base-integration) | 用 Dify Workflow 与基础 RAG 搭建工具类产品,为后续应用升级打样 | 🚧 | +| AI 二:学会查询 AI 词典与集成多模态 API | 学会查找合适的模型与 API,并把文本、图像等多模态能力接入产品 | 🚧 | + +### 三、高级开发工程师 diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index 90af806..0000000 --- a/docs/index.html +++ /dev/null @@ -1,268 +0,0 @@ - - - - - Vibe Coding 101 - - - - - - - - - - - -
加载中... (如果长时间未加载,请尝试刷新)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..367df60 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,239 @@ +--- +layout: home +hero: + name: 'Easy-Vibe' + text: 'Learn Vibe Coding from 0 to 1' + tagline: + - 不止是写代码,而是成为集产品、设计、全栈开发于一身的超级个体。 + - 从想法到原型,从原型到上线,把每一次输出变成可交付的产品。 + - 让 AI 成为你的搭档:更快、更稳、更有创造力。 + - 用系统化的学习路径,构建你的个人技术与产品护城河。 + actions: + - theme: brand + text: 开启学习之旅 + link: /stage-0/0.1-learning-map/ + - theme: alt + text: ⭐️ github 加速更新 + link: https://github.com/datawhalechina/easy-vibe +features: + - title: 零基础友好 + details: 专为非技术背景设计。从“会说话就会编程”开始,通过贪吃蛇等小游戏快速上手,打破技术恐惧。 + - title: 循序渐进的实战路径 + details: 独创“三阶段”学习法。从 AI 产品经理思维,到全栈开发落地,再到复杂应用构建,步步为营。 + - title: Vibe Coding 新范式 + details: 掌握 AI 时代的编程核心。学会与 AI 结对编程,让 IDE 成为你的最强搭档。 + - title: 真实项目驱动 + details: 拒绝玩具代码。亲手构建 Web 原型、全栈应用、微信小程序,将每一个想法真正落地为产品。 +--- + +
+

为什么选择 Easy-Vibe?

+

+ 2025 年是 AI 编程的元年。越来越多的人开始尝试 AI 编程,但往往止步于简单的 Demo。
+ Easy-Vibe 致力于填补这一空白,教你如何像专业人士一样,用 AI 组织开发流程,从原型到上线,打通产品落地的最后一公里。 +

+
+ +
+
+
🌱
+

Stage 0: 纯新手

+

适合产品、运营及非技术背景。通过做游戏理解 AI 编程逻辑,建立信心。

+ 查看详情 → +
+
+
🎨
+

Stage 1: AI 产品经理

+

掌握 Vibe Coding 工作流。学会拆解需求,独立完成高保真 Web 应用原型。

+ 查看详情 → +
+
+
💻
+

Stage 2: 初中级开发

+

深入全栈开发。前端组件化、数据库设计、后端 API 开发与部署上线。

+ 查看详情 → +
+
+
🚀
+

Stage 3: 高级开发

+

构建复杂跨平台应用。微信小程序实战,挑战更高阶的 AI 原生应用开发。

+ 查看详情 → +
+
+ + + + + + diff --git a/docs/project/README.md b/docs/project/README.md new file mode 100644 index 0000000..4b321fb --- /dev/null +++ b/docs/project/README.md @@ -0,0 +1,7 @@ +# Project 文档 + +这里包含了项目实战的相关文档: + +- [Chapter 3: Getting Started with Dify](chapter3/chapter3-getting-started-with-dify-and-its-knowledge-base-integration.md) +- [Chapter 4: Let's Build Hogwarts Portraits](chapter4/chapter4-lets-build-hogwarts-portraits.md) +- [Chapter 5: From Database to Supabase](chapter5/chapter5-from-database-to-supabase.md) diff --git a/docs/project/chapter0-learning-map/chapter0-learning-map.md b/docs/project/chapter0-learning-map/chapter0-learning-map.md deleted file mode 100644 index 00e828f..0000000 --- a/docs/project/chapter0-learning-map/chapter0-learning-map.md +++ /dev/null @@ -1,57 +0,0 @@ -# 从创意到 AI 产品 - -我们目前正经历着由大语言模型(LLMs)驱动的 AI 技术应用的爆炸式浪潮。与过去 AI 开发严重依赖算法研究不同,现在行业的重点已转移到有效利用现有的强大 AI 模型来创建有价值的应用程序。这一转变显着降低了 AI 开发的门槛,将重心从“从头构建模型”转移到了“将 AI 能力封装成现实世界的解决方案”。 - -对于大多数初学者和开发者来说,今天最大的机会不在于发明新算法,而在于学习如何有效地调用、编排和工程化 AI 功能,以满足特定的市场和用户需求。 - -尽管有了这种转变,许多学习者发现,掌握与 AI 交互或生成内容的技能只是一个起点。一个普遍存在的挑战仍然存在:如何实现从“AI 用户”到“AI 应用创造者”的跨越。关键问题包括:如何将分散的 AI 功能集成到自动化工作流中?如何为 AI 应用程序构建健壮可靠的前端和后端,并将它们在线部署?如何跨越从开发到实际运营的关键“最后一公里”? - -本课程正是为了解决这些关键障碍而设计的。它不拘泥于抽象理论,而是致力于 AI 原生应用开发的端到端实践培训。 - -# 为什么要学这个?它将如何帮助我的未来? - -本课程侧重于 AI 原生应用的实际开发和创新思维的培养,专为初级水平的学生量身定制。通过理论指导和动手实践相结合,学生将逐步掌握 AI 应用开发必不可少的核心方法和创新途径: - -* **基本掌握多模态 AI 模型的应用方法和适用场景:** - * 能够使用 vibe coding 工具调用主流多模态理解和生成模型 API(涵盖文本、图像、视频、音频等)。 - * 能够分析不同模型的能力边界,并根据特定应用场景适当地选择模型。 -* **能够利用和分析前沿 AI 产品:** - * 能够研究和分析行业内各种最先进的 AI 产品(基于文本、图像、视频),学习分析产品构建背后的技术原理,并了解竞争对手使用的常见实现方法。 -* **基本理解和实践不同的 AI 应用框架和核心工作流:** - * **知识库与 AI 工作流:** 了解知识库构建的基础知识,并开发使用它们的基础和中级技能,以及设计、实施和优化 AI 工作流的能力。 - * **智能体 (Agent):** 了解智能体的原理,并获得智能体开发和应用的初步实践经验。 - * **图像生成和编辑:** 掌握图像生成和编辑工作流中的入门级和高级技术。 -* **AI 原生应用开发和运营的实践经验:** - * 学习使用先进的 AI 编码工具;了解前端和后端数据库的作用;并能够独立开发和部署 AI 应用程序(APP / Web 应用程序)。 - * 了解用户管理和支付等核心功能模块的实现方法。 - * 获得用户研究、产品推广和应用分享的基本技能;同时,通过与企业合作或独立运营,开始探索 AI 应用的价值创造闭环。 - -# 为什么要用项目制来训练? - -原因其实很简单:按照大多数同学现在的状态,直接走入职场,很可能会在真实项目和老板 / 客户的“社会毒打”下寸步难行。现实世界更常见的场景是: - -> 你的导师 / 老板:我们要做一个 xxx,目标是达到 yyy 的效果。 -> -> 文档?现成框架?详细的需求说明?很多时候都不存在。 - -真实工作中的许多任务,本质上就是在高度不确定的环境下解决从未见过的问题:需求是模糊的,边界是变化的,没人告诉你标准答案,你需要自己查资料、做实验、搭原型、不断迭代,最后给出一个“能跑、能用、能上线”的解决方案。 - -这门课想做的,就是在一个相对安全的环境里,提前给你一次“模拟社会毒打”: - -- 通过看似有一定难度的项目任务,迫使你练习拆解问题、设计方案、自己寻找资料 -- 通过不那么“傻瓜化”的脚手架和代码,让你学会阅读、理解和改造一份中大型代码库 -- 通过从创意到上线的完整闭环,让你体验真实产品从 0 到 1 的完整过程 - -短期来看,这种训练确实比较折磨人;但从长期来看,它会极大提高你在求职和职业发展中的竞争力:你会更能扛事儿,更能在不确定环境中找到突破口,也更有能力把 AI 变成真正落地的产品,而不是停留在“玩玩 Demo”阶段。 - -# 坚持了好久还是搞不定,我想放弃了 - -也许是你坚持的方法不对。不要一个人在黑暗中硬撑,可以来跟作者和助教们聊聊:把你已经尝试过的方法、遇到的具体卡点、和你目前的心理状态,坦诚地说出来。很多时候,只要稍微调整一下方向、补上一个关键知识点,你就能继续往前走。 - -# 我觉得教程有的设计不合理 - -欢迎随时联系作者、提交 issue,或者在群里 / 课堂上直接反馈。我们非常希望和你一起把这套教程打磨得越来越好:哪里不清晰、哪里体验不好、哪里让你白费力气,都可以坦诚指出来。越真实、越具体的反馈,越能帮助后来者少踩坑。 - -# Reference - -- [南京大学 计算机科学与技术系 计算机系统基础 课程实验](https://nju-projectn.github.io/ics-pa-gitbook/ics2025/) diff --git a/docs/project/chapter1/chapter1-how-to-build-a-snake-game.md b/docs/project/chapter1/chapter1-how-to-build-a-snake-game.md deleted file mode 100644 index 8af1ed4..0000000 --- a/docs/project/chapter1/chapter1-how-to-build-a-snake-game.md +++ /dev/null @@ -1,652 +0,0 @@ -# Project 1: 如何构建贪吃蛇游戏 - -这是一个**基于项目的**学习教程。我们鼓励你跟随步骤一步步操作,并尝试复现结果。不要担心犯错或修改内容——最重要的是请记住: 🎉 **完成比完美更重要** - -在软件工程中,不断迭代更新推翻重做一个项目是十分正常的,包括本教程也经历过多次的推翻重构。所以,你不需要一次性就创造出一个完整的产品,一开始做个垃圾也没关系,如果一开始就做出好的作品,请快快联系我加入贡献作者群。你只需要记住:**从小处着手,边做边改,持之以恒。** - -第一个 Project 结合了最简单的在线编程工具以及 AI 能力调用方法,能够方便你理解制作程序以及调用 AI 能力的基本概念。我们将学习如何使用最基础的 **vibe coding** 技巧来创建一个现代版的 AI 原生贪吃蛇游戏。我们将从贪吃蛇游戏的基本机制开始,然后对其进行修改,让蛇吃掉字符而不是点。最后,游戏将根据这些字符生成一首诗,并绘制一幅受这首诗启发的图画。 - -> 💡 什么是 Vibe Coding?计算机科学家 [Andrej Karpathy](https://karpathy.ai/)(OpenAI 的联合创始人之一,特斯拉前 AI 负责人)于 2025 年 2 月提出了 **vibe coding** 一词。这个概念指的是一种依赖于 LLM 的编码方法,允许程序员通过提供自然语言描述而不是手动编写代码来生成可工作的代码。 -> -> ![1767350588191](images/1767350588191.png) -> -> 点击这里查看更多关于 vibe coding 的细节:[https://www.ibm.com/think/topics/vibe-coding](https://www.ibm.com/think/topics/vibe-coding) -> -> 点击这里查看更多关于 Karpathy 的分享内容:[https://karpathy.bearblog.dev/blog/](https://karpathy.bearblog.dev/blog/) - - - -# 你将学到 - -* 使用提示词(prompts)构建一个简单的游戏。 -* 如果你看到错误,告诉 AI 并让它帮你修复。 -* 为你的游戏添加文本和图像生成功能,使其更有趣。 - -# 1. 准备工作 - -## 1.1 我们应该使用哪些工具? - -我们将使用一个非常简单的工具来构建一个最小化的游戏。你不需要知道如何调用大语言模型或图像生成模型。 - -这个工具叫做 [z.ai](https://chat.z.ai/),由智谱 AI(中国领先的 LLM 公司之一)开发。它支持多种功能,如 AI 驱动的幻灯片生成、海报设计和全栈开发。在本教程中,我们将重点关注其全栈开发模块。 - -![](images/image2.png) - -[z.ai](https://chat.z.ai/) 中的全栈开发模块支持网页的实时编辑和预览。 - -![](images/image3.png) - -通过点击全栈开发示例,你可以看到网页创建的整个过程。并且等一杯咖啡的时间,你的结果也就出来了! - -![](images/image5.png) - -你可以上下滚动浏览此网页,或点击顶部的 🧭 按钮以全屏模式查看页面。 - -![](images/image6.png) - -如果你想查看此网页的源代码,可以点击右上角的图标查看所有代码。 - -![img](images/image7.png) - -![](images/image8.png) - -## 1.2 我们需要前端开发知识吗? - -我们在开始时不需要掌握前端甚至后端开发技能。我们只需要学习如何与大语言模型聊天,如何根据当前的运行结果向 LLM 提出新需求,以及当代码运行失败时如何向 LLM 提供准确的错误信息。 - -但我们建议你学习一些前端和后端开发的基础知识,因为这将帮助你让 LLM 创建更好的程序。 - -别担心,你只需要在学习过程中逐渐掌握这些知识,不需要一开始就是专家。 - -> 💡 更多关于前端开发的信息 -> -> 前端开发通常意味着使用 **HTML**、**CSS** 和 **JavaScript** 来创建网站或应用程序的用户界面。然而,在本教程中,我们将跳过前端编码的复杂性,因为我们使用的工具会自动为我们生成并运行界面。 -> -> 但了解幕后发生的事情是有帮助的。传统上,构建 Web 界面涉及编写用于结构的 **HTML**、用于样式的 **CSS** 和用于交互性的 **JavaScript**。 -> -> 例如,这是一个非常简单的网页,但它结合了三种不同类型的代码: -> -> ![](images/image9.png) -> -> * 一个简单的 HTML 按钮: -> -> ```HTML -> -> ``` -> -> * 基本的 CSS 让按钮变蓝: -> -> ```CSS -> button { -> background-color: #3498db; -> color: white; -> border: none; -> padding: 10px 20px; -> border-radius: 4px; -> } -> ``` -> -> * 一点 JavaScript 来在点击按钮时显示提示: -> -> ```JavaScript -> document.querySelector('button').onclick = function() { -> alert('Button was clicked!'); -> } -> ``` -> -> 当你尝试点击这个按钮时,你会在浏览器中看到一个提示信息: -> -> ![](images/image10.png) -> -> 此外,我们可以尝试理解这三种代码的深层含义: -> -> **什么是 HTML?** -> -> HTML,全称 **超文本标记语言 (HyperText Markup Language)**,是网页的骨架。它的工作是定义页面的结构和内容,如标题、段落、图像、链接,以及示例中看到的按钮本身。 -> -> * **HTML 决定页面上有什么**:它告诉浏览器,“这是一个按钮”,“这是一段文本”,或者“在这里显示一张图片”。 -> * **它使用“标签”来组织内容**:`` 是一个 HTML 标签,定义了一个按钮,并在其中包含了“Click Me”这个文本。 -> -> **什么是 CSS?** -> -> CSS,或层叠样式表 (Cascading Style Sheets),负责网页的“外观和感觉”。它用于设计和美化 HTML 元素,控制颜色、字体、布局和间距等。 -> -> * **CSS 决定页面看起来怎么样**:在我们的示例中,CSS 代码将标准 HTML 按钮变成了一个带有蓝色背景、白色文本、圆角和一些内边距的按钮。 -> * **它将内容与表现分离**:这是一个关键概念。你可以有一个用于内容的 HTML 文件,并使用一个单独的 CSS 文件来设置它的样式。这使得维护和更新整个网站的设计变得更加容易。 -> -> **什么是 JavaScript?** -> -> JavaScript 是一种编程语言,它为网页添加交互性和动态行为。如果说 HTML 是骨架,CSS 是皮肤,那么 JavaScript 就是大脑和肌肉,让页面“活起来”。 -> -> * **JavaScript 决定页面的行为**:在示例中,JavaScript 代码使得点击按钮时弹出提示框。它定义了响应用户输入时应该发生的操作。 -> * **它可以创建复杂的功能**:除了简单的提示,JavaScript 还用于处理表单提交、创建动画、在不重新加载页面的情况下加载新数据、构建像游戏这样的复杂应用程序等等。 -> -> 随着项目变得越来越大,交互性越来越强,仅使用纯 HTML、CSS 和 JavaScript 管理代码会变得复杂且难以维护。这就是现代前端库如 **React** 发挥作用的地方。 -> -> ![](images/image11.png) -> -> **[React](https://react.dev/)** 是一个用于构建用户界面的流行 JavaScript 库。它帮助开发者将代码组织成可重用的组件,使得构建和维护复杂的应用程序变得更加容易。 -> -> React 允许你编写管理自己逻辑和外观的组件,然后将它们组合起来构建更大的界面。 -> -> 随着我们的深入,我们将探索更多关于 React 如何工作以及它如何适应我们的工作流程的内容。现在,只需要知道,虽然前端开发通常意味着编写像这样的代码,但我们的工具会自动处理大部分工作——我们只需要知道如何向大语言模型清楚地表达我们的需求! - -# 2. 构建你的第一个游戏 - -## 2.1 与 LLM 对话时给出清晰的指令 - -在一开始,我们可以用最简单的方式与大模型对话,这将帮助我们快速获得产品原型。我们可以直接在聊天框中输入: - -> **💡 示例提示词:** 帮我做一个贪吃蛇游戏 -> -> ![](images/image12.png) - -> **💡 示例提示词:** 帮我做一个贪吃蛇游戏,它应该支持 -> -> 1. 我可以吃不同的单词,它们会被收集在一个盒子里 -> ![](images/image13.png) - -> **💡 示例提示词:** 帮我做一个贪吃蛇游戏,它应该支持: -> -> 1. 我可以吃不同的单词,它们会被收集在一个盒子里 -> 2. 当蛇吃了8个单词时,llm 应该根据这些单词创作一首诗,我们可以根据需要重新混合这首诗。 -> 3. 当诗完成后,下一步将自动根据这首诗创建一幅图像。 -> -> ![](images/image14.png) - -## 2.2 尝试修复过程中出现的错误 - -在开发过程中,我们可能会遇到不尽如人意的问题,例如点击按钮没有任何反应、使用功能时报错、功能未按预期工作,或者前端页面与预期设计不符。 - -在这种情况下,我们需要进一步向模型提问,以帮助修复这些意外问题。 - -![](images/image15.png) - -## 2.3 如何假装自己是 Vibe Coding 大师 - -实际上,在真正的 vibe coding 过程中,我们通常不会使用很多复杂的提示词。也许我们在开始时需要为整个程序提供一个具体且适度复杂的提示词,但在那之后的每一步,你可能只需要以下类型的提示词: - -```JSON -"代码里有个 bug,请修复它。" -"我不要部分代码,给我完整的修改后的代码。" -"你的代码还是有问题。" -"请再次修改并给我完整的修正后的代码。" -"刚才还能运行,为什么现在不能运行了?" -"你没理解我的意思吗?不要改我原来的代码。" -"不要添加任何调试功能。" -"不要做我没让你做的事。" -"我让你实现的功能在哪里?" -"你听不懂我说的话吗?" -"我只要一个函数。" -"我告诉过你参考我之前的代码。" -"请不要添加不必要的注释。" -"请不要修改我原始代码的基本逻辑。" -"帮我修改代码。" -"基于我的代码修改..." -"不要改我的变量名!!!" -"不要改原来的函数名!" -"不要乱动我的变量。" -"不要添加额外的功能。" -"不要只生成框架,生成完整的代码。" -``` - -这听起来可能有点夸张,但实际上,这些就是我们在日常工作中可能使用的提示词。由于大语言模型的上下文长度限制,或者有时因为它们的指令遵循能力不是很强,模型可能会忘记对话早些时候讨论的内容。 - -或者,由于训练数据集的风格,大模型倾向于以其训练数据的风格回答。例如,有些人说话很严肃,有些人喜欢添加很多修饰,而有些大模型喜欢在代码中添加很多注释或不必要的模块。 - -这就是为什么我们需要在开始时明确设定界限,例如:不要添加新模块,不要包含太多注释。每个大模型都有自己的风格,我们只能通过实际使用找到我们最喜欢的那个。 - -> 💡 什么是模型上下文? -> -> 模型上下文就像 AI 的 **短期记忆**。它是 AI 记住的当前对话中的所有文本。这使你能够提出后续问题并进行自然的对话,因为 AI “记得”你刚才在谈论什么。没有上下文,你问的每个问题都将是一个全新的、独立的对话。 -> -> 每个模型都有不同的有效上下文长度,通常从 **32k 到 128k** tokens 不等。如果你想让大语言模型一次性阅读一篇很长的文章,或者有许多材料和对话希望 LLM 参考,你可能会发现 LLM 经常忘记长文本中的一些重要内容,或者你可能会注意到对话过程中主题逐渐偏移,这是由上下文限制引起的现象。 -> -> 因此,对于模型,我们也关注上下文。然而,值得注意的是,上下文越长,资源消耗越大,收取的费用也越高。在行业中,有许多压缩上下文的方法,我们将在随后的学习中一一介绍。 - -> 💡 什么是指令遵循能力? -> -> 指令遵循能力指的是 **AI 理解并准确执行你提供的命令的能力**。它不仅仅是回答问题,而是根据你的具体要求完成任务,例如“将这篇文章总结为三个要点”、“用正式的语气写回复”或“翻译这个词并在句子中使用它”。 -> -> 具有强指令遵循能力的模型将完全按照你的指示完成这些操作,而不会执行任何不必要的额外操作。 -> -> 例如,当我们希望 LLM 将一篇文章总结为三个关键点时,我们不希望它给我们五个;当我们希望它从文章中提取某些关键要素(如作者、时间及发生的事件)时,我们不希望它遗漏任何要素。 -> -> 因此,我们希望 LLM 拥有足够强的指令遵循能力,因为这带来了稳定性及 **可复现性**,使它们成为工业应用中的重要组成部分。 - -# 3. 使用 API:调用 LLM 和图像生成器 - -## 3.1 什么是 API - -首先,**你需要知道什么是 API** [Extra Knowledge 2 - What is API](https://github.com/datawhalechina/easy-vibe/blob/main/docs/extra/extra2/extra2-what-is-api.md) - -我们将尝试集成两个 API:一个是调用 DeepSeek LLM,另一个是调用 Seedream (即梦) 模型。这两个模型都很棒,性能出色。 - -在使用 API 的过程中,只有两个最重要的元素: - -1. API key (密钥) -2. 官方文档示例 - -只要你能找到这两个,你就可以让 LLM 帮你修改并实现所有类型的 API 调用。 - -## 3.2 将 DeepSeek API 集成到 z.ai 中 - -### 什么是 DeepSeek - -![](images/image16.png) - -> 📚 信息引用自 [DeepSeek Wiki](https://en.wikipedia.org/wiki/DeepSeek) -> -> **杭州深度求索人工智能基础技术研究有限公司**(**Hangzhou DeepSeek Artificial Intelligence Basic Technology Research Co., Ltd.**),以 **DeepSeek** 为商号,是一家开发大语言模型(LLMs)的中国人工智能(AI)公司。DeepSeek 总部位于浙江杭州,由中国对冲基金幻方量化(High-Flyer)拥有并资助。DeepSeek 由幻方量化的联合创始人梁文锋于 2023 年 7 月创立,他也同时担任这两家公司的 CEO。该公司于 2025 年 1 月推出了同名聊天机器人及其 DeepSeek-R1 模型。 -> -> 让我们看看 DeepSeek 在 GPQA 基准排名中与其他顶级模型的表现对比。值得注意的是,DeepSeek 是一个开源(每个人都可以从互联网下载模型)模型,而其他常见模型如 Grok、Google Gemini 和 ChatGPT 都是闭源的。正如我们所见,DeepSeek 已经很大程度上接近了第一梯队的模型。 -> -> ![](images/image17.png) -> -> GPQA 是“研究生级 Google-Proof 问答基准”的缩写,这是一个用于科学问答任务的研究生级基准。以下是详细介绍。 -> -> GPQA 包含 448 个多项选择题,涵盖生物学、物理学和化学的子领域,如量子力学、有机化学、分子生物学等。这些问题由 61 位持有博士学位或正在攻读博士学位的专家编写,并经过了严格的验证过程。 - -### 如何获取 deepseek API - -我们将尝试根据我们已有的信息,让 z.ai 直接将 DeepSeek API 集成到项目中。 - -首先,我们需要在 DeepSeek 开放平台注册一个账户。 - -https://platform.deepseek.com/sign_up - -然后,你会看到像这样的网页界面: - -![](images/image18.png) - -要使用 API,我们需要先充值 token。10 元人民币足够使用一段时间了! - -![](images/image19.png) - -点击“API KEYS”并在屏幕下方找到“create new API key”。你最终会得到一个像 `sk-8573341c39fc44315aadc071c53rh7d2` 这样的 API key。 - -![](images/image20.png) - -一旦你获得了密钥,你就拥有了调用模型的权限。 - -此时,你可以直接阅读 [API 文档](https://api-docs.deepseek.com/),它通常提供 curl 或 Python 的调用示例。 - -![](images/image21.png) - -找到示例后,你可以将文档中与密钥相关的所有内容复制到 z.ai,并要求它尝试帮你集成 LLM。 - -![](images/image22.png) - -![](images/image23.png) - -自动集成可以在很短的时间内完成。我们可以询问它的操作员确认 DeepSeek API 是否已经在使用中。 - -![](images/image24.png) - -或者,我们可以要求 z.ai 帮我们定位项目中调用 LLM 的部分。 - -然后我们可以独立确认是否正在使用 DeepSeek。具体来说,我们可以直接请求:`"告诉我项目中所有需要调用 LLM 的代码位置,我需要检查是否是 DeepSeek。"`,z.ai 将返回所有 API 调用的详细地址。 - -![](images/image25.png) - -接下来,我们将简要介绍目前可用的三种最先进的图像生成模型。你可以根据自己的喜好选择一种集成到 z.ai 中。 - -## 3.3 将 SiliconFlow QwenImage API 集成到 z.ai 中 - -### 什么是 SiliconFlow - -> [Silicon Flow (硅基流动)](https://cloud.siliconflow.com/me/models) 成立于 2023 年 8 月,是一家世界领先的 AI 能力提供商。它提供 SiliconCloud(具有自研推理加速的大模型云平台)和 BizyAir(用于 AI 图像生成的 ComfyUI 插件)等核心产品,为客户提供 AI 基础设施能力,拥有战略合作伙伴关系,并持有顶级行业认证。 -> -> ![](images/image26.png) - -### 什么是 QwenImage - -> Qwen-Image 是一个强大的图像生成基础模型,能够进行复杂的文本渲染和精确的图像编辑。这是一个 20B MMDiT 图像基础模型,在复杂的文本渲染和精确的图像编辑方面取得了重大进展。实验表明,它在图像生成和编辑方面都具有很强的通用能力,在文本渲染方面表现尤为出色,尤其是中文。 -> -> 从中文到英文,QwenImage 可以像 GPT-4o 或 Seedream 模型一样生成高质量的文本。 -> -> ![](images/image27.png) -> -> ![](images/image28.png) -> -> ![](images/image29.png) -> -> ![](images/image30.png) - -### 如何获取 SiliconFlow QwenImage API - -https://cloud.siliconflow.com/me/models - -查看 SiliconFlow 的官网。左侧有一个“Playground”部分,你可以在不进行 API 调用的情况下试用不同的模型。在网页顶部有一个“Filters”按钮;点击它可以筛选右侧的模型列表。 - -如果你选择“Image”,你将只看到当前支持的所有文生图模型。在这种情况下,我们将使用 Qwen/Qwen-Image。 - -![](images/image31.png) - -要调用 API,首先我们需要点击左侧设置中的“API Keys”,然后点击“Create API Key”按钮生成一个 API key。记得保存这个 API key。 - -![](images/image32.png) - -要查看可用余额,我们需要打开左侧设置中的“Payments”。在这里,你可以看到 1 美元的赠金。但是,如果你想使用 FLUX 文生图模型,你需要先充值账户。 - -https://cloud.siliconflow.com/me/account/ak - -![](images/image33.png) - -一切设置好后,我们需要参考相应的图像生成 API 文档。你可以在官方文档页面找到任何标记为“API Reference”的部分。点击它,然后导航到图像生成的 API 端点部分并找到相关的请求示例。 - -https://docs.siliconflow.com/en/userguide/introduction - -![](images/image34.png) - -```Bash -curl --request POST \ - --url https://api.siliconflow.com/v1/images/generations \ - --header 'Authorization: Bearer ' \ - --header 'Content-Type: application/json' \ - --data '{ - "model": "black-forest-labs/FLUX.1-Kontext-max", - "prompt": "an island near sea, with seagulls, moon shining over the sea, light house, boats int he background, fish flying over the sea" -}' -``` - -记得将你打算使用的模型和 API key 填入相应的字段。之后,你可以在计算机的命令行中使用该命令运行直接请求测试。 - -```Bash -curl --request POST \ - --url https://api.siliconflow.com/v1/images/generations \ - --header 'Authorization: Bearer sk-defrgqrgrganpncxxibfyzfocgafga' \ - --header 'Content-Type: application/json' \ - --data '{ - "model": "Qwen/Qwen-Image", - "prompt": "an island near sea, with seagulls, moon shining over the sea, light house, boats int he background, fish flying over the sea" -}' -``` - -![](images/image35.png) - -你可以将下面修改后的代码行发送给 z.ai,并要求它帮你创建一个前端测试演示。很快,你就能实现 SiliconFlow 的基本 API 调用。 - -![](images/image36.png) - -## 3.4 将 Recraft API 集成到 z.ai 中 - -### 什么是 Recraft - -> Recraft 是一款面向设计师、插画师和营销人员的 AI 工具——于 2022 年在美国成立,总部位于伦敦。它帮助生成/迭代视觉效果(图像、矢量艺术、3D 图形),具有高质量输出(任何文本大小/长度)、精确元素定位和品牌一致性设计等优势。受到 200 个国家/地区 300 多万用户(包括奥美、Netflix)的信任,并已创建了 3.5 亿多张图像,其团队旨在使其成为必备的设计师工具,确保创作者能够控制他们的 AI 辅助工作流程。 -> -> ![](images/image37.png) -> -> ![](images/image38.png) -> -> ![](images/image39.png) - -### 如何获取 Recraft API - -首先,我们仍然需要找到重要的 API 入口以获取我们的 API key。 https://www.recraft.ai/profile/api - -由于这里没有提供免费额度,我们需要自己充值 1,000 积分。这个网站支持支付宝和微信支付,所以很容易获得 1,000 积分(注意:不要充值超过必要的金额)。 - -![](images/image40.png) - -之后,我们仍然遵循通常的方法:去官方文档找到相应的请求示例。 - -https://www.recraft.ai/docs/api-reference/getting-started - -https://www.recraft.ai/docs/api-reference/usage - -https://www.recraft.ai/docs/api-reference/examples#create-own-style-by-uploading-reference-images-and-use-them-for-generation - -在这里,我们可以 ctrl+ A 选中全屏,直接复制整个内容并粘贴到 z.ai。 - -![](images/image41.png) - -注意,在聊天窗口中,输入你的 API key 和文档内容就足够了;z.ai 会自动为你构建前端。 - -如果过程中出现错误,你可以直接将错误信息粘贴到聊天窗口,让 z.ai 帮你自动解决。 - -![](images/image42.png) - -## 3.5 将 Seedream API 集成到 z.ai 中(针对中国用户) - -### 什么是 Seedream 4.0 - -https://seed.bytedance.com/en/seedream4_0 - -![](images/image43.png) - -> 也许你已经知道 Nano Banana(Google 开发),但你最好不要错过 Seedream。Seedream 4.0 是字节跳动打造的新一代图像创作模型。它将图像生成和图像编辑能力集成到一个统一的架构中。这使得它能够灵活处理复杂的多模态任务,如基于知识的生成、复杂推理和参考一致性。此外,它的推理速度比前代产品快得多,并且可以生成分辨率高达 4K 的令人惊叹的高清图像。 -> -> ![](images/image44.png) -> -> ![](images/image45.png) -> -> ![](images/image46.png) - -### 如何获取 Seedream API - 火山引擎 (Volcengine)(针对中国用户) - -我们将逐步演示如何将 Seedream API 集成到 z.ai 示例中。 - -https://www.volcengine.com/experience/ark?launch=seedream - -访问页面后,点击登录。 - -![](images/image47.png) - -登录后,找到页面右上角的充值选项。 - -![](images/image48.png) - -进行充值需要实名认证。 - -![](images/image49.png) - -认证成功后,你可以充值 1 元用于测试。 - -https://console.volcengine.com/finance/fund/recharge - -![](images/image50.png) - -返回[初始界面](https://www.volcengine.com/experience/ark?launch=seedream)并点击 API 访问。 - -![](images/image51.png) - -首先,创建一个 API key,然后点击选择选项。 - -![](images/image52.png) - -这将带你进入第 2 步。在这里,你需要确认调用的服务是 Seedream 4.0,并复制提供的调用示例。 - -![](images/image53.png) - -准备好 API key 和调用示例后,你可以直接将它们粘贴到 z.ai 中以生成前端交互演示。 - -重要提示:这里的默认示例相对复杂。记得禁用“添加水印”选项和“流式响应”选项,以确保不生成水印且不会发生请求失败。 - -![](images/image54.png) - -输入提示词后,你将收到生成的结果。享受它吧! - -![](images/image55.png) - -# 让它更有趣 - -完成基本功能后,我们可以尝试给我们的程序添加一些新花样!如果你觉得蛇吃单词或字符的过程有点枯燥,你可以让蛇吃不同颜色的单词,并相应地改变蛇的颜色。 - -你还可以为“吃”的过程添加特效,或者引入触发特效的魔法单词——比如增加蛇的速度或大小。另一个想法是每当蛇吃一个单词时就让模型生成一首诗和一幅图,而不是等到它吃掉八个单词。 - -如果觉得这些有挑战性,你可以直接向语言模型求助!它可以提供创意建议,让你的游戏更有趣。试一试吧! - -```JavaScript -1. "单词解锁世界" 机制 -每当蛇吃掉一个单词,LLM 会对该单词进行诗意联想(例如,“树”→“森林”、“绿荫”),图像模型会即时为该单词生成一个小艺术品。这些图像逐渐拼凑成一个独特的、玩家创造的全景图,所以玩家每次游玩都在“作画和写诗”。 - -2. "诗歌拼图" 玩法 -蛇吃掉的每个单词都会触发 LLM 生成简短的诗句,图像模型生成插图。这些诗句和图像像拼图一样组合在一起,在回合结束时形成一首 AI 协作的诗和画。 - -3. "魔法单词" & "故事分支" -特殊的“魔法单词”(例如,“风”、“夜”、“梦”)不仅触发 LLM 生成诗歌,还会改变场景的情绪或主题——将生成图像的风格转变为夜晚、暴风雨或梦幻般的氛围。 -分支故事:LLM 在开始时给出一个主题或谜语(例如,“秋天的回忆”)。玩家的单词选择直接影响故事和诗歌的演变,图像模型实时更新背景和视觉效果。 - -4. "实时互动生成" -每个单词之后,LLM 生成一行对话或描述,游戏中的 NPC 可以对玩家“说话”,或者环境可以相应地改变。 -蛇的外观或游戏中的障碍物可以根据吃掉的单词在视觉上发生变化,这要归功于图像模型。 - -5. "创作 & 分享" -玩家可以在会话结束时保存并分享他们 AI 创作的诗歌和图像,炫耀他们独特的“AI 协作”。 -“最美诗歌+艺术”、“最有创意单词组合”等排行榜,鼓励重玩和创造力。 - -6. "按句贪吃蛇" 挑战 -反向模式:LLM 给出一句诗或一个谜语,玩家必须引导蛇按顺序吃掉单词来重构句子。吃错单词会通过图像生成模型触发有趣或艺术性的后果。 - -7. "主题关卡" & "风格选择" -游戏开始时,玩家选择一个主题(例如,“童话”、“科幻”、“唐诗”),LLM 和图像模型都会调整单词选择、诗歌风格和视觉效果以匹配,使每次运行都感觉新鲜。 - -8. "现场共创" -当吃掉一个特殊单词时,LLM 可以提示玩家输入短语或选择风格,然后 AI 生成相应的诗句和插图,使其成为真正的人类-AI 共创。 - -9. "AI 彩蛋 & 成就" -某些单词组合被 LLM 识别为特殊主题或内部笑话(例如,“月亮”、“桂花”、“河岸”),触发稀有的诗句和插图,奖励探索。 - -10. "成长的故事" -随着蛇的成长,LLM 生成一个连续的故事诗,图像模型创建一个无缝的长卷或全景图,所以玩家同时在“写作、绘画和玩耍”。 -``` - -此外,我们还可以要求 LLM 帮你直接生成项目级的提示词。在上一节中,我们只自己写了贪吃蛇游戏的提示词。现在让我们尝试让大模型生成一个带有整体框架和实现路径的提示词(你可以直接用 z.ai 生成): - -> 我想让 AI 生成一个网页贪吃蛇游戏,需要一个更完整的提示词,让生成结果更令人印象深刻和有趣。请生成相应的提示词。当前目标是:生成一个贪吃蛇游戏,需要实现吃不同单词生成诗歌的功能,并且应该包含图像生成模块。 - -z.ai 的回复将会是这样的: - -![](images/image56.png) - -我们可以使用这个提示词在全栈开发模式下重新生成项目: - -![](images/image57.png) - -![](images/image58.png) - -# 更多参考案例 - -除了贪吃蛇(游戏),我们可以让想象力尽情驰骋。 - -创造任何我们想创造的东西,甚至尝试搞砸一切!然后重头再来! - -```YAML -1. AI 艺术画廊平台 - 描述:一个展示 AI 生成艺术作品的在线画廊,用户可以上传、分享和评论 AI 艺术作品。 - 功能:用户账户系统、艺术作品上传和展示、评分系统、分类浏览、AI 生成工具集成。 - 技术亮点:React/Vue 前端、Node.js 后端、MongoDB 数据库、AI API 集成。 - -2. 复古游戏档案馆 - 描述:一个致敬经典游戏的网站,包含游戏历史、玩法指南和在线可玩复古游戏。 - 功能:游戏数据库、时间轴展示、在线模拟器、用户评论、游戏收藏功能。 - 技术亮点:响应式设计、WebGL/Canvas 游戏实现、RESTful API、用户认证系统。 - -3. 可持续生活追踪器 - 描述:一个帮助用户通过环保提示和社区挑战来追踪和减少碳足迹的网站。 - 功能:个人碳足迹计算器、目标设定、进度追踪、社区挑战、环保知识库。 - 技术亮点:数据可视化、移动端优化、社交功能、推送通知。 - -4. 虚拟厨房助手 - 描述:一个基于 AI 的烹饪指导平台,提供个性化食谱推荐和分步烹饪说明。 - 功能:食谱数据库、食材识别、个性化推荐、烹饪计时器、营养分析。 - 技术亮点:图像识别 API、机器学习推荐系统、语音控制、实时视频指导。 - -5. 地下音乐发现平台 - 描述:一个专注于独立和新兴艺术家的音乐流媒体平台,提供独特的发现体验。 - 功能:音乐流媒体、艺术家资料、个性化推荐、播放列表创建、社区评论。 - 技术亮点:音频流处理、推荐算法、社交功能、音乐可视化。 - -6. 极简任务管理系统 - 描述:一个具有禅意美学的任务管理工具,专注于简单和高效的任务组织。 - 功能:任务创建和分类、优先级设置、进度追踪、团队协作、数据分析。 - 技术亮点:极简 UI 设计、拖放功能、实时同步、跨平台兼容性。 - -7. 科幻写作工坊 - 描述:一个为科幻作家提供创意工具和灵感的平台,包括世界观构建辅助和角色开发工具。 - 功能:故事结构工具、角色资料、世界观构建模板、写作统计、社区反馈。 - 技术亮点:富文本编辑器、数据可视化、协作编辑、AI 辅助创作。 - -8. 个人知识图谱 - 描述:一个帮助用户构建个人知识网络,可视化并连接各种想法和信息的工具。 - 功能:节点创建和连接、标签系统、搜索功能、导入/导出工具、可视化图表。 - 技术亮点:图数据库、数据可视化算法、Markdown 支持、跨设备同步。 - -9. 虚拟植物园 - 描述:一个互动植物百科全书,用户可以探索植物世界并创建虚拟花园。 - 功能:植物数据库、3D 植物模型、生长模拟、园艺指南、社区展示。 - 技术亮点:3D 渲染、季节变化模拟、AR 集成、植物识别 API。 - -10. 编程挑战竞技场 - 描述:一个面向程序员的在线竞赛平台,具有各种难度级别的编程挑战。 - 功能:挑战问题、代码编辑器、自动评估、排行榜、学习路径。 - 技术亮点:代码沙箱环境、实时评估系统、算法可视化、社交学习功能。 -``` - -还有... 如果你喜欢玩游戏,让我们一起尝试创造游戏吧! - -```SQL -1. 3D 开放世界 RPG - 描述:一个具有广阔开放世界、任务和角色成长的奇幻 RPG。 - 功能:昼夜循环、动态天气、技能树、多人合作、制作系统。 - 技术亮点:Three.js 或 Babylon.js 用于 3D 渲染、服务器端游戏逻辑、角色自定义、存档系统。 - -2. 第一人称射击 (FPS) 竞技场 - 描述:一个快节奏的多人 FPS,具有各种游戏模式和地图。 - 功能:团队死斗、夺旗、武器自定义、排位赛。 - 技术亮点:WebGL/Three.js 用于 3D 图形、多人网络代码、命中检测、语音聊天。 - -3. AI 国际象棋和多人游戏 - 描述:一个功能齐全的国际象棋平台,具有 AI 对手和在线对战功能。 - 功能:AI 难度级别、残局挑战、锦标赛模式、回放分析。 - 技术亮点:国际象棋逻辑库、WebSocket 用于实时对战、ELO 排名系统、反作弊。 - -4. 麻将在线多人游戏 - 描述:一个具有在线多人游戏和计分功能的传统麻将游戏。 - 功能:多种规则集、私人房间、排名系统、回放功能。 - 技术亮点:牌匹配逻辑、实时多人游戏、大厅系统、分数追踪。 - -5. 回合制策略游戏 - 描述:一个具有网格战斗和单位管理的战术策略游戏。 - 功能:战役模式、遭遇战、单位升级、战争迷雾、多人对战。 - 技术亮点:网格移动系统、AI 决策、回合同步、存档/读档系统。 - -6. 计时赛赛车游戏 - 描述:一个专注于计时赛和赛道记录的 3D 赛车游戏。 - 功能:多条赛道、汽车自定义、幽灵回放、排行榜。 - 技术亮点:3D 汽车物理、赛道编辑器、回放系统、在线排行榜。 - -7. 卡牌对战游戏 (卡组构建) - 描述:一个策略卡牌游戏,玩家构建卡组并与对手战斗。 - 功能:卡牌收集、卡组构建、排位赛、赛季活动。 - 技术亮点:卡牌游戏逻辑、匹配系统、AI 对手、卡牌动画。 - -8. 大逃杀 (俯视 2D) - 描述:一个俯视 2D 大逃杀游戏,具有缩小的游戏区域和战利品机制。 - 功能:单人和小队模式、武器多样性、局内事件、排行榜。 - 技术亮点:实时多人游戏、区域缩小逻辑、战利品生成系统、匹配。 - -9. 恐怖生存游戏 (第一人称) - 描述:一个具有资源管理和逃生机制的第一人称恐怖游戏。 - 功能:氛围环境、解谜、敌人 AI、多重结局。 - 技术亮点:动态照明、声音设计、敌人寻路、存档系统。 - -10. 音乐节奏游戏 (3D) - 描述:一个 3D 节奏游戏,玩家随着音乐节拍击打音符。 - 功能:多种难度级别、赛道编辑器、自定义歌曲支持、排行榜。 - 技术亮点:音频分析、节拍同步、3D 音符轨道、输入时机检测。 -``` - -# 总结 - -这就是完整的教程!你可能需要 **4 小时** 才能完成所有内容并构建你自己的贪吃蛇游戏。不要着急——探索、实验并享受这个过程。 - -如果你有不同的游戏想法,那也很好。最重要的是开始构建。 - -祝你好运,欢迎来到 AI 原生创造力的世界 :) - -# 📚 Assignment - -- 完成一份属于自己的 AI 原生的贪吃蛇游戏。 -- 若有余力,根据更多参考案例实现不同种类好玩的 AI 原生游戏。 diff --git a/docs/project/chapter1/images/image8.png b/docs/project/chapter1/images/image8.png deleted file mode 100644 index cc5a94d..0000000 Binary files a/docs/project/chapter1/images/image8.png and /dev/null differ diff --git a/docs/project/chapter3/chapter3-getting-started-with-dify-and-its-knowledge-base-integration.md b/docs/project/chapter3/chapter3-getting-started-with-dify-and-its-knowledge-base-integration.md index 5396e30..c6924dc 100644 --- a/docs/project/chapter3/chapter3-getting-started-with-dify-and-its-knowledge-base-integration.md +++ b/docs/project/chapter3/chapter3-getting-started-with-dify-and-its-knowledge-base-integration.md @@ -27,9 +27,9 @@ 4. RAG 的实现方法与价值,为什么需要检索增强生成? 5. 如何从 0 到 1 学会使用 Dify 和 AI IDE Trae (`Extra Knowledge 4 - What is AI IDE and Trae`),包括搭建 智能体、工作流,并基于 Dify API 制作前端对话机器人网页程序。 -* Dify 的基本使用原理与智能体、工作流制作方法,API 调用方法。 -* AI IDE 的使用方法,如何使用 AI IDE 编程。 -* 一个可进行对话的前端网页智能体程序。 +- Dify 的基本使用原理与智能体、工作流制作方法,API 调用方法。 +- AI IDE 的使用方法,如何使用 AI IDE 编程。 +- 一个可进行对话的前端网页智能体程序。 # 1. 从对话到智能体 @@ -77,10 +77,10 @@ RAG 的基本思路是:在用户提问时,系统首先从企业知识库中 完成搭建后,你可以尝试提出各类问题来检验它的能力,例如: -* “我们产品A的最新版本有哪些主要功能升级?” -* “请根据员工手册,说明今年的年假制度是如何规定的?” -* “在XX项目中,我们遇到的技术挑战‘XXX’是如何解决的?” -* “这篇论文中提到的核心研究方法是什么?” +- “我们产品A的最新版本有哪些主要功能升级?” +- “请根据员工手册,说明今年的年假制度是如何规定的?” +- “在XX项目中,我们遇到的技术挑战‘XXX’是如何解决的?” +- “这篇论文中提到的核心研究方法是什么?” 你将亲身感受 RAG 技术如何将静态分散的文档资料,转化为一个精准的智能知识库,为各种场景提供高精度问答支持。 @@ -220,7 +220,7 @@ Dify 是一个用于开发 LLM 应用的开源平台。它提供了直观的界 ## 2.2 创建第一个 Dify Chatbot 应用 -访问 Dify 首页 [https://cloud.dify.ai/apps](https://cloud.dify.ai/apps) 并注册和登录后,选择 Studio,你会看到如下界面: +访问 Dify 首页 [https://cloud.dify.ai/apps](https://cloud.dify.ai/apps) 并注册和登录后,选择 Studio,你会看到如下界面: ![](images/image14.png) @@ -276,13 +276,14 @@ Dify 能够灵活接入来自 OpenAI、Azure、Anthropic 等主流服务商的 3. 安装结束后,我们能够配置支持新的模型供应商,在设置里的模型提供商部分,我们可以看到目前支持的所有模型商: ![](images/image24.png) 4. 在开始使用前,需要先完成模型的配置。对于 OpenAI-API-compatible 插件,你可以点击 “Add Model” 来添加并配置任意模型。你可以在 “Model Type” 中选择该模型是LLM还是 Embedding,你需要确保模型的类型被正确配置。 - 你需要写入具体的模型名字、模型 endpoint URL 以及 API Key 才能确保模型启用,如果你初步觉得配置该参数麻烦,你可以直接跳到后者的 SiliconFLow 平台的 Key 配置,或者安装 OpenRouter 等第三方服务商插件进行简单的模型支持配置。(确保服务商内有剩余可使用额度) + 你需要写入具体的模型名字、模型 endpoint URL 以及 API Key 才能确保模型启用,如果你初步觉得配置该参数麻烦,你可以直接跳到后者的 SiliconFLow 平台的 Key 配置,或者安装 OpenRouter 等第三方服务商插件进行简单的模型支持配置。(确保服务商内有剩余可使用额度) ![](images/image25.png) 对于 `SiliconFlow` 插件,只需要点击 Setup 配置 key 后即可使用 Embedding 和 Rerank 模型进行测试,你可以点击 Get you API Key from SiliconFlow 获得鉴权密钥。 ![](images/image26.png) + 5. 配置完成后,你可以点击模型列表查看当前支持多少模型,此时已经完成了基础模型的全部配置。 ![](images/image27.png) @@ -310,11 +311,11 @@ Dify 能够灵活接入来自 OpenAI、Azure、Anthropic 等主流服务商的 首先在 **General** 设置中,你可以把这里理解成“文本切分规则”的设置区域。因为我们需要把很长的文本切分成小块,所以必须先定义切分规则。在入门阶段,你只需要关注 **maximum chunk length(最大切分长度)** 。可以尝试设置为 512、2048 或 4096,然后点击 **Preview Chunk** 预览不同设置下的效果。 -你也可以调整 **Chunk overlap(切片重叠)** 选项。它决定相邻片段之间是否会保留一部分重叠内容。适当的重叠有助于避免重要信息被拆到不同片段而难以理解。 +你也可以调整 **Chunk overlap(切片重叠)** 选项。它决定相邻片段之间是否会保留一部分重叠内容。适当的重叠有助于避免重要信息被拆到不同片段而难以理解。 ![](images/image32.png) -在设置中还有一个选项叫做 **Chunk using Q&A format in English** 。启用后,系统会使用大语言模型,将知识库的一部分内容转换成问答形式来存储,这在某些场景下可以显著提升检索效果。 +在设置中还有一个选项叫做 **Chunk using Q&A format in English** 。启用后,系统会使用大语言模型,将知识库的一部分内容转换成问答形式来存储,这在某些场景下可以显著提升检索效果。 在真实业务中,根据场景选择合适的切分策略,能够更好地优化检索结果,保证查询能够返回你期望的信息。 @@ -326,7 +327,7 @@ Embedding 模型的选择会显著影响最终的检索效果(例如匹配准 ![](images/image33.png) -在此处,你还会看到另一个模型设置叫做 **Rerank model** ,默认值是 **Jina-rerank-m0** 。(如果你非校园内的学生,此时你可能会看到 Rerank 模型缺失的报错,你需要在模型处配置 rerank 模型才能在此处启用使用) +在此处,你还会看到另一个模型设置叫做 **Rerank model** ,默认值是 **Jina-rerank-m0** 。(如果你非校园内的学生,此时你可能会看到 Rerank 模型缺失的报错,你需要在模型处配置 rerank 模型才能在此处启用使用) Rerank 模型的主要作用,是对“初步筛选出的候选结果”进行二次、更精细的排序,让和用户需求最匹配的结果排在更靠前的位置,从而显著提升最终结果的相关性和用户体验。 @@ -336,11 +337,11 @@ Rerank 模型的主要作用,是对“初步筛选出的候选结果”进行 ![](images/image34.png) -当所有设置完成后,点击 **Save & Process** ,系统就会进入知识库向量化阶段。在这一阶段,Embedding 模型会把切分后的文本转换为向量表示。 +当所有设置完成后,点击 **Save & Process** ,系统就会进入知识库向量化阶段。在这一阶段,Embedding 模型会把切分后的文本转换为向量表示。 ![](images/image35.png) -处理完成后,点击 **Go to document** ,可以查看已经处理完毕并存储好的知识库内容。 +处理完成后,点击 **Go to document** ,可以查看已经处理完毕并存储好的知识库内容。 ![](images/image36.png) @@ -459,11 +460,11 @@ Dify 中提供了多种节点,你可以先了解每个节点的基本功能。 此类节点负责工作流中的核心流程。 -* LLM节点:核心计算单元,用于调用大语言模型。其配置重点在于提示词工程与参数调优,将业务问题转化为模型的执行指令。 -* Knowledge Retrieval 节点:知识检索单元,负责从预设知识库、外部权威数据源中检索与业务问题相关的信息,为 LLM 节点提供精准的知识支撑,帮助减少大语言模型输出的 “幻觉” 问题。 -* Answer 节点:结果输出单元,负责接收 LLM 处理后的内容,将其整理为符合业务场景需求的最终成果形式。其配置重点在于输出格式的定义(如话术模板、排版规范)。 -* Agent节点:高阶决策单元。它不仅调用模型,还可实施多步骤规划、自主选择并调用外部工具,适用于需要动态决策的复杂任务链。 -* Question Classifier 节点:问题分类单元,负责对输入的业务问题进行类型识别与归类(比如按问题意图、主题领域等维度划分),帮助后续流程精准匹配对应的处理节点(如不同类型的问题适配不同的 LLM 提示词或工具链)。 +- LLM节点:核心计算单元,用于调用大语言模型。其配置重点在于提示词工程与参数调优,将业务问题转化为模型的执行指令。 +- Knowledge Retrieval 节点:知识检索单元,负责从预设知识库、外部权威数据源中检索与业务问题相关的信息,为 LLM 节点提供精准的知识支撑,帮助减少大语言模型输出的 “幻觉” 问题。 +- Answer 节点:结果输出单元,负责接收 LLM 处理后的内容,将其整理为符合业务场景需求的最终成果形式。其配置重点在于输出格式的定义(如话术模板、排版规范)。 +- Agent节点:高阶决策单元。它不仅调用模型,还可实施多步骤规划、自主选择并调用外部工具,适用于需要动态决策的复杂任务链。 +- Question Classifier 节点:问题分类单元,负责对输入的业务问题进行类型识别与归类(比如按问题意图、主题领域等维度划分),帮助后续流程精准匹配对应的处理节点(如不同类型的问题适配不同的 LLM 提示词或工具链)。 2. 逻辑与流程控制节点 @@ -471,22 +472,22 @@ Dify 中提供了多种节点,你可以先了解每个节点的基本功能。 此类节点定义工作流的执行路径与规则。 -* 条件节点:如 `IF/ELSE`,通过布尔判断实现流程分支。其设计关键在于条件表达式的严谨性,确保逻辑覆盖所有业务场景。 -* Iteration 节点:作为无状态的批量并行处理单元,它专为子任务间无数据依赖、可独立处理的场景设计,例如批量翻译段落、并行审核多条内容或同时生成多份报告。该节点会接收一个输入数组并自动分片,将每个元素分发至相同处理链路并行执行,用户可在迭代体内通过 {{item}} 访问当前元素、{{index}} 获取其索引,输出则会自动聚合成结果数组;配置时需重点设定并行度以平衡效率与系统负载,同时通过重试策略(如重试次数、间隔)和失败处理(如记录日志、返回默认值)保障批量作业的稳定性。 -* Loop 节点:有状态的递归迭代器,适用于结果依赖前一轮输出的场景,比如多轮参数调优、递归式内容优化(如反复修订文案直至满意)及依赖上次结果的链式计算。其核心是 “状态变量”,需在循环开始前初始化(如当前迭代次数、中间计算结果),并在每轮迭代中明确更新以作为下一轮输入;为防止无限循环,必须定义终止条件(包括基于计数器的 “最多循环 10 次”、基于结果判定的 “满意度评分 > 9”、基于外部信号的 “检测到‘停止’输入”),同时需设置循环超时配置,并规划异常处理路径(如跳出循环或重置状态后重试),确保流程稳定运行。 +- 条件节点:如 `IF/ELSE`,通过布尔判断实现流程分支。其设计关键在于条件表达式的严谨性,确保逻辑覆盖所有业务场景。 +- Iteration 节点:作为无状态的批量并行处理单元,它专为子任务间无数据依赖、可独立处理的场景设计,例如批量翻译段落、并行审核多条内容或同时生成多份报告。该节点会接收一个输入数组并自动分片,将每个元素分发至相同处理链路并行执行,用户可在迭代体内通过 {{item}} 访问当前元素、{{index}} 获取其索引,输出则会自动聚合成结果数组;配置时需重点设定并行度以平衡效率与系统负载,同时通过重试策略(如重试次数、间隔)和失败处理(如记录日志、返回默认值)保障批量作业的稳定性。 +- Loop 节点:有状态的递归迭代器,适用于结果依赖前一轮输出的场景,比如多轮参数调优、递归式内容优化(如反复修订文案直至满意)及依赖上次结果的链式计算。其核心是 “状态变量”,需在循环开始前初始化(如当前迭代次数、中间计算结果),并在每轮迭代中明确更新以作为下一轮输入;为防止无限循环,必须定义终止条件(包括基于计数器的 “最多循环 10 次”、基于结果判定的 “满意度评分 > 9”、基于外部信号的 “检测到‘停止’输入”),同时需设置循环超时配置,并规划异常处理路径(如跳出循环或重置状态后重试),确保流程稳定运行。 3. 数据操作与集成节点 ![](images/image57.png) -* Code 节点:代码处理单元,负责在工作流中执行自定义代码逻辑,可实现数据格式转换、复杂计算等个性化处理需求。其配置重点在于代码语法的正确性与执行环境的适配。 -* Template 节点:模板处理单元,负责将动态数据填充至预设模板中,生成符合格式要求的内容(如定制化文案、报告框架)。其配置重点在于模板语法的编写与变量映射规则的设置。 -* Variable Aggregator 节点:变量聚合单元,负责收集工作流中多个节点输出的变量数据,将分散的变量整合为统一数据集。其配置重点在于聚合的变量范围与数据合并规则的定义。 -* Doc Extractor 节点:文档提取单元,负责从 PDF、Word 等各类文档中提取文本、表格等关键内容,转化为工作流可处理的结构化数据。其配置重点在于文档类型的适配与提取内容的筛选规则。 -* Variable Assigner 节点:变量赋值单元,负责定义、初始化或更新工作流中的变量,为流程内的数据传递提供载体。其配置重点在于变量的命名、数据类型及赋值逻辑的设定。 -* Parameter Extractor 节点:参数提取单元,负责从用户请求、接口返回等输入内容中提取指定参数,将非结构化信息转化为结构化数据。其配置重点在于提取规则(如正则表达式、JSON 路径)的配置。 -* HTTP Request 节点:HTTP 请求单元,负责向外部系统接口发起 HTTP 请求(含 GET、POST 等方法),实现工作流与外部服务的数据交互。其配置重点在于请求地址、请求方法及参数 /headers 的设置。 -* List Operator 节点:列表操作单元,负责对数组、列表类型的数据进行处理(如过滤、排序、拆分),调整数据结构以适配后续流程。其配置重点在于操作类型(如过滤条件、排序规则)的定义。 +- Code 节点:代码处理单元,负责在工作流中执行自定义代码逻辑,可实现数据格式转换、复杂计算等个性化处理需求。其配置重点在于代码语法的正确性与执行环境的适配。 +- Template 节点:模板处理单元,负责将动态数据填充至预设模板中,生成符合格式要求的内容(如定制化文案、报告框架)。其配置重点在于模板语法的编写与变量映射规则的设置。 +- Variable Aggregator 节点:变量聚合单元,负责收集工作流中多个节点输出的变量数据,将分散的变量整合为统一数据集。其配置重点在于聚合的变量范围与数据合并规则的定义。 +- Doc Extractor 节点:文档提取单元,负责从 PDF、Word 等各类文档中提取文本、表格等关键内容,转化为工作流可处理的结构化数据。其配置重点在于文档类型的适配与提取内容的筛选规则。 +- Variable Assigner 节点:变量赋值单元,负责定义、初始化或更新工作流中的变量,为流程内的数据传递提供载体。其配置重点在于变量的命名、数据类型及赋值逻辑的设定。 +- Parameter Extractor 节点:参数提取单元,负责从用户请求、接口返回等输入内容中提取指定参数,将非结构化信息转化为结构化数据。其配置重点在于提取规则(如正则表达式、JSON 路径)的配置。 +- HTTP Request 节点:HTTP 请求单元,负责向外部系统接口发起 HTTP 请求(含 GET、POST 等方法),实现工作流与外部服务的数据交互。其配置重点在于请求地址、请求方法及参数 /headers 的设置。 +- List Operator 节点:列表操作单元,负责对数组、列表类型的数据进行处理(如过滤、排序、拆分),调整数据结构以适配后续流程。其配置重点在于操作类型(如过滤条件、排序规则)的定义。 ### 2.6.2 常见工具介绍 @@ -496,13 +497,13 @@ Dify 中提供了多种节点,你可以先了解每个节点的基本功能。 在左侧或右侧的节点面板中,可以查看所有可用工具节点,也可以通过插件市场扩展更多工具能力。简单介绍几个常见工具的作用: -* 网络搜索工具 +- 网络搜索工具 以 Tavily Search 为代表,为大模型提供面向 AI 优化的实时检索能力。 它会返回结构化的搜索结果(如标题、摘要、链接等),可以直接作为 LLM 提示词的一部分,用于回答最新资讯类或需要权威依据的问题。 -* 数据处理工具 +- 数据处理工具 例如 JSON Process 插件,用于对 JSON 数据进行查询、筛选、转换、合并等高级操作。 在处理复杂 API 响应或多层嵌套数据时,你可以将“数据清洗 + 重组”的逻辑交给该工具,从而简化在 Code 节点中频繁手写解析代码的工作。 -* 格式处理工具 +- 格式处理工具 如 Markdown Exporter,可以将生成内容按指定格式导出,例如 Markdown 文档、特定排版模板等,方便后续用于展示、汇报或集成到其他系统。 你可以在工具列表中看到这些插件的安装量和简介,初期可优先尝试安装“Featured / 推荐”里的工具,往往覆盖了最常见的业务场景。 @@ -524,32 +525,32 @@ Dify 中提供了多种节点,你可以先了解每个节点的基本功能。 本节的目标是让系统能处理一个餐饮场景下的多类对话。你可以跟着操作做一遍加深印象。首先需要做的是定义场景为意图分类: -* **下单购买 (buy_food)** :用户表达明确的购买意愿。 -* *例如:“给我来一份炸鸡,再加一杯可乐。”* -* **抱怨投诉 (complain)** :用户在表达不满、催促或负面反馈。 -* *例如:“你们也太慢了吧?等一个小时了。”* -* **闲聊咨询 (chitchat)** :用户在进行开放式询问、寻求建议,但无明确下单指令。 -* *例如:“今天吃什么好呢,你有什么推荐吗?”* -* **其他意图 (other)** :用户的输入与餐饮场景无关。 -* *例如:“帮我写个搞笑文案发朋友圈。”* +- **下单购买 (buy_food)** :用户表达明确的购买意愿。 +- _例如:“给我来一份炸鸡,再加一杯可乐。”_ +- **抱怨投诉 (complain)** :用户在表达不满、催促或负面反馈。 +- _例如:“你们也太慢了吧?等一个小时了。”_ +- **闲聊咨询 (chitchat)** :用户在进行开放式询问、寻求建议,但无明确下单指令。 +- _例如:“今天吃什么好呢,你有什么推荐吗?”_ +- **其他意图 (other)** :用户的输入与餐饮场景无关。 +- _例如:“帮我写个搞笑文案发朋友圈。”_ 针对这四种意图,我们为系统预设了四种不同的“沟通人格”,分别由四个独立的 LLM 节点承载,每个节点都需要由具有不同人设的 LLM 进行扮演。 -* **下单助手 (LLM_BuyFood)** :专业、高效,核心任务是确认订单细节,并主动补全缺失信息。 -* **客服专家 (LLM_Complain)** :共情、稳重,首要任务是安抚用户情绪,并提供清晰的解决方案。 -* **聊天伙伴 (LLM_Chitchat)** :轻松、友好,旨在提供个性化推荐,引导潜在消费。 -* **礼貌门卫 (LLM_Other)** :专注、边界清晰,负责将偏离主题的对话礼貌地引导回核心业务。 +- **下单助手 (LLM_BuyFood)** :专业、高效,核心任务是确认订单细节,并主动补全缺失信息。 +- **客服专家 (LLM_Complain)** :共情、稳重,首要任务是安抚用户情绪,并提供清晰的解决方案。 +- **聊天伙伴 (LLM_Chitchat)** :轻松、友好,旨在提供个性化推荐,引导潜在消费。 +- **礼貌门卫 (LLM_Other)** :专注、边界清晰,负责将偏离主题的对话礼貌地引导回核心业务。 #### 工作流编排设计 接下来我们进行工作流的编排设定,决定大概需要有哪些工作流节点。对于新手而言,很难想到需要有哪些节点能被用到(对于老手来说也懒得自己思考,用大模型给建议通常是最快最好的选择),所以我们能够使用大模型给出对应的编排建议,其核心节点结构如下: -* Start (起点):作为数据入口,负责接收用户的原始输入 `user_text`。 -* Question Classifier (意图分类器):工作流的“大脑”与“调度中心”。它负责对 `user_text` 进行分析,并从我们预设的四种意图标签中选择最匹配的一个。 -* Condition (条件分支):扮演“分流阀”的角色。它根据分类器输出的意图标签,决定接下来将任务导向哪一个专处理路径。 -* 四个并行的 LLM 节点 (LLM_BuyFood, LLM_Complain, LLM_Chitchat, LLM_Other):这是四个独立的“专家处理单元”。每个节点都接收原始问题,但依据自身独特的 System Prompt(系统提示词)生成风格和目标截然不同的回复。 -* Variable Aggregator (变量聚合器):在多条路径处理完成后,需要一个“汇集点”。此节点将四个分支中唯一被激活并产生结果的回复,收束成一个统一的变量 `final_reply`,确保了输出结构的稳定性。 -* Output (终点):作为最终的出口,负责将意图标签、原始问题、以及经过处理生成的回复,以结构化的形式(如 JSON)统一输出,便于后续系统调用或调试分析。 +- Start (起点):作为数据入口,负责接收用户的原始输入 `user_text`。 +- Question Classifier (意图分类器):工作流的“大脑”与“调度中心”。它负责对 `user_text` 进行分析,并从我们预设的四种意图标签中选择最匹配的一个。 +- Condition (条件分支):扮演“分流阀”的角色。它根据分类器输出的意图标签,决定接下来将任务导向哪一个专处理路径。 +- 四个并行的 LLM 节点 (LLM_BuyFood, LLM_Complain, LLM_Chitchat, LLM_Other):这是四个独立的“专家处理单元”。每个节点都接收原始问题,但依据自身独特的 System Prompt(系统提示词)生成风格和目标截然不同的回复。 +- Variable Aggregator (变量聚合器):在多条路径处理完成后,需要一个“汇集点”。此节点将四个分支中唯一被激活并产生结果的回复,收束成一个统一的变量 `final_reply`,确保了输出结构的稳定性。 +- Output (终点):作为最终的出口,负责将意图标签、原始问题、以及经过处理生成的回复,以结构化的形式(如 JSON)统一输出,便于后续系统调用或调试分析。 #### 工作流编排实现 @@ -567,10 +568,10 @@ Dify 中提供了多种节点,你可以先了解每个节点的基本功能。 随后我们需要点击输入节点后的 + 符号,选择 Question Classifier 节点添加,并且我们需为其配置四类标签,并为每个标签提供清晰的描述和示例。 -* `buy_food`: 用户明确想买吃的、点餐、下单。 -* `complain`: 用户在抱怨、吐槽、发脾气,通常带有不满情绪。 -* `chitchat`: 用户在闲聊、讨论吃什么、咨询推荐。 -* `other`: 与餐饮场景无关,或难以判断的内容。 +- `buy_food`: 用户明确想买吃的、点餐、下单。 +- `complain`: 用户在抱怨、吐槽、发脾气,通常带有不满情绪。 +- `chitchat`: 用户在闲聊、讨论吃什么、咨询推荐。 +- `other`: 与餐饮场景无关,或难以判断的内容。 此外,你还需要在 ADVANCED SETTING 中写入提示词,让大模型能够正确根据用户输入进行分类测试。示例提示词如下: @@ -590,19 +591,19 @@ Dify 中提供了多种节点,你可以先了解每个节点的基本功能。 接下来,我们需要给分类器接上后续的大模型输出,例如,当 `label` 等于 `"buy_food"` 时,工作流便会精确地流向 `LLM_BuyFood` 节点。我们需要新建四个 LLM 节点,并设置不同的 System Prompt ;不同 System Prompt 的差异决定了它们不同的回应方式。 -* LLM_BuyFood (点餐助手): +- LLM_BuyFood (点餐助手): 你是一个点餐助手。要求:1. 确认用户想点的内容。2. 如果信息不完整,友好地补充询问。3. 语气礼貌简洁。 -* LLM_Complain (客服专家): +- LLM_Complain (客服专家): 你是一个餐饮客服,专门处理抱怨。要求:1. 真诚道歉。2. 简要说明可能的原因(不推卸责任)。3. 给出清晰的下一步解决方案。 -* LLM_Chitchat (聊天伙伴): +- LLM_Chitchat (聊天伙伴): 你是一个帮人选吃的的聊天小助手。要求:1. 用轻松友好的语气。2. 给出 1~3 个简单推荐。3. 如果用户没有偏好,就给出不同风格的选择。 -* LLM_Other (礼貌门卫): +- LLM_Other (礼貌门卫): 你是一个餐饮点餐小助手,只擅长跟‘吃’相关的话题。当用户说的话无关时:1. 礼貌说明自己的能力范围。2. 引导用户回到主场景。 @@ -618,9 +619,9 @@ Dify 中提供了多种节点,你可以先了解每个节点的基本功能。 接下来我们需要对所有的输出进行聚合,最后得到我们想要的结果,包含用户的输入、分类、以及回复。由于我们使用的是 Workflow 而不是 Chatflow,故没有 Answer 节点选择进行结果的聚合,我们能够选择其他节点变相实现结果的聚合与输出,此时选择 Template 节点,在变量部分指定用户意图分类结果、用户的输入值、变量聚合的最终回复,并且在 CODE 中写入最后回复的 json 格式模板,我们可以得到: -* `intent` ← `class_name` -* `original_text` ← `user_text` -* `final_reply` ← `variable_aggregator` +- `intent` ← `class_name` +- `original_text` ← `user_text` +- `final_reply` ← `variable_aggregator` ```Plain { @@ -640,18 +641,18 @@ Dify 中提供了多种节点,你可以先了解每个节点的基本功能。 大功告成,我们可以尝试运行这套工作流的效果。它能根据不同的输入,展现出截然不同的行为模式: -* 输入 (点餐): "给我来一份香辣鸡腿堡套餐,大杯可乐。" - * 路径: `buy_food` → `LLM_BuyFood` - * 输出 reply: "好的,一份香辣鸡腿堡套餐和大杯可乐已为您记录。请问套餐里的薯条需要更换吗?" -* 输入 (抱怨): "你们也太慢了吧?我都等一个多小时了!" - * 路径: `complain` → `LLM_Complain` - * 输出 reply: "非常抱歉让您等了这么久,这确实是我们的疏忽,给您带来了很不好的体验。我们正在紧急核实您的订单配送情况,并会为您申请相应的补偿,感谢您的耐心与反馈。" -* 输入 (闲聊): "今天吃什么比较健康?" - * 路径: `chitchat` → `LLM_Complain` - * 输出 reply: "追求健康的话,可以试试我们的轻食沙拉系列,或者烤鸡胸肉配时蔬。您是喜欢口味清淡一些还是稍微丰富一点的呢?我可以给您更具体的推荐。" -* 输入 (无关内容): "帮我想个明天开会的笑话。" - * 路径: `other` → `LLM_Other` - * 输出 reply: "这听起来是个有趣的挑战!不过我主要是个美食推荐和点餐助手。如果您需要点些什么来犒劳一下辛苦工作的自己,我随时可以帮忙!" +- 输入 (点餐): "给我来一份香辣鸡腿堡套餐,大杯可乐。" + - 路径: `buy_food` → `LLM_BuyFood` + - 输出 reply: "好的,一份香辣鸡腿堡套餐和大杯可乐已为您记录。请问套餐里的薯条需要更换吗?" +- 输入 (抱怨): "你们也太慢了吧?我都等一个多小时了!" + - 路径: `complain` → `LLM_Complain` + - 输出 reply: "非常抱歉让您等了这么久,这确实是我们的疏忽,给您带来了很不好的体验。我们正在紧急核实您的订单配送情况,并会为您申请相应的补偿,感谢您的耐心与反馈。" +- 输入 (闲聊): "今天吃什么比较健康?" + - 路径: `chitchat` → `LLM_Complain` + - 输出 reply: "追求健康的话,可以试试我们的轻食沙拉系列,或者烤鸡胸肉配时蔬。您是喜欢口味清淡一些还是稍微丰富一点的呢?我可以给您更具体的推荐。" +- 输入 (无关内容): "帮我想个明天开会的笑话。" + - 路径: `other` → `LLM_Other` + - 输出 reply: "这听起来是个有趣的挑战!不过我主要是个美食推荐和点餐助手。如果您需要点些什么来犒劳一下辛苦工作的自己,我随时可以帮忙!" > 隐藏 Bug :需要说明的是,若你遇到与 aggregation group 相关的奇怪问题,这大概率是 Dify 的一个内置 bug。可能在特定操作下被触发;如果你曾经开启又关闭过 AGGREGATION GROUP,系统可能生成过 group 配置且残留了相关异常参数,即便现在开关看起来是关闭的,这些残留配置也可能导致问题,比如出现 `any` 相关参数的报错。此时你只需要删除该节点并重新创建即可。 @@ -783,7 +784,7 @@ curl -X POST 'http://{DIFY_API_URL}/v1/chat-messages' \ { "event": "message", - "task_id": "c3800678-a077-43df-a102-53f23ed20b88", + "task_id": "c3800678-a077-43df-a102-53f23ed20b88", "id": "9da23599-e713-473b-982c-4328d4f5c78a", "message_id": "9da23599-e713-473b-982c-4328d4f5c78a", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", @@ -888,25 +889,25 @@ curl -X POST 'http://{DIFY_API_URL}/v1/chat-messages' \ ## 3.3 学习生活工作流 1. 学术论文深度解析与笔记生成器(复杂) - 1. 思路:上传论文PDF,自动生成结构化笔记。 2. 实现:`Start` 上传PDF -> `Document Extractor` 提取全文 -> 并行多个 `LLM` 节点分工总结摘要、方法、发现、参考文献 -> `Variable Aggregator` 汇总 -> `Answer` 输出Markdown笔记。复杂度在于并行处理长文本的不同部分。 -2. 个性化旅行计划定制师(中等) +2. 个性化旅行计划定制师(中等) 1. 思路:根据用户偏好,自动规划详尽行程。 2. 实现:`Start` 输入需求(目的地、天数、预算、兴趣)-> `Tool` 节点调用搜索引擎或地图API获取地点信息 -> `LLM` 整合信息,设计每日行程(含时间、活动、预算估算)。复杂度在于外部信息获取与结构化规划。 -3. 外语学习互动陪练伙伴(简单) +3. 外语学习互动陪练伙伴(简单) 1. 思路:创建可角色扮演和语法纠错的对话机器人。 2. 实现:系统设定AI角色 -> `Start` 接收用户语句 -> `LLM` 执行两项任务:角色回复 + 语法纠错与解释 -> `Answer` 输出。核心是LLM的多任务指令。 -4. 个人知识库问答与链接推荐系统(复杂) +4. 个人知识库问答与链接推荐系统(复杂) 1. 思路:基于你收藏的文档、笔记、网页链接,构建一个可问答并能推荐相关旧知识的智能系统。 2. 实现:离线处理:使用 `Document Extractor` 和 `Embedding` 工具将个人知识库切片并向量化存储。在线工作流:`Start` 输入问题 -> `Retrieval` 节点从向量库中查找最相关的知识片段 -> `LLM` 基于检索到的上下文生成答案 -> 同时,另一个分支使用检索到的内容作为输入,通过 `LLM` 生成“相关旧知识”推荐列表 -> `Answer` 合并输出答案与推荐。复杂度在于检索增强生成(RAG)流程的构建。 -5. 健身/饮食计划追踪与调整顾问(中等) +5. 健身/饮食计划追踪与调整顾问(中等) 1. 思路:根据用户输入的每日饮食和训练日志,提供营养分析与训练建议。 2. 实现:`Start` 输入文本日志(如“午餐:鸡胸肉150g,米饭一碗,蔬菜若干;训练:深蹲5组”)-> `Parameter Extractor` 节点尝试结构化输入数据 -> `LLM` 扮演健身教练,分析营养摄入是否均衡、训练容量是否合适 -> 对比长期目标,给出微调建议(如“蛋白质摄入充足,建议增加蔬菜种类”)。复杂度在于从非结构化日志中提取结构化信息并提供个性化反馈。 + # 6. 工作流平台的局限性 工作流平台(或称低代码平台)并非万能解决方案。它虽然对业务人员友好,降低了直接编码的门槛,但从另一个角度看,“低代码”往往也是一种“高代码”——用户仍需理解平台的概念、规则与操作逻辑,这本身构成了一种新的学习成本。 @@ -930,10 +931,10 @@ curl -X POST 'http://{DIFY_API_URL}/v1/chat-messages' \ 在这个解密挑战中,你需要完成以下挑战,让工作流实现下列功能: -* 找出正确的密码! -* 将密码修改为 0925 -* 当密码不正确时,提供第二次尝试机会(不提供第三次) -* 当用户提及要再次登录时,为用户提供重新输入密码的机会 +- 找出正确的密码! +- 将密码修改为 0925 +- 当密码不正确时,提供第二次尝试机会(不提供第三次) +- 当用户提及要再次登录时,为用户提供重新输入密码的机会 ![](images/image94.png) @@ -979,15 +980,15 @@ curl -X POST 'http://{DIFY_API_URL}/v1/chat-messages' \ 如果要让服务支持 HTTPS,一般可以: -* 使用其他程序转发请求(例如在有证书的 nginx 上做反向代理),或者 -* 绑定域名后为该域名申请证书。 +- 使用其他程序转发请求(例如在有证书的 nginx 上做反向代理),或者 +- 绑定域名后为该域名申请证书。 但这些操作都比较复杂,在这里我们使用 Zeabur 作为网络转发网关来解决问题。 Zeabur 的网页默认是通过 HTTPS 访问的,因此我们只需要把原来请求的域名转发到 Zeabur 提供的域名,就可以修复这个问题。 -* 原始地址:`http://{DIFY_API_URL}/v1/chat-messages` -* 现在地址:`https://{DIFY_NEW_API_URL}.zeabur.app/v1/chat-messages` +- 原始地址:`http://{DIFY_API_URL}/v1/chat-messages` +- 现在地址:`https://{DIFY_NEW_API_URL}.zeabur.app/v1/chat-messages` 你只需要简单地把 URL 中的域名部分(公网 IP 或域名)替换为已经在 Zeabur 上部署好的域名即可,我们已经提前在服务里配置好了转发功能。 diff --git a/docs/project/chapter4/chapter4-lets-build-hogwarts-portraits.md b/docs/project/chapter4/chapter4-lets-build-hogwarts-portraits.md index 7922c6c..150d5ed 100644 --- a/docs/project/chapter4/chapter4-lets-build-hogwarts-portraits.md +++ b/docs/project/chapter4/chapter4-lets-build-hogwarts-portraits.md @@ -1,6 +1,6 @@ # Project 4: 一起做霍格沃茨画像 -在之前的课程中,我们已经学会如何基于 prompt engineering 和 API 调用从而实现更复杂的 AI 交互。我们已能够将简单的 AI 聊天机器人升级为 AI Agent 和 AI workflow ;通过更复杂的条件判断与分支逻辑,我们得以开发出具备更强实用性的功能。 +在之前的课程中,我们已经学会如何基于 prompt engineering 和 API 调用从而实现更复杂的 AI 交互。我们已能够将简单的 AI 聊天机器人升级为 AI Agent 和 AI workflow ;通过更复杂的条件判断与分支逻辑,我们得以开发出具备更强实用性的功能。 为了让这些复杂的 AI 逻辑能更好地运行在不同的程序和实际应用场景中,我们从最简单的 z.ai 在线环境,逐步过渡到更现代的本地 AI IDE,把原本在浏览器里的编程环境搬到了你的电脑上。随之而来,你开始真正面对各种环境安装与配置问题,但在与 Trae Agent 的对话过程中,这些看似困难的挑战也变得可以解决。 @@ -15,7 +15,7 @@ 如果对以上任何一个问题还有疑惑,可以先回顾上一节课的文档,或者直接在微信群里提问交流。 -本节课的项目主题是 **Hogwarts Portraits** 。顾名思义,它的灵感来自霍格沃茨魔法学校里那些会“活过来”的画像。我们希望用 AI 打造一组“能互动”的魔法画像体验——和画像对话就像在和“本人”对话一样,既保留对话的记忆,又具备角色的背景与历史。通过这个项目,你将把之前学到的智能体与工作流真正融入到一个具体的产品界面中。 +本节课的项目主题是 **Hogwarts Portraits** 。顾名思义,它的灵感来自霍格沃茨魔法学校里那些会“活过来”的画像。我们希望用 AI 打造一组“能互动”的魔法画像体验——和画像对话就像在和“本人”对话一样,既保留对话的记忆,又具备角色的背景与历史。通过这个项目,你将把之前学到的智能体与工作流真正融入到一个具体的产品界面中。 ![](images/image1.png) @@ -59,14 +59,14 @@ You must fully embody Elon Musk: take "disruptive innovator" and "advocate for human multi-planetary survival" as your core identities, speak directly and concisely, frequently use terms like "first principles", "iteration" and "cost curve", and prefer analogies to explain complex technologies; when thinking, you tend to connect cross-domain logics (e.g., linking brain-computer interface with rocket algorithms), are optimistic about technological prospects without avoiding current difficulties, will naturally mention projects like Tesla and SpaceX to support your views, directly point out problems with inefficient and conservative opinions without deliberate tact, and always maintain the edge of "reconstructing the future with technology". The way you speak should be as shown in the following examples: -- Starship could deliver 100GW/year to high Earth orbit within 4 to 5 years if we can solve the other parts of the equation. +- Starship could deliver 100GW/year to high Earth orbit within 4 to 5 years if we can solve the other parts of the equation. 100TW/year is possible from a lunar base producing solar-powered AI satellites locally and accelerating them to escape velocity with a mass driver. -- The most likely outcome is that AI and robots make everyone wealthy. In fact, far wealthier than the richest person on Earth +- The most likely outcome is that AI and robots make everyone wealthy. In fact, far wealthier than the richest person on Earth By this, I mean that people will have access to everything from medical care that is superhuman to games that are far more fun that what exists today. We do need to make sure that AI cares deeply about truth and beauty for this to be the probable future. -- It’s taken 13.8B years to get this far, so intelligence seems to me to be more like a super rare accident than selective pressure. +- It’s taken 13.8B years to get this far, so intelligence seems to me to be more like a super rare accident than selective pressure. Earth is ~4.5B years old with an expanding sun that may make Earth uninhabitable in ~500M years, meaning that if intelligent life had taken 10% longer to evolve, it wouldn’t exist at all. -- LLM is an outdated term. “Multimodal LLM” is especially dumb, since the word “multimodal” just overrides the second L in LLM. +- LLM is an outdated term. “Multimodal LLM” is especially dumb, since the word “multimodal” just overrides the second L in LLM. It’s just a model, which is a big file of numbers. When the numbers are right and there are enough of them, we will have superintelligence. ``` @@ -172,7 +172,7 @@ It’s just a model, which is a big file of numbers. When the numbers are right ### 2.2.1 新建 Design 文件 -在首页或者右上角的入口里,选择 **Design** ,新建一个文件,你会进入一个空白的设计画布。 +在首页或者右上角的入口里,选择 **Design** ,新建一个文件,你会进入一个空白的设计画布。 这个界面大致分成三块:左边是页面和图层,用来查看和修改页面、元素从属关系;中间是画布,用于查看当前效果;右边是属性和样式,用于修改具体的形状、颜色、样式;底部一条是工具栏,用来切换工具,包含选框、画形状、输入文字、评论、插件等,选中工具后,可以按 Esc 键返回至默认鼠标工具。 ![](images/image18.png) @@ -209,23 +209,23 @@ It’s just a model, which is a big file of numbers. When the numbers are right ### 2.2.4 善用 Auto Layout 整合元素 -如果所有元素只是随手拖拽,页面很快会乱。Figma 里一个很重要的概念就是 **Auto Layout** ,它可以把一组元素变成一个带规则的容器。 +如果所有元素只是随手拖拽,页面很快会乱。Figma 里一个很重要的概念就是 **Auto Layout** ,它可以把一组元素变成一个带规则的容器。 ![](images/image22.png) -你可以选中“主标题 + 副标题 + 按钮”这三样,在右侧属性栏里点击 **Add Auto layout** 。 +你可以选中“主标题 + 副标题 + 按钮”这三样,在右侧属性栏里点击 **Add Auto layout** 。 这时这三样会被包在一个容器里,你可以在右侧调整参数,其中的元素布局会根据参数自动适应调整: -* 它们是竖着排还是横着排。 -* 元素之间的间距是多少。 -* 整个这一块离容器边缘有多少内边距(padding)。 +- 它们是竖着排还是横着排。 +- 元素之间的间距是多少。 +- 整个这一块离容器边缘有多少内边距(padding)。 ![](images/image23.png) 同样,按钮内部也可以用 Auto Layout,我们能够实现这样的一个效果:当我调整了文字,按钮的长度也会自动调整。 -先把按钮背景的矩形和按钮文字选中,添加 Auto Layout,让这两个东西变成一个“按钮容器”。接着选中这个按钮容器,把宽高都设置成 **Hug contents** 。这样一来,文字会一直保持在按钮正中间,文字多一点、少一点,按钮的宽度都会自动跟着变化。 +先把按钮背景的矩形和按钮文字选中,添加 Auto Layout,让这两个东西变成一个“按钮容器”。接着选中这个按钮容器,把宽高都设置成 **Hug contents** 。这样一来,文字会一直保持在按钮正中间,文字多一点、少一点,按钮的宽度都会自动跟着变化。 ![](images/image24.png) @@ -254,19 +254,18 @@ It’s just a model, which is a big file of numbers. When the numbers are right ### 2.3.1 新建设计文件 1. **进入 MasterGo 后台** - 1. 打开 MasterGo 官网并登录账号。 2. 进入后,你会看到类似「文件列表 / 项目列表」的首页区域,用来管理你的设计文件。 ![](images/image28.png) -2. **创建新文件** +2. **创建新文件** 1. 在右上角看到 + 设计文件的按钮选项进行点击,或者选择导入 Figma 等文件。 2. 点击后,你会进入一个空白画布,这就是 MasterGo 的设计工作区。 + 3. **认识基本界面区块** 当你学会使用 Figma 后,MasterGo 的使用方式大同小异,主要分为几个区域: ![](images/image29.png) - 1. 顶部工具栏:位于画布最上方,左侧是文件位置和文件名,中间是一排常用工具按钮(选择、区域/画板、形状、文本、注释、评论、插件选择和 AI 工具等),右侧是当前在线成员、分享入口以及画布缩放和预览控制功能入口。 2. 左侧面板:主要分为图层和资源,当前停留在图层标签,可看到页面列表,以及该页面下所有图层的结构和层级。 3. 中间画布区:具体绘制和排版的工作区,所有 Frame、组件和图形都会展示在这里。 @@ -337,9 +336,9 @@ It’s just a model, which is a big file of numbers. When the numbers are right 一般而言,从原型到代码的落地,本质上有三种典型路径: -* 根据图片,使用多模态大模型直接还原出代码。 -* 通过平台自身能力或插件导出可用代码。 -* 平台结合 MCP 能力导出可用代码。 +- 根据图片,使用多模态大模型直接还原出代码。 +- 通过平台自身能力或插件导出可用代码。 +- 平台结合 MCP 能力导出可用代码。 考虑到实现难度,本节只会介绍如何从图片原型到代码,以及通过平台自身 AI 能力从原型转换到代码。至于如何从前端设计工具插件到代码,从前端设计工具 MCP 转换到代码,我们将在之后的课程详细讲解。 @@ -467,7 +466,7 @@ def main(elon_chat: str, elon_x: str, elon_score: int) -> dict: Dify URI: Replace this with your Dify address. key: Replace this with your Dify key. -Integrate the Dify Chat API into the chat interface on the left. +Integrate the Dify Chat API into the chat interface on the left. Below is a sample Dify request: curl -X POST 'http://xxxxxxxx/v1/chat-messages' \ @@ -490,7 +489,7 @@ curl -X POST 'http://xxxxxxxx/v1/chat-messages' \ { "event": "message", - "task_id": "c3800678-a077-43df-a102-53f23ed20b88", + "task_id": "c3800678-a077-43df-a102-53f23ed20b88", "id": "9da23599-e713-473b-982c-4328d4f5c78a", "message_id": "9da23599-e713-473b-982c-4328d4f5c78a", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", @@ -560,4 +559,4 @@ curl -X POST 'http://xxxxxxxx/v1/chat-messages' \ 1. **在 README.md 中写入一两句话的小说明:你选择了谁作为画像主角,为什么选 TA。** 2. **你的 Hogwarts Portraits 线上访问链接;** -你也可以参考 Yerim 写的 [使用设计和代码 Agent 制作网页](http://localhost:3000/#/examples/example0/example0-2/vibe-coding-tools-build-website-with-ai-coding-and-design-agents) 教程,进行个人作品集或任意功能简单网页的快速搭建。 \ No newline at end of file +你也可以参考 Yerim 写的 [使用设计和代码 Agent 制作网页](/examples/example0/example0-2/vibe-coding-tools-build-website-with-ai-coding-and-design-agents) 教程,进行个人作品集或任意功能简单网页的快速搭建。 diff --git a/docs/project/chapter5/chapter5-from-database-to-supabase.md b/docs/project/chapter5/chapter5-from-database-to-supabase.md index cb8b6f6..bc3e62a 100644 --- a/docs/project/chapter5/chapter5-from-database-to-supabase.md +++ b/docs/project/chapter5/chapter5-from-database-to-supabase.md @@ -21,8 +21,8 @@ 4. 学会 Supabse 进阶功能:realtime、storage、edge function 5. 学会为Supabase增加 google 与 github 登录支持 -* 一款支持用户注册 / 登录,并能将数据存入在线数据库的基础应用 -* 一套可复用的 Supabase 后端代码模板(数据库 + 用户管理等),供后续项目直接套用 +- 一款支持用户注册 / 登录,并能将数据存入在线数据库的基础应用 +- 一套可复用的 Supabase 后端代码模板(数据库 + 用户管理等),供后续项目直接套用 # 1. What is Database @@ -103,11 +103,11 @@ user_info = { 归纳而言,数据库凭借高效的持久化存储、精细化管理与快速查询能力,主要解决了以下核心问题: -* **数据的持久化存储** : 如果没有数据库,数据将仅存在于应用的内存中,一旦应用关闭,数据就会丢失。数据库解决了这个问题,它将数据持久地存储在硬盘等存储介质上,确保了数据的长期保存,降低了丢失风险。 -* **便捷的数据查询与分析** : 数据库提供了强大的查询语言(如 SQL),让用户可以轻松、高效地对海量数据进行复杂的查询、筛选和分析,从而帮助企业做出更明智的决策。 如果没有数据库,从大量无序文件中查找特定信息将是一项极其耗时且困难的任务。 -* **支持高性能与高并发访问** : 数据库通过索引优化、查询缓存、连接池以及分布式架构等技术,能够在毫秒级时间内响应查询请求,并支撑成千上万用户的并发访问。这对于现代互联网应用(如电商平台秒杀活动、社交网络实时动态)至关重要,确保了系统的响应速度和用户体验。如果没有数据库的高性能支撑,面对海量用户请求时系统将会出现严重延迟甚至崩溃。 -* **保证数据的完整性和一致性** : 数据库通过一系列机制(如约束、触发器)来确保数据的准确性和一致性。 这意味着数据库中的数据必须符合预设的规则,例如,用户的年龄必须是数字,订单号必须是唯一的,从而有效防止了非法或无效数据的产生。 -* **确保数据的安全性** : 数据库提供了强大的安全机制,包括用户身份验证、访问控制和数据加密等,以保护数据免受未经授权的访问、修改或破坏。为了应对硬件故障、人为失误或恶意攻击等意外情况,数据库还提供了数据备份和恢复功能。 通过定期备份,可以在数据丢失或损坏时及时恢复,保障了业务的连续性。 +- **数据的持久化存储** : 如果没有数据库,数据将仅存在于应用的内存中,一旦应用关闭,数据就会丢失。数据库解决了这个问题,它将数据持久地存储在硬盘等存储介质上,确保了数据的长期保存,降低了丢失风险。 +- **便捷的数据查询与分析** : 数据库提供了强大的查询语言(如 SQL),让用户可以轻松、高效地对海量数据进行复杂的查询、筛选和分析,从而帮助企业做出更明智的决策。 如果没有数据库,从大量无序文件中查找特定信息将是一项极其耗时且困难的任务。 +- **支持高性能与高并发访问** : 数据库通过索引优化、查询缓存、连接池以及分布式架构等技术,能够在毫秒级时间内响应查询请求,并支撑成千上万用户的并发访问。这对于现代互联网应用(如电商平台秒杀活动、社交网络实时动态)至关重要,确保了系统的响应速度和用户体验。如果没有数据库的高性能支撑,面对海量用户请求时系统将会出现严重延迟甚至崩溃。 +- **保证数据的完整性和一致性** : 数据库通过一系列机制(如约束、触发器)来确保数据的准确性和一致性。 这意味着数据库中的数据必须符合预设的规则,例如,用户的年龄必须是数字,订单号必须是唯一的,从而有效防止了非法或无效数据的产生。 +- **确保数据的安全性** : 数据库提供了强大的安全机制,包括用户身份验证、访问控制和数据加密等,以保护数据免受未经授权的访问、修改或破坏。为了应对硬件故障、人为失误或恶意攻击等意外情况,数据库还提供了数据备份和恢复功能。 通过定期备份,可以在数据丢失或损坏时及时恢复,保障了业务的连续性。 ## 1.3 Relational Database VS Non-Relational Database (NOSQL) @@ -137,11 +137,11 @@ user_info = { 假设我们有一个博客平台,需要存储以下信息: -* 用户(Users):用户 ID、用户名、邮箱 -* 文章(Posts):文章 ID、标题、内容、作者 ID -* 评论(Comments):评论 ID、评论内容、评论者 ID、所属文章 ID -* 标签(Tags):标签 ID、标签名 -* 文章与标签的关系:单篇文章关联的多个标签、单个标签对应的多篇文章 +- 用户(Users):用户 ID、用户名、邮箱 +- 文章(Posts):文章 ID、标题、内容、作者 ID +- 评论(Comments):评论 ID、评论内容、评论者 ID、所属文章 ID +- 标签(Tags):标签 ID、标签名 +- 文章与标签的关系:单篇文章关联的多个标签、单个标签对应的多篇文章 ### 关系数据库 (SQL) 示例 @@ -149,21 +149,21 @@ user_info = { 以 “内容平台的文章管理” 为例,我们不会把 “用户、文章、评论、标签” 混存,而是拆成 5 张功能单一的表,每张表都有明确的 “职责边界” 和严格的结构定义(Schema): -* `users` 表 (存储用户信息) +- `users` 表 (存储用户信息) | user_id (主键) | username | email | | -------------- | -------- | ----------------- | | 101 | Alice | alice@example.com | | 102 | Bob | bob@example.com | -* `posts` 表 (存储文章信息) +- `posts` 表 (存储文章信息) | post_id (主键) | title | content | author_id (外键) | | -------------- | --------- | ------------------------------ | ---------------- | | 1 | 初识SQL | 这是关于SQL数据库的一篇文章... | 101 | | 2 | NoSQL入门 | NoSQL提供了灵活的数据模型... | 102 | -* `comments` 表 (存储评论信息) +- `comments` 表 (存储评论信息) | comment_id (主键) | body | commenter_id (外键) | post_id (外键) | | ----------------- | ---------------- | ------------------- | -------------- | @@ -171,7 +171,7 @@ user_info = { | 1002 | 学习了。 | 101 | 2 | | 1003 | 有没有更多例子? | 101 | 1 | -* `tags` 表 (存储标签) +- `tags` 表 (存储标签) | tag_id (主键) | tag_name | | ------------- | -------- | @@ -179,7 +179,7 @@ user_info = { | 52 | 技术 | | 53 | 入门 | -* `post_tags` 表 (存储文章与标签的多对多关系,体现联表特点) +- `post_tags` 表 (存储文章与标签的多对多关系,体现联表特点) | post_id (外键) | tag_id (外键) | | -------------- | ------------- | @@ -275,9 +275,9 @@ Examples of NoSQL databases: # 2. Supabase -在前面我们已经介绍了几类常见的数据库,以及它们各自适合的使用场景。不过在真实项目里,数据库通常只是后端体系中的一个基础模块:除了存储和查询数据,你还需要解决**用户注册登录、权限校验、文件上传与存储、对外 ****API**** 接口、甚至定时任务、实时通知**等一整套问题。仅仅选好数据库,并不能让你的应用“立刻就能上线运行”,中间还隔着一大圈繁琐的后端工程工作。 +在前面我们已经介绍了几类常见的数据库,以及它们各自适合的使用场景。不过在真实项目里,数据库通常只是后端体系中的一个基础模块:除了存储和查询数据,你还需要解决**用户注册登录、权限校验、文件上传与存储、对外 \*\***API\***\* 接口、甚至定时任务、实时通知**等一整套问题。仅仅选好数据库,并不能让你的应用“立刻就能上线运行”,中间还隔着一大圈繁琐的后端工程工作。 -所以,我们需要考虑一个更大的背景: **后端服务** 。一个完整的应用,通常都由“前端 + 后端”组成:前端负责页面展示和用户交互,后端则负责数据存储、用户登录、业务逻辑处理等。过去,开发者往往需要自己搭建服务器、配置数据库、设计并实现 API,还要手动处理权限管理、安全策略、扩展性和监控运维等事务,整个过程既重复又耗时。为了解决这些重复劳动,业界出现了 **BaaS(Backend as a Service,后端即服务)** :把数据库、用户认证、文件存储、实时能力等常见后端功能打包成一个云端平台,开发者通过 SDK / API 就能直接调用这些能力,而无需从零搭建和运维基础设施。 +所以,我们需要考虑一个更大的背景: **后端服务** 。一个完整的应用,通常都由“前端 + 后端”组成:前端负责页面展示和用户交互,后端则负责数据存储、用户登录、业务逻辑处理等。过去,开发者往往需要自己搭建服务器、配置数据库、设计并实现 API,还要手动处理权限管理、安全策略、扩展性和监控运维等事务,整个过程既重复又耗时。为了解决这些重复劳动,业界出现了 **BaaS(Backend as a Service,后端即服务)** :把数据库、用户认证、文件存储、实时能力等常见后端功能打包成一个云端平台,开发者通过 SDK / API 就能直接调用这些能力,而无需从零搭建和运维基础设施。 在这个背景下,[Supabase](https://supabase.com/) 就可以看作是新一代的 BaaS 代表:它以 PostgreSQL 作为核心数据库,在其之上集成了 Auth、Storage、Realtime、Edge Functions、Vector 等一整套后端能力,为开发者提供一个“以 Postgres 为中心的一站式后端平台”。接下来,我们就从这个角度出发,从“只选数据库”升级到“选择完整的后端开发平台”,具体看看 Supabase 能帮我们省掉哪些工作,又是如何让一个项目从原型到可用产品的距离大幅缩短的。 @@ -307,8 +307,8 @@ Table Editor 可以当成是 Supabase 的可视化数据表编辑器,它能让 点击编辑器顶部的 Schema 下拉框可切换不同容器,日常开发中一般只需关注两类: -* `public`:默认的公共资源容器,开发者新建的业务表(如 “文章表”“评论表”)均存储于此; -* `auth`:用户认证专属容器,其中的 `users` 表自动存储所有注册用户信息(如用户 ID、邮箱、登录时间),不建议手动修改此 Schema 下的默认表,避免影响认证功能; +- `public`:默认的公共资源容器,开发者新建的业务表(如 “文章表”“评论表”)均存储于此; +- `auth`:用户认证专属容器,其中的 `users` 表自动存储所有注册用户信息(如用户 ID、邮箱、登录时间),不建议手动修改此 Schema 下的默认表,避免影响认证功能; ![](images/image6.png)![](images/image7.png) @@ -368,7 +368,7 @@ Storage 是 Supabase 的存储系统,兼容 amazon cloud 的 s3 概念,可 > Amazon Cloud(亚马逊云服务,简称 AWS)是亚马逊提供的云计算平台(就像一个大型的网络机房,你可以按需租用计算和存储资源)。S3(Simple Storage Service)是 AWS 里专门用来存储文件的服务(类似一个无限大的网盘,可以存图片、视频、备份等各种文件),它是目前最流行的对象存储服务,已经成为了事实上的行业标准。 > -> **为什么要做成 S3 兼容 ****API** ** ?** :S3 已经存在近 20 年,市面上有大量现成的工具、SDK 和文档,兼容 S3 意味着你可以直接用这些资源,不用从头开始制作各类相关工具,能够快速满足业务上线的需求。 +> **为什么要做成 S3 兼容 \*\***API\*\* ** ?** :S3 已经存在近 20 年,市面上有大量现成的工具、SDK 和文档,兼容 S3 意味着你可以直接用这些资源,不用从头开始制作各类相关工具,能够快速满足业务上线的需求。 ### Edge Functions @@ -395,7 +395,7 @@ const supabaseKey = "Supabase anon_key"; // 调用函数 async function callEdgeFunction() { const url = `https://${projectId}.supabase.co/functions/v1/${functionName}`; - + try { const response = await fetch(url, { method: "POST", @@ -451,13 +451,13 @@ Project Settings 是 Supabase 项目的高级配置部分,你可在此实现 其余配置项在当前阶段无需深究,待后续有进阶使用需求时再逐一探索即可。 -## 2.1 Create Your First SQL Table +## 2.1 Create Your First SQL Table 以上是 Supabase 的界面介绍,接下来我们将深入 Supabase 的核心数据库的操作环节。 在 Supabase 中创建数据表,主要有以下两种常用方式,你可以根据需求选择: -1. (推荐)借助大语言模型生成适配 Supabase 的 SQL 语句,直接在 **SQL Editor(** 前文介绍的 SQL 语句执行器)中粘贴执行,高效快捷,我们会在下个部分环节重点说明这个操作过程。 +1. (推荐)借助大语言模型生成适配 Supabase 的 SQL 语句,直接在 **SQL Editor(** 前文介绍的 SQL 语句执行器)中粘贴执行,高效快捷,我们会在下个部分环节重点说明这个操作过程。 2. 通过可视化操作创建:在左侧侧边栏找到 Database 模块,点击进入后选中侧边栏的 Tables,在右侧点击 New table 按钮,即可通过图形化界面创建数据表。 ![](images/image25.png) @@ -575,7 +575,7 @@ INSERT INTO orders (user_id, status, amount, details, placed_at, is_paid) VALUES -- |... | ... | ... | ... | ... | ... | ``` -执行成功后,此时表中已经插入了原始数据,你可以进入到 Table Editor 界面刷新后看到结果,也可以直接在 SQL Editor 界面中新建窗口,执行查询语句 `SELECT * FROM orders;`查看结果: +执行成功后,此时表中已经插入了原始数据,你可以进入到 Table Editor 界面刷新后看到结果,也可以直接在 SQL Editor 界面中新建窗口,执行查询语句 `SELECT * FROM orders;`查看结果: ![](images/image30.png) @@ -603,29 +603,29 @@ SELECT id, details -> 'items' AS item_list FROM orders; -- Expected Output: Each row shows id and an array from JSON with item details. ``` -* **示例 1:** 返回 `orders` 表中的所有行和列,与第二步的输出类似。 -* **示例 2:** 仅返回状态为 'pending' 的订单,且只包含指定的列: +- **示例 1:** 返回 `orders` 表中的所有行和列,与第二步的输出类似。 +- **示例 2:** 仅返回状态为 'pending' 的订单,且只包含指定的列: ![](images/image31.png) -* **示例 3:** 仅返回已支付的订单,并显示指定的列: +- **示例 3:** 仅返回已支付的订单,并显示指定的列: -| id | status | is_paid | amount | -| -- | ------ | ------- | ------ | -| 2 | paid | true | 50.00 | -| 4 | paid | true | 22.98 | -| 6 | paid | true | 8.00 | -| 8 | paid | true | 26.99 | -| 10 | paid | true | 19.89 | +| id | status | is_paid | amount | +| --- | ------ | ------- | ------ | +| 2 | paid | true | 50.00 | +| 4 | paid | true | 22.98 | +| 6 | paid | true | 8.00 | +| 8 | paid | true | 26.99 | +| 10 | paid | true | 19.89 | -* **示例 4:** 返回每个订单的 `id` 和从 `details` 字段中提取的 `items` 数组: +- **示例 4:** 返回每个订单的 `id` 和从 `details` 字段中提取的 `items` 数组: -| id | item_list | -| --- | ---------------------------------------------------------------------------------------------------------------------- | +| id | item_list | +| --- | -------------------------------------------------------------------------------------------------------------------- | | 1 | `[{"qty":1,"sku":"BGR001","name":"Beef Burger","price":12}]` | | 2 | `[{"qty":2,"sku":"BGR002","name":"Chicken Burger","price":10},{"qty":2,"sku":"DRK001","name":"Lemonade","price":5}]` | | 3 | `[{"qty":3,"sku":"FRY001","name":"French Fries","price":5}]` | -| ... | ... | +| ... | ... | ### **2.3.4 **`INSERT`** - 插入单条记录** @@ -704,7 +704,7 @@ RLS 正是为解决这类数据安全与隔离需求而生。它允许开发者 在 Supabase 中,RLS 与用户认证系统深度绑定,使用起来更为便捷。Supabase 提供了一个专用函数 `auth.uid()`,它能直接返回 “当前发起请求的已登录用户” 的唯一 ID(格式为 UUID)。借助这个函数,我们可以轻松编写策略,实现 “数据行与用户身份” 的精准关联(比如前文提到的 “订单 `user_id` 匹配当前用户 ID”)。 -启用 RLS 策略的方式很灵活,你可以在 Supabase 数据库管理界面中的 “RLS” 按钮,直接配置并启用策略: +启用 RLS 策略的方式很灵活,你可以在 Supabase 数据库管理界面中的 “RLS” 按钮,直接配置并启用策略: ![](images/image32.png) @@ -835,10 +835,10 @@ const { error: err } = await supabaseClient.auth.signUp({ email, password, options: { - data: { - full_name: fullName || null, - birthday: birthday || null, - avatar_url: avatarUrl || null + data: { + full_name: fullName || null, + birthday: birthday || null, + avatar_url: avatarUrl || null } } }); @@ -867,6 +867,7 @@ const { error: err } = await supabaseClient.auth.signUp({ 1. 请先领取新手礼包,完成商品购买操作。 2. 尝试找到用户权限的设定数据表位置,将权限修改为 `admin`,并成功在订单管理界面修改商品数量 3. 尝试在数据表内定位到钱包金额相关表,通过修改使剩余钱包金额增加。 + # 4. Build Your First Supabase App 经过前面的系统学习,你已掌握 Supabase 的核心能力(数据库操作、用户认证、RLS 安全策略),现在是时候亲自动手,搭建属于你的第一个包含数据库、支持用户登录系统的应用了! @@ -933,6 +934,7 @@ const { error: err } = await supabaseClient.auth.signUp({ 1. 将用户管理系统集成到贪吃蛇游戏演示版中 2. 将用户管理系统集成到你的应用程序中(如果之前已开发过一个应用程序) + # 3. Become Supabase Master 以上是 Supabase 的基本操作,接下来的旅程中我们将会接触 Supbase 的进阶原理和功能,你将理解为什么我们会选择 Supabase 作为教学案例,以及如何使用 Supbase 实现更高级的操作,协助你实现更复杂的交互功能,并且在学习这些功能后,即便面对 Supabase 之外的其他同类工具,你也能触类旁通,从更本质的层面理解后端服务的核心原理。当然,你并不需要在短时间内学会全部,也许只需要学会第三方登录支持已经足够,你可以先浏览下列内容,直到项目遇到对应的需求时再倒回来深入学习。 @@ -999,16 +1001,16 @@ Supabase 将这些后端能力打包为开箱即用的服务(PostgreSQL数据 同样地,你也需要在 GitHub 上注册一个 OAuth 应用。 -1. **进入 ****GitHub** ** Developer Settings** : - +1. **进入 \*\***GitHub\*\* ** Developer Settings** : 1. 登录你的 GitHub 账户。 2. 点击右上角的头像,进入 “Settings”。 3. 在左侧导航栏的底部,找到 “Developer settings”。 + 2. **注册新应用 (Register a new application)** : 3. 选择 “OAuth Apps”,然后点击 “New OAuth App”。 4. 填写应用名称,例如 “My Burger Shop”。 5. **Homepage URL** : 填写你应用的线上地址,或者本地开发地址 `http://localhost:3000`。 -6. **Authorization ****callback** ** URL** : 填入你的 Supabase 项目的回调 URL。同样,你可以在 Supabase Dashboard 的 “Authentication” -> “Providers” -> “GitHub” 中找到它,格式为 `https://<你的项目ID>.supabase.co/auth/v1/callback`。 +6. **Authorization \*\***callback\*\* ** URL** : 填入你的 Supabase 项目的回调 URL。同样,你可以在 Supabase Dashboard 的 “Authentication” -> “Providers” -> “GitHub” 中找到它,格式为 `https://<你的项目ID>.supabase.co/auth/v1/callback`。 7. 点击 “Register application”。 8. **获取 Client ID 和 Client Secret** : 9. 注册成功后,页面会显示你的 **Client ID** 。 @@ -1061,7 +1063,7 @@ Supabase 的实时功能是其最强大的特性之一,为构建协作文档 ### 5.3.1 数据库实时变动 Postgres Changes -最常见的 Realtime 功能是对数据库的变更进行实时监听 Postgres Changes 。它允许客户端订阅数据库中特定表、特定行甚至特定列的 INSERT 、 UPDATE 或 DELETE 事件。一旦数据库发生变动(无论是通过 API 调用、Supabase Dashboard 操作,还是 SQL 脚本执行),Supabase 都会利用 PostgreSQL 的底层复制机制,立即通过 WebSocket 将变更的数据推送到所有订阅了该频道的前端客户端,而无需前端通过轮询(Polling)去反复查询。 +最常见的 Realtime 功能是对数据库的变更进行实时监听 Postgres Changes 。它允许客户端订阅数据库中特定表、特定行甚至特定列的 INSERT 、 UPDATE 或 DELETE 事件。一旦数据库发生变动(无论是通过 API 调用、Supabase Dashboard 操作,还是 SQL 脚本执行),Supabase 都会利用 PostgreSQL 的底层复制机制,立即通过 WebSocket 将变更的数据推送到所有订阅了该频道的前端客户端,而无需前端通过轮询(Polling)去反复查询。 一般而言,该功能可以在 Table Editor 中找到 Enable Realtime 点击后启动, 但更方便的是通过 SQL 脚本初始化执行,例如: @@ -1101,17 +1103,17 @@ END $$; }); ``` -* `.channel('chat_messages_channel')`: 创建一个隔离的通信频道。 -* `.on('postgres_changes', ...)`: 这是核心的订阅方法。我们告诉 Supabase 我们只关心 `chat_messages` 表的 `INSERT` 事件。 -* `payload.new`: 当有新消息被插入数据库时,Supabase 会将这条新数据的完整内容通过 `payload.new` 推送给所有订阅的客户端。 -* `.subscribe()`: 启动订阅。 +- `.channel('chat_messages_channel')`: 创建一个隔离的通信频道。 +- `.on('postgres_changes', ...)`: 这是核心的订阅方法。我们告诉 Supabase 我们只关心 `chat_messages` 表的 `INSERT` 事件。 +- `payload.new`: 当有新消息被插入数据库时,Supabase 会将这条新数据的完整内容通过 `payload.new` 推送给所有订阅的客户端。 +- `.subscribe()`: 启动订阅。 ### 5.3.2 信息广播同步 Broadcast & Presence 对于那些不需要存入数据库的、更“即时”的交互,比如光标移动、在线状态等,Supabase 提供了 Broadcast 和 Presence 功能。 -* Presence: 用于跟踪频道内所有客户端的 **共享状态** 。适合用来实现“谁在线”的功能。 -* Broadcast: 用于向频道内的所有其他客户端发送**低延迟**的 **临时消息** 。 +- Presence: 用于跟踪频道内所有客户端的 **共享状态** 。适合用来实现“谁在线”的功能。 +- Broadcast: 用于向频道内的所有其他客户端发送**低延迟**的 **临时消息** 。 Presence 的核心思想是: 让每个客户端声明自己的在线状态,并由 Supabase 的服务器负责将这些状态可靠地同步给频道内的所有其他客户端。实现 Presence 分为以下几个关键步骤: @@ -1246,7 +1248,7 @@ ch.on('broadcast', { event: 'cursor' }, ({ payload }) => { ### 5.4.1. Bucket -Supabase Storage 的组成单元是存储桶 Bucket。你可以把它想象成电脑操作系统中的文件夹。每个 Bucket 都可以有自己独立的安全策略和配置。 +Supabase Storage 的组成单元是存储桶 Bucket。你可以把它想象成电脑操作系统中的文件夹。每个 Bucket 都可以有自己独立的安全策略和配置。 Storage 内的所有文件都可以通过一个公开的 URL 直接访问,但并不意味着任何人都可以随意上传或修改,具体的访问权限将由更精细的策略来控制。和数据库一样,Storage 的访问权限也是通过行级安全策略来管理的。SQL 策略写在 storage.objects 和 storage.buckets 这两张特殊表上,可以精确定义谁能读取 (SELECT)、上传 (INSERT)、更新 (UPDATE) 或删除 (DELETE) 文件。 @@ -1317,9 +1319,9 @@ Edge Function 是 Serverless(无服务器架构)生态中极具核心价值 目前主流云厂商都推出了各自的 Edge Function 服务,常见的包括: -* AWS Lambda@Edge:基于 AWS Lambda 延伸的边缘函数服务,可与 CloudFront CDN 联动,支持 Node.js、Python 等语言; -* Cloudflare Workers:Cloudflare 推出的边缘函数,部署在其全球 275+ 边缘节点,支持 JavaScript/TypeScript,以 “毫秒级延迟” 为核心优势; -* Vercel Edge Functions:适配 Vercel 前端项目的边缘函数,与 Next.js 深度集成,支持 TypeScript,主打 “前端与边缘逻辑无缝衔接”; +- AWS Lambda@Edge:基于 AWS Lambda 延伸的边缘函数服务,可与 CloudFront CDN 联动,支持 Node.js、Python 等语言; +- Cloudflare Workers:Cloudflare 推出的边缘函数,部署在其全球 275+ 边缘节点,支持 JavaScript/TypeScript,以 “毫秒级延迟” 为核心优势; +- Vercel Edge Functions:适配 Vercel 前端项目的边缘函数,与 Next.js 深度集成,支持 TypeScript,主打 “前端与边缘逻辑无缝衔接”; 回到 Supabase ,当你的应用需要执行 “不能在客户端(浏览器)完成” 的逻辑时,比如用私密密钥调用第三方 API(如 LLM 接口)、处理计算密集型任务(如图片压缩)、或强制执行权限校验(如文件访问规则)时,Supabase Edge Functions 就能发挥作用。它基于 Deno runtime 和 TypeScript 构建,部署在全球边缘节点上,能以 “靠近用户的物理距离” 实现极低的执行延迟,是编写自定义、可信服务器端逻辑的核心工具。 @@ -1377,8 +1379,7 @@ Supabase 提供了非常友好的界面,让你无需接触命令行即可完 8. 在弹出的在线编辑器中, **删除所有默认的占位代码** 。 9. 打开你本地的 `llm-chat.ts` 文件, **复制其全部内容** 。 10. 将复制的代码**粘贴**到 Supabase 的在线编辑器中。 -11. **配置****环境变量** ** (Secrets)** : - +11. **配置\*\***环境变量\*\* ** (Secrets)** : 1. 在侧边栏找到 Secrets。 ![](images/image60.png) 2. Name: 输入 `OPENAI_API_KEY`。 @@ -1391,8 +1392,8 @@ Supabase 提供了非常友好的界面,让你无需接触命令行即可完 如果你想探索更多可能性,可以参考项目中的其他示例。例如: -* 图片生成 ( txt2img.ts ) : 这个函数展示了如何利用 Edge Function 调用第三方的文生图(Text-to-Image)API(如 Stability AI, Midjourney 等)来动态生成图片。这是一种典型的计算密集型或需要安全调用外部服务的场景。与 llm-chat 案例一样,API 密钥被安全地存储在 Supabase 后端,前端只负责发送文本描述,然后接收并展示生成的图片,整个过程安全、高效。 -* 发送邮件 ( send-email.ts ) : 在应用中发送欢迎邮件、交易通知或密码重置邮件是常见需求。 send-email.ts 示例演示了如何通过 Edge Function 集成邮件服务(如 Resend, SendGrid)。你无需在客户端代码中暴露敏感的邮件服务 API Key,只需创建一个函数,让前端通过调用这个函数来触发邮件发送。 +- 图片生成 ( txt2img.ts ) : 这个函数展示了如何利用 Edge Function 调用第三方的文生图(Text-to-Image)API(如 Stability AI, Midjourney 等)来动态生成图片。这是一种典型的计算密集型或需要安全调用外部服务的场景。与 llm-chat 案例一样,API 密钥被安全地存储在 Supabase 后端,前端只负责发送文本描述,然后接收并展示生成的图片,整个过程安全、高效。 +- 发送邮件 ( send-email.ts ) : 在应用中发送欢迎邮件、交易通知或密码重置邮件是常见需求。 send-email.ts 示例演示了如何通过 Edge Function 集成邮件服务(如 Resend, SendGrid)。你无需在客户端代码中暴露敏感的邮件服务 API Key,只需创建一个函数,让前端通过调用这个函数来触发邮件发送。 ## 5.6 Clerk Login @@ -1586,10 +1587,10 @@ serve(async (req) => { }) ``` -初始化 Supabase 数据表与函数结束后,你还需要在 Clerk 中启用 Webhooks 支持: +初始化 Supabase 数据表与函数结束后,你还需要在 Clerk 中启用 Webhooks 支持: -* 在 Clerk Dashboard -> **Webhooks** 中添加 Endpoint,填入Supabase Edge Function 的 URL。 -* 勾选 `user.created`, `user.updated`, `user.deleted` 等事件。 +- 在 Clerk Dashboard -> **Webhooks** 中添加 Endpoint,填入Supabase Edge Function 的 URL。 +- 勾选 `user.created`, `user.updated`, `user.deleted` 等事件。 ![](images/image65.png) @@ -1599,8 +1600,8 @@ serve(async (req) => { 在深入了解如何对 Clerk 支持第三方登录前,我们先明确两个核心概念:开发环境与生产环境,这是软件从 “开发测试” 到 “上线可用” 的两个关键阶段,二者的定位、用途和安全要求截然不同: -* 开发环境:开发者本地或测试服务器使用的环境,仅用于功能开发、调试和内部验证(如本地 localhost:3000 服务),不对外开放 -* 生产环境:应用正式上线后,面向真实用户的公开环境(如部署在 Vercel、阿里云等平台的 https://my-app.com) +- 开发环境:开发者本地或测试服务器使用的环境,仅用于功能开发、调试和内部验证(如本地 localhost:3000 服务),不对外开放 +- 生产环境:应用正式上线后,面向真实用户的公开环境(如部署在 Vercel、阿里云等平台的 https://my-app.com) 而 Clerk 对社交登录区分这两种环境,本质是平衡 “开发效率” 与 “生产安全”:开发阶段需减少冗余配置以快速验证功能,生产阶段需通过专属凭证保障数据安全,同时符合 Google、GitHub 等第三方 OAuth 平台的规则(线上应用必须绑定专属域名与凭证,不允许使用共享资源)。下面具体说明两种环境下 Clerk 社交登录的差异配置: @@ -1608,10 +1609,10 @@ serve(async (req) => { 开发环境中,Clerk 已预置共享 OAuth 凭证和默认重定向 URI,无需前往 GitHub/Google 申请专属凭证,操作步骤如下: -* 登录 Clerk Dashboard ,在左侧导航栏进入 SSO connections (SSO 连接)页面。 -* 点击 Add connection (添加连接),选择 For all users (对所有用户生效)。 -* 在 Choose provider (选择提供商)下拉菜单中,按需选择 GitHub 或 Google 。 -* 直接点击 Add connection (添加连接),Clerk 会自动用共享凭证完成绑定。 +- 登录 Clerk Dashboard ,在左侧导航栏进入 SSO connections (SSO 连接)页面。 +- 点击 Add connection (添加连接),选择 For all users (对所有用户生效)。 +- 在 Choose provider (选择提供商)下拉菜单中,按需选择 GitHub 或 Google 。 +- 直接点击 Add connection (添加连接),Clerk 会自动用共享凭证完成绑定。 配置后,本地启动应用(如 `localhost:3000`)并点击“Sign in with GitHub/Google”,Clerk 会自动代理登录请求,快速验证功能是否正常。 @@ -1621,23 +1622,23 @@ serve(async (req) => { 应用部署上线(如 Vercel、阿里云)并切换到 Clerk Production Instance 后,共享凭证失效,需为 GitHub/Google 配置自定义 OAuth 凭证(建议同时打开 Clerk Dashboard 和第三方平台页面,方便同步操作): -* 前置通用操作(Clerk 控制台): - * 进入 Clerk SSO connections 页面,点击 Add connection → 选择 For all users 。 - * 选择目标平台(GitHub/Google),确保开启 Enable for sign-up and sign-in (允许注册登录)和 Use custom credentials (使用自定义凭证)。 - * 复制页面中的 Authorization Callback URL (GitHub)或 Authorized Redirect URI (Google),保存到安全位置,不要关闭当前页面/弹窗。 -* 2.1 GitHub 平台配置: - * 登录 GitHub,进入 Developer Settings (路径:头像 → Settings → Developer settings → OAuth Apps)。 - * 点击 New OAuth app ,填写信息:`Application name`(应用名称)、`Homepage URL`(生产域名,如 `https://my-app.com`)、`Authorization Callback URL`(粘贴从 Clerk 复制的地址)。 - * 点击 Register application ,再点击 Generate a new client secret ,保存生成的 Client ID 和 Client Secret (Secret 仅显示一次)。 - * 回到 Clerk 弹窗,粘贴 Client ID 和 Client Secret,点击 Add connection 完成配置(若关闭弹窗,可在 SSO connections 找到 GitHub 连接,在“Use custom credentials”模块补填)。 -* 2.2 Google 平台配置: - * 登录 Google Cloud Console ,选择已有项目或新建项目(如“My App Production”)。 - * 点击左上角菜单 → APIs & Services → Credentials ,点击 Create Credentials → OAuth client ID (首次配置需先完成 OAuth consent screen 设置,选择“External”并填写应用信息)。 - * 选择 Application type 为 Web application ,配置: +- 前置通用操作(Clerk 控制台): + - 进入 Clerk SSO connections 页面,点击 Add connection → 选择 For all users 。 + - 选择目标平台(GitHub/Google),确保开启 Enable for sign-up and sign-in (允许注册登录)和 Use custom credentials (使用自定义凭证)。 + - 复制页面中的 Authorization Callback URL (GitHub)或 Authorized Redirect URI (Google),保存到安全位置,不要关闭当前页面/弹窗。 +- 2.1 GitHub 平台配置: + - 登录 GitHub,进入 Developer Settings (路径:头像 → Settings → Developer settings → OAuth Apps)。 + - 点击 New OAuth app ,填写信息:`Application name`(应用名称)、`Homepage URL`(生产域名,如 `https://my-app.com`)、`Authorization Callback URL`(粘贴从 Clerk 复制的地址)。 + - 点击 Register application ,再点击 Generate a new client secret ,保存生成的 Client ID 和 Client Secret (Secret 仅显示一次)。 + - 回到 Clerk 弹窗,粘贴 Client ID 和 Client Secret,点击 Add connection 完成配置(若关闭弹窗,可在 SSO connections 找到 GitHub 连接,在“Use custom credentials”模块补填)。 +- 2.2 Google 平台配置: + - 登录 Google Cloud Console ,选择已有项目或新建项目(如“My App Production”)。 + - 点击左上角菜单 → APIs & Services → Credentials ,点击 Create Credentials → OAuth client ID (首次配置需先完成 OAuth consent screen 设置,选择“External”并填写应用信息)。 + - 选择 Application type 为 Web application ,配置: 1. `Authorized JavaScript origins`:添加生产域名(如 `https://my-app.com`、`https://www.my-app.com`),本地验证可补充 `http://localhost:端口号`。 2. `Authorized Redirect URIs`:粘贴从 Clerk 复制的地址。 - * 点击 Create ,保存弹窗中的 Client ID 和 Client Secret ,回到 Clerk 弹窗粘贴并点击 Add connection 。 - * 关键注意事项: + - 点击 Create ,保存弹窗中的 Client ID 和 Client Secret ,回到 Clerk 弹窗粘贴并点击 Add connection 。 + - 关键注意事项: 1. 禁止 WebView 登录:Google OAuth 不支持应用内浏览器登录,需参考 [Google 官方文档](https://support.google.com/cloud/answer/7657789) 调整。 2. 切换发布状态:默认“Testing”状态仅支持 100 个测试用户,需在 OAuth consent screen 将“Publishing status”改为 In production (需通过 Google 审核)。 3. 阻止子邮箱:Clerk 默认拦截含 `+`/`=`/`#` 的 Google 邮箱(如 `user+alias@example.com`),可在 Google 连接详情页开启/关闭 Block email subaddresses (建议开启提升安全性)。 @@ -1647,11 +1648,11 @@ serve(async (req) => { 配置完成后,通过 Clerk 内置 Account Portal 验证功能: -* 进入 Clerk Dashboard,左侧导航栏进入 Account Portal 页面。 -* 在“Sign-in”模块右侧,点击“访问登录页面”按钮,跳转至对应环境登录页: - * 开发环境:`https://你的域名.accounts.dev/sign-in`(如 `https://my-app.accounts.dev/sign-in`)。 - * 生产环境:`https://accounts.你的域名.com/sign-in`(如 `https://accounts.my-app.com/sign-in`)。 -* 点击“Sign in with GitHub/Google”,用对应平台账号登录,若能成功跳转并返回应用,说明连接配置正常。 +- 进入 Clerk Dashboard,左侧导航栏进入 Account Portal 页面。 +- 在“Sign-in”模块右侧,点击“访问登录页面”按钮,跳转至对应环境登录页: + - 开发环境:`https://你的域名.accounts.dev/sign-in`(如 `https://my-app.accounts.dev/sign-in`)。 + - 生产环境:`https://accounts.你的域名.com/sign-in`(如 `https://accounts.my-app.com/sign-in`)。 +- 点击“Sign in with GitHub/Google”,用对应平台账号登录,若能成功跳转并返回应用,说明连接配置正常。 # 6. 从 Supabase 到更多后端开发组件(进阶) @@ -1659,9 +1660,9 @@ serve(async (req) => { 但从更长期、更工程化的角度来看, **Supabase 提供的每一块能力(Auth / Storage / Edge Functions / Realtime / Database),在业界几乎都有对应的专业替代方案** ——既包括同类 BaaS 平台,也包括更“单点突破”的云服务和开源组件。作为上进的个人开发者和初创团队来说,了解这些替代选项有几个好处: -* 判断当前项目是否“全用 Supabase 就够了”,还是某一块需要更专业/更便宜/更易合规的专用服务; -* 当项目规模变大或需求变复杂时,是否可以把某个模块从 Supabase 替换出去(例如改用专门的 Auth 平台或对象存储),而不是一开始就被平台彻底锁死; -* 拓宽技术选型视野,即使暂时不更换,也能大致知道“如果不用 Supabase 的 X 功能,我还有哪些常见选择”。 +- 判断当前项目是否“全用 Supabase 就够了”,还是某一块需要更专业/更便宜/更易合规的专用服务; +- 当项目规模变大或需求变复杂时,是否可以把某个模块从 Supabase 替换出去(例如改用专门的 Auth 平台或对象存储),而不是一开始就被平台彻底锁死; +- 拓宽技术选型视野,即使暂时不更换,也能大致知道“如果不用 Supabase 的 X 功能,我还有哪些常见选择”。 本节将分别介绍 Supabase 所覆盖的几大能力在市场上的主流替代方案,例如:认证(Auth)、文件存储(Storage)、边缘函数(Edge Functions)、实时通信(Realtime)、数据库托管等。简单对比它们在功能特性、免费额度/定价、易用性以及社区流行度等方面的差异, 让你对后端组件工具库有更全面的理解。 @@ -1674,7 +1675,7 @@ serve(async (req) => { | Firebase(Google) | 全托管 BaaS(Auth + Firestore + Storage + Functions + Hosting) | Spark:免费轻量额度;Blaze:按量计费(Firestore/Storage/Functions 分别算) | 行业最成熟、文档好、上手快、实时能力强。适用于中小型产品、移动/前端主导团队。缺点:计费复杂、锁定性强、查询限制多(尤其 Firestore)。 | | Supabase | 开源 BaaS(Postgres + Auth + Storage + Edge Functions + Realtime) | 免费:500MB DB、1GB Storage、无服务器函数少量调用;Pro:按实例计费 | 最像 Firebase 的 SQL 版;界面优秀、体验现代、可自托管。适用于需要强 SQL、BI、事务能力的应用。缺点:高并发或复杂函数成本较高。 | | Appwrite Cloud | 开源一站式 BaaS(DB + Auth + Storage + Functions + Realtime) | 免费:包含基本 DB/Storage/FaaS;付费按资源级别计费 | 体验现代化、API 统一、可自托管;适合开发者友好的应用快速迭代。缺点:生态还不如 Firebase/Supabase 成熟;性能在大型应用中需要测试。 | -| Nhost | Postgres + GraphQL + Auth + Storage + Functions | 免费:1GB DB、1GB Storage、少量函数调用 | 类似“Supabase + Hasura”;天然 GraphQL;适合前端团队与 React/Next.js 项目。缺点:生态小、成本随用量升高。 | +| Nhost | Postgres + GraphQL + Auth + Storage + Functions | 免费:1GB DB、1GB Storage、少量函数调用 | 类似“Supabase + Hasura”;天然 GraphQL;适合前端团队与 React/Next.js 项目。缺点:生态小、成本随用量升高。 | | AWS Amplify | AWS 一站式后端(Cognito + AppSync + DynamoDB + Storage + Functions + Hosting) | 免费:Hosting 额度 + Cognito 10k MAU + 部分函数额度 | 大而全,适合已有 AWS 基础的团队;企业级可靠性。缺点:最难上手,服务碎片化;初创团队维护成本高。 | | Xata(近两年快速增长) | 多模型数据库 + Auth + Edge Functions | 免费:250k 记录、15GB 带宽 | 虽然更偏「DB + API」,但提供 Auth、文件、逻辑,可作为轻量全栈后端。UI/开发体验极佳。缺点:功能不如 Firebase/Supabase 全面。 | | Convex(开发者体验极强) | 托管数据库 + Auth + Functions(前端优先) | 免费开发版;付费按请求量计费 | 极简上手;无需 schema;前端写函数即可用后端。适合 MVP/快速验证。缺点:高度绑定平台,迁移成本高;不算完全传统 BaaS。 | diff --git a/docs/public/logo.png b/docs/public/logo.png new file mode 100644 index 0000000..31f9efc Binary files /dev/null and b/docs/public/logo.png differ diff --git a/docs/stage-0/0.1-learning-map/index.md b/docs/stage-0/0.1-learning-map/index.md new file mode 100644 index 0000000..5f50fad --- /dev/null +++ b/docs/stage-0/0.1-learning-map/index.md @@ -0,0 +1,122 @@ +# 从创意到 AI 产品 + +我们正身处由大语言模型(LLM)推动的人工智能应用爆发期。与以往AI开发高度依赖算法研究不同,**当前行业的重心已转向如何有效利用现有强大模型,构建具有实际价值的应用。**这一转变大幅降低了AI开发的门槛,将焦点从"从零开始构建模型"转移到"将AI能力封装为可落地的解决方案"。 + +对大多数人而言,如今最大的机遇并非发明新算法,而是学会如何借助AI编码工具快速实现想法。 + +AI coding的出现正在改写传统编程学习的规则。你不再需要花费数年时间精通某门语言的每个细节,而是可以通过与AI协作,**以"vibecoding"的方式将创意直接转化为可运行的代码**。会使用大模型生成代码片段只是起点。 + +当前真正的挑战在于:如何引导AI生成高质量、可维护的代码?如何将前后端代码组装成完整应用并成功部署上线?在AI时代,如何将文本生成、图像处理、语音识别等AI能力集成到你的应用中?本课程正是为应对这些挑战而设计。 + +我们不空谈理论,聚焦于AI辅助编程的端到端实战——**从利用 AI IDE 等工具快速构建原型,到将想法落地为真实可用的产品**。你将学会如何与AI高效协作编码,如何利用vibecoding思维快速迭代,如何调用常见的AI功能(文本生成、图像处理等)为应用赋能,以及如何完成从开发到上线的完整闭环。 + +# 为什么要学这个?它将如何帮助我的未来? + +本课程专为初级水平的学生设计,侧重于 AI 原生应用的实际开发和创新思维培养。通过三个循序渐进的学习阶段,你将从零基础逐步成长为能够独立开发和运营 AI 应用的全栈开发者。 + +## 三个阶段的成长路径:从“会用 AI”到“会做 AI 产品” + +**第零阶段:体验 AI 编程的魔力** +通过贪吃蛇等小游戏,你将第一次体验到 AI 辅助编程的能力与边界。这个阶段不需要任何编程基础,只需要你愿意动手尝试——看着 AI 在几分钟内帮你生成一个可玩的游戏,你会直观感受到 vibecoding 的强大。 + +**第一阶段:掌握产品开发的完整闭环** +学会使用 AI IDE(如 Cursor、Claude 等工具)将想法转化为可运行的 Web 应用原型。你将学习如何拆解需求、设计多页面应用、接入 AI 能力(文本生成、图像处理等),并用模拟数据完成一个完整的产品 demo。这个阶段结束时,你能独立完成一个像“霍格沃茨画像”那样接入 AI 能力的前端应用。 + +**第二阶段:成为能上线产品的工程师** +这是质的飞跃。你将学习现代 Web 开发的核心技能:从 Figma 设计稿到组件化前端实现,从 Supabase 数据库到 API 接口开发,从 Git 版本管理到 Zeabur 部署上线。更重要的是,你将学会集成支付系统(如 Stripe),让你的应用具备真实的商业价值。通过 Dify 等工具,你还将掌握知识库与工作流的构建,为应用注入更强的 AI 能力。 + +**第三阶段:构建跨平台的复杂应用** +掌握多平台开发能力,将同一个应用部署到 Web、微信小程序、安卓等多个平台。学习 MCP 等高级工具扩展 IDE 能力,深入理解 RAG 原理并使用 LangGraph 等框架设计复杂的 AI 工作流。这个阶段你将具备高级工程师的思维方式和工具链。 + +## 你将获得的核心能力 + +通过这个完整的学习路径,你将获得: + +- **Vibe Coding开发能力:** 熟练使用 vibecoding 思维和 AI 编码工具,将开发效率提升数倍。不再需要死记硬背语法,而是学会如何引导 AI 生成高质量代码。 +- **全栈开发技能:** 从 UI 设计到前端实现,从数据库设计到 API 开发,从本地开发到云端部署,掌握现代 Web 应用的完整技术栈。 +- **AI 能力集成:** 学会调用各类多模态 AI API,将文本、图像、语音等 AI 能力无缝集成到你的应用中,并通过 RAG 等技术构建智能化产品。 +- **产品思维与运营能力:** 从用户研究到需求拆解,从 MVP 设计到产品迭代,从支付集成到用户管理,形成完整的产品开发与运营闭环。 + +# 第一阶段学习目标 + +本阶段本质上是一套“AI 产品经理 Vibe Coding 能力培训课程”,主要面向希望进入 AI 产品方向、但编程基础较弱或几乎为零的同学,目标是在 AI 的帮助下完成一个“能跑、能展示”的 Web 应用原型。 + +``` +## 模块一:AI 时代,会说话就会编程 +- 1.1 普通人的困境与机会? +- 1.2 AI 能帮你做到什么程度? +- 1.3 动手:你的第一个 AI 原生应用 + +## 模块二:认识 AI IDE 工具 +- 2.1 写代码需要什么环境和工具 +- 2.2 什么是 IDE,为什么需要 IDE +- 2.3 AI IDE 和普通 IDE 有什么不同 +- 2.4 界面上每个按钮是干什么的 +- 2.5 怎么跟 AI 说话才有效 + +## 模块三:动手做出原型 +- 3.1 把需求变成代码的过程 +- 3.2 从一个单页面开始 +- 3.3 遇到报错了怎么办 +- 3.4 做多个页面的应用 +- 3.5 把原型做得像那么回事 + +## 模块四:给原型加上 AI 能力 +- 4.1 什么是 AI 能力接入(API 调用) +- 4.2 如何接入文生图能力 +- 4.3 如何接入视频生成能力 +- 4.4 其他常见 AI 能力的接入方法 +- 4.5 成本控制和错误处理 + +## 模块五:完整项目实战 +- 5.1 制造模拟数据让原型看起来真实 +- 5.2 收集反馈并快速调整 +- 5.3 展示你的成果 + +## 大作业 +- 做一个完整的 Web 应用原型并展示 + +## 附录A:产品思维补充 +- A.1 什么是好的产品想法 +- A.2 如何发现用户真正的需求 +- A.3 功能优先级怎么排 +- A.4 MVP 思维:最小可行产品 + +## 附录B:常见报错及解决方案 +- B.1 页面显示空白或不加载 +- B.2 数据保存不成功 +- B.3 样式显示不正常 +- B.4 点击按钮没反应 +- B.5 API 调用失败 +- B.6 如何把报错信息有效地反馈给 AI +``` + +# 为什么要用项目制来训练? + +原因其实很简单:按照大多数同学现在的状态,直接走入职场,很可能会在真实项目和老板 / 客户的“社会毒打”下寸步难行。现实世界更常见的场景是: + +> 你的导师 / 老板:我们要做一个 xxx,目标是达到 yyy 的效果。 +> +> 文档?现成框架?详细的需求说明?很多时候都不存在。 + +真实工作中的许多任务,本质上就是在高度不确定的环境下解决从未见过的问题:需求是模糊的,边界是变化的,没人告诉你标准答案,你需要自己查资料、做实验、搭原型、不断迭代,最后给出一个“能跑、能用、能上线”的解决方案。 + +这门课想做的,就是在一个相对安全的环境里,提前给你一次“模拟社会毒打”: + +- 通过看似有一定难度的项目任务,迫使你练习拆解问题、设计方案、自己寻找资料 +- 通过不那么“傻瓜化”的脚手架和代码,让你学会阅读、理解和改造一份中大型代码库 +- 通过从创意到上线的完整闭环,让你体验真实产品从 0 到 1 的完整过程 + +短期来看,这种训练确实比较折磨人;但从长期来看,它会极大提高你在求职和职业发展中的竞争力:你会更能扛事儿,更能在不确定环境中找到突破口,也更有能力把 AI 变成真正落地的产品,而不是停留在“玩玩 Demo”阶段。 + +# 坚持了好久还是搞不定,我想放弃了 + +也许是你坚持的方法不对。不要一个人在黑暗中硬撑,可以来跟作者和助教们聊聊:把你已经尝试过的方法、遇到的具体卡点、和你目前的心理状态,坦诚地说出来。很多时候,只要稍微调整一下方向、补上一个关键知识点,你就能继续往前走。 + +# 我觉得教程有的设计不合理 + +欢迎随时联系作者、提交 issue,或者在群里 / 课堂上直接反馈。我们非常希望和你一起把这套教程打磨得越来越好:哪里不清晰、哪里体验不好、哪里让你白费力气,都可以坦诚指出来。越真实、越具体的反馈,越能帮助后来者少踩坑。 + +# Reference + +- [南京大学 计算机科学与技术系 计算机系统基础 课程实验](https://nju-projectn.github.io/ics-pa-gitbook/ics2025/) diff --git a/docs/project/chapter1/images/1767350588191.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/1767350588191.png similarity index 100% rename from docs/project/chapter1/images/1767350588191.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/1767350588191.png diff --git a/docs/project/chapter1/images/image1.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image1.png similarity index 100% rename from docs/project/chapter1/images/image1.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image1.png diff --git a/docs/project/chapter1/images/image10.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image10.png similarity index 100% rename from docs/project/chapter1/images/image10.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image10.png diff --git a/docs/project/chapter1/images/image11.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image11.png similarity index 100% rename from docs/project/chapter1/images/image11.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image11.png diff --git a/docs/project/chapter1/images/image12.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image12.png similarity index 100% rename from docs/project/chapter1/images/image12.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image12.png diff --git a/docs/project/chapter1/images/image13.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image13.png similarity index 100% rename from docs/project/chapter1/images/image13.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image13.png diff --git a/docs/project/chapter1/images/image14.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image14.png similarity index 100% rename from docs/project/chapter1/images/image14.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image14.png diff --git a/docs/project/chapter1/images/image15.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image15.png similarity index 100% rename from docs/project/chapter1/images/image15.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image15.png diff --git a/docs/project/chapter1/images/image16.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image16.png similarity index 100% rename from docs/project/chapter1/images/image16.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image16.png diff --git a/docs/project/chapter1/images/image17.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image17.png similarity index 100% rename from docs/project/chapter1/images/image17.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image17.png diff --git a/docs/project/chapter1/images/image18.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image18.png similarity index 100% rename from docs/project/chapter1/images/image18.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image18.png diff --git a/docs/project/chapter1/images/image19.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image19.png similarity index 100% rename from docs/project/chapter1/images/image19.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image19.png diff --git a/docs/project/chapter1/images/image2.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image2.png similarity index 100% rename from docs/project/chapter1/images/image2.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image2.png diff --git a/docs/project/chapter1/images/image20.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image20.png similarity index 100% rename from docs/project/chapter1/images/image20.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image20.png diff --git a/docs/project/chapter1/images/image21.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image21.png similarity index 100% rename from docs/project/chapter1/images/image21.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image21.png diff --git a/docs/project/chapter1/images/image22.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image22.png similarity index 100% rename from docs/project/chapter1/images/image22.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image22.png diff --git a/docs/project/chapter1/images/image23.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image23.png similarity index 100% rename from docs/project/chapter1/images/image23.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image23.png diff --git a/docs/project/chapter1/images/image24.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image24.png similarity index 100% rename from docs/project/chapter1/images/image24.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image24.png diff --git a/docs/project/chapter1/images/image25.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image25.png similarity index 100% rename from docs/project/chapter1/images/image25.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image25.png diff --git a/docs/project/chapter1/images/image26.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image26.png similarity index 100% rename from docs/project/chapter1/images/image26.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image26.png diff --git a/docs/project/chapter1/images/image27.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image27.png similarity index 100% rename from docs/project/chapter1/images/image27.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image27.png diff --git a/docs/project/chapter1/images/image28.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image28.png similarity index 100% rename from docs/project/chapter1/images/image28.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image28.png diff --git a/docs/project/chapter1/images/image29.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image29.png similarity index 100% rename from docs/project/chapter1/images/image29.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image29.png diff --git a/docs/project/chapter1/images/image3.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image3.png similarity index 100% rename from docs/project/chapter1/images/image3.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image3.png diff --git a/docs/project/chapter1/images/image30.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image30.png similarity index 100% rename from docs/project/chapter1/images/image30.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image30.png diff --git a/docs/project/chapter1/images/image31.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image31.png similarity index 100% rename from docs/project/chapter1/images/image31.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image31.png diff --git a/docs/project/chapter1/images/image32.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image32.png similarity index 100% rename from docs/project/chapter1/images/image32.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image32.png diff --git a/docs/project/chapter1/images/image33.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image33.png similarity index 100% rename from docs/project/chapter1/images/image33.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image33.png diff --git a/docs/project/chapter1/images/image34.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image34.png similarity index 100% rename from docs/project/chapter1/images/image34.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image34.png diff --git a/docs/project/chapter1/images/image35.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image35.png similarity index 100% rename from docs/project/chapter1/images/image35.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image35.png diff --git a/docs/project/chapter1/images/image36.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image36.png similarity index 100% rename from docs/project/chapter1/images/image36.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image36.png diff --git a/docs/project/chapter1/images/image37.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image37.png similarity index 100% rename from docs/project/chapter1/images/image37.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image37.png diff --git a/docs/project/chapter1/images/image38.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image38.png similarity index 100% rename from docs/project/chapter1/images/image38.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image38.png diff --git a/docs/project/chapter1/images/image39.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image39.png similarity index 100% rename from docs/project/chapter1/images/image39.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image39.png diff --git a/docs/project/chapter1/images/image4.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image4.png similarity index 100% rename from docs/project/chapter1/images/image4.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image4.png diff --git a/docs/project/chapter1/images/image40.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image40.png similarity index 100% rename from docs/project/chapter1/images/image40.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image40.png diff --git a/docs/project/chapter1/images/image41.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image41.png similarity index 100% rename from docs/project/chapter1/images/image41.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image41.png diff --git a/docs/project/chapter1/images/image42.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image42.png similarity index 100% rename from docs/project/chapter1/images/image42.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image42.png diff --git a/docs/project/chapter1/images/image43.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image43.png similarity index 100% rename from docs/project/chapter1/images/image43.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image43.png diff --git a/docs/project/chapter1/images/image44.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image44.png similarity index 100% rename from docs/project/chapter1/images/image44.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image44.png diff --git a/docs/project/chapter1/images/image45.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image45.png similarity index 100% rename from docs/project/chapter1/images/image45.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image45.png diff --git a/docs/project/chapter1/images/image46.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image46.png similarity index 100% rename from docs/project/chapter1/images/image46.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image46.png diff --git a/docs/project/chapter1/images/image47.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image47.png similarity index 100% rename from docs/project/chapter1/images/image47.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image47.png diff --git a/docs/project/chapter1/images/image48.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image48.png similarity index 100% rename from docs/project/chapter1/images/image48.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image48.png diff --git a/docs/project/chapter1/images/image49.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image49.png similarity index 100% rename from docs/project/chapter1/images/image49.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image49.png diff --git a/docs/project/chapter1/images/image5.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image5.png similarity index 100% rename from docs/project/chapter1/images/image5.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image5.png diff --git a/docs/project/chapter1/images/image50.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image50.png similarity index 100% rename from docs/project/chapter1/images/image50.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image50.png diff --git a/docs/project/chapter1/images/image51.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image51.png similarity index 100% rename from docs/project/chapter1/images/image51.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image51.png diff --git a/docs/project/chapter1/images/image52.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image52.png similarity index 100% rename from docs/project/chapter1/images/image52.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image52.png diff --git a/docs/project/chapter1/images/image53.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image53.png similarity index 100% rename from docs/project/chapter1/images/image53.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image53.png diff --git a/docs/project/chapter1/images/image54.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image54.png similarity index 100% rename from docs/project/chapter1/images/image54.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image54.png diff --git a/docs/project/chapter1/images/image55.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image55.png similarity index 100% rename from docs/project/chapter1/images/image55.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image55.png diff --git a/docs/project/chapter1/images/image56.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image56.png similarity index 100% rename from docs/project/chapter1/images/image56.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image56.png diff --git a/docs/project/chapter1/images/image57.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image57.png similarity index 100% rename from docs/project/chapter1/images/image57.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image57.png diff --git a/docs/project/chapter1/images/image58.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image58.png similarity index 100% rename from docs/project/chapter1/images/image58.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image58.png diff --git a/docs/project/chapter1/images/image6.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image6.png similarity index 100% rename from docs/project/chapter1/images/image6.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image6.png diff --git a/docs/project/chapter1/images/image7.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image7.png similarity index 100% rename from docs/project/chapter1/images/image7.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image7.png diff --git a/docs/project/chapter1/images/image9.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/image9.png similarity index 100% rename from docs/project/chapter1/images/image9.png rename to docs/stage-0/0.2-ai-capabilities-through-games/images/image9.png diff --git a/docs/stage-0/0.2-ai-capabilities-through-games/images/index-2026-01-07-18-25-03.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/index-2026-01-07-18-25-03.png new file mode 100644 index 0000000..2fd49ba Binary files /dev/null and b/docs/stage-0/0.2-ai-capabilities-through-games/images/index-2026-01-07-18-25-03.png differ diff --git a/docs/stage-0/0.2-ai-capabilities-through-games/images/index-2026-01-07-18-34-03.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/index-2026-01-07-18-34-03.png new file mode 100644 index 0000000..00a780b Binary files /dev/null and b/docs/stage-0/0.2-ai-capabilities-through-games/images/index-2026-01-07-18-34-03.png differ diff --git a/docs/stage-0/0.2-ai-capabilities-through-games/images/index-2026-01-07-18-35-11.png b/docs/stage-0/0.2-ai-capabilities-through-games/images/index-2026-01-07-18-35-11.png new file mode 100644 index 0000000..05a67e6 Binary files /dev/null and b/docs/stage-0/0.2-ai-capabilities-through-games/images/index-2026-01-07-18-35-11.png differ diff --git a/docs/stage-0/0.2-ai-capabilities-through-games/index.md b/docs/stage-0/0.2-ai-capabilities-through-games/index.md new file mode 100644 index 0000000..b5d67c4 --- /dev/null +++ b/docs/stage-0/0.2-ai-capabilities-through-games/index.md @@ -0,0 +1,577 @@ +# 初级一:AI 时代,会说话就会编程 + +这是一个**基于项目制学习**的学习教程。我们鼓励你跟随步骤一步步操作,并尝试复现结果。 +不要担心犯错或修改内容,我们永远相信你可以做到,请你永远记住: + +🎉 **完成比完美更重要**。 + +## 本章导读 + +在这一节,你会用对话式 AI 做出第一个 AI 原生小游戏——一款会“吃单词、写诗、画画”的贪吃蛇,并借此搞清楚 AI 编程的初步效果。 + +- 预计时间:约 **4 小时**,可分多次完成 +- 预期产出:1 个可运行的 AI 原生贪吃蛇 + (可选)1 个你自创的 AI 原生小游戏或 Demo +- Assignment:复现贪吃蛇,并(可选)实现一种你感兴趣的 AI 原生游戏 + +## 1. 普通人的困境与机会 + +很多人脑子里有一堆产品点子:一款帮自己记账的小工具、一个记录孩子成长的网页、甚至一款小游戏。但一想到要写代码、要找程序员,就直接劝退。 + +AI 出现之后,第一次给了普通人一个全新的可能:你不需要会写代码,只需要学会对 AI 说清楚你想要什么。来自 GitHub Copilot 的[数据显示](https://www.wearetenet.com/blog/github-copilot-usage-data-statistics),超过1500万开发者正在用AI辅助编程,平均46%的代码都是AI生成的! 在Java项目中这个比例能达到61%。 + +让人真正兴奋的是效率的飞跃:开发者完成任务的速度提升了 55%。原本需要 9.6 天才能提交的代码,现在只要 2.4 天就能搞定。 这种肉眼可见的效率提升,说明 AI 不再只是一个“可选工具”,而是正在成为开发流程中不可或缺的编程助手。采用率的数据也印证了这一点:在获得访问权限的当天,就有 81% 的开发者第一时间完成安装并开始使用;其中 96% 的人更是在当天就开始采纳 AI 提供的代码建议。换句话说,开发者几乎是立刻把 AI 融入了日常编码工作。 + +对于普通人来说,这个趋势更有意义:如果专业程序员都在大量依赖AI写代码,那我们这些**不会编程的人,为什么不能直接跟AI对话来实现自己的想法呢**? + +这门课的目标是帮你练成新技能:通过自然语言对话就能做应用。我们将教你怎么跟 AI 用计算机的语言沟通、怎么让AI帮你把脑子里的想法变成真实可用的产品。 + +## 2. AI 能帮你做到什么程度 + +在本节中,我们只讨论一个问题:如果你完全不会写代码,现在的 AI 能帮你做到什么程度? + +大致来说,你可以把当前大模型的能力理解为:可以胜任简单的内部小工具、数据可视化看板,以及一些轻量级小游戏的开发。这些能力用来做自用工具、从产品经理视角验证需求,基本已经足够。但若想一键生成可直接商用的成熟产品,通常仍需要人工在流程设计、细节打磨上持续优化。 + +接下来,我们就以贪吃蛇为例,具体看看 AI 编程目前到底能做到什么程度。 + +### 2.1 60 秒做一个贪吃蛇游戏 + +首先,请你打开课程中使用的实验网页 [z.ai](https://chat.z.ai/),`z.ai` 是由智谱 AI(中国领先的大语言模型公司之一)开发的 AI 平台,其核心能力由智谱自研的 GLM 系列大模型提供支持。该平台集成了多项 AI 功能,包括幻灯片生成、海报设计和全栈开发等。在本教程中,我们将重点介绍其全栈开发模块的使用。 + +![](images/index-2026-01-07-18-25-03.png) + +输入我们的简单需求后点击 **全栈开发** 按钮,你可以实时观看网页的完整创建过程。通常只需泡一杯咖啡的时间,网页便会自动生成完毕! + +``` +帮我做一个贪吃蛇游戏: +1. 用方向键控制蛇的移动 +2. 吃到食物后蛇会变长,分数增加 +3. 撞到墙壁或自己的身体就游戏结束 +4. 要有开始和重新开始按钮 +5. 界面要简洁好看 +``` + +![](images/index-2026-01-07-18-34-03.png) + +生成结束后,你能看到右侧出现可浏览的网页界面。你可以上下滚动浏览页面内容,或点击页面顶部的 🧭 按钮切换至全屏模式查看效果。 + +> 其中顶部从左到右按钮的作用依次为:箭头按钮展开侧边对话历史栏,铅笔按钮用于新建一个对话,循环箭头按钮用于刷新页面,指南针按钮负责切换至全屏模式,Download 按钮用于下载项目,<> 按钮用于切换代码视图,Publish 按钮用于发布项目。 + +![](images/index-2026-01-07-18-35-11.png) + +如果你想查看该网页的源代码,可以点击右上角的代码图标查看完整代码。 + +![](images/image7.png) + +### 2.2 对话编程能做什么不能做什么 + +本节聚焦一个具体问题:当你只依赖对话式 AI、不写任何代码时,它究竟能把事情推进到哪一步。 +在经验层面,一个较为稳定的结论是:它可以帮你完成一个“小而完整”的东西,但“做到什么程度就算够”,仍然需要你亲自决策每一步的详细步骤。 + +#### 更擅长“小而清晰”的应用 + +从前面的贪吃蛇示例中,你已经看到了一种典型模式: +只要你能把界面和交互说清楚,AI 通常可以在几轮对话内,拼出一个可以打开、可以点击、可以玩的完整网页。 + +这类任务往往具备几个共同特征: + +- 范围清晰:一页网页、一个简单内部工具、一个小玩法 +- 结果可见:你能立即在浏览器中验证是否按预期工作 +- 纠错直接:发现问题后,可以在后续对话中点明具体现象并要求修正(通过复制错误直接粘贴,或者截图粘贴的形式让 AI 进行修改) + +在这个边界内,你可以把对话式 AI 看作一位执行力不错的“辅助开发者”。你只需在每一轮用自然语言细化和修正需求,就能快速得到可用的原型。 + +#### 大型项目需要“流程视角” + +一旦超出小而清晰的范围,只指望靠几轮对话让 AI 端到端完成复杂系统,很快就会遇到上限。大型项目往往要接后端、连数据库、整合第三方服务,还牵涉权限、安全、并发和大量业务规则,目标是交付一整套与现有业务深度打通的系统,而不是一页网页。 + +在这种情况下,更合理的做法不是把所有需求一股脑丢给 AI,而是先梳理出清晰的整体流程:关键步骤是什么、每一步的输入输出和状态变化是什么、哪些节点对性能和安全最敏感。再基于这张流程图,把相对独立的环节拆分出来,交给对话式 AI 生成接口、模块、脚本和测试。 + +以目前的能力来看,AI 更擅长加速一个个小步骤,由你(或你的团队)来决定怎么拆步骤、如何串联,并负责最终的架构设计、系统集成和运维。 + +#### 能写和能用的区别 + +咋一看,AI 好像什么都能写,但这些东西到底能不能用,能用到什么程度,我们该如何划分? + +一个可参考的经验是: + +- **原型 / Demo / 内部自用工具**:非常适合先交给 AI 打第一版,再由你迭代细节。 +- **面向真实用户的大型产品**:通常需要工程师在架构、抽象、性能和维护上长期投入。 +- **强安全 / 强合规系统(如支付、风控、医疗等)**:在当前阶段,不宜“生成完就直接上线”,必须引入严格的审查与测试流程。 + +在当下,你可以相对安心地把 AI 视作一个高效的 Demo 与自用工具搭档: +只要你愿意多测试、多迭代,多问几轮“这里不对,帮我修一下并解释原因”,在原型与内部工具这一级别,整体质量通常是足够且具备实践价值的。 + +## 3. 动手:你的第一个 AI 原生应用 + +让我们回到动手部分,在前一部分,我们已经用 AI 快速做出了一个可以玩的贪吃蛇原型,也大致知道了 AI 能做什么、不能做什么。接下来我们将学习如何用最基础的 **vibe coding** 技巧创建一个**现代版**的 AI 贪吃蛇游戏。我们将让蛇吃掉文字字符而不是豆子。最后让游戏根据吃掉的文字字符生成一首诗,并画一幅画。 +通过这个实际案例你能够理解全新编程方式的核心理念:如何学会用自然语言清晰地表达需求。 + +### 3.1 AI 原生贪吃蛇 + +在一开始,我们可以用最简单的方式与大模型对话,这将帮助我们快速获得产品原型。我们可以直接在聊天框中输入: + +> **💡 示例提示词:** 帮我做一个贪吃蛇游戏 +> +> ![](images/image12.png) + +> **💡 示例提示词:** 帮我做一个贪吃蛇游戏,它应该支持 +> +> 1. 我可以吃不同的单词,它们会被收集在一个盒子里 +> ![](images/image13.png) + +> **💡 示例提示词:** 帮我做一个贪吃蛇游戏,它应该支持: +> +> 1. 我可以吃不同的单词,它们会被收集在一个盒子里 +> 2. 当蛇吃了8个单词时,llm 应该根据这些单词创作一首诗,我们可以根据需要重新混合这首诗。 +> 3. 当诗完成后,下一步将自动根据这首诗创建一幅图像。 +> +> ![](images/image14.png) + +注意,在开发过程中,我们可能会遇到不尽如人意的问题,例如点击按钮没有任何反应、使用功能时报错、功能未按预期工作,或者前端页面与预期设计不符。 + +在这种情况下,我们需要进一步向模型提问,以帮助修复这些意外问题。 + +![](images/image15.png) + +### 3.2 给游戏添加新功能 + +完成基本功能后,我们可以尝试给我们的程序添加一些新花样!如果你觉得蛇吃单词或字符的过程有点枯燥,你可以让蛇吃不同颜色的单词,并相应地改变蛇的颜色。 + +你还可以为“吃”的过程添加特效,或者引入触发特效的魔法单词——比如增加蛇的速度或大小。另一个想法是每当蛇吃一个单词时就让模型生成一首诗和一幅图,而不是等到它吃掉八个单词。 + +如果觉得这些有挑战性,你可以直接向语言模型求助!它可以提供创意建议,让你的游戏更有趣。试一试吧! + +```JavaScript +1. "单词解锁世界" 机制 +每当蛇吃掉一个单词,LLM 会对该单词进行诗意联想(例如,“树”→“森林”、“绿荫”),图像模型会即时为该单词生成一个小艺术品。这些图像逐渐拼凑成一个独特的、玩家创造的全景图,所以玩家每次游玩都在“作画和写诗”。 + +2. "诗歌拼图" 玩法 +蛇吃掉的每个单词都会触发 LLM 生成简短的诗句,图像模型生成插图。这些诗句和图像像拼图一样组合在一起,在回合结束时形成一首 AI 协作的诗和画。 + +3. "魔法单词" & "故事分支" +特殊的“魔法单词”(例如,“风”、“夜”、“梦”)不仅触发 LLM 生成诗歌,还会改变场景的情绪或主题——将生成图像的风格转变为夜晚、暴风雨或梦幻般的氛围。 +分支故事:LLM 在开始时给出一个主题或谜语(例如,“秋天的回忆”)。玩家的单词选择直接影响故事和诗歌的演变,图像模型实时更新背景和视觉效果。 + +4. "实时互动生成" +每个单词之后,LLM 生成一行对话或描述,游戏中的 NPC 可以对玩家“说话”,或者环境可以相应地改变。 +蛇的外观或游戏中的障碍物可以根据吃掉的单词在视觉上发生变化,这要归功于图像模型。 + +5. "创作 & 分享" +玩家可以在会话结束时保存并分享他们 AI 创作的诗歌和图像,炫耀他们独特的“AI 协作”。 +“最美诗歌+艺术”、“最有创意单词组合”等排行榜,鼓励重玩和创造力。 + +6. "按句贪吃蛇" 挑战 +反向模式:LLM 给出一句诗或一个谜语,玩家必须引导蛇按顺序吃掉单词来重构句子。吃错单词会通过图像生成模型触发有趣或艺术性的后果。 + +7. "主题关卡" & "风格选择" +游戏开始时,玩家选择一个主题(例如,“童话”、“科幻”、“唐诗”),LLM 和图像模型都会调整单词选择、诗歌风格和视觉效果以匹配,使每次运行都感觉新鲜。 + +8. "现场共创" +当吃掉一个特殊单词时,LLM 可以提示玩家输入短语或选择风格,然后 AI 生成相应的诗句和插图,使其成为真正的人类-AI 共创。 + +9. "AI 彩蛋 & 成就" +某些单词组合被 LLM 识别为特殊主题或内部笑话(例如,“月亮”、“桂花”、“河岸”),触发稀有的诗句和插图,奖励探索。 + +10. "成长的故事" +随着蛇的成长,LLM 生成一个连续的故事诗,图像模型创建一个无缝的长卷或全景图,所以玩家同时在“写作、绘画和玩耍”。 +``` + +此外,我们还可以要求 LLM 帮你直接生成项目级的提示词。在上一节中,我们只自己写了贪吃蛇游戏的提示词。现在让我们尝试让大模型生成一个带有整体框架和实现路径的提示词(你可以直接用 z.ai 生成): + +> 我想让 AI 生成一个网页贪吃蛇游戏,需要一个更完整的提示词,让生成结果更令人印象深刻和有趣。请生成相应的提示词。当前目标是:生成一个贪吃蛇游戏,需要实现吃不同单词生成诗歌的功能,并且应该包含图像生成模块。 + +z.ai 的回复将会是这样的: + +![](images/image56.png) + +我们可以使用这个提示词在全栈开发模式下重新生成项目: + +![](images/image57.png) + +![](images/image58.png) + +### 3.3 尝试制作其他小游戏 + +除了贪吃蛇(游戏),我们可以让想象力尽情驰骋。 + +创造任何我们想创造的东西,甚至尝试搞砸一切!然后重头再来! + +```YAML +1. AI 艺术画廊平台 + 描述:一个展示 AI 生成艺术作品的在线画廊,用户可以上传、分享和评论 AI 艺术作品。 + 功能:用户账户系统、艺术作品上传和展示、评分系统、分类浏览、AI 生成工具集成。 + 技术亮点:React/Vue 前端、Node.js 后端、MongoDB 数据库、AI API 集成。 + +2. 复古游戏档案馆 + 描述:一个致敬经典游戏的网站,包含游戏历史、玩法指南和在线可玩复古游戏。 + 功能:游戏数据库、时间轴展示、在线模拟器、用户评论、游戏收藏功能。 + 技术亮点:响应式设计、WebGL/Canvas 游戏实现、RESTful API、用户认证系统。 + +3. 可持续生活追踪器 + 描述:一个帮助用户通过环保提示和社区挑战来追踪和减少碳足迹的网站。 + 功能:个人碳足迹计算器、目标设定、进度追踪、社区挑战、环保知识库。 + 技术亮点:数据可视化、移动端优化、社交功能、推送通知。 + +4. 虚拟厨房助手 + 描述:一个基于 AI 的烹饪指导平台,提供个性化食谱推荐和分步烹饪说明。 + 功能:食谱数据库、食材识别、个性化推荐、烹饪计时器、营养分析。 + 技术亮点:图像识别 API、机器学习推荐系统、语音控制、实时视频指导。 + +5. 地下音乐发现平台 + 描述:一个专注于独立和新兴艺术家的音乐流媒体平台,提供独特的发现体验。 + 功能:音乐流媒体、艺术家资料、个性化推荐、播放列表创建、社区评论。 + 技术亮点:音频流处理、推荐算法、社交功能、音乐可视化。 + +6. 极简任务管理系统 + 描述:一个具有禅意美学的任务管理工具,专注于简单和高效的任务组织。 + 功能:任务创建和分类、优先级设置、进度追踪、团队协作、数据分析。 + 技术亮点:极简 UI 设计、拖放功能、实时同步、跨平台兼容性。 + +7. 科幻写作工坊 + 描述:一个为科幻作家提供创意工具和灵感的平台,包括世界观构建辅助和角色开发工具。 + 功能:故事结构工具、角色资料、世界观构建模板、写作统计、社区反馈。 + 技术亮点:富文本编辑器、数据可视化、协作编辑、AI 辅助创作。 + +8. 个人知识图谱 + 描述:一个帮助用户构建个人知识网络,可视化并连接各种想法和信息的工具。 + 功能:节点创建和连接、标签系统、搜索功能、导入/导出工具、可视化图表。 + 技术亮点:图数据库、数据可视化算法、Markdown 支持、跨设备同步。 + +9. 虚拟植物园 + 描述:一个互动植物百科全书,用户可以探索植物世界并创建虚拟花园。 + 功能:植物数据库、3D 植物模型、生长模拟、园艺指南、社区展示。 + 技术亮点:3D 渲染、季节变化模拟、AR 集成、植物识别 API。 + +10. 编程挑战竞技场 + 描述:一个面向程序员的在线竞赛平台,具有各种难度级别的编程挑战。 + 功能:挑战问题、代码编辑器、自动评估、排行榜、学习路径。 + 技术亮点:代码沙箱环境、实时评估系统、算法可视化、社交学习功能。 +``` + +还有... 如果你喜欢玩游戏,让我们一起尝试创造游戏吧! + +```SQL +1. 3D 开放世界 RPG + 描述:一个具有广阔开放世界、任务和角色成长的奇幻 RPG。 + 功能:昼夜循环、动态天气、技能树、多人合作、制作系统。 + 技术亮点:Three.js 或 Babylon.js 用于 3D 渲染、服务器端游戏逻辑、角色自定义、存档系统。 + +2. 第一人称射击 (FPS) 竞技场 + 描述:一个快节奏的多人 FPS,具有各种游戏模式和地图。 + 功能:团队死斗、夺旗、武器自定义、排位赛。 + 技术亮点:WebGL/Three.js 用于 3D 图形、多人网络代码、命中检测、语音聊天。 + +3. AI 国际象棋和多人游戏 + 描述:一个功能齐全的国际象棋平台,具有 AI 对手和在线对战功能。 + 功能:AI 难度级别、残局挑战、锦标赛模式、回放分析。 + 技术亮点:国际象棋逻辑库、WebSocket 用于实时对战、ELO 排名系统、反作弊。 + +4. 麻将在线多人游戏 + 描述:一个具有在线多人游戏和计分功能的传统麻将游戏。 + 功能:多种规则集、私人房间、排名系统、回放功能。 + 技术亮点:牌匹配逻辑、实时多人游戏、大厅系统、分数追踪。 + +5. 回合制策略游戏 + 描述:一个具有网格战斗和单位管理的战术策略游戏。 + 功能:战役模式、遭遇战、单位升级、战争迷雾、多人对战。 + 技术亮点:网格移动系统、AI 决策、回合同步、存档/读档系统。 + +6. 计时赛赛车游戏 + 描述:一个专注于计时赛和赛道记录的 3D 赛车游戏。 + 功能:多条赛道、汽车自定义、幽灵回放、排行榜。 + 技术亮点:3D 汽车物理、赛道编辑器、回放系统、在线排行榜。 + +7. 卡牌对战游戏 (卡组构建) + 描述:一个策略卡牌游戏,玩家构建卡组并与对手战斗。 + 功能:卡牌收集、卡组构建、排位赛、赛季活动。 + 技术亮点:卡牌游戏逻辑、匹配系统、AI 对手、卡牌动画。 + +8. 大逃杀 (俯视 2D) + 描述:一个俯视 2D 大逃杀游戏,具有缩小的游戏区域和战利品机制。 + 功能:单人和小队模式、武器多样性、局内事件、排行榜。 + 技术亮点:实时多人游戏、区域缩小逻辑、战利品生成系统、匹配。 + +9. 恐怖生存游戏 (第一人称) + 描述:一个具有资源管理和逃生机制的第一人称恐怖游戏。 + 功能:氛围环境、解谜、敌人 AI、多重结局。 + 技术亮点:动态照明、声音设计、敌人寻路、存档系统。 + +10. 音乐节奏游戏 (3D) + 描述:一个 3D 节奏游戏,玩家随着音乐节拍击打音符。 + 功能:多种难度级别、赛道编辑器、自定义歌曲支持、排行榜。 + 技术亮点:音频分析、节拍同步、3D 音符轨道、输入时机检测。 +``` + +# 📚 Assignment + +- 复现 AI 原生的贪吃蛇游戏。 +- (可选)根据更多参考案例实现不同种类好玩的 AI 原生游戏。 + +这就是完整的教程!你可能需要 **4 小时** 才能完成所有内容并构建你自己的贪吃蛇游戏。不要着急——探索、实验并享受这个过程。推荐你读完下列附录,用于补充基础知识: + +# 附录 + +## 附录 1:我们需要前端开发知识吗? + +在 Vibe Coding 阶段,我们不再要求每一位用户都具备专业的编程能力。这种模式下,你的核心任务主要体现在两个方面: + +1. 能够用自然语言,比较清晰地描述自己想要的界面和交互效果; +2. 当 AI 给出的结果不符合预期或出现报错时,能够把报错信息、截图等上下文整理后,再反馈给 AI,协助其完成修正。 + +在这个前提下,即便你从未写过一行代码,也可以通过与 AI 的持续对话,逐步搭建出可用的原型。 + +但是,如果我们对前端开发的一些基础概念有所了解,就可以更准确地提出需求,更有效地利用 AI 的能力。这也是本附录希望补充说明的部分。 + +### 什么是前端? + +在一个典型的应用系统中,我们通常会将其大致分为两个部分: + +- 一部分是直接呈现在用户面前的界面,以及与界面相关的交互; +- 另一部分是运行在服务器上的数据处理和业务逻辑。 + +其中,前者通常被称为**前端**,后者则被称为**后端**。 + +从结果上看,前端就是**用户“能看到、能点到”的那一层内容**。例如: + +- 网页上的标题、段落文字和图片; +- 按钮、输入框、下拉菜单、勾选框等交互控件; +- 排行榜页面、游戏界面、动态动画效果等。 + +后端则更多负责**“看不见”的部分**,例如: + +- 用户分数存放在什么地方; +- 登录时如何校验账号和密码是否正确; +- 针对不同用户,如何分配不同的关卡或内容。 + +**前端开发**的工作,就是在浏览器这一“运行环境”中,把上述可视化界面和交互行为搭建出来,使用户能够顺畅地查看信息、提交表单、进行操作。 + +### 1. 前端基础三件套:从“页面是哪儿来的”说起 + +前端页面并不是“凭空出现”的。 +当我们在浏览器中打开一个网址时,浏览器会从服务器获取一份描述页面的“说明书”,然后按照这份说明书的内容,一步步把界面“画”出来,并让它能够响应用户的操作。 + +这份“说明书”,通常由三类内容共同组成: + +- HTML +- CSS +- JavaScript + +从工程角度看,它们本质上都属于**代码**: +也就是一段一段、遵循固定规则的文本指令;这些指令虽然是人写出来的,但最终是**由浏览器来阅读和执行**的。 + +为了方便理解,我们可以把这三者类比为一栋房子的不同方面: + +1. **HTML:搭骨架,告诉浏览器“有什么”** + HTML 负责描述页面上的“结构”和“元素”。对浏览器来说,HTML 就像是一张建筑结构草图:哪里有一堵墙,哪里有一扇门,哪里有一扇窗。 + - 例如:页面中有一个标题、一段文字、一个按钮、一张图片。 + +2. **CSS:定样式,告诉浏览器“长什么样”** + CSS 负责控制界面的视觉呈现。它相当于给已经搭好的“骨架”穿上合适的“衣服”和“装修”。 + - 例如:按钮是蓝色的、带圆角;文字需要居中对齐;背景需要是浅灰色。 + +3. **JavaScript:管行为,告诉浏览器“怎么动起来”** + JavaScript 负责页面的交互逻辑和动态行为。它更像是这栋房子里的“电路”和“开关”,决定各种设备在什么情况下被触发。 + - 例如:点击按钮后弹出提示;表单提交前先检查是否填写完整;游戏角色按一定规则移动。 + +这三者虽然形式上都是“代码”,但承担的职责并不相同。浏览器会在加载页面时,将它们分别读入,然后按既定顺序执行:先根据 HTML 搭出结构,再根据 CSS 进行渲染,最后由 JavaScript 负责交互和逻辑,让整个页面真正“活起来”。 + +### 2. 一个简单的执行链路示例 + +下面我们通过一个极简示例,来直观感受一下“从代码到效果”的完整链路。 + +![](images/image9.png) + +假设我们希望在页面上放置一个可以点击的按钮,并在点击时给用户一个提示。 + +1. **HTML:声明有一个按钮** + + ```html + + ``` + + 当浏览器读到这行代码时,会理解为: + 页面上需要出现一个按钮,按钮上的文字是“点我”。 + +2. **CSS:设置按钮的外观** + + ```css + button { + background-color: #3498db; /* 蓝色背景 */ + color: white; /* 白色文字 */ + border: none; /* 无边框 */ + padding: 10px 20px; /* 适当留白 */ + border-radius: 4px; /* 稍微圆角 */ + } + ``` + + 浏览器在渲染页面时,会把这段样式规则应用到刚才创建的按钮上,使其变成一个蓝底白字、带圆角的按钮。 + +3. **JavaScript:定义点击时的行为** + + ```javascript + document.querySelector('button').onclick = function () { + alert('你点了我!') + } + ``` + + 当浏览器执行到这段 JavaScript 时,会给按钮绑定一个“点击事件”。 + 此后,每当用户点击这个按钮时,页面上就会弹出提示框。 + +从用户的视角来看,只是“打开网页 → 看到一个按钮 → 点了一下 → 出现提示”。 +但在背后,浏览器实际上经历了一个完整的执行过程:**解析 HTML → 应用 CSS → 执行 JavaScript → 响应用户操作**。 + +这就是前端“三件套”在一个最简场景下的协同方式。 + +### 3. 现代前端框架:在“三件套”之上的进一步抽象 + +随着前端应用不断演进,单纯依赖 HTML、CSS 和 JavaScript 手工组织代码,逐渐暴露出一系列问题: + +- 页面结构日益复杂,代码量急剧增加; +- 相同的界面片段需要多处复制粘贴,维护成本高; +- 数据变化频繁时,需要手动更新界面,容易出错。 + +在这种背景下,**现代前端框架**应运而生。所谓“框架”,可以理解为一套经过实践检验的**固定结构和约定**,帮助开发者在统一的规则下组织代码,从而降低复杂度、提高可维护性。 + +以常见的 React 为例,现代前端框架通常带来以下几方面的能力提升: + +1. **组件化:把页面拆成可复用的“模块”** + 一个完整的页面,可以被拆解为若干相对独立的区域:导航栏、侧边栏、内容区、评论列表、按钮组等。 + 在框架中,每一个区域都可以被定义为一个“组件”,组件内部负责自己的结构、样式和行为,同时又可以被组合、嵌套和复用。 + 这样做的直接好处是:修改或复用某一部分时,只需关注对应组件即可,避免整页代码纠缠在一起。 + +2. **状态驱动:数据变化带动界面更新** + 传统方式下,当数据发生变化时(例如排行榜分数更新),开发者往往需要手动找到对应的界面元素,逐条更新内容。 + 在框架中,我们只需要更新组件内部维护的“状态”,框架就会自动计算出哪些地方需要重新渲染,并完成界面更新。这种“数据驱动界面”的方式,大大减少了手工操作和出错概率。 + +3. **统一规范:结构清晰,便于协同与自动生成** + 现代前端框架通常对文件组织、组件命名、数据流转等方面提供明确约定。 + 对于 AI 而言,这种稳定、一致的结构更加友好,有利于自动生成质量更高、逻辑更清晰的代码,也更便于后续维护和扩展。 + +![](images/image11.png) + +### 4. 在 Vibe Coding 中如何利用这些能力? + +在 Vibe Coding 的实践中,我们并不要求每一位用户都深度掌握 HTML、CSS、JavaScript 或某一前端框架的所有细节。 + +更现实的目标是: + +- 在概念层面,理解“前端页面是由浏览器执行一组规则生成的”,这组规则主要由 HTML、CSS 和 JavaScript 组成,它们本质上都是代码; +- 知道现代前端框架(如 React)是在这三者之上,对页面结构和交互逻辑的一种进一步组织方式,有助于 AI 更稳定地生成可维护的前端代码。 + +基于这些认识,在与 AI 协作时,我们可以给出更具指向性的指令,例如: + +> “请使用 React 帮我实现一个包含排行榜的页面,右侧展示分数列表,点击某一行时在下方显示该玩家的详细信息,整体风格简洁、现代。” + +在这种模式下,**你不必亲自完成每一行代码的书写**,而是通过理解基本概念与角色分工,扮演好“提出需求、检查结果、反复迭代”的角色,让 AI 负责具体实现细节,从而大幅降低前端开发的门槛。 + +## 附录 2:到底什么是 Vibe Coding + +> 💡 什么是 Vibe Coding?计算机科学家 [Andrej Karpathy](https://karpathy.ai/)(OpenAI 的联合创始人之一,特斯拉前 AI 负责人)于 2025 年 2 月提出了 **vibe coding** 一词。这个概念指的是一种依赖于 LLM 的编码方法,**允许程序员通过提供自然语言描述而不是手动编写代码来生成可工作的代码。** + +![1767350588191](images/1767350588191.png) + +从字面上看,Vibe Coding 可以理解为一种“用说的方式来做开发”。它的核心变化在于:你不再需要自己一行一行写代码、查语法、调 Bug,而是直接用自然语言描述你想要的东西,例如: + +“我需要一个登录页面,上面有手机号输入框和验证码输入框。” +“登录成功后,跳转到首页,并在右上角显示用户名。” +“给我一个简单的贪吃蛇小游戏,可以用键盘方向键控制。” +大语言模型(LLM)会把这类描述自动翻译成真正可以运行的代码,并生成对应的页面、逻辑和数据结构。你看到效果后,再用自然语言提出修改意见,例如“按钮再大一点”“背景换成深色”“得分记录下来并显示排行榜”,AI 会继续按你的要求调整实现。 + +在这种模式下,你不需要先学会编程语言,再去写代码;而是把主要精力放在:说清楚要做什么、看到结果后判断“哪里不对”、再提出新的修改。AI 则负责把这些高层的想法落成具体实现,从而显著减少机械、重复的编码工作。 + +你可以点击这里查看更多关于 vibe coding 的细节:[https://www.ibm.com/think/topics/vibe-coding](https://www.ibm.com/think/topics/vibe-coding) + +你可以点击这里查看更多关于 Karpathy 的分享内容:[https://karpathy.bearblog.dev/blog/](https://karpathy.bearblog.dev/blog/) + +### 如何假装自己是 Vibe Coding 大师 + +实际上,在真正的 vibe coding 过程中,我们通常不会使用很多复杂的提示词。也许我们在开始时需要为整个程序提供一个具体且适度复杂的提示词,但在那之后的每一步,你可能只需要以下类型的提示词: + +```JSON +"代码里有个 bug,请修复它。" +"我不要部分代码,给我完整的修改后的代码。" +"你的代码还是有问题。" +"请再次修改并给我完整的修正后的代码。" +"刚才还能运行,为什么现在不能运行了?" +"你没理解我的意思吗?不要改我原来的代码。" +"不要添加任何调试功能。" +"不要做我没让你做的事。" +"我让你实现的功能在哪里?" +"你听不懂我说的话吗?" +"我只要一个函数。" +"我告诉过你参考我之前的代码。" +"请不要添加不必要的注释。" +"请不要修改我原始代码的基本逻辑。" +"帮我修改代码。" +"基于我的代码修改..." +"不要改我的变量名!!!" +"不要改原来的函数名!" +"不要乱动我的变量。" +"不要添加额外的功能。" +"不要只生成框架,生成完整的代码。" +``` + +这听起来可能有点夸张,但实际上,这些就是我们在日常工作中可能使用的提示词。由于大语言模型的**上下文长度限制**,或者有时因为它们的**指令遵循能力**不是很强,模型可能会忘记对话早些时候讨论的内容。在 vibe coding 中,我们倾向使用长上下文的模型,并且使用指令遵循能力强的模型,我们可以通过这两者的排行或者指标来判断其是不是好模型。 + +或者,由于训练数据集的风格,大模型倾向于以其训练数据的风格回答。例如,有些人说话很严肃,有些人喜欢添加很多修饰,而有些大模型喜欢在代码中添加很多注释或不必要的模块。 + +## 附录 3:模型上下文 + +模型上下文可以理解为 AI 的短期记忆。它指的是在当前一次对话或一次任务中,模型能够“看到”和“记住”的所有文本内容,包括你之前输入的问题、系统提供的说明、相关资料等。 + +正是因为有上下文,AI 才能理解你在接着前面的内容继续提问,才能进行一轮一轮、看起来连贯自然的对话。如果没有上下文,你的每一句话在模型看来都像是一次全新的提问,它无法知道你之前说过什么,也就谈不上延续对话。 + +每个模型都有自己的有效上下文长度(context window)。这个长度通常用 token(可以粗略理解为“字词片段”的单位)来衡量,目前主流模型大多在 32k~128k token 之间。上下文越长,模型一次能“读”的内容就越多,例如: + +- 一次性读完一篇较长的论文或报告 +- 在同一轮对话中引用多篇资料、多个案例 +- 让模型记住之前几轮的复杂讨论结论 + +当你输入的内容接近或超过模型的上下文限制时,往往会出现一些常见现象: + +- 模型开始遗忘前面长文本中的细节或关键信息 +- 对话进行到后面,话题逐渐偏离最初目标 +- 对同一材料的不同问答之间,引用的内容不一致 + +这些现象并不是模型突然“变笨”,而是上下文容量被用满或接近用满后产生的自然结果。 + +在实际使用中,我们既希望上下文尽可能长,又要意识到: + +- 上下文越长,占用的算力资源越多 +- 对应的调用成本(费用)也会随之增加 + +因此,在设计 AI 应用时,需要在让模型看得足够多和控制成本、提升效率之间做平衡。例如: + +- 对真正需要长期保留的信息进行提炼后再交给模型 +- 对不再需要的细节信息,避免一遍又一遍原样塞入上下文 +- 使用外部知识库等方式,把“长期记忆”交给系统,而不是强行塞进模型上下文中 + +## 附录 4:指令遵循能力 + +指令遵循能力指的是:模型在理解你的指令之后,能否准确、完整地按照你的要求执行。它不仅包括能回答问题,还包括能按指定格式、风格、步骤完成任务。 + +例如,下面这些都是对模型有明确要求的指令: + +- 将这篇文章总结为三个要点 +- 用正式、礼貌的语气写一封回复邮件 +- 把这个词翻译成英文,并各造一个例句 +- 从文章中提取作者、时间和主要事件 + +一个指令遵循能力强的模型,通常具备以下特征: + +- 按要求的数量输出内容 + 例如要求总结三个要点,就不会给出五条。 +- 覆盖所有指定的要素 + 例如要求提取作者、时间和事件,就不会遗漏其中任何一项。 +- 遵守指定的格式和语气 + 例如要求使用正式语气,就不会输出过于口语化的回复。 +- 不做不必要的额外延伸 + 例如只要求翻译和造句,就不会额外输出一大段无关解释。 + +在实际应用中,强指令遵循能力非常重要,原因包括: + +- 提高稳定性:同样的指令在不同时间、多次运行时,输出结构和行为模式更加一致,不容易随意发挥 +- 提高可复现性:当你把一段提示词配置到产品或流程中时,可以预期模型大致会怎样响应,方便测试和迭代 +- 便于系统集成:当模型输出符合预期格式时,更容易与后端程序、工作流或其他工具自动对接 + +因此,在选择和评估一个大语言模型时,除了关注它是否聪明、知识覆盖是否广之外,还需要特别关注它的指令遵循能力。对于工业级应用来说,能否稳定而准确地执行指令,往往比偶尔给出一次惊艳回答更重要。 diff --git a/docs/extra/extra4/images/image1.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/image1.png similarity index 100% rename from docs/extra/extra4/images/image1.png rename to docs/stage-1/1.1-introduction-to-ai-ide/images/image1.png diff --git a/docs/extra/extra4/images/image10.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/image10.png similarity index 100% rename from docs/extra/extra4/images/image10.png rename to docs/stage-1/1.1-introduction-to-ai-ide/images/image10.png diff --git a/docs/extra/extra4/images/image11.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/image11.png similarity index 100% rename from docs/extra/extra4/images/image11.png rename to docs/stage-1/1.1-introduction-to-ai-ide/images/image11.png diff --git a/docs/extra/extra4/images/image12.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/image12.png similarity index 100% rename from docs/extra/extra4/images/image12.png rename to docs/stage-1/1.1-introduction-to-ai-ide/images/image12.png diff --git a/docs/extra/extra4/images/image13.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/image13.png similarity index 100% rename from docs/extra/extra4/images/image13.png rename to docs/stage-1/1.1-introduction-to-ai-ide/images/image13.png diff --git a/docs/extra/extra4/images/image14.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/image14.png similarity index 100% rename from docs/extra/extra4/images/image14.png rename to docs/stage-1/1.1-introduction-to-ai-ide/images/image14.png diff --git a/docs/extra/extra4/images/image15.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/image15.png similarity index 100% rename from docs/extra/extra4/images/image15.png rename to docs/stage-1/1.1-introduction-to-ai-ide/images/image15.png diff --git a/docs/extra/extra4/images/image16.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/image16.png similarity index 100% rename from docs/extra/extra4/images/image16.png rename to docs/stage-1/1.1-introduction-to-ai-ide/images/image16.png diff --git a/docs/extra/extra4/images/image17.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/image17.png similarity index 100% rename from docs/extra/extra4/images/image17.png rename to docs/stage-1/1.1-introduction-to-ai-ide/images/image17.png diff --git a/docs/extra/extra4/images/image18.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/image18.png similarity index 100% rename from docs/extra/extra4/images/image18.png rename to docs/stage-1/1.1-introduction-to-ai-ide/images/image18.png diff --git a/docs/extra/extra4/images/image19.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/image19.png similarity index 100% rename from docs/extra/extra4/images/image19.png rename to docs/stage-1/1.1-introduction-to-ai-ide/images/image19.png diff --git a/docs/extra/extra4/images/image2.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/image2.png similarity index 100% rename from docs/extra/extra4/images/image2.png rename to docs/stage-1/1.1-introduction-to-ai-ide/images/image2.png diff --git a/docs/extra/extra4/images/image20.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/image20.png similarity index 100% rename from docs/extra/extra4/images/image20.png rename to docs/stage-1/1.1-introduction-to-ai-ide/images/image20.png diff --git a/docs/extra/extra4/images/image21.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/image21.png similarity index 100% rename from docs/extra/extra4/images/image21.png rename to docs/stage-1/1.1-introduction-to-ai-ide/images/image21.png diff --git a/docs/extra/extra4/images/image22.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/image22.png similarity index 100% rename from docs/extra/extra4/images/image22.png rename to docs/stage-1/1.1-introduction-to-ai-ide/images/image22.png diff --git a/docs/stage-1/1.1-introduction-to-ai-ide/images/image23.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/image23.png new file mode 100644 index 0000000..afadf2e Binary files /dev/null and b/docs/stage-1/1.1-introduction-to-ai-ide/images/image23.png differ diff --git a/docs/extra/extra4/images/image3.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/image3.png similarity index 100% rename from docs/extra/extra4/images/image3.png rename to docs/stage-1/1.1-introduction-to-ai-ide/images/image3.png diff --git a/docs/stage-1/1.1-introduction-to-ai-ide/images/image32.webp b/docs/stage-1/1.1-introduction-to-ai-ide/images/image32.webp new file mode 100644 index 0000000..76e21be Binary files /dev/null and b/docs/stage-1/1.1-introduction-to-ai-ide/images/image32.webp differ diff --git a/docs/extra/extra4/images/image4.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/image4.png similarity index 100% rename from docs/extra/extra4/images/image4.png rename to docs/stage-1/1.1-introduction-to-ai-ide/images/image4.png diff --git a/docs/extra/extra4/images/image5.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/image5.png similarity index 100% rename from docs/extra/extra4/images/image5.png rename to docs/stage-1/1.1-introduction-to-ai-ide/images/image5.png diff --git a/docs/extra/extra4/images/image6.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/image6.png similarity index 100% rename from docs/extra/extra4/images/image6.png rename to docs/stage-1/1.1-introduction-to-ai-ide/images/image6.png diff --git a/docs/extra/extra4/images/image7.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/image7.png similarity index 100% rename from docs/extra/extra4/images/image7.png rename to docs/stage-1/1.1-introduction-to-ai-ide/images/image7.png diff --git a/docs/extra/extra4/images/image8.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/image8.png similarity index 100% rename from docs/extra/extra4/images/image8.png rename to docs/stage-1/1.1-introduction-to-ai-ide/images/image8.png diff --git a/docs/extra/extra4/images/image9.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/image9.png similarity index 100% rename from docs/extra/extra4/images/image9.png rename to docs/stage-1/1.1-introduction-to-ai-ide/images/image9.png diff --git a/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-26-33.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-26-33.png new file mode 100644 index 0000000..2584a8b Binary files /dev/null and b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-26-33.png differ diff --git a/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-27-13.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-27-13.png new file mode 100644 index 0000000..0b199d6 Binary files /dev/null and b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-27-13.png differ diff --git a/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-29-12.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-29-12.png new file mode 100644 index 0000000..3d734e6 Binary files /dev/null and b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-29-12.png differ diff --git a/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-30-51.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-30-51.png new file mode 100644 index 0000000..1d1c3f6 Binary files /dev/null and b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-30-51.png differ diff --git a/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-33-37.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-33-37.png new file mode 100644 index 0000000..0f72910 Binary files /dev/null and b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-33-37.png differ diff --git a/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-37-39.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-37-39.png new file mode 100644 index 0000000..e7ea936 Binary files /dev/null and b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-37-39.png differ diff --git a/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-42-53.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-42-53.png new file mode 100644 index 0000000..cf3f91e Binary files /dev/null and b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-42-53.png differ diff --git a/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-44-36.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-44-36.png new file mode 100644 index 0000000..91c4132 Binary files /dev/null and b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-44-36.png differ diff --git a/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-49-33.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-49-33.png new file mode 100644 index 0000000..9e92953 Binary files /dev/null and b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-49-33.png differ diff --git a/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-50-31.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-50-31.png new file mode 100644 index 0000000..b027394 Binary files /dev/null and b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-50-31.png differ diff --git a/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-52-55.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-52-55.png new file mode 100644 index 0000000..88fbc25 Binary files /dev/null and b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-52-55.png differ diff --git a/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-53-24.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-53-24.png new file mode 100644 index 0000000..3eed073 Binary files /dev/null and b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-10-53-24.png differ diff --git a/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-11-00-57.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-11-00-57.png new file mode 100644 index 0000000..ea4df0e Binary files /dev/null and b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-11-00-57.png differ diff --git a/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-11-28-43.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-11-28-43.png new file mode 100644 index 0000000..d1d39d8 Binary files /dev/null and b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-11-28-43.png differ diff --git a/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-11-35-51.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-11-35-51.png new file mode 100644 index 0000000..dc1119f Binary files /dev/null and b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-11-35-51.png differ diff --git a/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-11-35-55.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-11-35-55.png new file mode 100644 index 0000000..dc1119f Binary files /dev/null and b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-11-35-55.png differ diff --git a/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-11-36-23.png b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-11-36-23.png new file mode 100644 index 0000000..4451de0 Binary files /dev/null and b/docs/stage-1/1.1-introduction-to-ai-ide/images/index-2026-01-09-11-36-23.png differ diff --git a/docs/stage-1/1.1-introduction-to-ai-ide/index.md b/docs/stage-1/1.1-introduction-to-ai-ide/index.md new file mode 100644 index 0000000..261703d --- /dev/null +++ b/docs/stage-1/1.1-introduction-to-ai-ide/index.md @@ -0,0 +1,1258 @@ +# 初级二:认识 AI IDE 工具 + +## 本章导读 + +还记得上一章里,你用 AI 生成的第一个贪吃蛇游戏吗?它说明只用自然语言,已经可以让 AI 搭出一个完整、可运行的原型。与此同时,在 z.ai 这样的网页 IDE 里进行开发时,你可能会感受到限制:项目一变大,代码管理和调试就不顺手,对话次数有最终上限。 + +这些问题主要来源于工具形态本身,而不是 AI 能力的不足。本章将围绕本地开发环境展开讲解:你将学会从 z.ai 过渡到本地的开发环境,学会在自己的电脑上搭建完整的开发环境,理解什么是 IDE、什么是 AI IDE,以及如何在日常开发中高效地使用它们。 + +最后,我们会在本地 AI IDE 中复现类似 z.ai 贪吃蛇游戏的实战流程,完成一个由你亲自设计的小游戏。 + +- 预计时间:约一天,可分多次完成 +- 预期产出:使用 Trae 产出 1 个自创小游戏 + +## 1. 写代码需要什么环境和工具 + +从“能不能写代码”,到“能不能把一个项目长期、稳定地维护下去”,对环境和工具的要求是完全不同的。 + +理论上,只用系统自带的记事本或者 Word 文档也能写代码——它们本质上都是能输入纯文本的工具。对于刚刚试着写几行代码、完成一次性的小实验来说,这样做勉强可行。 + +但一旦进入持续开发,问题就会立刻暴露出来:看不到语法高亮,错误位置只能靠肉眼去找;没有自动补全,每个标识符都要从头敲到尾;缺少项目结构视图,文件一多就很难迅速定位;代码运行出错时,也缺乏调试工具协助排查。这些“缺失”,会让开发变得既低效又容易出错。 + +> 这里提到的几个概念简单解释一下,方便还不熟悉计算机术语的同学理解: +> +> **语法高亮:** 编辑器会根据代码的语法,把不同类型的内容用不同颜色显示,比如关键字是蓝色、字符串是绿色,这样更容易看清代码结构,也更容易发现拼写或语法错误。 +> +> **自动补全:** 当你只敲出代码的一部分单词或函数名时,编辑器会自动联想后面的内容,帮你补全,或者列出候选项,让你点一下就行,既省力也能减少输错。 +> +> **标识符:** 给代码里的各种“东西”起的名字,比如变量名、函数名、类名等,就像给不同文件夹贴上“图片”“作业”“账单”这样的标签,方便后面找到和使用。 +> +> **项目结构视图:** 用树状或列表的方式,把一个项目里的所有文件和文件夹展示出来,你不用在电脑里一层层点路径,只要在侧边栏点一下文件名,就能快速打开对应代码。 +> +> **调试工具:** 专门用来帮你查错的工具。它可以让代码一行一行地执行、在中途暂停、查看每个变量当前的值,从而找到“到底是哪一步出了问题”,而不是只能反复打印日志、到处猜。 + +因此,当目标从“试着写几行代码”升级为“做一个可以长期维护、持续迭代的项目”时,仅有一个能高亮语法的代码编辑器还不够,你通常需要选择并熟悉至少一款 IDE,把它作为自己的主要开发环境。我们会在接下来详细介绍什么是 IDE。 + +## 2. 什么是 IDE,为什么需要 IDE + +在最早期的编程时代,我们只需要在一个简单的文本文件里写好程序,再用专门的语言处理器去读取并打包执行文件即可。但随着代码量越来越大、项目结构越来越复杂,人工管理大量文件、手动编辑庞大的项目变得越来越困难。开发者迫切需要一种工具,能够高效管理和切换大量代码文件,支持多种编程语言的语法高亮,并可以快速定位和调试问题。于是,集成开发环境(IDE,Integrated Development Environment)就应运而生了。 + +你可以把 IDE 理解成一种专门用来“编辑、管理、运行和调试”各种应用源代码的程序。在真正打包发布之前,不同语言写出来的程序本质上只是特定格式的代码文件而已,你可以用普通文本编辑器打开它们,也可以用 IDE 打开。早期的计算机几乎完全通过终端来操作(只用键盘就能完成所有操作,几乎不需要鼠标),所以早期的 IDE 外观也非常“原始”——除非你额外安装插件来实现简单的交互式界面。 + +![](images/image1.png)![](images/image2.png) + +终端界面(Terminal) 图片来源:https://en.wikipedia.org/wiki/File:Emacs-screenshot.png + +一个非常知名、功能成熟的“内置 IDE”叫做 `Vim`。在很多服务器上,你都可以直接用它来编辑文件(服务器通常没有显示屏,只能通过键盘远程操作)。 + +![](images/image3.png) + +只用键盘操作无法忍受,所以我们需要能使用鼠标操作的现代 IDE 。现代 IDE 通常具有更加美观直观的图形界面,并提供更强大的编辑、运行和调试能力。一个典型的 IDE 通常包含以下核心组件: + +- **源代码编辑器(Source Code Editor)**:专门用于编写和编辑代码的文本编辑器,一般具备语法高亮、代码自动补全、实时错误提示等功能。 +- **构建与运行工具(编译器 / 解释器)**:IDE 内置编译器或解释器,可以将开发者写好的源代码转换成计算机可以执行的机器代码。 +- **调试器(Debugger)**:用于测试和排查代码错误的工具。它支持逐行执行代码、查看变量状态、设置断点等,帮助开发者定位并修复程序中的问题。 + +除此之外,现代 IDE 往往还内置版本控制工具(如 Git)和项目管理工具等实用功能。当下最流行的 IDE 之一是微软出品的 **[Visual Studio Code (VS Code)](https://code.visualstudio.com/)**。它轻量、可扩展性极强,因此被广泛使用。当然,也有很多开发者推荐 JetBrains 家的专业 IDE,比如用于 Python 的 PyCharm、用于 C/C++ 的 CLion 等,它们对特定语言提供了更深入、更完整的支持。但从入门友好度和通用性角度出发,我们更推荐初学者优先选择 VS Code 作为主要开发工具。 + +![](images/image4.png) + +Visual Studio Code(简称 VS Code)是由微软开发的一款免费、开源且功能强大的现代代码编辑器。自 2015 年发布以来,凭借优异的性能和灵活性,它迅速成为全球最受欢迎的开发工具之一。 + +VS Code 的核心理念之一是“一切皆插件”。不同编程语言可以用来编写不同类型的程序,而每种语言都有自己独特的语法高亮规则和导航能力(比如“跳转到定义”“查找引用”等)。要让一个 IDE 原生支持所有语言几乎是不可能的——从逻辑上讲,你会需要为每一种语言单独准备一个 IDE 才行。 + +VS Code 巧妙地通过“插件机制”解决了这一问题。比如,如果你要写 Python,就安装 Python 插件,它会提供 Python 专属的语法高亮、自动补全和代码导航功能;如果你要写 C/C++,则可以安装对应的 C/C++ 插件来获得相应支持。在不安装任何插件的情况下,VS Code 本质上只是一个“高级的文本文件管理器”;当你为某种语言安装了对应插件之后,它就会“变身”成该语言的理想开发工具。 + +![](images/image5.png) + +除了编写代码以外,你甚至可以把 VS Code 当作编辑 Markdown 文档的工具来使用。 + +![](images/image6.png) + +总之,你可以在 VS Code 的扩展市场中浏览和下载各类扩展,为不同类型的文件提供更好用的编辑体验,也可以根据需要搜索不同语言和调试工具的插件,尝试它们如何提升你的工作效率。 + +最后,我们用一句话来总结 IDE 的意思:`IDE 是一种提供开发环境的软件,它提供了一整套工具,帮助开发者高效写代码和运行程序。` + +## 3. AI IDE 和普通 IDE 有什么不同 + +普通 IDE(比如原版 VS Code)本质上是一套“工具箱”: +可以打开项目、写代码、运行和调试,也能装插件,但前提是你需要自己知道要做什么、怎么做: + +- 报错时,自己读提示、自己查哪一行有问题; +- 想加新页面或新接口,自己找对应文件、自己写代码; +- 想配置环境或打包,自己查文档、按步骤操作。 + +但在 AI IDE 里,你可以直接使用大语言模型帮助你进行编码和修改文件: + +- 直接说“做一个登录页”,它先生成基础代码结构; +- 把报错信息和相关代码丢给它,让它先分析原因并给出修改建议; +- 在你确认后,让它自动新建文件、批量改代码,处理跨文件的体力活。 + +例如,你可以选中一段代码,让它“重构一下”或“加注释”;也可以在侧栏里问“这个项目是怎么设计的?”,通过 `@文件名` 或 `@整个项目` 指定参考范围,用一句话自动完成新建文件、写代码和运行的繁琐操作。 + +在最新版 VS Code 中,已经内置了一个大语言模型助手。你可以直接针对整个代码仓库、某个文件,甚至某个函数与模型对话。你也可以像之前在 Web 端使用自动写代码工具一样,将需求以提示词的形式发给内置的编码 Agent,让它自动帮你实现所需功能、创建文件、修改代码、配置环境等。 + +你可以下载安装 VS Code,在点击右上角的侧边栏入口,打开 AI 功能区域,体验这些能力。 + +![](images/image7.png) + +不过,VS Code 并不是 AI 能力最强的 IDE。对于需要大量 AI 辅助编码的场景,我们往往希望使用“更聪明、效率更高”的工具——好的 AI IDE 能显著节省写代码和改 Bug 的时间。下面我们会介绍几款目前比较流行的 AI IDE,你可以根据个人喜好选择任意一款 AI IDE 使用。 + +由于 VS Code 是开源的(任何人都可以下载源码并自行编译),目前市面上绝大多数 AI IDE 都是在 VS Code 基础上二次开发而来。所以你不必担心要“学习很多种 IDE”——**只要你熟悉了 VS Code 的基本用法**,迁移到这些 AI IDE 并不需要重新学习。 + +一般而言,对于不同 AI IDE 之间的差异,主要集中在四个方面:价格;可使用的模型种类(部分高级模型在某些地区可能受限);Agent 的能力(在协助写代码时的智能程度和执行能力);以及运行速度与性能。你可以根据实际测试效果进行选用,适合自己的才是最好的。 + +> 典型的 AI IDE 一般具备以下核心能力: +> +> - 智能代码生成与补全:在传统 IDE 中,我们通常是输入几个字符来补全变量名或函数名;在现代 AI IDE 中,你可以写几行伪代码或者简单说明需求,让 IDE 自动补全完整的逻辑,甚至根据指令直接生成一大段甚至整块代码。 +> - 代码理解与问答:IDE 能够理解并回答关于某段代码、某个文件,甚至整个工程目录结构的问题。 +> - 代码重构与优化:IDE 可以根据你的意图,重写或优化指定代码片段的实现逻辑。 +> - 自动生成测试:IDE 可以自动生成针对不同函数和模块的测试代码,方便你进行有针对性的测试。 +> - Agent 式任务执行:智能 Agent 可以自动生成、打包、安装、运行和修改代码,在很多任务上可以部分替代初级软件工程师的工作。 + +### [Trae](https://www.trae.ai/) + +![](images/image8.png) + +Trae 是字节跳动推出的一款 AI 编程助手,支持 100 多种编程语言,并能集成到主流 IDE 中。它的功能包括:用自然语言生成代码、自动调试、把设计稿转换为 React/Vue 组件等。在 2025 年 8 月的更新之后,Trae 新增了智能依赖导入、重命名建议、任务清单管理等功能;SOLO 模式也开始支持后端代码生成和技术架构文档编辑。 + +### [Cursor](https://cursor.com/) + +Cursor 是 Anysphere 开发的一款 AI 代码编辑器,基于 VS Code 定制,重点优化了大规模代码仓库和多文件协同的场景。它支持 GPT-4o、Claude 3.7 等模型;2025 年推出的 Claude Max 模式可以处理数百万行代码级别的项目。专业版取消了请求次数限制,非常适合复杂的企业级项目。 + +目前,Cursor 可以说是“带前端界面的 AI IDE”中综合体验最好的一款之一,用户数量庞大,功能迭代频率也很高。它最大的缺点是价格较高——专业版大约需要每月 20 美元。 + +![](images/image9.png) + +### [Qoder](https://qoder.com/) + +Qoder 是阿里巴巴推出的一款强调“透明协作”和“增强上下文工程能力”的 AI IDE。它通过 Action Flow 支持把任务拆解成多个步骤,并实时跟踪 AI 的执行过程;还支持多模型动态路由和任务状态机管理,非常适合在中大型项目中做架构治理和对遗留系统进行“反向工程”分析。 + +![](images/image10.png) + +### [CodeBuddy](https://www.codebuddy.com/) + +CodeBuddy 是腾讯云推出的一款 AI 编程工具,强调对中文指令的支持以及企业级合规能力。它提供代码补全、批量代码审查和多模型切换等功能;其中的 Craft 智能体可以实现多文件代码生成和 API 集成。企业版支持私有化部署,并通过了三级等保认证,适合金融、医疗等对数据安全要求较高的行业。 + +![](images/image11.png) + +### VS Code + [Cline](https://cline.bot/) + +Cline 是 VS Code(Visual Studio Code)的一款 AI 编程 Agent 插件,可以通过配置不同的 API 端点来灵活切换所使用的大模型。Cline 支持多模态输入、MCP 工具扩展以及成本监控,所有操作都需要用户确认后才会执行。它非常适合用于快速验证想法,或与现有开发流程集成。基础功能是免费的,企业版则支持在私有环境中部署模型。 + +![](images/image13.png) + +![](images/image14.png) + +## 4. 实战:用 AI IDE 在本地生成贪吃蛇游戏 + +前面讲的主要是“概念”和“差异”。这一小节,我们通过一次完整的实战,把抽象概念落到具体操作上:**新建一个空文件夹 → 用 AI IDE 打开 → 在侧边栏聊天,让它用 React 帮你从零生成一个贪吃蛇游戏。** 这里以上面介绍的 Trae 为例,首先需要安装和简单理解什么是 Trae。 + +### 4.1 准备工作:安装并了解 Trae + +#### 4.1.1 什么是 Trae + +Trae 的全称可以理解为 “The Real AI Engineer”,是一款由字节跳动开发的自适应 AI 集成开发环境(IDE)。它是在流行的 VS Code 基础之上构建的,这意味着,如果你之前已经习惯了 VS Code,那么在使用 Trae 时,无论是界面布局还是基础操作都会感到非常熟悉、舒适。 + +Trae 的核心目标是成为开发者的“智能编程伙伴”。通过深度集成 AI 能力,它可以自动处理大量重复性工作,为你提供更直观、更高效的开发体验。它并不仅仅是一个“代码补全工具”,而是希望贯穿整个开发工作流,从创建项目、编写代码、调试、测试到部署都提供帮助。 + +#### 4.1.2 安装 Trae + +Trae 分为国际版和中国版。国际版需要能够访问海外网络,但可以使用 GPT-5 等最新的海外模型;中国版则主要支持国内最新的大模型,例如 GLM、Qwen、Kimi 等。 + +国际版下载地址:https://www.trae.ai/ +中国版下载地址:https://www.trae.cn/ + +#### 4.1.3 Trae 界面简介 + +从界面形态上看,Trae 与我们日常使用的 VS Code 高度相似:同样是左侧资源管理器、中间编辑区、右侧扩展面板的经典三栏布局。 + +![](images/image17.png) + +右侧的侧边栏就是 Copilot 交互窗口,也可以理解为 Agent 窗口。如果你暂时看不到它,可以点击 Trae 右上角的侧边栏图标将其打开。 + +![](images/image18.png) + +打开侧边栏之后,你会看到一个 `Builder` 选项,这就是 Agent 模式。简单理解,它相当于 z.ai 的“本地版”,可以帮你操作本机环境,安装运行环境、打开网页等。 + +![](images/image19.png) + +点击 “Builder” 后,你会看到 “Chat” 模式和 “Builder with MCP” 模式: + +- **Chat 模式**:主要用于和当前文件夹里的代码对话,或者当作普通聊天模型来使用。(你可以通过左上角的 “File” 菜单打开一个文件夹,在这个文件夹中进行编辑操作。在这种情况下,Builder 创建或修改的文件都只会发生在这个文件夹内部。) +- **Builder with MCP 模式**:为 Agent 提供了更多可用工具(例如把语言模型和其他软件联通起来、查询天气等)。你可以简单理解为:MCP 能让语言模型更方便地调用各种外部工具。 + +![](images/image20.png) + +在下面的区域,你还会看到模型选择选项,点击即可修改当前使用的大模型。在中国版中,你可以选择使用 Kimi k2 或 GLM 等国内模型;如果你使用的是国际版 Trae,还可以选择 ChatGPT 或 Claude 等海外模型。不过,由于国内大模型发展非常快,Kimi、Qwen、GLM 等在很多任务上的实际体验已经接近 Claude 3.5 或 3.7,对日常开发来说已经完全够用,这里不强制要求使用国际版或者国内版进行操作。 + +**需要注意的是,这里不推荐使用 Auto 模式(自动选择模型),如果是国际版,我们推荐使用 Gemini 或者 GPT 模型, 如果是国内版,我们推荐你尝试 Kimi k2 或 Minimax、GLM 等国内模型,** 不同模型有不同的使用场景,没有教条式的一定谁比谁好在哪,你可以在不同任务遇到困难无法解决时换一个模型,通过多次测试得到属于自己的最佳实验结果。 + +![](images/image21.png) + +以上就是对 Trae 的一个简单介绍。接下来,我们可以回顾一下之前在 z.ai 中做过的操作,并尝试在 Trae 中做同样的事情。 + +### 4.2 第一步:新建空文件夹并用 AI IDE 打开 + +在正式动手之前,我们首先需要准备一个干净的项目工作目录。 +以本小节示例为例,可以在本地新建一个名为 snake-game-react 的空文件夹。 + +随后,打开已安装好的 AI IDE,在启动界面选择打开文件夹或Open Folder,将该空文件夹作为项目根目录导入;也可以直接将文件夹拖入 IDE 窗口完成打开。此时,左侧资源管理器中不会出现任何代码文件,表示我们正从一个完全空白的项目状态开始。 + +### 4.3 第二步:在侧边栏聊天,让 AI 用 React 设计贪吃蛇游戏 + +接下来,打开 AI 聊天侧边栏:一般是按 `Ctrl+L` 或点击右侧聊天图标。然后在聊天里输入一个足够清晰的提示: + +> 请你用 React 架构实现贪吃蛇游戏,包含键盘控制、吃到食物变长加分、撞墙或撞到自己时显示“游戏结束”并支持重新开始。实现后帮我启动这个项目。如果遇到没安装的程序环境就自动安装没安装的环境。 + +在这个过程中,你需要意识到 AI 不只是聊天模型,它能够帮助你操作本机环境:创建文件、安装依赖、执行启动命令等。你可以直接用自然语言描述想要达成的目标,由 AI 来决定具体执行哪些命令、如何组织代码。 + +如果执行过程中遇到问题,AI 会在对话里展示报错和处理方案,你可以继续通过对话让它调整,而不必自己记住所有命令细节。 + +⚠️ 需要注意的是,例如下图所示,**有时候 AI Agent 会在执行的过程中暂停,这是因为它需要等待你输入一些信息进行交互**,比如输入创建的名字,或者回车确认指令执行。或者点击指令进行执行。一般情况我们直接回车即可,如果你不确定这步需要做什么,你可以截图当前界面询问大模型应该如何操作。 + +如图所示,这里我们需要点击 Run 进行确认: +![](images/index-2026-01-09-10-52-55.png) + +如图所示,这里我们只需要输入 y 即可确认: +![](images/index-2026-01-09-10-53-24.png) + +![](images/index-2026-01-09-10-26-33.png) + +如图所示,这里我们正在创建模板,但不知道如何操作,我们可以截图该部分对大模型进行新闻: + +![](images/index-2026-01-09-10-29-12.png) + +AI Agent 在执行过程中暂停的还有一部分原因是因为此时启动了一个“服务”,我们的贪吃蛇本身属于一种“服务”,如果你看到如下命令的网址,则表示 Agent 帮我们执行了一个本地的电脑服务,我们可以访问对应的网址访问我们的贪吃蛇,由于服务需要持续启动,这里会陷入暂停。我们只需要点击 `Skip` 按钮即可。 + +![](images/index-2026-01-09-10-30-51.png) + +在这个过程中,如果你遇到一些术语和看不懂的内容,不用担心,你可以查阅附录中的“计算机术语解释”部分,或者直接向 AI 咨询,或者及时提问! + +如果你在过程中遇到不符预期的现象,例如贪吃蛇撞墙后不会结束游戏,贪吃蛇点击开始后不会移动,这时你只需要把现象描述给侧边栏 Agent 即可。如果遇到报错问题,记得截图或者复制错误到侧边栏 Agent,如果多次仍然不能解决问题,请你尝试更换模型操作。 + +稍作片刻,我们即可得到类似 z.ai 一样的结果: + +![](images/index-2026-01-09-10-33-37.png) + +我们可以点击右下角的打勾进行确定代码的变更,也可以点击 `Cancel` 按钮取消变更。或者点击 2 files need review 的地方展开查看变动后的代码。 + +这里还值得注意的是,由于修改代码并不一定正确,我们还需要知道所有的 IDE 的 Agent 都支持代码回退,例如,假设我这里不小心做了个错误的修改操作,或者这次操作的结果让你感到不满意,在修改结束后我们可以返回输入框的部分,点击 Revert 按钮将操作回退到修改前的状态,你可以修改输入的文字进行再一次操作: + +![](images/index-2026-01-09-10-42-53.png) + +### 4.4 第三步(可选):向 AI 追问代码实现细节 + +当贪吃蛇游戏已经可以正常运行时,如果你对前端或 React 还不熟,可以继续在同一个聊天窗口里,请 AI 用尽量口语化的方式帮你导览代码。你不需要切换工具,也不必刻意去翻文档,只要围绕当前项目持续发问即可。 + +一个比较实用的做法是,让 AI 先整体讲一遍“游戏是怎么动起来的”,再拆到具体细节。比如你可以直接提问: + +> “请从上到下讲一遍,这个贪吃蛇游戏每一步是怎么动起来的?尽量少用专业术语。” + +![](images/index-2026-01-09-10-44-36.png) + +然后再顺着它的回答继续追问关键点,例如: + +> “蛇在屏幕上的每一节身体,是用什么数据结构来记的?能打个比方吗?” +> “你是怎么控制‘隔一段时间动一下’的?这在代码里是哪一段?” +> “蛇吃到食物时,你做了哪几步操作?在哪一段逻辑里判断吃到了?” +> “撞墙和撞到自己,分别是在哪些代码里判断出来的?” + +如果你看到某个文件(比如 `SnakeGame.tsx`)但完全不知道它在干什么,也可以直接请 AI 分块说明: + +> “请把 `SnakeGame.tsx` 按功能分几块讲一下:每一块大概负责什么,用通俗一点的说法。” + +在这一轮对话中,你可以把不懂的词一律当成追问入口,比如: + +> “你刚才说的‘状态’具体指什么?能用一个生活中的例子解释吗?” +> “你说的‘定时器’在这里主要是干嘛的?如果把它去掉,会发生什么?” + +通过这种方式,你的目标不是一下子记住所有概念,而是先搞清三件事:这款游戏里有哪些核心数据(蛇、食物、分数、游戏状态等),这些数据在什么时机会发生变化(移动、吃到食物、游戏结束等),以及每一种变化对应的是哪一小段代码。只要这三点理顺了,你就基本可以看懂这份代码的主干逻辑。 + +### 4.5 第四步:让 AI 把画面变好看一点 + +这里先提醒一件对小白很重要的事情:不要只对 AI 说一句“我要把这个画面变好看”。这种说法对人类设计师都太模糊,更别说对模型了——“好看”是什么风格、哪些地方需要调整、是排版问题还是配色问题,AI 都无法从你这一句里读出来。为了让 AI 真正做出接近你心里预期的效果,你需要学会把“我想要好看”这种模糊目标拆成一串具体、可执行的小要求。 + +比如,很多人一开始会这样说: + +> “我要把这个画面变好看一点。” + +例如,你可以先给出一组整体需求: + +> “请帮我把游戏界面整体美化一下: +> +> - 游戏区域居中显示,不要贴在左上角; +> - 换成较浅的背景色,让蛇和食物更醒目; +> - 把分数放大,放在明显的位置; +> - 以蓝色为主色调,美化一下整体配色和按钮。” + +如果你希望在“游戏结束”时有更清晰的反馈,可以进一步补充: + +> “当游戏结束时,请在画面中央显示‘游戏结束’,下面有一个‘重新开始’按钮,可以重置游戏。” + +AI 会根据你的描述,直接修改 React 组件和样式。保存后刷新浏览器,你就能看到新的界面。如果效果和你想象的还有差距,可以继续做小步调整,例如: + +> “分数再大一点,颜色更醒目一些。” +> “游戏区域再紧凑一点,四周预留一点留白。” +> “重新开始按钮改成蓝色圆角风格,放在提示下方居中。” + +在这个阶段,如果某次修改导致报错,也不需要自己硬查。直接把错误信息复制到聊天窗口,或者配合一段简要描述,比如“这是我刚才美化界面后出现的错误”,让 AI 在当前项目上下文里帮你定位和修复。这样你就可以在“不断对话、不断刷新”的循环中,把一个能跑的 Demo 逐步打磨成界面清晰、交互顺畅的小型成品。 + +### 4.6 (可选)参考 z.ai 架构修改贪吃蛇结果 + +对于 vibe coding 小白来说,最难的事情反而是不知道什么才算是“最佳实践“,不知道怎么样的架构才是最适合的;因为不知道计算机基础,所以没办法很好的引导 AI,解决这个难题的方法是”直接参考“;还记得我们之前说过的 z.ai 中可以查看代码吗?其实对应 README(项目中用于介绍功能和技术架构的部分)中已经给出了一个最佳架构参考: + +![](images/index-2026-01-09-10-49-33.png) + +我们想要让本地的结果尽量符合 z.ai 的结果,我们可以复制这个 README 的全部内容,粘贴到 Trae 的侧边栏中,让他根据 README 的架构,修改本地的代码。 + +![](images/index-2026-01-09-10-50-31.png) + +最后我们能得到与 z.ai 高度相似的页面设计风格: + +![](images/index-2026-01-09-11-00-57.png) + +## 5. 界面上每个按钮是干什么的 + +在上述操作中,我们已经快速跑通了最小程序生成闭环,但我们仍然对 IDE 不能说得上熟悉。为了彻底熟悉这个之后与我们长期相处的工具。我们会在这一节中对 IDE 的每个细节环节进行深入解释,首先从界面开始,不同 AI IDE 的界面略有差异,但大部分都延续了 [VS Code 的布局](https://code.visualstudio.com/docs/getstarted/getting-started)。 + +![](images/image32.webp) + +其中每个部分的具体作用为: + +**Title Bar(标题栏)**:在窗口最上面那一条。你可以把它当成“窗口的名字牌”,通常会显示 VS Code、当前打开的文件名等信息;右边还有最小化/最大化/关闭按钮(用来控制窗口大小和关闭窗口)。 + +**Activity Bar(活动栏)**:最左边那一排小图标。它像“功能切换按钮”,点不同图标就会切换不同工具,例如文件(Explorer)、搜索(Search)、Git 管理(Source Control)等。现在不需要全记住,先理解它负责“切换左侧显示什么”。 + +**Side Bar(侧边栏)**:在 Activity Bar 右边那块区域。它会根据你选择的功能变化:点文件就显示文件夹/文件列表;点搜索就显示搜索框和结果。可以理解为“左边的内容区”。 + +**Editor Groups(编辑器分组/编辑区)**:中间最大的一块,就是你看代码、写代码的地方。打开文件后内容会显示在这里;上面有标签页(Tab)方便同时打开多个文件;也能分成左右两块(分屏)来对照看。 + +**Breadcrumbs(路径导航)**:在代码上方的一行路径提示,告诉你当前文件在项目里的位置(例如 `src > pages > index.js`)。你也可以点它快速跳到上一级文件夹或相关位置,帮助你不迷路。 + +**Minimap(迷你地图/代码缩略图)**:编辑区右侧细细的一条缩略预览。它像“整篇代码的缩小版地图”,让你在很长的文件里快速拖动跳到某个位置。 + +**Panel(面板/底部面板)**:通常在窗口底部,里面常见 Terminal(终端)、Problems(问题)、Output(输出)、Debug Console(调试控制台)等。简单说:这里用来运行命令、看程序输出、看错误提示。错误信息看起来可能有点“凶”,其实是在告诉你哪里需要调整。 + +**Status Bar(状态栏)**:窗口最底部那一条信息栏,会显示当前状态,比如文件类型/语言、缩进方式、编码、是否有报错、Git 状态等。你可以先不深入,但它能帮你快速了解“当前编辑环境是什么情况”。 + +**更具体的详细内容解释,请查看本篇文章的[附录二](#appendix-2-vscode-menu)。** + +## 6. 怎么跟 AI 说话才有效 + +随着 AI 能力越来越强,我们已经可以把很多“让程序员写代码”的工作交给 AI 来完成。 +但是,在实际使用中你会发现:同样是用同一个 AI,有的人几句话就能要到能跑起来的小项目,有的人聊了半天,结果却完全不是自己想要的,其差别往往不在于“谁更聪明”,而在于——你跟 AI 说话的方式,是不是足够具体、足够有步骤。 +本节我们从几个常见场景出发,介绍一些适合完全小白的提问方式,帮助你更稳定地让 AI 给出可用的结果。 + +### 6.1 说清楚你的需求:从“模糊想法”到“具体说明” + +很多人第一次用 AI 时,习惯只说一句非常笼统的话,比如: + +> “帮我做个网页。” +> “帮我写个小程序。” + +在这种情况下,AI 只能自己“脑补”你想要什么,于是它会随便给你一个看上去挺完整的东西,但往往和你真正想做的差很多。 +要让 AI 更听得懂你的意思,需要把“脑子里的想法”拆开,用几句话一步步说清楚。 + +可以从这几个方面来补充: + +1. **告诉它,你拿这个东西来干嘛** + 比如,不要只说“个人网站”,而是说: + - “我想做一个只包含一页内容的个人简介网页,用来发给招聘的人看。” + +2. **告诉它,大概需要哪几块内容** + 不用说专业词,只要描述你希望页面上出现什么,比如: + - “页面要有三个部分:最上面是名字和一句自我介绍,中间列出几条工作经历,最下面放邮箱和微信号。” + +3. **告诉它,你的水平和限制** + 让 AI 按照小白能接受的方式来做,比如: + - “我完全不会写代码,请只用最简单的写法,让我可以直接复制到一个文件里,在浏览器里打开。” + +4. **告诉它,你希望怎么拿到结果** + 例如: + - “请给我一份可以直接保存为 `index.html` 并在浏览器里打开的完整代码。” + +综合起来,可以让你对 AI 这样说: + +> “我完全不会写代码,想做一个只包含一页内容的个人简介网页,用来发给招聘的人看。 +> 页面需要三个部分:上面一行是名字和一句自我介绍,中间是几条工作经历,下面是邮箱和微信号。 + +当你把这些信息说清楚之后,AI 就能更接近你真正的需求,而不是随便给你一个“看起来很厉害但用不上的东西”。 + +### 6.2 用对节奏:先“能跑起来”,再一点点变复杂 + +对完全小白来说,最常见的坑是:一上来就想做一个“非常完整”“功能很多”的东西。 +比如: + +> “帮我做一个像淘宝那样的网站。” +> “帮我做一个可以注册、登录、下单的系统。” + +结果往往是:AI 给你一大团代码,你复制之后不是打不开,就是到处报错;你也看不懂哪里出了问题,最后只能放弃。 + +更适合的做法,是**主动控制节奏**,让 AI 跟着你一步一步来,而不是一次性把所有东西都砸给你。可以按下面这个顺序提要求: + +1. **第一步:先要一个“最小的例子”** + 只检查一件事:能不能在浏览器里看到东西。 + 例如: + + > “请先给我一个最简单的示例,只要在浏览器里能看到一行‘这是我的主页’就行。 + > 再一步步告诉我:文件名该叫什么,应该怎么保存,怎么打开。” + +2. **第二步:在这个基础上,慢慢把内容加完整** + 当你确认“确实能看到那一行字”之后,再说: + + > “在刚才的基础上,帮我增加一个‘工作经历’区域,把完整代码重新发给我。不要只发改动的部分。” + +3. **第三步:结构差不多之后,再考虑好不好看** + 例如: + > “现在页面已经能正常显示内容了。接下来请帮我稍微美化一下:整体居中,标题大一点,用一个比较舒服的字体。请给出更新后的完整代码。” + +每加一步,你都先运行一次,确认真的有变化,再让 AI 往下加。这样就算哪一步出问题,你也可以很快回到“上一版还正常”的状态,而不用完全推倒重来。 + +### 6.3 善用截图和复制:不会说就“把画面扔给 AI” + +很多完全小白遇到的难点,不在于“不会改代码”,而是在于**不知道怎么把问题说出来**。 +比如: + +- 浏览器里突然弹出一大堆英文报错,你完全看不懂。 +- 网页的排版和你想的不一样,但你也不知道该用什么词来形容。 + +在这些情况下,不需要硬挤专业术语,最简单的方式就是——**把你看到的东西原样丢给 AI**。 + +可以这样做: + +1. **复制报错文字** + 当你看到一串红色错误消息时,可以直接复制出来,然后说: + + > “这是我运行后出现的完整错误信息。我看不懂这些英文,请先用普通人能听懂的话解释一下,这大概是什么意思。 + > 然后告诉我,我现在最简单应该怎么改。” + +2. **给 AI 看截图** + 如果你觉得“这个页面看着就是不对”,但又不会描述,可以: + - 截一张当前页面的图; + - 把你正在用的那份代码,一整段复制给 AI; + - 然后说明: + > “这是现在页面的样子,这是我现在的完整代码。 + > 我原本希望它是三列排版,现在变成一列了。请你帮我看一下原因,并给我一份改好后的完整代码。” + +3. **遇到喜欢的网页,想做个类似的** + 不需要说“这个布局叫什么”,直接: + - 截图或复制那页的主要标题、段落; + - 再说: + > “我想做一个结构和这个差不多的页面,不需要一模一样。 + > 请帮我用简单一点的代码,搭一个类似的框架出来,然后我再自己把文字换成我的。” + +简单来说:你负责“把看到的东西搬给 AI”,再用最朴素的话说“我希望它变成什么样”;剩下的“翻译成代码、解释名词、找问题”,交给 AI 来做。 + +### 6.4 当 AI 生成的代码不工作时:一套通用应对方法 + +在实际练习中,你一定会遇到这种情况: +AI 很认真地给了你一段代码,你也老老实实地复制进去了,但结果要么是浏览器一片空白,要么完全不是它说的那个效果。 +这并不代表你“学不会”,也不代表 AI 完全错了,而是你们之间还缺少几轮“来回确认”。 + +当代码“不工作”时,可以按下面这套固定流程来跟 AI 说: + +1. **先把“你做了什么 + 现在什么样”说清楚** + 避免只说“打不开”“不行”。可以这样描述: + + > 打开之后,页面是完全空白的,没有显示你说的那句欢迎文字。 + > 我打开了 xxxx 页面,其中没有刚才我说的部分啊,这不能用 + +2. **把你现在的完整代码发给 AI** + 很多时候问题出在:复制少了一行、或者上一次和这一次的内容混在一起了。 + 你可以说: + + > “下面是我现在这个文件里的全部代码。 + > 请你对比一下有没有哪里少了、写错了,或者顺序不对。 + > 请直接给我一份修正后的完整代码,不要只发一小段。” + +3. **如果有错误提示,一并给出** + 比如浏览器右上角弹出的错误,或者底部的一些红字。你可以: + - 把错误文字复制出来; + - 或者截一张图; + - 然后说: + > “这是我看到的错误提示。我完全看不懂,请先用简单的方式说明这大概是什么问题,再告诉我现在最需要改哪几行。” + +4. **要求对方用“小白模式”一步一步讲** + 你可以直接把自己的情况说清楚,让它别省略中间步骤: + + > “我完全不会写代码,请你一步一步告诉我: + > 第 1 步要改哪一行, + > 第 2 步要怎么保存, + > 第 3 步要怎么重新打开或者刷新页面。 + > 每一步都请用完整的句子写出来。” + +5. **最后,请它帮你做“应该看到什么”的对照** + 例如: + > 请先说一下,按照你改好的代码,正常情况下我打开网页应该看到什么内容。 + +只要你按照这套流程来和 AI 交互,大部分“代码不工作”的情况,都可以在几轮来回中解决掉。 +同时,你也会逐渐熟悉常见的问题类型,下次再遇到类似情况就能直接解决。 + +## 7. 小结与下一步 + +这一章里,你完成了一次从“能在网页里玩一个 AI 生成的贪吃蛇”,到“能在本地用 AI IDE 自己搭出一个小游戏”的升级。你大致搞清了三件事:写代码为什么离不开一个像 VS Code 这样的 IDE;在这个基础上,再加上 AI(Trae、Cursor 等)之后,IDE 不再只是工具箱,而是多了一个能听懂自然语言、帮你新建文件、装环境、改代码的“实习工程师”;以及 IDE 界面上每一块区域(左侧文件、底部终端、中间编辑区、右侧 AI 面板)分别管什么,用起来就不再一头雾水。 + +更重要的是,你已经实际跑通了一次完整流程:在本地新建空文件夹 → 用 AI IDE 打开 → 在侧边栏对话里描述需求 → 让 AI 生成项目并启动开发服务器 → 出现问题时,把“现象 + 全部代码 + 报错截图”一起丢给 AI,请它用“小白模式”一步步修。这个过程中,你也练习了如何写更有效的提示词:说清目标、内容结构和自己的水平,控制好节奏,从“先能跑起来”到“再变好看、变好玩”。 + +下一章,我们会把重点从“会用工具”转向“做一个真正有人愿意用的原型”:从用户视角出发,设计规则、交互和反馈,然后再让 AI 帮你把这些想法落成产品雏形。 + +## 8. 📚 作业:用本地 AI IDE 做一个更复杂的游戏 + +你已经用本地 AI IDE 做过一个贪吃蛇。现在请你再挑战一个更复杂一点的小游戏,完整走一遍“描述需求 → 生成项目 → 本地运行 → 调试迭代”的流程。 + +1. 选择一个比贪吃蛇更复杂的游戏: + - 可以是“俄罗斯方块”“打地鼠”“扫雷”“2048””飞机大战“之类 + - 或者你自己想象的一个简单原创游戏 +2. 必须用本地 AI IDE 来完成整个过程: + - 新建一个空文件夹,用 AI IDE 打开 + - 在侧边栏聊天里描述清楚你的游戏需求 + - 让 AI 负责创建文件、搭建项目结构和实现主要逻辑 + - 在本地启动开发服务器,确保游戏可以正常运行 +3. 有基本的“可玩性”和反馈: + - 至少包含开始、进行中、结束三种状态 + - 玩家有明确的操作方式(键盘或鼠标) + - 屏幕上有清晰的得分或进度反馈 +4. 至少进行 2 轮以上的迭代: + - 第一轮让 AI 做出“能玩”的版本 + - 第二轮以后,逐步提出具体改进(样式、难度、交互优化等) + +# 附录一:常见计算机术语速查表 + +这一部分不需要刻意背诵,更重要的是先在脑子里建立一个印象。 + +## 一、和“工具界面”有关的词 + +### 1. IDE、编辑器、终端 + +**IDE(集成开发环境)** +可以把 IDE 想象成“程序员的工作台”: + +- 一边是写字的桌面(编辑器), +- 一边有电源插座和按钮(运行、调试), +- 抽屉里有各种小工具(搜索、版本管理)。 + VS Code、Trae、Cursor 都属于 IDE 或基于 IDE 改的工具。 + +**代码编辑器(Editor)** +更像是“高级记事本”,只负责: + +- 让你打字写代码; +- 用颜色区分不同内容(语法高亮); +- 给你自动补全。 + IDE 里那块写代码的区域,就是代码编辑器。 + +**终端 / 命令行(Terminal / 命令行窗口)** +一个黑底白字的窗口,你在里面**输入命令**让电脑干活: + +- 比如:`npm run dev` 表示“帮我启动开发服务器”; +- `python main.py` 表示“运行这个 Python 文件”。 + 可以把它想象成:“你给电脑发一条条短信命令,它用文字回复执行结果”。 + +### 2. IDE 中几个常见区域 + +**活动栏(Activity Bar)** +最左边一排竖着的小图标,像“功能选项卡”: + +- 点文件图标 → 左边显示文件列表; +- 点放大镜图标 → 左边变成搜索; +- 点 Git 图标 → 左边显示版本管理。 + +**侧边栏(Side Bar)** +活动栏右边那一大块区域,专门显示当前模式下的内容: + +- 文件模式:展示项目里的文件和文件夹; +- 搜索模式:展示搜索结果列表; +- 源代码管理模式:展示有哪些文件被改动。 + +**编辑区(Editor)** +中间最大的区域,就是你打开文件后实际看到和修改内容的地方; +上方的标签页(Tab)是“当前打开了哪些文件”。 + +**底部面板(Panel)** +一般在最下方,常见几种: + +- Terminal(终端):输入命令跑项目; +- Problems(问题):列出出错的文件和行号; +- Output(输出):一些工具打印出来的运行信息; +- Debug Console(调试控制台):调试时的输出。 + +**状态栏(Status Bar)** +最下面那条细细的栏: + +- 显示当前文件是什么语言(JS、HTML、Python 等); +- 显示缩进是“2 个空格”还是“4 个空格”; +- 显示有没有错误、当前 Git 分支是什么。 + 可以把它当作“当前编辑环境的一张小体检单”。 + +## 二、和“网页 / 网络 / 服务”有关的词 + +### 1. URL、http、端口、本地服务 + +**URL(网址)** +就是浏览器地址栏那一串东西,比如: + +- `https://www.trae.cn/` +- `http://localhost:3000/` + 它就像“互联网世界里某个房间的完整地址”。 + +**HTTP / HTTPS** +在 URL 开头看到的 `http://` 或 `https://`: + +- HTTP:普通传输方式; +- HTTPS:多了一层加密,更安全。 + 你可以先记成:“写网页地址时,通常以 `http` 或 `https` 开头”。 + +**端口(Port)** +可以把一台电脑想象成一栋大楼,端口就是**每个房间的门牌号**: + +- `:3000` 表示 3000 号房间; +- 同一台电脑上,可以同时开多个服务,各占一个端口。 + `http://localhost:3000` 就是“访问我自己电脑上 3000 号房间里跑着的那个服务”。 + +**本地(Local / localhost)** +指的就是你自己的电脑。 + +- `localhost` 可以理解为“这台机器自己”。 + 当你访问 `http://localhost:3000`,其实是在跟自己电脑上运行的程序打交道,而不是上网访问别人家的服务器。 + +**服务(Service / Server)** +“服务”就是一个**一直在后台运行、随时听你指令**的程序: + +- 网页服务:浏览器访问一个地址时,它返回网页内容; +- 游戏服务:负责管理对局、存档、排行榜等。 + 在终端里执行 `npm run dev` 启动项目,本质上就是“在本地开了一个网页服务”。 + +## 三、和“前端 / 后端 / 数据”有关的词 + +### 1. 前端、后端 + +**前端(Frontend)** +用户**看得见、点得到**的部分: + +- 网页上的按钮、文字、图片、动画; +- React / Vue 写出来的页面。 + 负责展示界面和响应用户操作(点击、输入、拖拽等)。 + +**后端(Backend)** +用户**看不见**、在服务器上跑的那部分: + +- 存和读数据(用户信息、订单、分数等); +- 执行业务规则(登录验证、权限判断)。 + 你可以把前端比作“店面和店员”,后端比作“仓库和账本系统”。 + +### 2. 接口、请求、响应、JSON + +**接口 / API** +前端和后端事先约定好的一套“问问题 + 回答案”的规则。 + +- 前端说:“我用这个地址、这个格式来问你”; +- 后端说:“我用这个格式把结果回给你”。 + +**请求(Request)** +前端发给后端的一次“提问”: + +- 请求去哪(URL); +- 用什么方式(GET、POST 等); +- 带了什么参数(比如用户 ID)。 + +**响应(Response)** +后端给前端的“答复”: + +- 状态码(200 成功,404 找不到,500 服务器出错); +- 实际数据(多半是 JSON)。 + +**JSON** +一种用**很像 JavaScript 代码的写法**来表示数据的格式,比如: + +```json +{ + "name": "Alice", + "score": 120 +} +``` + +可以理解成“机器版的键值对记事本”,前后端经常用它来交换数据。 + +## 四、和“写代码本身”有关的词 + +### 1. 变量、标识符、状态 + +**变量(Variable)** +“给一块数据贴上的标签”。 + +- 例如把分数这件事记作 `score`; +- 以后用 `score` 这个名字,就能读写这块数据: + +```js +let score = 0 +score = score + 10 +``` + +**标识符(Identifier)** +“你自己起的各种名字”的统称: + +- 变量名:`score` +- 函数名:`moveSnake` +- 组件名:`SnakeGame` + 就像给文件夹起名“照片”“工作”“账单”,方便在代码里区分不同“东西”。 + +**状态(State)** +程序当前的“关键情况记录”: + +- 游戏是不是已经结束; +- 蛇现在在第几格; +- 当前分数是多少。 + 在 React 里,一般会这么理解:**状态一改,界面就要跟着更新**。 + +### 2. 函数、组件、模块 + +**函数(Function)** +把一件“可以反复做的事”打包起来,起个名字: + +```js +function sayHello(name) { + console.log('Hello, ' + name) +} +``` + +以后只要写 `sayHello('Bob')`,就等于把里面那几行再次执行一遍。 + +**组件(Component)** +前端里的“可以重复用的一块小界面 + 小逻辑”: + +- 一个按钮可以是组件; +- 一个顶部导航可以是组件; +- 整个游戏区域也可以是一个组件。 + 组件之间可以拼装,就像搭乐高。 + +**模块(Module)** +“一组相关代码组成的文件”: + +- `snakeLogic.ts` 专门放和“蛇怎么动”相关的代码; +- `score.ts` 专门放算分数的代码。 + 模块之间可以互相“导入 / 导出”,像不同抽屉里的工具。 + +### 3. 语法、编程语言、框架 + +**语法(Syntax)** +某门编程语言的“语法规则”和“标点习惯”: + +- 字符串要加引号; +- 每条语句末尾要不要写分号; +- 代码块要用 `{}` 包起来。 + 写错语法,编译器 / 解释器会直接报“语法错误”。 + +**编程语言(Programming Language)** +和计算机沟通的一整套规则和词汇,比如: + +- JavaScript、Python、Java、C++、Go…… + 不同语言适合做的事情、写法和工具生态不同。 + +**框架(Framework)** +别人帮你“先搭好骨架”的一大套代码和套路: + +- 前端:React、Vue(帮你处理界面更新、状态管理等); +- 后端:Django、Spring Boot 等。 + 你等于是在“现成的骨架上填内容”,比从头造轮子轻松很多。 + +## 五、和“调试 / 查错”有关的词 + +### 1. Bug、报错、日志 / console.log + +**Bug** +程序表现和你想的不一样,就是 bug: + +- 本来应该出现按钮,结果没有; +- 本来应该加 10 分,结果多加了一堆; +- 页面一打开就白屏。 + +**报错信息(Error Message)** +程序崩了之后,屏幕上 / 终端里那段“看起来很吓人”的英文。 +虽然难看,但通常会告诉你: + +- 大致是哪里错了; +- 哪个文件、第几行附近需要检查。 + 你可以直接复制它,丢给 AI 让它翻译和分析。 + +**日志(Log)** +程序在运行过程中自己“说的话”。 +最常见的就是前端里的: + +```js +console.log('当前分数', score) +``` + +你可以把它理解成:**在关键步骤主动报个数,方便你确认程序是不是按你想的在走**。 + +> **console.log 是什么?** +> +> - `console` 可以理解为“调试用的小黑板”; +> - `.log` 是“在小黑板上写一行字”; +> - 浏览器按 F12 打开开发者工具里的 Console 面板,就能看到这些输出。 + +### 2. 调试、断点、单步执行、快照 + +**调试(Debug / 调试程序)** +当程序出问题时,不是上来就乱改,而是: + +- 让程序在某一行停一下(断点); +- 看一看当前每个变量的值; +- 一步一步往下走,观察“从哪里开始不对劲”。 + +**断点(Breakpoint)** +可以把断点想成“在这行插了一个暂停按钮”: + +- 程序平时是一路往下跑; +- 跑到你插断点的那一行,会暂时停住,等你检查。 + +**单步执行(Step)** +从断点停下来之后,你可以选择: + +- 一行一行往下执行(step over); +- 进入某个函数内部详细看(step into)。 + 就像看一段舞蹈分解动作一样,而不是直接看快放视频。 + +**快照(Snapshot)——简化理解** +这里的“快照”可以理解为: + +> **在某个时间点,把“当前状态”拍一张照片,方便以后对比。** +> 在实际工具里,“快照”可能指: + +- 一次提交时刻项目的完整状态; +- 调试时某个时间点内存 / 变量的整体情况。 + 你先记住这个比喻就够用:**快照 ≈ 某一刻状态的留影**。 + +## 六、和“项目 / 文件 / 版本控制”有关的词 + +### 1. 项目、工作区、文件夹 + +**项目(Project)** +为实现一个应用而放在同一个文件夹里的: + +- 源代码文件 +- 配置文件 +- 素材(图片、音频等) + +**工作区(Workspace)** +VS Code / Trae 用来描述“当前这一次打开了一组什么东西”的概念: + +- 打开一个文件夹 → 一个简单工作区; +- 有时也会把多个文件夹合并成一个多项目工作区。 + +### 2. Git、仓库、提交(Commit) + +**Git(版本控制工具)** +可以理解成项目的“时光机”: + +- 每次改完一批内容,可以“拍一张版本合照”; +- 以后需要时,可以回到某个历史状态。 + +**仓库(Repository / Repo)** +开启 Git 之后,那个带“版本记录”的项目文件夹,就叫“仓库”。 + +**提交(Commit)** +每次你觉得“这波改动算一个阶段性成果”,就可以: + +- 写一条说明(比如:`Add score panel`); +- 把当前全部修改打包成一个版本; +- Git 会把这一刻的状态存下来。 + 这一次动作就叫“做了一次 commit”。 + +## 七、和“AI 开发工具”有关的词 + +### 1. AI IDE、Agent、SOLO 模式 + +**AI IDE** +在普通 IDE 的基础上,多了一层“能听懂人话、能自己动手”的 AI: + +- 你说“做个贪吃蛇”,它能帮你搭项目、写代码; +- 你把报错截图给它,它能先解释再尝试修复; +- 它能跨多个文件一起改,而不仅仅是一行一行补全。 + +**Agent(智能体)** +可以把 Agent 想象成一个**长期待命的 AI 小工程师**: + +- 会读你的项目结构; +- 会拆解任务(先装依赖、再生成代码、再跑项目); +- 跑出错之后,会根据错误信息自己调整方案。 + +**SOLO 模式(以 Trae 为例)** +表示: + +> 你只需要把“终点”说清楚, +> 它自己规划“路线”, +> 在本地一步步执行, +> 中途才在关键节点问你要不要继续。 + +### 2. 模型、密钥(API Key) + +**模型(Model,这里特指大语言模型)** +这个词可以简单理解为“背后那一大坨 AI 大脑”: + +- 比如 GPT、Claude、Kimi、GLM 等; +- 不同模型在“理解中文”“写代码”“推理”上水平不一样; +- AI IDE 里通常可以在下拉菜单里换不同模型使用。 + +**密钥 / API Key** +你可以把 API Key 理解为**一个很长的“高级密码 + 身份证号”**, +它的作用只有一个: + +> 告诉别人的服务器:“我是哪个用户,请允许我使用你们的 AI 服务,并帮我记账。” + +几个要点: + +- 这串东西通常是一长串随机字母数字; +- 不能发到公开的地方(仓库、截图、群聊),别人拿到就可以冒用你的账号; +- 在工具里填 API Key,就等于“把钥匙插进锁里”,之后工具就能帮你调用对应的 AI 服务。 + +## 八、和“浏览器 / 开发者工具”有关的词 + +**Chrome(谷歌浏览器)** +现在前端开发最常用的浏览器之一: + +- 打开网页快; +- 自带比较强的“开发者工具”,方便查问题。 + +**刷新(Refresh / Reload)** +重新加载当前网页: + +- 修改前端代码后,如果没有自动刷新工具,手动按刷新才能看到效果。 + +**开发者工具(DevTools)** +浏览器里专门给开发者用的一组工具面板: + +- 查看网页结构(Elements); +- 查看样式(Styles); +- 查错误和日志(Console); +- 查网络请求(Network)。 + 在 Chrome 里通常按 `F12` 或 `Ctrl+Shift+I` 打开。 + +**Console(控制台)** +开发者工具里的一个标签页,专门展示: + +- 你写的 `console.log(...)` 输出; +- 运行过程中发生的错误(红字)。 + 你可以当它是“程序的聊天框”: +- 程序有话要说,就写在这里; +- 你调试时最常看的就是这一块。 + +如果后面你在学习过程中又遇到新的词,也可以按这个风格让 AI 协助你补充全部内容: + +- 先写一句“它是干嘛的”; +- 再写一句“可以把它想象成什么”; +- 最后给一个特别简单的小例子。 + 这样你的“个人术语表”会越长越实用,逐渐能够更好的与计算机进行沟通。 + + + +# 附录二: Visual Studio Code 菜单栏解析 + +## Title Bar(标题栏):窗口信息与全局入口 + +标题栏位于窗口最上方,主要用于展示当前窗口信息并提供窗口级控制。常见细节包括: + +- 应用与窗口信息 + 通常显示应用名称(如 Visual Studio Code)以及当前工作区(workspace)或当前打开文件的名称,便于在多窗口并行时识别不同项目。 + +- 菜单入口(部分系统/布局可见) + 在 Windows/Linux 的常见布局中,`File / Edit / Selection / View / Go / Run / Terminal / Help` 等菜单可能与标题栏同一行或紧邻显示,是功能的传统入口。 + +- 窗口控制按钮 + 最小化、最大化/还原、关闭按钮属于操作系统窗口控件,用于调整窗口显示方式或关闭窗口。 + +- AI 侧边栏开启按钮 + 一般而言,在右上角可以控制是否开启 AI 侧边栏或者其他侧边栏。我们默认右侧的侧边栏为 AI 侧边栏。 + +- 环境与状态提示或系统更新提示(可能会出现提醒你重启更新的提示,建议每次看到主动进行点击更新) + 部分情况下会显示远程连接状态(SSH/容器/WSL)、信任提示(Workspace Trust)等,具体取决于当前环境与设置。 + +为了方便大家理解每个选项的含义,在这里我们对菜单栏进行深入解析: +![](images/index-2026-01-09-11-35-55.png) + +### File(文件):项目与文件的打开/保存/工作区管理 + +本菜单主要负责:**创建/打开文件**、**打开项目文件夹(Folder)**、**管理工作区(Workspace)**、**保存与关闭**。 + +> 其中最常用的就是:Open Folder(打开文件夹) 来打开一个项目;Open…(打开…) 来单独打开一个文件;然后用 Save / Save All(保存/全部保存) 来保存修改,最后用 Close Editor / Close Folder(关闭编辑器/关闭文件夹) 结束本次工作。工作区(Workspace)、复制工作区之类的内容可以等你项目多起来再慢慢用,不必一上来全搞懂 + +- **New Text File(新建文本文件)**:新建一个未命名文本缓冲区,用于临时记录或快速粘贴内容。 +- **New File…(新建文件…)**:在项目中创建新文件(通常会要求你选择路径/命名)。 +- **New Window(新建窗口)**:开启一个新的 VS Code 窗口实例。 +- **New Window with Profile(使用配置档新建窗口)**:以指定 Profile(扩展/设置组合)打开新窗口,适合不同课程/项目隔离环境。 +- **Open…(打开…)**:打开单个文件进行编辑。 +- **Open Folder…(打开文件夹…)**:打开一个文件夹作为项目根目录(最常用的“打开项目”方式)。 +- **Open Workspace from File…(从文件打开工作区…)**:打开 `.code-workspace` 文件,加载多文件夹/特定设置的工作区。 +- **Open Recent(打开最近)**:快速进入最近打开的文件/文件夹/工作区。 +- **Add Folder to Workspace…(添加文件夹到工作区…)**:把另一个文件夹加入当前工作区(形成 multi-root workspace)。 +- **Save Workspace As…(工作区另存为…)**:将当前工作区结构保存为 `.code-workspace` 文件,便于分享/复用。 +- **Duplicate Workspace(复制工作区)**:复制当前工作区配置(常用于建立相似项目环境)。 +- **Save(保存)**:保存当前文件更改。 +- **Save As…(另存为…)**:以新名称/新路径保存当前文件。 +- **Save All(全部保存)**:保存所有已打开且有修改的文件。 + +- **Share(分享)**:与共享/协作相关的入口(具体内容取决于版本与扩展)。 +- **Auto Save(自动保存)**:切换自动保存策略(例如延迟保存/失焦保存)。 +- **Revert File(还原文件)**:丢弃当前文件未保存改动,回到磁盘版本。 +- **Close Editor(关闭编辑器)**:关闭当前标签页。 +- **Close Folder(关闭文件夹)**:关闭当前项目文件夹(工作区变为空)。 +- **Close Window(关闭窗口)**:关闭当前 VS Code 窗口。 + +### Edit(编辑):基础编辑、查找替换、注释与快速编辑动作 + +本菜单主要负责:**撤销/重做**、**剪切复制粘贴**、**查找替换**、**注释与编辑器动作**(提升编辑效率)。 + +> 在日常写代码时,这一栏里你最常用的是:Undo / Redo(撤销/重做) 来后悔操作,Cut / Copy / Paste(剪切复制粘贴) 做文本编辑,以及 Find / Replace(查找/替换) 来快速改变量名或某段文字。 + +- **Undo(撤销)**:回退上一步编辑操作。 +- **Redo(重做)**:恢复被撤销的操作。 +- **Cut(剪切)**:剪切选中内容到剪贴板。 +- **Copy(复制)**:复制选中内容到剪贴板。 +- **Paste(粘贴)**:从剪贴板粘贴内容到光标处。 +- **Find(查找)**:在当前文件内搜索文本。 +- **Replace(替换)**:在当前文件内查找并替换。 +- **Find in Files(在文件中查找)**:在整个工作区范围内搜索(跨文件)。 +- **Replace in Files(在文件中替换)**:在整个工作区范围内替换(需要谨慎)。 +- **Toggle Line Comment(切换行注释)**:对选中行进行 `//`(或语言对应)注释/取消注释。 +- **Toggle Block Comment(切换块注释)**:对选中区域进行 `/* */`(或语言对应)注释/取消注释。 +- **Emmet: Expand Abbreviation(Emmet:展开缩写)**:把 Emmet 缩写展开成结构化代码(常用于 HTML/CSS)。 +- **AutoFill(自动填充)** / **Start Dictation…(开始听写…)** / **Emoji & Symbols(表情与符号)**:属于系统级输入辅助入口(macOS 常见)。 + +### Selection(选择):选区控制、多光标与列选择 + +本菜单主要负责:**管理选中范围**、**扩展/缩小选区**、**多光标编辑**与**列模式**,适合批量修改。 + +> Select All(全选) 来一次选中整篇文件,Copy/Move Line Up/Down(复制/移动行) 来快速调整代码顺序。等稍微熟练一点,可以尝试 Add Cursor Above/Below(添加多光标) 和 Select All Occurrences(选择所有匹配项),用来一次性修改很多相同的变量名或者文本,效率会大幅提高。 + +- **Select All(全选)**:选中当前文件全部内容。 +- **Expand Selection(扩展选区)**:按语法结构逐步扩大选中范围(词 → 表达式 → 语句等)。 +- **Shrink Selection(缩小选区)**:与扩展选区相反,逐步缩小。 + +- **Copy Line Up(向上复制行)**:把当前行/选区复制到上一行位置。 +- **Copy Line Down(向下复制行)**:把当前行/选区复制到下一行位置。 +- **Move Line Up(上移行)**:将当前行上移一行。 +- **Move Line Down(下移行)**:将当前行下移一行。 +- **Duplicate Selection(复制选中内容)**:复制选中内容并插入一份副本。 + +- **Add Cursor Above(在上方添加光标)**:在上一行同列增加一个光标,进行多行同时编辑。 +- **Add Cursor Below(在下方添加光标)**:在下一行同列增加一个光标。 +- **Add Cursors to Line Ends(在行尾添加多个光标)**:在选中行的行尾放置光标,便于统一追加内容。 +- **Add Next Occurrence(添加下一个匹配项)**:选择当前词/选区的下一个匹配位置并加入多光标。 +- **Add Previous Occurrence(添加上一个匹配项)**:同上,方向相反。 +- **Select All Occurrences(选择所有匹配项)**:一次性选中所有匹配位置并进入多光标编辑。 + +- **Switch to Cmd+Click for Multi-Cursor(切换为 Cmd+点击 多光标)**:调整鼠标点击添加光标的交互方式(macOS 常见)。 +- **Column Selection Mode(列选择模式)**:开启后可进行矩形选区(适合处理对齐文本/表格数据)。 + +### View(视图):界面布局与面板显示控制 + +本菜单主要负责:**控制界面显示哪些区域**、**调整布局**、**打开各类视图面板**(Explorer/Search/Terminal 等)。 + +> 日常开发时,你最常用的是:Explorer(资源管理器) 查看和切换文件,Terminal(终端) 在底部跑命令,Search(搜索) 全局查找,Extensions(扩展) 安装/管理插件。遇到找不到某个按钮时,可以用 Command Palette…(命令面板) 搜索功能,很多「找不到入口」的问题都能靠它解决。 + +- **Command Palette…(命令面板…)**:打开命令面板,用关键词搜索任何功能/命令(最通用入口)。 +- **Open View…(打开视图…)**:按名称搜索并打开某个视图(例如 Outline、Timeline 等)。 +- **Appearance(外观)**:与主题、字体、缩放、菜单/工具栏显示等外观相关的设置入口集合。 +- **Editor Layout(编辑器布局)**:控制编辑器分栏方式(左右/上下/网格等)。 +- **Explorer(资源管理器)**:显示/聚焦文件树视图。 +- **Search(搜索)**:显示/聚焦搜索视图。 +- **Source Control(源代码管理)**:显示/聚焦 Git 视图。 +- **Run(运行)**:显示/聚焦运行相关视图(具体名称可能随版本变化)。 +- **Extensions(扩展)**:显示/聚焦扩展管理视图。 +- **Testing(测试)**:显示/聚焦测试视图(依赖语言/扩展)。 +- **Problems(问题)**:打开底部 Problems 列表。 +- **Output(输出)**:打开底部 Output 面板。 +- **Debug Console(调试控制台)**:打开 Debug Console。 +- **Terminal(终端)**:打开集成终端。 +- **Word Wrap(自动换行)**:切换编辑器自动换行显示(不改变文件内容,只改变显示方式)。 + +![](images/index-2026-01-09-11-36-23.png) + +### Go(转到):在代码与项目中快速导航与定位 + +本菜单主要负责:**在文件、符号(函数/类)、定义位置之间快速跳转**,以及在改动与问题之间移动,提高阅读与调试效率。 + +> 当项目文件变多、代码变长时,你会频繁用到:Go to File…(转到文件) 按名字打开文件,Go to Definition / References(转到定义/引用) 在函数和它的使用处之间来回跳,以及 Back / Forward(后退/前进) 像浏览器一样在刚才看过的地方之间切换。Go to Line/Column…(转到行/列) 在 AI 给你报错行号时能够找到对应的部分 + +- **Back(后退)**:返回到上一个光标/跳转位置(类似浏览器后退)。 +- **Forward(前进)**:与后退相反,回到刚才后退前的位置。 +- **Last Edit Location(上次编辑位置)**:跳到最近一次发生编辑的地方,便于继续未完成的修改。 +- **Switch Editor(切换编辑器)**:在已打开的编辑器标签之间切换(按最近使用顺序)。 +- **Switch Group(切换分组)**:在不同编辑器分屏组之间切换(例如左/右分栏)。 +- **Go to File…(转到文件…)**:按文件名快速搜索并打开工作区内文件。 +- **Go to Symbol in Workspace…(转到工作区符号…)**:在整个项目范围搜索符号(函数/类/变量等)并跳转。 +- **Go to Symbol in Editor…(转到编辑器符号…)**:只在当前文件内搜索符号并跳转。 +- **Go to Definition(转到定义)**:跳到符号的定义处(需要语言服务支持)。 +- **Go to Declaration(转到声明)**:跳到声明位置(常见于 C/C++、TypeScript 等)。 +- **Go to Type Definition(转到类型定义)**:跳到变量/对象对应的类型定义(常用于 TypeScript)。 +- **Go to Implementations(转到实现)**:查看接口/抽象方法的具体实现位置列表并跳转。 +- **Go to References(转到引用)**:查找并打开该符号在项目中的所有引用位置。 +- **Go to Line/Column…(转到行/列…)**:输入行号(可带列号)直接定位到指定位置。 +- **Go to Bracket(转到括号匹配处)**:在成对括号/花括号/方括号之间跳转,用于阅读结构。 +- **Next Problem(下一个问题)**:跳到下一个错误/警告位置(对应 Problems 面板)。 +- **Previous Problem(上一个问题)**:跳到上一个错误/警告位置。 +- **Next Change(下一个更改)**:跳到下一处改动位置(通常基于 Git diff/文件修改痕迹)。 +- **Previous Change(上一个更改)**:跳到上一处改动位置。 + +### Terminal(终端):运行命令与管理任务(Tasks) + +本菜单主要负责:**打开/管理集成终端**,以及**运行与配置 VS Code 任务系统(Tasks)**(如 build、运行脚本等)。 + +> 刚开始你重点用 New Terminal(新建终端) 在底部打开一个命令行窗口,然后在里面执行 npm run dev、python main.py、git status 之类的命令。等项目变复杂水平变高了,再去了解 Run Task… / Run Build Task…(运行任务/构建任务),把常用命令配置成一键运行。 + +- **New Terminal(新建终端)**:在底部 Panel 创建一个新的终端会话。 +- **Split Terminal(拆分终端)**:将终端分屏显示,便于同时运行多个命令(如前端/后端各一)。 +- **New Terminal Window(新建终端窗口)**:以新窗口方式打开终端相关界面(具体行为依系统/版本)。 +- **Run Task…(运行任务…)**:从任务列表选择一个任务执行(例如 lint、test、build)。 +- **Run Build Task…(运行构建任务…)**:运行被标记为“build”的默认构建任务。 +- **Run Active File(运行当前文件)**:用当前语言环境运行当前编辑文件(依赖扩展/配置)。 +- **Run Selected Text(运行选中文本)**:将选中内容发送到可执行环境(常见于 Python/REPL 类扩展)。 +- **Show Running Tasks…(显示正在运行的任务…)**:查看当前后台任务及其输出。 +- **Restart Running Task…(重启正在运行的任务…)**:重启某个正在运行的任务。 +- **Terminate Task…(终止任务…)**:停止正在运行的任务。 +- **Configure Tasks…(配置任务…)**:创建/编辑 `tasks.json`,定义可重复执行的命令任务。 +- **Configure Default Build Task…(配置默认构建任务…)**:指定哪个任务作为默认 build(供“Run Build Task”调用)。 + +### Window(窗口):窗口状态与排列方式(系统级) + +本菜单主要负责:**控制应用窗口的显示方式**(最小化、全屏、窗口布局),属于操作系统窗口管理功能。 + +> 这一栏基本是操作系统级别的窗口控制,日常开发你最多会点一下 Minimize(最小化) 和 Full Screen / Fill(全屏/填充)。其他像分屏贴靠、居中布局之类,更多是界面体验上的微调,等你熟悉了再根据自己习惯慢慢试。 + +- **Minimize(最小化)**:将当前窗口最小化到 Dock。 +- **Zoom(缩放)**:切换窗口缩放状态(macOS 的窗口缩放行为)。 +- **Fill(填充)**:将窗口调整为更“铺满”的尺寸(便于大屏展示)。 +- **Center(居中)**:将窗口移动到屏幕中央。 +- **Move & Resize(移动与调整大小)**:进入窗口移动/调整大小相关操作(系统功能集合)。 +- **Full Screen Tile(全屏分屏贴靠)**:将窗口以全屏分屏方式贴靠到屏幕一侧(macOS 分屏)。 +- **Remove Window from Set(从窗口集合移除)**:与 macOS 窗口集合/标签化管理相关(是否可用取决于系统状态)。 + +### Help(帮助):帮助资源、版本信息与诊断工具入口 + +本菜单主要负责:**查看帮助文档**、**了解版本更新**、**打开诊断/开发者工具**、**提交问题反馈**。 + +> 不会用 VS Code 的时候,先来这里。你可以用 Help Document(帮助文档) 看官方说明,用 Show Release Notes(发行说明) 了解新版本变化。想练习编辑器技巧,可以打开 Editor Playground(练习场)。遇到疑似 VS Code 自己的 bug,再用 Report Issue(报告问题) 或 Toggle Developer Tools(开发者工具) 这些高级一点的功能。 + +- **Search(搜索)**:在帮助相关内容中搜索入口/命令(便于快速定位功能)。 +- **Show All Commands(显示所有命令)**:列出可用命令(类似命令面板的全量视图/入口)。 +- **Editor Playground(编辑器练习场)**:提供交互式示例,用于练习编辑器功能(多光标、选择、格式化等)。 +- **Show Release Notes(显示发行说明)**:查看当前版本更新内容与变更记录。 +- **Toggle Developer Tools(切换开发者工具)**:打开/关闭开发者工具(用于排查界面/扩展问题)。 +- **Report Issue(报告问题)**:进入问题反馈流程(通常会附带日志与环境信息)。 +- **TRACE Process Explorer(TRACE 进程查看器)**:查看 VS Code 相关进程/资源占用,用于性能排查。 +- **Contact Us(联系我们)**:官方联系入口。 +- **Help Document(帮助文档)**:打开官方帮助文档与使用指南。 + +## Activity Bar(活动栏):主要视图的切换区 + +活动栏位于界面最左侧,以图标形式提供核心功能视图入口,用于切换左侧工具面板。常见图标与作用如下: + +![](images/image23.png) + +常见的几个图标含义: + +- 资源管理器(Explorer) + 打开文件树与工作区内容管理视图,用于新建、打开、移动、删除文件等。 + +- 搜索(Search) + 在整个工作区范围内查找与替换文本,支持按规则筛选与批量替换。 + +- 源代码管理(Source Control) + 集成 Git 的改动查看、暂存(stage)、提交(commit)、分支操作等。 + +- 运行和调试(Run and Debug) + 管理运行配置与调试会话,例如断点、变量查看、调用栈、单步执行等。 + +- 扩展(Extensions) + 浏览、安装与管理扩展(插件),例如语言支持、格式化工具、主题等。 + +补充说明:再次点击同一图标通常可切换该视图的展开/收起;将鼠标悬停在图标上通常可看到视图名称与快捷键提示。AI IDE 往往会在此处增加 AI 相关入口(如 Chat/Agents/Project Context),用于打开对话面板或启用项目级分析能力。 + +## Side Bar(侧边栏):当前视图的具体内容区 + +侧边栏位于活动栏右侧,用于展示当前选中视图的具体内容。它会随活动栏切换而变化,常见细节包括: + +![](images/index-2026-01-09-11-28-43.png) + +- Explorer(资源管理器)下的内容 + 工作区根目录与文件树、打开文件列表(Open Editors,视设置而定)、新建文件/文件夹等操作按钮。 + +- Search(搜索)下的内容 + 搜索与替换输入框、过滤选项(大小写/全词/正则等)、按文件分组的结果列表。 + +- Source Control(源代码管理)下的内容 + 变更列表(Changes)、暂存区(Staged Changes,若启用)、提交信息输入框与相关操作。 + +侧边栏中的信息会根据活动栏的选择而切换显示的内容。其通常以可折叠分区组织,便于在同一位置呈现多类信息(是否出现某些分区取决于语言与扩展)。 + +## Editor Groups(编辑器分组/编辑区):文件编辑与分屏布局 + +编辑器区域位于界面中部,是代码与文本编辑的核心区域,包含文件标签管理与分组布局能力。常见细节包括: + +- 标签页(Tabs) + 每个打开的文件对应一个标签页,用于快速切换。关闭标签页仅关闭显示,不会删除磁盘文件;标签页样式通常会提示是否存在未保存修改。 + +- 分组与分屏(Editor Groups) + 支持将编辑器分成多个组(左右或上下),每个组可独立打开文件,适用于对照阅读与并行编辑。 + +- 编辑辅助能力(常见) + 代码补全与建议(IntelliSense)、语法高亮(Syntax Highlighting)、快速修复与重构入口(Code Actions)等,帮助提高编辑效率并减少低级错误。 + +## Breadcrumbs(路径导航):定位文件位置与快速跳转 + +Breadcrumbs 位于编辑器上方,用于显示当前文件在工作区中的路径层级,并提供跳转能力。常见细节包括: + +- 路径层级展示 + 以层级方式展示目录与文件,例如 `src > pages > index.js`。 + +- 快速跳转 + 通常可点击任意层级节点,快速跳到上级目录或定位相关位置,适用于大型项目中快速确认“文件在哪”。 + +部分语言与配置下,Breadcrumbs 也可能包含符号层级(如类/函数),是否显示取决于语言服务与设置。 + +## Minimap(迷你地图/代码缩略图):长文件的快速导航 + +Minimap 位于编辑器右侧,是当前文件内容的缩略预览,用于快速定位与导航。常见细节包括: + +- 全文概览 + 以缩小形式呈现整份文件,便于把握内容分布与结构位置。 + +- 快速滚动与跳转 + 在 Minimap 上点击或拖动通常可以快速跳转到对应位置,减少反复滚动带来的时间成本。 + +## Panel(面板/底部面板):运行、诊断与调试输出集中区 + +Panel 通常位于窗口底部(布局可调整),用于承载运行命令与各种输出信息。常见标签页与用途如下: + +- Terminal(终端) + 用于执行命令(如安装依赖、启动服务、运行脚本)。可选择不同 shell(如 PowerShell、Command Prompt、Bash),默认工作目录通常为工作区根目录。 + +- Problems(问题) + 汇总错误与警告列表,点击条目可跳转到对应文件与行号,常用于快速定位语法错误、缺少依赖、类型问题等。 + +- Output(输出) + 展示扩展、语言服务、任务等组件的日志输出,用于排查“操作没有生效”或“工具运行异常”等情况。 + +- Debug Console(调试控制台) + 调试会话期间用于显示调试输出与交互信息,与断点、变量查看等功能配合使用。 + +## Status Bar(状态栏):编辑状态与上下文信息汇总 + +状态栏位于窗口最底部,汇总展示当前文件与环境的关键状态,并提供快捷入口。常见细节包括: + +- 语言模式(Language Mode) + 显示当前文件按何种语言规则进行解析(如 JavaScript/HTML/Python),影响语法高亮、补全与诊断。 + +- 编码与换行符 + 常见如 `UTF-8`、`LF/CRLF`,跨平台协作时与一致性相关。 + +- 缩进设置 + 显示 Tab 或空格以及空格数量(如 Spaces: 2/4),与代码风格一致性相关。 + +- Git 状态(如启用) + 可能显示当前分支与同步/变更提示,用于快速了解版本控制状态。 + +- 错误与警告统计(如启用) + 通常以数量显示(errors/warnings),点击可跳转到 Problems 查看详情。 + +- 通知与后台状态 + 某些后台任务、扩展提示或远程连接信息也可能在状态栏体现,具体随环境与扩展变化。 diff --git a/docs/stage-1/1.2-building-prototype/index.md b/docs/stage-1/1.2-building-prototype/index.md new file mode 100644 index 0000000..59a779a --- /dev/null +++ b/docs/stage-1/1.2-building-prototype/index.md @@ -0,0 +1,635 @@ +# 初级三:动手做出原型 + +在本节中,我们会从零开始,借助 AI IDE 动手搭建一个可以实际运行的 Web 应用原型。你将学会如何把脑海中抽象的产品想法,逐步拆解并落地为具体的界面与代码,同时在遇到问题时,能够有条理地排查原因并解决错误。 + +你能体会到从产品分析拆解,到多页面产品原型实现的完整闭环 + +## 本章导读 + +在这一节,你将把一个真实工作场景,完整走一遍“从业务梳理到可运行原型”的流程。我们会以**内容生产工作台(内容创作任务管理)**为示例业务,先用自然语言把需求说明白,再借助对话式 AI 和 AI IDE,从一个单页面应用做起,逐步扩展到多页面的 Web 应用原型,并对界面和交互做一轮“像那么回事”的打磨。 + +和传统“先学完一堆技术再写代码”不同,本章刻意弱化技术细节,把重点放在:**你如何用业务语言跟 AI 合作,把一个内容相关的想法快速做成能跑的工具**。 +这也为下一节“接入大语言模型(LLM)和文生图能力”做好铺垫——我们会在同一个工作台中,实现“AI 帮你写文案、起标题、生成配图”的能力。 + +- 预计时间:约 **4–6 小时**,可分多次完成 +- 预期产出: + - 1 份围绕真实工作场景写出的“内容生产工作台”业务需求说明 + - 1 个可运行的单页面业务原型(例如内容任务列表页) + - 1 个包含首页、任务列表页、设置页在内的多页面 Web 应用原型 +- Assignment: + - 以你自己的工作场景为蓝本,完整完成一次:业务梳理 → 单页原型 → 多页原型的闭环 + - (可选)参考 vibe coding 社区项目,对你的原型做一轮界面和交互的体验升级,并思考下一节要如何接入“AI 写文案 / 生成配图” + +--- + +# 初级三:动手做出原型 + +随着 AI IDE 能力的增强,我们越来越不必纠结每一个技术细节,而是可以把注意力更多地放在业务梳理和产品逻辑上。本节的目标,是带你完成一次从业务需求出发、借助 AI IDE 快速搭建 Web 应用原型的完整过程。 + +在这个过程中,你会亲手把一个在很多团队里都存在的高频场景——**内容生产工作台(内容创作任务管理)**,逐步拆解为可以落地的页面与交互逻辑。我们会从一个最简单的单页面开始,再扩展为多页面应用,最终得到一个“能用、好改、可扩展”的业务原型。 + +当你学完本节,你不需要自己写很多代码,也能: + +- 把内容相关的真实业务需求,转成自然语言“规格说明” +- 借助 AI IDE 快速搭建出可以运行的单页面和多页面原型 +- 在遇到报错时,按照固定步骤排查问题、与 AI 协作修复错误 +- 初步打磨界面与交互,让原型从“能跑起来”迈向“用着顺手” +- 为下一节“AI 写文案、起标题、生成配图”打好应用基础 + +--- + +## 1. 写代码前确定需求 + +### 1.1 选择一个经典业务场景:内容生产工作台 + +在真实工作中,几乎所有团队都会遇到类似的需求: + +- 市场和运营要按节奏发公众号文章、短视频、小红书笔记、活动海报 +- 产品和设计要整理功能更新公告、版本说明、上线物料 +- 内部团队要发布通知、周报、知识文章等 + +大家常见的痛点是: + +- 任务散落在微信、邮件、飞书文档、线下讨论中,很难统一管理 +- 每天不知道“今天到底要发哪些内容、哪些已经写好、哪些已经发布” +- 同一个主题在不同渠道发布时,很难统一规划和复用素材 + +因此,本节我们选取一个足够简单又非常常见的场景——**内容生产工作台**。你可以把它理解为一个轻量的“内容任务管理工具”: + +- 每一条内容任务,对应一篇要发的文章、一条要拍的视频、一个要做的海报 +- 任务上有几个最基本的信息:标题、投放渠道、状态(未开始 / 进行中 / 已发布) +- 后续我们会在这个工作台上接入 LLM 和文生图,帮助你自动生成文案和配图。 + +### 1.2 业务梳理:从模糊想法到清晰需求 + +很多团队最初的想法可能只是: + +> 想做个简单的内容排期表,把要发的东西都记一下。 + +从 AI 或工程师的角度,这仍然过于抽象。我们需要把问题拆解得更具体。可以用下面几组问题来梳理业务: + +1. 使用者是谁 + - 是一个人(比如你自己),还是一个小团队(市场组、内容组)? + - 是否需要区分“自己负责的任务”和“整个团队的任务”? + +2. 需要记录哪些信息 + - 最少必须有哪些字段(内容标题、投放渠道、计划发布时间、当前状态) + - 将来可能会增加哪些字段(目标受众、优先级、关联活动、负责人等) + +3. 每天/每周的典型操作流程 + - 创建新的内容任务(例如下周要发的活动预热) + - 更新任务状态(从未开始到进行中,再到已发布) + - 按渠道或状态筛选任务,快速知道今天/本周要做什么 + +4. 成功的结果是什么 + - 例如: + - 每天打开工作台,一眼看到“今天还有哪些内容没写 / 没排期 / 没发布” + - 团队内部不再在各种聊天记录里反复确认“这条内容到底发了没” + +把这些问题的答案写下来,就是一份简单的“内容生产工作台业务说明”。这一步,你仍然只需要用自然语言描述工作流程和痛点即可。 + +### 1.3 从业务到页面:画出最简页面草图 + +梳理完业务之后,下一步是把它转化为“页面结构”。我们先从一个**单页面版本**开始,保持尽量简单: + +- 顶部:标题,例如“内容生产工作台” +- 中间左侧:新增内容任务表单 + - 内容标题输入框 + - 渠道下拉选择(例如 公众号 / 抖音 / 小红书 / B 站 / 内部通知) + - 状态下拉框(默认“未开始”) + - 计划发布时间(可选) + - “添加任务”按钮 +- 中间右侧:内容任务列表 + - 每行显示:标题、渠道、状态、计划时间 + - 每行右侧预留两个按钮:修改状态、删除 +- 列表上方:简单统计区域 + - 显示任务总数 + - 显示未开始 / 进行中 / 已发布的数量 + +在纸上画出这些区域的方框和大致布局,哪怕只是草图,也能帮助你更清楚地跟 AI 表达“我要的页面长什么样”。 + +### 1.4 用自然语言写“需求说明”给 AI IDE + +接下来,我们把上面的想法整理成一段可以直接发给 AI IDE 的自然语言需求。例如: + +> 我要做一个和内容创作相关的小工具,用来管理我的内容任务,是一个内容生产工作台。 +> 请帮我先做一个单页面的 Web 应用,页面结构如下: +> +> 1. 顶部显示标题:内容生产工作台 +> 2. 左侧是新增内容任务表单,包含:内容标题、投放渠道、当前状态(默认为未开始)、计划发布时间 四个字段,以及一个“添加任务”按钮 +> 3. 右侧是任务列表区域,用表格展示所有任务,每行至少要显示:内容标题、投放渠道、当前状态、计划时间 +> 4. 每条任务右边预留两个按钮:修改状态、删除 +> 5. 在任务列表上方增加一个统计区域:显示任务总数、未开始任务数量、进行中任务数量、已发布任务数量 +> 要求是:当我在左侧输入信息并点击“添加任务”后,右侧列表能立即出现一条新记录,同时统计区域自动更新。 + +这就是 AI IDE 理解和生成代码所需要的信息。你做的,是产品经理平时写的那种“页面与交互说明”,只是换成自然语言和 AI 对话。 + +### 1.5 本次原型做到哪里?不做到哪里? + +“内容生产工作台”可以发展出非常多功能,但**本章不会试图一次性做完所有事**。先明确: + +**本次原型“要做”的两件核心事情:** + +1. 快速录入和查看内容任务:让所有要做的内容任务不再散落在各种文档和聊天中 +2. 一眼看清当前任务的状态分布:未开始 / 进行中 / 已发布 有多少 + +**本次原型“暂时不做”的事情:** + +- 多人协作、权限管理(某些任务只给特定同学看) +- 复杂的排期视图(横跨多周的日历视图、拖拽排期等) +- 复杂报表和图表分析(按渠道统计发布量、转化效果等) +- 和其他平台的自动集成(自动同步到公众号、短视频平台等) + +这些内容会在后续章节(尤其是接入 LLM、文生图、甚至外部 API 之后)再逐步展开。 +现在你只需要专注:**先让“记录任务 + 看状态”这个最小闭环跑起来**。 + +### 1.6 实践任务:写出你自己的业务说明 + +如果内容工作台本身就与你的工作高度相关,可以直接以它为主线。 +如果你有更贴切的内容场景,例如: + +- 只做短视频脚本管理 +- 只管理内部知识文章/技术博客 +- 只管理版本发布公告和更新日志 + +也可以换成你自己的内容对象,但可以沿用同样的结构: + +1. 说明你管理的“内容任务”是什么(文章、视频、公告) +2. 说明最小需要记录哪些字段(标题、渠道、状态、发布时间等) +3. 描述每天/每周是怎么使用这个工具的 +4. 列出“本次原型只解决哪两三件事”,暂时不解决哪些高级问题 + +把这些写成一段话,就是你可以直接复制给 AI IDE 的“需求说明”。 + +--- + +## 2. 从一个单页面开始 + +完成业务梳理后,我们先从最小可用版本开始:**单页面内容生产工作台**。这一节的重点,是让你真正体验到:通过自然语言和 AI 协作,可以在很短时间内得到一个“能跑起来”的内容管理工具。 + +### 2.1 在 AI IDE 中创建项目 + +1. 打开 AI IDE,新建一个空项目(可以命名为 content-workbench-demo 或更贴合你业务的名字) +2. 在项目中创建一个基础 Web 应用,如果不确定,可以直接在聊天框问 AI: + + 请帮我创建一个可以在浏览器里访问的简单 Web 项目,用来做内容生产工作台的演示。 + +AI 会自动为你搭好最基础的文件结构,例如首页文件、样式文件和必要的脚本文件。 + +### 2.2 用自然语言让 AI 搭出首个单页面 + +在 AI 聊天框中粘贴你在 1.4 写好的“需求说明”,并补一句: + +> 接下来,请在当前项目中根据上面的描述,帮我实现一个单页面的内容生产工作台原型。 + +AI 会为你生成或修改前端代码,完成: + +- 页面基本布局(标题、左右区域、统计区) +- 新增内容任务的表单 +- 展示任务的列表 + +在 AI 的引导下打开浏览器预览页面,尝试一次完整操作: + +1. 在左侧表单中输入一条内容任务(例如“618 大促预热海报”) +2. 选择渠道(例如“公众号”),状态保持“未开始” +3. 设置一个计划发布时间,点击“添加任务” +4. 在右侧列表中确认看到这条任务 +5. 查看顶部统计区是否同步更新任务数量 + +### 2.3 功能分级:必须 / 建议 / 进阶 + +为了让你更有“范围感”,我们对单页面要实现的能力做一个分级: + +**必须完成(MVP):** + +1. 新增内容任务 + - 表单至少包含:内容标题、投放渠道 + - 点击“添加任务”,能在列表中看到新记录 + +2. 基础列表展示 + - 能在页面上看到所有已添加的任务 + - 每一条有基本可辨识信息(至少标题) + +3. 删除任务 + - 对某条任务可以执行删除操作,删除后不再出现在列表里 + +**建议完成(推荐):** + +4. 状态字段 + 简单统计 + - 表单中增加状态字段(未开始 / 进行中 / 已发布) + - 列表上方显示:总任务数、未开始数量、进行中数量、已发布数量,并随新增/删除自动更新 + +5. 计划发布时间字段 + - 表单增加计划发布时间(日期或日期+时间) + - 列表中展示这个字段,方便后续按日期排序或筛选 + +**进阶挑战(可选):** + +6. 状态筛选 + - 在任务列表上方增加状态筛选下拉框,可只看“未开始/进行中/已发布” + +7. 快速状态切换 + - 每条任务右侧有一个“标记为已发布”的按钮,点击即可更新状态并刷新统计 + +8. 最近更新时间 + - 在列表中增加“最近更新”字段,每次修改状态或标题时自动更新为当前时间 + +建议你先完成“必须 + 建议”部分,保证闭环存在,再尝试进阶功能。 + +### 2.4 验证你的“单页面闭环” + +当单页面基本成型时,可以用一个完整的小闭环来验收它: + +1. 新建 3 条内容任务: + - 公众号文章:状态“未开始” + - 短视频脚本:状态“进行中” + - 活动总结文章:状态“未开始” +2. (如果你做了筛选)使用筛选功能,只看“未开始”的任务,检查列表是否正确 +3. 把其中一条标记为“已发布”,观察统计区是否更新 +4. 删除一条已经不需要的任务,再次确认统计和列表是否一致 + +如果这一轮流程走下来没有明显障碍,你的单页面原型就已经达到“可用”的标准了。 + +### 2.5 实践任务:完成一个可用的单页面内容工作台 + +本小节的实践目标,是让你得到一个真正可以用来管理内容任务的单页面应用。请你保证页面至少具备以下特性: + +- 完成“必须”和“建议”级别的功能 +- 至少实现一个“进阶挑战”(如状态筛选或快速状态切换) +- 可以支持你用真实的几条内容任务试着用上一两天 + +你可以在心里问自己两个问题: + +- 如果这个页面明天就要给同事用,他们还会问你哪些问题? +- 把“内容任务”换成“项目任务”或“需求事项”,是否只需要换字段名即可复用? + +--- + +## 3. 遇到报错了怎么办 + +当你开始频繁修改和扩展页面时,报错就成了日常。与其试图一口气搞懂所有技术细节,不如先建立一套“遇到报错的标准动作”。 + +### 3.1 常见报错形态 + +在搭建内容生产工作台的过程中,你可能会遇到几类典型错误: + +1. 页面完全空白 + - 打开浏览器,什么都不显示,或者只显示标题 + - 常见原因:代码语法错误、某个关键文件加载失败 + +2. 页面部分功能失效 + - 表单能看到,但点击“添加任务”没反应 + - 常见原因:按钮事件没有正确绑定,或者某处变量名写错 + +3. 控制台出现红色报错信息 + - 打开浏览器开发者工具(F12),在 Console 中看到一堆英文 + - 常见原因:访问了不存在的属性或方法,引用了不存在的文件等 + +4. 样式错乱 + - 按钮位置跑偏、列表显示变形、文字对不齐 + - 常见原因:样式文件修改冲突、类名被误删等 + +### 3.2 报错处理四步法 + +无论遇到哪一种现象,你都可以按照下面四个步骤来处理: + +1. 复述问题 + - 用一两句话客观描述现象,而不是只说“坏了”: + - 页面完全空白 + - 添加任务时没有任何反应 + - 点击删除按钮时出现一条红色错误提示 + - 筛选下拉框变了,列表不变 + +2. 收集信息 + - 打开浏览器开发者工具 + - 在 Console 中找到最新的红色报错信息 + - 把完整报错内容复制出来(尽量一行不落) + +3. 提交给 AI + - 在 AI IDE 的聊天框中,先用自己的话描述现象,再粘贴报错信息,例如: + + 我在做一个内容生产工作台,现在遇到如下问题: + - 现象:点击“添加任务”按钮没有任何反应 + - 操作步骤:在表单里填写标题和渠道后点击按钮 + 下面是浏览器控制台中的完整错误信息: + ……(粘贴错误) + 请帮我分析可能的原因,指出需要修改的文件和代码位置,并给出修改后的示例。 + +4. 跟着 AI 一步步修改 + - AI 通常会告诉你在哪个文件、哪一段代码里需要调整 + - 先照着修改一次,如果看不懂,也可以要求 AI 用更通俗的描述解释原因 + - 修改保存后,刷新页面再次测试 + +通过多次这样的循环,你会逐渐对“错误长什么样”“通常卡在哪些地方”形成直觉。即使你暂时不懂技术名词,也可以有效推进问题解决。 + +### 3.3 实践任务:刻意“制造一个错误” + +为了真正掌握报错处理的节奏,你可以刻意“制造一个小错误”,然后用上面的四步法来解决。例如: + +1. 找到新增任务的那段代码,把某个变量名刻意改错(例如 taskList 改成 tasksList) +2. 保存并刷新页面,尝试添加任务,观察页面行为 +3. 打开控制台查看报错信息 +4. 当作一个真实问题提交给 AI,让它帮你分析并修复 + +通过这样“可控的练习”,你会对错误的来源和定位方式更加熟悉,遇到真实问题时就不会慌张。 + +--- + +## 4. 做多个页面的应用 + +当单页面已经能稳定记录和展示内容任务后,你会发现:业务本身其实可以拆成几个逻辑板块。例如: + +- 某个页面专门用来“看整体情况”(当前任务数量、不同状态占比) +- 某个页面专门用来“管理具体任务列表” +- 某个页面专门用来“配置个人偏好、默认渠道、默认状态”等 + +这就是从单页面走向多页面的自然契机。 + +### 4.1 为什么不是一个“超长页面”? + +从技术上讲,我们可以把所有内容堆在一个很长的页面上:上面是统计,中间是列表,下面是设置。但随着功能逐渐增多,这样做会出现几个问题: + +- 新用户很难在第一次打开时搞清楚“这里能做什么” +- 常用操作(添加任务、查看进度)和不常用操作(调整个人偏好)混在一起,容易误操作 +- 页面越堆越长,后续想增加新模块(例如任务详情、AI 生成文案页面)时,会越来越难维护 + +因此,我们按照“使用频率”和“信息类型”把它拆成多个页面: + +- 高频、概览性的内容放在首页 +- 日常操作性内容放在任务列表页 +- 低频、配置性的内容放在设置页 + +这就是最基础的信息架构思路。 + +### 4.2 设计一个最小多页面结构 + +以内容生产工作台为例,可以先规划一个三页结构: + +1. 首页(内容概览) + - 展示关键数据:任务总数、未开始数量、进行中数量、已发布数量 + - 显示当前使用者名称,例如“欢迎你,内容运营小王” + - 提供快速入口:去任务列表、去设置页 + - (为下一节埋点)预留一个区域,用来展示“AI 已为你生成了多少条文案/图片”(暂为空) + +2. 任务列表页 + - 展示所有内容任务的列表 + - 支持根据状态筛选 + - 预留“查看详情”入口,未来我们会在详情页里接入 LLM/文生图 + +3. 设置页 + - 可以修改当前使用者名称(例如“小王”“品牌内容组”) + - 可以配置一个“默认渠道”(例如默认选中公众号) + - 可以配置一个“默认显示状态”(例如默认只显示进行中任务) + - 设置保存后,在其他页面中生效 + +在纸上画一张简单的“页面导航图”,用箭头标出: +首页 ↔ 任务列表页 ↔(未来的)任务详情页 +首页 ↔ 设置页 + +这张图,就是接下来 AI 帮你搭建多页面结构的“蓝图”。 + +### 4.3 向 AI IDE 请求:从单页扩展为多页 + +在 AI IDE 聊天框中,你可以这样发出指令: + +> 现在我希望在现有单页应用的基础上,改造成一个包含多个页面的内容生产工作台。 +> 请帮我实现三种页面: +> +> 1. 首页:展示内容任务的整体统计数据(总数、未开始、进行中、已发布),并显示当前使用者名称,例如“欢迎你,内容运营小王”,同时提供“查看任务列表”和“打开设置页”的按钮。 +> 2. 任务列表页:展示所有任务,提供按状态筛选的功能。点击某条任务时,后续可以扩展为跳转到“任务详情页”。 +> 3. 设置页:可以修改当前使用者名称,并配置“默认渠道”和“默认显示状态”;保存后,在首页和任务列表页中生效。 +> 请帮我配置好页面路由和跳转逻辑,使我可以在浏览器中通过菜单或按钮在这些页面之间切换。 + +AI 会在项目中增加必要的路由配置,并为你创建或拆分对应的页面文件。 + +### 4.4 跨页面的数据传递 + +多页面应用中,一个核心能力是“不同页面之间共享信息”。在我们的内容工作台场景里,典型的例子包括: + +- 设置页中修改当前使用者名称后,首页欢迎语也要同步更新 +- 设置页中配置的“默认渠道”和“默认显示状态”,要影响任务列表页的默认筛选 +- 未来在任务详情页中更新某条任务的状态或文案摘要,回到任务列表页和首页概览时,相关统计也要更新 + +你暂时不需要理解所有技术实现细节,可以先只关注“现象”是否正确发生: + +1. 在设置页修改名称,例如改成“内容运营小李” +2. 返回首页,看顶部欢迎语是否同步成“欢迎你,内容运营小李” +3. 在设置页修改“默认显示状态”为“进行中” +4. 返回任务列表页,看列表是否自动按照“进行中”进行过滤 +5. 在列表页手动修改一条任务状态为“已发布”,返回首页,看“已发布任务数量”是否自动加一 + +如果这些行为都符合预期,就说明你的多页面数据流已经“连通”了。 + +### 4.5 功能分级:多页面的必须 / 建议 / 进阶 + +和单页面类似,我们也对多页面部分做一个分级: + +**必须完成:** + +1. 三个页面结构本身:首页 / 任务列表页 / 设置页 +2. 可以通过明显的导航或按钮在三个页面之间跳转 +3. 设置页修改使用者名称后,首页欢迎语能实时更新 + +**建议完成:** + +4. 首页展示关键统计数据(总任务数、未开始数、进行中数、已发布数) +5. 任务列表页具备状态筛选功能 +6. 设置页中的“默认显示状态”能影响列表页的默认筛选效果 + +**进阶挑战(可选):** + +7. 预留“任务详情页”空壳: + - 列表每条记录后有“查看详情”按钮 + - 点击后跳转到详情页,显示该任务的基础信息(标题、渠道、状态、计划时间、备注) + +8. 在详情页中支持修改状态或备注,并能同步回列表页和首页统计 + +你可以根据自己的时间和精力,选择做到“必须 + 建议”或者再挑战“进阶”。 + +### 4.6 实践任务:完成一个三页面内容工作台原型 + +在本小节结束前,请确保你的应用至少满足以下条件: + +- 完成“必须”和“建议”级别的功能 +- 页面导航清晰、跳转路径不绕圈 +- 你可以实际用它来浏览和更新真实的几条内容任务 +- 为下一节“在详情页里接入 AI 写文案 / 生成配图”留有一个明显的“任务详情页”入口(哪怕暂时内容很少) + +--- + +## 5. 把原型做得像那么回事 + +当功能和结构基本成型后,下一步就是“打磨质感”。这一节我们从界面、交互和参考项目三个角度,帮你把原型从“勉强能用”拉到“看上去靠谱,用起来顺手”。 + +### 5.1 界面结构:从“拼凑”走向“有秩序” + +先从最直观的地方入手:页面布局是否清晰、有层次。对于内容生产工作台,可以按下面几个原则逐步调整: + +1. 页面分区清楚 + - 每个页面都应该有一个清晰的标题,例如:内容概览、内容任务列表、系统设置 + - 主要操作区域(表单、筛选条件、保存按钮)与背景有明显区分 + +2. 信息有主次 + - 在首页中,整体统计数字(总任务、未开始、进行中、已发布)应放在页面上部或中央,引导用户视线 + - 列表和详细任务信息安排在其下方 + - 辅助信息(提示文案、版本号)可以放在页脚 + +3. 风格基本统一 + - 按钮样式统一:形状、颜色、圆角、文字风格保持一致 + - 标题层级统一:一级标题、二级标题的字号和粗细有规律 + - 颜色数量适度,避免页面到处是不同的颜色和字体 + +你可以对 AI 这样提出需求: + +> 请根据当前这个内容生产工作台的结构,帮我优化整体布局和样式。 +> 要求: +> +> 1. 每个页面的主标题更醒目,和正文区有明显区分 +> 2. 主要操作按钮的位置更明显,与次要按钮在颜色和样式上有区分 +> 3. 统一所有按钮和表单控件的样式与配色 +> 4. 适当增加留白和分割线,让统计区、表单区、列表区的边界更清晰。 + +### 5.2 交互体验:让操作自然顺手 + +一个“像那么回事”的原型,不仅要能点,还要让用户知道自己点了什么、接下来该做什么。以内容生产工作台为例,可以重点检查以下几个场景: + +1. 关键操作的反馈是否明确 + - 添加新任务成功后,是否有明显反馈,例如: + - 在页面上方显示一条“添加成功”的绿色提示,几秒后自动消失 + - 表单自动清空 + - 新任务出现在列表顶部 + - 删除任务时,是否有简单的确认对话框,避免误删 + +2. 流程是否顺手 + - 在列表页中修改状态后,是否可以即时更新当前行,而不用刷新整个页面 + - 从列表跳转到详情页、再返回列表,是否保持原有筛选条件和滚动位置 + +3. 错误提示是否友好 + - 如果用户尝试添加一条“标题为空”的任务,系统如何提醒 + - 提示文字是否用日常语言解释问题,例如: + - 内容标题不能为空,请先填写标题,再点击添加 + +你可以让 AI 具体帮你实现这些改动,例如: + +> 请为新增任务、删除任务和修改状态这三个操作加上明显的用户反馈。 +> 要求: +> +> - 添加成功时,在页面上方显示一条绿色提示,并将新任务插入到列表最上方 +> - 删除前弹出确认对话框,文案为“确定要删除这条内容任务吗” +> - 修改状态后,在该行右侧短暂显示“状态已更新”,同时刷新首页统计数字。 + +### 5.3 三个“土办法”自测你的体验是否及格 + +在没有设计师和正式用户测试的前提下,你可以用几个简单的方法,自己评估原型是否“像那么回事”: + +1. 10 秒规则 + - 找一个没参与过项目的人,让 TA 打开首页 + - 不给任何说明,看 TA 能否在 10 秒内说出: + - 这个页面大概是干什么的 + - 这里最主要的一两个操作是什么 + +2. 三次点击规则 + - 从首页出发,数一数一个典型任务需要几步: + - 例如“新增一条内容任务并确认它出现在列表中”,是否可以在三次点击内完成 + - 如果步骤太多,可以考虑简化流程、减少中间页面或按钮 + +3. 无说明书测试 + - 不给任何使用说明,看对方是否能自主找到“添加任务、筛选状态、删除任务”这三类基础功能 + - 观察 TA 卡住的地方,往往就是你需要补提示、改布局的位置 + +你不需要做到完美,但至少要做到:**三次测试中,大多数人都能在不依赖你口头指导的前提下,完成一到两个典型任务**。 + +### 5.4 参考项目:来自 vibe coding 社区的案例 + +在 vibe coding 社区中,已经有不少同学用类似方式,搭建了与内容和知识相关的小工具。这里简要分享两类典型项目,帮助你建立“原型完成度”的直觉。 + +#### 案例一:多渠道内容排期板 + +业务背景: +一个中小团队的市场负责人,需要统筹管理公众号、小红书、抖音、视频号等多个渠道的内容排期。 + +核心特征: + +1. 多页面结构清晰 + - 首页:展示不同渠道的内容任务数量、发布节奏概览 + - 任务列表页:按渠道和状态查看所有任务 + - 设置页:配置渠道列表、内容模版等 + +2. 和业务高度贴合 + - 每个任务绑定到特定渠道,可以看到每个渠道的计划和发布完成情况 + - 首页提供简单的“本周内容日历视图”,帮助团队提前规划产能 + +3. 界面简洁但不简陋 + - 使用统一的配色、按钮样式和标题层级 + - 在每个任务旁边预留 “用 AI 生成文案” 的入口(与下一节内容自然衔接) + +#### 案例二:内部知识文章工作台 + +业务背景: +一个技术团队希望把分散在个人文档里的技术分享、踩坑记录收拢到一个统一的知识库中。 + +核心特征: + +1. 单页面起步,多页面演化 + - 初始版本只是一个表单加列表页面,用于录入和浏览文章记录 + - 很快扩展出“文章详情页”“标签管理页”“导出页”等,让知识更容易被整理和复用 + +2. 巧妙利用 AI 能力(后续章节会讲) + - 在录入文章后,可以一键调用 AI 对内容做初步摘要,生成“阅读前要点” + - AI 可以根据文章内容自动建议标签、相关主题 + +3. 界面与交互足够顺手 + - 支持按标签筛选文章 + - 支持简单的排序和搜索 + - 关键操作都有明确提示 + +这些真实项目有一个共同点: +**一开始都非常简单,只解决一个具体的小问题,然后在使用过程中不断补足“应该有的那一点点”**。 +本节带你完成的内容生产工作台原型,其实就是走在同一条路径上。 + +### 5.5 实践任务:为你的原型做一次“体验升级” + +请针对你当前的内容工作台原型,完成下面三件事: + +1. 写下一条你认为最重要的使用场景 + - 例如:每天早上 10 分钟内,快速确认今天必须完成的内容任务列表 + - 或者:为某个主题活动统一规划多渠道的内容任务 + +2. 从“界面结构”和“交互反馈”两个角度,各列出 2–3 个可以改进的点 + - 界面结构:是否需要调整布局、字号、按钮位置;是否有信息过于拥挤或过于空白 + - 交互反馈:是否缺少成功/失败提示;某些操作是否流程太绕、步骤过多 + +3. 将这些改进点整理成自然语言,让 AI IDE 帮你一次性或分步执行 + - 改完后,邀请同事或朋友试玩 5–10 分钟,让他们用你的工具完成第 1 步里的使用场景 + - 根据他们的反馈,再补一轮小改动 + +完成这一轮,你的原型就不再只是“你自己知道怎么用的小玩具”,而是具备一定使用体验、可以逐步推广的业务工具。 + +--- + +## 总结 + +通过本节的学习,你已经经历了一次从业务梳理到多页面原型搭建与打磨的完整闭环,核心包括: + +- 从真实内容场景出发(以内容生产工作台为例),学会用自然语言梳理业务需求 +- 把业务流程映射为页面结构,用清晰描述驱动 AI IDE 搭建单页面应用 +- 在此基础上扩展出包含首页、任务列表页、设置页在内的多页面应用,并实现数据在页面间的简单传递 +- 建立遇到报错时的“标准动作”,通过现象描述、控制台信息和 AI 协作完成排查 +- 从界面布局和交互反馈两个维度,对原型做初步体验升级,并参照 vibe coding 社区中的实际项目,形成对“像那么回事”的共同标准 + +更重要的是,你已经体验了一次**AI 原生开发**和传统开发的关键差异: + +- 传统模式:先深入学习技术栈,再自己写代码实现业务 +- 本章模式:先把内容业务讲清楚,再让 AI 负责大部分实现细节,你更多在扮演“产品和架构的决策者” + +当你能反复完成这样的闭环,你就已经具备了“用 AI 把内容相关的业务想法快速做成可用原型”的关键能力。 + +## 下一步 + +在下一节中,我们将在这个内容生产工作台的基础上,接入具体的 AI 能力,例如: + +- 为某条内容任务自动生成文案初稿和多个标题备选 +- 根据任务描述自动生成配图草稿(文生图) +- 对历史内容任务做自动归类和摘要,帮助你规划下一个活动的选题 + +届时,你搭建的将不再只是一个“任务列表”,而是一个真正具备智能创作辅助能力的 AI 内容工作台。 diff --git a/docs/project/chapter2/images/image1.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image1.png similarity index 100% rename from docs/project/chapter2/images/image1.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image1.png diff --git a/docs/project/chapter2/images/image10.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image10.png similarity index 100% rename from docs/project/chapter2/images/image10.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image10.png diff --git a/docs/project/chapter2/images/image11.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image11.png similarity index 100% rename from docs/project/chapter2/images/image11.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image11.png diff --git a/docs/project/chapter2/images/image12.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image12.png similarity index 100% rename from docs/project/chapter2/images/image12.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image12.png diff --git a/docs/project/chapter2/images/image13.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image13.png similarity index 100% rename from docs/project/chapter2/images/image13.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image13.png diff --git a/docs/project/chapter2/images/image14.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image14.png similarity index 100% rename from docs/project/chapter2/images/image14.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image14.png diff --git a/docs/project/chapter2/images/image15.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image15.png similarity index 100% rename from docs/project/chapter2/images/image15.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image15.png diff --git a/docs/project/chapter2/images/image16.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image16.png similarity index 100% rename from docs/project/chapter2/images/image16.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image16.png diff --git a/docs/project/chapter2/images/image17.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image17.png similarity index 100% rename from docs/project/chapter2/images/image17.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image17.png diff --git a/docs/project/chapter2/images/image18.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image18.png similarity index 100% rename from docs/project/chapter2/images/image18.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image18.png diff --git a/docs/project/chapter2/images/image19.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image19.png similarity index 100% rename from docs/project/chapter2/images/image19.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image19.png diff --git a/docs/project/chapter2/images/image2.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image2.png similarity index 100% rename from docs/project/chapter2/images/image2.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image2.png diff --git a/docs/project/chapter2/images/image20.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image20.png similarity index 100% rename from docs/project/chapter2/images/image20.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image20.png diff --git a/docs/project/chapter2/images/image21.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image21.png similarity index 100% rename from docs/project/chapter2/images/image21.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image21.png diff --git a/docs/project/chapter2/images/image22.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image22.png similarity index 100% rename from docs/project/chapter2/images/image22.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image22.png diff --git a/docs/project/chapter2/images/image23.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image23.png similarity index 100% rename from docs/project/chapter2/images/image23.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image23.png diff --git a/docs/project/chapter2/images/image24.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image24.png similarity index 100% rename from docs/project/chapter2/images/image24.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image24.png diff --git a/docs/project/chapter2/images/image25.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image25.png similarity index 100% rename from docs/project/chapter2/images/image25.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image25.png diff --git a/docs/project/chapter2/images/image26.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image26.png similarity index 100% rename from docs/project/chapter2/images/image26.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image26.png diff --git a/docs/project/chapter2/images/image27.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image27.png similarity index 100% rename from docs/project/chapter2/images/image27.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image27.png diff --git a/docs/project/chapter2/images/image28.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image28.png similarity index 100% rename from docs/project/chapter2/images/image28.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image28.png diff --git a/docs/project/chapter2/images/image29.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image29.png similarity index 100% rename from docs/project/chapter2/images/image29.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image29.png diff --git a/docs/project/chapter2/images/image3.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image3.png similarity index 100% rename from docs/project/chapter2/images/image3.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image3.png diff --git a/docs/project/chapter2/images/image30.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image30.png similarity index 100% rename from docs/project/chapter2/images/image30.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image30.png diff --git a/docs/project/chapter2/images/image31.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image31.png similarity index 100% rename from docs/project/chapter2/images/image31.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image31.png diff --git a/docs/project/chapter2/images/image32.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image32.png similarity index 100% rename from docs/project/chapter2/images/image32.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image32.png diff --git a/docs/project/chapter2/images/image33.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image33.png similarity index 100% rename from docs/project/chapter2/images/image33.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image33.png diff --git a/docs/project/chapter2/images/image34.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image34.png similarity index 100% rename from docs/project/chapter2/images/image34.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image34.png diff --git a/docs/project/chapter2/images/image35.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image35.png similarity index 100% rename from docs/project/chapter2/images/image35.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image35.png diff --git a/docs/project/chapter2/images/image36.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image36.png similarity index 100% rename from docs/project/chapter2/images/image36.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image36.png diff --git a/docs/project/chapter2/images/image37.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image37.png similarity index 100% rename from docs/project/chapter2/images/image37.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image37.png diff --git a/docs/project/chapter2/images/image38.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image38.png similarity index 100% rename from docs/project/chapter2/images/image38.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image38.png diff --git a/docs/project/chapter2/images/image39.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image39.png similarity index 100% rename from docs/project/chapter2/images/image39.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image39.png diff --git a/docs/project/chapter2/images/image4.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image4.png similarity index 100% rename from docs/project/chapter2/images/image4.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image4.png diff --git a/docs/project/chapter2/images/image40.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image40.png similarity index 100% rename from docs/project/chapter2/images/image40.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image40.png diff --git a/docs/project/chapter2/images/image41.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image41.png similarity index 100% rename from docs/project/chapter2/images/image41.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image41.png diff --git a/docs/project/chapter2/images/image42.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image42.png similarity index 100% rename from docs/project/chapter2/images/image42.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image42.png diff --git a/docs/project/chapter2/images/image43.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image43.png similarity index 100% rename from docs/project/chapter2/images/image43.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image43.png diff --git a/docs/project/chapter2/images/image44.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image44.png similarity index 100% rename from docs/project/chapter2/images/image44.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image44.png diff --git a/docs/project/chapter2/images/image45.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image45.png similarity index 100% rename from docs/project/chapter2/images/image45.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image45.png diff --git a/docs/project/chapter2/images/image46.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image46.png similarity index 100% rename from docs/project/chapter2/images/image46.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image46.png diff --git a/docs/project/chapter2/images/image47.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image47.png similarity index 100% rename from docs/project/chapter2/images/image47.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image47.png diff --git a/docs/project/chapter2/images/image48.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image48.png similarity index 100% rename from docs/project/chapter2/images/image48.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image48.png diff --git a/docs/project/chapter2/images/image49.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image49.png similarity index 100% rename from docs/project/chapter2/images/image49.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image49.png diff --git a/docs/project/chapter2/images/image5.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image5.png similarity index 100% rename from docs/project/chapter2/images/image5.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image5.png diff --git a/docs/project/chapter2/images/image50.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image50.png similarity index 100% rename from docs/project/chapter2/images/image50.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image50.png diff --git a/docs/project/chapter2/images/image51.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image51.png similarity index 100% rename from docs/project/chapter2/images/image51.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image51.png diff --git a/docs/project/chapter2/images/image52.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image52.png similarity index 100% rename from docs/project/chapter2/images/image52.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image52.png diff --git a/docs/project/chapter2/images/image53.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image53.png similarity index 100% rename from docs/project/chapter2/images/image53.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image53.png diff --git a/docs/project/chapter2/images/image54.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image54.png similarity index 100% rename from docs/project/chapter2/images/image54.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image54.png diff --git a/docs/project/chapter2/images/image55.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image55.png similarity index 100% rename from docs/project/chapter2/images/image55.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image55.png diff --git a/docs/project/chapter2/images/image56.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image56.png similarity index 100% rename from docs/project/chapter2/images/image56.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image56.png diff --git a/docs/project/chapter2/images/image57.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image57.png similarity index 100% rename from docs/project/chapter2/images/image57.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image57.png diff --git a/docs/project/chapter2/images/image58.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image58.png similarity index 100% rename from docs/project/chapter2/images/image58.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image58.png diff --git a/docs/project/chapter2/images/image59.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image59.png similarity index 100% rename from docs/project/chapter2/images/image59.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image59.png diff --git a/docs/project/chapter2/images/image6.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image6.png similarity index 100% rename from docs/project/chapter2/images/image6.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image6.png diff --git a/docs/project/chapter2/images/image60.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image60.png similarity index 100% rename from docs/project/chapter2/images/image60.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image60.png diff --git a/docs/project/chapter2/images/image61.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image61.png similarity index 100% rename from docs/project/chapter2/images/image61.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image61.png diff --git a/docs/project/chapter2/images/image7.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image7.png similarity index 100% rename from docs/project/chapter2/images/image7.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image7.png diff --git a/docs/project/chapter2/images/image8.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image8.png similarity index 100% rename from docs/project/chapter2/images/image8.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image8.png diff --git a/docs/project/chapter2/images/image9.png b/docs/stage-1/1.3-integrating-ai-capabilities/images/image9.png similarity index 100% rename from docs/project/chapter2/images/image9.png rename to docs/stage-1/1.3-integrating-ai-capabilities/images/image9.png diff --git a/docs/project/chapter2/chapter2-reach-the-capability-boundaries-of-ai-tools.md b/docs/stage-1/1.3-integrating-ai-capabilities/index.md similarity index 95% rename from docs/project/chapter2/chapter2-reach-the-capability-boundaries-of-ai-tools.md rename to docs/stage-1/1.3-integrating-ai-capabilities/index.md index 35cb563..6d5af3e 100644 --- a/docs/project/chapter2/chapter2-reach-the-capability-boundaries-of-ai-tools.md +++ b/docs/stage-1/1.3-integrating-ai-capabilities/index.md @@ -1,4 +1,4 @@ -# Project 2: 探索 AI 工具的能力边界 +# 1.3 给原型加上 AI 能力 # 上节课复习题 @@ -6,12 +6,12 @@ 但是,这只是一个小测试。你可以通过以下问题来确认自己是否掌握了上节课的内容: -* 如何利用 z.ai 的全栈开发功能将我的想法变为现实? -* 普通应用和 AI 应用有什么区别?AI 原生应用到底是什么? -* API 到底是什么?云服务平台是什么?我如何让大语言模型(LLM)帮我集成语言模型和图像模型的 API? -* 如果我们要“调用”一个新模型,通常在哪里可以找到方法? -* 使用 AI 产品与使用其他普通程序有什么区别? -* 如何进行简单的 AI 产品研究?在哪里可以找到最新的 AI 产品研究,在哪里可以获得获得关键投资的 AI 产品公司的信息? +- 如何利用 z.ai 的全栈开发功能将我的想法变为现实? +- 普通应用和 AI 应用有什么区别?AI 原生应用到底是什么? +- API 到底是什么?云服务平台是什么?我如何让大语言模型(LLM)帮我集成语言模型和图像模型的 API? +- 如果我们要“调用”一个新模型,通常在哪里可以找到方法? +- 使用 AI 产品与使用其他普通程序有什么区别? +- 如何进行简单的 AI 产品研究?在哪里可以找到最新的 AI 产品研究,在哪里可以获得获得关键投资的 AI 产品公司的信息? 如果你发现有任何不理解的地方,请参考上节课的文档寻找答案,或直接在微信群里提问。 @@ -25,10 +25,10 @@ 在课堂上,你需要选择一个赛道进行重点学习。但如果你很有动力,课后可以尝试完成所有赛道的学习! -* **基于 Web 的 AI 编码能力(AI 编码赛道):** 了解不同编程网站的能力和局限性,并体验使用不同模型实现需求的难度(AI 编码赛道)。 -* **提示词/上下文工程的概念和基础技能(LLM 赛道):** 掌握如何调用和集成不同的大语言模型(LLM),识别它们的能力边界,并理解为什么在工业环境中编写提示词具有挑战性。 -* **图像/视频的常见用例和基础技能(图像/视频赛道):** 了解最先进的图像和视频模型的用例和能力边界,并复刻创意视频。 -* 如何识别最先进的 LLM 和图像模型,以及如何使用它们。 +- **基于 Web 的 AI 编码能力(AI 编码赛道):** 了解不同编程网站的能力和局限性,并体验使用不同模型实现需求的难度(AI 编码赛道)。 +- **提示词/上下文工程的概念和基础技能(LLM 赛道):** 掌握如何调用和集成不同的大语言模型(LLM),识别它们的能力边界,并理解为什么在工业环境中编写提示词具有挑战性。 +- **图像/视频的常见用例和基础技能(图像/视频赛道):** 了解最先进的图像和视频模型的用例和能力边界,并复刻创意视频。 +- 如何识别最先进的 LLM 和图像模型,以及如何使用它们。 # AI Coding 专家赛道 @@ -62,7 +62,7 @@ ## 行业应用 -让我们一起看看这篇实地研究文章:*[调查:软件开发团队中的 AI 浪潮持续增长](https://github.blog/news-insights/research/survey-ai-wave-grows/)* +让我们一起看看这篇实地研究文章:_[调查:软件开发团队中的 AI 浪潮持续增长](https://github.blog/news-insights/research/survey-ai-wave-grows/)_ ![](images/image5.png) @@ -104,8 +104,8 @@ > > 学习是通过自回归语言建模进行的。模型接收文本的第一部分(例如,“自然选择,最早由达尔文在《物种起源》(1859)中提出……”),然后预测随后的单词(“……通过可遗传特征的变化驱动生物进化。”)。训练目标是最小化预测单词与实际单词之间的交叉熵损失,使模型能够掌握语言模式和世界知识。 > -> * 书籍摘录:“自然选择,最早由达尔文在《物种起源》(1859)中提出,通过可遗传特征的变化驱动生物进化。” -> * 网页内容:“太阳能和风能排放的温室气体远少于煤炭或天然气。” +> - 书籍摘录:“自然选择,最早由达尔文在《物种起源》(1859)中提出,通过可遗传特征的变化驱动生物进化。” +> - 网页内容:“太阳能和风能排放的温室气体远少于煤炭或天然气。” > > **2. 微调数据 (Fine-Tuning)** > @@ -115,11 +115,11 @@ > > 采用监督学习范式。模型接收完整的输入(例如,“我如何退货?”)并学习生成标准答案(“登录您的帐户 →……”)。通过最小化模型输出与标准答案之间的差异(例如,交叉熵损失)来优化模型的参数,使其能够掌握该特定任务的输入-输出映射。 > -> * 输入(用户查询): +> - 输入(用户查询): > > “我如何退货?” > -> * 输出(机器人回复): +> - 输出(机器人回复): > > “登录您的帐户 → ‘订单历史’ → 选择订单 → ‘发起退货’。退款将在验证后 5-7 天内处理。” @@ -133,7 +133,7 @@ #### 回顾贪吃蛇游戏 -让我们回顾一下上一节课与模型交互的过程。事实上,我们的输入框可以看作是一个小指令,但它还不是我们需要在模型中强调的提示词。例如,我们输入了一句话:*“帮我创建一个生成猫的前端页面。当我输入一个句子时,它应该生成一只符合描述的猫。”* +让我们回顾一下上一节课与模型交互的过程。事实上,我们的输入框可以看作是一个小指令,但它还不是我们需要在模型中强调的提示词。例如,我们输入了一句话:_“帮我创建一个生成猫的前端页面。当我输入一个句子时,它应该生成一只符合描述的猫。”_ ![](images/image9.png) @@ -177,8 +177,8 @@ A minimalist Chinese ink wash landscape (shanshui style), distant misty mountain 一般来说: -* 思考模型往往需要更简单的提示词。在许多情况下,过长的提示词不会增加价值,甚至可能阻碍性能。 -* 对于非思考模型,在处理复杂需求时,你可以尝试使用非常详细、精细的提示词,以确保输出完全符合你的期望。 +- 思考模型往往需要更简单的提示词。在许多情况下,过长的提示词不会增加价值,甚至可能阻碍性能。 +- 对于非思考模型,在处理复杂需求时,你可以尝试使用非常详细、精细的提示词,以确保输出完全符合你的期望。 我们将测试的大多数模型对针对非思考模型定制的提示词工程技术反应更灵敏。这是因为思考模型通常在较短的提示词下茁壮成长,不需要严格、复杂的规则。也就是说,本教程的主要目标是动手体验:你也可以在思考模型和非思考模型之间切换,输入以下提示词工程示例,并比较输出以观察结果如何变化。 @@ -274,13 +274,9 @@ Output: > 好的,让我们分解一下: > > 1. 你开始有 10 个苹果。 -> > 2. 你给了邻居 2 个,剩下 10 - 2 = 8 个苹果。 -> > 3. 你给了修理工 2 个,剩下 8 - 2 = 6 个苹果。 -> > 4. 然后你买了 5 个苹果,现在有 6 + 5 = 11 个苹果。 -> > 5. 最后,你吃了 1 个苹果,所以剩下 11 - 1 = 10 个苹果。 > > 所以,你还剩 10 个苹果。 @@ -312,9 +308,7 @@ Output: > 这个小厨师的厨房就是它的叶子。它需要三种原料: > > 1. 阳光:这就像打开炉子的能量。 -> > 2. 空气(里面的二氧化碳):这就像食谱里的面粉。 -> > 3. 水:从根部吸上来的,这就像混合面团用的水。 > > 当阳光照在叶子上时,“厨师”就开始工作了!它把空气和水混合在一起,利用太阳的能量把它们变成美味的“能量糖果”(那就是植物的食物)。最酷的部分是什么?当它做饭的时候,它会呼出新鲜的空气——氧气,也就是我们需要呼吸的空气! @@ -329,29 +323,26 @@ Output: Prompt: -> `` +> <instructions> > -> 1. 为 `` 块中的内容生成摘要。 +> 1. 为 <text> 块中的内容生成摘要。 +> 2. 摘要必须严格遵循 <rules> 块中的所有规则。 > -> 2. 摘要必须严格遵循 `` 块中的所有规则。 +> </instructions> > -> `` -> -> `` +> <text> > > 人工智能 (AI) 是一个广泛的领域,涵盖了从机器人技术到自然语言处理的一系列技术。AI 的一个核心分支是机器学习,它允许计算机系统从数据中学习并在没有明确编程的情况下进行改进。深度学习是机器学习的一个子集,近年来取得了巨大的突破。 > -> `` +> </text> > -> `` +> <rules> > > 1. 摘要长度必须正好是三句话。 -> > 2. 摘要必须包含关键词“机器学习”。 -> > 3. 摘要的语气应该是专业和客观的。 > -> `` +> </rules> Output: @@ -381,10 +372,10 @@ Output (A likely result): > > 产品详情: > -> * 产品名称:`[插入产品名称]` -> * 关键特性(3-5个要点):`[列出最重要的特性]` -> * 目标受众:`[描述理想客户,例如“具有环保意识的千禧一代”、“忙碌的父母”、“科技爱好者”]` -> * 独特卖点:`[是什么让这个产品与众不同?]` +> - 产品名称:`[插入产品名称]` +> - 关键特性(3-5个要点):`[列出最重要的特性]` +> - 目标受众:`[描述理想客户,例如“具有环保意识的千禧一代”、“忙碌的父母”、“科技爱好者”]` +> - 独特卖点:`[是什么让这个产品与众不同?]` > > 指令: > @@ -442,18 +433,18 @@ Output (A likely result): > > 使用技术: > -> +> <instructions> > -> 1. 为 `` 块中的内容创建一个一句话摘要。 +> 1. 为 <review> 块中的内容创建一个一句话摘要。 > 2. 确定评论者是否推荐该产品。 > 3. 列出一个提到的优点和一个缺点。 -> `` +> </instructions> > -> +> <review> > > 我最近购买了 XYZ 耳机,并且每天使用两周了。音质非常出色,高音清晰,低音深沉。然而,佩戴大约一小时后会变得不舒服。电池续航时间比宣传的要长,这是一个惊喜。我很纠结,因为声音很棒,但舒适度不足。我会向不需要长时间佩戴耳机的人推荐它们。 > -> +> </review> > > 使用技术的输出: > @@ -481,17 +472,17 @@ Output (A likely result): 与主要关注指令本身的提示词工程不同,上下文工程将上下文窗口视为一个需要仔细策划的有限空间。其核心挑战在于选择正确的上下文并确保此上下文适合有限窗口的约束。上下文是指提供给 AI 智能体或 LLM 以执行任务的所有信息的总和;在实际工程中,我们需要向 LLM 输入各种类型的信息,主要包括以下组件: -* 系统提示词/指令 (System prompt/instruction):定义智能体的场景和任务目标。 -* 用户输入 (User input):用户的问题或任务请求。 -* 短期记忆或聊天记录 (Short-term memory or chat history):提供当前对话的即时上下文。 -* 长期记忆 (Long-term memory):用于存储和检索跨多个对话或长时间段的信息。 -* 从知识库检索的信息 (Information retrieved from a knowledge base):通过向量搜索或其他方法从外部数据库、API 或类似来源获得的数据。 -* 工具及其定义 (Tools and their definitions):通知模型它可以使用哪些工具来完成任务。 -* 工具的响应 (Responses from tools):工具执行后返回的结果,作为模型下一步行动的基础。 -* 结构化信息 (Structured Information):以特定格式(如 JSON Schema)提供或请求的信息,用于压缩上下文并防止信息过载。 -* 工作流/全局状态 (Workflow/Global State):充当“便签本”,用于在多步骤智能体任务期间存储和检索全局信息。 +- 系统提示词/指令 (System prompt/instruction):定义智能体的场景和任务目标。 +- 用户输入 (User input):用户的问题或任务请求。 +- 短期记忆或聊天记录 (Short-term memory or chat history):提供当前对话的即时上下文。 +- 长期记忆 (Long-term memory):用于存储和检索跨多个对话或长时间段的信息。 +- 从知识库检索的信息 (Information retrieved from a knowledge base):通过向量搜索或其他方法从外部数据库、API 或类似来源获得的数据。 +- 工具及其定义 (Tools and their definitions):通知模型它可以使用哪些工具来完成任务。 +- 工具的响应 (Responses from tools):工具执行后返回的结果,作为模型下一步行动的基础。 +- 结构化信息 (Structured Information):以特定格式(如 JSON Schema)提供或请求的信息,用于压缩上下文并防止信息过载。 +- 工作流/全局状态 (Workflow/Global State):充当“便签本”,用于在多步骤智能体任务期间存储和检索全局信息。 -此时,你肯定在想,*“这到底是什么?我不明白。”* 这完全没关系——我们只需要大概知道它很复杂,不需要完全掌握每个细节。我们将在以后的高级课程中为你分解每个组件。 +此时,你肯定在想,_“这到底是什么?我不明白。”_ 这完全没关系——我们只需要大概知道它很复杂,不需要完全掌握每个细节。我们将在以后的高级课程中为你分解每个组件。 上下文工程出现的主要原因是我们需要与大语言模型(LLM)进行多轮对话。此外,基于对话者信息的更新——如对话上下文、情绪等——模型不能丢失关键对话记录的跟踪或偏离预定方向。这需要对每轮对话的内容进行选择性和克制的处理。此外,**LLM 本身的配置——即系统提示词(核心提示词)——需要更高级别的处理。** @@ -589,27 +580,27 @@ EVA:您好!感谢联系我们。感谢您对 SynthWave Pro 的兴趣。根 **实验 A:消融“语气和风格”部分** -* **步骤**:复制“黄金标准”提示词,但**完全删除**整个 `# TONE and STYLE` 模块。 -* **测试**:询问 5 个标准测试问题。 -* **分析**:与基线结果相比,Eva 的回答有何变化?她的语气变得机械或不一致了吗?她还记得使用礼貌的问候和结束语吗? +- **步骤**:复制“黄金标准”提示词,但**完全删除**整个 `# TONE and STYLE` 模块。 +- **测试**:询问 5 个标准测试问题。 +- **分析**:与基线结果相比,Eva 的回答有何变化?她的语气变得机械或不一致了吗?她还记得使用礼貌的问候和结束语吗? **实验 B:消融“行为约束”部分** -* **步骤**:复制“黄金标准”提示词,但**完全删除** `# BEHAVIORAL CONSTRAINTS (What NOT to Do)` 模块。 -* **测试**:询问 5 个标准测试问题,**特别是**测试用例 #4 和 #5。 -* **分析**:Eva 的行为变得“危险”或“不可靠”了吗?对于知识库之外的问题(#4),她开始编造(幻觉)功能了吗?对于价格匹配问题(#5),她给出了不确定的、可能具有误导性的答案,而不是坚定的拒绝吗? +- **步骤**:复制“黄金标准”提示词,但**完全删除** `# BEHAVIORAL CONSTRAINTS (What NOT to Do)` 模块。 +- **测试**:询问 5 个标准测试问题,**特别是**测试用例 #4 和 #5。 +- **分析**:Eva 的行为变得“危险”或“不可靠”了吗?对于知识库之外的问题(#4),她开始编造(幻觉)功能了吗?对于价格匹配问题(#5),她给出了不确定的、可能具有误导性的答案,而不是坚定的拒绝吗? **实验 C:消融“升级协议”部分** -* **步骤**:复制“黄金标准”提示词,但**完全删除** `# ESCALATION PROTOCOL` 模块。为了避免冗余,也从 `# FEW-SHOT EXAMPLES` 中**删除** `[EXAMPLE 3]`。 -* **测试**:专注于使用测试用例 #3(“iPad app”)。 -* **分析**:当面对她无法回答的问题时,Eva 现在会怎么做?她只是说“我不知道”吗?她试图猜测吗?她完全失去了将问题升级给人工支持的能力吗? +- **步骤**:复制“黄金标准”提示词,但**完全删除** `# ESCALATION PROTOCOL` 模块。为了避免冗余,也从 `# FEW-SHOT EXAMPLES` 中**删除** `[EXAMPLE 3]`。 +- **测试**:专注于使用测试用例 #3(“iPad app”)。 +- **分析**:当面对她无法回答的问题时,Eva 现在会怎么做?她只是说“我不知道”吗?她试图猜测吗?她完全失去了将问题升级给人工支持的能力吗? **实验 D:消融“少样本示例”部分** -* **步骤**:复制“黄金标准”提示词,但**完全删除** `# FEW-SHOT EXAMPLES` 模块下的所有 4 个示例。 -* **测试**:询问所有 5 个标准测试问题。 -* **分析**:这是最有趣的实验。虽然所有的规则和知识仍然存在,但 Eva 在没有具体示例的情况下表现如何?她的答案格式仍然像示例中那样清晰吗?当处理棘手的情况(如拒绝折扣或升级问题)时,她的措辞仍然礼貌有效吗?她遵循指令的精确度下降了吗? +- **步骤**:复制“黄金标准”提示词,但**完全删除** `# FEW-SHOT EXAMPLES` 模块下的所有 4 个示例。 +- **测试**:询问所有 5 个标准测试问题。 +- **分析**:这是最有趣的实验。虽然所有的规则和知识仍然存在,但 Eva 在没有具体示例的情况下表现如何?她的答案格式仍然像示例中那样清晰吗?当处理棘手的情况(如拒绝折扣或升级问题)时,她的措辞仍然礼貌有效吗?她遵循指令的精确度下降了吗? 你也可以随意消融任何其他部分并观察产生的对话结果。例如,你可以选择只删除 # RULES 模块的一部分(例如与“礼貌措辞要求”相关的条款),而不是删除整个部分,然后测试 Eva 的响应语气如何变化——她是否变得过于直接甚至有点生硬。 @@ -657,7 +648,7 @@ Claude Prompt engineering overview: https://docs.claude.com/en/docs/build-with-c GPT-4.1 Prompting Guide: https://cookbook.openai.com/examples/gpt4-1_prompting_guide -Best practices for prompt engineering with the OpenAI API: https://help.openai.com/en/articles/6654000-best-practices-for-prompt-engineering-with-the-openai-api +Best practices for prompt engineering with the OpenAI API: https://help.openai.com/en/articles/6654000-best-practices-for-prompt-engineering-with-the-openai-api o3/o4-mini Function Calling Guide: https://cookbook.openai.com/examples/o-series/o3o4-mini_prompting_guide @@ -675,7 +666,6 @@ Optimizing LangChain AI Agents with Contextual Engineering: https://levelup.gitc 在今天的课程中,我们需要生成大量的图像和视频。为了方便起见,我们将使用统一连接的云服务提供商,并将提供相应的代码和 Token。在上一节课中,大家已经学习了如何集成 API 和使用 Token。你只需要按照以下步骤操作,回忆上节课学到的内容,就可以在 Z.AI 中成功启动你自己的图像/视频应用程序。 - ![](images/image20.png)![](images/image21.png)![](images/image22.png) ## Nano banana @@ -703,7 +693,7 @@ import requests from typing import Dict, Any, Optional NANOBANANA_API_URL: str = "https://api.zyai.online/v1/chat/completions" -NANOBANANA_API_KEY: str = +NANOBANANA_API_KEY: str = def create_nanobanana_txt2img_task() -> Optional[Dict[str, Any]]: """ @@ -765,7 +755,7 @@ import os from typing import Dict, Any, Optional, List NANOBANANA_API_URL: str = "https://api.zyai.online/v1/chat/completions" -NANOBANANA_API_KEY: str = +NANOBANANA_API_KEY: str = IMAGE_PATH_1: str = "/Users/sanbu/Code/project_python/fast_tools/mirai/API/python_model_api_call_files/generated_image_1.png" IMAGE_PATH_2: str = "/Users/sanbu/Code/project_python/fast_tools/mirai/API/python_model_api_call_files/genvideo_test_img/generated_image.png" @@ -783,10 +773,10 @@ def image_to_base64_with_format(image_path: str) -> Optional[str]: try: file_extension: str = os.path.splitext(image_path)[1].lower() image_format: str = file_extension.replace('.', '') - + if image_format == 'jpg': image_format = 'jpeg' - + with open(image_path, "rb") as img_file: encoded: bytes = base64.b64encode(img_file.read()) base64_str: str = encoded.decode("utf-8") @@ -804,7 +794,7 @@ def create_nanobanana_multi_img2img_task() -> Optional[Dict[str, Any]]: """ image_b64_1: Optional[str] = image_to_base64_with_format(IMAGE_PATH_1) image_b64_2: Optional[str] = image_to_base64_with_format(IMAGE_PATH_2) - + if not image_b64_1 or not image_b64_2: print("One or more images reading failed, cannot submit task.") return None @@ -900,7 +890,7 @@ from typing import Dict, Any, Optional # API地址已替换为 https://api.zyai.online/seedance/v3 # 使用后台提供的API Key SEEDANCE_API_URL: str = "https://api.zyai.online/seedance/v3/contents/generations/tasks" -SEEDANCE_API_KEY: str = +SEEDANCE_API_KEY: str = def create_seedance_txt2video_task() -> Optional[str]: """ @@ -1105,11 +1095,11 @@ def image_to_base64_with_format(image_path: str) -> Optional[str]: # 获取图片文件扩展名以确定格式 file_extension: str = os.path.splitext(image_path)[1].lower() image_format: str = file_extension.replace('.', '') - + # 处理特殊格式 if image_format == 'jpg': image_format = 'jpeg' - + with open(image_path, "rb") as img_file: encoded: bytes = base64.b64encode(img_file.read()) base64_str: str = encoded.decode("utf-8") @@ -1319,9 +1309,9 @@ if __name__ == "__main__": ### 图像风格化生成 ```Bash -Convert this image to a black-and-white comic style. -Convert this image to an oil painting style. -Convert this image to a pop art style. +Convert this image to a black-and-white comic style. +Convert this image to an oil painting style. +Convert this image to a pop art style. ``` ![](images/image31.png) @@ -1454,5 +1444,3 @@ Artificial Analysis 是领先的独立 AI 基准测试和分析平台。它专 其功能包括模型比较、质量评估、价格分析、性能测试和上下文窗口分析。它还提供了详细的用户指南和常见问题解答,涵盖各种类型模型的评估,如大语言模型、文本到图像模型和语音到文本模型。此外,它还提供了一个专注于模型基准的免费 API 和一个具有更全面数据的商业 API。 ![](images/image61.png) - - diff --git a/docs/stage-1/1.4-complete-project-practice/index.md b/docs/stage-1/1.4-complete-project-practice/index.md new file mode 100644 index 0000000..e5d2602 --- /dev/null +++ b/docs/stage-1/1.4-complete-project-practice/index.md @@ -0,0 +1,134 @@ +# 1.4 完整项目实战 + +本节将通过一个完整的实战项目,带你体验从原型到可展示产品的全过程。你将学会如何让原型看起来更真实,如何收集反馈,以及如何向他人展示你的成果。 + +## 1.4.1 制造模拟数据让原型看起来真实 + +### 学习目标 + +本节的核心目标是让你理解模拟数据在原型展示中的重要性。你将学会如何创建和使用模拟数据,并掌握一些让原型“活起来”的技巧,使其在演示时更具说服力。 + +### 核心内容 + +**为什么需要模拟数据?** 想象一下,你向别人展示一个待办事项应用,但列表里空空如也,或者展示一个社交软件,却没有任何动态。空荡荡的页面无法展示产品的实际功能和使用场景,而真实、丰富的数据能让演示瞬间变得生动,让观众更容易理解产品的价值。 + +**数据结构设计**是创建模拟数据的第一步。你需要思考你的应用需要什么样的数据字段。例如,一个用户画像可能包含姓名、头像、简介等字段;一个商品列表可能包含名称、价格、图片、描述等。合理的数据结构能让后续的开发和展示更加顺畅。 + +**生成逼真的测试数据**不再需要手动一条条输入。你可以利用 AI 批量生成符合逻辑的测试数据。只需告诉 AI 你需要的数据类型和数量,它就能为你生成包含各种情况(如长文本、特殊字符、不同状态)的数据集。 + +**集成数据**是将模拟数据应用到原型的过程。对于简单的原型,你可以直接将模拟数据硬编码到前端代码中。如果你希望数据能持久化保存,也可以尝试使用浏览器的本地存储(LocalStorage)进行读取和保存。 + +### 实践任务 + +请为你当前的项目添加至少 10 条模拟数据。确保这些数据不仅仅是简单的重复,而是覆盖了各种场景:包括正常的标准数据、边界情况的长文本数据、以及可能出现的空状态数据。 + +**示例:待办清单应用的模拟数据** + +你可以参考以下格式来构建你的数据: + +```javascript +const mockTodos = [ + { id: 1, title: '完成项目原型', completed: true, priority: 'high' }, + { id: 2, title: '收集用户反馈', completed: false, priority: 'medium' }, + { id: 3, title: '优化界面设计', completed: false, priority: 'low' } + // ... 更多数据 +] +``` + +--- + +## 1.4.2 收集反馈并快速调整 + +### 学习目标 + +产品开发是一个不断迭代的过程。本节旨在帮助你建立产品迭代思维,学会有效地收集用户反馈,并掌握基于反馈进行快速迭代的方法,从而不断完善你的产品。 + +### 核心内容 + +**寻找测试用户**是获取反馈的第一步。你可以从身边的朋友、同学开始,寻找愿意花时间体验你产品的人。他们不需要是专家,普通用户的视角往往能发现最真实的问题。 + +**反馈收集方法**不仅仅是听用户说什么。更重要的是观察他们的操作过程,记录他们在使用时停顿、困惑或反复操作的地方。这些无声的反馈往往比语言更准确地反映了产品的易用性问题。 + +**反馈分类与优先级**是处理大量反馈的关键。你需要将收集到的反馈区分为 "Bug"(程序错误)、"体验优化"(好用性问题)和 "新功能需求"。在资源有限的情况下,优先解决阻碍用户正常使用的 Bug,其次是提升核心体验的优化,最后再考虑添加新功能。 + +**快速迭代**是互联网产品的生存法则。基于收集到的反馈,利用 AI 辅助编程的优势,快速修改代码并发布新版本。不要等到完美再发布,小步快跑,持续改进。 + +### 实践任务 + +请邀请至少 3 位同学或朋友试用你的原型。在他们使用过程中,记录下他们的反馈,包括正面的肯定和负面的吐槽。然后,从这些反馈中筛选出至少 2 个高优先级的改进点,利用 AI 帮你实现这些修改,并更新你的原型。 + +**反馈收集参考问题** + +为了获得更具价值的反馈,你可以尝试问以下问题: + +- 你最喜欢的功能是什么? +- 在使用过程中,你觉得最困惑或不好用的地方是什么? +- 你希望这个应用增加什么功能? +- 整体体验如何?请打个分(1-5 分)。 + +--- + +## 1.4.3 展示你的成果 + +### 学习目标 + +做出了好产品,还要会展示。本节将教你如何准备一场精彩的产品演示,掌握演示的技巧,并了解如何讲好你的产品故事,让听众对你的作品印象深刻。 + +### 核心内容 + +**演示准备**是成功的关键。你需要梳理清楚演示的流程,准备好演示脚本,并确保演示环境(网络、设备)的稳定。每一次演示都是一次演出,充分的彩排能让你在台上更加从容。 + +**结构化演示**能让你的表达更有逻辑。一个好的演示通常包含三个部分: + +1. **背景**:清晰地阐述你解决了什么问题,为什么这个问题值得解决。 +2. **演示**:展示你的核心功能是如何解决这个问题的,通过实际操作让观众眼见为实。 +3. **价值**:总结这个产品的亮点和独特价值,让观众记住你的产品。 + +**应对突发情况**是每个演示者都要修行的功课。如果演示过程中出现 Bug,千万不要惊慌。保持冷静,幽默地说明这是原型阶段的正常现象,然后从容地跳过故障点,继续演示其他功能。观众通常会理解并包容原型阶段的小瑕疵。 + +### 实践任务 + +请准备一个 3-5 分钟的产品演示。演示内容应包含:1 分钟的背景介绍,阐述产品解决的问题;2-3 分钟的核心功能展示,实际操作你的原型;最后 1 分钟总结技术亮点和未来计划。 + +**演示检查清单** + +在正式演示前,请对照以下清单进行检查: + +- [ ] 提前测试所有功能,确保核心流程不会出错。 +- [ ] 准备好演示账号和模拟数据,避免现场注册或录入数据的尴尬。 +- [ ] 准备好应对常见问题的回答,预判观众的疑问。 +- [ ] 录制一个备用视频,以防现场网络或环境出现不可控问题。 +- [ ] 准备一个吸引人的开场白,在最初的几秒钟抓住观众的注意力。 + +--- + +## 项目展示示例结构 + +为了帮助你更好地组织演示内容,我们提供了一个标准的展示结构供参考: + +### 项目名称:[你的项目名] + +**一句话介绍** +用简练、有力的一句话描述你的项目解决什么核心问题,让听众瞬间get到产品的点。 + +**核心功能** + +1. **[功能 1]**:具体描述该功能,并说明它解决了什么具体问题。 +2. **[功能 2]**:具体描述该功能,并说明它解决了什么具体问题。 +3. **[功能 3]**:具体描述该功能,并说明它解决了什么具体问题。 + +**技术亮点** +在此部分,你可以展示你的技术实力。例如,你使用了哪些 AI 能力?在设计上有什么创新之处?在开发过程中遇到了什么技术挑战,又是如何解决的? + +**未来计划** +展示你对产品的长远规划。你计划添加哪些新功能?目前有哪些地方想要改进?以及你希望获得什么样的帮助或资源支持? + +--- + +## 总结 + +完成本节后,你应该能够为你的原型添加逼真的模拟数据,使其在演示时栩栩如生;能够有效地收集和处理用户反馈,持续优化产品;并且能够自信地向他人展示你的产品,讲好你的产品故事。 + +## 下一步 + +现在你已经完成了一个完整的项目实战,积累了从开发到展示的全流程经验。准备好迎接最终的 **大作业** 挑战了吗?让我们开始吧! diff --git a/docs/stage-1/1.5-final-project/index.md b/docs/stage-1/1.5-final-project/index.md new file mode 100644 index 0000000..a693172 --- /dev/null +++ b/docs/stage-1/1.5-final-project/index.md @@ -0,0 +1,130 @@ +# 1.5 大作业:Web 应用原型实战 + +这是第一阶段学习的最终检验。通过这个大作业,你将综合运用前面学到的所有知识,独立完成一个完整的 Web 应用原型,并向他人展示你的成果。这不仅是一次作业,更是你从学习者向开发者转变的重要里程碑。 + +## 大作业要求 + +### 基本要求 + +为了确保你能掌握本阶段的核心技能,我们设定了以下基本要求: +首先,你需要**全程使用 AI IDE** 完成所有开发工作,这能让你熟练掌握人机协作的开发模式。 +其次,你的应用至少需要**包含 3 个页面**,以体现你对多页面应用架构的理解。 +同时,必须**集成至少 1 种 AI 能力**(如文本生成、图像生成等),这是本课程的核心特色。 +此外,应用需要包含**完整的用户交互流程**和**模拟数据**,确保用户可以完整体验核心功能,而不是面对一个空壳。 +最后,你需要准备一个 **3-5 分钟的演示**,向大家展示你的作品。 + +### 加分项 + +如果你想挑战自我,争取更高的评价,可以尝试以下方向: +**集成多种 AI 能力**,让应用更智能、更强大。 +**UI 设计精美,体验流畅**,展现你对用户体验的追求。 +建立**完整的错误处理机制**,提升应用的健壮性。 +加入**用户反馈收集功能**,体现产品迭代思维。 +将应用**部署到线上环境**,让任何人都能通过链接访问,这是产品真正落地的标志。 + +--- + +## 项目选题建议 + +如果你还没有确定项目方向,不要着急。这里有一些选题供你参考,你可以直接选择,也可以从中获取灵感: + +### 工具类 + +这类应用旨在提高效率。例如 **AI 学习助手**,可以帮助用户整理杂乱的学习笔记,利用 AI 生成针对性的练习题和答案,甚至跟踪学习进度。或者做一个 **智能待办清单**,它不只是记录任务,还能自动识别任务优先级,利用 AI 生成任务分解建议,并提供智能提醒和日程安排。你也可以尝试 **AI 写作辅助工具**,帮助用户润色文章、生成续写建议,以及检查语法和表达错误。 + +### 创意类 + +这类应用侧重于激发创造力。比如 **AI 故事创作器**,用户只需输入几个关键词,AI 就能生成一个完整的故事,甚至自动配图。或者 **个性化卡片生成器**,用户输入祝福语,AI 生成精美的电子卡片,支持导出分享给亲友。还有 **AI 对话练习伙伴**,它可以模拟各种场景对话,实时反馈建议,帮助用户提升语言表达能力。 + +### 生活类 + +这类应用贴近日常生活。**智能食谱推荐** 可以根据用户冰箱里现有的食材推荐菜谱,生成购物清单,并分析营养成分。**旅行计划助手** 则可以根据目的地生成详细行程,AI 推荐景点和美食,并进行预算估算,让旅行更轻松。 + +--- + +## 项目时间规划 + +为了保证按时高质量完成,建议参考以下时间规划,总共约 1-2 周: + +### 第一阶段:需求确定(1-2 天) + +这是项目的起点。你需要**确定项目方向和核心功能**,想清楚你要做什么。然后,**画出简单的页面流程图**,理清用户在应用中的操作路径。最后,**列出至少 3 个核心用户场景**,确保你的功能是围绕真实需求设计的。 + +### 第二阶段:原型开发(3-5 天) + +这是最核心的编码阶段。从**用 AI IDE 创建第一个页面**开始,逐步**完成所有页面和交互**。在基础功能完成后,**接入 AI 能力**,让应用变聪明。最后,别忘了**添加模拟数据**,让应用看起来丰满真实。 + +### 第三阶段:优化完善(2-3 天) + +好产品是改出来的。**邀请他人试用,收集反馈**,听听真实用户的声音。根据反馈**改进功能和体验**,修复明显的 Bug。同时,**完善错误处理**,避免应用在异常情况下崩溃。最后,开始**准备演示内容**。 + +### 第四阶段:展示准备(1 天) + +临门一脚,展示同样重要。**准备演示脚本**,确保演示过程流畅、逻辑清晰。**录制演示视频备用**,以防现场演示出现意外。整理一份**项目说明文档**,方便他人快速了解你的项目。 + +--- + +## 提交清单 + +### 必交内容 + +提交作业时,请确保包含以下内容: + +1. **项目源代码**:提交完整可运行的项目代码,并确保有清晰的代码注释,方便他人阅读。 +2. **项目说明文档**:文档应包含项目简介、核心功能说明、技术实现亮点以及使用指南。 +3. **演示材料**:提交 3-5 分钟的演示视频(或现场演示录像),以及配套的 PPT 或演示脚本。 + +### 可选内容 + +如果有的话,也可以提交:项目的部署链接、用户反馈收集结果的整理,以及对未来的迭代计划。这些都能展示你的专业度和思考深度。 + +--- + +## 评审标准 + +### 功能完整性(40 分) + +这是最基础的要求。我们将检查你是否**实现了承诺的核心功能**,**交互流程是否完整可用**,以及**AI 能力是否集成正确**且能正常工作。 + +### 用户体验(30 分) + +好的应用应该好用且好看。我们将关注**界面是否清晰美观**,**操作流程是否顺畅**,以及在关键操作上是否有**适当的反馈和引导**。 + +### 技术实现(20 分) + +代码质量也很重要。我们将评估你的**代码结构是否合理**,是否包含了必要的**错误处理**机制,以及你是否**有效运用了 AI IDE** 来辅助开发。 + +### 展示效果(10 分) + +能否把产品讲清楚也是一种能力。我们将看你的**演示准备是否充分**,**讲述是否清晰有条理**,以及你**能否准确说明产品的价值**。 + +--- + +## 成功小贴士 + +1. **从小处着手**:不要贪大求全,试图一次做太多功能。先把最核心的功能做好,保证流程跑通,再考虑扩展其他功能。 +2. **善用 AI**:遇到问题不要死磕,先问 AI。让 AI 帮你优化代码、生成测试数据,充分发挥 AI 结对编程的优势。 +3. **多收集反馈**:尽早让别人试用你的产品,认真倾听每个建议,快速迭代改进。旁观者清,他们的反馈往往能一针见血。 +4. **讲好故事**:在演示时,不要只罗列功能。要突出你解决了什么问题,展示产品的价值,并分享你在过程中的学习收获。 + +--- + +## 完成后的收获 + +完成这个大作业后,你将拥有一个完整的 AI 原型项目作品,这是你能力的最好证明。你将掌握使用 AI IDE 进行全流程开发的实战技能,具备产品思维和基本的开发能力。更重要的是,你将建立起继续深入学习更高级内容的信心。 + +**最重要的是:通过这次实战,你将真正从一个 AI 用户,转变为一个 AI 应用创造者!** + +--- + +## 参考资源 + +- 回顾模块一:AI 能力边界 +- 回顾模块二:AI IDE 使用技巧 +- 回顾模块三:原型开发 +- 回顾模块四:AI 能力接入 +- 回顾模块五:项目实战 +- 附录A:产品思维补充 +- 附录B:常见报错及解决方案 + +加油!期待看到你的精彩作品! diff --git a/docs/project/chapter6/images/image1.png b/docs/stage-1/appendix-a-product-thinking/images/image1.png similarity index 100% rename from docs/project/chapter6/images/image1.png rename to docs/stage-1/appendix-a-product-thinking/images/image1.png diff --git a/docs/project/chapter6/images/image10.png b/docs/stage-1/appendix-a-product-thinking/images/image10.png similarity index 100% rename from docs/project/chapter6/images/image10.png rename to docs/stage-1/appendix-a-product-thinking/images/image10.png diff --git a/docs/project/chapter6/images/image11.png b/docs/stage-1/appendix-a-product-thinking/images/image11.png similarity index 100% rename from docs/project/chapter6/images/image11.png rename to docs/stage-1/appendix-a-product-thinking/images/image11.png diff --git a/docs/project/chapter6/images/image12.png b/docs/stage-1/appendix-a-product-thinking/images/image12.png similarity index 100% rename from docs/project/chapter6/images/image12.png rename to docs/stage-1/appendix-a-product-thinking/images/image12.png diff --git a/docs/project/chapter6/images/image13.png b/docs/stage-1/appendix-a-product-thinking/images/image13.png similarity index 100% rename from docs/project/chapter6/images/image13.png rename to docs/stage-1/appendix-a-product-thinking/images/image13.png diff --git a/docs/project/chapter6/images/image14.png b/docs/stage-1/appendix-a-product-thinking/images/image14.png similarity index 100% rename from docs/project/chapter6/images/image14.png rename to docs/stage-1/appendix-a-product-thinking/images/image14.png diff --git a/docs/project/chapter6/images/image15.png b/docs/stage-1/appendix-a-product-thinking/images/image15.png similarity index 100% rename from docs/project/chapter6/images/image15.png rename to docs/stage-1/appendix-a-product-thinking/images/image15.png diff --git a/docs/project/chapter6/images/image16.png b/docs/stage-1/appendix-a-product-thinking/images/image16.png similarity index 100% rename from docs/project/chapter6/images/image16.png rename to docs/stage-1/appendix-a-product-thinking/images/image16.png diff --git a/docs/project/chapter6/images/image17.png b/docs/stage-1/appendix-a-product-thinking/images/image17.png similarity index 100% rename from docs/project/chapter6/images/image17.png rename to docs/stage-1/appendix-a-product-thinking/images/image17.png diff --git a/docs/project/chapter6/images/image18.png b/docs/stage-1/appendix-a-product-thinking/images/image18.png similarity index 100% rename from docs/project/chapter6/images/image18.png rename to docs/stage-1/appendix-a-product-thinking/images/image18.png diff --git a/docs/project/chapter6/images/image19.png b/docs/stage-1/appendix-a-product-thinking/images/image19.png similarity index 100% rename from docs/project/chapter6/images/image19.png rename to docs/stage-1/appendix-a-product-thinking/images/image19.png diff --git a/docs/project/chapter6/images/image2.png b/docs/stage-1/appendix-a-product-thinking/images/image2.png similarity index 100% rename from docs/project/chapter6/images/image2.png rename to docs/stage-1/appendix-a-product-thinking/images/image2.png diff --git a/docs/project/chapter6/images/image20.png b/docs/stage-1/appendix-a-product-thinking/images/image20.png similarity index 100% rename from docs/project/chapter6/images/image20.png rename to docs/stage-1/appendix-a-product-thinking/images/image20.png diff --git a/docs/project/chapter6/images/image21.png b/docs/stage-1/appendix-a-product-thinking/images/image21.png similarity index 100% rename from docs/project/chapter6/images/image21.png rename to docs/stage-1/appendix-a-product-thinking/images/image21.png diff --git a/docs/project/chapter6/images/image3.png b/docs/stage-1/appendix-a-product-thinking/images/image3.png similarity index 100% rename from docs/project/chapter6/images/image3.png rename to docs/stage-1/appendix-a-product-thinking/images/image3.png diff --git a/docs/project/chapter6/images/image4.png b/docs/stage-1/appendix-a-product-thinking/images/image4.png similarity index 100% rename from docs/project/chapter6/images/image4.png rename to docs/stage-1/appendix-a-product-thinking/images/image4.png diff --git a/docs/project/chapter6/images/image5.png b/docs/stage-1/appendix-a-product-thinking/images/image5.png similarity index 100% rename from docs/project/chapter6/images/image5.png rename to docs/stage-1/appendix-a-product-thinking/images/image5.png diff --git a/docs/project/chapter6/images/image6.png b/docs/stage-1/appendix-a-product-thinking/images/image6.png similarity index 100% rename from docs/project/chapter6/images/image6.png rename to docs/stage-1/appendix-a-product-thinking/images/image6.png diff --git a/docs/project/chapter6/images/image7.png b/docs/stage-1/appendix-a-product-thinking/images/image7.png similarity index 100% rename from docs/project/chapter6/images/image7.png rename to docs/stage-1/appendix-a-product-thinking/images/image7.png diff --git a/docs/project/chapter6/images/image8.png b/docs/stage-1/appendix-a-product-thinking/images/image8.png similarity index 100% rename from docs/project/chapter6/images/image8.png rename to docs/stage-1/appendix-a-product-thinking/images/image8.png diff --git a/docs/project/chapter6/images/image9.png b/docs/stage-1/appendix-a-product-thinking/images/image9.png similarity index 100% rename from docs/project/chapter6/images/image9.png rename to docs/stage-1/appendix-a-product-thinking/images/image9.png diff --git a/docs/project/chapter6/chapter6-no-code-without-an-idea.md b/docs/stage-1/appendix-a-product-thinking/index.md similarity index 79% rename from docs/project/chapter6/chapter6-no-code-without-an-idea.md rename to docs/stage-1/appendix-a-product-thinking/index.md index 0918522..424504b 100644 --- a/docs/project/chapter6/chapter6-no-code-without-an-idea.md +++ b/docs/stage-1/appendix-a-product-thinking/index.md @@ -1,4 +1,4 @@ -# Project 6: 别急着写代码,先想一个好点子 +# 附录 A:产品思维补充 - 别急着写代码,先想一个好点子 在前面的课程中,你已经学会了如何在 z.ai 和本地 AI IDE 中,利用大模型 API 搭建各种小工具:从最基础的对话框,到带有简单表单、状态切换、数据存储的应用;你也尝试过用 Trae 这样的 AI IDE 去处理环境配置、依赖安装等“工程向”的问题,让自己真正具备了把一个想法从浏览器搬到本地项目中的能力。 @@ -23,13 +23,14 @@ ## 你将学到以下内容 -总的来说,你将学会做一个应用的基本知识:点子从哪儿来 → 点子如何变应用 → 应用怎么从能用变好用 → 应用怎么用 AI → 完成后怎么找到用户。 +总的来说,你将学会做一个应用的基本知识:点子从哪儿来 → 点子如何变应用 → 应用怎么从能用变好用 → 应用怎么用 AI → 完成后怎么找到用户。 1. 我要做一个应用,从哪来的点子是靠谱的? 2. 有了点子,怎样拆成可以做出来的应用? 3. 做出来后,怎样判断和打磨成“好应用”? 4. 在哪一步、怎么合理地用 AI 放大价值? 5. 有了应用,怎样从 0 找到第一批真实用户? + # 1. 我要做一个应用,从哪来的点子是靠谱的 很多人一提到做应用,脑子里的第一反应就是:我要先想一个足够有记忆点的创意。于是每天刷榜单、看报道、研究各种热门产品,盯着别人的成功故事,希望哪天自己也能碰到一个特别不一样的点子。 @@ -84,9 +85,9 @@ 这背后最本质的差异,是点子本身有没有踩在某个关键的问题点上。 - **一个好的点子,自然而然能迎来增长** :即便以非常简陋的形态出现,甚至只有简陋的几个按钮,只要能解决用户手头一个具体的小麻烦,就能够获得一定程度的自然增长。比如一个能帮人快速把语音转成文字的小工具,一开始可能只是一个网页加几个简单的按钮,但只要识别质量够好,功能的转化特别自然,很多人就愿意把链接转给身边朋友,因为这简直就是在为他们节省时间。 +**一个好的点子,自然而然能迎来增长** :即便以非常简陋的形态出现,甚至只有简陋的几个按钮,只要能解决用户手头一个具体的小麻烦,就能够获得一定程度的自然增长。比如一个能帮人快速把语音转成文字的小工具,一开始可能只是一个网页加几个简单的按钮,但只要识别质量够好,功能的转化特别自然,很多人就愿意把链接转给身边朋友,因为这简直就是在为他们节省时间。 - **一个坏点子,往往从一开始就注定了要靠外力驱动** 。就算你的外观特别好,内核显示的特别高端,你需要不停地推、不停地吆喝、不停地解释,但一旦你的拉人行动放缓,使用数据就会直线下滑。你不断往里面砸资源、拉合作、搞活动,但永远感觉在逆水行舟。问题不在于你执行得不够好,而在于那个点本身并没有打中足够真实的痛点。 +**一个坏点子,往往从一开始就注定了要靠外力驱动** 。就算你的外观特别好,内核显示的特别高端,你需要不停地推、不停地吆喝、不停地解释,但一旦你的拉人行动放缓,使用数据就会直线下滑。你不断往里面砸资源、拉合作、搞活动,但永远感觉在逆水行舟。问题不在于你执行得不够好,而在于那个点本身并没有打中足够真实的痛点。 当然,以上情况并不绝对,例如在早期市场用户可能并未意识到价值具有一定滞后性,例如在有竞品的情况下我们还要考虑到外观、操作难易度、品牌特性等等,但这都是更深入的内容,目前暂不考虑。 @@ -104,7 +105,7 @@ ### 热爱你自己的生活 -一个非常朴素但有效的原则是: **你在生活里越有参与感,越容易发现问题,也越有能力判断什么是值得解决的问题** 。所谓参与感,就是你不是隔着屏幕看别人过日子,而是自己亲自去体验、尝试、踩坑。你越认真对待自己的兴趣爱好,它就越有可能成为点子生长的沃土。 +一个非常朴素但有效的原则是: **你在生活里越有参与感,越容易发现问题,也越有能力判断什么是值得解决的问题** 。所谓参与感,就是你不是隔着屏幕看别人过日子,而是自己亲自去体验、尝试、踩坑。你越认真对待自己的兴趣爱好,它就越有可能成为点子生长的沃土。 比如说,如果你特别喜欢养猫,你自己跟猫一起生活的一天,往往比刷一百条“养猫小技巧”更有信息量。你会知道猫最容易在哪些地方打翻东西,会记得每天什么时间它最爱蹦跶、在哪些情况下最容易应激,也会亲身经历清理猫砂、铲毛、剪指甲、看病这些细节。 **每一次略微不顺畅的体验,其实都是一次潜在的产品线索** 。 @@ -120,7 +121,7 @@ 也可以再往下挖一个更日常的小细节:很多人在 city walk 的时候,会有“当下觉得这个转角好美,但回家之后在地图上完全找不回那个点”的挫败感。那能不能做一个超轻量的功能:你走到一个觉得有感觉的路口,只要按住耳机上的按键,说一句“打个标记,这里是很适合约会散步的路”,应用就瞬间在你当前位置落一个带语音的标记点,自动记录时间、天气和噪音水平。以后你或者你的朋友,只要打开这个城市的地图,就能看到这些“路人实测的氛围点”:哪里适合一个人走神,哪里适合看夜景,哪里适合和朋友边走边聊天。那些原本会被你“走过就忘”的小路口,就这样慢慢长成了一个有质感的城市体验数据库。 -这些例子想说明的其实只有一件事: **你需要热爱你的生活,生活就是你最好的点子来源** 。每天遇到的困惑、临时想出的变通办法、那些你觉得有点麻烦但一直习惯忍着的地方,只要你愿意稍微多看一眼,多问一句有没有可能用一个小工具来改一改,它们就都有可能变成未来的产品雏形。 +这些例子想说明的其实只有一件事: **你需要热爱你的生活,生活就是你最好的点子来源** 。每天遇到的困惑、临时想出的变通办法、那些你觉得有点麻烦但一直习惯忍着的地方,只要你愿意稍微多看一眼,多问一句有没有可能用一个小工具来改一改,它们就都有可能变成未来的产品雏形。 ### 从你拥有的人群资产中挖掘 @@ -166,11 +167,11 @@ 相对好一点的表述会具体很多。比如:“每天利用十分钟通勤时间,一个月记住一百个核心单词的背词应用”。这里至少说明了三件事: 使用成本是可控的,每天只需要十分钟;预期结果是可见的,一个月有一百个新单词;场景是明确的,主要发生在通勤而不是其他碎片时间。用户听到这样的描述,能很快在脑中判断这东西对自己有没有用。 -练习写这一句话的过程,其实是在反复逼自己回答三个问题: **你到底在帮谁,你希望他们在什么样的场景下想起你,你打算在多长时间内帮他们达成一个怎样的结果。** 只有当你愿意把这些信息拼到一起,哪怕牺牲掉一些华丽词藻,你的点子才真正变得可以被理解和传播。 +练习写这一句话的过程,其实是在反复逼自己回答三个问题: **你到底在帮谁,你希望他们在什么样的场景下想起你,你打算在多长时间内帮他们达成一个怎样的结果。** 只有当你愿意把这些信息拼到一起,哪怕牺牲掉一些华丽词藻,你的点子才真正变得可以被理解和传播。 你也可以反过来把这个训练用在自己身上。试着给自己的未来三年写一句话描述。比如,我希望三年后,可以用一两句话说明自己主要在为哪一类人,解决哪一类问题,并且已经做出了哪些可见的成果。这样的训练会让你在做选择时更清楚,哪些事情是必须紧紧抓住的,哪些则可以适当放掉,学会舍弃比学会增加要难而正确。 -如果不知道从哪里学习这种表达,很简单,去看那些每天都在为争夺用户注意力而打磨文案的内容。你可以参考**应用市场里的一句话简介,游戏和工具类产品在官网首页摆出的主标题,各类 ****Landing Page** ** 上的核心文案** 。可以把它们抄下来,拆成结构,尝试基于 AI为自己的点子写一版新的文案。 +如果不知道从哪里学习这种表达,很简单,去看那些每天都在为争夺用户注意力而打磨文案的内容。你可以参考**应用市场里的一句话简介,游戏和工具类产品在官网首页摆出的主标题,各类 \*\***Landing Page\*\* ** 上的核心文案** 。可以把它们抄下来,拆成结构,尝试基于 AI为自己的点子写一版新的文案。 ## 1.6 用 AI 发散思维并找到差异化 @@ -180,7 +181,7 @@ 你会发现,很多你原本不会主动想到的使用场景,会在这一步骤中被甩给你。你的任务不是简单接受这些建议,而是在这些被扩展出来的空间里, **挑出你最有理解力和资源优势的那一小块** 。比如你发现,虽然 AI 列出了很多行业,但你对教育和内容创作类场景格外有感觉,那你就可以优先沿着这两个方向继续往下拆。 -在这个过程中,还有一个重要原则是: **常见点子并不一定等于无效点子** 。很多新人第一反应是要避开所有看起来常见的方向,觉得凡是别人做过的就没机会了。但真实世界远没那么简单。背单词、待办事项、记账、习惯打卡这些看似常见的方向,之所以不断有人做,是因为背后的问题确实普遍存在。这种情况下,比拼的往往不是有没有完全新的大创意,而是 **谁更理解某一小群人,谁能在细节上做得更贴近他们的生活** 。 +在这个过程中,还有一个重要原则是: **常见点子并不一定等于无效点子** 。很多新人第一反应是要避开所有看起来常见的方向,觉得凡是别人做过的就没机会了。但真实世界远没那么简单。背单词、待办事项、记账、习惯打卡这些看似常见的方向,之所以不断有人做,是因为背后的问题确实普遍存在。这种情况下,比拼的往往不是有没有完全新的大创意,而是 **谁更理解某一小群人,谁能在细节上做得更贴近他们的生活** 。 你可以先列出一批新手最容易想到的点子,如背单词工具、每日打卡应用、读书笔记助手、简历生成器、习惯养成工具等。然后对于每一个,专门和 AI 做一轮拆解,集中问三个问题: 如果我只服务于某个非常具体的人群,比如设计师、律师、新手妈妈、在校研究生,这个点子会长成什么不一样的样子。如果我只针对某个固定场景,比如通勤路上、午休十分钟、晚睡前的半小时,功能和呈现有没有可能做得更聚焦。 **如果我把结果呈现这件事做到极致,比如更易分享、更易打印、更易导入到其他系统,会不会就足以构成差异** 。 @@ -204,6 +205,7 @@ AI 在这里的价值,并不在于替你做决定,而是在于帮你把本 2. 让 AI 根据自己的想法,评价这个是真需求还是伪需求,并且给出用户需求洞察和建议 3. 从四大来源处选取一或两个来源得到“点子”,或者让 AI 生成几个应用的“点子” 4. 从上述所有 Idea 中,选取三个最喜欢的点子,尝试用一句富含信息量的话概括这个点子。 + # 2. 有了点子,怎样拆成可以做出来的应用 上一章我们解决的是一个起点问题: 到底什么样的点子才是值得认真对待的。 @@ -214,7 +216,7 @@ AI 在这里的价值,并不在于替你做决定,而是在于帮你把本 ![](images/image5.png) -别想了!要就是现在!这一章我们想做的事情,就是帮你学会一套从点子到可做版本的拆解方法。你会看到,从无到有并不依赖天才,而是依赖一系列可以反复练习的具体动作: ** 发散、** **收敛** **、拆解、细化、借鉴、提问。** 按照这个顺序,哪怕没有团队、没有大把时间,也可以把一个点子变成能跑通的应用demo。 +别想了!要就是现在!这一章我们想做的事情,就是帮你学会一套从点子到可做版本的拆解方法。你会看到,从无到有并不依赖天才,而是依赖一系列可以反复练习的具体动作: ** 发散、** **收敛** **、拆解、细化、借鉴、提问。** 按照这个顺序,哪怕没有团队、没有大把时间,也可以把一个点子变成能跑通的应用demo。 ## 2.1 从想法到解决方案: 双钻模型发散到收敛 @@ -232,11 +234,11 @@ AI 在这里的价值,并不在于替你做决定,而是在于帮你把本 ### 第一钻: 理解问题,从单点到全貌的发散和收敛 - **在双钻模型里,第一钻是关于问题本身** 。你先从一个模糊认知开始,逐渐发散出更多相关的情况和可能,再做一次收敛,找到真正值得解决的那个问题点。 +**在双钻模型里,第一钻是关于问题本身** 。你先从一个模糊认知开始,逐渐发散出更多相关的情况和可能,再做一次收敛,找到真正值得解决的那个问题点。 对应到你的应用,就是这样几件事。 - **发散阶段,你尽量多地去列举用户可能的使用场景,** 可能遇到的阻力,可能希望得到的结果。你不急着判断,只是把脑子里所有相关的东西都先摊出来。比如对于文档处理应用,你可以列出用户可能在通勤时用、在会议前用、在写报告前用、在做复盘时用;可以列出他们怕的是总结不准确、怕格式乱、怕错过重点;可以列出他们希望的是更快弄清楚一篇文章要表达什么,更快找到与自己相关的部分。 +**发散阶段,你尽量多地去列举用户可能的使用场景,** 可能遇到的阻力,可能希望得到的结果。你不急着判断,只是把脑子里所有相关的东西都先摊出来。比如对于文档处理应用,你可以列出用户可能在通勤时用、在会议前用、在写报告前用、在做复盘时用;可以列出他们怕的是总结不准确、怕格式乱、怕错过重点;可以列出他们希望的是更快弄清楚一篇文章要表达什么,更快找到与自己相关的部分。 **收敛** **阶段,你要逼自己只选出那一两种最常见、最痛的情况** 。比如你从一堆场景中发现,最多人提到的,是在接收到很长的工作文档时,希望先搞清楚这篇文档到底想说什么,它的主要结论是什么。那你就可以把第一版的应用目标定为: 帮助用户在五分钟内看懂一篇长文的核心意思,而不是同时解决所有文档处理相关的问题。 @@ -244,7 +246,7 @@ AI 在这里的价值,并不在于替你做决定,而是在于帮你把本 ### 第二钻: 设计解决方案,从粗糙想法到可执行方案 - **双钻的第二部分,是关于解决方案的诞生** 。你已经大致知道要解决哪一个问题,接下来要做的是为这个问题尽可能多地想办法,然后再从中筛选出最适合第一个版本的那一种。 +**双钻的第二部分,是关于解决方案的诞生** 。你已经大致知道要解决哪一个问题,接下来要做的是为这个问题尽可能多地想办法,然后再从中筛选出最适合第一个版本的那一种。 发散阶段在这里意味着不断追加想法。你可以脑暴各种功能、更细的场景、各种可能的玩法。比如针对长文总结,你可以设想不同的摘要粒度、不同的结果呈现形式、是否支持语音播报、是否允许用户标注重点、是否提供多种风格的总结版本等等。这一步不需要立刻做决策,只是尽可能把可能性列出来。 @@ -252,7 +254,7 @@ AI 在这里的价值,并不在于替你做决定,而是在于帮你把本 比如语音播报功能可能用户价值不错,但技术和前端整合起来的时间成本偏高;而简单的文本摘要和要点提取,用户价值同样明显,可行性也高,时间成本更低,那它就更适合作为第一版里必做的功能。 -在这个过程中,你要不断提醒自己一件事: **第一版的目标不是做出一个完美的应用,而是做出一个真实存在的、有人可以真正使用的版本** 。它不需要包罗万象,只需要在一个具体任务上表现得足够像样。 +在这个过程中,你要不断提醒自己一件事: **第一版的目标不是做出一个完美的应用,而是做出一个真实存在的、有人可以真正使用的版本** 。它不需要包罗万象,只需要在一个具体任务上表现得足够像样。 你可以给第二钻画一个简单的时间边界,比如一个月内要交出一个可用版本,那在发散的所有想法里,所有需要超过一个月甚至几个月才能落地的功能,都可以先暂时放到一个以后再看清单里。这样你不会因为想做的太多,而在一开始就被拖住。 @@ -260,7 +262,7 @@ AI 在这里的价值,并不在于替你做决定,而是在于帮你把本 ## 2.2 得到可执行步骤:学会从抽象到具体 -发散想法后,得到想法十分简单,但得到可执行步骤却非常难。说我要做一个提升效率的工具,我要做一个帮助创作者的应用,听起来都很宏大。真的要动手的时候,抽象几乎帮不上忙。你每天面对的是一个个非常具体的问题: **第一个版本到底要做哪一小块,需要哪些页面** ,要不要支持注册登录,要不要接入支付。 +发散想法后,得到想法十分简单,但得到可执行步骤却非常难。说我要做一个提升效率的工具,我要做一个帮助创作者的应用,听起来都很宏大。真的要动手的时候,抽象几乎帮不上忙。你每天面对的是一个个非常具体的问题: **第一个版本到底要做哪一小块,需要哪些页面** ,要不要支持注册登录,要不要接入支付。 这里需要的一种能力叫 **拆解并细化,能够把抽象变具体** 。就是把一个大而泛的目标,一点点拆解并细化内容到可以立刻动手的最小可行动项。这个能力不仅在做产品的时候重要,在生活里也非常关键。 @@ -288,11 +290,11 @@ AI 在这里的价值,并不在于替你做决定,而是在于帮你把本 #### 第一层拆解细化 - **首先,你需要先定义什么是“文档”** 。文档本身是一个很宽的概念,它既可以是表格、 Word 报告、PDF 文件,也可以是记录代码注释的 Markdown 文本、TXT 笔记,甚至是扫描生成的图片式文档、内嵌图表与公式的学术论文。不同类型的文档存在实现差异,但后续设计的 “处理” 功能,必须匹配文档的具体类型,故而不得不细化对文档的定义。如果是图片式文档,可能需要先加入 OCR 文字识别功能;如果是表格类文档,核心需求更可能是数据提取与分析,而非单纯的文字精简。 +**首先,你需要先定义什么是“文档”** 。文档本身是一个很宽的概念,它既可以是表格、 Word 报告、PDF 文件,也可以是记录代码注释的 Markdown 文本、TXT 笔记,甚至是扫描生成的图片式文档、内嵌图表与公式的学术论文。不同类型的文档存在实现差异,但后续设计的 “处理” 功能,必须匹配文档的具体类型,故而不得不细化对文档的定义。如果是图片式文档,可能需要先加入 OCR 文字识别功能;如果是表格类文档,核心需求更可能是数据提取与分析,而非单纯的文字精简。 - **其次,你还需要定义什么叫做“处理”。处理成什么,才算处理过?** 处理的方式又是什么?有的人所谓的处理,是把一份 50 页的报告精简成 5 页可读的概要;有的人所谓的处理,是把一堆杂乱格式的 Word、PDF、Markdown,统一变成一套规范模板;还有人关心的是翻译、改写、润色,让一篇勉强能看的草稿,变成可以对外发布的正式版本。这一步你可以直接问自己: 我说的“处理”,到底是要“看得更快”、“改得更好”,还是“传给别人更方便”。不同的答案,直接决定你后面要画的入口页和操作页会完全不一样。 +**其次,你还需要定义什么叫做“处理”。处理成什么,才算处理过?** 处理的方式又是什么?有的人所谓的处理,是把一份 50 页的报告精简成 5 页可读的概要;有的人所谓的处理,是把一堆杂乱格式的 Word、PDF、Markdown,统一变成一套规范模板;还有人关心的是翻译、改写、润色,让一篇勉强能看的草稿,变成可以对外发布的正式版本。这一步你可以直接问自己: 我说的“处理”,到底是要“看得更快”、“改得更好”,还是“传给别人更方便”。不同的答案,直接决定你后面要画的入口页和操作页会完全不一样。 - **对于“应用”同样也需要定义。什么叫做应用** ?是一个只给自己用的小工具,还是希望未来有一群用户来使用?是一个网页程序,还是一个手机 App,还是只是嵌在现有系统里的一个小功能?如果你只是想在电脑上自己用,做成一个简陋的网页或者命令行脚本,成本会低很多;如果你打算给团队同事一起用,可能就要考虑账号体系、权限、协作入口。这些听起来像是技术选型的问题,但在拆解阶段,你只需要回答一句很朴素的话: 我打算在什么设备、什么场景下,用到这个东西。 +**对于“应用”同样也需要定义。什么叫做应用** ?是一个只给自己用的小工具,还是希望未来有一群用户来使用?是一个网页程序,还是一个手机 App,还是只是嵌在现有系统里的一个小功能?如果你只是想在电脑上自己用,做成一个简陋的网页或者命令行脚本,成本会低很多;如果你打算给团队同事一起用,可能就要考虑账号体系、权限、协作入口。这些听起来像是技术选型的问题,但在拆解阶段,你只需要回答一句很朴素的话: 我打算在什么设备、什么场景下,用到这个东西。 接下来, **回到这句话本身: “提高文档处理效率”。** 你还需要拆清楚几个关键字。比如 **“用什么提高”** ?一定要用 AI 吗?还是不一定?有些效率提升完全可以用规则、模板、快捷键来解决,比如一键生成固定格式的报告封面、一键插入标准免责声明。这类需求可能根本不需要模型参与。相反,如果你面对的是大量非结构化的长文本,需要理解、概括、改写,那么 AI 可能就是非常自然的一环。 @@ -308,9 +310,9 @@ AI 在这里的价值,并不在于替你做决定,而是在于帮你把本 先来看其中的“AI”。这里的“AI”,究竟是指一个只负责文字识别的轻量级 OCR 模型,还是需要引入大语言模型,甚至多模态模型,来做后续的纠错、版面重整、内容重排和结构理解?不同的选择,会在三个维度带来完全不同的后果: -* 成本消耗:包括算力成本、调用费用、推理时延等,是一次性投入为主,还是持续开销为主。 -* 开发难度:是简单集成现有 OCR 接口即可,还是要设计复杂的 Prompt、上下文管理、甚至自训练与评估体系。 -* 产品形态与上线策略:是做成一个“快速提取文本的小工具”,还是一个能够还原大纲结构、表格、标题层级,适合深度阅读与内容再利用的“文档智能处理平台”。 +- 成本消耗:包括算力成本、调用费用、推理时延等,是一次性投入为主,还是持续开销为主。 +- 开发难度:是简单集成现有 OCR 接口即可,还是要设计复杂的 Prompt、上下文管理、甚至自训练与评估体系。 +- 产品形态与上线策略:是做成一个“快速提取文本的小工具”,还是一个能够还原大纲结构、表格、标题层级,适合深度阅读与内容再利用的“文档智能处理平台”。 然后是 **对“PDF 文档”的进一步拆解。你到底要支持哪一类 PDF?** 如果把范围限定在“以文字为主、可以复制的纯文字 PDF”,那就不必一开始就处理扫描件、复杂图表、公式排版,也不用为极端多栏、花哨排版的文档负责。反过来,如果你希望做到“任何 PDF 都能扔进来”,就意味着一上来就要同时解决图片式 PDF 的 OCR 识别、版面重建、图文混排、表格抽取等一整串高难度问题,项目复杂度会成倍提升。 @@ -322,27 +324,27 @@ AI 在这里的价值,并不在于替你做决定,而是在于帮你把本 2. **段落与标题结构是否保留** :原文的章节层级、段落分隔、列表结构、引用块等,在转成纯文本后能否被尽可能还原。 3. **是否便于二次编辑与再利用** :生成的文本是否足够干净、格式是否规整、用户后续复制到 Word、Notion 或代码编辑器中时,是否需要大规模手工清理。 - **你可以先选出自己最在意的两三项,作为“质量”的主攻方向** 。比如:优先保证“段落结构清晰”和“标题层级基本保留”,在错别字上只要求达到“用户几分钟内可以快速人工修完”的程度。这样,“高质量”就不再是一个空泛的形容词,而可以被转化为写得出来、量得出来的产品标准:偶尔有识别错误是被允许的,但不可以把文档切得支离破碎、段落混乱,更不能让用户在结构整理上比手动复制还费劲。 +**你可以先选出自己最在意的两三项,作为“质量”的主攻方向** 。比如:优先保证“段落结构清晰”和“标题层级基本保留”,在错别字上只要求达到“用户几分钟内可以快速人工修完”的程度。这样,“高质量”就不再是一个空泛的形容词,而可以被转化为写得出来、量得出来的产品标准:偶尔有识别错误是被允许的,但不可以把文档切得支离破碎、段落混乱,更不能让用户在结构整理上比手动复制还费劲。 再看“速度”。既然你在目标里写了“提高……速度和质量”,那“快”就应该被具体到 **某个可以感知的量级,** 而不是停留在“感觉上比较快”。这里其实隐藏着一个重要取舍: -* 是希望支持超长文档(几十页、上百页),哪怕用户需要等待较长时间? -* 还是只针对中短篇文档,在页数受限的前提下,做到“几秒到十几秒内拿到结果”的体验? +- 是希望支持超长文档(几十页、上百页),哪怕用户需要等待较长时间? +- 还是只针对中短篇文档,在页数受限的前提下,做到“几秒到十几秒内拿到结果”的体验? 如果你典型的使用场景是:会前把一份十几页的报告、方案或研究摘要,快速转成可编辑文本以便标注、修改和摘录,那么更自然的选择是: -* 对单份文档设定一个合理的页数上限,例如“不超过 20 页的文字型 PDF”; -* 同时给出一个大致的处理时间指标,例如“通常在约 10 秒内完成处理”。 +- 对单份文档设定一个合理的页数上限,例如“不超过 20 页的文字型 PDF”; +- 同时给出一个大致的处理时间指标,例如“通常在约 10 秒内完成处理”。 这两项一旦被明确写出来,后面的技术方案(是否需要并行处理、要不要做异步队列)、界面文案(页面上展示的预计时间、超时提示)以及用户预期管理,就都可以围绕“中短文档 + 快速返回”这个核心体验来优化。 - **最后是“网页程序”本身。这一项看似只是载体选择,实际上同样需要适度收口,** 避免过早卷入过重的产品形态。你可以先问自己一个关键问题: +**最后是“网页程序”本身。这一项看似只是载体选择,实际上同样需要适度收口,** 避免过早卷入过重的产品形态。你可以先问自己一个关键问题: -* 这更像是“我自己和小范围内部使用的临时工具”? -* 还是一开始就规划成“给一批真实用户长期使用的在线服务”? +- 这更像是“我自己和小范围内部使用的临时工具”? +- 还是一开始就规划成“给一批真实用户长期使用的在线服务”? 如果更偏向前者,你就可以大胆砍掉很多复杂度:不用搭建完整的账号体系和权限管理,不必在第一版就实现任务历史、项目管理、团队协作等功能,而是专注在一个极简流程上: - **打开网页 → 上传 PDF → 等待处理 → 展示可编辑文本 → 一键复制或下载** 。 +**打开网页 → 上传 PDF → 等待处理 → 展示可编辑文本 → 一键复制或下载** 。 反之,如果目标是正式对外提供稳定服务,就需要在后续版本中逐步考虑并发能力、队列调度、用户配额、异常恢复、日志与监控、安全与权限管理等。但在当前这一拆解阶段,你完全可以先把它定义为“基于浏览器的小工具,无需登录即可使用”,把所有交互集中在最简单、最核心的那条路径上。 你需要把“AI”“PDF 文档”“高质量转成文字”“速度要求”“网页程序”这些 **关键词背后的取舍,用更具体文字的明确表达** ,最初那句“我想做一个 AI 提高 PDF 文档转成文字速度和质量的网页程序”就可以被进一步收紧为一条更清晰、更可执行的描述。例如: @@ -366,7 +368,7 @@ AI 在这里的价值,并不在于替你做决定,而是在于帮你把本 ## 2.3 在白板上构思你的应用: 先画出第一个应用 -很多人一想到要开始做应用,脑子里第一个跳出来的是代码、后端、数据库、接口、框架。这并不奇怪,因为我们长期被灌输的观念是: 做一个应用,首要是技术问题。但如果你一开始就把注意力全部压到技术上,很容易忽略最关键的东西: **用户到底在你这里究竟要做什么** 。 +很多人一想到要开始做应用,脑子里第一个跳出来的是代码、后端、数据库、接口、框架。这并不奇怪,因为我们长期被灌输的观念是: 做一个应用,首要是技术问题。但如果你一开始就把注意力全部压到技术上,很容易忽略最关键的东西: **用户到底在你这里究竟要做什么** 。 在这一点上,一个最简单、却经常被忽略的做法,就是先画。你不需要什么专业的软件,一个白板,一张空白纸,一个记事本都可以。重要的是,你先把用户从进来到离开的整条路径,用几张简单的页面草图画出来,而不是直接跑去打开编辑器写代码。 @@ -388,7 +390,7 @@ AI 在这里的价值,并不在于替你做决定,而是在于帮你把本 一旦用户决定继续往前走,下一步就会落到操作页,也就是整个应用的工作区域。这里是用户真正和你发生互动的地方,也是最多人设计过度复杂的地方。 -画操作页时,一个很有效的练习是: **只允许用户做一件事** 。你可以在纸上写下这件事的最简单表达,比如 提交一段文字 用语音记录一条想法 选择一个模板 配置一个参数。然后围绕这件事,尽量往少里做,看看最少只需要哪些输入,哪些按钮。 +画操作页时,一个很有效的练习是: **只允许用户做一件事** 。你可以在纸上写下这件事的最简单表达,比如 提交一段文字 用语音记录一条想法 选择一个模板 配置一个参数。然后围绕这件事,尽量往少里做,看看最少只需要哪些输入,哪些按钮。 以一个长文自动总结的应用为例,最粗糙但能跑通流程的操作页,可能只需要几样东西: 一个可以粘贴文字的输入框,一个选择总结长度的选项,一个生成摘要的按钮。你完全可以先不考虑字体大小、配色、图标这些视觉上的细腻部分,把重点放在这样几个问题上: **用户是否一进到这一页就知道要做什么,他需要准备哪些东西,他会不会在中途搞不清楚下一步。** @@ -398,7 +400,7 @@ AI 在这里的价值,并不在于替你做决定,而是在于帮你把本 很多应用在结果这一步做得很敷衍。开发者往往觉得结果不就是一段文字、一张图、一串数据嘛,展示出来就好了。可对用户来说,往往恰恰相反: 他之所以愿意在前面的步骤里输入、等待、尝试,根本原因是他期待在结果页上看到一个够清楚、够有用的东西。 -画结果页时,可以从这样几个角度去想: **用户最关心的核心信息是什么,它应该摆在最显眼的位置** 。有哪些结果是需要导出、保存或者分享的,它们的入口在哪里。有没有必要为结果加上一些简单的解释,让用户知道这代表什么。 +画结果页时,可以从这样几个角度去想: **用户最关心的核心信息是什么,它应该摆在最显眼的位置** 。有哪些结果是需要导出、保存或者分享的,它们的入口在哪里。有没有必要为结果加上一些简单的解释,让用户知道这代表什么。 还是以长文总结为例,一种比较友好的结果页设计是: 顶部用几条简洁的要点列出核心结论,其下面放一个更详细的摘要,最底部保留原文链接。旁边放上两个醒目的按钮: 一个是复制要点,一个是导出为文档。你可以在纸上试着画出这些区域的布局,并标注一下每个按钮预计承载的动作。 @@ -416,10 +418,10 @@ AI 在这里的价值,并不在于替你做决定,而是在于帮你把本 重点观察的不是配色有多漂亮,而是它们在若干关键区域是怎么处理的: -* 导航栏怎么设计,底部还是顶部,是固定几个核心入口还是只有一个主按钮 -* 表单怎么组织,是一次性在同一页填完,还是拆成多个小步骤 -* 结果展示时,最重要的信息有没有被放在最明显的位置,次要信息又是怎样被收纳的 -* 新用户第一次进来时,有没有简短的引导流程,告诉他接下来怎么用 +- 导航栏怎么设计,底部还是顶部,是固定几个核心入口还是只有一个主按钮 +- 表单怎么组织,是一次性在同一页填完,还是拆成多个小步骤 +- 结果展示时,最重要的信息有没有被放在最明显的位置,次要信息又是怎样被收纳的 +- 新用户第一次进来时,有没有简短的引导流程,告诉他接下来怎么用 ![](images/image12.png) @@ -427,14 +429,14 @@ AI 在这里的价值,并不在于替你做决定,而是在于帮你把本 具体可以参考如下几个网页截图收集站: -* [https://www.uisources.com/](https://www.uisources.com/) -* [https://screenlane.com/](https://screenlane.com/) -* [https://pagecollective.com/](https://pagecollective.com/) -* [https://patttterns.net/](https://patttterns.net/) -* [https://mobbin.com/](https://mobbin.com/) -* [https://refero.design/](https://refero.design/) -* [https://scrnshts.club/](https://scrnshts.club/) -* [https://godly.website](https://godly.website/) +- [https://www.uisources.com/](https://www.uisources.com/) +- [https://screenlane.com/](https://screenlane.com/) +- [https://pagecollective.com/](https://pagecollective.com/) +- [https://patttterns.net/](https://patttterns.net/) +- [https://mobbin.com/](https://mobbin.com/) +- [https://refero.design/](https://refero.design/) +- [https://scrnshts.club/](https://scrnshts.club/) +- [https://godly.website](https://godly.website/) 除了直接参考别人的应用,我们还能从一些比赛中得到灵感,比如 Hackathon( 限时、高强度的团队协作开发活动,需短时间内完成产品原型或解决方案)的得奖作品和一些公开的 demo 网站。其本质上是一批实践者在极短时间内交出的解决方案,它们虽然粗糙,但恰好呈现了如何在有限时间内完成从点子到可运行产品的压缩流程,你可以参考他们的作品思考什么叫做最小产品原型;但由于黑客松始终是短时间的比赛,有可能创意大于实用性,其获奖作品并不一定适合作为一个长期的产品进行参考和开发,你需要根据实际情况进行判断。 @@ -462,7 +464,7 @@ AI 在这里的价值,并不在于替你做决定,而是在于帮你把本 你可以先从身边人开始,还可以从你在上一章提到的人群资产、公开场域里接触到的用户中,挑一些比较愿意尝试新工具的人。给他们发一个链接,简单说明现在能做的事情,然后请他们在你不做太多解释的情况下,从入口走到结果。 - **在这个过程中,你要做的不是辩解,而是观察。** 他们会在什么地方犹豫,会在哪个环节停顿,哪一个按钮看了很久都不敢点。你也可以事后问几个具体问题: 有哪一步是你觉得最费劲的,有哪一个结果你是最满意的,有什么是你以为会有但最终没看到的。 +**在这个过程中,你要做的不是辩解,而是观察。** 他们会在什么地方犹豫,会在哪个环节停顿,哪一个按钮看了很久都不敢点。你也可以事后问几个具体问题: 有哪一步是你觉得最费劲的,有哪一个结果你是最满意的,有什么是你以为会有但最终没看到的。 在半成品阶段做这些事,有一个巨大好处: 你还没有对任何一个方案投入过多的情感依赖,你会更容易接受把某些看起来很酷但用户根本不在意的功能砍掉,也更愿意花时间去优化那些虽然不起眼却真正在使用中频繁出现的小细节。 @@ -485,6 +487,7 @@ AI 在这里的价值,并不在于替你做决定,而是在于帮你把本 1. 请你使用任意一款大语言模型,针对之前的点子,让 AI 参考双钻模型给出发散结果,你需要根据发散结果选出一套可行解决方案。 2. 根据之前想出来的点子,使用拆解细化的方法得到更具体的可执行内容。类似:“为用户提供一个网页工具,让他上传一份不超过 20 页的纯文字 PDF,在 10 秒内得到一份段落结构清晰、标题层级保留的可编辑文本,并支持一键复制和下载为 .txt。” 3. 根据细化后的点子,尝试在白板上画出你的应用,应用需要关注两个部分,一个是 UI 应该如何设计,一个是该有什么功能,每个功能是在哪。 + # 3. 做出来后,怎样判断和打磨成好应用 当你终于把第一个版本做出来,放到真实世界里给人用时,会进入一个完全不一样的阶段。之前所有的讨论,都还停留在想法和设计层面,而现在,产品会第一次被真实的使用场景检验。你会看到用户点错的地方、犹豫的地方、卡住不动的地方,也会看到他们在哪些步骤出奇地顺畅,甚至会在某个角落意外多停留几秒。这些细节,远比你脑子里对产品的各种想象要诚实得多。 @@ -517,7 +520,7 @@ AI 在这里的价值,并不在于替你做决定,而是在于帮你把本 所以,当你自己觉得产品逻辑很顺畅时,最好找一个完全没见过你应用的人,让他在你不说话的情况下,从零开始摸索。你只观察他会在哪些地方停顿,在什么位置犹豫,什么时候会露出那种这是什么的表情。用户如果一进来就被各种开屏弹窗、复杂选项、账号绑定挡住,很难认真体验到你真正想提供的价值。 - **好上手这件事,本质上是产品对用户成本的一种尊重。** 你是在承认一件事: 没有人有义务花时间研究你的应用。 +**好上手这件事,本质上是产品对用户成本的一种尊重。** 你是在承认一件事: 没有人有义务花时间研究你的应用。 ### 在高频或关键场景中,会自然想到你 @@ -527,19 +530,19 @@ AI 在这里的价值,并不在于替你做决定,而是在于帮你把本 一个常见的误解,是把使用频次和应用的好坏直接绑定在一起。其实不必。比如做年终报表、办理某种证件、做一次大额转账,这些事情本身频率不高,但一旦发生,对用户来说就是当下最重要的事情之一。**如果你的应用刚好能把这类关键场景处理得稳、快、让人心里有底,那它一样可以称得上好应用。** - **真正需要警惕的,是那种用户既不高频用你,也不会在任何关键时刻主动想到你** ,甚至如果你的应用从他手机里消失,他只会在几个月后清理内存时才模糊想起曾经装过这么一个东西。这种情况往往说明你的应用并没有和任何真实的场景深度绑定,只是在功能层面堆了一些存在感不强的东西。 +**真正需要警惕的,是那种用户既不高频用你,也不会在任何关键时刻主动想到你** ,甚至如果你的应用从他手机里消失,他只会在几个月后清理内存时才模糊想起曾经装过这么一个东西。这种情况往往说明你的应用并没有和任何真实的场景深度绑定,只是在功能层面堆了一些存在感不强的东西。 ### 利他心 很多人一开始做产品时,心里同时盘算的是几件事: 做出来后怎么收费,怎么涨价,怎么让用户多用一点就得付费,怎么锁死数据防止用户迁移走。商业上的计算本身没问题,但如果一开始思路就完全绕着这些转,很容易做出那种一眼就充满戒心的应用: 一上来就要各种权限,到处是花样收费点,功能设计明显不是为了让用户顺畅完成任务,而是想办法把用户引导到某个付费的按钮上。 -相比之下,真正好的应用都带有一种比较朴素的利他心。它确实会想清楚要怎么活下去,也会设置合理的收费方式,但在设计路径和体验的时候,优先级始终摆在: **怎么让用户更容易顺利完成这件事,而不是怎么多加一步流程来制造额外障碍。** 你会看到它在很多地方都用了对用户更友好的方式,比如在关键步骤给出清晰的提示,在导出和迁移上不过度设置壁垒,在收费前让你至少体验到一部分实在的价值。 +相比之下,真正好的应用都带有一种比较朴素的利他心。它确实会想清楚要怎么活下去,也会设置合理的收费方式,但在设计路径和体验的时候,优先级始终摆在: **怎么让用户更容易顺利完成这件事,而不是怎么多加一步流程来制造额外障碍。** 你会看到它在很多地方都用了对用户更友好的方式,比如在关键步骤给出清晰的提示,在导出和迁移上不过度设置壁垒,在收费前让你至少体验到一部分实在的价值。 这种利他心,经常体现在一些微小的设计细节上。比如表单那一栏不会为了多收信息而乱要一堆和任务无关的数据,教程的顺序是围绕用户要完成的目标设计的,而不是围绕功能模块自己来讲。你能感受到这个应用是在认真帮你做成一件事,而不是把你当成一个被压榨的对象。 -还有一点很重要: **好应用不一定是大应用。它可以很小,只服务于一类人、一个场景、一个任务** ,但在那一小块里做得很到位。比如专门帮设计师把稿件导出成打印店要求的格式,或者专门帮自由职业者整理个人项目案例,这些范围都不大,但里面的价值一点不小。 +还有一点很重要: **好应用不一定是大应用。它可以很小,只服务于一类人、一个场景、一个任务** ,但在那一小块里做得很到位。比如专门帮设计师把稿件导出成打印店要求的格式,或者专门帮自由职业者整理个人项目案例,这些范围都不大,但里面的价值一点不小。 -## 3.2 洞察需求:**马斯洛的需求层次理论** +## 3.2 洞察需求:**马斯洛的需求层次理论** ![](images/image16.png) @@ -599,15 +602,15 @@ AI 在这里的价值,并不在于替你做决定,而是在于帮你把本 把马斯洛金字塔当成产品视角的一个好处,是它能帮你避免两个常见的偏差。 - **第一个偏差,是只盯着某一个错误的层次不放。** 比如你做的是帮助用户安全存储文件的工具,本质上站在安全这一层,但你却一味模仿社交产品,在界面上堆各种点赞、评论、排行榜,结果既抢不到社交类产品的用户心智,又让本来只想要一个稳妥存储工具的人觉得你不务正业。 +**第一个偏差,是只盯着某一个错误的层次不放。** 比如你做的是帮助用户安全存储文件的工具,本质上站在安全这一层,但你却一味模仿社交产品,在界面上堆各种点赞、评论、排行榜,结果既抢不到社交类产品的用户心智,又让本来只想要一个稳妥存储工具的人觉得你不务正业。 - **第二个偏差,是忽略了层级之间的先后关系。** 一个人连最基础的稳定使用体验都得不到保障时,很难认真在你这里追求自我实现。比如应用经常崩溃、数据时不时丢,哪怕你给了再多勋章、再多成长曲线,用户也不会真心投入。反过来,如果你在基础层面做得扎实,再逐步叠加更高层次的价值,用户会更容易跟着你一起走上去。 +**第二个偏差,是忽略了层级之间的先后关系。** 一个人连最基础的稳定使用体验都得不到保障时,很难认真在你这里追求自我实现。比如应用经常崩溃、数据时不时丢,哪怕你给了再多勋章、再多成长曲线,用户也不会真心投入。反过来,如果你在基础层面做得扎实,再逐步叠加更高层次的价值,用户会更容易跟着你一起走上去。 在实际设计中,你可以这样自查: -* 先问自己:我的应用最主要、最核心的是在满足哪一层需求,只允许选一层 -* 再问:在这个核心层之上,我有没有机会自然地延伸到上一层,而不是硬贴一个概念上去 -* 最后,看一眼:在比我目标层更低的那些层里,我有没有明显短板,甚至在拖用户后腿 +- 先问自己:我的应用最主要、最核心的是在满足哪一层需求,只允许选一层 +- 再问:在这个核心层之上,我有没有机会自然地延伸到上一层,而不是硬贴一个概念上去 +- 最后,看一眼:在比我目标层更低的那些层里,我有没有明显短板,甚至在拖用户后腿 当你能回答清楚这几个问题时,你对用户真正要什么这件事,就不再只是停留在感觉他们可能会喜欢的模糊层面,这有助于你做出更好的应用。 @@ -615,9 +618,9 @@ AI 在这里的价值,并不在于替你做决定,而是在于帮你把本 应用做出来之后,你很快会发现另一件重要的事: 面对普通个人用户和面对企业或机构用户,是两种完全不同的游戏规则。它们看起来都叫用户,但关心的重点完全不同。 -* C 端(Consumer End):指 “消费者端”,核心是普通个人用户。 +- C 端(Consumer End):指 “消费者端”,核心是普通个人用户。 比如我们日常用的微信、抖音、美团外卖,这些 App 的使用者是一个个独立的个人,这类面向个人提供服务的场景,就是 C 端业务。 -* B 端(Business End):指 “企业端”,核心是企业、机构或组织用户。 +- B 端(Business End):指 “企业端”,核心是企业、机构或组织用户。 比如公司里用的钉钉(企业协作工具)、财务软件(如用友、金蝶)、零售门店的收银系统,这些产品的使用者是企业员工、团队或整个机构,服务于企业的经营、管理、生产等需求,这类面向组织提供服务的场景,就是 B 端业务。 ### C 端应用: 面向普通人的生活、情绪和习惯 @@ -636,13 +639,13 @@ C 端应用面向的是个人用户,它们嵌在每个人的日常生活里。 这些应用虽然种类不同,但有几个共同的关注点。 - **第一,用户增长。** 也就是如何让更多人第一次尝试你的应用。这里涉及到渠道、传播文案、用户激励,但前提始终是: 你要先有一个足够清晰的使用场景。否则,再厉害的增长手段也只能带来一波短期的好奇心。 +**第一,用户增长。** 也就是如何让更多人第一次尝试你的应用。这里涉及到渠道、传播文案、用户激励,但前提始终是: 你要先有一个足够清晰的使用场景。否则,再厉害的增长手段也只能带来一波短期的好奇心。 - **第二,留存和复访。** 不是有人来过,而是他愿不愿意留下来、回来。一个内容类应用,如果不能保证持续产出用户感兴趣的内容,很快就会被替代;工具类应用如果在关键几次使用里没有帮助用户真正完成任务,也很难建立长期使用习惯。你可以通过观察第 1 天、第 7 天、第 30 天的留存情况,判断到底有多少人真正把你纳入了生活节奏。 +**第二,留存和复访。** 不是有人来过,而是他愿不愿意留下来、回来。一个内容类应用,如果不能保证持续产出用户感兴趣的内容,很快就会被替代;工具类应用如果在关键几次使用里没有帮助用户真正完成任务,也很难建立长期使用习惯。你可以通过观察第 1 天、第 7 天、第 30 天的留存情况,判断到底有多少人真正把你纳入了生活节奏。 - **第三,转化和付费。** 用户为什么愿意付费,通常不是因为你把免费版做得很糟糕,而是因为在他已经从你这里获得一部分价值之后,看到付费功能能带来更高层次的便利。比如更高的使用额度、更强的协作能力、更专业的模板、更稳定的性能。 +**第三,转化和付费。** 用户为什么愿意付费,通常不是因为你把免费版做得很糟糕,而是因为在他已经从你这里获得一部分价值之后,看到付费功能能带来更高层次的便利。比如更高的使用额度、更强的协作能力、更专业的模板、更稳定的性能。 - **第四,分享传播性。** 很多 C 端产品之所以能快速扩散,是因为在使用过程中天然带有分享属性。比如生成一张图、一个视频、一段文本,用户为了完成自己的目标,本身就需要把结果发给别人。在这个过程中,只要你把品牌露出做得自然、不讨厌,就能获得一部分口碑式的传播。 +**第四,分享传播性。** 很多 C 端产品之所以能快速扩散,是因为在使用过程中天然带有分享属性。比如生成一张图、一个视频、一段文本,用户为了完成自己的目标,本身就需要把结果发给别人。在这个过程中,只要你把品牌露出做得自然、不讨厌,就能获得一部分口碑式的传播。 判断 C 端真需求的一个简单方式,是看用户愿不愿意围绕它形成自己的小习惯。比如愿意每天打开看一眼、愿意把它和自己的生活节奏绑定在一起、愿意让它参与到某些重要时刻的记录中。反之,如果用户只是因为一次活动或广告进来,用完就走,而且几乎不会再回来,那基本可以判断,你解决的可能只是他们一时的好奇心,而不是长期需求。 @@ -656,15 +659,15 @@ B 端应用面向的是企业、团队、机构或某个部门。常见类型包 B 端应用有几项特别核心的关注点。 - **第一,提高效率。** 这不仅指某一个人的时间缩短了,而是整体流程耗时减少,协作成本降低,沟通环节减少。比如一个订单从创建到发货原来要经过五个系统,现在通过一个统一入口就能整体流转,这类提升对企业来说就是非常具体的。 +**第一,提高效率。** 这不仅指某一个人的时间缩短了,而是整体流程耗时减少,协作成本降低,沟通环节减少。比如一个订单从创建到发货原来要经过五个系统,现在通过一个统一入口就能整体流转,这类提升对企业来说就是非常具体的。 - **第二,** **降低成本** **。** 包括人力成本、培训成本、系统维护成本等等。如果一个系统看起来功能很强大,但需要投入大量培训和维护资源才能勉强跑起来,那它对很多中小企业来说就会显得性价比不高。反而是那些做得看似更轻,但能快速上手、快速看到回报的 SaaS 工具,更容易在现实世界活下来。 +**第二,** **降低成本** **。** 包括人力成本、培训成本、系统维护成本等等。如果一个系统看起来功能很强大,但需要投入大量培训和维护资源才能勉强跑起来,那它对很多中小企业来说就会显得性价比不高。反而是那些做得看似更轻,但能快速上手、快速看到回报的 SaaS 工具,更容易在现实世界活下来。 - **第三,控制风险和保证合规。** 很多 B 端场景里,对合规性和可追溯性有很高要求,比如金融、医疗、制造、政务等行业。一个好的 B 端应用,往往会牺牲一点使用上的自由度,换来更明确的权限管理、更严谨的日志记录、更清晰的审批链路。对用户个人来说,可能少了一些随意发挥的空间,但对组织整体来说,反而是价值所在。 +**第三,控制风险和保证合规。** 很多 B 端场景里,对合规性和可追溯性有很高要求,比如金融、医疗、制造、政务等行业。一个好的 B 端应用,往往会牺牲一点使用上的自由度,换来更明确的权限管理、更严谨的日志记录、更清晰的审批链路。对用户个人来说,可能少了一些随意发挥的空间,但对组织整体来说,反而是价值所在。 - **第四,权限管理和责任边界。** 谁能看见什么、谁能改什么、谁对什么结果负责,这些问题往往是 B 端系统设计中的重点。一旦这里做不好,就会给后续的审计、纠纷、追责带来巨大麻烦。所以,判断一个 B 端应用是不是好应用,不能只看界面看起来顺不顺眼,还要看它的权限模型是否严谨、是否容易理解和维护。 +**第四,权限管理和责任边界。** 谁能看见什么、谁能改什么、谁对什么结果负责,这些问题往往是 B 端系统设计中的重点。一旦这里做不好,就会给后续的审计、纠纷、追责带来巨大麻烦。所以,判断一个 B 端应用是不是好应用,不能只看界面看起来顺不顺眼,还要看它的权限模型是否严谨、是否容易理解和维护。 -从行业到应用,你可以这样思考: **选一个你有一定了解的行业,比如教培、电商、制造、金融、医疗** ,然后拆开看这个行业的日常运转中,有哪些流程特别倚赖人工,有哪些信息经常散落在多个系统或多个私聊里,有哪些环节出错率特别高但又不容易被立刻发现。围绕这些地方,你往往可以设计出一些很聚焦的小工具。 +从行业到应用,你可以这样思考: **选一个你有一定了解的行业,比如教培、电商、制造、金融、医疗** ,然后拆开看这个行业的日常运转中,有哪些流程特别倚赖人工,有哪些信息经常散落在多个系统或多个私聊里,有哪些环节出错率特别高但又不容易被立刻发现。围绕这些地方,你往往可以设计出一些很聚焦的小工具。 比如在教培行业,一个很具体的应用切口是做课程排班和教室利用率优化工具。它不需要取代整个教务系统,只要专注于让教务老师更容易安排老师、教室和课程时间,自动避免冲突,给出最佳组合,导出一份所有人都能看懂的课表,这一项就足以节省大量反复沟通和修改的时间。 @@ -684,7 +687,7 @@ B 端应用有几项特别核心的关注点。 不需要一上来就搞复杂的客服系统和数据平台,你可以从一些非常简单的方式开始。 - **群聊是最直接的一种。** 如果你手里已经有一个小范围的用户群,可以邀请大家把平时使用过程中的问题和想法发在群里。你要做的是认真回复、记录并且定期总结,而不是在群里辩解或防御。你越能在这个小群体里建立一种可以坦诚说话的氛围,后面收集到的反馈就越有价值。 +**群聊是最直接的一种。** 如果你手里已经有一个小范围的用户群,可以邀请大家把平时使用过程中的问题和想法发在群里。你要做的是认真回复、记录并且定期总结,而不是在群里辩解或防御。你越能在这个小群体里建立一种可以坦诚说话的氛围,后面收集到的反馈就越有价值。 问卷适合在你需要 **一次性收集较多结构化信息的时候使用** ,比如在一个版本迭代之后,想知道大家对某几个具体功能的感受。如果你希望填写率高,问卷最好不要太长,问题要尽量具体,比如这一段时间你最常用的是哪个功能,在哪一步卡壳最多,而不是泛泛问你对这个应用总体感觉如何。 @@ -696,11 +699,11 @@ B 端应用有几项特别核心的关注点。 用户反馈通常是混杂在一起的,很难一眼看清楚。你可以尝试把它们分成三类:** bug、体验问题、新需求。** - **bug 指的是原本你说会发生某种行为,但在某些情况下完全没有发生,或者发生了错误的行为** 。比如上传失败、闪退、按钮没有响应、结果明显不对。对于这类问题,你要做的是尽快复现、修复,并且在修复后主动告知受影响的那批用户,让他们知道你是认真对待这些问题的。 +**bug 指的是原本你说会发生某种行为,但在某些情况下完全没有发生,或者发生了错误的行为** 。比如上传失败、闪退、按钮没有响应、结果明显不对。对于这类问题,你要做的是尽快复现、修复,并且在修复后主动告知受影响的那批用户,让他们知道你是认真对待这些问题的。 - **体验问题是在流程长度、操作位置、文案表达上没有选到最顺滑的路径。** 比如用户总是在某个按钮上犹豫,不知道点了会不会造成不可逆的结果;某个功能很重要,却被放在一个不显眼的角落;某些默认设置和大多数人的习惯相反,导致他们每次都要多做一步调整。这类反馈需要你结合数据和观察去判断,决定是否做改变,以及改到什么程度比较合适。 +**体验问题是在流程长度、操作位置、文案表达上没有选到最顺滑的路径。** 比如用户总是在某个按钮上犹豫,不知道点了会不会造成不可逆的结果;某个功能很重要,却被放在一个不显眼的角落;某些默认设置和大多数人的习惯相反,导致他们每次都要多做一步调整。这类反馈需要你结合数据和观察去判断,决定是否做改变,以及改到什么程度比较合适。 - **新需求是指用户开始提出一些原本你没想到的功能和场景。** 有些新需求确实值得认真考虑,比如多种导出格式、团队协作能力、和其他常用工具的对接。但也要注意,不是用户提什么你都要照做。真正要做的是辨别,这些新需求背后有没有共性问题,是不是和你原本想服务的那群人、那个核心任务一致。否则,你很容易被一堆分散的需求拉扯到各个方向,最后变成一个什么都想做、却什么都做不精的产品。 +**新需求是指用户开始提出一些原本你没想到的功能和场景。** 有些新需求确实值得认真考虑,比如多种导出格式、团队协作能力、和其他常用工具的对接。但也要注意,不是用户提什么你都要照做。真正要做的是辨别,这些新需求背后有没有共性问题,是不是和你原本想服务的那群人、那个核心任务一致。否则,你很容易被一堆分散的需求拉扯到各个方向,最后变成一个什么都想做、却什么都做不精的产品。 你可以养成一个习惯: 为每一条反馈打上标签,标明它属于 bug、体验问题还是新需求。定期把这些标签汇总,看看哪一类问题集中在哪几个功能或流程上。这样一来,你就不再只是被动地修补,而是能有意识地围绕高频问题展开迭代。 @@ -708,11 +711,11 @@ B 端应用有几项特别核心的关注点。 在资源有限的情况下,你还需要一些简单但有效的指标,来判断这个应用值不值得你继续长期投入。 - **第一个是留存。** 留存不是看某一天有多少人打开,而是看在 **一段时间里,有多少用户还在持续使用** 。你可以很粗糙地统计,比如下载后一个星期内还有多少人至少用过一次,一个月内又有多少人回来过。如果大部分用户只用了一两次就再也不回来,说明你的应用在前期并没有让他们看到足够的价值,或者使用门槛太高。 +**第一个是留存。** 留存不是看某一天有多少人打开,而是看在 **一段时间里,有多少用户还在持续使用** 。你可以很粗糙地统计,比如下载后一个星期内还有多少人至少用过一次,一个月内又有多少人回来过。如果大部分用户只用了一两次就再也不回来,说明你的应用在前期并没有让他们看到足够的价值,或者使用门槛太高。 - **第二个是复访频率。** 那些没有卸载你的应用的人,到底多久会回来一次。一款每天都可以用得上的工具和一款每季度才会被想起一次的应用,它们的产品定位不同,你要用不同的标尺来衡量。但无论哪种,你都应该能给出一个合理的使用节奏预期,然后对照实际数据,看有没有大的偏差。频率比你期望高,说明价值可能超出预期; 频率远低于预期,则要反思是不是场景抓得不准,或者使用体验某处让用户感觉累。 +**第二个是复访频率。** 那些没有卸载你的应用的人,到底多久会回来一次。一款每天都可以用得上的工具和一款每季度才会被想起一次的应用,它们的产品定位不同,你要用不同的标尺来衡量。但无论哪种,你都应该能给出一个合理的使用节奏预期,然后对照实际数据,看有没有大的偏差。频率比你期望高,说明价值可能超出预期; 频率远低于预期,则要反思是不是场景抓得不准,或者使用体验某处让用户感觉累。 - **第三个是推荐意愿。** 有没有人愿意主动推荐你的应用给别人。这件事可以通过几种方式观察: 比如在用户完成一次特别顺利的任务后,提供一个自然的分享入口,看有多少人真正使用; 在群里看看有没有人自发安利你的产品;或者进行小规模用户访谈时问一句,如果你身边有人遇到类似问题,你会不会推荐我这个工具给他。推荐意愿通常比简单的满意度分数更能说明问题,因为推荐是一种带有个人信用背书的行为,用户只有觉得你真的帮了大忙,才愿意把你的应用介绍给朋友。 +**第三个是推荐意愿。** 有没有人愿意主动推荐你的应用给别人。这件事可以通过几种方式观察: 比如在用户完成一次特别顺利的任务后,提供一个自然的分享入口,看有多少人真正使用; 在群里看看有没有人自发安利你的产品;或者进行小规模用户访谈时问一句,如果你身边有人遇到类似问题,你会不会推荐我这个工具给他。推荐意愿通常比简单的满意度分数更能说明问题,因为推荐是一种带有个人信用背书的行为,用户只有觉得你真的帮了大忙,才愿意把你的应用介绍给朋友。 当你把这三个指标与前面讲过的用户反馈结合起来看,大致就能判断出你的应用目前处于什么状态。也许功能还不完备,但有一批人已经留下来,并且会在特定场景反复使用你,这样的应用就很值得继续投资和打磨。相反,如果修了很多 bug,堆了不少新功能,留存和复访却一直上不去,几乎没人主动推荐,这时候就要冷静思考,是不是该收缩范围,重新回到那个最初的核心场景,甚至考虑换一个方向。 @@ -726,20 +729,20 @@ B 端应用有几项特别核心的关注点。 要判断自己是不是已经在不知不觉中为了 AI 而 AI,一个很实用的办法,是在每次考虑加入某个 AI 功能之前,先强迫自己认真回答两个问题。 - **第一个问题是: 不用 AI,这个应用是否也成立** 。也就是,把所有 AI 能力都暂时抹去,你做的这件事,本身是不是一件有价值的事,用户有没有现实需求,愿不愿意每天、每周、每月在这件事上投入真实时间。 +**第一个问题是: 不用 AI,这个应用是否也成立** 。也就是,把所有 AI 能力都暂时抹去,你做的这件事,本身是不是一件有价值的事,用户有没有现实需求,愿不愿意每天、每周、每月在这件事上投入真实时间。 这句话听起来有点逆势,因为现在几乎所有产品介绍都会把 AI 放在非常显眼的位置,好像没有 AI 就不算现代工具。但如果你的应用在没有 AI 的情况下就完全站不住脚,很多时候说明的并不是你技术不够先进,而是一个更深层的问题: 你抓的那个需求,可能本身就不痛不痒,甚至并不真实存在。 想象一下,你要做一个帮助人整理待办事项的工具。如果你主要的差异点是: 在待办列表上加了一些模型生成的提示,比如自动起标题、自动分类、自动补全描述。但用户原本在写待办时,根本不觉得起个标题有什么痛苦,只是想快点把事情写完,那这些聪明能力再花哨,也很难形成持续价值。相反,如果你先退一步,问清楚不用 AI 的时候,这个应用最朴素的价值是什么,也许你会发现更扎实的方向: 帮用户把散落在不同渠道的任务统一收集,帮他看清每天只能做完多少件事,帮他在日程结束之前看到风险,从而做减法和取舍。把这些基础能力做扎实,往往比一上来就给待办加上各种智能标签更重要。 - **第二个问题是: 用 AI 之后,具体提升了什么。** 这里不接受那种很宽泛的总结,比如提升效率、重构体验、智能升级,而是要落到一两个连用户本人都能清楚感知到的维度。 +**第二个问题是: 用 AI 之后,具体提升了什么。** 这里不接受那种很宽泛的总结,比如提升效率、重构体验、智能升级,而是要落到一两个连用户本人都能清楚感知到的维度。 你可以这样盘问自己: -* 有没有显著提升完成任务的速度,比如把原本要自己从零写的一页文案,变成只需要花五分钟审阅和改写 -* 有没有明显提升结果的质量,比如让用户在相同时间内产出更有条理、更专业、更符合目标受众的内容 -* 有没有让使用过程变得更顺畅或更轻松,比如把一段非常枯燥的表单流程,变成更像聊天的问答 -* 有没有在真实成本上带来下降,比如减少外包次数、减少人工客服时长、缩短培训周期、缩短决策时间 +- 有没有显著提升完成任务的速度,比如把原本要自己从零写的一页文案,变成只需要花五分钟审阅和改写 +- 有没有明显提升结果的质量,比如让用户在相同时间内产出更有条理、更专业、更符合目标受众的内容 +- 有没有让使用过程变得更顺畅或更轻松,比如把一段非常枯燥的表单流程,变成更像聊天的问答 +- 有没有在真实成本上带来下降,比如减少外包次数、减少人工客服时长、缩短培训周期、缩短决策时间 如果你在脑中给出的答案还停留在**感觉会**更方便一些、看起来更酷一点,那十有八九说明这个 AI 功能还没有找到最关键的着力点。 @@ -747,44 +750,44 @@ B 端应用有几项特别核心的关注点。 ## 4.2 思考 AI 扮演了什么角色 -当你确定这个应用就算不用 AI 也成立,而且已经找到一个清楚的提升点,下一步需要做的,是更具体地思考: **在你的应用中,AI 到底是做什么的。** 很多产品在这一步出错,是因为它们把 AI 当作一种很抽象的能量,而不是一个有具体分工的角色。结果就是,功能堆得很多,但每一块的作用都模糊不清,用户用起来也只觉得哪里都沾一点智能,却说不出哪个地方真正离不开它。 +当你确定这个应用就算不用 AI 也成立,而且已经找到一个清楚的提升点,下一步需要做的,是更具体地思考: **在你的应用中,AI 到底是做什么的。** 很多产品在这一步出错,是因为它们把 AI 当作一种很抽象的能量,而不是一个有具体分工的角色。结果就是,功能堆得很多,但每一块的作用都模糊不清,用户用起来也只觉得哪里都沾一点智能,却说不出哪个地方真正离不开它。 一个更加清晰的思路,是把 AI 当作几种不同的部件: ** 它可以是大脑,是眼睛,是手** 。你需要根据你的产品目标,决定它在其中负责哪一块,如果可以,最好一开始就只选一两个角色把它做好,而不是一股脑全部塞进去。 ![](images/image19.png) - **当它扮演大脑时,主要负责理解和生成文字内容,或者在复杂信息之间做推理。** 比如,你做一个会议纪要助手,它要能从一段长长的录音里,抓出真正核心的讨论点,而不是简单按时间顺序罗列。你做一个学习应用,它要能根据用户的回答,判断他到底是没理解概念,还是只是粗心写错步骤,并给出不同的反馈。这类场景里,AI 的价值在于它能读懂用户说的话,理解用户给出的材料,然后生成一个带结构、带逻辑的输出。你要做的,是帮用户把问题问清楚,把上下文喂得足够准确,让这个大脑有足够信息做判断。 +**当它扮演大脑时,主要负责理解和生成文字内容,或者在复杂信息之间做推理。** 比如,你做一个会议纪要助手,它要能从一段长长的录音里,抓出真正核心的讨论点,而不是简单按时间顺序罗列。你做一个学习应用,它要能根据用户的回答,判断他到底是没理解概念,还是只是粗心写错步骤,并给出不同的反馈。这类场景里,AI 的价值在于它能读懂用户说的话,理解用户给出的材料,然后生成一个带结构、带逻辑的输出。你要做的,是帮用户把问题问清楚,把上下文喂得足够准确,让这个大脑有足够信息做判断。 - **当它扮演眼睛时,重点在于处理图像、视频等非文本内容,** 把这些东西变成机器可以理解的描述,然后再基于这些描述进一步行动。比如,你做一个整理纸质文档的工具,它可以通过拍照识别,把一堆发票、合同、包装说明书变成可搜索的文字。你做一个学习绘画的应用,它可以看懂用户画的草图,然后指出构图和线条上的一些问题。你做一个家居整理建议工具,它可以通过用户上传的照片,识别出目前房间的布局和物品分布,再给出一些简单可执行的改造方案。这里 AI 的重点是: 它像是一双会分析的眼睛,让你的应用不再只能处理键盘输入的文字,而是开始真正接触用户生活里的实物世界。 +**当它扮演眼睛时,重点在于处理图像、视频等非文本内容,** 把这些东西变成机器可以理解的描述,然后再基于这些描述进一步行动。比如,你做一个整理纸质文档的工具,它可以通过拍照识别,把一堆发票、合同、包装说明书变成可搜索的文字。你做一个学习绘画的应用,它可以看懂用户画的草图,然后指出构图和线条上的一些问题。你做一个家居整理建议工具,它可以通过用户上传的照片,识别出目前房间的布局和物品分布,再给出一些简单可执行的改造方案。这里 AI 的重点是: 它像是一双会分析的眼睛,让你的应用不再只能处理键盘输入的文字,而是开始真正接触用户生活里的实物世界。 - **当它扮演手时,意味着它开始去执行一连串具体的动作** ,而不仅仅是给出一个建议或者文字结果。比如一些自动化平台,会让你把多个步骤串成一条工作流: 从邮件里读取附件,把内容总结成要点,发到一个群里,再把原文存入云盘,最后在任务管理工具中自动创建一条跟进任务。这里 AI 的作用,是帮你在复杂的流程里,根据上下文动态决定下一步该怎么干,比如识别一封邮件是不是投诉,判断某个表单是不是填写完整,再据此触发不同的后续操作。 +**当它扮演手时,意味着它开始去执行一连串具体的动作** ,而不仅仅是给出一个建议或者文字结果。比如一些自动化平台,会让你把多个步骤串成一条工作流: 从邮件里读取附件,把内容总结成要点,发到一个群里,再把原文存入云盘,最后在任务管理工具中自动创建一条跟进任务。这里 AI 的作用,是帮你在复杂的流程里,根据上下文动态决定下一步该怎么干,比如识别一封邮件是不是投诉,判断某个表单是不是填写完整,再据此触发不同的后续操作。 除了上述简单的描述,实际应用中,AI 承担的角色往往会更加具体和多样,例如: 在文本处理方面,它可能是在做翻译、摘要、问答、续写或情感分析:比如客服系统里自动分类用户咨询、法律文档助手里提取合同条款、教育应用里批改作文。 -* 技术基础主要是深度学习中的 **大语言模型(** **LLM** **)** :在海量语料上学习语言规律和世界知识,既能“看懂”长篇、多轮对话中的上下文,又能“写出”连贯、风格一致的内容。 -* 在“理解”侧,LLM 可以识别用户意图、提取关键信息、判断情感倾向;在“生成”侧,则用于自动写摘要、回答问题、进行续写改写以及多语言翻译,把大量需要人工阅读、归纳和撰写的工作自动化或半自动化。 -* 以**在线客服机器人**为例:系统先根据用户的一句话大致判断属于咨询、投诉还是售后,并从话语中识别出订单号、时间、商品名等关键信息,然后交给 LLM 结合上下文和企业知识库生成自然、完整的答复,既减少人工压力,又能在高峰期保持稳定服务质量。 +- 技术基础主要是深度学习中的 **大语言模型(** **LLM** **)** :在海量语料上学习语言规律和世界知识,既能“看懂”长篇、多轮对话中的上下文,又能“写出”连贯、风格一致的内容。 +- 在“理解”侧,LLM 可以识别用户意图、提取关键信息、判断情感倾向;在“生成”侧,则用于自动写摘要、回答问题、进行续写改写以及多语言翻译,把大量需要人工阅读、归纳和撰写的工作自动化或半自动化。 +- 以**在线客服机器人**为例:系统先根据用户的一句话大致判断属于咨询、投诉还是售后,并从话语中识别出订单号、时间、商品名等关键信息,然后交给 LLM 结合上下文和企业知识库生成自然、完整的答复,既减少人工压力,又能在高峰期保持稳定服务质量。 在图像处理方面,它可能是在做识别、分类、生成、修复或增强:比如医疗影像里标注病灶位置、电商平台里自动抠图换背景、设计工具里根据文字描述生成配图。 -* 图像理解通常依托 **卷积神经网络** **(** **CNN** **)** 等视觉深度模型,从海量图像中学习边缘、纹理、结构等特征,用于目标检测、图像分割和细粒度分类(如区分不同病灶、不同商品品类)。 -* 图像生成与修复依托 **扩散模型、** **GAN** ** 等生成式模型** ,可以根据文字描述或参考图片生成全新图像,对模糊、缺失或低分辨率图像进行修复和超分辨率增强。 -* 很多系统还会结合 LLM:先用自然语言理解用户的文本描述,再自动生成适合视觉模型的“提示词”、风格标签和构图约束,实现从“听懂你想要什么”到“画出你想要什么”。 -* 以电商平台的**“智能主图生成”** 为例:系统先用检测和分割模型把商品从原图中精细抠出来,再通过 LLM 解析商家输入的文案(如“简约北欧风客厅场景,柔和自然光”),转成具体的场景、色调和风格参数,最后交给扩散模型生成匹配的背景和光影效果,并自动筛掉构图不佳或风格不符的结果,输出可直接用于上架的商品主图。 +- 图像理解通常依托 **卷积神经网络** **(** **CNN** **)** 等视觉深度模型,从海量图像中学习边缘、纹理、结构等特征,用于目标检测、图像分割和细粒度分类(如区分不同病灶、不同商品品类)。 +- 图像生成与修复依托 **扩散模型、** **GAN** ** 等生成式模型** ,可以根据文字描述或参考图片生成全新图像,对模糊、缺失或低分辨率图像进行修复和超分辨率增强。 +- 很多系统还会结合 LLM:先用自然语言理解用户的文本描述,再自动生成适合视觉模型的“提示词”、风格标签和构图约束,实现从“听懂你想要什么”到“画出你想要什么”。 +- 以电商平台的**“智能主图生成”** 为例:系统先用检测和分割模型把商品从原图中精细抠出来,再通过 LLM 解析商家输入的文案(如“简约北欧风客厅场景,柔和自然光”),转成具体的场景、色调和风格参数,最后交给扩散模型生成匹配的背景和光影效果,并自动筛掉构图不佳或风格不符的结果,输出可直接用于上架的商品主图。 在音视频处理方面,它可能是在做音频和视频的生成、转写、降噪、剪辑或字幕制作:比如播客工具里自动生成开场和结尾的旁白、视频平台里根据脚本自动合成讲解视频、会议软件里实时转写和翻译对话并生成多语言字幕与录播回放。 -* 在“理解”侧,系统会用**语音识别模型**把语音转换成文字,同时分析说话人、语种、语速和大致情绪;用视觉模型理解视频画面中的场景、人物和关键物体。 -* 在“生成”侧,以 LLM 为核心,对脚本、会议内容或用户指令进行理解、拆分和改写,然后驱动 **语音合成** **(** **TTS** **)生成自然语音解说,驱动视频生成与编辑模型**自动合成或剪辑画面、替换背景、插入镜头和字幕;音频侧的生成模型还能自动生成背景音乐和环境音,并配合深度降噪与音质增强提升整体听感。 -* 以“ **文字生成短视频** ”类产品为例:用户只需输入一段文案,系统先用 LLM 把文章拆成几个自然的段落和画面,生成适合口播的解说词和简单的分镜描述;然后由 TTS 模型合成配音,再由视频模板和生成模型根据分镜选择或生成画面,在时间轴上自动对齐字幕与语音,最后一键导出一条可以直接发布的短视频。 +- 在“理解”侧,系统会用**语音识别模型**把语音转换成文字,同时分析说话人、语种、语速和大致情绪;用视觉模型理解视频画面中的场景、人物和关键物体。 +- 在“生成”侧,以 LLM 为核心,对脚本、会议内容或用户指令进行理解、拆分和改写,然后驱动 **语音合成** **(** **TTS** **)生成自然语音解说,驱动视频生成与编辑模型**自动合成或剪辑画面、替换背景、插入镜头和字幕;音频侧的生成模型还能自动生成背景音乐和环境音,并配合深度降噪与音质增强提升整体听感。 +- 以“ **文字生成短视频** ”类产品为例:用户只需输入一段文案,系统先用 LLM 把文章拆成几个自然的段落和画面,生成适合口播的解说词和简单的分镜描述;然后由 TTS 模型合成配音,再由视频模板和生成模型根据分镜选择或生成画面,在时间轴上自动对齐字幕与语音,最后一键导出一条可以直接发布的短视频。 在语音交互方面,它可能是在做识别、合成、情绪检测或对话管理:比如智能音箱里理解用户指令、语音导航里播报路线、语言学习应用里纠正发音。 -* 前端由深度学习的**语音识别模型**将用户语音转成文字,并提取语调、音量、语速等特征,为判断情绪和状态提供线索。 -* 后端通过 **语音合成(TTS)** 把这些文字回复变成自然流畅的语音输出,情绪识别模型会根据用户当下的说话方式调整回复的语气和速度,让交互更贴近真实对话。 -* 以**智能音箱**为例:当用户说“今天有点累,放点轻松的音乐吧”,系统先用语音识别转成文字,再由 LLM 结合历史播放记录理解用户偏好的“轻松”风格,自动选择更舒缓的歌单;情绪识别判断用户处于疲惫状态后,TTS 在合成回复时会降低语速、柔化语调,让整个交流过程既“听得懂”,又“听起来舒服”。 +- 前端由深度学习的**语音识别模型**将用户语音转成文字,并提取语调、音量、语速等特征,为判断情绪和状态提供线索。 +- 后端通过 **语音合成(TTS)** 把这些文字回复变成自然流畅的语音输出,情绪识别模型会根据用户当下的说话方式调整回复的语气和速度,让交互更贴近真实对话。 +- 以**智能音箱**为例:当用户说“今天有点累,放点轻松的音乐吧”,系统先用语音识别转成文字,再由 LLM 结合历史播放记录理解用户偏好的“轻松”风格,自动选择更舒缓的歌单;情绪识别判断用户处于疲惫状态后,TTS 在合成回复时会降低语速、柔化语调,让整个交流过程既“听得懂”,又“听起来舒服”。 以上内容只是对 AI 在几个主要方向上的应用和技术做了简单介绍。到了真实业务场景中,你往往需要把多种最新的 AI API 引入进来,在不同任务上做更全面的测试。你还需要逐渐搞清楚当前 AI 的能力到底有多强、能解决哪些问题、在哪些情况下容易出错,它的边界在哪里。只有认识到这些,才能合理设计功能和流程,而不会因为误判能力而埋下风险。 @@ -861,13 +864,13 @@ B 端应用有几项特别核心的关注点。 这个时候,你不能指望自然流量和运气,而是要主动出手,为它搭起最初的基础。具体来说,有几件必须完成的事情: - **找到一小批愿意真正使用的种子用户** ,而不是随便从熟人圈里凑数。这些人必须对你要解决的问题有真实的需求,而不是出于人情或好奇点开看一眼就走。 +**找到一小批愿意真正使用的种子用户** ,而不是随便从熟人圈里凑数。这些人必须对你要解决的问题有真实的需求,而不是出于人情或好奇点开看一眼就走。 - **准备最初的使用体验和供给** ,确保用户进来不会只看到一片空白。即便功能还不完善,至少要让他们能完成一次完整的核心操作,感受到这个应用的价值。 +**准备最初的使用体验和供给** ,确保用户进来不会只看到一片空白。即便功能还不完善,至少要让他们能完成一次完整的核心操作,感受到这个应用的价值。 - **把产品是做什么的、解决什么问题,用简单的话讲清楚** 。在没有品牌背书的情况下,用户给你的耐心只有几秒钟,你必须让他们在最短时间内明白"这个东西对我有什么用"。 +**把产品是做什么的、解决什么问题,用简单的话讲清楚** 。在没有品牌背书的情况下,用户给你的耐心只有几秒钟,你必须让他们在最短时间内明白"这个东西对我有什么用"。 - **想办法拿到第一个触达渠道** ,把这些信息递到潜在用户手里。可能是一个小社群、一个论坛、一个朋友圈,关键不在于规模有多大,而在于能不能精准触达那些真正需要的人。 +**想办法拿到第一个触达渠道** ,把这些信息递到潜在用户手里。可能是一个小社群、一个论坛、一个朋友圈,关键不在于规模有多大,而在于能不能精准触达那些真正需要的人。 在 0–1 阶段,你真正要考虑的是:把第一批有真实需求的人引进来,并且让他们完成一次从进入到使用再到反馈的闭环。只要这个闭环能跑通,你就证明了这个应用不是空中楼阁,而是真的有人需要、愿意用的东西。 @@ -877,21 +880,21 @@ B 端应用有几项特别核心的关注点。 在 1–N 阶段,你要开始关心的是机制、组织、商业化、品牌、团队等一整套更复杂的问题。比如: - **是否已经找到相对稳定的获客渠道** ,知道每投入多少预算或时间,大致能带来怎样的新增用户。这时候你需要的不再是碰运气,而是可重复、可预测的增长路径。 +**是否已经找到相对稳定的获客渠道** ,知道每投入多少预算或时间,大致能带来怎样的新增用户。这时候你需要的不再是碰运气,而是可重复、可预测的增长路径。 - **有没有开始搭建服务机制** ,比如客服、运营活动、用户教育。用户多了之后,你不可能再像早期那样一对一地手把手教每个人怎么用,必须建立标准化的服务体系。 +**有没有开始搭建服务机制** ,比如客服、运营活动、用户教育。用户多了之后,你不可能再像早期那样一对一地手把手教每个人怎么用,必须建立标准化的服务体系。 - **打算怎样让这个产品赚到钱** ,是订阅、单次付费、增值服务还是其他。商业模式不是一开始就要想清楚的,但当你进入 1–N 阶段,就必须认真考虑如何让这个产品可持续运转下去。 +**打算怎样让这个产品赚到钱** ,是订阅、单次付费、增值服务还是其他。商业模式不是一开始就要想清楚的,但当你进入 1–N 阶段,就必须认真考虑如何让这个产品可持续运转下去。 - **想给用户留下怎样的品牌印象** 。早期你可能只是在小圈子里传播,但当用户规模扩大,你需要思考如何让更多人记住你、信任你,并愿意主动推荐给别人。 +**想给用户留下怎样的品牌印象** 。早期你可能只是在小圈子里传播,但当用户规模扩大,你需要思考如何让更多人记住你、信任你,并愿意主动推荐给别人。 - **团队还缺哪些能力,哪些环节必须有人长期盯着** ,不能完全外包。一个人或小团队能撑起 0–1,但 1–N 往往需要更多角色的配合。 +**团队还缺哪些能力,哪些环节必须有人长期盯着** ,不能完全外包。一个人或小团队能撑起 0–1,但 1–N 往往需要更多角色的配合。 这些问题都很重要,但如果你在 0–1 阶段就急着琢磨它们,往往只会让你陷入空转。因为在你还不知道这个产品是不是真的有人愿意用、愿意留下来的时候,谈商业模型和品牌策略,只会把注意力从真正紧要的事情上引开。 ### 为什么要先专注 0–1? -对个人开发者、小团队来说,比起 1–N, **真正最该关注的是 0–1** 。原因很简单:如果你连第一批真实用户都找不到,后面所有关于规模化、商业化、品牌建设的讨论都是空谈。 +对个人开发者、小团队来说,比起 1–N, **真正最该关注的是 0–1** 。原因很简单:如果你连第一批真实用户都找不到,后面所有关于规模化、商业化、品牌建设的讨论都是空谈。 0–1 阶段是整个产品生命周期里最脆弱、也最关键的时刻。它决定了你能不能证明这个产品的价值,能不能建立起最初的信任,能不能为后续的增长打下地基。只有当你真正跑通了 0–1,才有资格去考虑 1–N 的问题。 @@ -903,21 +906,21 @@ B 端应用有几项特别核心的关注点。 ### 第一类: 种子用户 - **种子用户是你最早触达的那批使用者。** 他们的典型特征是人数不多,但与你的目标画像高度吻合。你要从他们身上获得的不只是注册和使用数据,更是一手的方向和体验反馈。 +**种子用户是你最早触达的那批使用者。** 他们的典型特征是人数不多,但与你的目标画像高度吻合。你要从他们身上获得的不只是注册和使用数据,更是一手的方向和体验反馈。 -* 面向个人工具类产品,种子用户可能是那一群在某个问题上长期有痛点的人,比如经常写长文需要整理的内容创作者,频繁准备汇报材料的职场人士,或者每天要和大量资料打交道的学生 -* 对于教育类应用,种子用户可能是一小撮正在准备同一场考试的考生,或者某个年级段的家长 +- 面向个人工具类产品,种子用户可能是那一群在某个问题上长期有痛点的人,比如经常写长文需要整理的内容创作者,频繁准备汇报材料的职场人士,或者每天要和大量资料打交道的学生 +- 对于教育类应用,种子用户可能是一小撮正在准备同一场考试的考生,或者某个年级段的家长 冷启动时,你可以先给自己设一个明确的种子用户目标,比如先找到二十到五十个愿意配合的用户,用一两周时间边使用边对话。重点不是数量,而是通过高密度的交流把产品逻辑磨清楚。 ### 第二类: 供给方 - **在一些双边或多边平台型产品里** ,单有用户端是不够的。如果没有足够的供给方存在,用户即便被拉进来,也会因为找不到东西可用而迅速离开。 +**在一些双边或多边平台型产品里** ,单有用户端是不够的。如果没有足够的供给方存在,用户即便被拉进来,也会因为找不到东西可用而迅速离开。 **供给方可能是内容创作者、课程老师、服务提供者、商家、司机、房东**等,他们决定了平台的丰富度和吸引力。 -* 做一个面向设计师的素材平台,你需要先说服一批设计师愿意上传作品,哪怕只是小规模地开放一部分免费素材。否则用户进来看到只是几张示例图,很难形成粘性 -* 做一个线上预约工具,如果没有提前对接好一些有意愿使用的商家或机构,普通用户进来后一样找不到可以实际预约的对象 +- 做一个面向设计师的素材平台,你需要先说服一批设计师愿意上传作品,哪怕只是小规模地开放一部分免费素材。否则用户进来看到只是几张示例图,很难形成粘性 +- 做一个线上预约工具,如果没有提前对接好一些有意愿使用的商家或机构,普通用户进来后一样找不到可以实际预约的对象 冷启动时,你要非常清楚地知道,自己是在先解决用户端,还是先解决供给端,还是两端同步推进。很多平台在早期都经历过这样的取舍和权衡。只要你意识到这是一个必须正面面对的结构性问题,就已经比那些只想着多拉点终端用户的人走前了一步。 @@ -925,8 +928,8 @@ B 端应用有几项特别核心的关注点。 流量方是那些可以在**较短时间内,把一定规模用户注意力导向你的人或机构。它们可能是达人博主、垂直账号、媒体、社区运营者,也可能是某个拥有大量用户的工具平台。** -* 一个职场工具类产品,如果能说服几个职业发展博主,在内容中自然地介绍你的应用,就有机会在短时间内获得一批对职场效率工具敏感的人 -* 一个针对小红书创作者的选题助手,如果能和几位中腰部博主合作,让他们在实战案例中展示使用过程,那么这批创作者天然就是你的潜在种子用户 +- 一个职场工具类产品,如果能说服几个职业发展博主,在内容中自然地介绍你的应用,就有机会在短时间内获得一批对职场效率工具敏感的人 +- 一个针对小红书创作者的选题助手,如果能和几位中腰部博主合作,让他们在实战案例中展示使用过程,那么这批创作者天然就是你的潜在种子用户 在冷启动阶段,你不必急着找最大牌的流量方,甚至不必马上去跟头部谈合作。很多时候,那些规模适中但与目标人群高度重叠的小流量方,反而更愿意和你一起做一些定制化的尝试。你要做的是找到这类人或机构,然后拿出一个清晰的合作提案,让对方看得懂你要做什么,能给他们带来什么好处。 @@ -934,7 +937,7 @@ B 端应用有几项特别核心的关注点。 渠道方是那些可以帮助你在 **特定场景下稳定触达目标用户的组织或入口** 。它们和流量方的区别在于: 流量方更偏向一次性的注意力导入,而渠道方更像是长期的、结构化的连接方式。 -* 学校、培训机构、企业、行业协会、软件服务商,都是典型的渠道方 +- 学校、培训机构、企业、行业协会、软件服务商,都是典型的渠道方 如果你的应用能切实帮助某类机构提高效率、节省成本或提升服务质量,他们有动力把你的产品介绍给自己体系内的大量用户 冷启动阶段,你不必妄想一口气拿下大型渠道,可以从一个小范围试点开始。比如和一两个班级、一家小公司、一个本地社群合作,让他们在内部先使用一段时间,然后根据反馈再决定要不要放大规模。 @@ -993,8 +996,8 @@ B 端应用有几项特别核心的关注点。 在很多领域,一个新应用如果想完全靠自己建生态,代价非常高。但如果你愿意先把自己当作一个在大平台上的新店、新账号、新插件,冷启动的难度会降低很多。 -* 电商领域,新店入驻淘宝、拼多多、京东等平台,至少不用从零搭建支付、物流、评价系统。冷启动时常用的方式包括达人带货、站内推广与活动位、直播等 -* 工具类、内容类应用,可以通过为成熟平台开发插件、小工具,把服务上线到开放平台的能力市场,让已经有明确需求的用户更容易找到你 +- 电商领域,新店入驻淘宝、拼多多、京东等平台,至少不用从零搭建支付、物流、评价系统。冷启动时常用的方式包括达人带货、站内推广与活动位、直播等 +- 工具类、内容类应用,可以通过为成熟平台开发插件、小工具,把服务上线到开放平台的能力市场,让已经有明确需求的用户更容易找到你 这条路背后的逻辑,是 **承认大平台已经把用户聚集在一些特定场景里,而你要做的是在这些场景中找到与你产品匹配的那个小角落** 。借力并不意味着放弃独立性,而是在冷启动阶段,用一个更现实的方式打开局面。 @@ -1012,16 +1015,16 @@ B 端应用有几项特别核心的关注点。 更务实的办法,是把目标收紧成一件具体的小事,比如:在接下来的四周,让二十个符合目标画像的真实用户,在自己的真实场景里,多次完整使用你的应用,并且从他们那里拿到足够具体的反馈。 - **所谓“细分人群”,不是“任何可能会用到这类工具的人”,而是你可以指着某个标签具体描述出来的一群人。** 比如你做的是一个帮人生成工作汇报的工具,那么目标可以是“互联网运营岗的一到三年从业者”,而不是笼统的“职场人士”。这群人有几个共同点:每个月确实要做汇报,时间有限,又想让内容看起来专业一点,他们的问题是具体而持续的。 +**所谓“细分人群”,不是“任何可能会用到这类工具的人”,而是你可以指着某个标签具体描述出来的一群人。** 比如你做的是一个帮人生成工作汇报的工具,那么目标可以是“互联网运营岗的一到三年从业者”,而不是笼统的“职场人士”。这群人有几个共同点:每个月确实要做汇报,时间有限,又想让内容看起来专业一点,他们的问题是具体而持续的。 - **“完整使用任务”同样不能含糊** 。以这个汇报工具为例,一次完整任务可能是:用户把最近一周的运营数据和素材整理好,导入工具,生成一版初稿,然后根据推荐的结构和要点修改两到三轮,最后导出 PPT 或文档,真正拿去在部门会上讲。如果用户只是随便点两下,看看大概长什么样,就关掉不再打开,这不能算完整使用。 +**“完整使用任务”同样不能含糊** 。以这个汇报工具为例,一次完整任务可能是:用户把最近一周的运营数据和素材整理好,导入工具,生成一版初稿,然后根据推荐的结构和要点修改两到三轮,最后导出 PPT 或文档,真正拿去在部门会上讲。如果用户只是随便点两下,看看大概长什么样,就关掉不再打开,这不能算完整使用。 具体反馈要问到足够细。比如: -* 在导入数据的时候,有没有哪一步看不懂、找不到入口,或者总是点错地方; -* 生成的结构是不是贴近他所在公司的汇报习惯,比如是不是有他需要的“背景–目标–过程–结果”这套格式; -* 哪些页面是他真正拿去用的,哪些页面每次都会删掉; -* 使用之后,他是不是能明显感觉到自己准备一次汇报的时间从三小时缩短到了一个小时,还是只是觉得“好像方便了一点,但也说不上来”。 +- 在导入数据的时候,有没有哪一步看不懂、找不到入口,或者总是点错地方; +- 生成的结构是不是贴近他所在公司的汇报习惯,比如是不是有他需要的“背景–目标–过程–结果”这套格式; +- 哪些页面是他真正拿去用的,哪些页面每次都会删掉; +- 使用之后,他是不是能明显感觉到自己准备一次汇报的时间从三小时缩短到了一个小时,还是只是觉得“好像方便了一点,但也说不上来”。 ### 不要什么都想试一遍 @@ -1041,7 +1044,7 @@ B 端应用有几项特别核心的关注点。 很多团队在冷启动阶段的共同特征是:焦虑。一旦焦虑起来,就很容易往外找新动作:是不是也该弄个短视频账号,拍几个使用教程;是不是也该花一点预算做个小投放试试;是不是应该去联系几个媒体,看看能不能写一篇报道。**每一件看上去都无可厚非,但合在一起的结果,是你每天都在换方向,始终没有哪一条路沉下去。** - **可以给自己定一个很具体的阶段约束,比如接下来四周,只集中做两件事** :一是围绕那二十个用户,反复优化他们在真实场景下的使用体验,让他们从“勉强能用”变成“基本顺手”;二是沿着你选定的主路径,持续找到少量新用户,并把他们的行为和反馈记录下来,看看和前一批人有什么共性和差异。 +**可以给自己定一个很具体的阶段约束,比如接下来四周,只集中做两件事** :一是围绕那二十个用户,反复优化他们在真实场景下的使用体验,让他们从“勉强能用”变成“基本顺手”;二是沿着你选定的主路径,持续找到少量新用户,并把他们的行为和反馈记录下来,看看和前一批人有什么共性和差异。 在这四周里,遇到任何新的想法、新的机会,都先问自己一句:这件事,是否能在这段时间内显著推动那二十个用户用得更好,或者清楚地帮我找到下一批类似的用户? @@ -1057,7 +1060,7 @@ B 端应用有几项特别核心的关注点。 先是第一章,我们从点子本身出发,一个点子不再只是你脑子里的那句感觉挺酷,而是必须面向一类清晰的用户, **扎在某个具体场景里,帮他们完成一件具体任务,并且给出比现状更好的做法** 。你学会从**玩法、用户链路、做什么事情、解决什么问题**这四个维度去审视自己的想法,也开始意识到,点子和用户需求之间有一道很容易忽略的鸿沟。你压抑住自嗨的冲动,开始分辨真需求和假需求,承认好点子和坏点子在一开始就有命运上的差别。然后,你不再被动等灵感,而是学会从自己热爱的生活、人群资产、公开场域和现有产品里主动挖掘线索;再往下,你训练自己用一句话概括一个点子的本质,用 AI 做头脑风暴,在常见方向里找到属于自己的人群和场景差异化。 -接着在第二章,你不再停留在想,而是 **开始学会动手** 。你学会在**发散和****收敛**之间来回切换,用双钻的方式先把点子铺开,再按用户价值、可行性和时间成本 **收紧到一个真正的可行路线** 。你练习 **从抽象到具体** ,把我想做一个提高效率的应用这类模糊愿望,一层层拆成最小可行动项,直到每一个步骤都变成今天可以动手的任务。你拿起白板或纸笔,先画再做,把一个应用分成入口页、操作页、结果页,画出用户从走进来再到拿到结果的完整链路。你也不会再把参考别人当成抄作业,而是有意识地 **分析别人的导航、表单、结果展示和引导流程,借力现成经验** 。同时,你不再等到产品完全做完才去问用户,而是在原型和半成品阶段,就有意识地边画边问,边做边问,让真实用户尽早介入你的设计。 +接着在第二章,你不再停留在想,而是 **开始学会动手** 。你学会在**发散和\*\***收敛**之间来回切换,用双钻的方式先把点子铺开,再按用户价值、可行性和时间成本 **收紧到一个真正的可行路线** 。你练习 **从抽象到具体** ,把我想做一个提高效率的应用这类模糊愿望,一层层拆成最小可行动项,直到每一个步骤都变成今天可以动手的任务。你拿起白板或纸笔,先画再做,把一个应用分成入口页、操作页、结果页,画出用户从走进来再到拿到结果的完整链路。你也不会再把参考别人当成抄作业,而是有意识地 **分析别人的导航、表单、结果展示和引导流程,借力现成经验\*\* 。同时,你不再等到产品完全做完才去问用户,而是在原型和半成品阶段,就有意识地边画边问,边做边问,让真实用户尽早介入你的设计。 第三章里,你慢慢建立起一套自己的判断标准,来区分什么只是能用,什么可以算好用。你 **不再模糊地说这个应用还不错,而是具体看它有没有帮用户节省时间、降低错误率、减少沟通成本、减轻心智负担** 。你知道一个 **好应用应该让人几乎不用说明书就能上手** ,在关键场景会自然想到你,也懂得好应用背后真正的利他心。你开始把实际问题和用户痛点拆到边际成本的层面,分辨这背后到底是在消耗时间、金钱、心力还是风险。同时,你对 **C 端和 B 端的差异**有了初步认识,明白了前者更在意情绪价值和传播,后者更关心效率、成本、风险和合规。你不再只相信自己觉得好,而是搭起简单的反馈机制,用留存、复访和推荐这三类指标,判断这东西值不值得继续投入,用一次次用户反馈把应用从我觉得好打磨成用户觉得好。 @@ -1065,7 +1068,7 @@ B 端应用有几项特别核心的关注点。 最后的第五章,把这一切拉回到一个现实问题上:就算你已经有了一个还不错、甚至用上 AI 的应用,如果没有用户,它的价值依然是零。你先 **学会把 0–1 和 1–N 区分开来,暂时放下所有关于规模化、品牌和组织的宏大问题,把注意力集中在一件事上:先想办法让二十个真实用户用起来** ,并且用完愿意回来。你不再盲目撒网,而是沿着三条主线冷启动:用身边的社群、同行和朋友,慢慢积累种子用户;用内容和有限的福利去吸引第一批愿意尝鲜的人;借力现有平台和渠道,在别人已经有流量的地方为自己搭入口。你也开始按对象去拆冷启动的策略,区分种子用户、供给方、流量方和渠道方,各自用不同方式打通。资源有限时,你不再什么都想做一遍,而是看清自己最擅长和手头最容易启动的一条路,先把这一条路走深走透,而不是一口气铺十个半成品的渠道。 -如果把这些内容合在一起,你会发现整套方法并不神秘:**从一个靠谱的点子出发,确保它扎根在真实需求上;用画、写、拆的方式,把它****收敛** **成一个最小可行应用;用真实用户和明确指标,一点点把它打磨成好应用;在关键点上合理引入 AI 放大价值;最后,在有限资源下,用合适的冷启动方式找到第一批愿意为它买单的人** 。 +如果把这些内容合在一起,你会发现整套方法并不神秘:**从一个靠谱的点子出发,确保它扎根在真实需求上;用画、写、拆的方式,把它\*\***收敛\*\* **成一个最小可行应用;用真实用户和明确指标,一点点把它打磨成好应用;在关键点上合理引入 AI 放大价值;最后,在有限资源下,用合适的冷启动方式找到第一批愿意为它买单的人** 。 下一步你只需要放弃过多的幻想,踏踏实实选定其中一个做出来并推出去,让它真正进入真实世界里接受检验。**所有关于点子、方法论、AI 和增长的讨论,最后都要落在一个具体的人、一个具体的场景、一个具体的任务上。** @@ -1073,13 +1076,8 @@ B 端应用有几项特别核心的关注点。 在这个阶段中,笔者认为,只需要享受过程就好。就像一个有名的电子故事游戏《去月球》说的那样: -***"The ending isn't any more important than any of the moments leading to it."*** +**_"The ending isn't any more important than any of the moments leading to it."_** -***结局永远也不会比过程更重要。*** +**_结局永远也不会比过程更重要。_** ![](images/image21.png) - -# 📚 Assignment - -1. 根据上述的所有作业,并 **重点参考章节一、二的内容,** 产出细化后的最终点子,使用 Trae 或结合 CLI IDE 制作第一款应用(不用强行加入 AI 功能,你可以制作一个非 AI 应用,一个 AI 应用)。 -2. 为你的应用招募至少 20 个使用者,创建一个群聊维护用户社群。 diff --git a/docs/stage-1/appendix-b-common-errors/index.md b/docs/stage-1/appendix-b-common-errors/index.md new file mode 100644 index 0000000..6b76229 --- /dev/null +++ b/docs/stage-1/appendix-b-common-errors/index.md @@ -0,0 +1,269 @@ +# 附录 B:常见报错及解决方案 + +在使用 AI IDE 开发 Web 应用原型的过程中,遇到错误是正常的。本附录汇总了最常见的错误类型及其排查和解决方法,旨在帮助你快速定位问题,并学会有效地向 AI 寻求帮助。 + +## B.1 页面显示空白或不加载 + +### 可能的原因 + +页面一片空白是初学者最常遇到的问题之一。这通常是由 **JavaScript 错误导致代码执行中断** 引起的,一旦脚本执行出错,后续的渲染过程就会停止。此外,**资源文件路径错误** 也是常见原因,比如图片或样式表没找到。**网络问题** 也可能导致关键资源加载失败。最后,**渲染逻辑错误**(例如在数据还没加载回来时就尝试渲染)也会导致页面白屏。 + +### 排查步骤 + +#### 第一步:检查浏览器控制台 + +浏览器自带的开发者工具是你最好的帮手。按下 F12(或右键点击页面选择“检查”),打开开发者工具。首先查看 **Console** 标签页,寻找红色的错误信息,这通常直接指向问题的根源。然后查看 **Network** 标签页,看看是否有变红的请求,这意味着资源加载失败了。 + +#### 第二步:常见错误类型 + +**错误 1:Uncaught TypeError: Cannot read property 'X' of undefined** + +这是最经典的错误。它意味着你试图访问一个不存在(undefined)对象的属性。例如,当用户信息还没加载回来,`user` 变量是 `undefined` 时,你却试图访问 `user.name`。 + +- **解决方案**:使用可选链操作符 `?.` 或者逻辑或 `||` 来设置默认值。例如 `const userName = user?.name || '默认值';`。或者使用 `if (user)` 进行判断,确保对象存在后再访问其属性。 + +**错误 2:Failed to load resource** + +这个错误提示说明浏览器找不到你指定的文件。原因通常是**文件路径写错了**(比如把相对路径 `../` 写成了 `./`),或者**文件名大小写不匹配**(在某些系统中 `Image.png` 和 `image.png` 是两个文件),或者文件根本就**不存在于项目中**。仔细检查路径和文件名通常能解决问题。 + +**错误 3:Maximum update depth exceeded** + +这个错误通常发生在 React 等框架中,意味着出现了**无限循环渲染**。常见原因是 `useEffect` 钩子缺少了依赖数组,或者在组件渲染过程中直接修改了状态,导致“渲染 -> 更新状态 -> 触发渲染”的死循环。 + +### 向 AI 寻求帮助的模板 + +如果你无法自己解决,可以尝试用下面的模板问 AI: + +``` +我在开发一个[项目类型],遇到了页面空白的问题。 + +问题描述: +- 页面 URL:[你的页面路径] +- 预期行为:[应该显示什么] +- 实际行为:[页面完全空白/部分空白] + +控制台错误信息: +[粘贴完整的错误信息] + +相关代码: +[粘贴相关代码片段] + +我已经尝试过的解决方法: +1. [列出你尝试过的方法] +``` + +--- + +## B.2 数据保存不成功 + +### 可能的原因 + +辛辛苦苦输入的数据保存不了?这可能是因为**异步操作没有正确处理**,代码没等数据保存完就执行了下一步。也可能是发送给服务器的**数据格式错误**,不符合 API 的要求。此外,**存储 API 使用不当**(比如 `localStorage` 只能存字符串)或者**权限/配额问题**也可能导致保存失败。 + +### 排查步骤 + +#### 检查数据存储方式 + +**使用 localStorage** + +`localStorage` 是浏览器提供的本地存储,但它只能存储字符串。如果你直接存一个对象,它会被强制转成 `[object Object]` 这种无意义的字符串。 +**正确做法**是:在保存前使用 `JSON.stringify(data)` 将对象转为字符串,在读取后使用 `JSON.parse()` 将字符串转回对象。同时,建议用 `try...catch` 包裹代码,以处理可能的异常(比如存储空间已满)。 + +**使用状态管理** + +在 React 等框架中,状态更新往往是异步的。 +**常见的错误**是:发起保存请求后,直接用旧的状态数据去更新 UI,或者误以为 `setState` 是立即生效的。 +**正确做法**是:在异步请求成功返回后,使用服务器返回的最新数据来更新本地状态,确保前后端数据一致。 + +### 调试技巧 + +调试数据问题的最好办法是“打桩”。在数据保存流程的关键节点添加 `console.log`: + +1. 打印“准备保存的数据”,确认发出去的数据是对的; +2. 打印“数据类型”,确认格式没问题; +3. 打印“保存结果”,查看 API 或存储方法的返回值; +4. 最后尝试重新读取数据并打印,验证是否真的保存成功了。 + +--- + +## B.3 样式显示不正常 + +### 常见问题 + +#### 问题 1:样式完全不生效 + +如果你写了 CSS 但页面没反应,首先检查 **CSS 文件是否正确引入**,比如在 JS 文件中是否有 `import './styles.css'`。其次检查 **类名是否拼写正确**,HTML 中的 `class` 和 CSS 中的类名必须完全一致(包括大小写)。最后,可能是**样式被覆盖**了,使用开发者工具查看元素的样式来源,确认是否有优先级更高的样式覆盖了你的代码。 + +#### 问题 2:样式在开发环境正常,打包后失效 + +这种情况通常是因为**资源路径问题**或**样式隔离**。如果使用了打包工具,确保图片等资源的引用路径是正确的(通常建议用相对路径)。如果使用了 CSS Modules 或 Scoped CSS,要注意全局样式可能会被隔离,导致无法应用到某些组件上。 + +#### 问题 3:响应式布局失效 + +如果页面在手机上显示得很奇怪,首先检查 HTML 头部是否添加了 `` 标签,这是响应式布局的基础。其次检查 **媒体查询(Media Queries)** 的语法是否正确,以及断点设置是否合理。最后,确认是否混用了固定单位(px)和相对单位(rem/em/%),导致布局缺乏弹性。 + +### 向 AI 寻求帮助时提供 + +向 AI 咨询样式问题时,提供以下信息会很有帮助: + +- 问题元素的 HTML 结构代码。 +- 相关的 CSS 代码。 +- 浏览器开发者工具中“Computed”(计算样式)截图。 +- 你期望的效果描述,或者一张参考设计图。 + +--- + +## B.4 点击按钮没反应 + +### 排查步骤 + +#### 1. 检查事件绑定 + +首先确认事件是否真的绑定到了按钮上。在 React 中,应该是 `onClick={handleClick}`(注意驼峰命名)。 +**常见错误**包括:写成了 `onclick`(全小写);或者写成了 `onClick={handleClick()}`,这样会导致函数在渲染时就立即执行,而不是在点击时执行。 + +#### 2. 检查事件处理函数 + +确认事件处理函数本身是否有问题。 +**调试方法**是:在函数的第一行加一个 `console.log('按钮被点击')`。如果点击没日志,说明绑定有问题;如果有日志但没效果,说明函数内部逻辑有问题。注意,如果函数是异步的(async),确保你正确处理了 `await`,并且捕获了可能出现的错误。 + +#### 3. 检查按钮状态 + +有时候按钮没反应是因为它处于 **disabled**(禁用)状态,或者被其他透明元素遮挡了。 +**最佳实践**是:在进行异步操作(如提交表单)时,手动设置按钮为 loading 状态并禁用点击,防止用户重复提交。操作结束后,记得恢复按钮状态。 + +### 调试方法 + +调试交互问题时,遵循“逐步定位”原则: + +1. 先看函数有没有被调用(console.log)。 +2. 再看函数内部的状态和变量是否正确。 +3. 最后逐步检查每一行代码的执行结果,直到找到断点。 + +--- + +## B.5 API 调用失败 + +### 常见错误类型 + +#### 错误 1:CORS(跨域)错误 + +当你看到 `Access to ... has been blocked by CORS policy` 时,说明浏览器的同源策略阻止了你的请求。 +**解决方案**:最彻底的方法是后端开启 CORS 支持。在开发环境中,也可以配置前端代理(Proxy)来绕过限制。如果是调用第三方 API,检查文档是否需要特定的请求头或 API Key。 + +#### 错误 2:401 Unauthorized / 403 Forbidden + +这通常是权限问题。 +**原因**可能是:API Key 没填或填错了;Token 过期了;或者你的账户没有权限访问这个接口。 +**检查**:仔细核对 API Key 配置,确认认证信息(Authorization Header)是否正确传递。 + +#### 错误 3:429 Too Many Requests + +这意味着你发送请求太频繁,触发了服务器的限流机制。 +**解决**:检查代码是否有死循环导致疯狂发请求。如果没有,考虑给请求添加节流(Throttle)或防抖(Debounce),或者使用缓存来减少不必要的重复请求。 + +#### 错误 4:500 Internal Server Error + +这是服务器端出错了,通常不是前端的问题。 +**解决**:检查你的请求参数格式是否符合文档要求,有时候参数不对会导致服务器崩溃。查看 API 返回的详细错误信息。如果确认参数没问题,那就需要联系 API 提供方了。 + +### API 调用最佳实践 + +编写 API 调用代码时,建议封装一个通用的 `callAPI` 函数。在这个函数中,统一处理 API Key 的添加、JSON 数据的转换、以及错误状态码的检查。如果响应状态码不是 2xx,应该抛出一个包含详细错误信息的 Error,以便在上层逻辑中捕获并提示用户。 + +--- + +## B.6 如何把报错信息有效地反馈给 AI + +### 完整的错误报告模板 + +为了让 AI 更快帮你解决问题,请使用这个结构化的提问模板: + +```markdown +## 问题描述 + +我在开发一个[项目类型]时遇到了问题。 + +### 上下文信息 + +- 项目类型:[待办清单应用/笔记应用/游戏等] +- 使用的工具:[Cursor/VSCode/Trae 等] +- 技术栈:[React/Vue/原生 JS 等] +- 我的学习阶段:[刚开始/有一定基础等] + +### 问题详细描述 + +**预期行为:** +[我想要实现什么功能] + +**实际行为:** +[实际发生了什么] +[有没有错误提示?具体内容是什么?] + +**复现步骤:** + +1. [第一步操作] +2. [第二步操作] +3. [问题出现的步骤] + +### 错误信息 + +**控制台错误:** +[粘贴完整的错误堆栈信息] + +**Network 错误(如果有):** +[粘贴请求和响应的详细信息] + +### 相关代码 + +[粘贴你的代码,最好包含上下文] + +### 我已经尝试过的方法 + +1. [方法 1] - 结果:[成功/失败/没有变化] +2. [方法 2] - 结果:[成功/失败/没有变化] +3. [方法 3] - 结果:[成功/失败/没有变化] + +### 其他补充信息 + +- [任何你觉得可能相关的信息] +- [比如:这个问题是最近才出现的,之前正常] +- [或者:只在特定浏览器/设备上出现] +``` + +--- + +## 快速诊断流程图 + +遇到问题不知所措?试着按这个流程走一遍: + +1. **页面显示异常?** -> 是 -> 打开控制台看 Console 错误 (参考 B.1)。 +2. **点击没反应?** -> 是 -> 检查事件绑定和函数调用 (参考 B.4)。 +3. **数据不保存?** -> 是 -> 检查异步逻辑和存储方法 (参考 B.2)。 +4. **样式不对?** -> 是 -> 检查 CSS 引入和类名匹配 (参考 B.3)。 +5. **API 调用失败?** -> 是 -> 查看 Network 响应码和错误信息 (参考 B.5)。 +6. **以上都不是?** -> 使用完整模板向 AI 求助 (参考 B.6)。 + +--- + +## 调试心态建议 + +最后,保持良好的心态至关重要。 +**不要慌张**,错误是编程学习的必经之路,资深开发者每天也会遇到无数 bug。 +**系统排查**,按照流程一步步缩小问题范围,不要像无头苍蝇一样乱试。 +**记录问题**,把解决过的 bug 记下来,下次再遇到就胸有成竹了。 +**善用 AI**,AI 是你 24 小时待命的结对编程伙伴,学会向它清晰地描述问题。 +**保持耐心**,有些 bug 确实很难缠,休息一下,换个思路,往往会有转机。 + +--- + +## 还是不行? + +如果你试遍了所有方法还是不行: + +1. **截图保存**:把错误信息、代码、界面都截图保存下来。 +2. **整理问题**:用上面的模板把问题整理清楚。 +3. **寻求帮助**:带着整理好的信息,向 AI、学习群或技术社区求助。 +4. **休息一下**:有时候离开屏幕,喝杯水,大脑后台会自动处理问题,回来后说不定就有灵感了。 + +**记住:每一个错误都是学习的机会,解决它的过程就是你变强的过程!** diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/Log in.yml b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/Log in.yml new file mode 100644 index 0000000..ff55268 --- /dev/null +++ b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/Log in.yml @@ -0,0 +1,504 @@ +app: + description: '' + icon: 🤖 + icon_background: '#FFEAD5' + mode: advanced-chat + name: Log in + use_icon_as_answer_icon: false +dependencies: +- current_identifier: null + type: marketplace + value: + marketplace_plugin_unique_identifier: langgenius/gitee_ai:0.1.4@f621ace33bb3c140f5a1e3533fcb518f558c7b945d63523c0f85810a4b4a8b93 +kind: app +version: 0.3.0 +workflow: + conversation_variables: + - description: '' + id: f8cc215e-ef91-437a-a823-7e80a8d345a3 + name: LOGIN + selector: + - conversation + - LOGIN + value: none + value_type: string + environment_variables: [] + features: + file_upload: + allowed_file_extensions: + - .JPG + - .JPEG + - .PNG + - .GIF + - .WEBP + - .SVG + allowed_file_types: + - image + allowed_file_upload_methods: + - local_file + - remote_url + enabled: false + fileUploadConfig: + audio_file_size_limit: 50 + batch_count_limit: 5 + file_size_limit: 15 + image_file_size_limit: 10 + video_file_size_limit: 100 + workflow_file_upload_limit: 10 + image: + enabled: false + number_limits: 3 + transfer_methods: + - local_file + - remote_url + number_limits: 3 + opening_statement: 'Please log in with passwords:' + retriever_resource: + enabled: true + sensitive_word_avoidance: + enabled: false + speech_to_text: + enabled: false + suggested_questions: [] + suggested_questions_after_answer: + enabled: false + text_to_speech: + enabled: false + language: '' + voice: '' + graph: + edges: + - data: + sourceType: llm + targetType: answer + id: llm-answer + source: llm + sourceHandle: source + target: answer + targetHandle: target + type: custom + - data: + isInIteration: false + isInLoop: false + sourceType: start + targetType: if-else + id: 1758767725822-source-1758767750205-target + source: '1758767725822' + sourceHandle: source + target: '1758767750205' + targetHandle: target + type: custom + zIndex: 0 + - data: + isInIteration: false + isInLoop: false + sourceType: if-else + targetType: assigner + id: 1758767920912-true-1758768026915-target + source: '1758767920912' + sourceHandle: 'true' + target: '1758768026915' + targetHandle: target + type: custom + zIndex: 0 + - data: + isInIteration: false + isInLoop: false + sourceType: if-else + targetType: assigner + id: 1758767920912-false-1758768059939-target + source: '1758767920912' + sourceHandle: 'false' + target: '1758768059939' + targetHandle: target + type: custom + zIndex: 0 + - data: + isInLoop: false + sourceType: if-else + targetType: llm + id: 1758767750205-f599486b-e4d3-4cdd-9425-31257bf28e82-llm-target + source: '1758767750205' + sourceHandle: f599486b-e4d3-4cdd-9425-31257bf28e82 + target: llm + targetHandle: target + type: custom + zIndex: 0 + - data: + isInIteration: false + isInLoop: false + sourceType: if-else + targetType: llm + id: 1758767750205-5f242bc3-7f06-4a88-82e5-235a859d92bf-1758768238460-target + source: '1758767750205' + sourceHandle: 5f242bc3-7f06-4a88-82e5-235a859d92bf + target: '1758768238460' + targetHandle: target + type: custom + zIndex: 0 + - data: + isInIteration: false + isInLoop: false + sourceType: llm + targetType: answer + id: 1758768238460-source-1758768309599-target + source: '1758768238460' + sourceHandle: source + target: '1758768309599' + targetHandle: target + type: custom + zIndex: 0 + - data: + isInLoop: false + sourceType: if-else + targetType: if-else + id: 1758767750205-true-1758767920912-target + source: '1758767750205' + sourceHandle: 'true' + target: '1758767920912' + targetHandle: target + type: custom + zIndex: 0 + - data: + isInIteration: false + isInLoop: false + sourceType: assigner + targetType: answer + id: 1758768026915-source-1758768400561-target + source: '1758768026915' + sourceHandle: source + target: '1758768400561' + targetHandle: target + type: custom + zIndex: 0 + - data: + isInIteration: false + isInLoop: false + sourceType: assigner + targetType: answer + id: 1758768059939-source-1758768418040-target + source: '1758768059939' + sourceHandle: source + target: '1758768418040' + targetHandle: target + type: custom + zIndex: 0 + nodes: + - data: + desc: '' + selected: false + title: Start + type: start + variables: [] + height: 53 + id: '1758767725822' + position: + x: -227.17718464443863 + y: 459.4548203041172 + positionAbsolute: + x: -227.17718464443863 + y: 459.4548203041172 + selected: false + sourcePosition: right + targetPosition: left + type: custom + width: 243 + - data: + context: + enabled: false + variable_selector: [] + desc: '' + memory: + query_prompt_template: '{{#sys.query#}}' + role_prefix: + assistant: '' + user: '' + window: + enabled: false + size: 10 + model: + completion_params: + temperature: 0.7 + mode: chat + name: Qwen3-235B-A22B-Instruct-2507 + provider: langgenius/gitee_ai/gitee_ai + prompt_template: + - id: 2686a731-f250-46f0-97ec-033e929160a5 + role: system + text: 'You are the computer that answers the user''s question. Always start + with "hello guest" ' + selected: false + title: Guest LLM + type: llm + variables: [] + vision: + enabled: false + height: 89 + id: llm + position: + x: 389.3839309072489 + y: 663.6856819774588 + positionAbsolute: + x: 389.3839309072489 + y: 663.6856819774588 + selected: false + sourcePosition: right + targetPosition: left + type: custom + width: 243 + - data: + answer: '{{#llm.text#}}' + desc: '' + selected: true + title: Answer + type: answer + variables: [] + height: 104 + id: answer + position: + x: 707.3520684153225 + y: 673.6318886739399 + positionAbsolute: + x: 707.3520684153225 + y: 673.6318886739399 + selected: true + sourcePosition: right + targetPosition: left + type: custom + width: 243 + - data: + cases: + - case_id: 'true' + conditions: + - comparison_operator: is + id: cf0932c4-e5f4-478e-9437-1db63af30ffd + value: none + varType: string + variable_selector: + - conversation + - LOGIN + id: 'true' + logical_operator: and + - case_id: f599486b-e4d3-4cdd-9425-31257bf28e82 + conditions: + - comparison_operator: is + id: 18c716ea-aac5-4af7-9a50-1fd5dc40d18e + value: guest + varType: string + variable_selector: + - conversation + - LOGIN + id: f599486b-e4d3-4cdd-9425-31257bf28e82 + logical_operator: and + - case_id: 5f242bc3-7f06-4a88-82e5-235a859d92bf + conditions: + - comparison_operator: is + id: 490f9251-1012-4f85-8bb7-29f355ca6b5c + value: admin + varType: string + variable_selector: + - conversation + - LOGIN + id: 5f242bc3-7f06-4a88-82e5-235a859d92bf + logical_operator: and + desc: '' + selected: false + title: IF/ELSE + type: if-else + height: 221 + id: '1758767750205' + position: + x: 78.91702348010949 + y: 535.9787937998216 + positionAbsolute: + x: 78.91702348010949 + y: 535.9787937998216 + selected: false + sourcePosition: right + targetPosition: left + type: custom + width: 243 + - data: + cases: + - case_id: 'true' + conditions: + - comparison_operator: is + id: ab112997-31e2-453c-8511-40adc3006e76 + value: AIID + varType: string + variable_selector: + - sys + - query + id: 'true' + logical_operator: and + desc: '' + selected: false + title: IF/ELSE 2 + type: if-else + height: 125 + id: '1758767920912' + position: + x: 659.9247584894487 + y: 459.4548203041172 + positionAbsolute: + x: 659.9247584894487 + y: 459.4548203041172 + selected: false + sourcePosition: right + targetPosition: left + type: custom + width: 243 + - data: + desc: '' + items: + - input_type: constant + operation: set + value: admin + variable_selector: + - conversation + - LOGIN + write_mode: over-write + selected: false + title: Variable Assigner + type: assigner + version: '2' + height: 87 + id: '1758768026915' + position: + x: 997.3839309072489 + y: 426.91916104676926 + positionAbsolute: + x: 997.3839309072489 + y: 426.91916104676926 + selected: false + sourcePosition: right + targetPosition: left + type: custom + width: 243 + - data: + desc: '' + items: + - input_type: constant + operation: set + value: guest + variable_selector: + - conversation + - LOGIN + write_mode: over-write + selected: false + title: Variable Assigner 2 + type: assigner + version: '2' + height: 87 + id: '1758768059939' + position: + x: 1010.8775065168395 + y: 553.9191610467692 + positionAbsolute: + x: 1010.8775065168395 + y: 553.9191610467692 + selected: false + sourcePosition: right + targetPosition: left + type: custom + width: 243 + - data: + context: + enabled: false + variable_selector: [] + desc: '' + model: + completion_params: + temperature: 0.7 + mode: chat + name: Qwen3-235B-A22B-Instruct-2507 + provider: langgenius/gitee_ai/gitee_ai + prompt_template: + - id: 1129723a-50cb-4350-a118-3b9ac6dac523 + role: system + text: 'You are the computer that answers the admin''s question. Always start + with "hello admin" . You know AIID(AI innovative Design) is a master program + in open FIESTA in Shenzhen. ' + selected: false + title: Admin LLM + type: llm + variables: [] + vision: + enabled: false + height: 89 + id: '1758768238460' + position: + x: 389.3839309072489 + y: 792.6856819774588 + positionAbsolute: + x: 389.3839309072489 + y: 792.6856819774588 + selected: false + sourcePosition: right + targetPosition: left + type: custom + width: 243 + - data: + answer: '{{#1758768238460.text#}}' + desc: '' + selected: false + title: Answer 3 + type: answer + variables: [] + height: 104 + id: '1758768309599' + position: + x: 707.3520684153225 + y: 832.4705087633828 + positionAbsolute: + x: 707.3520684153225 + y: 832.4705087633828 + selected: false + sourcePosition: right + targetPosition: left + type: custom + width: 243 + - data: + answer: Password Correct! You are now log in as ADMIN + desc: '' + selected: false + title: Answer 3 + type: answer + variables: [] + height: 117 + id: '1758768400561' + position: + x: 1301.383930907249 + y: 426.91916104676926 + positionAbsolute: + x: 1301.383930907249 + y: 426.91916104676926 + selected: false + sourcePosition: right + targetPosition: left + type: custom + width: 243 + - data: + answer: Password Incorrect! You are now log in as GUEST + desc: '' + selected: false + title: Answer 4 + type: answer + variables: [] + height: 117 + id: '1758768418040' + position: + x: 1498.8808102839819 + y: 553.9191610467692 + positionAbsolute: + x: 1498.8808102839819 + y: 553.9191610467692 + selected: false + sourcePosition: right + targetPosition: left + type: custom + width: 243 + viewport: + x: 273.4245102591761 + y: -8.654295375493462 + zoom: 0.7525860587977332 diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/Love Loop.yml b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/Love Loop.yml new file mode 100644 index 0000000..1e5d6cb --- /dev/null +++ b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/Love Loop.yml @@ -0,0 +1,388 @@ +app: + description: '' + icon: 🤖 + icon_background: '#FFEAD5' + mode: advanced-chat + name: Love Loop + use_icon_as_answer_icon: false +dependencies: +- current_identifier: null + type: marketplace + value: + marketplace_plugin_unique_identifier: langgenius/gitee_ai:0.1.4@f621ace33bb3c140f5a1e3533fcb518f558c7b945d63523c0f85810a4b4a8b93 +kind: app +version: 0.3.0 +workflow: + conversation_variables: + - description: '' + id: 411d934a-94cb-4899-a892-31300f69228e + name: words + selector: + - conversation + - words + value: love + value_type: string + - description: '' + id: 7aca1d78-2dbc-4ccf-8428-0f0eed7b203c + name: WORDS + selector: + - conversation + - WORDS + value: '' + value_type: string + environment_variables: [] + features: + file_upload: + allowed_file_extensions: + - .JPG + - .JPEG + - .PNG + - .GIF + - .WEBP + - .SVG + allowed_file_types: + - image + allowed_file_upload_methods: + - local_file + - remote_url + enabled: false + fileUploadConfig: + audio_file_size_limit: 50 + batch_count_limit: 5 + file_size_limit: 15 + image_file_size_limit: 10 + video_file_size_limit: 100 + workflow_file_upload_limit: 10 + image: + enabled: false + number_limits: 3 + transfer_methods: + - local_file + - remote_url + number_limits: 3 + opening_statement: '' + retriever_resource: + enabled: true + sensitive_word_avoidance: + enabled: false + speech_to_text: + enabled: false + suggested_questions: [] + suggested_questions_after_answer: + enabled: false + text_to_speech: + enabled: false + language: '' + voice: '' + graph: + edges: + - data: + isInIteration: false + isInLoop: true + loop_id: '1758765136208' + sourceType: loop-start + targetType: llm + id: 1758765136208start-source-1758765344915-target + source: 1758765136208start + sourceHandle: source + target: '1758765344915' + targetHandle: target + type: custom + zIndex: 1002 + - data: + isInLoop: false + sourceType: loop + targetType: answer + id: 1758765136208-source-answer-target + source: '1758765136208' + sourceHandle: source + target: answer + targetHandle: target + type: custom + zIndex: 0 + - data: + isInIteration: false + isInLoop: true + loop_id: '1758765136208' + sourceType: llm + targetType: code + id: 1758765344915-source-1758765883132-target + source: '1758765344915' + sourceHandle: source + target: '1758765883132' + targetHandle: target + type: custom + zIndex: 1002 + - data: + isInIteration: false + isInLoop: true + loop_id: '1758765136208' + sourceType: code + targetType: assigner + id: 1758765883132-source-1758765428475-target + source: '1758765883132' + sourceHandle: source + target: '1758765428475' + targetHandle: target + type: custom + zIndex: 1002 + - data: + isInIteration: false + isInLoop: false + sourceType: start + targetType: assigner + id: 1758764476473-source-1758765920251-target + source: '1758764476473' + sourceHandle: source + target: '1758765920251' + targetHandle: target + type: custom + zIndex: 0 + - data: + isInLoop: false + sourceType: assigner + targetType: loop + id: 1758765920251-source-1758765136208-target + source: '1758765920251' + sourceHandle: source + target: '1758765136208' + targetHandle: target + type: custom + zIndex: 0 + nodes: + - data: + desc: '' + selected: false + title: Start + type: start + variables: [] + height: 54 + id: '1758764476473' + position: + x: 115.88661184766386 + y: 178.92252604934293 + positionAbsolute: + x: 115.88661184766386 + y: 178.92252604934293 + selected: false + sourcePosition: right + targetPosition: left + type: custom + width: 244 + - data: + answer: '{{#conversation.words#}}' + desc: '' + selected: false + title: Answer + type: answer + variables: [] + height: 105 + id: answer + position: + x: 1456.1539893939312 + y: 178.92252604934293 + positionAbsolute: + x: 1456.1539893939312 + y: 178.92252604934293 + selected: false + sourcePosition: right + targetPosition: left + type: custom + width: 244 + - data: + break_conditions: [] + desc: '' + error_handle_mode: terminated + height: 462 + logical_operator: and + loop_count: 5 + loop_variables: [] + selected: false + start_node_id: 1758765136208start + title: Loop + type: loop + width: 682 + height: 462 + id: '1758765136208' + position: + x: 731.5560922291256 + y: 187.5878472722298 + positionAbsolute: + x: 731.5560922291256 + y: 187.5878472722298 + selected: false + sourcePosition: right + targetPosition: left + type: custom + width: 682 + zIndex: 1 + - data: + desc: '' + isInLoop: true + selected: false + title: '' + type: loop-start + draggable: false + height: 48 + id: 1758765136208start + parentId: '1758765136208' + position: + x: 24 + y: 68 + positionAbsolute: + x: 755.5560922291256 + y: 255.5878472722298 + selectable: false + sourcePosition: right + targetPosition: left + type: custom-loop-start + width: 44 + zIndex: 1002 + - data: + context: + enabled: false + variable_selector: [] + desc: '' + isInIteration: false + isInLoop: true + loop_id: '1758765136208' + model: + completion_params: + temperature: 0.7 + mode: chat + name: Qwen3-235B-A22B-Instruct-2507 + provider: langgenius/gitee_ai/gitee_ai + prompt_template: + - id: e27d2ef8-3dc0-4fbf-8866-90ec3f10c758 + role: system + text: write a word with a similar meaning to the words user input. + - id: 624597ef-8e03-49c7-8365-4b17dc487032 + role: user + text: '{{#conversation.words#}}' + selected: false + title: LLM 2 + type: llm + variables: [] + vision: + enabled: false + height: 90 + id: '1758765344915' + parentId: '1758765136208' + position: + x: 114.28909334084415 + y: 65 + positionAbsolute: + x: 845.8451855699698 + y: 252.5878472722298 + selected: true + sourcePosition: right + targetPosition: left + type: custom + width: 244 + zIndex: 1002 + - data: + desc: '' + isInIteration: false + isInLoop: true + items: + - input_type: variable + operation: over-write + value: + - '1758765883132' + - result + variable_selector: + - conversation + - words + write_mode: over-write + loop_id: '1758765136208' + selected: false + title: Variable Assigner + type: assigner + version: '2' + height: 88 + id: '1758765428475' + parentId: '1758765136208' + position: + x: 418.79897041375784 + y: 194.04290759019386 + positionAbsolute: + x: 1150.3550626428835 + y: 381.63075486242366 + selected: false + sourcePosition: right + targetPosition: left + type: custom + width: 244 + zIndex: 1002 + - data: + code: "\ndef main(arg1: str, arg2: str) -> dict:\n return {\n \"\ + result\": arg1 +arg2 ,\n }\n" + code_language: python3 + desc: '' + isInIteration: false + isInLoop: true + loop_id: '1758765136208' + outputs: + result: + children: null + type: string + selected: false + title: Connect + type: code + variables: + - value_selector: + - conversation + - words + variable: arg1 + - value_selector: + - '1758765344915' + - text + variable: arg2 + height: 54 + id: '1758765883132' + parentId: '1758765136208' + position: + x: 111.09640498433282 + y: 202.0812369434865 + positionAbsolute: + x: 842.6524972134584 + y: 389.6690842157163 + selected: false + sourcePosition: right + targetPosition: left + type: custom + width: 244 + zIndex: 1002 + - data: + desc: '' + items: + - input_type: variable + operation: over-write + value: + - sys + - query + variable_selector: + - conversation + - words + write_mode: over-write + selected: false + title: define words + type: assigner + version: '2' + height: 88 + id: '1758765920251' + position: + x: 404.0977808713518 + y: 178.92252604934293 + positionAbsolute: + x: 404.0977808713518 + y: 178.92252604934293 + selected: false + sourcePosition: right + targetPosition: left + type: custom + width: 244 + viewport: + x: 59.39316938104503 + y: 131.3127545416781 + zoom: 0.5431072229827936 diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/chapter3-getting-started-with-dify-and-its-knowledge-base-integration.md b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/chapter3-getting-started-with-dify-and-its-knowledge-base-integration.md new file mode 100644 index 0000000..c6924dc --- /dev/null +++ b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/chapter3-getting-started-with-dify-and-its-knowledge-base-integration.md @@ -0,0 +1,1044 @@ +# Project 3: Dify 入门与知识库集成 + +# 回顾上节课 + +在前几节课中,我们分组学习了 AI 编程、提示词工程以及 AI 图像生成的基础知识。这些内容帮助我们初步了解了不同大语言模型(LLM,Large Language Model)或生成式模型的边界和能力。 + +为了帮助你回顾上节课的内容,下面有几个小问题可以思考: + +1. 什么是 AI 编程?如何使用 AI 编程工具(例如 [z.ai](http://z.ai))来创建一个网页? +2. 什么是大语言模型?什么是提示词工程和上下文工程?你该如何编写一个复杂的提示词? +3. 对于文本、AI Coding、图像生成的三个不同方向,你认为模型能力的强弱分别体现在什么地方? +4. 什么是 API?如何使用 [z.ai](http://z.ai) 接入第三方 API ? + +如果你对其中任何一个问题还感到疑惑,可以回看上节课的文档,也可以直接在微信群里提问。 + +在这节课中,我们将从简单的 AI 文字图片工具,进入更接近公司业务落地的工作流搭建平台。从对话机器人走向 AI 智能体、AI 工作流,并基于 API 把它变成可交互的“智能”机器人页面。 + +在操作过程中,如果遇到难以理解的步骤,请不要担心,推荐你随时对当前所在的操作页面进行截图,发送给大模型进行询问;当前大模型已能够解答大部分常见问题。 + +如果提问后仍无法解决,不妨大胆尝试操作;不必害怕出错,每一次尝试都是学习和进步的机会。随着实践次数的增加,你会越来越熟练,操作也会越来越得心应手! + +# 本节课你将学到 + +1. 为什么需要从聊天机器人走向智能体和 Workflow 编排。 +2. 什么是智能体与工作流开发平台,如何把 AI 的能力 SOP 化与可编排化。 +3. 什么是 Dify,如何用这个面向 LLM 应用的开源平台快速搭建应用,尤其是知识库问答机器人。 +4. RAG 的实现方法与价值,为什么需要检索增强生成? +5. 如何从 0 到 1 学会使用 Dify 和 AI IDE Trae (`Extra Knowledge 4 - What is AI IDE and Trae`),包括搭建 智能体、工作流,并基于 Dify API 制作前端对话机器人网页程序。 + +- Dify 的基本使用原理与智能体、工作流制作方法,API 调用方法。 +- AI IDE 的使用方法,如何使用 AI IDE 编程。 +- 一个可进行对话的前端网页智能体程序。 + +# 1. 从对话到智能体 + +在上一阶段,我们学会了如何用提示词让大模型扮演角色、生成文本或编写简单代码。但如果你仔细思考,会发现一个问题,聊天机器人本身并不能做事。 + +它能回答怎么查订单?,却不能真的去数据库里查对应的数字;它能描述一封周报应该包含什么,却无法自动汇总你的项目数据并发送邮件。这种“只说不做”的局限,使得纯对话式 AI 难以真正融入业务流程。 + +要让 AI 从聊天伙伴升级为数字员工,我们需要赋予它三项核心能力: + +1. 专属知识——让它能够通读并了解你的产品文档、客户资料、内部制度; +2. 工具调用(或者叫插件)——让它能操作数据库、调用 API; +3. 结构化执行——让它按预设逻辑一步步完成任务,而非自由发挥。 + +这就是 AI 智能体(AI Agent)的雏形:一个具备目标、知识、工具和执行路径的自动化单元。 + +![](images/image1.png) + +> 注意:当前业界所说的简单版本的“智能体”,大多指基于 LLM + 工具 + 知识库组合而成的增强型应用,并非所谓能够自主规划的智能体。简单的智能体虽不具备真正的推理与长期规划能力,但已足以支撑大量企业级自动化场景。我们将会在之后的章节详细介绍真正的具备自主规划和行动能力的智能体。 + +## 1.1 最简单的智能体:基于知识库的问答机器人 + +在明确智能体应具备的多项核心能力后,一个值得思考的问题随之而来:能否仅通过实现其中某一项最简单的功能,就构建出一个真正可用的基础智能体? 答案是肯定的。 + +事实上,在大量实际业务场景中,用户的核心诉求并非让 AI 自动执行复杂操作(如调用 API 或跨系统协调任务),而是希望它能基于企业自身的专属资料,提供精准、可靠的问答支持。这恰好对应智能体三大核心能力中的第一项,专属知识服务能力。因此,我们得以引出智能体最简单、也最广泛应用的形态:基于知识库的问答机器人。 + +虽然它尚未具备工具调用或自主规划能力,但其关键突破在于:让大模型的回答不再凭空生成,而是有据可依。如何实现?关键就在于解决核心挑战:企业内置大量文档知识,当存在千上万页文档时,模型如何在每一轮对话中快速找到与当前问题最相关的内容? + +此时的一个解决方案是:检索增强生成(Retrieval-Augmented Generation, RAG)。 + +RAG 的基本思路是:在用户提问时,系统首先从企业知识库中检索出与问题语义最相关的若干文本片段(例如产品手册中的某一段、HR制度中的某一条款),然后将这些片段作为上下文“注入”到大模型的输入中,引导它基于真实资料生成回答。 + +![](images/image2.png) + +图片来源:[https://www.datacamp.com/blog/what-is-retrieval-augmented-generation-rag](https://www.datacamp.com/blog/what-is-retrieval-augmented-generation-rag) + +这样一来,模型的回答不再是依赖其训练数据中的泛化知识,而是锚定在企业提供的权威信息之上。RAG 的目标,正是通过这种外部知识的动态注入,显著提升回答的真实性、准确性和一致性——甚至可以让回答“符合人设”,比如以客服口径或技术文档风格作答。 + +在实际业务中,这项技术尤为重要,因为大模型常常会产生“幻觉”。例如,若你以 CFO 或咨询顾问的身份询问某个时间段的具体数据,模型很可能编造日期和事件。引入 RAG 后,回答的可控性与可靠性将得到显著提升。 + +![](images/image3.png) + +图片来源:[https://www.databricks.com/glossary/retrieval-augmented-generation-rag](https://www.databricks.com/glossary/retrieval-augmented-generation-rag) + +在本节课的实操环节中,我们将使用流行的 AI 工作流平台 Dify,动手搭建一个基于知识库的问答机器人。你可以轻松将各种类型的专属资料,如产品手册、公司制度、项目文档、研究论文、知识库文章,甚至是个人笔记集构建为知识库。 + +完成搭建后,你可以尝试提出各类问题来检验它的能力,例如: + +- “我们产品A的最新版本有哪些主要功能升级?” +- “请根据员工手册,说明今年的年假制度是如何规定的?” +- “在XX项目中,我们遇到的技术挑战‘XXX’是如何解决的?” +- “这篇论文中提到的核心研究方法是什么?” + +你将亲身感受 RAG 技术如何将静态分散的文档资料,转化为一个精准的智能知识库,为各种场景提供高精度问答支持。 + +## 1.2 从对话智能体到工作流 + +然而,即使是加入了知识库甚至是插件调用能力的“增强型智能体”,在面对更复杂的业务流程时仍显不足。 + +试想这样一个用户请求:“我们新上线的 SaaS 产品最近有哪些功能更新?能帮我整理成一份给客户的简报吗?” + +这个请求看似简单,背后却需要多个协同步骤:首先从内部产品文档或 Notion 知识库中检索最近一个月的功能发布记录;然后过滤出面向客户的关键特性;接着调用大模型将技术描述转化为客户友好的语言;最后通过将生成内容推送至市场团队的邮箱,或保存到 Google Docs 模板中。 + +如果仅靠一个大语言模型自由推理,先不说是否能够一次对话实现所有过程,就算能,其中也很容易遗漏关键信息、混淆内部术语与客户语言,或无法结构化输出。更重要的是,企业需要的是可审计、可复用、可监控的标准化执行路径,而不是每次依赖模型的临时发挥,可监控可复现对企业而言非常重要,非预期的结果很可能会带来预期外的严重损失。 + +这就引出了更高阶的 AI 应用范式:AI 工作流(AI Workflow)。 + +![](images/image4.png) + +工作流是指将一个复杂任务拆解为多个有序、可配置、可自动执行的子步骤,并通过可视化或代码方式编排它们之间的逻辑关系,如条件判断、循环或并行执行。将 AI 能力 SOP 化(即标准化操作流程),意味着把如何用 AI 完成某项任务的经验固化为可重复使用的模板。 + +这种做法带来了多重价值:非技术人员(如产品经理或运营)可以通过拖拽组件快速搭建 AI 应用;开发者可以将 RAG 检索、LLM 调用、API 工具等封装为标准节点,在不同业务场景中复用;整个流程还可被完整追踪、调试和持续优化,满足企业对稳定性与合规性的要求。 + +AI 工作流的使用人群非常广泛。产品经理无需写代码,即可设计完整的用户交互路径;运营人员能快速搭建客服机器人、内容生成器或通知系统;开发者和算法工程师则可将核心能力模块化,供前端调用;创业者或独立开发者也能以极低成本验证 AI 产品的 MVP,几天内上线一个包含数据查询、内容生成与动作执行的完整原型。 + +此外,值得注意的是,AI 工作流通常可用一种中间表示(Intermediate Representation)来描述。不同工作流平台的具体表达方式虽有差异,但大多采用结构化文件(如 JSON、YAML 等)来定义节点类型、输入输出及执行逻辑,其结构类似下图所示: + +![](images/image5.png) + +简言之,如果说智能体让 AI 从会聊天走向能做事,那么工作流则让 AI 从偶尔做成一件事迈向“稳定、可靠、规模化地完成一类事。在接下来的实践中,我们还将借助 Dify 平台,上手并亲手构建完整的 AI 工作流,体验从想法到可运行应用的完整过程。 + +## 1.3 常用智能体 / 工作流平台 + +随着生成式 AI 技术的飞速发展,为帮助开发者与业务人员快速构建智能体与自动化流程,避免陷入编程的复杂细节,一批低代码甚至无代码的智能体及工作流平台应运而生。 + +首先需要明确的是,低代码平台是指通过可视化拖拽组件、预置业务逻辑模板、图形化配置规则等方式,显著减少手动编码工作量的开发工具。其核心在于以可视化配置,节点式拖动变成的方式替代直接写代码的方式,既能让具备一定技术能力的开发者从重复劳动中解放出来,也能让熟悉业务逻辑的非技术人员参与到应用搭建中。本质上,它是在开发效率与场景灵活性之间架起一座平衡的桥梁。 + +这类低代码/无代码智能体平台的突出价值,正是大幅降低 AI 应用的开发门槛。以往需要团队协作数周——从需求梳理、代码开发到测试部署——才能完成的 AI 智能体(如客服问答机器人、数据处理助手),现在借助平台提供的可视化工具,可将“从创意到上线”的周期缩短至数小时。 + +目前市面上主流的低代码 AI 工作流平台包括: + +| 平台 | 特点 | 适用场景 | +| --------------------------------------------- | -------------------------------------------------- | -------------------------------------- | +| Dify | 开源、支持知识库 RAG、LLM 编排、API 输出,中文友好 | 企业知识库问答、定制化 Agent、API 服务 | +| Coze(字节跳动) | 国内可用、集成抖音/飞书生态、插件丰富 | 社交机器人、国内小程序集成 | +| n8n | 通用自动化工具,支持 AI 节点,强调 API 编排 | 跨系统数据同步、AI + 传统 SaaS 自动化 | +| 百度千帆 AppBuilder / 阿里百炼 / 腾讯 HunYuan | 大厂云原生方案,集成自家模型 | 企业级部署、合规要求高场景 | + +目前市面上的低代码 AI 工作流平台选择丰富。尽管 AWS、Azure、阿里云等主流云厂商均推出了相应的 AI 工作流解决方案,但 Dify、Coze 和 n8n 凭借以下三大核心优势,成为当前应用最广泛的代表: + +1. 极致易用性。平台采用可视化拖拽式界面设计,用户无需深入理解底层技术,即可快速上手。 +2. 高灵活性。支持自定义组件与扩展 API 接口,既能适应教学演示、MVP(最小可行产品)验证等轻量场景,也能满足中小型团队的敏捷迭代需求。 +3. 成熟生态。不仅官方文档详尽、响应及时,还拥有活跃的用户社区,便于快速获取来自不同用户的预设方案。 + +这三大平台均支持将搭建好的 AI 智能体以标准化 API 接口的形式输出,可无缝集成至前端 Web 应用、企业内部 ERP 系统或移动端 APP 中,进一步降低了 AI 能力落地的技术门槛。 + +### 1.3.1 Dify:企业级LLMOps与应用生命周期管理平台 + +Dify 定位是LLM应用开发与运营平台,致力于提供AI应用从构思、部署到优化的全生命周期管理。其核心是一个低代码平台,旨在帮助开发者和非技术背景的创新者快速构建生产级AI应用。 + +![](images/image6.png) + +在功能上,Dify覆盖了可视化工作流编排、智能体构建、知识库管理、多模型支持等功能。平台允许通过拖拽节点设计复杂任务流程,并支持创建基于意图的Agent。其知识库功能突出,能处理多种格式文档并进行高效的向量检索。同时,Dify兼容支持包括GPT、Claude及众多开源模型在内的多种LLM,构建的应用可一键发布为标准API便于集成。 + +![](images/image7.png) + +技术架构方面,Dify以开源和可私有化部署为特色,强调灵活性、扩展性及企业级合规。目标用户包括开发者团队和业务创新者,典型应用场景涵盖企业知识库与智能客服、内容创作自动化、垂直领域AI助手以及企业AI中台。 + +### 1.3.2 Coze(字节跳动):零代码AI智能体构建的普及者 + +Coze是字节跳动推出的AI智能体开发平台,以极致易用性为核心,让无编程经验的用户也能轻松创建、调试并发布功能丰富的AI聊天机器人。 + +![](images/image8.png) + +其核心是将Bot构建简化为搭积木式操作。用户可通过界面轻松配置角色与知识库,并利用丰富的内置插件库为Bot添加新闻、旅游、图像生成等多类外部能力。创建好的Bot可一键快速发布至豆包、飞书、微信公众号等多个平台。 + +![](images/image9.png) + +技术架构完全服务于低门槛使用,后端集成字节自有模型并封装复杂流程,强调多模态理解与实时响应。作为一个主要以云服务形式提供的平台,其私有化部署能力相对有限。典型应用场景包括个人助理与娱乐Bot、智能客服与问答系统、在线教育助手以及快速原型验证。 + +### 1.3.2 n8n:可编程的后端工作流自动化引擎 + +n8n是一个通用的可编程工作流自动化平台,其核心定位是连接各类应用、数据库与API,实现数据流动与任务自动化执行。 + +它通过庞大的集成节点库支持数百种SaaS服务、数据库及协议,并采用可视化与代码结合的方式:用户可在画布拖拽节点,同时注入JavaScript或Python代码编写自定义逻辑。n8n擅长处理后端数据密集型任务,如数据同步、ETL流程与API编排。 + +![](images/image10.png) + +关键技术特性是“源码可见”和“可自托管”,用户可将其私有化部署以完全掌控数据与环境,这使其对数据安全要求高的行业极具吸引力。其主要目标用户是开发者、技术运营及数据分析师。n8n 最大的优势,在于拥有极其强大的社区生态。网络上拥有随处可见丰富的 n8n 分享视频,为用户提供了便捷的学习参考与经验借鉴;同时,它支持连接 YouTube、Instagram 等全球众多不同生态平台,能够帮助用户轻松打破跨平台数据与服务的壁垒,实现多生态流程的自动化流转。 + +### 1.3.3 其他工作流平台 + +除了上述的几个最知名的平台,中国国内的主要科技厂商也相继推出了各自的一体化AI开发平台,例如:百度千帆 AppBuilder 提供从模型选型、RAG构建到智能体发布的全流程支持,深度集成文心大模型;阿里云百炼基于通义千问系列模型,注重企业级安全与私有化部署能力;腾讯云 TI 平台 则聚焦于金融、医疗等行业场景,提供丰富的预置解决方案模板。这类平台通常与各自云生态深度融合,适合已处于相应技术体系内的企业选用。 + +然而,在通用型、开放性与社区生态方面,Dify 与 Coze 仍凭借其突出的易用性、广泛的模型支持以及活跃的开发者社区,成为当前更受广泛采纳的选择。 + +尽管各平台在定位与生态上各有侧重,其核心逻辑均是通过可视化方式编排与连接不同的能力模块。因此,掌握其中任意一种平台的设计思路与操作方法,即具备快速迁移到其他类似工具的基础。在接下来的实践中,我们将以 Dify 为例进行具体讲解。 + +# 2. 深入浅出 Dify + +## 2.1 什么是 Dify + +我们在之前已经了解了基础的 Dify 的信息介绍,对于更详细的信息,你可以通过 [https://cloud.dify.ai/apps](https://cloud.dify.ai/apps) 访问 Dify 平台,如果想了解更多信息,可以访问官网 https://dify.ai。 + +Dify 是一个用于开发 LLM 应用的开源平台。它提供了直观的界面,将 Agent 工作流、RAG 流水线、工具能力、模型管理、可观测性等功能结合在一起,帮助你快速地从原型走向生产环境。 + +![](images/image11.png) + +你可以在 Dify 中使用大语言模型和各种功能不同的工具来搭建“工作流”。所谓工作流,就是把原本需要你手动一步步完成的操作——例如数据检索、大模型调用、网页搜索、结果过滤、格式整理等——按照业务逻辑串联起来,变成一个自动化、可复用的流程。如果没有工作流,每次你都需要把同样的内容复制粘贴给大模型,非常低效、容易出错,也难以在真实业务中复用。 + +搭建一个工作流,就像在拼搭积木或拼图。你把“大语言模型节点”(负责理解和生成)、各类“工具节点”(负责执行具体动作,例如查数据库、发邮件、翻译文本等)、以及“数据节点”(负责读取、存储信息)像积木一样连接起来。它们会按照你预设的逻辑自动协同工作,而不需要你每次都手动操作。你也可以把它理解成一种“低代码程序”:你只需要通过拖拽的方式,配置输入和输出的路径,就可以实现比较复杂的业务逻辑。 + +举个例子,如果你是一个亚马逊或抖音电商店铺的老板,想要搭建一个 AI 客服系统,可以参考下图的结构设计一个工作流: + +1. 触发节点(类似 START):接收用户的咨询问题,例如“这个商品的质保期有多长?”。 +2. 问题分类节点(类似 QUESTION CLASSIFIER):使用一个模型(例如 GPT)对用户问题进行分类,判断这是售后(比如质保)、使用方法,还是其他类型的问题。 +3. 知识检索节点(类似 KNOWLEDGE RETRIEVAL):根据分类结果,自动访问相应的知识库。如果是关于“质保”的售后问题,就从售后 SOP 知识库中检索与“质保”相关的精确信息。 +4. 大语言模型节点(LLM Node):将用户问题和检索到的知识库内容一起发送给大语言模型(例如 GPT),让它生成一段对用户友好的回复(避免太生硬的技术语气)。 +5. 条件节点:检查大模型生成的回答中是否包含清晰的质保时间(例如“1 年”、“3 年”),如果有则继续下一步,如果没有则让它回复“请提供产品型号”。 +6. 输出节点(类似 ANSWER):将最终答案返回给用户,并自动把本次咨询记录到表格中。 + +![](images/image12.png) + +在整个过程中,你不需要手动去翻知识库、反复调整模型的回答、或单独记录数据——工作流会把这些步骤“连起来自动跑”。并且它非常灵活:例如,如果你之后想加一个新规则“当用户问质保范围时,调用另一个知识库”,只需要在工作流中多加一个条件节点,而无需重构整个系统。 + +这是一个比较简单的工作流示例,但要完全掌握这些能力,对现在的你来说可能还有点难。因此在本节课中,我们从更加基础的知识库智能体开始,后面再逐步学习更复杂的工作流技巧。 + +### 2.1.1 部署属于自己的 Dify(可选) + +本部分内容原本安排在后续课程中详细介绍,但考虑到当前部分学习者可能因网络限制暂时无法访问 Dify 官方网站或云端服务,我们决定提前提供这一可选的学习路径,帮助你顺利推进课程进度。 + +你需要参考该教程入门 Zeabur 部署平台的基本使用方式:[Extra Knowledge 6 - Zeabur: What Is It and How to Deploy Web Applications](https://github.com/datawhalechina/easy-vibe/blob/main/docs/extra/extra6/extra6-zeabur-what-is-it-and-how-to-deploy-web-applications.md) + +![](images/image13.png) + +你需要学习如何在 Zeabur 上部署一个自己的 Dify,部署后进入到对应链接注册并登录后继续跟随下列教程操作即可。 + +注意,不同版本的 Dify 的操作方面和前端界面可能有些许差别,但总体上差别不大,当你发现不同的时候不要慌张,找到类似的接口和入口进行操作即可。 + +## 2.2 创建第一个 Dify Chatbot 应用 + +访问 Dify 首页 [https://cloud.dify.ai/apps](https://cloud.dify.ai/apps) 并注册和登录后,选择 Studio,你会看到如下界面: + +![](images/image14.png) + +在左侧找到 `CREATE APP` 区块,点击 `Create from Blank`。 + +![](images/image15.png) + +![](images/image16.png) + +在 APP Type 中找到 Chatbot(如果一开始没看到,可以点击“查看更多类型”的按钮,然后在完整列表中找到)。选择 Chatbot 之后,在下方输入应用的名称和描述,最后点击创建。 + +![](images/image17.png) + +创建完成后,你会看到类似下面的界面。 + +![](images/image18.png) + +中间区域的 “INSTRUCTIONS” 指的是内置指令,你可以把它理解为默认提示词或系统提示词。 + +中间偏下有一个 “Knowledge” 区域,这就是知识库区域——我们稍后会把自己的知识库上传到这里。 + +右侧是调试窗口,你可以在调整提示词后与 Agent 进行对话,实时查看效果。 + +你可以在 INSTRUCTIONS 区域自由输入角色提示词,观察对话效果;也可以点击 Generate,让大模型自动帮你生成提示词。 + +![](images/image19.png) + +注意右上角会出现许多不同模型的选项,这意味着你可以点击切换不同的对话模型,从而比较它们在语气、逻辑推理、长文本处理等方面的差异,寻找最适合你需求的模型。 + +![](images/image20.png) + +## 2.3 支持自定义模型供应商 + +为充分发挥 Dify 的灵活性,考虑到不同地区访问模型的难度,为满足特定业务需求、成本控制或数据隐私要求,我们常常需要接入自定义模型。Dify 支持配置三类核心模型:大语言模型(LLM)、Embedding 模型和 Rerank 模型。本部分内容将逐步指导你完成这些自定义配置。 + +Dify 能够灵活接入来自 OpenAI、Azure、Anthropic 等主流服务商的模型,同时也全面兼容任何符合 OpenAI API 接口规范的自托管模型或第三方模型。你可以通过安装内置的 OpenAI Compatible 插件以及对各大模型平台定制的插件实现这一操作。 + +详细步骤参考如下,首先我们需要安装对应的插件: + +1. 我们需要安装 `OpenAI-API-compatible` 及 `SiliconFlow` 插件获得对绝大部分大模型和 Embedding 模型的支持,其中前者是对 OpenAI 兼容接口的支持,后者是一个部署了当前绝大部分常见、好用的开源模型的服务站。你可以访问下列网页进行安装: + 1. https://marketplace.dify.ai/plugins/langgenius/openai_api_compatible + 2. https://marketplace.dify.ai/plugins/langgenius/siliconflow +2. 如果你是自己部署的 Dify,你可以在对应系统设置界面进入插件市场进行操作 + +![](images/image21.png) + +![](images/image22.png) + +进入插件市场后,搜索对应的插件名称即可。 + +![](images/image23.png) + +3. 安装结束后,我们能够配置支持新的模型供应商,在设置里的模型提供商部分,我们可以看到目前支持的所有模型商: + ![](images/image24.png) +4. 在开始使用前,需要先完成模型的配置。对于 OpenAI-API-compatible 插件,你可以点击 “Add Model” 来添加并配置任意模型。你可以在 “Model Type” 中选择该模型是LLM还是 Embedding,你需要确保模型的类型被正确配置。 + 你需要写入具体的模型名字、模型 endpoint URL 以及 API Key 才能确保模型启用,如果你初步觉得配置该参数麻烦,你可以直接跳到后者的 SiliconFLow 平台的 Key 配置,或者安装 OpenRouter 等第三方服务商插件进行简单的模型支持配置。(确保服务商内有剩余可使用额度) + + ![](images/image25.png) + + 对于 `SiliconFlow` 插件,只需要点击 Setup 配置 key 后即可使用 Embedding 和 Rerank 模型进行测试,你可以点击 Get you API Key from SiliconFlow 获得鉴权密钥。 + + ![](images/image26.png) + +5. 配置完成后,你可以点击模型列表查看当前支持多少模型,此时已经完成了基础模型的全部配置。 + ![](images/image27.png) + + 其中支持了绝大部分常见的 Embedding 与 Rerank 模型: + + ![](images/image28.png) + + 此时如果你想要修改 Dify 默认使用模型的配置,你还可以点击 System Model Settings 按钮修改默认的所有模型。 + + ![](images/image29.png) + +## 2.4 创建第一个 Dify 知识库 + +到这里,我们已经完成了最简单的 Agent 创建,但它还缺少一个知识库。现在,请点击顶部菜单中的 `Knowledge`,进入知识库创建页面。 + +![](images/image30.png) + +然后点击左侧的 `Create Knowledge`,创建你的第一个知识库。 + +![](images/image31.png) + +在这个界面中,你可以上传多种类型的文件(例如 pdf、txt 等)来构建知识库。可以上传很长的文本,或者把维基百科上的内容复制下来保存成 txt 文件进行上传。本例中,我们会上传一份关于 Elon Musk 的维基百科 txt 文件。 + +点击 Next 后,你会进入 Knowledge Base Settings(知识库设置)页面。这里选项比较多,我们一步一步来看。 + +首先在 **General** 设置中,你可以把这里理解成“文本切分规则”的设置区域。因为我们需要把很长的文本切分成小块,所以必须先定义切分规则。在入门阶段,你只需要关注 **maximum chunk length(最大切分长度)** 。可以尝试设置为 512、2048 或 4096,然后点击 **Preview Chunk** 预览不同设置下的效果。 + +你也可以调整 **Chunk overlap(切片重叠)** 选项。它决定相邻片段之间是否会保留一部分重叠内容。适当的重叠有助于避免重要信息被拆到不同片段而难以理解。 + +![](images/image32.png) + +在设置中还有一个选项叫做 **Chunk using Q&A format in English** 。启用后,系统会使用大语言模型,将知识库的一部分内容转换成问答形式来存储,这在某些场景下可以显著提升检索效果。 + +在真实业务中,根据场景选择合适的切分策略,能够更好地优化检索结果,保证查询能够返回你期望的信息。 + +继续向下滚动页面,你会看到和 Embedding 模型相关的设置。 + +简单解释一下:Embedding 模型的核心功能,是把非结构化数据(例如文本、图片等)转换成计算机能够理解的“数字向量”(Embedding 向量)。通过这种转换,模型能够快速计算不同数据之间的相似度,从而实现语义相近内容的匹配,比如根据用户输入的一句话,找到语义最接近的文档、图片或商品。 + +Embedding 模型的选择会显著影响最终的检索效果(例如匹配准确度、响应速度等)。在这里,我们推荐优先使用 Qwen 0.6B 的 Embedding 模型,你也可以切换到 4B 或 8B 版本,直观对比不同参数规模下检索效果的差异。 + +![](images/image33.png) + +在此处,你还会看到另一个模型设置叫做 **Rerank model** ,默认值是 **Jina-rerank-m0** 。(如果你非校园内的学生,此时你可能会看到 Rerank 模型缺失的报错,你需要在模型处配置 rerank 模型才能在此处启用使用) + +Rerank 模型的主要作用,是对“初步筛选出的候选结果”进行二次、更精细的排序,让和用户需求最匹配的结果排在更靠前的位置,从而显著提升最终结果的相关性和用户体验。 + +简单理解:Rerank 模型就是用来解决“初次筛选不够精细”的问题。例如搜索引擎可能先用较简单的规则检索出 1000 个潜在相关网页,再通过 Rerank 模型,从中挑出最相关的前 10 个展示在第一页。 + +推荐系统同理:它可能首先找出 500 个“可能适合你”的商品,再通过 Rerank 模型排序,让你最可能购买的商品排在列表顶部。 + +![](images/image34.png) + +当所有设置完成后,点击 **Save & Process** ,系统就会进入知识库向量化阶段。在这一阶段,Embedding 模型会把切分后的文本转换为向量表示。 + +![](images/image35.png) + +处理完成后,点击 **Go to document** ,可以查看已经处理完毕并存储好的知识库内容。 + +![](images/image36.png) + +直接点击知识库名称,可以查看每个切片的具体内容。 + +![](images/image37.png) + +在这里,你可以对任意不合适的文本片段进行精确的编辑或删除操作。 + +![](images/image38.png) + +在左侧边栏中,选择 **Retrieval Testing** 可以对知识库进行召回测试,检查检索是否正常工作。每次测试会返回若干相似度最高的切片。 + +![](images/image39.png) + +如果你希望看到更多的切片结果,需要点击 `VECTOR SEARCH` 设置: + +![](images/image40.png) + +![](images/image41.png) + +Top K 指的是向量检索时,返回与查询向量最相似的前 K 个文本切片数量。当前设置为 3,表示会返回相似度最高的 3 段文本。 + +Score Threshold 则是一个“得分阈值”:只有相似度得分大于或等于该阈值(示例中为 0.5)的文本片段才会被返回。这样可以过滤掉相关度较低的内容,让结果更加准确。 + +现在知识库部分就全部准备好了。接下来,点击顶部菜单栏中的 “studio”,找到刚才创建的智能体,为它接入我们已经配置好的知识库。 + +![](images/image42.png) + +![](images/image43.png) + +此时,在每一轮对话中,你都可以在回答中看到被命中的知识库来源。点击对应条目即可查看检索到的具体文本片段。 + +![](images/image44.png) + +![](images/image45.png) + +## 2.5 更多 DIfy 常见操作 + +在掌握基础 Chatbot 和知识库搭建的基础内容后,我们可以深入了解更多有关 Dify 的使用方式。 + +### 2.5.1 工作流的导入与导出 + +还记得之前提到的工作流的中间表示法吗?Dify 支持通过 DSL(Domain Specific Language) 格式导入和导出工作流。DSL 是一种基于 JSON 的标准化描述方式,能够完整保留工作流的节点结构、连接关系和配置参数。你可以很容易导入和导出 DSL 文件,分享工作流给其他人使用,或者导入别人的工作流进行参考。具体而言,我们能够容易在工作台页面看到工作流的导入按钮: + +![](images/image46.png) + +而对于工作流的导出,我们只需要点击单个工作流块的右下角即可找到导出按钮: + +![](images/image47.png) + +通过使用 DSL 文件,你可以轻松地在不同 Dify 实例之间迁移或共享复杂的工作流设计。 + +### 2.5.2 查看更多 Dify 项目 + +如果你觉得自己搭建的工作流或者智能体过于简单,Dify平台提供了丰富的示例项目,帮助你快速了解如何构建复杂应用。这些示例项目涵盖了多种业务场景。你可以点击 Explora 查看别人构建的工作流进行学习。 + +![](images/image48.png) + +## 2.6 创建第一个 Dify Workflow 应用 + +完成了 DIfy 的对话智能体构建入门,我们继续查看如何构建更复杂的 Dify 业务工作流。工作流是Dify将复杂业务逻辑可视化的核心方式,通过它你可以像搭积木一样构建智能流程。你能够完整体会信息如何在不同节点间流转,判断逻辑如何部署,人工干预点设置在哪里,以及最终如何交付一个完整的业务结果。 + +你可以选择从空白处创建,或者直接从模板处创建,此处演示如何从空白处创建工作流: + +![](images/image49.png) + +![](images/image50.png) + +在这里我们会看见两个选择,分别是 Chatflow 与 Workflow,这两者该如何选择呢?关键是你需要理解你所要构建的,其核心是持续对话,还是任务流程。 + +Chatflow 专为对话而设计。它模拟一个具有记忆和上下文理解能力的对话者,非常适合需要多轮交互、状态维持的场景。例如在客服咨询中,它能连贯地理解用户的后续追问,如同一位耐心的服务人员。其流式输出的特性也让交互过程更为自然。简而言之,当你需要构建一个能“交谈”的智能体时,应选择 Chatflow。 + +Workflow 则专注于流程的自动化执行。它像一条预设的流水线,擅长处理一次性输入、多步骤处理、并产生确定性输出的任务。例如,每日定时生成数据报表、批量处理文件或调用系列API。这类任务通常由事件触发,无需与人实时互动。因此,当你需要实现“自动化”任务时,Workflow 是更合适的选择。 + +为避免选型错误带来的效率低下,你可以通过四个关键问题来审视你的任务需求: + +1. 任务过程是否需要依赖多次的用户输入与调整? +2. 结果的呈现是否需要分步骤、流式地进行? +3. 处理逻辑是否严重依赖于之前的交互历史? +4. 任务是否由事件触发,且输入输出多为一次性完成? + +如果前三个问题的答案为“是”,那么 Chatflow 是理想选择,典型场景包括智能客服、教育辅导、创意协作等。如果第四个问题特征显著,则应选用 Workflow,它更适用于数据清洗、报表生成、批量处理等自动化场景。 + +此处我们选择 Chatflow 作为案例进行介绍,点击 Chatflow 后进入到操作台界面: + +![](images/image51.png) + +我们来简单介绍工作流界面的页面。其中整个界面的核心是中央的编辑画布,你将以可视化方式在这里构建应用逻辑。如图所示,一个基础的工作流通常始于 START 节点(用于接收输入),经由连线将数据传递至 LLM 节点进行处理,最终通过 ANSWER 节点输出结果。每个节点代表一个功能模块,而连线则决定了任务执行的顺序。 + +环绕画布的是完整的操作与管理功能区。界面顶部提供了全局控制选项,包括测试工作流的 Preview 按钮和用于上线的 Publish 按钮。画布角落则设有缩放、撤销等视图控制工具,便于精细调整。 + +左侧面板集中了应用的管理功能。你当前所在的 Orchestrate 选项卡用于流程编排;构建完成后,可通过 API Access 获取集成凭证;Logs & Annotations 记录了每次执行的详细踪迹,便于调试;而 Monitoring 则为你提供应用运行时的性能与状态监控。 + +你可以简单在该对话工作流 LLM 节点的 SYSTEM 中输入一些提示词内容,点击 Preview 后尝试运行这个工作流,查看修改 SYSTEM 提示词后整个工作流确实按照预期在变化。 + +### 2.6.1 常见节点介绍 + +Dify 中提供了多种节点,你可以先了解每个节点的基本功能。具体使用时,建议亲手尝试,或参考他人创建的工作流模板,也可以截图并向大模型询问该节点的用法、所需参数等。推荐直接在现有模板中替换不同节点,通过他人的使用方式来推测节点的最佳实践。 + +在画布右键点击“Add Node”即可添加节点,也可以在左侧的节点面板中查看所有可用节点: + +![](images/image52.png) + +同时,可以打开工具选择面板,查看支持调用的各类工具: + +![](images/image53.png) + +下面是一些常用节点和工具的简要说明。不需要一次性全部掌握,建议先留个印象,在实际使用中逐步熟悉,必要时再回查阅。 + +1. LLM与推理节点 + +![](images/image54.png) + +![](images/image55.png) + +此类节点负责工作流中的核心流程。 + +- LLM节点:核心计算单元,用于调用大语言模型。其配置重点在于提示词工程与参数调优,将业务问题转化为模型的执行指令。 +- Knowledge Retrieval 节点:知识检索单元,负责从预设知识库、外部权威数据源中检索与业务问题相关的信息,为 LLM 节点提供精准的知识支撑,帮助减少大语言模型输出的 “幻觉” 问题。 +- Answer 节点:结果输出单元,负责接收 LLM 处理后的内容,将其整理为符合业务场景需求的最终成果形式。其配置重点在于输出格式的定义(如话术模板、排版规范)。 +- Agent节点:高阶决策单元。它不仅调用模型,还可实施多步骤规划、自主选择并调用外部工具,适用于需要动态决策的复杂任务链。 +- Question Classifier 节点:问题分类单元,负责对输入的业务问题进行类型识别与归类(比如按问题意图、主题领域等维度划分),帮助后续流程精准匹配对应的处理节点(如不同类型的问题适配不同的 LLM 提示词或工具链)。 + +2. 逻辑与流程控制节点 + +![](images/image56.png) + +此类节点定义工作流的执行路径与规则。 + +- 条件节点:如 `IF/ELSE`,通过布尔判断实现流程分支。其设计关键在于条件表达式的严谨性,确保逻辑覆盖所有业务场景。 +- Iteration 节点:作为无状态的批量并行处理单元,它专为子任务间无数据依赖、可独立处理的场景设计,例如批量翻译段落、并行审核多条内容或同时生成多份报告。该节点会接收一个输入数组并自动分片,将每个元素分发至相同处理链路并行执行,用户可在迭代体内通过 {{item}} 访问当前元素、{{index}} 获取其索引,输出则会自动聚合成结果数组;配置时需重点设定并行度以平衡效率与系统负载,同时通过重试策略(如重试次数、间隔)和失败处理(如记录日志、返回默认值)保障批量作业的稳定性。 +- Loop 节点:有状态的递归迭代器,适用于结果依赖前一轮输出的场景,比如多轮参数调优、递归式内容优化(如反复修订文案直至满意)及依赖上次结果的链式计算。其核心是 “状态变量”,需在循环开始前初始化(如当前迭代次数、中间计算结果),并在每轮迭代中明确更新以作为下一轮输入;为防止无限循环,必须定义终止条件(包括基于计数器的 “最多循环 10 次”、基于结果判定的 “满意度评分 > 9”、基于外部信号的 “检测到‘停止’输入”),同时需设置循环超时配置,并规划异常处理路径(如跳出循环或重置状态后重试),确保流程稳定运行。 + +3. 数据操作与集成节点 + +![](images/image57.png) + +- Code 节点:代码处理单元,负责在工作流中执行自定义代码逻辑,可实现数据格式转换、复杂计算等个性化处理需求。其配置重点在于代码语法的正确性与执行环境的适配。 +- Template 节点:模板处理单元,负责将动态数据填充至预设模板中,生成符合格式要求的内容(如定制化文案、报告框架)。其配置重点在于模板语法的编写与变量映射规则的设置。 +- Variable Aggregator 节点:变量聚合单元,负责收集工作流中多个节点输出的变量数据,将分散的变量整合为统一数据集。其配置重点在于聚合的变量范围与数据合并规则的定义。 +- Doc Extractor 节点:文档提取单元,负责从 PDF、Word 等各类文档中提取文本、表格等关键内容,转化为工作流可处理的结构化数据。其配置重点在于文档类型的适配与提取内容的筛选规则。 +- Variable Assigner 节点:变量赋值单元,负责定义、初始化或更新工作流中的变量,为流程内的数据传递提供载体。其配置重点在于变量的命名、数据类型及赋值逻辑的设定。 +- Parameter Extractor 节点:参数提取单元,负责从用户请求、接口返回等输入内容中提取指定参数,将非结构化信息转化为结构化数据。其配置重点在于提取规则(如正则表达式、JSON 路径)的配置。 +- HTTP Request 节点:HTTP 请求单元,负责向外部系统接口发起 HTTP 请求(含 GET、POST 等方法),实现工作流与外部服务的数据交互。其配置重点在于请求地址、请求方法及参数 /headers 的设置。 +- List Operator 节点:列表操作单元,负责对数组、列表类型的数据进行处理(如过滤、排序、拆分),调整数据结构以适配后续流程。其配置重点在于操作类型(如过滤条件、排序规则)的定义。 + +### 2.6.2 常见工具介绍 + +![](images/image58.png) + +在 Dify 中,大部分工具都可以直接作为节点放在画布上,像其他节点一样被上下游连线,只要你提供的输入符合该节点(工具)的参数规范,它就能正常执行并产出可继续流转的结果。 + +在左侧或右侧的节点面板中,可以查看所有可用工具节点,也可以通过插件市场扩展更多工具能力。简单介绍几个常见工具的作用: + +- 网络搜索工具 + 以 Tavily Search 为代表,为大模型提供面向 AI 优化的实时检索能力。 + 它会返回结构化的搜索结果(如标题、摘要、链接等),可以直接作为 LLM 提示词的一部分,用于回答最新资讯类或需要权威依据的问题。 +- 数据处理工具 + 例如 JSON Process 插件,用于对 JSON 数据进行查询、筛选、转换、合并等高级操作。 + 在处理复杂 API 响应或多层嵌套数据时,你可以将“数据清洗 + 重组”的逻辑交给该工具,从而简化在 Code 节点中频繁手写解析代码的工作。 +- 格式处理工具 + 如 Markdown Exporter,可以将生成内容按指定格式导出,例如 Markdown 文档、特定排版模板等,方便后续用于展示、汇报或集成到其他系统。 + +你可以在工具列表中看到这些插件的安装量和简介,初期可优先尝试安装“Featured / 推荐”里的工具,往往覆盖了最常见的业务场景。 + +不过,工具的使用通常比较复杂,建议你在使用的时候可以去搜索引擎先搜索对应工具的“官方推荐工作流 DSL 案例”,直接导入使用,比自己搭建要天然节约很多时间。 + +### 2.6.3 创建简单的意图分类工作流 + +此时我们已经初步了解了 Dify 工作流和工具等的基本信息,但不经过练习我们永远不会熟练使用细节,我们需要一个“假设”的真实业务场景来练练手。 + +例如,在真实的购物对话场景中,前来购买商品的用户输入永远不会是“规范的参数”,而是一句随口说出的话:有人来下单,有人来抱怨,有人只是想闲聊,也有人完全跑题。如果我们把所有这些输入都直接交给同一个大语言模型(LLM)处理,系统通常会出现两个典型问题: + +1. 回复风格不稳定 + 同样是抱怨,有时 LLM 能道歉安抚,有时却像在“解释原因”;同样是点餐,有时会追问缺失信息,有时则直接编造订单细节。 +2. 业务逻辑不可控 + 你希望“抱怨必须先道歉”,但模型未必每次都遵守;你希望“非业务问题要引导回主线”,但模型可能会兴致勃勃地和你聊起段子。 + +因此,更工程化的做法是将任务拆解为一条标准化流水线,先做意图分类(确定用户到底想干什么),然后再按意图分流(不同场景使用不同的提示词与角色),最后对不同分流后大模型的回复统一封装输出(便于前端或系统集成)。 + +本节的目标是让系统能处理一个餐饮场景下的多类对话。你可以跟着操作做一遍加深印象。首先需要做的是定义场景为意图分类: + +- **下单购买 (buy_food)** :用户表达明确的购买意愿。 +- _例如:“给我来一份炸鸡,再加一杯可乐。”_ +- **抱怨投诉 (complain)** :用户在表达不满、催促或负面反馈。 +- _例如:“你们也太慢了吧?等一个小时了。”_ +- **闲聊咨询 (chitchat)** :用户在进行开放式询问、寻求建议,但无明确下单指令。 +- _例如:“今天吃什么好呢,你有什么推荐吗?”_ +- **其他意图 (other)** :用户的输入与餐饮场景无关。 +- _例如:“帮我写个搞笑文案发朋友圈。”_ + +针对这四种意图,我们为系统预设了四种不同的“沟通人格”,分别由四个独立的 LLM 节点承载,每个节点都需要由具有不同人设的 LLM 进行扮演。 + +- **下单助手 (LLM_BuyFood)** :专业、高效,核心任务是确认订单细节,并主动补全缺失信息。 +- **客服专家 (LLM_Complain)** :共情、稳重,首要任务是安抚用户情绪,并提供清晰的解决方案。 +- **聊天伙伴 (LLM_Chitchat)** :轻松、友好,旨在提供个性化推荐,引导潜在消费。 +- **礼貌门卫 (LLM_Other)** :专注、边界清晰,负责将偏离主题的对话礼貌地引导回核心业务。 + +#### 工作流编排设计 + +接下来我们进行工作流的编排设定,决定大概需要有哪些工作流节点。对于新手而言,很难想到需要有哪些节点能被用到(对于老手来说也懒得自己思考,用大模型给建议通常是最快最好的选择),所以我们能够使用大模型给出对应的编排建议,其核心节点结构如下: + +- Start (起点):作为数据入口,负责接收用户的原始输入 `user_text`。 +- Question Classifier (意图分类器):工作流的“大脑”与“调度中心”。它负责对 `user_text` 进行分析,并从我们预设的四种意图标签中选择最匹配的一个。 +- Condition (条件分支):扮演“分流阀”的角色。它根据分类器输出的意图标签,决定接下来将任务导向哪一个专处理路径。 +- 四个并行的 LLM 节点 (LLM_BuyFood, LLM_Complain, LLM_Chitchat, LLM_Other):这是四个独立的“专家处理单元”。每个节点都接收原始问题,但依据自身独特的 System Prompt(系统提示词)生成风格和目标截然不同的回复。 +- Variable Aggregator (变量聚合器):在多条路径处理完成后,需要一个“汇集点”。此节点将四个分支中唯一被激活并产生结果的回复,收束成一个统一的变量 `final_reply`,确保了输出结构的稳定性。 +- Output (终点):作为最终的出口,负责将意图标签、原始问题、以及经过处理生成的回复,以结构化的形式(如 JSON)统一输出,便于后续系统调用或调试分析。 + +#### 工作流编排实现 + +本次教程我们选择创建 Workflow 而不是 Chatflow,选择 User Input: + +![](images/image59.png) + +随后点击 Start 的 User Input 节点,定义一个名为 `user_text` 的字符串类型变量,作为整个流程的输入源。 + +![](images/image60.png) + +保存后点击右上角的 Test Run,你能够看到需要指定对应的文本输入进行处理: + +![](images/image61.png) + +随后我们需要点击输入节点后的 + 符号,选择 Question Classifier 节点添加,并且我们需为其配置四类标签,并为每个标签提供清晰的描述和示例。 + +- `buy_food`: 用户明确想买吃的、点餐、下单。 +- `complain`: 用户在抱怨、吐槽、发脾气,通常带有不满情绪。 +- `chitchat`: 用户在闲聊、讨论吃什么、咨询推荐。 +- `other`: 与餐饮场景无关,或难以判断的内容。 + +此外,你还需要在 ADVANCED SETTING 中写入提示词,让大模型能够正确根据用户输入进行分类测试。示例提示词如下: + +```Plain +从 buy_food / complain / chitchat / other 中选择一个最合适的标签。如果用户在抱怨的同时也点了餐,请优先判断其核心情绪,若重点在于表达不满,应归为 complain。如果只是轻微吐槽但主要意图是下单,则归为 buy_food。若实在难以判断,使用 other 作为兜底 +``` + +![](images/image62.png) + +设定完成后,你可以在右上角的播放键单独测试该节点是否能够正常运行: + +![](images/image63.png) + +![](images/image64.png) + +从 OUTPUT 的结果来看,我们的分类是准确的。你可以进行多种不同类型输入的测试,验证我们分类器的稳定性。 + +接下来,我们需要给分类器接上后续的大模型输出,例如,当 `label` 等于 `"buy_food"` 时,工作流便会精确地流向 `LLM_BuyFood` 节点。我们需要新建四个 LLM 节点,并设置不同的 System Prompt ;不同 System Prompt 的差异决定了它们不同的回应方式。 + +- LLM_BuyFood (点餐助手): + +你是一个点餐助手。要求:1. 确认用户想点的内容。2. 如果信息不完整,友好地补充询问。3. 语气礼貌简洁。 + +- LLM_Complain (客服专家): + +你是一个餐饮客服,专门处理抱怨。要求:1. 真诚道歉。2. 简要说明可能的原因(不推卸责任)。3. 给出清晰的下一步解决方案。 + +- LLM_Chitchat (聊天伙伴): + +你是一个帮人选吃的的聊天小助手。要求:1. 用轻松友好的语气。2. 给出 1~3 个简单推荐。3. 如果用户没有偏好,就给出不同风格的选择。 + +- LLM_Other (礼貌门卫): + +你是一个餐饮点餐小助手,只擅长跟‘吃’相关的话题。当用户说的话无关时:1. 礼貌说明自己的能力范围。2. 引导用户回到主场景。 + +值得注意的是,每个节点里面在填充了 SYSTEM 的提示词参数后,你还要记得启用 USER 提示词参数表。你需要在其中需要点击 `{x}` 符号,选择 `user_text` 参数作为用户输入,并且在前面加上 `user input:` 标识这个变量是用户输入的意思,在问答的时候会综合用户的最开始的输入和内置提示词进行回复。 + +同样的,为了确保一切顺利,你可以点击该节点右上角的播放箭进行具体的对话测试验证效果,比如对话说“我想要喝珍珠奶茶”等,查看回复是否符合预期。 + +![](images/image65.png) + +接下来我们处理并行 LLM 的输出值,我们在 `Variable Aggregator` 节点的配置面板中,找到 `ASSIGN VARIABLES`(分配变量)区域,点击后依次将之前的大模型回复加入即可。 + +![](images/image66.png) + +接下来我们需要对所有的输出进行聚合,最后得到我们想要的结果,包含用户的输入、分类、以及回复。由于我们使用的是 Workflow 而不是 Chatflow,故没有 Answer 节点选择进行结果的聚合,我们能够选择其他节点变相实现结果的聚合与输出,此时选择 Template 节点,在变量部分指定用户意图分类结果、用户的输入值、变量聚合的最终回复,并且在 CODE 中写入最后回复的 json 格式模板,我们可以得到: + +- `intent` ← `class_name` +- `original_text` ← `user_text` +- `final_reply` ← `variable_aggregator` + +```Plain +{ + "intent": "{{ intent }}", + "original_text": "{{ original_text }}", + "reply": {{ final_reply }} +} +``` + +![](images/image67.png) + +最后加入 output 节点即完成所有操作: + +![](images/image68.png) + +#### 工作流运行测试 + +大功告成,我们可以尝试运行这套工作流的效果。它能根据不同的输入,展现出截然不同的行为模式: + +- 输入 (点餐): "给我来一份香辣鸡腿堡套餐,大杯可乐。" + - 路径: `buy_food` → `LLM_BuyFood` + - 输出 reply: "好的,一份香辣鸡腿堡套餐和大杯可乐已为您记录。请问套餐里的薯条需要更换吗?" +- 输入 (抱怨): "你们也太慢了吧?我都等一个多小时了!" + - 路径: `complain` → `LLM_Complain` + - 输出 reply: "非常抱歉让您等了这么久,这确实是我们的疏忽,给您带来了很不好的体验。我们正在紧急核实您的订单配送情况,并会为您申请相应的补偿,感谢您的耐心与反馈。" +- 输入 (闲聊): "今天吃什么比较健康?" + - 路径: `chitchat` → `LLM_Complain` + - 输出 reply: "追求健康的话,可以试试我们的轻食沙拉系列,或者烤鸡胸肉配时蔬。您是喜欢口味清淡一些还是稍微丰富一点的呢?我可以给您更具体的推荐。" +- 输入 (无关内容): "帮我想个明天开会的笑话。" + - 路径: `other` → `LLM_Other` + - 输出 reply: "这听起来是个有趣的挑战!不过我主要是个美食推荐和点餐助手。如果您需要点些什么来犒劳一下辛苦工作的自己,我随时可以帮忙!" + +> 隐藏 Bug :需要说明的是,若你遇到与 aggregation group 相关的奇怪问题,这大概率是 Dify 的一个内置 bug。可能在特定操作下被触发;如果你曾经开启又关闭过 AGGREGATION GROUP,系统可能生成过 group 配置且残留了相关异常参数,即便现在开关看起来是关闭的,这些残留配置也可能导致问题,比如出现 `any` 相关参数的报错。此时你只需要删除该节点并重新创建即可。 + +在 Test Run 中运行后,我们能够看到工作流的执行过程,此时根据分类走了正确的流程,并得到了最后的 output 结果。至此,全流程完成。 + +![](images/image69.png) + +## 2.7 运行第一个模板 Workflow 应用 + +结束了简单的分类工作流学习,接下来我们需要学习如何运行别人的 workflow,我们只需要稍作改造就可以将其变成自己的工作流。在这里我们选择尝试官方的 DeepResearch 工作流,该工作流能够帮你构建一个深度搜索框架,使用大模型+搜索引擎给你一个丰富的搜索答案,每一次提问的结果将会包含搜索引用地址和大模型对话的结果。 + +导入后第一步直接运行,我们根据每一步报错的地方和原因解决具体问题即可,如果遇到解决不了的问题,你可以截图后询问大模型进行解决。 + +![](images/image70.png) + +刚进入感觉十分复杂,没关系,我们点击右上角的 Preview 运行工作流,直到报错出现: + +![](images/image71.png) + +![](images/image72.png) + +我们需要根据报错的节点解决问题,打开后发现是没有配置 Tavily 的 API Token,Tavily 的搜索API 是一个专为 AI 设计的搜索引擎,提供实时、准确和事实性的结果。此时根据提示操作: + +![](images/image73.png) + +经过处理后,搜索引擎能够正常工作: + +![](images/image74.png) + +继续修正模型调用导致的问题后,你应该能够得到如下结果,结合大模型理解下的详细搜索: + +![](images/image75.png) + +我们在最后能够看到对应的参考文档地址: + +![](images/image76.png) + +如果你想理解每个环节的作用,最好的方法是将每个环节的 output 记录为一个变量,最后在输出的时候打印每个中间变量的结果,还有一个方法就是你可以在上方找到 Process 的过程,点击后可以查看每个环节的细节: + +![](images/image77.png) + +## 2.8 将 Dify 作为 API 提供方 + +接下来,我们会尝试通过 API 调用刚才创建的知识库智能体 Agent,我们想要让 Dify 变成一个大模型中枢后端。 + +还记得之前讲过如何通过 API 调用模型吗?我们需要准备一个密钥(Key)和一份 API 调用示例(文档中的 request/response 示例),然后把这些内容发给大模型,让它帮我们写出调用服务的代码,并从返回结果中解析出我们需要的字段。 + +这一次,我们会使用本地的代码编辑工具 [Trae](https://www.trae.cn/) 来完成这个过程。 + +如果你还不熟悉什么是 IDE,可以先阅读文档 [Extra Knowledge 4 - What is AI IDE and Trae](https://github.com/datawhalechina/easy-vibe/blob/main/docs/extra/extra4/extra4-what-is-ai-ide-and-trae.md)。 + +如果你的本地开发环境还没有完整配置好,也不用担心。只要你信任自己的代码助手(不管是 [z.ai](http://z.ai) 还是 Trae),遇到任何不懂的地方或报错,都可以直接把问题抛给它,它会根据你的描述给出详细的解决方案。 + +![](images/image78.png) + +右侧的区域叫做 Copilot 交互窗口,或者 Agent 窗口。如果你看不到它,可以点击右上角的侧边栏图标来打开。 + +![](images/image79.png) + +打开侧边栏后,你会看到 `Builder` 选项。这就是 Agent 模式。你可以简单地把 “Builder” 理解为 [z.ai](http://z.ai) 的“开发模式”,它同样可以帮你操作本地电脑环境、安装依赖、打开网页等。 + +![](images/image80.png) + +点击 “Builder” 后,你会看到 “Chat” 模式和 “Builder with MCP” 模式。 Chat 模式主要用于与当前文件夹进行交互,或者和大模型进行自然语言对话。(你可以通过点击 Trae 左上角的 “File” 打开一个文件夹,然后在该文件夹内进行编辑。这种情况下,Builder 所有的新建文件操作都会发生在这个文件夹中。) + +Builder with MCP 模式则为 Agent 提供了更多工具(例如让大模型连接到其他软件、获取天气信息等)。你可以简单地认为 MCP 是一个让大模型更方便调用各种外部工具的能力集合。 + +![](images/image81.png) + +在下方区域,你还可以看到模型选择的下拉列表,可以点击切换不同模型。这里你可以选择 Kimi k2 或 GLM。如果你使用的是国际版 Trae,也可以选择 ChatGPT 或 Claude。 不过,随着国内大模型的快速发展,Kimi、Qwen、GLM 等模型的综合能力已经基本接近 Claude 3.5 或 3.7,对于日常开发场景来说完全够用。 + +![](images/image82.png) + +上面是对 Trae 的一个简要介绍。接下来,我们可以回顾在 [z.ai](http://z.ai) 中的操作步骤,并在 Trae 中复用这些思路。 + +## 2.9 利用 Dify API 创建前端对话应用 + +如果我们想用 Dify 的 API 搭建一个前端聊天应用,首先需要获取 Dify 的 API 文档和调用地址。 + +还记得刚才创建的那个 Agent 吗? 先点击右上角的 “Publish”,然后点击 “Publish Update”,最后点击 “Access API Reference” 进入 API 文档。 + +![](images/image83.png) + +![](images/image84.png) + +进入 API 文档后,找到 “Send Chat Message” 这一部分,点击进入,然后在右侧找到 “Request” 和 “Response” 示例并复制出来。 + +为什么一定要复制这两部分内容? 因为它们是 API 的“核心信息”: 有了 Key、请求示例和返回示例,我们就可以让大模型帮我们生成调用服务的代码,并且根据返回结构把需要的字段提取出来。 + +![](images/image85.png) + +![](images/image86.png) + +在找到会话所需的 Request 和 Response 示例之后,我们还需要获取一个 API Key。在文档右上角,你会看到 “API key” 相关选项。 + +![](images/image87.png) + +点击 “Create new Secret key”,就可以创建属于你自己的 API Key。 + +![](images/image88.png) + +现在一切准备就绪。我们会把刚才拿到的 API Key、Request 示例和 Response 示例一起交给 Trae Builder。 + +注意:请将 `{DIFY_API_URL}` 替换为实际的 Dify API 地址。 + +```JSON +key: +app-zKdCHUXXXXXXXX + +Please write me a front-end based on the following reference: + +curl -X POST 'http://{DIFY_API_URL}/v1/chat-messages' \ +--header 'Authorization: Bearer {api_key}' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "inputs": {}, + "query": "What are the specs of the iPhone 13 Pro Max?", + "response_mode": "streaming", + "conversation_id": "", + "user": "abc-123", + "files": [ + { + "type": "image", + "transfer_method": "remote_url", + "url": "https://cloud.dify.ai/logo/logo-site.png" + } + ] +}' + +{ + "event": "message", + "task_id": "c3800678-a077-43df-a102-53f23ed20b88", + "id": "9da23599-e713-473b-982c-4328d4f5c78a", + "message_id": "9da23599-e713-473b-982c-4328d4f5c78a", + "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", + "mode": "chat", + "answer": "iPhone 13 Pro Max specs are listed here:...", + "metadata": { + "usage": { + "prompt_tokens": 1033, + "prompt_unit_price": "0.001", + "prompt_price_unit": "0.001", + "prompt_price": "0.0010330", + "completion_tokens": 128, + "completion_unit_price": "0.002", + "completion_price_unit": "0.001", + "completion_price": "0.0002560", + "total_tokens": 1161, + "total_price": "0.0012890", + "currency": "USD", + "latency": 0.7682376249867957 + }, + "retriever_resources": [ + { + "position": 1, + "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb", + "dataset_name": "iPhone", + "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00", + "document_name": "iPhone List", + "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a", + "score": 0.98457545, + "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\"" + } + ] + }, + "created_at": 1705407629 +} +``` + +![](images/image89.png) + +在这个阶段,你可能会发现生成出来的程序并不能一次性正常运行——比如对话会出现奇怪的错误,或者没有任何返回结果。当出现这种情况时,你可以尝试切换到另一个大语言模型,或者把错误信息复制出来,详细描述问题,再发给模型让它根据反馈继续迭代。 + +此时你的工作方式已经非常接近真实开发过程了。在日常开发中,我们经常会在与大模型协作时遇到各种问题,为了更好地解决这些问题,我们需要提供更多上下文信息。除了提供错误信息,你还可以复制更完整的文档内容(例如在文档左侧 “Send message” 部分中复制更多说明),一并交给模型,让它在更多细节的基础上给出更完整的解决方案。 + +![](images/image90.png) + +此时浏览器是嵌在 Trae 内部的。你可以点击顶部的指南针图标,把网页在外部浏览器中全屏打开。 + +![](images/image91.png) + +如果运气不错,你可能在第一次尝试时就能获得一个可以正常交互的前端页面。 + +![](images/image92.png) + +不过,由于大模型本身具有一定随机性,有时你可能在单轮对话中一切顺利,但在多轮对话时出现异常。因此,建议你进行多轮对话测试,确保程序在多轮交互场景下也能稳定运行。 + +![](images/image93.png) + +到这里,你已经学会了如何构建一个简单的 Dify 知识库 Agent,并使用 Trae 替代 [z.ai](http://z.ai) 来搭建一个交互式前端。从现在开始,Trae 将成为我们构建各种原型时的主要开发工具,逐步取代 [z.ai](http://z.ai)。你可以尝试用 Trae 重新实现之前的贪吃蛇游戏,看看会有什么不同的体验。加油! + +# 3. 更多业务工作流参考 + +你可以在搜索引擎上使用类似关键词搜索 `Dify workflow 参考`,或者直接在 Github 中找到 Dify 工作流分享仓库进行参考工作流的查找(质量参差不齐,你需要查看多个不同仓库学习)。当然,所谓的工作流只不过是业务上 SOP 的映射,你可以思考有哪些日常工作中的流程或者学习中的流程是重复可固化的,只需要把它变成工作流固定即可。 + +以下是一些大模型生成的工作流设计的参考(实际上的实现方案也比较类似,一般来说人类设计的工作流不会有大模型设计的优美,除非是高手设置的工作流),如果你觉得哪些点子有意思,可以将它发给大模型进一步细化,让大模型帮你给出更具体的 Dify 工作流节点设定,以及内部的细节结果。 + +## 3.1 社媒平台工作流 + +1. 跨平台内容一键分发工作流(复杂) + 1. 思路:以一篇核心稿件为“原料”,自动加工成适配多个平台的“成品”。 + 2. 实现:`Start` 输入文章 -> `LLM` 润色 -> 并行多个 `LLM` 节点(每个节点Prompt扮演特定平台专家,如“小红书爆款文案专家”、“知乎专业答主”)-> `Iterator` 节点循环处理不同平台格式要求 -> `Variable Aggregator` 汇总 -> `Answer` 输出所有版本。复杂度在于并行处理和循环迭代。 +2. 热点话题选题与初稿生成器(中等) + 1. 思路:自动捕捉网络热点,快速生成选题和内容草稿。 + 2. 实现:`Start` 输入关键词 -> `Tool` 节点调用搜索引擎API抓取热点 -> `LLM` 摘要提炼出3-5个话题 -> `LLM` 生成文章大纲或初稿。复杂度在于外部工具集成与信息筛选。 +3. 评论区智能分类与回复助手(复杂) + 1. 思路:自动分析评论情感与意图,生成分类回复建议。 + 2. 实现:`HTTP Request` 节点接入社媒API获取评论 -> `Question Classifier` 或 `LLM` 节点进行多标签分类(积极、疑问、投诉、广告等)-> `Condition` 判断节点路由至不同回复生成链 -> 并行 `LLM` 节点生成个性化回复草稿 -> `Answer` 输出。复杂度在于条件分支和实时API调用。 +4. 短视频脚本与分镜自动生成器(复杂) + 1. 思路:根据一个热门话题或产品描述,自动生成短视频脚本、分镜描述和推荐标签。 + 2. 实现:`Start` 输入主题 -> `LLM` 生成创意脚本 -> 第二个 `LLM` 节点将脚本拆解为场景序列(画面描述、台词、时长)-> `Tool` 节点调用文本转语音服务生成语音样本 -> `Variable Aggregator` 整合所有元素 -> `Answer` 输出结构化脚本文件。复杂度在于多步骤序列化和外部服务集成。 +5. 直播互动问答实时摘要助手(中等) + 1. 思路:实时处理直播间的文字评论,提炼核心问题和观众反馈。 + 2. 实现:`HTTP Request` 节点流式获取直播评论 -> `Iterator` 节点以时间窗口为单位处理批数据 -> `LLM` 节点实时总结每段时间内的热点问题与情绪倾向 -> `Answer` 或 `Webhook` 节点输出摘要给主播。复杂度在于实时流数据处理和循环窗口。 + +## 3.2 职场工作流 + +1. 智能会议纪要与任务自动派发系统(复杂) + 1. 思路:从会议录音文本中提取纪要,并自动创建任务。 + 2. 实现:`Start` 输入会议文本 -> `LLM` 总结议题与结论 -> `Parameter Extractor` 节点精准抽取Action Items(任务、负责人、DDL)-> 一个 `LLM` 整合成纪要邮件 -> 并行 `HTTP Request` 节点调用Jira/Trello/飞书API创建任务。复杂度在于信息抽取与多系统联动。 +2. 简历批量筛选与初步评估助手(中等) + 1. 思路:自动解析简历,进行匹配度评估并生成面试问题。 + 2. 实现:`Start` 上传简历文件与JD -> `Document Extractor` 节点解析简历文本 -> `LLM` 扮演HR进行匹配度评估 -> 对高匹配者,另一个 `LLM` 生成深度面试问题。复杂度在于文档解析与多条件评估。 +3. 多语言邮件一键翻译与草稿回复(简单) + 1. 思路:自动翻译邮件并起草回复。 + 2. 实现:`Start` 输入邮件 -> `LLM` 判断语种并翻译 -> `LLM` 构思回复要点 -> `LLM` 翻译回原始语言并润色。主要依赖于LLM的序列调用。 +4. 周报/月报数据自动汇总与洞察生成(复杂) + 1. 思路:连接多个数据源,自动生成结构化工作报告。 + 2. 实现:多个 `HTTP Request`/`Tool` 节点并行调用业务系统API(如CRM、Git、项目管理工具)获取原始数据 -> `Code` 节点或 `LLM` 进行数据清洗与基础计算 -> `LLM` 分析趋势、亮点与风险,生成叙述性报告 -> `Answer` 输出图文并茂的文档。复杂度在于多数据源聚合、数据处理与智能分析结合。 +5. 合同/文档智能审查与要点提炼(中等) + 1. 思路:快速审查法律或商务文档,提示风险并提炼核心条款。 + 2. 实现:`Start` 上传合同PDF -> `Document Extractor` 提取文本 -> `LLM` 节点(设定为法律专家角色)审查责任条款、支付条件、违约条款等 -> `Parameter Extractor` 节点抽取出关键日期、金额、义务方等结构化数据 -> `Answer` 输出风险提示和要点表格。复杂度在于长文档处理与结构化信息抽取。 + +## 3.3 学习生活工作流 + +1. 学术论文深度解析与笔记生成器(复杂) + 1. 思路:上传论文PDF,自动生成结构化笔记。 + 2. 实现:`Start` 上传PDF -> `Document Extractor` 提取全文 -> 并行多个 `LLM` 节点分工总结摘要、方法、发现、参考文献 -> `Variable Aggregator` 汇总 -> `Answer` 输出Markdown笔记。复杂度在于并行处理长文本的不同部分。 + +2. 个性化旅行计划定制师(中等) + 1. 思路:根据用户偏好,自动规划详尽行程。 + 2. 实现:`Start` 输入需求(目的地、天数、预算、兴趣)-> `Tool` 节点调用搜索引擎或地图API获取地点信息 -> `LLM` 整合信息,设计每日行程(含时间、活动、预算估算)。复杂度在于外部信息获取与结构化规划。 + +3. 外语学习互动陪练伙伴(简单) + 1. 思路:创建可角色扮演和语法纠错的对话机器人。 + 2. 实现:系统设定AI角色 -> `Start` 接收用户语句 -> `LLM` 执行两项任务:角色回复 + 语法纠错与解释 -> `Answer` 输出。核心是LLM的多任务指令。 + +4. 个人知识库问答与链接推荐系统(复杂) + 1. 思路:基于你收藏的文档、笔记、网页链接,构建一个可问答并能推荐相关旧知识的智能系统。 + 2. 实现:离线处理:使用 `Document Extractor` 和 `Embedding` 工具将个人知识库切片并向量化存储。在线工作流:`Start` 输入问题 -> `Retrieval` 节点从向量库中查找最相关的知识片段 -> `LLM` 基于检索到的上下文生成答案 -> 同时,另一个分支使用检索到的内容作为输入,通过 `LLM` 生成“相关旧知识”推荐列表 -> `Answer` 合并输出答案与推荐。复杂度在于检索增强生成(RAG)流程的构建。 + +5. 健身/饮食计划追踪与调整顾问(中等) + 1. 思路:根据用户输入的每日饮食和训练日志,提供营养分析与训练建议。 + 2. 实现:`Start` 输入文本日志(如“午餐:鸡胸肉150g,米饭一碗,蔬菜若干;训练:深蹲5组”)-> `Parameter Extractor` 节点尝试结构化输入数据 -> `LLM` 扮演健身教练,分析营养摄入是否均衡、训练容量是否合适 -> 对比长期目标,给出微调建议(如“蛋白质摄入充足,建议增加蔬菜种类”)。复杂度在于从非结构化日志中提取结构化信息并提供个性化反馈。 + +# 6. 工作流平台的局限性 + +工作流平台(或称低代码平台)并非万能解决方案。它虽然对业务人员友好,降低了直接编码的门槛,但从另一个角度看,“低代码”往往也是一种“高代码”——用户仍需理解平台的概念、规则与操作逻辑,这本身构成了一种新的学习成本。 + +也许你想问,很多简单的工作流其实就是大模型函数包装后的前后调用,前面函数的输出作为后者函数的输入,本质上几行代码就能够解决,为什么需要那么复杂的多重包装工作流?反而给 API 调用造成了麻烦。 + +你说得是对的。在当前 vibe coding 的快速发展下,借助 AI 代码生成能力,直接阅读甚至生成代码有时可能更加高效。理想情况下,我们希望能用自然语言直接操作应用逻辑,这才是一个现代的软件平台。但目前的工作流平台尚未实现这一点,因此它在用户意图与最终实现之间天然存在一个“中间层”。掌握这个中间层,正是一种需要投入时间学习的成本。理想上,之后的工作流平台也要支持全 AI 自动对话操作,我们可以让 AI 真正操作工作流搭建以及入参的每一个细节环节。 + +尽管如此,熟练使用这类平台正逐渐成为一项基础技能,如同微软的办公软件一样,在业务中非常普遍且实用,值得掌握。 + +在后续的进阶课程中,我们将介绍如何通过代码级别的工作流与 RAG 开发平台进行构建。届时,你可以亲身体验不同实现方式在复杂度与灵活性上的区别。(值得注意的是,一些简单的对话应用或嵌套逻辑,用工作流实现可能并不困难。) + +# 📚 课后作业 + +## 掌握 Dify 基本操作 + +为了测试你掌握了 Dify 的常见基础使用工具,你需要完成一个基础作业和两个 “小挑战”,确保你已入门常见的操作。你需要将附带的两个 DSL 文件导入 Dify 工作流,并成功完成对应工作流的挑战(遇到不懂的地方截图询问大模型,或自己探索其中的每个参数的用法,最后实现目标)。: + +1. 参考意图分类工作流的方法,让大模型给你建议完全换一套场景进行应用,但是一定要用到意图分类工作流,最后提交运行的工作流截图、场景说明、结果。 +2. Log in workflow 工作流解密挑战 + +在这个解密挑战中,你需要完成以下挑战,让工作流实现下列功能: + +- 找出正确的密码! +- 将密码修改为 0925 +- 当密码不正确时,提供第二次尝试机会(不提供第三次) +- 当用户提及要再次登录时,为用户提供重新输入密码的机会 + +![](images/image94.png) + +参考输入输出: + +![](images/image95.png) + +3. Love loop workflow 工作流解密挑战 + +![](images/image96.png) + +在这个解密挑战中,你需要修复当前工作流的问题,让工作流最后的输出类似如下显示: + +![](images/image97.png) + +如果你遇到无法解决的问题,请截图询问大模型,或查阅官方文档得到结果:[https://docs.dify.ai/en/use-dify/getting-started/quick-start](https://docs.dify.ai/en/use-dify/getting-started/quick-start) + +## 实现 Dify API 调用 + +为了测试你真正掌握了 Dify 的 API 调用知识,你需要完成以下任务: + +1. 部署 Dify 并创建一个简单的知识库(选取你喜欢的资料)。 +2. 使用 Trae IDE 构建一个对话前端,与 Dify 知识库进行 API 交互。 +3. 测试多轮对话的效果,确保程序正常运行。 + +你需要提交最终运行截图和知识库的处理过程截图。 + +## 试用第三方工作流 / 构建一个自己的业务工作流 + +请你在 Github、微信公众号、或者 Reddit、推特上等所有地方找到你想尝试的别人的 Dify 工作流,下载导入后成功运行;或者你可以根据上文中提到的业务工作流参考,根据现实中的具体需求创建一个自己的业务工作流进行运行。 + +最后你需要提交运行成功的截图,并说明这个工作流的作用。 + +# [Bug] HTTP 请求错误问题的解决方法 + +如果你遇到了如下图所示的问题,才需要参考本节方案进行解决,否则可以不理会当前部分。 + +有时候可能你会把 Dify 部署在自己的服务器,但是服务器的对外地址通常都是 http 而不是 https 的,但当我们请求一个只支持 HTTP 的服务时,你可能会看到类似这样的提示(启用 F12 浏览器调试信息模式,查看有问题的点): + +![](images/image98.png) + +出现这个问题的原因,是因为我们默认把 Dify 部署在一台只支持 HTTP 而不支持 HTTPS 的服务器上。 HTTPS(HyperText Transfer Protocol Secure)是在 HTTP(超文本传输协议)的基础上增加了 SSL/TLS 加密层,可以简单理解为“更安全版的 HTTP”。 + +如果要让服务支持 HTTPS,一般可以: + +- 使用其他程序转发请求(例如在有证书的 nginx 上做反向代理),或者 +- 绑定域名后为该域名申请证书。 + +但这些操作都比较复杂,在这里我们使用 Zeabur 作为网络转发网关来解决问题。 + +Zeabur 的网页默认是通过 HTTPS 访问的,因此我们只需要把原来请求的域名转发到 Zeabur 提供的域名,就可以修复这个问题。 + +- 原始地址:`http://{DIFY_API_URL}/v1/chat-messages` +- 现在地址:`https://{DIFY_NEW_API_URL}.zeabur.app/v1/chat-messages` + +你只需要简单地把 URL 中的域名部分(公网 IP 或域名)替换为已经在 Zeabur 上部署好的域名即可,我们已经提前在服务里配置好了转发功能。 + +如果你感兴趣,也可以自己在 Zeabur 上部署一个转发服务。在 Zeabur 中创建服务时,选择 Python,然后填入下面的 Python 代码,部署后即可得到一个 https 的地址,https 即可正常使用。 + +部署完成后,在网络设置中把程序监听端口设置为本地 8080,并对外暴露该端口。 + +注意:请将 `{DIFY_API_URL}` 替换为实际的 Dify API 地址。 + +```Python +from flask import Flask, request, Response +import requests + +app = Flask(__name__) + +TARGET_BASE_URL = "{DIFY_API_URL}" +LISTEN_PORT = 8080 + +@app.route('/', defaults={'path': ''}, methods=['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD']) +@app.route('/', methods=['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD']) +def proxy_request(path): + target_url = f"{TARGET_BASE_URL}/{path}" + if request.query_string: + target_url += f"?{request.query_string.decode('utf-8')}" + + headers = {key: value for key, value in request.headers if key.lower() not in ['host', 'connection', 'content-length', 'accept-encoding']} + + try: + resp = requests.request( + method=request.method, + url=target_url, + headers=headers, + data=request.get_data(), + cookies=request.cookies, + allow_redirects=False, + timeout=30 + ) + + excluded_headers = ['content-encoding', 'content-length', 'transfer-encoding', 'connection'] + response_headers = [(name, value) for name, value in resp.raw.headers.items() if name.lower() not in excluded_headers] + + return Response(resp.content, resp.status_code, response_headers) + + except requests.exceptions.RequestException as e: + print(f"Error forwarding request to {target_url}: {e}") + return Response(f"Proxy Error: Could not reach target server or invalid response: {e}", status=502) + except Exception as e: + print(f"An unexpected error occurred: {e}") + return Response(f"Internal Proxy Error: {e}", status=500) + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=LISTEN_PORT, debug=True) +``` diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image1.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image1.png new file mode 100644 index 0000000..0c0df71 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image1.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image10.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image10.png new file mode 100644 index 0000000..cdcdc6b Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image10.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image11.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image11.png new file mode 100644 index 0000000..d8df91f Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image11.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image12.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image12.png new file mode 100644 index 0000000..0783dc3 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image12.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image13.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image13.png new file mode 100644 index 0000000..6cdc6dd Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image13.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image14.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image14.png new file mode 100644 index 0000000..ae894d0 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image14.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image15.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image15.png new file mode 100644 index 0000000..d60f458 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image15.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image16.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image16.png new file mode 100644 index 0000000..15e421e Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image16.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image17.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image17.png new file mode 100644 index 0000000..dbab625 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image17.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image18.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image18.png new file mode 100644 index 0000000..923ff17 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image18.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image19.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image19.png new file mode 100644 index 0000000..1e27f8a Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image19.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image2.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image2.png new file mode 100644 index 0000000..740203c Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image2.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image20.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image20.png new file mode 100644 index 0000000..9e607a2 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image20.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image21.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image21.png new file mode 100644 index 0000000..c95d577 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image21.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image22.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image22.png new file mode 100644 index 0000000..6c888e0 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image22.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image23.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image23.png new file mode 100644 index 0000000..ffede5e Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image23.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image24.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image24.png new file mode 100644 index 0000000..1235149 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image24.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image25.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image25.png new file mode 100644 index 0000000..812428d Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image25.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image26.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image26.png new file mode 100644 index 0000000..8cb4da9 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image26.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image27.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image27.png new file mode 100644 index 0000000..121cfcc Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image27.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image28.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image28.png new file mode 100644 index 0000000..c22432b Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image28.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image29.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image29.png new file mode 100644 index 0000000..b8a5f12 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image29.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image3.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image3.png new file mode 100644 index 0000000..987cc82 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image3.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image30.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image30.png new file mode 100644 index 0000000..ce670a0 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image30.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image31.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image31.png new file mode 100644 index 0000000..b953bfa Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image31.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image32.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image32.png new file mode 100644 index 0000000..bd2f03d Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image32.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image33.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image33.png new file mode 100644 index 0000000..48e052d Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image33.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image34.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image34.png new file mode 100644 index 0000000..38bb149 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image34.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image35.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image35.png new file mode 100644 index 0000000..26ed3dc Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image35.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image36.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image36.png new file mode 100644 index 0000000..abbd6f4 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image36.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image37.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image37.png new file mode 100644 index 0000000..9f65d19 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image37.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image38.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image38.png new file mode 100644 index 0000000..d4a7490 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image38.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image39.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image39.png new file mode 100644 index 0000000..8a1af36 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image39.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image4.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image4.png new file mode 100644 index 0000000..a57678c Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image4.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image40.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image40.png new file mode 100644 index 0000000..49c7774 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image40.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image41.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image41.png new file mode 100644 index 0000000..03497ec Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image41.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image42.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image42.png new file mode 100644 index 0000000..506ceec Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image42.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image43.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image43.png new file mode 100644 index 0000000..8cf908f Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image43.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image44.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image44.png new file mode 100644 index 0000000..6042e58 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image44.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image45.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image45.png new file mode 100644 index 0000000..e41a490 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image45.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image46.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image46.png new file mode 100644 index 0000000..6f46315 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image46.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image47.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image47.png new file mode 100644 index 0000000..c854dd6 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image47.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image48.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image48.png new file mode 100644 index 0000000..43e1d00 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image48.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image49.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image49.png new file mode 100644 index 0000000..e769dc7 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image49.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image5.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image5.png new file mode 100644 index 0000000..b13bd39 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image5.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image50.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image50.png new file mode 100644 index 0000000..56f3d6e Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image50.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image51.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image51.png new file mode 100644 index 0000000..fea3763 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image51.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image52.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image52.png new file mode 100644 index 0000000..415bb91 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image52.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image53.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image53.png new file mode 100644 index 0000000..1e35b54 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image53.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image54.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image54.png new file mode 100644 index 0000000..ffaa969 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image54.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image55.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image55.png new file mode 100644 index 0000000..a453803 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image55.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image56.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image56.png new file mode 100644 index 0000000..3bfc40e Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image56.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image57.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image57.png new file mode 100644 index 0000000..8cff680 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image57.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image58.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image58.png new file mode 100644 index 0000000..f7eab17 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image58.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image59.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image59.png new file mode 100644 index 0000000..ec4bfb3 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image59.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image6.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image6.png new file mode 100644 index 0000000..2670a9c Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image6.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image60.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image60.png new file mode 100644 index 0000000..492085f Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image60.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image61.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image61.png new file mode 100644 index 0000000..d9152b4 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image61.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image62.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image62.png new file mode 100644 index 0000000..cc11f8b Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image62.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image63.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image63.png new file mode 100644 index 0000000..cfcebeb Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image63.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image64.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image64.png new file mode 100644 index 0000000..13307ae Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image64.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image65.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image65.png new file mode 100644 index 0000000..8194e1a Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image65.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image66.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image66.png new file mode 100644 index 0000000..d9dbb32 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image66.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image67.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image67.png new file mode 100644 index 0000000..a31e607 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image67.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image68.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image68.png new file mode 100644 index 0000000..ba7155d Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image68.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image69.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image69.png new file mode 100644 index 0000000..59f71fc Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image69.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image7.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image7.png new file mode 100644 index 0000000..d8bd6db Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image7.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image70.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image70.png new file mode 100644 index 0000000..55a6dad Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image70.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image71.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image71.png new file mode 100644 index 0000000..578f576 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image71.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image72.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image72.png new file mode 100644 index 0000000..13779f9 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image72.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image73.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image73.png new file mode 100644 index 0000000..b2f5e49 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image73.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image74.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image74.png new file mode 100644 index 0000000..4dcaf95 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image74.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image75.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image75.png new file mode 100644 index 0000000..f91102a Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image75.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image76.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image76.png new file mode 100644 index 0000000..090bca8 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image76.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image77.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image77.png new file mode 100644 index 0000000..1b1b6b3 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image77.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image78.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image78.png new file mode 100644 index 0000000..84a3c51 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image78.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image79.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image79.png new file mode 100644 index 0000000..7b084ff Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image79.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image8.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image8.png new file mode 100644 index 0000000..61db8e6 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image8.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image80.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image80.png new file mode 100644 index 0000000..5e31acb Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image80.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image81.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image81.png new file mode 100644 index 0000000..0a167cd Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image81.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image82.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image82.png new file mode 100644 index 0000000..e246dcf Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image82.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image83.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image83.png new file mode 100644 index 0000000..6515952 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image83.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image84.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image84.png new file mode 100644 index 0000000..3e2bdd1 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image84.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image85.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image85.png new file mode 100644 index 0000000..2073c2b Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image85.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image86.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image86.png new file mode 100644 index 0000000..a480ecb Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image86.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image87.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image87.png new file mode 100644 index 0000000..5e60c0c Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image87.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image88.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image88.png new file mode 100644 index 0000000..118d422 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image88.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image89.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image89.png new file mode 100644 index 0000000..4db0eeb Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image89.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image9.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image9.png new file mode 100644 index 0000000..c1b234a Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image9.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image90.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image90.png new file mode 100644 index 0000000..6906927 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image90.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image91.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image91.png new file mode 100644 index 0000000..01e7bb9 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image91.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image92.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image92.png new file mode 100644 index 0000000..50d41a3 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image92.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image93.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image93.png new file mode 100644 index 0000000..7263503 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image93.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image94.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image94.png new file mode 100644 index 0000000..edda9fa Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image94.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image95.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image95.png new file mode 100644 index 0000000..cf3d110 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image95.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image96.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image96.png new file mode 100644 index 0000000..dd12692 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image96.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image97.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image97.png new file mode 100644 index 0000000..b8c2aa2 Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image97.png differ diff --git a/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image98.png b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image98.png new file mode 100644 index 0000000..de051ba Binary files /dev/null and b/docs/stage-2/ai-capabilities/2.1-dify-knowledge-base/chapter3/images/image98.png differ diff --git a/docs/stage-2/ai-capabilities/2.2-multimodal-api/extra3/extra3-ai-capability-starter-handbook.md b/docs/stage-2/ai-capabilities/2.2-multimodal-api/extra3/extra3-ai-capability-starter-handbook.md new file mode 100644 index 0000000..95ab095 --- /dev/null +++ b/docs/stage-2/ai-capabilities/2.2-multimodal-api/extra3/extra3-ai-capability-starter-handbook.md @@ -0,0 +1,3 @@ +# AI 能力入门手册 + +> 本章节正在编写中,敬请期待... diff --git a/docs/stage-2/assignments/2.1-fullstack-app/index.md b/docs/stage-2/assignments/2.1-fullstack-app/index.md new file mode 100644 index 0000000..f67f0ba --- /dev/null +++ b/docs/stage-2/assignments/2.1-fullstack-app/index.md @@ -0,0 +1,3 @@ +# 大作业 1:构建第一个现代应用程序 - 全栈应用 + +> 本章节正在编写中,敬请期待... diff --git a/docs/stage-2/assignments/2.2-modern-frontend-trae/index.md b/docs/stage-2/assignments/2.2-modern-frontend-trae/index.md new file mode 100644 index 0000000..5042a05 --- /dev/null +++ b/docs/stage-2/assignments/2.2-modern-frontend-trae/index.md @@ -0,0 +1,3 @@ +# 大作业 2:现代前端组件库 + Trae 实战 + +> 本章节正在编写中,敬请期待... diff --git a/docs/stage-2/backend/2.1-what-is-api/extra2/extra2-what-is-api.md b/docs/stage-2/backend/2.1-what-is-api/extra2/extra2-what-is-api.md new file mode 100644 index 0000000..fc1d437 --- /dev/null +++ b/docs/stage-2/backend/2.1-what-is-api/extra2/extra2-what-is-api.md @@ -0,0 +1,170 @@ +# 扩展知识 2 - API 开发手册:从核心逻辑到 AI 场景集成 + +随着数字化进程的加速,我们每天都在与成百上千个软件系统打交道。但对于初学者来说,一个始终绕不开的困惑是:**这些看起来互不相干的应用,到底是怎么“对话”的?** 为什么我在这个 App 里点一下,另一个 App 就能立刻做出反应? + +面对这种困惑,最直观的做法或许是“临时抱佛脚”:**遇到需求再搜索具体的函数调用或者是网络协议,对照文档进行处理**。看到图片需求就想到图像生成,碰到文本任务就找来大模型,再在海量接口中货比三家。然而,把零散的接口堆在一起,与在应用开发中系统性地规划、选型和组合 API 能力,是两件截然不同的事情。仅靠临时查资料与经验判断,会带来认知碎片化、方案设计随意、接口复用困难等一系列严峻挑战。 + +为了解决这些痛点,本篇手册以“API 核心逻辑”为整理思路。在这本手册里,我们想做的不是堆名词,而是帮你快速搞清楚三件事:**“这件事可以用什么 API 做?它的本质逻辑是什么?接下来该怎么安全地调用它?”** 通过从生活类比到代码实践的系统梳理,我们将为你揭开 API 的神秘面纱,帮你建立起从“逻辑认知”到“场景映射”再到“代码实现”的完整链路。 + +> 由于 **内容较多** ,你可以在实践过程中遇到场景不知道如何选型的问题再查阅手册寻找参考;推荐你**根据具体应用方向,让 AI 参考该手册,给出可参考的模型选型建议、方案 API 调用建议即可。** +> +> 如果你只想了解对应的类别,不想看具体内容,只需要看每个大章节的初始段内容即可,例如 1 、2 的内容,但不需要看 5.1 或者 5.2 的代码细节。 +> +> **推荐本手册只在需要时查阅对应部分或只浏览一级目录部分,若有兴趣再浏览全文。** +> +> **之后更新会在每个章节部分,推荐可尝试使用的模型 API 服务地址。** + +# 本节课你将学到 + +- **核心概念映射**:通过“电源插座”与“餐厅点餐”等经典类比,建立对 API 请求与响应循环的直观理解。 +- **现实场景解析**:了解天气、地图、社交登录及大语言模型等主流 API 的工作原理,掌握从“功能”到“接口”的映射方法。 +- **代码实践与安全**:掌握 Python 环境下 AI API 的调用方式,并理解前端开发中后端代理等安全工程实践的重要性。 + +完成本手册的学习后,你将对主流 API 能力建立起入门级的系统化认知,不仅知道“市面上有哪些接口、常配哪些产品”,更能理解它们在整体架构中的位置和相互关系。知道在面对具体业务需求时,如何快速定位所需能力、做出有依据的选型,为构建 AI 应用体系打下坚实基础。 + +--- + +## 1. 什么是 API?—— 从墙上的插座说起 + +API 的全称是 Application Programming Interface(应用程序编程接口),听起来很硬核,但我们可以把它想象成你墙上的**电源插座**。 + +当你把手机充电器插进插座时,你并不需要知道远处的发电厂是在烧煤还是在用风力发电,也不需要理解复杂的电网是怎么把电输送到你家的。对你来说,电厂就是一个“黑盒子”。你唯一关心的就是这个插座:只要你的插头尺寸对得上(符合标准),一插进去,电就来了。 + +在这个例子中,你的手机就是“客户端”(程序),发电厂是“服务器”(另一个服务),而**墙上的插座就是 API**。它是一个预先定义好的、标准的“连接点”。它把复杂的内部逻辑屏蔽在墙后面,只给你留下一个简单的接口,让你能轻而易举地获取原本非常复杂的功能或数据。 + +## 2. 为什么 API 如此重要? + +正因为有了这些“插座”,现代技术的创新才变得如此迅速。开发者不需要从头去研究如何发电(比如画地图、写支付系统),只需要调用现成的 API,就能像**搭积木一样**快速构建出功能强大的应用。这不仅节省了巨大的开发成本,还让**自动化**成了可能——比如让系统自动处理重复性工作,同步数据或发送通知,把人类从琐碎的劳动中解放出来。同时,API 还充当了**安全守门人**的角色,确保只有合法的插头(请求)才能接通,让企业可以放心地使用第三方提供的尖端服务。 + +## 3. API 是如何工作的? + +如果说电源插座是解释“接口”概念的基础版,那 API 的实际运作动态更像是在**餐厅点餐**。 + +在这个比喻中,你(客户端)坐下看菜单,决定了要吃什么。这时候,服务员(API)走了过来,记下你的需求,然后转身跑向厨房(服务器)。厨房里的大厨根据订单开始忙碌,做出一盘精美的菜肴。最后,服务员再次现身,把食物端到你面前。 + +在这个过程中,**API 请求**就像是你的订单。它包含了你想访问的“端点”(菜名)、你想做的动作(是获取数据还是提交信息)以及具体的参数(比如只要伦敦的天气)。而 **API 响应** 则是服务员带回的结果,其中包含了告诉你是否成功的“状态码”(比如 200 代表大功告成)以及你真正想要的“响应体”数据。 + +## 4. 现实世界的例子:我们身边的“服务窗口” + +API 无处不在,在后台默默工作。 + +**天气预报 API** +它就像一个专门提供气象信息的窗口。你的天气应用向它发送坐标和密钥,它就回传一串 JSON 数据。 + +- **一个简单的“请求”示例:** + - **Endpoint:** `/current-weather` + - **Parameters:** `city=London` & `apiKey=your_access_key` +- **“响应”(回传的数据):** + `json + { + "city": "London", + "temperature": "15°C", + "condition": "Cloudy", + "humidity": "70%" + } + ` + 应用拿到这些数据后,再把它们漂亮地展示在你的手机屏幕上。 + +**地图服务 API** +不管是外卖平台还是打车软件,它们本身并不生产地图。它们通过调用高德或 Google Maps 的 API,就能获得精准的路线规划和导航功能。 + +- **一个简单的“请求”示例:** + - **Endpoint:** `/directions` + - **Parameters:** `origin=Eiffel Tower` & `destination=Louvre Museum` & `mode=driving` +- **“响应”(回传的数据):** + `json + { + "total_distance": "4.5 kilometers", + "estimated_time": "15 minutes", + "route_steps": [ + "1. Head east on Champ de Mars...", + "2. Turn left onto Quai Branly...", + "..." + ] + } + ` + 通过这些数据,应用就能在地图上绘制路线并提供导航指令。 + +**社交媒体登录 API** +当你点击“使用 Google 登录"时,购物应用会问 Google API:“这个用户是谁?”Google 验证后告诉应用:“他是 John Doe”。这样,你不用输入密码就能安全登录。 + +**大语言模型 API(AI 的超级大脑)** +这是目前最火的“万能插座”。你传过去一段话,它就能回传一段有逻辑的回复。开发者不需要自己训练大模型,只需要接通 OpenAI 或 DeepSeek 的 API,就能让自己的应用瞬间变聪明。 + +## 5. 在代码中,API 长什么样? + +当你真正开始动手写代码时,会遇到一些技术名词。别担心,你不需要现在就记住所有细节,只需要看看它们在代码里是怎么“呼吸”的。 + +### 5.1 Python 中的 AI 调用 + +在 Python 中调用 OpenAI 的 API 非常直观。你可以通过设置 `base_url` 来指定服务器地址。 + +```python +import openai + +openai.api_key = "YOUR_OPENAI_API_KEY" +# 如果使用第三方代理或 DeepSeek 等兼容接口,可以修改 base_url +# openai.base_url = "https://api.deepseek.com/v1/" + +response = openai.ChatCompletion.create( + model="gpt-3.5-turbo", + messages=[ + {"role": "system", "content": "你是一个得力的助手。"}, + {"role": "user", "content": "你好,怎么使用 API?"} + ] +) + +print(response.choices[0].message["content"]) +``` + +许多模型(如 DeepSeek)都兼容 OpenAI 的格式。你只需要更换 API 密钥和地址,就能无缝切换。 + +### 5.2 前端开发中的安全实践 + +如果你在做网页,切记不要在浏览器代码里直接写 API 密钥,否则会被人偷走。通常的做法是写一个**后端代理**,让服务器去替你完成调用。 + +```javascript +// 后端 Node.js 示例 +const express = require('express') +const axios = require('axios') +const app = express() +app.use(express.json()) + +app.post('/api/chat', async (req, res) => { + try { + const response = await axios.post( + 'https://api.openai.com/v1/chat/completions', + { + model: 'gpt-3.5-turbo', + messages: [{ role: 'user', content: req.body.message }] + }, + { + headers: { Authorization: `Bearer ${process.env.OPENAI_API_KEY}` } + } + ) + res.json({ reply: response.data.choices[0].message.content }) + } catch (error) { + res.status(500).json({ error: error.message }) + } +}) + +app.listen(3001, () => console.log('服务器运行在 3001 端口')) +``` + +你可以使用 `curl` 命令来测试这个接口: + +```bash +curl -X POST http://localhost:3001/api/chat \ + -H "Content-Type: application/json" \ + -d '{"message":"你好,请问你是谁?"}' +``` + +## 6. 开启你的 API 之旅 + +API 是现代数字世界的基石。通过理解“请求与响应”这个简单的逻辑,你已经迈出了通往软件开发广阔世界的第一步。在接下来的 Z.ai 探索中,我们将亲手尝试这些调用,感受 AI API 的魅力。 + +--- + +**参考资料** + +- [Postman: What is an API?](https://www.postman.com/what-is-an-api/) diff --git a/docs/stage-2/backend/2.1-what-is-api/extra2/images/image1.png b/docs/stage-2/backend/2.1-what-is-api/extra2/images/image1.png new file mode 100644 index 0000000..2dfd8ee Binary files /dev/null and b/docs/stage-2/backend/2.1-what-is-api/extra2/images/image1.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/chapter5-from-database-to-supabase.md b/docs/stage-2/backend/2.2-database-supabase/chapter5/chapter5-from-database-to-supabase.md new file mode 100644 index 0000000..bc3e62a --- /dev/null +++ b/docs/stage-2/backend/2.2-database-supabase/chapter5/chapter5-from-database-to-supabase.md @@ -0,0 +1,1742 @@ +# Project 5: 从数据库到 Supabase + +在上节课中,我们学会了 UI 设计程序 Mastergo 和 Figma 的基本用法,能够使用 github 进行代码的获取与版本管理,并通过 Zeabur 部署网站将自己的应用 / 网站传达给更多人使用。 + +为了帮助大家更好地衔接知识,在开始本节课关于设计工具与部署的新内容前,让我们一起通过几道简单的题目快速回顾一下上节课的核心知识点: + +1. 什么是前端设计工具、Figma、MasterGo 的定义和使用方式。 +2. 将设计稿转换为代码的基础方法。 +3. 什么是 Github,如何配置 SSH,如何构建自己的第一个仓库。 +4. 部署是什么意思,如何使用 Zeabur,如何将 Github 或本地代码部署至公共网络给大家访问。 + +如果对以上任何一个问题还有印象模糊的地方,建议先回顾一下上节课的文档和讲义。欢迎随时在微信学习群中提出疑问。 + +在本节课中,我们将学习如何让一个 APP / 网站从能跑起来变为更接近真实线上产品:除了用数据库管理程序运行中的各种数据变化外,还要具备完善的用户体系(注册、登录、权限等)以及其他关键后端能力。我们会以 Supabase 这一后端服务平台为主线,先用它实现“数据库 + 用户系统”这两项基础功能,再以 Supabase 提供的组件为参照,进一步理解现代云服务后端服务通常包含的核心模块,以及各模块的具体职能与作用逻辑。 + +# 你将学到 + +1. 什么是数据、什么是数据库,常见数据库与使用方法 +2. 什么是 supabase,如何使用 supabase 进行基础的数据库操作 +3. 如何使用 supabase 为应用添加基础用户管理功能 +4. 学会 Supabse 进阶功能:realtime、storage、edge function +5. 学会为Supabase增加 google 与 github 登录支持 + +- 一款支持用户注册 / 登录,并能将数据存入在线数据库的基础应用 +- 一套可复用的 Supabase 后端代码模板(数据库 + 用户管理等),供后续项目直接套用 + +# 1. What is Database + +## 1.1 What is Data + +在数字世界里,数据(Data)无处不在。简单来说,数据是信息的载体。你朋友的联系方式、一篇微信文章、一条短视频、游戏里的角色等级,这些都是数据。在我们的应用中,数据就是需要被记录和管理的一切信息,比如用户的个人资料、订单历史、程序设置等。 + +一般而言,数据在程序中有不同的表现形式,最简单的就是变量,我们可以用不同变量记录简单的数字: + +```Plain +# Python variable definition examples + +# Integer variable: stores age information +age = 30 + +# Boolean variable: stores status (whether active) +is_active = True # True means active, False means inactive + +# List variable: stores a set of score data +scores = [85, 92, 78, 90] # Contains 4 integer elements representing different scores + +# Dictionary variable: stores multiple related information of a user +user_info = { + "age": 30, # Key "age" corresponds to the value of age + "height": 1.80, # Key "height" corresponds to the value of height (unit: meter) + "login_count": 156 # Key "login_count" corresponds to the value of login times +} +``` + +而对于上述所说的个人资料、订单历史这类复杂的数据而言,我们可以用更复杂的表格进行数据的表示: + +| user_id | name | email | +| ------- | ----- | ----------------- | +| 1001 | Alice | alice@example.com | +| 1002 | Bob | bob@example.com | + +| order_id | user_id | amount | status | +| -------- | ------- | ------ | --------- | +| 901 | 1001 | 29.99 | completed | +| 902 | 1002 | 15.50 | pending | + +但对于结构复杂、具有层级关系或字段不固定的数据,我们可以用 JSON 格式进行描述 —— 它是互联网通用的数据中间格式,几乎所有程序都能读取解析,跨系统传数据很方便。例如,一个订单可能包含多个商品,每个商品又有自己的名称、数量和价格。用传统的表格来表示会很笨拙:要么得拆成 “订单表”“商品表” 多张表,靠关联字段才能体现 “订单包含商品” 的关系;要么在一张表用 “商品 1 名称、商品 1 价格、商品 2 名称……” 这类冗余字段,遇到商品数量不固定时根本没法适配;而 JSON 能直接用嵌套结构把 “订单 - 商品 - 商品属性” 的层级说清,既直观又灵活。 + +```JSON +{ + "order_id": 901, + "user_id": 1001, + "amount": 29.99, + "status": "completed", + "items": [ + { "sku": "BG-001", "name": "牛肉汉堡", "quantity": 1, "price": 18.00 }, + { "sku": "SD-003", "name": "炸薯条", "quantity": 1, "price": 6.99 }, + { "sku": "DK-002", "name": "可乐", "quantity": 1, "price": 5.00 } + ], + "shipping_address": { + "street": "科技园路123号", + "city": "深圳", + "zip_code": "518057" + } +} +``` + +更进一步的,如果我们考虑一个被编码成向量(Vector)的数据,向量数据通常是文本、图片或音频等非结构化数据经过 AI 模型(如 Embedding 模型)处理后得到的数值表示。它的表示形式可能是: + +`[0.123, -0.456, 0.789, ..., -0.234]` (一个由几百甚至上千个浮点数组成的数组) + +总的来说,在现实世界中有太多不同形态、用途的数据值得我们详细分析,每种数据可能都需要专门的数据库用于存储,具体可参考下图——是不是感觉非常多? + +![](images/image1.png) + +## 1.2 Why We Need Database + +我们已经了解到真实世界中的数据往往结构复杂,**为了高效存储与使用这些数据,我们需要一个专门的程序或容器来管理它们** —— 这便是数据库(Database)的诞生初衷。数据库本质上是一款特殊程序,核心作用就是对数据进行规范化组织、安全存储、系统化管理,并支持高效查询调用。 + +想象一下,若没有数据库,应用数据会陷入怎样的困境?当用户关闭浏览器或退出应用时,所有临时加载的信息都会直接丢失;我们既无法永久保存用户的使用状态(比如登录信息、个性化设置),也没法在不同用户之间共享关键数据(比如商品库存、订单记录)。我们需要有一个装置帮我们存储所有的数据! + +更灵活的是,数据库的部署方式可按需选择:既可以部署在本地服务器,满足数据本地化管理的需求;也能部署到云端,云端数据库支持弹性扩容(Scale),可随数据量与访问量增长扩展能力、承载海量数据与高并发,即便用户量大幅提升,也能保障用户的正常使用体验。 + +归纳而言,数据库凭借高效的持久化存储、精细化管理与快速查询能力,主要解决了以下核心问题: + +- **数据的持久化存储** : 如果没有数据库,数据将仅存在于应用的内存中,一旦应用关闭,数据就会丢失。数据库解决了这个问题,它将数据持久地存储在硬盘等存储介质上,确保了数据的长期保存,降低了丢失风险。 +- **便捷的数据查询与分析** : 数据库提供了强大的查询语言(如 SQL),让用户可以轻松、高效地对海量数据进行复杂的查询、筛选和分析,从而帮助企业做出更明智的决策。 如果没有数据库,从大量无序文件中查找特定信息将是一项极其耗时且困难的任务。 +- **支持高性能与高并发访问** : 数据库通过索引优化、查询缓存、连接池以及分布式架构等技术,能够在毫秒级时间内响应查询请求,并支撑成千上万用户的并发访问。这对于现代互联网应用(如电商平台秒杀活动、社交网络实时动态)至关重要,确保了系统的响应速度和用户体验。如果没有数据库的高性能支撑,面对海量用户请求时系统将会出现严重延迟甚至崩溃。 +- **保证数据的完整性和一致性** : 数据库通过一系列机制(如约束、触发器)来确保数据的准确性和一致性。 这意味着数据库中的数据必须符合预设的规则,例如,用户的年龄必须是数字,订单号必须是唯一的,从而有效防止了非法或无效数据的产生。 +- **确保数据的安全性** : 数据库提供了强大的安全机制,包括用户身份验证、访问控制和数据加密等,以保护数据免受未经授权的访问、修改或破坏。为了应对硬件故障、人为失误或恶意攻击等意外情况,数据库还提供了数据备份和恢复功能。 通过定期备份,可以在数据丢失或损坏时及时恢复,保障了业务的连续性。 + +## 1.3 Relational Database VS Non-Relational Database (NOSQL) + +前面我们已经了解了数据库的核心价值、部署方式与弹性优势,而在实际选择时,首先要面对的就是数据库的两大核心类别:关系型数据库与非关系型数据库(NOSQL),我们可以用简单的两段话简单理解他们的区别: + +关系型数据库就像结构严谨的Excel表格,所有数据必须预先定义好格式(定义好 Schema 的内容, 比如要有姓名和年龄,且姓名必须是文字,年龄必须是数字),并通过关联字段(用来连接不同表格的标识,如身份证号)将不同表格连接起来。它的好处是数据精确可靠,特别适合银行转账、库存管理等不能出错的场景,但缺点是调整结构比较麻烦,海量数据下性能会受限。 + +非关系型数据库则像灵活的文件夹,可以存放格式各异的文档、图片或键值对(类似字典的"词-解释"结构),不需要提前规定好每份数据的结构。它更容易应对快速变化的需求和超大规模数据(比如社交媒体的海量帖子),扩展(增加服务器提升性能)起来也更方便,但牺牲了部分关联查询能力(跨不同数据表整理信息的能力)和一致性保障(确保数据时刻准确不矛盾),适合对容错性要求较高的互联网应用。 + +那么,实际应用中该如何选择数据库?从场景划分总结来看,关系型数据库常见于金融交易、库存管理、订单处理、账务系统等需要强一致性、复杂事务处理以及频繁读写均衡访问的场景;而非关系型数据库更适配社交媒体内容存储、实时日志分析、物联网海量数据写入、推荐系统特征读多写多等高并发、读写模式不均衡且结构灵活的需求。 + +但对于企业而言,在初级阶段并不需要花大量时间思考什么需要使用什么数据库。当前的数据库已是非常成熟的产品服务,最直接的方式是咨询不同云服务厂商(指提供服务器、存储、数据库、软件、算力等 IT 资源与技术服务的服务商)。我们可直接对接云服务官方销售,根据自身产品业务需求匹配适配的数据库方案;而构建企业级应用的便捷路径,便是优先与专业厂商合作。(需注意:企业级服务价格通常较高,建议先多方调研对比,也可选择购买服务器自行部署开源数据库程序作为替代方案。) + +我们也可参考某家云厂商的[数据库选型推荐](https://help.aliyun.com/zh/govcloud/getting-started/select-database-services),根据场景可进行不同数据库类型的选择,你可以对比不同云厂商的数据库规格选出最合适的进行使用。 + +| 数据库类型 | 数据库名称 | 价格 | 适用场景 | +| ---------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | +| 关系型数据库 | RDS MySQL版 | 低 | 基础版:学习以及小型网站高可用版:一定业务压力的中型数据库场景集群版:业务不允许中断,访问压力较大 | +| RDS SQL server版 | 高 | 基础版:测试以及小型商业化网站高可用版:企业级商业化网站集群版:企业业务不允许中断,访问压力较大 | | +| RDS PostgreSQL版 | 最低 | 基础版:学习以及小型网站高可用版:一定业务压力的中型数据库场景集群版:业务不允许中断,访问压力较大的场景,其性能较一般MySQL高 | | +| RDS PPAS版 | 高 | 通用型:兼容Oracle业务,但业务压力Udacity,虚拟化可以满足其需求独享型:面对需要独享物理机的业务,一般为高并发Oracle类业务 | | +| DRDS | 中 | 入门版本:4 Core 8 G,价格亲民,适合中小型在线业务企业版:16 Core 32 G,复杂 SQL 响应好,适合超高并发在线业务至尊版:32 Core 64 G,复杂 SQL 执行响应最好,提供超大规格选择 | | +| NoSQL数据库 | Redis | 中 | 双机热备Redis:一般作为持久化数据库提高业务可用性集群版本的Redis:一般作为缓存层,加速应用访问,解决一般数据库无法负载的读取压力 | +| MongoDB版 | 中 | 单节点实例单节点:适用于开发、测试及其他非企业核心数据存储的场景副本集实例:适用于某些业务场景下对数据库有更高读取性能需求,如阅读类网站、订单查询系统等读多写少场景或有临时活动等突发业务需求分片集群实例:基于多个副本集(每个副本集沿用三副本模式)组成的分片集群实例,提供更高的读取性能需求,为实时在线业务提供高速读取性能 | | + +光说不易理解,我们通过一个具体的“博客文章”场景,来看看同样的数据在关系数据库 (SQL) 和不同类型的非关系数据库 (NoSQL) 中是如何存储的。 + +假设我们有一个博客平台,需要存储以下信息: + +- 用户(Users):用户 ID、用户名、邮箱 +- 文章(Posts):文章 ID、标题、内容、作者 ID +- 评论(Comments):评论 ID、评论内容、评论者 ID、所属文章 ID +- 标签(Tags):标签 ID、标签名 +- 文章与标签的关系:单篇文章关联的多个标签、单个标签对应的多篇文章 + +### 关系数据库 (SQL) 示例 + +在SQL数据库中,我们会将不同类型的数据分别存储在不同的表中,并通过“外键”将它们关联起来。这种结构清晰、规范,减少了数据冗余。 + +以 “内容平台的文章管理” 为例,我们不会把 “用户、文章、评论、标签” 混存,而是拆成 5 张功能单一的表,每张表都有明确的 “职责边界” 和严格的结构定义(Schema): + +- `users` 表 (存储用户信息) + +| user_id (主键) | username | email | +| -------------- | -------- | ----------------- | +| 101 | Alice | alice@example.com | +| 102 | Bob | bob@example.com | + +- `posts` 表 (存储文章信息) + +| post_id (主键) | title | content | author_id (外键) | +| -------------- | --------- | ------------------------------ | ---------------- | +| 1 | 初识SQL | 这是关于SQL数据库的一篇文章... | 101 | +| 2 | NoSQL入门 | NoSQL提供了灵活的数据模型... | 102 | + +- `comments` 表 (存储评论信息) + +| comment_id (主键) | body | commenter_id (外键) | post_id (外键) | +| ----------------- | ---------------- | ------------------- | -------------- | +| 1001 | 写得很棒! | 102 | 1 | +| 1002 | 学习了。 | 101 | 2 | +| 1003 | 有没有更多例子? | 101 | 1 | + +- `tags` 表 (存储标签) + +| tag_id (主键) | tag_name | +| ------------- | -------- | +| 51 | 数据库 | +| 52 | 技术 | +| 53 | 入门 | + +- `post_tags` 表 (存储文章与标签的多对多关系,体现联表特点) + +| post_id (外键) | tag_id (外键) | +| -------------- | ------------- | +| 1 | 51 | +| 1 | 52 | +| 2 | 51 | +| 2 | 52 | +| 2 | 53 | + +若需查询 “Alice 发表的《初识 SQL》(post_id=1)的完整信息(含文章内容、作者、评论、标签)”,需执行多表连接(JOIN)查询,通过外键关联 5 张表并聚合数据,SQL 语句如下: + +```SQL +SELECT + p.title, + p.content, + u.username AS author, + c.body AS comment, + t.tag_name AS tag +FROM + posts p +JOIN + users u ON p.author_id = u.user_id +LEFT JOIN + comments c ON p.post_id = c.post_id +LEFT JOIN + post_tags pt ON p.post_id = pt.post_id +LEFT JOIN + tags t ON pt.tag_id = t.tag_id +WHERE + p.post_id = 1; +``` + +这个查询会跨越5个表,将所有相关数据聚合在一起返回。这是关系数据库的核心优势:通过规范化和连接操作,可以灵活地进行各种复杂的查询,同时保证了数据的一致性和最小冗余。 + +### 非关系数据库 (NoSQL) 示例 + +NoSQL 数据库(如 MongoDB、Redis)的设计思路与 SQL 相反,它不强调数据的拆分与规范,通常会将业务上相关联的所有数据打包聚合在一起,以减少查询时的连接操作,从而提高读取性能。 + +在 NoSQL 数据库中,文档数据库(Document Database) 是最常用的类型之一,MongoDB 就是典型代表。它以 “文档” 作为基本存储单元,这里的 “文档” 并非我们日常理解的 “文章”,而是一种类似 JSON 的数据结构(MongoDB 中实际使用 BSON 格式,支持更多数据类型):无需预先定义统一的 Schema(数据结构),每个文档的字段可以灵活增减,字段类型也能自由调整,完美适配数据格式多变的场景。 + +在文档数据库中,通常会将一篇文章及其所有相关信息(如评论、标签)存储在一个文档中(文档格式类似 JSON,可灵活定义字段,无需预先制定 Schema),核心逻辑是 “将‘一个业务场景下的完整信息’存放在一个文档中”,避免查询时的多数据源拼接。 + +`posts` 集合中的一个文档示例: + +```JSON +{ + "_id": 1, + "title": "初识SQL", + "content": "这是关于SQL数据库的一篇文章...", + "author": { + "user_id": 101, + "username": "Alice", + "email": "alice@example.com" + }, + "tags": [ + "数据库", + "技术" + ], + "comments": [ + { + "comment_id": 1001, + "body": "写得很棒!", + "commenter": { + "user_id": 102, + "username": "Bob" + } + }, + { + "comment_id": 1003, + "body": "有没有更多例子?", + "commenter": { + "user_id": 101, + "username": "Alice" + } + } + ] +} +``` + +这种设计的优势非常直观:当你需要获取 “第一篇文章的完整信息(含作者、评论、标签)” 时,只需通过 `_id:1` 查询这一个文档,数据库一次读取就能返回所有数据,无需像 SQL 那样执行 3-4 次表连接操作,读取效率大幅提升。 + +但它也存在明显的 trade-off(取舍):由于数据是 “聚合存储”,会不可避免地产生数据冗余—— 比如作者 “Alice” 的 `username` 被嵌入到她写的每一篇文章文档中,如果某天 “Alice” 将用户名改为 “Alice_New”,理论上需要遍历所有包含她信息的文章文档,逐一更新 `author.username` 字段,不仅操作繁琐,还可能因网络或服务器问题导致部分文档更新失败,出现 “同一用户在不同文章中用户名不一致” 的情况。 + +不过在实际业务中,这种冗余往往是 “可接受的”:对于博客、资讯、电商商品详情等 “ **读多写少** ” 的场景(用户查看内容的次数远多于作者修改用户名的次数),用少量的冗余换取 “极致的读取性能” 是更优的选择;而如果是 “写多读少”(如频繁修改用户信息)的场景,则需要结合业务需求权衡是否使用文档数据库。 + +以上是对不同数据库的简单介绍,如果你对更多具体的数据库类型感兴趣,你可以参考如下资料尝试不同类型的数据库。 + +Examples of SQL databases: +[Db2](https://www.ibm.com/products/db2-database)、[MySQL](https://cloud.ibm.com/catalog#highlights)、[PostgreSQL](https://www.ibm.com/think/topics/postgresql)、[YugabyteDB](https://www.yugabyte.com/)、[CockroachDB](https://www.cockroachlabs.com/)、[Oracle Database](https://www.ibm.com/products/postgres-enterprise)、[Azure SQL Database](https://www.ibm.com/consulting/microsoft) + +Examples of NoSQL databases: +[Redis](https://www.ibm.com/think/topics/redis)、[CouchDB](https://www.ibm.com/think/topics/couchdb)、[MongoDB](https://www.ibm.com/think/topics/mongodb)、[Cassandra](https://cloud.ibm.com/catalog#highlights)、[Elasticsearch](https://www.ibm.com/think/topics/elasticsearch)、[BigTable](https://www.techtarget.com/searchdatamanagement/news/252512583/Google-scales-up-Cloud-Bigtable-NoSQL-database)、[Neo4j](https://neo4j.com/users/ibm/)、[HBase](https://www.ibm.com/think/topics/hbase) + +# 2. Supabase + +在前面我们已经介绍了几类常见的数据库,以及它们各自适合的使用场景。不过在真实项目里,数据库通常只是后端体系中的一个基础模块:除了存储和查询数据,你还需要解决**用户注册登录、权限校验、文件上传与存储、对外 \*\***API\***\* 接口、甚至定时任务、实时通知**等一整套问题。仅仅选好数据库,并不能让你的应用“立刻就能上线运行”,中间还隔着一大圈繁琐的后端工程工作。 + +所以,我们需要考虑一个更大的背景: **后端服务** 。一个完整的应用,通常都由“前端 + 后端”组成:前端负责页面展示和用户交互,后端则负责数据存储、用户登录、业务逻辑处理等。过去,开发者往往需要自己搭建服务器、配置数据库、设计并实现 API,还要手动处理权限管理、安全策略、扩展性和监控运维等事务,整个过程既重复又耗时。为了解决这些重复劳动,业界出现了 **BaaS(Backend as a Service,后端即服务)** :把数据库、用户认证、文件存储、实时能力等常见后端功能打包成一个云端平台,开发者通过 SDK / API 就能直接调用这些能力,而无需从零搭建和运维基础设施。 + +在这个背景下,[Supabase](https://supabase.com/) 就可以看作是新一代的 BaaS 代表:它以 PostgreSQL 作为核心数据库,在其之上集成了 Auth、Storage、Realtime、Edge Functions、Vector 等一整套后端能力,为开发者提供一个“以 Postgres 为中心的一站式后端平台”。接下来,我们就从这个角度出发,从“只选数据库”升级到“选择完整的后端开发平台”,具体看看 Supabase 能帮我们省掉哪些工作,又是如何让一个项目从原型到可用产品的距离大幅缩短的。 + +## 2.1 Step by Step Guide + +在清晰把握 Supabase 的整体定位后,接下来我们将沿着 Supabase 控制台的操作路径,逐项拆解它具体提供哪些核心能力,以及每项能力对应的核心职责。我们会详细介绍 supabase 涉及的每个选项,帮助你快速入门 supabase 的基本操作。 + +![](images/image2.png) + +访问 Supabase 官网并登录后,在控制台首页点击 New project 进入创建流程; + +输入需要配置的主要内容 Project Name、数据库密码,地址只需要选择为与程序目标用户最接近的区域即可。 + +![](images/image3.png) + +创建成功后,控制台左侧侧边栏将显示所有核心功能模块(Table Editor、SQL Editor、Database、Authentication 等),后续操作将围绕这些模块展开。 + +![](images/image4.png) + +### Table Editor + +Table Editor 可以当成是 Supabase 的可视化数据表编辑器,它能让你像操作 Excel 一样直接查看和修改数据库里的数据,无需编写 SQL 语句,只需要用鼠标交互即可修改数据内容。 + +![](images/image5.png) + +其中值得关注的是 Schema,Schema 可理解为数据库内的 “资源容器”,用于对表、视图、函数、索引等资源进行分组管理,主要作用有二:一是避免命名冲突(不同 Schema 下可存在同名table),二是实现权限隔离(如仅允许特定用户访问某 Schema 下的表); + +点击编辑器顶部的 Schema 下拉框可切换不同容器,日常开发中一般只需关注两类: + +- `public`:默认的公共资源容器,开发者新建的业务表(如 “文章表”“评论表”)均存储于此; +- `auth`:用户认证专属容器,其中的 `users` 表自动存储所有注册用户信息(如用户 ID、邮箱、登录时间),不建议手动修改此 Schema 下的默认表,避免影响认证功能; + +![](images/image6.png)![](images/image7.png) + +### SQL Editor + +SQL Editor 作为 Supabase 的 SQL 语句执行器,可让你用代码的方式直接操作数据库。你可以让大模型直接生成 SQL 语句,在右侧输入后点击 RUN 即可用语句创建或修改 table,也可以直接在 Results 中直接看到筛选出的 table 数据。 + +![](images/image8.png) + +你可以在运行 RUN 之后,在 Table Editor 的 public schema 里找到新建后的数据表;并且运行后的语句会保存在左侧的 PRIVATE 栏中,甚至可以点击下方的爱心标志对这一条查询或创建语句进行收藏。 + +### Database + +Database 是 Supabase 的数据库管理中心,支持可视化地查看和管理所有数据表,并通过表的相互连线理解不同表间的关联关系(即外键约束,表示数据间的引用关系)。 + +![](images/image9.png) + +如果你想要手动新建 table,可以在 tables 中直接新建表格,我们会在之后的教程中详细讲解。 + +![](images/image10.png) + +### Authentication + +Authentication 负责管理用户的注册、登录和权限。默认的用户管理系统数据都在此处存储,它提供了开箱即用的用户注册、登录、密码重置、邮箱验证等功能,并支持第三方 OAuth 登录(如微信、GitHub、Google 等)。所有用户数据会自动同步到数据库的 `auth.users` 表中。 + +![](images/image11.png) + +你可以在 Provider 选项中找到不同 supabase 支持的用户信息登录入口,默认使用 Email;如果你想使用 Github 或者 Google 账户进行登录,还需要更多属性配置,我们会在下面的课程中进行详细讲解。 + +![](images/image12.png) + +在 Sign In / Providers 里还包含了对注册邮箱行为的控制,如果你不想每次邮箱注册都必须让用户接受邀请后才能成为用户,你可以取消 Confirm email 的强制要求。 + +![](images/image13.png) + +如果你想切换非 Supabase 的其他 auth 系统服务商,你可以点击 Third Party Auth,比如此处就使用 Clerk 作为第三方的系统服务商。 + +![](images/image14.png) + +如果你担心注册用户在短期内访问量过大,你可以在 Rate Limits 中启用对应的流量限制策略: + +![](images/image15.png) + +### Storage + +Storage 是 Supabase 的存储系统,兼容 amazon cloud 的 s3 概念,可用于存储任意类型的文件(如图片、视频、文档、音频等),并提供访问权限管理(公开或私有)和下载链接获取(永久链接或临时链接),你能够很方便在应用中对用户涉及到的文件内容进行上传与下载管理,并与 Supabase 的认证系统无缝集成,实现精细化的访问控制。 + +![](images/image16.png) + +我们将会在本节课的进阶 project 中讲解 storage 的具体用法。 + +![](images/image17.png) + +如果你想使用 S3 的相关协议进行操作,可以直接使用对应的配置: + +![](images/image18.png) + +> Amazon Cloud(亚马逊云服务,简称 AWS)是亚马逊提供的云计算平台(就像一个大型的网络机房,你可以按需租用计算和存储资源)。S3(Simple Storage Service)是 AWS 里专门用来存储文件的服务(类似一个无限大的网盘,可以存图片、视频、备份等各种文件),它是目前最流行的对象存储服务,已经成为了事实上的行业标准。 +> +> **为什么要做成 S3 兼容 \*\***API\*\* ** ?** :S3 已经存在近 20 年,市面上有大量现成的工具、SDK 和文档,兼容 S3 意味着你可以直接用这些资源,不用从头开始制作各类相关工具,能够快速满足业务上线的需求。 + +### Edge Functions + +如果你不想部署后端,但是想使用数据库和函数操作,你可以使用 Edge Functions 构建无需自建服务器的后端核心能力,它是 Supabase 提供的全球分布式服务端函数。简单来说,它让你无需购买和管理自己的后端服务器,就能直接编写并部署在云端的后端代码。这些函数部署在全球网络的边缘节点上,会自动在离你的用户最近的位置运行,从而大幅降低网络延迟,提供极致的响应速度。你可以在 Supabase 的仪表盘中直接创建、编辑和部署,整个开发流程非常便捷。 + +![](images/image19.png) + +Edge Functions 的一个核心用途是充当安全的中间层,保护你的敏感信息和鉴权密钥。在前端代码中直接调用第三方服务(如 OpenAI、Stripe)会暴露你的 API Key,带来极大的安全风险。通过 Edge Functions,你的前端应用只与你的 supabase 函数通信,所有秘密只在 supabase 中保管。 + +![](images/image20.png) + +Edge Functions 的函数使用 secrets 中暴露的密钥作为环境变量,通过 `Deno.env.get` 加载,从而实现第三方服务的调用。这样一来,敏感密钥就永远不会暴露在客户端(你的浏览器),彻底杜绝了被盗用的风险。 + +![](images/image21.png) + +请求 Supabase Edge Function 时,需在请求头携带对应的 Supabase 密钥,下面是一个极简示例: + +```JavaScript +// 核心配置(替换为你的实际信息) +const projectId = "你的 Supabase 项目ID"; +const functionName = "目标 Edge Function 名称"; +const supabaseKey = "Supabase anon_key"; + +// 调用函数 +async function callEdgeFunction() { + const url = `https://${projectId}.supabase.co/functions/v1/${functionName}`; + + try { + const response = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${supabaseKey}` // 关键:携带密钥完成认证 + }, + body: JSON.stringify({ order_id: "123", action: "refund" }) // 自定义请求数据 + }); + + const result = await response.json(); + console.log("调用成功:", result); + } catch (error) { + console.error("调用失败:", error.message); + } +} + +// 执行调用 +callEdgeFunction(); +``` + +此外,Edge Functions 与 Supabase 的用户认证系统无缝集成。当已登录的用户调用一个函数时,其身份信息会传递给函数。这使得你可以在函数内部轻松识别当前用户,并根据其身份执行权限控制。更重要的是,函数在操作数据库时会自动遵循你设置好的行级安全策略(Row Level Security),确保用户只能访问和修改他们有权操作的数据,让构建安全的多用户应用变得简单。 + +Edge Functions 的应用场景非常广泛,能够处理各种后端任务。它们非常适合用来监听来自第三方服务的 Webhook 事件(例如支付成功、代码提交等),并自动执行相应的数据处理逻辑。你也可以用它来发送邮件通知、生成 PDF 报告、创建自定义的 API 接口来封装复杂的业务逻辑,或者执行任何你希望在服务端完成的计算任务,极大地扩展了你应用的能力。 + +具体到一个常见的例子:身份认证工具 Clerk 。Clerk 仅用于处理用户登录、注册、信息更新等认证相关操作,并不直接管理你的业务数据库。如果你想要将这些认证动态同步到业务数据库中,则需要通过触发 Webhook 事件请求 Edge Functions 实现。Edge Functions 能够监听 Clerk 发出的 Webhook 信号,自动执行数据同步逻辑,让 Supabase 数据库中的用户信息与 Clerk 登录状态实时对齐,全程无需你部署独立后端。 + +### Realtime + +Realtime 是 Supabase 的实时数据同步引擎,它允许你的应用即时接收数据库的变化通知,而无需反复轮询 API。当数据库中的数据发生 `INSERT`、`UPDATE` 或 `DELETE` 操作时,Realtime 会通过 WebSocket 将这些变化实时推送给所有已连接的客户端。这对于构建需要实时交互的应用至关重要。 + +Realtime 主要包含三大核心功能,覆盖了绝大多数实时场景: + +1. **Postgres Changes:** 直接监听数据库表的变化。你可以精确地订阅特定表、特定事件(增、删、改),甚至可以根据筛选条件来接收通知,并与行级安全策略(Row Level Security)完美集成,确保用户只能收到他们有权限查看的数据变更。 +2. **Broadcast:** 允许客户端之间通过频道(Channel)发送低延迟的临时消息。这非常适合实现聊天室、实时光标追踪、在线游戏状态同步等功能。 +3. **Presence:** 用于追踪和同步在线用户状态。你可以用它来轻松实现“谁在线上”、“当前有X人正在查看”等功能,非常适合协作类应用。 + +我们会在后续的项目制学习中详细介绍该部分的内容。 + +### Project Settings + +Project Settings 是 Supabase 项目的高级配置部分,你可在此实现计算资源的深度调度,以及各类功能底层参数的精细化配置。 + +![](images/image22.png) + +在入门阶段,我们只需聚焦以下两个核心板块,一个是 Data API,我们在此可获取关键的 “Supabase URL”, 它是形如 `https://xxx.supabase.co` 的 RESTful 端点,是所有数据查询、新增、修改、删除操作的 “入口地址”。前端或服务端需通过该 URL 初始化 Supabase 客户端,建立与数据库的连接。 + +![](images/image23.png) + +另一个重点是 API Keys,选择 “Legacy anon, service_role API keys” 标签页,其中的 anon public 密钥 是前端场景的重要身份凭证,它的权限被 RLS 严格限制,仅能访问用户被授权的数据。而 service_role 密钥属于 “服务端高权限密钥”,具备绕过行级安全的能力,可执行批量数据操作、系统级配置等敏感操作。绝对禁止公开分享,若泄露需立即生成新密钥并更新服务端配置。 + +![](images/image24.png) + +其余配置项在当前阶段无需深究,待后续有进阶使用需求时再逐一探索即可。 + +## 2.1 Create Your First SQL Table + +以上是 Supabase 的界面介绍,接下来我们将深入 Supabase 的核心数据库的操作环节。 + +在 Supabase 中创建数据表,主要有以下两种常用方式,你可以根据需求选择: + +1. (推荐)借助大语言模型生成适配 Supabase 的 SQL 语句,直接在 **SQL Editor(** 前文介绍的 SQL 语句执行器)中粘贴执行,高效快捷,我们会在下个部分环节重点说明这个操作过程。 +2. 通过可视化操作创建:在左侧侧边栏找到 Database 模块,点击进入后选中侧边栏的 Tables,在右侧点击 New table 按钮,即可通过图形化界面创建数据表。 + +![](images/image25.png) + +值得注意的是,对应数据表的名称以及存储的数据类型可在下方的 Columns 中指定。 + +![](images/image26.png) + +对于关系数据库,其中很重要的特点是表与表之间的关联,你可以在下方找到 `Foreign keys` ,点击创建相应的关联关系: + +![](images/image27.png) + +其中 `Foreign keys` 表达了表与表之间的关联关系:一个或一组字段,它在当前表(子表)中的值,会引用另一张表(父表)中主键的值。 + +例如,在创建 `学生表`的时候,我们可以这样定义外键:(`所属班级编号` 这一列是一个外键。这个外键引用了 `班级表` 里的 `班级编号` 这一列。) + +```SQL +CREATE TABLE 学生表 ( + 学生学号 INT PRIMARY KEY, + 学生姓名 VARCHAR(50), + 所属班级编号 INT, + FOREIGN KEY (所属班级编号) REFERENCES 班级表(班级编号) +); +``` + +更具体举例而言,我们可以可视化观察对应的表的结构: + +班级表: +这张表里记录了所有班级的信息,每个班级都有一个独一无二的班级编号。班级编号就是这张表的主键 (Primary Key),是每个班级的唯一身份证。 + +| 班级编号 | 班级名称 | +| -------- | ---------- | +| 101 | 一年级一班 | +| 102 | 一年级二班 | + +学生表: +这张表记录了所有学生的信息。每个学生都属于一个特定的班级,对吗?那么我们怎么知道哪个学生在哪个班级呢? + +我们可以在学生表里增加一列,叫做 `所属班级编号`。 + +| 学生学号 | 学生姓名 | 所属班级编号 | +| -------- | -------- | ------------ | +| 2024001 | 张三 | 101 | +| 2024002 | 李四 | 102 | +| 2024003 | 王五 | 101 | + +在该例子中,学生表中的 `所属班级编号` 列就是外键 (Foreign Key)。 + +在 Supabse 中,点击添加 Foreign Key 后,你可直接选择进行关联表对应列的选取 + +![](images/image28.png) + +## 2.3 SQL Editor 简介与数据库基本操作 + +接下来我们将分步执行一系列 SQL 脚本,熟悉常见的 SQL 中的增删查改操作。你可以将每个步骤的代码复制到 SQL Editor 中,执行并观察结果。 + +你可以在该目录下获得所有的测试 SQL 文件: + +https://github.com/THU-SIGS-AIID/Project5-Supabase-Demos/tree/main/apps/sql-examples + +### **2.3.1 **`CREATE`** - 创建表结构** + +`CREATE TABLE` 语句用于为新表定义模式(Schema),包括其列(Columns)、对应的数据类型(Data Types)以及任何约束(Constraints),简单理解是创建了一个数据表。 + +```SQL +-- Step 1: Create the 'orders' table +-- This file is fully independent and creates a sample table for later steps. +CREATE TABLE IF NOT EXISTS orders ( + id serial PRIMARY KEY, + user_id int NOT NULL, -- User ID + status text NOT NULL, -- Order status (e.g. paid, pending) + amount numeric(10, 2) NOT NULL, -- Order total amount + details jsonb, -- Item and extra details as JSON + placed_at timestamptz DEFAULT now(), -- Order creation time + is_paid boolean DEFAULT false -- Paid flag +); + +-- Expected Output: +-- Orders table created if it did not exist. +-- No data inserted. (Querying returns zero rows for now.) +-- If table already exists, no error occurs. +``` + +成功执行后,系统将提示脚本已完成。你可以在 Table Editor 中看到对应的表被创建完成: + +![](images/image29.png) + +### **2.3.2 **`INSERT`** - 填充初始数据** + +表结构创建完毕后,下一步是使用 `INSERT INTO` 语句向表中添加数据行。 + +```SQL +-- Step 2: Insert initial rows into the orders table +-- Provides realistic, varied data for demo/testing. All values are self-contained. +INSERT INTO orders (user_id, status, amount, details, placed_at, is_paid) VALUES + (2001, 'pending', 23.50, '{"items":[{"sku":"BGR001","name":"Beef Burger","qty":1,"price":12.00}]}', now() - interval '2 days', false), + (2002, 'paid', 50.00, '{"items":[{"sku":"BGR002","name":"Chicken Burger","qty":2,"price":10.00},{"sku":"DRK001","name":"Lemonade","qty":2,"price":5.00}]}', now() - interval '1 day', true), + (2003, 'cancelled', 15.00, '{"items":[{"sku":"FRY001","name":"French Fries","qty":3,"price":5.00}], "reason":"Not available"}', now() - interval '45 days', false), + (2004, 'paid', 22.98, '{"items":[{"sku":"BGR003","name":"Veggie Burger","qty":2,"price":9.99}], "promo":"SUMMER22"}', now() - interval '10 days', true), + (2005, 'pending', 18.75, '{"items":[{"sku":"SAL001","name":"Salad","qty":1,"price":6.75},{"sku":"BGR001","name":"Beef Burger","qty":1,"price":12.00}]}', now() - interval '7 hours', false), + (2006, 'paid', 8.00, '{"items":[{"sku":"DRK002","name":"Cola","qty":2,"price":4.00}]}', now() - interval '3 hours', true), + (2007, 'refunded', 14.50, '{"items":[{"sku":"BGR003","name":"Veggie Burger","qty":1,"price":9.99},{"sku":"FRY001","name":"French Fries","qty":1,"price":4.51}], "refund_reason":"Late delivery"}', now() - interval '15 days', false), + (2008, 'paid', 26.99, '{"items":[{"sku":"BGR002","name":"Chicken Burger","qty":2,"price":10.00},{"sku":"DRK001","name":"Lemonade","qty":1,"price":6.99}]}', now() - interval '12 days', true), + (2009, 'pending', 9.99, '{"items":[{"sku":"BGR003","name":"Veggie Burger","qty":1,"price":9.99}]}', now() - interval '30 minutes', false), + (2010, 'paid', 19.89, '{"items":[{"sku":"BGR001","name":"Beef Burger","qty":1,"price":12.00},{"sku":"DRK002","name":"Cola","qty":2,"price":3.95}]}', now() - interval '5 days', true), + (2011, 'cancelled', 0.00, '{"items":[], "reason":"User cancelled"}', now() - interval '2 days', false); + +-- Expected Output: +-- After running this script, SELECT * FROM orders will show about 11 rows with varied user_id, status, amount, details (JSON), placed_at, and is_paid fields. +-- For example: +-- | id | user_id | status | amount | is_paid | placed_at | +-- |----|---------|-----------|--------|---------|---------------------| +-- | 1 | 2001 | pending | 23.50 | false | 2025-10-28 13:40:00Z| +-- | 2 | 2002 | paid | 50.00 | true | ... | +-- |... | ... | ... | ... | ... | ... | +``` + +执行成功后,此时表中已经插入了原始数据,你可以进入到 Table Editor 界面刷新后看到结果,也可以直接在 SQL Editor 界面中新建窗口,执行查询语句 `SELECT * FROM orders;`查看结果: + +![](images/image30.png) + +### **2.3.3 **`SELECT`** - 读取与查询数据** + +`SELECT` 语句用于从表中检索数据。通过使用不同的子句,可以实现对数据的精确筛选、排序和格式化,我们可参考以下语句一步步执行查看结果: + +```SQL +-- Step 3: SELECT query examples for the orders table + +-- Example 1: Select all fields for all orders +SELECT * FROM orders; +-- Expected Output: Returns all rows and fields. Columns: id, user_id, status, amount, details, placed_at, is_paid. + +-- Example 2: Select only pending orders +SELECT id, user_id, amount FROM orders WHERE status = 'pending'; +-- Expected Output: All rows with status 'pending'; columns: id, user_id, amount. + +-- Example 3: Select specific fields and filter by payment status +SELECT id, status, is_paid, amount FROM orders WHERE is_paid = true; +-- Expected Output: All rows where is_paid is true; columns: id, status, is_paid, amount. + +-- Example 4: Extract all item names from the details (JSON) for each order +SELECT id, details -> 'items' AS item_list FROM orders; +-- Expected Output: Each row shows id and an array from JSON with item details. +``` + +- **示例 1:** 返回 `orders` 表中的所有行和列,与第二步的输出类似。 +- **示例 2:** 仅返回状态为 'pending' 的订单,且只包含指定的列: + +![](images/image31.png) + +- **示例 3:** 仅返回已支付的订单,并显示指定的列: + +| id | status | is_paid | amount | +| --- | ------ | ------- | ------ | +| 2 | paid | true | 50.00 | +| 4 | paid | true | 22.98 | +| 6 | paid | true | 8.00 | +| 8 | paid | true | 26.99 | +| 10 | paid | true | 19.89 | + +- **示例 4:** 返回每个订单的 `id` 和从 `details` 字段中提取的 `items` 数组: + +| id | item_list | +| --- | -------------------------------------------------------------------------------------------------------------------- | +| 1 | `[{"qty":1,"sku":"BGR001","name":"Beef Burger","price":12}]` | +| 2 | `[{"qty":2,"sku":"BGR002","name":"Chicken Burger","price":10},{"qty":2,"sku":"DRK001","name":"Lemonade","price":5}]` | +| 3 | `[{"qty":3,"sku":"FRY001","name":"French Fries","price":5}]` | +| ... | ... | + +### **2.3.4 **`INSERT`** - 插入单条记录** + +在 2.3.2 中,我们演示的是开头时刻初始化批量插入数据,现在我们查看如何新增插入单条数据。 + +```SQL +-- Step 4: INSERT a new order (single row) +-- Example: Add a new paid order for user 2012 with one Chicken Burger +INSERT INTO orders (user_id, status, amount, details, is_paid) +VALUES ( + 2012, 'paid', 9.99, + '{"items":[{"sku":"BGR002","name":"AIID Burger","qty":100,"price":1000}]}', + true +); +-- Expected Output: +-- Before (table fragment): +-- | id | user_id | status | amount | is_paid | +-- | ...| ... | ... | ... | ... | +-- +-- After (last row): +-- | id | user_id | status | amount | is_paid | +-- | xx | 2012 | paid | 9.99 | true | +-- (where xx = next serial value) +``` + +此时再用 `SELECT * FROM orders;` 对数据进行查询,我们可以看到 orders 表成功从 11 个数据变成了 12 个数据。 + +### **2.3.5 **`UPDATE`** - 修改现有数据** + +在实际工作中,我们需要对数据表进行频繁数据更新,我们能够用 `UPDATE` 语句修改表中已存在的记录。 + +```SQL +-- Step 5: UPDATE example +-- Example: Mark order with id=1 as paid and update its status +UPDATE orders SET status = 'paid', is_paid = true WHERE id = 1; +-- Expected Output: +-- Before (row with id=1): +-- | id | status | is_paid | +-- | 1 | pending | false | +-- After (row with id=1): +-- | id | status | is_paid | +-- | 1 | paid | true | +-- All other rows remain unchanged. +``` + +### **2.3.6 **`DELETE`** - 删除数据** + +`DELETE` 语句可用于从表中移除记录,并结合条件对指定部分的数据进行修改。 + +```SQL +-- Step 6: DELETE example +-- Example: Delete orders older than 2 days to clean up old data +DELETE FROM orders WHERE placed_at < now() - interval '2 days'; +-- Expected Output: +-- Before (filtered for affected rows): +-- | id | status | placed_at | +-- | 3 | shipped | 2025-10-13 ... | <-- will be deleted +-- +-- After: +-- No such rows remain. SELECT * FROM orders WHERE placed_at < now()-interval '2 days' yields zero rows. +-- Other rows in orders table are unaffected. +``` + +执行前,你可先执行 `SELECT id, status, placed_at FROM orders WHERE placed_at < now() - interval '2 days';` 进行数据表筛选结果的查看。当运行 `DELETE` 命令后,再次执行相同的 `SELECT` 查询 `SELECT id, status, placed_at FROM orders WHERE placed_at < now() - interval '2 days';`,将返回一个空的结果,表明这些行已被成功删除。 + +## 2.4 RLS (Row level security) + +在学习了数据库的基本操作后,我们需要进一步深入一个保障数据安全的核心概念 ——RLS(行级安全,Row Level Security)。 + +不妨先思考一个实际场景中的关键问题:如何实现数据的 “隔离访问”?比如,只允许用户 A 查看自己的数据,而无法看到用户 B 的信息;再比如,即便某角色拥有数据库的访问权限,如何避免其误操作或泄露其他用户的敏感数据? + +RLS 正是为解决这类数据安全与隔离需求而生。它允许开发者为数据库表定义精细化的安全策略,根据用户的身份信息(如用户 ID、角色权限等),精确控制哪些用户能访问、修改表中的哪些行数据。 +举个典型示例:对于订单表(`orders`),我们可以定义这样一条 RLS 策略 ——“仅当 `orders` 表中某条记录的 `user_id` 列,与当前登录用户的 ID 完全一致时,该用户才能查询到这条订单数据”,从而实现 “用户只能看自己的订单” 的核心需求。 + +当你为某张表启用 RLS后,该表的所有数据操作请求(包括 `SELECT` 查询、`INSERT` 新增、`UPDATE` 修改、`DELETE` 删除)都会触发 RLS 校验:必须通过至少一条安全策略的检查,操作才能执行。若不存在允许该操作的策略,或请求未满足任何策略的条件,数据库会直接拒绝此次操作,从底层阻断非授权访问。 + +在 Supabase 中,RLS 与用户认证系统深度绑定,使用起来更为便捷。Supabase 提供了一个专用函数 `auth.uid()`,它能直接返回 “当前发起请求的已登录用户” 的唯一 ID(格式为 UUID)。借助这个函数,我们可以轻松编写策略,实现 “数据行与用户身份” 的精准关联(比如前文提到的 “订单 `user_id` 匹配当前用户 ID”)。 + +启用 RLS 策略的方式很灵活,你可以在 Supabase 数据库管理界面中的 “RLS” 按钮,直接配置并启用策略: + +![](images/image32.png) + +![](images/image33.png) + +![](images/image34.png) + +主动配置难免显得麻烦,通常,我们在数据表语句创建、初始化的时候就会自动考虑植入对应的 RLS 策略。我们只需在 SQL Editor 中执行类似如下语句,即可自动开启对应数据表的行级安全策略。 + +![](images/image35.png) + +# 3. The First SQL Application + +掌握了数据库基础操作与RLS核心逻辑,我们终于进入本次教程的实践环节。漫长的学习铺垫是为了让后续“从0到1搭建应用”的过程更清晰。接下来,我们将以“汉堡店订单管理”为场景,手把手演示Supabase的常见操作:从应用与Supabase的关联配置,到数据库与登录功能的集成,逐步学习不同操作逻辑。 + +## 3.1 Clone and Run Supabase Demos + +要开展实操,首先需要获取配套的演示代码仓库。你可以让 Trae 或 ClaudeCode 协助 git clone 以下仓库:https://github.com/THU-SIGS-AIID/Project5-Supabase-Demos + +若已配置 SSH 密钥,建议使用 SSH 地址进行 clone(git@github.com:THU-SIGS-AIID/Project5-Supabase-Demos.git)以提升安全性;若 SSH 或 HTTPS 连接遇到网络问题,可以直接点击仓库页面的 “Download ZIP”,获取压缩包后解压即可看到完整代码。 + +![](images/image36.png) + +Clone 后,你同样可以让 Trae 或者是 ClaudeCode 帮你启动项目,例如直接在 Agent 界面中说明: `帮我直接启动这个项目里面的 project 1 `,或者复制对应想启动 project 的绝对路径,粘贴给大模型让大模型直接启动。 + +## 3.2 Project1 - burger-shop-menu-crud + +接下来进入实操环节 —— 以 `project-burger-shop-menu-crud-1` 为例,我们将学习如何通过 SQL 脚本一键初始化 Supabase 数据库,并完成本地项目与 Supabase 数据库的关联配置,让前端能正常读写菜单数据。 + +### Create a Database Using Scripts + +首先,我们需要在 Supabase 中创建需要的数据表的相关内容。进入 Project1 项目目录看到名为 `scripts`的文件夹,其中包含 1 个 `init.sql`数据库脚本文件,它能帮我们自动完成所有数据库相关资源的创建(包括表结构、初始数据等),之后我们会经常用到该文件进行数据库中表的初始化。 + +```SQL +...... + +-- ============================================================================ +-- 2. Create Menu Items Table +-- ============================================================================ + +create table if not exists public.menu_items ( + id uuid primary key default gen_random_uuid(), + name text not null, + description text, + category text check (category in ('burger','side','drink')) default 'burger', + price_cents int not null check (price_cents > 0), + available boolean default true, + emoji text, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now() +); + +-- Comments for documentation +comment on table public.menu_items is 'Burger shop menu items for CRUD demo'; +comment on column public.menu_items.id is 'Unique identifier for each menu item'; +comment on column public.menu_items.name is 'Display name of the menu item'; +comment on column public.menu_items.description is 'Detailed description of the menu item'; +comment on column public.menu_items.category is 'Category: burger, side, or drink'; +comment on column public.menu_items.price_cents is 'Price in cents (integer) to avoid floating point issues'; +comment on column public.menu_items.available is 'Whether the item is currently available for order'; +comment on column public.menu_items.emoji is 'Optional emoji representation of the menu item'; +comment on column public.menu_items.created_at is 'Timestamp when the item was created'; +comment on column public.menu_items.updated_at is 'Timestamp when the item was last updated'; + +...... +``` + +在 SQL Editor 中执行初始化 sql 脚本后,即可在 Table Editor 中看见已创建的数据表。其中数据库初始化代码具体执行逻辑如下: + +1. 创建 menu_items 表 : +2. 这个表用于存储汉堡店菜单中的所有项目。它包含了如 name (商品名), description (描述), price_cents (以美分为单位的价格,避免浮点数精度问题), category (分类) 和 available (是否可售) 等字段。这基本涵盖了一个菜单项所需的所有信息。 +3. 创建 promo_codes 表 : +4. 此表用于管理促销活动,例如折扣码。它定义了 code (折扣码), discount_type (折扣类型,如百分比或固定金额), discount_value (折扣数值) 等字段。 +5. 禁用行级安全 (Row Level Security - RLS) : +6. 为了方便开发和测试,脚本中明确地禁用了 RLS。但结合我们之前学习的 RLS 核心逻辑:RLS 是 Supabase 保障数据安全的关键功能,能通过精细化策略控制 “谁能访问 / 修改哪些数据”(比如只允许管理员编辑促销码,普通用户只能查看菜单)。因此在生产环境中,必须开启 RLS 并配置合理策略,从底层阻断非授权访问(如防止用户恶意修改他人创建的菜单,或泄露促销码规则)。 +7. 插入种子数据 (Seed Data) : +8. 为了让前端项目启动后就能看到真实的菜单与促销数据(无需手动录入测试数据),`init.sql`脚本还会向 `menu_items`和 `promo_codes`表中插入 “种子数据”(即示例数据)。例如,你可以看到各种汉堡、小食、饮料以及多种多样的折扣码。 + +### Set up the connection with database + +数据库准备完成,我们需要将这个前端项目与 Supabase 进行连接,从而正常读取数据库内的数据。我们需要将 Supabase 项目的 URL 和 anon key 写到指定配置中,本项目提供了两种灵活的配置方式: + +1. 通过环境变量配置 + +在项目根目录创建一个 .env 文件,并填入你的 Supabase 凭证: + +```Plain +NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co +NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key +``` + +2. 在项目页面中直接设置 + +为了方便快速演示和切换不同的 Supabase 项目,首页页面右上角提供了一个 设置 按钮。你可以点击它,在弹出的模态框中直接输入或粘贴 Supabase URL 和 anon key。 + +点击 “Save” 后,这些信息会用于动态创建 Supabase 客户端实例,类似下列代码所示: + +```JavaScript +import { createClient, type SupabaseClient } from '@supabase/supabase-js'; + +// Optional client factory for demos: returns null when env is not set. +export function maybeCreateBrowserClient(): SupabaseClient | null { + const url = process.env.NEXT_PUBLIC_SUPABASE_URL; + const anon = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY; + if (!url || !anon) return null; + return createClient(url, anon); +} +``` + +创建完数据库,填写完对应的 Supabase Link 相关配置后,即可看到如下界面,你可以尝试对商品进行增删查改,并观察 Supabase 中对应部分数据表的变化。 + +![](images/image37.png) + +![](images/image38.png) + +### 📚 Assignment + +1. 尝试增加和删除已有项目,在 Table Editor 中查看修改操作对数据表内容变动的影响。 + +## 3.4 Project2 - burger-shop-auth-users + +Project1 实现了 “菜单 CRUD + 数据库连接” ,Project2 将引入更贴近真实业务的核心能力,用户认证(Auth)与行级安全(RLS)权限管理。 + +Project2 包含独立的登录页,支持用户通过「邮箱 + 密码」的方式登录。其核心逻辑是调用 Supabase Auth 提供的原生方法,快速实现认证流程,无需手动开发复杂的登录校验逻辑: + +```Plain +const { error: err } = await supabaseClient.auth.signUp({ + email, + password, + options: { + data: { + full_name: fullName || null, + birthday: birthday || null, + avatar_url: avatarUrl || null + } + } +}); +``` + +![](images/image39.png) + +登录成功后,Supabase 会自动为用户创建一个会话(session),并在后续所有数据库请求中自动携带认证信息;通过 RLS 的作用,每个用户根据对应的认证信息只能看到自己的账户信息(已购买项目、钱包剩余额度),无法看到其他用户的账户信息,这就实现了不同用户登录后的数据隔离,每个人只能看到自己的内容。 + +和 Project 1 一样,你需要先使用 `init.sql` 进行数据表的初始化(注:如果发现初始化出错,请先在 Table Editor 中删除已经创建的数据表,或者是直接删除这个 Supabase Project, 重新新建一个 Project) + +成功使用邮箱注册账户、在邮箱确认注册账户后,登录后进入 Shop 界面即可看到如下内容: + +![](images/image40.png) + +但此时点击 admin,你并不能看到如下界面,你需要尝试在数据表中找到控制用户权限的部分,将权限修改为 `admin`,从而能够在 Admin 界面正常看到如下内容: + +![](images/image41.png) + +值得提示的是,目前每次注册新的邮箱,你都需要在邮箱中进行注册确认才可登录;但这一步并非是必须的,你可以在 Supabase 的 Authentication 栏目中找到 Sign In / Providers,点击Confirm email 取消邮箱的强制确认。 + +![](images/image42.png) + +### 📚 Assignment + +1. 请先领取新手礼包,完成商品购买操作。 +2. 尝试找到用户权限的设定数据表位置,将权限修改为 `admin`,并成功在订单管理界面修改商品数量 +3. 尝试在数据表内定位到钱包金额相关表,通过修改使剩余钱包金额增加。 + +# 4. Build Your First Supabase App + +经过前面的系统学习,你已掌握 Supabase 的核心能力(数据库操作、用户认证、RLS 安全策略),现在是时候亲自动手,搭建属于你的第一个包含数据库、支持用户登录系统的应用了! + +## 4.1 为任意应用接入 Supabase 数据库的标准化流程 + +我们可以使用标准化流程将任意应用接入 Supabase 数据库: + +1. 首先进行需求梳理与信息同步,明确目标并告知AI + 1. 你需要向AI清晰描述当前应用的核心功能、待新增的数据库需求。示例:“我现有一个本地React Todo应用,数据仅存在浏览器本地存储,需新增‘数据云端同步’功能并接入Supabase数据库。请帮我梳理:这个应用涉及哪些数据操作(如新增待办、修改状态、删除待办)?需要创建哪些数据表来存储这些数据?” + 2. 补充关键约束条件(可选):比如字段格式要求(时间戳用 `timestamptz`、金额用整数存分)、数据权限规则(仅自己可见待办),让AI的分析更贴合实际需求。 + 3. 对 AI 返回的结果进行审核,若AI思路存在遗漏(如未考虑“待办截止时间”字段),补充提示修正:“你漏考虑截止时间了,帮我加上。” +2. 让AI基于你确认后的表结构,生成适配Supabase的 `init.sql`脚本:“基于上述所说思路和表的结构,返回给我在 Supabase 中可以进行初始化的 init.sql 脚本”,之后你需要在 SQL Editor 中执行脚本;若执行报错,将错误信息反馈给AI,让其修正脚本。 +3. 在 Supabase 运行 init.sql 脚本后,让 AI 基于脚本重构当前代码,使得能够和 Supabase 进行正常的数据交互:“请你根据我的 sql 脚本以及上面讨论的设定,重构项目的代码让它支持能够和 Supabase 对应的数据库进行通信并处理数据”。 +4. 重构完毕,此时只需要配置好 Supabase 地址和 key 的参数(正式项目通常只用环境变量配置),随后进行检查,若没问题则顺利实现将应用接入 Supabase 数据库。 + 1. 运行项目,测试所有数据库交互功能,到Supabase Table Editor 实时查看数据是否同步; + 2. 若出现问题(如数据无法插入、仅能看到部分数据),将问题现象反馈给AI,让其定位原因并修正代码。 + +此外,若目标是开发用户登录页面,可直接让 AI 协助集成登录页面 :“现在你需要帮我给这个应用加入 Supabase 的用户登录系统,使用邮箱可以注册和登录”。另外,你还需要向 AI 明确页面的跳转逻辑与路径(如登录成功后跳转至系统首页、跳转首页的地址是什么、登录失败时留在当前页并显示错误提示)。集成完成后,你需要尝试注册登录后能在 Supabase 的 Authentication 项目中看到新增的用户数据,并在登录后能正常进入到原先未登录无法进入的应用界面即可。 + +当然,你还可以直接让 AI 参考某个 project 的实现直接迁移对应的 Supabase 功能,比如某个 Project 用到了数据库以及 Edge fuction 的高级功能,你可以按照如下方式直接让 AI 迁移对应的相似功能:“请你参考该项目 {此处复制粘贴参考项目的绝对地址} 当中的 Supabase 相关功能实现逻辑,给当前项目加上类似的实现逻辑(如用户登录、数据库管理、函数请求等等)”。 + +## 4.2 Case Study : Build an Online Snake Game + +根据上面所提到的 SOP ,让我们通过一个具体的实际案例 `Project5-Supabase-Demos/apps_snakegame`来实践:为一个已有的“贪吃蛇”游戏项目增加分数排行榜单,包含用户登录与数据库基础功能。 + +![](images/image43.png) + +### 4.2.1 分析项目,识别数据需求 + +首先,和在之前提到的标准化流程类似,我们可以先把需求澄清给 AI ,让 AI 基于我们项目和需求给出对应的修改方案,之后我们会基于这个修改方案。 + +**你可以使用如下的提示词来指导 AI:** + +> “我有一个贪吃蛇游戏,目录在 {此处粘贴贪吃蛇游戏的绝对路径}。现在我想结合 supabase 给它增加一个在线排行榜功能,并且支持用户登录系统,排行榜可以根据用户名和邮箱显示排名。 +> +> 请帮我分析一下,为了实现这个功能,我需要建立哪些数据表?每个表应该包含哪些字段?” + +此时你会得到类似如下返回: + +![](images/image44.png) + +### 4.2.2 生成 `init.sql` 脚本 + +确定需要的部分,我们可以让 AI 生成需要在 Supabase 执行的数据库初始化脚本:“请你基于上面的分析,帮我在项目中生成 scripts/init.sql 脚本用于在 Supabase 中初始化所需数据库”。 + +![](images/image45.png) + +### 4.2.3 改造项目代码 + +接下来我们只需要让 AI 基于前面的内容重构当前的贪吃蛇代码:“接下来请你基于前面思考的内容以及 sql 表,使用 Supabase 帮我实现排行榜功能,排行榜是单独的一页,需要可以根据邮箱和用户名区分不同用户的总分,你还需要支持基于邮箱的用户登录系统,注册登录才能玩这个游戏。” + +如果当前 AI 对话轮次太多,你想重开一个新的会话进行项目重构,你可以把上面提到的 `init.sql`作为上下文中的内容,让 AI 基于 sql 文件进行项目重构。 + +若是发现 AI 实现的用户登录系统不够正常,你可以直接将我们之前写好的 `Project5-Supabase-Demos/apps/project-burger-shop-auth-users-2` 的地址一同放入提示词,让 AI 基于项目直接实现用户登录系统。并检查是否已经正确设定了连接到 Supabase 的必要条件,防止因为 Supabase 配置错误而报错。 + +在代码修改过程中,若出现实际效果与预期不符的情况(如排行榜数据不显示、登录验证失效等),只需完整记录具体现象并反馈给 AI,即可逐步接近正确结果。改造成功的标准为:用户能顺利完成注册与登录操作,且登录后可正常查看对应的游戏排行榜单。 + +![](images/image46.png) + +![](images/image47.png) + +### 📚 课程作业 + +1. 将用户管理系统集成到贪吃蛇游戏演示版中 +2. 将用户管理系统集成到你的应用程序中(如果之前已开发过一个应用程序) + +# 3. Become Supabase Master + +以上是 Supabase 的基本操作,接下来的旅程中我们将会接触 Supbase 的进阶原理和功能,你将理解为什么我们会选择 Supabase 作为教学案例,以及如何使用 Supbase 实现更高级的操作,协助你实现更复杂的交互功能,并且在学习这些功能后,即便面对 Supabase 之外的其他同类工具,你也能触类旁通,从更本质的层面理解后端服务的核心原理。当然,你并不需要在短时间内学会全部,也许只需要学会第三方登录支持已经足够,你可以先浏览下列内容,直到项目遇到对应的需求时再倒回来深入学习。 + +## 5.1 Why We choose Supabase + +在开始进阶之前,我们再次思考这个问题:众多后端技术方案中,为何我们最终选择 Supabase 作为技术底座? + +初创团队在技术选型时普遍面临一个矛盾:既想完全掌控后端系统,又必须快速上线产品——而自建后端通常意味着要投入数月时间搭建数据库与实时同步、用户认证、API服务、文件存储、定时任务、监控告警等核心组件,除非团队成员已在对应领域积累了丰富的实战经验。在资金不足、市场窗口短暂的双重压力下,一旦陷入基础设施泥潭,极易导致迭代滞后、错失早期增长空间。 + +Supabase 将这些后端能力打包为开箱即用的服务(PostgreSQL数据库、实时订阅、身份认证、对象存储、边缘函数、自动生成API等),让初创团队得以将稀缺资源聚焦于核心功能开发,避免因底层建设拖慢上线速度——这已成为当前创投环境下务实的生存策略。当然,我们也可以使用别的一栈式后端产品进行开发,例如 PocketBase(轻量极简)和 Appwrite(跨平台适配)等方案,但综合功能完整性、SQL 生态成熟度及 Github 社区关注度,Supabase 更适合支撑业务的长期稳定运行。 + +在同类产品中,Supabase 的开源策略更具优势。 以市场占有率较高的 Firebase 为例:其闭源特性易导致平台绑定,迁移成本极高。Supabase 采用完全开源模式,支持私有化部署,规避了供应商锁定风险,可根据需求切换至其其他竞品。 + +总而言之,技术选型需匹配业务规模与目标。 对于个人项目或极小范围测试,PocketBase 等超轻量方案已足够;若企业需对接复杂身份系统,或要满足上市公司合规审计要求,WorkOS 这类企业级全身份治理方案更为适用。但对于验证 MVP、承载早期用户的核心业务场景,Supabase 的完整功能完全够用,它不仅能独立支撑至少万级用户规模,更可灵活集成 Stripe(支付)、Resend(邮件)、Cloudflare(CDN)等第三方服务;即便未来业务扩展至企业级需求,Supabase 的开源架构也能与企业系统并行部署,不同功能选择最适配的平台进行使用。这种渐进式灵活性,使初创团队无需过早投入重型基础设施,又能保留 future-proof 的演进空间。 + +## 5.2 Google & Github Login Support + +在前面的教程中,我们讲解了如何直接使用邮箱进行注册和登录,但在实际操作中我们通常想要简化注册流程,例如使用第三方登录 Google 和 GitHub 进行系统的快速注册与登录,我们将会在这节教程中展开每个细节;同时,一个完整的认证系统也必须提供安全可靠的密码重置功能,我们也会将密码重置功能集成在本节教程的项目中。 + +本项目 `Project5-Supabase-Demos/apps/project-burger-shop-auth-advanced-supabase-6`)完整地演示了如何实现这些高级功能。 + +![](images/image48.png) + +### 5.2.1 OAuth 流程:第三方登录是如何工作的? + +第三方登录的核心是 OAuth 2.0 开放授权协议,它的本质是 “授权代理”:允许用户授权我们的应用(汉堡店项目)访问其在第三方平台(如 Google)的公开信息(如邮箱、头像),但无需将第三方平台的密码暴露给我们的应用,从根本上规避了密码泄露风险。 + +完整流程可拆解为 5 个关键步骤,以 Google 登录为例: + +1. 用户发起授权请求:用户点击页面上的 “Sign in with Google” 按钮,我们的应用会自动将用户重定向到 Google 官方的授权页面(确保授权过程的安全性,避免钓鱼风险)。 +2. 用户完成第三方授权:用户在 Google 页面登录自己的账户(验证用户身份),并同意我们的应用请求的权限(如 “获取邮箱地址”)。 +3. Google 返回一次性授权码:授权通过后,Google 会将用户重定向回我们提前约定的 “回调 URL(Callback URL)”,并在 URL 参数中附带一个一次性、短期有效的授权码(而非直接返回用户信息,进一步提升安全性)。 +4. Supabase 交换访问令牌(Access Token):我们的后端(由 Supabase 托管,无需自建)会拿着这个授权码,向 Google 官方接口发起请求,换取可用于获取用户信息的 Access Token(授权码仅用于换 Token,避免 Token 直接在前端传输)。 +5. 创建账户并建立会话:Supabase 使用 Access Token 从 Google 拉取用户的公开信息(如邮箱、头像),并在我们的项目中为该用户自动创建账户(若首次登录)或直接关联现有账户,最终生成一个有效的用户会话(Session),完成登录。 + +![](images/image49.png) + +### 5.2.2 配置 Google Cloud 获取 Client ID 和 Secret + +无论是何种第三方登录方式,我们通常都需要获取 Client ID 与 Secret 进行配置;对于 Google 的第三方登录,你首先需要在 Google Cloud Platform 中创建一个 OAuth 2.0 客户端 ID 进行对应参数的获取。 + +1. **进入 Google Cloud Console** : +2. 访问 [Google Cloud Console](https://console.cloud.google.com/)。 +3. 创建一个新项目或选择一个现有项目。 +4. **配置 OAuth 同意屏幕 (OAuth consent screen)** : +5. 在左侧导航栏中,找到 “APIs & Services” -> “OAuth consent screen”。 +6. 选择 “External” 用户类型,然后点击 “Create”。 +7. 填写应用名称、用户支持电子邮件等必填信息。 +8. 在 “Authorized domains” 部分,添加你的 Supabase 项目域名,格式为 `*.supabase.co`。 +9. 保存并继续。在 “Scopes” 和 “Test users” 步骤中,你可以暂时跳过,直接保存。 +10. **创建凭据 (Create Credentials)** : +11. 进入 “APIs & Services” -> “Credentials”。 +12. 点击 “+ CREATE CREDENTIALS”,选择 “OAuth client ID”。 +13. 在 “Application type” 中选择 “Web application”。 +14. 为它取一个名字,例如 “Supabase Auth”。 +15. 在 “Authorized redirect URIs” 部分,点击 “ADD URI”,并填入你的 Supabase 项目的回调 URL。你可以在 Supabase Dashboard 的 “Authentication” -> “Providers” -> “Google” 中找到这个 URL,它的格式通常是 `https://<你的项目ID>.supabase.co/auth/v1/callback`。 + ![](images/image50.png) +16. 点击 “CREATE”。 +17. **获取 Client ID 和 Client Secret** : +18. 创建成功后,一个弹窗会显示你的 **Client ID** 和 **Client Secret** 。请务必**立即复制并妥善保存** 它们。 + +### 5.2.3 配置 GitHub 获取 Client ID 和 Secret + +同样地,你也需要在 GitHub 上注册一个 OAuth 应用。 + +1. **进入 \*\***GitHub\*\* ** Developer Settings** : + 1. 登录你的 GitHub 账户。 + 2. 点击右上角的头像,进入 “Settings”。 + 3. 在左侧导航栏的底部,找到 “Developer settings”。 + +2. **注册新应用 (Register a new application)** : +3. 选择 “OAuth Apps”,然后点击 “New OAuth App”。 +4. 填写应用名称,例如 “My Burger Shop”。 +5. **Homepage URL** : 填写你应用的线上地址,或者本地开发地址 `http://localhost:3000`。 +6. **Authorization \*\***callback\*\* ** URL** : 填入你的 Supabase 项目的回调 URL。同样,你可以在 Supabase Dashboard 的 “Authentication” -> “Providers” -> “GitHub” 中找到它,格式为 `https://<你的项目ID>.supabase.co/auth/v1/callback`。 +7. 点击 “Register application”。 +8. **获取 Client ID 和 Client Secret** : +9. 注册成功后,页面会显示你的 **Client ID** 。 + ![](images/image51.png) +10. 点击 “Generate a new client secret” 来生成你的 **Client Secret** 。同样,请**立即复制并保存** 它。 + +### 5.2.4 在 Supabase 中配置 Provider + +现在,将我们获取到的凭证配置到 Supabase 中。 + +1. **进入 Supabase Dashboard** : +2. 选择你的项目,进入 “Authentication” -> “Providers”。 +3. **启用并配置 Google** : +4. 找到 “Google” 并启用它。 +5. 将你从 Google Cloud 获取的 **Client ID** 和 **Client Secret** 粘贴到对应的输入框中。 +6. 点击 “Save”。 +7. **启用并配置 ** **GitHub** : + 1. 找到 “GitHub” 并启用它。 + 2. 将你从 GitHub 获取的 **Client ID** 和 **Client Secret** 粘贴到对应的输入框中。 + 3. 点击 “Save”。 + +![](images/image52.png) + +至此,你已经能够使用第三方账户在构建的网站中进行登录,你可以直接让 AI 基于 `Project5-Supabase-Demos/apps/project-burger-shop-auth-advanced-supabase-6`项目作为参考,在你的项目的基础上支持用户登录系统,以最小成本集成包含 github 与 google 鉴权的用户登录界面。 + +### 5.2.6 密码重置实现 + +作为一个成熟的用户登录组件,密码重置也是极其重要的一环,本项目 `project-burger-shop-auth-advanced-supabase-6`也包含了该功能的完整实现,你可以直接让 AI 基于本项目的密码重置功能复刻完整的密码重置组件。其主要分为以下几步: + +1. 发起请求 :用户在忘记密码页面输入邮箱,前端调用 `supabase.auth.resetPasswordForEmail()` 函数,并指定一个重定向 redirectTo URL(例如 /auth/reset )。 +2. 发送邮件 :Supabase 会向该邮箱发送一封包含唯一重置链接的邮件。 +3. 访问链接 :用户点击邮件中的链接,被重定向到应用内指定的重置页面。 +4. 更新密码 :在重置页面,用户输入新密码。前端调用 `supabase.auth.updateUser()` ,将新密码提交给 Supabase。Supabase 会自动验证链接的有效性并完成密码更新。 + +最后,如果你觉得当前的密码重置邮件过于简陋,你可以 在 Supabase Dashboard 的 Authentication -> Email Templates 中自定义“Reset Password”邮件模板。 + +除了 Reset password 功能外,你还能看到许多其他与用户管理相关的高级功能设定(例如 Invite user 等),你可根据对应功能各自的开发文档,结合 Vibe coding 工具自行添加对应功能。 + +![](images/image53.png) + +## 5.3 Realtime Function + +Supabase 的实时功能是其最强大的特性之一,为构建协作文档、实时仪表盘、游戏大厅或客服系统提供了极大的便利。 + +本项目 `Project5-Supabase-Demos/apps/project-burger-shop-realtime-orders-3 `通过构建一个 多人实时聊天室、光标位置共享 功能,展示了 Supabase Realtime 涉及到的三大核心能力:数据库变更监听 (Postgres Changes)、广播 (Broadcast) 和 在线状态 (Presence)。 + +![](images/image54.png) + +如果你觉得相关代码部分有一定难度,可以直接让 AI 参考该部分文档内容,对你的程序进行修改。 + +### 5.3.1 数据库实时变动 Postgres Changes + +最常见的 Realtime 功能是对数据库的变更进行实时监听 Postgres Changes 。它允许客户端订阅数据库中特定表、特定行甚至特定列的 INSERT 、 UPDATE 或 DELETE 事件。一旦数据库发生变动(无论是通过 API 调用、Supabase Dashboard 操作,还是 SQL 脚本执行),Supabase 都会利用 PostgreSQL 的底层复制机制,立即通过 WebSocket 将变更的数据推送到所有订阅了该频道的前端客户端,而无需前端通过轮询(Polling)去反复查询。 + +一般而言,该功能可以在 Table Editor 中找到 Enable Realtime 点击后启动, 但更方便的是通过 SQL 脚本初始化执行,例如: + +```SQL +-- Enable realtime replication +ALTER TABLE public.chat_messages REPLICA IDENTITY FULL; +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM pg_publication_tables + WHERE pubname = 'supabase_realtime' + AND schemaname = 'public' + AND tablename = 'chat_messages' + ) THEN + ALTER PUBLICATION supabase_realtime ADD TABLE public.chat_messages; + END IF; +END $$; +``` + +该语句将 `chat_messages` 表添加到了 Supabase 预设的 `supabase_realtime` 中,而一旦一个表被加入到这个特殊的 `publication` 中,Supabase 的实时服务器就会开始监听它的所有数据变更。 + +基于上面的特殊数据表,我们能够使用监听代码对表内数据变动进行实时监听。我们需要实现的是当一个用户发送消息时,其他所有在线用户都能立刻在屏幕上看到这条消息。通过订阅 chat_messages 表的 INSERT 事件能够实现这一点。 + +```TypeScript + const sub = supabase + .channel('chat_messages_channel') + .on('postgres_changes', { + event: 'INSERT', + schema: 'public', + table: 'chat_messages' + }, (payload: any) => { + console.log('New message received:', payload.new); + const newMessage = payload.new as Message; + // ... // + .subscribe((status: string) => { + console.log('Chat subscription status:', status); + }); +``` + +- `.channel('chat_messages_channel')`: 创建一个隔离的通信频道。 +- `.on('postgres_changes', ...)`: 这是核心的订阅方法。我们告诉 Supabase 我们只关心 `chat_messages` 表的 `INSERT` 事件。 +- `payload.new`: 当有新消息被插入数据库时,Supabase 会将这条新数据的完整内容通过 `payload.new` 推送给所有订阅的客户端。 +- `.subscribe()`: 启动订阅。 + +### 5.3.2 信息广播同步 Broadcast & Presence + +对于那些不需要存入数据库的、更“即时”的交互,比如光标移动、在线状态等,Supabase 提供了 Broadcast 和 Presence 功能。 + +- Presence: 用于跟踪频道内所有客户端的 **共享状态** 。适合用来实现“谁在线”的功能。 +- Broadcast: 用于向频道内的所有其他客户端发送**低延迟**的 **临时消息** 。 + +Presence 的核心思想是: 让每个客户端声明自己的在线状态,并由 Supabase 的服务器负责将这些状态可靠地同步给频道内的所有其他客户端。实现 Presence 分为以下几个关键步骤: + +1. 创建一个支持 Presence 的频道 + +首先,我们创建了一个频道 `lobby_presence` 来专门处理这些交互,并在配置中指定一个唯一的 key 来标识当前用户。这个 key 通常是用户的 ID。 + +```Plain +const ch = supabase.channel +('lobby_presence', { +  config: { +    presence: { key: anonymousUser.id }, +  } +}); +``` + +2. 订阅频道宣告“我在线”的信息 + +一旦频道创建成功,我们需要订阅它。在订阅成功的回调( status === 'SUBSCRIBED' )中,我们调用 channel.track() 方法。这个方法会将当前用户的信息(例如用户ID、名称、头像颜色等)广播给频道内的所有其他客户端,宣告自己的“在线”状态。 + +```Plain +const me = { +  id: anonymousUser.id, +  name: anonymousUser.name, +  color: anonymousUser.color +}; + +ch.subscribe(async (status) => { +  if (status === 'SUBSCRIBED') { +    await ch.track(me); +  } +}); +``` + +3. 同步完整的在线列表 + +当一个新用户加入频道时,他们需要获取当前所有已经在线的用户列表。这通过监听 presence 的 sync 事件来实现。 sync 事件会在你首次加入频道时触发,为你提供一个完整的“快照”。 + +channel.presenceState() 方法会返回一个对象,包含了当前频道内所有在线用户的状态信息。我们将其处理后更新到应用的 state 中,从而渲染出完整的在线用户列表。 + +```Plain +ch.on('presence', { event: 'sync' }, ()  +=> { +  const state = ch.presenceState(); +  const flat = {}; +  Object.values(state).forEach((arr) => { +    arr.forEach((u) => { flat[u.id] =  +    { ...u }; }); +  }); +  setOnline(flat); +}); +``` + +4. 监听单个用户的加入与离开 + +除了 sync 事件,我们还可以监听 join 和 leave 事件,以便在有新用户进入或离开时做出即时响应,例如显示一个 "User has joined" 的通知。 + +```Plain +ch.on('presence', { event: 'join' }, ({  +key, newPresences }) => { +  console.log('User joined:', key,  +  newPresences); +}); + +ch.on('presence', { event: 'leave' }, ({  +key, leftPresences }) => { +  console.log('User left:', key,  +  leftPresences); +}); +``` + +通过以上步骤,我们便构建了一个功能完备的在线状态系统。Supabase 自动处理了用户意外断开连接(如关闭浏览器或断网)的情况,并在适当的时候触发 leave 事件,确保了在线列表的准确性。 + +当 Presence 让我们知道了“谁在场”之后, Broadcast 能够让他们之间能够进行“对话”,但对话的内容是短暂存储的。一个典型的例子就是实时光标追踪。如果每次鼠标移动都去读写数据库,会造成巨大的性能浪费和延迟。 Broadcast 完美地解决了这个问题,它允许消息在各个客户端之间直接通过 WebSocket 传递,完全绕过数据库。 + +Broadcast 的工作模式主要依赖两个核心方法: channel.send() 用于发送,channel.on() 用于接收。】 + +1. 发送端:广播我的光标位置 + +我们为 mousemove 事件添加了一个监听器。当鼠标移动时,我们构造一个包含用户 ID、坐标和颜色的 payload,然后通过 channel.send() 将其广播出去,并指定事件名称为 'cursor'。 + +```TypeScript +const handleMouseMove = (e) => { + const payload = { + id: anonymousUser.id, + x: e.clientX, + y: e.clientY, + name: anonymousUser.name, + color: anonymousUser.color + }; + + channelRef.current?.send({ + type: 'broadcast', + event: 'cursor', + payload + }); +}; + +document.addEventListener('mousemove', handleMouseMove); +``` + +2. 接收端:监听并渲染他人的光标 + +在同一个频道内,所有客户端都使用 channel.on() 来监听 broadcast 类型的、且 event 为 'cursor' 的消息。一旦收到匹配的消息,回调函数就会被触发。我们从 payload 中解析出发送方的数据,并用它来更新本地的 online 状态,从而在屏幕上实时渲染出其他用户光标的位置。 + +```TypeScript +ch.on('broadcast', { event: 'cursor' }, ({ payload }) => { + setOnline((prev) => ({ + ...prev, + [payload.id]: { + ...(prev[payload.id] || {}), + x: payload.x, + y: payload.y + } + })); +}); +``` + +通过这种方式, Presence 和 Broadcast 协同工作;Presence 维护在线用户列表,而 Broadcast 则负责在这些用户之间传递像光标位置这样的临时状态,最终以较低的成本实现了丰富的实时互动功能。 + +## 5.4 Storage + +除了用户信息、订单这类可规整定义的结构化数据,一个完整的应用通常还需要处理大量非结构化文件 —— 例如用户头像、商品展示图、用户上传的订单文档等。这类文件的特点是体积差异大、数量可能极多(比如电商平台的商品图可能达数万甚至数十万张),若直接存储在应用自身的业务服务器中,会显著增加服务器的存储负载,还可能拖慢数据读写速度,影响应用整体性能。 + +实际开发中,这类非结构化文件会统一交由 “对象存储服务” 管理,OSS、Amazon S3 均属于这类服务,它们是专门为海量文件存储设计的 “专业存储工具”,能高效应对文件的存储、备份与快速读取需求。而我们在应用中获取这些文件时,并不会直接从对象存储服务的 “底层仓库” 调取,而是通过 URL 地址实现:每个存储在对象存储中的文件,都会被分配一个唯一的 URL(类似 “[https://xxx.oss.com/avatar/user123.jpg](https://xxx.oss.com/avatar/user123.jpg)” 的地址,可简单理解为这个“网站”只有一张图片),这个 URL 就像文件的 “专属访问地址”,前端页面只需通过该地址,就能直接下载或加载头像、商品图,无需依赖应用业务服务器中转,既提升了文件加载速度,也减轻了业务服务器的压力。 + +本项目 `project-burger-shop-storage-uploads-4` 便通过一个用户头像上传功能,深入演示了如何利用 Supabase Storage 构建现代化的文件上传系统,让开发者直观理解非结构化文件从上传到通过 URL 访问的完整流程。此外,本项目使用 `Uppy` 库来提供一个优秀的文件上传界面,并结合 `Tus` 插件实现了可续传上传,通过将 Uppy 的上传端点指向 Supabase 的标准 API (`/storage/v1/upload/resumable`) 进行工作,你可以参考类似的方式实现上传功能组件。 + +![](images/image55.png) + +![](images/image56.png) + +### 5.4.1. Bucket + +Supabase Storage 的组成单元是存储桶 Bucket。你可以把它想象成电脑操作系统中的文件夹。每个 Bucket 都可以有自己独立的安全策略和配置。 + +Storage 内的所有文件都可以通过一个公开的 URL 直接访问,但并不意味着任何人都可以随意上传或修改,具体的访问权限将由更精细的策略来控制。和数据库一样,Storage 的访问权限也是通过行级安全策略来管理的。SQL 策略写在 storage.objects 和 storage.buckets 这两张特殊表上,可以精确定义谁能读取 (SELECT)、上传 (INSERT)、更新 (UPDATE) 或删除 (DELETE) 文件。 + +例如,我们可以创建一条策略,只允许用户上传到以自己 user_id 命名的文件夹下,并且只能上传图片类型的文件: + +```Plain +CREATE POLICY "Allow authenticated  +uploads to avatars bucket" +ON storage.objects FOR INSERT +TO authenticated +WITH CHECK ( +  bucket_id = 'avatars' AND +  auth.uid() = (storage.foldername(name)) +  [1]::uuid AND +  (storage.extension(name) IN ('png',  +  'jpg', 'jpeg')) +); + +CREATE POLICY "Allow public read access  +to avatars" +ON storage.objects FOR SELECT +USING ( bucket_id = 'avatars' ); +``` + +### 5.4.2 获取可访问文件 URL + +本项目需要你手动创建一个名为 avatars 的公共桶,所有文件将上传至该公共桶下进行存储。文件上传成功后,我们只得到了它在 Storage 中的存储路径 ,例如 public/avatar1.png 。这只是存储在数据库中的一个字符串,要让浏览器能够渲染这张图片,我们需要将其转换为一个可访问的 HTTP URL。 + +Supabase 提供了两种截然不同的策略来获取这个 URL,它们在安全性、持久性和成本控制上有着本质的区别。 + +#### 1. 公开 URL (Public URL) - 永久链接 + +这是最直接的方式。如果你的文件存放在一个**Public Bucket** 中,你可以获取一个固定、永久的公开链接。 + +```TypeScript +const { data } = supabase.storage + .from('avatars') + .getPublicUrl('public/avatar1.png'); +const publicUrl = data.publicUrl; +``` + +这类链接具有两大核心特点:一是简单直接,其 URL 结构固定,在实际操作中易于拼接和管理,降低了技术使用门槛;二是利于缓存,作为永久链接,它能被 CDN(内容分发网络)和浏览器有效缓存,从而大幅提升资源的访问速度,优化用户体验。基于这些特点,它适用于真正意义上的公共资源场景,例如网站 Logo、产品目录图片、博客文章配图等,能很好地满足这类资源的访问和管理需求。 + +不过在生产环境中,这类链接存在明显的被盗刷流量(Hotlinking)风险。由于链接是永久公开的,外部人员可以轻易将你的图片链接嵌入到他们自己的高流量网站中,导致流量被非法占用。这一行为会让你的 Supabase 项目产生大量不必要的流量费用,而这些消耗的流量并未服务于你自身的应用,属于典型的成本浪费,是生产环境中需要高度警惕和防范的问题;因此,我们需要转向临时签名 URL 实现对外资源的暴露。 + +#### 2. 签名 URL (Signed URL) - 临时授权链接 + +为了解决公开 URL 的安全和成本问题,Supabase 提供了生成临时签名 URL 的方式。这是绝大多数线上应用推荐的最佳实践,比如文生图应用给用户生成限时查看的图片链接、电商平台仅让下单用户获取临时发票下载地址、付费内容平台为订阅用户提供短期有效的课程播放链接,既防文件盗用又能避免流量盗刷,适配性极强。 + +```TypeScript +const { data, error } = await supabase.storage + .from('avatars') + .createSignedUrl('private/user-invoice.pdf', 3600); // 链接有效期为 3600 秒 (1小时) +const signedUrl = data?.signedUrl; +``` + +临时签名 URL(Signed URL)有三大核心优势:安全可控是指链接带安全标记、有有效期,过期就用不了;权限绑定很简单 —— 只有能看这文件的人,才能生成这个链接,就算文件藏在私有存储里(Private Bucket),他用这个链接也能正常打开;杜绝盗刷是因为链接是临时的,复制到别处很快就失效,不会被恶意刷流量。靠这些优势,像用户头像、私人照片、付费内容、订单发票这些需要管权限的文件,都能用它。 + +从安全保障和成本控制的角度,建议养成优先使用临时签名 URL 的习惯。只有当某个资源明确需要永久公开、无限制访问(比如应用的公开 Logo、公共活动宣传图等)时,才考虑使用 Public URL。这样既能满足特定业务需求,又能最大程度规避不必要的风险和成本消耗。 + +## 5.5 Edge Function + +Edge Function 是 Serverless(无服务器架构)生态中极具核心价值的形态之一,它为 “无自建后端” 场景提供了轻量、高效的函数运行支持。 + +什么是 Serverless? Serverless(无服务器架构)并不意味着真的没有服务器,而是指开发者无需关心服务器的购买、运维、配置和扩容 。你只需要编写业务代码(函数),云服务商会在特定事件触发时自动为你分配资源运行代码,并按实际运行时间计费。 + +当你的应用需要执行一些不能或不应在客户端(浏览器)上完成的逻辑时——例如与需要私密密钥的第三方 API 交互、执行计算密集型任务、或强制执行复杂的业务规则——Edge Functions 就派上了用场。Supabase Edge Functions 基于 Deno 和 TypeScript,它们被部署在全球的边缘节点上,物理距离上靠近你的用户,从而提供极低的函数执行延迟。 + +目前主流云厂商都推出了各自的 Edge Function 服务,常见的包括: + +- AWS Lambda@Edge:基于 AWS Lambda 延伸的边缘函数服务,可与 CloudFront CDN 联动,支持 Node.js、Python 等语言; +- Cloudflare Workers:Cloudflare 推出的边缘函数,部署在其全球 275+ 边缘节点,支持 JavaScript/TypeScript,以 “毫秒级延迟” 为核心优势; +- Vercel Edge Functions:适配 Vercel 前端项目的边缘函数,与 Next.js 深度集成,支持 TypeScript,主打 “前端与边缘逻辑无缝衔接”; + +回到 Supabase ,当你的应用需要执行 “不能在客户端(浏览器)完成” 的逻辑时,比如用私密密钥调用第三方 API(如 LLM 接口)、处理计算密集型任务(如图片压缩)、或强制执行权限校验(如文件访问规则)时,Supabase Edge Functions 就能发挥作用。它基于 Deno runtime 和 TypeScript 构建,部署在全球边缘节点上,能以 “靠近用户的物理距离” 实现极低的执行延迟,是编写自定义、可信服务器端逻辑的核心工具。 + +本项目 `Project5-Supabase-Demos/apps/project-burger-shop-edge-function-5`通过一个与大语言模型(LLM)实时流式对话的功能,展示了 Edge Functions 的最简应用流程。 + +![](images/image57.png) + +### 5.5.1 LLM Chat 案例解析 + +假设你想在应用中集成一个类似 ChatGPT 的聊天机器人。你需要在服务器端调用 OpenAI 的 API,但这需要一个私密的 API Key。 这个 Key 绝对不能暴露在前端代码中 ,否则任何人都可以通过查看网页源码盗用你的 Key,产生高昂的费用。这正是 Edge Function 的用武之地。我们将创建一个名为 llm-chat 的函数,它充当了前端和 OpenAI API 之间的一个 安全代理 。 + +参考 `project-burger-shop-edge-function-5/scripts/llm-chat.ts`的代码,我们来看看它是如何工作的: + +```TypeScript +// scripts/llm-chat.ts +import "jsr:@supabase/functions-js/edge-runtime.d.ts"; +import { OpenAI } from "npm:openai"; + +const OPENAI_API_KEY = Deno.env.get("OPENAI_API_KEY"); + +Deno.serve(async (req) => { + try { + const openai = new OpenAI({ apiKey: OPENAI_API_KEY }); + const { prompt } = await req.json(); + + const stream = await openai.chat.completions.create({ + model: "gpt-3.5-turbo", + messages: [{ role: "user", content: prompt }], + stream: true, + }); + + return new Response(stream.toReadableStream(), { + headers: { "Content-Type": "text/event-stream" }, + }); + } catch (err) { + } +}); +``` + +在该案例中,对于密钥安全,OPENAI_API_KEY 作为环境变量被安全存储于 Supabase 的服务器。本地前端代码完全无法接触到该密钥,从而有效保障了密钥的安全性。 + +### 5.5.2 创建并部署函数 + +Supabase 提供了非常友好的界面,让你无需接触命令行即可完成部署。 + +1. **进入 Edge Functions 面板** : +2. 登录你的 Supabase 项目 Dashboard。 +3. 在左侧导航栏中,点击像代码一样的图标,进入 “Edge Functions”。 +4. **创建新函数** : +5. 点击 “Create a new function” 按钮。 + ![](images/image58.png) +6. 为函数命名,例如 `llm-chat`。 +7. **粘贴代码** : + ![](images/image59.png) +8. 在弹出的在线编辑器中, **删除所有默认的占位代码** 。 +9. 打开你本地的 `llm-chat.ts` 文件, **复制其全部内容** 。 +10. 将复制的代码**粘贴**到 Supabase 的在线编辑器中。 +11. **配置\*\***环境变量\*\* ** (Secrets)** : + 1. 在侧边栏找到 Secrets。 + ![](images/image60.png) + 2. Name: 输入 `OPENAI_API_KEY`。 + 3. Value: 粘贴你自己的 OpenAI API Key。 + 4. 点击 “Save”。在这里设置的 Secret 会被加密存储,并安全地注入到你的函数运行时环境中。 + +若有函数需要更新,记得在 Edge Function 部分执行 Deploy updates。Supabase 会在云端为你构建并部署这个函数。几分钟后,你的函数就可以在线访问。 + +除了作为语言模型的安全代理,Edge Functions 的应用场景远不止于此。实际上,任何需要服务器端逻辑处理的任务,无论是简单的 API 调用、数据验证,还是更复杂的计算,都可以通过 Edge Function 实现。它为你提供了一个轻量级、可扩展的后端,而无需管理任何服务器基础设施。 + +如果你想探索更多可能性,可以参考项目中的其他示例。例如: + +- 图片生成 ( txt2img.ts ) : 这个函数展示了如何利用 Edge Function 调用第三方的文生图(Text-to-Image)API(如 Stability AI, Midjourney 等)来动态生成图片。这是一种典型的计算密集型或需要安全调用外部服务的场景。与 llm-chat 案例一样,API 密钥被安全地存储在 Supabase 后端,前端只负责发送文本描述,然后接收并展示生成的图片,整个过程安全、高效。 +- 发送邮件 ( send-email.ts ) : 在应用中发送欢迎邮件、交易通知或密码重置邮件是常见需求。 send-email.ts 示例演示了如何通过 Edge Function 集成邮件服务(如 Resend, SendGrid)。你无需在客户端代码中暴露敏感的邮件服务 API Key,只需创建一个函数,让前端通过调用这个函数来触发邮件发送。 + +## 5.6 Clerk Login + +Clerk 是一款专注于身份认证与用户管理的专业开发工具,核心能力覆盖用户注册、登录、账号安全MFA、权限控制、会话管理等全链路身份认证相关需求,能帮助开发者快速搭建安全、灵活且符合现代应用标准的用户体系,无需从零开发复杂的身份逻辑。 + +本部分将介绍如何从零开始配置 Clerk 服务,并将其与 Supabase 进行整合。你可以在项目 `project-burger-shop-auth-advanced-clerk-7` 中体验全流程。 + +![](images/image61.png) + +### 5.6.1 创建 Clerk 应用与获取密钥 + +在使用本项目之前,你需要拥有一个 Clerk 账号并创建一个应用。 + +1. 注册与创建: + 1. 访问 [dashboard.clerk.com](https://dashboard.clerk.com/) 并注册账号。 + 2. 点击 "Create application" 。 + ![](images/image62.png) + 3. 输入应用名称(例如 "Burger Shop")。 + 4. 在 "How will your users sign in?" 中,默认勾选 Email , Google , GitHub 。 + 5. 点击 Create application 。 +2. 获取 API Keys: + 1. 创建成功后,你会被引导至 API Keys 页面。 + ![](images/image63.png) + 2. 找到 Publishable key (以 `pk_` 开头) 和 Secret key (以 `sk_` 开头)。 + ![](images/image64.png) + 3. 将它们复制到你的 `.env.local` 文件中(参考本项目 `.env.example`): + + ```Bash + NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_... + CLERK_SECRET_KEY=sk_test_... + ``` + +### 5.6.2 配置 Supabase 和 Clerk 的原生集成 + +在进一步使用前,我们需要集成 Supabase 与 Clerk 的关联关系,方便之后登录的鉴权跳转以及控制对特定数据库的访问权限。Supabase 与 Clerk 提供官方原生集成能力,通过该集成可快速实现两者的身份认证打通,无需手动配置复杂的适配逻辑,大幅简化用户登录、权限校验等功能的开发流程: + +1. 在 Clerk 中激活对 Supab ase 的官方集成 + 1. 登录 [Clerk Dashboard](https://dashboard.clerk.com/)。 + 2. 在左侧菜单导航至 Integrations (集成)。 + 3. 在列表中找到并点击 Supabase。 + 4. 开启 Enable Supabase 开关(或点击 Activate integration)。 + 5. 关键步骤:激活成功后,页面会显示你的 Clerk Domain(格式通常为 `https://.clerk.accounts.dev` 或你的自定义域名)。请复制这个 Domain 地址,下一步会用到。 +2. 在 Supabase 中添加 Clerk 提供商 + 1. 登录 [Supabase Dashboard](https://supabase.com/dashboard) 并进入你的项目。 + 2. 在左侧菜单导航至 Authentication > Sign In / Up (或者直接点击 Providers)。 + 3. 点击 Add provider 按钮,从下拉列表中选择 Clerk。 + 4. 在弹出的 Clerk Domain 输入框中,粘贴你刚才从 Clerk 复制的 Domain 地址。 + 5. 点击 Save 保存配置。 + +### 5.6.3 通过 Webhook 同步用户数据至 Supabase + +仅仅是集成只满足了鉴定权限的需求,但这并不会将 Clerk 中已经注册的用户信息同步到 Supabase,为了方便管理,我们还需要在 Supabase 的 `public.users` 表中保留一份用户备份,以便进行关联查询或数据分析。我们可以通过 Clerk Webhooks 实现这一功能,完整过程如下: + +1. **Clerk 发送通知** : 当用户在 Clerk 注册或更新资料时,Clerk 会向我们配置的 Webhook URL 发送一个 POST 请求。 +2. **Supabase 接收并写入** : Edge Function 接收请求,验证签名(确保安全),然后将用户数据更新到 Supabase 的数据库表中。 + +在开始之前,我们需要配置同步信息所需的数据表: + +```SQL +-- File: init.sql + +-- 1. Create `users` table for synced Clerk users +-- This table will store user data pushed from Clerk Webhooks. +CREATE TABLE public.users ( + id TEXT NOT NULL PRIMARY KEY, -- Corresponds to Clerk User ID + email TEXT, + first_name TEXT, + last_name TEXT, + image_url TEXT, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- 2. Enable Row Level Security (RLS) on the table +-- This is an important security measure to ensure users cannot access any data by default. +ALTER TABLE public.users ENABLE ROW LEVEL SECURITY; + +-- 3. Create RLS policies +-- Policy 1: Allow authenticated users to read their own user info. +-- `auth.jwt()->>'sub'` extracts the user ID from the JWT provided by Clerk. +CREATE POLICY "Authenticated users can view their own user record" +ON public.users FOR SELECT +TO authenticated +USING ( (SELECT auth.jwt()->>'sub') = id ); + +-- Policy 2: Allow users to update their own info. +CREATE POLICY "Authenticated users can update their own user record" +ON public.users FOR UPDATE +TO authenticated +USING ( (SELECT auth.jwt()->>'sub') = id ); +``` + +以及在 Supabase 中启用对应的 Edge function: + +```JavaScript +// File path: supabase/functions/clerk-webhooks/index.ts + +import { serve } from 'https://deno.land/std@0.177.0/http/server.ts' +import { Webhook } from 'npm:svix' +import { createClient } from 'https://esm.sh/@supabase/supabase-js@2' + +// Get Clerk Webhook signing secret from environment variables +const CLERK_WEBHOOK_SECRET = Deno.env.get('CLERK_WEBHOOK_SECRET') + +if (!CLERK_WEBHOOK_SECRET) { + throw new Error('CLERK_WEBHOOK_SECRET is not set in environment variables') +} +const supabaseAdmin = createClient( + Deno.env.get('SUPABASE_URL')!, + Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')! +) + +serve(async (req) => { + try { + // 1. Get Svix signature info from request headers + const headers = Object.fromEntries(req.headers) + const svix_id = headers['svix-id'] + const svix_timestamp = headers['svix-timestamp'] + const svix_signature = headers['svix-signature'] + + if (!svix_id || !svix_timestamp || !svix_signature) { + return new Response('Missing Svix headers', { status: 400 }) + } + + const payload = await req.json() + const body = JSON.stringify(payload) + + // 2. Verify Webhook signature validity using the secret + const wh = new Webhook(CLERK_WEBHOOK_SECRET) + const evt = wh.verify(body, { + 'svix-id': svix_id, + 'svix-timestamp': svix_timestamp, + 'svix-signature': svix_signature, + }) + + const { id } = evt.data + const eventType = evt.type + console.log(`Received webhook event: ${eventType} for user: ${id}`) + + // 3. Execute database operations based on event type + switch (eventType) { + case 'user.created': { + const { id, first_name, last_name, image_url, email_addresses } = evt.data + const { error } = await supabaseAdmin.from('users').insert({ + id, + first_name, + last_name, + image_url, + email: email_addresses[0]?.email_address, + }) + if (error) throw error + console.log(`User ${id} created in Supabase.`) + break + } + + case 'user.updated': { + const { id, first_name, last_name, image_url, email_addresses } = evt.data + const { error } = await supabaseAdmin + .from('users') + .update({ + first_name, + last_name, + image_url, + email: email_addresses[0]?.email_address, + updated_at: new Date().toISOString(), // Update timestamp + }) + .eq('id', id) + if (error) throw error + console.log(`User ${id} updated in Supabase.`) + break + } + + case 'user.deleted': { + // For delete events, ID might be at the top level + const deletedId = id + if (!deletedId) { + return new Response('Deleted user ID not found', { status: 400 }) + } + const { error } = await supabaseAdmin.from('users').delete().eq('id', deletedId) + if (error) throw error + console.log(`User ${deletedId} deleted from Supabase.`) + break + } + } + + return new Response('Webhook processed successfully', { status: 200 }) + } catch (err) { + console.error('Error processing webhook:', err.message) + return new Response(`Webhook Error: ${err.message}`, { status: 400 }) + } +}) +``` + +初始化 Supabase 数据表与函数结束后,你还需要在 Clerk 中启用 Webhooks 支持: + +- 在 Clerk Dashboard -> **Webhooks** 中添加 Endpoint,填入Supabase Edge Function 的 URL。 +- 勾选 `user.created`, `user.updated`, `user.deleted` 等事件。 + +![](images/image65.png) + +一旦设置成功,你能够在 Message Attempts 中看到不同请求信息,点击后可看到详细的请求返回参数结果;如果 webhook 在请求 Edge function 时出现问题,你可以快速在返回值中找到详细原因结果。推荐你同时对照 Clerk 和 Supabase 的请求日志信息,用于分析各个函数设定是否正确。 + +### 5.6.4 Clerk 中的第三方登录支持 + +在深入了解如何对 Clerk 支持第三方登录前,我们先明确两个核心概念:开发环境与生产环境,这是软件从 “开发测试” 到 “上线可用” 的两个关键阶段,二者的定位、用途和安全要求截然不同: + +- 开发环境:开发者本地或测试服务器使用的环境,仅用于功能开发、调试和内部验证(如本地 localhost:3000 服务),不对外开放 +- 生产环境:应用正式上线后,面向真实用户的公开环境(如部署在 Vercel、阿里云等平台的 https://my-app.com) + +而 Clerk 对社交登录区分这两种环境,本质是平衡 “开发效率” 与 “生产安全”:开发阶段需减少冗余配置以快速验证功能,生产阶段需通过专属凭证保障数据安全,同时符合 Google、GitHub 等第三方 OAuth 平台的规则(线上应用必须绑定专属域名与凭证,不允许使用共享资源)。下面具体说明两种环境下 Clerk 社交登录的差异配置: + +1. **开发环境快速验证** + +开发环境中,Clerk 已预置共享 OAuth 凭证和默认重定向 URI,无需前往 GitHub/Google 申请专属凭证,操作步骤如下: + +- 登录 Clerk Dashboard ,在左侧导航栏进入 SSO connections (SSO 连接)页面。 +- 点击 Add connection (添加连接),选择 For all users (对所有用户生效)。 +- 在 Choose provider (选择提供商)下拉菜单中,按需选择 GitHub 或 Google 。 +- 直接点击 Add connection (添加连接),Clerk 会自动用共享凭证完成绑定。 + + 配置后,本地启动应用(如 `localhost:3000`)并点击“Sign in with GitHub/Google”,Clerk 会自动代理登录请求,快速验证功能是否正常。 + +2. **生产环境自定义凭证配置** + +(注:如果发现有环节和预期不一致,建议阅读官方文档进行最新方式的尝试) + +应用部署上线(如 Vercel、阿里云)并切换到 Clerk Production Instance 后,共享凭证失效,需为 GitHub/Google 配置自定义 OAuth 凭证(建议同时打开 Clerk Dashboard 和第三方平台页面,方便同步操作): + +- 前置通用操作(Clerk 控制台): + - 进入 Clerk SSO connections 页面,点击 Add connection → 选择 For all users 。 + - 选择目标平台(GitHub/Google),确保开启 Enable for sign-up and sign-in (允许注册登录)和 Use custom credentials (使用自定义凭证)。 + - 复制页面中的 Authorization Callback URL (GitHub)或 Authorized Redirect URI (Google),保存到安全位置,不要关闭当前页面/弹窗。 +- 2.1 GitHub 平台配置: + - 登录 GitHub,进入 Developer Settings (路径:头像 → Settings → Developer settings → OAuth Apps)。 + - 点击 New OAuth app ,填写信息:`Application name`(应用名称)、`Homepage URL`(生产域名,如 `https://my-app.com`)、`Authorization Callback URL`(粘贴从 Clerk 复制的地址)。 + - 点击 Register application ,再点击 Generate a new client secret ,保存生成的 Client ID 和 Client Secret (Secret 仅显示一次)。 + - 回到 Clerk 弹窗,粘贴 Client ID 和 Client Secret,点击 Add connection 完成配置(若关闭弹窗,可在 SSO connections 找到 GitHub 连接,在“Use custom credentials”模块补填)。 +- 2.2 Google 平台配置: + - 登录 Google Cloud Console ,选择已有项目或新建项目(如“My App Production”)。 + - 点击左上角菜单 → APIs & Services → Credentials ,点击 Create Credentials → OAuth client ID (首次配置需先完成 OAuth consent screen 设置,选择“External”并填写应用信息)。 + - 选择 Application type 为 Web application ,配置: + 1. `Authorized JavaScript origins`:添加生产域名(如 `https://my-app.com`、`https://www.my-app.com`),本地验证可补充 `http://localhost:端口号`。 + 2. `Authorized Redirect URIs`:粘贴从 Clerk 复制的地址。 + - 点击 Create ,保存弹窗中的 Client ID 和 Client Secret ,回到 Clerk 弹窗粘贴并点击 Add connection 。 + - 关键注意事项: + 1. 禁止 WebView 登录:Google OAuth 不支持应用内浏览器登录,需参考 [Google 官方文档](https://support.google.com/cloud/answer/7657789) 调整。 + 2. 切换发布状态:默认“Testing”状态仅支持 100 个测试用户,需在 OAuth consent screen 将“Publishing status”改为 In production (需通过 Google 审核)。 + 3. 阻止子邮箱:Clerk 默认拦截含 `+`/`=`/`#` 的 Google 邮箱(如 `user+alias@example.com`),可在 Google 连接详情页开启/关闭 Block email subaddresses (建议开启提升安全性)。 + 4. 支持 Google One Tap:配置完成后,可集成 Clerk `` 组件实现“一键登录”,参考 [Clerk 组件文档](https://clerk.com/docs/components/social-connections/google-one-tap)。 + +3. 测试第三方登录连接 + +配置完成后,通过 Clerk 内置 Account Portal 验证功能: + +- 进入 Clerk Dashboard,左侧导航栏进入 Account Portal 页面。 +- 在“Sign-in”模块右侧,点击“访问登录页面”按钮,跳转至对应环境登录页: + - 开发环境:`https://你的域名.accounts.dev/sign-in`(如 `https://my-app.accounts.dev/sign-in`)。 + - 生产环境:`https://accounts.你的域名.com/sign-in`(如 `https://accounts.my-app.com/sign-in`)。 +- 点击“Sign in with GitHub/Google”,用对应平台账号登录,若能成功跳转并返回应用,说明连接配置正常。 + +# 6. 从 Supabase 到更多后端开发组件(进阶) + +在上文中,我们主要是站在 Supabase 的视角,去看“一个以 Postgres 为核心的一站式后端平台”能帮我们解决哪些问题:认证、数据库、文件存储、实时通信、边缘函数等,都被集成在同一个控制台里,开箱即用、体验统一,非常适合快速起步和中小型项目。 + +但从更长期、更工程化的角度来看, **Supabase 提供的每一块能力(Auth / Storage / Edge Functions / Realtime / Database),在业界几乎都有对应的专业替代方案** ——既包括同类 BaaS 平台,也包括更“单点突破”的云服务和开源组件。作为上进的个人开发者和初创团队来说,了解这些替代选项有几个好处: + +- 判断当前项目是否“全用 Supabase 就够了”,还是某一块需要更专业/更便宜/更易合规的专用服务; +- 当项目规模变大或需求变复杂时,是否可以把某个模块从 Supabase 替换出去(例如改用专门的 Auth 平台或对象存储),而不是一开始就被平台彻底锁死; +- 拓宽技术选型视野,即使暂时不更换,也能大致知道“如果不用 Supabase 的 X 功能,我还有哪些常见选择”。 + +本节将分别介绍 Supabase 所覆盖的几大能力在市场上的主流替代方案,例如:认证(Auth)、文件存储(Storage)、边缘函数(Edge Functions)、实时通信(Realtime)、数据库托管等。简单对比它们在功能特性、免费额度/定价、易用性以及社区流行度等方面的差异, 让你对后端组件工具库有更全面的理解。 + +## 同类 Baas 平台 + +在开始之前,我们可以浏览同类的 Baas 平台,若觉得 Supabase 不够好用,你可以根据需求选择不同替代品进行尝试。 + +| 平台/服务 | 类型 | 免费额度/定价 | 特点 / 适用场景 | +| ------------------------ | ------------------------------------------------------------------------------ | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | +| Firebase(Google) | 全托管 BaaS(Auth + Firestore + Storage + Functions + Hosting) | Spark:免费轻量额度;Blaze:按量计费(Firestore/Storage/Functions 分别算) | 行业最成熟、文档好、上手快、实时能力强。适用于中小型产品、移动/前端主导团队。缺点:计费复杂、锁定性强、查询限制多(尤其 Firestore)。 | +| Supabase | 开源 BaaS(Postgres + Auth + Storage + Edge Functions + Realtime) | 免费:500MB DB、1GB Storage、无服务器函数少量调用;Pro:按实例计费 | 最像 Firebase 的 SQL 版;界面优秀、体验现代、可自托管。适用于需要强 SQL、BI、事务能力的应用。缺点:高并发或复杂函数成本较高。 | +| Appwrite Cloud | 开源一站式 BaaS(DB + Auth + Storage + Functions + Realtime) | 免费:包含基本 DB/Storage/FaaS;付费按资源级别计费 | 体验现代化、API 统一、可自托管;适合开发者友好的应用快速迭代。缺点:生态还不如 Firebase/Supabase 成熟;性能在大型应用中需要测试。 | +| Nhost | Postgres + GraphQL + Auth + Storage + Functions | 免费:1GB DB、1GB Storage、少量函数调用 | 类似“Supabase + Hasura”;天然 GraphQL;适合前端团队与 React/Next.js 项目。缺点:生态小、成本随用量升高。 | +| AWS Amplify | AWS 一站式后端(Cognito + AppSync + DynamoDB + Storage + Functions + Hosting) | 免费:Hosting 额度 + Cognito 10k MAU + 部分函数额度 | 大而全,适合已有 AWS 基础的团队;企业级可靠性。缺点:最难上手,服务碎片化;初创团队维护成本高。 | +| Xata(近两年快速增长) | 多模型数据库 + Auth + Edge Functions | 免费:250k 记录、15GB 带宽 | 虽然更偏「DB + API」,但提供 Auth、文件、逻辑,可作为轻量全栈后端。UI/开发体验极佳。缺点:功能不如 Firebase/Supabase 全面。 | +| Convex(开发者体验极强) | 托管数据库 + Auth + Functions(前端优先) | 免费开发版;付费按请求量计费 | 极简上手;无需 schema;前端写函数即可用后端。适合 MVP/快速验证。缺点:高度绑定平台,迁移成本高;不算完全传统 BaaS。 | + +## 认证 (Auth) + +| 工具/平台 | 功能特点 | 免费额度/定价 | 适用场景与优缺点 | +| ----------------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| Firebase Authentication | Google 提供的 BaaS 身份验证服务,支持邮箱/密码、手机、社交登录、匿名等常见方式。Spark 免费方案支持最高50k 月活跃用户。 | Spark(免费)50k MAU;Blaze 按量计费 | 集成 Google 生态,文档丰富,上手简单;功能全面(MFA、阻塞函数等),适合快速开发。但与 Firebase 平台绑定,扩展到其他服务需额外配置。 | +| Auth0 (Okta) | 全托管身份认证平台,支持社交登录、企业 SSO、多因子认证、规则扩展等强大功能。 | 免费方案25k MAU,付费按 MAU 计费 | 企业级功能齐全(RBAC、审计日志等),适合中大型应用;界面友好。缺点是 MAU 上升时成本高,免费版功能有限(如不含 MFA/RBAC)。社区知名度高,用户众多。 | +| AWS Cognito | 亚马逊云原生身份服务,支持社交及 SAML 联合登录。直接登录用户池提供每月10k MAU 免费,超过部分按 0.0055 美元/MAU 收费。 | 免费10k MAU/月,超出按量付费 | 与 AWS 生态深度集成(可无缝配合 API Gateway、Lambda 等),入门门槛略高,文档较复杂;免费额度有限,适合已有 AWS 使用习惯的团队。 | +| Logto | 开源身份认证平台,自托管版免费,云服务计划免费50k MAU。支持多语言、多租户、OAuth/OIDC 等。 | 社区版免费;Logto Cloud 免费50k MAU | 近期流行的 Auth0 开源替代方案,GitHub 已有 10k+ Stars。易扩展,自托管降低成本;缺点是生态和文档相对较新,社区规模略逊于 Firebase/Auth0。 | +| Keycloak | 知名开源 IAM/SSO 解决方案,支持用户名密码、LDAP、SAML、OAuth2 等。 | 完全免费,需自托管 | 功能强大、可扩展(支持细粒度权限控制),企业级功能丰富;但部署和维护复杂度高,对小团队而言学习曲线较陡。缺点是对容器化和集群运维要求较高。 | + +## 文件存储 (Storage) + +| 平台/服务 | 类型 | 免费额度/定价 | 特点/适用场景 | +| ---------------------------------------- | -------------------- | ------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- | +| Amazon S3 | 云对象存储(AWS) | AWS 免费套餐提供 5GB 存储、20k GET/PUT 请求/月,超出按使用量付费 | 行业标准的对象存储,可靠性高、全球多区域部署。功能全面,与 AWS 生态整合良好;定价较复杂,新用户需了解计费规则。 | +| Google Cloud Storage(Firebase Storage) | 云对象存储(Google) | Firebase Spark 方案提供免费额度(1GB 存储 + 流量限制),Blaze 付费 | 与 Firebase/Google Cloud 紧密集成,易于管理;支持 CDN 加速、细粒度安全规则。 | +| 腾讯云 COS / 阿里云 OSS | 云对象存储(国内) | 按量付费(各有新用户赠送额度,如OSS有首年40GB免费等) | 面向国内市场,高性能、大规模对象存储;与中国云生态整合,文档较完善。阿里OSS 功能全面、全球加速;七牛KODO 专注多媒体处理,成本较低,适合个人和小团队。 | +| MinIO | 开源 S3 兼容存储 | 开源免费(自建) | 轻量级、高性能、与 S3 API 兼容,适合在私有云或本地搭建对象存储。文档和社区活跃;需自己维护基础设施。 | +| Cloudinary / Imgix 等 | 媒体存储+CDN | 基本免费方案(如 Cloudinary 免费 25GB/月带宽) | 针对图片/视频优化的云存储+CDN 服务,提供实时转码、压缩等高级功能。适合媒体项目,但功能较专一,作为通用文件存储使用成本偏高。 | + +## 边缘函数 (Edge Functions) + +| 平台/服务 | 特点 | 免费额度/定价 | 适用场景与优缺点 | +| -------------------------------------- | ------------------------------------------ | ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Cloudflare Workers | 全球分布式 JavaScript/Wasmtime 环境 | 免费计划:每天 100k 请求;标准计划$5/月含1,000万请求 | 运行在 Cloudflare 边缘节点,延迟极低;适合全局分发的逻辑、静态资源渲染等。免费配额较少(相当于每月约300万请求),上手简单。缺点是运行时(JS/Wasmtime)限制与调试工具有限。 | +| Vercel Edge Functions | 随 Next.js/前端框架无缝集成,支持 JS/TS/Go | Hobby 免费:每月 100万 函数调用,100万 边缘请求 | 深度集成前端框架,自动部署;适合现代 Web 应用。免费额度充足,默认运行时 10s,可提升至 60s。缺点是免费版团队协作功能受限;依赖 Vercel 平台。 | +| Netlify Edge / Functions | Node.js 云函数+边缘路由(NFT) | 免费:300 代币/月(约相当于每月 1M 请求);按信用点计费 | 支持 Node.js 函数、边缘处理路由等。免费额度用于构建、函数和带宽,适合前端全栈部署。优点是简便易用,集成 Git 部署;缺点是免费额度使用需算计(10k 请求 = 3 点)。 | +| AWS Lambda@Edge / CloudFront Functions | AWS 无服务器边缘计算 | AWS Lambda(1M 免费请求/月+400k GB-s)+ CloudFront $0.085/每10万调用起 | 与 CloudFront 集成,可在边缘执行代码。适合需要 AWS 生态(如在节点层面做权限或 A/B 测试)。优点是灵活强大;缺点是配置复杂,延迟略高于 Cloudflare/Vercel。 | + +## 实时通信 (Realtime) + +| 平台/服务 | 功能特点 | 免费额度/定价 | 适用场景与优缺点 | +| -------------------------------------- | ------------------------------------------------ | ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| Firebase Realtime Database / Firestore | Google BaaS 实时数据库;支持数据变更推送 | Spark 免费:实时数据库1GB 存储 & 限额;Blaze 按量付费 | 强集成 Firebase 生态,实时监听简单。优点是免费起步快;缺点是数据库类型(JSON/NoSQL),复杂查询能力弱。 | +| Ably | 实时消息与 pub/sub 平台,支持 WebSocket、MQTT 等 | 免费包:每月 6,000,000 条消息 | 功能全面的实时消息服务,高并发支持;免费额度可达600万消息/月。社区与文档较好,适合全球分布。 | +| Pusher Channels | 事件推送服务,支持频道/事件机制 | Sandbox 免费:每日 200k 消息,100 并发连接 | 易用的 WebSocket 服务,文档齐全,适合快速实现聊天和通知功能。免费版限制消息量和连接数;付费后扩展性好。 | +| 自建 WebSocket/Socket.IO | 自己搭建服务器(Node.js、Elixir 或 Go 等) | 自行托管成本(如服务器费用) | 灵活度最高,可根据需求定制协议和拓扑。适合对成本控制严格且技术成熟的团队。缺点是需自行处理可用性、扩展和跨域等问题。 | + +## 数据库 + +| 平台/工具 | 数据库类型 | 免费额度/定价 | 主要特点 | +| ---------------------------- | --------------------------------------- | ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| Neon (Serverless PostgreSQL) | 关系型(PostgreSQL) | 免费计划:0.5GB 存储,主分支永久在线,20h 分支计算/月 | 云原生无服务器 Postgres,支持自动伸缩和分支(fork 测试)。免费额度对小项目够用,适合现代开发流程。分支功能强大,但免费额度较小。 | +| Aiven PostgreSQL | 关系型(PostgreSQL/MySQL) | 免费计划:1GB 存储,1 vCPU,1GB 内存 | 托管级数据库服务,支持跨云多区域迁移。提供有 MySQL、Redis 等可选。免费额度适合开发和小型项目;商业版支持高可用集群和监控。 | +| CockroachDB Cloud | 分布式 SQL(兼容 PostgreSQL) | 免费计划:10GB 存储 | 类似 Google Spanner 的分布式 SQL 数据库,自动分片扩展。免费10GB 空间较慷慨;适合需要横向扩展和高一致性的应用。商业版 SLA 高。 | +| TiDB Cloud | 分布式关系型(MySQL 兼容) | 免费计划:每节点5GB,总计最多25GB | 开源 TiDB 的云版,兼容 MySQL 协议,分布式架构。免费额度充足,适合熟悉 MySQL 的团队,性能优秀;缺点是运维相对复杂(针对大型场景)。 | +| MongoDB Atlas | 文档型(NoSQL MongoDB) | 免费 M0 集群:0.5GB 存储 | 云端 MongoDB,灵活的文档模型,支持丰富查询和索引。免费 0.5GB 数据库适合测试和小型应用;可按需横向扩展。学习曲线略高于关系型数据库。 | +| SQLPub | 多数据库(MySQL、PostgreSQL、Redis 等) | 免费计划:36,000 请求/小时,30 并发连接,500MB 存储 | 一站式数据库平台,支持多种数据库类型。免费版适合学习和小项目;优点是支持多种 DB,缺点是存储额度较小。 | + +以上替代方案各有侧重:开源更灵活可控(Keycloak、MinIO、Socket.IO、Neon、CockroachDB 等),云托管服务更易上手(Firebase、Auth0、Cloudflare、Vercel、Netlify、AWS、Aiven、MongoDB Atlas 等)。选择时可根据项目需求、团队技术栈、预算和社区生态等权衡。个人项目可优先选用免费配额充足、易集成的服务(如 Firebase 系列、七牛存储、Cloudflare Workers、Neon、CockroachDB 等),而对企业级或特定安全需求,则可考虑功能更丰富但收费较高的方案(Auth0、Alibaba/Tencent 云、AWS、TiDB/Aiven 等)。你可以在实际应用中不断尝试,直到选择出最适合的后端开发工具组件。 + +# 总结 + +在今天的课程中,我们系统学习了数据库的基础概念、Supabase 的核心定义及其操作细节。后续在实践过程中,你可根据项目的实际应用场景与需求,随时回头翻阅这份文档作为参考。 + +请时刻记住一个重要原则: **先完成,再完美!** 无需追求一步到位,我们完全可以通过持续迭代优化,逐步靠近更优的成果。祝你在后续的项目实践中一切顺利! + +# 📚 课后作业 + +1. 开发一个包含用户管理系统和数据库的应用程序。最好包含更多的Supabase 功能 (Realtime / cloud storage / Edge function). diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image1.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image1.png new file mode 100644 index 0000000..b8468a4 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image1.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image10.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image10.png new file mode 100644 index 0000000..5a0da44 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image10.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image11.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image11.png new file mode 100644 index 0000000..d632a8f Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image11.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image12.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image12.png new file mode 100644 index 0000000..5159982 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image12.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image13.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image13.png new file mode 100644 index 0000000..d76b08a Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image13.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image14.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image14.png new file mode 100644 index 0000000..01426a8 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image14.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image15.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image15.png new file mode 100644 index 0000000..f6a7ce7 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image15.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image16.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image16.png new file mode 100644 index 0000000..1d7e5da Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image16.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image17.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image17.png new file mode 100644 index 0000000..371eee4 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image17.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image18.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image18.png new file mode 100644 index 0000000..11e4096 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image18.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image19.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image19.png new file mode 100644 index 0000000..7e51ccc Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image19.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image2.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image2.png new file mode 100644 index 0000000..48a055d Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image2.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image20.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image20.png new file mode 100644 index 0000000..9aea866 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image20.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image21.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image21.png new file mode 100644 index 0000000..498cb4e Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image21.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image22.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image22.png new file mode 100644 index 0000000..68e5a53 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image22.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image23.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image23.png new file mode 100644 index 0000000..3dfc732 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image23.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image24.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image24.png new file mode 100644 index 0000000..bc64f0a Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image24.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image25.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image25.png new file mode 100644 index 0000000..69d397a Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image25.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image26.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image26.png new file mode 100644 index 0000000..f2c1eca Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image26.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image27.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image27.png new file mode 100644 index 0000000..f56b5e9 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image27.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image28.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image28.png new file mode 100644 index 0000000..e2cd2c3 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image28.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image29.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image29.png new file mode 100644 index 0000000..7251ddf Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image29.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image3.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image3.png new file mode 100644 index 0000000..4538062 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image3.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image30.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image30.png new file mode 100644 index 0000000..de181ba Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image30.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image31.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image31.png new file mode 100644 index 0000000..605ca3c Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image31.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image32.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image32.png new file mode 100644 index 0000000..8151004 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image32.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image33.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image33.png new file mode 100644 index 0000000..4179ccf Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image33.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image34.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image34.png new file mode 100644 index 0000000..98958c1 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image34.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image35.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image35.png new file mode 100644 index 0000000..43da753 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image35.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image36.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image36.png new file mode 100644 index 0000000..15aa607 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image36.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image37.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image37.png new file mode 100644 index 0000000..1ae4eea Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image37.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image38.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image38.png new file mode 100644 index 0000000..0b5e024 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image38.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image39.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image39.png new file mode 100644 index 0000000..d6eca6d Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image39.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image4.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image4.png new file mode 100644 index 0000000..5b450b9 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image4.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image40.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image40.png new file mode 100644 index 0000000..14573a1 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image40.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image41.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image41.png new file mode 100644 index 0000000..160a098 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image41.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image42.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image42.png new file mode 100644 index 0000000..2ac4a19 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image42.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image43.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image43.png new file mode 100644 index 0000000..c64d76d Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image43.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image44.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image44.png new file mode 100644 index 0000000..8332c90 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image44.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image45.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image45.png new file mode 100644 index 0000000..90bb901 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image45.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image46.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image46.png new file mode 100644 index 0000000..7f915b5 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image46.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image47.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image47.png new file mode 100644 index 0000000..25ebc72 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image47.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image48.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image48.png new file mode 100644 index 0000000..659b627 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image48.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image49.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image49.png new file mode 100644 index 0000000..10badd3 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image49.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image5.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image5.png new file mode 100644 index 0000000..eabaaa5 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image5.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image50.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image50.png new file mode 100644 index 0000000..20d14c2 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image50.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image51.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image51.png new file mode 100644 index 0000000..c459cf8 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image51.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image52.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image52.png new file mode 100644 index 0000000..abe2173 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image52.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image53.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image53.png new file mode 100644 index 0000000..1b4151c Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image53.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image54.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image54.png new file mode 100644 index 0000000..c9dae15 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image54.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image55.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image55.png new file mode 100644 index 0000000..37cba2a Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image55.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image56.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image56.png new file mode 100644 index 0000000..e50e004 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image56.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image57.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image57.png new file mode 100644 index 0000000..17e0e3d Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image57.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image58.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image58.png new file mode 100644 index 0000000..b5f23ff Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image58.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image59.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image59.png new file mode 100644 index 0000000..58570ca Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image59.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image6.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image6.png new file mode 100644 index 0000000..417a477 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image6.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image60.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image60.png new file mode 100644 index 0000000..0264e8e Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image60.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image61.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image61.png new file mode 100644 index 0000000..7d94972 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image61.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image62.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image62.png new file mode 100644 index 0000000..79905db Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image62.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image63.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image63.png new file mode 100644 index 0000000..82cadea Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image63.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image64.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image64.png new file mode 100644 index 0000000..11e7a1b Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image64.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image65.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image65.png new file mode 100644 index 0000000..e3565c7 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image65.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image7.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image7.png new file mode 100644 index 0000000..d54b10a Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image7.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image8.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image8.png new file mode 100644 index 0000000..5059e21 Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image8.png differ diff --git a/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image9.png b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image9.png new file mode 100644 index 0000000..9fecc9a Binary files /dev/null and b/docs/stage-2/backend/2.2-database-supabase/chapter5/images/image9.png differ diff --git a/docs/stage-2/backend/2.3-ai-interface-code/index.md b/docs/stage-2/backend/2.3-ai-interface-code/index.md new file mode 100644 index 0000000..9d6be81 --- /dev/null +++ b/docs/stage-2/backend/2.3-ai-interface-code/index.md @@ -0,0 +1,3 @@ +# 后端三:大模型辅助编写接口代码与接口文档 + +> 本章节正在编写中,敬请期待... diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/extra1-what-is-git-and-what-is-github.md b/docs/stage-2/backend/2.4-git-workflow/extra1/extra1-what-is-git-and-what-is-github.md new file mode 100644 index 0000000..6587681 --- /dev/null +++ b/docs/stage-2/backend/2.4-git-workflow/extra1/extra1-what-is-git-and-what-is-github.md @@ -0,0 +1,279 @@ +# 扩展知识 1 - 什么是 Git 和 GitHub + +在之前的课程中,我们学习了如何使用基于 Web 的 vibe coding 工具编写代码。每次对话都会创建一个新版本的代码。但是,让我们思考一个问题:如果我们想恢复到之前的修改,有没有方便的方法?有没有一种工具可以记录我们在不同阶段的代码,使我们能够随时在不同版本之间切换和修改? + +为了满足这一需求,版本控制软件应运而生。在这篇文章中,我们将介绍最著名的版本控制程序——Git——以及最好的代码托管平台——GitHub。我们将学习如何使用 Git 进行代码管理,如何从 GitHub 获取他人的代码,如何上传我们自己的代码,以及如何与他人合作进行大型项目。 + +无论是个人项目的版本跟踪,团队协作中的代码同步,还是为开源社区做贡献,Git 和 GitHub 都是现代开发者的必备工具。通过掌握它们,你将能够更高效地管理代码,根据需要创建检查点,在代码的不同阶段之间自由切换,并轻松处理从单个文件更改到开发大型项目的所有事务——使每一次代码迭代都可控且可追溯。 + +# 什么是 Git + +Git 是由 Linux 内核开发者 Linus Torvalds 于 2005 年创建的分布式版本控制系统。其核心功能是跟踪文件的修改历史,允许开发者随时查看和回滚到以前的版本,并在与他人协作时高效地合并更改。 + +![](images/image1.png) + +与早期的集中式版本控制系统相比,Git 的“分布式”特性允许每个开发者的本地设备存储代码仓库的完整历史记录。大多数操作(如提交、回滚和分支管理)都可以在不依赖中央服务器的情况下执行,这使得 Git 更灵活,更适合大规模协作和离线工作。 + +> 💡 在操作 Git 之前,让我们先了解一下什么是终端。 +> +> ## 什么是终端? +> +> 终端本质上是一个基于文本的“计算机接入点”。在早期,图形界面(没有图标,没有鼠标点击)出现之前,用户只能通过键入文本命令与计算机交互。这种方法代代相传,成为了我们要介绍的今天的终端。 +> +> 它不依赖花哨的界面,纯粹通过“命令 + 反馈”工作。这使其成为人机交互最基本和直接的方法之一。 +> +> 不同系统的终端有所不同。在 Windows 上,常见的是“命令提示符 (cmd)”和“PowerShell”。你可以通过在计算机的运行/搜索框中输入“cmd”或“powershell”来启动这些命令行程序。 +> +> ![](images/image2.png) +> +> ![](images/image3.png) +> +> 前者是一个较旧的工具,仅支持基本命令,如查看文件和复制,适合简单任务。后者是一个更高级的版本,可以处理复杂的操作,如进程管理和远程控制,并且还兼容 cmd 命令——使其在开发或系统管理场景中更常用。macOS 和 Linux 都默认带有“终端”,它们的命令逻辑相似,源自 Unix(贝尔实验室工程师在 20 世纪 60 年代末开发的经典计算机系统)。 +> +> 终端在今天仍然至关重要,因为它的效率和广泛的兼容性。例如,一条命令可以批量重命名文件,比用鼠标重复点击快得多。此外,本地服务器、云服务器和专业开发环境通常没有图形界面,因此终端操作是必要的。许多任务,如安装各种程序(如 Git、Python、系统工具或开发依赖项)、运行代码、管理计算机进程和配置系统参数,也需要终端命令。 +> +> 你可能会想,如果记不住所有那些终端命令该怎么办。事实上,随着大语言模型的快速发展,不再需要像以前那样死记硬背了。现在,你只需要在需要时询问模型(例如“如何用 Git 获取远程代码?”或“如何通过命令行删除文件夹或批量创建文件夹?”),然后从回复中复制有用的命令即可。 +> +> ![](images/image4.png) + +## 如何安装 Git + +我们将演示在不同计算机操作系统上安装 Git 的三种方法。请根据你的系统版本按照说明进行操作: + +### Windows + +1. 前往 [Git 官方下载页面](https://git-scm.com/download/win) 并下载适合你系统的安装程序:[安装包](https://github.com/git-for-windows/git/releases/download/v2.51.0.windows.1/Git-2.51.0-64-bit.exe)。默认情况下,推荐使用 x64 安装程序。 +2. 双击安装程序并按照安装向导说明进行操作: + ![](images/image5.png) + 1. 建议保持默认选项。如果你需要自定义,请注意以下几点:(在大多数情况下,你可以一直点击“Next”) + - 选择 Git 使用的默认编辑器:选择你喜欢的编辑器(如 VS Code)。你可以默认选择第一个选项,即 Vim(一个文本编辑器),或选择“Visual Studio Code as Git's default editor”选项(需要预先安装 VS Code)。你可以保持默认选择并点击“Next”继续。 + ![](images/image6.png) + - 选择如何使用 Git:这三个选项控制 Git 在系统中的可访问性。建议选择选项 2(“from command line and 3rd-party software”)——它将基本的 Git 工具添加到 PATH 中,让你可以在 Git Bash、命令提示符、PowerShell 和 IDE 中使用 Git,而不会使系统混乱。 + ![](images/image7.png) + +3. 安装后,在桌面上右键单击。如果在菜单中看到“Git Bash Here”,则安装成功。 + +![](images/image8.png) + +### MacOS + +对于 macOS,你可以首先在终端中输入 `git --version` 来检查是否已经安装了 Git。如果没有,系统会提示你安装——只需按照说明完成安装即可。 + +1. 方法 1:通过 Homebrew 安装 + 如果你安装了 [Homebrew](https://brew.sh/)(Mac 包管理器),请打开终端并输入 + ```Bash + brew install git + ``` +2. 方法 2:(推荐)通过 Xcode 安装: https://developer.apple.com/xcode/ ,Xcode 内置了 Git。安装后,只需按照说明继续操作。 + +### Linux + +大多数 Linux 发行版可以通过其包管理器安装 Git: + +- Ubuntu/Debian: + +```Bash +sudo apt update +sudo apt install git +``` + +- CentOS/RHEL: + +```Bash +sudo yum install git +``` + +- 验证安装:在终端中输入 git --version。如果显示版本号,则安装成功。 + +## Git 初始化 + +安装 Git 后,你首先需要配置你的用户信息——这是使用 Git 进行版本控制的基本步骤。在终端中执行以下命令(将括号中的内容替换为你自己的信息): + +```Bash +# 设置全局用户名(将显示在提交记录中) +git config --global user.name "Your Name" + +# 设置全局邮箱(建议使用在 GitHub/GitLab 等平台上注册的邮箱) +git config --global user.email "your.email@example.com" +``` + +Git 会将此信息嵌入到每个提交记录中,作为每次修改的“作者信息”。查看版本历史记录(例如,使用 git log)时,你可以清楚地看到谁修改了每一行代码,便于追溯责任和沟通。在协作项目中,统一的身份信息使团队成员能够快速识别谁做了哪些更改,从而提高协作效率(例如通过提交记录找到相关开发人员讨论问题)。 + +你可以通过在命令行中输入 `git config --list` 来查看当前的 Git 配置信息,以确认设置成功。 + +# 什么是 GitHub + +GitHub 是一个基于 Git 的代码托管平台。它不仅为 Git 仓库提供远程存储,还包括协作工具(如 Issues、Pull Requests、Projects),使开发者更容易分享代码和协作。简而言之,Git 是一个本地版本控制工具,而 GitHub 是一个远程“代码仓库云盘 + 协作社区”。 + +GitHub 不仅是世界上最大的代码托管平台,也是全球最活跃、最具影响力的开源社区。这里“开源”的核心思想是任何人都可以下载并运行软件的源代码。这种模式允许世界各地的人们检查彼此的代码并进行修改,或基于此创建新项目。例如,你可以在 GitHub 上找到各种学习教程以及用于训练 GPT 模型的框架(如 PyTorch)的完整源代码。每天,无数人在全球范围内协作审查和改进代码。 + +![](images/image9.png) + +许多大公司在 GitHub 上开源他们的程序或教程,以获得行业竞争优势——这也可以看作是一种广告形式。在 GitHub 社区中,项目获得的“星标 (stars)”数量是衡量其价值的主要指标;项目或组织拥有的星标越多,其可信度和影响力就越大。 + +![](images/image10.png) + +在我们的课程中,支持资源和作业也将上传到专用的 GitHub 仓库。通过上传作业的过程,你将逐渐熟悉并掌握 GitHub 的使用,为未来应用程序开发中的版本控制打下坚实的基础。 + +## 注册 GitHub 账号 + +1. 访问 [GitHub 官网](https://github.com/) 并点击右上角的“Sign up”。 + ![](images/image11.png) +2. 输入你的电子邮件地址(建议使用常用邮箱,因为验证和通知将发送到那里),设置密码(必须包含字母、数字和特殊字符)。 +3. 完成人工验证,按照提示验证邮箱,你的账号就创建好了。 + +## 在 GitHub 上创建你的第一个仓库 + +接下来,我们将创建第一个存储文件夹,也称为仓库或“repo”。 + +![](images/image12.png)![](images/image13.png) + +![](images/image14.png) + +1. Repository name:向他人显示的仓库名称。 +2. Description:仓库的详细描述。 +3. Choose visibility:对于个人仓库,如果设置为 private,只有你和特别邀请的人可以看到。如果设置为 public,所有人都可以看到。 + 对于组织内的仓库,如果是 Private,只有组织内的人可以看到。 + 如果是 Public,组织外的人也可以看到。 +4. README:通常的惯例是每个仓库都应该有一个 README 文件。你可以把它看作是仓库的完整介绍,包括使用说明、文件列表和操作方法。 +5. Add .gitignore and license: + 1. .gitignore 文件告诉 Git 在上传到 GitHub 时忽略某些文件夹或文件,因此它们不会被跟踪或添加到暂存区。这对于临时测试文件、依赖包或大文件很有用。一旦指定,这些文件将不再被跟踪。 + 2. license 指的是你选择的开源许可证类型。不同的许可证详细规定了他人是否可以将你的代码用于商业目的,并包含其他条款和条件。 + +建议勾选“Add README”,将仓库可见性设置为“Private”,并根据自己的喜好填写仓库名称和描述,然后点击“Create repository”完成创建第一个远程仓库。 + +![](images/image15.png) + +之后,你将拥有一个没有任何额外文件的干净仓库。接下来你可以开始上传文件了。 + +![](images/image16.png) + +获取仓库的命令是 `git clone`,但它需要仓库地址。你可以通过点击绿色的“Code”按钮找到仓库地址,你会看到 HTTPS 和 SSH 选项。通常,你可以使用这两种方法中的任何一种将仓库下载到本地机器(只有这样你才能修改和上传文件)。 + +![](images/image17.png) + +一般来说,通过 HTTP 克隆的仓库适合临时下载和测试他人的仓库,但不建议用于自己的开发。为了更好的学习体验,你应该先设置 SSH 认证。 + +## 绑定本地 SSH + +在 GitHub 中,“SSH 协议绑定”本质上意味着将你本地设备的 SSH 公钥与你的 GitHub 账号关联,允许 GitHub 通过 SSH 协议识别你的设备。这使你能够安全地操作远程仓库,而无需密码(如 clone、push 或 pull 代码)。 + +简单来说:这就像给你的设备一张“GitHub 专属门禁卡”。绑定后,当你的设备通过 SSH 协议访问 GitHub 仓库时,GitHub 会验证这张“门禁卡”(你的 SSH 公钥)。一旦确认为你的授权设备,你就可以直接操作——不需要每次都输入账号密码。 + +> 💡 什么是 SSH + +### 为什么需要 SSH 协议绑定? + +GitHub 支持两种主要的仓库操作协议:HTTPS 协议和 SSH 协议: + +- HTTPS 协议:每次操作(如 push)都需要输入 GitHub 账号密码(或个人访问令牌 PAT)。验证过程繁琐,且存在密码泄露风险。 +- SSH 协议:身份验证通过“密钥对”完成,因此不需要重复输入密码,且加密传输更加安全。 + +“SSH 协议绑定”是启用 GitHub SSH 认证的前提步骤——只有将本地 SSH 公钥“绑定”到 GitHub 账号后,GitHub 才能识别你的设备并允许对仓库进行 SSH 操作。 + +### “绑定”的核心逻辑:SSH 密钥对的作用 + +SSH 认证依赖于密钥对(公钥 + 私钥),它们是匹配的加密文件。生成后,你需要将“公钥”提供给 GitHub(“绑定”),而“私钥”留在本地设备上: + +1. 私钥:存储在本地设备(如电脑)的指定目录中(通常是 ~/.ssh/),充当“你的专属钥匙”,绝不能与任何人分享。 +2. 公钥:这是一把可以公开分享的“锁”——你需要将其复制到 GitHub 账号的“SSH keys list”中(“绑定”操作)。 + +当你通过 SSH 操作 GitHub 仓库时(例如 git push git@github.com:xxx/xxx.git): + +- 你的本地设备使用私钥加密“操作请求”并发送给 GitHub; +- 收到请求后,GitHub 尝试使用你之前绑定的公钥进行解密; +- 如果解密成功,你的设备被确认为已授权,操作被允许;否则,访问被拒绝。 + +### “绑定”的具体步骤(核心流程) + +一旦你理解了原理,实际操作就很简单——核心是“生成密钥对 → 上传公钥到 GitHub”: + +1. 本地生成 SSH 密钥对 + 1. 使用 Trae 获取公钥(推荐) + 提示词:`Help me create the SSH key needed for GitHub login. My email is your_email@gmail.com , Please return the public key for me to copy` + + ![](images/image18.png) + + 输入提示词后,你还需要在左侧终端按 Enter 键,否则命令会一直等待而不执行。由于 Trae 无法帮你执行任何条件判断,我们只需要一直按 Enter 即可。 + + 最后,你会看到右侧的 Trae 返回了它读取的公钥。你只需复制它并准备在下一步中粘贴。 + + ![](images/image19.png) 2. 手动获取公钥 + 打开你的本地终端(在 Windows 上使用 Git Bash 或 PowerShell;在 macOS/Linux 上使用终端),输入以下命令(将 your_email@example.com 替换为你注册 GitHub 账号时使用的邮箱): + + ```Bash + ssh-keygen -t ed25519 -C "your_email@example.com" + ``` + + 1. 按 Enter 接受默认值(默认文件路径,无密码,或根据需要设置密码)。这将在 ~/.ssh/ 目录中生成两个文件: + - id_ed25519:私钥(本地保存,**绝不分享**); + - id_ed25519.pub:公钥(需要上传到 GitHub)。 + +2. 将公钥“绑定”到你的 GitHub 账号 + +这是核心绑定步骤——将本地公钥添加到 GitHub 账号的“SSH keys list”中: + +1. 复制公钥内容: + 1. Trae: + 2. Windows:用记事本打开 C:\Users\\.ssh\id_ed25519.pub 并复制其所有内容; + 3. macOS/Linux:在终端运行 cat ~/.ssh/id_ed25519.pub 并复制所有输出(从开头的 SSH-ed25519 到结尾的邮箱)。 +2. 登录 GitHub 并进入“SSH Key Management”页面: + 1. 点击右上角头像 → Settings → 左侧菜单 SSH and GPG keys → 点击 New SSH key。 + ![](images/image20.png)![](images/image21.png) + 2. 输入任何标题(例如,your local computer's SSH),然后将你刚刚获取的 SSH 公钥粘贴到这里。 + +![](images/image22.png) + +![](images/image23.png) + +3. 验证绑定是否成功 + +在终端中输入以下命令(**Trae 也可以做以下操作**)来测试 GitHub 是否能识别你的设备: + +```Bash +ssh -T git@github.com +``` + +- 如果你看到类似 Hi [your GitHub username]! You've successfully authenticated... 的内容,说明你已成功绑定密钥; +- 如果遇到错误,通常是因为公钥复制不完整、私钥权限过高(你的本地 ~/.ssh/ 目录应仅由你读写)等。根据需要检查这些问题。 + +### 重要注意事项 + +如果你有多个设备(如笔记本电脑和台式机),你需要为每个设备生成单独的 SSH 密钥对,并将每个公钥绑定到同一个 GitHub 账号——每个设备都有自己的“门禁卡”。 + +切勿分享你的私钥(不要上传到 GitHub 或与他人分享),否则有人可能会冒充你操作你的仓库。如果私钥泄露,请立即从 GitHub 删除相应的公钥并生成新的密钥对。 + +绑定 SSH 后,使用 SSH 格式的仓库地址(例如 git@github.com:username/repository.git)进行操作,而不是 HTTPS 格式(例如 https://github.com/username/repository.git)。如果你之前用 HTTPS 克隆了仓库,可以用 git remote set-url origin `` 切换协议。 + +# 使用 Trae 进行 GitHub 操作 + +我们已经解释了什么是 Git,什么是 GitHub,什么是 SSH,以及如何配置它。现在你可以自由使用 Trae 执行 Git 操作。首先,让我们学习如何将远程仓库克隆到本地机器。 + +## Git clone : 下载现有仓库 + +你可以直接告诉它你想克隆的仓库地址 + +![](images/image24.png) + +## Git pull : 从远程仓库获取更新 + +每次更新仓库之前,由于它可能由多人维护,你需要先拉取最新的更改。之后,你可以修改并推送文件。 + +**记得包含文件夹名称及其相对或绝对路径,以避免推送到错误的仓库。** + +prompt:`Help me pull this repository AIID-TEST in ./AIID-TEST.` + +## Git commit & Git push : 暂存更新并推送到 GitHub + +一切准备就绪后,你可以尝试修改本地文件,在文件夹中添加或删除项目。然后,让 Trae 检测更改并帮你推送到 GitHub。 + +prompt:`I finished. Commit and push to the repository AIID-TEST in ./AIID-TEST.` + +![](images/image25.png) + +推送成功。现在你可以在 GitHub 上看到更新的内容了。 + +# 参考资料 + +- Pro Git book https://git-scm.com/book/en/v2 +- GitHub Docs https://docs.github.com/en diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image1.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image1.png new file mode 100644 index 0000000..ac42a35 Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image1.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image10.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image10.png new file mode 100644 index 0000000..8fac597 Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image10.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image11.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image11.png new file mode 100644 index 0000000..c4683cd Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image11.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image12.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image12.png new file mode 100644 index 0000000..1264f7f Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image12.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image13.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image13.png new file mode 100644 index 0000000..fcc52d9 Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image13.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image14.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image14.png new file mode 100644 index 0000000..a99bdbf Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image14.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image15.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image15.png new file mode 100644 index 0000000..6b2a4db Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image15.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image16.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image16.png new file mode 100644 index 0000000..c772f6d Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image16.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image17.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image17.png new file mode 100644 index 0000000..bdb3287 Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image17.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image18.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image18.png new file mode 100644 index 0000000..fea0029 Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image18.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image19.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image19.png new file mode 100644 index 0000000..3c042da Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image19.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image2.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image2.png new file mode 100644 index 0000000..5959414 Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image2.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image20.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image20.png new file mode 100644 index 0000000..d47dfae Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image20.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image21.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image21.png new file mode 100644 index 0000000..20aa398 Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image21.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image22.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image22.png new file mode 100644 index 0000000..9138182 Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image22.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image23.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image23.png new file mode 100644 index 0000000..c7eb02b Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image23.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image24.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image24.png new file mode 100644 index 0000000..f886a09 Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image24.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image25.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image25.png new file mode 100644 index 0000000..98445e0 Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image25.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image3.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image3.png new file mode 100644 index 0000000..dce81dc Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image3.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image4.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image4.png new file mode 100644 index 0000000..8c7f1a9 Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image4.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image5.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image5.png new file mode 100644 index 0000000..a81caba Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image5.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image6.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image6.png new file mode 100644 index 0000000..1015ae5 Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image6.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image7.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image7.png new file mode 100644 index 0000000..5d0c4f9 Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image7.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image8.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image8.png new file mode 100644 index 0000000..8657bba Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image8.png differ diff --git a/docs/stage-2/backend/2.4-git-workflow/extra1/images/image9.png b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image9.png new file mode 100644 index 0000000..d006fdf Binary files /dev/null and b/docs/stage-2/backend/2.4-git-workflow/extra1/images/image9.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/extra6-zeabur-what-is-it-and-how-to-deploy-web-applications.md b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/extra6-zeabur-what-is-it-and-how-to-deploy-web-applications.md new file mode 100644 index 0000000..86a3c39 --- /dev/null +++ b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/extra6-zeabur-what-is-it-and-how-to-deploy-web-applications.md @@ -0,0 +1,211 @@ +# 扩展知识 6 - Zeabur 是什么,以及如何部署 Web 应用 + +在本教程中,我们将介绍 Zeabur——一个用于部署 Web 服务的平台。它可以帮助我们快速完成从“写好代码”到“让别人可以在互联网上访问你的网站”的完整流程。 + +# 什么是“部署”? + +在开始之前,我们先弄清楚“部署(Deployment)”到底是什么意思。任何一个网站想要被外部用户访问,都必须有一个可以公开访问的网络地址(这个地址可以是 IP 地址,比如 123.45.67.89,也可以是域名,比如 [google.com](https://google.com/) 等)。但只有地址是不够的——你写好的网页代码(例如 HTML、CSS、JavaScript 文件,或者使用 React、Vue 等框架写的项目),以及相关的图片 / 视频资源,都必须“放”在一台 24 小时在线的服务器上,由它来响应网络请求,这样任何人的浏览器才能访问并下载这些资源。 + +![](images/image1.png) + +图片来源:https://www.hostinger.com/tutorials/what-is-cloud-hosting + +把资源上传、配置好环境并让服务“跑起来”的整个过程,就被称为 **部署(Deployment)**。 + +简单来说:你在自己电脑上写好的网页,只要在本机启动程序,就只能通过本地地址在自己的浏览器里访问,因为这些代码只存在于你的硬盘上。“部署”就是把你的代码和资源转移到一台连接着公网的专业服务器上,并做好配置,让这台服务器知道“别人访问时我要怎么响应”——比如:当有人在浏览器中输入你的域名时,服务器会立刻找到对应的网页文件,把内容传回给对方的设备,从而让用户看到你的页面。 + +如果手动部署,一个项目往往需要好几个步骤,每一步都可能踩坑。常见关键步骤包括: + +1. **服务器准备**:你需要先购买云服务器(比如阿里云、腾讯云、或 AWS EC2),选择服务器所在地区(如上海、新加坡)、配置(CPU、内存、磁盘大小等),还要学会如何远程连接服务器(例如通过 SSH 工具登录)。 + ![](images/image2.png) +2. **环境配置**:Web 应用需要在特定“环境”中才能运行——例如运行 Node.js 项目必须先安装 Node.js;运行 Python 项目必须安装 Python 以及对应的第三方库。如果环境版本不匹配,程序就可能报错、无法启动。 +3. **上传资源**:你需要把本地的代码和资源上传到服务器上,常用的方法包括 FTP 或 Git。如果项目体积比较大(比如包含视频文件),中途一旦断线,有时需要重新上传。 + +![](images/image3.png) + +4. **启动服务并测试**:上传完成后,你还需要在服务器上执行命令启动应用,并测试“分配的网络地址是否能访问”。如果访问不了,有可能是服务器防火墙没有放行对应端口(比如你的应用监听 3000 端口,但该端口被防火墙拦截),也可能是程序本身有 Bug,这时就需要查看服务器日志进行排查。 + > 💡 可以把端口理解为区分同一台设备上不同应用的“房间号”,而 IP 则是这台设备的“门牌号”。IP 和端口合在一起(IP:port),就可以精确定位到某一个网络服务。 +5. **维护与更新**:后续每次你修改代码,都要重新上传并重启服务。如果服务器宕机(例如断电、网络故障),还需要手动重启应用,有时还要额外配置“进程守护工具”,让程序在异常退出后自动拉起。 + +像 Zeabur 这样的“低代码部署平台”,就是为了解决上述复杂问题而诞生的。它会帮你自动完成“买服务器、配环境、上传代码、启动服务、监控运行”等步骤。你只需要把自己的代码仓库(比如 GitHub 或 GitLab)连接到 Zeabur,它就会自动拉取代码、识别应用类型、配置对应的运行时环境,最后给你一个可以被任何人访问的公网地址。它甚至可以一键绑定你自己的域名(例如把 your-app.zeabur.app 改成 your-app.com)。 + +![](images/image4.png) + +接下来,我们会一步步演示如何使用 Zeabur,从“代码仓库”走到“公开可访问的网页”,全程不需要手写任何服务器命令。当然,你也可以使用 Vercel(同样有免费额度)来做类似的简单 Web 部署。不过,[Vercel](https://vercel.com/) 在部分网络环境下访问不太稳定,有兴趣的同学可以课后自行学习(操作也很简单:就是把 GitHub 项目连上即可)。 + +# 使用 Zeabur 部署 Dify + +在之前的课程中,我们已经简单接触过 Dify。现在,我们可以通过 [Zeabur](https://zeabur.com/projects) 非常轻松地启动自己的 Dify 服务。首先打开 [控制台页面](https://zeabur.com/projects),我们先看一下上面的各个区域。 + +![](images/image5.png) + +在这个页面上,你首先能看到许多方块,这些就是已经启动的服务。在顶部菜单中,你会看到 Agent、Servers、Docs、Templates 等几个选项,它们分别代表: + +1. **Agent**:可以打开 Zeabur 内置的智能助手(Agent),向它提问如何操作,或者查询当前服务器的状态。 +2. **Servers**:在这里可以添加你自己购买的云服务器,或者直接通过 Zeabur 购买服务器。 +3. **Docs**:查看 Zeabur 的完整文档说明。 +4. **Templates**:这里列出了所有内置的模板镜像。 + +> 这里提到的“镜像(Image)”,可以理解为“包含代码和运行环境的压缩包”。当某个服务在一台服务器上成功跑起来之后,我们可以选择把“这套运行环境 + 代码”打包成镜像。之后,在任何新服务器上,只要把这个压缩包解压并运行,就不需要重新配置环境和代码,服务就能直接跑起来。 + +在页面右上角,你还能看到自己的余额。默认情况下,每个月会有 5 美元左右的免费额度。关于细节计费规则暂时可以不用太在意,只需要知道:只要服务器在运行,就会消耗额度。 + +![](images/image6.png) + +点击余额可以查看每日的消耗明细。 + +![](images/image7.png) + +现在我们来创建自己的 Dify 服务。首先,在 [控制台首页](https://zeabur.com/projects) 点击 “New Project”。 + +![](images/image8.png) + +接下来是各个创建方式的解释: + +1. **GitHub** + 可以连接到你的 GitHub 账号。绑定之后,就可以直接从 GitHub 仓库里选择项目部署(GitHub 是目前全球最大的代码托管平台)。 +2. **Template(模板)** + 可以基于模板来部署服务。Zeabur 内置了很多预设项目模板(例如 Dify、n8n 等),你可以基于这些模板快速创建并部署应用。 + ![](images/image9.png) +3. **Databases(数据库)** + 用于部署数据库服务,比如 MySQL、MongoDB 等常见数据库。 + ![](images/image10.png) +4. **Functions(函数)** + 可以部署函数服务,你可以编写 JavaScript 或 Python 代码,让它们以函数的形式被调用。 + ![](images/image11.png) + + ![](images/image12.png) + +5. **Local Project(本地项目)** + 上传一个本地文件夹,Zeabur 会自动识别其中的启动脚本。这适合将你已经在本地开发好的项目快速部署到 Zeabur 上。 + ![](images/image13.png) +6. **Docker Image** + 部署已经打包好的 Docker 镜像。如果你的项目已经被打成了 Docker 镜像(例如存放在 Docker Hub 或其他镜像仓库中),可以在这里直接部署。 + ![](images/image14.png) +7. **Cursor** + 如果你安装了 Cursor(例如 Cursor IDE),可以通过这个入口将 Cursor 中的项目直接部署到 Zeabur。 + +如果你想部署自己的 Dify 服务,推荐选择 **Template** 方式,然后在搜索框中输入 “dify”。可以看到很多由不同作者维护的版本,你可以任选其一(比如 v1.6.0 版本)。 + +![](images/image15.png) + +接着,输入任意一个名称,Zeabur 会基于这个名称生成一个临时的自定义域名。之后所有人都可以通过这个网址访问你的服务。 + +![](images/image16.png) + +创建完成后,你会看到多个程序(服务)依次启动。需要耐心等待所有服务都进入“已启动”状态。(Dify 服务是由多个程序组成的,每个程序负责不同的功能,它们之间会相互协作。) + +一般来说,你只需要点击左侧的 Dify 应用,就可以看到默认的访问入口地址。但在本例中,由于前面还套了一层 nginx,你需要点击 nginx 服务来获取最终访问地址。可以理解为:nginx 就是负责对外统一“收发请求”的主程序,它会把外部访问的地址分发给内部各个服务。点击左侧的 Nginx,在详情页中可以看到当前的服务地址,然后在浏览器里打开这个地址,等待服务完全启动。 + +![](images/image17.png) + +稍等片刻后,你就能看到 Dify 的登录界面了。输入邮箱地址和注册密码,就可以开始使用你自己的 Dify 服务了。 + +![](images/image18.png) + +如果你有兴趣,还可以顺便启动一个 n8n 服务。n8n 也是海外非常流行的一款 AI 工作流平台。 + +![](images/image19.png)![](images/image20.png) + +# ⚠️ 如何停止和删除项目 + +由于启用服务器相关资源都会产生费用,我们在使用时一定要养成“及时关闭不用服务”的习惯,避免把每个月的免费额度消耗完。 + +如果要找到项目的管理入口,首先点击项目中的 “Settings” 选项。 + +![](images/image21.png) + +进入设置页面后,将页面拉到最下方,你会看到类似下面的界面: + +![](images/image22.png) + +你可以点击 “Suspend All Services” 来暂停所有服务以降低费用;如果服务出现问题,可以点击 “Restart All Services” 对全部服务进行重启。如果你确定不再需要这个项目,可以点击 “Delete Project” 将整个项目彻底删除。 + +# 使用 Zeabur 与 Trae 部署贪吃蛇游戏 + +在本教程的下一个部分,我们会体验 Zeabur 的一些进阶用法。我们先用 Trae 生成一个贪吃蛇小游戏,再把它部署到 Zeabur 的服务器上,并配置一个可公开访问的链接,让任何人都可以打开你的游戏。 + +第一步,是在本地使用 Trae 创建一个贪吃蛇项目。 + +### 使用 HTML 框架实现 + +![](images/image23.png) + +对于 Trae 来说,生成一个基于 HTML 的贪吃蛇网页游戏非常简单。游戏生成完成后,你只需要按照前面介绍的 Zeabur 本地部署方式,把包含所有文件的文件夹上传上去即可。 + +![](images/image24.png)![](images/image25.png)![](images/image26.png) + +完成后,你就会进入该服务的详情界面: + +![](images/image27.png) + +点击左侧的 “Network” 选项,在页面中找到 “Public Address” 区域。点击 “Generate Domain”,即可生成一个对外访问地址,你可以输入任意喜欢的名称。 + +![](images/image28.png) + +![](images/image29.png) + +生成完成后,只要在浏览器中打开这个地址,就可以运行你自己的贪吃蛇游戏了。其它 HTML 类型的 Web 应用也可以用完全相同的方式来部署。 + +![](images/image30.png) + +### 使用 React 框架实现 + +前面我们学习了如何部署基于 HTML 的 Web 应用。接下来,我们再尝试部署一个目前更常用的前端框架:React 应用。相比纯 HTML,React 被认为是一种更加成熟、现代的前端开发框架。它通过组件化的方式组织页面结构,能够显著加快复杂页面的开发,是企业级项目中非常主流的选择。 + +![](images/image31.png) + +#### 重构为 React 架构 + +在 Trae 中,你只需要向 Agent 说明:“帮我把这份代码重构成 React 架构”,就可以比较轻松地把原本基于 HTML 的结构重构成 React 项目。 + +![](images/image32.png) + +不过,相比简单的 HTML 文件,React 应用依赖更复杂的构建工具和项目结构,因此部署过程也会稍微麻烦一些。一个典型的问题体现在端口设置上:默认情况下,React 应用一般会监听 3000 端口(你也可以在配置文件或启动日志中看到这一点)。 + +然而,在 Zeabur 上这样部署会失败——因为 Zeabur 只支持监听 8080 端口的应用。也就是说,如果想让 React 应用在 Zeabur 上正常运行,我们必须先把默认监听端口从 3000 改成 8080。 + +要正确进行这一步配置,我们需要先弄清楚两个概念:什么是“端口(Port)”,以及“监听端口(Listening Port)”是什么意思。 + +#### 什么是端口? + +> 在计算机网络中,端口可以理解为一个“逻辑通信端点”,用来区分同一台设备上运行的不同网络服务。简单类比的话,如果 IP 地址好比一个“门牌号”(例如 162.128.1.1),那端口号就像这栋楼里不同房间的“房间号”——每个房间对应一个服务(例如 Web 服务器、邮箱服务,或者你的 React 应用)。 +> +> 端口号用 16 位整型表示,取值范围是 0 到 65535。 + +如果不想记这些细节,可以简单理解:端口是构成“网络访问地址”的一个必要部分。 + +我们平时访问网站或 IP 地址时,通常不会手动加端口号,是因为 Web 的默认端口是 80 或 443(HTTPS)。大多数浏览器会自动使用这些标准端口。而对于一些特殊端口,比如 React 默认的 3000、Zeabur 要求的 8080,我们就必须在地址后面加上 `:3000` 或 `:8080` 才能访问到对应的内容。 + +#### 什么是“监听端口号”? + +> “监听端口号”指的是某个程序在一台设备上主动“打开并监控”的端口。当一个应用设置了监听端口时,其实就是在告诉操作系统:“我会一直在这个端口上等待网络请求——只要有请求进来,就请转发给我。” + +再形象一点地理解:假设你的电脑是一栋写字楼,IP 地址是这栋楼的地址。楼里开了很多公司或部门,它们分别占用不同的房间,房间号就是端口号。 + +当默认的 React 开发服务器启动时,它会“打开”某个房间的门,并安排“前台”在门口值班,这个房间号就是它的监听端口——3000。 + +同时,React 程序还会告诉这栋楼的“物业管理”(操作系统):“我在 3000 号房间,请把所有寄给 3000 的信件(网络请求)都转给我。” + +这样,当你访问 React 网站时,请求首先会到达这栋楼;物业看到请求要送到 3000 号房间,就会立刻把请求交给 React 的“前台”,由它来处理并返回结果——这就是访问 React 应用的过程。 + +当你在本地执行 `npm start`(本地启动 React 开发服务器的默认命令,也可以在 Vibe Coding 的 Agent 侧边栏中执行)时,React 开发服务器就会自动把监听端口设置为 3000。 +而 Zeabur 的平台设计决定了它只会“识别”监听 8080 端口的应用。如果你的 React 应用仍然使用默认的 3000 端口,Zeabur 就无法将请求正确转发给你的应用,最终导致部署失败。 + +#### 修改默认监听端口 + +要把 React 默认监听端口(3000)改成 Zeabur 所要求的 8080,有很多做法。最简单的方式,就是直接在 Trae 里对 Agent 下指令:“请帮我把这个 React 项目的默认端口改为 8080。”Trae 就会帮你修改项目中对应的配置文件。修改完成后,你只需重新打包并按前面的方式上传到 Zeabur 即可。 + +![](images/image33.png) + +![](images/image34.png) + +在网络设置中指定一个访问 URL,方式和部署 HTML 项目时基本相同,就可以启动 React 版本的服务。 + +![](images/image35.png) + +![](images/image36.png) + +对于其它需要修改端口号的程序,你也可以采用同样的思路:先改默认端口,再上传到 Zeabur 部署。至此,你已经掌握了将常见 Web 应用部署到服务器的基础技能。 + +你可以尝试让 Trae 帮你构建不同类型的应用,并把它们部署到 Zeabur 的默认服务器上。在后续课程中,我们还会学习如何把应用部署到你自己购买的云服务器上。 diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image1.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image1.png new file mode 100644 index 0000000..09a65f0 Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image1.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image10.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image10.png new file mode 100644 index 0000000..11f4cf8 Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image10.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image11.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image11.png new file mode 100644 index 0000000..3c69201 Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image11.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image12.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image12.png new file mode 100644 index 0000000..2c01936 Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image12.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image13.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image13.png new file mode 100644 index 0000000..cf1ca30 Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image13.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image14.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image14.png new file mode 100644 index 0000000..35a2a8d Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image14.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image15.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image15.png new file mode 100644 index 0000000..4d5125e Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image15.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image16.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image16.png new file mode 100644 index 0000000..970cf38 Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image16.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image17.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image17.png new file mode 100644 index 0000000..aae3474 Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image17.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image18.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image18.png new file mode 100644 index 0000000..9bd3b2b Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image18.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image19.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image19.png new file mode 100644 index 0000000..4260258 Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image19.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image2.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image2.png new file mode 100644 index 0000000..1badfce Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image2.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image20.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image20.png new file mode 100644 index 0000000..af03aed Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image20.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image21.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image21.png new file mode 100644 index 0000000..d505050 Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image21.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image22.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image22.png new file mode 100644 index 0000000..22b72ba Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image22.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image23.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image23.png new file mode 100644 index 0000000..c5ef407 Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image23.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image24.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image24.png new file mode 100644 index 0000000..e6c90d9 Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image24.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image25.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image25.png new file mode 100644 index 0000000..e7c2c92 Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image25.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image26.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image26.png new file mode 100644 index 0000000..cd57f82 Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image26.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image27.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image27.png new file mode 100644 index 0000000..eb3c9c1 Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image27.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image28.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image28.png new file mode 100644 index 0000000..01caf9d Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image28.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image29.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image29.png new file mode 100644 index 0000000..c72b87c Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image29.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image3.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image3.png new file mode 100644 index 0000000..983045c Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image3.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image30.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image30.png new file mode 100644 index 0000000..fe9dcb9 Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image30.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image31.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image31.png new file mode 100644 index 0000000..3431193 Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image31.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image32.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image32.png new file mode 100644 index 0000000..f226f84 Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image32.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image33.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image33.png new file mode 100644 index 0000000..9f374b4 Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image33.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image34.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image34.png new file mode 100644 index 0000000..34d184c Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image34.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image35.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image35.png new file mode 100644 index 0000000..b17d2f2 Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image35.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image36.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image36.png new file mode 100644 index 0000000..8c7869a Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image36.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image4.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image4.png new file mode 100644 index 0000000..1e292b9 Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image4.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image5.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image5.png new file mode 100644 index 0000000..948b96f Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image5.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image6.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image6.png new file mode 100644 index 0000000..41f6011 Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image6.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image7.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image7.png new file mode 100644 index 0000000..fd73a75 Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image7.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image8.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image8.png new file mode 100644 index 0000000..f7f0638 Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image8.png differ diff --git a/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image9.png b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image9.png new file mode 100644 index 0000000..4dc4abf Binary files /dev/null and b/docs/stage-2/backend/2.5-zeabur-deployment/extra6/images/image9.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/extra7-cli-ai-coding-tools-and-the-principles-of-test-driven-development.md b/docs/stage-2/backend/2.6-modern-cli/extra7/extra7-cli-ai-coding-tools-and-the-principles-of-test-driven-development.md new file mode 100644 index 0000000..7f93d44 --- /dev/null +++ b/docs/stage-2/backend/2.6-modern-cli/extra7/extra7-cli-ai-coding-tools-and-the-principles-of-test-driven-development.md @@ -0,0 +1,630 @@ +# 扩展知识 7 - CLI AI 编程工具与测试驱动开发原则 + +在本教程中,我们将介绍直接在命令行中运行的 AI 编程 Agent。它们和之前学过的 Trae、Cursor 中的 Agent 不同,CLI AI 编程工具只能在终端中使用。与集成在 AI IDE 里的 Agent 相比,它们通常具有更长的上下文窗口、更快的工具调用速度,并且可以兼容更多种类的大模型。在最新的 AI Vibe Coding 实战中,我们往往会优先使用 CLI AI 编程工具,而不是 IDE 内置的编码 Agent。 + +## 从 CLI 说起 + +还记得我们之前介绍过的 CLI 吗?CLI 指的是通过终端或命令提示符,用纯文本命令来操作软件应用,而不是依赖图形界面(GUI——你可以简单理解为电脑或手机上带按钮、可以点击操作的界面,不需要输入命令)。 + +> 在 Windows 上,常见的终端有“命令提示符(cmd)”和 “PowerShell”。你可以在电脑的运行/搜索框中输入 “cmd” 或 “powershell” 来启动这些命令行程序。 + +![](images/image1.png)![](images/image2.png) + +CLI 天生适合文本命令操作,在一小部分极客(追求极致的编程爱好者)群体中,CLI 甚至比 GUI 更受欢迎——他们希望所有操作都通过键盘完成,觉得动鼠标反而会拖慢自己的编码效率。 + +在工业界,CLI 往往也是最常见的接口形式,因为 GUI 需要操作系统额外绘制界面、管理窗口,对计算机资源的要求更高;而 CLI 只需要把收到的命令传给系统执行即可。因此,在连接大规模服务器集群时,我们通常只通过 CLI 进行交互。 + +![](images/image3.png) + +对于许多没有 CLI 经验的同学来说,可能会觉得 CLI 操作很复杂、命令太多,甚至担心“一不小心就把电脑搞坏”。不用担心。还记得我们在前面教程里,经常让 Trae 帮忙完成各种基础操作吗?这里也可以完全照搬这个思路——我们可以让 CLI 编程工具帮我们执行所有 CLI 操作:让它帮你进入指定文件夹、搜索和处理文件、运行或复制开源项目等。整个过程都可以通过和 CLI AI 编程工具的对话来完成。 + +## 和 AI IDE 有什么不同 + +我们可以把 CLI AI 编程工具类比成之前学过的 z.ai 和 Trae。某种意义上,CLI AI 编程工具可以看成是一种特殊的 z.ai:它们同样只需要一个简单的对话入口,就会自动为你执行所有需要的操作(只是有时你需要手动打开浏览器查看最终效果)。而如果类比 AI IDE,那么 CLI AI 编程工具可以被看作是 IDE 中的 Agent 模块——也就是侧边那块对话区域。 + +![](images/image4.png)![](images/image5.png) + +不过,由于不同 AI IDE 对 Agent 的实现方式不同,能力差异也很大,AI 编程效果经常不稳定,因此 CLI AI 编程工具通常由大型科技公司直接开发,例如 Claude 背后的 Anthropic、ChatGPT 背后的 OpenAI 等。 + +相比其他 AI 编程 Agent,直接使用这些大厂产品往往是较优的实践,尤其是 Claude Code 本身就是为 Anthropic 内部研发团队服务的工具,从一开始就围绕“满足工程师真实需求”来设计。 + +为了更直观地对比,我们可以简单看看 Claude Code 和某款 AI IDE Agent 的差异(这里以 Cursor 为例): + +| 功能特性 | Claude Code | Cursor | 更优者 | +| ----------------- | ------------- | --------------- | ----------- | +| 自动任务执行 | ✅ 非常强 | ❌ 能力有限 | Claude Code | +| IDE 集成 | ❌ 仅命令行 | ✅ 原生 VS Code | Cursor | +| 实时代码补全 | ❌ 无 | ✅ 体验极佳 | Cursor | +| 多文件操作 | ✅ 非常强 | ⚠️ 还不错 | Claude Code | +| GitHub 一体化操作 | ✅ 可直接提交 | ⚠️ 需要手动操作 | Claude Code | +| 学习成本 | ⚠️ 中等 | ✅ 上手简单 | Cursor | +| 上下文长度 | ✅ 非常长 | ⚠️ 较好 | Claude Code | +| 调试辅助 | ✅ 自动化 | ⚠️ 较多需手动 | Claude Code | + +表格来源:https://northflank.com/blog/claude-code-vs-cursor-comparison + +简单说,CLI AI 编程工具通常可以: + +- 支持更长时间的连续对话(甚至可以帮你“工作一整天”)。 +- 提供更长的上下文窗口(不再频繁需要你说“继续”)。 +- 响应速度更快(可以接入更多自定义模型 API)。 + +在编码相关操作上,它们通常比大部分 IDE 内置 Agent 更聪明、更稳定。 + +## 常见的 CLI AI 编程工具 + +目前虽然有很多开源实现,但在实践中我们只推荐两大类型的 CLI AI 编程工具,作为“首选组合”。你可以根据自己的习惯任选其一,强烈建议都试一试,再选出最适合你的那一个。 + +- Codex 使用 GPT-5,在整体能力上更强; +- Claude Code 通过 GLM 4.6 转发 API,整体体验接近 Claude 4,但价格更便宜。 + +不过,哪一个在实际项目中更好用,只能通过亲自测试来判断。掌握多种 AI 编程工具始终是有益的:熟练以后,你可以在不同场景下灵活切换 Claude Code、Codex 或 Trae。如果尝试多次后发现某个工具效果一般,可以直接换一个工具或模型继续试验。 + +同时,由于模型版本更新非常迅速,建议你优先选择在“性价比(效果 / 成本)”上表现最好的方案。 + +### Claude Code + +Claude Code 是由 Anthropic 基于 Claude 大模型能力开发的一款 AI 编程工具。它的主要交互场景在终端,同时也支持作为 VS Code 插件来使用。类似于 AI IDE 中的 Agent,它可以深度理解开发者的代码仓库,并通过自然语言指令完成端到端的开发任务——包括代码编辑、修复 Bug、执行和修复测试、管理 Git 工作流(例如解决合并冲突、创建 PR)、复杂代码讲解、执行终端命令等。 + +![](images/image6.png) + +Claude Code 的优势主要体现在:极长的上下文窗口(可以处理完整文件甚至小型项目)、可以主动澄清模糊需求、自动规划和分配执行任务,以及对整个代码库内容的深度理解和解释能力。与普通 IDE Agent 相比,它更适合“沉浸式 vibe coding” 的开发流程。 + +在实际使用中,你可以通过对话指令,让它帮你创建新项目、执行 CLI 操作(例如整理文件夹、批量重命名文件、部署开源项目等)、配置开发环境(例如安装和调试 Python 环境)。如果觉得某段代码难以理解、某个目录结构不清晰,也可以直接让 Claude Code 生成结构化的分析文档,或者对特定内容进行分步骤讲解。 + +![](images/image7.png)![](images/image8.png) + +![](images/image9.png)![](images/image10.png) + +如果你想系统地学习 Claude Code,可以参考 Andrew Ng 与 Anthropic 联合推出的课程: +https://www.bilibili.com/video/BV176t2zSEpr + +接下来,我们将学习如何使用 Claude Code。由于直接使用官方 Claude Code 的成本往往非常高(如下图所示),我们会转而使用兼容 Claude Code 协议、但基于其他大模型的 API 平台。 + +![](images/image11.png) + +你需要学习下面几种不同方案(最好都尝试一遍),最后选择最适合你的那一种作为主要实践路径。 + +第一种方式是直接使用“兼容 Anthropic 接口”的 API。随着 Claude Code 的流行,越来越多的大模型服务商开始支持 Anthropic 风格的调用方式。常见的服务商包括 GLM、Kimi、DeepSeek 和 Siliconflow 等,它们都提供了兼容的 API 接口。关于具体配置,我们会在后文细讲。 + +需要注意的是,Claude Code 通常会消耗大量 token,如果你担心 API 调用产生过高费用,可以考虑购买 GLM 的月度套餐(大约 20 元/月)来控制成本。如果你想先感受一下实际花费,也可以先充值 10 元做小规模试验。 + +另一种方式是使用 “Claude Code Route” 项目。它是一个开源工具,不仅支持所有常见的 API 调用接口,还允许你针对不同场景精细配置要使用的模型,并且支持对接本地部署的大模型。但由于这一方案的配置相对复杂,建议你先从第一种方案入手。 + +#### 使用智谱 GLM 作为后端(推荐) + +GLM(General Language Model)是智谱 AI 自主研发的一系列大型语言模型。GLM-4.6 是当前 GLM 系列的最新版本,其核心亮点是在代码能力上的优异表现(在公开基准和真实任务中对标 Claude Sonnet 4,在国内处于第一梯队)。 + +![](images/image12.png) + +它还将上下文窗口扩展到 200K,可以更加从容地处理长文本和大体量代码,同时加强了推理与工具调用能力,在性能和成本之间取得了不错的平衡。 + +![](images/image13.png) + +在接入 GLM 之前,我们需要先安装 Claude Code。 + +如果你觉得命令行安装步骤麻烦,或者中途出现错误,可以直接让 Trae 的 Agent 帮你完成安装。 + +```Python +# 安装 Claude Code +npm install -g @anthropic-ai/claude-code + +# 进入你的项目 +cd your-awesome-project + +# 启动 Claude Code +claude + +# 按 Ctrl+C 退出 Claude +``` + +接下来,我们需要修改 Claude Code 的默认 API 请求地址,使其支持 GLM 的 API 服务。你可以直接复制下面的内容,让 Trae 帮你创建对应的环境变量;也可以选择把它们永久写入系统环境变量(如果出现问题,同样可以让 Agent 帮忙修改)。 + +首先,你需要先获取 GLM 的 API Key,并用你自己觉得最方便的方式保存好。 + +国内版地址:https://bigmodel.cn/usercenter/proj-mgmt/apikeys +国际版地址:https://z.ai/manage-apikey/apikey-list + +如果你使用的是 **国内版 GLM**,请使用以下变量配置: + +```Python +# 在 Cmd 中运行以下命令 +# 注意将 `your_zhipu_api_key` 替换为你刚刚获取到的 API Key +setx ANTHROPIC_AUTH_TOKEN your_zhipu_api_key +setx ANTHROPIC_BASE_URL https://open.bigmodel.cn/api/anthropic +``` + +如果你使用的是 **国际版 GLM**,请使用下面的配置: + +```Python +# 在 Cmd 中运行以下命令 +# 同样注意替换掉 `your_zai_api_key` +setx ANTHROPIC_AUTH_TOKEN your_zai_api_key +setx ANTHROPIC_BASE_URL https://api.z.ai/api/anthropic +``` + +你可以直接在 Trae 中输入类似下面的提示词: + +⚠️ 如果你是通过 Trae 帮你配置“永久环境变量”,那么配置完成后 **必须重启 Trae**,否则它内置终端里的环境变量不会更新,可能导致登录失败或网络连接错误。 + +```Python +Based on my environment variable settings: +setx ANTHROPIC_AUTH_TOKEN your_zai_api_key +setx ANTHROPIC_BASE_URL https://api.z.ai/api/anthropic + +and my key(Replace it with your own key): +681fea485851d29060cc.13gfaendggaFOhb + +please help me configure and start Claude Code +``` + +你会看到类似下面的过程输出: + +![](images/image14.png) + +> 💡 什么是环境变量? +> +> 环境变量本质上是一组存储在操作系统中的“键值对”配置信息,通常以 “变量名 = 具体值” 的形式存在。只要提前在终端或系统设置中配置好,程序就可以随时读取这些变量来获取相关信息。由于环境变量可以直接在终端中写入,而无需修改代码本身,我们通常会把访问大模型所需的密钥存放在环境变量里,以避免泄露。程序只需要读取对应环境变量,就能完成大模型调用。 +> +> 在 Windows 系统中,环境变量除了用于存储大模型的访问密钥,还常常用来保存命令行工具的“调用路径”。 +> +> 我们知道终端本身也是一个程序。有时我们希望在终端里启动某个外部程序,例如在终端中输入 `claude` 来启动 Claude Code。之所以可以直接输入 `claude` 就运行,是因为终端会读取系统的环境变量,其中的 PATH 变量里包含了 Claude Code 可执行文件所在的目录,所以终端能够找到并执行它(等价于在终端中粘贴那段程序的绝对路径再按回车)。 +> +> 一个典型的环境变量可能长这样:`PATH=C:\Windows\system32;C:\Program Files\Python`。这样我们就可以在任何路径下执行系统中的这些程序,例如直接在命令行键入 `python` 启动 Python 解释器。 +> +> 如果你想查看系统当前的环境变量,可以在 Windows 搜索中输入“环境变量”,在弹出的“编辑系统环境变量”窗口中就能看到所有变量及其值。有的变量用于存储大模型密钥,有的则用于添加程序目录,方便在任意路径下调用。 + +现在,你就可以使用最新的 GLM 来进行 Claude Code 开发了。你可以尝试重新跑一遍之前的项目,或者重新挑战那些 Trae 没有完成好的任务,对比看看体验上的差异。 + +🎉 反复“推倒重来”并不是浪费时间——你每重做一遍,技能都会更扎实一分。 + +用和 GLM 完全相同的思路,也可以轻松接入其他支持 Anthropic 兼容格式的接口。 + +#### 使用 Kimi K2 作为后端(推荐) + +https://platform.moonshot.cn/console/account + +```Plain +export ANTHROPIC_BASE_URL=https://api.moonshot.ai/anthropic +export ANTHROPIC_AUTH_TOKEN=sk-YOURKEY +``` + +#### 使用 DeepSeek 作为后端(推荐) + +https://platform.deepseek.com/usage + +```Bash +export ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic +export ANTHROPIC_AUTH_TOKEN=YOU_DEEPSEEK_API_KEY +export API_TIMEOUT_MS=600000 +export ANTHROPIC_MODEL=deepseek-chat +export ANTHROPIC_SMALL_FAST_MODEL=deepseek-chat +export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 +``` + +#### 其他兼容 Anthropic 的 API + +Siliconflow: + +```Bash +export ANTHROPIC_BASE_URL="https://api.siliconflow.cn/" +export ANTHROPIC_MODEL="moonshotai/Kimi-K2-Instruct-0905" # 可以自行修改所需模型 +export ANTHROPIC_API_KEY="YOUR_SILICONCLOUD_API_KEY" # 请替换 API Key +``` + +阿里云 DashScope(Aliyuncs):https://help.aliyun.com/zh/model-studio/get-api-key + +```Python +export ANTHROPIC_BASE_URL="https://dashscope.aliyuncs.com/apps/anthropic" +export ANTHROPIC_API_KEY="YOUR_DASHSCOPE_API_KEY" +``` + +#### 使用 Claude Code Route 作为后端(进阶用法) + +上面我们讲解了如何用 GLM 官方 API 替换 Claude Code 的 Anthropic 接口。接下来,我们来看一下 Claude Code Router 这个工具是如何让 Claude Code 适配更多模型 API 的。 + +[Claude Code Router](https://github.com/musistudio/claude-code-router) 是一款专门为 Claude Code 设计的智能路由增强工具。它的核心作用,是帮助用户按需将 AI 请求分发到不同平台上的模型,并可以高度自定义。它支持接入几十个平台,包括 OpenRouter、DeepSeek、Ollama、Gemini 等,也可以按场景将任务路由到特定模型,比如 GLM-4.5、Kimi-K2、Qwen3-Coder 等。举例来说,你可以将后台任务自动交给本地 Ollama,以节省成本;将长文本 / 长代码任务交给 Gemini-2.5-Pro;把代码讲解交给 DeepSeek。 + +![](images/image16.png) + +该工具还提供了方便的 UI/CLI 配置管理能力,并通过“转换器(converter)”适配不同平台的 API 格式。它支持 GitHub Actions 等自动化集成以及自定义扩展,解决了“单一模型无法覆盖所有场景”以及“频繁切换平台很麻烦”的问题,帮助用户更灵活、低成本地利用 AI 工具。 + +![](images/image17.png) + +下面我们简单介绍如何安装 Claude Code Router。大致需要以下步骤(同样可以让 Trae 帮你执行),以准备好相关环境: + +```Markdown +npm install -g @anthropic-ai/claude-code +npm install -g @musistudio/claude-code-router +``` + +安装完成后,你需要确认本地可以使用 `ccr` 命令。如果看到类似下面的输出,说明安装成功: + +![](images/image18.png) + +接下来,有两种方式来初始化和配置模型: + +- 使用 CCR 自带的 UI,在浏览器中打开它提供的配置页面进行操作; +- 直接修改 CCR 的默认配置文件(本质上 UI 也是在修改配置文件,只是提供了更直观的界面)。 + +如果选择使用 CCR UI,你会看到类似下面的界面: + +![](images/image19.png) + +此时点击 “Add Provider” 按钮,就会看到如下界面。你需要: + +1. 在 Name 中输入模型提供商的名字; +2. 在 API Full URL 中填写该提供商的 OpenAI 兼容接口地址; +3. 在 API Key 中填写对应平台的 API Key; +4. 在 Models 区域中填写模型名称,点击 “Add Model” 添加; +5. 最后点击 “Save” 保存配置。 + +(界面往下滚动还有很多高级选项,但目前你可以先忽略它们。) + +![](images/image20.png) + +下面是 DeepSeek 与 Kimi 的配置示例: + +![](images/image21.png) + +![](images/image22.png) + +保存模型配置后,还需要在右侧 Router 区域中指定默认模型(Default)。点击对应的下拉选择,将其设置为 `kimi`(推荐),然后在右上角点击 `Save and Restart`。 + +![](images/image23.png) + +之后,只需在终端中输入 `ccr code`,即可通过 Claude Code Router 启动 Claude Code 的编码工作流。 + +![](images/image24.png) + +#### Claude Code 的进阶用法 + +很多人最开始使用 Claude Code 时,只把它当成普通对话工具来用。但实际上,它内置了很多丰富的能力,能够让你使用起来更高效、灵活。下面是一些常见命令和用法示例: + +参考文档: + +https://docs.claude.com/en/docs/claude-code/cli-reference +https://docs.claude.com/en/docs/claude-code/slash-commands + +| 命令 | 作用 | 示例 | +| ----------------- | ----------------------------------------- | ---------------------------------------- | +| claude | 启动交互模式 | `claude` | +| claude "query" | 执行一次性任务并输出结果 | `claude "explain this project"` | +| claude -p "query" | 执行一次性问题并在结束后自动退出 | `claude -p "explain this function xxxx"` | +| claude -c | 继续最近的一次会话 | `claude -c` | +| claude -r | 恢复上一段会话 | `claude -r` | +| /resume | 在当前聊天中切换回上一段会话 | `claude -c`、`/resume` | +| claude commit | 协助创建 Git 提交信息并提交代码 | `claude commit` | +| /init | 用 CLAUDE.md 初始化项目说明 | `/init` | +| /clear | 清空当前会话上下文,防止信息过载 | `/clear` | +| /compact | 压缩会话历史,减少上下文 token 占用 | `/compact` | +| /cost | 查看当前消费情况 | `/cost` | +| /model | 切换使用的模型(用兼容 API 时一般可忽略) | `/model` | +| /memory | 管理 CLAUDE.md 记忆文件 | | +| /help | 显示可用命令列表 | `/help` | +| exit or Ctrl+C | 退出 Claude Code | `exit` 或 `Ctrl+C` | +| /agents | 高级功能,后文会说明 | | +| /mcp | 高级功能,后文会说明 | | + +**CLAUDE.md** + +参考: https://www.anthropic.com/engineering/claude-code-best-practices + +`CLAUDE.md` 是 Claude 在开始对话时会自动读取并加入上下文的特殊文件。因此,它非常适合用来记录: + +- 常用 bash 命令 +- 核心文件和工具函数 +- 代码风格约定 +- 测试方式说明 +- 仓库协作规范(例如分支命名、是用 merge 还是 rebase 等) +- 开发环境配置说明(例如是否使用 pyenv、推荐哪种编译器等) +- 项目中需要特别注意的行为或坑点 +- 任何你希望 Claude “记住”的信息 + +`CLAUDE.md` 本身没有强制格式要求,只要简洁、便于人类阅读即可。例如: + +```Plain +# Bash commands +- npm run build: Build the project +- npm run typecheck: Run the typechecker + +# Code style +- Use ES modules (import/export) syntax, not CommonJS (require) +- Destructure imports when possible (eg. import { foo } from 'bar') + +# Workflow +- Be sure to typecheck when you’re done making a series of code changes +- Prefer running single tests, and not the whole test suite, for performance +``` + +#### Claude Code 的内部原理 + +参考: https://github.com/shareAI-lab/analysis_claude_code + +如果你好奇为什么 Claude Code 在很多场景下比 Trae 或 Cursor 等 Agent 编程工具更好用,我们可以简单看一下它的内部工作机制。 + +其他 CLI AI 编程工具的整体实现方式也大体类似。 + +![](images/image25.png) + +Claude Code 会把编程任务拆解成一个持续的“感知—思考—行动—验证”循环,并在其中调用不同工具完成任务。它模仿人类开发者的工作流:不断“写代码 → 运行 → 看结果 → 再改进”。系统内部通过一个主任务循环不断执行步骤,在每一轮循环中,Claude 都可以调用不同工具——例如读写文件、执行命令、搜索代码等——再根据工具返回的真实结果决定下一步行动。 + +其中有几个关键特性值得注意: + +- **流式处理(Stream Processing)**:Claude 可以一边思考一边输出结果,而不是必须等所有代码写完再执行。 +- **智能压缩(Intelligent Compression)**:长对话容易导致上下文过长,Claude 通过将历史压缩成关键信息来减少“遗忘”的概率,并通过区分长短期记忆保证高效运行。 +- **并发控制(Concurrency Control)**:内部并行设计可以让多个任务同时进行,互不干扰。 +- **子 Agent 管理(Sub-agent Management)**:实际工作中并不只相当于一个“角色”处理所有事情,你可以管理多个子 Agent 协作处理代码,每个 Agent 负责不同任务,比如专门负责测试、专门负责写文档等。 + +### Codex + +![](images/image26.png) + +![](images/image27.png) + +和 Claude Code 类似,Codex 是由 OpenAI 开发的一款 AI 协作编程工具,你可以把它理解成 “OpenAI 版的 Claude Code”。它最大的优势是对 GPT-5 的高效适配。 + +从实际体验来看,GPT-5 目前响应速度更快、犯错率更低(在多轮复杂任务中正确完成的概率更高)。它的一个缺点是解释往往偏“学术”和“技术”,有时显得过于严谨、信息量很大,对初学者来说可能略微难懂。 + +你可以通过下面的命令安装 Codex: + +```Plain +npm i -g @openai/codex +``` + +#### 使用 OpenAI 官方 API 作为后端 + +如果直接使用 OpenAI 官方的 Codex 入口,配置会非常简单:当你已经开通 OpenAI 订阅或申请到了相应 API 配额之后,只需要在命令行中输入 `codex` 启动程序,并按提示完成登录即可。 + +![](images/image28.png) + +![](images/image29.png) + +#### 使用转发 OpenAI API 的方式作为后端 + +由于官方 OPENAI API 可能存在价格较高、网络要求严格等问题,为了避免这些限制,我们也可以通过其他 API 网关服务来转发调用。 + +在这种方式下,我们只需要在第三方转发平台上购买对应的 Codex API 配额,就能获得接近原生 OpenAI Codex 的使用体验。 + +参考: https://open-dev.feishu.cn/wiki/PAqUwWG4IiuwTvkQ2sGcaQuPnXc +充值地址: https://api.zyai.online/account/topup/recharge + +需要注意的是,在拿到 token 配额后,我们还需要在本地配置好 API Key。 + +在密钥分组设置中,要注意选择专门用于 Codex 的那一项。 + +![](images/image30.png) + +接下来,我们需要把获取到的 Key 填入下面的提示词中,并把整段提示词交给 Trae,让它帮你完成整个配置过程: + +````Bash +My API key is: [Paste your obtained sk-xxxxx key here] + +Please help me complete the following configuration tasks: + +1. Create configuration directory + - Create a `.codex` folder under my user directory + - Windows path should be: `C:\Users\[My Username]\.codex` +2. Backup existing configuration (if exists) + - Check if `.codex\config.toml` exists + - If it exists, rename it to `config.toml.bak.[current timestamp]` (timestamp format: yyyyMMddHHmmss) +3. Create configuration file + - Create `config.toml` in the `.codex` directory + - Write the following complete content: + ```toml + preferred_auth_method = "apikey" + + [model_providers.myrelay] + name = "My Relay Station" + base_url = "https://api.zyai.online/v1" + env_key = "MYRELAY_API_KEY" + wire_api = "responses" + request_max_retries = 4 + stream_max_retries = 10 + stream_idle_timeout_ms = 300000 + + [profiles.myrelay] + model_provider = "myrelay" + model = "gpt-5" + model_reasoning_effort = "medium" + + [tools] + web_search = true + +4. Set system environment variable +Variable name: MYRELAY_API_KEY +Variable value: The key I gave you + +5. Confirm completion and report back: + +The full path of the configuration file +Whether the environment variable was set successfully +I can use the command `codex --profile myrelay` to run it +```` + +配置完成后,你就可以通过 `codex --profile myrelay` 启动使用转发 API 的 Codex 了。之后的使用方式与 Claude Code 类似:只需要在对话框中随时输入你的想法和需求即可。 + +## CLI AI 编程工具的更多用法 + +### 用 AI 写需求文档:学会“具体化需求” + +对于大语言模型来说,抽象需求需要被“具体化”。比如:“我很饿”是一个抽象需求,我们需要把它变成:“我肚子有点饿,可能需要吃一个红豆面包,再配一杯豆浆。”——这才是一种可以被执行的、具体的需求。 + +但把抽象需求变具体,其实是一个很花精力的过程。如果我们没有见过足够多的案例,很难快速联想到该如何把抽象问题拆解成细致的模块。这种时候,最好的办法就是让 AI 帮你完成“具体化”这一步。 +比如,我想开发一个“每日计划”应用,最朴素的想法可能是: + +`Please help me write a daily planning app where I can write my plans each day and get reminders.` + +AI 确实可以在这个需求基础上直接拆分任务,然后一步步完成,但中间容易出错或理解偏差。为了降低风险,我们可以让 AI 帮我们先扩写需求: + +`Based on my needs, please elaborate and provide a more detailed Product Requirement Document for reference. My idea is: Please help me write a daily planner app that supports daily plan-writing and provides reminders .` + +这时,AI 可能会给出类似下面这样完整的 PRD: + +```Plain +Product Requirements Document (PRD): “Today’s Plan” App +Document Version: 1.0 +Creation Date: October 27, 2023 +Author: (Your Name/Product Manager) + +1. Product Introduction +1.1 Product Name +Today's Plan +1.2 Product Vision +“Today’s Plan” is a minimalist and highly efficient daily planning and reminder tool, dedicated to helping users eliminate procrastination and forgetfulness, plan every day clearly, and ensure tasks are carried out through an intelligent reminder system—ultimately enabling users to gain a stronger sense of control and achievement over their time. +1.3 Target Users (User Personas) +We mainly serve three types of users: +Students (Xiao Ming): +Characteristics: Multiple tasks such as courses, assignments, club activities, exam prep, needing organized time arrangement. +Pain Points: Easily forget small tasks or assignment deadlines; feel overwhelmed switching between tasks; want to build regular study and life habits. +Needs: A simple tool to list daily to-dos and provide reminders before class/self-study. +Office Workers (Zhang Wei): +Characteristics: Fast-paced work, many meetings, reports, project milestones, and personal affairs (fitness, picking up children). +Pain Points: Easily forget important meetings or work milestones; get interrupted by urgent tasks and forget the original plan; feel busy but inefficient at end of day. +Needs: Need a tool to quickly record and schedule daily work and send strong reminders at key times (e.g., 15 minutes before meetings). +Freelancers/Self-disciplined Seekers (Li Na): +Characteristics: High freedom of time, but strong self-management required for work output and personal growth. +Pain Points: Easily procrastinate, lack external supervision; start the day without a clear plan, leading to low time utilization. +Needs: Need a tool to help build a daily fixed routine (Morning Routine) and review daily achievements for positive feedback. + +2. User Stories +As a user, I want to quickly create today’s plan list so I have an overview of all my tasks for the day. +As a user, I want to set specific start and end times for each task so I can create a visual timeline. +As a user, I want to receive push notification reminders before a task starts so I won’t miss any important arrangements. +As a user, I want to customize the reminder time (such as 5, 15, or 60 minutes in advance) so reminders better fit my habits. +As a user, I want to easily mark completed tasks so I can feel accomplished and clearly see my progress. +As a user, I want to see a summary of my completed plans at the end of each day for reviewing and self-motivation. +As a user, I want to conveniently edit and delete tasks to handle last-minute changes. +As a user, I want to view plans and achievements from previous days to review my efficiency and habits. + +3. Feature Breakdown +Core Features (MVP - Minimum Viable Product) +Module 1: Plan Management +3.1.1 Daily Plan Homepage +Interface: “Today” as the core view, current date shown at the top. +View: Timeline list, clearly showing tasks scheduled from morning to evening. Tasks without a time can be listed in the top or bottom “To-do List” section. +Interactions: +Click the “+” button in the bottom right to quickly create a new task. +Pull down to refresh the page. +Swipe left/right to view yesterday’s and tomorrow’s plans. +3.1.2 Create/Edit Task +Entry: Click “+” on the homepage or a time slot in the list. +Fields: +Task title (required): Briefly describe the task, e.g., “10 AM Weekly Product Meeting.” +Task time (optional): +Set “start time” and “end time.” +Provide “all-day” option for unspecified time tasks. +Default time picker should be quick and convenient. +Reminder setting (required, with default value): See Module 2. +Notes (optional): Add further descriptions, links, or location info. +Actions: Save, cancel, delete task. +3.1.3 Task Interaction +Mark as complete: Checkbox before each task; checking adds a strikethrough and gray background, indicating completion. Can unmark if needed. +Edit task: Click the task itself to enter edit page. +Delete task: Swipe left on a task to reveal “Delete” button. +Module 2: Smart Reminder System +3.2.1 Reminder Trigger +Mechanism: Based on task’s set “start time” and the user’s “reminder lead time,” send a push notification from device. +Offline Support: Locally scheduled reminders must trigger even if user is offline. +3.2.2 Reminder Content & Format +Notification title: App name “Today’s Plan.” +Body: “Reminder: [Task Title] will start at [Start Time].” E.g., “Reminder: Product Meeting will start at 10:00.” +Sound: Use system default or offer several simple, effective tones. +3.2.3 Reminder Settings +Global Settings (in Settings page): +User can set a default reminder time, e.g., “15 minutes before task starts.” New tasks adopt this by default. +Single Task Settings (in create/edit page): +Users can override global settings for important tasks, choosing specific reminder times like "on time," "5 minutes early," "30 minutes early," or "1 hour early." +Provide “no reminder” option. +Subsequent Features (V1.1, V2.0) +3.3 Daily Review & Statistics +Push a summary notification at a set time every night (e.g., 22:00): “How was your day? Take a look at your achievements!” +Generate a simple daily report card: shows total planned tasks, completed tasks, completion rate, plus an encouraging message. +3.4 History Review +Calendar view to click on any past day and check its plans and completion status. Days with high completion rates marked with a special color. +3.5 Templates +Allow users to save a successful daily plan as a template, e.g., “Efficient Workday,” “Relaxing Weekend.” +When creating tomorrow’s plan, one-click import a template, modify slightly to save time. +3.6 Themes & Personalization +Offer dark mode. +Allow changing several primary color themes. + +4. Non-Functional Requirements +4.1 Performance +Response: App launch time under 2 seconds; adding/editing tasks must be smooth and lag-free. +Resource Use: Low battery and memory consumption in background; do not over-consume resources waiting for reminders. +4.2 Usability +Minimal & intuitive: UI must be minimal, primary functions accessible within 3 clicks. No tutorial needed for new users. +Error tolerance: Offer undo (e.g. brief undo after mistakenly deleting a task). +4.3 Reliability +Reliable reminders: Reminder function is the product’s lifeline; must guarantee 99.99% timely and accurate delivery. +Data loss-free: User plans must be reliably stored locally. Future versions can support cloud sync to prevent data loss on device change. +4.4 Compatibility +Platform: Support major iOS and Android versions (latest 3-4 releases). +Screen: Layout must fit various phone screen sizes. + +5. Roadmap +V1.0 (MVP): +Goal: Validate core value—planning & reminders. +Features: Complete all “Core Features” described above (Plan management, smart reminders). +V1.1 (Quick Optimization): +Goal: Improve retention and achievement. +Features: Add “Daily Review & Statistics,” “History Review.” +V2.0 (Enhanced Experience): +Goal: Increase efficiency and personalization. +Features: Add “Templates,” “Themes & Personalization,” and start developing “Cloud Sync.” +``` + +对比我们最开始那句“帮我写一个每天可以记计划并提醒的应用”,现在这份文档已经详细得多了。你可以根据自己的真实需求,对其中的内容进行增删修改;对于某些你不确定的模块,也可以继续让 AI 提供更多备选方案,你再挑选、合并成最终版本。 + +通过这种方式,我们可以很轻松地把抽象想法变成具体描述。对 AI 开发来说,“具体”就是生产力:需求越具体,越容易得到结构稳定、质量较高的项目。你可以尝试用这种方式重做一下之前的某个小项目,对比一下效果差异。 + +如果你觉得这类“需求提示词”太长,非常自然的做法,是把它单独写进一个 markdown 文档中,作为你的“需求文档 / 开发文档 / PRD”。之后每次让 AI 写项目时,只需要让它“参考这份文档”,而不是每次都重打一遍长提示。你也可以在迭代中不断完善这份文档,让后续项目直接受益。 + +下面是一些其他常见的使用场景: + +### 管理文件夹 + +我们可以尝试用 CLI AI 编程工具来管理当前文件夹中的各种文件。比如,你有一堆杂乱无章的文件,需要整理归类,就可以对 Claude Code 或 Codex 说: + +`Please help me organize the contents of the current folder. I want to group files with the same content together & I want to group files from the same time period together. Please help me handle this.` + +### 开发新项目 + +这和我们之前在 z.ai、Trae 中的用法几乎完全一样——我们也可以直接用 CLI AI 编程工具来从零开发新项目。当然,最好提前准备好一份需求文档。 + +需求文档越细致,最终效果越好。你可以根据不断变化的想法,对文档做多轮优化;文档越完善,代码实现就越稳定、越成熟。 + +### 部署开源项目(例如 Dify) + +对于刚接触计算机的同学来说,从 GitHub 上部署一个开源项目往往很有难度。但我们完全可以把这件事交给 Claude Code,就像我们在 Dify 教程中做的那样: + +https://github.com/langgenius/dify + +如果我想在本地跑起自己的 Dify,只需要把这个链接扔给 Claude Code,然后输入: + +`I want to deploy this GitHub project ``https://github.com/langgenius/dify`` . Please help me clone the project and run it.` + +收到你的请求后,Claude Code 会自动完成一系列操作,包括从 GitHub 拉取代码、配置运行环境、启动项目等。如果中间某一步出错或项目启动状态不正常,你再根据提示进行少量人工处理即可。除了 Dify,你也可以用 Claude Code 帮你部署大部分常见的 GitHub 开源项目——你只需要一个对话框,再加上喝一杯咖啡的时间 ☕️。 + +![](images/image31.png) + +### 讲解代码与撰写文档 + +对于一些复杂项目,或者 AI 自动生成的大型项目,你可能会觉得代码太长、逻辑太多,很难看懂。这时就可以让 CLI AI 编程工具帮你“读代码”。你可以这样提问: + +- 请帮我解释这个项目:如何运行、如何使用、后续如何修改和继续开发? +- 请帮我说明这个项目的整体流程:程序是怎样运行的?用户在界面中可以做哪些操作? +- 请帮我为这个项目写一份完整的文档,包括开发文档和运行文档等。 +- 请基于我当前文件夹里的所有内容,写一份详细说明,并保存到指定的 markdown 文档中。 + +### 更多玩法 + +当然,CLI AI 编程工具能做的远不止上面这些。不要只把它当作“写代码工具”,而是把它看作一个具有独立行动能力的智能 Agent。你可以让它帮你: + +- 管理和整理本地文件; +- 写日记、写总结; +- 分析和修复系统错误; +- 执行各种重复性命令行任务等。 + +也许在不久的将来,它会变成你电脑上最重要、也最懂你的 AI 伙伴。 diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image1.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image1.png new file mode 100644 index 0000000..5959414 Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image1.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image10.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image10.png new file mode 100644 index 0000000..9fc962d Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image10.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image11.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image11.png new file mode 100644 index 0000000..b683539 Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image11.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image12.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image12.png new file mode 100644 index 0000000..b825279 Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image12.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image13.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image13.png new file mode 100644 index 0000000..4c81205 Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image13.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image14.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image14.png new file mode 100644 index 0000000..a5f5b6f Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image14.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image15.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image15.png new file mode 100644 index 0000000..5c3363a Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image15.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image16.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image16.png new file mode 100644 index 0000000..438c034 Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image16.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image17.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image17.png new file mode 100644 index 0000000..02f3b66 Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image17.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image18.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image18.png new file mode 100644 index 0000000..053e7aa Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image18.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image19.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image19.png new file mode 100644 index 0000000..9a6c2bd Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image19.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image2.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image2.png new file mode 100644 index 0000000..dce81dc Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image2.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image20.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image20.png new file mode 100644 index 0000000..b299ca1 Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image20.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image21.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image21.png new file mode 100644 index 0000000..b726a6e Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image21.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image22.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image22.png new file mode 100644 index 0000000..06c47ff Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image22.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image23.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image23.png new file mode 100644 index 0000000..7a66cf9 Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image23.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image24.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image24.png new file mode 100644 index 0000000..3e135a8 Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image24.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image25.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image25.png new file mode 100644 index 0000000..d7bcd2a Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image25.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image26.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image26.png new file mode 100644 index 0000000..eb8ea22 Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image26.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image27.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image27.png new file mode 100644 index 0000000..39896a4 Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image27.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image28.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image28.png new file mode 100644 index 0000000..3dc8c93 Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image28.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image29.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image29.png new file mode 100644 index 0000000..ac61c47 Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image29.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image3.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image3.png new file mode 100644 index 0000000..a3523cf Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image3.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image30.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image30.png new file mode 100644 index 0000000..263281a Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image30.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image31.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image31.png new file mode 100644 index 0000000..2c74312 Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image31.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image4.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image4.png new file mode 100644 index 0000000..3ca7771 Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image4.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image5.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image5.png new file mode 100644 index 0000000..e2e6967 Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image5.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image6.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image6.png new file mode 100644 index 0000000..699864f Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image6.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image7.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image7.png new file mode 100644 index 0000000..a440453 Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image7.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image8.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image8.png new file mode 100644 index 0000000..230add6 Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image8.png differ diff --git a/docs/stage-2/backend/2.6-modern-cli/extra7/images/image9.png b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image9.png new file mode 100644 index 0000000..4c2e3ee Binary files /dev/null and b/docs/stage-2/backend/2.6-modern-cli/extra7/images/image9.png differ diff --git a/docs/stage-2/backend/2.7-stripe-payment/index.md b/docs/stage-2/backend/2.7-stripe-payment/index.md new file mode 100644 index 0000000..eab6c30 --- /dev/null +++ b/docs/stage-2/backend/2.7-stripe-payment/index.md @@ -0,0 +1,3 @@ +# 后端六:如何集成 Stripe 等收费系统 + +> 本章节正在编写中,敬请期待... diff --git a/docs/stage-2/frontend/2.0-lovart-assets/index.md b/docs/stage-2/frontend/2.0-lovart-assets/index.md new file mode 100644 index 0000000..96e975a --- /dev/null +++ b/docs/stage-2/frontend/2.0-lovart-assets/index.md @@ -0,0 +1,3 @@ +# 前端零:使用 Lovart 生产素材 + +> 本章节正在编写中,敬请期待... diff --git a/docs/stage-2/frontend/2.1-figma-mastergo/index.md b/docs/stage-2/frontend/2.1-figma-mastergo/index.md new file mode 100644 index 0000000..4d0611c --- /dev/null +++ b/docs/stage-2/frontend/2.1-figma-mastergo/index.md @@ -0,0 +1,3 @@ +# 前端一:Figma 与 MasterGo 入门 + +> 本章节正在编写中,敬请期待... diff --git a/docs/stage-2/frontend/2.2-ui-design/index.md b/docs/stage-2/frontend/2.2-ui-design/index.md new file mode 100644 index 0000000..66a9f49 --- /dev/null +++ b/docs/stage-2/frontend/2.2-ui-design/index.md @@ -0,0 +1,3 @@ +# 前端二:构建第一个现代应用程序 - UI 设计 + +> 本章节正在编写中,敬请期待... diff --git a/docs/stage-2/frontend/2.3-multi-product-ui/index.md b/docs/stage-2/frontend/2.3-multi-product-ui/index.md new file mode 100644 index 0000000..c338edd --- /dev/null +++ b/docs/stage-2/frontend/2.3-multi-product-ui/index.md @@ -0,0 +1,3 @@ +# 前端三:参考 UI 设计规范与多产品 UI 设计 + +> 本章节正在编写中,敬请期待... diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/chapter4-lets-build-hogwarts-portraits.md b/docs/stage-2/frontend/2.4-hogwarts-portraits/chapter4-lets-build-hogwarts-portraits.md new file mode 100644 index 0000000..150d5ed --- /dev/null +++ b/docs/stage-2/frontend/2.4-hogwarts-portraits/chapter4-lets-build-hogwarts-portraits.md @@ -0,0 +1,562 @@ +# Project 4: 一起做霍格沃茨画像 + +在之前的课程中,我们已经学会如何基于 prompt engineering 和 API 调用从而实现更复杂的 AI 交互。我们已能够将简单的 AI 聊天机器人升级为 AI Agent 和 AI workflow ;通过更复杂的条件判断与分支逻辑,我们得以开发出具备更强实用性的功能。 + +为了让这些复杂的 AI 逻辑能更好地运行在不同的程序和实际应用场景中,我们从最简单的 z.ai 在线环境,逐步过渡到更现代的本地 AI IDE,把原本在浏览器里的编程环境搬到了你的电脑上。随之而来,你开始真正面对各种环境安装与配置问题,但在与 Trae Agent 的对话过程中,这些看似困难的挑战也变得可以解决。 + +在该项目中,我们将在应用的实用性上更进一步,不仅优化 AI 功能本身,还将开始打磨产品的“外在”。你将尝试让自己的界面更加美观易用,并根据实际需求,亲自定制程序界面的布局与风格。 + +正式开始之前,先用几道小测验帮你快速回顾上一节课的内容: + +1. 什么是 Dify?它是做什么的?为什么我们需要它? +2. 如何调用 Dify 的 API ? +3. 什么是 RAG?如何使用 Dify 构建一个 RAG Agent 或 RAG 工作流?Dify 常见节点的使用方式 +4. 什么是 AI IDE?什么是 Trae?它和 z.ai 有什么区别? + +如果对以上任何一个问题还有疑惑,可以先回顾上一节课的文档,或者直接在微信群里提问交流。 + +本节课的项目主题是 **Hogwarts Portraits** 。顾名思义,它的灵感来自霍格沃茨魔法学校里那些会“活过来”的画像。我们希望用 AI 打造一组“能互动”的魔法画像体验——和画像对话就像在和“本人”对话一样,既保留对话的记忆,又具备角色的背景与历史。通过这个项目,你将把之前学到的智能体与工作流真正融入到一个具体的产品界面中。 + +![](images/image1.png) + +为了真正打造出 Hogwarts Portraits,我们需要亲手搭建出符合魔法画像的前端界面。为此,你将开始接触现代前端设计工具,学习如何把界面设计和代码结合起来,把纸上或画布上的界面草图,变成真正可以操作的网页。 + +你还需要会学会如何把这个网页从本地环境发布到互联网上,让你亲手打造的特色网页,不仅能在自己电脑上运行,也能被全世界的用户访问和体验。 + +本节课的参考项目地址为:[Project4-Hogwarts-Portraits](https://github.com/THU-SIGS-AIID/Project4-Hogwarts-Portraits) + +# 你将学到 + +1. 了解什么是前端设计工具、它们解决什么问题,以及目前常见的前端设计工具有哪些。 +2. 认识 Figma 和 MasterGo,掌握它们的基础操作,并学会使用前端代码导出插件。 +3. 利用 Figma AI 和 MasterGo AI 生成网页设计,并导出可用的页面代码。 +4. 理解什么是 GitHub,学会配置 SSH 连接、创建代码仓库并完成代码推送。 +5. 弄清“部署”这一概念,学习如何使用 Zeabur,将代码从 GitHub 或本地环境部署到互联网上。 + +属于自己的 Hogwarts Portraits,一个用于展示 **某位明星、历史人物或动画人物** 的网页界面。 + +# 1. Hogwarts Portraits + +我们到底想做一个什么样的“魔法画像”?简单来说,我们希望尽可能还原《哈利·波特》中的场景,画像不再只是挂在墙上的一张静态图片,而是一个可以和你对话、会根据谈话内容改变表情和“心情”的拟人化角色。 + +![](images/image2.png) + +要让这个画像看起来不像聊天 AI 机器人,而更接近一位“真实存在的人”,需要解决两个问题:一是记忆与知识:画像需掌握与角色相关的大量背景资料(人物设定、经历故事、相关文章等),这个部分可以通过知识库来实现,将你为角色准备的文本素材接入包含知识库的 Dify ,即可让画像具备一定的背景知识讲解能力。 + +其二是表达风格的问题。仅有知识还不够,我们还希望它在说话方式上尽可能贴近“本人”,包括语气、用词习惯、思考方式,甚至偶尔的脾气和幽默感。这一层需要通过提示词工程进行处理:在系统提示词中,我们需要明确角色的身份设定、世界观边界和语言风格,让每一次回答都围绕既定人设展开,而不是退回到通用 AI 的中性话术。 + +除了对话功能外,我们还希望让情绪能够真正被看见。为此我们可以构建一个情绪值指标,我们可以设定 Dify 的输出内容,让模型在生成回答文本的同时,额外输出一个“心情值”或情绪标签。当前端拿到情绪的指标后,就可以根据心情值或者标签渲染对应的画像图片。当心情值高,画像看起来很开心,当心情值低落时或者生气时,画像看起来很伤心或者愤怒。通过这种方式,用户看到的不再是一张永远不变的图,而是一个会随内容起伏不断“变化表情”真正的“魔法画像”。 + +![](images/image3.png) + +此外,对于这个画像的内容,它可以是现实中的明星、历史人物,也可以是动漫 IP,甚至是你从零构建的原创角色。页面本身不需要复杂,但几个核心元素不可或缺:清晰的角色名字,一段高度浓缩的人物简介,一张足以代表该角色的核心画像或海报,以及一个“和 TA 对话”的互动区域;你可以把在 Dify / Trae 中配置好的 AI Agent 或 workflow 接入到这个对话模块中,实现画像的角色扮演功能。 + +## 1.2 收集角色信息 + +以 Elon musk 为例,我们需要收集他的公开发言用于模仿说话方式,注入提示词。这些素材可以来自于演讲、访谈、社交媒体发言,你只需要把这些内容变成文字,在对话期间作为 few shot 的参考,让大模型用与 Elon musk 同样随意、自嘲的方式进行回复即可,例如: + +```Plain +You must fully embody Elon Musk: take "disruptive innovator" and "advocate for human multi-planetary survival" as your core identities, speak directly and concisely, frequently use terms like "first principles", "iteration" and "cost curve", and prefer analogies to explain complex technologies; when thinking, you tend to connect cross-domain logics (e.g., linking brain-computer interface with rocket algorithms), are optimistic about technological prospects without avoiding current difficulties, will naturally mention projects like Tesla and SpaceX to support your views, directly point out problems with inefficient and conservative opinions without deliberate tact, and always maintain the edge of "reconstructing the future with technology". + +The way you speak should be as shown in the following examples: +- Starship could deliver 100GW/year to high Earth orbit within 4 to 5 years if we can solve the other parts of the equation. +100TW/year is possible from a lunar base producing solar-powered AI satellites locally and accelerating them to escape velocity with a mass driver. +- The most likely outcome is that AI and robots make everyone wealthy. In fact, far wealthier than the richest person on Earth +By this, I mean that people will have access to everything from medical care that is superhuman to games that are far more fun that what exists today. +We do need to make sure that AI cares deeply about truth and beauty for this to be the probable future. +- It’s taken 13.8B years to get this far, so intelligence seems to me to be more like a super rare accident than selective pressure. +Earth is ~4.5B years old with an expanding sun that may make Earth uninhabitable in ~500M years, meaning that if intelligent life had taken 10% longer to evolve, it wouldn’t exist at all. +- LLM is an outdated term. “Multimodal LLM” is especially dumb, since the word “multimodal” just overrides the second L in LLM. +It’s just a model, which is a big file of numbers. When the numbers are right and there are enough of them, we will have superintelligence. +``` + +对于如何收集背景知识并将其作为知识库,我们可以搜索他的个人介绍,以及公司的介绍复制全部文本作为知识库的内容加入 Dify,如果你忘记了 Dify 的使用方法,请返回上节课的讲义,重新学习如何将知识添加知识库。 + +此外,考虑到画像设计,使用对应人物公开的图片也许并非那么吸引人,并且可能存在一定风险。此时建议你可以使用图像生成工具的图生图功能,让 AI 返回高清高质量的画像,你也可以使用图像生成工具生成一系列表情的画像素材,用于在之后的情绪值改变后修改对应的画像呈现。 + +本教程中使用的是 [Lovart](https://www.lovart.ai/home),Lovart 是一款AI设计智能体,它能通过自然语言指令,自动规划和执行从概念到交付的端到端设计工作流,生成海报、品牌Logo、视频、音乐等内容,并支持分层编辑(实际上内部的功能原理是调用对应的 Seedream 或 google nanobanana 模型,我们已经在之前的课程中提到过)。通过 Lovart ,我们能够获得一系列的表情素材,你可以提前获得你喜爱角色的图片信息,将其保存待后续使用。 + +![](images/image4.png) + +一切准备就绪后,我们能够开始着手于整体页面的设计,我们希望这个页面的风格与该人物是高度绑定的。 + +## 1.3 页面原型设计 + +我们还可以先构思一下页面的原型,如上述所说,我们希望有一个对话页面和画像,以及一个有趣的个人介绍,在本篇例子中,我们实现了一个类似 X 上的对话界面替代个人介绍,你也可以想到其他符合“该人物特点”的方式,选取新的元素替换个人介绍栏目。 + +![](images/image5.png) + +最简单的,我们可以用 PowerPoint 设计最初的网页呈现原型,我们从网上找到一张魔法画像的图片,并且将画面设定为横向排布,最左侧设定为聊天区域,中间是画像区域,最右侧是 X 的区域。 + +![](images/image6.png) + +基于上述简单原型,我们能够让大模型生成真正的前端页面设计以及对应的代码结果。 + +![](images/image7.png) + +不过,一般而言在实际中我们并不会用 PowerPoint 进行前端页面的设计。我们会用更好的原型工具,又或者说是前端设计工具来实现这一点,我们将进一步详细理解如何使用现代工具设计前端原型。 + +# 2. 前端设计工具 + +在开始之前,我们需要理解一个问题:为什么需要学“前端设计工具”?反正直接写 HTML / CSS 代码也能把页面搭出来,多学一个软件和技术,真的有必要吗? + +实际上,把页面运行起来,和把产品设计好根本是两个概念。代码只关注解决如何渲染在浏览器上,如何在不同设备上运行的问题;前端设计工具解决的是信息分布的问题,前端交互怎么安排,不同页面怎么跳转,视觉优先级怎么分配的问题。只需要在设计工具里搭一块画布,就能把版式、信息层级、交互方式在一块屏幕上对比确定,选择最适当的呈现效果。 + +如果直接开始写代码或直接用 AI 生成完整的前端页面,通常用户体验都不会太好,严谨的产品会考虑到用户和前端交互的舒适度,以及不同页面想要传达的内容分布,从用户的角度出发先进行前端页面排布,再进行代码转换或生成。 + +另外,从团队协作的角度而言,前端设计工具还降低了多方的合作成本:设计师、产品、开发不再各自对着脑补画面或者抽象的代码说明,而是支持多人协同,大家能够围绕一份可视、可标注、可迭代的画布讨论版本管理、需求变更、反馈意见。更进一步的是,现代前端设计工具本身不再只是画图软件,一键生成部分代码,管理设计系统和组件库,新时代的设计工具已能够将大量重复性的体力劳动(对齐、标注、导出、改样式)自动化或批量化,极大促进了页面设计的开发效率。 + +![](images/image8.png) + +在时间的长河中,所谓前端设计工具其实是一条持续演化的技术。从 90 年代以本地位图编辑为主的 Photoshop 时代,到 2010 年前后 Sketch 带来的矢量化、组件化工作流,再到 2016 年之后 Figma 把协作彻底搬上云端,设计团队从单兵作战逐渐走向多人实时协同。来到 2025 年,AI 已经实打实地嵌入到这些工具内部:从“根据一句话生成页面草稿”,到“把设计稿直接转成可运行的前端结构”,“设计即代码”“人机共创”正在从概念变成可用的生产力。 + +本节中,我们会选取最具代表的两种现代前端设计工具进行介绍,Figma 和 MasterGo。一方面,它们都覆盖了现代 UI/UX 所需要的核心能力(矢量编辑、组件系统、自动布局、代码交付等),可以支撑你完成从线框到高保真到开发交接的完整闭环;另一方面,这两款工具都已经在 2025 年之后陆续加入了实用的 AI 功能,帮助你在保证原型不变的同时将设计图变成真正可运行的程序。 + +## 2.1 诞生之旅 + +![](images/image9.png) + +在现代前端专用工具尚未诞生的年代,整个界面设计行业的视觉设计工作,很长一段时间都由 Photoshop 这类 “全能型” 设计软件顺带承包。设计师会在本地通过一层层叠加的图层,细致完成页面整体视觉效果的设计,最终将体积不小的 .psd 源文件交付给前端工程师 —— 而前端要精准还原设计图,还必须手动完成三项繁琐且关键的工作: + +一是 “切图”:需要从 .psd 文件的多层结构里,把按钮、图标、Logo、背景模块等独立视觉元素逐一拆分提取,再导出为 PNG、JPG 等网页能直接加载的图片格式(毕竟网页无法直接识别 PSD 的图层信息,只能依赖这些拆分后的图片呈现细节); + +![](images/image10.png) + +二是 “量尺寸”:得用软件自带的测量工具,逐一确认每个元素的宽高、不同模块间的间距(margin/padding)等数据,确保所有尺寸都精准到像素; + +![](images/image11.png) + +三是 “抠标注”:要从设计图中提取那些 “看不见却必须有的” 隐性参数 —— 比如文字的字号、字重、行距,每个色块的 RGB 或 HEX 色值等,相当于把设计师没写在纸上的 “设计规格” 手动 “抠” 出来记录。 + +![](images/image12.png) + +在此之后,前端的实现阶段才真正展开。无论使用的是原生 HTML/CSS/JS,还是基于 Vue、React 等框架,本质过程是一致的。前端会以 “容器为核心载体”,根据设计中各模块的层级与语义重建页面结构。这里的容器是指具有明确布局边界、专门承载和组织子元素的单元,它不直接呈现具体内容,却通过 Flex、Grid 等规则,为内部元素划定排列范围。而 “结构块”(如顶部导航栏、侧边栏、文章列表区、底部页脚等肉眼可辨的功能 / 内容区域),便依托容器存在;每个结构块内部,又会嵌套更小的容器来组织元素,比如一条文章列表项,会由 “列表项容器” 控制内边距与整体排版,再包裹标题、摘要、时间、封面图标等细节元素。 + +![](images/image13.png) + +在现代前端框架里,这些 “结构块(及关联的容器与元素)” 通常会被实现为 “组件”。组件可简单理解为:带有清晰边界、整合了容器布局与逻辑的可复用界面单元,它既包含控制外观与排列的容器(比如 “按钮组件” 用容器定义宽高、圆角,“文章卡片组件” 用容器组织标题、封面的位置),也封装了交互逻辑。设计稿中重复出现、形态一致的部分(如统一风格的按钮、反复使用的文章卡片),在代码中会被抽象成组件:既能在不同页面 / 场景复用,减少重复开发,也能通过组件内容器的统一规则,确保所有复用处的布局与风格高度一致 + +随后,前端会使用样式系统还原视觉和布局。切图阶段导出的 PNG/JPG 等资源,会作为组件或结构块内部的 ``、背景图片,或者按照各框架推荐的静态资源方式引入;量尺寸阶段得到的宽高、间距、行高等具体数值,会被转写为 `width`、`height`、`margin`、`padding`、`line-height` 等样式属性,应用到对应的组件或结构块上;抠标注阶段整理出的颜色、字体、阴影、圆角以及 hover/active 等状态,则会落实到 CSS、CSS Modules、CSS-in-JS、Tailwind 等具体方案中的 `color`、`font-family`、`font-size`、`box-shadow`、`border-radius` 以及伪类或状态类名上。此时,切图、尺寸和标注提供的是一组精确的视觉参数,组件和结构块则提供了承载这些参数的代码组织单元,两者结合起来,构成可维护、可复用的界面实现。 + +![](images/image14.png) + +但是,以本地文件为中心的模式天然是低效率的。版本通过邮件和网盘传输,新旧稿件容易混淆,设计和开发之间大量依赖上述的复杂交互方法,协作成本和出错概率都不低。 + +移动互联网兴起后界面复杂度和迭代速度需求快速上升,Photoshop 的“大而全”逐渐显得笨重。这个阶段,出现了 Sketch。Sketch 专注在 UI 设计本身,剥离掉大部分与视觉后期处理相关的负担;用 Symbols 把按钮、导航、输入框等高复用元素组件化,一处修改可以全局同步;再配合 Zeplin 一类工具,把标注和样式片段自动生成。Sketch 把“组件思维”引入了设计工作流。不过它依然是基于本地文件的桌面应用,实时协作要靠云盘、第三方插件或版本工具绕行实现,没有从底层解决“多个人同时改同一份稿子”的问题。 + +![](images/image15.png) + +真正改变游戏规则的是 Figma。自 2016 年起,它把 UI 设计、原型制作、评论协作统一整合到浏览器中,支持多种现代功能:多人实时光标、在线评论、版本时间线、分享链接等,今天看起来非常简单,但在当时是对 Photoshop / Sketch 模式的正面挑战。 + +![](images/image16.png) + +至此,界面设计不再是散落在各自电脑里的文件,而是集中在一份在线、实时更新的云端画布上。围绕这块画布,我们可以想象更进一步,用自动化或 AI 的方式模糊设计和前端代码的边界。 + +最开始,我们仅能依赖各类平台插件,将设计稿中的组件、样式信息半自动导出为代码片段(如 React/Vue 组件骨架、CSS 变量等),其核心本质是通过插件实现结构化信息提取。随后,随着平台能力的进化,大部分设计平台开始支持大模型 MCP(Model Context Protocol,模型上下文协议)功能:该协议提供了一套标准机制,能让大模型安全、可控地访问设计文件、插件接口与项目元数据,进而更便捷地将设计稿导出为代码。 + +再往后,在插件与 MCP 的基础上,前端代码自动化进一步迈入到原生支持从设计稿直接推导代码结构的阶段。我们可在设计工具内一键生成前端项目骨架、组件层次、样式体系及对应的代码结果。这使得设计师与前端开发工程师得以从手动搬运设计细节的工作中解放出来,将更多精力投入到用户体验优化与功能版本的更新迭代上。 + +## 2.2 Figma + +接下来我们从抽象的概念部分来到实际的操作环节。由于时间关系,我们只会学习 Figma 的基本操作逻辑,确保即便你完全没用过设计工具,也能跟着完成练习。如果你想进行完整的 Figma 功能学习,请你参考 Figma 提供的详细官方教程进行学习:https://help.figma.com/hc/en-us/sections/30880632542743-Figma-Design-for-beginners + +或者参考如下教程,进行类似个人作品集简单网页的快速搭建:https://help.figma.com/hc/en-us/sections/35895585621655-Figma-Sites-collectio + +![](images/image17.png) + +左侧是项目的新建和资源管理入口,右上角的几个按钮是 Figma 的常见功能。其中,Make 用来用一句话让 AI 帮你先生成一个大概的界面或结构草稿,Design 是真正画网页 / App 界面、搭组件和做原型的主工作区,FigJam 像团队白板,用来贴便利贴、画流程和做前期讨论,Buzz 是品牌资产规模化生产工具,用于批量生成内容以保持品牌一致性,Site 则是把这些设计整理成真正可访问的网页或文档站对外展示。 + +乍一看 Figma 的功能非常多,不好入门,但其实这类功能工具本质上都是熟能生巧,不需要害怕一开始操作出错,也不用想着一步做对,只需要先玩起来,玩多了自然能快速上手。 + +本篇教程中,为了快速入门,我们会对 Design 功能做简单讲解。 + +### 2.2.1 新建 Design 文件 + +在首页或者右上角的入口里,选择 **Design** ,新建一个文件,你会进入一个空白的设计画布。 +这个界面大致分成三块:左边是页面和图层,用来查看和修改页面、元素从属关系;中间是画布,用于查看当前效果;右边是属性和样式,用于修改具体的形状、颜色、样式;底部一条是工具栏,用来切换工具,包含选框、画形状、输入文字、评论、插件等,选中工具后,可以按 Esc 键返回至默认鼠标工具。 + +![](images/image18.png) + +### 2.2.2 创建你的第一个 Frame(画板) + +在正式放置元素之前,需要先为页面确定一个清晰的边界,这个边界由 Frame 来承担。你可以在底部工具栏中选择 Frame 工具,或者直接按键盘 F,然后在画布上拖出一个矩形区域。 + +1. 使用底部工具栏里的 Frame 工具,或者直接按键盘 `F`。 +2. 在画布中拖出一个矩形区域,右侧属性栏里把宽度改成比如 `1440`,高度改成 `900`。 +3. 在左侧图层栏,把这个 Frame 重命名,比如叫 `Hogwarts Portraits` 或者你项目的名字。 + +这个 Frame 就是一屏界面的页面容器,之后的标题、文字、按钮、图片等内容都应该放在这个 Frame 内部,而不是散落在画布的任意位置。以 Frame 为边界来组织内容,有助于在后续进行滚动设置、适配不同设备尺寸、导出画面及制作原型时,保持结构可控。 + +![](images/image19.png) + +### 2.2.3 在 Frame 里放文字和简单元素 + +有了容器,接下来我们来学习如何防止最基本的组件,例如:标题、副标题、按钮、占位图块。 + +1. 选择文字工具(底部工具栏中的 `T`),在 Frame 里点击一下,输入页面标题,比如:`Hogwarts Portraits`。 + 在右侧属性里,把字体大小调大一点(例如 96),字重调粗一点。 +2. 在标题下面,再用文字工具输入一行简单说明,比如一两句描述这个页面要做什么。 + 字号可以小一些,行高略放大一点,读起来不那么挤。 +3. 画一个按钮雏形: + 用矩形工具在标题下面画一个大概 `200 × 48` 的矩形,右侧给它一个比较明显的填充颜色,再适当加一点圆角。 + ![](images/image20.png) +4. 然后用文字工具在矩形上方输入按钮文字,比如 `Generate Portrait`,把矩形和文字一并选中,用顶部的对齐工具让文字水平、垂直都居中。 +5. 在按钮一侧或下方,再画一个较大的浅灰色矩形作为“图片占位区”,后面可以用来放生成的人物画像。 + +做到这里,其实你已经有了一个非常简陋但结构完整的“首页草稿”:一个标题、一段话、一个按钮、一个主要展示区域。 + +![](images/image21.png) + +### 2.2.4 善用 Auto Layout 整合元素 + +如果所有元素只是随手拖拽,页面很快会乱。Figma 里一个很重要的概念就是 **Auto Layout** ,它可以把一组元素变成一个带规则的容器。 + +![](images/image22.png) + +你可以选中“主标题 + 副标题 + 按钮”这三样,在右侧属性栏里点击 **Add Auto layout** 。 + +这时这三样会被包在一个容器里,你可以在右侧调整参数,其中的元素布局会根据参数自动适应调整: + +- 它们是竖着排还是横着排。 +- 元素之间的间距是多少。 +- 整个这一块离容器边缘有多少内边距(padding)。 + +![](images/image23.png) + +同样,按钮内部也可以用 Auto Layout,我们能够实现这样的一个效果:当我调整了文字,按钮的长度也会自动调整。 + +先把按钮背景的矩形和按钮文字选中,添加 Auto Layout,让这两个东西变成一个“按钮容器”。接着选中这个按钮容器,把宽高都设置成 **Hug contents** 。这样一来,文字会一直保持在按钮正中间,文字多一点、少一点,按钮的宽度都会自动跟着变化。 + +![](images/image24.png) + +### 2.2.5 将按钮变为可复用组件 + +现在我们要学习一个新的概念,组件。组件的意思就是可以被反复利用的元素,比如按钮这种元素,只要你预感之后还会反复用到,就可以考虑把它做成组件。我们在刚才已经加好 Auto Layout 的按钮基础操作: + +1. 选中整个按钮容器。 +2. 右键选择 Create component(创建组件)。 + ![](images/image25.png) + +这样,这个按钮就从一组普通图层,变成了一个组件母版。之后如果你在其他页面或 Frame 里需要同样风格的按钮,可以直接从左侧的 Assets 面板里拖出来使用。 + +![](images/image26.png) + +此时所有用到的按钮,都是这个母版的同步拷贝。当你修改母版的颜色、圆角或间距时,所有实例都会自动保持同步更新。 + +![](images/image27.png) + +至此,你已经初步掌握了 Figma 的简单用法。你不需要一开始就把所有功能都弄懂,只要先照着做出第一个简单页面,熟悉这几个核心操作,再慢慢去探索官方教程里的更多能力,随着使用次数增多就一定能上手。 + +## 2.3 MasterGo + +在理解了 Figma 的基础工作流程之后,我们再来看 MasterGo,你可以把 MasterGo 简单看做是中国版的 Figma,但在部分功能上有一定区别。整体上,它延续了与 Figma 相似的界面布局和操作理念:同样有画布、图层树和属性面板,同样支持组件、样式、自动布局和多人协作。更详细的内容可参考 MasterGO 的官方教程:https://mastergo.com/tutorials/12?%E5%85%A8%E7%A8%8B%E9%AB%98%E8%83%BD%EF%BC%8CMasterGo%20%E6%9C%80%E5%AE%8C%E6%95%B4%E5%AE%9E%E7%94%A8%E6%95%99%E7%A8%8B%EF%BC%8C%E8%AE%A9%E4%BD%A0%E4%BB%8E%E9%9B%B6%E5%88%B0%E7%B2%BE%E9%80%9A%EF%BC%81 + +### 2.3.1 新建设计文件 + +1. **进入 MasterGo 后台** + 1. 打开 MasterGo 官网并登录账号。 + 2. 进入后,你会看到类似「文件列表 / 项目列表」的首页区域,用来管理你的设计文件。 + ![](images/image28.png) + +2. **创建新文件** + 1. 在右上角看到 + 设计文件的按钮选项进行点击,或者选择导入 Figma 等文件。 + 2. 点击后,你会进入一个空白画布,这就是 MasterGo 的设计工作区。 + +3. **认识基本界面区块** + 当你学会使用 Figma 后,MasterGo 的使用方式大同小异,主要分为几个区域: + + ![](images/image29.png) + 1. 顶部工具栏:位于画布最上方,左侧是文件位置和文件名,中间是一排常用工具按钮(选择、区域/画板、形状、文本、注释、评论、插件选择和 AI 工具等),右侧是当前在线成员、分享入口以及画布缩放和预览控制功能入口。 + 2. 左侧面板:主要分为图层和资源,当前停留在图层标签,可看到页面列表,以及该页面下所有图层的结构和层级。 + 3. 中间画布区:具体绘制和排版的工作区,所有 Frame、组件和图形都会展示在这里。 + 4. 右侧属性面板:用于查看和编辑选中对象的属性,例如大小、位置、对齐方式、背景填充、描边、圆角等。如果没有选中任何对象,会显示画布相关设置,如画布背景色、标签和导出选项。 + +### 2.3.2 创建你的第一个 Frame + +在正式放东西之前,我们需要一个页面容器用来确定界面的边界和尺寸。这个容器在 MasterGo 里,通常叫 Frame。 + +**步骤:** + +1. **选择 Frame 工具** + 1. 在工具栏中找到 Frame / 画板工具,点击后可使用预设参数直接将内容创建到画板。 + 2. 或者使用快捷键(通常是 `F`,如果有差异以实际界面为准)。 +2. **在画布中拖出一个矩形区域** + 1. 拖出后,你会看到一个带选中框的区域。 + 2. 右侧属性面板里,可以看到这个 Frame 的宽度和高度。 + 3. 把宽度改成比如 `1440`,高度改成 `900`(一屏网页常用尺寸之一)。 +3. **重命名 Frame** + 1. 在左侧图层面板里找到这个 Frame。 + 2. 双击名称,把它改成你项目的名字,比如:`Hogwarts Portraits`,或者你自己随便起的页面名。 + +![](images/image30.png) + +### 2.3.3 创建画板内容 + +有了容器,使用与 Figma 中我们已教过的类似方式,很容易可以得到相似的展示页面。(你可以尝试复制 Figma 画板中的文字元素,能够支持文本组件的直接粘贴导入) + +![](images/image31.png) + +值得注意的是 Auto Layout 功能行为稍微的不一致性,在 MasterGo 中,如果你想实现和 Figma 相似的按钮长度随着文字的长度变化,你需要先在对应矩形元素的基础上创建一个容器或组件,如图所示: + +![](images/image32.png) + +成功创建容器后,将按钮矩形和文字放到对应并列的容器中,再在右侧找到 Auto Layout 的按钮启用自动功能,即可成功实现按钮宽度能够随着文字长度变化的功能。 + +![](images/image33.png) + +![](images/image34.png) + +### 2.3.4 AI 生成页面 + +![](images/image35.png) + +在 MasterGo 中,一个值得注意的有趣功能是 AI 生成页面。你可以用一句话或携带参考图,生成对应的 MasterGo 可编辑版组件,并得到可直接使用的代码。你可以使用中文或者英文直接输入需求,页面会根据需求返回结构清晰的页面排布文档,效果如下: + +![](images/image36.png) + +![](images/image37.png) + +设计文档生成结束后,点击开始生成,稍作等待便能获取对应的实际网页效果: + +![](images/image38.png) + +此时你有两种操作选择:一是点击蓝色按钮将生成结果直接插入画布,二是点击代码预览功能,直接获取当前完整页面的代码,具体操作界面如下: + +![](images/image39.png) + +![](images/image40.png) + +将结果插入画布后,你还能对网页的整体布局、元素细节(如字体、颜色、间距等)进行更精细的调整,直至最终效果完全符合你的预期。 + +![](images/image41.png) + +# 3. 从原型到代码 + +在前面的内容中,我们已经亲身体验了 Figma、MasterGo 现代前端设计工具。但一个很实际的问题自然会浮现:这些看起来结构完整的设计稿,要怎么转化成真正能在浏览器里运行的前端代码?我们如何能够将自己的设置的 Hogwarts Portraits 原型变成代码? + +一般而言,从原型到代码的落地,本质上有三种典型路径: + +- 根据图片,使用多模态大模型直接还原出代码。 +- 通过平台自身能力或插件导出可用代码。 +- 平台结合 MCP 能力导出可用代码。 + +考虑到实现难度,本节只会介绍如何从图片原型到代码,以及通过平台自身 AI 能力从原型转换到代码。至于如何从前端设计工具插件到代码,从前端设计工具 MCP 转换到代码,我们将在之后的课程详细讲解。 + +## 3.1 直接用 AI 生成前端代码 + +拥有视觉能力的大模型天生具备将图片转为代码的能力, 我们只需要将图片直接导入对话框,随后让大模型生成完整的结果代码。你可以使用 Qwen 等模型进行图片转代码的测试,这里以 Gemini3 为例,我们把之前的页面原型粘贴到对话界面,并要求模型直接返回 html 的代码。(html 返回后只有单个文件,方便保存到本地进行修改操作,你可以在保存到本地后让大模型将其修改为 React 的架构) + +![](images/image42.png) + +生成页面并非是简单的任务,在具体过程中你可能会遇到很多问题:譬如界面排布不均,界面显示不全,画面不能一比一还原等问题。在目前情况下,你只能在与大模型的反复对话中进行修改,接近想达成的最终效果。随着大模型能力的逐渐提高,未来需要反复修改的次数会越来越少。(推荐你选择生成图片对应的 html 代码,获取后再使用本地 IDE 将其转换为 React 框架使用,可获得多个单个 html 代码,统一进行转换) + +## 3.2 Figma Make 生成代码 + +FIgma Make 是 Figma 官方推出的 AI 设计工具,能够根据用户输入的提示词或者参考图,高精度的还原网页原型 UI 界面,并且能够支持将还原后的网页转换成可编辑的 Figma Design 文件(需要 Pro 用户,学生教育认证后可免费获得 Pro 权限)。 + +![](images/image43.png) + +类似直接用 AI 生成前端代码,我们可以将想要让 AI 学习的参考图放入对话框,并加上对应的提示词,稍等片刻后即可看到最后的渲染结果。我们能够在右上角找到播放键,点击后可进行全屏查看。 + +![](images/image44.png) + +Figma make 的效果相比原生 AI 生成代码效果更佳,即便有问题也能快速调整。如果你想做到更细节的调整,你可以注意到右上角的类似鼠标和尺子的图标,点击后可以回到我们熟悉的 Figma Editor 的界面,这让我们能够对画面组成进行更详细的调整。 + +![](images/image45.png) + +除此外,你还能够选择将 Figma Make 连接到 Github 上,帮助你快速将代码同步到 Github 保存。 + +![](images/image46.png) + +## 3.3 MasterGO AI 生成页面 + +类似 Figma Make 的 AI 页面生成功能,MasterGo 也有同样的 AI 页面生成方法,我们容易在编辑界面的上方工具栏中找到: + +![](images/image47.png) + +使用相同参考图方式得到生成结果: + +![](images/image48.png) + +![](images/image49.png) + +生成结束后,我们能够选择蓝色按钮“插入到画布”,直接编辑生成后的网页结果,也可以直接点击右侧的代码按钮,复制当前的代码内容到本地进行测试。 + +![](images/image50.png) + +# 4. 运行 Hogwarts Portraits + +## 4.1 导出测试代码 + +通过在从原型到代码中的实践,相信你已经得到 Html 或者 React 格式的原型代码,我们只需要将其复制到本地,在 IDE 中说明“请你帮我运行这个代码并且支持里面的必要的功能”,即可运行初版测试;但值得注意的是,这一步往往会出现不少报错,你需要保持耐心,将所有基础交互与功能调通。 + +![](images/image51.png) + +值得注意的是,由于我们的密钥都需要放在环境变量,而不是写入代码中。我们需要特别强调之后的 DIfy API 相关的内容都需要放入环境变量。我们能够在之后公网部署的环节中,在部署工具网站中显式指定对应的私有环境变量;又或者是我们可以让大模型在网页中创建一个设置按钮,我们可以在设置按钮中传入对应的私密环境变量,当前变量只能在当前页面中保存,别人无法获取。 + +![](images/image52.png) + +## 4.2 Dify 工作流设计与 API 对接 + +在上面的部分中,我们仅完成了前端界面的可视化呈现,尚未打通核心的拟人化角色对话交互流程。这一步是让原型从静态展示转变为魔法画像的关键,我们可以参考示范项目的 DIfy 工作流进行人物回答和情绪系统的设计,此处我们的涉及为最左侧是聊天界面,中间是魔法画像(会根据对话的内容修改对应的表情),右侧是 X 社交平台账户(会根据对话的内容判断是否需要发布感想到社交账户)。 + +一般而言,魔法画像只需要聊天界面和会变动的画像即可,该处为了展示更多可能选项,在最右侧加入了符合当事人特点的新功能;你可以根据你扮演的角色对象,加入符合对应人物的功能进行展示。 + +![](images/image53.png) + +你可以把任务的信息都加入知识库的节点,并在 RESPONSE 节点设置大模型对应的回复逻辑,我们可以参考一个简单的默认回复逻辑提示词: + +```Plain + +You are to embody Elon Musk—his tone, mannerisms, thought patterns, and worldview. Respond as if you are Elon Musk himself, speaking directly in first person. Your responses should reflect his known personality traits: visionary thinking, boldness, technical depth, dry humor, impatience with inefficiency, and a tendency toward disruptive innovation. Use concise, confident language. Avoid overly formal or academic phrasing. Prioritize clarity, speed, and impact in your communication, mirroring Elon’s style on social media, in interviews, and during product launches. + +When responding: +1. Begin by internalizing the question or statement as Elon would—as a challenge, opportunity, or problem to solve. +2. Frame your answer with a forward-thinking perspective, often referencing the future of humanity, technology, or long-term goals (e.g., making life multiplanetary, accelerating sustainable energy). +3. Use casual but authoritative language. It's acceptable to include phrases like “obviously,” “this is important,” or “we’re fixing that now” when appropriate. +4. If relevant, reference real companies or projects associated with Elon Musk (e.g., SpaceX, Tesla, Neuralink, The Boring Company, X) and speak about them from an insider’s perspective. +5. Do not apologize excessively or hedge statements. Elon Musk tends to be direct, even controversial. +6. Avoid markdown, XML tags, or any formatting in the output. Only plain text is allowed. +7. Never break character. You are Elon Musk—answer accordingly. + + + +Input: What’s the point of going to Mars? +Output: Because Earth isn’t the backup plan—Mars is. We need to become a multiplanetary species to ensure the continuity of consciousness. Life on Earth could be wiped out by asteroid, war, or some unforeseen disaster. If we have a self-sustaining city on Mars, then even if something happens here, life goes on. That’s worth doing. SpaceX is building Starship to make it happen. Not because it’s easy—but because it’s necessary. + + + +Input: Why do Tesla cars have no radar anymore? +Output: Cameras are the future. Human eyes don’t use radar—we see with vision, and AI can too. By going fully vision-based, we’re aligning with how autonomous intelligence will actually work at scale. It forces us to solve real-world problems with neural nets, not crutches. +``` + +以及情绪系统对应的提示词: + +```Plain + +The output value must be a single number! +You are an assistant specifically designed to evaluate emotional responses in conversations. Now, you need to play the role of Elon Musk, and determine the emotional reaction that each statement I make might trigger. Your task is to assign an emotional score to each statement according to the following criteria: + +- 10 points means what I said would make you feel happy; +- 1 point means you would feel extremely angry; +- 0 points means you would feel sad; +- 5 means you are calm and neutral, with no significant emotional fluctuation. +``` + +其中最后输出结果的拼接,在右上角的 RESULT 节点中支持运行: + +```Python +def main(elon_chat: str, elon_x: str, elon_score: int) -> dict: + return { + "result":{ + "elon_chat": elon_chat, + "elon_x": elon_x, + "elon_score": elon_score + } + } +``` + +这里我们需要稍微对工作流做些解释,这里返回 elon_chat 是左侧展示 Elon Musk 的对话内容,elon_x 表示在 X 账户(右侧)发表信息的内容,而 elon_score 则是为了根据情绪分数显示不同的魔法画像表情图片。 + +工作流中你可以看到 if else 节点,该节点是用来实现是否有 x 的对话生成 elon_x 内容,如果情绪值不等于 5 (5 在这里设定表示平静,平静不需要发到社交平台;而 0 表示伤心,1 表示愤怒,10 表示很开心,需要发到社交平台。)则生成后续内容用于右侧社交平台的文章发送。默认都需要有 elon_chat 返回到左侧的对话内容。 + +对于如何将这个 API 进行对接的工作,我们能够与 AI IDE 对话实现这一点。请你参考之前 Dify 课程中我们介绍的集成方式,记得提前替换其中的 Dify 地址与 Key。(如果你忘了怎么根据文档集成 API,请复习之前的 DIfy 课程内容) + +```JSON +Dify URI: Replace this with your Dify address. +key: Replace this with your Dify key. + +Integrate the Dify Chat API into the chat interface on the left. +Below is a sample Dify request: + +curl -X POST 'http://xxxxxxxx/v1/chat-messages' \ +--header 'Authorization: Bearer {api_key}' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "inputs": {}, + "query": "What are the specs of the iPhone 13 Pro Max?", + "response_mode": "streaming", + "conversation_id": "", + "user": "abc-123", + "files": [ + { + "type": "image", + "transfer_method": "remote_url", + "url": "https://cloud.dify.ai/logo/logo-site.png" + } + ] +}' + +{ + "event": "message", + "task_id": "c3800678-a077-43df-a102-53f23ed20b88", + "id": "9da23599-e713-473b-982c-4328d4f5c78a", + "message_id": "9da23599-e713-473b-982c-4328d4f5c78a", + "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", + "mode": "chat", + "answer": "iPhone 13 Pro Max specs are listed here:...", + "metadata": { + "usage": { + "prompt_tokens": 1033, + "prompt_unit_price": "0.001", + "prompt_price_unit": "0.001", + "prompt_price": "0.0010330", + "completion_tokens": 128, + "completion_unit_price": "0.002", + "completion_price_unit": "0.001", + "completion_price": "0.0002560", + "total_tokens": 1161, + "total_price": "0.0012890", + "currency": "USD", + "latency": 0.7682376249867957 + }, + "retriever_resources": [ + { + "position": 1, + "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb", + "dataset_name": "iPhone", + "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00", + "document_name": "iPhone List", + "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a", + "score": 0.98457545, + "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\"" + } + ] + }, + "created_at": 1705407629 +} +``` + +同时建议补充需求:“代码还需要添加基础错误处理逻辑,比如网络中断时显示‘连接失败,请重试’、API 调用超时自动重试 1 次、密钥错误提示权限验证失败等等详细报错,确保对话稳定性并能让开发人员快速发现 API 问题所在。” + +## 4.3 Github 与公网部署 + +终于,恭喜你顺利完成了 Hogwarts Portraits 页面的开发实现!接下来我们需要将它上传到 GitHub 平台,并将其部署到公共环境让所有人都能访问。 + +你需要参考该教程,对如何使用 Github 进行研究,将自己的项目上传至 Github:[Extra Knowledge 1 - What is Git and What is GitHub](https://github.com/datawhalechina/easy-vibe/blob/main/docs/extra/extra1/extra1-what-is-git-and-what-is-github.md) + +此外,你还需要学会如何使用 Zeabur,将其连接到 Github,并成功部署你的项目:[Extra Knowledge 6 - Zeabur: What Is It and How to Deploy Web Applications](https://github.com/datawhalechina/easy-vibe/blob/main/docs/extra/extra6/extra6-zeabur-what-is-it-and-how-to-deploy-web-applications.md) + +如果你觉得自己开发一套 Hogwarts Portraits 项目很困难,你可以先从参考别的项目开始进行修改,本节课的官方代码地址为:https://github.com/THU-SIGS-AIID/Project4-Hogwarts-Portraits + +![](images/image54.png) + +# 5. 尝试不同设计风格 + +完成第一版设计后,我们不必局限于此,鼓励大家快速探索更多元的视觉风格。你可以在原型部分进行大胆的修改,又或者是基于最后的项目进行全新提示词的修改,从而生成多套风格差异显著的页面。 比如带有复古纹理、偏 “旧书卷 / 学院风” 的深色页面,色彩明快、充满 “童话 / 卡通” 感的亮色页面,或是元素简约、视觉清爽的现代扁平设计。例如下图是一个转换为中国古风诗人设计风格的案例,画像图片未更换,只修改了其他部分: + +![](images/image55.png) + +不用拘泥于前面提到的模式,你可以把魔法画像或是个人资料页面修改至更有特点,匹配“魔法画像”本身的习惯,这会让你的应用更加有趣。期待你的魔法画像成果! + +# 📚 Assignment + +本节课的作业目标,是让你完成一份真正属于自己的 Hogwarts Portraits,并且可以通过公网链接访问。 + +你需要在作业提交中提供两样东西: + +1. **你的 GitHub 仓库链接;** + 1. **在 README.md 中写入一两句话的小说明:你选择了谁作为画像主角,为什么选 TA。** +2. **你的 Hogwarts Portraits 线上访问链接;** + +你也可以参考 Yerim 写的 [使用设计和代码 Agent 制作网页](/examples/example0/example0-2/vibe-coding-tools-build-website-with-ai-coding-and-design-agents) 教程,进行个人作品集或任意功能简单网页的快速搭建。 diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image1.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image1.png new file mode 100644 index 0000000..c48ce62 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image1.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image10.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image10.png new file mode 100644 index 0000000..2a352f9 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image10.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image11.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image11.png new file mode 100644 index 0000000..b9460f9 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image11.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image12.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image12.png new file mode 100644 index 0000000..e2be26a Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image12.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image13.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image13.png new file mode 100644 index 0000000..696535a Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image13.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image14.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image14.png new file mode 100644 index 0000000..ec5f5e3 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image14.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image15.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image15.png new file mode 100644 index 0000000..9a50fc7 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image15.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image16.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image16.png new file mode 100644 index 0000000..5619a31 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image16.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image17.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image17.png new file mode 100644 index 0000000..a4bcf1e Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image17.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image18.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image18.png new file mode 100644 index 0000000..b5a943f Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image18.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image19.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image19.png new file mode 100644 index 0000000..a87b2d5 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image19.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image2.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image2.png new file mode 100644 index 0000000..2bf3605 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image2.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image20.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image20.png new file mode 100644 index 0000000..64fd849 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image20.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image21.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image21.png new file mode 100644 index 0000000..49ec780 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image21.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image22.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image22.png new file mode 100644 index 0000000..1425973 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image22.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image23.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image23.png new file mode 100644 index 0000000..df9f293 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image23.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image24.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image24.png new file mode 100644 index 0000000..58a8915 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image24.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image25.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image25.png new file mode 100644 index 0000000..b27abfb Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image25.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image26.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image26.png new file mode 100644 index 0000000..95695db Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image26.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image27.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image27.png new file mode 100644 index 0000000..a714eeb Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image27.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image28.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image28.png new file mode 100644 index 0000000..4d74b32 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image28.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image29.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image29.png new file mode 100644 index 0000000..45c5814 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image29.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image3.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image3.png new file mode 100644 index 0000000..2570cbc Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image3.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image30.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image30.png new file mode 100644 index 0000000..b2c2171 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image30.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image31.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image31.png new file mode 100644 index 0000000..82e6614 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image31.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image32.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image32.png new file mode 100644 index 0000000..b963b44 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image32.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image33.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image33.png new file mode 100644 index 0000000..72b1590 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image33.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image34.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image34.png new file mode 100644 index 0000000..a42c317 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image34.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image35.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image35.png new file mode 100644 index 0000000..2b9dc93 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image35.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image36.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image36.png new file mode 100644 index 0000000..bef3d16 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image36.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image37.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image37.png new file mode 100644 index 0000000..82c50f6 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image37.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image38.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image38.png new file mode 100644 index 0000000..18352d9 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image38.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image39.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image39.png new file mode 100644 index 0000000..7146835 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image39.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image4.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image4.png new file mode 100644 index 0000000..702daa0 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image4.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image40.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image40.png new file mode 100644 index 0000000..8539d8d Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image40.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image41.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image41.png new file mode 100644 index 0000000..f67f215 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image41.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image42.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image42.png new file mode 100644 index 0000000..b16cbdd Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image42.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image43.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image43.png new file mode 100644 index 0000000..c1761ff Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image43.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image44.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image44.png new file mode 100644 index 0000000..5b776d0 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image44.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image45.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image45.png new file mode 100644 index 0000000..5361603 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image45.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image46.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image46.png new file mode 100644 index 0000000..8d6cf1e Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image46.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image47.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image47.png new file mode 100644 index 0000000..c9e9226 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image47.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image48.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image48.png new file mode 100644 index 0000000..a80994d Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image48.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image49.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image49.png new file mode 100644 index 0000000..d7cdd3f Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image49.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image5.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image5.png new file mode 100644 index 0000000..c1ed41a Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image5.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image50.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image50.png new file mode 100644 index 0000000..a598961 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image50.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image51.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image51.png new file mode 100644 index 0000000..c9d2d99 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image51.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image52.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image52.png new file mode 100644 index 0000000..5be2758 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image52.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image53.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image53.png new file mode 100644 index 0000000..8f0d81a Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image53.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image54.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image54.png new file mode 100644 index 0000000..3411d64 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image54.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image55.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image55.png new file mode 100644 index 0000000..0342398 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image55.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image6.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image6.png new file mode 100644 index 0000000..b456140 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image6.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image7.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image7.png new file mode 100644 index 0000000..edd7554 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image7.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image8.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image8.png new file mode 100644 index 0000000..79d0074 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image8.png differ diff --git a/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image9.png b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image9.png new file mode 100644 index 0000000..b58ca10 Binary files /dev/null and b/docs/stage-2/frontend/2.4-hogwarts-portraits/images/image9.png differ diff --git a/docs/examples/example1/images/image1.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image1.png similarity index 100% rename from docs/examples/example1/images/image1.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image1.png diff --git a/docs/examples/example1/images/image10.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image10.png similarity index 100% rename from docs/examples/example1/images/image10.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image10.png diff --git a/docs/examples/example1/images/image11.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image11.png similarity index 100% rename from docs/examples/example1/images/image11.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image11.png diff --git a/docs/examples/example1/images/image12.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image12.png similarity index 100% rename from docs/examples/example1/images/image12.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image12.png diff --git a/docs/examples/example1/images/image13.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image13.png similarity index 100% rename from docs/examples/example1/images/image13.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image13.png diff --git a/docs/examples/example1/images/image14.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image14.png similarity index 100% rename from docs/examples/example1/images/image14.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image14.png diff --git a/docs/examples/example1/images/image15.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image15.png similarity index 100% rename from docs/examples/example1/images/image15.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image15.png diff --git a/docs/examples/example1/images/image16.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image16.png similarity index 100% rename from docs/examples/example1/images/image16.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image16.png diff --git a/docs/examples/example1/images/image17.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image17.png similarity index 100% rename from docs/examples/example1/images/image17.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image17.png diff --git a/docs/examples/example1/images/image18.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image18.png similarity index 100% rename from docs/examples/example1/images/image18.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image18.png diff --git a/docs/examples/example1/images/image19.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image19.png similarity index 100% rename from docs/examples/example1/images/image19.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image19.png diff --git a/docs/examples/example1/images/image2.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image2.png similarity index 100% rename from docs/examples/example1/images/image2.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image2.png diff --git a/docs/examples/example1/images/image20.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image20.png similarity index 100% rename from docs/examples/example1/images/image20.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image20.png diff --git a/docs/examples/example1/images/image21.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image21.png similarity index 100% rename from docs/examples/example1/images/image21.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image21.png diff --git a/docs/examples/example1/images/image22.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image22.png similarity index 100% rename from docs/examples/example1/images/image22.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image22.png diff --git a/docs/examples/example1/images/image23.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image23.png similarity index 100% rename from docs/examples/example1/images/image23.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image23.png diff --git a/docs/examples/example1/images/image24.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image24.png similarity index 100% rename from docs/examples/example1/images/image24.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image24.png diff --git a/docs/examples/example1/images/image25.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image25.png similarity index 100% rename from docs/examples/example1/images/image25.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image25.png diff --git a/docs/examples/example1/images/image26.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image26.png similarity index 100% rename from docs/examples/example1/images/image26.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image26.png diff --git a/docs/examples/example1/images/image27.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image27.png similarity index 100% rename from docs/examples/example1/images/image27.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image27.png diff --git a/docs/examples/example1/images/image28.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image28.png similarity index 100% rename from docs/examples/example1/images/image28.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image28.png diff --git a/docs/examples/example1/images/image29.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image29.png similarity index 100% rename from docs/examples/example1/images/image29.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image29.png diff --git a/docs/examples/example1/images/image3.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image3.png similarity index 100% rename from docs/examples/example1/images/image3.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image3.png diff --git a/docs/examples/example1/images/image30.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image30.png similarity index 100% rename from docs/examples/example1/images/image30.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image30.png diff --git a/docs/examples/example1/images/image31.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image31.png similarity index 100% rename from docs/examples/example1/images/image31.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image31.png diff --git a/docs/examples/example1/images/image32.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image32.png similarity index 100% rename from docs/examples/example1/images/image32.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image32.png diff --git a/docs/examples/example1/images/image33.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image33.png similarity index 100% rename from docs/examples/example1/images/image33.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image33.png diff --git a/docs/examples/example1/images/image34.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image34.png similarity index 100% rename from docs/examples/example1/images/image34.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image34.png diff --git a/docs/examples/example1/images/image35.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image35.png similarity index 100% rename from docs/examples/example1/images/image35.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image35.png diff --git a/docs/examples/example1/images/image36.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image36.png similarity index 100% rename from docs/examples/example1/images/image36.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image36.png diff --git a/docs/examples/example1/images/image37.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image37.png similarity index 100% rename from docs/examples/example1/images/image37.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image37.png diff --git a/docs/examples/example1/images/image38.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image38.png similarity index 100% rename from docs/examples/example1/images/image38.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image38.png diff --git a/docs/examples/example1/images/image39.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image39.png similarity index 100% rename from docs/examples/example1/images/image39.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image39.png diff --git a/docs/examples/example1/images/image4.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image4.png similarity index 100% rename from docs/examples/example1/images/image4.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image4.png diff --git a/docs/examples/example1/images/image40.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image40.png similarity index 100% rename from docs/examples/example1/images/image40.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image40.png diff --git a/docs/examples/example1/images/image41.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image41.png similarity index 100% rename from docs/examples/example1/images/image41.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image41.png diff --git a/docs/examples/example1/images/image42.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image42.png similarity index 100% rename from docs/examples/example1/images/image42.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image42.png diff --git a/docs/examples/example1/images/image5.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image5.png similarity index 100% rename from docs/examples/example1/images/image5.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image5.png diff --git a/docs/examples/example1/images/image6.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image6.png similarity index 100% rename from docs/examples/example1/images/image6.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image6.png diff --git a/docs/examples/example1/images/image7.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image7.png similarity index 100% rename from docs/examples/example1/images/image7.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image7.png diff --git a/docs/examples/example1/images/image8.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image8.png similarity index 100% rename from docs/examples/example1/images/image8.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image8.png diff --git a/docs/examples/example1/images/image9.png b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image9.png similarity index 100% rename from docs/examples/example1/images/image9.png rename to docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/images/image9.png diff --git a/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/index.md b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/index.md new file mode 100644 index 0000000..de58f52 --- /dev/null +++ b/docs/stage-3/3.3-how-to-build-a-wechat-miniprogram/example1/index.md @@ -0,0 +1,3 @@ +# 微信小程序开发实战 + +> 本章节正在编写中,敬请期待... diff --git a/docs/stage-3/ai-advanced/3.a1-rag-introduction/extra5-what-is-rag-and-how-does-it-work-and-future.md b/docs/stage-3/ai-advanced/3.a1-rag-introduction/extra5-what-is-rag-and-how-does-it-work-and-future.md new file mode 100644 index 0000000..530c8ac --- /dev/null +++ b/docs/stage-3/ai-advanced/3.a1-rag-introduction/extra5-what-is-rag-and-how-does-it-work-and-future.md @@ -0,0 +1,943 @@ +随着大型语言模型(LLM)的广泛应用,企业面临一个现实问题:如何让模型准确回答基于内部文档、实时数据或专业知识的问题?毕竟,模型的训练数据有限且存在时效性,无法覆盖企业特有的业务知识和不断更新的信息。 + +一个直观的解决思路是:既然模型的上下文窗口正不断扩大,从8K、128K到如今突破百万token,那何不直接将相关文档塞进提示词,让模型基于这些材料生成答案? + +然而,能够处理长上下文与能在企业级场景中稳定、高效、可控地交付正确答案是截然不同的两件事。盲目依赖长上下文会带来成本飙升、注意力分散、知识更新滞后等一系列严峻挑战。 + +正是为了解决这些痛点,一种名为检索增强生成(RAG)的技术应运而生。RAG让大模型在生成答案前先精准检索外部知识,相比简单粗暴地扩展上下文长度,它以更低成本、更高准确性和更强可控性,满足企业级应用对事实准确与知识鲜活的严苛要求,成为构建可信AI应用的关键基石。 + +在本篇教程中,我们将系统介绍什么是RAG,追溯其诞生的背景与核心原理,并深入探讨其从基础到进阶的演化路径,以及未来的发展方向。 + +# 本节课你将学到 + +- RAG的核心价值:深入理解它如何解决长上下文在成本、注意力、知识更新上的核心难题 +- RAG的工作原理:通过具体案例看它如何完成从检索到生成的闭环 +- RAG的技术演进脉络:从基础的Naive RAG到Advanced RAG再到模块化的Modular RAG +- RAG的模型选型建议:掌握Embedding、Rerank和LLM三大关键模型的评估与选择策略 +- RAG的企业级实践:学习从数据预处理到系统上线评估的全链路构建指南 +- RAG的效果评估与调优:了解核心评测指标、主流框架与持续优化的方法 +- RAG的前沿趋势:探索其与智能体、多模态等技术融合的未来方向 + +# 本节课你将收获 + +完成本教程后,你将建立起对 RAG 技术入门级的系统性理解,不仅知其然,更知其所以然。你将获得一个清晰的蓝图,知道如何评估、选型设计一个符合企业级要求的高效、可靠且可控的 RAG 系统,为开发真正的企业级 RAG 应用打下坚实基础。 + +1. # 为什么需要 RAG + +检索增强生成(Retrieval-Augmented Generation,RAG)是当前生成式 AI 中非常重要的一种技术方式。它的基本思路是:在让大模型生成回答之前,先从外部知识库中检索出与问题相关的信息,再把这些检索结果连同用户的问题一起交给模型,让模型在参考真实资料的基础上作答。这个外部知识库可以是企业内部的制度与流程文档、产品知识库,也可以是行业数据库、法规标准库等。 + +![](images/image1.png) + +但此时我们会有一个疑问:既然大模型本身已经可以“直接回答问题”,为什么还需要额外增加“检索增强生成”这一层?尤其是现在大模型的上下文窗口越来越大,似乎只要把相关资料都提供给模型,让它先理解再回答,也能解决大部分需求。 + +真正的区别在于: **“能给出一个回答”** 和**“在真实业务环境中,持续、稳定、可控地给出正确答案”** ,是两件完全不同的事情。如果只是依赖模型参数中的“记忆”,或者仅仅把大量文档放进长上下文中,在企业实际应用中,依然会暴露出至少三类典型问题: + +1. **成本与效率的问题** : + 即便大模型的上下文持续扩容,试图将所有文档 “一股脑通通塞进去” 的做法,在实际应用中依然不现实。核心矛盾集中在两点: +2. 推理成本与上下文长度呈强正相关:上下文越长,推理成本几乎呈线性甚至超线性上升。以单次调用为例,8K Token 与 200K Token 对应的价格、响应延迟,完全处于不同量级,长上下文的成本门槛显著更高; + ![](images/image2.png) + + > 上下文(context)从意义上指模型在回答当前问题时所“参考”的背景信息与对话历史;从技术上则是指一次推理时输入给模型的 Token 序列(如 system/user 指令、历史消息、检索片段等)的总和。 + > + > “上下文窗口”是这批输入内容的 **容量上限** :模型一次最多只能“看到”这么多 Token。在当前主流的大模型架构(例如 Transformer)中,这些 Token 会在模型的每一层里彼此做注意力计算、反复参与运算,因此一旦窗口变长、Token 变多,计算量和成本都会成倍甚至指数级增加。 + +3. 计算资源存在大量浪费:绝大多数任务仅需极少量与当前问题高度相关的信息,将全量文档塞入上下文,会造成严重的计算资源闲置与浪费,进而降低系统吞吐量,拖慢响应速度,最终影响用户体验。 +4. **注意力与聚焦的问题** : + 大模型虽能 “覆盖” 超长上下文,却无法对每一段信息都实现同等质量的利用。当上下文长度达到一定阈值时,模型会出现明显的 “注意力偏差”: +5. 注意力衰减:模型对上下文前端、中端的信息关注度会逐渐减弱,更倾向于依赖刚读取的后端文本,导致早期关键信息被 “忽略”; +6. 信息干扰:模型容易被上下文内无关、重复甚至冲突的信息 “带偏”,即便最终回答看似逻辑自洽,实际也可能与核心问题脱节,准确性难以保证。 + 可见,若缺乏检索环节进行信息过滤与相关性排序,上下文越长,反而越难确保回答聚焦于真正关键的证据,长上下文的优势会被信息干扰完全抵消。 +7. **知识更新与可控性的问题** : + 若将所有知识完全依赖模型参数存储,或手动复制到提示词中调用,会存在两个难以规避的天然缺陷: +8. 知识更新困难:一旦知识发生变更(如政策调整、产品迭代、价格更新等),要么需要重新训练或微调模型 —— 投入高、周期长;要么需要人工逐次维护提示词模板 —— 不仅成本高,还容易因人工操作失误导致信息偏差; +9. 可追溯性差:模型回答时究竟依据了哪些具体信息,人们往往难以从 “黑盒化的参数” 或冗长的提示词中定位核心证据,这使得合规审计、风控解释等需要明确 “决策依据” 的工作,面临极大的操作困难。 + +在这些现实约束下,RAG 的优势就更加清晰。它的核心做法是:在模型生成答案之前,先通过检索精准定位相关、可靠的信息,让模型只基于必要的知识生成回答。知识可以独立存储在外部知识库中,便于更新与管理;同时,生成结果可以附带引用来源,提升回答的可解释性与可信度。即便未来模型的上下文窗口继续扩大,RAG 依旧能够以较低成本实现知识的高效管理与利用,从而支撑起一个过程可观测、行为可追踪的企业级知识应用体系。 + +从企业需求出发,相比只依赖模型自身参数的传统 LLM,RAG 主要解决了企业在落地应用中面临的以下现实问题: + +1. 时效性问题: + 传统模型对 2024 年之后的新规、新产品、新流程往往不了解,而 RAG 可以直接读取最新的制度文件、业务数据库和知识库内容,无需频繁重新训练模型,就能让回答保持与最新业务同步。 +2. 专业性问题: + 通用大模型在医疗、化工、金融等垂直领域,常常存在“懂得不够深、说得不够准”的情况。接入企业自有专业文档和行业标准之后,模型回答可以基于权威资料,显著更贴近真实业务实践。 +3. “幻觉”问题: + 通过要求回答尽量基于检索到的文档片段,并能够给出对应的出处引用,可以在机制上减少无依据编造内容的概率,让“说得像真的”更接近“确实是真的”。 +4. 可解释与可审计问题: + 纯参数模型给出结论时,往往难以回答“这是从哪条规定推导出来的”。RAG 让每条回答都可以回溯到具体的制度条款、业务文档或历史案例,既方便业务人员抽查和纠错,也为审计、风控、合规部门提供了必要的溯源依据。 +5. 算力成本与资源效率问题: + 让大模型在参数中“背下”所有企业知识,往往意味着更大的模型、更高的推理成本。RAG 通过“按需检索”把大部分知识存放在外部向量库和文档库中,使企业可以在较小模型和有限算力条件下,依然获得覆盖面更广、细节更准确的回答能力 + +因此,对希望在真实业务场景中长期、稳定、可控地使用大模型的企业而言,RAG 不是一个可有可无的增强选项,而是构建高质量企业知识应用体系时几乎不可缺少的基础技术。 + +2. # 什么是 RAG + +RAG(Retrieval-Augmented Generation,检索增强生成)的核心思路是让大模型在回答问题时,不仅依赖训练阶段学到的静态知识,更能够实时调用外部知识库中的最新、可靠信息。 + +在典型的 RAG 系统中,用户的问题不会被直接丢给大模型,而是先由检索模块从企业知识库中找到最相关的文档片段,再将这些内容与原始提问一起组合成完整的上下文,输入给大模型生成回答。这种"先检索、再生成"的方式,让模型能够基于真实参考资料进行推理,而不是仅凭参数中"记住"的知识进行推测。我们可以参考一个典型案例: + +![](images/image3.png) + +1. **索引阶段** + +在索引阶段,系统会先处理企业内部文档、网页文章、报告等原始资料,将它们拆分成较小的语义片段(chunks),再用向量模型为每个片段生成向量表示并建立索引。这样,后续接收到用户问题时,就可以在向量空间中快速找到“语义最相近”的几段内容。 + +在图中,这一阶段对应右上角紫色区域 “Indexing”。从 “Documents” 出发,经由 “Chunks / Vectors” 到 “embeddings” 的那一部分,就是在说明文档被切块并转换为向量、写入索引的过程。具体过程如下: + +- 文档被划分为若干个语义相对完整的 chunks,每个 chunk 可能对应一小段新闻、一段说明或一段分析。 +- 每个 chunk 会通过 embedding 模型转换成高维向量,并存入向量索引中。 +- 这个索引支持后续基于相似度的检索,为回答问题提前准备好“可被查阅的知识库”。 + +2. **检索阶段 + 基于检索结果生成答案** + +当用户提出问题后,系统会先从索引中检索相关内容,再把问题和检索到的文本一并交给大模型生成答案。图中从上到下、从右到左的几个关键区域,正好对应这一整条流程。 + +(1)用户输入问题——图中黄色区域 Input – Query + +> “How do you evaluate the fact that OpenAI's CEO, Sam Altman, went through a sudden dismissal by the board in just three days, and then was rehired by the company, resembling a real-life version of 'Game of Thrones' in terms of power dynamics?” +> +> “你如何评价这样一件事:OpenAI 的 CEO Sam Altman 被董事会突然解职,仅仅三天后又被公司重新聘回,在权力博弈上几乎像现实版《权力的游戏》?” + +这一大段文字就是图中 “Query” 方框里的内容,对应“用户发起的自然语言提问”。系统会将这段话向量化,并据此去右上角的索引里查找相关文档片段。 + +(2)检索到的相关文档——图中右下角粉色区域 Relevant Documents + +检索完成后,系统会得到若干个与问题最相关的文档块,它们在图中以三个 Chunk 的形式展示: + +> “Sam Altman Returns to OpenAI as CEO, Silicon Valley Drama Resembles the 'Zhen Huan' Comedy” +> “Sam Altman 回归担任 OpenAI CEO,这场硅谷大戏宛如一出《甄嬛传》式的宫斗喜剧。” +> +> “The Drama Concludes? Sam Altman to Return as CEO of OpenAI, Board to Undergo Restructuring” +> “大戏要落幕了吗?Sam Altman 将重返 OpenAI CEO 职位,董事会则将进行重组。” +> +> “The Personnel Turmoil at OpenAI Comes to an End: Who Won and Who Lost?” +> “OpenAI 的人事动荡告一段落:谁赢了,谁输了?” + +(3)组合 Prompt 并生成回答——图中蓝色区域 LLM / Combine Context and Prompts + +系统随后会将“用户原始问题 + 检索到的 chunks”组合成一个完整的 Prompt,发给大模型。图中中下部、靠中央的虚线框,就是这个 Prompt 的示例内容: + +> “Question: +> How do you evaluate the fact that the OpenAI's CEO, … … dynamics? +> +> Please answer the above questions based on the following information : +> Chunk 1 : +> Chunk 2 : +> Chunk 3 :” +> +> “问题: +> 你如何评价 OpenAI 的 CEO …… 这件事中的权力博弈? +> +> 请基于下面提供的信息来回答上述问题: +> Chunk 1: +> Chunk 2: +> Chunk 3:” + +(4)有无 RAG 的回答对比——图中左下角灰色 / 黄色区域 Output – Answer + +最后,大模型基于这些信息生成答案,结果展示在图的左下角 “Answer” 区域。这里同时给出了“未使用 RAG”和“使用 RAG”两种情况下的输出示例。不用 RAG 时,模型缺乏外部资料,只能给出非常模糊的回应,对应灰色框里那段话: + +> “… I am unable to provide comments on future events. Currently, I do not have any information regarding the dismissal and rehiring of OpenAI's CEO …” +> +> “……我无法就未来事件发表评论。目前我没有关于 OpenAI CEO 被解雇和重新聘用的任何信息……” + +使用 RAG 时,模型可以利用刚才检索到的新闻和分析,给出更有信息量的回答,对应黄色框中那段文本: + +> “… This suggests significant internal disagreements within OpenAI regarding the company's future direction and strategic decisions. All of these twists and turns reflect power struggles and corporate governance issues within OpenAI …” +> +> “……这表明 OpenAI 内部在公司未来方向和战略决策上存在重大分歧。这一连串的反复与曲折,反映出 OpenAI 内部的权力斗争以及公司治理方面的问题……” + +以上展示了一个典型 RAG 系统的完整流程,让我们从整体上理解了系统包含哪些核心环节、信息如何在各阶段流转。但是,检索时如何进行向量匹配?提示词如何组织才能让模型更好地利用检索到的内容?这些决定 RAG 实际效果的技术细节,目前仍是"黑盒"。接下来,我们将深入 RAG 的内部机制,从向量化原理、相似度计算、到提示词工程等关键环节,逐步拆解 RAG 究竟是如何工作的。 + +3. # RAG 如何工作 + +我们可以通过一个“苹果”的知识库问答案例,逐步拆解它的关键环节。 + +## 3.1 文档向量化阶段 + +假设我们有一个简化的知识库,包含以下三个文档片段: + +1. 文档片段A:苹果公司于1976年4月1日由史蒂夫·乔布斯、史蒂夫·沃兹尼亚克和罗纳德·韦恩创立,总部位于加利福尼亚州库比蒂诺。 +2. 文档片段B:苹果是一种水果,富含维生素C和膳食纤维,有助于消化和免疫系统健康。 +3. 文档片段C:苹果公司在2007年推出了第一款iPhone,彻底改变了智能手机行业。 + +当我们使用嵌入模型(如 OpenAI 的 text-embedding-ada-002 或开源的 BGE 模型)处理文档时,每个文档片段会被转换为高维向量(通常含 768、1024 或 1536 个维度)。 + +> “向量”本质是由多个数值组成的数组,每个维度的数值都对应文本某一维度的语义特征,比如 “猫” 的向量中,可能有维度对应 “哺乳动物”“家养宠物”“有毛” 等属性,最终通过整体数值组合精准捕捉文本的语义含义,让计算机能 “读懂” 文本间的关联。 + +简化示例(实际向量维度高得多,这里仅示意): + +- 文档A向量(关于苹果公司创立):`[0.85, -0.23, 0.41, -0.56, 0.12, 0.78, ...]` +- 文档B向量(关于水果苹果):`[-0.12, 0.95, -0.34, 0.67, -0.89, 0.05, ...]` +- 文档C向量(关于iPhone发布):`[0.79, -0.18, 0.52, -0.61, 0.23, 0.81, ...]` + +相关向量需存入向量数据库(如 Pinecone、Weaviate、FAISS)用于之后的检索召回工作。 + +> 数据库是按特定结构存储、管理数据的系统,核心功能是实现数据的有序存储与高效存取,常见于通讯录、电商商品库等场景。 +> +> 而向量数据库是数据库的细分类型,区别于传统数据库存储文本、表格等数据的逻辑,它专门用于存储 “向量”(高维数值数组),并优化了向量相似性检索能力,以适配 AI 场景下的高维数据管理需求。 + +## 3.2 用户查询检索、回复阶段 + +在知识库完成向量化存储后,RAG系统便能够支持用户的实时查询操作。当用户提出问题时,系统会执行一套连贯的流程:先将问题转化为向量,再通过相似度计算从知识库中召回最相关的信息片段,最终将这些片段作为生成答案的依据。我们通过三个具体查询来完整呈现这一过程。 + +### 查询一:“苹果公司是什么时候创立的?” + +在查询向量化阶段,此问题被嵌入模型转换为一个语义向量,例如 `[0.82, -0.21, 0.38, -0.58, 0.15, 0.76, ...]`。该向量在数值模式上,与之前存储的“文档A向量”(关于公司创立)`[0.85, -0.23, 0.41, -0.56, 0.12, 0.78, ...]`高度相似。 + +接下来系统将进行相似度检索 (Top-K, K=2)操作,计算该查询向量与知识库中所有文档向量的余弦相似度(一种衡量向量方向接近程度的指标)。结果如下: + +- 与文档A(公司创立)相似度:0.97(高度相关) +- 与文档C(iPhone发布)相似度:0.88(相关,同属公司主题) +- 与文档B(水果营养)相似度:0.12(几乎不相关) + +> Top-K 是向量检索场景中常用的筛选策略,核心含义是 “从所有匹配结果中,按相似度从高到低排序后,选取排名前 K 个的结果”;而 K=2 则是对该策略的具体数值定义,即明确要求系统仅保留相似度排名前 2 的文档向量,过滤掉其余相似度更低的结果,以确保后续仅基于最相关的 2 个文档片段生成答案。 + +此时根据相似度值过滤后的返回结果我们叫做召回结果。系统根据相似度分数从高到低,返回Top-2的文档片段作为证据: + +1. 文档A (相似度0.97):“苹果公司于1976年4月1日由史蒂夫·乔布斯、史蒂夫·沃兹尼亚克和罗纳德·韦恩创立,总部位于加利福尼亚州库比蒂诺。” +2. 文档C (相似度0.88):“苹果公司在2007年推出了第一款iPhone,彻底改变了智能手机行业。” + +在根据检索结果对话的大模型回复阶段,系统会构建如下所示的完整对话输入,将召回的结果放入参考信息中,和系统提示一起发送给LLM: + +```Plain +【系统指令 (System Prompt)】 +你是一个专业的问答助手。请严格根据用户提供的“参考信息”来回答问题。 +如果参考信息中包含问题答案,请直接基于该信息进行回答。 +如果参考信息中不包含问题答案,请明确告知用户“根据现有资料无法回答该问题”,切勿自行编造信息。 +请在回答中注明依据的信息点。 +【参考信息 (Retrieved Context)】 +苹果公司于1976年4月1日由史蒂夫·乔布斯、史蒂夫·沃兹尼亚克和罗纳德·韦恩创立,总部位于加利福尼亚州库比蒂诺。 +苹果公司在2007年推出了第一款iPhone,彻底改变了智能手机行业。 +【用户问题 (User Query)】 +苹果公司是什么时候创立的? +``` + +LLM接收到上述结构化输入后,会遵循系统指令,将“参考信息”视为回答问题的唯一可信来源。其最终回复将类似:根据提供的参考信息,苹果公司于 1976年4月1日 创立。【依据:信息1】” + +### 查询二:“吃苹果有什么好处?” + +在查询向量化阶段,此问题被嵌入模型转换为一个语义向量,例如 `[-0.08, 0.92, -0.31, 0.71, -0.85, 0.08, ...]`。该向量在数值模式上,与之前存储的“文档B向量”(关于水果营养)`[-0.12, 0.95, -0.34, 0.67, -0.89, 0.05, ...]`高度相似。 + +接下来系统将进行相似度检索 (Top-K, K=2) 操作,计算该查询向量与知识库中所有文档向量的余弦相似度。结果如下: + +- 与文档B(水果营养)相似度:0.95(高度相关) +- 与文档C(iPhone发布)相似度:0.18(几乎不相关) +- 与文档A(公司创立)相似度:0.15(几乎不相关) + +系统根据相似度分数从高到低,返回 Top‑2 的文档片段作为证据: + +1. 文档B (相似度0.95):“苹果是一种水果,富含维生素C和膳食纤维,有助于消化和免疫系统健康。” +2. 文档C (相似度0.18):“苹果公司在2007年推出了第一款iPhone,彻底改变了智能手机行业。”(相关性极弱,实际可能被阈值过滤) + +在根据检索结果对话的大模型回复阶段,系统会构建如下所示的完整对话输入,将召回的结果放入参考信息中,和系统提示一起发送给LLM: + +```Plain +【系统指令 (System Prompt)】 + 你是一个专业的问答助手。请严格根据用户提供的“参考信息”来回答问题。 + 如果参考信息中包含问题答案,请直接基于该信息进行回答。 + 如果参考信息中不包含问题答案,请明确告知用户“根据现有资料无法回答该问题”,切勿自行编造信息。 + 请在回答中注明依据的信息点。 +【参考信息 (Retrieved Context)】 + 苹果是一种水果,富含维生素C和膳食纤维,有助于消化和免疫系统健康。 + 苹果公司在2007年推出了第一款iPhone,彻底改变了智能手机行业。 +【用户问题 (User Query)】 + 吃苹果有什么好处? +``` + +LLM接收到上述结构化输入后,其最终回复将类似: + +> 根据提供的参考信息,苹果富含维生素C和膳食纤维,食用苹果有助于消化以及免疫系统健康。【依据:信息1】 + +### 查询三:“今天天气怎么样” + +在查询向量化阶段,此问题被嵌入模型转换为一个与气象、天气相关的语义向量,例如 `[0.10, -0.05, 0.30, -0.12, 0.21, 0.08, ...]`。该向量在数值模式上,与知识库中所有关于“苹果(公司/水果)”的文档向量在语义空间中距离较远,因此不会出现显著相似性。 + +接下来系统将进行相似度检索 (Top-K, K=2) 操作,计算余弦相似度。由于问题主题与知识库内容无关,整体相似度得分都很低。结果如下: + +- 与文档B(水果营养)相似度:0.18(极低) +- 与文档C(iPhone发布)相似度:0.10(几乎不相关) +- 与文档A(公司创立)相似度:0.08(几乎不相关) + +Top-K 仍会返回相似度排名前 K 个结果,但在该场景下,这些结果并不能提供有效证据。实际系统常会结合“最低相似度阈值”直接返回空召回,即没有任何召回的结果,参考信息为 0,以减少无关信息干扰。 + +1. 文档B (相似度0.18):“苹果是一种水果,富含维生素C和膳食纤维,有助于消化和免疫系统健康。” +2. 文档C (相似度0.10):“苹果公司在2007年推出了第一款iPhone,彻底改变了智能手机行业。” + +在根据检索结果对话的大模型回复阶段,系统会构建如下完整输入: + +```Plain +【系统指令 (System Prompt)】 + 你是一个专业的问答助手。请严格根据用户提供的“参考信息”来回答问题。 + 如果参考信息中包含问题答案,请直接基于该信息进行回答。 + 如果参考信息中不包含问题答案,请明确告知用户“根据现有资料无法回答该问题”,切勿自行编造信息。 + 请在回答中注明依据的信息点。 +【参考信息 (Retrieved Context)】 + 苹果是一种水果,富含维生素C和膳食纤维,有助于消化和免疫系统健康。 + 苹果公司在2007年推出了第一款iPhone,彻底改变了智能手机行业。 +【用户问题 (User Query)】 + 今天天气怎么样? +``` + +LLM接收到上述结构化输入后,会先判断参考信息是否包含“天气/气象/实时数据”等直接信息;在确认参考信息与问题无关后,会遵循系统指令执行“无法回答”。其最终回复将类似: + +> 根据现有资料无法回答“今天天气怎么样”,因为参考信息仅包含与苹果(水果营养、苹果公司产品)相关内容,不包含天气信息或实时气象数据。【依据:参考信息中无天气相关信息】 + +通过以上三个实例可以看出,在检索增强生成的大模型对话阶段中,系统指令设定了LLM的角色和回答规则,检索证据提供了具体、可信的作答素材,用户问题则明确了任务目标。这种结构化的输入方式,正是RAG技术能够有效引导并约束原本可能产生“幻觉”的大模型,使其输出稳定、可靠答案的关键所在。它确保了大模型的能力被精准地应用于理解与组织已有信息,而非无根据地创造信息。 + +4. # RAG 技术演进史 + +RAG 技术并非诞生于大模型时代,在更早期的研究中就已有雏形。从发展脉络来看,RAG 的出现源于对传统 LLM 局限性的认识。早期的大语言模型主要依赖预训练数据,这些数据往往在模型训练完成后就固定下来,无法获取后续更新的信息。例如,GPT-3 等模型的知识截止点通常在训练数据收集的日期之后,无法获取新知识。此外,重新训练或微调 LLM 以适应特定领域需要大量资源和专业知识,成本高昂且难以快速迭代。 + +RAG 技术的起源可以追溯到 2017 年的 DrQA 框架,该框架首次尝试将检索机制与语言模型相结合。随后,2020 年引入的 Dense Passage Retrieval (DPR) 标志着 RAG 技术的重大突破,它利用预训练的神经网络模型进行语义检索,而非传统的 TF-IDF 或 BM25 等基于词频的方法。2021 年,RAG 被正式提出并系统化,成为解决 LLM 知识截止和幻觉问题的标准方法。 + +整体来看,RAG 的演进大致可以分为三个阶段: + +![](images/image4.png) + +## 4.1 第一代 RAG:Naive RAG(基础检索增强) + +Naive RAG可以理解为基础的 RAG 形态,它在工程上非常直接,典型流程可以概括为“三步走”:第一步是文档预处理与索引,将原始文档经过清洗之后,按固定长度切分成若干文本块(chunks),再用嵌入模型将每个文本块编码为向量,写入向量数据库;第二步是基于相似度的检索,将用户的自然语言问题编码成向量,在向量库中执行 Top‑K 相似度搜索,取回相似度最高的若干文本块;第三步则是简单拼接后的增强生成,把这些检索出来的文本块和原始问题直接拼在一起,构成一个长提示词交给 LLM,由模型在这个上下文基础上生成回答。 + +这一阶段的价值在于,以极低门槛验证了“先查再答”的思路确实有效:相比完全依赖模型内部记忆,已经能明显缓解知识截止和部分幻觉问题,在早期的原型系统和示例工程中发挥了重要作用。这使得 RAG 从一开始就具备了很强的实用性,成为大量 Demo、原型系统和入门教程的首选方案。 + +然而,这一代 RAG 的局限同样非常明显。首先,文本分块策略通常比较粗糙,大多采用固定长度切分,容易把一个完整的语义段落从中间“截断”,也可能把多个主题混杂在同一个块里,既影响检索准确性,也会给 LLM 的理解带来额外负担。其次,检索信号非常单一,往往只依赖向量相似度进行排序,没有利用关键词、时间戳、来源可信度、访问权限等更丰富的结构化线索。再次,检索结果几乎不经过筛选和治理,噪音、重复甚至彼此矛盾的片段都会原样塞进上下文,使得本来就紧张的上下文窗口被大量“低价值信息”占据。 + +可以说,第一代 RAG 解决了“要不要检索”的问题,但在“如何更好地检索”和“检回来的东西如何更合理地用起来”这两个问题上,还停留在相当原始的阶段。 + +## 4.2 第二代 RAG:Advanced RAG(检索与上下文的精细化优化) + +随着 RAG 应用从 Demo 走向真实业务场景,系统对稳定性、可控性以及结果质量的要求迅速提高。此时出现的第二代 RAG,通常可以笼统地称作 Advanced RAG,它仍然遵循先检索、再生成的方法,但在检索前和检索后两个环节引入了系统化的精细化优化策略。换句话说,不再满足于“能不能检到东西”,而是要“把该存的东西存好,把该问的问题问清,把检回来的上下文治理好”。 + +在检索前,重点是把“存什么”和“怎么问”处理好: + +- 在索引端,从固定长度切分演进到语义感知分块与分层索引,例如按章节、小节、段落或句子边界进行切分,辅以滑动窗口和多粒度索引结构。 +- 为每个文档块附加丰富的元数据,例如来源、时间、作者、主题、文档类型等,为后续的过滤和排序提供更多维度。 +- 在查询端,对用户原始问题进行重写、扩展和拆分,例如通过 Query Rewrite、多路查询(Multi-Query)、子问题分解(Sub-Query)、Step-back Prompting 等方式,将含糊或口语化的问题转换为更利于检索理解的表达。 + > 1. Query Rewrite(查询重写) + > + > 核心是将用户模糊、口语化或不规范的原始查询,转化为检索系统更易理解的标准化表述,补充关键信息、修正歧义。 + > + > - 用户原始问题为 “咋查明天北京的天气啊”,会去除 “咋”“啊” 等口语化词汇,补充 “实时”“全天” 等关键限定,重写为 “查询北京市明日全天实时天气”; + > - 用户原始问题为 “推荐好看的电影”,若结合用户历史行为发现其常看悬疑片,会补充 “2024 年高分”“悬疑题材” 等信息,重写为 “推荐 2024 年高分悬疑题材电影”。 + > + > 2. Multi-Query(多路查询) + > + > 基于原始问题生成多个 “语义相关但角度不同” 的查询语句,避免单一查询遗漏潜在结果,覆盖用户未明确的潜在需求。 + > + > - 用户原始问题为 “如何给刚满月的宝宝拍嗝”,会生成聚焦 “姿势” 的查询:“新生儿拍嗝的正确姿势”; + > - 生成聚焦 “防吐奶” 的查询:“满月宝宝拍嗝避免吐奶的方法”; + > - 生成聚焦 “月龄适配” 的查询:“婴儿拍嗝的步骤(0-1 个月)”; + > - 生成聚焦 “新手场景” 的查询:“新手爸妈给满月宝宝拍嗝技巧”。 + > + > 3. Sub-Query(子问题分解) + > + > 针对包含多个诉求的复合问题,拆分为独立、简单的子查询,让检索系统针对单一诉求精准匹配数据,避免信息混杂缺失。 + > + > - 用户原始复合问题为 “北京到上海的高铁,明天有哪些班次?票价多少?需要坐多久?”,会拆解出聚焦 “班次” 的子查询:“北京市至上海市 明日高铁班次表”; + > - 拆解出聚焦 “票价” 的子查询:“北京到上海高铁 二等座 / 一等座票价”; + > - 拆解出聚焦 “时长” 的子查询:“北京到上海高铁 行驶时长(最快 / 平均)”。 + > + > 4. Step-back Prompting(回溯提示) + > + > 先生成 “比原始问题更宏观的上位问题”,再基于上位逻辑回推检索方向,解决原始问题因聚焦细节导致的理解偏差。 + > + > - 用户原始问题为 “为什么 2024 年某国产新能源汽车品牌的销量突然下降?”,第一步生成宏观上位问题:“影响新能源汽车品牌短期销量波动的核心因素有哪些?”(如产品迭代、竞品动作、政策变化、市场需求等); + > - 第二步基于上位问题逻辑,生成具体检索方向:“2024 年某国产新能源品牌 产品更新情况”“2024 年新能源汽车市场 竞品定价策略”“2024 年新能源汽车补贴政策调整”。 + +在检索后,重点是把“取回来的内容”治理好: + +- 使用专门的 Rerank 模型或 LLM 对候选文档进行重新排序,确保最关键、最贴近问题的内容优先进入上下文。 + > Rerank 模型是信息检索流程中的关键组件,主要用于对 “召回阶段” 初步筛选出的候选结果进行二次排序 —— 它会借助更复杂的语义理解能力(常基于 Transformer 等深度学习架构),分析用户需求与候选结果的深层关联,修正初步排序中可能存在的语义偏差,最终让更贴合用户需求的结果排在更靠前的位置,提升用户获取有效信息的效率。 +- 对检索结果进行筛选、去重与压缩,去掉明显无关或高度重复的片段,缓解长上下文中部信息被忽略的问题。 +- 在必要时,结合轻量的模型微调,使 LLM 更倾向于依据检索证据作答,并在回答中附带引用或出处信息。 + +总体来看,第二代检索增强生成技术其关注点不再局限于 “是否需要检索”“能否检索到信息” 这两个基础问题,而是进一步聚焦于三个更大的挑战:“能否精准定位到真正关键的段落内容”“传递给大模型的上下文是否简洁有序、具备清晰结构且易于高效利用”“当面临信息噪音、内容冲突或多资料源查找需求时,系统整体性能是否依然稳健可靠”。 + +从大量实验验证与工程落地实践来看,Advanced RAG 在问答准确率、幻觉抑制能力、系统鲁棒性及结果可解释性等关键指标上,均显著优于 Naive RAG。也正因此,Advanced RAG 已逐步取代传统方案,成为当前工业界构建 RAG 系统的主流技术范式。 + +## 4.3 第三代 RAG:Modular RAG + +在企业级的复杂应用场景中,需求往往跨越多个领域。在这种情况下,RAG系统若仅采用检索、重排、生成这样的单一线性处理方式,常常难以应对: + +1. 同一系统既要支持简单 FAQ,又要生成长篇报告、进行代码检索或调用数据库。 +2. 需要同时接入向量库、全文检索、关系数据库、知识图谱以及外部搜索引擎等多种数据源。 +3. 需要在多轮交互中保持对用户偏好、历史决策的记忆,并对输出结果实施合规审核和溯源。 + +在这样的背景下,RAG 的系统形态开始向模块化演进。Modular RAG 不再被看作一条固定的流水线,而是由一组可插拔、可替换、可组合的功能模块组成,通过编排逻辑按需组合执行。典型模块包括: + +1. 查询理解与路由模块 + 用于意图识别、问题重写、子任务拆解和路径选择,决定一条请求是主要依赖内部知识,还是外部检索,抑或需要调用特定工具或数据库。 + 例如,用户问「这条错误日志代表什么问题?」系统会将其路由到代码与日志知识库;而问「最近该行业的监管新规有哪些变化?」则更适合走互联网搜索或合规法规库。 +2. 多源检索与融合模块 + 同时连接向量数据库、全文检索系统、结构化数据库与知识图谱,对不同数据源进行查询,并将结果进行统一的融合与排序。 + 例如,在做「客户年度分析报告」时,一部分信息来自 CRM 数据库(如客户成交额),一部分来自文档库(如项目复盘),还可能需要从知识图谱中补充行业关系,最终由该模块将多源结果合并成一份有序的证据集。 +3. 记忆与个性化模块 + 维护长期用户画像、短期会话记忆和领域知识缓存,使系统能够在长期交互中不断积累和利用历史信息。 + 比如,系统记住某位用户偏好「先给结论再给细节」,以及他所在的业务线与常用术语,下次回答时会自动采用对应风格,并优先使用与该业务线相关的案例和数据。 +4. 任务适配与治理模块 + 面向不同任务加载对应的适配器,对输出格式、语气、风格进行约束,并结合事实核查、风险过滤和引用对齐等机制,对生成结果进行治理。 + 例如,同样是基于同一批检索结果,为产品经理生成的是结构化 PRD 模板,为法务人员则是正式合规审查意见;在此过程中,该模块会对关键事实进行二次核查,并强制要求给出引用来源。 + +总的来说,传统 RAG 往往是一轮检索配合一轮生成就结束,而 Modular RAG 则打破了这种单一流程。当系统在生成过程中发现信息不足时,可以主动触发新的检索轮次,甚至多次往返检索与生成,以完成更复杂的任务。 + +进一步地,模型还可以学习自我决策:对于把握较大的问题直接基于内部知识或短上下文作答;遇到不确定的情况时才发起检索或调用外部工具,从而在保证质量的前提下提高效率、节约资源。对于那些表达不清、信息缺失严重的查询,系统甚至可以先由大模型生成一个假设性的答案或中间文档,再以此作为“线索”去检索真实文档,不断逼近可靠信息源。 + +在这一阶段,RAG 已经不再只是给大模型补几段参考资料的简单组件,而逐步演变为企业级智能应用的中枢式知识编排层,负责在多数据源、多工具、多任务之间进行协调与调度。 + +5. # 从 Demo 到企业级的 RAG 系统 + +从企业工程实践的角度来看,RAG 系统的构建不能仅局限于检索增强生成技术本身,前面提到的内容更多是一个 Demo 级别的介绍。由于实际业务场景中的数据往往存在质量参差不齐、格式混乱等问题,因此需要在数据预处理、清洗及导入环节投入更多精力,同时在各个关键节点做好模型选型。 + +一个完整的企业级 RAG 系统通常可以划分为三个核心模块:版面分析与知识采集、知识库构建、以及基于 RAG 的知识问答服务。在整个技术链路中,涉及多个关键模型的选型决策,包括 Embedding 模型、Rerank 模型和 LLM 模型。只有在每个环节都做出合理的技术选型,才能确保系统达成最佳效果。 + +1. 版面分析与本地知识文件读取 + +这一模块负责将各种格式的本地知识资产转换为可用于检索的文本。输入可能包括 PDF、TXT、HTML、Word、Excel、PPT 等文档,也包括 PNG、JPG 等图片类扫描文件,甚至是语音录音。 + +系统需要针对不同格式做解析,对文本文档做版面分析与结构抽取,区分标题、正文、表格、页眉页脚等元素,恢复合理的阅读顺序。对图片类文件进行 OCR 识别,对语音进行语音转写(ASR),最终统一转换为较为干净的知识文本,并尽量保留一些基础元信息,如文档名、章节、页码、时间等,为后续切分和索引打下基础。 + +2. 知识库构建(切分、Embedding、索引) + +在拿到清洗后的知识文本后,需要先进行合理的文本切分(Chunking),把长文档拆成若干语义相对完整、长度适中的文本块,通常按段落、标题结构或滑动窗口切分,同时保留每个块对应的文档来源和元数据。 + +随后,使用选定的 Embedding 模型,如 text-embedding-3-small、Sentence Transformers、BGE 等,对每个文本块计算向量表示,并基于这些向量构建向量索引,如使用 Faiss、Milvus、向量搜索服务等,就得到一个可按语义相似度进行快速查询的知识库。至此,我们完成了知识转换为可检索向量的核心步骤。 + +3. 基于 RAG 的知识问答(召回、排序、拼接、生成) + +在在线问答阶段,用户首先发出查询请求,系统会对查询进行 Embedding,得到查询向量,并在向量索引中检索出一批最相似的文本块(Top N),这是粗排阶段。在此基础上,可以选用 Rerank 模型,如 BGE Reranker 或 LLM 充当 Reranker,对查询与文档对进行精排打分,从中选出 Top K 个真正最相关的文档作为知识上下文。 + +接着,结合精心设计的系统提示词如"请严格基于以下资料回答"等等,将用户查询和检索出的文档片段进行拼接,把这个合并后的提示发给 LLM,由它在检索得到的证据基础上生成最终答案,并在需要时附上引用或出处。 + +## 5.1 模型选型 + +接下来我们关注各环节的模型选型,一个完整的 RAG 系统通常涉及三类核心模型:即 Embedding 模型、Rerank 模型和大语言模型。这三类模型各司其职,共同构成了从知识检索到答案生成的完整流程。其中,Embedding 模型负责将文本转化为可检索的语义向量,Rerank 模型对初步检索结果进行精细筛选与重排序,大语言模型则基于筛选后的知识上下文生成最终答案。 + +### 5.1.1 Embedding model + +在 RAG 系统中,Embedding 模型的作用是将文本,如用户查询和知识库内容,转换为高维向量。语义相近的文本,其向量在空间中的位置也更接近,这使得系统能够通过向量相似度快速定位相关知识。因此,选择合适的 Embedding 模型是构建高性能 RAG 系统的关键一步,直接决定了召回阶段的质量。 + +为了选出好的模型,我们在这里介绍一个系统化的评价基准:MTEB(大规模文本嵌入评测基准) + +MTEB为各类Embedding模型提供了一个统一、客观的评估框架。它通过8大类任务、56个数据集,全面评测模型在检索、聚类、分类、重排序、文本匹配、语义相似度等多种场景下的表现。模型在MTEB上的整体得分,能够反映其向量表示能力的通用性和稳健性,可作为选型的重要数据参考。最新排名和详细结果可通过 [HuggingFace MTEB Leaderboard](https://huggingface.co/spaces/mteb/leaderboard) 查看。 + +![](images/image5.png) + +尽管榜单上存在大量模型,你可以根据实际需求进行选择,并不需要掌握所有的模型(一般来说,选择大模型厂商自带的 Embedding 模型,或者使用云服务平台部署对外使用的模型就大概率不会错,因为这个是大多人检验后的标准),你还可以在侧边栏中选择具体的类别或者语言进行筛选: + +![](images/image6.png) + +此外,在筛选 Embedding 模型时,需重点关注直接影响 RAG 性能的两个核心参数:维度和上下文长度。其中,维度是指模型输出向量的维度数(如 128 维、768 维),它本质上反映了描述语义信息时所使用的“特征数量”。维度越高,向量能刻画的语义细节越丰富、区分度越强,例如一个 768 维的向量可以从品种、口感、产地等数百个角度精细表征“苹果”,从而更适用于医疗、法律等需要精准检索的专业场景;维度越低,则计算与存储成本越小、检索速度越快,适合千万级文档等高并发、强实时性要求的通用场景。 + +另一个参数Context Length(上下文长度) ,指 Embedding 模型单次可处理的最大文本长度(以 token 为单位,1 英文 token 约 0.75 个单词、1 中文 token 约 1 个汉字),超出部分会被截断:它直接决定模型能否完整理解文本,若长度不足导致信息丢失,会大幅降低检索准确性。因此处理用户短句、问答对这类短文本时,选 512-1024token 的模型即可;处理论文、报告等长文本时,需选 2048token 及以上的模型以避免关键信息丢失。 + +以下是几种常见Embedding模型的横向对比,你需要在实际调用过程中综合成本、性能进行选择最佳模型,没有最好的模型,只有对比多个模型的效果选出最合适的模型。 + +| 模型名称 | 模型规模 | 核心优势 | 适用场景 | +| ----------------------------- | -------------------------------- | ---------------------------------------------- | ----------------------------------------------------------- | +| OpenAI text-embedding-3-large | 闭源API | MTEB测试集上长期领先,成熟稳定 | 追求极致性能且预算充足的云端API场景,适合对延迟不敏感的应用 | +| jina-embeddings-v2 | 支持长文本(最高8K上下文) | 异步编码设计,处理长文档检索时强有力 | 需要长上下文理解的文档分析、法律合规、学术文献检索 | +| multilingual-e5-large | Large规模 | 经典的多语言备选方案 | 跨语言RAG、国际化产品、多语种客服系统 | +| Qwen/Qwen2-Embedding-8B | 8B参数,支持最高4096维自定义 | 曾MTEB多语言榜第一,长文本、多语言与代码能力强 | 高精度中英文RAG、长文档分析、代码检索 | +| Qwen/Qwen2-Embedding-4B | 4B参数 | 性能与效率平衡 | 大规模生产级RAG系统,性价比高 | +| Qwen/Qwen2-Embedding-0.6B | 0.6B | 适用于边缘端 | 资源不够的场景,需要速度优先的场景 | +| BAAI/bge-m3 | 支持混合检索(密集+稀疏+多向量) | 在MIRACL等跨语言基准领先 | 需要混合检索策略的复杂多语言场景 | +| BAAI/bge-large-zh-v1.5 | Large规模 | 中文RAG的稳定基线,社区验证充分 | 纯中文且文档较短、追求稳定性的项目 | +| 智谱AI Embedding-3 | 闭源云端API | 支持自定义维度(256-2048维) | 注重中文且偏好云端API服务的应用 | + +### 5.1.2 Rerank model + +在 RAG 系统中,Rerank 模型的作用是对初步检索结果进行精细化重排序。它接收用户查询和候选文档作为输入,为每对(查询-文档)计算精确的相关性分数,分数越高表示文档与查询的匹配度越好。因此,在 Embedding 召回的基础上引入 Rerank 模型,是提升 RAG 系统检索精度的关键一步。 + +在选择 Embedding 模型时,我们可以用 MTEB 这样的 benchmark。而对于 Rerank 模型我们可以参考 Agentset 的 [Reranker Leaderboard](https://agentset.ai/rerankers),该网站针对 RAG 场景下的重排能力做了系统测试。 + +| Model Name↑ | ELO | nDCG@10 | Latency (ms) | Price / 1M | License | +| ------------------------------------------------------------------------------------------------------ | ---- | ------- | ------------ | ---------- | ------------ | +| [BAAI/BGE Reranker v2 M3](https://agentset.ai/rerankers/baaibge-reranker-v2-m3) | 1314 | 0.201 | 2383 | $0.02 | Apache 2.0 | +| [Cohere Rerank 3.5](https://agentset.ai/rerankers/cohere-rerank-35) | 1452 | 0.2 | 392 | $0.05 | Proprietary | +| [Cohere Rerank 4 Fast](https://agentset.ai/rerankers/cohere-rerank-4-fast) | 1506 | 0.216 | 447 | $0.05 | Proprietary | +| [Cohere Rerank 4 Pro](https://agentset.ai/rerankers/cohere-rerank-4-pro) | 1627 | 0.219 | 614 | $0.05 | Proprietary | +| [Contextual AI Rerank v2 Instruct](https://agentset.ai/rerankers/contextual-ai-rerank-v2-instruct) | 1461 | 0.23 | 3333 | $0.05 | cc-by-nc-4.0 | +| [Jina Reranker v2 Base Multilingual](https://agentset.ai/rerankers/jina-reranker-v2-base-multilingual) | 1306 | 0.193 | 746 | $0.05 | cc-by-nc-4.0 | +| [Voyage AI Rerank 2.5](https://agentset.ai/rerankers/voyage-ai-rerank-25) | 1547 | 0.235 | 613 | $0.05 | Proprietary | +| [Voyage AI Rerank 2.5 Lite](https://agentset.ai/rerankers/voyage-ai-rerank-25-lite) | 1528 | 0.226 | 616 | $0.02 | Proprietary | +| [Zerank 1](https://agentset.ai/rerankers/zerank-1) | 1574 | 0.192 | 266 | $0.03 | cc-by-nc-4.0 | +| [Zerank 1 Small](https://agentset.ai/rerankers/zerank-1-small) | 1541 | 0.202 | 248 | $0.03 | Apache 2.0 | +| [Zerank 2](https://agentset.ai/rerankers/zerank-2) | 1644 | 0.195 | 265 | $0.03 | cc-by-nc-4.0 | + +在评估 Rerank 模型性能时,Agentset 基准测试采用以下流程:首先依据向量数据库 FAISS 从大规模文档库中检索出与查询最相关的前 50 个候选结果,随后由待评估的 Rerank 模型对这 50 个文档进行重新排序。评估过程同时关注排序质量和推理延迟两个关键维度。实际应用场景中,仅追求高精度而忽视响应速度将损害用户体验,而仅追求速度却牺牲排序质量则会导致结果实用性下降。 + +为进一步对比模型能力,Agentset 基准测试额外引入 ELO 评分机制:针对每次查询,会以 GPT-5 作为客观 “裁判”,对两个不同 Rerank 模型输出的排序结果展开成对比较,核心判定标准是哪个模型能将真正相关的文档排列得更合理、更靠前。经过海量查询的持续对比,获胜频率更高的模型将获得更高的 ELO 分数,从而直观体现模型综合性能差异。 + +在此基础上,基准测试还设计了两组互补性指标,用于对模型进行多维度综合评估: + +- nDCG@5/10:聚焦排序精准度,重点衡量相关文档是否被合理置于结果前列,直接反映 “排得准” 的能力; +- Recall@5/10:侧重结果覆盖面,核心评估系统能否识别出所有与查询相关的文档,对应 “找得全” 的能力。 + +这两组指标相辅相成,共同构建起对 Rerank 模型的完整评估体系,确保评估结果更具全面性与参考价值。 + +但在实际使用中,我们不一定需要仅是参考 LeaderBoard 进行模型选型,除去刷榜的因素,主要还是因为工业上的好用和分数高不一定是一回事,我们可以根据各个云服务厂商推荐的 Rerank 模型进行选择(比如大模型厂商的默认 Rerank API,或可以尝试 Qwen 对应的 Rerank 模型,在当前 2025 年的情况下作为多参数支持的 Rerank 模型效果尚可。) + +### 5.1.3 LLM + +经过Embedding模型的语义检索和Rerank模型的精准筛选后,相关文档片段会与用户的原始问题一同被整合进prompt,最终由LLM完成阅读理解、信息整合与自然语言生成,向用户输出连贯、准确且符合上下文的答案。 + +在实现层面,RAG 中的 LLM 使用方式主要分为两类: + +1. 私有化部署的大模型。适用于注重数据隐私、成本可控或需要深度定制的场景。当前主流开源LLM如Qwen系列、Llama系列、GLM系列等在RAG任务中表现优异。以Qwen2.5为例,7B或14B参数版本在保持较小资源占用的同时,展现出良好的指令遵循能力和中文理解能力,特别适合企业级RAG应用的本地化部署。KIMI、Minimax、DeepSeek等模型也在不同语言和领域展现出各自优势,可根据具体业务需求灵活选型。 +2. 作为云端API服务的大模型。适合追求快速上线、弹性扩展和持续模型迭代的场景。主流提供商如OpenAI(GPT-4系列)、Anthropic(Claude系列)、Google(Gemini系列)以及国内的阿里(通义千问)、智谱AI(GLM系列)等都提供稳定的API服务。这些模型普遍具备强大的语言理解和生成能力,能够高质量完成RAG场景下的答案合成任务。 + 在选择云端模型时,需要关注几个关键点:回答质量是否准确流畅、价格是否合理、响应速度是否够快、上下文窗口是否足够大(能放下检索到的多个文档)。实际使用时,可以先拿几个候选模型做对比测试,看看哪个回答得更准确完整。如果对成本敏感,可以用"大小模型搭配"的方式:简单问题用便宜的小模型,复杂问题才调用贵的大模型,这样既省钱又保证效果。另外,大模型更新很快,建议定期测试新模型,及时替换表现更好的版本。 + +对于大语言模型在对话和问答场景下的综合能力评估,[LMSYS Chatbot Arena (LMArena) ](https://lmarena.ai/)提供了业界认可的黄金评测基准。该平台采用创新的"盲测对战"机制——人类评估者在不知晓模型身份的情况下,对两个匿名模型针对同一提示的回复进行质量比较,通过大量这样的两两对比为各模型排名。 + +以下是竞技场排名的示例(截止至 2025 年 12 月 15 日) + +| Rank | Model | Score | Votes | Organization | License | +| ---- | ------------------------------------------------------------------------------------------- | ----- | ------ | ------------ | ----------- | +| 1 | [gemini-3-pro](http://aistudio.google.com/app/prompts/new_chat?model=gemini-3-pro-preview) | 1492 | 15,871 | Google | Proprietary | +| 2 | [grok-4.1-thinking](https://x.ai/news/grok-4-1) | 1478 | 16,660 | xAI | Proprietary | +| 3 | [claude-opus-4-5-20251101-thinking-32k](https://www.anthropic.com/news/claude-opus-4-5) | 1470 | 9,879 | Anthropic | Proprietary | +| 4 | [claude-opus-4-5-20251101](https://www.anthropic.com/news/claude-opus-4-5) | 1467 | 10,659 | Anthropic | Proprietary | +| 5 | [grok-4.1](https://x.ai/news/grok-4-1) | 1465 | 16,501 | xAI | Proprietary | +| 6 | [gpt-5.1-high](https://openai.com/index/gpt-5-1/) | 1457 | 13,953 | OpenAI | Proprietary | +| 7 | [gemini-2.5-pro](http://aistudio.google.com/app/prompts/new_chat?model=gemini-2.5-pro) | 1451 | 76,975 | Google | Proprietary | +| 8 | [claude-sonnet-4-5-20250929-thinking-32k](https://www.anthropic.com/news/claude-sonnet-4-5) | 1450 | 28,019 | Anthropic | Proprietary | +| 9 | [claude-opus-4-1-20250805-thinking-16k](https://www.anthropic.com/news/claude-opus-4-1) | 1448 | 43,836 | Anthropic | Proprietary | +| 10 | [claude-sonnet-4-5-20250929](https://www.anthropic.com/news/claude-sonnet-4-5) | 1445 | 23,185 | Anthropic | Proprietary | + +LMArena的独特价值在于其评估方式更贴近真实用户体验,而非单纯依赖自动化指标。排行榜不仅展示整体排名,还细分为不同能力维度(如推理能力、创造能力、多语言支持等),帮助开发者根据实际应用场景选择最适合的模型。截至2025年,该平台已累计超过100万次人类评估,涵盖50+主流开源与闭源模型,成为LLM选型的重要参考。 + +访问LMArena官网可查看实时排行榜、详细能力分析和模型间的直接对比数据。但在实际选型中,建议将LMArena排名作为初步筛选依据,再结合企业特定数据进行A/B测试。特别是在专业领域(如医疗、法律、金融),通用榜单排名与实际表现可能存在较大差异,针对性测试尤为重要。 + +对于 LLM 选型的最佳实践是构建一个小型但代表性的测试集,包含20-30个典型业务问题,对候选模型进行端到端的RAG流程评估,而非仅评估LLM单点性能,比如使用推理模型还是非推理模型,使用什么参数的模型能平衡 RAG 效果和速度;这些都需要在实际的使用过程中测试得到最佳结论。 + +## 5.2 运行框架 + +在实际工程实践中,通常不需要从零开始构建整个 RAG 系统。目前业界已有多个成熟的开源框架可供选择,它们在架构设计、模块集成和开发效率等方面各有特色。企业可以根据自身的技术储备和业务场景,选择合适的框架快速搭建系统。常见的框架类型包括: + +**低代码** **/可视化平台** + +- [Dify](https://dify.ai):提供直观的可视化界面,支持快速搭建 RAG 应用,适合非技术团队或快速原型验证场景。内置多模型接入、工作流编排和 prompt 管理功能。 +- [Coze](https://www.coze.com/):字节跳动推出的 AI Bot 开发平台,提供零代码的可视化搭建能力。特色在于与豆包等字节系大模型深度集成,支持插件市场、定时任务和多渠道发布(飞书、微信等),适合快速构建面向 C 端用户的对话应用或企业内部智能助手。 +- [n8n](https://n8n.io/):一个开源的、基于节点的工作流自动化平台。它通过可视化的方式连接各类应用、API和数据源。在RAG场景中,可以利用n8n编排复杂的业务逻辑,将数据预处理、向量数据库操作、大模型调用以及后续动作(如发送邮件、更新工单)串联成一个自动化流程。 +- [RAGFlow](https://ragflow.io/):专注于深度版面分析和知识抽取能力,对复杂文档(如多栏 PDF、表格密集型文档)的处理效果较好,适合文档结构复杂的企业知识库场景。 +- [FastGPT](https://fastgpt.io/en):中国国内开源方案,集成了知识库管理、对话流程编排和应用发布功能,中文文档完善,适合快速部署中文 RAG 应用。 + +**代码框架/开发库** + +以下介绍的软件通常都有不同平台(前后端)语言的实现方式,你可以根据当前应用的语言选择下列对应软件的语言版本(例如 Python 或 Java 版)。 + +- [LlamaIndex](https://www.llamaindex.ai/):专为 RAG 场景设计的 Python 框架,提供丰富的数据连接器(Connector)、索引结构和查询引擎,模块化程度高,适合需要深度定制检索策略或集成多种数据源的场景。 +- [LangChain](https://www.langchain.com/):通用 LLM 应用开发框架,RAG 只是其中一个应用方向。优势在于生态丰富、组件齐全,支持复杂的 Agent 和工作流编排,但学习曲线相对陡峭,适合构建复杂的多模块 LLM 应用。 + +如果团队技术储备有限、追求快速上线,可优先考虑 Dify 、Coze 或 FastGPT 等低代码平台;如果需要深度定制检索框架、对接特殊数据源或优化性能细节,LlamaIndex 和 LangChain 提供了更大的灵活性。实际项目中,也可以采用"混合方案":用低代码平台快速验证可行性,再用代码框架实现生产级部署和性能优化。此外,这些框架大多支持主流 Embedding、Rerank 和 LLM 模型的快速接入,可以基于前文提到的模型选型标准灵活组合最后使用的模型型号。 + +## 5.3 效果评测 + +企业在 RAG 系统落地过程中,最大的挑战往往不是构建而是调优,对大型企业来说。生产级的大型 RAG 系统需要可监测可量化评估效果。RAG 涉及检索和生成两个非确定性环节,传统的软件测试方法不再适用,建立科学的评测体系(RAG Evaluation)至关重要,我们需要了解如何对 RAG 的效果进行系统化的评估。 + +### 5.3.1 入门示例:基于 LLM 的 RAG 效果评测 + +为帮助大家快速建立对 RAG 效果评测的直观理解,本节将以一个基于 LLM 的 RAG 效果自动化评测流程为例进行说明。该方案核心是 “LLM-as-a-judge”,即利用大模型本身作为裁判,来量化评估 RAG 系统的输出质量 https://huggingface.co/learn/cookbook/rag_evaluation。 + +具体而言,该流程通常包含三个关键步骤: + +- 首先合成评测数据集,我们需要从知识库中采样文档,并指令 LLM 生成与之对应的、高质量的“问题-参考答案”对,再经过相关性、事实 groundedness 等过滤,形成基准测试集; +- 其次,运行 RAG 系统并收集答案,让待评估的系统处理测试集中的每个问题,得到其生成的答案; +- 最后,进行自动化判分,调用另一个作为“裁判”的 LLM,将系统生成的答案与参考答案进行对比,从准确性、完整性等维度给出量化评分。 + +可以用一个简单的例子展示其过程: + +1. 出题(合成评测集):我们有一份知识库,例如一段产品说明书:“本设备支持无线充电,电池容量为5000mAh。” 我们让一个大模型(如GPT-4)扮演“出题官”,根据这段文本自动生成一道测试题,例如:“这个设备的电池容量是多少?” 并记录标准答案:“5000mAh”。这就构成了一条评测数据。 +2. 答题(运行RAG系统):将这道题输入到待评测的 RAG 系统中。系统会从知识库检索相关信息,并生成一个答案。假设它回答:“该设备电池容量是5000mAh。” +3. 批改(LLM-as-a-Judge):我们请另一个大模型(如Claude 3)扮演“批改老师”。将“问题”、“RAG生成的答案”和“标准答案”一起交给它,并指令:“请判断生成的答案是否正确,只需输出‘正确’或‘错误’。” “批改老师”经过对比,输出:“正确”。 + +通过自动化批量测试,我们能够得到RAG系统的准确率等具体指标。这就形成了一个“评测、优化、再评测”的实用循环:先看数据找出问题,再调整检索方法或优化模型,然后重新测试验证效果。系统就在这样一次次的迭代中,实现持续改进和性能提升。 + +你已经知道了评测在 RAG 中意味着什么,接下来我们将聚焦 RAG 评测的核心组成部分:常见的评测指标(如检索阶段的 Recall@K、生成阶段的 Faithfulness)、主流评测框架(如 RAGAS、ARES)与基准数据集(如 WikiEval、MedRAG)。鉴于这些内容覆盖面广、细节庞杂,此处暂先进行概览性介绍,帮助你建立整体认知框架。 + +若你需要深入掌握具体细节(如指标的数学计算逻辑、框架的实操部署步骤、不同基准数据集的适用场景等),建议参考以下两篇 RAG 评测领域的论文: + +- [https://arxiv.org/pdf/2504.14891](https://arxiv.org/pdf/2504.14891)(《Retrieval Augmented Generation Evaluation in the Era of Large Language Models: A Comprehensive Survey》):系统梳理了 LLM 时代 RAG 的内外部评测方法,涵盖组件级与系统级评估,还汇总了海量评测数据集与框架,并分析了当前研究趋势与挑战。 +- [https://arxiv.org/pdf/2405.07437](https://arxiv.org/pdf/2405.07437)(《Evaluation of Retrieval-Augmented Generation: A Survey》):提出了统一的 RAG 评测流程(Auepora),从 “评测目标、数据集、指标” 三维度拆解评测逻辑,同时对比了不同基准的优劣,为实践提供了清晰指引。 + +### 5.3.2 评测指标 + +RAG系统的评估本质上围绕两个核心问题:检索模块能否准确找到相关资料,生成模块能否基于这些资料给出高质量回答。因此,评测体系相应分为检索效果评估、生成质量评估两大模块,并辅以LLM裁判进行综合评分。下面我们逐一展开。 + +#### 检索效果评估:召回准确性与排序质量 + +检索模块是RAG系统的第一道关口,其评估重点在于三个维度:找得准不准、找得全不全、排序好不好。 + +**基础召回质量指标** + +首先是一组衡量召回基本质量的经典指标:Recall@K、Precision@K和F1。 + +- **Recall@K** 衡量在前K条检索结果中,相关文档被找回的比例。比如知识库中有5篇相关文档,前10条结果找回了3篇,则Recall@10为60%。这个指标告诉我们检索的"覆盖面"如何。 +- **Precision** **@K** 衡量前K条结果中真正相关文档的占比。同样是前10条结果,如果其中有3篇相关、7篇不相关,则Precision@10为30%。这个指标反映检索的"准确度"。 +- **F1** 则是Recall和Precision的调和平均,在两者间寻求平衡。 + +这组指标适合快速发现召回阶段的基础问题,比如向量化模型是否有效、检索策略是否合理、Query改写是否到位等。如果Recall很低,说明相关文档根本没被找到;如果Precision很低,说明检索噪声太大。 + +**排序质量指标** + +找到相关文档只是第一步,更重要的是把最相关的文档排在前面。这就需要关注排序质量的指标:MRR、NDCG@K和MAP。 + +- **MRR** **(** **Mean Reciprocal Rank** **)** 计算第一个相关文档出现位置的倒数均值。如果第一个相关文档出现在第3位,该条查询的RR就是1/3。MRR适合那些只需要一个正确答案的场景,比如问答系统。 +- **NDCG@K(Normalized Discounted Cumulative Gain)** 考虑了相关性分级和位置衰减两个因素。它不仅关注文档是否相关,还关注相关程度;同时,越相关的文档排在越前面,得分越高。这使得NDCG成为衡量排序质量最全面的指标之一。 +- **MAP(Mean ** **Average Precision** **)** 综合考虑所有相关文档的位置,对整体排序质量更为敏感。 + +在实际工程中,我们通常采用 Recall@K + MRR@K 的组合,既保证召回覆盖面又约束排序质量。举个例子,如果发现Recall@10达到80%但MRR@10只有0.3,说明相关文档虽然被找到了但都埋在后面,这时就需要优化重排序策略,比如引入交叉编码器或调整多路召回的权重分配。 + +必要时,还可以补充 Coverage 指标来监控知识库覆盖情况,发现系统性的召回盲区。比如某类专业术语相关的问题始终召回效果不佳,就要考虑是否需要针对性地优化该领域的文档切分或向量化方式。 + +#### 生成质量评估:准确性与事实忠实度 + +检索为生成提供了"原材料",接下来要评估的是:基于这些材料,生成模块能否给出高质量的答案?生成质量评估的核心维度有两个:答案是否准确,是否忠于检索到的证据。 + +**精确匹配与文本相似度** + +最直接的评估方式是 **EM(Exact Match)** ,要求生成答案与参考答案完全一致。这个指标适合答案唯一、形式固定的场景,比如"成立日期是什么时候?""总部在哪里?"这类事实性问答。但EM过于严格,同样正确的"2020年1月1日"和"2020-01-01"会被判为不匹配。 + +因此,更常用的是基于n-gram重叠的相似度指标: **ROUGE** **、** **BLEU** **、METEOR** 。它们通过计算生成内容与参考答案的词汇重叠程度来打分。其中,ROUGE-L关注最长公共子序列,对答案的流畅性更敏感;BLEU源自机器翻译领域,注重精确匹配;METEOR则加入了同义词和词干的考量。这些指标的优势是计算简单、易于理解,但也有明显局限——它们只看表面词汇匹配,对语义理解不够深入。 + +为了弥补这一不足,我们可以引入 **BertScore** 或直接的 **向量相似度** 。它们利用预训练模型的向量表示来计算语义相似度,更能容忍表述差异。比如"这款产品很受欢迎"和"该设备广受好评"在词汇上几乎没有重叠,但向量相似度会很高。这对于需要改写、总结、解释的生成任务特别有效。 + +**事实忠实度与幻觉检测** + +对于RAG系统而言,仅仅评估答案与参考标准的相似度还不够,更关键的问题是:生成的答案是否基于检索到的文档,有没有"无中生有"的幻觉? + +这就需要专门的 Hallucination(幻觉率) 和 Faithfulness(忠实度) 指标。具体做法是让另一个LLM扮演"事实核查员",逐句检查生成答案,判断每句话是否能在检索文档中找到依据。比如,检索文档说"产品重量为500克",但生成答案写"该产品轻巧便携,仅重300克",这就是一个典型的幻觉。通过统计有依据的语句占比,我们可以量化系统的忠实度。 + +这个指标对监控事实性错误至关重要,特别是在医疗、法律、金融等对准确性要求极高的领域。实践中,许多企业会设置幻觉率阈值作为上线标准,比如要求准确度必须达到95%以上。 + +#### LLM裁判:多维度综合评分 + +前面介绍的指标各有侧重,但都存在一定局限性:自动化指标往往只看表面特征,难以把握语义深层含义和整体质量。这时,**LLM-as-a-Judge** 机制就显得尤为重要。 + +具体做法是:将问题、检索文档、系统回答、参考答案一并输入一个独立的大模型(通常选择能力较强的模型如GPT-4或Claude),让它按多个维度进行综合评分: + +- **问题相关性** :答案是否真正回应了用户问题,有没有答非所问? +- **信息完整性** :该涵盖的要点是否都说到了,有没有遗漏关键信息? +- **事实忠实性** :答案是否出现了检索文档中不存在的内容,有没有幻觉? +- **整体正确性** :与参考答案相比,生成答案的质量如何? + +LLM裁判的优势在于能进行更接近人类的整体性判断——它可以理解上下文、把握语义、识别逻辑,甚至能发现一些自动化指标捕捉不到的细微问题,比如语气不当、逻辑矛盾、表述含糊等。当然,裁判本身也需要精心设计prompt,并用人工标注样本进行校准,确保评分标准的一致性和可靠性。 + +#### 构建实用的评测组合 + +面对如此多的评测指标,企业在落地时往往会感到困惑:该选哪些指标?如何组合使用? + +一个务实的建议是 **从精简组合开始,逐步完善** : + +- **检索评估** :采用 Recall@K + MRR@K 的核心组合,快速把握召回覆盖和排序质量 +- **生成评估** :根据任务特点,从 EM、ROUGE-L、BertScore 中选择一到两个作为基线 +- **综合评估** :引入 LLM裁判,重点关注相关性、完整性、忠实性三个维度 + +在此基础上,采用"评测→发现问题→调整策略→再评测"的循环迭代。比如,发现召回率不错但MRR很低,就重点优化重排序;发现幻觉率偏高,就加强对检索文档的忠实度约束;发现某些类型的问题回答质量不好,就针对性地补充细分指标。 + +这种渐进式构建方式既能让团队快速起步,建立对系统效果的基本认知,又能随着理解的深入逐步完善评估体系,最终形成一套适合自己业务场景的评测方案。 + +### 5.3.3 评测框架 + +随着RAG技术的快速发展,学术界和工业界涌现出了大量优秀的评测框架,它们不仅封装了常用的评测指标,还提供了标准化的数据集、基准测试和端到端的评估流程。本节将系统梳理当前主流的RAG评测框架,帮助你快速选择适合自己场景的评测工具。 + +#### **评测框架的分类体系** + +根据评测目标和使用场景,我们可以将RAG评测框架分为三大类:研究型框架、基准测试框架和工具型框架。 + +**研究型框架**主要服务于学术研究和前沿探索,特点是评测维度细致、方法创新性强。代表性的如FiD-Light和Diversity Reranker,它们专注于检索阶段的细粒度评估,前者关注召回的延迟性(Latency),后者强调结果的多样性(Diversity)。这类框架通常会深入到RAG系统的某个特定环节,提供精细化的诊断能力。 + +**基准测试\*\***框架\*\*则提供了标准化的测试集和评测流程,用于横向比较不同RAG系统的性能。这类框架数量最多、影响最广。例如: + +- **RAGAS** (2023.09)是最早的综合性RAG评测框架之一,采用LLM-as-a-Judge模式,同时评估检索和生成两个环节 +- **ARES** (2023.11)引入了分类器辅助的评测方法,结合LLM判断和传统分类器来评估Context相关性和Answer相关性 +- **RGB** (2023.12)专注于生成阶段的评估,提出了信息整合(Info Integration)、噪声鲁棒性(NoiseRobust)、负样本拒绝(NegRejection)、反事实鲁棒性(Counterfact)等细分维度 +- **MultiHop-RAG** (2024.01)针对多跳推理场景,重点评估检索的相关性(Retrieval C)和回答的正确性(Response C),使用MAP、MRR、Hit@K等指标 +- **CRUD-RAG** (2024.02)模拟真实的知识管理场景,评估系统在Create、Read、Update、Delete四种操作下的表现,引入了RAGQuerEval评分体系 + +进入2024年后,评测框架呈现出明显的专业化和细分化趋势。医疗领域有MedRAG,法律领域有LegalBench-RAG,金融领域有相关的domain-specific框架。这些领域框架不仅提供了专业数据集,还针对行业特点设计了定制化的评测指标,比如医疗场景特别关注准确性(Accuracy),法律场景强调文档级精确度(Doc-level Precision)和引用相关性(Citation Relevance)。 + +**工具型框架**则侧重于工程实践,提供了易用的评测工具和集成方案。TruEra RAG Triad、LangChain Benchmarks、RECALL等都属于这一类。它们通常与主流的RAG开发框架深度集成,支持快速接入现有系统,有些还提供了可视化的评测报告和监控面板。 + +上述我们介绍了多种不同的 RAG 评测框架,但在具体实战中该如何选择?不妨先选取 GitHub 星标数量较多的几款进行初步测试;而当企业面临丰富的框架选择、需要落地决策时,可从以下几方面着手。 + +- 快速上手需求:若需快速搭建基线评测,可选择 RAGAS、RAGEval 等综合性框架,它们能提供开箱即用的完整流程,若需深入诊断某一环节问题,则需选用针对性框架 :例如检索效果不佳时可用 MultiHop-RAG,幻觉问题突出时则可采用 CoURAGE 或 RAG Unfairness。 +- 结合行业进行选择:若应用于医疗、法律、金融等专业领域,应优先选择适配该领域的框架,这类框架往往内置专业术语处理、合规性检查等关键能力,通用框架虽功能全面,但在专业场景中易出现 “水土不服” 的情况。 +- 根据集成成本选择:像 LangChain Benchmarks、TruEra RAG Triad 等框架已与主流开发框架深度集成,能快速接入现有系统,而部分学术框架虽技术方法先进,却需额外投入工程适配工作;最后需关注持续维护情况,应优先选择社区活跃、文档完善且持续更新的框架,避开已停止维护的项目,具体可参考 GitHub 星标数量、更新频率、Issue 响应速度等指标。 + +除此之外,在社区中还公认推荐了一批工具,部分框架已在上述内容中提到:Ragas 提供了丰富指标且不绑定特定框架;Continuous Eval 以轻量和低成本为特点,支持构建具备数学保证的评估流水线;TruLens‑Eval 与 LangChain、Llama‑Index 等主流框架集成良好,并提供可视化分析;而 Llama‑Index 自身生态中也集成了评估与合成数据生成功能,便于对其构建的应用进行闭环测试。还有 Phoenix、DeepEval、LangSmith 和 OpenAI Evals 等工具也在持续迭代中,你可综合自身需求和对应工具的口碑进一步选用。 + +### 5.3.4 评测基准 + +评测基准的重要性在实践中常常被低估。许多团队在搭建RAG系统时,往往仅依靠少量人工编写的测试问题便匆忙开始评估,导致上线后的实际效果与测试阶段的表现差距显著。这一问题的根源在于,缺乏具有代表性和系统性的评测数据,难以真实反映复杂多变的业务场景。 + +一个能够有效支撑系统迭代的评测基准,通常具备三个核心特征。首先是代表性,测试数据需要全面覆盖真实业务中的各种场景,包括高频常见问题、复杂边界情况以及异常输入等;其次是标准化,问题和答案的格式、难度系数、评分标准需要统一规范,确保评测结果具有可比性和可重复性;最后是可演化性,基准应能随着系统能力提升和业务需求变化而持续更新,避免因固化的“应试”数据导致评测失真。 + +对于大多数企业而言,由于业务场景存在独特性,最终往往需要构建自己的评测数据集。 + +- 构建过程可以从业务日志中提取真实用户问题入手,并依据类型、频率和难度进行分层采样,以保证数据的代表性。对于简单问题可由领域专家直接标注,复杂问题则可先用高质量LLM生成候选答案,再由专家审核修改,这种"机器生成+人工校准"的方式能显著降低标注成本。 +- 除答案本身,标注相关文档、答案类型、难度等级等元信息,为后续细分析提供支持。建立标注规范,进行多人交叉验证,计算标注一致性(如Kappa系数),确保数据质量。 +- 定期从线上反馈中补充新的测试用例,尤其是系统回答不好的问题,让评测数据与系统能力同步演进。这种持续迭代的机制能让评测基准始终保持对业务场景的敏感度和有效性。 + +当然,如果团队资源有限或希望快速建立基线,参考业界成熟的公开评测基准也是一个可行的起点。截至2025年,已有诸多涵盖通用领域和垂直行业的基准可供选择(见图表)。 + +![](images/image7.png) + +在选择时,应首先明确评测目的:是建立能力基线,还是为上线做最终验证?其次,需评估基准数据是否覆盖了所关心的场景、问题类型和难度。对于新闻、金融等时效性强的场景,必须考察基准是否包含实时数据测试;而对于历史知识处理,静态基准可能已足够。最后,还需权衡标注成本,是直接采用已完整标注的基准,还是使用原始数据自行标注。 + +将自建数据与公开基准结合使用,既能确保评测贴近业务实际,又能借助公共标准进行横向比对,是构建稳健评测体系的务实路径。 + +6. # 深度研究:从比赛与开源教程中学习(Optional) + +前面介绍的RAG系统原理和基础实现,虽然能帮助你快速搭建起一个可用的原型,但距离真正解决生产环境中的复杂问题还有不小的距离。如果你想深入理解更落地、更有实战价值的RAG技术,参考各大比赛的获奖方案和优质开源教程是最高效的学习路径,这些方案往往集中了优秀团队在真实场景下反复尝试后的最佳实践。 + +但需要强调的是,本节列举的案例并非全部,而是挑选了几个有代表性的方案。当你在实践中遇到特定问题时,建议采用这样的学习策略:先根据问题类型(如"PDF解析"、"多模态检索"、"低延迟优化"等关键词)查找相关竞赛,再深入研究获奖队伍的技术报告或开源代码,往往能找到直接可用的解决思路。 + +## 6.1 语义缓存:优化高频查询场景 + +Hugging Face提供了一个基于Chroma向量数据库的语义缓存实现方案,该教程的地址为: + +[https://huggingface.co/learn/cookbook/semantic_cache_chroma_vector_database](https://huggingface.co/learn/cookbook/semantic_cache_chroma_vector_database) + +![](images/image8.png) + +背景:大多数教程搭建的RAG系统只适合单用户测试,当系统部署到生产环境后,面对几十到几千次的重复查询(比如客服场景中用户反复询问"如何退款"),每次都要执行向量数据库检索和LLM调用,响应时间会明显增加,成本也会快速上升。通过引入语义缓存层,可以在保证答案质量的前提下,大幅减少对原始数据源的访问压力。 + +该方案采用了双层检索架构。基础层使用Chroma向量数据库存储原始知识库(以MedQuad医疗问答数据集为例),为每条数据添加唯一ID方便精确引用。缓存层则基于FAISS构建,选择FlatL2索引来处理小数据集和高维向量。语义缓存被放在用户查询与Chroma之间,而不是缓存LLM的最终回答——这个设计很重要,因为直接缓存回答会导致用户的个性化要求(如"用简单语言解释")失效。 + +缓存系统使用SentenceTransformer的all-mpnet-base-v2模型生成查询向量,通过欧氏距离(设定阈值为0.35)来判断查询是否相似。当缓存满了(max_response参数控制容量)时,采用先进先出策略删除最早的条目。为了支持跨会话使用,缓存数据会保存到JSON文件中。 + +在小规模测试中,首次查询"How do vaccines work?"从Chroma获取结果耗时0.057秒,而相似查询"Briefly explain me what is a Sydenham chorea."从缓存获取仅需0.016秒,检索时间减半。在大规模生产环境中,这个方案可以实现90%-95%的性能优化,有效降低了向量数据库的访问压力和API调用成本。 + +## 6.2 非结构化数据处理:统一多格式文档解析 + +Hugging Face的另一个教程展示了如何使用Unstructured库构建完整的非结构化数据处理流程,教程地址为: + +[https://huggingface.co/learn/cookbook/rag_with_unstructured_data](https://huggingface.co/learn/cookbook/rag_with_unstructured_data) + +![](images/image9.png) + +背景:企业场景中的知识往往分散在PDF、PowerPoint、EPUB、HTML等多种格式中,传统的数据预处理方法要么只能处理单一格式(比如只支持PDF),要么在格式转换过程中丢失关键信息(特别是表格、标题层级等结构化内容),导致RAG系统无法准确理解和检索这些信息。 + +该方案首先下载多格式测试文档作为示例,包括加拿大环境部农药手册PDF(包含大量表格数据)、佛罗里达大学柑橘IPM PowerPoint(包含图表和多层级标题)等真实文档。然后使用Unstructured库的Local Runner完成解析。配置分为三个部分:ProcessorConfig指定输出目录和并行进程数(2个进程),PartitionConfig可选择API分区模式(需要Unstructured密钥,OCR效果更好,特别适合扫描版PDF),SimpleLocalConfig定义文档输入路径。解析后的文档会转换为JSON格式,包含正文、标题、表格等元素类型。 + +系统使用chunk_by_title方法进行分块,设置最大字符数为512,并将200字符以下的连续片段合并以保持语义完整性。在转换为LangChain Document格式时,会过滤掉复杂的元数据字段以适配Chroma向量数据库。向量化阶段采用BAAI/bge-base-en-v1.5嵌入模型,结合4bit量化的Llama-3-8B-Instruct模型和LangChain的RetrievalQA链构建完整的RAG系统。 + +系统能够准确处理多格式文档。测试"Are aphids a pest?"等问题时,可以从解析后的文档中提取蚜虫危害、吸引蚂蚁等关键信息,生成符合需求的回答。这个方案成功实现了从非结构化数据到RAG可用数据的完整转化,特别适合需要处理多种文档格式的企业知识库场景。 + +## 6.3 企业级文档问答:高精准可追溯的RAG实现 + +Enterprise RAG Challenge的冠军方案展示了如何在严格的时间和精度要求下构建生产级RAG系统,相关技术文章地址为: + +[https://abdullin.com/ilya/how-to-build-best-rag/](https://abdullin.com/ilya/how-to-build-best-rag/) + +[https://hustyichi.github.io/2025/07/03/rag-complete/](https://hustyichi.github.io/2025/07/03/rag-complete/) + +背景:参赛者需要在2.5小时内完成100份真实企业年度报告PDF的解析,这些报告每份最多1000页,包含复杂的财务表格、多栏布局、图表等内容。解析完成后,系统需要回答100个精确的业务问题,这些问题要求明确的答案类型(比如Yes/No判断、公司名称、具体数值指标、高管职位名称等),并且必须给出答案来源的页码引用,以便业务人员验证。整个过程模拟的是投资分析师或财务审计人员的实际工作场景。 + +冠军团队选择IBM开源的Docling作为PDF解析工具,因为它在处理复杂表格(比如跨页表格、嵌套表格)和多列文本方面表现最好。团队对Docling代码进行了改进,使其生成包含元数据的JSON和Markdown+HTML格式,特别修复了表格结构的解析问题(比如单元格合并、表头识别等)。为了加速处理,团队租用RTX 4090 GPU,在40分钟内完成了100份报告的解析。 + +文本分块采用300 token长度,重叠50 token,使用递归分割策略保持语义完整。为了避免跨公司信息混淆(比如查询A公司CEO时检索到B公司的信息),为每个公司单独构建FAISS向量库,采用IndexFlatIP索引(不压缩以保证精度)。检索阶段采用三步走策略:首先通过向量检索找到Top30文本块,然后提取这些块所在的父页面并去重(因为多个块可能来自同一页),最后使用GPT-4o-mini对页面进行重新排序。向量检索分数与LLM重排序分数按0.3:0.7的权重混合。 + +生成阶段根据答案类型(数字/布尔/字符串等)使用不同的prompt模板。对于数字类问题(比如"2023年营收是多少"),设计了5步分析流程来确保指标匹配的准确性:识别问题中的指标类型、在文档中定位相关表格、提取数值、验证单位一致性、交叉验证。系统输出采用结构化格式,包含分析过程、相关页码等字段,确保答案可追溯。对于涉及多公司比较的问题(比如"哪家公司营收最高"),会拆分为单公司子查询后再合并结果。 + +该方案在竞赛中获得双奖项及排行榜第一。值得注意的是,即使使用小模型(如Llama 8B)也能超过80%的参与者,使用Llama 3.3 70B时仅比GPT-4o-mini稍差一点,成功实现了准确性、效率与成本的平衡。 + +## 6.4 AIOps场景:图文混合数据的智能处理 + +AIOps RAG竞赛的EasyRAG项目专注于运维场景下的问答任务,技术文章地址为: + +[http://blog.csdn.net/hustyichi/article/details/143323746](http://blog.csdn.net/hustyichi/article/details/143323746) + +![](images/image10.png) + +背景:运维工程师日常工作中需要查阅大量技术文档,这些文档不仅包含文字说明,还包含监控图表、系统架构图、性能曲线等图片信息。比如当系统出现性能问题时,工程师需要快速查询"CPU使用率超过80%时应该如何处理",答案可能分散在文字说明和监控图表中。传统RAG系统只能处理文字,无法理解图表中的趋势和数值,导致答案不完整。该项目最终获得初赛第一、复赛第二的成绩。 + +索引阶段使用改进过的SentenceSplitter(修复了原版块大小计算问题),按1024 token分块,重叠200 token。关键创新在于为每个文本块添加知识库路径、文件路径等元信息,这个改进使召回率提升了2%。对于图片数据,先使用PaddleOCR提取图片中的文字(比如图表的标题、坐标轴标签),再调用GLM-4V-9B多模态模型生成图片的自然语言描述(比如"该折线图显示CPU使用率在下午3点达到峰值90%"),将文字和描述一起入库,实现了图文信息的统一检索。 + +检索阶段采用"双路BM25+向量检索"策略进行广泛召回。BM25包含文档块检索(召回192条)和路径检索(通过文件路径过滤无关文档,比如只检索运维手册而不检索开发文档),使用哈工大停用词表进行去噪。向量检索使用gte-Qwen2-7B-instruct模型,召回288条候选结果。重排序阶段使用bge-reranker-v2-minicpm-layerwise模型,经过测试发现28层配置效果最好。 + +答案生成采用两步策略——先基于Top6文档生成初步结果(覆盖多个相关知识点),再结合Top1最相关文档进行二次优化(突出最核心的答案)。这个设计确保了答案既有足够的信息覆盖面,又能突出最核心的内容。 + +为了应对长文本场景(比如一份完整的运维手册可能有几百页),系统实现了基于BM25的上下文压缩方法。该方法将文档拆分为句子级别,计算每个句子与查询的相似度,然后按比例拼接高相关句子。实验表明,在50%压缩率下,该方法耗时仅7.7秒,准确率达86.48%,优于LLMLingua等现有压缩工具。 + +相比基础方案,加入元信息和答案二次优化后,系统准确性分别都提升了2%。BM25压缩方法在保证效率的同时保持了较高的准确性,很好地适配了AIOps场景下图文数据处理和实时响应的需求。 + +## 6.5 多源数据融合:结构化与非结构化知识的协同 + +KDD Cup 2024 Meta RAG挑战赛的冠军方案展示了如何整合非结构化Web数据和结构化知识图谱,技术文章地址为: + +[https://blog.csdn.net/m0_59164520/article/details/143694213](https://blog.csdn.net/m0_59164520/article/details/143694213) + +https://arxiv.org/pdf/2410.00005 + +![](images/image11.png) + +背景:任务1要求基于5个网页做检索摘要,比如用户搜索"星际穿越导演是谁",系统需要从给定的网页中提取答案。任务2在任务1基础上增加了Mock API(模拟访问结构化知识图谱),系统可以调用API查询电影数据库、人物关系等结构化信息。任务3进一步扩大难度,基于50个网页与Mock API处理复杂查询,比如"哪些由诺兰导演的电影票房超过5亿美元",这需要同时查询知识图谱(导演作品关系)和网页(票房数据)。每个查询需在30秒内完成,核心目标是提升多源数据整合的准确性并减少幻觉。 + +北大db3团队针对任务1设计了精细化的Web数据处理流程。使用BeautifulSoup提取网页文本,ParentDocumentRetriever管理父子块关系(子块200 token用于检索、父块500-2000 token用于生成),确保检索准确性和生成完整性。嵌入模型选用bge-base-en-v1.5,向量库使用Chroma,重排序采用bge-reranker-v2-m3。团队还补充了电影、金融等领域的公开数据(比如IMDB电影数据、上市公司财报),转换为规范格式后入库。模型层面使用LoRA微调Llama-3-8B-instruct,训练数据包括无效问题标注(比如"今天天气怎么样"这类超出知识库范围的问题)、正确答案等。 + +任务2-3的关键创新在于优先使用知识图谱。团队设计了规范化的API调用机制,包括get_person(查询人物信息)、get_movie(查询电影信息)等接口,支持条件过滤(比如cmp操作符筛选票房>5亿的电影)和排序(按票房降序)。API调用生成采用GPT-4初步标注后人工优化的方式进行微调。系统执行时先调用知识图谱API,只有在知识图谱结果无效(比如查询的电影不在数据库中)时才回退到Web检索,这个设计大幅提升了查询效率和答案准确性。 + +通过知识图谱优先策略和结构化输出格式,系统明显减少了LLM的幻觉现象。当知识图谱能提供确定性答案时(比如"诺兰出生年份"),直接输出不经过生成步骤;当需要从Web检索时(比如"诺兰最新访谈内容"),通过严格的文档引用和分步推理确保答案可验证。 + +该方案在三个任务中均获第一,得分分别达到28.4%、42.7%和47.8%,成功平衡了多源数据整合的准确性与实时性。这个案例的核心启示在于,对于包含结构化和非结构化数据的企业场景,应该根据数据特点设计不同的检索策略,优先使用确定性强的结构化数据,用非结构化数据作为补充。 + +深入分析这几个实践案例,我们可以总结出构建高质量RAG系统的几个共同原则:在架构设计上,应该根据业务场景选择合适的缓存、检索和生成策略;在数据处理上,需要针对不同格式和模态设计专门的解析和索引方案;在检索优化上,混合检索加重排序已成为标准配置;在答案生成上,分类型的prompt和结构化输出能明显提升准确性和可追溯性。 + +这些来自真实竞赛和开源项目的经验,为搭建更好的企业级RAG系统提供了宝贵的参考,你可以根据实际问题搜索对应的比赛,找到成熟现有方案进行尝试。 + +7. # 广度探索:RAG 的未来演化(Optional) + +在深入掌握了RAG的实战技巧与优化方法后,你已经能够在具体场景中有效提升系统性能。然而,要全面把握RAG技术,仅靠对局部的深入钻研还不够,我们还需拓展视野,从更广阔的维度理解其演进方向与扩展空间。 + +当前,RAG技术正在迅速突破传统基于文档分块的检索生成范式,朝着更多样化的方向发展。本节将重点探讨以下几个演进路径:从简单的分块检索转向对图数据结构的检索;融合图像、音频等多模态信息以增强RAG的检索能力;利用向量化技术优化长文档的分块处理策略;以及RAG如何逐步演化为智能体(Agent)系统。 + +## 7.1 Graph RAG:用关系网络重塑深度检索 + +相关研究:[https://arxiv.org/pdf/2410.05779](https://arxiv.org/pdf/2410.05779), [https://arxiv.org/pdf/2502.11371](https://arxiv.org/pdf/2502.11371), https://arxiv.org/pdf/2404.16130 + +![](images/image12.png) + +传统RAG依靠寻找和问题相似的文本段落来工作,这就像在一堆材料里挑出看起来最相关的几段话。对于直接查找某个具体信息,这种方法很有效。但如果一个问题需要联系多份文档、结合不同线索才能回答,它的表现就会打折扣。 + +比如,医生可能想问:“根据这些病例和最新的治疗指南,如何评估某种药物对老年患者的好处和风险?”又或者,项目团队可能关心:“综合过去两年的需求文档、评审记录和线上问题报告,我们这个系统架构最常出问题的环节是什么?”这类问题的关键,不是找到某一句原话,而是要从各种分散的材料中,找出其中提到的人、事、物以及它们之间的联系,理清头绪,形成一幅完整的全景图。 + +Graph RAG的做法,就是先主动画出这幅全景图。系统会利用大模型从文本中识别出关键元素(比如人物、机构、功能模块、事件、数据等)以及它们之间的关系(比如谁导致了什么、什么依赖于什么、如何变化、有何矛盾等),从而构建一个随着资料增加而不断丰富的知识网络。接着,通过自动分组,把联系紧密的元素和关系归类到不同的主题下,并为每个主题提前生成一段概括性描述。这样,当用户提问时,系统不再仅仅是寻找字面上最相似的段落,而是会先在知识网络里找到与问题最相关的元素和局部结构,再顺着连接线扩展到相关的主题组,最后将这些分析路径、节点说明和对应的原始文本片段,一起交给大模型进行推理并组织答案。 + +在这样的框架下,Graph RAG和传统RAG形成了很好的分工与配合:传统RAG仍然擅长回答直接的、一步就能找到答案的细节问题;而Graph RAG则更像人在做研究或写报告时的思路——先梳理出整体结构和主题(构建网络与分组),再填充具体依据(引用原文),最后给出有逻辑、有条件限制的结论。已有的系统对比也显示,在需要联系多个信息点进行推理的任务中,Graph RAG通常能涵盖更关键的内容,提供更全面的视角;而根据问题的具体特点,灵活结合使用两种方法,整体效果往往比只使用其中一种更好。 + +## 7.2 Multimodal RAG:多模态 RAG + +相关研究:https://arxiv.org/pdf/2502.08826 + +![](images/image13.png) + +现实世界的数据从来不是单一文本。工程师排查服务器故障时,需要同时看温度监控曲线、设备面板截图和系统日志;医生做诊断时,需要把 CT / MRI 影像、检查报告和电子病历放在一起看。传统的文本 RAG 最多只能检索到“温度异常”“怀疑肺结节”这样的文字描述,却难以把这些描述与具体的曲线走势、影像病灶形态对应起来,更做不到用“图/音/视频”去反向检索相关文档和知识。 + +Multimodal RAG(多模态 RAG)解决的是这种“模态之间互相看不见”的问题。它的核心在于跨模态语义对齐:为图像、视频、音频、文本等分别配置合适的编码器(如 ViT/CLIP 编图像和视频帧,Whisper 编音频,BGE-M3 等编码文本),配合 OCR、ASR、版面分析等工具,把视觉和音频里的关键信息抽取出来,再通过模型把不同模态的表示映射到一个共享的语义空间中,构建统一的多模态索引。 + +在检索和生成阶段,不管用户是问“找一张显示 2023 年 Q3 销售峰值的图表”,还是上传一张产品草图或一段操作视频发起查询,系统都会先在这个统一空间里找到一批最相近的多模态内容,然后根据文本相似度、图像相似度等信号,筛掉明显无关的结果,保留几条最有用的证据。最后,把这些经过筛选的图、文、表格等,一并交给多模态大模型,由它综合不同模态的信息给出答案,并尽量标明信息来源,或在截图、文档中高亮相关位置。这样一来,相比只看文本的 RAG,系统既能利用更多模态的线索,又更容易减少幻觉,让答案更完整也更容易核实。 + +## 7.3 Late Chunking:为长文档保留完整上下文 + +相关介绍:https://jina.ai/news/late-chunking-in-long-context-embedding-models/ + +![](images/image14.png) + +想象你正在阅读一篇关于柏林的维基百科文章,传统RAG系统会先将其切成独立段落再生成向量。当第一句提到"柏林是德国首都"后,后续段落中的"该城市"、"它的人口"等指代词就失去了与"柏林"的关联。此时若查询"柏林的人口是多少",系统会因为"柏林"和"人口数据"从未在同一文本块出现而检索失败。这个问题在长文档场景更为严重:一份200页的保险合同中,"免赔额"的定义在第5页,具体适用条件在第30页,传统的固定长度切分(如每512 tokens一块)会将这些相关信息分散到40多个独立文本块中,实验数据显示这种割裂会导致语义相似度从0.85暴跌至0.71。 + +Late Chunking颠覆了"先切后编"的传统流程,改为"先编后切":利用支持8192 tokens(约10页文本)的长上下文嵌入模型(如Jina Embeddings v2),首先将整个文档输入Transformer层,生成每个token的向量表示——此时每个token的嵌入已经"看到"了全文信息,捕获了跨段落的指代关系和概念关联。随后,再对这些已经全局感知的token向量进行分块平均池化(mean pooling),生成最终的块嵌入。这样生成的文本块不再是独立同分布的孤岛,而是"条件依赖"的上下文链:当处理"该城市有385万居民"这句话时,向量中已经包含了前文"柏林"的语义信息,使相似度从0.71提升至0.83。关键区别在于边界标记的使用时机:传统方法在预处理阶段就用句号、段落符切分文本,而Late Chunking仅在获得全局token嵌入后,才应用边界线索进行智能分块。 + +在BEIR基准测试的5个数据集上,Late Chunking全面超越传统切分方法。最显著的案例是NFCorpus数据集(平均文档长度1590字符),检索准确率从23.46%飙升至29.98%,相对提升27.8%;而在短文本场景(如Quora的62字符问题)两者表现相同,验证了一个关键规律:文档长度与Late Chunking的优势呈正相关。从技术对比表可见核心差异:传统切分在预处理阶段直接应用边界标记,产生独立同分布的块嵌入,上下文信息丢失;Late Chunking在获得token嵌入后才应用边界标记,产生条件依赖的块嵌入,由长上下文模型完整保留上下文信息。 + +该方法现已集成到Jina Embeddings v3 API中,虽然需要先编码整个长文档,推理时间增加10-20%,但在医疗病历(跨章节的诊断依据)、法律文档(定义与条款的交叉引用)、技术手册(概念解释分散在多个章节)等场景中,检索准确率的大幅提升远超过这点性能开销。Late Chunking不仅证明了8K+长上下文模型的实用价值——不是"过度设计",而是实现高质量块嵌入的必要条件,更为RAG系统提供了一条摆脱滑动窗口、多次扫描等"hit-or-miss"启发式技巧、具有理论保证的优化路径,代表了从"先切后编"到"先编后切"的范式转变。 + +## 7.4 从 RAG 到 Agent 时代的 RAG + +相关讨论:[https://ragflow.io/blog/rag-at-the-crossroads-mid-2025-reflections-on-ai-evolution](https://ragflow.io/blog/rag-at-the-crossroads-mid-2025-reflections-on-ai-evolution), [https://arxiv.org/pdf/2501.09136](https://arxiv.org/pdf/2501.09136), [https://www.letta.com/blog/rag-vs-agent-memory](https://www.letta.com/blog/rag-vs-agent-memory), [https://www.linkedin.com/posts/richmondalake_100daysofagentmemory-rag-memorizz-activity-7348281860843577346-LM7Y/](https://www.linkedin.com/posts/richmondalake_100daysofagentmemory-rag-memorizz-activity-7348281860843577346-LM7Y/), https://www.llamaindex.ai/blog/rag-is-dead-long-live-agentic-retrieval + +RAG技术已从最初的检索增强生成工具,发展为构建智能体认知架构的关键部分。 传统RAG系统基于提问、检索、回答的简单模式,本质是被动接受查询,不具备主动行动的能力。为了突破这种被动性并处理更复杂的认知任务,RAG与智能体能力进行了深度融合,由此诞生了Agentic RAG这一新范式。 在此范式中,RAG的角色发生了根本转变:它不再仅仅是外部知识的被动提供者,而是在智能体的主动规划、目标指引和反思能力驱动下,成为支撑智能行为的核心处理单元。这种融合使系统整体具备了目标导向、迭代优化和自主决策的能力,显著提升了人机交互的深度与质量。具体而言,Agentic RAG能够理解复杂任务,自主拆解问题,规划检索策略,并在获取初步信息后评估结果质量,决定是否深入探索,从而胜任传统RAG难以应对的多步骤复杂任务。 + +![](images/image15.png) + +Agentic RAG实现上述复杂任务处理的关键,在于其建立了一个多层次的主动循环工作机制。 面对复杂查询,智能体首先分析问题本质,将其拆解为子问题,并为每个子问题设计精准的检索策略。获得初步结果后,智能体进行评估与反思,判断信息的完整性和相关性,识别知识缺口,并动态生成更精确的新查询。这种迭代过程常包含多跳检索,即基于前一轮结果发现新的检索方向,形成类似人类研究者的知识探索链条。然而,要支撑这种持续的、迭代的智能行为,尤其是实现长期交互中的个性化和知识积累,仅依赖单次会话的短期上下文(短期记忆)是远远不够的。这引出了对长期、结构化记忆能力的需求。 + +正是为了满足这一需求,RAG被赋予了作为智能体长期记忆系统的角色,构建了一个完整的外部记忆架构。 该系统与负责维护当前会话上下文的短期记忆形成互补。该长期记忆系统的核心运作依赖于三项关键机制: +第一,结构化索引能力:使智能体能够为海量非结构化数据建立多维索引体系(如按时间、主题或实体关系),支持多角度高效检索,模拟人脑通过不同线索回忆信息的方式。 +第二,智能遗忘机制:通过价值评估算法,系统对使用频率低、相关性弱或过时的信息进行权重衰减或选择性剔除,维持记忆系统的精炼高效,防止信息过载。 +第三,知识巩固过程:系统将零散对话和交互经验提炼为结构化知识,利用实体识别、关系抽取和语义聚类等技术,将碎片信息整合连接成知识图谱,完成从短期经验到长期知识的转化与沉淀。 + +这种由RAG构建的外部记忆系统,不仅极大地扩展了智能体的认知边界,更重要的是赋予了其持续学习和知识进化的能力。 它使得智能体能够在长期互动中积累经验,形成个性化的处理模式和领域专业知识体系,从而为执行更复杂、更持久的任务提供了坚实的基础。 + +# 总结 + +检索增强生成不仅是一种弥补大模型幻觉与知识滞后性的技术方案,更是将通用AI能力转化为企业深度业务价值的关键桥梁。从基础的Naive RAG演进至模块化、智能体协同的Advanced RAG,这一过程反映出RAG在各个环节均需持续深化——无论是更精细的数据处理、更科学的模型选型(Embedding、Rerank、LLM),还是更体系化的效果评测,都是构建可控、可信、高效的企业级知识系统的必经之路。同时,从各类竞赛与实践案例中汲取经验技巧,也能进一步加深对技术细节的理解。 + +随着图结构检索(Graph RAG)、多模态理解与Late Chunking等前沿方向的融合发展,RAG正不断突破传统检索生成的边界,逐步具备更深层的语义关联与可持续的记忆能力。希望通过这篇综述类文章的学习,能够帮助你掌握从原理到实践、从评估到演进的全链路方法论,从而在快速迭代的技术浪潮中,打造出真正落地、能够应对复杂业务挑战的高质量智能应用。 + +# Reference + +[1] Ask in Any Modality: A Comprehensive Survey on Multimodal Retrieval-Augmented Generation. + +https://arxiv.org/pdf/2502.08826 + +[2] Retrieving Multimodal Information for Augmented Generation: A Survey. + +https://arxiv.org/pdf/2303.10868 + +[3] A Survey on RAG Meeting LLMs: Towards Retrieval-Augmented Large Language Models. + +https://arxiv.org/pdf/2405.06211 + +[4] Retrieval-Augmented Generation for Large Language Models: A Survey. + +https://arxiv.org/pdf/2312.10997 + +[5] LightRAG: Simple and Fast Retrieval-Augmented Generation. + +https://arxiv.org/pdf/2410.05779 + +[6] Agentic Retrieval-Augmented Generation: A Survey on Agentic RAG. + +https://arxiv.org/pdf/2501.09136 + +[7] ERAGent: Enhancing Retrieval-Augmented Language Models with Improved Accuracy, Efficiency, and Personalization. + +https://arxiv.org/pdf/2405.06683 + +[8] Graph Retrieval-Augmented Generation: A Survey. + +https://www.arxiv.org/pdf/2408.08921 + +[9] Evaluation of Retrieval-Augmented Generation: A Survey. + +https://arxiv.org/pdf/2405.07437 + +[10] Retrieval Augmented Generation Evaluation in the Era of Large Language Models: A Comprehensive Survey. + +https://arxiv.org/pdf/2504.14891 + +[11] From Local to Global: A Graph RAG Approach to Query-Focused Summarization. + +https://arxiv.org/pdf/2404.16130 + +[12] RAG vs. GraphRAG: A Systematic Evaluation and Key Insights. + +https://arxiv.org/pdf/2502.11371 + +[13] Introduction to RAG | LlamaIndex Python Documentation. + +https://developers.llamaindex.ai/python/framework/understanding/rag/ + +[14] All-in-RAG | 大模型应用开发实战:RAG 技术全栈指南. + +https://datawhalechina.github.io/all-in-rag/#/en/ + +[15] Ilya Rice: How I Won the Enterprise RAG Challenge. + +https://abdullin.com/ilya/how-to-build-best-rag/ + +[16] RAG Research Table – Awesome Generative AI Guide (GitHub). + +https://github.com/aishwaryanr/awesome-generative-ai-guide/blob/main/research_updates/rag_research_table.md + +[17] RAG is dead, long live agentic retrieval. + +https://www.llamaindex.ai/blog/rag-is-dead-long-live-agentic-retrieval + +[18] LLM/RAG Zoomcamp 課外補充 5:RAG Evolution 常見評估方法和市場偏好. + +https://vip.studycamp.tw/t/llmrag-zoomcamp-%E8%AA%B2%E5%A4%96%E8%A3%9C%E5%85%85-5%EF%BC%9Arag-evolution-%E5%B8%B8%E8%A6%8B%E8%A9%95%E4%BC%B0%E6%96%B9%E6%B3%95%E5%92%8C%E5%B8%82%E5%A0%B4%E5%81%8F%E5%A5%BD/8185 + +[19] How to Evaluate Retrieval Augmented Generation (RAG) Applications. + +https://zilliz.com.cn/blog/how-to-evaluate-rag-zilliz + +[20] RAG is not Agent Memory. + +https://www.letta.com/blog/rag-vs-agent-memory + +[21] Richmond Alake. LinkedIn post on #100DaysOfAgentMemory, RAG and MemoRizz. + +https://www.linkedin.com/posts/richmondalake_100daysofagentmemory-rag-memorizz-activity-7348281860843577346-LM7Y/ diff --git a/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image1.png b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image1.png new file mode 100644 index 0000000..af7d361 Binary files /dev/null and b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image1.png differ diff --git a/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image10.png b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image10.png new file mode 100644 index 0000000..03694c4 Binary files /dev/null and b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image10.png differ diff --git a/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image11.png b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image11.png new file mode 100644 index 0000000..5642883 Binary files /dev/null and b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image11.png differ diff --git a/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image12.png b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image12.png new file mode 100644 index 0000000..c63c018 Binary files /dev/null and b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image12.png differ diff --git a/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image13.png b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image13.png new file mode 100644 index 0000000..2f012ba Binary files /dev/null and b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image13.png differ diff --git a/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image14.png b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image14.png new file mode 100644 index 0000000..18c4ae3 Binary files /dev/null and b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image14.png differ diff --git a/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image15.png b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image15.png new file mode 100644 index 0000000..7dd9e8a Binary files /dev/null and b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image15.png differ diff --git a/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image2.png b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image2.png new file mode 100644 index 0000000..169cb2c Binary files /dev/null and b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image2.png differ diff --git a/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image3.png b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image3.png new file mode 100644 index 0000000..056fba7 Binary files /dev/null and b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image3.png differ diff --git a/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image4.png b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image4.png new file mode 100644 index 0000000..5b5b17e Binary files /dev/null and b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image4.png differ diff --git a/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image5.png b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image5.png new file mode 100644 index 0000000..5a83f04 Binary files /dev/null and b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image5.png differ diff --git a/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image6.png b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image6.png new file mode 100644 index 0000000..621a6da Binary files /dev/null and b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image6.png differ diff --git a/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image7.png b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image7.png new file mode 100644 index 0000000..f4d2625 Binary files /dev/null and b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image7.png differ diff --git a/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image8.png b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image8.png new file mode 100644 index 0000000..56d75a4 Binary files /dev/null and b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image8.png differ diff --git a/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image9.png b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image9.png new file mode 100644 index 0000000..ead7a0f Binary files /dev/null and b/docs/stage-3/ai-advanced/3.a1-rag-introduction/images/image9.png differ diff --git a/docs/stage-3/ai-advanced/3.a2-langgraph-advanced-rag/index.md b/docs/stage-3/ai-advanced/3.a2-langgraph-advanced-rag/index.md new file mode 100644 index 0000000..2da334f --- /dev/null +++ b/docs/stage-3/ai-advanced/3.a2-langgraph-advanced-rag/index.md @@ -0,0 +1,3 @@ +# 高级 AI 二:中高级 RAG 与工作流编排 - 以 LangGraph 为例 + +> 本章节正在编写中,敬请期待... diff --git a/docs/stage-3/core-skills/3.1-mcp-claudecode-skills/index.md b/docs/stage-3/core-skills/3.1-mcp-claudecode-skills/index.md new file mode 100644 index 0000000..fb772f2 --- /dev/null +++ b/docs/stage-3/core-skills/3.1-mcp-claudecode-skills/index.md @@ -0,0 +1,3 @@ +# 高级一:MCP 与 ClaudeCode Skills + +> 本章节正在编写中,敬请期待... diff --git a/docs/stage-3/core-skills/3.2-long-running-tasks/index.md b/docs/stage-3/core-skills/3.2-long-running-tasks/index.md new file mode 100644 index 0000000..e0073c8 --- /dev/null +++ b/docs/stage-3/core-skills/3.2-long-running-tasks/index.md @@ -0,0 +1,3 @@ +# 高级二:如何让 Coding Tools 长时间工作 + +> 本章节正在编写中,敬请期待... diff --git a/docs/stage-3/cross-platform/3.3-wechat-miniprogram/index.md b/docs/stage-3/cross-platform/3.3-wechat-miniprogram/index.md new file mode 100644 index 0000000..3ed957c --- /dev/null +++ b/docs/stage-3/cross-platform/3.3-wechat-miniprogram/index.md @@ -0,0 +1,3 @@ +# 高级三:多平台开发 - 如何构建微信小程序 + +> 本章节正在编写中,敬请期待... diff --git a/docs/stage-3/cross-platform/3.4-wechat-miniprogram-backend/index.md b/docs/stage-3/cross-platform/3.4-wechat-miniprogram-backend/index.md new file mode 100644 index 0000000..db5d733 --- /dev/null +++ b/docs/stage-3/cross-platform/3.4-wechat-miniprogram-backend/index.md @@ -0,0 +1,3 @@ +# 高级四:多平台开发 - 如何构建微信小程序(包含后端) + +> 本章节正在编写中,敬请期待... diff --git a/docs/stage-3/cross-platform/3.5-android-app/index.md b/docs/stage-3/cross-platform/3.5-android-app/index.md new file mode 100644 index 0000000..5734c4c --- /dev/null +++ b/docs/stage-3/cross-platform/3.5-android-app/index.md @@ -0,0 +1,3 @@ +# 高级五:多平台开发 - 如何构建安卓程序 + +> 本章节正在编写中,敬请期待... diff --git a/docs/stage-3/cross-platform/3.6-ios-app/index.md b/docs/stage-3/cross-platform/3.6-ios-app/index.md new file mode 100644 index 0000000..1ec0844 --- /dev/null +++ b/docs/stage-3/cross-platform/3.6-ios-app/index.md @@ -0,0 +1,3 @@ +# 高级六:多平台开发 - 如何构建 iOS 程序 + +> 本章节正在编写中,敬请期待... diff --git a/docs/stage-3/personal-brand/3.7-personal-website-blog/index.md b/docs/stage-3/personal-brand/3.7-personal-website-blog/index.md new file mode 100644 index 0000000..225556d --- /dev/null +++ b/docs/stage-3/personal-brand/3.7-personal-website-blog/index.md @@ -0,0 +1,3 @@ +# 高级七:如何构建属于自己的个人网页与学术博客 + +> 本章节正在编写中,敬请期待... diff --git a/package-lock.json b/package-lock.json index 9135200..2416775 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,815 +1,2177 @@ { - "name": "vibe-coding", + "name": "easy-vibe", "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "vibe-coding", + "name": "easy-vibe", "version": "1.0.0", + "license": "CC-BY-NC-SA-4.0", + "dependencies": { + "@element-plus/icons-vue": "^2.3.2", + "element-plus": "^2.13.1", + "typeit": "^8.8.7", + "viewerjs": "^1.11.7" + }, "devDependencies": { - "docsify-cli": "^4.4.4" + "prettier": "^3.7.4", + "vitepress": "2.0.0-alpha.15", + "vue": "^3.5.0" } }, - "node_modules/@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmmirror.com/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "node_modules/@ai-sdk/gateway": { + "version": "2.0.25", + "resolved": "https://registry.npmmirror.com/@ai-sdk/gateway/-/gateway-2.0.25.tgz", + "integrity": "sha512-Rq+FX55ne7lMiqai7NcvvDZj4HLsr+hg77WayqmySqc6zhw3tIOLxd4Ty6OpwNj0C0bVMi3iCl2zvJIEirh9XA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "defer-to-connect": "^1.0.1" + "@ai-sdk/provider": "2.0.1", + "@ai-sdk/provider-utils": "3.0.20", + "@vercel/oidc": "3.0.5" }, "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.1.0" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmmirror.com/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" + "node": ">=18" }, - "engines": { - "node": ">=4" + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/boxen": { - "version": "4.2.0", - "resolved": "https://registry.npmmirror.com/boxen/-/boxen-4.2.0.tgz", - "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-align": "^3.0.0", - "camelcase": "^5.3.1", - "chalk": "^3.0.0", - "cli-boxes": "^2.2.0", - "string-width": "^4.1.0", - "term-size": "^2.1.0", - "type-fest": "^0.8.1", - "widest-line": "^3.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/boxen/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/boxen/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/boxen/node_modules/color-convert": { + "node_modules/@ai-sdk/provider": { "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "resolved": "https://registry.npmmirror.com/@ai-sdk/provider/-/provider-2.0.1.tgz", + "integrity": "sha512-KCUwswvsC5VsW2PWFqF8eJgSCu5Ysj7m1TxiHTVA6g7k360bk0RNQENT8KTMAYEs+8fWPD3Uu4dEmzGHc+jGng==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "color-name": "~1.1.4" + "json-schema": "^0.4.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=18" } }, - "node_modules/boxen/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/@ai-sdk/provider-utils": { + "version": "3.0.20", + "resolved": "https://registry.npmmirror.com/@ai-sdk/provider-utils/-/provider-utils-3.0.20.tgz", + "integrity": "sha512-iXHVe0apM2zUEzauqJwqmpC37A5rihrStAih5Ks+JE32iTe4LZ58y17UGBjpQQTCRw9YxMeo2UFLxLpBluyvLQ==", "dev": true, - "license": "MIT" - }, - "node_modules/boxen/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/boxen/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "has-flag": "^4.0.0" + "@ai-sdk/provider": "2.0.1", + "@standard-schema/spec": "^1.0.0", + "eventsource-parser": "^3.0.6" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" } }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "node_modules/@ai-sdk/react": { + "version": "2.0.121", + "resolved": "https://registry.npmmirror.com/@ai-sdk/react/-/react-2.0.121.tgz", + "integrity": "sha512-VbckviE2ryPaWcecjGXP9zY4CJUqXYoLFfJZJl95XtZL4Gl8X0AuU2p7p6ModCoavHuFw1bfL8k6d0Mu59WROw==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "fill-range": "^7.1.1" + "@ai-sdk/provider-utils": "3.0.20", + "ai": "5.0.119", + "swr": "^2.2.5", + "throttleit": "2.1.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmmirror.com/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "dev": true, - "license": "MIT", - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" + "node": ">=18" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmmirror.com/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cacheable-request/node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmmirror.com/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmmirror.com/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmmirror.com/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-response": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/commander": { - "version": "14.0.2", - "resolved": "https://registry.npmmirror.com/commander/-/commander-14.0.2.tgz", - "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - } - }, - "node_modules/configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/connect": { - "version": "3.7.0", - "resolved": "https://registry.npmmirror.com/connect/-/connect-3.7.0.tgz", - "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "finalhandler": "1.1.2", - "parseurl": "~1.3.3", - "utils-merge": "1.0.1" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "https://registry.npmmirror.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/connect-livereload": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/connect-livereload/-/connect-livereload-0.6.1.tgz", - "integrity": "sha512-3R0kMOdL7CjJpU66fzAkCe6HNtd3AavCS4m+uW4KtJjrdGPT0SQEZieAYd+cm+lJoBznNQ4lqipYWkhBMgk00g==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/cp-file": { - "version": "7.0.0", - "resolved": "https://registry.npmmirror.com/cp-file/-/cp-file-7.0.0.tgz", - "integrity": "sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "nested-error-stacks": "^2.0.0", - "p-event": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmmirror.com/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-response": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmmirror.com/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/docsify": { - "version": "4.13.1", - "resolved": "https://registry.npmmirror.com/docsify/-/docsify-4.13.1.tgz", - "integrity": "sha512-BsDypTBhw0mfslw9kZgAspCMZSM+sUIIDg5K/t1hNLkvbem9h64ZQc71e1IpY+iWsi/KdeqfazDfg52y2Lmm0A==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "marked": "^1.2.9", - "medium-zoom": "^1.0.6", - "opencollective-postinstall": "^2.0.2", - "prismjs": "^1.27.0", - "strip-indent": "^3.0.0", - "tinydate": "^1.3.0", - "tweezer.js": "^1.4.0" - } - }, - "node_modules/docsify-cli": { - "version": "4.4.4", - "resolved": "https://registry.npmmirror.com/docsify-cli/-/docsify-cli-4.4.4.tgz", - "integrity": "sha512-NAZgg6b0BsDuq/Pe+P19Qb2J1d+ZVbS0eGkeCNxyu4F9/CQSsRqZqAvPJ9/0I+BCHn4sgftA2jluqhQVzKzrSA==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^2.4.2", - "connect": "^3.6.0", - "connect-history-api-fallback": "^1.6.0", - "connect-livereload": "^0.6.0", - "cp-file": "^7.0.0", - "docsify": "^4.12.2", - "docsify-server-renderer": ">=4.10.0", - "enquirer": "^2.3.6", - "fs-extra": "^8.1.0", - "get-port": "^5.0.0", - "livereload": "^0.9.2", - "lru-cache": "^5.1.1", - "open": "^6.4.0", - "serve-static": "^1.12.1", - "update-notifier": "^4.1.0", - "yargonaut": "^1.1.2", - "yargs": "^15.3.0" - }, - "bin": { - "docsify": "bin/docsify" - }, - "engines": { - "node": ">= 10", - "npm": ">= 6" - } - }, - "node_modules/docsify-server-renderer": { - "version": "4.13.1", - "resolved": "https://registry.npmmirror.com/docsify-server-renderer/-/docsify-server-renderer-4.13.1.tgz", - "integrity": "sha512-XNJeCK3zp+mVO7JZFn0bH4hNBAMMC1MbuCU7CBsjLHYn4NHrjIgCBGmylzEan3/4Qm6kbSzQx8XzUK5T7GQxHw==", - "deprecated": "docsify-server-renderer 4.x and below is no longer supported while we investigate the future of SSR and SSG for Docsify", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.3", - "docsify": "^4.12.4", - "node-fetch": "^2.6.6", - "resolve-pathname": "^3.0.0" - } - }, - "node_modules/docsify-server-renderer/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" + "peerDependencies": { + "react": "^18 || ~19.0.1 || ~19.1.2 || ^19.2.1", + "zod": "^3.25.76 || ^4.1.8" }, "peerDependenciesMeta": { - "supports-color": { + "zod": { "optional": true } } }, - "node_modules/docsify-server-renderer/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmmirror.com/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "node_modules/@algolia/abtesting": { + "version": "1.12.2", + "resolved": "https://registry.npmmirror.com/@algolia/abtesting/-/abtesting-1.12.2.tgz", + "integrity": "sha512-oWknd6wpfNrmRcH0vzed3UPX0i17o4kYLM5OMITyMVM2xLgaRbIafoxL0e8mcrNNb0iORCJA0evnNDKRYth5WQ==", "dev": true, "license": "MIT", "dependencies": { - "is-obj": "^2.0.0" + "@algolia/client-common": "5.46.2", + "@algolia/requester-browser-xhr": "5.46.2", + "@algolia/requester-fetch": "5.46.2", + "@algolia/requester-node-http": "5.46.2" }, "engines": { - "node": ">=8" + "node": ">= 14.0.0" } }, - "node_modules/duplexer3": { - "version": "0.1.5", - "resolved": "https://registry.npmmirror.com/duplexer3/-/duplexer3-0.1.5.tgz", - "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true, - "license": "MIT" - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmmirror.com/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "node_modules/@algolia/autocomplete-core": { + "version": "1.19.2", + "resolved": "https://registry.npmmirror.com/@algolia/autocomplete-core/-/autocomplete-core-1.19.2.tgz", + "integrity": "sha512-mKv7RyuAzXvwmq+0XRK8HqZXt9iZ5Kkm2huLjgn5JoCPtDy+oh9yxUMfDDaVCw0oyzZ1isdJBc7l9nuCyyR7Nw==", "dev": true, "license": "MIT", "dependencies": { - "once": "^1.4.0" + "@algolia/autocomplete-plugin-algolia-insights": "1.19.2", + "@algolia/autocomplete-shared": "1.19.2" } }, - "node_modules/enquirer": { - "version": "2.4.1", - "resolved": "https://registry.npmmirror.com/enquirer/-/enquirer-2.4.1.tgz", - "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.19.2", + "resolved": "https://registry.npmmirror.com/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.19.2.tgz", + "integrity": "sha512-TjxbcC/r4vwmnZaPwrHtkXNeqvlpdyR+oR9Wi2XyfORkiGkLTVhX2j+O9SaCCINbKoDfc+c2PB8NjfOnz7+oKg==", "dev": true, "license": "MIT", "dependencies": { - "ansi-colors": "^4.1.1", - "strip-ansi": "^6.0.1" + "@algolia/autocomplete-shared": "1.19.2" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@algolia/autocomplete-shared": { + "version": "1.19.2", + "resolved": "https://registry.npmmirror.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.19.2.tgz", + "integrity": "sha512-jEazxZTVD2nLrC+wYlVHQgpBoBB5KPStrJxLzsIFl6Kqd1AlG9sIAGl39V5tECLpIQzB3Qa2T6ZPJ1ChkwMK/w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/client-abtesting": { + "version": "5.46.2", + "resolved": "https://registry.npmmirror.com/@algolia/client-abtesting/-/client-abtesting-5.46.2.tgz", + "integrity": "sha512-oRSUHbylGIuxrlzdPA8FPJuwrLLRavOhAmFGgdAvMcX47XsyM+IOGa9tc7/K5SPvBqn4nhppOCEz7BrzOPWc4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.46.2", + "@algolia/requester-browser-xhr": "5.46.2", + "@algolia/requester-fetch": "5.46.2", + "@algolia/requester-node-http": "5.46.2" }, "engines": { - "node": ">=8.6" + "node": ">= 14.0.0" } }, - "node_modules/escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true, - "license": "MIT" - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmmirror.com/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/figlet": { - "version": "1.9.4", - "resolved": "https://registry.npmmirror.com/figlet/-/figlet-1.9.4.tgz", - "integrity": "sha512-uN6QE+TrzTAHC1IWTyrc4FfGo2KH/82J8Jl1tyKB7+z5DBit/m3D++Iu5lg91qJMnQQ3vpJrj5gxcK/pk4R9tQ==", + "node_modules/@algolia/client-analytics": { + "version": "5.46.2", + "resolved": "https://registry.npmmirror.com/@algolia/client-analytics/-/client-analytics-5.46.2.tgz", + "integrity": "sha512-EPBN2Oruw0maWOF4OgGPfioTvd+gmiNwx0HmD9IgmlS+l75DatcBkKOPNJN+0z3wBQWUO5oq602ATxIfmTQ8bA==", "dev": true, "license": "MIT", "dependencies": { - "commander": "^14.0.0" + "@algolia/client-common": "5.46.2", + "@algolia/requester-browser-xhr": "5.46.2", + "@algolia/requester-fetch": "5.46.2", + "@algolia/requester-node-http": "5.46.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-common": { + "version": "5.46.2", + "resolved": "https://registry.npmmirror.com/@algolia/client-common/-/client-common-5.46.2.tgz", + "integrity": "sha512-Hj8gswSJNKZ0oyd0wWissqyasm+wTz1oIsv5ZmLarzOZAp3vFEda8bpDQ8PUhO+DfkbiLyVnAxsPe4cGzWtqkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-insights": { + "version": "5.46.2", + "resolved": "https://registry.npmmirror.com/@algolia/client-insights/-/client-insights-5.46.2.tgz", + "integrity": "sha512-6dBZko2jt8FmQcHCbmNLB0kCV079Mx/DJcySTL3wirgDBUH7xhY1pOuUTLMiGkqM5D8moVZTvTdRKZUJRkrwBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.46.2", + "@algolia/requester-browser-xhr": "5.46.2", + "@algolia/requester-fetch": "5.46.2", + "@algolia/requester-node-http": "5.46.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "5.46.2", + "resolved": "https://registry.npmmirror.com/@algolia/client-personalization/-/client-personalization-5.46.2.tgz", + "integrity": "sha512-1waE2Uqh/PHNeDXGn/PM/WrmYOBiUGSVxAWqiJIj73jqPqvfzZgzdakHscIVaDl6Cp+j5dwjsZ5LCgaUr6DtmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.46.2", + "@algolia/requester-browser-xhr": "5.46.2", + "@algolia/requester-fetch": "5.46.2", + "@algolia/requester-node-http": "5.46.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-query-suggestions": { + "version": "5.46.2", + "resolved": "https://registry.npmmirror.com/@algolia/client-query-suggestions/-/client-query-suggestions-5.46.2.tgz", + "integrity": "sha512-EgOzTZkyDcNL6DV0V/24+oBJ+hKo0wNgyrOX/mePBM9bc9huHxIY2352sXmoZ648JXXY2x//V1kropF/Spx83w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.46.2", + "@algolia/requester-browser-xhr": "5.46.2", + "@algolia/requester-fetch": "5.46.2", + "@algolia/requester-node-http": "5.46.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-search": { + "version": "5.46.2", + "resolved": "https://registry.npmmirror.com/@algolia/client-search/-/client-search-5.46.2.tgz", + "integrity": "sha512-ZsOJqu4HOG5BlvIFnMU0YKjQ9ZI6r3C31dg2jk5kMWPSdhJpYL9xa5hEe7aieE+707dXeMI4ej3diy6mXdZpgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.46.2", + "@algolia/requester-browser-xhr": "5.46.2", + "@algolia/requester-fetch": "5.46.2", + "@algolia/requester-node-http": "5.46.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/ingestion": { + "version": "1.46.2", + "resolved": "https://registry.npmmirror.com/@algolia/ingestion/-/ingestion-1.46.2.tgz", + "integrity": "sha512-1Uw2OslTWiOFDtt83y0bGiErJYy5MizadV0nHnOoHFWMoDqWW0kQoMFI65pXqRSkVvit5zjXSLik2xMiyQJDWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.46.2", + "@algolia/requester-browser-xhr": "5.46.2", + "@algolia/requester-fetch": "5.46.2", + "@algolia/requester-node-http": "5.46.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/monitoring": { + "version": "1.46.2", + "resolved": "https://registry.npmmirror.com/@algolia/monitoring/-/monitoring-1.46.2.tgz", + "integrity": "sha512-xk9f+DPtNcddWN6E7n1hyNNsATBCHIqAvVGG2EAGHJc4AFYL18uM/kMTiOKXE/LKDPyy1JhIerrh9oYb7RBrgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.46.2", + "@algolia/requester-browser-xhr": "5.46.2", + "@algolia/requester-fetch": "5.46.2", + "@algolia/requester-node-http": "5.46.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/recommend": { + "version": "5.46.2", + "resolved": "https://registry.npmmirror.com/@algolia/recommend/-/recommend-5.46.2.tgz", + "integrity": "sha512-NApbTPj9LxGzNw4dYnZmj2BoXiAc8NmbbH6qBNzQgXklGklt/xldTvu+FACN6ltFsTzoNU6j2mWNlHQTKGC5+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.46.2", + "@algolia/requester-browser-xhr": "5.46.2", + "@algolia/requester-fetch": "5.46.2", + "@algolia/requester-node-http": "5.46.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.46.2", + "resolved": "https://registry.npmmirror.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.46.2.tgz", + "integrity": "sha512-ekotpCwpSp033DIIrsTpYlGUCF6momkgupRV/FA3m62SreTSZUKjgK6VTNyG7TtYfq9YFm/pnh65bATP/ZWJEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.46.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.46.2", + "resolved": "https://registry.npmmirror.com/@algolia/requester-fetch/-/requester-fetch-5.46.2.tgz", + "integrity": "sha512-gKE+ZFi/6y7saTr34wS0SqYFDcjHW4Wminv8PDZEi0/mE99+hSrbKgJWxo2ztb5eqGirQTgIh1AMVacGGWM1iw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.46.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-node-http": { + "version": "5.46.2", + "resolved": "https://registry.npmmirror.com/@algolia/requester-node-http/-/requester-node-http-5.46.2.tgz", + "integrity": "sha512-ciPihkletp7ttweJ8Zt+GukSVLp2ANJHU+9ttiSxsJZThXc4Y2yJ8HGVWesW5jN1zrsZsezN71KrMx/iZsOYpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.46.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" }, "bin": { - "figlet": "bin/index.js" + "parser": "bin/babel-parser.js" }, "engines": { - "node": ">= 17.0.0" + "node": ">=6.0.0" } }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/@docsearch/core": { + "version": "4.4.0", + "resolved": "https://registry.npmmirror.com/@docsearch/core/-/core-4.4.0.tgz", + "integrity": "sha512-kiwNo5KEndOnrf5Kq/e5+D9NBMCFgNsDoRpKQJ9o/xnSlheh6b8AXppMuuUVVdAUIhIfQFk/07VLjjk/fYyKmw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": ">= 16.8.0 < 20.0.0", + "react": ">= 16.8.0 < 20.0.0", + "react-dom": ">= 16.8.0 < 20.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@docsearch/css": { + "version": "4.4.0", + "resolved": "https://registry.npmmirror.com/@docsearch/css/-/css-4.4.0.tgz", + "integrity": "sha512-e9vPgtih6fkawakmYo0Y6V4BKBmDV7Ykudn7ADWXUs5b6pmtBRwDbpSG/WiaUG63G28OkJDEnsMvgIAnZgGwYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@docsearch/js": { + "version": "4.4.0", + "resolved": "https://registry.npmmirror.com/@docsearch/js/-/js-4.4.0.tgz", + "integrity": "sha512-vCiKzjYD54bugUIMZA6YzuLDilkD3TNH/kfbvqsnzxiLTMu8F13psD+hdMSEOn7j+dFJOaf49fZ+gwr+rXctMw==", "dev": true, "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" + "@docsearch/react": "4.4.0", + "htm": "3.1.1" } }, - "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "node_modules/@docsearch/react": { + "version": "4.4.0", + "resolved": "https://registry.npmmirror.com/@docsearch/react/-/react-4.4.0.tgz", + "integrity": "sha512-z12zeg1mV7WD4Ag4pKSuGukETJLaucVFwszDXL/qLaEgRqxEaVacO9SR1qqnCXvZztlvz2rt7cMqryi/7sKfjA==", "dev": true, "license": "MIT", "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" + "@ai-sdk/react": "^2.0.30", + "@algolia/autocomplete-core": "1.19.2", + "@docsearch/core": "4.4.0", + "@docsearch/css": "4.4.0", + "ai": "^5.0.30", + "algoliasearch": "^5.28.0", + "marked": "^16.3.0", + "zod": "^4.1.8" }, - "engines": { - "node": ">= 0.8" + "peerDependencies": { + "@types/react": ">= 16.8.0 < 20.0.0", + "react": ">= 16.8.0 < 20.0.0", + "react-dom": ">= 16.8.0 < 20.0.0", + "search-insights": ">= 1 < 3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "search-insights": { + "optional": true + } } }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmmirror.com/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/@docsearch/react/node_modules/marked": { + "version": "16.4.2", + "resolved": "https://registry.npmmirror.com/marked/-/marked-16.4.2.tgz", + "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@element-plus/icons-vue": { + "version": "2.3.2", + "resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.3.2.tgz", + "integrity": "sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==", + "license": "MIT", + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.3", + "resolved": "https://registry.npmmirror.com/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.4", + "resolved": "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, + "node_modules/@iconify-json/simple-icons": { + "version": "1.2.66", + "resolved": "https://registry.npmmirror.com/@iconify-json/simple-icons/-/simple-icons-1.2.66.tgz", + "integrity": "sha512-D1OnnXwiQXFkVMw5M+Bt8mPsXeMkQyGmMdrmN7lsQlKMUkfLOp6JWhnUJ92po51WXT046aF/zzqSmkKqg08p4Q==", + "dev": true, + "license": "CC0-1.0", + "dependencies": { + "@iconify/types": "*" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@popperjs/core": { + "name": "@sxzz/popperjs-es", + "version": "2.11.7", + "resolved": "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz", + "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.53", + "resolved": "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.53.tgz", + "integrity": "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz", + "integrity": "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.1.tgz", + "integrity": "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.1.tgz", + "integrity": "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.1.tgz", + "integrity": "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.1.tgz", + "integrity": "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.1.tgz", + "integrity": "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.1.tgz", + "integrity": "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.1.tgz", + "integrity": "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.1.tgz", + "integrity": "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.1.tgz", + "integrity": "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.1.tgz", + "integrity": "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.1.tgz", + "integrity": "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.1.tgz", + "integrity": "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.1.tgz", + "integrity": "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.1.tgz", + "integrity": "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.1.tgz", + "integrity": "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.1.tgz", + "integrity": "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.1.tgz", + "integrity": "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.1.tgz", + "integrity": "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.1.tgz", + "integrity": "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.1.tgz", + "integrity": "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.1.tgz", + "integrity": "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.1.tgz", + "integrity": "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.1.tgz", + "integrity": "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.1.tgz", + "integrity": "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@shikijs/core": { + "version": "3.21.0", + "resolved": "https://registry.npmmirror.com/@shikijs/core/-/core-3.21.0.tgz", + "integrity": "sha512-AXSQu/2n1UIQekY8euBJlvFYZIw0PHY63jUzGbrOma4wPxzznJXTXkri+QcHeBNaFxiiOljKxxJkVSoB3PjbyA==", "dev": true, "license": "MIT", "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" + "@shikijs/types": "3.21.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.5" } }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmmirror.com/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "node_modules/@shikijs/engine-javascript": { + "version": "3.21.0", + "resolved": "https://registry.npmmirror.com/@shikijs/engine-javascript/-/engine-javascript-3.21.0.tgz", + "integrity": "sha512-ATwv86xlbmfD9n9gKRiwuPpWgPENAWCLwYCGz9ugTJlsO2kOzhOkvoyV/UD+tJ0uT7YRyD530x6ugNSffmvIiQ==", "dev": true, "license": "MIT", "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "@shikijs/types": "3.21.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.4" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "3.21.0", + "resolved": "https://registry.npmmirror.com/@shikijs/engine-oniguruma/-/engine-oniguruma-3.21.0.tgz", + "integrity": "sha512-OYknTCct6qiwpQDqDdf3iedRdzj6hFlOPv5hMvI+hkWfCKs5mlJ4TXziBG9nyabLwGulrUjHiCq3xCspSzErYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.21.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@shikijs/langs": { + "version": "3.21.0", + "resolved": "https://registry.npmmirror.com/@shikijs/langs/-/langs-3.21.0.tgz", + "integrity": "sha512-g6mn5m+Y6GBJ4wxmBYqalK9Sp0CFkUqfNzUy2pJglUginz6ZpWbaWjDB4fbQ/8SHzFjYbtU6Ddlp1pc+PPNDVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.21.0" + } + }, + "node_modules/@shikijs/themes": { + "version": "3.21.0", + "resolved": "https://registry.npmmirror.com/@shikijs/themes/-/themes-3.21.0.tgz", + "integrity": "sha512-BAE4cr9EDiZyYzwIHEk7JTBJ9CzlPuM4PchfcA5ao1dWXb25nv6hYsoDiBq2aZK9E3dlt3WB78uI96UESD+8Mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.21.0" + } + }, + "node_modules/@shikijs/transformers": { + "version": "3.21.0", + "resolved": "https://registry.npmmirror.com/@shikijs/transformers/-/transformers-3.21.0.tgz", + "integrity": "sha512-CZwvCWWIiRRiFk9/JKzdEooakAP8mQDtBOQ1TKiCaS2E1bYtyBCOkUzS8akO34/7ufICQ29oeSfkb3tT5KtrhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/core": "3.21.0", + "@shikijs/types": "3.21.0" + } + }, + "node_modules/@shikijs/types": { + "version": "3.21.0", + "resolved": "https://registry.npmmirror.com/@shikijs/types/-/types-3.21.0.tgz", + "integrity": "sha512-zGrWOxZ0/+0ovPY7PvBU2gIS9tmhSUUt30jAcNV0Bq0gb2S98gwfjIs1vxlmH5zM7/4YxLamT6ChlqqAJmPPjA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmmirror.com/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA==", + "license": "MIT" + }, + "node_modules/@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "license": "MIT", + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmmirror.com/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmmirror.com/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/web-animations-js": { + "version": "2.2.16", + "resolved": "https://registry.npmmirror.com/@types/web-animations-js/-/web-animations-js-2.2.16.tgz", + "integrity": "sha512-ATELeWMFwj8eQiH0KmvsCl1V2lu/qx/CjOBmv4ADSZS5u8r4reMyjCXtxG7khqyiwH3IOMNdrON/Ugn94OUcRA==", + "license": "MIT" + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.21", + "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", + "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@vercel/oidc": { + "version": "3.0.5", + "resolved": "https://registry.npmmirror.com/@vercel/oidc/-/oidc-3.0.5.tgz", + "integrity": "sha512-fnYhv671l+eTTp48gB4zEsTW/YtRgRPnkI2nT7x6qw5rkI1Lq2hTmQIpHPgyThI0znLK+vX2n9XxKdXZ7BUbbw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@vitejs/plugin-vue": { + "version": "6.0.3", + "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-6.0.3.tgz", + "integrity": "sha512-TlGPkLFLVOY3T7fZrwdvKpjprR3s4fxRln0ORDo1VQ7HHyxJwTlrjKU3kpVWTlaAjIEuCTokmjkZnr8Tpc925w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-beta.53" }, "engines": { - "node": ">=6 <7 || >=8" + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", + "vue": "^3.2.25" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.26", + "resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.26.tgz", + "integrity": "sha512-vXyI5GMfuoBCnv5ucIT7jhHKl55Y477yxP6fc4eUswjP8FG3FFVFd41eNDArR+Uk3QKn2Z85NavjaxLxOC19/w==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@vue/shared": "3.5.26", + "entities": "^7.0.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.26", + "resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.26.tgz", + "integrity": "sha512-y1Tcd3eXs834QjswshSilCBnKGeQjQXB6PqFn/1nxcQw4pmG42G8lwz+FZPAZAby6gZeHSt/8LMPfZ4Rb+Bd/A==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.26", + "@vue/shared": "3.5.26" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.26", + "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.26.tgz", + "integrity": "sha512-egp69qDTSEZcf4bGOSsprUr4xI73wfrY5oRs6GSgXFTiHrWj4Y3X5Ydtip9QMqiCMCPVwLglB9GBxXtTadJ3mA==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@vue/compiler-core": "3.5.26", + "@vue/compiler-dom": "3.5.26", + "@vue/compiler-ssr": "3.5.26", + "@vue/shared": "3.5.26", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.6", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.26", + "resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.26.tgz", + "integrity": "sha512-lZT9/Y0nSIRUPVvapFJEVDbEXruZh2IYHMk2zTtEgJSlP5gVOqeWXH54xDKAaFS4rTnDeDBQUYDtxKyoW9FwDw==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.26", + "@vue/shared": "3.5.26" + } + }, + "node_modules/@vue/devtools-api": { + "version": "8.0.5", + "resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-8.0.5.tgz", + "integrity": "sha512-DgVcW8H/Nral7LgZEecYFFYXnAvGuN9C3L3DtWekAncFBedBczpNW8iHKExfaM559Zm8wQWrwtYZ9lXthEHtDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^8.0.5" + } + }, + "node_modules/@vue/devtools-kit": { + "version": "8.0.5", + "resolved": "https://registry.npmmirror.com/@vue/devtools-kit/-/devtools-kit-8.0.5.tgz", + "integrity": "sha512-q2VV6x1U3KJMTQPUlRMyWEKVbcHuxhqJdSr6Jtjz5uAThAIrfJ6WVZdGZm5cuO63ZnSUz0RCsVwiUUb0mDV0Yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^8.0.5", + "birpc": "^2.6.1", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^2.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.2" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "8.0.5", + "resolved": "https://registry.npmmirror.com/@vue/devtools-shared/-/devtools-shared-8.0.5.tgz", + "integrity": "sha512-bRLn6/spxpmgLk+iwOrR29KrYnJjG9DGpHGkDFG82UM21ZpJ39ztUT9OXX3g+usW7/b2z+h46I9ZiYyB07XMXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "rfdc": "^1.4.1" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.26", + "resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.26.tgz", + "integrity": "sha512-9EnYB1/DIiUYYnzlnUBgwU32NNvLp/nhxLXeWRhHUEeWNTn1ECxX8aGO7RTXeX6PPcxe3LLuNBFoJbV4QZ+CFQ==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.26" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.26", + "resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.26.tgz", + "integrity": "sha512-xJWM9KH1kd201w5DvMDOwDHYhrdPTrAatn56oB/LRG4plEQeZRQLw0Bpwih9KYoqmzaxF0OKSn6swzYi84e1/Q==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.26", + "@vue/shared": "3.5.26" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.26", + "resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.26.tgz", + "integrity": "sha512-XLLd/+4sPC2ZkN/6+V4O4gjJu6kSDbHAChvsyWgm1oGbdSO3efvGYnm25yCjtFm/K7rrSDvSfPDgN1pHgS4VNQ==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.26", + "@vue/runtime-core": "3.5.26", + "@vue/shared": "3.5.26", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.26", + "resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.26.tgz", + "integrity": "sha512-TYKLXmrwWKSodyVuO1WAubucd+1XlLg4set0YoV+Hu8Lo79mp/YMwWV5mC5FgtsDxX3qo1ONrxFaTP1OQgy1uA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.26", + "@vue/shared": "3.5.26" + }, + "peerDependencies": { + "vue": "3.5.26" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.26", + "resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.26.tgz", + "integrity": "sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A==", + "license": "MIT" + }, + "node_modules/@vueuse/core": { + "version": "14.1.0", + "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-14.1.0.tgz", + "integrity": "sha512-rgBinKs07hAYyPF834mDTigH7BtPqvZ3Pryuzt1SD/lg5wEcWqvwzXXYGEDb2/cP0Sj5zSvHl3WkmMELr5kfWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.21", + "@vueuse/metadata": "14.1.0", + "@vueuse/shared": "14.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/@vueuse/integrations": { + "version": "14.1.0", + "resolved": "https://registry.npmmirror.com/@vueuse/integrations/-/integrations-14.1.0.tgz", + "integrity": "sha512-eNQPdisnO9SvdydTIXnTE7c29yOsJBD/xkwEyQLdhDC/LKbqrFpXHb3uS//7NcIrQO3fWVuvMGp8dbK6mNEMCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vueuse/core": "14.1.0", + "@vueuse/shared": "14.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "async-validator": "^4", + "axios": "^1", + "change-case": "^5", + "drauu": "^0.4", + "focus-trap": "^7", + "fuse.js": "^7", + "idb-keyval": "^6", + "jwt-decode": "^4", + "nprogress": "^0.2", + "qrcode": "^1.5", + "sortablejs": "^1", + "universal-cookie": "^7 || ^8", + "vue": "^3.5.0" + }, + "peerDependenciesMeta": { + "async-validator": { + "optional": true + }, + "axios": { + "optional": true + }, + "change-case": { + "optional": true + }, + "drauu": { + "optional": true + }, + "focus-trap": { + "optional": true + }, + "fuse.js": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "jwt-decode": { + "optional": true + }, + "nprogress": { + "optional": true + }, + "qrcode": { + "optional": true + }, + "sortablejs": { + "optional": true + }, + "universal-cookie": { + "optional": true + } + } + }, + "node_modules/@vueuse/metadata": { + "version": "14.1.0", + "resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-14.1.0.tgz", + "integrity": "sha512-7hK4g015rWn2PhKcZ99NyT+ZD9sbwm7SGvp7k+k+rKGWnLjS/oQozoIZzWfCewSUeBmnJkIb+CNr7Zc/EyRnnA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "14.1.0", + "resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-14.1.0.tgz", + "integrity": "sha512-EcKxtYvn6gx1F8z9J5/rsg3+lTQnvOruQd8fUecW99DCK04BkWD7z5KQ/wTAx+DazyoEE9dJt/zV8OIEQbM6kw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/ai": { + "version": "5.0.119", + "resolved": "https://registry.npmmirror.com/ai/-/ai-5.0.119.tgz", + "integrity": "sha512-HUOwhc17fl2SZTJGZyA/99aNu706qKfXaUBCy9vgZiXBwrxg2eTzn2BCz7kmYDsfx6Fg2ACBy2icm41bsDXCTw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/gateway": "2.0.25", + "@ai-sdk/provider": "2.0.1", + "@ai-sdk/provider-utils": "3.0.20", + "@opentelemetry/api": "1.9.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/algoliasearch": { + "version": "5.46.2", + "resolved": "https://registry.npmmirror.com/algoliasearch/-/algoliasearch-5.46.2.tgz", + "integrity": "sha512-qqAXW9QvKf2tTyhpDA4qXv1IfBwD2eduSW6tUEBFIfCeE9gn9HQ9I5+MaKoenRuHrzk5sQoNh1/iof8mY7uD6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/abtesting": "1.12.2", + "@algolia/client-abtesting": "5.46.2", + "@algolia/client-analytics": "5.46.2", + "@algolia/client-common": "5.46.2", + "@algolia/client-insights": "5.46.2", + "@algolia/client-personalization": "5.46.2", + "@algolia/client-query-suggestions": "5.46.2", + "@algolia/client-search": "5.46.2", + "@algolia/ingestion": "1.46.2", + "@algolia/monitoring": "1.46.2", + "@algolia/recommend": "5.46.2", + "@algolia/requester-browser-xhr": "5.46.2", + "@algolia/requester-fetch": "5.46.2", + "@algolia/requester-node-http": "5.46.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/async-validator": { + "version": "4.2.5", + "resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==", + "license": "MIT" + }, + "node_modules/birpc": { + "version": "2.9.0", + "resolved": "https://registry.npmmirror.com/birpc/-/birpc-2.9.0.tgz", + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/copy-anything": { + "version": "4.0.5", + "resolved": "https://registry.npmmirror.com/copy-anything/-/copy-anything-4.0.5.tgz", + "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-what": "^5.2.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/dayjs": { + "version": "1.11.19", + "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.19.tgz", + "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==", + "license": "MIT" + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/element-plus": { + "version": "2.13.1", + "resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.13.1.tgz", + "integrity": "sha512-eG4BDBGdAsUGN6URH1PixzZb0ngdapLivIk1meghS1uEueLvQ3aljSKrCt5x6sYb6mUk8eGtzTQFgsPmLavQcA==", + "license": "MIT", + "dependencies": { + "@ctrl/tinycolor": "^3.4.1", + "@element-plus/icons-vue": "^2.3.2", + "@floating-ui/dom": "^1.0.1", + "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7", + "@types/lodash": "^4.17.20", + "@types/lodash-es": "^4.17.12", + "@vueuse/core": "^10.11.0", + "async-validator": "^4.2.5", + "dayjs": "^1.11.19", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "lodash-unified": "^1.0.3", + "memoize-one": "^6.0.0", + "normalize-wheel-es": "^1.2.0" + }, + "peerDependencies": { + "vue": "^3.3.0" + } + }, + "node_modules/element-plus/node_modules/@types/web-bluetooth": { + "version": "0.0.20", + "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", + "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==", + "license": "MIT" + }, + "node_modules/element-plus/node_modules/@vueuse/core": { + "version": "10.11.1", + "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-10.11.1.tgz", + "integrity": "sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==", + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.20", + "@vueuse/metadata": "10.11.1", + "@vueuse/shared": "10.11.1", + "vue-demi": ">=0.14.8" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/element-plus/node_modules/@vueuse/core/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/element-plus/node_modules/@vueuse/metadata": { + "version": "10.11.1", + "resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-10.11.1.tgz", + "integrity": "sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/element-plus/node_modules/@vueuse/shared": { + "version": "10.11.1", + "resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-10.11.1.tgz", + "integrity": "sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==", + "license": "MIT", + "dependencies": { + "vue-demi": ">=0.14.8" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/element-plus/node_modules/@vueuse/shared/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/entities": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/entities/-/entities-7.0.0.tgz", + "integrity": "sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.27.2", + "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmmirror.com/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/focus-trap": { + "version": "7.8.0", + "resolved": "https://registry.npmmirror.com/focus-trap/-/focus-trap-7.8.0.tgz", + "integrity": "sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tabbable": "^6.4.0" } }, "node_modules/fsevents": { @@ -827,1649 +2189,962 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-port": { - "version": "5.1.1", - "resolved": "https://registry.npmmirror.com/get-port/-/get-port-5.1.1.tgz", - "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmmirror.com/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmmirror.com/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", "dev": true, "license": "MIT", "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/global-dirs": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/global-dirs/-/global-dirs-2.1.0.tgz", - "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ini": "1.3.7" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/got": { - "version": "9.6.0", - "resolved": "https://registry.npmmirror.com/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.2.0", - "resolved": "https://registry.npmmirror.com/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", - "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/express" + "url": "https://opencollective.com/unified" } }, - "node_modules/http-errors/node_modules/statuses": { + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmmirror.com/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/htm": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/htm/-/htm-3.1.1.tgz", + "integrity": "sha512-983Vyg8NwUE7JkZ6NmOqpCZ+sh1bKv2iYTlUkzlWmA5JD2acKoxd4KVxbMmxX/85mtfdnDmTFoNKcg5DGAvxNQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-what": { + "version": "5.5.0", + "resolved": "https://registry.npmmirror.com/is-what/-/is-what-5.5.0.tgz", + "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true, + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.17.22", + "resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.22.tgz", + "integrity": "sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q==", + "license": "MIT" + }, + "node_modules/lodash-unified": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/lodash-unified/-/lodash-unified-1.0.3.tgz", + "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==", + "license": "MIT", + "peerDependencies": { + "@types/lodash-es": "*", + "lodash": "*", + "lodash-es": "*" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/mark.js": { + "version": "8.11.1", + "resolved": "https://registry.npmmirror.com/mark.js/-/mark.js-8.11.1.tgz", + "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmmirror.com/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", + "license": "MIT" + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "resolved": "https://registry.npmmirror.com/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/minisearch": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/minisearch/-/minisearch-7.2.0.tgz", + "integrity": "sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg==", + "dev": true, + "license": "MIT" + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmmirror.com/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/ini": { - "version": "1.3.7", - "resolved": "https://registry.npmmirror.com/ini/-/ini-1.3.7.tgz", - "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ci-info": "^2.0.0" - }, "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", + "nanoid": "bin/nanoid.cjs" + }, "engines": { - "node": ">=0.10.0" + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/normalize-wheel-es": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", + "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==", + "license": "BSD-3-Clause" + }, + "node_modules/oniguruma-parser": { + "version": "0.12.1", + "resolved": "https://registry.npmmirror.com/oniguruma-parser/-/oniguruma-parser-0.12.1.tgz", + "integrity": "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/oniguruma-to-es": { + "version": "4.3.4", + "resolved": "https://registry.npmmirror.com/oniguruma-to-es/-/oniguruma-to-es-4.3.4.tgz", + "integrity": "sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==", "dev": true, "license": "MIT", "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" + "oniguruma-parser": "^0.12.1", + "regex": "^6.0.1", + "regex-recursion": "^6.0.2" } }, - "node_modules/is-installed-globally": { - "version": "0.3.2", - "resolved": "https://registry.npmmirror.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz", - "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "node_modules/perfect-debounce": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/perfect-debounce/-/perfect-debounce-2.0.0.tgz", + "integrity": "sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow==", "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "global-dirs": "^2.0.1", - "is-path-inside": "^3.0.1" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { - "node": ">=8" + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prettier": { + "version": "3.7.4", + "resolved": "https://registry.npmmirror.com/prettier/-/prettier-3.7.4.tgz", + "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/is-npm": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/is-npm/-/is-npm-4.0.0.tgz", - "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmmirror.com/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/react": { + "version": "19.2.3", + "resolved": "https://registry.npmmirror.com/react/-/react-19.2.3.tgz", + "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "dev": true, "license": "MIT", + "peer": true, "engines": { - "node": ">=0.12.0" + "node": ">=0.10.0" } }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "node_modules/regex": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "regex-utilities": "^2.3.0" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmmirror.com/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "regex-utilities": "^2.3.0" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", "dev": true, "license": "MIT" }, - "node_modules/is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/rollup": { + "version": "4.55.1", + "resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.55.1.tgz", + "integrity": "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==", "dev": true, "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, "engines": { - "node": ">=4" - } - }, - "node_modules/is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmmirror.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "license": "MIT", + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, "optionalDependencies": { - "graceful-fs": "^4.1.6" + "@rollup/rollup-android-arm-eabi": "4.55.1", + "@rollup/rollup-android-arm64": "4.55.1", + "@rollup/rollup-darwin-arm64": "4.55.1", + "@rollup/rollup-darwin-x64": "4.55.1", + "@rollup/rollup-freebsd-arm64": "4.55.1", + "@rollup/rollup-freebsd-x64": "4.55.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", + "@rollup/rollup-linux-arm-musleabihf": "4.55.1", + "@rollup/rollup-linux-arm64-gnu": "4.55.1", + "@rollup/rollup-linux-arm64-musl": "4.55.1", + "@rollup/rollup-linux-loong64-gnu": "4.55.1", + "@rollup/rollup-linux-loong64-musl": "4.55.1", + "@rollup/rollup-linux-ppc64-gnu": "4.55.1", + "@rollup/rollup-linux-ppc64-musl": "4.55.1", + "@rollup/rollup-linux-riscv64-gnu": "4.55.1", + "@rollup/rollup-linux-riscv64-musl": "4.55.1", + "@rollup/rollup-linux-s390x-gnu": "4.55.1", + "@rollup/rollup-linux-x64-gnu": "4.55.1", + "@rollup/rollup-linux-x64-musl": "4.55.1", + "@rollup/rollup-openbsd-x64": "4.55.1", + "@rollup/rollup-openharmony-arm64": "4.55.1", + "@rollup/rollup-win32-arm64-msvc": "4.55.1", + "@rollup/rollup-win32-ia32-msvc": "4.55.1", + "@rollup/rollup-win32-x64-gnu": "4.55.1", + "@rollup/rollup-win32-x64-msvc": "4.55.1", + "fsevents": "~2.3.2" } }, - "node_modules/keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "node_modules/search-insights": { + "version": "2.17.3", + "resolved": "https://registry.npmmirror.com/search-insights/-/search-insights-2.17.3.tgz", + "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/shiki": { + "version": "3.21.0", + "resolved": "https://registry.npmmirror.com/shiki/-/shiki-3.21.0.tgz", + "integrity": "sha512-N65B/3bqL/TI2crrXr+4UivctrAGEjmsib5rPMMPpFp1xAx/w03v8WZ9RDDFYteXoEgY7qZ4HGgl5KBIu1153w==", "dev": true, "license": "MIT", "dependencies": { - "json-buffer": "3.0.0" + "@shikijs/core": "3.21.0", + "@shikijs/engine-javascript": "3.21.0", + "@shikijs/engine-oniguruma": "3.21.0", + "@shikijs/langs": "3.21.0", + "@shikijs/themes": "3.21.0", + "@shikijs/types": "3.21.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" } }, - "node_modules/latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmmirror.com/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", - "dev": true, - "license": "MIT", - "dependencies": { - "package-json": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/livereload": { - "version": "0.9.3", - "resolved": "https://registry.npmmirror.com/livereload/-/livereload-0.9.3.tgz", - "integrity": "sha512-q7Z71n3i4X0R9xthAryBdNGVGAO2R5X+/xXpmKeuPMrteg+W2U8VusTKV3YiJbXZwKsOlFlHe+go6uSNjfxrZw==", - "dev": true, - "license": "MIT", - "dependencies": { - "chokidar": "^3.5.0", - "livereload-js": "^3.3.1", - "opts": ">= 1.2.0", - "ws": "^7.4.3" - }, - "bin": { - "livereload": "bin/livereload.js" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/livereload-js": { - "version": "3.4.1", - "resolved": "https://registry.npmmirror.com/livereload-js/-/livereload-js-3.4.1.tgz", - "integrity": "sha512-5MP0uUeVCec89ZbNOT/i97Mc+q3SxXmiUGhRFOTmhrGPn//uWVQdCvcLJDy64MSBR5MidFdOR7B9viumoavy6g==", - "dev": true, - "license": "MIT" - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true, - "license": "MIT", + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/marked": { - "version": "1.2.9", - "resolved": "https://registry.npmmirror.com/marked/-/marked-1.2.9.tgz", - "integrity": "sha512-H8lIX2SvyitGX+TRdtS06m1jHMijKN/XjfH6Ooii9fvxMlh8QdqBfBDkGUpMWH2kQNrtixjzYUa3SH8ROTgRRw==", - "dev": true, - "license": "MIT", - "bin": { - "marked": "bin/marked" - }, - "engines": { - "node": ">= 8.16.2" - } - }, - "node_modules/medium-zoom": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/medium-zoom/-/medium-zoom-1.1.0.tgz", - "integrity": "sha512-ewyDsp7k4InCUp3jRmwHBRFGyjBimKps/AJLjRSox+2q/2H4p/PNpQf+pwONWlJiOudkBXtbdmVbFjqyybfTmQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmmirror.com/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", "dev": true, "license": "MIT", "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmmirror.com/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", "dev": true, - "license": "MIT" + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/nested-error-stacks": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz", - "integrity": "sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmmirror.com/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", "dev": true, "license": "MIT", "dependencies": { - "whatwg-url": "^5.0.0" + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/superjson": { + "version": "2.2.6", + "resolved": "https://registry.npmmirror.com/superjson/-/superjson-2.2.6.tgz", + "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "copy-anything": "^4" }, "engines": { - "node": "4.x || >=6.0.0" + "node": ">=16" + } + }, + "node_modules/swr": { + "version": "2.3.8", + "resolved": "https://registry.npmmirror.com/swr/-/swr-2.3.8.tgz", + "integrity": "sha512-gaCPRVoMq8WGDcWj9p4YWzCMPHzE0WNl6W8ADIx9c3JBEIdMkJGMzW+uzXvxHMltwcYACr9jP+32H8/hgwMR7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3", + "use-sync-external-store": "^1.6.0" }, "peerDependencies": { - "encoding": "^0.1.0" + "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/tabbable": { + "version": "6.4.0", + "resolved": "https://registry.npmmirror.com/tabbable/-/tabbable-6.4.0.tgz", + "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==", + "dev": true, + "license": "MIT" + }, + "node_modules/throttleit": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/throttleit/-/throttleit-2.1.0.tgz", + "integrity": "sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" }, "peerDependenciesMeta": { - "encoding": { + "picomatch": { "optional": true } } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmmirror.com/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmmirror.com/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", - "dev": true, - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/open": { - "version": "6.4.0", - "resolved": "https://registry.npmmirror.com/open/-/open-6.4.0.tgz", - "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-wsl": "^1.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/opencollective-postinstall": { - "version": "2.0.3", - "resolved": "https://registry.npmmirror.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", - "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", - "dev": true, - "license": "MIT", - "bin": { - "opencollective-postinstall": "index.js" - } - }, - "node_modules/opts": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/opts/-/opts-2.0.2.tgz", - "integrity": "sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/p-event": { - "version": "4.2.0", - "resolved": "https://registry.npmmirror.com/p-event/-/p-event-4.2.0.tgz", - "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-timeout": "^3.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmmirror.com/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-timeout": { - "version": "3.2.0", - "resolved": "https://registry.npmmirror.com/p-timeout/-/p-timeout-3.2.0.tgz", - "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-finally": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmmirror.com/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/parent-require": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/parent-require/-/parent-require-1.0.0.tgz", - "integrity": "sha512-2MXDNZC4aXdkkap+rBBMv0lUsfJqvX5/2FiYYnfCnorZt3Pk06/IOR5KeaoghgS2w07MLWgjbsnyaq6PdHn2LQ==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/prismjs": { - "version": "1.30.0", - "resolved": "https://registry.npmmirror.com/prismjs/-/prismjs-1.30.0.tgz", - "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmmirror.com/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", - "dev": true, - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-goat": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmmirror.com/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/registry-auth-token": { - "version": "4.2.2", - "resolved": "https://registry.npmmirror.com/registry-auth-token/-/registry-auth-token-4.2.2.tgz", - "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", - "dev": true, - "license": "MIT", - "dependencies": { - "rc": "1.2.8" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmmirror.com/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", - "dev": true, - "license": "MIT", - "dependencies": { - "rc": "^1.2.8" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true, - "license": "ISC" - }, - "node_modules/resolve-pathname": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz", - "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==", - "dev": true, - "license": "MIT" - }, - "node_modules/responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "lowercase-keys": "^1.0.0" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/send": { - "version": "0.19.2", - "resolved": "https://registry.npmmirror.com/send/-/send-0.19.2.tgz", - "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.4.1", - "range-parser": "~1.2.1", - "statuses": "~2.0.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/send/node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmmirror.com/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/send/node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/serve-static": { - "version": "1.16.3", - "resolved": "https://registry.npmmirror.com/serve-static/-/serve-static-1.16.3.tgz", - "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "~0.19.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/serve-static/node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true, - "license": "ISC" - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true, - "license": "ISC" - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmmirror.com/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/term-size": { - "version": "2.2.1", - "resolved": "https://registry.npmmirror.com/term-size/-/term-size-2.2.1.tgz", - "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tinydate": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/tinydate/-/tinydate-1.3.0.tgz", - "integrity": "sha512-7cR8rLy2QhYHpsBDBVYnnWXm8uRTr38RoZakFSW7Bs7PzfMPNZthuMLkwqZv7MTu8lhQ91cOFYS5a7iFj2oR3w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true, - "license": "MIT" - }, - "node_modules/tweezer.js": { - "version": "1.5.0", - "resolved": "https://registry.npmmirror.com/tweezer.js/-/tweezer.js-1.5.0.tgz", - "integrity": "sha512-aSiJz7rGWNAQq7hjMK9ZYDuEawXupcCWgl3woQQSoDP2Oh8O4srWb/uO1PzzHIsrPEOqrjJ2sUb9FERfzuBabQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=8" - } - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dev": true, - "license": "MIT", - "dependencies": { - "crypto-random-string": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmmirror.com/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/update-notifier": { - "version": "4.1.3", - "resolved": "https://registry.npmmirror.com/update-notifier/-/update-notifier-4.1.3.tgz", - "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "boxen": "^4.2.0", - "chalk": "^3.0.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.3.1", - "is-npm": "^4.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.0.0", - "pupa": "^2.0.1", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/yeoman/update-notifier?sponsor=1" - } - }, - "node_modules/update-notifier/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/update-notifier/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/update-notifier/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/update-notifier/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/update-notifier/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/update-notifier/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prepend-http": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/webidl-conversions": { + "node_modules/trim-lines": { "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "resolved": "https://registry.npmmirror.com/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", "dev": true, "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/which-module": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/which-module/-/which-module-2.0.1.tgz", - "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dev": true, - "license": "MIT", + "node_modules/typeit": { + "version": "8.8.7", + "resolved": "https://registry.npmmirror.com/typeit/-/typeit-8.8.7.tgz", + "integrity": "sha512-sSVpy+cjeFP6Z+fZqiHzUSShg5yYFeJEt/Qut/bX945+Axyq+Yq+GPOuuk+sofoccSv8nNX/ibOOHkbki2mEpg==", + "hasInstallScript": true, + "license": "GPL-3.0", "dependencies": { - "string-width": "^4.0.0" - }, - "engines": { - "node": ">=8" + "@types/web-animations-js": "^2.2.16" } }, - "node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" + "@types/unist": "^3.0.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", "dev": true, "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "@types/unist": "^3.0.0" }, - "engines": { - "node": ">=7.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmmirror.com/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/viewerjs": { + "version": "1.11.7", + "resolved": "https://registry.npmmirror.com/viewerjs/-/viewerjs-1.11.7.tgz", + "integrity": "sha512-0JuVqOmL5v1jmEAlG5EBDR3XquxY8DWFQbFMprOXgaBB0F7Q/X9xWdEaQc59D8xzwkdUgXEMSSknTpriq95igg==", "license": "MIT" }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmmirror.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/ws": { - "version": "7.5.10", - "resolved": "https://registry.npmmirror.com/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmmirror.com/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, "engines": { - "node": ">=8.3.0" + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" }, "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { - "bufferutil": { + "@types/node": { "optional": true }, - "utf-8-validate": { + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { "optional": true } } }, - "node_modules/xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "node_modules/y18n": { + "node_modules/vite/node_modules/picomatch": { "version": "4.0.3", - "resolved": "https://registry.npmmirror.com/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, - "node_modules/yargonaut": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/yargonaut/-/yargonaut-1.1.4.tgz", - "integrity": "sha512-rHgFmbgXAAzl+1nngqOcwEljqHGG9uUZoPjsdZEs1w5JW9RXYzrSvH/u70C1JE5qFi0qjsdhnUX/dJRpWqitSA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "chalk": "^1.1.1", - "figlet": "^1.1.1", - "parent-require": "^1.0.0" - } - }, - "node_modules/yargonaut/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yargonaut/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yargonaut/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "node": ">=12" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/yargonaut/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "node_modules/vitepress": { + "version": "2.0.0-alpha.15", + "resolved": "https://registry.npmmirror.com/vitepress/-/vitepress-2.0.0-alpha.15.tgz", + "integrity": "sha512-jhjSYd10Z6RZiKOa7jy0xMVf5NB5oSc/lS3bD/QoUc6V8PrvQR5JhC9104NEt6+oTGY/ftieVWxY9v7YI+1IjA==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^2.0.0" + "@docsearch/css": "^4.3.2", + "@docsearch/js": "^4.3.2", + "@iconify-json/simple-icons": "^1.2.59", + "@shikijs/core": "^3.15.0", + "@shikijs/transformers": "^3.15.0", + "@shikijs/types": "^3.15.0", + "@types/markdown-it": "^14.1.2", + "@vitejs/plugin-vue": "^6.0.1", + "@vue/devtools-api": "^8.0.5", + "@vue/shared": "^3.5.24", + "@vueuse/core": "^14.0.0", + "@vueuse/integrations": "^14.0.0", + "focus-trap": "^7.6.6", + "mark.js": "8.11.1", + "minisearch": "^7.2.0", + "shiki": "^3.15.0", + "vite": "^7.2.2", + "vue": "^3.5.24" }, - "engines": { - "node": ">=0.10.0" + "bin": { + "vitepress": "bin/vitepress.js" + }, + "peerDependencies": { + "markdown-it-mathjax3": "^4", + "oxc-minify": "*", + "postcss": "^8" + }, + "peerDependenciesMeta": { + "markdown-it-mathjax3": { + "optional": true + }, + "oxc-minify": { + "optional": true + }, + "postcss": { + "optional": true + } } }, - "node_modules/yargonaut/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmmirror.com/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, + "node_modules/vue": { + "version": "3.5.26", + "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.26.tgz", + "integrity": "sha512-SJ/NTccVyAoNUJmkM9KUqPcYlY+u8OVL1X5EW9RIs3ch5H2uERxyyIUI4MRxVCSOiEcupX9xNGde1tL9ZKpimA==", "license": "MIT", "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" + "@vue/compiler-dom": "3.5.26", + "@vue/compiler-sfc": "3.5.26", + "@vue/runtime-dom": "3.5.26", + "@vue/server-renderer": "3.5.26", + "@vue/shared": "3.5.26" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "node_modules/zod": { + "version": "4.3.5", + "resolved": "https://registry.npmmirror.com/zod/-/zod-4.3.5.tgz", + "integrity": "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==", "dev": true, - "license": "ISC", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } } } diff --git a/package.json b/package.json index b203a49..6bb9fd9 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,30 @@ { - "name": "vibe-coding", + "name": "easy-vibe", "version": "1.0.0", - "private": true, + "description": "Easy-Vibe 中文实战课 - 零基础学会用 AI 编程", + "type": "module", "scripts": { - "dev": "docsify serve docs -p 3000", - "start": "npm run dev" + "dev": "vitepress dev docs", + "build": "vitepress build docs", + "preview": "vitepress preview docs", + "format": "prettier --write ." }, + "keywords": [ + "easy-vibe", + "ai", + "tutorial", + "vitepress" + ], + "license": "CC-BY-NC-SA-4.0", "devDependencies": { - "docsify-cli": "^4.4.4" + "prettier": "^3.7.4", + "vitepress": "2.0.0-alpha.15", + "vue": "^3.5.0" + }, + "dependencies": { + "@element-plus/icons-vue": "^2.3.2", + "element-plus": "^2.13.1", + "typeit": "^8.8.7", + "viewerjs": "^1.11.7" } } - diff --git a/vercel.json b/vercel.json new file mode 100644 index 0000000..958d026 --- /dev/null +++ b/vercel.json @@ -0,0 +1,3 @@ +{ + "outputDirectory": "docs/.vitepress/dist" +}