核心概念

配置系统 (Configuration System)

Aster 提供了灵活的配置系统,支持 YAML 配置文件、环境变量展开、配置合并和验证。配置系统使得 Agent 的创建和管理更加简单和可维护。

配置系统 (Configuration System)

Aster 提供了灵活的配置系统,支持 YAML 配置文件、环境变量展开、配置合并和验证。配置系统使得 Agent 的创建和管理更加简单和可维护。

概述

配置系统的核心功能:

  • YAML 配置文件:使用 YAML 格式定义 Agent 配置
  • 环境变量展开:支持在配置中使用环境变量
  • 配置合并:支持多个配置文件的合并
  • 配置验证:自动验证配置的完整性和正确性
  • 类型安全:强类型配置结构
  • 默认值:合理的默认配置

配置结构

AgentConfig

Agent 的完整配置结构:

type AgentConfig struct {
    // 基础信息
    AgentID         string
    TemplateID      string        // 必需
    TemplateVersion string

    // 模型配置
    ModelConfig *ModelConfig

    // 工具和中间件
    Tools       []string
    Middlewares []string

    // 沙箱配置
    Sandbox *SandboxConfig

    // 存储配置
    Store *StoreConfig

    // 多租户配置
    Multitenancy *MultitenancyConfig

    // 记忆系统配置
    Memory *MemoryConfig

    // 其他配置
    Metadata map[string]any
}

ModelConfig

模型提供商配置:

type ModelConfig struct {
    Provider      string        // "anthropic", "openai", etc.
    Model         string        // 模型名称
    APIKey        string        // API 密钥
    BaseURL       string        // 自定义 API 端点
    ExecutionMode ExecutionMode // streaming/non-streaming/auto
}

基本使用

1. 创建配置文件

创建 agent.yaml 文件:

# agent.yaml
template_id: "general-assistant"
template_version: "1.0.0"

model_config:
  provider: "anthropic"
  model: "claude-3-5-sonnet-20241022"
  api_key: "${ANTHROPIC_API_KEY}"
  execution_mode: "streaming"

tools:
  - "read_file"
  - "write_file"
  - "bash"

middlewares:
  - "logging"
  - "rate_limit"

metadata:
  environment: "production"
  team: "platform"

2. 加载配置

import (
    "github.com/astercloud/aster/pkg/config"
)

// 创建配置加载器
loader := config.NewLoader()

// 加载配置
agentConfig, err := loader.LoadAgentConfig("agent.yaml")
if err != nil {
    return err
}

// 使用配置创建 Agent
agent, err := agent.NewAgent(agentConfig)
if err != nil {
    return err
}

环境变量展开

配置系统支持多种环境变量语法:

基本语法

# 简单变量引用
api_key: "${API_KEY}"

# 或使用 $ 语法
api_key: "$API_KEY"

# 带默认值
api_key: "${API_KEY:-sk-default-key}"

# 必需变量(如果不存在会报错)
api_key: "${API_KEY:?API key is required}"

示例

model_config:
  provider: "anthropic"
  model: "${MODEL_NAME:-claude-3-5-sonnet-20241022}"
  api_key: "${ANTHROPIC_API_KEY:?ANTHROPIC_API_KEY must be set}"
  base_url: "${API_BASE_URL:-https://api.anthropic.com}"

database:
  host: "${DB_HOST:-localhost}"
  port: "${DB_PORT:-5432}"
  name: "${DB_NAME}"
  user: "${DB_USER}"
  password: "${DB_PASSWORD:?Database password is required}"

环境变量前缀

使用前缀来组织环境变量:

// 使用 APP_ 前缀
loader := config.NewLoader(
    config.WithEnvPrefix("APP_"),
)

// 配置文件中使用不带前缀的名称
// api_key: "${API_KEY}"
// 实际会查找 APP_API_KEY 环境变量

自定义变量

除了环境变量,还可以提供自定义变量:

loader := config.NewLoader(
    config.WithVariables(map[string]string{
        "ENVIRONMENT": "production",
        "REGION":      "us-west-2",
        "VERSION":     "1.0.0",
    }),
)

// 配置文件中使用
// metadata:
//   environment: "${ENVIRONMENT}"
//   region: "${REGION}"

配置合并

支持多个配置文件的合并,用于不同环境或场景:

基础配置 + 环境配置

// 加载基础配置
baseConfig, err := loader.LoadAgentConfig("base.yaml")
if err != nil {
    return err
}

// 加载环境特定配置
prodConfig, err := loader.LoadAgentConfig("production.yaml")
if err != nil {
    return err
}

// 合并配置(后面的配置会覆盖前面的)
finalConfig := config.MergeConfigs(baseConfig, prodConfig)

示例配置文件

base.yaml - 基础配置:

template_id: "general-assistant"

model_config:
  provider: "anthropic"
  model: "claude-3-5-sonnet-20241022"

tools:
  - "read_file"
  - "write_file"

metadata:
  version: "1.0.0"

production.yaml - 生产环境配置:

model_config:
  api_key: "${PROD_API_KEY}"
  base_url: "https://api.production.example.com"

