1. 为什么Kafka会跟AI走到一起,我先交代背景
这大半年我一直在折腾公司的AI中台,说直白点,就是把大模型、向量库、RAG这些能力真正落到业务里。一开始方案很简单:业务服务直接HTTP调用AI服务,请求过去、结果回来,上线跑了两周也能用。可等流量一上来,问题全暴露了——AI推理慢,下游请求排队;突发流量把AI服务打满,花钱扩容又扛不住波峰;更头疼的是业务侧想把用户行为、上下文、反馈这些消息串起来喂给模型,HTTP同步链路根本做不了异步解耦。这时候团队里有人提了一句:要不要把Kafka接进来?
这个提议我一开始是犹豫的。Kafka是老牌消息队列了,大数据场景里很成熟,但和AI放在一起总觉得有点怪。后来调研了一圈,发现业界早就在这么做:AI应用的事件驱动架构、推理请求异步化、RAG知识库的数据同步,基本都是用Kafka当数据动脉。说白了,Kafka真正解决的是AI链路里的"流量削峰"和"数据流转"两个最头疼的问题。
所以我决定把Kafka正式接入AI平台。这篇文章我把整个过程的思考、架构、踩坑全部记录下来。适合谁看?正在搞AI应用开发、自己搭RAG流程、被AI服务高并发折磨过的后端工程师,以及那些准备把AI能力产品化的技术负责人。看完你能少走很多弯路。
2. 整体设计思路:Kafka在AI链路里到底承担什么角色
2.1 AI项目为什么需要消息队列,而不是继续用HTTP
先说一个很多人问我的问题:AI服务不就是"发个请求-拿个结果"吗?为什么非要多插一个Kafka进去,这不是增加复杂度吗?
我第一次也是这么想的,但实际把AI应用拆开看,你会发现真正的AI生产链路远远比"一次推理"复杂。举个我们线上项目的例子:一个智能文档助手,用户上传文档后,系统要执行文档解析、分块、向量化、写入向量库、同步元数据、触发模型生成摘要、推送事件通知。这里面每一步耗时差异极大,向量化可能几十毫秒,大模型摘要可能要几十秒。如果用HTTP同步调,用户上传一次文档,请求得挂在那里等一分钟。但用Kafka把整个流程拆成异步事件流,用户上传完立刻得到"已受理"的响应,后台各环节各自消费消息、独立处理,体验完全不一样。
所以Kafka在AI里的角色,本质上是一根"异步消息总管"。它让AI链路里快的环节不等慢的环节,削峰填谷,同时所有AI事件都有记录,可以回溯、重放、审计。这是HTTP直连完全给不了的能力。
2.2 我规划的三种Topic,对应AI三大类数据流
接入Kafka之前,最重要的不是写代码,而是先梳理业务里面到底有哪些"流"。我根据自己的项目情况,把AI相关的Topic分成了三类,每一类的数据特征和消费方式都不一样:
第一类是业务事件流,前缀业务领域命名。比如用户操作、文档上传、反馈提交。这类消息量大、实时性要求高、允许短暂丢失,主要用于触发AI服务的调用。我管它叫触发型数据,核心诉求是快。
第二类是特征数据流,给AI模型喂的上下文。这个比较关键。比如用户的浏览序列、历史对话记录、个性化标签,这些数据原来散落在各个微服务里,现在统一进Kafka,AI服务消费后构建完整的模型输入。这类数据要求顺序性和完整性,所以分区策略必须仔细设计。
第三类是结果回写流,AI推理结果出来后要回传业务系统。比如审核结论、推荐结果、生成的内容,这类数据要保证不丢,通俗讲就是"必须到账",我会把acks参数设置得很严格。
我踩过的一个坑是想着一条Topic打天下,后来发现不同类型的数据混在一起,消费组能力和业务隔离都做不好,一旦某个环节消费慢会连带拖垮所有流程。所以分类Topic看起来啰嗦,实际上是从根上给系统留了解耦的余地。
2.3 选Kafka而不是RabbitMQ,我的具体理由
聊架构的时候经常被问到:"你有RabbitMQ了,为什么还选Kafka接AI?"这个问题我专门做过对比,直接放结论:RabbitMQ适合任务分发,Kafka适合数据流管道,AI场景里优先级恰恰是"大数据量、顺序性、可重放",这几项正好都是Kafka的强项。
几个硬指标大家参考:Kafka单分区能保持顺序写入,单机轻松扛十万级消息吞吐;消息默认保留7天,组可以在任何时候从历史偏移位置重新消费,这对AI调参、模型回放训练事件、出bug后数据修复来说太重要了。RabbitMQ消费确认后消息就删了,没有重放能力,AI批量重算时就抓瞎。虽然Kafka在路由灵活性上不如RabbitMQ,但在AI链路里,消息量级和重放需求压倒一切,所以我选Kafka没悬念。
3. 环境搭建与基础配置,这一步必须扎实
3.1 Docker一键搭建Kafka集群的实操记录
我自己本地调试用的是Docker单机,生产环境是3节点集群。先给一个最实用的Docker部署方案,很多人卡在环境上,我直接贴我验证过的配置:
version: '3' services: zookeeper: image: bitnami/zookeeper:3.9 container_name: zk ports: - "2181:2181" environment: - ALLOW_ANONYMOUS_LOGIN=yes kafka1: image: bitnami/kafka:3.6 container_name: kafka1 depends_on: - zookeeper ports: - "9092:9092" environment: - KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181 - KAFKA_CFG_BROKER_ID=1 - KAFKA_CFG_LISTENERS=PLAINTEXT://0.0.0.0:9092 - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092 - ALLOW_PLAINTEXT_LISTENER=yes volumes: - kafka_data1:/bitnami/kafka kafka2: image: bitnami/kafka:3.6 container_name: kafka2 depends_on: - zookeeper ports: - "9093:9092" environment: - KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181 - KAFKA_CFG_BROKER_ID=2 - KAFKA_CFG_LISTENERS=PLAINTEXT://0.0.0.0:9092 - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9093 - ALLOW_PLAINTEXT_LISTENER=yes volumes: - kafka_data2:/bitnami/kafka volumes: kafka_data1: kafka_data2:注意几个坑:ADVERTISED_LISTENERS必须配成客户端实际能访问的地址,我见过很多人在容器里能连,宿主机反而连不上的情况,基本都是这个参数写错了。还有,如果你本地是Mac或Windows,localhost没问题;如果是远程服务器,这里要改成服务器IP。另外Kafka从2.8开始已经在转向KRaft模式,不依赖ZooKeeper了,但很多公司线下还是ZooKeeper模式。我生产环境为了稳定,用的还是ZooKeeper模式,这是保守选择。
启动命令很简单,docker-compose up -d,然后看一下状态:
docker-compose ps看到两个Kafka容器都healthy就说明起来了。生产环境建议用KRaft或者单独的ZooKeeper集群,别把状态节点和业务节点混在一个Docker Compose里,不然重建容器时元数据会丢。
3.2 创建Topic时必须想清楚的三个参数
Kafka的Topic创建不是随手一个命令就完事,分区数、副本数、消息保留时间这三个参数,一定要根据AI场景提前规划。我见过很多团队Topic建完了,后面想改分区数,整个顺序全乱,惨不忍睹。
我们以AI业务事件流为例,我创建时的命令长这样:
kafka-topics.sh --bootstrap-server localhost:9092 \ --create --topic ai-business-events \ --partitions 12 \ --replication-factor 2 \ --config retention.ms=172800000 \ --config cleanup.policy=delete分区数的选择要看消费端并行度。我们AI服务起了6个实例,分区数取12,是实例数的2倍,这样每个实例最多同时消费2个分区,并行度有余量,未来扩容实例数到10个也不用马上改分区。如果分区数小于消费者数,会有消费者闲着,浪费资源。
副本数2,是考虑到只有一个测试机器,但形成习惯:生产环境至少2副本,核心Topic必须3副本。Kafka不是说副本越多越好,副本要占磁盘,也影响写入性能,但都2副本都不到的话,broker挂一个,整个分区就没主了。
retention.ms设置的是消息保留时间。AI场景里我建议保留48小时以上,因为模型调优经常要重放两三天的数据。有些数据量大的Topic,我会加一条cleanup.policy=compact,保留最新的key状态,这种一般给特征数据流用,避免全量重放时把Kafka磁盘打爆。
3.3 生产消费命令验证,一条命令足以暴露配置问题
服务起来之后,我习惯先手动生产消费几条数据验证链路连通性。很多人觉得这一步多余,直接写代码调试,结果一报错分不清是Kafka的问题还是代码的问题。
# 打开生产者终端 kafka-console-producer.sh --bootstrap-server localhost:9092 \ --topic ai-business-events # 输入一条消息 {"event":"document_upload","doc_id":"abc123","user_id":"10001"}再开一个终端:
kafka-console-consumer.sh --bootstrap-server localhost:9092 \ --topic ai-business-events \ --from-beginning如果生产者敲完回车,消费者这边立刻打印出消息,说明Kafka本身没问题。这里有个小细节:消费者加--group参数后,--from-beginning只在offset不存在时生效。如果你之前消费过,又想重新看全量数据,要么换一个group id,要么加--from-beginning配合新组名,这个逻辑非常容易绕晕,记不住的话直接换组名最省事。
问一句热词里提到"kafka生产消费命令启动一次会一直运行吗",答案是会。console-consumer默认就是持续监听模式,不会消费完就退出,除非你按Ctrl+C。这也是Kafka和普通队列的一个区别,它没有"取完即止"的概念,消费者更像是一个订阅者,一直等着新消息来。
4. 核心环节实现:Kafka如何真正驱动AI服务干活
4.1 生产者侧:把业务事件送进Kafka的关键配置
接下来是代码层面,这部分是整个接入的重点。我们的业务后端是Java Spring Boot,用了spring-kafka。先看生产者的配置:
spring: kafka: bootstrap-servers: localhost:9092 producer: key-serializer: org.apache.kafka.common.serialization.StringSerializer value-serializer: org.apache.kafka.common.serialization.StringSerializer acks: 1 retries: 3 batch-size: 16384 linger-ms: 5 buffer-memory: 33554432关键参数我一个个解释。acks有三个值:0代表不等待broker确认,速度最快但可能丢;1代表leader写入成功就返回,绝大多数场景够用;-1(all)代表所有副本都写入成功才返回,最安全但最慢。我们的业务事件Topic我用了acks=1,因为这类数据丢了影响可控,但AI推理触发消息漏了会导致用户看到"卡住没反应",所以我的AI触发Topic单独配了acks=-1。
retries是发送失败后的重试次数,默认值其实很大,但我喜欢显式设置成3,结合delivery.timeout.ms一起用,防止无脑重试。这里的坑是:retries设置了但没开enable.idempotence,极端情况下会重复写入消息。所以生产环境我建议直接加一行:
enable-idempotence: true开启幂等后,Kafka会为每次写入加序列号,broker端自动去重,配合acks=all,基本不会出现多写少写的情况。代价是吞吐量下降一些,AI场景绝对值得。
还有一个参数linger.ms要解释一下。Kafka发送消息不是一条一条立刻发的,而是一批一批攒着发,linger.ms=5表示最多等5毫秒。这个看起来不起眼,但对高性能推送很关键。你可以把生产者想象成快递员,攒够一车再发,省的趟趟跑,但如果你追求极低延迟(比如实时弹幕),这个值就设小;如果是批量喂给AI的特征数据,调大一点反而吞吐更高。
发送消息的代码很简单:
kafkaTemplate.send("ai-business-events", userId, jsonString);这里的第二个参数是key,我传了userId,这样同一个用户的所有事件会进同一个分区,从根本上保证同一个用户的事件顺序。这个设计在之前一直没注意到,直到我们做AI上下文拼接时发现用户的对话顺序错乱了,排查了半天才定位到是分区key导致的——因为不同分区内部的顺序是固定的,但跨分区之间没有全局顺序。所以凡是顺序敏感的消息,key必须精心设计。
4.2 消费者侧:让AI服务异步消费消息并推理
再来看消费者的实现。这是最核心的一段,AI服务监听Topic,来一条消息就直接调用大模型推理,然后回写结果。
@Component public class AIInferenceConsumer { @KafkaListener(topics = "ai-infer-request", groupId = "ai-infer-group", concurrency = "6") public void onMessage(ConsumerRecord<String, String> record) { // 1. 解析消息里的业务参数 InferRequest request = JSON.parseObject(record.value(), InferRequest.class); // 2. 调用大模型服务 String result = llmService.infer(request.getPrompt(), request.getContext()); // 3. 回写结果 kafkaTemplate.send("ai-infer-result", request.getRequestId(), result); // 4. 手动提交offset ackMode = AckMode.MANUAL_IMMEDIATE; } }这段代码有三个点要注意。第一,groupId决定了多个实例消费时的分担方式,同一个组里的实例会平分分区,不同组之间是相互独立的。比如我们有AI审核服务和AI推荐服务都订阅同一个事件Topic,如果它们用同一个groupId,就变成轮流消费了,这是错的。一定要为不同数据消费者创建不同的groupId,才能实现"一份消息多处消费"。
第二,concurrency参数要和分区数匹配。我前面建了12个分区,这里concurrency=6,每个实例消费两个分区。如果concurrency超过了分区数,多出来的线程就闲置着,看着有线程数,实际都在空转。
第三,关于offset提交,我强烈建议AI场景用手动提交。为什么?因为AI推理的失败率比普通业务高,比如模型超时、上下文过长、API限流。如果用默认的自动提交,消息拉到本地就提交offset,结果AI推理抛异常了,这条消息也消费完了,直接就丢了,而且不会有任何重试。手动提交至少给我们一个机会,在异常时决定是重试、还是进死信、还是把消息重新发回Topic。
手动提交的配置如下:
spring: kafka: consumer: enable-auto-commit: false auto-offset-reset: latest注意auto-offset-reset的值:earliest表示找不到偏移量时从最早开始消费,latest表示从最新开始。AI场景里,我们通常用latest,因为旧的业务事件重放太多次意义不大。但我做特征数据流的消费者时改成了earliest,这类数据需要全量到齐再拼上下文,从头消费反而更稳妥。
4.3 用Kafka给RAG知识库做实时同步,这是最实用的一环
大模型应用绕不开RAG,RAG绕不开向量库和知识库的同步。过去我写了一大堆定时任务,每隔几分钟全量扫描数据库,把新增数据塞进向量库,效率低,实时性差,数据库压力还大。这个项目里我直接改成Kafka驱动,体验好了不是一个级别。
做法是:文档编辑服务每保存一次,就往ai-rag-sync这个Topic发一条消息,消息里带着文档ID、变更类型。向量化消费者收到消息后,调用Embedding模型生成向量,写入向量库,更新知识索引。
@KafkaListener(topics = "ai-rag-sync", groupId = "rag-sync-group") public void syncKnowledge(ConsumerRecord<String, String> record) { DocEvent event = JSON.parseObject(record.value(), DocEvent.class); switch (event.getAction()) { case "create": case "update": // 重新读取文档内容 -> 分块 -> embedding -> 覆盖写入向量库 embeddingService.syncDocument(event.getDocId()); break; case "delete": embeddingService.removeDocument(event.getDocId()); break; } }这个场景里Kafka的价值有两个:一是解耦,文档服务和向量同步服务不用同步调用,文档服务只管发消息,向量同步扛不住高并发时就慢慢消费,天然形成背压;二是重放能力强,如果向量库的数据坏了,或者Embedding模型升级需要重新生成向量,把消费组reset到最早offset,消息会从头再来一遍,相当于天然的重建工具。实测下来,我们几百万条知识分片的重建时间从原来的数小时缩短到几十分钟,还不用写专门的脚本。
4.4 AI Agent事件流,一个我推荐大家都试试的玩法
今年AI agent概念很火,我自己也搞了一个简单的智能助手agent。这个agent会执行多步操作:先理解用户意图,再调用工具查数据,最后用大模型生成回复。原来的实现是纯函数式的,所有步骤在一个请求里顺序执行,一旦某一步卡住,整个请求就挂了。后来我用Kafka把agent的事件流串起来,效果出奇地好。
实现的思路是:每个agent执行实例有一个全局唯一的traceId,所有步骤的事件都发到同一个分区。比如"用户提问"事件进Topic,agent编排消费者收到后,解析意图,然后发出"调用工具"事件;工具消费者处理完,再发"模型生成"事件;最后生成事件被另一个消费者收下,最终回复推送给用户。整个过程是异步的,每一步都可以独立重试,用户那边不会因为工具调用慢导致HTTP超时。
有人会问,消息异步了,用户怎么知道最终结果?答案是结果发送到WebSocket或者消息推送服务,我这里是最终回复事件消费后推送到前端。这种基于事件流的agent架构,天然支持断点续跑,bug也好排查,每一个环节都有日志,顺着traceId一拉就是完整链路。
5. 生产环境常见问题与排查技巧盘点
5.1 消息延迟突然很高,先别急着加机器
AI接入后跑了一周,有次线上反馈:用户上传文档后到收到摘要回复,足足等了2分钟。正常情况应该是30秒左右。我先看Kafka监控面板,发现生产速率很低,但消费端积压越来越大,典型的消费能力跟不上。
按照排查套路,我先看lag。Kafka提供了查看lag的手段,但跨集群查看不太方便,这里推荐直接用Kafka工具命令行:
kafka-consumer-groups.sh --bootstrap-server localhost:9092 \ --group ai-infer-group \ --describe输出结果里关注LAG列,这个数字代表该分区积压了多少条未消费消息。如果某个分区LAG特别大,其他分区正常,那就是分区热点了,很可能是key设计导致大量消息涌进同一个分区。如果所有分区LAG都大,则是消费者整体瓶颈。
那次的排查结论是消费者线程阻塞了。怎么定位的?很简单,把消费者代码里的业务耗时打点,发现有的推理请求因为prompt太长,大模型处理耗时超过60秒,而消费者是单线程等待模型返回,一个慢请求把后面所有分区都堵住了。解决方式有两个:一是把消费者线程数调大,让一个慢请求占住一个线程时不阻塞其他分区;二是给推理调用加超时与熔断,超过10秒直接返回失败,消息进死信队列,后续单独补偿。
给你们一个经验值:AI消费者的线程数 = 分区数 / 2 通常够用,如果推理单次超过5秒,线程数要再往上加,甚至要考虑异步推理模式,也就是消费者只负责把请求发到推理引擎,不等结果马上返回,推理完成后再投递结果消息。
5.2 LAG积压排查清单,我整理的一个速查表
每次线上lag告警,团队里就会手忙脚乱。后来我把排查流程固化成一个清单,照着走,bug基本逃不掉:
| 现象 | 可能原因 | 排查动作 | 解决方案 |
|---|---|---|---|
| 某分区LAG一直涨 | 分区key倾斜 | 看该分区消费记录 | 重新设计key,热点key加盐或分桶 |
| 所有分区LAG都涨 | 消费实例数不够 | 看消费者组实例数 | 扩容消费者实例到分区数一致 |
| LAG稳定但延迟高 | 单条消息处理慢 | 打点看消费者耗时 | 优化推理链路,超时熔断 |
| LAG偶尔波动后恢复 | 有大消息进场 | 查看消息字节大小 | 调整单条消息大小限制 |
| 重启后LAG跳变 | offset提交异常 | 检查消费组offset | 修正提交方式,必要时reset |
这个表格我打印出来贴在了工位上,每次出问题照着查就行。额外提醒一句,排查LAG不要只看最大值,要看每个分区的分布。一个分区LAG大和一个消费者挂掉是两码事,别一上来就重启Kafka那套,绝大多数问题都是消费者侧。
5.3 重复消费问题,AI场景下不能完全避免但可以兜底
"kafka能重复消费吗"这个问题被问烂了,答案是能。Kafka消费语义是at-least-once,至少一次,就是说正常情况下每条消息至少被处理一次,但网络超时、消费者宕机、重平衡等场景下,同一个消息可能被处理两次。对普通业务来说,重复消费顶多多写一条数据库记录。但对AI场景,重复消费意味着重复调用大模型API,那是真金白银的成本,而且重复生成的回复还可能让用户看到两条一样的内容。
我们的解决方案是三个层次兜底。第一层,开启幂等生产者,避免生产者本身重复写。第二层,消费者处理时加上业务幂等键,比如用请求ID查一下结果表,如果已经存在就直接跳过。第三层,对关键AI操作,记录一个处理状态表,处理前查状态,处理中更新状态,完成后再次更新。
最容易被忽略的是rebalance触发的重复消费。比如消费者实例扩容、宕机、心跳超时,分区重新分配,此时正在处理的消息还没提交offset,分区被别的实例接管后,这条消息会被重新消费。解决办法有两个:一是把max.poll.interval.ms调大,给长任务处理留足时间,别让Kafka以为你挂了;二是用AckMode.MANUAL配合在处理完成后立刻提交,缩小重复窗口。
5.4 Kafka和RabbitMQ到底怎么选,结合AI场景再讲透一点
前面提了一嘴,这里补充一个完整的对比视角。很多团队在技术选型的时候反复纠结,我给一个直接的判断框架:如果你的消息是"任务"概念,每个任务需要一个worker处理一次,选RabbitMQ。如果消息是"数据流/事件流",需要被多个系统订阅、需要重放、需要离线分析,选Kafka。
用AI场景来套:AI推理请求的异步化,介于两者之间,但因为有重试、重放、按用户顺序的需求,我更倾向Kafka。RAG知识库同步,数据流特征明显,必须Kafka。日志归集、行为分析,Kafka天然适合。而具体的、一次性的任务分发,比如发邮件、发送通知,RabbitMQ更轻量。
如果团队已经有一套RabbitMQ,也别急着全量替换。可以先用RabbitMQ做任务分发,Kafka只接数据流,两个并行跑,中间通过桥接服务转发,稳一段时间再慢慢收敛。这也是我踩过几次坑之后学到的,架构迁移最忌讳一上来就推倒重来。
5.5 可视化监控工具,没有它排查效率低一半
命令行排查是基本功,但不能天天靠命令行盯线上。我用了两款工具,配合起来基本无死角:Kafka UI和Prometheus + Grafana。Kafka UI是一个Web界面工具,能看到Topic列表、分区状态、消费者组、offset延迟,数据可视化对新手特别友好。Prometheus + Grafana走的是指标采集路线,需要额外部署JMX exporter,适合深入监控broker的CPU、内存、磁盘、网络吞吐。
我个人的建议是:团队规模小、刚起步,先用Kafka UI这种轻量工具;等服务上规模了再上Prometheus + Grafana。监控的核心指标我一般盯这几个:生产速率、消费速率、分区的LAG变化趋势、消息大小分布、broker端CPU和磁盘使用率。LAG这个指标尤其重要,建议设置阈值告警,比如超过5000条就触发钉钉或者邮件通知。
6. 接入过程里最大的几个坑,重新整理一遍
最后分享几个我在接入过程中反复踩、最后总结出经验的问题。第一个是客户端版本和broker版本不匹配。我们实际用spring-kafka,spring-kafka版本是2.9,连Kafka 3.0的时候出了一堆序列化异常,查了半天是版本兼容问题。所以接入前先确认客户端和broker的版本兼容矩阵,不要盲目用最新版,也不要隔了太多大版本。
第二个是Kafka机器的内存和磁盘规划。Kafka不是内存型消息队列,但消费者拉取的批次数据会占用page cache,JVM本身也要内存。我踩过的一个坑是把Kafka部署在只有4G内存的机器上,业务高峰期直接OOM。建议生产机器至少16G内存,磁盘用SSD,同时把log.segment.bytes和log.retention.bytes提前规划好,否则磁盘写满了broker会直接拒收消息。
第三个是消息大小默认限制。AI场景经常要传长文本,比如RAG分块后的原始内容,动辄几百KB。但Kafka默认message.max.bytes是1MB,超了直接报错。我们在生产环境把这个值调到了10MB,同时调大了broker端和consumer端的对应参数。注意这里有个连环坑:只调broker端不调consumer端,consumer拉取时会一直报"record too large",两边参数要一起改。
第四个是关于AI服务超时和重试。AI推理的不确定性和普通接口完全不同,普通接口最多超时重试三次,AI模型调用可能因为prompt复杂度不同,响应时间从几百毫秒到几十秒都有。如果消费者这边设置固定的超时时间,偶尔就会误伤长任务。我的策略是:消费者拉取消息后,先把消息状态改成"处理中"放到Redis,然后异步等待最大60秒,如果超时就把消息发回重试Topic,同时把这个事件标记为异常。这个策略换来的是整体稳定性,而不是单条消息的极致体验。
最后再分享一点实际体会
这次把Kafka接入AI平台,最大的收获不是学会怎么配Kafka,而是理解了一件事:AI应用不是只有"模型"这一个环节,它同样是一个分布式系统,需要面对高并发、数据一致性、异步解耦这些问题。Kafka不会让AI模型本身变聪明,但它能让整个AI服务像一个正常的生产级系统一样可靠运行。
如果你也在做AI应用,我建议你至少把Kafka用起来,哪怕先只在一条业务链路上试水。从一个Topic开始,跑通生产者消费者,再逐步接入RAG同步、Agent事件流。我保证你跑通之后,回头看自己曾经用HTTP同步硬扛AI请求的代码,会由衷感叹一声:这锅Kafka背得值。