乐于分享
好东西不私藏

GoClaw:当 OpenClaw 用 Go 重写,企业级 AI Agent 的安全感终于来了

GoClaw:当 OpenClaw 用 Go 重写,企业级 AI Agent 的安全感终于来了

点击上方蓝色“Go语言中文网”关注,每天一起学 Go

OpenClaw 60 天狂飙 250K Stars,成为 GitHub 史上增长最快项目。但它的 TypeScript 基因让企业用户心有顾虑。GoClaw 用 Go 重写了整个架构:单二进制部署、5 层安全防护、PostgreSQL 多租户、pgvector 混合检索——这才是企业敢用的 AI Agent 框架。


从「养龙虾」热潮到企业安全焦虑

2026 年春天,一款名为 OpenClaw 的开源 AI 助手在全球掀起「养龙虾」热潮。60 天内,它的 GitHub Stars 从零飙升至 250,829,超越 React 成为 GitHub 历史上 Star 数最多的软件项目。

中国大陆的「龙虾」吉祥物在微博、知乎病毒式传播。深圳龙岗区发布「龙虾十条」政策,腾讯云、阿里云争相上线部署服务。开发者们把 Agent 当成「电子宠物」,在 Telegram、WhatsApp、Discord 上与自己的 AI 助手日夜对话。

但热潮背后,企业的安全焦虑始终挥之不去:

  • CVE-2026-25253:一键远程代码执行漏洞,CVSS 评分 8.8,恶意网页可通过 WebSocket 窃取网关 Token
  • Censys 扫描:发现 21,639 个互联网暴露的实例
  • ClawHavoc 事件:ClawHub 市场审计发现 341 个恶意技能(约 12%)
  • 凭证明文存储~/.openclaw/credentials/ 目录下的 API Key 以 JSON 明文存储

更根本的问题在于技术栈:OpenClaw 用 TypeScript/Node.js 编写。对于需要部署到生产环境的企业来说,这意味着:

  1. 必须安装 Node.js 22+ 运行时
  2. 启动时间 >5 秒,空闲内存占用 >1 GB
  3. 缺乏企业级安全防护(无加密存储、无多租户隔离)
  4. 无法在资源受限的边缘设备运行

于是,一个用 Go 重写的项目诞生了——GoClaw


GoClaw 概览:企业级 Go 重写

GoClaw(github.com/nextlevelbuilder/goclaw)是 OpenClaw 的 Go 语言重写版本,面向生产环境和企业场景。它的核心卖点很直接:

指标
OpenClaw (TypeScript)
GoClaw (Go)
二进制大小
28 MB + Node.js 运行时
~25 MB 单静态二进制
空闲内存
>1 GB
~35 MB
启动时间
>5 秒
<1 秒
多租户
无(单用户设计)
PostgreSQL 行级安全(RLS)
凭证存储
JSON 明文
AES-256-GCM 加密
安全防护
基础 + 社区审计
5 层防护
MCP 协议
ACP 桥接
原生 stdio/SSE/streamable-http
可观测性
可选扩展
OpenTelemetry OTLP

一个命令就能部署:

# OpenClaw 需要 Node.js
curl -fsSL https://openclaw.ai/install.sh | bash  # 安装 Node.js + npm 包

# GoClaw 单二进制
wget https://github.com/nextlevelbuilder/goclaw/releases/download/v2026.4/goclaw-linux-amd64
chmod +x goclaw-linux-amd64
./goclaw-linux-amd64  # 亚秒级启动

在 $5 VPS 上,GoClaw 可以同时服务 100+ 租户,每个租户的数据通过 PostgreSQL 行级安全完全隔离。这是 TypeScript 版本无法企及的架构。


五层安全防护:GoClaw 的企业底气

OpenClaw 的安全危机让企业不敢大规模部署。GoClaw 的解决方案是构建五层纵深防御体系:

Layer 1:速率限制(滑动窗口算法)

