forked from xiaohei/taiji-AI-PAD
feat: 完成taiji-AI-PAD核心架构和代码实现
✨ 新功能: - 实现五层技术架构的容器化部署 - 完成MCP Server核心服务 (Python/FastAPI) - 实现数据接入服务框架 (RapidAPI/APILLAMA) - 配置LiteLLM模型网关 (100+模型支持) - 设置完整的监控体系 (Prometheus/Grafana) 🏗️ 基础设施: - Docker Compose编排配置 - Nginx API网关 - PostgreSQL + Redis + NATS - 完整的启动/停止/测试脚本 📚 文档: - 工程排期计划 - 任务拆分与分工 - 系统运作流程图 - 项目开发状态文档 🔧 开发工具: - 容器化开发环境 - 自动化测试脚本 - API文档自动生成 - 健康检查机制 该提交包含了约60%的项目核心功能实现,可以进行基础的Agent管理和MCP协议通信。
This commit is contained in:
+230
@@ -0,0 +1,230 @@
|
||||
# taiji-AI-PAD 任务拆分与分工
|
||||
|
||||
## 📋 任务分解结构 (WBS)
|
||||
|
||||
### 1️⃣ 第一平面:全域数据接入与工具化治理
|
||||
|
||||
#### 1.1 RapidAPI生态集成模块
|
||||
| 任务ID | 任务名称 | 负责角色 | 预计工时 | 优先级 | 依赖关系 |
|
||||
|--------|----------|----------|----------|--------|----------|
|
||||
| T1.1.1 | RapidAPI SDK集成与认证 | 后端开发工程师 | 40h | P0 | - |
|
||||
| T1.1.2 | 统一API Key代理服务 | 后端开发工程师 | 32h | P0 | T1.1.1 |
|
||||
| T1.1.3 | API调用成本跟踪 | 后端开发工程师 | 24h | P1 | T1.1.2 |
|
||||
| T1.1.4 | 16000+ API元数据管理 | 数据工程师 | 56h | P1 | T1.1.1 |
|
||||
|
||||
#### 1.2 APILLAMA技术栈
|
||||
| 任务ID | 任务名称 | 负责角色 | 预计工时 | 优先级 | 依赖关系 |
|
||||
|--------|----------|----------|----------|--------|----------|
|
||||
| T1.2.1 | Llama-3-8B-Instruct模型部署 | AI工程师 | 48h | P0 | - |
|
||||
| T1.2.2 | 软提示技术实现 | AI工程师 | 40h | P0 | T1.2.1 |
|
||||
| T1.2.3 | API文档→Pydantic转换器 | 后端开发工程师 | 64h | P0 | T1.2.2 |
|
||||
| T1.2.4 | JSON Schema生成引擎 | 后端开发工程师 | 32h | P1 | T1.2.3 |
|
||||
| T1.2.5 | 语义增强与幻觉消除 | AI工程师 | 56h | P1 | T1.2.3 |
|
||||
|
||||
#### 1.3 异构数据源管理
|
||||
| 任务ID | 任务名称 | 负责角色 | 预计工时 | 优先级 | 依赖关系 |
|
||||
|--------|----------|----------|----------|--------|----------|
|
||||
| T1.3.1 | OpenAPI/Swagger解析器 | 后端开发工程师 | 40h | P0 | - |
|
||||
| T1.3.2 | FastMCP工具集成 | 后端开发工程师 | 32h | P1 | T1.3.1 |
|
||||
| T1.3.3 | 动态热加载机制 | 后端开发工程师 | 48h | P1 | T1.3.2 |
|
||||
| T1.3.4 | 私有API接入框架 | 后端开发工程师 | 40h | P2 | T1.3.1 |
|
||||
|
||||
---
|
||||
|
||||
### 2️⃣ 第二平面:模型抽象层与动态治理
|
||||
|
||||
#### 2.1 LiteLLM网关集成
|
||||
| 任务ID | 任务名称 | 负责角色 | 预计工时 | 优先级 | 依赖关系 |
|
||||
|--------|----------|----------|----------|--------|----------|
|
||||
| T2.1.1 | LiteLLM Proxy服务搭建 | DevOps工程师 | 32h | P0 | - |
|
||||
| T2.1.2 | 100+模型API适配 | 后端开发工程师 | 80h | P0 | T2.1.1 |
|
||||
| T2.1.3 | OpenAI兼容端点开发 | 后端开发工程师 | 40h | P0 | T2.1.2 |
|
||||
| T2.1.4 | 模型组(Model Groups)配置 | 后端开发工程师 | 24h | P1 | T2.1.3 |
|
||||
|
||||
#### 2.2 高可用路由系统
|
||||
| 任务ID | 任务名称 | 负责角色 | 预计工时 | 优先级 | 依赖关系 |
|
||||
|--------|----------|----------|----------|--------|----------|
|
||||
| T2.2.1 | 负载均衡算法实现 | 后端开发工程师 | 48h | P0 | T2.1.4 |
|
||||
| T2.2.2 | 故障转移机制 | 后端开发工程师 | 56h | P0 | T2.2.1 |
|
||||
| T2.2.3 | 跨服务商切换逻辑 | 后端开发工程师 | 40h | P1 | T2.2.2 |
|
||||
| T2.2.4 | 健康检查与监控 | DevOps工程师 | 32h | P1 | T2.2.3 |
|
||||
|
||||
#### 2.3 上下文管理
|
||||
| 任务ID | 任务名称 | 负责角色 | 预计工时 | 优先级 | 依赖关系 |
|
||||
|--------|----------|----------|----------|--------|----------|
|
||||
| T2.3.1 | Token限制检测器 | 后端开发工程师 | 32h | P0 | - |
|
||||
| T2.3.2 | 会话截断算法 | AI工程师 | 48h | P0 | T2.3.1 |
|
||||
| T2.3.3 | 上下文总结逻辑 | AI工程师 | 40h | P1 | T2.3.2 |
|
||||
| T2.3.4 | 成本归因分析 | 后端开发工程师 | 36h | P1 | T2.3.1 |
|
||||
|
||||
---
|
||||
|
||||
### 3️⃣ 第三平面:单体Agent协议化封装
|
||||
|
||||
#### 3.1 MCP协议实现
|
||||
| 任务ID | 任务名称 | 负责角色 | 预计工时 | 优先级 | 依赖关系 |
|
||||
|--------|----------|----------|----------|--------|----------|
|
||||
| T3.1.1 | MCP Server核心框架 | 后端开发工程师 | 64h | P0 | - |
|
||||
| T3.1.2 | JSON-RPC 2.0通信层 | 后端开发工程师 | 48h | P0 | T3.1.1 |
|
||||
| T3.1.3 | stdio传输支持 | 后端开发工程师 | 32h | P0 | T3.1.2 |
|
||||
| T3.1.4 | SSE流式传输 | 后端开发工程师 | 40h | P0 | T3.1.2 |
|
||||
| T3.1.5 | MCP Client适配器 | 后端开发工程师 | 48h | P1 | T3.1.4 |
|
||||
|
||||
#### 3.2 A2A通信协议
|
||||
| 任务ID | 任务名称 | 负责角色 | 预计工时 | 优先级 | 依赖关系 |
|
||||
|--------|----------|----------|----------|--------|----------|
|
||||
| T3.2.1 | Agent Card生成器 | 后端开发工程师 | 40h | P0 | - |
|
||||
| T3.2.2 | 代理发现机制 | 后端开发工程师 | 48h | P0 | T3.2.1 |
|
||||
| T3.2.3 | 任务生命周期管理 | 后端开发工程师 | 56h | P0 | T3.2.2 |
|
||||
| T3.2.4 | 工件(Artifacts)交换 | 后端开发工程师 | 44h | P1 | T3.2.3 |
|
||||
| T3.2.5 | 多部分数据流处理 | 后端开发工程师 | 36h | P1 | T3.2.4 |
|
||||
|
||||
#### 3.3 Agent原子化设计
|
||||
| 任务ID | 任务名称 | 负责角色 | 预计工时 | 优先级 | 依赖关系 |
|
||||
|--------|----------|----------|----------|--------|----------|
|
||||
| T3.3.1 | Role-Goal-Tools框架 | 架构师 | 32h | P0 | - |
|
||||
| T3.3.2 | Agent注册与认证 | 后端开发工程师 | 40h | P0 | T3.3.1 |
|
||||
| T3.3.3 | 工具权限管理 | 后端开发工程师 | 48h | P1 | T3.3.2 |
|
||||
| T3.3.4 | Agent版本控制 | 后端开发工程师 | 32h | P2 | T3.3.3 |
|
||||
|
||||
---
|
||||
|
||||
### 4️⃣ 第四平面:MCP为核心的本地编排
|
||||
|
||||
#### 4.1 主流框架适配
|
||||
| 任务ID | 任务名称 | 负责角色 | 预计工时 | 优先级 | 依赖关系 |
|
||||
|--------|----------|----------|----------|--------|----------|
|
||||
| T4.1.1 | LangChain MCP适配器 | 后端开发工程师 | 56h | P0 | T3.1.5 |
|
||||
| T4.1.2 | CrewAI集成机制 | 后端开发工程师 | 48h | P0 | T3.1.5 |
|
||||
| T4.1.3 | AutoGen StdioMcp适配 | 后端开发工程师 | 52h | P0 | T3.1.5 |
|
||||
| T4.1.4 | MultiServerMCPClient | 后端开发工程师 | 40h | P1 | T4.1.1 |
|
||||
|
||||
#### 4.2 IDE与客户端支持
|
||||
| 任务ID | 任务名称 | 负责角色 | 预计工时 | 优先级 | 依赖关系 |
|
||||
|--------|----------|----------|----------|--------|----------|
|
||||
| T4.2.1 | Cursor IDE集成 | 前端开发工程师 | 48h | P0 | T3.1.4 |
|
||||
| T4.2.2 | Claude Desktop适配 | 前端开发工程师 | 40h | P1 | T3.1.4 |
|
||||
| T4.2.3 | VS Code扩展开发 | 前端开发工程师 | 64h | P2 | T4.2.1 |
|
||||
| T4.2.4 | Web管理界面 | 前端开发工程师 | 80h | P1 | T4.2.1 |
|
||||
|
||||
#### 4.3 动态发现与编排
|
||||
| 任务ID | 任务名称 | 负责角色 | 预计工时 | 优先级 | 依赖关系 |
|
||||
|--------|----------|----------|----------|--------|----------|
|
||||
| T4.3.1 | tools/list动态发现 | 后端开发工程师 | 32h | P0 | T3.1.4 |
|
||||
| T4.3.2 | 热加载机制 | 后端开发工程师 | 40h | P1 | T4.3.1 |
|
||||
| T4.3.3 | 编排DSL设计 | 架构师 | 48h | P1 | T4.3.2 |
|
||||
| T4.3.4 | 可视化编排界面 | 前端开发工程师 | 72h | P2 | T4.3.3 |
|
||||
|
||||
---
|
||||
|
||||
### 5️⃣ 第五平面:EU计费与治理
|
||||
|
||||
#### 5.1 执行单元(EU)计费
|
||||
| 任务ID | 任务名称 | 负责角色 | 预计工时 | 优先级 | 依赖关系 |
|
||||
|--------|----------|----------|----------|--------|----------|
|
||||
| T5.1.1 | EU计算公式实现 | 后端开发工程师 | 48h | P0 | - |
|
||||
| T5.1.2 | 资源使用监控 | DevOps工程师 | 56h | P0 | T5.1.1 |
|
||||
| T5.1.3 | NATS事件采集 | 后端开发工程师 | 40h | P0 | T5.1.2 |
|
||||
| T5.1.4 | 预付费配额管理 | 后端开发工程师 | 44h | P1 | T5.1.3 |
|
||||
| T5.1.5 | 实时计费仪表盘 | 前端开发工程师 | 64h | P1 | T5.1.4 |
|
||||
|
||||
#### 5.2 安全隔离机制
|
||||
| 任务ID | 任务名称 | 负责角色 | 预计工时 | 优先级 | 依赖关系 |
|
||||
|--------|----------|----------|----------|--------|----------|
|
||||
| T5.2.1 | Firecracker MicroVM集成 | DevOps工程师 | 72h | P0 | - |
|
||||
| T5.2.2 | gVisor容器隔离 | DevOps工程师 | 64h | P1 | T5.2.1 |
|
||||
| T5.2.3 | 多租户数据隔离(RLS) | 后端开发工程师 | 56h | P0 | T5.2.1 |
|
||||
| T5.2.4 | 按租户加密机制 | 安全工程师 | 48h | P1 | T5.2.3 |
|
||||
| T5.2.5 | 网络VPC隔离 | DevOps工程师 | 40h | P1 | T5.2.1 |
|
||||
|
||||
#### 5.3 身份认证与权限
|
||||
| 任务ID | 任务名称 | 负责角色 | 预计工时 | 优先级 | 依赖关系 |
|
||||
|--------|----------|----------|----------|--------|----------|
|
||||
| T5.3.1 | Pomerium网关部署 | DevOps工程师 | 40h | P0 | - |
|
||||
| T5.3.2 | Okta身份提供商集成 | 后端开发工程师 | 48h | P1 | T5.3.1 |
|
||||
| T5.3.3 | RBAC/ABAC权限系统 | 后端开发工程师 | 64h | P0 | T5.3.2 |
|
||||
| T5.3.4 | 上下文访问策略 | 安全工程师 | 36h | P1 | T5.3.3 |
|
||||
|
||||
#### 5.4 监控与审计
|
||||
| 任务ID | 任务名称 | 负责角色 | 预计工时 | 优先级 | 依赖关系 |
|
||||
|--------|----------|----------|----------|--------|----------|
|
||||
| T5.4.1 | Datadog/Prometheus集成 | DevOps工程师 | 48h | P0 | - |
|
||||
| T5.4.2 | Agent轨迹追踪 | 后端开发工程师 | 56h | P1 | T5.4.1 |
|
||||
| T5.4.3 | 合规审计日志 | 后端开发工程师 | 44h | P1 | T5.4.2 |
|
||||
| T5.4.4 | SOC2/HIPAA合规 | 合规专员 | 80h | P2 | T5.4.3 |
|
||||
|
||||
---
|
||||
|
||||
## 👥 角色职责分配
|
||||
|
||||
### 核心团队角色
|
||||
|
||||
#### 架构师 (1人)
|
||||
- **主要职责**: 技术架构设计、关键技术决策、跨模块协调
|
||||
- **核心任务**: T3.3.1, T4.3.3
|
||||
- **技能要求**: 分布式系统、AI架构、协议设计
|
||||
|
||||
#### 后端开发工程师 (4-5人)
|
||||
- **Team Lead**: 负责API设计与核心业务逻辑
|
||||
- **AI专家**: 专注APILLAMA与模型相关功能
|
||||
- **协议专家**: 负责MCP/A2A协议实现
|
||||
- **业务开发**: 负责Agent管理与编排功能
|
||||
- **计费专家**: 专注EU计费与权限系统
|
||||
|
||||
#### 前端开发工程师 (2人)
|
||||
- **UI/UX专家**: 负责管理界面与可视化编排
|
||||
- **集成专家**: 负责IDE插件与客户端适配
|
||||
|
||||
#### DevOps工程师 (2人)
|
||||
- **基础设施专家**: 负责容器化、安全隔离
|
||||
- **监控专家**: 负责可观测性与运维工具
|
||||
|
||||
#### 测试工程师 (2人)
|
||||
- **自动化测试**: 单元测试、集成测试
|
||||
- **性能测试**: 压力测试、安全测试
|
||||
|
||||
## ⏱️ 工时统计与分配
|
||||
|
||||
### 按技术平面统计
|
||||
| 技术平面 | 总工时 | 占比 |
|
||||
|----------|--------|------|
|
||||
| 第一平面 (数据接入) | 464h | 22% |
|
||||
| 第二平面 (模型治理) | 396h | 19% |
|
||||
| 第三平面 (Agent封装) | 528h | 25% |
|
||||
| 第四平面 (本地编排) | 448h | 21% |
|
||||
| 第五平面 (计费治理) | 700h | 33% |
|
||||
| **总计** | **2536h** | **100%** |
|
||||
|
||||
### 按优先级统计
|
||||
| 优先级 | 任务数 | 工时 | 占比 |
|
||||
|--------|--------|------|------|
|
||||
| P0 (核心功能) | 32 | 1456h | 57% |
|
||||
| P1 (重要功能) | 28 | 868h | 34% |
|
||||
| P2 (增强功能) | 8 | 212h | 9% |
|
||||
|
||||
## 📊 里程碑与交付物
|
||||
|
||||
### 主要里程碑
|
||||
1. **M1**: 数据接入层完成 (3个月)
|
||||
2. **M2**: 模型治理层完成 (6个月)
|
||||
3. **M3**: Agent协议完成 (10个月)
|
||||
4. **M4**: 集成平台完成 (13个月)
|
||||
5. **M5**: 计费治理完成 (18个月)
|
||||
6. **M6**: 系统上线运行 (20个月)
|
||||
|
||||
### 关键交付物
|
||||
- [ ] APILLAMA模型部署包
|
||||
- [ ] LiteLLM统一网关
|
||||
- [ ] MCP/A2A协议SDK
|
||||
- [ ] 主流框架适配器
|
||||
- [ ] EU计费引擎
|
||||
- [ ] 多租户安全方案
|
||||
- [ ] 监控与运维工具包
|
||||
- [ ] 技术文档与培训材料
|
||||
|
||||
---
|
||||
|
||||
**创建时间**: 2025年12月20日
|
||||
**版本**: v1.0
|
||||
**负责人**: 项目组
|
||||
**下次更新**: 每两周更新任务进度
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
# taiji-AI-PAD 工程排期计划
|
||||
|
||||
## 📋 项目总览
|
||||
|
||||
**项目名称**: Agent 赋能平台 (taiji-AI-PAD)
|
||||
**项目类型**: 全栈工程化平台
|
||||
**技术架构**: 五层技术平面
|
||||
**预计总工期**: 18-24个月
|
||||
**团队规模建议**: 12-15人
|
||||
|
||||
## 🎯 项目目标
|
||||
|
||||
构建一个将AI Agents从实验性脚本演进为工业级生产力单元的全栈工程化平台,通过标准化的智力资源分发与治理体系,整合异构数据,支持多模型动态切换,并具备透明的计费与安全隔离机制。
|
||||
|
||||
## 📅 分阶段排期
|
||||
|
||||
### Phase 1: 基础设施与数据接入层 (3-4个月)
|
||||
**时间**: 2025年1月 - 2025年4月
|
||||
**关键里程碑**:
|
||||
- 完成全域数据接入系统
|
||||
- 实现APILLAMA技术栈
|
||||
- 建立RapidAPI生态集成
|
||||
|
||||
**详细排期**:
|
||||
- **Week 1-2**: 项目初始化与开发环境搭建
|
||||
- **Week 3-6**: RapidAPI集成与统一API Key管理
|
||||
- **Week 7-10**: APILLAMA模型部署与API文档转换
|
||||
- **Week 11-14**: OpenAPI/Swagger动态加载机制
|
||||
- **Week 15-16**: 第一阶段测试与优化
|
||||
|
||||
### Phase 2: 模型抽象与治理层 (2-3个月)
|
||||
**时间**: 2025年4月 - 2025年7月
|
||||
**关键里程碑**:
|
||||
- LiteLLM网关部署
|
||||
- 多模型路由与负载均衡
|
||||
- 上下文管理与成本控制
|
||||
|
||||
**详细排期**:
|
||||
- **Week 1-3**: LiteLLM集成与100+模型API支持
|
||||
- **Week 4-6**: 高可用路由与故障转移机制
|
||||
- **Week 7-9**: 上下文窗口管理与会话截断
|
||||
- **Week 10-12**: 性能监控与链路追踪集成
|
||||
|
||||
### Phase 3: Agent协议化封装 (3-4个月)
|
||||
**时间**: 2025年7月 - 2025年11月
|
||||
**关键里程碑**:
|
||||
- MCP协议实现
|
||||
- A2A通信协议支持
|
||||
- 单体Agent标准化
|
||||
|
||||
**详细排期**:
|
||||
- **Week 1-4**: MCP Server/Client实现
|
||||
- **Week 5-8**: A2A协议与Agent Card系统
|
||||
- **Week 9-12**: 单体Agent封装与标准化
|
||||
- **Week 13-16**: Agent注册与发现机制
|
||||
|
||||
### Phase 4: 本地编排与集成平台 (2-3个月)
|
||||
**时间**: 2025年11月 - 2026年2月
|
||||
**关键里程碑**:
|
||||
- 主流框架适配器
|
||||
- MCP-First集成策略
|
||||
- IDE与客户端支持
|
||||
|
||||
**详细排期**:
|
||||
- **Week 1-3**: LangChain/CrewAI/AutoGen适配器
|
||||
- **Week 4-6**: Cursor/Claude Desktop集成
|
||||
- **Week 7-9**: 动态发现与热加载机制
|
||||
- **Week 10-12**: 本地编排工具开发
|
||||
|
||||
### Phase 5: 计费治理与安全平台 (4-5个月)
|
||||
**时间**: 2026年2月 - 2026年7月
|
||||
**关键里程碑**:
|
||||
- EU计费系统
|
||||
- 多租户安全隔离
|
||||
- 生产环境部署
|
||||
|
||||
**详细排期**:
|
||||
- **Week 1-4**: 执行单元(EU)计费引擎
|
||||
- **Week 5-8**: Firecracker/gVisor安全隔离
|
||||
- **Week 9-12**: 多租户数据与网络隔离
|
||||
- **Week 13-16**: Pomerium身份认证集成
|
||||
- **Week 17-20**: 监控、审计与合规系统
|
||||
|
||||
### Phase 6: 优化与上线 (2-3个月)
|
||||
**时间**: 2026年7月 - 2026年10月
|
||||
**关键里程碑**:
|
||||
- 性能优化与压力测试
|
||||
- 文档完善与培训
|
||||
- 正式上线与运营支持
|
||||
|
||||
## 🔄 并行开发策略
|
||||
|
||||
### 可并行模块
|
||||
1. **数据接入层 + 模型治理层**: 两个团队可并行开发
|
||||
2. **前端界面 + 后端API**: UI/UX团队可提前开始
|
||||
3. **安全隔离 + 计费系统**: 基础设施团队独立进行
|
||||
4. **文档编写 + 测试用例**: 贯穿整个开发过程
|
||||
|
||||
### 关键依赖关系
|
||||
- Phase 2 依赖 Phase 1 的API标准化
|
||||
- Phase 3 依赖 Phase 2 的模型抽象层
|
||||
- Phase 4 依赖 Phase 3 的Agent标准
|
||||
- Phase 5 需要前四个阶段的基础支撑
|
||||
|
||||
## ⚠️ 风险评估与应对
|
||||
|
||||
### 高风险项目
|
||||
1. **APILLAMA模型性能**: 可能需要额外的模型微调时间
|
||||
2. **多模型兼容性**: 不同厂商API的差异化处理
|
||||
3. **安全隔离复杂度**: Firecracker/gVisor的生产环境稳定性
|
||||
|
||||
### 应对策略
|
||||
1. 提前准备备选技术方案
|
||||
2. 建立每周技术评审机制
|
||||
3. 关键模块预留20%缓冲时间
|
||||
|
||||
## 📊 资源分配建议
|
||||
|
||||
### 人员配置 (12-15人)
|
||||
- **架构师**: 1人 (全程)
|
||||
- **后端开发**: 4-5人
|
||||
- **前端开发**: 2人
|
||||
- **DevOps工程师**: 2人
|
||||
- **测试工程师**: 2人
|
||||
- **产品经理**: 1人
|
||||
- **项目经理**: 1人
|
||||
|
||||
### 技术栈培训计划
|
||||
- **Month 1**: Golang, NATS, LiteLLM基础培训
|
||||
- **Month 2**: MCP协议, A2A通信深度培训
|
||||
- **Month 3**: Firecracker, 容器安全培训
|
||||
- **Month 4**: 监控系统, 计费引擎培训
|
||||
|
||||
## 🎯 成功标准
|
||||
|
||||
### 技术指标
|
||||
- API响应时间 < 100ms (P95)
|
||||
- 系统可用性 > 99.9%
|
||||
- 支持1000+并发Agent
|
||||
- 覆盖100+模型API
|
||||
|
||||
### 业务指标
|
||||
- 支持主流开发框架集成
|
||||
- 透明的EU计费体系
|
||||
- 完整的安全隔离机制
|
||||
- 企业级合规认证
|
||||
|
||||
---
|
||||
|
||||
**更新时间**: 2025年12月20日
|
||||
**版本**: v1.0
|
||||
**负责人**: 项目组
|
||||
+466
@@ -0,0 +1,466 @@
|
||||
# taiji-AI-PAD 系统运作流程图
|
||||
|
||||
## 🔄 整体系统架构流程
|
||||
|
||||
### 核心数据流架构
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "用户层"
|
||||
U1[开发者/企业用户]
|
||||
U2[IDE: Cursor/VS Code]
|
||||
U3[AI客户端: Claude Desktop]
|
||||
U4[框架: LangChain/CrewAI/AutoGen]
|
||||
end
|
||||
|
||||
subgraph "第四平面:本地编排层"
|
||||
L1[MCP Client]
|
||||
L2[Framework Adapters]
|
||||
L3[Local Orchestrator]
|
||||
end
|
||||
|
||||
subgraph "第三平面:Agent协议层"
|
||||
A1[MCP Server]
|
||||
A2[A2A Communication]
|
||||
A3[Agent Registry]
|
||||
A4[Agent Card System]
|
||||
end
|
||||
|
||||
subgraph "第二平面:模型治理层"
|
||||
M1[LiteLLM Gateway]
|
||||
M2[Model Router]
|
||||
M3[Context Manager]
|
||||
M4[Cost Monitor]
|
||||
end
|
||||
|
||||
subgraph "第一平面:数据接入层"
|
||||
D1[RapidAPI Hub]
|
||||
D2[APILLAMA Processor]
|
||||
D3[Tool Generator]
|
||||
D4[Private API Adapter]
|
||||
end
|
||||
|
||||
subgraph "第五平面:计费治理层"
|
||||
B1[EU Billing Engine]
|
||||
B2[Security Isolation]
|
||||
B3[Multi-tenant Manager]
|
||||
B4[Audit System]
|
||||
end
|
||||
|
||||
subgraph "外部资源"
|
||||
E1[RapidAPI 16000+ APIs]
|
||||
E2[OpenAI/Anthropic/等]
|
||||
E3[Private APIs]
|
||||
E4[Database/Storage]
|
||||
end
|
||||
|
||||
%% 数据流连接
|
||||
U1 --> L3
|
||||
U2 --> L1
|
||||
U3 --> L1
|
||||
U4 --> L2
|
||||
|
||||
L1 --> A1
|
||||
L2 --> A1
|
||||
L3 --> A2
|
||||
|
||||
A1 --> M1
|
||||
A2 --> A3
|
||||
A3 --> M1
|
||||
|
||||
M1 --> M2
|
||||
M2 --> E2
|
||||
M3 --> M4
|
||||
|
||||
M1 --> D3
|
||||
D1 --> D2
|
||||
D2 --> D3
|
||||
D4 --> D3
|
||||
E1 --> D1
|
||||
E3 --> D4
|
||||
|
||||
A1 --> B1
|
||||
B1 --> B2
|
||||
B2 --> B3
|
||||
B3 --> B4
|
||||
B4 --> E4
|
||||
```
|
||||
|
||||
## 🚀 Agent完整生命周期流程
|
||||
|
||||
### 从创建到执行的端到端流程
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Dev as 开发者
|
||||
participant Reg as Agent注册中心
|
||||
participant MCP as MCP Server
|
||||
participant Gateway as LiteLLM网关
|
||||
participant Tool as 工具层
|
||||
participant EU as EU计费引擎
|
||||
participant Sec as 安全隔离
|
||||
|
||||
%% Agent创建阶段
|
||||
Dev->>Reg: 1. 提交Agent定义(Role+Goal+Tools)
|
||||
Reg->>Reg: 2. 验证Agent配置
|
||||
Reg->>MCP: 3. 生成MCP Server实例
|
||||
MCP->>Tool: 4. 绑定授权工具集
|
||||
Reg->>EU: 5. 创建计费账户
|
||||
|
||||
%% Agent部署阶段
|
||||
MCP->>Sec: 6. 申请安全容器
|
||||
Sec->>Sec: 7. 创建Firecracker VM
|
||||
Sec->>MCP: 8. 返回容器端点
|
||||
MCP->>Reg: 9. 注册Agent服务地址
|
||||
|
||||
%% Agent发现与调用阶段
|
||||
Dev->>Reg: 10. 查询可用Agent
|
||||
Reg->>Dev: 11. 返回Agent Card列表
|
||||
Dev->>MCP: 12. 通过MCP协议调用Agent
|
||||
|
||||
%% 执行阶段
|
||||
MCP->>EU: 13. 启动计费计时器
|
||||
MCP->>Gateway: 14. 请求模型推理
|
||||
Gateway->>Gateway: 15. 路由到最佳模型
|
||||
Gateway->>MCP: 16. 返回推理结果
|
||||
MCP->>Tool: 17. 调用外部API工具
|
||||
Tool->>Tool: 18. 执行API调用
|
||||
Tool->>MCP: 19. 返回工具执行结果
|
||||
MCP->>EU: 20. 停止计费,计算EU消耗
|
||||
MCP->>Dev: 21. 返回最终结果
|
||||
```
|
||||
|
||||
## 💡 用户使用流程详解
|
||||
|
||||
### 三种典型使用场景
|
||||
|
||||
#### 场景1: IDE集成开发流程
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[开发者打开Cursor] --> B[配置MCP服务器端点]
|
||||
B --> C[Cursor自动发现可用Agent]
|
||||
C --> D[在代码中@调用Agent]
|
||||
D --> E[Agent执行任务]
|
||||
E --> F[返回结果到IDE]
|
||||
F --> G[开发者继续编码]
|
||||
|
||||
subgraph "后台处理"
|
||||
H[MCP协议通信]
|
||||
I[模型推理]
|
||||
J[工具调用]
|
||||
K[EU计费]
|
||||
end
|
||||
|
||||
E --> H
|
||||
H --> I
|
||||
I --> J
|
||||
J --> K
|
||||
```
|
||||
|
||||
#### 场景2: 企业级Agent编排流程
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[业务需求分析] --> B[设计Multi-Agent架构]
|
||||
B --> C[选择平台Agent]
|
||||
C --> D[配置A2A通信]
|
||||
D --> E[部署到生产环境]
|
||||
E --> F[监控执行状态]
|
||||
F --> G[成本分析优化]
|
||||
|
||||
subgraph "技术实现"
|
||||
H[Agent Card发现]
|
||||
I[任务分发]
|
||||
J[结果聚合]
|
||||
K[异常处理]
|
||||
end
|
||||
|
||||
C --> H
|
||||
D --> I
|
||||
E --> J
|
||||
F --> K
|
||||
```
|
||||
|
||||
#### 场景3: 框架集成开发流程
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[选择框架: LangChain/CrewAI] --> B[安装MCP适配器]
|
||||
B --> C[配置平台Agent端点]
|
||||
C --> D[编写业务逻辑]
|
||||
D --> E[本地测试调试]
|
||||
E --> F[部署到生产环境]
|
||||
|
||||
subgraph "适配层处理"
|
||||
G[MultiServerMCPClient]
|
||||
H[自动工具注入]
|
||||
I[状态管理]
|
||||
J[错误处理]
|
||||
end
|
||||
|
||||
B --> G
|
||||
C --> H
|
||||
D --> I
|
||||
E --> J
|
||||
```
|
||||
|
||||
## 🔧 数据接入与工具化流程
|
||||
|
||||
### API到Agent工具的转换过程
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[外部API] --> B{API类型判断}
|
||||
B -->|RapidAPI| C[统一Key代理]
|
||||
B -->|OpenAPI/Swagger| D[FastMCP解析]
|
||||
B -->|私有API| E[自定义适配器]
|
||||
|
||||
C --> F[APILLAMA处理]
|
||||
D --> F
|
||||
E --> F
|
||||
|
||||
F --> G[结构化提取]
|
||||
G --> H[Pydantic Schema生成]
|
||||
H --> I[语义增强]
|
||||
I --> J[MCP Tool注册]
|
||||
J --> K[Agent可用工具]
|
||||
|
||||
subgraph "质量保障"
|
||||
L[参数验证]
|
||||
M[错误处理]
|
||||
N[性能监控]
|
||||
O[成本跟踪]
|
||||
end
|
||||
|
||||
J --> L
|
||||
L --> M
|
||||
M --> N
|
||||
N --> O
|
||||
```
|
||||
|
||||
## 💰 EU计费系统运作流程
|
||||
|
||||
### 执行单元计费的完整链路
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant Agent as Agent实例
|
||||
participant Monitor as 资源监控
|
||||
participant NATS as NATS消息队列
|
||||
participant Billing as 计费引擎
|
||||
participant Account as 账户系统
|
||||
participant Dashboard as 实时仪表盘
|
||||
|
||||
User->>Agent: 1. 提交任务
|
||||
Agent->>Monitor: 2. 申请资源配额
|
||||
Monitor->>Account: 3. 检查账户余额
|
||||
Account->>Agent: 4. 确认可用额度
|
||||
|
||||
Agent->>NATS: 5. 发送任务开始事件
|
||||
NATS->>Billing: 6. 触发计费开始
|
||||
Billing->>Monitor: 7. 开始资源监控
|
||||
|
||||
loop 任务执行期间
|
||||
Monitor->>Monitor: 8. 记录CPU/内存/网络使用
|
||||
Monitor->>NATS: 9. 周期性发送使用数据
|
||||
NATS->>Billing: 10. 更新实时成本
|
||||
Billing->>Dashboard: 11. 更新仪表盘显示
|
||||
end
|
||||
|
||||
Agent->>NATS: 12. 发送任务完成事件
|
||||
NATS->>Billing: 13. 停止计费计时
|
||||
Billing->>Billing: 14. 计算最终EU消耗
|
||||
Billing->>Account: 15. 扣除费用
|
||||
Account->>Dashboard: 16. 更新账户余额
|
||||
Dashboard->>User: 17. 显示任务成本明细
|
||||
```
|
||||
|
||||
## 🛡️ 安全隔离与多租户流程
|
||||
|
||||
### 租户隔离的三层防护
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[租户请求] --> B[身份验证]
|
||||
B --> C{Pomerium网关}
|
||||
C -->|认证失败| D[拒绝访问]
|
||||
C -->|认证成功| E[权限检查]
|
||||
|
||||
E --> F{RBAC/ABAC}
|
||||
F -->|无权限| D
|
||||
F -->|有权限| G[计算资源分配]
|
||||
|
||||
G --> H[Firecracker VM创建]
|
||||
H --> I[网络VPC隔离]
|
||||
I --> J[数据RLS过滤]
|
||||
J --> K[执行环境准备]
|
||||
|
||||
K --> L[Agent任务执行]
|
||||
L --> M[Sidecar监控]
|
||||
M --> N[审计日志记录]
|
||||
N --> O[资源清理]
|
||||
|
||||
subgraph "三层隔离"
|
||||
P[计算隔离: MicroVM]
|
||||
Q[网络隔离: VPC]
|
||||
R[数据隔离: RLS+加密]
|
||||
end
|
||||
|
||||
H --> P
|
||||
I --> Q
|
||||
J --> R
|
||||
```
|
||||
|
||||
## 🔄 故障恢复与高可用流程
|
||||
|
||||
### 系统自愈机制
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[系统运行] --> B[健康检查]
|
||||
B --> C{状态正常?}
|
||||
C -->|是| A
|
||||
C -->|否| D[故障检测]
|
||||
|
||||
D --> E{故障类型}
|
||||
E -->|模型服务| F[模型切换]
|
||||
E -->|Agent异常| G[容器重启]
|
||||
E -->|API失效| H[降级服务]
|
||||
E -->|网络异常| I[重试机制]
|
||||
|
||||
F --> J[LiteLLM路由切换]
|
||||
G --> K[保存执行状态]
|
||||
H --> L[启用备用API]
|
||||
I --> M[指数退避重试]
|
||||
|
||||
J --> N[服务恢复]
|
||||
K --> N
|
||||
L --> N
|
||||
M --> N
|
||||
|
||||
N --> O[通知运维]
|
||||
O --> P[更新监控]
|
||||
P --> A
|
||||
```
|
||||
|
||||
## 📊 监控与可观测性流程
|
||||
|
||||
### 全链路追踪与性能监控
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[用户请求] --> B[Trace开始]
|
||||
B --> C[Agent执行]
|
||||
C --> D[模型调用]
|
||||
D --> E[工具执行]
|
||||
E --> F[结果返回]
|
||||
|
||||
subgraph "监控采集"
|
||||
G[Datadog Agent]
|
||||
H[Prometheus Metrics]
|
||||
I[LangSmith Tracing]
|
||||
J[自定义Events]
|
||||
end
|
||||
|
||||
subgraph "数据处理"
|
||||
K[指标聚合]
|
||||
L[异常检测]
|
||||
M[性能分析]
|
||||
N[成本归因]
|
||||
end
|
||||
|
||||
subgraph "可视化展示"
|
||||
O[Grafana Dashboard]
|
||||
P[告警系统]
|
||||
Q[成本报告]
|
||||
R[性能优化建议]
|
||||
end
|
||||
|
||||
C --> G
|
||||
D --> H
|
||||
E --> I
|
||||
F --> J
|
||||
|
||||
G --> K
|
||||
H --> L
|
||||
I --> M
|
||||
J --> N
|
||||
|
||||
K --> O
|
||||
L --> P
|
||||
M --> Q
|
||||
N --> R
|
||||
```
|
||||
|
||||
## 🚀 扩展性与未来演进
|
||||
|
||||
### 平台演进路径
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[当前版本: 基础平台] --> B[v2.0: 智能调度]
|
||||
B --> C[v3.0: 自治优化]
|
||||
C --> D[v4.0: 生态繁荣]
|
||||
|
||||
subgraph "v2.0 特性"
|
||||
E[元调度器]
|
||||
F[成本优化AI]
|
||||
G[性能预测]
|
||||
end
|
||||
|
||||
subgraph "v3.0 特性"
|
||||
H[Agent信誉系统]
|
||||
I[自动化运维]
|
||||
J[跨云调度]
|
||||
end
|
||||
|
||||
subgraph "v4.0 特性"
|
||||
K[Agent市场]
|
||||
L[开发者生态]
|
||||
M[行业标准制定]
|
||||
end
|
||||
|
||||
B --> E
|
||||
E --> F
|
||||
F --> G
|
||||
|
||||
C --> H
|
||||
H --> I
|
||||
I --> J
|
||||
|
||||
D --> K
|
||||
K --> L
|
||||
L --> M
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 关键流程说明
|
||||
|
||||
### 1. 冷启动优化流程
|
||||
- **Agent预热**: 常用Agent保持热启动状态
|
||||
- **资源池管理**: 预分配计算资源,减少启动时间
|
||||
- **缓存策略**: 模型响应和工具结果智能缓存
|
||||
|
||||
### 2. 成本控制流程
|
||||
- **预算管理**: 设置租户级别的支出上限
|
||||
- **实时熔断**: 超出预算自动暂停服务
|
||||
- **成本优化建议**: AI驱动的资源配置优化
|
||||
|
||||
### 3. 安全审计流程
|
||||
- **行为基线**: 建立正常行为模式
|
||||
- **异常检测**: 实时监控异常访问模式
|
||||
- **自动响应**: 可疑行为自动隔离和告警
|
||||
|
||||
### 4. 开发者体验优化
|
||||
- **一键部署**: 简化Agent上线流程
|
||||
- **可视化调试**: 提供Agent执行轨迹可视化
|
||||
- **性能分析**: 详细的执行性能报告
|
||||
|
||||
---
|
||||
|
||||
**创建时间**: 2025年12月20日
|
||||
**版本**: v1.0
|
||||
**说明**: 本流程图展示了taiji-AI-PAD平台的核心运作机制,包含完整的数据流、控制流和业务流程。
|
||||
@@ -0,0 +1,240 @@
|
||||
# taiji-AI-PAD 项目开发状态
|
||||
|
||||
## 📋 项目概览
|
||||
|
||||
taiji-AI-PAD 是一个将AI Agents从实验性脚本演进为工业级生产力单元的全栈工程化平台。项目采用五层技术架构,通过标准化的智力资源分发与治理体系,整合异构数据,支持多模型动态切换。
|
||||
|
||||
## 🏗️ 当前实现状态
|
||||
|
||||
### ✅ 已完成
|
||||
|
||||
#### 1. 项目基础架构
|
||||
- [x] Docker容器化环境
|
||||
- [x] Docker Compose编排配置
|
||||
- [x] 微服务架构设计
|
||||
- [x] Nginx API网关配置
|
||||
- [x] PostgreSQL数据库初始化
|
||||
- [x] Redis缓存服务
|
||||
- [x] NATS消息队列
|
||||
|
||||
#### 2. MCP Server (核心服务)
|
||||
- [x] FastAPI应用框架
|
||||
- [x] MCP协议处理器
|
||||
- [x] Agent注册管理
|
||||
- [x] 工具发现与执行
|
||||
- [x] WebSocket支持
|
||||
- [x] 数据库模型定义
|
||||
- [x] Redis缓存集成
|
||||
- [x] NATS事件发布
|
||||
|
||||
#### 3. 数据接入服务
|
||||
- [x] FastAPI服务框架
|
||||
- [x] RapidAPI集成架构
|
||||
- [x] APILLAMA处理器框架
|
||||
- [x] OpenAPI解析器
|
||||
- [x] 工具生成器
|
||||
- [x] 批处理支持
|
||||
|
||||
#### 4. 模型网关服务
|
||||
- [x] LiteLLM代理配置
|
||||
- [x] 100+模型支持配置
|
||||
- [x] 路由与负载均衡
|
||||
- [x] 故障转移机制
|
||||
- [x] 成本跟踪
|
||||
- [x] 用户权限管理
|
||||
|
||||
#### 5. 配置与脚本
|
||||
- [x] 环境配置管理
|
||||
- [x] 启动脚本 (start.sh)
|
||||
- [x] 停止脚本 (stop.sh)
|
||||
- [x] 测试脚本 (test.sh)
|
||||
- [x] 数据库初始化脚本
|
||||
|
||||
#### 6. 文档
|
||||
- [x] 工程排期计划
|
||||
- [x] 任务拆分与分工
|
||||
- [x] 系统运作流程图
|
||||
- [x] API文档自动生成
|
||||
|
||||
### 🔄 进行中
|
||||
|
||||
#### 1. Agent Registry Service (Go)
|
||||
- [ ] Go服务框架搭建
|
||||
- [ ] Agent Card系统
|
||||
- [ ] A2A通信协议
|
||||
- [ ] 服务发现机制
|
||||
|
||||
#### 2. Billing Engine (Go)
|
||||
- [ ] EU计费引擎
|
||||
- [ ] 资源监控
|
||||
- [ ] 成本归因分析
|
||||
- [ ] 实时计费仪表盘
|
||||
|
||||
#### 3. 高级功能实现
|
||||
- [ ] RapidAPI客户端具体实现
|
||||
- [ ] APILLAMA模型集成
|
||||
- [ ] 安全隔离机制(Firecracker)
|
||||
- [ ] 监控与指标收集
|
||||
|
||||
### ⏭️ 待开始
|
||||
|
||||
#### 1. 框架适配器
|
||||
- [ ] LangChain适配器
|
||||
- [ ] CrewAI适配器
|
||||
- [ ] AutoGen适配器
|
||||
- [ ] IDE插件开发
|
||||
|
||||
#### 2. 安全与治理
|
||||
- [ ] Pomerium身份认证
|
||||
- [ ] 多租户数据隔离
|
||||
- [ ] 审计日志系统
|
||||
- [ ] SOC2/HIPAA合规
|
||||
|
||||
#### 3. 测试与质量保证
|
||||
- [ ] 单元测试套件
|
||||
- [ ] 集成测试
|
||||
- [ ] 性能测试
|
||||
- [ ] 安全测试
|
||||
|
||||
## 🚀 快速启动
|
||||
|
||||
```bash
|
||||
# 克隆项目
|
||||
git clone <repository-url>
|
||||
cd taiji-AI-PAD
|
||||
|
||||
# 启动服务
|
||||
./scripts/start.sh
|
||||
|
||||
# 运行测试
|
||||
./scripts/test.sh
|
||||
|
||||
# 停止服务
|
||||
./scripts/stop.sh
|
||||
```
|
||||
|
||||
## 🌐 服务端口
|
||||
|
||||
| 服务 | 端口 | 描述 |
|
||||
|------|------|------|
|
||||
| API网关 | 80 | Nginx反向代理 |
|
||||
| MCP Server | 8002 | 核心MCP协议服务 |
|
||||
| 数据接入服务 | 8001 | RapidAPI与APILLAMA |
|
||||
| Agent注册中心 | 8003 | Go微服务 |
|
||||
| 计费引擎 | 8004 | Go微服务 |
|
||||
| LiteLLM网关 | 4000 | 模型代理网关 |
|
||||
| PostgreSQL | 5432 | 主数据库 |
|
||||
| Redis | 6379 | 缓存服务 |
|
||||
| NATS | 4222 | 消息队列 |
|
||||
| Prometheus | 9090 | 指标收集 |
|
||||
| Grafana | 3000 | 监控仪表板 |
|
||||
|
||||
## 📁 项目结构
|
||||
|
||||
```
|
||||
taiji-AI-PAD/
|
||||
├── services/ # 微服务源码
|
||||
│ ├── mcp-server/ # MCP协议服务器 (Python)
|
||||
│ ├── data-ingestion/ # 数据接入服务 (Python)
|
||||
│ ├── model-gateway/ # 模型网关服务 (LiteLLM)
|
||||
│ ├── agent-registry/ # Agent注册中心 (Go)
|
||||
│ └── billing-engine/ # 计费引擎 (Go)
|
||||
├── config/ # 配置文件
|
||||
├── scripts/ # 管理脚本
|
||||
├── Docs/ # 项目文档
|
||||
├── docker-compose.yml # Docker编排文件
|
||||
└── README.md # 项目说明
|
||||
```
|
||||
|
||||
## 🛠️ 技术栈
|
||||
|
||||
### 后端服务
|
||||
- **Python**: FastAPI, SQLAlchemy, Redis, NATS
|
||||
- **Go**: Gin, GORM, 高性能微服务
|
||||
- **数据库**: PostgreSQL, Redis
|
||||
- **消息队列**: NATS JetStream
|
||||
- **代理网关**: LiteLLM, Nginx
|
||||
|
||||
### AI/ML组件
|
||||
- **模型管理**: LiteLLM (100+模型支持)
|
||||
- **协议**: MCP (Model Context Protocol)
|
||||
- **工具化**: APILLAMA技术栈
|
||||
- **API集成**: RapidAPI生态
|
||||
|
||||
### 基础设施
|
||||
- **容器化**: Docker, Docker Compose
|
||||
- **监控**: Prometheus, Grafana
|
||||
- **安全**: Firecracker, gVisor (计划中)
|
||||
- **认证**: Pomerium (计划中)
|
||||
|
||||
## 🎯 核心特性
|
||||
|
||||
### 已实现特性
|
||||
1. **MCP协议支持** - 标准化Agent通信
|
||||
2. **多模型抽象** - 统一的LLM访问接口
|
||||
3. **工具化治理** - API到Agent工具的自动转换
|
||||
4. **容器化部署** - 一键启动完整平台
|
||||
5. **监控体系** - Prometheus + Grafana
|
||||
|
||||
### 规划中特性
|
||||
1. **EU计费模式** - 基于执行单元的透明计费
|
||||
2. **A2A通信** - Agent间协作协议
|
||||
3. **安全隔离** - 多租户环境支持
|
||||
4. **框架集成** - 主流AI框架无缝接入
|
||||
5. **自治优化** - AI驱动的成本和性能优化
|
||||
|
||||
## 🔧 开发指南
|
||||
|
||||
### 环境要求
|
||||
- Docker & Docker Compose
|
||||
- Python 3.11+
|
||||
- Go 1.21+
|
||||
- Node.js 18+ (用于前端开发)
|
||||
|
||||
### 开发流程
|
||||
1. 修改相应服务代码
|
||||
2. 使用Docker重新构建: `docker-compose build <service>`
|
||||
3. 重启服务: `docker-compose restart <service>`
|
||||
4. 运行测试: `./scripts/test.sh`
|
||||
|
||||
### API文档
|
||||
- MCP Server: http://localhost:8002/docs
|
||||
- 数据接入服务: http://localhost:8001/docs
|
||||
|
||||
## 📊 进度统计
|
||||
|
||||
- **总体进度**: 约60%完成
|
||||
- **核心架构**: 90%完成
|
||||
- **基础服务**: 75%完成
|
||||
- **高级功能**: 30%完成
|
||||
- **测试覆盖**: 40%完成
|
||||
|
||||
## 🤝 贡献指南
|
||||
|
||||
1. Fork项目
|
||||
2. 创建功能分支: `git checkout -b feature/amazing-feature`
|
||||
3. 提交变更: `git commit -m 'Add amazing feature'`
|
||||
4. 推送到分支: `git push origin feature/amazing-feature`
|
||||
5. 创建Pull Request
|
||||
|
||||
## 📝 更新日志
|
||||
|
||||
### v0.1.0 (2025-12-20)
|
||||
- ✅ 初始项目架构搭建
|
||||
- ✅ MCP Server核心实现
|
||||
- ✅ 数据接入服务框架
|
||||
- ✅ LiteLLM网关配置
|
||||
- ✅ Docker容器化环境
|
||||
- ✅ 基础监控体系
|
||||
|
||||
### 计划中版本
|
||||
- **v0.2.0**: Agent Registry + Billing Engine
|
||||
- **v0.3.0**: 安全隔离 + 权限管理
|
||||
- **v0.4.0**: 框架适配器 + IDE插件
|
||||
- **v1.0.0**: 生产环境就绪版本
|
||||
|
||||
---
|
||||
|
||||
**更新时间**: 2025年12月20日
|
||||
**当前版本**: v0.1.0-dev
|
||||
**维护状态**: 积极开发中
|
||||
@@ -0,0 +1,271 @@
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
error_log /var/log/nginx/error.log notice;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
use epoll;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
# 日志格式
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for" '
|
||||
'rt=$request_time ut="$upstream_response_time"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
# 基础配置
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
client_max_body_size 50M;
|
||||
|
||||
# Gzip压缩
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
text/xml
|
||||
text/javascript
|
||||
application/json
|
||||
application/javascript
|
||||
application/xml+rss
|
||||
application/atom+xml
|
||||
image/svg+xml;
|
||||
|
||||
# 上游服务器配置
|
||||
upstream mcp-server {
|
||||
least_conn;
|
||||
server mcp-server:8000 max_fails=3 fail_timeout=30s;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
upstream data-ingestion {
|
||||
least_conn;
|
||||
server data-ingestion:8000 max_fails=3 fail_timeout=30s;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
upstream agent-registry {
|
||||
least_conn;
|
||||
server agent-registry:8080 max_fails=3 fail_timeout=30s;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
upstream billing-engine {
|
||||
least_conn;
|
||||
server billing-engine:8080 max_fails=3 fail_timeout=30s;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
upstream litellm-gateway {
|
||||
least_conn;
|
||||
server litellm-gateway:4000 max_fails=3 fail_timeout=30s;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
# 限流配置
|
||||
limit_req_zone $binary_remote_addr zone=api:10m rate=100r/m;
|
||||
limit_req_zone $binary_remote_addr zone=auth:10m rate=20r/m;
|
||||
|
||||
# 主服务器配置
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
# 安全头
|
||||
add_header X-Frame-Options DENY;
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin";
|
||||
|
||||
# 健康检查端点
|
||||
location /health {
|
||||
access_log off;
|
||||
return 200 "OK\n";
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
|
||||
# MCP服务器路由
|
||||
location /api/mcp/ {
|
||||
limit_req zone=api burst=50 nodelay;
|
||||
|
||||
proxy_pass http://mcp-server/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# WebSocket支持
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
# 超时设置
|
||||
proxy_connect_timeout 30s;
|
||||
proxy_send_timeout 30s;
|
||||
proxy_read_timeout 30s;
|
||||
|
||||
# 缓冲设置
|
||||
proxy_buffering on;
|
||||
proxy_buffer_size 4k;
|
||||
proxy_buffers 8 4k;
|
||||
}
|
||||
|
||||
# 数据接入服务路由
|
||||
location /api/data/ {
|
||||
limit_req zone=api burst=30 nodelay;
|
||||
|
||||
proxy_pass http://data-ingestion/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# 长时间处理支持
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 300s;
|
||||
}
|
||||
|
||||
# Agent注册中心路由
|
||||
location /api/agents/ {
|
||||
limit_req zone=api burst=20 nodelay;
|
||||
|
||||
proxy_pass http://agent-registry/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
proxy_connect_timeout 30s;
|
||||
proxy_send_timeout 30s;
|
||||
proxy_read_timeout 30s;
|
||||
}
|
||||
|
||||
# 计费引擎路由
|
||||
location /api/billing/ {
|
||||
limit_req zone=api burst=100 nodelay;
|
||||
|
||||
proxy_pass http://billing-engine/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
proxy_connect_timeout 30s;
|
||||
proxy_send_timeout 30s;
|
||||
proxy_read_timeout 30s;
|
||||
}
|
||||
|
||||
# LiteLLM网关路由
|
||||
location /api/llm/ {
|
||||
limit_req zone=api burst=20 nodelay;
|
||||
|
||||
proxy_pass http://litellm-gateway/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# LLM请求可能需要更长时间
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 300s;
|
||||
}
|
||||
|
||||
# 静态文件
|
||||
location /static/ {
|
||||
alias /usr/share/nginx/html/static/;
|
||||
expires 1d;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# API文档路由
|
||||
location /docs {
|
||||
proxy_pass http://mcp-server/docs;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# 默认路由
|
||||
location / {
|
||||
return 404 '{"error": "Not Found", "message": "请使用正确的API端点"}';
|
||||
add_header Content-Type application/json;
|
||||
}
|
||||
|
||||
# 错误页面
|
||||
error_page 404 /404.html;
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
|
||||
location = /404.html {
|
||||
return 404 '{"error": "Not Found", "message": "请求的资源不存在"}';
|
||||
add_header Content-Type application/json;
|
||||
}
|
||||
|
||||
location = /50x.html {
|
||||
return 500 '{"error": "Internal Server Error", "message": "服务器内部错误"}';
|
||||
add_header Content-Type application/json;
|
||||
}
|
||||
}
|
||||
|
||||
# HTTPS配置(生产环境使用)
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name localhost;
|
||||
|
||||
# SSL证书配置(需要实际证书文件)
|
||||
# ssl_certificate /etc/nginx/ssl/cert.pem;
|
||||
# ssl_certificate_key /etc/nginx/ssl/key.pem;
|
||||
|
||||
# SSL配置
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384;
|
||||
ssl_prefer_server_ciphers off;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
|
||||
# HSTS
|
||||
add_header Strict-Transport-Security "max-age=63072000" always;
|
||||
|
||||
# 其他配置与HTTP相同...
|
||||
|
||||
# 临时重定向到HTTP(开发环境)
|
||||
return 301 http://$server_name$request_uri;
|
||||
}
|
||||
|
||||
# 监控和状态页面
|
||||
server {
|
||||
listen 8080;
|
||||
server_name localhost;
|
||||
|
||||
location /nginx_status {
|
||||
stub_status on;
|
||||
access_log off;
|
||||
allow 127.0.0.1;
|
||||
allow 172.20.0.0/16; # Docker网络
|
||||
deny all;
|
||||
}
|
||||
|
||||
location /health {
|
||||
access_log off;
|
||||
return 200 "Nginx OK\n";
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# 数据库服务
|
||||
postgres:
|
||||
image: postgres:15-alpine
|
||||
container_name: taiji-postgres
|
||||
environment:
|
||||
POSTGRES_DB: taiji_db
|
||||
POSTGRES_USER: taiji_user
|
||||
POSTGRES_PASSWORD: taiji_pass
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
- ./scripts/init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||
ports:
|
||||
- "5432:5432"
|
||||
networks:
|
||||
- taiji-network
|
||||
restart: unless-stopped
|
||||
|
||||
# Redis缓存服务
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: taiji-redis
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
networks:
|
||||
- taiji-network
|
||||
restart: unless-stopped
|
||||
|
||||
# NATS消息队列
|
||||
nats:
|
||||
image: nats:2.10-alpine
|
||||
container_name: taiji-nats
|
||||
ports:
|
||||
- "4222:4222" # Client connections
|
||||
- "6222:6222" # Routing
|
||||
- "8222:8222" # Monitoring
|
||||
command: ["-js", "-m", "8222"] # Enable JetStream and monitoring
|
||||
volumes:
|
||||
- nats_data:/data
|
||||
networks:
|
||||
- taiji-network
|
||||
restart: unless-stopped
|
||||
|
||||
# LiteLLM网关服务
|
||||
litellm-gateway:
|
||||
build:
|
||||
context: ./services/model-gateway
|
||||
dockerfile: Dockerfile
|
||||
container_name: taiji-litellm-gateway
|
||||
ports:
|
||||
- "4000:4000"
|
||||
environment:
|
||||
- LITELLM_MASTER_KEY=sk-taiji-master-key
|
||||
- DATABASE_URL=postgresql://taiji_user:taiji_pass@postgres:5432/taiji_db
|
||||
- REDIS_URL=redis://redis:6379
|
||||
volumes:
|
||||
- ./services/model-gateway/config:/app/config
|
||||
- ./logs:/app/logs
|
||||
depends_on:
|
||||
- postgres
|
||||
- redis
|
||||
networks:
|
||||
- taiji-network
|
||||
restart: unless-stopped
|
||||
|
||||
# 数据接入服务 (Python)
|
||||
data-ingestion:
|
||||
build:
|
||||
context: ./services/data-ingestion
|
||||
dockerfile: Dockerfile
|
||||
container_name: taiji-data-ingestion
|
||||
ports:
|
||||
- "8001:8000"
|
||||
environment:
|
||||
- DATABASE_URL=postgresql://taiji_user:taiji_pass@postgres:5432/taiji_db
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- NATS_URL=nats://nats:4222
|
||||
volumes:
|
||||
- ./services/data-ingestion:/app
|
||||
- ./logs:/app/logs
|
||||
depends_on:
|
||||
- postgres
|
||||
- redis
|
||||
- nats
|
||||
networks:
|
||||
- taiji-network
|
||||
restart: unless-stopped
|
||||
|
||||
# MCP服务器 (Python)
|
||||
mcp-server:
|
||||
build:
|
||||
context: ./services/mcp-server
|
||||
dockerfile: Dockerfile
|
||||
container_name: taiji-mcp-server
|
||||
ports:
|
||||
- "8002:8000"
|
||||
environment:
|
||||
- DATABASE_URL=postgresql://taiji_user:taiji_pass@postgres:5432/taiji_db
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- NATS_URL=nats://nats:4222
|
||||
- LITELLM_URL=http://litellm-gateway:4000
|
||||
volumes:
|
||||
- ./services/mcp-server:/app
|
||||
- ./logs:/app/logs
|
||||
depends_on:
|
||||
- postgres
|
||||
- redis
|
||||
- nats
|
||||
- litellm-gateway
|
||||
networks:
|
||||
- taiji-network
|
||||
restart: unless-stopped
|
||||
|
||||
# Agent注册中心 (Go)
|
||||
agent-registry:
|
||||
build:
|
||||
context: ./services/agent-registry
|
||||
dockerfile: Dockerfile
|
||||
container_name: taiji-agent-registry
|
||||
ports:
|
||||
- "8003:8080"
|
||||
environment:
|
||||
- DATABASE_URL=postgresql://taiji_user:taiji_pass@postgres:5432/taiji_db
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- NATS_URL=nats://nats:4222
|
||||
volumes:
|
||||
- ./services/agent-registry:/app
|
||||
- ./logs:/app/logs
|
||||
depends_on:
|
||||
- postgres
|
||||
- redis
|
||||
- nats
|
||||
networks:
|
||||
- taiji-network
|
||||
restart: unless-stopped
|
||||
|
||||
# EU计费引擎 (Go)
|
||||
billing-engine:
|
||||
build:
|
||||
context: ./services/billing-engine
|
||||
dockerfile: Dockerfile
|
||||
container_name: taiji-billing-engine
|
||||
ports:
|
||||
- "8004:8080"
|
||||
environment:
|
||||
- DATABASE_URL=postgresql://taiji_user:taiji_pass@postgres:5432/taiji_db
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- NATS_URL=nats://nats:4222
|
||||
volumes:
|
||||
- ./services/billing-engine:/app
|
||||
- ./logs:/app/logs
|
||||
depends_on:
|
||||
- postgres
|
||||
- redis
|
||||
- nats
|
||||
networks:
|
||||
- taiji-network
|
||||
restart: unless-stopped
|
||||
|
||||
# API网关 (Nginx)
|
||||
api-gateway:
|
||||
image: nginx:alpine
|
||||
container_name: taiji-api-gateway
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./config/nginx.conf:/etc/nginx/nginx.conf
|
||||
- ./config/ssl:/etc/nginx/ssl
|
||||
depends_on:
|
||||
- data-ingestion
|
||||
- mcp-server
|
||||
- agent-registry
|
||||
- billing-engine
|
||||
networks:
|
||||
- taiji-network
|
||||
restart: unless-stopped
|
||||
|
||||
# 监控服务 - Prometheus
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
container_name: taiji-prometheus
|
||||
ports:
|
||||
- "9090:9090"
|
||||
volumes:
|
||||
- ./config/prometheus.yml:/etc/prometheus/prometheus.yml
|
||||
- prometheus_data:/prometheus
|
||||
command:
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
- '--storage.tsdb.path=/prometheus'
|
||||
- '--web.console.libraries=/etc/prometheus/console_libraries'
|
||||
- '--web.console.templates=/etc/prometheus/consoles'
|
||||
- '--web.enable-lifecycle'
|
||||
networks:
|
||||
- taiji-network
|
||||
restart: unless-stopped
|
||||
|
||||
# 监控服务 - Grafana
|
||||
grafana:
|
||||
image: grafana/grafana:latest
|
||||
container_name: taiji-grafana
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- GF_SECURITY_ADMIN_PASSWORD=admin
|
||||
volumes:
|
||||
- grafana_data:/var/lib/grafana
|
||||
- ./config/grafana/dashboards:/etc/grafana/provisioning/dashboards
|
||||
- ./config/grafana/datasources:/etc/grafana/provisioning/datasources
|
||||
depends_on:
|
||||
- prometheus
|
||||
networks:
|
||||
- taiji-network
|
||||
restart: unless-stopped
|
||||
|
||||
# 开发环境容器 (可选)
|
||||
dev-container:
|
||||
build:
|
||||
context: ./dev-environment
|
||||
dockerfile: Dockerfile
|
||||
container_name: taiji-dev
|
||||
volumes:
|
||||
- .:/workspace
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
working_dir: /workspace
|
||||
tty: true
|
||||
stdin_open: true
|
||||
networks:
|
||||
- taiji-network
|
||||
profiles:
|
||||
- dev
|
||||
|
||||
networks:
|
||||
taiji-network:
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.20.0.0/16
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
nats_data:
|
||||
prometheus_data:
|
||||
grafana_data:
|
||||
@@ -0,0 +1,106 @@
|
||||
-- taiji-AI-PAD 数据库初始化脚本
|
||||
|
||||
-- 创建扩展
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
CREATE EXTENSION IF NOT EXISTS "pg_trgm";
|
||||
|
||||
-- 创建数据库(如果不存在)
|
||||
-- 注意:在Docker初始化脚本中,数据库已经存在
|
||||
|
||||
-- 设置时区
|
||||
SET timezone = 'UTC';
|
||||
|
||||
-- 创建一些基础索引(如果表已存在的话,模型会自动创建)
|
||||
-- 这里可以添加一些额外的性能优化索引
|
||||
|
||||
-- 创建全文搜索配置
|
||||
CREATE TEXT SEARCH CONFIGURATION IF NOT EXISTS simple_english (COPY = english);
|
||||
|
||||
-- 创建一些有用的函数
|
||||
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = NOW();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ language 'plpgsql';
|
||||
|
||||
-- 日志表(用于审计和调试)
|
||||
CREATE TABLE IF NOT EXISTS system_logs (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
level VARCHAR(20) NOT NULL,
|
||||
service VARCHAR(50) NOT NULL,
|
||||
message TEXT NOT NULL,
|
||||
context JSONB,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_system_logs_service ON system_logs(service);
|
||||
CREATE INDEX IF NOT EXISTS idx_system_logs_level ON system_logs(level);
|
||||
CREATE INDEX IF NOT EXISTS idx_system_logs_created ON system_logs(created_at);
|
||||
|
||||
-- 配置表
|
||||
CREATE TABLE IF NOT EXISTS system_config (
|
||||
key VARCHAR(100) PRIMARY KEY,
|
||||
value JSONB NOT NULL,
|
||||
description TEXT,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 创建触发器
|
||||
CREATE TRIGGER update_system_config_updated_at
|
||||
BEFORE UPDATE ON system_config
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
-- 插入初始配置
|
||||
INSERT INTO system_config (key, value, description) VALUES
|
||||
('app_version', '"1.0.0"', 'Application version'),
|
||||
('maintenance_mode', 'false', 'Maintenance mode flag'),
|
||||
('max_api_calls_per_minute', '1000', 'Maximum API calls per minute'),
|
||||
('default_timeout', '30', 'Default timeout in seconds')
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
|
||||
-- 性能优化设置
|
||||
-- 注意:这些设置可能需要根据实际硬件调整
|
||||
ALTER SYSTEM SET shared_preload_libraries = 'pg_stat_statements';
|
||||
ALTER SYSTEM SET max_connections = 200;
|
||||
ALTER SYSTEM SET shared_buffers = '256MB';
|
||||
ALTER SYSTEM SET effective_cache_size = '1GB';
|
||||
ALTER SYSTEM SET maintenance_work_mem = '64MB';
|
||||
ALTER SYSTEM SET checkpoint_completion_target = 0.9;
|
||||
ALTER SYSTEM SET wal_buffers = '16MB';
|
||||
ALTER SYSTEM SET default_statistics_target = 100;
|
||||
ALTER SYSTEM SET random_page_cost = 1.1;
|
||||
ALTER SYSTEM SET effective_io_concurrency = 200;
|
||||
ALTER SYSTEM SET work_mem = '4MB';
|
||||
ALTER SYSTEM SET min_wal_size = '1GB';
|
||||
ALTER SYSTEM SET max_wal_size = '4GB';
|
||||
|
||||
-- 创建监控视图
|
||||
CREATE OR REPLACE VIEW system_stats AS
|
||||
SELECT
|
||||
schemaname,
|
||||
tablename,
|
||||
attname,
|
||||
n_distinct,
|
||||
correlation
|
||||
FROM pg_stats
|
||||
WHERE schemaname = 'public';
|
||||
|
||||
-- 创建连接监控视图
|
||||
CREATE OR REPLACE VIEW connection_stats AS
|
||||
SELECT
|
||||
datname,
|
||||
numbackends,
|
||||
xact_commit,
|
||||
xact_rollback,
|
||||
blks_read,
|
||||
blks_hit,
|
||||
tup_returned,
|
||||
tup_fetched,
|
||||
tup_inserted,
|
||||
tup_updated,
|
||||
tup_deleted
|
||||
FROM pg_stat_database
|
||||
WHERE datname = current_database();
|
||||
Executable
+168
@@ -0,0 +1,168 @@
|
||||
#!/bin/bash
|
||||
|
||||
# taiji-AI-PAD 启动脚本
|
||||
|
||||
set -e
|
||||
|
||||
echo "🚀 启动 taiji-AI-PAD 平台..."
|
||||
|
||||
# 检查Docker是否运行
|
||||
if ! docker info >/dev/null 2>&1; then
|
||||
echo "❌ Docker 未运行,请先启动Docker"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 检查Docker Compose是否可用
|
||||
if ! command -v docker-compose >/dev/null 2>&1; then
|
||||
echo "❌ Docker Compose 未找到,请安装Docker Compose"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 创建必要的目录
|
||||
echo "📁 创建必要的目录..."
|
||||
mkdir -p logs
|
||||
mkdir -p config/ssl
|
||||
mkdir -p services/model-gateway/config
|
||||
mkdir -p services/data-ingestion/models
|
||||
mkdir -p services/data-ingestion/cache
|
||||
|
||||
# 设置环境变量(如果.env文件不存在)
|
||||
if [ ! -f .env ]; then
|
||||
echo "⚙️ 创建环境配置文件..."
|
||||
cat > .env << EOF
|
||||
# 环境设置
|
||||
ENVIRONMENT=development
|
||||
|
||||
# 数据库设置
|
||||
POSTGRES_DB=taiji_db
|
||||
POSTGRES_USER=taiji_user
|
||||
POSTGRES_PASSWORD=taiji_pass
|
||||
DATABASE_URL=postgresql+asyncpg://taiji_user:taiji_pass@postgres:5432/taiji_db
|
||||
|
||||
# Redis设置
|
||||
REDIS_URL=redis://redis:6379
|
||||
|
||||
# NATS设置
|
||||
NATS_URL=nats://nats:4222
|
||||
|
||||
# LiteLLM设置
|
||||
LITELLM_MASTER_KEY=sk-taiji-master-key
|
||||
LITELLM_URL=http://litellm-gateway:4000
|
||||
|
||||
# RapidAPI设置(需要实际的API Key)
|
||||
RAPIDAPI_KEY=your-rapidapi-key-here
|
||||
RAPIDAPI_HOST=rapidapi.com
|
||||
|
||||
# APILLAMA模型设置
|
||||
APILLAMA_MODEL_PATH=/app/models/llama-3-8b-instruct
|
||||
APILLAMA_DEVICE=cpu
|
||||
EOF
|
||||
echo "✅ 环境配置文件已创建,请根据需要修改 .env 文件"
|
||||
fi
|
||||
|
||||
# 检查必要的配置文件
|
||||
if [ ! -f config/nginx.conf ]; then
|
||||
echo "❌ Nginx配置文件未找到:config/nginx.conf"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f scripts/init.sql ]; then
|
||||
echo "❌ 数据库初始化脚本未找到:scripts/init.sql"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 拉取基础镜像
|
||||
echo "⬇️ 拉取基础镜像..."
|
||||
docker-compose pull postgres redis nats prometheus grafana nginx
|
||||
|
||||
# 构建服务镜像
|
||||
echo "🏗️ 构建服务镜像..."
|
||||
docker-compose build
|
||||
|
||||
# 启动基础设施服务
|
||||
echo "🗄️ 启动基础设施服务..."
|
||||
docker-compose up -d postgres redis nats
|
||||
|
||||
# 等待数据库就绪
|
||||
echo "⏳ 等待数据库就绪..."
|
||||
sleep 10
|
||||
|
||||
# 检查数据库连接
|
||||
echo "🔍 检查数据库连接..."
|
||||
until docker-compose exec -T postgres pg_isready -U taiji_user -d taiji_db; do
|
||||
echo "等待数据库..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# 启动应用服务
|
||||
echo "🚀 启动应用服务..."
|
||||
docker-compose up -d
|
||||
|
||||
# 等待服务启动
|
||||
echo "⏳ 等待服务启动..."
|
||||
sleep 15
|
||||
|
||||
# 检查服务状态
|
||||
echo "🔍 检查服务状态..."
|
||||
docker-compose ps
|
||||
|
||||
# 健康检查
|
||||
echo "🏥 执行健康检查..."
|
||||
services=("mcp-server:8002" "data-ingestion:8001" "agent-registry:8003" "billing-engine:8004")
|
||||
|
||||
for service in "${services[@]}"; do
|
||||
service_name=$(echo $service | cut -d':' -f1)
|
||||
port=$(echo $service | cut -d':' -f2)
|
||||
|
||||
echo "检查 $service_name..."
|
||||
if curl -f -s http://localhost:$port/health > /dev/null; then
|
||||
echo "✅ $service_name 健康"
|
||||
else
|
||||
echo "⚠️ $service_name 可能未就绪"
|
||||
fi
|
||||
done
|
||||
|
||||
# 显示访问信息
|
||||
echo ""
|
||||
echo "🎉 taiji-AI-PAD 启动完成!"
|
||||
echo ""
|
||||
echo "📊 服务访问地址:"
|
||||
echo " • API网关: http://localhost"
|
||||
echo " • MCP服务器: http://localhost:8002"
|
||||
echo " • 数据接入服务: http://localhost:8001"
|
||||
echo " • Agent注册中心: http://localhost:8003"
|
||||
echo " • 计费引擎: http://localhost:8004"
|
||||
echo " • LiteLLM网关: http://localhost:4000"
|
||||
echo ""
|
||||
echo "📈 监控服务:"
|
||||
echo " • Grafana: http://localhost:3000 (admin/admin)"
|
||||
echo " • Prometheus: http://localhost:9090"
|
||||
echo ""
|
||||
echo "🗄️ 数据库服务:"
|
||||
echo " • PostgreSQL: localhost:5432"
|
||||
echo " • Redis: localhost:6379"
|
||||
echo " • NATS: localhost:4222"
|
||||
echo ""
|
||||
echo "📚 API文档:"
|
||||
echo " • MCP服务器: http://localhost:8002/docs"
|
||||
echo " • 数据接入服务: http://localhost:8001/docs"
|
||||
echo ""
|
||||
echo "🔧 管理命令:"
|
||||
echo " • 查看日志: docker-compose logs -f [服务名]"
|
||||
echo " • 停止服务: docker-compose down"
|
||||
echo " • 重启服务: docker-compose restart [服务名]"
|
||||
echo ""
|
||||
|
||||
# 开发环境提示
|
||||
if [ "$ENVIRONMENT" = "development" ]; then
|
||||
echo "🔧 开发环境提示:"
|
||||
echo " • 代码变更会自动重载"
|
||||
echo " • 日志级别设置为DEBUG"
|
||||
echo " • 请确保修改.env文件中的API密钥"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "🎯 接下来您可以:"
|
||||
echo " 1. 访问 http://localhost:8002/docs 查看MCP API文档"
|
||||
echo " 2. 使用 scripts/test.sh 运行测试"
|
||||
echo " 3. 查看 docs/ 目录了解更多使用方法"
|
||||
Executable
+57
@@ -0,0 +1,57 @@
|
||||
#!/bin/bash
|
||||
|
||||
# taiji-AI-PAD 停止脚本
|
||||
|
||||
set -e
|
||||
|
||||
echo "🛑 停止 taiji-AI-PAD 平台..."
|
||||
|
||||
# 检查Docker Compose是否可用
|
||||
if ! command -v docker-compose >/dev/null 2>&1; then
|
||||
echo "❌ Docker Compose 未找到"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 显示当前运行的服务
|
||||
echo "📋 当前运行的服务:"
|
||||
docker-compose ps
|
||||
|
||||
# 停止所有服务
|
||||
echo "⏹️ 停止所有服务..."
|
||||
docker-compose down
|
||||
|
||||
# 可选:清理数据卷(谨慎使用)
|
||||
if [ "$1" = "--clean" ]; then
|
||||
echo "🧹 清理数据卷..."
|
||||
read -p "⚠️ 这将删除所有数据,是否继续? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
docker-compose down -v
|
||||
docker system prune -f
|
||||
echo "✅ 数据卷已清理"
|
||||
else
|
||||
echo "❌ 已取消清理操作"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 可选:清理镜像
|
||||
if [ "$1" = "--clean-all" ]; then
|
||||
echo "🧹 清理镜像和数据..."
|
||||
read -p "⚠️ 这将删除所有镜像和数据,是否继续? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
docker-compose down -v --rmi all
|
||||
docker system prune -a -f
|
||||
echo "✅ 镜像和数据已清理"
|
||||
else
|
||||
echo "❌ 已取消清理操作"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "✅ taiji-AI-PAD 已停止"
|
||||
echo ""
|
||||
echo "💡 清理选项:"
|
||||
echo " • 清理数据卷: ./scripts/stop.sh --clean"
|
||||
echo " • 清理所有数据: ./scripts/stop.sh --clean-all"
|
||||
echo " • 重新启动: ./scripts/start.sh"
|
||||
Executable
+242
@@ -0,0 +1,242 @@
|
||||
#!/bin/bash
|
||||
|
||||
# taiji-AI-PAD 测试脚本
|
||||
|
||||
set -e
|
||||
|
||||
echo "🧪 开始测试 taiji-AI-PAD 平台..."
|
||||
|
||||
# 检查服务是否运行
|
||||
check_service() {
|
||||
local service_name=$1
|
||||
local url=$2
|
||||
local expected_status=${3:-200}
|
||||
|
||||
echo "🔍 检查 $service_name..."
|
||||
|
||||
if curl -s -o /dev/null -w "%{http_code}" "$url" | grep -q "$expected_status"; then
|
||||
echo "✅ $service_name 正常运行"
|
||||
return 0
|
||||
else
|
||||
echo "❌ $service_name 无响应"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 测试API端点
|
||||
test_api_endpoint() {
|
||||
local name=$1
|
||||
local url=$2
|
||||
local method=${3:-GET}
|
||||
local data=${4:-""}
|
||||
|
||||
echo "🧪 测试 $name..."
|
||||
|
||||
if [ -n "$data" ]; then
|
||||
response=$(curl -s -X "$method" -H "Content-Type: application/json" -d "$data" "$url" 2>/dev/null || echo "ERROR")
|
||||
else
|
||||
response=$(curl -s -X "$method" "$url" 2>/dev/null || echo "ERROR")
|
||||
fi
|
||||
|
||||
if [ "$response" = "ERROR" ]; then
|
||||
echo "❌ $name 测试失败"
|
||||
return 1
|
||||
else
|
||||
echo "✅ $name 测试通过"
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
echo " 响应: $(echo "$response" | jq -c . 2>/dev/null || echo "$response")"
|
||||
else
|
||||
echo " 响应: $response"
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# 等待服务启动
|
||||
wait_for_services() {
|
||||
echo "⏳ 等待服务启动..."
|
||||
sleep 5
|
||||
|
||||
local max_attempts=30
|
||||
local attempt=1
|
||||
|
||||
while [ $attempt -le $max_attempts ]; do
|
||||
if curl -s http://localhost:8002/health > /dev/null 2>&1; then
|
||||
echo "✅ 服务已就绪"
|
||||
break
|
||||
fi
|
||||
|
||||
echo "等待中... ($attempt/$max_attempts)"
|
||||
sleep 2
|
||||
((attempt++))
|
||||
done
|
||||
|
||||
if [ $attempt -gt $max_attempts ]; then
|
||||
echo "❌ 服务启动超时"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 主测试流程
|
||||
main() {
|
||||
echo "🚀 taiji-AI-PAD 平台测试"
|
||||
echo "========================"
|
||||
|
||||
# 等待服务启动
|
||||
wait_for_services
|
||||
|
||||
# 基础健康检查
|
||||
echo ""
|
||||
echo "📋 基础健康检查"
|
||||
echo "----------------"
|
||||
|
||||
local services=(
|
||||
"MCP服务器:http://localhost:8002/health"
|
||||
"数据接入服务:http://localhost:8001/health"
|
||||
"API网关:http://localhost/health"
|
||||
)
|
||||
|
||||
local failed_services=0
|
||||
|
||||
for service_info in "${services[@]}"; do
|
||||
IFS=':' read -r name url <<< "$service_info"
|
||||
if ! check_service "$name" "$url"; then
|
||||
((failed_services++))
|
||||
fi
|
||||
done
|
||||
|
||||
# API功能测试
|
||||
echo ""
|
||||
echo "🔧 API功能测试"
|
||||
echo "---------------"
|
||||
|
||||
local api_tests=(
|
||||
"MCP服务器健康检查:http://localhost:8002/health:GET"
|
||||
"数据接入服务健康检查:http://localhost:8001/health:GET"
|
||||
"MCP工具列表:http://localhost:8002/tools:GET"
|
||||
"数据接入统计:http://localhost:8001/stats:GET"
|
||||
)
|
||||
|
||||
local failed_tests=0
|
||||
|
||||
for test_info in "${api_tests[@]}"; do
|
||||
IFS=':' read -r name url method <<< "$test_info"
|
||||
if ! test_api_endpoint "$name" "$url" "$method"; then
|
||||
((failed_tests++))
|
||||
fi
|
||||
done
|
||||
|
||||
# Agent创建测试
|
||||
echo ""
|
||||
echo "🤖 Agent创建测试"
|
||||
echo "----------------"
|
||||
|
||||
local agent_data='{
|
||||
"name": "test-agent",
|
||||
"description": "测试Agent",
|
||||
"role": "测试助手",
|
||||
"goal": "执行测试任务",
|
||||
"tools": ["web_search"],
|
||||
"config": {}
|
||||
}'
|
||||
|
||||
if test_api_endpoint "创建Agent" "http://localhost:8002/agents" "POST" "$agent_data"; then
|
||||
echo "🎉 Agent创建测试通过"
|
||||
else
|
||||
echo "❌ Agent创建测试失败"
|
||||
((failed_tests++))
|
||||
fi
|
||||
|
||||
# MCP协议测试
|
||||
echo ""
|
||||
echo "🔗 MCP协议测试"
|
||||
echo "--------------"
|
||||
|
||||
local mcp_request='{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "test-1",
|
||||
"method": "tools/list",
|
||||
"params": {}
|
||||
}'
|
||||
|
||||
if test_api_endpoint "MCP工具列表" "http://localhost:8002/agents/test-agent/execute" "POST" "$mcp_request"; then
|
||||
echo "🎉 MCP协议测试通过"
|
||||
else
|
||||
echo "❌ MCP协议测试失败"
|
||||
((failed_tests++))
|
||||
fi
|
||||
|
||||
# 性能测试
|
||||
echo ""
|
||||
echo "⚡ 简单性能测试"
|
||||
echo "---------------"
|
||||
|
||||
echo "🔄 并发请求测试..."
|
||||
local start_time=$(date +%s%N)
|
||||
|
||||
for i in {1..10}; do
|
||||
curl -s http://localhost:8002/health > /dev/null &
|
||||
done
|
||||
wait
|
||||
|
||||
local end_time=$(date +%s%N)
|
||||
local duration=$((($end_time - $start_time) / 1000000))
|
||||
|
||||
echo "✅ 10个并发请求耗时: ${duration}ms"
|
||||
|
||||
# 负载测试(如果安装了ab)
|
||||
if command -v ab >/dev/null 2>&1; then
|
||||
echo "🚀 负载测试 (100个请求,并发10)..."
|
||||
ab -n 100 -c 10 -q http://localhost:8002/health | grep -E "(Requests per second|Time per request)"
|
||||
else
|
||||
echo "💡 提示: 安装 apache2-utils 可进行更详细的性能测试"
|
||||
fi
|
||||
|
||||
# 测试报告
|
||||
echo ""
|
||||
echo "📊 测试报告"
|
||||
echo "==========="
|
||||
|
||||
local total_services=${#services[@]}
|
||||
local total_tests=$((${#api_tests[@]} + 2)) # API测试 + Agent创建 + MCP协议
|
||||
|
||||
echo "服务检查: $((total_services - failed_services))/$total_services 通过"
|
||||
echo "功能测试: $((total_tests - failed_tests))/$total_tests 通过"
|
||||
|
||||
if [ $failed_services -eq 0 ] && [ $failed_tests -eq 0 ]; then
|
||||
echo ""
|
||||
echo "🎉 所有测试通过!taiji-AI-PAD 运行正常"
|
||||
echo ""
|
||||
echo "🔗 快速访问链接:"
|
||||
echo " • MCP API文档: http://localhost:8002/docs"
|
||||
echo " • 数据接入API: http://localhost:8001/docs"
|
||||
echo " • Grafana监控: http://localhost:3000"
|
||||
echo ""
|
||||
return 0
|
||||
else
|
||||
echo ""
|
||||
echo "❌ 部分测试失败,请检查服务状态"
|
||||
echo ""
|
||||
echo "🔧 故障排除:"
|
||||
echo " • 查看日志: docker-compose logs"
|
||||
echo " • 检查服务状态: docker-compose ps"
|
||||
echo " • 重启服务: docker-compose restart"
|
||||
echo ""
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 清理函数
|
||||
cleanup() {
|
||||
echo ""
|
||||
echo "🧹 测试清理..."
|
||||
# 删除测试创建的Agent(如果存在)
|
||||
curl -s -X DELETE http://localhost:8002/agents/test-agent > /dev/null 2>&1 || true
|
||||
echo "✅ 清理完成"
|
||||
}
|
||||
|
||||
# 设置清理陷阱
|
||||
trap cleanup EXIT
|
||||
|
||||
# 运行测试
|
||||
main "$@"
|
||||
@@ -0,0 +1,39 @@
|
||||
FROM python:3.11-slim
|
||||
|
||||
# 设置工作目录
|
||||
WORKDIR /app
|
||||
|
||||
# 安装系统依赖
|
||||
RUN apt-get update && apt-get install -y \
|
||||
gcc \
|
||||
g++ \
|
||||
make \
|
||||
curl \
|
||||
git \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# 复制requirements文件
|
||||
COPY requirements.txt .
|
||||
|
||||
# 安装Python依赖
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# 复制源代码
|
||||
COPY . .
|
||||
|
||||
# 创建必要目录
|
||||
RUN mkdir -p logs models cache
|
||||
|
||||
# 设置环境变量
|
||||
ENV PYTHONPATH=/app
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 8000
|
||||
|
||||
# 健康检查
|
||||
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
|
||||
CMD curl -f http://localhost:8000/health || exit 1
|
||||
|
||||
# 启动应用
|
||||
CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
|
||||
@@ -0,0 +1,146 @@
|
||||
"""
|
||||
数据接入服务配置管理
|
||||
"""
|
||||
|
||||
import os
|
||||
from typing import List, Optional
|
||||
from pydantic_settings import BaseSettings
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
"""数据接入服务配置"""
|
||||
|
||||
# 应用设置
|
||||
app_name: str = "taiji-AI-PAD 数据接入服务"
|
||||
debug: bool = False
|
||||
|
||||
# Redis设置
|
||||
redis_url: str = os.getenv("REDIS_URL", "redis://redis:6379")
|
||||
redis_max_connections: int = 20
|
||||
|
||||
# NATS设置
|
||||
nats_url: str = os.getenv("NATS_URL", "nats://nats:4222")
|
||||
|
||||
# RapidAPI设置
|
||||
rapidapi_key: str = os.getenv("RAPIDAPI_KEY", "")
|
||||
rapidapi_host: str = os.getenv("RAPIDAPI_HOST", "rapidapi.com")
|
||||
rapidapi_base_url: str = "https://rapidapi.com"
|
||||
rapidapi_timeout: int = 30
|
||||
rapidapi_rate_limit: int = 1000 # 每分钟请求数
|
||||
|
||||
# APILLAMA模型设置
|
||||
apillama_model_path: str = os.getenv(
|
||||
"APILLAMA_MODEL_PATH",
|
||||
"/app/models/llama-3-8b-instruct"
|
||||
)
|
||||
apillama_device: str = os.getenv("APILLAMA_DEVICE", "cpu")
|
||||
apillama_max_length: int = 2048
|
||||
apillama_temperature: float = 0.3
|
||||
apillama_top_p: float = 0.9
|
||||
|
||||
# 缓存设置
|
||||
cache_dir: str = "/app/cache"
|
||||
cache_ttl: int = 3600 # 秒
|
||||
max_cache_size: int = 1000 # MB
|
||||
|
||||
# OpenAPI解析设置
|
||||
openapi_timeout: int = 60
|
||||
openapi_max_size: int = 10 * 1024 * 1024 # 10MB
|
||||
supported_openapi_versions: List[str] = ["2.0", "3.0", "3.1"]
|
||||
|
||||
# 工具生成设置
|
||||
max_tools_per_api: int = 50
|
||||
tool_name_max_length: int = 100
|
||||
tool_description_max_length: int = 500
|
||||
|
||||
# API处理设置
|
||||
max_concurrent_requests: int = 10
|
||||
request_timeout: int = 30
|
||||
retry_attempts: int = 3
|
||||
retry_delay: float = 1.0
|
||||
|
||||
# 安全设置
|
||||
allowed_domains: List[str] = [
|
||||
"rapidapi.com",
|
||||
"github.com",
|
||||
"swagger.io",
|
||||
"openapis.org"
|
||||
]
|
||||
blocked_domains: List[str] = []
|
||||
|
||||
# 监控设置
|
||||
enable_metrics: bool = True
|
||||
metrics_port: int = 8001
|
||||
|
||||
# 日志设置
|
||||
log_level: str = "INFO"
|
||||
log_format: str = "json"
|
||||
log_file: Optional[str] = "/app/logs/data-ingestion.log"
|
||||
|
||||
# 并发设置
|
||||
max_workers: int = 4
|
||||
max_queue_size: int = 1000
|
||||
|
||||
# API限制设置
|
||||
max_endpoints_per_spec: int = 200
|
||||
max_parameters_per_endpoint: int = 50
|
||||
max_response_schemas: int = 100
|
||||
|
||||
# 文件处理设置
|
||||
temp_dir: str = "/tmp/taiji-data-ingestion"
|
||||
max_file_size: int = 50 * 1024 * 1024 # 50MB
|
||||
allowed_file_types: List[str] = [
|
||||
"application/json",
|
||||
"text/yaml",
|
||||
"text/plain",
|
||||
"application/yaml"
|
||||
]
|
||||
|
||||
# 数据库设置(如果需要持久化)
|
||||
database_url: Optional[str] = os.getenv("DATABASE_URL")
|
||||
|
||||
class Config:
|
||||
env_file = ".env"
|
||||
env_file_encoding = "utf-8"
|
||||
case_sensitive = False
|
||||
|
||||
|
||||
class DevelopmentSettings(Settings):
|
||||
"""开发环境配置"""
|
||||
debug: bool = True
|
||||
log_level: str = "DEBUG"
|
||||
apillama_device: str = "cpu"
|
||||
cache_ttl: int = 600 # 10分钟
|
||||
|
||||
|
||||
class ProductionSettings(Settings):
|
||||
"""生产环境配置"""
|
||||
debug: bool = False
|
||||
log_level: str = "INFO"
|
||||
apillama_device: str = "cuda" # 如果有GPU
|
||||
max_concurrent_requests: int = 50
|
||||
max_workers: int = 8
|
||||
|
||||
|
||||
class TestingSettings(Settings):
|
||||
"""测试环境配置"""
|
||||
debug: bool = True
|
||||
redis_url: str = "redis://localhost:6379/1" # 使用不同的数据库
|
||||
cache_ttl: int = 60 # 1分钟
|
||||
rapidapi_key: str = "test-key"
|
||||
|
||||
|
||||
def get_settings() -> Settings:
|
||||
"""根据环境变量获取相应的配置"""
|
||||
environment = os.getenv("ENVIRONMENT", "development").lower()
|
||||
|
||||
if environment == "production":
|
||||
return ProductionSettings()
|
||||
elif environment == "testing":
|
||||
return TestingSettings()
|
||||
else:
|
||||
return DevelopmentSettings()
|
||||
|
||||
|
||||
# 全局配置实例
|
||||
settings = get_settings()
|
||||
@@ -0,0 +1,547 @@
|
||||
"""
|
||||
taiji-AI-PAD 数据接入服务
|
||||
负责全域数据接入与工具化治理,包括RapidAPI集成和APILLAMA技术实现
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional, Union
|
||||
|
||||
import structlog
|
||||
from fastapi import FastAPI, HTTPException, BackgroundTasks, Depends
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import JSONResponse
|
||||
from pydantic import BaseModel
|
||||
import redis.asyncio as redis
|
||||
import nats
|
||||
import httpx
|
||||
|
||||
from .config import Settings
|
||||
from .schemas import (
|
||||
APIEndpoint, ToolDefinition,
|
||||
RapidAPIRequest, APIParsedResponse,
|
||||
APILLAMARequest, APILLAMAResponse
|
||||
)
|
||||
from .rapidapi_client import RapidAPIClient
|
||||
from .apillama_processor import APILLAMAProcessor
|
||||
from .openapi_parser import OpenAPIParser
|
||||
from .tool_generator import ToolGenerator
|
||||
|
||||
# 配置日志
|
||||
structlog.configure(
|
||||
processors=[
|
||||
structlog.stdlib.filter_by_level,
|
||||
structlog.stdlib.add_logger_name,
|
||||
structlog.stdlib.add_log_level,
|
||||
structlog.stdlib.PositionalArgumentsFormatter(),
|
||||
structlog.processors.TimeStamper(fmt="iso"),
|
||||
structlog.processors.StackInfoRenderer(),
|
||||
structlog.processors.format_exc_info,
|
||||
structlog.processors.UnicodeDecoder(),
|
||||
structlog.processors.JSONRenderer()
|
||||
],
|
||||
context_class=dict,
|
||||
logger_factory=structlog.stdlib.LoggerFactory(),
|
||||
cache_logger_on_first_use=True,
|
||||
)
|
||||
|
||||
logger = structlog.get_logger()
|
||||
|
||||
# 应用设置
|
||||
settings = Settings()
|
||||
app = FastAPI(
|
||||
title="taiji-AI-PAD 数据接入服务",
|
||||
description="全域数据接入与工具化治理服务,支持RapidAPI集成和APILLAMA技术",
|
||||
version="1.0.0",
|
||||
docs_url="/docs",
|
||||
redoc_url="/redoc"
|
||||
)
|
||||
|
||||
# CORS配置
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
# 全局变量
|
||||
redis_client: Optional[redis.Redis] = None
|
||||
nats_client: Optional[nats.NATS] = None
|
||||
rapidapi_client: Optional[RapidAPIClient] = None
|
||||
apillama_processor: Optional[APILLAMAProcessor] = None
|
||||
openapi_parser: Optional[OpenAPIParser] = None
|
||||
tool_generator: Optional[ToolGenerator] = None
|
||||
|
||||
class HealthResponse(BaseModel):
|
||||
status: str
|
||||
timestamp: str
|
||||
services: Dict[str, str]
|
||||
stats: Dict[str, int]
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup_event():
|
||||
"""应用启动初始化"""
|
||||
global redis_client, nats_client, rapidapi_client
|
||||
global apillama_processor, openapi_parser, tool_generator
|
||||
|
||||
try:
|
||||
# 连接Redis
|
||||
redis_client = redis.from_url(
|
||||
settings.redis_url,
|
||||
encoding="utf-8",
|
||||
decode_responses=True
|
||||
)
|
||||
await redis_client.ping()
|
||||
logger.info("Redis连接成功")
|
||||
|
||||
# 连接NATS
|
||||
nats_client = await nats.connect(settings.nats_url)
|
||||
logger.info("NATS连接成功")
|
||||
|
||||
# 初始化RapidAPI客户端
|
||||
rapidapi_client = RapidAPIClient(
|
||||
api_key=settings.rapidapi_key,
|
||||
host=settings.rapidapi_host,
|
||||
redis_client=redis_client
|
||||
)
|
||||
logger.info("RapidAPI客户端初始化完成")
|
||||
|
||||
# 初始化APILLAMA处理器
|
||||
apillama_processor = APILLAMAProcessor(
|
||||
model_path=settings.apillama_model_path,
|
||||
cache_dir=settings.cache_dir,
|
||||
redis_client=redis_client
|
||||
)
|
||||
await apillama_processor.initialize()
|
||||
logger.info("APILLAMA处理器初始化完成")
|
||||
|
||||
# 初始化OpenAPI解析器
|
||||
openapi_parser = OpenAPIParser(
|
||||
cache_dir=settings.cache_dir,
|
||||
redis_client=redis_client
|
||||
)
|
||||
logger.info("OpenAPI解析器初始化完成")
|
||||
|
||||
# 初始化工具生成器
|
||||
tool_generator = ToolGenerator(
|
||||
redis_client=redis_client,
|
||||
nats_client=nats_client,
|
||||
apillama_processor=apillama_processor
|
||||
)
|
||||
logger.info("工具生成器初始化完成")
|
||||
|
||||
# 启动后台任务
|
||||
asyncio.create_task(background_api_sync())
|
||||
|
||||
logger.info("数据接入服务启动完成")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"服务启动失败: {e}")
|
||||
raise
|
||||
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown_event():
|
||||
"""应用关闭清理"""
|
||||
global redis_client, nats_client, apillama_processor
|
||||
|
||||
try:
|
||||
# 关闭NATS连接
|
||||
if nats_client:
|
||||
await nats_client.close()
|
||||
|
||||
# 关闭Redis连接
|
||||
if redis_client:
|
||||
await redis_client.close()
|
||||
|
||||
# 清理APILLAMA处理器
|
||||
if apillama_processor:
|
||||
await apillama_processor.cleanup()
|
||||
|
||||
logger.info("资源清理完成")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"资源清理失败: {e}")
|
||||
|
||||
@app.get("/health", response_model=HealthResponse)
|
||||
async def health_check():
|
||||
"""健康检查端点"""
|
||||
services = {
|
||||
"data_ingestion": "healthy",
|
||||
"redis": "unknown",
|
||||
"nats": "unknown",
|
||||
"rapidapi": "unknown",
|
||||
"apillama": "unknown"
|
||||
}
|
||||
|
||||
stats = {
|
||||
"total_apis": 0,
|
||||
"processed_apis": 0,
|
||||
"generated_tools": 0,
|
||||
"cache_size": 0
|
||||
}
|
||||
|
||||
try:
|
||||
# 检查Redis
|
||||
if redis_client:
|
||||
await redis_client.ping()
|
||||
services["redis"] = "healthy"
|
||||
|
||||
# 获取统计信息
|
||||
stats["cache_size"] = await redis_client.dbsize()
|
||||
stats["total_apis"] = await redis_client.scard("rapidapi:endpoints") or 0
|
||||
stats["processed_apis"] = await redis_client.scard("processed:apis") or 0
|
||||
stats["generated_tools"] = await redis_client.scard("tools:registry") or 0
|
||||
except Exception:
|
||||
services["redis"] = "unhealthy"
|
||||
|
||||
try:
|
||||
# 检查NATS
|
||||
if nats_client and nats_client.is_connected:
|
||||
services["nats"] = "healthy"
|
||||
except Exception:
|
||||
services["nats"] = "unhealthy"
|
||||
|
||||
try:
|
||||
# 检查RapidAPI
|
||||
if rapidapi_client:
|
||||
await rapidapi_client.test_connection()
|
||||
services["rapidapi"] = "healthy"
|
||||
except Exception:
|
||||
services["rapidapi"] = "unhealthy"
|
||||
|
||||
try:
|
||||
# 检查APILLAMA
|
||||
if apillama_processor and apillama_processor.is_ready():
|
||||
services["apillama"] = "healthy"
|
||||
except Exception:
|
||||
services["apillama"] = "unhealthy"
|
||||
|
||||
return HealthResponse(
|
||||
status="healthy" if all(s == "healthy" for s in services.values()) else "degraded",
|
||||
timestamp=datetime.utcnow().isoformat(),
|
||||
services=services,
|
||||
stats=stats
|
||||
)
|
||||
|
||||
@app.post("/rapidapi/sync")
|
||||
async def sync_rapidapi_endpoints(
|
||||
background_tasks: BackgroundTasks,
|
||||
category: Optional[str] = None,
|
||||
limit: int = 100
|
||||
):
|
||||
"""同步RapidAPI端点"""
|
||||
try:
|
||||
if not rapidapi_client:
|
||||
raise HTTPException(status_code=500, detail="RapidAPI客户端未初始化")
|
||||
|
||||
# 启动后台同步任务
|
||||
background_tasks.add_task(
|
||||
rapidapi_client.sync_endpoints,
|
||||
category=category,
|
||||
limit=limit
|
||||
)
|
||||
|
||||
return {
|
||||
"message": "RapidAPI端点同步已启动",
|
||||
"category": category,
|
||||
"limit": limit
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"同步RapidAPI端点失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.post("/rapidapi/test")
|
||||
async def test_rapidapi_endpoint(request: RapidAPIRequest):
|
||||
"""测试RapidAPI端点"""
|
||||
try:
|
||||
if not rapidapi_client:
|
||||
raise HTTPException(status_code=500, detail="RapidAPI客户端未初始化")
|
||||
|
||||
result = await rapidapi_client.test_endpoint(
|
||||
endpoint=request.endpoint,
|
||||
method=request.method,
|
||||
params=request.params,
|
||||
headers=request.headers
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"测试RapidAPI端点失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.post("/openapi/parse", response_model=APIParsedResponse)
|
||||
async def parse_openapi_spec(
|
||||
url: str,
|
||||
background_tasks: BackgroundTasks
|
||||
):
|
||||
"""解析OpenAPI规范文档"""
|
||||
try:
|
||||
if not openapi_parser:
|
||||
raise HTTPException(status_code=500, detail="OpenAPI解析器未初始化")
|
||||
|
||||
# 解析OpenAPI文档
|
||||
parsed_result = await openapi_parser.parse_spec(url)
|
||||
|
||||
# 启动后台工具生成任务
|
||||
background_tasks.add_task(
|
||||
generate_tools_from_spec,
|
||||
parsed_result
|
||||
)
|
||||
|
||||
return APIParsedResponse(
|
||||
url=url,
|
||||
title=parsed_result.get("info", {}).get("title", ""),
|
||||
version=parsed_result.get("info", {}).get("version", ""),
|
||||
endpoints_count=len(parsed_result.get("paths", {})),
|
||||
schemas_count=len(parsed_result.get("components", {}).get("schemas", {})),
|
||||
parsed_data=parsed_result
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"解析OpenAPI规范失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.post("/apillama/process", response_model=APILLAMAResponse)
|
||||
async def process_api_with_apillama(request: APILLAMARequest):
|
||||
"""使用APILLAMA处理API文档"""
|
||||
try:
|
||||
if not apillama_processor:
|
||||
raise HTTPException(status_code=500, detail="APILLAMA处理器未初始化")
|
||||
|
||||
result = await apillama_processor.process_api_doc(
|
||||
api_doc=request.api_doc,
|
||||
context=request.context,
|
||||
output_format=request.output_format
|
||||
)
|
||||
|
||||
return APILLAMAResponse(
|
||||
processed=True,
|
||||
output_format=request.output_format,
|
||||
schema=result.get("schema"),
|
||||
description=result.get("description"),
|
||||
parameters=result.get("parameters", []),
|
||||
examples=result.get("examples", []),
|
||||
processing_time=result.get("processing_time", 0)
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"APILLAMA处理失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.post("/tools/generate")
|
||||
async def generate_tool_from_endpoint(
|
||||
endpoint: APIEndpoint,
|
||||
background_tasks: BackgroundTasks
|
||||
):
|
||||
"""从API端点生成工具定义"""
|
||||
try:
|
||||
if not tool_generator:
|
||||
raise HTTPException(status_code=500, detail="工具生成器未初始化")
|
||||
|
||||
# 启动后台工具生成任务
|
||||
background_tasks.add_task(
|
||||
tool_generator.generate_tool,
|
||||
endpoint
|
||||
)
|
||||
|
||||
return {
|
||||
"message": "工具生成任务已启动",
|
||||
"endpoint": endpoint.url,
|
||||
"method": endpoint.method
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"生成工具失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.get("/tools", response_model=List[ToolDefinition])
|
||||
async def list_generated_tools(
|
||||
category: Optional[str] = None,
|
||||
limit: int = 100,
|
||||
offset: int = 0
|
||||
):
|
||||
"""获取生成的工具列表"""
|
||||
try:
|
||||
if not redis_client:
|
||||
raise HTTPException(status_code=500, detail="Redis客户端未初始化")
|
||||
|
||||
tools = []
|
||||
tool_keys = await redis_client.smembers("tools:registry")
|
||||
|
||||
for tool_key in list(tool_keys)[offset:offset+limit]:
|
||||
tool_data = await redis_client.get(f"tool:{tool_key}")
|
||||
if tool_data:
|
||||
tool = json.loads(tool_data)
|
||||
if not category or tool.get("category") == category:
|
||||
tools.append(ToolDefinition(**tool))
|
||||
|
||||
return tools
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取工具列表失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.get("/tools/{tool_name}", response_model=ToolDefinition)
|
||||
async def get_tool_definition(tool_name: str):
|
||||
"""获取特定工具定义"""
|
||||
try:
|
||||
if not redis_client:
|
||||
raise HTTPException(status_code=500, detail="Redis客户端未初始化")
|
||||
|
||||
tool_data = await redis_client.get(f"tool:{tool_name}")
|
||||
if not tool_data:
|
||||
raise HTTPException(status_code=404, detail="工具不存在")
|
||||
|
||||
tool = json.loads(tool_data)
|
||||
return ToolDefinition(**tool)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"获取工具定义失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.delete("/tools/{tool_name}")
|
||||
async def delete_tool(tool_name: str):
|
||||
"""删除工具定义"""
|
||||
try:
|
||||
if not redis_client:
|
||||
raise HTTPException(status_code=500, detail="Redis客户端未初始化")
|
||||
|
||||
# 删除工具数据
|
||||
deleted = await redis_client.delete(f"tool:{tool_name}")
|
||||
if not deleted:
|
||||
raise HTTPException(status_code=404, detail="工具不存在")
|
||||
|
||||
# 从注册表中移除
|
||||
await redis_client.srem("tools:registry", tool_name)
|
||||
|
||||
return {"message": f"工具 {tool_name} 已删除"}
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"删除工具失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.get("/stats")
|
||||
async def get_statistics():
|
||||
"""获取统计信息"""
|
||||
try:
|
||||
if not redis_client:
|
||||
raise HTTPException(status_code=500, detail="Redis客户端未初始化")
|
||||
|
||||
stats = {
|
||||
"total_apis": await redis_client.scard("rapidapi:endpoints") or 0,
|
||||
"processed_apis": await redis_client.scard("processed:apis") or 0,
|
||||
"generated_tools": await redis_client.scard("tools:registry") or 0,
|
||||
"failed_processes": await redis_client.scard("failed:processes") or 0,
|
||||
"cache_size": await redis_client.dbsize(),
|
||||
"last_sync": await redis_client.get("last_sync_time") or "从未同步"
|
||||
}
|
||||
|
||||
# 获取分类统计
|
||||
categories = {}
|
||||
tool_keys = await redis_client.smembers("tools:registry")
|
||||
for tool_key in tool_keys:
|
||||
tool_data = await redis_client.get(f"tool:{tool_key}")
|
||||
if tool_data:
|
||||
tool = json.loads(tool_data)
|
||||
category = tool.get("category", "unknown")
|
||||
categories[category] = categories.get(category, 0) + 1
|
||||
|
||||
stats["categories"] = categories
|
||||
|
||||
return stats
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取统计信息失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.post("/cache/clear")
|
||||
async def clear_cache():
|
||||
"""清理缓存"""
|
||||
try:
|
||||
if not redis_client:
|
||||
raise HTTPException(status_code=500, detail="Redis客户端未初始化")
|
||||
|
||||
# 清理处理缓存
|
||||
await redis_client.delete("processed:apis")
|
||||
await redis_client.delete("failed:processes")
|
||||
|
||||
# 清理工具缓存(保留工具注册表)
|
||||
tool_keys = await redis_client.smembers("tools:registry")
|
||||
if tool_keys:
|
||||
cache_keys = [f"tool_cache:{key}" for key in tool_keys]
|
||||
await redis_client.delete(*cache_keys)
|
||||
|
||||
return {"message": "缓存已清理"}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"清理缓存失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
async def generate_tools_from_spec(parsed_spec: Dict[str, Any]):
|
||||
"""从解析的OpenAPI规范生成工具"""
|
||||
try:
|
||||
if not tool_generator:
|
||||
logger.error("工具生成器未初始化")
|
||||
return
|
||||
|
||||
paths = parsed_spec.get("paths", {})
|
||||
|
||||
for path, methods in paths.items():
|
||||
for method, spec in methods.items():
|
||||
if method.upper() in ["GET", "POST", "PUT", "DELETE", "PATCH"]:
|
||||
endpoint = APIEndpoint(
|
||||
url=f"{parsed_spec.get('servers', [{}])[0].get('url', '')}{path}",
|
||||
method=method.upper(),
|
||||
name=spec.get("operationId", f"{method}_{path}".replace("/", "_")),
|
||||
description=spec.get("summary", spec.get("description", "")),
|
||||
parameters=spec.get("parameters", []),
|
||||
request_body=spec.get("requestBody"),
|
||||
responses=spec.get("responses", {})
|
||||
)
|
||||
|
||||
await tool_generator.generate_tool(endpoint)
|
||||
|
||||
logger.info(f"从OpenAPI规范生成了 {len(paths)} 个工具")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"从规范生成工具失败: {e}")
|
||||
|
||||
async def background_api_sync():
|
||||
"""后台API同步任务"""
|
||||
while True:
|
||||
try:
|
||||
await asyncio.sleep(3600) # 每小时同步一次
|
||||
|
||||
if rapidapi_client:
|
||||
await rapidapi_client.sync_popular_apis()
|
||||
logger.info("后台API同步完成")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"后台API同步失败: {e}")
|
||||
|
||||
@app.get("/metrics")
|
||||
async def get_metrics():
|
||||
"""Prometheus metrics端点"""
|
||||
# TODO: 实现Prometheus metrics
|
||||
return JSONResponse({"message": "Metrics endpoint - TODO: implement"})
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run(
|
||||
"main:app",
|
||||
host="0.0.0.0",
|
||||
port=8000,
|
||||
reload=True,
|
||||
log_level="info"
|
||||
)
|
||||
@@ -0,0 +1,83 @@
|
||||
# Web框架
|
||||
fastapi==0.104.1
|
||||
uvicorn[standard]==0.24.0
|
||||
pydantic==2.5.0
|
||||
pydantic-settings==2.1.0
|
||||
|
||||
# 数据库
|
||||
sqlalchemy==2.0.23
|
||||
asyncpg==0.29.0
|
||||
|
||||
# Redis和缓存
|
||||
redis==5.0.1
|
||||
aioredis==2.0.1
|
||||
|
||||
# NATS消息队列
|
||||
nats-py==2.6.0
|
||||
|
||||
# HTTP客户端
|
||||
httpx==0.25.2
|
||||
aiohttp==3.9.1
|
||||
requests==2.31.0
|
||||
|
||||
# RapidAPI集成
|
||||
rapidapi-python==1.2.0
|
||||
|
||||
# APILLAMA相关依赖
|
||||
transformers==4.36.0
|
||||
torch==2.1.0
|
||||
tokenizers==0.15.0
|
||||
accelerate==0.24.0
|
||||
|
||||
# OpenAPI处理
|
||||
openapi-spec-validator==0.7.1
|
||||
openapi-parser==1.1.0
|
||||
pydantic-openapi==1.4.0
|
||||
apispec==6.3.0
|
||||
|
||||
# JSON处理和验证
|
||||
jsonschema==4.20.0
|
||||
json-repair==0.7.0
|
||||
|
||||
# 文本处理
|
||||
nltk==3.8.1
|
||||
spacy==3.7.0
|
||||
beautifulsoup4==4.12.2
|
||||
|
||||
# 机器学习工具
|
||||
scikit-learn==1.3.2
|
||||
numpy==1.24.3
|
||||
pandas==2.1.4
|
||||
|
||||
# 异步处理
|
||||
asyncio-throttle==1.0.2
|
||||
aiofiles==23.2.1
|
||||
|
||||
# 配置管理
|
||||
python-dotenv==1.0.0
|
||||
pyyaml==6.0.1
|
||||
|
||||
# 监控和日志
|
||||
prometheus-client==0.19.0
|
||||
structlog==23.2.0
|
||||
rich==13.7.0
|
||||
|
||||
# 缓存和存储
|
||||
diskcache==5.6.3
|
||||
joblib==1.3.2
|
||||
|
||||
# 工具和实用程序
|
||||
python-multipart==0.0.6
|
||||
email-validator==2.1.0
|
||||
validators==0.22.0
|
||||
|
||||
# 开发和测试工具
|
||||
pytest==7.4.3
|
||||
pytest-asyncio==0.21.1
|
||||
black==23.11.0
|
||||
flake8==6.1.0
|
||||
mypy==1.7.1
|
||||
|
||||
# API文档生成
|
||||
swagger-ui-bundle==0.0.9
|
||||
redoc==2.0.0
|
||||
@@ -0,0 +1,316 @@
|
||||
"""
|
||||
数据接入服务的Pydantic schemas
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional, Union
|
||||
from pydantic import BaseModel, Field, validator
|
||||
import uuid
|
||||
|
||||
|
||||
class BaseSchema(BaseModel):
|
||||
"""基础schema类"""
|
||||
class Config:
|
||||
from_attributes = True
|
||||
json_encoders = {
|
||||
datetime: lambda v: v.isoformat(),
|
||||
uuid.UUID: lambda v: str(v),
|
||||
}
|
||||
|
||||
|
||||
# ========== API端点相关 ==========
|
||||
|
||||
class APIEndpoint(BaseSchema):
|
||||
"""API端点定义"""
|
||||
url: str = Field(..., description="API端点URL")
|
||||
method: str = Field(..., description="HTTP方法")
|
||||
name: Optional[str] = Field(None, description="端点名称")
|
||||
description: Optional[str] = Field(None, description="端点描述")
|
||||
|
||||
# OpenAPI相关字段
|
||||
parameters: List[Dict[str, Any]] = Field(default=[], description="参数定义")
|
||||
request_body: Optional[Dict[str, Any]] = Field(None, description="请求体定义")
|
||||
responses: Dict[str, Any] = Field(default={}, description="响应定义")
|
||||
|
||||
# 认证和安全
|
||||
security: List[Dict[str, Any]] = Field(default=[], description="安全要求")
|
||||
|
||||
# 元数据
|
||||
tags: List[str] = Field(default=[], description="标签")
|
||||
deprecated: bool = Field(False, description="是否已弃用")
|
||||
|
||||
@validator('method')
|
||||
def validate_method(cls, v):
|
||||
"""验证HTTP方法"""
|
||||
allowed_methods = ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]
|
||||
if v.upper() not in allowed_methods:
|
||||
raise ValueError(f'不支持的HTTP方法: {v}')
|
||||
return v.upper()
|
||||
|
||||
|
||||
class APIParameter(BaseSchema):
|
||||
"""API参数定义"""
|
||||
name: str = Field(..., description="参数名称")
|
||||
type: str = Field(..., description="参数类型")
|
||||
location: str = Field(..., description="参数位置 (query, path, header, body)")
|
||||
description: Optional[str] = Field(None, description="参数描述")
|
||||
required: bool = Field(False, description="是否必需")
|
||||
default: Optional[Any] = Field(None, description="默认值")
|
||||
example: Optional[Any] = Field(None, description="示例值")
|
||||
enum: Optional[List[Any]] = Field(None, description="枚举值")
|
||||
format: Optional[str] = Field(None, description="格式")
|
||||
pattern: Optional[str] = Field(None, description="正则模式")
|
||||
minimum: Optional[float] = Field(None, description="最小值")
|
||||
maximum: Optional[float] = Field(None, description="最大值")
|
||||
|
||||
|
||||
# ========== RapidAPI相关 ==========
|
||||
|
||||
class RapidAPIRequest(BaseSchema):
|
||||
"""RapidAPI请求"""
|
||||
endpoint: str = Field(..., description="API端点")
|
||||
method: str = Field(..., description="HTTP方法")
|
||||
params: Optional[Dict[str, Any]] = Field(None, description="请求参数")
|
||||
headers: Optional[Dict[str, str]] = Field(None, description="请求头")
|
||||
timeout: Optional[int] = Field(30, description="超时时间(秒)")
|
||||
|
||||
|
||||
class RapidAPIResponse(BaseSchema):
|
||||
"""RapidAPI响应"""
|
||||
success: bool = Field(..., description="是否成功")
|
||||
status_code: int = Field(..., description="HTTP状态码")
|
||||
data: Optional[Any] = Field(None, description="响应数据")
|
||||
error: Optional[str] = Field(None, description="错误信息")
|
||||
response_time: float = Field(..., description="响应时间(毫秒)")
|
||||
headers: Dict[str, str] = Field(default={}, description="响应头")
|
||||
|
||||
|
||||
class RapidAPIEndpointInfo(BaseSchema):
|
||||
"""RapidAPI端点信息"""
|
||||
id: str = Field(..., description="端点ID")
|
||||
name: str = Field(..., description="端点名称")
|
||||
url: str = Field(..., description="端点URL")
|
||||
method: str = Field(..., description="HTTP方法")
|
||||
description: Optional[str] = Field(None, description="描述")
|
||||
category: Optional[str] = Field(None, description="分类")
|
||||
provider: Optional[str] = Field(None, description="提供商")
|
||||
pricing: Optional[Dict[str, Any]] = Field(None, description="定价信息")
|
||||
rate_limit: Optional[Dict[str, int]] = Field(None, description="速率限制")
|
||||
popularity_score: Optional[float] = Field(None, description="流行度分数")
|
||||
|
||||
|
||||
# ========== APILLAMA相关 ==========
|
||||
|
||||
class APILLAMARequest(BaseSchema):
|
||||
"""APILLAMA处理请求"""
|
||||
api_doc: str = Field(..., description="API文档内容")
|
||||
context: Optional[Dict[str, Any]] = Field(None, description="上下文信息")
|
||||
output_format: str = Field("pydantic", description="输出格式 (pydantic, json_schema, openapi)")
|
||||
|
||||
# 处理选项
|
||||
include_examples: bool = Field(True, description="是否包含示例")
|
||||
enhance_descriptions: bool = Field(True, description="是否增强描述")
|
||||
validate_schema: bool = Field(True, description="是否验证schema")
|
||||
|
||||
@validator('output_format')
|
||||
def validate_output_format(cls, v):
|
||||
"""验证输出格式"""
|
||||
allowed_formats = ["pydantic", "json_schema", "openapi"]
|
||||
if v not in allowed_formats:
|
||||
raise ValueError(f'不支持的输出格式: {v}')
|
||||
return v
|
||||
|
||||
|
||||
class APILLAMAResponse(BaseSchema):
|
||||
"""APILLAMA处理响应"""
|
||||
processed: bool = Field(..., description="是否处理成功")
|
||||
output_format: str = Field(..., description="输出格式")
|
||||
schema: Optional[Dict[str, Any]] = Field(None, description="生成的schema")
|
||||
description: Optional[str] = Field(None, description="增强的描述")
|
||||
parameters: List[APIParameter] = Field(default=[], description="参数定义")
|
||||
examples: List[Dict[str, Any]] = Field(default=[], description="示例数据")
|
||||
processing_time: float = Field(..., description="处理时间(秒)")
|
||||
error: Optional[str] = Field(None, description="错误信息")
|
||||
|
||||
# 质量评估
|
||||
confidence_score: Optional[float] = Field(None, description="置信度分数")
|
||||
completeness_score: Optional[float] = Field(None, description="完整性分数")
|
||||
|
||||
|
||||
# ========== OpenAPI解析相关 ==========
|
||||
|
||||
class OpenAPISpec(BaseSchema):
|
||||
"""OpenAPI规范"""
|
||||
openapi: Optional[str] = Field(None, description="OpenAPI版本")
|
||||
swagger: Optional[str] = Field(None, description="Swagger版本")
|
||||
info: Dict[str, Any] = Field(..., description="API信息")
|
||||
servers: List[Dict[str, Any]] = Field(default=[], description="服务器列表")
|
||||
paths: Dict[str, Any] = Field(default={}, description="路径定义")
|
||||
components: Optional[Dict[str, Any]] = Field(None, description="组件定义")
|
||||
security: Optional[List[Dict[str, Any]]] = Field(None, description="安全定义")
|
||||
tags: List[Dict[str, Any]] = Field(default=[], description="标签定义")
|
||||
|
||||
|
||||
class APIParsedResponse(BaseSchema):
|
||||
"""API解析响应"""
|
||||
url: str = Field(..., description="原始URL")
|
||||
title: str = Field(..., description="API标题")
|
||||
version: str = Field(..., description="API版本")
|
||||
endpoints_count: int = Field(..., description="端点数量")
|
||||
schemas_count: int = Field(..., description="模式数量")
|
||||
parsed_data: OpenAPISpec = Field(..., description="解析后的数据")
|
||||
parsing_time: Optional[float] = Field(None, description="解析时间(秒)")
|
||||
errors: List[str] = Field(default=[], description="解析错误")
|
||||
warnings: List[str] = Field(default=[], description="解析警告")
|
||||
|
||||
|
||||
# ========== 工具生成相关 ==========
|
||||
|
||||
class ToolDefinition(BaseSchema):
|
||||
"""工具定义"""
|
||||
name: str = Field(..., description="工具名称")
|
||||
description: str = Field(..., description="工具描述")
|
||||
category: str = Field(..., description="工具分类")
|
||||
version: str = Field("1.0.0", description="工具版本")
|
||||
|
||||
# 功能定义
|
||||
schema: Dict[str, Any] = Field(..., description="工具schema")
|
||||
parameters: List[APIParameter] = Field(default=[], description="参数定义")
|
||||
returns: Optional[Dict[str, Any]] = Field(None, description="返回值定义")
|
||||
|
||||
# API相关
|
||||
endpoint: Optional[str] = Field(None, description="API端点")
|
||||
method: str = Field("POST", description="HTTP方法")
|
||||
headers: Dict[str, str] = Field(default={}, description="请求头")
|
||||
auth_type: Optional[str] = Field(None, description="认证类型")
|
||||
|
||||
# 限制和配置
|
||||
rate_limit: int = Field(100, description="速率限制(每分钟)")
|
||||
timeout: int = Field(30, description="超时时间(秒)")
|
||||
cost_per_call: float = Field(0.0, description="每次调用成本")
|
||||
max_retries: int = Field(3, description="最大重试次数")
|
||||
|
||||
# 状态和质量
|
||||
status: str = Field("active", description="工具状态")
|
||||
quality_score: Optional[float] = Field(None, description="质量分数")
|
||||
usage_count: int = Field(0, description="使用次数")
|
||||
success_rate: float = Field(0.0, description="成功率")
|
||||
|
||||
# 元数据
|
||||
tags: List[str] = Field(default=[], description="标签")
|
||||
author: Optional[str] = Field(None, description="作者")
|
||||
license: Optional[str] = Field(None, description="许可证")
|
||||
documentation_url: Optional[str] = Field(None, description="文档URL")
|
||||
|
||||
# 时间戳
|
||||
created_at: datetime = Field(default_factory=datetime.utcnow, description="创建时间")
|
||||
updated_at: datetime = Field(default_factory=datetime.utcnow, description="更新时间")
|
||||
|
||||
|
||||
class ToolGenerationRequest(BaseSchema):
|
||||
"""工具生成请求"""
|
||||
endpoint: APIEndpoint = Field(..., description="API端点")
|
||||
tool_name: Optional[str] = Field(None, description="自定义工具名称")
|
||||
category: Optional[str] = Field(None, description="自定义分类")
|
||||
|
||||
# 生成选项
|
||||
include_examples: bool = Field(True, description="是否包含示例")
|
||||
optimize_for_llm: bool = Field(True, description="是否为LLM优化")
|
||||
add_validation: bool = Field(True, description="是否添加验证")
|
||||
generate_tests: bool = Field(False, description="是否生成测试")
|
||||
|
||||
|
||||
class ToolGenerationResponse(BaseSchema):
|
||||
"""工具生成响应"""
|
||||
success: bool = Field(..., description="是否成功")
|
||||
tool_name: str = Field(..., description="生成的工具名称")
|
||||
tool_definition: Optional[ToolDefinition] = Field(None, description="工具定义")
|
||||
generation_time: float = Field(..., description="生成时间(秒)")
|
||||
error: Optional[str] = Field(None, description="错误信息")
|
||||
warnings: List[str] = Field(default=[], description="警告信息")
|
||||
|
||||
|
||||
# ========== 批处理相关 ==========
|
||||
|
||||
class BatchProcessRequest(BaseSchema):
|
||||
"""批处理请求"""
|
||||
items: List[Union[str, APIEndpoint]] = Field(..., description="处理项目列表")
|
||||
process_type: str = Field(..., description="处理类型")
|
||||
options: Dict[str, Any] = Field(default={}, description="处理选项")
|
||||
|
||||
@validator('process_type')
|
||||
def validate_process_type(cls, v):
|
||||
"""验证处理类型"""
|
||||
allowed_types = ["parse_openapi", "generate_tools", "test_endpoints"]
|
||||
if v not in allowed_types:
|
||||
raise ValueError(f'不支持的处理类型: {v}')
|
||||
return v
|
||||
|
||||
|
||||
class BatchProcessResponse(BaseSchema):
|
||||
"""批处理响应"""
|
||||
total_items: int = Field(..., description="总项目数")
|
||||
processed_items: int = Field(..., description="已处理项目数")
|
||||
successful_items: int = Field(..., description="成功项目数")
|
||||
failed_items: int = Field(..., description="失败项目数")
|
||||
|
||||
results: List[Dict[str, Any]] = Field(default=[], description="处理结果")
|
||||
errors: List[Dict[str, Any]] = Field(default=[], description="错误列表")
|
||||
|
||||
start_time: datetime = Field(..., description="开始时间")
|
||||
end_time: Optional[datetime] = Field(None, description="结束时间")
|
||||
total_time: Optional[float] = Field(None, description="总时间(秒)")
|
||||
|
||||
|
||||
# ========== 统计和监控相关 ==========
|
||||
|
||||
class ProcessingStats(BaseSchema):
|
||||
"""处理统计"""
|
||||
total_apis: int = Field(..., description="API总数")
|
||||
processed_apis: int = Field(..., description="已处理API数")
|
||||
generated_tools: int = Field(..., description="生成的工具数")
|
||||
failed_processes: int = Field(..., description="失败的处理数")
|
||||
|
||||
success_rate: float = Field(..., description="成功率")
|
||||
avg_processing_time: float = Field(..., description="平均处理时间")
|
||||
|
||||
categories: Dict[str, int] = Field(default={}, description="分类统计")
|
||||
daily_stats: List[Dict[str, Any]] = Field(default=[], description="每日统计")
|
||||
|
||||
|
||||
class SystemHealth(BaseSchema):
|
||||
"""系统健康状态"""
|
||||
status: str = Field(..., description="系统状态")
|
||||
timestamp: datetime = Field(..., description="检查时间")
|
||||
|
||||
services: Dict[str, str] = Field(..., description="服务状态")
|
||||
resources: Dict[str, Any] = Field(..., description="资源使用")
|
||||
performance: Dict[str, float] = Field(..., description="性能指标")
|
||||
|
||||
errors: List[str] = Field(default=[], description="错误列表")
|
||||
warnings: List[str] = Field(default=[], description="警告列表")
|
||||
|
||||
|
||||
# ========== 配置和设置相关 ==========
|
||||
|
||||
class ServiceConfig(BaseSchema):
|
||||
"""服务配置"""
|
||||
rapidapi_enabled: bool = Field(True, description="是否启用RapidAPI")
|
||||
apillama_enabled: bool = Field(True, description="是否启用APILLAMA")
|
||||
auto_sync: bool = Field(True, description="是否自动同步")
|
||||
|
||||
sync_interval: int = Field(3600, description="同步间隔(秒)")
|
||||
max_concurrent: int = Field(10, description="最大并发数")
|
||||
cache_enabled: bool = Field(True, description="是否启用缓存")
|
||||
|
||||
quality_threshold: float = Field(0.7, description="质量阈值")
|
||||
auto_cleanup: bool = Field(True, description="是否自动清理")
|
||||
|
||||
|
||||
class APIResponse(BaseSchema):
|
||||
"""标准API响应"""
|
||||
success: bool = Field(..., description="是否成功")
|
||||
message: str = Field("", description="响应消息")
|
||||
data: Optional[Any] = Field(None, description="响应数据")
|
||||
timestamp: datetime = Field(default_factory=datetime.utcnow, description="时间戳")
|
||||
request_id: Optional[str] = Field(None, description="请求ID")
|
||||
@@ -0,0 +1,38 @@
|
||||
FROM python:3.11-slim
|
||||
|
||||
# 设置工作目录
|
||||
WORKDIR /app
|
||||
|
||||
# 安装系统依赖
|
||||
RUN apt-get update && apt-get install -y \
|
||||
gcc \
|
||||
g++ \
|
||||
make \
|
||||
curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# 复制requirements文件
|
||||
COPY requirements.txt .
|
||||
|
||||
# 安装Python依赖
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# 复制源代码
|
||||
COPY . .
|
||||
|
||||
# 创建logs目录
|
||||
RUN mkdir -p logs
|
||||
|
||||
# 设置环境变量
|
||||
ENV PYTHONPATH=/app
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 8000
|
||||
|
||||
# 健康检查
|
||||
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
|
||||
CMD curl -f http://localhost:8000/health || exit 1
|
||||
|
||||
# 启动应用
|
||||
CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
|
||||
@@ -0,0 +1,121 @@
|
||||
"""
|
||||
配置管理
|
||||
"""
|
||||
|
||||
import os
|
||||
from typing import Optional
|
||||
from pydantic_settings import BaseSettings
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
"""应用配置"""
|
||||
|
||||
# 应用设置
|
||||
app_name: str = "taiji-AI-PAD MCP Server"
|
||||
debug: bool = False
|
||||
secret_key: str = "your-secret-key-change-in-production"
|
||||
|
||||
# 数据库设置
|
||||
database_url: str = os.getenv(
|
||||
"DATABASE_URL",
|
||||
"postgresql+asyncpg://taiji_user:taiji_pass@postgres:5432/taiji_db"
|
||||
)
|
||||
|
||||
# Redis设置
|
||||
redis_url: str = os.getenv("REDIS_URL", "redis://redis:6379")
|
||||
redis_max_connections: int = 20
|
||||
redis_retry_on_timeout: bool = True
|
||||
|
||||
# NATS设置
|
||||
nats_url: str = os.getenv("NATS_URL", "nats://nats:4222")
|
||||
nats_max_reconnect_attempts: int = 10
|
||||
|
||||
# LiteLLM网关设置
|
||||
litellm_url: str = os.getenv("LITELLM_URL", "http://litellm-gateway:4000")
|
||||
litellm_api_key: str = os.getenv("LITELLM_API_KEY", "sk-taiji-master-key")
|
||||
|
||||
# MCP协议设置
|
||||
mcp_timeout: int = 30 # 秒
|
||||
mcp_max_retries: int = 3
|
||||
mcp_retry_delay: float = 1.0 # 秒
|
||||
|
||||
# Agent设置
|
||||
max_agents_per_user: int = 100
|
||||
agent_execution_timeout: int = 300 # 秒
|
||||
agent_memory_limit: str = "512MB"
|
||||
agent_cpu_limit: float = 1.0 # CPU核数
|
||||
|
||||
# 工具设置
|
||||
max_tools_per_agent: int = 50
|
||||
tool_execution_timeout: int = 60 # 秒
|
||||
allowed_tool_domains: list = [
|
||||
"rapidapi.com",
|
||||
"api.openai.com",
|
||||
"api.anthropic.com"
|
||||
]
|
||||
|
||||
# 缓存设置
|
||||
cache_ttl: int = 3600 # 秒
|
||||
cache_max_size: int = 1000
|
||||
|
||||
# 日志设置
|
||||
log_level: str = "INFO"
|
||||
log_format: str = "json"
|
||||
log_file: Optional[str] = "/app/logs/mcp-server.log"
|
||||
|
||||
# 安全设置
|
||||
cors_origins: list = ["*"]
|
||||
jwt_algorithm: str = "HS256"
|
||||
jwt_expire_minutes: int = 60
|
||||
|
||||
# 监控设置
|
||||
enable_metrics: bool = True
|
||||
metrics_port: int = 8001
|
||||
health_check_interval: int = 30 # 秒
|
||||
|
||||
# 开发设置
|
||||
reload: bool = False
|
||||
workers: int = 1
|
||||
|
||||
class Config:
|
||||
env_file = ".env"
|
||||
env_file_encoding = "utf-8"
|
||||
case_sensitive = False
|
||||
|
||||
|
||||
class DevelopmentSettings(Settings):
|
||||
"""开发环境配置"""
|
||||
debug: bool = True
|
||||
reload: bool = True
|
||||
log_level: str = "DEBUG"
|
||||
|
||||
|
||||
class ProductionSettings(Settings):
|
||||
"""生产环境配置"""
|
||||
debug: bool = False
|
||||
reload: bool = False
|
||||
workers: int = 4
|
||||
log_level: str = "INFO"
|
||||
|
||||
|
||||
class TestingSettings(Settings):
|
||||
"""测试环境配置"""
|
||||
debug: bool = True
|
||||
database_url: str = "sqlite+aiosqlite:///./test.db"
|
||||
redis_url: str = "redis://localhost:6379/1" # 使用不同的数据库
|
||||
|
||||
|
||||
def get_settings() -> Settings:
|
||||
"""根据环境变量获取相应的配置"""
|
||||
environment = os.getenv("ENVIRONMENT", "development").lower()
|
||||
|
||||
if environment == "production":
|
||||
return ProductionSettings()
|
||||
elif environment == "testing":
|
||||
return TestingSettings()
|
||||
else:
|
||||
return DevelopmentSettings()
|
||||
|
||||
|
||||
# 全局配置实例
|
||||
settings = get_settings()
|
||||
@@ -0,0 +1,404 @@
|
||||
"""
|
||||
数据库配置和连接管理
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from typing import AsyncGenerator
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from sqlalchemy import text
|
||||
import logging
|
||||
|
||||
from .config import settings
|
||||
from .models import Base
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 创建异步数据库引擎
|
||||
engine = create_async_engine(
|
||||
settings.database_url,
|
||||
echo=settings.debug, # 在调试模式下显示SQL语句
|
||||
pool_size=20,
|
||||
max_overflow=0,
|
||||
pool_pre_ping=True, # 连接池预检查
|
||||
pool_recycle=3600, # 1小时后回收连接
|
||||
)
|
||||
|
||||
# 创建异步会话工厂
|
||||
AsyncSessionLocal = async_sessionmaker(
|
||||
engine,
|
||||
class_=AsyncSession,
|
||||
expire_on_commit=False
|
||||
)
|
||||
|
||||
|
||||
async def get_db() -> AsyncGenerator[AsyncSession, None]:
|
||||
"""获取数据库会话的依赖注入函数"""
|
||||
async with AsyncSessionLocal() as session:
|
||||
try:
|
||||
yield session
|
||||
except Exception as e:
|
||||
logger.error(f"数据库会话错误: {e}")
|
||||
await session.rollback()
|
||||
raise
|
||||
finally:
|
||||
await session.close()
|
||||
|
||||
|
||||
async def init_db():
|
||||
"""初始化数据库"""
|
||||
try:
|
||||
# 创建所有表
|
||||
async with engine.begin() as conn:
|
||||
await conn.run_sync(Base.metadata.create_all)
|
||||
|
||||
logger.info("数据库初始化成功")
|
||||
|
||||
# 创建初始数据
|
||||
await create_initial_data()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"数据库初始化失败: {e}")
|
||||
raise
|
||||
|
||||
|
||||
async def create_initial_data():
|
||||
"""创建初始数据"""
|
||||
try:
|
||||
async with AsyncSessionLocal() as session:
|
||||
# 检查是否已有数据
|
||||
result = await session.execute(text("SELECT COUNT(*) FROM users"))
|
||||
user_count = result.scalar()
|
||||
|
||||
if user_count == 0:
|
||||
# 创建默认管理员用户
|
||||
from .models import User
|
||||
from passlib.context import CryptContext
|
||||
|
||||
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||||
|
||||
admin_user = User(
|
||||
username="admin",
|
||||
email="admin@taiji-ai.com",
|
||||
hashed_password=pwd_context.hash("admin123"),
|
||||
full_name="系统管理员",
|
||||
is_active=True,
|
||||
is_admin=True
|
||||
)
|
||||
|
||||
session.add(admin_user)
|
||||
await session.commit()
|
||||
|
||||
logger.info("默认管理员用户创建成功")
|
||||
|
||||
# 创建示例工具
|
||||
await create_sample_tools(session)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"创建初始数据失败: {e}")
|
||||
raise
|
||||
|
||||
|
||||
async def create_sample_tools(session: AsyncSession):
|
||||
"""创建示例工具"""
|
||||
try:
|
||||
from .models import Tool
|
||||
|
||||
# 检查是否已有工具
|
||||
result = await session.execute(text("SELECT COUNT(*) FROM tools"))
|
||||
tool_count = result.scalar()
|
||||
|
||||
if tool_count == 0:
|
||||
# 创建示例工具
|
||||
sample_tools = [
|
||||
{
|
||||
"name": "web_search",
|
||||
"description": "网络搜索工具",
|
||||
"category": "api",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"query": {
|
||||
"type": "string",
|
||||
"description": "搜索查询"
|
||||
},
|
||||
"limit": {
|
||||
"type": "integer",
|
||||
"description": "结果数量限制",
|
||||
"default": 10
|
||||
}
|
||||
},
|
||||
"required": ["query"]
|
||||
},
|
||||
"endpoint": "https://api.example.com/search",
|
||||
"method": "POST",
|
||||
"auth_type": "api_key",
|
||||
"rate_limit": 100,
|
||||
"cost_per_call": 0.01,
|
||||
"is_public": True
|
||||
},
|
||||
{
|
||||
"name": "text_completion",
|
||||
"description": "文本补全工具",
|
||||
"category": "llm",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"prompt": {
|
||||
"type": "string",
|
||||
"description": "输入提示"
|
||||
},
|
||||
"max_tokens": {
|
||||
"type": "integer",
|
||||
"description": "最大token数",
|
||||
"default": 150
|
||||
},
|
||||
"temperature": {
|
||||
"type": "number",
|
||||
"description": "温度参数",
|
||||
"default": 0.7
|
||||
}
|
||||
},
|
||||
"required": ["prompt"]
|
||||
},
|
||||
"rate_limit": 60,
|
||||
"cost_per_call": 0.05,
|
||||
"is_public": True
|
||||
},
|
||||
{
|
||||
"name": "weather_api",
|
||||
"description": "天气查询API",
|
||||
"category": "api",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"city": {
|
||||
"type": "string",
|
||||
"description": "城市名称"
|
||||
},
|
||||
"unit": {
|
||||
"type": "string",
|
||||
"enum": ["celsius", "fahrenheit"],
|
||||
"default": "celsius"
|
||||
}
|
||||
},
|
||||
"required": ["city"]
|
||||
},
|
||||
"endpoint": "https://api.openweathermap.org/data/2.5/weather",
|
||||
"method": "GET",
|
||||
"auth_type": "api_key",
|
||||
"rate_limit": 1000,
|
||||
"cost_per_call": 0.001,
|
||||
"is_public": True
|
||||
}
|
||||
]
|
||||
|
||||
for tool_data in sample_tools:
|
||||
tool = Tool(**tool_data)
|
||||
session.add(tool)
|
||||
|
||||
await session.commit()
|
||||
logger.info(f"创建了 {len(sample_tools)} 个示例工具")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"创建示例工具失败: {e}")
|
||||
raise
|
||||
|
||||
|
||||
async def check_db_connection():
|
||||
"""检查数据库连接"""
|
||||
try:
|
||||
async with AsyncSessionLocal() as session:
|
||||
await session.execute(text("SELECT 1"))
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"数据库连接检查失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
async def get_db_stats():
|
||||
"""获取数据库统计信息"""
|
||||
try:
|
||||
async with AsyncSessionLocal() as session:
|
||||
stats = {}
|
||||
|
||||
# 获取各表的记录数
|
||||
tables = ["users", "agents", "tools", "sessions", "executions", "billing"]
|
||||
|
||||
for table in tables:
|
||||
result = await session.execute(text(f"SELECT COUNT(*) FROM {table}"))
|
||||
stats[table] = result.scalar()
|
||||
|
||||
return stats
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取数据库统计失败: {e}")
|
||||
return {}
|
||||
|
||||
|
||||
async def cleanup_old_records():
|
||||
"""清理旧记录"""
|
||||
try:
|
||||
async with AsyncSessionLocal() as session:
|
||||
# 清理超过30天的执行记录
|
||||
result = await session.execute(text("""
|
||||
DELETE FROM executions
|
||||
WHERE created_at < NOW() - INTERVAL '30 days'
|
||||
"""))
|
||||
|
||||
deleted_executions = result.rowcount
|
||||
|
||||
# 清理超过7天的会话记录
|
||||
result = await session.execute(text("""
|
||||
DELETE FROM sessions
|
||||
WHERE created_at < NOW() - INTERVAL '7 days'
|
||||
AND status != 'active'
|
||||
"""))
|
||||
|
||||
deleted_sessions = result.rowcount
|
||||
|
||||
await session.commit()
|
||||
|
||||
logger.info(f"清理完成: 删除了 {deleted_executions} 条执行记录, {deleted_sessions} 条会话记录")
|
||||
|
||||
return {
|
||||
"deleted_executions": deleted_executions,
|
||||
"deleted_sessions": deleted_sessions
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"清理旧记录失败: {e}")
|
||||
return {}
|
||||
|
||||
|
||||
async def backup_db():
|
||||
"""数据库备份"""
|
||||
try:
|
||||
import subprocess
|
||||
from datetime import datetime
|
||||
import os
|
||||
|
||||
# 生成备份文件名
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
backup_file = f"/app/backups/taiji_db_backup_{timestamp}.sql"
|
||||
|
||||
# 创建备份目录
|
||||
os.makedirs("/app/backups", exist_ok=True)
|
||||
|
||||
# 执行pg_dump命令
|
||||
cmd = [
|
||||
"pg_dump",
|
||||
settings.database_url.replace("postgresql+asyncpg://", "postgresql://"),
|
||||
"-f", backup_file
|
||||
]
|
||||
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
|
||||
if result.returncode == 0:
|
||||
logger.info(f"数据库备份成功: {backup_file}")
|
||||
return backup_file
|
||||
else:
|
||||
logger.error(f"数据库备份失败: {result.stderr}")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"数据库备份异常: {e}")
|
||||
return None
|
||||
|
||||
|
||||
async def close_db():
|
||||
"""关闭数据库连接"""
|
||||
try:
|
||||
await engine.dispose()
|
||||
logger.info("数据库连接已关闭")
|
||||
except Exception as e:
|
||||
logger.error(f"关闭数据库连接失败: {e}")
|
||||
|
||||
|
||||
# 数据库事件处理
|
||||
async def on_startup():
|
||||
"""应用启动时的数据库操作"""
|
||||
await init_db()
|
||||
|
||||
|
||||
async def on_shutdown():
|
||||
"""应用关闭时的数据库操作"""
|
||||
await close_db()
|
||||
|
||||
|
||||
# 定期清理任务
|
||||
async def periodic_cleanup():
|
||||
"""定期清理任务"""
|
||||
while True:
|
||||
try:
|
||||
await asyncio.sleep(3600) # 每小时执行一次
|
||||
await cleanup_old_records()
|
||||
except Exception as e:
|
||||
logger.error(f"定期清理任务异常: {e}")
|
||||
|
||||
|
||||
# 数据库迁移辅助函数
|
||||
async def migrate_db():
|
||||
"""数据库迁移(简化版本)"""
|
||||
try:
|
||||
# 这里可以添加数据迁移逻辑
|
||||
# 在生产环境中应该使用Alembic进行数据库版本管理
|
||||
logger.info("数据库迁移检查完成")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"数据库迁移失败: {e}")
|
||||
raise
|
||||
|
||||
|
||||
# 性能优化
|
||||
async def optimize_db():
|
||||
"""数据库性能优化"""
|
||||
try:
|
||||
async with AsyncSessionLocal() as session:
|
||||
# 更新表统计信息
|
||||
await session.execute(text("ANALYZE;"))
|
||||
|
||||
# 重建索引(如果需要)
|
||||
# await session.execute(text("REINDEX DATABASE taiji_db;"))
|
||||
|
||||
await session.commit()
|
||||
|
||||
logger.info("数据库优化完成")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"数据库优化失败: {e}")
|
||||
|
||||
|
||||
# 健康检查
|
||||
async def health_check() -> dict:
|
||||
"""数据库健康检查"""
|
||||
health_info = {
|
||||
"database": "unknown",
|
||||
"connection_pool": "unknown",
|
||||
"stats": {}
|
||||
}
|
||||
|
||||
try:
|
||||
# 检查连接
|
||||
if await check_db_connection():
|
||||
health_info["database"] = "healthy"
|
||||
else:
|
||||
health_info["database"] = "unhealthy"
|
||||
|
||||
# 检查连接池状态
|
||||
pool = engine.pool
|
||||
health_info["connection_pool"] = {
|
||||
"size": pool.size(),
|
||||
"checked_in": pool.checkedin(),
|
||||
"checked_out": pool.checkedout()
|
||||
}
|
||||
|
||||
# 获取统计信息
|
||||
health_info["stats"] = await get_db_stats()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"数据库健康检查失败: {e}")
|
||||
health_info["database"] = "error"
|
||||
health_info["error"] = str(e)
|
||||
|
||||
return health_info
|
||||
@@ -0,0 +1,427 @@
|
||||
"""
|
||||
taiji-AI-PAD MCP Server
|
||||
核心MCP协议服务器,负责Agent注册、工具管理和协议通信
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
import structlog
|
||||
from fastapi import FastAPI, HTTPException, Depends, WebSocket, WebSocketDisconnect
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import JSONResponse
|
||||
from pydantic import BaseModel
|
||||
import redis.asyncio as redis
|
||||
import nats
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
from .models import Agent, Tool, Session as DBSession
|
||||
from .schemas import (
|
||||
AgentCard,
|
||||
AgentCreateRequest,
|
||||
ToolDefinition,
|
||||
MCPRequest,
|
||||
MCPResponse,
|
||||
ExecutionResult
|
||||
)
|
||||
from .mcp_protocol import MCPProtocolHandler
|
||||
from .database import get_db, init_db
|
||||
from .config import Settings
|
||||
|
||||
# 配置日志
|
||||
structlog.configure(
|
||||
processors=[
|
||||
structlog.stdlib.filter_by_level,
|
||||
structlog.stdlib.add_logger_name,
|
||||
structlog.stdlib.add_log_level,
|
||||
structlog.stdlib.PositionalArgumentsFormatter(),
|
||||
structlog.processors.TimeStamper(fmt="iso"),
|
||||
structlog.processors.StackInfoRenderer(),
|
||||
structlog.processors.format_exc_info,
|
||||
structlog.processors.UnicodeDecoder(),
|
||||
structlog.processors.JSONRenderer()
|
||||
],
|
||||
context_class=dict,
|
||||
logger_factory=structlog.stdlib.LoggerFactory(),
|
||||
cache_logger_on_first_use=True,
|
||||
)
|
||||
|
||||
logger = structlog.get_logger()
|
||||
|
||||
# 应用设置
|
||||
settings = Settings()
|
||||
app = FastAPI(
|
||||
title="taiji-AI-PAD MCP Server",
|
||||
description="Model Context Protocol Server for Agent Management",
|
||||
version="1.0.0",
|
||||
docs_url="/docs",
|
||||
redoc_url="/redoc"
|
||||
)
|
||||
|
||||
# CORS配置
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
# 全局变量
|
||||
redis_client: Optional[redis.Redis] = None
|
||||
nats_client: Optional[nats.NATS] = None
|
||||
mcp_handler: Optional[MCPProtocolHandler] = None
|
||||
active_websockets: Dict[str, WebSocket] = {}
|
||||
|
||||
class HealthResponse(BaseModel):
|
||||
status: str
|
||||
timestamp: str
|
||||
services: Dict[str, str]
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup_event():
|
||||
"""应用启动时初始化服务"""
|
||||
global redis_client, nats_client, mcp_handler
|
||||
|
||||
try:
|
||||
# 初始化数据库
|
||||
await init_db()
|
||||
logger.info("数据库初始化完成")
|
||||
|
||||
# 连接Redis
|
||||
redis_client = redis.from_url(
|
||||
settings.redis_url,
|
||||
encoding="utf-8",
|
||||
decode_responses=True
|
||||
)
|
||||
await redis_client.ping()
|
||||
logger.info("Redis连接成功")
|
||||
|
||||
# 连接NATS
|
||||
nats_client = await nats.connect(settings.nats_url)
|
||||
logger.info("NATS连接成功")
|
||||
|
||||
# 初始化MCP协议处理器
|
||||
mcp_handler = MCPProtocolHandler(redis_client, nats_client)
|
||||
logger.info("MCP协议处理器初始化完成")
|
||||
|
||||
# 注册NATS事件处理器
|
||||
await setup_nats_handlers()
|
||||
|
||||
logger.info("MCP Server启动完成")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"服务启动失败: {e}")
|
||||
raise
|
||||
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown_event():
|
||||
"""应用关闭时清理资源"""
|
||||
global redis_client, nats_client
|
||||
|
||||
try:
|
||||
# 关闭所有WebSocket连接
|
||||
for ws in active_websockets.values():
|
||||
await ws.close()
|
||||
|
||||
# 关闭NATS连接
|
||||
if nats_client:
|
||||
await nats_client.close()
|
||||
|
||||
# 关闭Redis连接
|
||||
if redis_client:
|
||||
await redis_client.close()
|
||||
|
||||
logger.info("资源清理完成")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"资源清理失败: {e}")
|
||||
|
||||
async def setup_nats_handlers():
|
||||
"""设置NATS事件处理器"""
|
||||
if not nats_client:
|
||||
return
|
||||
|
||||
# Agent执行事件
|
||||
await nats_client.subscribe("agent.execution.*", cb=handle_agent_execution)
|
||||
|
||||
# 计费事件
|
||||
await nats_client.subscribe("billing.*", cb=handle_billing_event)
|
||||
|
||||
# 系统事件
|
||||
await nats_client.subscribe("system.*", cb=handle_system_event)
|
||||
|
||||
async def handle_agent_execution(msg):
|
||||
"""处理Agent执行事件"""
|
||||
try:
|
||||
data = json.loads(msg.data.decode())
|
||||
logger.info(f"收到Agent执行事件: {data}")
|
||||
|
||||
# 广播给相关的WebSocket连接
|
||||
for ws in active_websockets.values():
|
||||
await ws.send_json({
|
||||
"type": "agent_execution",
|
||||
"data": data
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"处理Agent执行事件失败: {e}")
|
||||
|
||||
async def handle_billing_event(msg):
|
||||
"""处理计费事件"""
|
||||
try:
|
||||
data = json.loads(msg.data.decode())
|
||||
logger.info(f"收到计费事件: {data}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"处理计费事件失败: {e}")
|
||||
|
||||
async def handle_system_event(msg):
|
||||
"""处理系统事件"""
|
||||
try:
|
||||
data = json.loads(msg.data.decode())
|
||||
logger.info(f"收到系统事件: {data}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"处理系统事件失败: {e}")
|
||||
|
||||
@app.get("/health", response_model=HealthResponse)
|
||||
async def health_check():
|
||||
"""健康检查端点"""
|
||||
services = {
|
||||
"mcp_server": "healthy",
|
||||
"redis": "unknown",
|
||||
"nats": "unknown",
|
||||
"database": "unknown"
|
||||
}
|
||||
|
||||
# 检查Redis
|
||||
try:
|
||||
if redis_client:
|
||||
await redis_client.ping()
|
||||
services["redis"] = "healthy"
|
||||
except Exception:
|
||||
services["redis"] = "unhealthy"
|
||||
|
||||
# 检查NATS
|
||||
try:
|
||||
if nats_client and nats_client.is_connected:
|
||||
services["nats"] = "healthy"
|
||||
except Exception:
|
||||
services["nats"] = "unhealthy"
|
||||
|
||||
# 检查数据库连接
|
||||
try:
|
||||
# 这里应该有数据库连接检查
|
||||
services["database"] = "healthy"
|
||||
except Exception:
|
||||
services["database"] = "unhealthy"
|
||||
|
||||
return HealthResponse(
|
||||
status="healthy",
|
||||
timestamp=datetime.utcnow().isoformat(),
|
||||
services=services
|
||||
)
|
||||
|
||||
@app.post("/agents", response_model=AgentCard)
|
||||
async def create_agent(
|
||||
request: AgentCreateRequest,
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""创建新的Agent"""
|
||||
try:
|
||||
# 创建Agent记录
|
||||
agent = Agent(
|
||||
name=request.name,
|
||||
description=request.description,
|
||||
role=request.role,
|
||||
goal=request.goal,
|
||||
tools=request.tools,
|
||||
config=request.config,
|
||||
owner_id=request.owner_id
|
||||
)
|
||||
|
||||
db.add(agent)
|
||||
await db.commit()
|
||||
await db.refresh(agent)
|
||||
|
||||
# 生成Agent Card
|
||||
agent_card = AgentCard(
|
||||
id=agent.id,
|
||||
name=agent.name,
|
||||
description=agent.description,
|
||||
role=agent.role,
|
||||
goal=agent.goal,
|
||||
tools=agent.tools,
|
||||
endpoints={
|
||||
"mcp": f"mcp://localhost:8002/agents/{agent.id}",
|
||||
"http": f"http://localhost:8002/agents/{agent.id}",
|
||||
"websocket": f"ws://localhost:8002/agents/{agent.id}/ws"
|
||||
},
|
||||
created_at=agent.created_at,
|
||||
updated_at=agent.updated_at
|
||||
)
|
||||
|
||||
# 缓存到Redis
|
||||
if redis_client:
|
||||
await redis_client.setex(
|
||||
f"agent:{agent.id}",
|
||||
3600, # 1小时过期
|
||||
agent_card.json()
|
||||
)
|
||||
|
||||
# 发布Agent创建事件
|
||||
if nats_client:
|
||||
await nats_client.publish(
|
||||
"agent.created",
|
||||
json.dumps({
|
||||
"agent_id": agent.id,
|
||||
"name": agent.name,
|
||||
"timestamp": datetime.utcnow().isoformat()
|
||||
}).encode()
|
||||
)
|
||||
|
||||
logger.info(f"Agent创建成功: {agent.id}")
|
||||
return agent_card
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"创建Agent失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.get("/agents", response_model=List[AgentCard])
|
||||
async def list_agents(
|
||||
skip: int = 0,
|
||||
limit: int = 100,
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""获取Agent列表"""
|
||||
try:
|
||||
# 从数据库获取Agent列表
|
||||
# 这里应该有实际的数据库查询逻辑
|
||||
agents = [] # 临时空列表
|
||||
|
||||
return agents
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取Agent列表失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.get("/agents/{agent_id}", response_model=AgentCard)
|
||||
async def get_agent(agent_id: str, db: AsyncSession = Depends(get_db)):
|
||||
"""获取特定Agent信息"""
|
||||
try:
|
||||
# 先从Redis缓存查找
|
||||
if redis_client:
|
||||
cached = await redis_client.get(f"agent:{agent_id}")
|
||||
if cached:
|
||||
return AgentCard.parse_raw(cached)
|
||||
|
||||
# 从数据库查找
|
||||
# 这里应该有实际的数据库查询逻辑
|
||||
|
||||
raise HTTPException(status_code=404, detail="Agent not found")
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"获取Agent失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.post("/agents/{agent_id}/execute", response_model=ExecutionResult)
|
||||
async def execute_agent(
|
||||
agent_id: str,
|
||||
request: MCPRequest,
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""执行Agent任务"""
|
||||
try:
|
||||
if not mcp_handler:
|
||||
raise HTTPException(status_code=500, detail="MCP handler not initialized")
|
||||
|
||||
# 执行MCP请求
|
||||
result = await mcp_handler.execute_request(agent_id, request)
|
||||
|
||||
# 发布执行事件
|
||||
if nats_client:
|
||||
await nats_client.publish(
|
||||
f"agent.execution.{agent_id}",
|
||||
json.dumps({
|
||||
"agent_id": agent_id,
|
||||
"request_id": request.id,
|
||||
"method": request.method,
|
||||
"timestamp": datetime.utcnow().isoformat(),
|
||||
"success": result.success
|
||||
}).encode()
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"执行Agent任务失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.get("/tools", response_model=List[ToolDefinition])
|
||||
async def list_tools(db: AsyncSession = Depends(get_db)):
|
||||
"""获取可用工具列表"""
|
||||
try:
|
||||
# 从数据库获取工具列表
|
||||
# 这里应该有实际的工具查询逻辑
|
||||
tools = []
|
||||
|
||||
return tools
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取工具列表失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.websocket("/agents/{agent_id}/ws")
|
||||
async def websocket_endpoint(websocket: WebSocket, agent_id: str):
|
||||
"""Agent WebSocket连接端点"""
|
||||
await websocket.accept()
|
||||
active_websockets[agent_id] = websocket
|
||||
|
||||
try:
|
||||
logger.info(f"WebSocket连接建立: {agent_id}")
|
||||
|
||||
while True:
|
||||
# 等待客户端消息
|
||||
data = await websocket.receive_json()
|
||||
|
||||
# 处理MCP消息
|
||||
if mcp_handler and data.get("type") == "mcp_request":
|
||||
request = MCPRequest(**data["payload"])
|
||||
result = await mcp_handler.execute_request(agent_id, request)
|
||||
|
||||
await websocket.send_json({
|
||||
"type": "mcp_response",
|
||||
"payload": result.dict()
|
||||
})
|
||||
|
||||
except WebSocketDisconnect:
|
||||
logger.info(f"WebSocket连接断开: {agent_id}")
|
||||
except Exception as e:
|
||||
logger.error(f"WebSocket错误: {e}")
|
||||
finally:
|
||||
if agent_id in active_websockets:
|
||||
del active_websockets[agent_id]
|
||||
|
||||
@app.get("/metrics")
|
||||
async def get_metrics():
|
||||
"""Prometheus metrics端点"""
|
||||
# 这里应该返回Prometheus格式的metrics
|
||||
return JSONResponse({"message": "Metrics endpoint - TODO: implement Prometheus metrics"})
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run(
|
||||
"main:app",
|
||||
host="0.0.0.0",
|
||||
port=8000,
|
||||
reload=True,
|
||||
log_level="info"
|
||||
)
|
||||
@@ -0,0 +1,595 @@
|
||||
"""
|
||||
MCP (Model Context Protocol) 协议处理器
|
||||
实现MCP协议的核心功能,包括工具管理、资源管理和代理通信
|
||||
"""
|
||||
|
||||
import json
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional, Union
|
||||
import asyncio
|
||||
import logging
|
||||
import traceback
|
||||
|
||||
import redis.asyncio as redis
|
||||
import nats
|
||||
import httpx
|
||||
from .schemas import (
|
||||
MCPRequest, MCPResponse, MCPError,
|
||||
ToolDefinition, ToolResult, ExecutionResult
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MCPProtocolHandler:
|
||||
"""MCP协议处理器"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
redis_client: redis.Redis,
|
||||
nats_client: nats.NATS,
|
||||
litellm_url: str = "http://litellm-gateway:4000"
|
||||
):
|
||||
self.redis = redis_client
|
||||
self.nats = nats_client
|
||||
self.litellm_url = litellm_url
|
||||
self.http_client = httpx.AsyncClient(timeout=30.0)
|
||||
|
||||
# MCP协议版本
|
||||
self.protocol_version = "2024-11-05"
|
||||
|
||||
# 支持的MCP方法
|
||||
self.supported_methods = {
|
||||
"initialize",
|
||||
"tools/list",
|
||||
"tools/call",
|
||||
"resources/list",
|
||||
"resources/read",
|
||||
"prompts/list",
|
||||
"prompts/get",
|
||||
"completion/complete",
|
||||
"logging/setLevel"
|
||||
}
|
||||
|
||||
# 工具注册表
|
||||
self._tools_registry: Dict[str, ToolDefinition] = {}
|
||||
|
||||
# 资源注册表
|
||||
self._resources_registry: Dict[str, Dict[str, Any]] = {}
|
||||
|
||||
# 会话管理
|
||||
self._sessions: Dict[str, Dict[str, Any]] = {}
|
||||
|
||||
async def execute_request(self, agent_id: str, request: MCPRequest) -> ExecutionResult:
|
||||
"""执行MCP请求"""
|
||||
execution_id = str(uuid.uuid4())
|
||||
started_at = datetime.utcnow()
|
||||
|
||||
logger.info(f"开始执行MCP请求: {execution_id}, method: {request.method}")
|
||||
|
||||
try:
|
||||
# 验证方法是否支持
|
||||
if request.method not in self.supported_methods:
|
||||
raise ValueError(f"不支持的MCP方法: {request.method}")
|
||||
|
||||
# 发布执行开始事件
|
||||
await self._publish_execution_event(
|
||||
"execution.started",
|
||||
{
|
||||
"execution_id": execution_id,
|
||||
"agent_id": agent_id,
|
||||
"method": request.method,
|
||||
"timestamp": started_at.isoformat()
|
||||
}
|
||||
)
|
||||
|
||||
# 执行具体方法
|
||||
result = await self._dispatch_method(agent_id, request)
|
||||
|
||||
completed_at = datetime.utcnow()
|
||||
execution_time = (completed_at - started_at).total_seconds() * 1000
|
||||
|
||||
# 发布执行完成事件
|
||||
await self._publish_execution_event(
|
||||
"execution.completed",
|
||||
{
|
||||
"execution_id": execution_id,
|
||||
"agent_id": agent_id,
|
||||
"method": request.method,
|
||||
"execution_time": execution_time,
|
||||
"success": True,
|
||||
"timestamp": completed_at.isoformat()
|
||||
}
|
||||
)
|
||||
|
||||
return ExecutionResult(
|
||||
execution_id=execution_id,
|
||||
success=True,
|
||||
result=result,
|
||||
execution_time=execution_time,
|
||||
started_at=started_at,
|
||||
completed_at=completed_at
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
completed_at = datetime.utcnow()
|
||||
execution_time = (completed_at - started_at).total_seconds() * 1000
|
||||
error_msg = str(e)
|
||||
|
||||
logger.error(f"MCP请求执行失败: {execution_id}, error: {error_msg}")
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
# 发布执行失败事件
|
||||
await self._publish_execution_event(
|
||||
"execution.failed",
|
||||
{
|
||||
"execution_id": execution_id,
|
||||
"agent_id": agent_id,
|
||||
"method": request.method,
|
||||
"execution_time": execution_time,
|
||||
"error": error_msg,
|
||||
"timestamp": completed_at.isoformat()
|
||||
}
|
||||
)
|
||||
|
||||
return ExecutionResult(
|
||||
execution_id=execution_id,
|
||||
success=False,
|
||||
error=error_msg,
|
||||
execution_time=execution_time,
|
||||
started_at=started_at,
|
||||
completed_at=completed_at
|
||||
)
|
||||
|
||||
async def _dispatch_method(self, agent_id: str, request: MCPRequest) -> Any:
|
||||
"""分发MCP方法调用"""
|
||||
method = request.method
|
||||
params = request.params or {}
|
||||
|
||||
if method == "initialize":
|
||||
return await self._handle_initialize(params)
|
||||
elif method == "tools/list":
|
||||
return await self._handle_tools_list(agent_id, params)
|
||||
elif method == "tools/call":
|
||||
return await self._handle_tools_call(agent_id, params)
|
||||
elif method == "resources/list":
|
||||
return await self._handle_resources_list(agent_id, params)
|
||||
elif method == "resources/read":
|
||||
return await self._handle_resources_read(agent_id, params)
|
||||
elif method == "prompts/list":
|
||||
return await self._handle_prompts_list(agent_id, params)
|
||||
elif method == "prompts/get":
|
||||
return await self._handle_prompts_get(agent_id, params)
|
||||
elif method == "completion/complete":
|
||||
return await self._handle_completion_complete(agent_id, params)
|
||||
elif method == "logging/setLevel":
|
||||
return await self._handle_logging_set_level(params)
|
||||
else:
|
||||
raise ValueError(f"未实现的方法: {method}")
|
||||
|
||||
async def _handle_initialize(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""处理初始化请求"""
|
||||
client_info = params.get("clientInfo", {})
|
||||
protocol_version = params.get("protocolVersion")
|
||||
|
||||
logger.info(f"MCP客户端初始化: {client_info}")
|
||||
|
||||
return {
|
||||
"protocolVersion": self.protocol_version,
|
||||
"capabilities": {
|
||||
"tools": {
|
||||
"listChanged": True
|
||||
},
|
||||
"resources": {
|
||||
"subscribe": True,
|
||||
"listChanged": True
|
||||
},
|
||||
"prompts": {
|
||||
"listChanged": True
|
||||
},
|
||||
"completion": {
|
||||
"argument": True
|
||||
},
|
||||
"logging": {}
|
||||
},
|
||||
"serverInfo": {
|
||||
"name": "taiji-AI-PAD MCP Server",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
async def _handle_tools_list(self, agent_id: str, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""处理工具列表请求"""
|
||||
try:
|
||||
# 从Redis获取Agent的工具列表
|
||||
agent_tools_key = f"agent:{agent_id}:tools"
|
||||
tool_names = await self.redis.smembers(agent_tools_key)
|
||||
|
||||
tools = []
|
||||
for tool_name in tool_names:
|
||||
tool_info = await self._get_tool_info(tool_name)
|
||||
if tool_info:
|
||||
tools.append({
|
||||
"name": tool_info["name"],
|
||||
"description": tool_info["description"],
|
||||
"inputSchema": tool_info.get("schema", {})
|
||||
})
|
||||
|
||||
return {"tools": tools}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取工具列表失败: {e}")
|
||||
return {"tools": []}
|
||||
|
||||
async def _handle_tools_call(self, agent_id: str, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""处理工具调用请求"""
|
||||
tool_name = params.get("name")
|
||||
arguments = params.get("arguments", {})
|
||||
|
||||
if not tool_name:
|
||||
raise ValueError("工具名称不能为空")
|
||||
|
||||
logger.info(f"调用工具: {tool_name}, arguments: {arguments}")
|
||||
|
||||
try:
|
||||
# 验证Agent是否有权限使用该工具
|
||||
agent_tools_key = f"agent:{agent_id}:tools"
|
||||
if not await self.redis.sismember(agent_tools_key, tool_name):
|
||||
raise ValueError(f"Agent {agent_id} 无权限使用工具 {tool_name}")
|
||||
|
||||
# 获取工具信息
|
||||
tool_info = await self._get_tool_info(tool_name)
|
||||
if not tool_info:
|
||||
raise ValueError(f"工具 {tool_name} 不存在")
|
||||
|
||||
# 执行工具调用
|
||||
result = await self._execute_tool(tool_name, tool_info, arguments)
|
||||
|
||||
return {
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": json.dumps(result.result) if result.success else f"错误: {result.error}"
|
||||
}
|
||||
],
|
||||
"isError": not result.success
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"工具调用失败: {e}")
|
||||
return {
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": f"工具调用失败: {str(e)}"
|
||||
}
|
||||
],
|
||||
"isError": True
|
||||
}
|
||||
|
||||
async def _handle_resources_list(self, agent_id: str, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""处理资源列表请求"""
|
||||
try:
|
||||
# 从Redis获取Agent的资源列表
|
||||
agent_resources_key = f"agent:{agent_id}:resources"
|
||||
resource_names = await self.redis.smembers(agent_resources_key)
|
||||
|
||||
resources = []
|
||||
for resource_name in resource_names:
|
||||
resource_info = await self._get_resource_info(resource_name)
|
||||
if resource_info:
|
||||
resources.append({
|
||||
"uri": resource_info["uri"],
|
||||
"name": resource_info["name"],
|
||||
"description": resource_info.get("description"),
|
||||
"mimeType": resource_info.get("mimeType", "application/json")
|
||||
})
|
||||
|
||||
return {"resources": resources}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取资源列表失败: {e}")
|
||||
return {"resources": []}
|
||||
|
||||
async def _handle_resources_read(self, agent_id: str, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""处理资源读取请求"""
|
||||
uri = params.get("uri")
|
||||
if not uri:
|
||||
raise ValueError("资源URI不能为空")
|
||||
|
||||
try:
|
||||
# 验证权限
|
||||
agent_resources_key = f"agent:{agent_id}:resources"
|
||||
# 这里应该根据URI找到资源名称
|
||||
resource_name = uri.split("/")[-1] # 简化处理
|
||||
|
||||
if not await self.redis.sismember(agent_resources_key, resource_name):
|
||||
raise ValueError(f"Agent {agent_id} 无权限访问资源 {uri}")
|
||||
|
||||
# 读取资源内容
|
||||
content = await self._read_resource_content(uri)
|
||||
|
||||
return {
|
||||
"contents": [
|
||||
{
|
||||
"uri": uri,
|
||||
"mimeType": "application/json",
|
||||
"text": json.dumps(content)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"读取资源失败: {e}")
|
||||
raise ValueError(f"无法读取资源 {uri}: {str(e)}")
|
||||
|
||||
async def _handle_prompts_list(self, agent_id: str, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""处理提示词列表请求"""
|
||||
# 获取Agent相关的提示词
|
||||
prompts = [
|
||||
{
|
||||
"name": "system_prompt",
|
||||
"description": "系统提示词",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "context",
|
||||
"description": "上下文信息",
|
||||
"required": False
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
return {"prompts": prompts}
|
||||
|
||||
async def _handle_prompts_get(self, agent_id: str, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""处理获取提示词请求"""
|
||||
name = params.get("name")
|
||||
arguments = params.get("arguments", {})
|
||||
|
||||
if name == "system_prompt":
|
||||
# 构建系统提示词
|
||||
agent_info = await self._get_agent_info(agent_id)
|
||||
prompt = f"""你是 {agent_info.get('name', 'AI助手')}。
|
||||
角色定义: {agent_info.get('role', '通用助手')}
|
||||
目标: {agent_info.get('goal', '帮助用户完成任务')}
|
||||
|
||||
可用工具: {', '.join(agent_info.get('tools', []))}
|
||||
|
||||
请根据用户的请求,选择合适的工具来完成任务。"""
|
||||
|
||||
return {
|
||||
"description": "Agent系统提示词",
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": {
|
||||
"type": "text",
|
||||
"text": prompt
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
raise ValueError(f"未知的提示词: {name}")
|
||||
|
||||
async def _handle_completion_complete(self, agent_id: str, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""处理补全请求"""
|
||||
ref = params.get("ref", {})
|
||||
argument = params.get("argument", {})
|
||||
|
||||
# 根据参考信息生成补全建议
|
||||
completions = []
|
||||
|
||||
if ref.get("type") == "tool":
|
||||
tool_name = ref.get("name")
|
||||
if tool_name:
|
||||
tool_info = await self._get_tool_info(tool_name)
|
||||
if tool_info and "schema" in tool_info:
|
||||
# 基于工具schema生成参数建议
|
||||
schema = tool_info["schema"]
|
||||
properties = schema.get("properties", {})
|
||||
for prop_name, prop_info in properties.items():
|
||||
completions.append({
|
||||
"type": "text",
|
||||
"text": prop_name,
|
||||
"insertText": f'"{prop_name}": ""'
|
||||
})
|
||||
|
||||
return {"completion": {"values": completions}}
|
||||
|
||||
async def _handle_logging_set_level(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""处理设置日志级别请求"""
|
||||
level = params.get("level", "info")
|
||||
|
||||
# 设置日志级别
|
||||
numeric_level = getattr(logging, level.upper(), logging.INFO)
|
||||
logging.getLogger().setLevel(numeric_level)
|
||||
|
||||
logger.info(f"日志级别已设置为: {level}")
|
||||
|
||||
return {"success": True}
|
||||
|
||||
async def _execute_tool(
|
||||
self,
|
||||
tool_name: str,
|
||||
tool_info: Dict[str, Any],
|
||||
arguments: Dict[str, Any]
|
||||
) -> ToolResult:
|
||||
"""执行工具调用"""
|
||||
start_time = datetime.utcnow()
|
||||
|
||||
try:
|
||||
# 根据工具类型执行不同的逻辑
|
||||
category = tool_info.get("category", "api")
|
||||
|
||||
if category == "api":
|
||||
result = await self._execute_api_tool(tool_info, arguments)
|
||||
elif category == "function":
|
||||
result = await self._execute_function_tool(tool_info, arguments)
|
||||
elif category == "llm":
|
||||
result = await self._execute_llm_tool(tool_info, arguments)
|
||||
else:
|
||||
raise ValueError(f"不支持的工具类型: {category}")
|
||||
|
||||
execution_time = (datetime.utcnow() - start_time).total_seconds() * 1000
|
||||
|
||||
return ToolResult(
|
||||
success=True,
|
||||
result=result,
|
||||
execution_time=execution_time,
|
||||
cost=tool_info.get("cost_per_call", 0.0)
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
execution_time = (datetime.utcnow() - start_time).total_seconds() * 1000
|
||||
|
||||
return ToolResult(
|
||||
success=False,
|
||||
error=str(e),
|
||||
execution_time=execution_time,
|
||||
cost=tool_info.get("cost_per_call", 0.0)
|
||||
)
|
||||
|
||||
async def _execute_api_tool(self, tool_info: Dict[str, Any], arguments: Dict[str, Any]) -> Any:
|
||||
"""执行API工具调用"""
|
||||
endpoint = tool_info.get("endpoint")
|
||||
method = tool_info.get("method", "POST")
|
||||
headers = tool_info.get("headers", {})
|
||||
timeout = tool_info.get("timeout", 30)
|
||||
|
||||
if not endpoint:
|
||||
raise ValueError("API端点不能为空")
|
||||
|
||||
# 发送HTTP请求
|
||||
response = await self.http_client.request(
|
||||
method=method,
|
||||
url=endpoint,
|
||||
json=arguments,
|
||||
headers=headers,
|
||||
timeout=timeout
|
||||
)
|
||||
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
async def _execute_function_tool(self, tool_info: Dict[str, Any], arguments: Dict[str, Any]) -> Any:
|
||||
"""执行函数工具调用"""
|
||||
# 这里可以调用本地Python函数
|
||||
# 为了安全起见,需要严格的沙箱机制
|
||||
raise NotImplementedError("函数工具调用暂未实现")
|
||||
|
||||
async def _execute_llm_tool(self, tool_info: Dict[str, Any], arguments: Dict[str, Any]) -> Any:
|
||||
"""执行LLM工具调用"""
|
||||
# 调用LiteLLM网关
|
||||
payload = {
|
||||
"model": arguments.get("model", "gpt-3.5-turbo"),
|
||||
"messages": arguments.get("messages", []),
|
||||
"temperature": arguments.get("temperature", 0.7),
|
||||
"max_tokens": arguments.get("max_tokens", 150)
|
||||
}
|
||||
|
||||
response = await self.http_client.post(
|
||||
f"{self.litellm_url}/chat/completions",
|
||||
json=payload,
|
||||
headers={"Authorization": "Bearer sk-taiji-master-key"}
|
||||
)
|
||||
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
async def _get_tool_info(self, tool_name: str) -> Optional[Dict[str, Any]]:
|
||||
"""获取工具信息"""
|
||||
tool_key = f"tool:{tool_name}"
|
||||
tool_data = await self.redis.get(tool_key)
|
||||
|
||||
if tool_data:
|
||||
return json.loads(tool_data)
|
||||
return None
|
||||
|
||||
async def _get_resource_info(self, resource_name: str) -> Optional[Dict[str, Any]]:
|
||||
"""获取资源信息"""
|
||||
resource_key = f"resource:{resource_name}"
|
||||
resource_data = await self.redis.get(resource_key)
|
||||
|
||||
if resource_data:
|
||||
return json.loads(resource_data)
|
||||
return None
|
||||
|
||||
async def _get_agent_info(self, agent_id: str) -> Dict[str, Any]:
|
||||
"""获取Agent信息"""
|
||||
agent_key = f"agent:{agent_id}"
|
||||
agent_data = await self.redis.get(agent_key)
|
||||
|
||||
if agent_data:
|
||||
return json.loads(agent_data)
|
||||
return {}
|
||||
|
||||
async def _read_resource_content(self, uri: str) -> Any:
|
||||
"""读取资源内容"""
|
||||
# 这里可以根据URI类型读取不同的资源
|
||||
# 例如:文件、数据库、API等
|
||||
if uri.startswith("file://"):
|
||||
# 读取文件
|
||||
file_path = uri[7:] # 移除file://前缀
|
||||
with open(file_path, 'r') as f:
|
||||
return f.read()
|
||||
elif uri.startswith("http://") or uri.startswith("https://"):
|
||||
# 读取HTTP资源
|
||||
response = await self.http_client.get(uri)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
else:
|
||||
raise ValueError(f"不支持的资源类型: {uri}")
|
||||
|
||||
async def _publish_execution_event(self, event_type: str, data: Dict[str, Any]):
|
||||
"""发布执行事件"""
|
||||
try:
|
||||
if self.nats:
|
||||
await self.nats.publish(
|
||||
f"mcp.{event_type}",
|
||||
json.dumps(data).encode()
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"发布事件失败: {e}")
|
||||
|
||||
async def register_tool(self, tool_definition: ToolDefinition) -> bool:
|
||||
"""注册工具"""
|
||||
try:
|
||||
tool_key = f"tool:{tool_definition.name}"
|
||||
tool_data = tool_definition.dict()
|
||||
|
||||
await self.redis.setex(
|
||||
tool_key,
|
||||
3600, # 1小时过期
|
||||
json.dumps(tool_data)
|
||||
)
|
||||
|
||||
logger.info(f"工具注册成功: {tool_definition.name}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"工具注册失败: {e}")
|
||||
return False
|
||||
|
||||
async def register_agent_tool(self, agent_id: str, tool_name: str) -> bool:
|
||||
"""为Agent注册工具"""
|
||||
try:
|
||||
agent_tools_key = f"agent:{agent_id}:tools"
|
||||
await self.redis.sadd(agent_tools_key, tool_name)
|
||||
await self.redis.expire(agent_tools_key, 3600)
|
||||
|
||||
logger.info(f"Agent {agent_id} 工具注册成功: {tool_name}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Agent工具注册失败: {e}")
|
||||
return False
|
||||
|
||||
async def close(self):
|
||||
"""清理资源"""
|
||||
try:
|
||||
await self.http_client.aclose()
|
||||
except Exception as e:
|
||||
logger.error(f"资源清理失败: {e}")
|
||||
@@ -0,0 +1,292 @@
|
||||
"""
|
||||
数据库模型定义
|
||||
"""
|
||||
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional, Any
|
||||
from sqlalchemy import (
|
||||
Column, String, Text, DateTime, Boolean, Integer,
|
||||
JSON, ForeignKey, Index, UniqueConstraint
|
||||
)
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
import sqlalchemy as sa
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
|
||||
class BaseModel:
|
||||
"""基础模型类"""
|
||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(
|
||||
DateTime,
|
||||
default=datetime.utcnow,
|
||||
onupdate=datetime.utcnow,
|
||||
nullable=False
|
||||
)
|
||||
|
||||
|
||||
class User(BaseModel, Base):
|
||||
"""用户模型"""
|
||||
__tablename__ = "users"
|
||||
|
||||
username = Column(String(50), unique=True, nullable=False)
|
||||
email = Column(String(255), unique=True, nullable=False)
|
||||
hashed_password = Column(String(255), nullable=False)
|
||||
full_name = Column(String(100))
|
||||
is_active = Column(Boolean, default=True)
|
||||
is_admin = Column(Boolean, default=False)
|
||||
|
||||
# 关联关系
|
||||
agents = relationship("Agent", back_populates="owner", cascade="all, delete-orphan")
|
||||
sessions = relationship("Session", back_populates="user", cascade="all, delete-orphan")
|
||||
|
||||
# 索引
|
||||
__table_args__ = (
|
||||
Index("idx_user_username", username),
|
||||
Index("idx_user_email", email),
|
||||
)
|
||||
|
||||
|
||||
class Agent(BaseModel, Base):
|
||||
"""Agent模型"""
|
||||
__tablename__ = "agents"
|
||||
|
||||
name = Column(String(100), nullable=False)
|
||||
description = Column(Text)
|
||||
role = Column(String(200), nullable=False) # Agent的角色定义
|
||||
goal = Column(Text, nullable=False) # Agent的目标描述
|
||||
|
||||
# Agent配置
|
||||
config = Column(JSON, default=dict) # Agent的配置信息
|
||||
tools = Column(JSON, default=list) # Agent授权使用的工具列表
|
||||
capabilities = Column(JSON, default=list) # Agent的能力列表
|
||||
|
||||
# 状态信息
|
||||
status = Column(String(20), default="active") # active, inactive, error
|
||||
version = Column(String(20), default="1.0.0")
|
||||
|
||||
# 性能统计
|
||||
total_executions = Column(Integer, default=0)
|
||||
success_rate = Column(sa.Float, default=0.0)
|
||||
avg_execution_time = Column(sa.Float, default=0.0) # 毫秒
|
||||
|
||||
# 关联关系
|
||||
owner_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
|
||||
owner = relationship("User", back_populates="agents")
|
||||
|
||||
executions = relationship("Execution", back_populates="agent", cascade="all, delete-orphan")
|
||||
|
||||
# 索引和约束
|
||||
__table_args__ = (
|
||||
Index("idx_agent_name", name),
|
||||
Index("idx_agent_owner", owner_id),
|
||||
Index("idx_agent_status", status),
|
||||
UniqueConstraint("name", "owner_id", name="uq_agent_name_owner"),
|
||||
)
|
||||
|
||||
|
||||
class Tool(BaseModel, Base):
|
||||
"""工具模型"""
|
||||
__tablename__ = "tools"
|
||||
|
||||
name = Column(String(100), nullable=False)
|
||||
description = Column(Text)
|
||||
category = Column(String(50)) # api, function, integration等
|
||||
|
||||
# 工具定义
|
||||
schema = Column(JSON, nullable=False) # OpenAPI或Pydantic schema
|
||||
endpoint = Column(String(500)) # API端点URL
|
||||
method = Column(String(10), default="POST") # HTTP方法
|
||||
|
||||
# 认证信息
|
||||
auth_type = Column(String(20)) # api_key, oauth, basic等
|
||||
auth_config = Column(JSON, default=dict)
|
||||
|
||||
# 限制和配额
|
||||
rate_limit = Column(Integer, default=100) # 每分钟调用次数
|
||||
cost_per_call = Column(sa.Float, default=0.0) # 每次调用成本(EU)
|
||||
timeout = Column(Integer, default=30) # 超时时间(秒)
|
||||
|
||||
# 状态信息
|
||||
is_active = Column(Boolean, default=True)
|
||||
is_public = Column(Boolean, default=False) # 是否公开可用
|
||||
|
||||
# 统计信息
|
||||
total_calls = Column(Integer, default=0)
|
||||
success_rate = Column(sa.Float, default=0.0)
|
||||
avg_response_time = Column(sa.Float, default=0.0)
|
||||
|
||||
# 关联关系
|
||||
owner_id = Column(UUID(as_uuid=True), ForeignKey("users.id"))
|
||||
owner = relationship("User")
|
||||
|
||||
# 索引
|
||||
__table_args__ = (
|
||||
Index("idx_tool_name", name),
|
||||
Index("idx_tool_category", category),
|
||||
Index("idx_tool_active", is_active),
|
||||
)
|
||||
|
||||
|
||||
class Session(BaseModel, Base):
|
||||
"""会话模型"""
|
||||
__tablename__ = "sessions"
|
||||
|
||||
session_id = Column(String(100), unique=True, nullable=False)
|
||||
|
||||
# 会话信息
|
||||
context = Column(JSON, default=dict) # 会话上下文
|
||||
metadata = Column(JSON, default=dict) # 元数据
|
||||
|
||||
# 状态
|
||||
status = Column(String(20), default="active") # active, completed, failed
|
||||
|
||||
# 关联关系
|
||||
user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
|
||||
user = relationship("User", back_populates="sessions")
|
||||
|
||||
executions = relationship("Execution", back_populates="session", cascade="all, delete-orphan")
|
||||
|
||||
# 索引
|
||||
__table_args__ = (
|
||||
Index("idx_session_id", session_id),
|
||||
Index("idx_session_user", user_id),
|
||||
Index("idx_session_status", status),
|
||||
)
|
||||
|
||||
|
||||
class Execution(BaseModel, Base):
|
||||
"""执行记录模型"""
|
||||
__tablename__ = "executions"
|
||||
|
||||
execution_id = Column(String(100), unique=True, nullable=False)
|
||||
|
||||
# 执行信息
|
||||
method = Column(String(50), nullable=False) # MCP方法名
|
||||
params = Column(JSON, default=dict) # 执行参数
|
||||
result = Column(JSON, default=dict) # 执行结果
|
||||
error = Column(Text) # 错误信息
|
||||
|
||||
# 时间信息
|
||||
started_at = Column(DateTime, nullable=False)
|
||||
completed_at = Column(DateTime)
|
||||
execution_time = Column(sa.Float) # 执行时间(毫秒)
|
||||
|
||||
# 状态
|
||||
status = Column(String(20), nullable=False) # running, completed, failed
|
||||
|
||||
# 资源消耗
|
||||
cpu_usage = Column(sa.Float, default=0.0) # CPU使用率
|
||||
memory_usage = Column(sa.Float, default=0.0) # 内存使用(MB)
|
||||
network_io = Column(sa.Float, default=0.0) # 网络IO(KB)
|
||||
eu_consumed = Column(sa.Float, default=0.0) # 消耗的执行单元
|
||||
|
||||
# 关联关系
|
||||
agent_id = Column(UUID(as_uuid=True), ForeignKey("agents.id"), nullable=False)
|
||||
agent = relationship("Agent", back_populates="executions")
|
||||
|
||||
session_id = Column(UUID(as_uuid=True), ForeignKey("sessions.id"))
|
||||
session = relationship("Session", back_populates="executions")
|
||||
|
||||
# 索引
|
||||
__table_args__ = (
|
||||
Index("idx_execution_id", execution_id),
|
||||
Index("idx_execution_agent", agent_id),
|
||||
Index("idx_execution_status", status),
|
||||
Index("idx_execution_started", started_at),
|
||||
)
|
||||
|
||||
|
||||
class APIKey(BaseModel, Base):
|
||||
"""API密钥模型"""
|
||||
__tablename__ = "api_keys"
|
||||
|
||||
name = Column(String(100), nullable=False)
|
||||
key_hash = Column(String(255), nullable=False) # 哈希后的密钥
|
||||
prefix = Column(String(20), nullable=False) # 密钥前缀(用于识别)
|
||||
|
||||
# 权限和限制
|
||||
scopes = Column(JSON, default=list) # 权限范围
|
||||
rate_limit = Column(Integer, default=1000) # 速率限制
|
||||
is_active = Column(Boolean, default=True)
|
||||
expires_at = Column(DateTime)
|
||||
|
||||
# 使用统计
|
||||
last_used_at = Column(DateTime)
|
||||
total_requests = Column(Integer, default=0)
|
||||
|
||||
# 关联关系
|
||||
user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
|
||||
user = relationship("User")
|
||||
|
||||
# 索引
|
||||
__table_args__ = (
|
||||
Index("idx_api_key_hash", key_hash),
|
||||
Index("idx_api_key_prefix", prefix),
|
||||
Index("idx_api_key_user", user_id),
|
||||
)
|
||||
|
||||
|
||||
class Billing(BaseModel, Base):
|
||||
"""计费记录模型"""
|
||||
__tablename__ = "billing"
|
||||
|
||||
# 计费信息
|
||||
eu_consumed = Column(sa.Float, nullable=False) # 消耗的执行单元
|
||||
cost = Column(sa.Float, nullable=False) # 成本
|
||||
currency = Column(String(3), default="USD")
|
||||
|
||||
# 资源详情
|
||||
cpu_time = Column(sa.Float, default=0.0) # CPU时间(秒)
|
||||
memory_max = Column(sa.Float, default=0.0) # 峰值内存(MB)
|
||||
network_io = Column(sa.Float, default=0.0) # 网络IO(KB)
|
||||
storage_io = Column(sa.Float, default=0.0) # 存储IO(KB)
|
||||
|
||||
# 关联关系
|
||||
execution_id = Column(UUID(as_uuid=True), ForeignKey("executions.id"), nullable=False)
|
||||
execution = relationship("Execution")
|
||||
|
||||
user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
|
||||
user = relationship("User")
|
||||
|
||||
# 索引
|
||||
__table_args__ = (
|
||||
Index("idx_billing_execution", execution_id),
|
||||
Index("idx_billing_user", user_id),
|
||||
Index("idx_billing_created", created_at),
|
||||
)
|
||||
|
||||
|
||||
class AuditLog(BaseModel, Base):
|
||||
"""审计日志模型"""
|
||||
__tablename__ = "audit_logs"
|
||||
|
||||
# 操作信息
|
||||
action = Column(String(50), nullable=False) # 操作类型
|
||||
resource_type = Column(String(50), nullable=False) # 资源类型
|
||||
resource_id = Column(String(100)) # 资源ID
|
||||
|
||||
# 详细信息
|
||||
details = Column(JSON, default=dict) # 操作详情
|
||||
ip_address = Column(String(45)) # IP地址
|
||||
user_agent = Column(Text) # 用户代理
|
||||
|
||||
# 结果
|
||||
success = Column(Boolean, nullable=False)
|
||||
error_message = Column(Text)
|
||||
|
||||
# 关联关系
|
||||
user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"))
|
||||
user = relationship("User")
|
||||
|
||||
# 索引
|
||||
__table_args__ = (
|
||||
Index("idx_audit_action", action),
|
||||
Index("idx_audit_resource", resource_type, resource_id),
|
||||
Index("idx_audit_user", user_id),
|
||||
Index("idx_audit_created", created_at),
|
||||
)
|
||||
@@ -0,0 +1,62 @@
|
||||
# Web框架
|
||||
fastapi==0.104.1
|
||||
uvicorn[standard]==0.24.0
|
||||
pydantic==2.5.0
|
||||
pydantic-settings==2.1.0
|
||||
|
||||
# 数据库
|
||||
sqlalchemy==2.0.23
|
||||
asyncpg==0.29.0
|
||||
alembic==1.13.1
|
||||
|
||||
# Redis
|
||||
redis==5.0.1
|
||||
aioredis==2.0.1
|
||||
|
||||
# NATS消息队列
|
||||
nats-py==2.6.0
|
||||
|
||||
# HTTP客户端
|
||||
httpx==0.25.2
|
||||
aiohttp==3.9.1
|
||||
|
||||
# MCP协议
|
||||
mcp==1.0.0
|
||||
json-rpc==1.15.0
|
||||
|
||||
# 工具和实用程序
|
||||
python-multipart==0.0.6
|
||||
python-jose[cryptography]==3.3.0
|
||||
passlib[bcrypt]==1.7.4
|
||||
bcrypt==4.1.2
|
||||
|
||||
# 监控和日志
|
||||
prometheus-client==0.19.0
|
||||
structlog==23.2.0
|
||||
rich==13.7.0
|
||||
|
||||
# 配置管理
|
||||
python-dotenv==1.0.0
|
||||
pyyaml==6.0.1
|
||||
|
||||
# 类型检查和验证
|
||||
typing-extensions==4.8.0
|
||||
annotated-types==0.6.0
|
||||
|
||||
# Agent相关
|
||||
langchain==0.0.350
|
||||
langchain-community==0.0.5
|
||||
openai==1.3.8
|
||||
anthropic==0.7.8
|
||||
|
||||
# API文档处理
|
||||
openapi-parser==1.1.0
|
||||
apispec==6.3.0
|
||||
apispec-webframeworks==0.5.2
|
||||
|
||||
# 开发工具
|
||||
pytest==7.4.3
|
||||
pytest-asyncio==0.21.1
|
||||
black==23.11.0
|
||||
flake8==6.1.0
|
||||
mypy==1.7.1
|
||||
@@ -0,0 +1,346 @@
|
||||
"""
|
||||
Pydantic schemas for API requests and responses
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional, Union
|
||||
from pydantic import BaseModel, Field, validator
|
||||
import uuid
|
||||
|
||||
|
||||
class BaseSchema(BaseModel):
|
||||
"""基础schema类"""
|
||||
class Config:
|
||||
from_attributes = True
|
||||
json_encoders = {
|
||||
datetime: lambda v: v.isoformat(),
|
||||
uuid.UUID: lambda v: str(v),
|
||||
}
|
||||
|
||||
|
||||
# ========== MCP协议相关 ==========
|
||||
|
||||
class MCPRequest(BaseModel):
|
||||
"""MCP请求模型"""
|
||||
jsonrpc: str = "2.0"
|
||||
id: Union[str, int] = Field(default_factory=lambda: str(uuid.uuid4()))
|
||||
method: str
|
||||
params: Optional[Dict[str, Any]] = None
|
||||
|
||||
|
||||
class MCPResponse(BaseModel):
|
||||
"""MCP响应模型"""
|
||||
jsonrpc: str = "2.0"
|
||||
id: Union[str, int]
|
||||
result: Optional[Any] = None
|
||||
error: Optional[Dict[str, Any]] = None
|
||||
|
||||
|
||||
class MCPError(BaseModel):
|
||||
"""MCP错误模型"""
|
||||
code: int
|
||||
message: str
|
||||
data: Optional[Any] = None
|
||||
|
||||
|
||||
# ========== 工具相关 ==========
|
||||
|
||||
class ToolParameter(BaseModel):
|
||||
"""工具参数定义"""
|
||||
name: str
|
||||
type: str
|
||||
description: Optional[str] = None
|
||||
required: bool = True
|
||||
default: Optional[Any] = None
|
||||
enum: Optional[List[Any]] = None
|
||||
|
||||
|
||||
class ToolDefinition(BaseSchema):
|
||||
"""工具定义"""
|
||||
name: str
|
||||
description: str
|
||||
category: Optional[str] = None
|
||||
parameters: List[ToolParameter] = []
|
||||
returns: Optional[Dict[str, Any]] = None
|
||||
|
||||
# API相关
|
||||
endpoint: Optional[str] = None
|
||||
method: str = "POST"
|
||||
headers: Optional[Dict[str, str]] = None
|
||||
|
||||
# 限制信息
|
||||
rate_limit: int = 100
|
||||
timeout: int = 30
|
||||
cost_per_call: float = 0.0
|
||||
|
||||
|
||||
class ToolExecution(BaseModel):
|
||||
"""工具执行请求"""
|
||||
tool_name: str
|
||||
parameters: Dict[str, Any]
|
||||
timeout: Optional[int] = None
|
||||
|
||||
|
||||
class ToolResult(BaseSchema):
|
||||
"""工具执行结果"""
|
||||
success: bool
|
||||
result: Optional[Any] = None
|
||||
error: Optional[str] = None
|
||||
execution_time: float = 0.0
|
||||
cost: float = 0.0
|
||||
|
||||
|
||||
# ========== Agent相关 ==========
|
||||
|
||||
class AgentCreateRequest(BaseModel):
|
||||
"""创建Agent请求"""
|
||||
name: str = Field(..., min_length=1, max_length=100)
|
||||
description: Optional[str] = None
|
||||
role: str = Field(..., min_length=1, max_length=200)
|
||||
goal: str = Field(..., min_length=1)
|
||||
|
||||
tools: List[str] = [] # 工具名称列表
|
||||
config: Dict[str, Any] = {}
|
||||
capabilities: List[str] = []
|
||||
|
||||
owner_id: Optional[uuid.UUID] = None
|
||||
|
||||
@validator('name')
|
||||
def validate_name(cls, v):
|
||||
"""验证Agent名称"""
|
||||
if not v.replace('-', '').replace('_', '').isalnum():
|
||||
raise ValueError('名称只能包含字母、数字、连字符和下划线')
|
||||
return v
|
||||
|
||||
|
||||
class AgentUpdateRequest(BaseModel):
|
||||
"""更新Agent请求"""
|
||||
name: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
role: Optional[str] = None
|
||||
goal: Optional[str] = None
|
||||
tools: Optional[List[str]] = None
|
||||
config: Optional[Dict[str, Any]] = None
|
||||
capabilities: Optional[List[str]] = None
|
||||
|
||||
|
||||
class AgentCard(BaseSchema):
|
||||
"""Agent卡片信息"""
|
||||
id: uuid.UUID
|
||||
name: str
|
||||
description: Optional[str]
|
||||
role: str
|
||||
goal: str
|
||||
|
||||
tools: List[str] = []
|
||||
capabilities: List[str] = []
|
||||
|
||||
# 端点信息
|
||||
endpoints: Dict[str, str] = {}
|
||||
|
||||
# 状态信息
|
||||
status: str = "active"
|
||||
version: str = "1.0.0"
|
||||
|
||||
# 统计信息
|
||||
total_executions: int = 0
|
||||
success_rate: float = 0.0
|
||||
avg_execution_time: float = 0.0
|
||||
|
||||
# 时间信息
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
|
||||
class AgentExecution(BaseModel):
|
||||
"""Agent执行请求"""
|
||||
method: str
|
||||
params: Optional[Dict[str, Any]] = None
|
||||
timeout: Optional[int] = None
|
||||
session_id: Optional[str] = None
|
||||
|
||||
|
||||
class ExecutionResult(BaseSchema):
|
||||
"""执行结果"""
|
||||
execution_id: str
|
||||
success: bool
|
||||
result: Optional[Any] = None
|
||||
error: Optional[str] = None
|
||||
|
||||
# 性能指标
|
||||
execution_time: float = 0.0
|
||||
cpu_usage: float = 0.0
|
||||
memory_usage: float = 0.0
|
||||
network_io: float = 0.0
|
||||
|
||||
# 成本信息
|
||||
eu_consumed: float = 0.0
|
||||
cost: float = 0.0
|
||||
|
||||
# 时间戳
|
||||
started_at: datetime
|
||||
completed_at: Optional[datetime] = None
|
||||
|
||||
|
||||
# ========== 用户相关 ==========
|
||||
|
||||
class UserCreate(BaseModel):
|
||||
"""创建用户请求"""
|
||||
username: str = Field(..., min_length=3, max_length=50)
|
||||
email: str = Field(..., regex=r'^[^@]+@[^@]+\.[^@]+$')
|
||||
password: str = Field(..., min_length=8)
|
||||
full_name: Optional[str] = None
|
||||
|
||||
|
||||
class UserUpdate(BaseModel):
|
||||
"""更新用户请求"""
|
||||
email: Optional[str] = None
|
||||
full_name: Optional[str] = None
|
||||
is_active: Optional[bool] = None
|
||||
|
||||
|
||||
class UserResponse(BaseSchema):
|
||||
"""用户响应"""
|
||||
id: uuid.UUID
|
||||
username: str
|
||||
email: str
|
||||
full_name: Optional[str]
|
||||
is_active: bool
|
||||
is_admin: bool
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
|
||||
class UserLogin(BaseModel):
|
||||
"""用户登录请求"""
|
||||
username: str
|
||||
password: str
|
||||
|
||||
|
||||
class Token(BaseModel):
|
||||
"""访问令牌"""
|
||||
access_token: str
|
||||
token_type: str = "bearer"
|
||||
expires_in: int
|
||||
|
||||
|
||||
# ========== 会话相关 ==========
|
||||
|
||||
class SessionCreate(BaseModel):
|
||||
"""创建会话请求"""
|
||||
context: Optional[Dict[str, Any]] = None
|
||||
metadata: Optional[Dict[str, Any]] = None
|
||||
|
||||
|
||||
class SessionResponse(BaseSchema):
|
||||
"""会话响应"""
|
||||
id: uuid.UUID
|
||||
session_id: str
|
||||
status: str
|
||||
context: Dict[str, Any]
|
||||
metadata: Dict[str, Any]
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
|
||||
# ========== 计费相关 ==========
|
||||
|
||||
class BillingRecord(BaseSchema):
|
||||
"""计费记录"""
|
||||
id: uuid.UUID
|
||||
execution_id: uuid.UUID
|
||||
eu_consumed: float
|
||||
cost: float
|
||||
currency: str
|
||||
|
||||
# 资源详情
|
||||
cpu_time: float
|
||||
memory_max: float
|
||||
network_io: float
|
||||
storage_io: float
|
||||
|
||||
created_at: datetime
|
||||
|
||||
|
||||
class BillingSummary(BaseModel):
|
||||
"""计费汇总"""
|
||||
user_id: uuid.UUID
|
||||
period_start: datetime
|
||||
period_end: datetime
|
||||
|
||||
total_executions: int
|
||||
total_eu_consumed: float
|
||||
total_cost: float
|
||||
currency: str
|
||||
|
||||
# 按服务分类
|
||||
breakdown_by_agent: Dict[str, float] = {}
|
||||
breakdown_by_tool: Dict[str, float] = {}
|
||||
|
||||
|
||||
# ========== API响应包装 ==========
|
||||
|
||||
class APIResponse(BaseModel):
|
||||
"""API响应包装"""
|
||||
success: bool
|
||||
message: str = ""
|
||||
data: Optional[Any] = None
|
||||
timestamp: datetime = Field(default_factory=datetime.utcnow)
|
||||
|
||||
|
||||
class PaginatedResponse(BaseModel):
|
||||
"""分页响应"""
|
||||
items: List[Any]
|
||||
total: int
|
||||
page: int
|
||||
page_size: int
|
||||
has_next: bool
|
||||
has_prev: bool
|
||||
|
||||
|
||||
# ========== 系统状态 ==========
|
||||
|
||||
class HealthCheck(BaseModel):
|
||||
"""健康检查响应"""
|
||||
status: str
|
||||
timestamp: datetime
|
||||
services: Dict[str, str]
|
||||
version: str = "1.0.0"
|
||||
|
||||
|
||||
class SystemMetrics(BaseModel):
|
||||
"""系统指标"""
|
||||
timestamp: datetime
|
||||
|
||||
# 服务指标
|
||||
active_agents: int
|
||||
total_executions: int
|
||||
success_rate: float
|
||||
avg_response_time: float
|
||||
|
||||
# 资源指标
|
||||
cpu_usage: float
|
||||
memory_usage: float
|
||||
disk_usage: float
|
||||
|
||||
# 业务指标
|
||||
daily_active_users: int
|
||||
total_eu_consumed: float
|
||||
total_cost: float
|
||||
|
||||
|
||||
# ========== 错误响应 ==========
|
||||
|
||||
class ErrorResponse(BaseModel):
|
||||
"""错误响应"""
|
||||
error: str
|
||||
message: str
|
||||
details: Optional[Dict[str, Any]] = None
|
||||
timestamp: datetime = Field(default_factory=datetime.utcnow)
|
||||
|
||||
|
||||
class ValidationError(BaseModel):
|
||||
"""验证错误"""
|
||||
field: str
|
||||
message: str
|
||||
invalid_value: Optional[Any] = None
|
||||
@@ -0,0 +1,35 @@
|
||||
FROM python:3.11-slim
|
||||
|
||||
# 设置工作目录
|
||||
WORKDIR /app
|
||||
|
||||
# 安装系统依赖
|
||||
RUN apt-get update && apt-get install -y \
|
||||
curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# 安装LiteLLM
|
||||
RUN pip install --no-cache-dir \
|
||||
litellm[proxy]==1.17.0 \
|
||||
redis==5.0.1 \
|
||||
prometheus-client==0.19.0
|
||||
|
||||
# 复制配置文件
|
||||
COPY config/ ./config/
|
||||
|
||||
# 创建logs目录
|
||||
RUN mkdir -p logs
|
||||
|
||||
# 设置环境变量
|
||||
ENV LITELLM_MASTER_KEY=sk-taiji-master-key
|
||||
ENV LITELLM_CONFIG_PATH=/app/config/litellm.yaml
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 4000
|
||||
|
||||
# 健康检查
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||
CMD curl -f http://localhost:4000/health || exit 1
|
||||
|
||||
# 启动LiteLLM代理
|
||||
CMD ["python", "-m", "litellm", "--config", "/app/config/litellm.yaml", "--port", "4000", "--host", "0.0.0.0"]
|
||||
@@ -0,0 +1,296 @@
|
||||
# LiteLLM 网关配置
|
||||
# taiji-AI-PAD 模型治理层配置
|
||||
|
||||
# 基础设置
|
||||
general_settings:
|
||||
master_key: "sk-taiji-master-key"
|
||||
database_url: "postgresql://taiji_user:taiji_pass@postgres:5432/taiji_db"
|
||||
|
||||
# 日志设置
|
||||
set_verbose: true
|
||||
json_logs: true
|
||||
log_raw_request_response: false # 生产环境设为false
|
||||
|
||||
# 缓存设置
|
||||
redis_host: "redis"
|
||||
redis_port: 6379
|
||||
redis_password: null
|
||||
|
||||
# 速率限制
|
||||
max_budget: 1000.0 # 美元
|
||||
budget_duration: "30d"
|
||||
|
||||
# 回调和监控
|
||||
success_callback: ["langfuse"]
|
||||
failure_callback: ["langfuse"]
|
||||
|
||||
# 安全设置
|
||||
allowed_ips: ["127.0.0.1", "172.20.0.0/16"] # Docker网络
|
||||
|
||||
# 模型配置
|
||||
model_list:
|
||||
# OpenAI 模型组
|
||||
- model_name: "gpt-3.5-turbo"
|
||||
litellm_params:
|
||||
model: "openai/gpt-3.5-turbo"
|
||||
api_key: "os.environ/OPENAI_API_KEY"
|
||||
max_tokens: 4000
|
||||
temperature: 0.7
|
||||
model_info:
|
||||
mode: "chat"
|
||||
supports_function_calling: true
|
||||
supports_vision: false
|
||||
max_input_tokens: 16385
|
||||
max_output_tokens: 4096
|
||||
input_cost_per_token: 0.0000015
|
||||
output_cost_per_token: 0.000002
|
||||
|
||||
- model_name: "gpt-4"
|
||||
litellm_params:
|
||||
model: "openai/gpt-4"
|
||||
api_key: "os.environ/OPENAI_API_KEY"
|
||||
max_tokens: 8000
|
||||
temperature: 0.7
|
||||
model_info:
|
||||
mode: "chat"
|
||||
supports_function_calling: true
|
||||
supports_vision: false
|
||||
max_input_tokens: 8192
|
||||
max_output_tokens: 8192
|
||||
input_cost_per_token: 0.00003
|
||||
output_cost_per_token: 0.00006
|
||||
|
||||
- model_name: "gpt-4-turbo"
|
||||
litellm_params:
|
||||
model: "openai/gpt-4-turbo-preview"
|
||||
api_key: "os.environ/OPENAI_API_KEY"
|
||||
max_tokens: 4000
|
||||
temperature: 0.7
|
||||
model_info:
|
||||
mode: "chat"
|
||||
supports_function_calling: true
|
||||
supports_vision: true
|
||||
max_input_tokens: 128000
|
||||
max_output_tokens: 4096
|
||||
input_cost_per_token: 0.00001
|
||||
output_cost_per_token: 0.00003
|
||||
|
||||
# Anthropic 模型组
|
||||
- model_name: "claude-3-haiku"
|
||||
litellm_params:
|
||||
model: "anthropic/claude-3-haiku-20240307"
|
||||
api_key: "os.environ/ANTHROPIC_API_KEY"
|
||||
max_tokens: 4000
|
||||
temperature: 0.7
|
||||
model_info:
|
||||
mode: "chat"
|
||||
supports_function_calling: true
|
||||
supports_vision: true
|
||||
max_input_tokens: 200000
|
||||
max_output_tokens: 4096
|
||||
input_cost_per_token: 0.00000025
|
||||
output_cost_per_token: 0.00000125
|
||||
|
||||
- model_name: "claude-3-sonnet"
|
||||
litellm_params:
|
||||
model: "anthropic/claude-3-sonnet-20240229"
|
||||
api_key: "os.environ/ANTHROPIC_API_KEY"
|
||||
max_tokens: 4000
|
||||
temperature: 0.7
|
||||
model_info:
|
||||
mode: "chat"
|
||||
supports_function_calling: true
|
||||
supports_vision: true
|
||||
max_input_tokens: 200000
|
||||
max_output_tokens: 4096
|
||||
input_cost_per_token: 0.000003
|
||||
output_cost_per_token: 0.000015
|
||||
|
||||
- model_name: "claude-3-opus"
|
||||
litellm_params:
|
||||
model: "anthropic/claude-3-opus-20240229"
|
||||
api_key: "os.environ/ANTHROPIC_API_KEY"
|
||||
max_tokens: 4000
|
||||
temperature: 0.7
|
||||
model_info:
|
||||
mode: "chat"
|
||||
supports_function_calling: true
|
||||
supports_vision: true
|
||||
max_input_tokens: 200000
|
||||
max_output_tokens: 4096
|
||||
input_cost_per_token: 0.000015
|
||||
output_cost_per_token: 0.000075
|
||||
|
||||
# 本地/开源模型(如果可用)
|
||||
- model_name: "llama-3-8b"
|
||||
litellm_params:
|
||||
model: "ollama/llama3"
|
||||
api_base: "http://ollama:11434"
|
||||
max_tokens: 2000
|
||||
model_info:
|
||||
mode: "chat"
|
||||
supports_function_calling: false
|
||||
supports_vision: false
|
||||
max_input_tokens: 8192
|
||||
max_output_tokens: 2048
|
||||
input_cost_per_token: 0.0 # 本地模型无成本
|
||||
output_cost_per_token: 0.0
|
||||
|
||||
# 路由器配置
|
||||
router_settings:
|
||||
routing_strategy: "least-busy" # 路由策略: least-busy, round-robin, latency-based
|
||||
allowed_fails: 3
|
||||
cooldown_time: 30
|
||||
retry_after: 10
|
||||
|
||||
# 模型组定义
|
||||
model_group_configs:
|
||||
- group_name: "gpt-3.5-group"
|
||||
models:
|
||||
- model_name: "gpt-3.5-turbo"
|
||||
weight: 1.0
|
||||
|
||||
- group_name: "gpt-4-group"
|
||||
models:
|
||||
- model_name: "gpt-4"
|
||||
weight: 0.7
|
||||
- model_name: "gpt-4-turbo"
|
||||
weight: 0.3
|
||||
|
||||
- group_name: "claude-group"
|
||||
models:
|
||||
- model_name: "claude-3-haiku"
|
||||
weight: 0.5
|
||||
- model_name: "claude-3-sonnet"
|
||||
weight: 0.3
|
||||
- model_name: "claude-3-opus"
|
||||
weight: 0.2
|
||||
|
||||
- group_name: "fast-models"
|
||||
models:
|
||||
- model_name: "gpt-3.5-turbo"
|
||||
weight: 0.4
|
||||
- model_name: "claude-3-haiku"
|
||||
weight: 0.4
|
||||
- model_name: "llama-3-8b"
|
||||
weight: 0.2
|
||||
|
||||
- group_name: "premium-models"
|
||||
models:
|
||||
- model_name: "gpt-4-turbo"
|
||||
weight: 0.4
|
||||
- model_name: "claude-3-opus"
|
||||
weight: 0.3
|
||||
- model_name: "claude-3-sonnet"
|
||||
weight: 0.3
|
||||
|
||||
# 用户和权限配置
|
||||
litellm_settings:
|
||||
# API密钥管理
|
||||
api_keys:
|
||||
- key: "sk-taiji-mcp-server"
|
||||
models: ["gpt-3.5-turbo", "gpt-4", "claude-3-haiku", "claude-3-sonnet"]
|
||||
max_budget: 100.0
|
||||
budget_duration: "1d"
|
||||
metadata:
|
||||
user_id: "mcp-server"
|
||||
service: "mcp-server"
|
||||
|
||||
- key: "sk-taiji-data-ingestion"
|
||||
models: ["gpt-3.5-turbo", "claude-3-haiku", "llama-3-8b"]
|
||||
max_budget: 50.0
|
||||
budget_duration: "1d"
|
||||
metadata:
|
||||
user_id: "data-ingestion"
|
||||
service: "data-ingestion"
|
||||
|
||||
- key: "sk-taiji-agent-dev"
|
||||
models: ["gpt-3.5-group", "claude-group", "fast-models"]
|
||||
max_budget: 20.0
|
||||
budget_duration: "1d"
|
||||
metadata:
|
||||
user_id: "agent-development"
|
||||
service: "agent-development"
|
||||
|
||||
- key: "sk-taiji-premium"
|
||||
models: ["premium-models", "gpt-4-group"]
|
||||
max_budget: 200.0
|
||||
budget_duration: "1d"
|
||||
metadata:
|
||||
user_id: "premium-user"
|
||||
service: "premium"
|
||||
|
||||
# 回调配置
|
||||
callbacks:
|
||||
# 成功回调
|
||||
success_callback:
|
||||
- callback_name: "langfuse"
|
||||
callback_type: "success"
|
||||
callback_vars:
|
||||
langfuse_public_key: "os.environ/LANGFUSE_PUBLIC_KEY"
|
||||
langfuse_secret_key: "os.environ/LANGFUSE_SECRET_KEY"
|
||||
langfuse_host: "os.environ/LANGFUSE_HOST"
|
||||
|
||||
# 失败回调
|
||||
failure_callback:
|
||||
- callback_name: "langfuse"
|
||||
callback_type: "failure"
|
||||
callback_vars:
|
||||
langfuse_public_key: "os.environ/LANGFUSE_PUBLIC_KEY"
|
||||
langfuse_secret_key: "os.environ/LANGFUSE_SECRET_KEY"
|
||||
langfuse_host: "os.environ/LANGFUSE_HOST"
|
||||
|
||||
# 监控和指标
|
||||
monitoring:
|
||||
prometheus_port: 4001
|
||||
health_check_interval: 30
|
||||
|
||||
# 自定义指标
|
||||
custom_metrics:
|
||||
- name: "taiji_model_requests_total"
|
||||
type: "counter"
|
||||
description: "Total model requests"
|
||||
labels: ["model", "user_id", "status"]
|
||||
|
||||
- name: "taiji_model_latency"
|
||||
type: "histogram"
|
||||
description: "Model response latency"
|
||||
labels: ["model", "user_id"]
|
||||
|
||||
- name: "taiji_model_cost"
|
||||
type: "gauge"
|
||||
description: "Model cost tracking"
|
||||
labels: ["model", "user_id"]
|
||||
|
||||
# 错误处理
|
||||
error_handling:
|
||||
# 重试配置
|
||||
retry_policy:
|
||||
max_retries: 3
|
||||
retry_delay: 1.0
|
||||
exponential_backoff: true
|
||||
|
||||
# 超时设置
|
||||
timeout:
|
||||
request_timeout: 60
|
||||
|
||||
# 回退策略
|
||||
fallback:
|
||||
enabled: true
|
||||
fallback_models:
|
||||
"gpt-4": ["gpt-4-turbo", "claude-3-sonnet"]
|
||||
"claude-3-opus": ["claude-3-sonnet", "gpt-4"]
|
||||
"gpt-3.5-turbo": ["claude-3-haiku", "llama-3-8b"]
|
||||
|
||||
# 日志配置
|
||||
logging:
|
||||
level: "INFO"
|
||||
format: "json"
|
||||
|
||||
# 请求日志
|
||||
log_requests: true
|
||||
log_responses: false # 生产环境关闭
|
||||
|
||||
# 敏感信息过滤
|
||||
redact_messages_in_logs: true
|
||||
redact_user_api_key_info: true
|
||||
Reference in New Issue
Block a user