metadata:
  environment: "production"
  log_level: "info"

development.yaml - 开发环境配置:

model_config:
  api_key: "${DEV_API_KEY}"

tools:
  - "read_file"
  - "write_file"
  - "bash"
  - "debug_tool"

metadata:
  environment: "development"
  log_level: "debug"

多层合并

// 合并多个配置
finalConfig := config.MergeConfigs(
    baseConfig,
    envConfig,
    userConfig,
    overrideConfig,
)

配置验证

配置加载时会自动验证:

必需字段验证

// template_id 是必需的
agentConfig := &types.AgentConfig{
    // 缺少 template_id
    ModelConfig: &types.ModelConfig{
        Provider: "anthropic",
        Model:    "claude-3-5-sonnet-20241022",
    },
}

// 验证会失败
err := loader.validateAgentConfig(agentConfig)
// err: "template_id is required"

ModelConfig 验证

// Provider 和 Model 都是必需的
modelConfig := &types.ModelConfig{
    Provider: "anthropic",
    // 缺少 Model
}

// 验证会失败
// err: "model is required when model_config is provided"

多租户配置验证

// 启用多租户时必须提供 org_id 或 tenant_id
multitenancy := &types.MultitenancyConfig{
    Enabled: true,
    // 缺少 OrgID 和 TenantID
}

// 验证会失败
// err: "org_id or tenant_id is required when multitenancy is enabled"

配置选项

Loader 选项

loader := config.NewLoader(
    // 启用/禁用环境变量展开
    config.WithEnvExpansion(true),

    // 设置环境变量前缀
    config.WithEnvPrefix("ASTER_"),

    // 提供自定义变量
    config.WithVariables(map[string]string{
        "APP_NAME": "my-agent",
        "VERSION":  "1.0.0",
    }),
)

从字符串加载

configYAML := `
template_id: "test-agent"
model_config:
  provider: "anthropic"
  model: "claude-3-5-sonnet-20241022"
`

var agentConfig types.AgentConfig
err := loader.LoadFromString(configYAML, &agentConfig)

完整配置示例

生产环境配置

# production.yaml
template_id: "production-assistant"
template_version: "2.0.0"
agent_id: "${AGENT_ID}"

model_config:
  provider: "anthropic"
  model: "claude-3-5-sonnet-20241022"
  api_key: "${ANTHROPIC_API_KEY:?API key is required}"
  base_url: "${API_BASE_URL:-https://api.anthropic.com}"
  execution_mode: "streaming"

tools:
  - "read_file"
  - "write_file"
  - "bash"
  - "web_search"

middlewares:
  - "logging"
  - "rate_limit"
  - "auth"
  - "metrics"

middleware_config:
  rate_limit:
    requests_per_minute: 60
    burst: 10
  logging:
    level: "info"
    format: "json"

sandbox:
  enabled: true
  kind: "docker"
  timeout_seconds: 300

store:
  type: "postgres"
  connection_string: "${DATABASE_URL:?Database URL is required}"

multitenancy:
  enabled: true
  org_id: "${ORG_ID}"
  tenant_id: "${TENANT_ID}"

memory:
  enabled: true
  vector_store:
    type: "weaviate"
    url: "${WEAVIATE_URL:-http://localhost:8080}"
    api_key: "${WEAVIATE_API_KEY}"
  embedder:
    provider: "openai"
    model: "text-embedding-3-small"
    api_key: "${OPENAI_API_KEY}"

metadata:
  environment: "production"
  region: "${AWS_REGION:-us-west-2}"
  version: "${APP_VERSION}"
  team: "platform"

开发环境配置

# development.yaml
template_id: "dev-assistant"
agent_id: "dev-agent-001"

model_config:
  provider: "anthropic"
  model: "claude-3-5-sonnet-20241022"
  api_key: "${ANTHROPIC_API_KEY}"
  execution_mode: "streaming"

tools:
  - "read_file"
  - "write_file"
  - "bash"
  - "debug_tool"

middlewares:
  - "logging"

middleware_config:
  logging:
    level: "debug"
    format: "text"

sandbox:
  enabled: false

store:
  type: "sqlite"
  path: "./dev.db"

memory:
  enabled: true
  vector_store:
    type: "weaviate"
    url: "http://localhost:8080"
  embedder:
    provider: "openai"
    model: "text-embedding-3-small"
    api_key: "${OPENAI_API_KEY}"

metadata:
  environment: "development"
  debug: true

最佳实践

1. 使用环境变量存储敏感信息

# 好的做法:敏感信息使用环境变量
model_config:
  api_key: "${ANTHROPIC_API_KEY}"

database:
  password: "${DB_PASSWORD}"

# 避免:硬编码敏感信息
# api_key: "sk-ant-api03-..."

2. 提供合理的默认值

# 为可选配置提供默认值
model_config:
  model: "${MODEL_NAME:-claude-3-5-sonnet-20241022}"
  base_url: "${API_BASE_URL:-https://api.anthropic.com}"

database:
  host: "${DB_HOST:-localhost}"
  port: "${DB_PORT:-5432}"