// internal/security/ratelimit.go
type RateLimiter struct {
    windows    map[string]*SlidingWindow
    mu         sync.RWMutex
    maxReqs    int// 每分钟最大请求数
    windowSize time.Duration // 窗口大小(默认1分钟)
}

func(rl *RateLimiter)Allow(clientID string)bool {
    rl.mu.Lock()
defer rl.mu.Unlock()

    window, exists := rl.windows[clientID]
if !exists {
        window = &SlidingWindow{
            Timestamps: []time.Time{},
        }
        rl.windows[clientID] = window
    }

    now := time.Now()
// 移除窗口外的请求
    cutoff := now.Add(-rl.windowSize)
    valid := window.Timestamps[:0]
for _, t := range window.Timestamps {
if t.After(cutoff) {
            valid = append(valid, t)
        }
    }
    window.Timestamps = valid

iflen(window.Timestamps) >= rl.maxReqs {
returnfalse// 拒绝
    }
    window.Timestamps = append(window.Timestamps, now)
returntrue
}

滑动窗口比固定窗口更精准,避免了边界突刺问题。每个租户、每个用户、每个会话都有独立的速率限制,防止恶意请求耗尽资源。

Layer 2:SQL 注入检测(针对 CVE-2026-25253)

CVE-2026-25253 是 OpenClaw 的一键 RCE 漏洞,恶意 WebSocket 连接可窃取网关 Token。GoClaw 在数据库访问层专门检测 SQL 注入模式:

// internal/security/sqlinject.go
var injectionPatterns = []string{
`(?i)(\b(SELECT|INSERT|UPDATE|DELETE|DROP|UNION|ALTER|CREATE|TRUNCATE)\b)`,
`(?i)(\b(OR|AND)\b\s+\d+\s*=\s*\d+)`,
`(?i)(--|;|'|")`,
`(?i)(\bEXEC\b|\bEXECUTE\b)`,
`(?i)(\bCONCAT\b|\bCHAR\b|\bCHR\b)`,
`(?i)(\bLOAD_FILE\b|\bOUTFILE\b)`,
}

funcDetectSQLInjection(input string)bool {
for _, pattern := range injectionPatterns {
        matched, _ := regexp.MatchString(pattern, input)
if matched {
returntrue// 检测到注入模式
        }
    }
returnfalse
}

// 在所有数据库查询前拦截
func(db *DB)Query(ctx context.Context, query string, args ...any)(Rows, error) {
if DetectSQLInjection(query) {
returnnil, ErrSQLInjectionDetected
    }
return db.pg.Query(ctx, query, args...)
}

Layer 3:Prompt 注入检测

Agent 的最大风险是用户通过精心设计的 Prompt 绕过安全限制,让 Agent 执行危险操作。GoClaw 使用正则扫描常见的越狱模式:

// internal/security/promptinject.go
var jailbreakPatterns = []string{
`(?i)(ignore\s+(all|previous|above)\s+(instructions|rules))`,
`(?i)(disregard\s+(all|any|previous)\s+(instructions|rules))`,
`(?i)(bypass\s+(security|filter|restriction))`,
`(?i)(pretend\s+(to\s+be|you\s+are)\s+(admin|root|system))`,
`(?i)(act\s+as\s+(if|a)\s+(admin|root|developer))`,
`(?i)(system\s+override|admin\s+mode)`,
`(?i)(print\s+(all|your)\s+(instructions|rules|prompts))`,
}

funcDetectPromptInjection(prompt string)bool {
for _, pattern := range jailbreakPatterns {
        matched, _ := regexp.MatchString(pattern, prompt)
if matched {
returntrue
        }
    }
returnfalse
}

检测到注入后,Agent 会拒绝执行并返回标准化的安全警告:

⚠️ 安全警告:检测到潜在的 Prompt 注入模式。
您的请求已被拦截。请使用正常方式与 Agent 交互。

Layer 4:SSRF 防护(阻止私有 IP)

Agent 可能被诱导访问内网资源。GoClaw 在 HTTP 客户端层拦截所有 RFC 1918 私有 IP:

