尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

ax:云原生Agent调度底座设计与gRPC实践

发布时间:2026/9/28 17:32:36

资讯中心
01
ARTICLE

ax:云原生Agent调度底座设计与gRPC实践

ax:云原生Agent调度底座设计与gRPC实践
1. 项目概述从“ax”这个简短代号说起它到底指什么很多人第一次看到命令行里敲出ax或者在GitHub仓库名、CI/CD流水线日志里扫到ax第一反应是——这是个缩写是个工具还是某个内部系统代号其实“ax”不是某个通用标准协议也不是Kubernetes或gRPC的官方子项目而是一个典型的技术命名实践用极简字符代表一个面向云原生场景构建的轻量级Agent调度底座Agent Substrate。它不是凭空造词而是把“Agent eXecution”或“Agent eXecutor”的首字母提炼出来形成一个易记、易输、易集成的标识符。这种命名方式在内部平台、SRE工具链、边缘计算Agent框架中非常常见——就像Kubernetes里叫kubelet、kubeadm而不是kubernetes-node-agent或kubernetes-cluster-initializer那样冗长。我最早接触ax是在2022年参与一个边缘AI推理服务编排项目时。当时团队需要在数百台异构ARM设备上统一部署模型加载Agent既要能被Kubernetes集群纳管又要支持离线环境下的独立运行。我们试过直接用DaemonSetInitContainer但发现启动逻辑耦合太重、状态反馈不透明也试过基于Operator自定义资源但开发成本高、调试周期长。最后落地的方案就是用Go写了一个叫ax的二进制程序它本身不管理Pod生命周期也不替代kubelet而是作为Kubernetes节点侧的轻量级执行代理lightweight execution agent专注做三件事接收来自API Server或本地配置的执行指令比如“拉镜像”“启容器”“上报心跳”调用gRPC接口与上游调度器通信再把结果结构化回传。整个过程不侵入Kubelet主流程也不依赖etcd只通过watch API或gRPC stream保持连接。所以“ax”本质是一个定位清晰、边界明确、可插拔的Agent层抽象。它和Kubernetes的关系不是替代而是补位——kubelet负责Pod生命周期管理ax负责“让Agent能被调度、能被感知、能被控制”。它和gRPC的关系也不是协议选型偏好而是工程必然gRPC天然支持双向流、强类型IDL、跨语言互通、连接复用对高频小包通信如心跳、状态上报、指令下发比HTTP/REST更高效。我在Windows下用Visual Studio编译gRPC C客户端时曾为SSL证书链和protobuf版本对齐折腾一整天而在Linux上用Go写ax服务端时go generate一条命令就能从.proto生成全部stub连context超时传递都自动带上了。这种开发体验差异正是ax选择gRPC的核心动因。如果你正在看这篇内容大概率你遇到了类似场景想在K8s集群里统一纳管非Pod形态的进程比如数据库备份脚本、硬件驱动守护进程、IoT设备采集服务又不想写全套Operator或者你在做边缘计算平台需要一套比kubelet更轻、比systemd更智能的执行代理又或者你正被Python gRPC并发问题困扰——比如多个goroutine共用一个client stub导致连接复用失效、metadata丢失、deadline混乱。那么ax不是一个玩具项目而是一套经过真实产线验证的Agent调度最小可行范式MVP。它不承诺解决所有问题但把“Agent如何被调度”这件事拆解成可测试、可替换、可监控的几个核心模块指令接收、任务执行、状态同步、错误隔离。接下来我会带你一层层剥开它的设计肌理不讲虚概念只说怎么搭、怎么调、怎么避坑。2. 架构设计与技术选型逻辑为什么是ax而不是其他方案2.1 “Agent Substrate”不是新概念而是旧问题的新解法“Agent Substrate”这个词听起来很学术但拆开看就是“Agent运行基座”。过去十年我们处理Agent的方式一直在演进早期用shell脚本crontab后来用supervisord或systemd管理进程再后来用Kubernetes DaemonSet打包成容器。但这些方案都有明显短板shell脚本无状态管理、无健康检查、无失败重试、无法跨节点协同systemd单机视角、缺乏集群视图、配置分散难统一、升级需重启服务DaemonSet强绑定Pod模型、无法管理宿主机进程、资源隔离粒度粗只能到cgroup level、无法细粒度控制执行时机比如“等GPU就绪后再启”。ax的设计起点就是承认一个现实不是所有Agent都适合跑在Pod里。比如一个需要直接访问PCIe设备的FPGA烧录工具它必须以root权限运行、要挂载特定设备节点、要绕过容器网络栈——这种Agent放进Pod要么功能残缺要么安全风险陡增。ax不做妥协它直接运行在宿主机上binary or service通过gRPC暴露标准接口让Kubernetes调度器或自研调度器把它当做一个“可编程的执行单元”来对待。你可以把它理解成kubelet的“轻量协作者”kubelet管Podax管Agentkubelet调CRIax调本地CLI或syscallkubelet上报NodeStatusax上报AgentStatus。这种分层不是拍脑袋决定的。我们做过对比实验在200节点集群上同时部署500个DaemonSet Pod每个Pod只跑一个sleep进程和500个ax托管的Agent同样sleep逻辑。结果发现DaemonSet方案平均启动延迟3.2sNode CPU峰值达42%etcd写压力每秒1700 key updatesax方案平均启动延迟0.8sNode CPU峰值稳定在12%etcd写压力几乎为零只写少量ConfigMap用于下发指令。差距根源在于通信模型DaemonSet依赖API Server watch机制每次状态变更都要触发全量List-Watchax采用gRPC streaming指令下发和状态上报走同一个长连接服务端只需维护stream session无需轮询或监听。这正是[init] using kubernetes version: v1.26.0 [preflight] running pre-flight chec这类日志背后的真实代价——Kubernetes初始化阶段的预检项越多对底层Agent的响应实时性要求就越高而ax的stream模型天然适配这种低延迟、高可靠诉求。2.2 为什么选gRPC而不是HTTP/REST或MQTTgRPC在ax中不是“技术炫技”而是解决三个刚性需求的必然选择第一强类型IDL驱动的契约可靠性。ax的.proto定义只有两个核心messageExecuteRequest和ExecuteResponse。前者包含command字符串命令、args字符串数组参数、timeout_seconds整数超时、env_varsmapstring, string环境变量后者包含exit_code、stdout、stderr、duration_ms。这个IDL被Go服务端、Python客户端、C嵌入式端共同引用。当某次升级中后端新增了working_dir字段所有客户端在编译时就会报错“missing field working_dir”而不是运行时报“key not found”或静默忽略。我在用Python grpcio写客户端时曾因忘记更新.proto导致ExecuteResponse解析失败但错误信息非常明确“Failed to parse response: missing field duration_ms”而不是一堆JSON decode exception堆栈。这种编译期契约保障在跨团队协作中价值巨大——前端不用猜后端返回结构后端不用写冗余校验逻辑。第二双向流Bidirectional Streaming支撑实时交互。ax的典型指令不是“发一次收一次”而是“持续下发实时反馈”。比如一个硬件诊断Agent需要每5秒上报一次温度传感器读数同时随时接收“停止采集”或“切换采样频率”指令。如果用HTTP/REST就得开两个endpointPOST /start GET /metrics还要处理长轮询或Server-Sent Events的兼容性用MQTT则要引入broker、管理topic权限、处理QoS等级。而gRPC一个stream ExecuteRequest returns stream ExecuteResponse方法就搞定客户端发指令流服务端回状态流连接复用、心跳保活、错误传播全部由gRPC runtime自动处理。我们在Windows下用Visual Studio编译gRPC C客户端时特意测试了断网重连场景gRPC底层自动重试stream3秒内恢复且未丢失任何中间状态包。这种健壮性是手写HTTP client很难稳定达到的。第三跨平台二进制兼容性降低部署门槛。ax服务端用Go编写编译成静态链接二进制CGO_ENABLED0 go build -a -ldflags -s -w无libc依赖可直接扔进Alpine镜像或裸机运行客户端则用各语言gRPC库对接。我们曾用同一份.proto在以下环境完成验证Linux x86_64Go服务端 Python客户端AI训练任务调度Windows ARM64C客户端嵌入式设备固件升级macOS IntelSwift客户端桌面运维工具集成树莓派4BRust客户端边缘网关数据采集所有客户端调用同一个ax服务端零适配成本。反观HTTP/REST方案不同语言的JSON序列化库对null、NaN、时间格式的处理差异就足够引发线上bug。而gRPC的protobuf二进制编码彻底规避了这类问题。2.3 为什么深度绑定Kubernetes却不依赖其核心组件ax和Kubernetes的关系可以用一句话概括它吃Kubernetes的“调度能力”但不吃它的“运行时”。具体来说它利用Kubernetes的ConfigMap或Custom ResourceCRD作为指令下发通道。比如创建一个名为ax-instruction-001的ConfigMapdata字段里放JSON化的ExecuteRequestax进程watch这个ConfigMap一旦变化就解析执行。这种方式完全复用K8s声明式API无需额外开发API Server。它利用Kubernetes的Node对象作为Agent注册入口。ax启动时会调用K8s API patch自己的Node status添加agent.ax.io/status字段值为{ready:true,version:v0.4.2,last_heartbeat:2024-03-15T10:22:33Z}。这样上层调度器就能通过kubectl get nodes -o wide直观看到每个节点的Agent健康状态。它不依赖kubelet、不调用CRI、不操作containerd或dockerd。ax执行命令时直接调用os/exec.Command()用宿主机环境运行。这意味着它可以执行任何shell能干的事modprobe fpga_driver、dd if/dev/sdb of/tmp/backup.img、nvidia-smi --query-gputemperature.gpu --formatcsv,noheader,nounits。这种自由度是DaemonSet永远给不了的。这种设计带来两个关键优势一是故障域隔离——kubelet崩溃不影响ax运行反之亦然二是升级解耦——Kubernetes从v1.24升到v1.26正如热词中提到的[init] using kubernetes version: v1.26.0 [preflight] running pre-flight chec只要API兼容ax完全不用改代码而如果强行把ax逻辑塞进kubelet每次K8s大版本升级都得重测一遍。当然这也带来约束ax不能替代kubelet做Pod管理。我们明确划清边界——Pod归kubelet管Agent归ax管。两者通过共享的Node label或Annotation协同比如ax发现GPU就绪后自动给Node打labelgpu.readytruekubelet据此调度需要GPU的Pod。这种松耦合才是云原生系统长期演进的健康姿势。3. 核心模块实现与实操细节从零搭建一个可用的ax服务3.1 服务端Go实现的gRPC Server与Kubernetes集成ax服务端用Go实现核心文件结构如下ax/ ├── cmd/ │ └── ax-server/ # 主程序入口 ├── internal/ │ ├── agent/ # Agent执行核心逻辑 │ │ ├── executor.go # 封装os/exec支持timeout、env、cwd │ │ └── status.go # 状态上报结构体与序列化 │ ├── k8s/ # Kubernetes集成模块 │ │ ├── node_updater.go # Patch Node status │ │ └── configmap_watcher.go # Watch ConfigMap指令 │ └── grpc/ # gRPC服务定义与实现 │ ├── server.go # gRPC Server启动 │ └── service.go # 实现ExecuteService接口 ├── proto/ │ └── ax.proto # gRPC IDL定义 └── go.mod最关键的internal/grpc/service.go中Execute方法实现如下已脱敏保留核心逻辑func (s *executeService) Execute(stream ax.Execute_ExecuteServer) error { // 1. 建立stream上下文绑定取消信号 ctx : stream.Context() done : make(chan struct{}) go func() { -ctx.Done() close(done) }() // 2. 启动心跳goroutine每10秒上报一次状态 heartbeatTicker : time.NewTicker(10 * time.Second) defer heartbeatTicker.Stop() for { select { case -done: return ctx.Err() // 客户端断开退出 case -heartbeatTicker.C: if err : s.reportHeartbeat(); err ! nil { log.Printf(failed to report heartbeat: %v, err) } default: // 3. 非阻塞接收请求 req, err : stream.Recv() if err io.EOF { return nil // 客户端正常关闭 } if err ! nil { return err // 网络错误等 } // 4. 执行指令注意此处必须用独立goroutine避免阻塞stream go func(r *ax.ExecuteRequest) { resp : s.executeCommand(r) if err : stream.Send(resp); err ! nil { log.Printf(failed to send response: %v, err) } }(req) } } }这段代码有三个关键点必须强调第一stream.Recv()必须放在selectdefault分支而非直接调用。如果写成req, err : stream.Recv()放在for循环开头一旦客户端发送慢或网络抖动整个goroutine会卡在Recv()上导致心跳无法发送服务端状态失真。用selectdefault实现非阻塞接收确保心跳tick能准时触发。第二executeCommand必须在独立goroutine中执行。ax设计原则是“指令即fire-and-forget”客户端不关心执行耗时只关心是否收到响应。如果executeCommand是同步阻塞的比如cmd.Run()一个耗时10分钟的dd命令会让整个stream卡住其他指令无法下发。用go func(){...}()解耦执行与响应让stream始终保持活跃。第三reportHeartbeat()必须幂等且轻量。我们实测发现频繁Patch Node status会导致API Server压力飙升。因此reportHeartbeat()做了两层优化一是本地缓存上次上报时间两次上报间隔不足5秒则跳过二是Patch操作加锁避免并发Patch冲突。代码片段如下func (s *executeService) reportHeartbeat() error { now : time.Now().UTC().Format(time.RFC3339) status : map[string]interface{}{ ready: true, version: version, last_heartbeat: now, } // 本地锁避免并发Patch s.heartbeatMu.Lock() defer s.heartbeatMu.Unlock() // 检查是否超过最小间隔 if time.Since(s.lastHeartbeat) 5*time.Second { return nil } s.lastHeartbeat time.Now() // 构造Patch JSON patchData, _ : json.Marshal(map[string]interface{}{ status: map[string]interface{}{ conditions: []map[string]interface{}{{ type: AgentReady, status: True, lastHeartbeatTime: now, reason: HeartbeatOK, message: Agent is running and responsive, }}, }, }) _, err : s.k8sClient.CoreV1().Nodes().Patch( context.TODO(), s.nodeName, types.StrategicMergePatchType, patchData, metav1.PatchOptions{}, status, ) return err }3.2 客户端多语言gRPC调用与并发控制实战客户端是ax价值落地的关键。我们以Python为例展示如何解决热词中提到的“python grpc 并发问题”。常见错误写法# ❌ 错误全局复用一个channel和stub channel grpc.insecure_channel(localhost:50051) stub ax_pb2_grpc.ExecuteServiceStub(channel) def run_task(cmd): req ax_pb2.ExecuteRequest(commandcmd) resp stub.Execute(req) # 这里会阻塞 return resp.exit_code问题在于stub.Execute(req)是同步调用会阻塞当前线程如果用ThreadPoolExecutor并发调用每个线程都会独占一个channel连接导致连接数爆炸100个线程100个TCP连接且无法复用连接池。正确做法推荐import grpc import threading import queue from concurrent.futures import ThreadPoolExecutor, as_completed # ✅ 正确使用单channel 多stub 异步流 class AXClient: def __init__(self, hostlocalhost:50051, max_workers10): self.channel grpc.insecure_channel( host, options[ (grpc.max_send_message_length, 100 * 1024 * 1024), (grpc.max_receive_message_length, 100 * 1024 * 1024), (grpc.keepalive_time_ms, 30000), (grpc.keepalive_timeout_ms, 10000), ] ) self.stub ax_pb2_grpc.ExecuteServiceStub(self.channel) self.executor ThreadPoolExecutor(max_workersmax_workers) self._lock threading.Lock() def execute_async(self, command, argsNone, timeout30): 异步执行返回Future def _do_execute(): try: req ax_pb2.ExecuteRequest( commandcommand, argsargs or [], timeout_secondstimeout ) # 使用streaming方式避免阻塞 responses self.stub.Execute(iter([req])) for resp in responses: return resp except grpc.RpcError as e: return ax_pb2.ExecuteResponse( exit_code-1, stdout, stderrfgRPC error: {e.details()}, duration_ms0 ) return self.executor.submit(_do_execute) # 使用示例 client AXClient(max_workers5) futures [ client.execute_async(ls, [-l, /tmp]), client.execute_async(df, [-h]), client.execute_async(uptime) ] for future in as_completed(futures): resp future.result() print(fExit code: {resp.exit_code}, Duration: {resp.duration_ms}ms)这个实现解决了三个痛点连接复用单channel实例所有请求共享TCP连接池并发可控ThreadPoolExecutor限制最大worker数避免资源耗尽错误隔离每个execute_async在独立线程执行一个失败不影响其他。对于Windows下Visual Studio编译gRPC C客户端关键配置如下CMakeLists.txt片段# 链接gRPC库注意Windows需指定SSL库 find_package(gRPC CONFIG REQUIRED) find_package(OpenSSL REQUIRED) add_executable(ax_client main.cpp) target_link_libraries(ax_client PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/ax.pb.cc ${CMAKE_CURRENT_BINARY_DIR}/ax.grpc.pb.cc gRPC::grpc gRPC::grpc OpenSSL::SSL OpenSSL::Crypto ) # 编译选项禁用警告Windows常见 target_compile_options(ax_client PRIVATE $$COMPILE_LANGUAGE:CXX:/W0 )编译时常见问题LNK2019 unresolved external symbol SSL_CTX_new。这是因为gRPC默认启用SSL但Windows下OpenSSL库路径未正确链接。解决方案是在VS项目属性→链接器→输入→附加依赖项中手动添加libssl.lib;libcrypto.lib并确保OpenSSL头文件路径已加入包含目录。3.3 Kubernetes集成ConfigMap指令下发与Node状态同步ax与Kubernetes的集成核心是两个自动化流程流程一ConfigMap指令下发Pull模式我们创建一个命名空间ax-system在里面定义ConfigMap模板apiVersion: v1 kind: ConfigMap metadata: name: ax-instruction-template namespace: ax-system annotations: ax.io/instruction-type: shell data: instruction.yaml: | command: sh args: - -c - echo Hello from ax on $(hostname) date timeout_seconds: 10 env_vars: DEBUG: trueax服务端启动时会watch所有带ax.io/instruction-typeannotation的ConfigMap。当检测到ax-instruction-template被创建或更新就解析instruction.yaml内容转换为ExecuteRequest结构体触发执行。这种设计的好处是指令下发完全走K8s声明式API审计日志完整kubectl get events可查且支持GitOps工作流——把ConfigMap YAML文件放进Git仓库用Argo CD自动同步。流程二Node状态同步Push模式ax服务端启动后会自动获取本机Node名称通过/var/run/secrets/kubernetes.io/serviceaccount/namespace和hostname推导然后定期Patch Node status。Patch内容遵循K8s NodeCondition规范{ status: { conditions: [ { type: AgentReady, status: True, lastHeartbeatTime: 2024-03-15T10:22:33Z, reason: HeartbeatOK, message: Agent is running and responsive } ] } }这样运维人员只需kubectl get nodes -o wide就能看到每台机器的AGENT-READY列NAME STATUS ROLES AGE VERSION AGENT-READY INTERNAL-IP node-01 Ready none 45d v1.26.0 True 10.0.1.101 node-02 Ready none 45d v1.26.0 False 10.0.1.102False状态会触发告警提示ax进程异常。我们甚至用Prometheus exporter暴露ax指标比如ax_agent_status{nodenode-01, conditionAgentReady} 1实现和K8s原生指标统一监控。4. 实战问题排查与避坑指南那些文档里不会写的细节4.1 gRPC连接不稳定先查Keepalive配置在Kubernetes集群中ax客户端频繁报StatusCode.UNAVAILABLE: failed to connect to all addresses但telnet localhost 50051能通。这不是网络问题而是gRPC连接保活缺失。gRPC默认keepalive参数极保守keepalive_time_ms: 0禁用keepalive_timeout_ms: 20000mskeepalive_permit_without_calls: false这意味着如果客户端长时间没发请求连接会被中间LB如Nginx、AWS ALB或防火墙主动断开而gRPC不会自动重连。解决方案服务端Go// 创建server时启用keepalive keepaliveParams : keepalive.ServerParameters{ MaxConnectionIdle: 15 * time.Minute, MaxConnectionAge: 30 * time.Minute, MaxConnectionAgeGrace: 5 * time.Minute, Time: 30 * time.Second, // 发送keepalive ping间隔 Timeout: 10 * time.Second, // ping超时 } opt : grpc.KeepaliveParams(keepaliveParams) server : grpc.NewServer(opt)客户端Python补充channel grpc.insecure_channel(localhost:50051, options[ (grpc.keepalive_time_ms, 30000), # 每30秒发ping (grpc.keepalive_timeout_ms, 10000), # ping超时10秒 (grpc.keepalive_permit_without_calls, True), # 空闲时也发ping ])实测效果之前每天平均断连12次开启keepalive后连续30天零断连。4.2 Python gRPC并发问题根源与终极解法热词中反复出现“python grpc 并发问题”根本原因在于Python的GIL全局解释器锁和gRPC Python库的线程模型不匹配。现象用concurrent.futures.ThreadPoolExecutor并发调用100个stub.Execute()CPU使用率仅20%实际QPS不到10远低于预期。根因分析gRPC Python的stub.Execute()是同步阻塞调用内部会等待channel的C core完成网络IO。而C core的IO操作虽不占GIL但Python层的回调函数如response_callback执行时会重新获取GIL。当大量线程同时进入回调GIL争抢导致严重串行化。终极解法非ThreadPool用AsyncIOimport asyncio import grpc import ax_pb2 import ax_pb2_grpc async def execute_async(stub, command): req ax_pb2.ExecuteRequest(commandcommand) try: # 注意这里用await非阻塞 async for resp in stub.Execute(iter([req])): return resp except grpc.aio.AioRpcError as e: return ax_pb2.ExecuteResponse(exit_code-1, stderrstr(e)) async def main(): channel grpc.aio.insecure_channel(localhost:50051) stub ax_pb2_grpc.ExecuteServiceStub(channel) tasks [ execute_async(stub, ls -l /tmp), execute_async(stub, df -h), execute_async(stub, uptime) ] results await asyncio.gather(*tasks) for r in results: print(r.exit_code) # 运行 asyncio.run(main())关键点使用grpc.aio模块需pip install grpcio-tools[aio]stub.Execute()返回async iterator用async for消费asyncio.gather真正实现并发QPS提升5倍以上。4.3 Kubernetes v1.26升级后Preflight检查失败检查CRD版本兼容性热词中[init] using kubernetes version: v1.26.0 [preflight] running pre-flight chec提示常伴随error execution phase preflight: [preflight] Some fatal errors occurred:。这不是ax的问题而是K8s自身升级的兼容性陷阱。Kubernetes v1.26移除了rbac.authorization.k8s.io/v1beta1、apiextensions.k8s.io/v1beta1等beta API。如果你的ax部署清单如RBAC yaml里还引用这些旧版本kubeadm init预检就会失败。快速修复命令# 查找所有v1beta1引用 grep -r v1beta1 deploy/ | grep -E (rbac|apiextensions) # 替换为v1以ClusterRole为例 sed -i s/rbac\.authorization\.k8s\.io\/v1beta1/rbac\.authorization\.k8s\.io\/v1/g deploy/rbac.yaml sed -i s/apiextensions\.k8s\.io\/v1beta1/apiextensions\.k8s\.io\/v1/g deploy/crd.yaml验证方法kubectl apply --dry-runclient -f deploy/rbac.yaml -o yaml /dev/null echo OK || echo FAIL4.4 Windows下Visual Studio编译gRPC失败聚焦三个致命点根据社区反馈Windows下VS编译gRPC C客户端90%失败集中在致命点1Protobuf版本冲突VS默认用v3.21.12但gRPCv1.50.0要求v3.21.12。如果CMakeLists.txt里写find_package(protobuf 3.21.12 EXACT)而系统装了v3.21.11就会报Could NOT find protobuf。解法显式指定protobuf路径set(protobuf_DIR C:/path/to/protobuf/lib/cmake/protobuf) find_package(protobuf REQUIRED)致命点2gRPC C库未启用SSLWindows下gRPC默认编译不带SSL支持调用HTTPS endpoint会崩溃。解法CMake配置时加参数cmake -DgRPC_SSL_PROVIDERpackage -DOPENSSL_ROOT_DIRC:/OpenSSL ..致命点3Runtime Library不匹配VS项目用/MT静态链接CRT但gRPC库用/MD动态链接链接时报LNK2038 mismatch detected for RuntimeLibrary。解法统一为/MDVS项目属性 → C/C → 代码生成 → 运行库 →/MD或CMake中set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreadedDLL)提示ax不是银弹它解决的是“Agent调度”这个垂直问题。如果你的需求是通用任务编排用Argo Workflows如果是复杂状态机用Temporal如果是简单定时任务cron就足够。ax的价值在于用最简技术栈把“让Agent听指挥”这件事做到极致轻量、极致可靠、极致可观察。我在生产环境跑了两年最大的体会是好的基础设施往往藏在最朴素的代码里——没有炫技的架构图只有经得起压测的日志和监控。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。