3. 使用配置文件分层

config/
  ├── base.yaml           # 基础配置
  ├── development.yaml    # 开发环境
  ├── staging.yaml        # 预发布环境
  └── production.yaml     # 生产环境
// 根据环境加载配置
env := os.Getenv("ENVIRONMENT")
baseConfig, _ := loader.LoadAgentConfig("config/base.yaml")
envConfig, _ := loader.LoadAgentConfig(fmt.Sprintf("config/%s.yaml", env))
finalConfig := config.MergeConfigs(baseConfig, envConfig)

4. 验证必需的环境变量

# 使用 :? 语法确保必需变量存在
model_config:
  api_key: "${ANTHROPIC_API_KEY:?ANTHROPIC_API_KEY environment variable is required}"

database:
  url: "${DATABASE_URL:?DATABASE_URL must be set}"

5. 使用有意义的配置键名

# 好的做法:清晰的键名
model_config:
  provider: "anthropic"
  model: "claude-3-5-sonnet-20241022"
  api_key: "${ANTHROPIC_API_KEY}"

# 避免:模糊的键名
# config:
#   p: "anthropic"
#   m: "claude-3-5-sonnet-20241022"

6. 文档化配置选项

# agent.yaml

# Agent 模板标识符(必需)
template_id: "general-assistant"

# 模板版本(可选)
template_version: "1.0.0"

# 模型配置
model_config:
  # 提供商:anthropic, openai, gemini
  provider: "anthropic"

  # 模型名称
  model: "claude-3-5-sonnet-20241022"

  # API 密钥(从环境变量读取)
  api_key: "${ANTHROPIC_API_KEY}"

7. 使用配置验证

// 加载后立即验证
agentConfig, err := loader.LoadAgentConfig("agent.yaml")
if err != nil {
    log.Fatalf("配置加载失败: %v", err)
}

// 配置已自动验证,可以安全使用
agent, err := agent.NewAgent(agentConfig)

配置文件位置

默认位置

// 项目配置文件
projectConfig := config.ProjectConfigFile()
// 返回: ./.aster/config.yaml

// 用户配置目录
configDir := config.ConfigDir()
// 返回: ~/.config/aster/

// 数据目录
dataDir := config.DataDir()
// 返回: ~/.local/share/aster/

解析配置文件路径

// 自动查找配置文件
configPath := config.ResolveConfigFile("agent.yaml")
// 查找顺序:
// 1. ./agent.yaml
// 2. ./.aster/agent.yaml
// 3. ~/.config/aster/agent.yaml

编程式配置

除了 YAML 文件,也可以通过代码创建配置:

agentConfig := &types.AgentConfig{
    TemplateID:      "code-assistant",
    TemplateVersion: "1.0.0",
    ModelConfig: &types.ModelConfig{
        Provider: "anthropic",
        Model:    "claude-3-5-sonnet-20241022",
        APIKey:   os.Getenv("ANTHROPIC_API_KEY"),
    },
    Tools: []string{
        "read_file",
        "write_file",
        "bash",
    },
    Metadata: map[string]any{
        "environment": "production",
        "version":     "1.0.0",
    },
}

agent, err := agent.NewAgent(agentConfig)

配置热重载

实现配置热重载:

import (
    "github.com/fsnotify/fsnotify"
)

func watchConfig(configPath string, onReload func(*types.AgentConfig)) error {
    watcher, err := fsnotify.NewWatcher()
    if err != nil {
        return err
    }
    defer watcher.Close()

    err = watcher.Add(configPath)
    if err != nil {
        return err
    }

    loader := config.NewLoader()

    for {
        select {
        case event := <-watcher.Events:
            if event.Op&fsnotify.Write == fsnotify.Write {
                // 重新加载配置
                newConfig, err := loader.LoadAgentConfig(configPath)
                if err != nil {
                    log.Printf("重载配置失败: %v", err)
                    continue
                }
                onReload(newConfig)
            }
        case err := <-watcher.Errors:
            log.Printf("配置监听错误: %v", err)
        }
    }
}

故障排查

配置加载失败

agentConfig, err := loader.LoadAgentConfig("agent.yaml")
if err != nil {
    // 检查文件是否存在
    if os.IsNotExist(err) {
        log.Fatal("配置文件不存在")
    }

    // 检查 YAML 语法错误
    if strings.Contains(err.Error(), "yaml") {
        log.Fatal("YAML 语法错误:", err)
    }

    // 检查验证错误
    if strings.Contains(err.Error(), "validate") {
        log.Fatal("配置验证失败:", err)
    }
}

环境变量未设置

# 使用 :? 语法会在变量未设置时报错
api_key: "${API_KEY:?API_KEY environment variable must be set}"

# 或提供默认值
api_key: "${API_KEY:-default-key}"

调试配置合并

base := loadConfig("base.yaml")
env := loadConfig("production.yaml")

// 打印合并前的配置
log.Printf("Base config: %+v", base)
log.Printf("Env config: %+v", env)

// 合并
final := config.MergeConfigs(base, env)

// 打印合并后的配置
log.Printf("Final config: %+v", final)

相关资源