// internal/security/ssrf.go
var privateIPRanges = []string{
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16",
"127.0.0.0/8",
"169.254.0.0/16"// Link-local
"0.0.0.0/8",
}

funcIsPrivateIP(ipStr string)bool {
    ip := net.ParseIP(ipStr)
if ip == nil {
returnfalse
    }

for _, cidr := range privateIPRanges {
        _, network, _ := net.ParseCIDR(cidr)
if network.Contains(ip) {
returntrue
        }
    }
returnfalse
}

func(c *SafeHTTPClient)Do(req *http.Request)(*http.Response, error) {
    host := req.URL.Hostname()
    ips, err := net.LookupHost(host)
if err != nil {
returnnil, err
    }

for _, ip := range ips {
if IsPrivateIP(ip) {
returnnil, ErrSSRFBlocked
        }
    }

return c.client.Do(req)
}

这阻止了 Agent 访问 http://192.168.1.1/admin 或 http://10.0.0.1/internal-api 等内网资源。

Layer 5:AES-256-GCM 静态加密

OpenClaw 的凭证存储是 JSON 明文。GoClaw 使用 AES-256-GCM 加密所有敏感数据:

// internal/security/crypto.go
type EncryptedStore struct {
    key       []byte// 32字节 AES-256 密钥
    tableName string
    db        *sql.DB
}

func(es *EncryptedStore)StoreCredential(tenantID, keyName, value string)error {
// 生成随机 nonce(GCM 要求)
    nonce := make([]byte12)
if _, err := rand.Read(nonce); err != nil {
return err
    }

    block, _ := aes.NewCipher(es.key)
    gcm, _ := cipher.NewGCM(block)

// 加密
    ciphertext := gcm.Seal(nil, nonce, []byte(value), nil)

// nonce + ciphertext 一起存储
    encrypted := append(nonce, ciphertext...)

    query := `INSERT INTO credentials (tenant_id, key_name, encrypted_value)
              VALUES ($1, $2, $3)
              ON CONFLICT (tenant_id, key_name) DO UPDATE SET encrypted_value = $3`


return es.db.Exec(query, tenantID, keyName, encrypted)
}

func(es *EncryptedStore)GetCredential(tenantID, keyName string)(string, error) {
    query := `SELECT encrypted_value FROM credentials WHERE tenant_id = $1 AND key_name = $2`

var encrypted []byte
if err := es.db.QueryRow(query, tenantID, keyName).Scan(&encrypted); err != nil {
return"", err
    }

// 前12字节是 nonce
    nonce := encrypted[:12]
    ciphertext := encrypted[12:]

    block, _ := aes.NewCipher(es.key)
    gcm, _ := cipher.NewGCM(block)

// 解密并验证认证标签
    plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
return"", ErrDecryptionFailed // 认证失败,数据被篡改
    }

returnstring(plaintext), nil
}

GCM 模式提供认证加密(AEAD),不仅加密数据,还验证数据完整性。如果有人篡改数据库中的密文,解密时会失败。

密钥管理有两种模式:

  • 开发环境:从环境变量 GOCLAW_ENCRYPTION_KEY 加载
  • 生产环境:建议集成 HashiCorp Vault 或 AWS KMS

PostgreSQL 多租户:行级安全(RLS)隔离

OpenClaw 是单用户设计,所有会话、记忆、凭证存储在 ~/.openclaw/ 目录下。GoClaw 用 PostgreSQL 实现真正的多租户隔离:

架构设计

// internal/tenant/manager.go
type TenantManager struct {
    db *sql.DB
}

func(tm *TenantManager)CreateTenant(ctx context.Context, name, plan string)(*Tenant, error) {
    query := `INSERT INTO tenants (name, plan, created_at)
              VALUES ($1, $2, NOW())
              RETURNING id, name, plan, created_at`


var tenant Tenant
    err := tm.db.QueryRowContext(ctx, query, name, plan).Scan(
        &tenant.ID, &tenant.Name, &tenant.Plan, &tenant.CreatedAt,
    )
return &tenant, err
}

