- 添加常见开发模式指南(API 端点、数据库字段、自定义 Agent、多语言内容) - 新增故障排除部分,涵盖常见问题和调试技巧 - 改进 GET /api/discovery/tasks 端点,支持通过查询参数传递 API key - 更新环境变量示例,使用更安全的 API key 格式
549 lines
15 KiB
Markdown
549 lines
15 KiB
Markdown
# 项目发现工作流 (Project Discovery Workflow)
|
||
|
||
本文档详细说明了 AI 项目自动发现和收录的完整工作流程。
|
||
|
||
## 📋 工作流概览
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ 项目发现完整流程 │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
|
||
1. n8n 自动化平台
|
||
│
|
||
├─ 定期抓取 GitHub/Twitter/HackerNews 等平台
|
||
├─ 筛选符合条件的项目链接
|
||
│
|
||
▼
|
||
2. 调用去重检查 API (推荐)
|
||
POST /api/discovery/check-duplicates
|
||
│
|
||
├─ 检查 URL 是否已存在任务
|
||
├─ 检查 URL 对应项目是否已收录
|
||
├─ 过滤出需要创建的 URL
|
||
│
|
||
▼
|
||
3. 调用创建任务 API
|
||
POST /api/discovery/tasks
|
||
│
|
||
├─ 存入 ProjectDiscoveryTask 表
|
||
├─ 状态: PENDING
|
||
│
|
||
▼
|
||
4. 手动触发本地命令 (定期执行)
|
||
/discover-projects
|
||
│
|
||
├─ 通过 curl 获取待处理任务
|
||
├─ 调用 Content Explorer Agent
|
||
│ ├─ 使用 agent-browser 探索项目
|
||
│ ├─ 提取项目信息 (README, 代码结构等)
|
||
│ ├─ 生成结构化 JSON 数据
|
||
│ └─ 应用内容质量标准
|
||
│
|
||
├─ 调用 API Submitter Agent
|
||
│ ├─ 批量标记任务为 IN_PROGRESS
|
||
│ ├─ 提交探索数据到完成 API
|
||
│ └─ 自动重试失败的提交
|
||
│
|
||
▼
|
||
5. 完成任务并入库
|
||
POST /api/discovery/tasks/{id}/complete
|
||
│
|
||
├─ 验证数据格式 (Zod Schema)
|
||
├─ 多级去重检测 (GitHub/Website URL)
|
||
├─ 创建或更新 Project
|
||
├─ 创建 Tag 和关联关系
|
||
├─ 创建 ExternalLink
|
||
│
|
||
├─ 更新任务状态: COMPLETED/FAILED
|
||
│
|
||
▼
|
||
6. 数据已入库,可在前台展示
|
||
```
|
||
|
||
---
|
||
|
||
## 🔄 详细步骤说明
|
||
|
||
### 步骤 1: n8n 自动收集项目链接
|
||
|
||
**平台**: n8n 自动化平台 (独立部署)
|
||
|
||
**工作内容**:
|
||
- 定期抓取 GitHub Trending、Twitter、HackerNews 等平台
|
||
- 根据关键词筛选 AI 相关项目
|
||
- 提取项目的基本信息 (名称、链接、简介等)
|
||
|
||
**输出数据格式**:
|
||
```json
|
||
{
|
||
"sourceUrl": "https://github.com/langchain-ai/langchain",
|
||
"sourceType": "github_trending" // 或 "twitter", "hackernews" 等
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 步骤 2: 调用创建任务 API
|
||
|
||
**API 端点**: `POST /api/discovery/tasks`
|
||
|
||
**调用示例**:
|
||
```bash
|
||
curl -X POST https://your-domain.com/api/discovery/tasks \
|
||
-H "Content-Type: application/json" \
|
||
-H "x-api-key: YOUR_API_KEY" \
|
||
-d '{
|
||
"apiKey": "YOUR_API_KEY",
|
||
"tasks": [
|
||
{
|
||
"sourceUrl": "https://github.com/langchain-ai/langchain",
|
||
"sourceType": "github_trending"
|
||
},
|
||
{
|
||
"sourceUrl": "https://github.com/openai/openai-quickstart-python",
|
||
"sourceType": "github_trending"
|
||
}
|
||
]
|
||
}'
|
||
```
|
||
|
||
**数据库变更**:
|
||
- 在 `ProjectDiscoveryTask` 表中插入新记录
|
||
- `status` = `PENDING`
|
||
- `sourceUrl` 和 `sourceType` 来自 n8n
|
||
- `createdAt` = 当前时间
|
||
|
||
---
|
||
|
||
### 步骤 2.5: 调用去重检查 API(推荐)
|
||
|
||
**API 端点**: `POST /api/discovery/check-duplicates`
|
||
|
||
**调用示例**:
|
||
```bash
|
||
curl -X POST https://your-domain.com/api/discovery/check-duplicates \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"apiKey": "YOUR_API_KEY",
|
||
"urls": [
|
||
"https://github.com/langchain-ai/langchain",
|
||
"https://github.com/openai/openai-quickstart-python"
|
||
]
|
||
}'
|
||
```
|
||
|
||
**返回结果**:
|
||
```json
|
||
{
|
||
"success": true,
|
||
"results": [
|
||
{
|
||
"url": "https://github.com/langchain-ai/langchain",
|
||
"shouldCreate": false,
|
||
"reason": "Task already exists with status PENDING",
|
||
"existingTask": {
|
||
"id": "cmxxxxx",
|
||
"status": "PENDING",
|
||
"sourceUrl": "https://github.com/langchain-ai/langchain",
|
||
"createdAt": "2025-01-18T10:00:00Z",
|
||
"projectId": null
|
||
}
|
||
},
|
||
{
|
||
"url": "https://github.com/openai/openai-quickstart-python",
|
||
"shouldCreate": true,
|
||
"reason": "No existing task or project found"
|
||
}
|
||
],
|
||
"stats": {
|
||
"total": 2,
|
||
"shouldCreate": 1,
|
||
"duplicate": 1
|
||
}
|
||
}
|
||
```
|
||
|
||
**去重逻辑**(按优先级):
|
||
1. **优先级 1**: 检查是否有 PENDING/IN_PROGRESS 的相同 URL 任务
|
||
- 如果存在 → `shouldCreate: false`
|
||
- 原因:任务已在处理中,避免重复探索
|
||
|
||
2. **优先级 2**: 检查是否有 COMPLETED/FAILED 的相同 URL 任务
|
||
- 如果存在 → `shouldCreate: false`
|
||
- 原因:任务已探索过,无需重复
|
||
|
||
3. **优先级 3**: 检查 URL 对应的项目是否已存在(通过 ExternalLink)
|
||
- 如果存在 → `shouldCreate: false`
|
||
- 原因:项目已通过其他来源收录
|
||
|
||
4. **默认**: 允许创建新任务
|
||
- `shouldCreate: true`
|
||
|
||
**n8n 集成建议**:
|
||
```javascript
|
||
// n8n Workflow 示例
|
||
const checkResponse = await fetch('https://your-domain.com/api/discovery/check-duplicates', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
apiKey: 'YOUR_API_KEY',
|
||
urls: collectedUrls // 从上一步收集的 URL 列表
|
||
})
|
||
})
|
||
|
||
const { results, stats } = await checkResponse.json()
|
||
|
||
// 过滤出应该创建任务的 URL
|
||
const urlsToCreate = results
|
||
.filter(r => r.shouldCreate)
|
||
.map(r => r.url)
|
||
|
||
// 只为不重复的 URL 创建任务
|
||
if (urlsToCreate.length > 0) {
|
||
await fetch('https://your-domain.com/api/discovery/tasks', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
apiKey: 'YOUR_API_KEY',
|
||
tasks: urlsToCreate.map(url => ({
|
||
sourceUrl: url,
|
||
sourceType: 'github_trending'
|
||
}))
|
||
})
|
||
})
|
||
}
|
||
|
||
console.log(`创建 ${urlsToCreate.length} 个新任务,跳过 ${stats.duplicate} 个重复任务`)
|
||
```
|
||
|
||
---
|
||
|
||
### 步骤 3: 手动触发本地命令
|
||
|
||
**执行环境**: 本地开发环境 (Local Development)
|
||
|
||
**执行命令**:
|
||
```bash
|
||
# 处理默认 10 个任务 (每批 3 个)
|
||
/discover-projects
|
||
|
||
# 处理指定数量的任务
|
||
/discover-projects 20
|
||
|
||
# 自定义批次大小
|
||
/discover-projects 9 --batch=2
|
||
|
||
# 处理所有待处理任务
|
||
/discover-projects all --batch=5
|
||
```
|
||
|
||
**命令执行流程**:
|
||
1. 通过 curl 调用 `GET /api/discovery/tasks?status=PENDING&limit=N`
|
||
2. 获取待处理的任务列表
|
||
3. 分批处理 (默认每批 3 个任务)
|
||
4. 为每个任务启动 **Content Explorer Agent**
|
||
|
||
---
|
||
|
||
### 步骤 3.1: Content Explorer Agent (项目探索)
|
||
|
||
**Agent 定义**: `.claude/agents/content-explorer-agent.md`
|
||
|
||
**核心能力**:
|
||
- 使用 `agent-browser` 子任务并行探索 GitHub 项目
|
||
- 访问项目主页、README、代码结构
|
||
- 提取项目元数据 (名称、描述、标签、链接等)
|
||
- 生成符合 `ProjectInputSchema` 的 JSON 数据
|
||
|
||
**内容质量标准** (参考: `.claude/schemas/project-content-template.md`):
|
||
- ✅ **描述**: 客观说明功能、突出价值、避免营销术语、10-500字
|
||
- ✅ **内容**: 从 README 提取并重新组织、符合中文表达习惯
|
||
- ✅ **链接**: 必须包含 GITHUB 链接、所有链接可访问
|
||
- ✅ **标签**: 1-10 个标签、按技术/应用/状态分类
|
||
- ✅ **动态数据**: Star/Fork 等动态数据不写入内容,使用 GitHub Badge
|
||
|
||
**输出数据格式**:
|
||
```json
|
||
{
|
||
"name": "LangChain",
|
||
"nameEn": "LangChain",
|
||
"description": "开发由 LLM 驱动的应用程序的框架,提供文档加载、文本分割、向量存储等核心组件",
|
||
"descriptionEn": "Framework for developing applications powered by language models",
|
||
"content": "## 核心功能\n\n- 文档加载: 支持 PDF、TXT、网页等多种格式\n- 文本分割: 智能分割长文本\n...",
|
||
"tags": [
|
||
{ "name": "LLM", "nameEn": "Large Language Model" },
|
||
{ "name": "框架", "nameEn": "Framework" }
|
||
],
|
||
"links": [
|
||
{ "type": "GITHUB", "url": "https://github.com/langchain-ai/langchain", "title": "GitHub 仓库" },
|
||
{ "type": "WEBSITE", "url": "https://python.langchain.com", "title": "官方文档" }
|
||
],
|
||
"status": "ACTIVE"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 步骤 3.2: API Submitter Agent (数据提交)
|
||
|
||
**Agent 定义**: `.claude/agents/api-submitter-agent.md`
|
||
|
||
**核心能力**:
|
||
- 批量标记任务为 `IN_PROGRESS`
|
||
- 调用 `POST /api/discovery/tasks/{id}/complete` 提交数据
|
||
- 自动重试失败的提交 (指数退避,最多 3 次)
|
||
- 处理部分成功/失败情况
|
||
|
||
**提交流程**:
|
||
```
|
||
1. PATCH /api/discovery/tasks/{id} → status=IN_PROGRESS
|
||
↓
|
||
2. POST /api/discovery/tasks/{id}/complete → 提交探索数据
|
||
↓
|
||
3. 检查响应
|
||
├─ 成功 → 标记任务完成
|
||
├─ 失败 → 重试 (最多 3 次)
|
||
└─ 最终失败 → 记录错误信息
|
||
```
|
||
|
||
---
|
||
|
||
### 步骤 4: 完成任务并入库
|
||
|
||
**API 端点**: `POST /api/discovery/tasks/{id}/complete`
|
||
|
||
**处理逻辑** (参考: `src/app/api/discovery/tasks/[id]/complete/route.ts`):
|
||
|
||
1. **验证数据格式**: 使用 `ProjectInputSchema` 验证
|
||
2. **多级去重检测**:
|
||
- 优先级 1: GitHub URL 精确匹配
|
||
- 优先级 2: Website URL 精确匹配
|
||
- 优先级 3: slug 匹配
|
||
3. **创建或更新项目**:
|
||
- 如果存在重复项目 → 更新所有字段、标签、链接
|
||
- 如果不存在 → 创建新项目
|
||
4. **更新任务状态**:
|
||
- 成功 → `COMPLETED`
|
||
- 失败 → `FAILED` (记录错误信息)
|
||
|
||
**数据库变更**:
|
||
- `Project` 表: 创建或更新记录
|
||
- `Tag` 表: Upsert 标签
|
||
- `ProjectTag` 表: 创建关联关系
|
||
- `ExternalLink` 表: 创建或更新链接
|
||
- `ProjectDiscoveryTask` 表: 更新 `status`、`projectId`、`completedAt`
|
||
|
||
---
|
||
|
||
## 🗂️ 数据模型关系
|
||
|
||
```
|
||
ProjectDiscoveryTask (任务表)
|
||
├─ id: String (主键)
|
||
├─ status: TaskStatus (PENDING/IN_PROGRESS/COMPLETED/FAILED)
|
||
├─ sourceUrl: String (n8n 提供的原始 URL)
|
||
├─ sourceType: String (github_trending/twitter/hackernews)
|
||
├─ explorationData: Json (Agent 探索结果)
|
||
├─ explorationSummary: String (探索摘要)
|
||
├─ projectId: String (关联到 Project.id)
|
||
├─ errorMessage: String (失败原因)
|
||
└─ createdAt/startedAt/completedAt: DateTime
|
||
|
||
Project (项目表) ← 通过 projectId 关联
|
||
├─ id, name, nameEn, slug
|
||
├─ description, descriptionEn
|
||
├─ content, contentEn
|
||
├─ status (ACTIVE/ARCHIVED)
|
||
└─ 关联: tags, links, discoveryTasks
|
||
|
||
Tag (标签表)
|
||
└─ 通过 ProjectTag 多对多关联
|
||
|
||
ExternalLink (外部链接表)
|
||
└─ 通过 projectId 一对多关联
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 环境配置
|
||
|
||
### 环境变量
|
||
|
||
```env
|
||
# .env.local (本地开发)
|
||
WEBHOOK_API_KEY=sk_live_your_secure_api_key_min_32_chars # 用于调用完成 API
|
||
|
||
# 生产环境 (Vercel Dashboard 配置)
|
||
DATABASE_URL=postgres://...
|
||
WEBHOOK_API_KEY=sk_live_your_secure_api_key_min_32_chars
|
||
```
|
||
|
||
### 依赖服务
|
||
|
||
1. **n8n 平台**:
|
||
- 独立部署 (自托管或云服务)
|
||
- 配置定时工作流 (Workflow)
|
||
- 存储 `WEBHOOK_API_KEY` 用于 API 调用
|
||
|
||
2. **本地开发环境**:
|
||
- Node.js 18+
|
||
- pnpm 包管理器
|
||
- Claude Code CLI (支持斜杠命令)
|
||
|
||
3. **生产环境**:
|
||
- Vercel (Next.js 部署)
|
||
- Neon PostgreSQL (数据库)
|
||
|
||
---
|
||
|
||
## 📊 执行监控
|
||
|
||
### 查看待处理任务
|
||
|
||
```bash
|
||
# 查询待处理任务数量
|
||
curl https://your-domain.com/api/discovery/tasks?status=PENDING&limit=100
|
||
|
||
# 查询进行中的任务
|
||
curl https://your-domain.com/api/discovery/tasks?status=IN_PROGRESS
|
||
|
||
# 查询失败的任务 (需要重试)
|
||
curl https://your-domain.com/api/discovery/tasks?status=FAILED
|
||
```
|
||
|
||
### 重试失败任务
|
||
|
||
```bash
|
||
# 手动重试失败的任务
|
||
/discover-projects 10 --status=FAILED
|
||
```
|
||
|
||
---
|
||
|
||
## 🎯 质量保障
|
||
|
||
### 内容质量标准 (详细参考: `.claude/schemas/project-content-template.md`)
|
||
|
||
1. **描述要求**:
|
||
- 清晰说明项目的核心功能
|
||
- 突出项目的独特价值
|
||
- 避免使用营销术语 ("最好"、"第一"、"革命性" 等)
|
||
- 字数控制在 10-500 字
|
||
|
||
2. **内容要求**:
|
||
- 从项目 README 提取并重新组织
|
||
- 避免机械翻译,符合中文表达习惯
|
||
- 支持 Markdown 格式
|
||
- 动态数据 (Star/Fork) 不写入内容
|
||
|
||
3. **链接要求**:
|
||
- 必须包含 GITHUB 链接
|
||
- 所有链接必须可访问
|
||
- 链接类型必须正确 (WEBSITE/GITHUB/HUGGINGFACE/PAPER)
|
||
|
||
4. **标签要求**:
|
||
- 1-10 个标签
|
||
- 按技术栈/应用领域/开发状态分类
|
||
- 中英文对应
|
||
|
||
### 数据验证
|
||
|
||
所有提交的数据必须通过 `ProjectInputSchema` 验证 (详见 `src/lib/validations.ts`):
|
||
|
||
```typescript
|
||
ProjectInputSchema {
|
||
name: string (1-200字符, 必填)
|
||
description: string (10-500字符, 必填)
|
||
tags: Tag[] (1-10个, 必填)
|
||
links: ExternalLink[] (1-10个, 必填)
|
||
nameEn?: string (1-200字符)
|
||
descriptionEn?: string
|
||
content?: string (Markdown, 最多10000字符)
|
||
contentEn?: string
|
||
status?: "ACTIVE" | "ARCHIVED"
|
||
source?: string
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🚀 快速开始
|
||
|
||
### 第一次使用
|
||
|
||
1. **配置 n8n 工作流**:
|
||
- 创建新的 n8n Workflow
|
||
- 配置定时触发器 (如每天凌晨 2 点)
|
||
- 添加 HTTP Request 节点调用 `POST /api/discovery/tasks`
|
||
|
||
2. **本地执行命令**:
|
||
```bash
|
||
# 启动开发服务器 (如果未运行)
|
||
pnpm dev
|
||
|
||
# 执行项目发现命令
|
||
/discover-projects
|
||
```
|
||
|
||
3. **查看结果**:
|
||
- 访问 https://your-domain.com 查看新收录的项目
|
||
- 检查数据库确认数据正确性
|
||
|
||
### 日常维护
|
||
|
||
1. **定期执行命令** (建议每天 1-2 次):
|
||
```bash
|
||
/discover-projects 20
|
||
```
|
||
|
||
2. **监控失败任务**:
|
||
- 检查 `status=FAILED` 的任务
|
||
- 分析错误原因 (网络问题、数据格式等)
|
||
- 必要时手动重试
|
||
|
||
3. **优化内容质量**:
|
||
- 随机抽查已收录项目的描述和内容
|
||
- 调整 Agent 的提示词以提升质量
|
||
|
||
---
|
||
|
||
## 🔍 故障排查
|
||
|
||
### 常见问题
|
||
|
||
1. **任务长时间处于 IN_PROGRESS 状态**:
|
||
- 可能原因: Agent 探索超时、网络问题
|
||
- 解决方案: 手动更新任务状态为 PENDING 后重试
|
||
|
||
2. **大量任务失败**:
|
||
- 检查 `errorMessage` 字段
|
||
- 常见原因: 数据格式不正确、URL 无法访问、API Key 错误
|
||
|
||
3. **重复项目被创建**:
|
||
- 检查去重逻辑是否正常工作
|
||
- 确认 `ExternalLink` 表的索引 `idx_link_type_url` 存在
|
||
|
||
4. **n8n 无法调用 API**:
|
||
- 检查 `WEBHOOK_API_KEY` 是否正确配置
|
||
- 确认 API 端点可访问
|
||
- 查看 n8n 执行日志
|
||
|
||
---
|
||
|
||
## 📚 相关文档
|
||
|
||
- **API 参考**: `docs/api-reference.md`
|
||
- **数据模型**: `prisma/schema.prisma`
|
||
- **验证规则**: `src/lib/validations.ts`
|
||
- **Agent 定义**: `.claude/agents/content-explorer-agent.md`
|
||
- **Agent 定义**: `.claude/agents/api-submitter-agent.md`
|
||
- **内容质量标准**: `.claude/schemas/project-content-template.md`
|
||
- **项目主文档**: `CLAUDE.md`
|
||
|
||
---
|
||
|
||
## 📝 更新日志
|
||
|
||
- **2025-01-18**: 创建文档,记录完整的项目发现工作流
|