设计一个在线游戏服务器
设计一个在线游戏服务器
📌 一、题目解读与需求澄清
本质问题:构建一个能支撑大量玩家实时交互、状态同步、低延迟通信的分布式游戏后端系统。与普通 Web 服务不同,游戏服务器的核心挑战在于:毫秒级延迟、有状态会话、高并发实时同步。
功能性需求(Functional Requirements)
| # | 需求 | 说明 |
|---|---|---|
| 1 | 玩家注册、登录与认证 | 支持账号体系,Session 管理 |
| 2 | 房间/匹配系统(Matchmaking) | 按技能/延迟/人数撮合玩家进入同一局 |
| 3 | 游戏房间管理 | 创建、加入、退出房间;房间内状态广播 |
| 4 | 实时游戏状态同步 | 玩家位置、动作、事件实时同步给房间内所有人 |
| 5 | 排行榜与战绩系统 | 保存每局结果,提供实时/历史排行 |
需要向面试官确认的典型问题:
- 游戏类型是什么?(MOBA、FPS、卡牌、策略?不同类型对延迟/同步模型要求差异极大)
- 每局游戏几个人参与?(2v2 vs 100人 Battle Royale 架构天差地别)
- 是否需要跨地区全球部署?
- 是否需要防作弊系统?
非功能性需求(Non-Functional Requirements)
| # | 需求 | 目标值 |
|---|---|---|
| 1 | 低延迟 | 游戏内状态同步 RTT < 100ms(理想 < 50ms) |
| 2 | 高可用 | 游戏核心服务 99.99% uptime,允许单节点故障不影响其他房间 |
| 3 | 可扩展性 | 支持百万 DAU,峰值 10 万并发房间 |
| 4 | 弱一致性(最终一致) | 游戏内状态允许短暂不一致,但排行榜、战绩数据强一致 |
| 5 | 防作弊与安全 | 服务端权威校验(Server Authoritative),客户端不能篡改游戏状态 |
容易被忽略的隐藏需求
- 断线重连:玩家网络抖动后需在几秒内恢复游戏状态,而非直接判负
- 热更新:游戏服务器需要能在不停服的情况下滚动更新(蓝绿部署)
- 房间生命周期管理:游戏结束后服务器资源如何回收?长期空房间的清理策略
- 作弊防护:客户端上报的位置/动作需要服务端校验合法性(速度上限检测、碰撞检测)
- 观战模式(Spectator):观众视角的数据流与参与者不同,延迟要求更宽松
📐 二、规模估算
基础假设
| 参数 | 假设值 | 说明 |
|---|---|---|
| DAU | 5,000,000(500万) | 中型网游规模 |
| 峰值在线并发 | DAU × 20% = 1,000,000 | 晚高峰约20%日活同时在线 |
| 每局人数 | 10人(5v5) | 以 MOBA 类型为参考 |
| 游戏时长 | 30分钟/局 | 平均值 |
| 每人每天局数 | 5局 | |
| 消息频率 | 20条/秒/玩家 | 位置更新+动作事件 |
QPS 计算
游戏内并发玩家数 = 1,000,000
每个玩家消息频率 = 20 msg/s
写 QPS(游戏状态上报):
= 1,000,000 × 20 = 20,000,000 msg/s(分布在各游戏服务器节点上)
每个房间内广播倍增:
单条消息 → 广播给房间内 9 个其他玩家
广播 QPS = 20M × 9 = 180,000,000 msg/s(各节点内部处理,不经过中心数据库)
Matchmaking QPS(匹配请求):
每局30分钟,DAU每天5局
= 5,000,000 × 5 / (24 × 3600) ≈ 290 次/秒(低)
排行榜读 QPS:
每次游戏结束更新一次
= 5,000,000 × 5 / 86400 ≈ 290 写/秒;读约 5,000 QPS
关键结论①:游戏内消息 QPS 极高,但绝大多数消息在游戏服务器内部处理(房间内广播),不会打穿到数据库层,数据库写入量远低于消息总量。
存储估算
每局战绩记录:
约 1KB(双方玩家ID + 得分 + 时长 + 关键事件)
= 5,000,000 玩家 × 5局/天 × 1KB = 25 GB/天
玩家账户数据:
5,000,000 × 2KB = 10 GB(可接受,MySQL 足够)
游戏录像(可选):
压缩后每局约 500KB
= 5,000,000 × 5 × 500KB / 10 = 1.25 TB/天(需对象存储,非强制需求)
带宽估算
单个玩家上下行:
上行(发送):每条消息 100 Bytes × 20/s = 2 KB/s
下行(接收):房间内9人广播 × 100 Bytes × 20/s = 18 KB/s
总下行带宽:
1,000,000 × 18 KB/s ≈ 18 GB/s = 144 Gbps
→ 分布在约 1000 个游戏节点,每节点约 144 Mbps(可接受)
关键结论②:系统是**消息密集型(Message-intensive)**而非存储密集型;带宽和 CPU 是主要瓶颈,游戏状态不落盘,全部存在内存中。
🏗️ 三、高层架构设计### 核心组件职责
Game Gateway:所有客户端的入口,负责维持 WebSocket/UDP 长连接,完成 Token 验证后,将游戏消息路由到对应的 Game Server 节点。本身无状态,可水平扩展。
Matchmaking Service:维护一个优先队列,按 ELO 分段、网络延迟、队伍组合撮合玩家。匹配成功后通知 Room Manager 分配游戏节点。
Room Manager:维护房间到游戏节点的映射表(存于 Redis),负责节点负载均衡,追踪房间生命周期(等待→进行中→结算→销毁)。
Game Server Cluster:最核心的组件。每个节点是一个有状态的进程,在内存中维护若干游戏房间的完整状态。接收玩家消息 → 校验合法性 → 更新游戏状态 → 广播给房间内所有玩家。
Kafka:游戏结束事件异步写入,解耦游戏节点与数据库,避免结算时的写入峰值直接冲击 DB。
核心数据流(玩家动作路径)
Client → [UDP/WebSocket] → Game Gateway
→ [Token 校验] Auth Service(首次连接)
→ 查 Redis 获取玩家所在 Room → 路由到对应 Game Server 节点
→ Game Server 接收动作 → 服务端合法性校验(防作弊)
→ 更新内存中的 Game State
→ 广播给房间内其他玩家
→ [游戏结束] 发 Kafka 事件 → Consumer 写 MySQL(战绩)+ Redis(排行榜)
核心数据库表设计
-- 玩家账户表(MySQL)
CREATE TABLE players (
player_id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(64) UNIQUE NOT NULL,
email VARCHAR(128) UNIQUE,
elo_rating INT DEFAULT 1000,
created_at TIMESTAMP DEFAULT NOW(),
INDEX idx_elo (elo_rating) -- 用于匹配时范围查询
);
-- 战绩表(MySQL,按 player_id 分区或 TimescaleDB)
CREATE TABLE match_records (
match_id CHAR(36) PRIMARY KEY, -- UUID
player_id BIGINT NOT NULL,
result ENUM('WIN','LOSE','DRAW'),
kills SMALLINT,
deaths SMALLINT,
elo_delta SMALLINT,
played_at TIMESTAMP,
INDEX idx_player_time (player_id, played_at DESC)
);
-- Redis 数据结构
-- 房间状态(Hash): room:{room_id} → {server_node, player_ids, status, ...}
-- 节点负载(Sorted Set): game_nodes → member=node_id, score=current_room_count
-- 排行榜(Sorted Set): leaderboard:global → member=player_id, score=elo_rating
-- 玩家在线状态(String): online:{player_id} → room_id(TTL 30s,心跳续期)
🔬 四、深入细节
子问题 1:游戏状态同步模型
问题描述:每个玩家每秒产生 20 次操作,10 人房间意味着每个客户端每秒要接收 180 条消息。如何在保证实时性的同时不让服务器和网络压垮?
解决方案分析:
方案 A:Lock-step(帧同步)
所有客户端在相同逻辑帧推进,服务器只广播输入,客户端本地模拟。延迟敏感,一人卡就影响全房间,适用于回合制/策略类游戏。
方案 B:State Synchronization(状态同步)
服务端是权威,持有完整游戏状态;客户端上报输入,服务端广播状态快照。适合 FPS/MOBA,天然防作弊。
方案 C:Delta Compression + Interest Management(增量压缩+兴趣管理)
服务器每 Tick 只下发相对上一帧的「变化部分」,且只下发玩家「关心」的对象(视野范围内)。这是大型游戏的标准做法。
推荐方案:State Sync + Delta Compression + 客户端预测(Client-Side Prediction)
# 服务端游戏循环(每个 Game Server 节点独立运行)
import asyncio
class GameRoom:
def __init__(self, room_id: str, players: list):
self.room_id = room_id
self.tick_rate = 20 # 每秒 20 tick
self.tick_interval = 1 / 20 # 50ms per tick
self.game_state = {} # player_id -> {x, y, hp, action}
self.pending_inputs = {} # 收集本 tick 的所有输入
async def game_loop(self):
while self.is_running:
tick_start = asyncio.get_event_loop().time()
# 1. 处理本 tick 收到的所有输入
inputs = self.consume_pending_inputs()
# 2. 服务端权威计算:校验 + 更新状态
new_state = self.simulate(inputs)
# 3. 计算 delta(只发变化部分,压缩带宽)
delta = self.compute_delta(self.game_state, new_state)
self.game_state = new_state
# 4. 广播 delta 给房间内所有玩家
await self.broadcast(delta)
# 5. 精确控制 tick 间隔(避免漂移)
elapsed = asyncio.get_event_loop().time() - tick_start
await asyncio.sleep(max(0, self.tick_interval - elapsed))
def simulate(self, inputs: dict) -> dict:
"""
服务端权威计算
- 校验移动速度是否超限(防止速度外挂)
- 校验技能 CD 是否满足
- 应用物理碰撞
"""
new_state = dict(self.game_state)
for player_id, action in inputs.items():
old_pos = new_state[player_id]['position']
new_pos = action['position']
# 速度校验:超过最大速度则忽略该输入
if self.exceeds_max_speed(old_pos, new_pos, self.tick_interval):
continue # 丢弃非法输入,保持旧状态
new_state[player_id]['position'] = new_pos
return new_state
def compute_delta(self, old_state: dict, new_state: dict) -> dict:
"""只返回发生变化的字段,减少广播数据量"""
delta = {}
for player_id, state in new_state.items():
if state != old_state.get(player_id):
delta[player_id] = state
return delta
客户端预测(Client-Side Prediction):客户端不等服务端确认就先本地展示移动结果,服务端回包后若有偏差则「插值纠正」(Reconciliation),给玩家流畅感而非等待延迟。
子问题 2:Matchmaking 系统设计
问题描述:要在低等待时间内,找到技能相近、网络延迟相近的 10 个玩家(5v5)组成一局。玩家等待越久,越难以接受;匹配质量越差,游戏体验越糟糕——这是个经典的时延 vs 质量 trade-off。
推荐方案:多维度优先队列 + 动态放宽(Expanding Search Window)
import heapq
import time
from dataclasses import dataclass, field
@dataclass(order=True)
class MatchRequest:
enqueue_time: float # 入队时间,用于计算等待时长
player_id: str = field(compare=False)
elo: int = field(compare=False) # 当前 ELO 分
preferred_region: str = field(compare=False)
class MatchmakingService:
def __init__(self):
# 按 ELO 分段,每段一个小队列(减少全量扫描)
self.queues: dict[str, list] = {} # elo_bucket -> min-heap by wait_time
self.elo_bucket_size = 100 # 每 100 分一个桶
def enqueue(self, req: MatchRequest):
bucket = req.elo // self.elo_bucket_size
if bucket not in self.queues:
self.queues[bucket] = []
heapq.heappush(self.queues[bucket], req)
def try_match(self, target_bucket: int) -> list | None:
"""
尝试从目标桶及相邻桶凑满 10 人
等待超过 30s 则扩大搜索范围(最多 ±3 桶)
"""
now = time.time()
candidates = []
# 动态放宽:等待越久,接受更大 ELO 差
for req in self._scan_buckets(target_bucket):
wait = now - req.enqueue_time
allowed_delta = min(3, int(wait / 10)) # 每等10秒多接受1个桶
if abs(req.elo // self.elo_bucket_size - target_bucket) <= allowed_delta:
candidates.append(req)
if len(candidates) == 10:
return self._form_teams(candidates)
return None
def _form_teams(self, players: list) -> tuple:
"""按 ELO 蛇形分队,使双方总分尽量均衡"""
sorted_players = sorted(players, key=lambda p: p.elo, reverse=True)
team_a, team_b = [], []
for i, p in enumerate(sorted_players):
if i % 2 == 0:
team_a.append(p)
else:
team_b.append(p)
return team_a, team_b
子问题 3:断线重连机制
问题描述:玩家断网后,其他玩家仍在游戏中。服务端如何处理这个「幽灵玩家」?玩家重连后如何快速恢复游戏状态?
核心设计要点:
- 心跳检测:客户端每 5 秒发心跳;服务端 15 秒未收到则标记为「断线」状态(非踢出)
- 状态保留:断线后保留该玩家的游戏状态,AI 接管或原地静止(视游戏类型)
- 重连令牌:建立连接时颁发
reconnect_token(有效期 5 分钟),断线后凭此令牌重连,无需重新登录 - 快照恢复:重连成功后,下发当前游戏完整快照(Full State Snapshot),后续恢复增量同步
class ReconnectionManager:
def __init__(self, redis_client):
self.redis = redis_client
async def handle_reconnect(self, token: str, ws):
"""
流程:验证令牌 → 找到玩家所在房间 → 发送完整快照
"""
session_data = await self.redis.get(f"reconnect:{token}")
if not session_data:
await ws.send({"error": "SESSION_EXPIRED"})
return
session = json.loads(session_data)
room = self.get_room(session["room_id"])
if not room or not room.is_running:
await ws.send({"error": "GAME_ENDED"})
return
# 替换旧连接
room.update_player_connection(session["player_id"], ws)
# 发送全量快照,让客户端快速同步到当前状态
snapshot = room.get_full_snapshot()
await ws.send({
"type": "RECONNECT_SNAPSHOT",
"tick": room.current_tick,
"state": snapshot
})
# 后续恢复正常增量广播
room.mark_player_reconnected(session["player_id"])
子问题 4:游戏服务器节点的水平扩缩容
问题描述:晚高峰需要 1000 个游戏节点,凌晨可能只需要 100 个。游戏服务器是有状态的(内存中有游戏状态),不能像无状态服务那样随意杀掉实例。如何优雅扩缩容?
推荐方案:Graceful Drain + Consistent Hashing + 节点预热
扩容流程:
1. 新节点启动 → 向 Etcd 注册自己(容量:0/max_rooms)
2. Room Manager 的负载均衡器发现新节点
3. 新房间优先路由到低负载节点
4. 旧节点不再接受新房间(但继续服务存量房间)
缩容流程(Graceful Drain):
1. 标记节点为 DRAINING 状态(不再接受新房间)
2. 等待存量房间自然结束(游戏时长有限,通常 30 分钟内清空)
3. 若需要紧急回收,超时后强制结束仍在进行的游戏(发补偿)
4. 节点从 Etcd 注销 → Pod 终止
关键指标:节点负载 = current_rooms / max_rooms(而非 CPU%)
触发扩容阈值:平均负载 > 70%
触发缩容阈值:平均负载 < 30% 且持续 10 分钟
子问题 5:排行榜设计(实时 + 历史)
问题描述:全服玩家排行榜,要求实时更新(每局结束后更新分数),并支持查询「我的排名」(可能是数百万名)。
Redis Sorted Set 方案(适合实时全球榜,千万量级以内):
import redis
r = redis.Redis()
def update_leaderboard(player_id: str, elo_delta: int):
"""游戏结束后更新,O(log N)"""
r.zincrby("leaderboard:global", elo_delta, player_id)
def get_top_100() -> list:
"""获取前 100,O(log N + 100)"""
return r.zrevrange("leaderboard:global", 0, 99, withscores=True)
def get_player_rank(player_id: str) -> int:
"""查询自己的排名,O(log N)"""
rank = r.zrevrank("leaderboard:global", player_id)
return rank + 1 if rank is not None else -1
def get_nearby_players(player_id: str, range=5) -> list:
"""
查询我附近排名的玩家(±5名)
这是很多游戏首页会展示的功能
"""
my_rank = r.zrevrank("leaderboard:global", player_id)
if my_rank is None:
return []
start = max(0, my_rank - range)
end = my_rank + range
return r.zrevrange("leaderboard:global", start, end, withscores=True)
当玩家量超过千万时,可分区域/服务器榜,再做跨区榜;或将榜单按时间分段(本赛季榜),控制单个 Sorted Set 的大小。
⚖️ 五、技术选型与 Trade-off 讨论
| 决策点 | 选项 A | 选项 B | 本题推荐 |
|---|---|---|---|
| 传输协议 | TCP/WebSocket(可靠,有序) | UDP(低延迟,可能丢包) | 视游戏类型:FPS 用 UDP + 应用层可靠性(QUIC);MOBA/卡牌用 WebSocket |
| 游戏同步模型 | 帧同步(Lock-step) | 状态同步(State Sync) | 状态同步:天然防作弊,服务端权威;帧同步适合回合制 |
| 游戏服务器语言 | Go / C++ | Node.js / Python | Go:goroutine 天然适合高并发连接;C++ 用于超高性能 FPS;避免 Python GIL |
| 玩家数据存储 | MySQL(关系型) | MongoDB(文档型) | MySQL:玩家账户、战绩有强关联关系,事务要求高 |
| 排行榜存储 | Redis Sorted Set | 数据库 rank() 函数 | Redis:O(log N) 实时排名;DB rank() 全表扫描,百万级即崩 |
| Matchmaking 算法 | 简单 ELO 范围匹配 | 机器学习预测对局质量 | ELO 范围匹配 + 动态放宽:ML 方案复杂且难调试,上线初期没必要 |
| 消息广播 | 游戏服务器直接广播 | 经过独立的 Pub/Sub 中间件 | 直接广播:房间内消息走内存,绕过网络;Kafka 只用于异步持久化事件 |
| 强一致 vs 最终一致 | 游戏内状态强一致 | 允许短暂不一致 | 游戏内最终一致 + 战绩强一致:游戏里延迟几十毫秒的同步偏差可接受,但战绩入库必须准确 |
❓ 六、常见面试追问点
Q1:为什么游戏服务器要用 UDP 而不是 TCP?
TCP 的重传机制在网络抖动时会造成「队头阻塞」(Head-of-line blocking)——一个丢包会阻塞后续所有包。对于游戏来说,一个过期的位置帧完全没有重传价值,新帧会覆盖它。UDP 允许应用层自己决定哪些数据「重要(需重传)」哪些「不重要(可丢弃)」,实现更灵活的可靠性控制。QUIC 协议本质上是 UDP 上的多路复用,解决了队头阻塞,是现代游戏的优先选择。
Q2:如何解决「客户端作弊(外挂)」问题?
核心原则是「Server Authoritative」——服务端永远是权威,客户端上报的所有动作都需要服务端校验。例如位置更新,服务端校验玩家移动距离是否超过速度上限 × 时间间隔;技能释放,服务端校验 CD 是否满足。结合异步行为分析(打击频率、视角突变、准心精准度统计)触发人工审核或自动封禁。客户端本地展示的状态只是「预测」,服务端有最终裁决权。
Q3:一个 Game Server 节点崩溃了怎么办?
Game Server 是有状态的,节点崩溃意味着上面所有房间的游戏状态丢失,无法像无状态服务那样直接重启恢复。常见方案是:定期将游戏状态快照写入 Redis(每隔 5-10 秒),节点崩溃后由 Room Manager 探测到(Etcd TTL 到期),将受影响的房间标记为「中断」,尝试在新节点上从最近快照恢复,并通知客户端重连。实际上,大多数游戏对此是「对局作废 + 补偿道具」而非强制恢复,因为恢复代价高且体验也不好。
Q4:Matchmaking 系统如何保证不同技能段的等待时间都合理?
高 ELO 玩家(如前 1%)在各自分段内人少,若严格匹配会等待很久。解决方案是「动态扩展窗口」——等待时间超过阈值(如 30 秒)后,自动放宽 ELO 范围(每多等 10 秒,接受更大的 ELO 差距)。同时引入「虚拟满员」机制:在等待期间用 AI 机器人作为占位,让真实玩家优先开局体验,后续替换为加入的真实玩家。
Q5:如何做游戏房间的负载均衡?
区别于 HTTP 服务的 Round-Robin,游戏房间负载均衡的核心是「将新房间分配到负载最低的节点」。Room Manager 用 Redis Sorted Set 维护所有节点的「当前房间数/最大房间数」,新房间请求时取 score 最低的节点(O(log N) 操作)。节点定期上报自己的负载,TTL 超期则自动摘除。
Q6:排行榜数据量太大,Redis 撑不住怎么办?
第一步,分赛季:排行榜不必是全时间段累积,划分为「本赛季」「历史最高」等分段,控制单个 Sorted Set 的大小。第二步,分区域服务器:每个大区独立榜单,减少单榜数量级。第三步,如果仍超过 Redis 容量,可以用「分位数抽样」:精确维护前 Top N(如前 10 万),其余玩家的排名通过分位数估算而非精确计算,99% 玩家感知不到差异。
Q7:如何实现玩家的「好友对战」(私人房间)?
创建私人房间时,Room Manager 生成一个 6 位邀请码(存 Redis,TTL 10 分钟),房主分享给好友。好友输入邀请码后,Gateway 查询 Redis 获取目标房间 ID 和对应节点地址,直接路由过去。私人房间跳过 Matchmaking 队列,但进入相同的 Game Server 处理逻辑。
Q8:如何处理游戏中的「掉帧/网络抖动」导致的短暂卡顿?
客户端维护一个「预测缓冲区(Jitter Buffer)」,存储最近 3-5 帧的服务端数据;当网络抖动短暂丢包时,用本地预测(客户端推算的物理运动)填充,等服务端数据到来后做插值平滑(Interpolation),避免画面跳变。这是所有现代网络游戏的标配技术,也叫 Entity Interpolation。
Q9:游戏需要全球多地区部署,如何保证跨区数据一致性?
玩家账户和全球排行榜走「多主架构 + 最终一致」,允许跨区 ELO 同步有分钟级延迟;游戏内状态严格限制在单一地区节点内(玩家匹配时优先同区),不存在跨区实时同步问题。只有游戏结束后战绩需要同步到全球库,用 Kafka 异步复制即可。
Q10:如果要支持 100 人 Battle Royale(类似绝地求生),架构有什么变化?
100 人房间的状态广播量是 5v5 的 10 倍,且无法全量广播(带宽不够)。核心方案是「Interest Management(兴趣管理)」:每个玩家只接收其视野范围内(如 200 米)的其他玩家状态;地图划分为区块(Zone),服务端按玩家位置动态决定下发哪些实体数据。对象数量超过一定阈值(如 20 个可见实体)还要做 LOD(Level of Detail),远处玩家更新频率降低至 5Hz,近处玩家保持 20Hz。单房间通常需要专用进程(而非多房间共享),配备更多 CPU 核心。
🗺️ 七、学习路线图
延伸阅读方向
方向一:网络同步技术
加布里埃尔·格莱金(Gabriel Gambetta)的系列文章《Fast-Paced Multiplayer》是这个领域最清晰的入门材料,涵盖 Client-Side Prediction、Entity Interpolation、Lag Compensation 的完整原理。Valve 的白皮书《Latency Compensating Methods in Client/Server In-game Protocol Design and Optimization》是工业界的经典实践。
方向二:游戏服务器架构开源项目
研究 Nakama(开源游戏后端框架,Go 语言)和 Agones(Kubernetes 上的游戏服务器管理框架,Google 出品)。前者覆盖 Matchmaking、排行榜、聊天的完整实现;后者解决游戏服务器有状态扩缩容问题,两者结合是现代云游戏后端的事实参考架构。
方向三:实时通信底层
深入了解 QUIC 协议(RFC 9000),它是 UDP 上的多路复用传输层,已被 Epic Games 等用于生产环境。WebRTC 数据通道(DataChannel)也值得研究,它提供了 P2P 通信能力,可用于降低延迟(客户端之间直连,减少服务端中转)。
知识复用关系
| 本题知识点 | 复用场景 |
|---|---|
| WebSocket 长连接管理 | 设计实时聊天系统(如 Slack、Discord) |
| Redis Sorted Set 排行榜 | 设计股票行情系统、实时竞价系统 |
| Matchmaking 优先队列 + 动态放宽 | 设计打车系统(司机乘客撮合) |
| 有状态服务的 Graceful Drain | 设计任何有状态微服务的滚动更新策略 |
| Delta Compression + 增量同步 | 设计协作文档(Google Docs)的 OT/CRDT 同步 |
| Interest Management 分区域推送 | 设计外卖/地图类系统的 Geo-Fence 推送 |
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)