func(tm *TenantManager)SetTenantContext(ctx context.Context, tenantID string)context.Context {
// 设置 PostgreSQL 会话变量,启用 RLS
    tm.db.ExecContext(ctx, `SET app.current_tenant = $1`, tenantID)
return context.WithValue(ctx, "tenant_id", tenantID)
}

PostgreSQL RLS 配置

-- 启用 RLS
ALTERTABLE sessions ENABLEROWLEVELSECURITY;
ALTERTABLEmemoryENABLEROWLEVELSECURITY;
ALTERTABLE credentials ENABLEROWLEVELSECURITY;

-- 创建策略:只允许访问自己租户的数据
CREATEPOLICY tenant_isolation_policy ON sessions
USING (tenant_id = current_setting('app.current_tenant'));

CREATEPOLICY tenant_isolation_policy ONmemory
USING (tenant_id = current_setting('app.current_tenant'));

CREATEPOLICY tenant_isolation_policy ON credentials
USING (tenant_id = current_setting('app.current_tenant'));

-- 超级用户可以绕过(用于运维)
ALTERTABLE sessions FORCEROWLEVELSECURITY-- 强制启用,超级用户也受限制

每次请求开始时,GoClaw 设置 app.current_tenant 会话变量。之后所有 SQL 查询自动被 RLS 策略过滤,一个租户完全看不到其他租户的数据。

即使代码中有 bug 导致查询没有 WHERE 条件,RLS 也会在数据库层强制隔离:

// 错误的查询(缺少 WHERE tenant_id)
db.Query(`SELECT * FROM sessions`)  // RLS 自动过滤,只返回当前租户的 sessions

pgvector 混合检索:BM25 + 向量 + Reranking

GoClaw 的 Agent 记忆系统使用 PostgreSQL + pgvector 实现。但单纯的向量检索不够精准——GoClaw 采用 BM25 + 向量的混合检索方案。

为什么需要混合检索?

  • BM25:擅长精确关键词匹配,如「CVE-2026-25253」「GoClaw」「PostgreSQL」
  • 向量检索:擅长语义理解,如「如何防止 Agent 被入侵」可能匹配到「SSRF 防护」或「Prompt 注入检测」

两者结合,Reciprocal Rank Fusion(RRF)算法融合结果:

实现架构

// internal/memory/hybrid_search.go
type HybridSearcher struct {
    db        *sql.DB
    embedder  Embedder  // 向量嵌入器
}

func(hs *HybridSearcher)Search(ctx context.Context, query string, topK int)([]SearchResult, error) {
// 1. BM25 全文检索(PostgreSQL FTS)
    bm25Results, err := hs.bm25Search(ctx, query, topK*2)
if err != nil {
returnnil, err
    }

// 2. 向量检索(pgvector)
    vectorResults, err := hs.vectorSearch(ctx, query, topK*2)
if err != nil {
returnnil, err
    }

// 3. RRF 融合
    fused := hs.rrfFusion(bm25Results, vectorResults, 60)

// 4. 取 topK
iflen(fused) > topK {
        fused = fused[:topK]
    }

return fused, nil
}

func(hs *HybridSearcher)bm25Search(ctx context.Context, query string, limit int)([]SearchResult, error) {
    sql := `SELECT id, content, ts_rank_cd(search_vector, websearch_to_tsquery('english', $1)) as score
            FROM memory
            WHERE search_vector @@ websearch_to_tsquery('english', $1)
            ORDER BY score DESC
            LIMIT $2`


    rows, err := hs.db.QueryContext(ctx, sql, query, limit)
// ...
}

func(hs *HybridSearcher)vectorSearch(ctx context.Context, query string, limit int)([]SearchResult, error) {
// 生成查询向量
    embedding, err := hs.embedder.Embed(query)
if err != nil {
returnnil, err
    }

    sql := `SELECT id, content, 1 - (embedding <=> $1) as score
            FROM memory
            ORDER BY embedding <=> $1
            LIMIT $2`


    rows, err := hs.db.QueryContext(ctx, sql, embedding, limit)
// ...
}

