Architecture

HTTP 层架构 (cmd/aster)

HTTP 层架构 (cmd/aster)

设计原则: 核心 SDK 与 HTTP 框架解耦 最后更新: 2024年11月17日


架构设计

核心原则

分层架构:

┌─────────────────────────────────────┐
│   cmd/aster (CLI 工具)           │
│   - 使用 Gin 框架                    │
│   - HTTP Server 实现                 │
│   - 子命令实现                        │
└──────────────┬──────────────────────┘
               │ 依赖
┌──────────────▼──────────────────────┐
│   pkg/* (核心 SDK)                  │
│   - 零 HTTP 框架依赖                 │
│   - 纯 Go 标准库 + 必要第三方库      │
│   - 可被任何项目安全导入             │
└─────────────────────────────────────┘

依赖隔离:

  • cmd/* → 可以依赖任何框架(Gin, Chi, Echo 等)
  • pkg/* → 只能依赖标准库和核心第三方库(不包括 HTTP 框架)

目录结构

cmd/aster/
├── main.go                      # 入口,子命令路由
├── serve.go                     # HTTP Server (使用 Gin)
├── http_handlers.go             # Gin HTTP handlers
├── agent_handlers.go            # Agent API handlers
├── memory_handlers.go           # Memory API handlers
├── memory_handlers_extended.go  # Semantic Memory handlers
├── session_handlers.go          # Session API handlers
├── workflow_handlers.go         # Workflow API handlers
├── tool_handlers.go             # Tool API handlers
├── middleware_handlers.go       # Middleware API handlers
├── telemetry_handlers.go        # Telemetry API handlers
├── eval_handlers.go             # Eval API handlers
├── mcp_handlers.go              # MCP API handlers
├── mcp_serve.go                 # MCP 服务子命令
├── subagent.go                  # Subagent 子命令
└── eval.go                      # Eval 子命令

职责:

  • CLI 工具入口
  • HTTP Server 实现(使用 Gin)
  • 子命令实现
  • 不作为库被导入

API 端点设计

100+ REST API 端点

📊 核心业务 (40+)
├── POST/GET/DELETE  /v1/agents
├── POST             /v1/agents/chat
├── POST             /v1/agents/chat/stream
├── GET/PUT          /v1/memory/working
├── POST             /v1/memory/semantic/search
├── POST/GET/DELETE  /v1/sessions
├── POST/GET/DELETE  /v1/workflows
└── POST             /v1/workflows/{id}/execute

🛠️ 工具和技能 (20+)
├── POST/GET/DELETE  /v1/tools
├── POST             /v1/tools/{id}/execute
├── POST/GET         /v1/skills
└── POST             /v1/skills/install

🔌 生态集成 (15+)
├── POST/GET/DELETE  /v1/mcp/servers
├── POST             /v1/mcp/servers/{id}/connect
├── GET              /v1/router/models
└── POST             /v1/sandbox/execute

📈 可观测性 (15+)
├── POST             /v1/telemetry/metrics
├── POST             /v1/telemetry/traces
├── GET              /v1/telemetry/health
├── POST             /v1/evals/text
└── GET              /v1/evals

⚙️ 管理功能 (10+)
├── POST/GET/DELETE  /v1/middlewares
├── POST/GET/DELETE  /v1/providers
├── POST/GET/DELETE  /v1/templates
└── GET              /v1/security/policies

使用方式

作为 CLI 工具使用

# 编译
go build -o aster ./cmd/aster

# 运行 HTTP Server(使用 Gin)
./aster serve --addr :8080

# 运行其他子命令
./aster mcp-serve
./aster subagent --type=Plan
./aster eval

自己实现 HTTP 层(用任何框架)

使用 Gin

package main

import (
    "github.com/gin-gonic/gin"
    "github.com/astercloud/aster/pkg/agent"
)

func main() {
    r := gin.Default()

    // 使用 aster 核心功能
    r.POST("/chat", func(c *gin.Context) {
        // 创建 Agent 并调用
        ag, _ := agent.Create(...)
        result, _ := ag.Chat(...)
        c.JSON(200, result)
    })

    r.Run(":8080")
}

使用 Echo

package main

import (
    "github.com/labstack/echo/v4"
    "github.com/astercloud/aster/pkg/agent"
)

func main() {
    e := echo.New()

    e.POST("/chat", func(c echo.Context) error {
        ag, _ := agent.Create(...)
        result, _ := ag.Chat(...)
        return c.JSON(200, result)
    })

    e.Start(":8080")
}

使用标准库

package main

import (
    "net/http"
    "github.com/astercloud/aster/pkg/agent"
)

func main() {
    http.HandleFunc("/chat", func(w http.ResponseWriter, r *http.Request) {
        ag, _ := agent.Create(...)
        result, _ := ag.Chat(...)
        json.NewEncoder(w).Encode(result)
    })

    http.ListenAndServe(":8080", nil)
}

响应格式

统一响应格式

{
  "success": true,
  "data": { ... }
}
{
  "success": false,
  "error": {
    "code": "bad_request",
    "message": "详细错误信息"
  }
}

流式响应(SSE)

event: thinking
data: {"content": "我正在思考..."}

event: text_chunk
data: {"delta": "Hello"}

event: tool_start
data: {"tool": "read_file", "args": {...}}

event: tool_end
data: {"tool": "read_file", "result": {...}}

event: done
data: {"final_text": "Hello, world!"}

依赖管理

go.mod 设计

module github.com/astercloud/aster

go 1.21

require (
    // 核心依赖(所有用户都会引入)
    github.com/google/uuid v1.6.0
    // ... 其他核心依赖
)

require (
    // HTTP 框架依赖(只在 cmd/aster 中使用)
    // 用户导入 pkg/* 时不会引入这些依赖
    github.com/gin-gonic/gin v1.11.0
)

依赖检查

# 检查 pkg 下是否有 Gin 依赖
grep -r "gin-gonic/gin" pkg/

# 应该返回空(pkg 下不能有 Gin 依赖)

约束和规则

✅ 允许

在 cmd/aster/ 中:

  • ✅ 使用 Gin
  • ✅ 使用任何 HTTP 框架
  • ✅ 使用任何 CLI 库

在 pkg/ 中:

  • ✅ 使用标准库(net/http 用于类型定义)
  • ✅ 使用核心第三方库(UUID, 日志等)
  • ✅ 定义接口而不是实现 HTTP handler

❌ 禁止

在 pkg/ 中:

  • ❌ 导入 github.com/gin-gonic/gin
  • ❌ 导入 github.com/labstack/echo
  • ❌ 导入 github.com/go-chi/chi
  • ❌ 导入任何 HTTP 框架

最佳实践

1. 作为 SDK 作者

// ✅ 好的做法(在 pkg/ 中)
package agent

// 定义接口
type Agent interface {
    Chat(ctx context.Context, input string) (*Result, error)
}

// 实现逻辑,不依赖 HTTP 框架
func Create(ctx context.Context, config *Config) (Agent, error) {
    // ...
}
// ❌ 坏的做法(在 pkg/ 中)
package agent

import "github.com/gin-gonic/gin"  // ❌ 不要这样!

func HandleChat(c *gin.Context) {  // ❌ 不要这样!
    // ...
}

2. 作为 SDK 用户

// ✅ 安全导入
import (
    "github.com/astercloud/aster/pkg/agent"
    "github.com/astercloud/aster/pkg/memory"
    // 不会引入 Gin!
)

// ✅ 自己选择框架
import "github.com/gin-gonic/gin"     // 你的项目可以用 Gin
// 或
import "github.com/labstack/echo/v4"  // 或者 Echo
// 或
import "net/http"                     // 或者标准库

对比

方面旧架构新架构
HTTP 框架pkg 中使用 Gin只在 cmd 中使用
SDK 导入会引入 Gin 依赖不会引入 Gin
灵活性用户被强制使用 Gin用户可用任何框架
兼容性可能版本冲突完全隔离
维护性pkg 膨胀清晰分层

总结

核心思想

SDK 核心不应该依赖任何 HTTP 框架,让用户自由选择

收益

  1. ✅ 用户可以用任何 HTTP 框架
  2. ✅ 避免依赖冲突
  3. ✅ 更小的依赖树
  4. ✅ 更好的模块化
  5. ✅ 更容易维护

原则

  • 核心在 pkg/:纯粹的业务逻辑
  • HTTP 在 cmd/:具体的实现细节
  • 用户自由:想用什么框架就用什么

版本: v2.0 最后更新: 2024年11月17日