从零构建高性能客服系统:Golang架构设计与智能体源码实战

2026-02-04

从零构建高性能客服系统:Golang架构设计与智能体源码实战

演示网站:gofly.v1kf.com
我的微信:llike620
我的微信

为什么我们要重新造轮子?

大家好,我是老王,一个在IM领域摸爬滚打了十年的老码农。这些年见过太多客服系统的痛点:SaaS版本数据安全如鲠在喉、Java老系统并发上不去、PHP版本的长连接就是个灾难…直到我们团队用Golang撸出了『唯一客服系统』,才真正找到了那个平衡点——高性能、可私有化、还能保持开发效率。今天就跟大家聊聊,这套系统的架构设计和智能体模块的源码实现。

核心架构:微服务但不是过度微服务

我们最初也纠结过要不要上完整的微服务架构,但考虑到中小企业的部署成本,最终采用了模块化单体+关键服务分离的设计:

go // 核心目录结构 /weikeyi ├── gateway/ # 网关层(Go+OpenResty) ├── core/ # 业务核心(会话、消息、路由) ├── ai_agent/ # 智能客服模块 ├── monitor/ # 监控与统计 └── deploy/ # 一键部署脚本

网关层用Go重写了WebSocket网关,单机支撑10万+长连接不是问题。这里有个小技巧:我们没直接用goroutine per connection,而是用了epoll+goroutine pool:

go func (w *WsServer) handleConn(conn net.Conn) { // 从池中获取goroutine处理 select { case w.pool <- struct{}{}: go w.process(conn) default: // 限流策略 conn.Write([]byte(“系统繁忙”)) conn.Close() } }

消息流转:零拷贝设计

客服系统最核心的就是消息流转。我们参考了Kafka的零拷贝思想,消息在内存中只有一份序列化数据:

go type MessageBroker struct { ringBuffer *RingBuffer // 环形缓冲区 subscribers map[string][]chan []byte mu sync.RWMutex }

// 发布消息时只序列化一次 func (b *MessageBroker) Publish(topic string, msg proto.Message) { data, _ := proto.Marshal(msg) b.ringBuffer.Put(topic, data) // 这里只是指针传递

// 订阅者直接读取同一份data
for _, ch := range b.subscribers[topic] {
    select {
    case ch <- data:
    default:
        // 非阻塞处理
    }
}

}

智能客服模块:不是简单的API调用

很多人以为智能客服就是调大模型API,其实核心在于上下文管理意图识别。我们的ai_agent模块包含:

go // 上下文窗口管理 type ContextWindow struct { maxTokens int messages []Message summaryCache string // 智能摘要缓存

// 关键优化:向量缓存
embeddingCache map[string][]float32

}

func (cw *ContextWindow) BuildPrompt() string { // 1. 优先使用摘要 if cw.needSummary() { return cw.buildSummaryPrompt() }

// 2. 最近对话优先
return cw.buildRecentPrompt()

}

数据库设计:读写分离的艺术

客服系统天然读写比例悬殊(约1:20)。我们的做法是:

  1. 会话数据:Redis分片 + MySQL归档
  2. 消息记录:ClickHouse冷热分离
  3. 配置信息:Etcd动态配置

go // 多级存储策略 type StorageManager struct { hotStore *RedisCluster // 热数据:在线会话 warmStore *MySQLProxy // 温数据:最近30天 coldStore *ClickHouseConn // 冷数据:历史记录 }

func (sm *StorageManager) SaveMessage(msg *Message) { // 异步写入三级存储 go func() { sm.hotStore.Store(msg) // 毫秒级 sm.warmStore.AsyncStore(msg) // 秒级 sm.coldStore.BatchStore(msg) // 分钟级批量 }() }

监控体系:不只是Prometheus

我们自研了轻量级监控组件,关键指标实时计算:

go // 关键业务指标实时计算 type BusinessMetrics struct { // 滑动窗口统计 responseTimes *RollingWindow satisfaction *EWMA // 指数加权移动平均

// 实时预警
alertRules []AlertRule

}

func (bm *BusinessMetrics) RecordResponse(timeMs int64) { bm.responseTimes.Add(float64(timeMs))

// P99延迟预警
if bm.responseTimes.P99() > 1000 {
    bm.triggerAlert("response_slow")
}

}

部署方案:Docker Compose还是K8s?

我们提供了两套方案:

轻量版:单机Docker Compose,20分钟搞定部署 yaml version: ‘3.8’ services: gateway: image: weikeyi/gateway:${VERSION} ports: - “80:80” - “443:443” - “9501:9501” # WebSocket端口

core: image: weikeyi/core:${VERSION} environment: - DB_HOST=mysql - REDIS_HOST=redis

企业版:K8s Helm Chart,支持水平扩展和蓝绿部署

性能数据:数字会说话

经过压测(8核16G服务器): - 单机长连接:10万+ - 消息吞吐:5万+/秒 - P99延迟:<200ms - 内存占用:<2GB(空载)

开源与闭源的选择

我们开源了核心框架(Apache 2.0),但企业级功能(如智能路由、CRM集成)需要商业授权。这种模式既能让开发者学习核心实现,又能保证项目的可持续发展。

踩过的坑

  1. Go GC停顿:大内存对象导致的STW问题,通过对象池缓解
  2. WebSocket断连:设计了智能重连+消息补发机制
  3. 分布式事务:最终一致性+补偿事务替代强一致性

写在最后

开发『唯一客服系统』这两年,最大的感触是:技术选型没有银弹,适合业务场景才是最好的。Golang在并发处理和部署便利性上确实给了我们很大惊喜。

如果你正在选型客服系统,或者想学习如何用Go构建高并发系统,欢迎来我们GitHub点个star,也欢迎加入我们的技术交流群一起切磋。

项目地址:github.com/weikeyi/kefu(示例地址) 文档:docs.weikeyi.com


PS:最近我们在重构智能客服的意图识别模块,用上了本地化的小模型,效果不错还省成本。下回可以专门聊聊这个。

PPS:文中代码为了清晰做了简化,完整实现请查看源码。