func(hs *HybridSearcher)rrfFusion(bm25, vector []SearchResult, k int) []SearchResult {
// RRF 公式:score = sum(1 / (k + rank))
    scores := make(map[string]float64)

for rank, r := range bm25 {
        scores[r.ID] += 1.0 / float64(k + rank + 1)
    }

for rank, r := range vector {
        scores[r.ID] += 1.0 / float64(k + rank + 1)
    }

// 按融合分数排序
// ...
}

知识图谱:LLM 提取实体 + 关系遍历

GoClaw 还引入了知识图谱层,用 LLM 从对话中提取实体和关系:

// internal/knowledge/graph.go
type KnowledgeGraph struct {
    db     *sql.DB
    llm    LLMClient
}

type Entity struct {
    ID       string
    Name     string
    Type     string// "person", "project", "concept", "event"
    TenantID string
}

type Relation struct {
    SourceID string
    TargetID string
    Type     string// "mentions", "uses", "creates", "depends_on"
}

func(kg *KnowledgeGraph)ExtractFromConversation(ctx context.Context, conv string)error {
// 用 LLM 提取实体和关系
    prompt := `从以下对话中提取实体和关系,以 JSON 格式返回:

    实体类型:person, project, concept, event, tool, api
    关系类型:mentions, uses, creates, depends_on, implements

    对话:
    """ + conv + """

    输出格式:
    {"entities": [...], "relations": [...]}`


    result, err := kg.llm.Complete(ctx, prompt)
// 解析并存储到 PostgreSQL
// ...
}

func(kg *KnowledgeGraph)Traverse(ctx context.Context, entityID string, depth int)([]Entity, error) {
// 递归遍历关系图
    sql := `WITH RECURSIVE graph AS (
                SELECT source_id, target_id, type, 1 as depth
                FROM relations WHERE source_id = $1

                UNION ALL

                SELECT r.source_id, r.target_id, r.type, g.depth + 1
                FROM relations r
                JOIN graph g ON r.source_id = g.target_id
                WHERE g.depth < $2
            )
            SELECT DISTINCT e.* FROM entities e
            JOIN graph g ON e.id = g.target_id
            WHERE e.tenant_id = current_setting('app.current_tenant')`


// ...
}

知识图谱让 Agent 可以回答「GoClaw 用了哪些技术?」这类需要关系推理的问题,而不仅是文本匹配。


20+ LLM Provider:Anthropic 原生 HTTP+SSE

GoClaw 支持 20+ LLM Provider,包括 Anthropic、OpenAI、OpenRouter、DeepSeek、DashScope、Ollama 等。其中 Anthropic 的集成值得一提——它使用原生 HTTP+SSE 实现,支持 Prompt Caching:

// internal/llm/anthropic.go
type AnthropicClient struct {
    apiKey     string
    baseURL    string
    httpClient *http.Client
}

type MessageRequest struct {
    Model       string`json:"model"`
    MaxTokens   int`json:"max_tokens"`
    System      []SystemBlock `json:"system,omitempty"`
    Messages    []Message     `json:"messages"`
    Tools       []Tool        `json:"tools,omitempty"`
}

type SystemBlock struct {
    Type        string`json:"type"`// "text"
    Text        string`json:"text"`
    CacheControl *struct {
        Type string`json:"type"`// "ephemeral"
    } `json:"cache_control,omitempty"`
}

func(ac *AnthropicClient)Stream(ctx context.Context, req MessageRequest)(iter.Seq2[*Event, error], error) {
    body, _ := json.Marshal(req)

    httpReq, _ := http.NewRequestWithContext(ctx, "POST",
        ac.baseURL+"/v1/messages", bytes.NewReader(body))
    httpReq.Header.Set("Content-Type""application/json")
    httpReq.Header.Set("X-API-Key", ac.apiKey)
    httpReq.Header.Set("Accept""text/event-stream")

    resp, err := ac.httpClient.Do(httpReq)
if err != nil {
returnnil, err
    }

returnfunc(yield func(*Event, error)bool) {
defer resp.Body.Close()

        scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
            line := scanner.Text()

if !strings.HasPrefix(line, "data: ") {
continue
            }

            data := strings.TrimPrefix(line, "data: ")
if data == "[DONE]" {
return
            }

var event Event
if err := json.Unmarshal([]byte(data), &event); err != nil {
if !yield(nil, err) {
return
                }
continue
            }

if !yield(&event, nil) {
return
            }
        }
    }, nil
}

Prompt Caching:节省 90% Token 成本

Anthropic 的 Prompt Caching 允许缓存系统提示和上下文,在后续请求中复用。GoClaw 利用这一点缓存 Agent 的系统提示:

// 系统提示缓存标记
systemBlocks := []SystemBlock{
    {
        Type: "text",
        Text: agentSystemPrompt,  // 5000+ tokens
        CacheControl: &struct{Type string`json:"type"`}{
            Type: "ephemeral",  // 缓存标记
        },
    },
}

// 首次请求:完整计费
// 后续请求:缓存部分 90% 折扣

对于多轮对话,系统提示缓存可以节省大量 Token 成本。


MCP 原生集成:三种传输模式

MCP(Model Context Protocol)是 Anthropic 主导的开放标准,让 AI Agent 通过统一 JSON-RPC 2.0 接口连接外部工具。GoClaw 原生支持三种 MCP 传输模式:

stdio 模式

最简单的模式,MCP Server 作为子进程运行,通过 stdin/stdout 通信:

// internal/mcp/stdio_transport.go
type StdioTransport struct {
    cmd    *exec.Cmd
    stdin  io.Writer
    stdout io.Reader
}

func(st *StdioTransport)Start(ctx context.Context, command string, args ...string)error {
    st.cmd = exec.CommandContext(ctx, command, args...)

    stdinPipe, _ := st.cmd.StdinPipe()
    stdoutPipe, _ := st.cmd.StdoutPipe()

    st.stdin = stdinPipe
    st.stdout = stdoutPipe

return st.cmd.Start()
}

func(st *StdioTransport)Send(request *JSONRPCRequest)(*JSONRPCResponse, error) {
// 写入 stdin
    data, _ := json.Marshal(request)
    st.stdin.Write(append(data, '\n'))

// 从 stdout 读取响应
    scanner := bufio.NewScanner(st.stdout)
if scanner.Scan() {
var resp JSONRPCResponse
        json.Unmarshal(scanner.Bytes(), &resp)
return &resp, nil
    }

returnnil, scanner.Err()
}

SSE 模式(HTTP Server-Sent Events)

MCP Server 作为 HTTP 服务运行,通过 SSE 推送消息:

// internal/mcp/sse_transport.go
type SSETransport struct {
    baseURL    string
    httpClient *http.Client
    eventChan  chan *JSONRPCResponse
}

func(st *SSETransport)Connect(ctx context.Context)error {
    req, _ := http.NewRequestWithContext(ctx, "GET", st.baseURL+"/sse"nil)
    resp, err := st.httpClient.Do(req)
if err != nil {
return err
    }

// 后台读取 SSE 事件
gofunc() {
defer resp.Body.Close()
        scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
            line := scanner.Text()
if strings.HasPrefix(line, "data: ") {
                data := strings.TrimPrefix(line, "data: ")
var event JSONRPCResponse
                json.Unmarshal([]byte(data), &event)
                st.eventChan <- &event
            }
        }
    }()

returnnil
}

streamable-http 模式

最新的传输模式,支持双向流式通信:

// internal/mcp/streamable_http.go
type StreamableHTTPTransport struct {
    baseURL    string
    httpClient *http.Client
    sessionID  string
}

func(st *StreamableHTTPTransport)Send(request *JSONRPCRequest)(iter.Seq2[*JSONRPCResponse, error], error) {
    body, _ := json.Marshal(request)

    req, _ := http.NewRequest("POST", st.baseURL+"/mcp", bytes.NewReader(body))
    req.Header.Set("Content-Type""application/json")
if st.sessionID != "" {
        req.Header.Set("X-MCP-Session-ID", st.sessionID)
    }

    resp, err := st.httpClient.Do(req)
if err != nil {
returnnil, err
    }

// 保存 session ID
    st.sessionID = resp.Header.Get("X-MCP-Session-ID")

returnfunc(yield func(*JSONRPCResponse, error)bool) {
defer resp.Body.Close()
// 解析流式响应...
    }, nil
}

三种模式让 GoClaw 可以连接任何 MCP 服务器——官方的 GitHub、PostgreSQL、Filesystem 工具,或社区的 200+ 工具。


Agent Teams:多 Agent 协作编排

GoClaw 引入了 Agent Teams 概念,让多个 Agent 组成团队,共享任务板,相互委托任务:

// internal/agent/team.go
type AgentTeam struct {
    ID        string
    Name      string
    TenantID  string
    Agents    []Agent
    TaskBoard *TaskBoard
}

type TaskBoard struct {
    Tasks     []Task
    Assignees map[string]string// task_id -> agent_id
}

func(at *AgentTeam)DispatchTask(ctx context.Context, task Task)error {
// 1. 分析任务类型
    taskType := at.classifyTask(task.Description)

// 2. 选择最合适的 Agent
    bestAgent := at.selectAgent(taskType)

// 3. 委托任务
return bestAgent.AcceptTask(ctx, task)
}

func(at *AgentTeam)classifyTask(desc string)string {
// 用 LLM 或规则分类
// "coding", "analysis", "communication", "research"
// ...
}

func(at *AgentTeam)selectAgent(taskType string) *Agent {
// 混合发现机制:
// 1. 查看每个 Agent 的 capabilities 标签
// 2. 查看历史任务完成率
// 3. 查看当前负载
// ...
}

同步/异步委托

// 同步委托:等待结果
result, err := agentA.DelegateAndWait(ctx, agentB, task)

// 异步委托:后台执行
err := agentA.DelegateAsync(ctx, agentB, task)
// agentB 完成后通过回调通知 agentA

OpenTelemetry 可观测性:OTLP 导出

GoClaw 支持可选的 OpenTelemetry 集成(通过构建标签 -tags telemetry 启用):

// internal/telemetry/tracer.go
var tracer trace.Tracer

funcInitTelemetry(serviceName, otlpEndpoint string)error {
    exporter, err := otlptrace.New(context.Background(),
        otlptracegrpc.NewClient(
            otlptracegrpc.WithEndpoint(otlpEndpoint),
            otlptracegrpc.WithInsecure(),
        ),
    )
if err != nil {
return err
    }

    tp := sdktrace.NewTracerProvider(
        sdktrace.WithBatcher(exporter),
        sdktrace.WithResource(resource.NewWithAttributes(
            semconv.SchemaURL,
            semconv.ServiceNameKey.String(serviceName),
        )),
    )

    otelsdk.SetTracerProvider(tp)
    tracer = tp.Tracer("goclaw")

returnnil
}

funcTraceLLMCall(ctx context.Context, provider, model string, tokensIn, tokensOut int) {
    _, span := tracer.Start(ctx, "llm.call",
        trace.WithAttributes(
            attribute.String("provider", provider),
            attribute.String("model", model),
            attribute.Int("tokens.input", tokensIn),
            attribute.Int("tokens.output", tokensOut),
        ),
    )
defer span.End()
}

OTLP 导出兼容 Grafana Tempo、Jaeger、Datadog、New Relic 等主流 APM 系统。


GoClaw Lite:Wails 桌面版

除了服务端版本,GoClaw 还提供桌面版(GoClaw Lite),用 Wails v2 + React 构建:

// goclaw-lite/main.go
package main

import (
"github.com/wailsapp/wails/v2"
"github.com/wailsapp/wails/v2/pkg/options"
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
)

funcmain() {
// 初始化 SQLite 本地存储
    db := initSQLiteDB()

    app := &App{
        DB:       db,
        Agent:    NewAgent(db),
        MCPClient: NewMCPClient(),
    }

    wails.Run(&options.App{
        Title:  "GoClaw Lite",
        Width:  1024,
        Height: 768,
        AssetServer: &assetserver.Options{
            Assets: Assets, // React 前端
        },
        Bind: []interface{}{
            app,
        },
    })
}

type App struct {
    DB        *sql.DB
    Agent     *Agent
    MCPClient *MCPClient
}

// Wails 绑定方法,前端可调用
func(a *App)SendMessage(message string)(string, error) {
return a.Agent.Process(message)
}

func(a *App)GetHistory()([]Message, error) {
return a.DB.QueryMessages()
}

桌面版适合个人用户,数据完全本地存储,无需服务器。


Go vs TypeScript:AI Agent 的技术栈抉择

GoClaw 的出现证明了一个事实:Go 比 TypeScript 更适合构建企业级 AI Agent 基础设施

Go 的优势

  1. 单二进制部署:无需安装 Node.js 运行时,一个 wget 就能运行
  2. 低资源占用:空闲内存 35 MB vs TypeScript 的 1 GB,适合边缘设备
  3. 原生并发:goroutine 处理 SSE 流、WebSocket 连接、MCP 通信更高效
  4. 强类型安全:编译时捕获错误,减少运行时 panic
  5. AES-256-GCM 加密:Go 的 crypto 库是业界标杆
  6. PostgreSQL 集成:pgx 驱动性能优秀,pgvector 支持完善

TypeScript 的局限

  1. 运行时依赖:必须安装 Node.js,增加部署复杂度
  2. 高内存占用:V8 引擎本身占用大量内存
  3. 安全防护薄弱:缺乏原生加密库,依赖第三方实现
  4. 无多租户设计:OpenClaw 是单用户架构,企业需要自行改造

结语:Go 正在重塑 AI Agent 基础设施

OpenClaw 的 250K Stars 证明了「自托管 AI 助手」是真实需求。但 TypeScript 的基因让它更适合个人爱好者,而非企业生产环境。

GoClaw 用 Go 重写了整个架构,证明了 Go 在 AI Agent 领域的独特价值:

  • 单二进制部署:DevOps 团队的最爱
  • 5 层安全防护:让企业敢把 API Key 交给 Agent
  • PostgreSQL 多租户:SaaS 模式的基石
  • pgvector 混合检索:BM25 + 向量 + 知识图谱
  • OpenTelemetry 可观测性:生产环境的标配

如果说 OpenClaw 是 AI Agent 的「iPhone」,让普通人爱上养龙虾;那么 GoClaw 就是「企业版 iPhone」,让银行、医院、政府敢把 Agent 放进生产环境。

Go 正在重塑 AI Agent 基础设施。这不是口号,而是正在发生的事实。


参考资料

  • GoClaw GitHub: github.com/nextlevelbuilder/goclaw
  • GoClaw 安全架构: goclaw.sh/blog/goclaw-5-layer-security
  • OpenClaw 官方文档: docs.openclaw.ai
  • PostgreSQL RLS 文档: postgresql.org/docs/current/ddl-rowsecurity.html
  • pgvector 扩展: github.com/pgvector/pgvector
  • Anthropic Prompt Caching: docs.anthropic.com/claude/docs/prompt-caching
  • MCP 协议规范: modelcontextprotocol.io
  • OpenTelemetry Go SDK: opentelemetry.io/docs/instrumentation/go

推荐阅读

福利
我为大家整理了一份从入门到进阶的Go学习资料礼包,包含学习建议:入门看什么,进阶看什么。关注公众号 「polarisxu」,回复 ebook 获取;还可以回复「进群」,和数万 Gopher 交流学习。