news 2026/2/9 14:35:26

Flink 实时风控系统的万字实战笔记

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Flink 实时风控系统的万字实战笔记

一、 宏观战场:不只是“快”那么简单

很多人对实时风控有个误区,觉得只要用了Flink,接了Kafka,事儿就成了。大错特错。在银行场景下,准确性(Accuracy)低延迟(Low Latency)是一对由于业务属性天然互斥的冤家。

你想想,为了不误杀用户的正常交易(比如他在出国旅游疯狂买买买),你需要更多的上下文数据(历史画像、甚至他上一秒的地理位置);但为了拦截盗刷,你必须在交易完成前的几百毫秒内给出判定结果。

所以,我们的架构设计必须围绕“状态(State)”来做文章。

1. 核心链路设计

别被那些复杂的微服务图纸吓到了,剥去外壳,核心的风控数据流向其实就这几步:

  • 交易接入层 (Transaction Ingress):通常是核心交易系统通过CDC(Change Data Capture)或者直接发消息队列。这里有个大坑:千万别直接消费数据库的Binlog,除非你的数据库是铁打的。建议在交易网关直接异步推送到Kafka。

  • 实时计算层 (The Brain - Flink):这是主战场。

    • 预处理:数据清洗、格式统一。

    • 特征工程:这是最耗时的。比如“过去5分钟交易总额”。

    • 规则引擎:硬代码写规则是找死,必须动态可配。

    • 模型打分:调用Python训练好的模型(PMML或TensorFlow Serving)。

  • 决策与下发 (Decision Sink):结果写入Redis(供交易系统同步查询)或推送到告警系统。

2. 为什么选择Flink而不是Spark Streaming?

在2023年以后,这已经不是个问题了,但在银行老系统中还得扯皮。理由就一个:Native Streaming vs Micro-batching

风控要的是一条交易进来,立刻处理,立刻输出。Spark Streaming那种“积攒500毫秒再处理”的微批模式,在平时还好,一旦遇到双十一或者黑五这种流量洪峰,延迟会指数级爆炸。银行的SLA(服务等级协议)通常要求风控耗时在100ms以内,Flink的单条处理能力是唯一解。

而且,Flink的StateBackend(状态后端)机制,特别是结合RocksDB,能让我们在本地内存和磁盘中存储TB级别的“用户历史行为”,这对于计算“过去30天该卡平均消费金额”这种指标至关重要。

二、 动态规则引擎:让业务方闭嘴的艺术

做风控开发最痛苦的是什么?不是写代码,而是改需求

业务方上午说:“单笔超过5万且位于境外就报警。” 代码刚上线,下午业务方跑来说:“不行,误报太多,得改成‘且过去24小时无境外记录’。”

如果你每次改规则都要重启Flink作业,那你离离职也不远了。重启意味着状态恢复(State Restore),这期间的数据积压(Backpressure)会造成巨大的延迟波动。

我们需要Broadcast State(广播状态)

1. 广播流的设计哲学

想象有两条河流。

  • 大河(交易流):每秒几万条交易数据,波涛汹涌。

  • 小溪(规则流):偶尔飘下来一片树叶(新的规则配置)。

Flink允许我们将“小溪”广播到所有处理“大河”的并行度节点(Task Managers)上。

2. 实战代码逻辑(伪代码与思路)

我们通常定义一个Rule实体类,不仅仅包含阈值,还包含Groovy脚本或者JSONPath逻辑。

核心步骤如下:

  1. 定义规则流:从My或配置中心(如Nacos)读取规则变化,通过CDC推送到Kafka的一个专用Topic。

  2. 广播它:使用MapStateDescriptor定义规则存储结构。

  3. 连接流TransactionStream.connect(RuleBroadcastStream)

这块有个极其隐蔽的坑,很多人第一次做都会掉进去:

状态的一致性与初始化问题。

当你新上线一个Flink Job,规则流可能还没来数据,这时候交易流已经在跑了,你的系统就是“裸奔”状态。所以,必须在open()方法里,先同步加载一份全量规则到内存,然后再依赖流式更新。

// 这是一个极其精简的示意,不要直接copy到生产环境 public class DynamicFraudDetector extends KeyedBroadcastProcessFunction<String, Transaction, Rule, Alert> { // 存储规则的MapState private MapStateDescriptor<String, Rule> ruleStateDescriptor; @Override public void processElement(Transaction tx, ReadOnlyContext ctx, Collector<Alert> out) { // 1. 获取当前所有的规则 ReadOnlyBroadcastState<String, Rule> rules = ctx.getBroadcastState(ruleStateDescriptor); // 2. 遍历规则进行匹配 for (Map.Entry<String, Rule> entry : rules.immutableEntries()) { Rule rule = entry.getValue(); // 3. 执行规则逻辑(这里通常会用策略模式或者动态脚本执行器) if (RuleEvaluator.evaluate(tx, rule)) { out.collect(new Alert(tx.getCardId(), "触发规则: " + rule.getName())); } } } @Override public void processBroadcastElement(Rule rule, Context ctx, Collector<Alert> out) { // 动态更新规则,不需要重启Job! BroadcastState<String, Rule> state = ctx.getBroadcastState(ruleStateDescriptor); if (rule.isDelete()) { state.remove(rule.getId()); } else { state.put(rule.getId(), rule); } } }

看明白了吗?通过这种方式,业务人员在后台点一下“生效”,Flink作业内部的逻辑毫秒级就会改变,完全无感。这才是高级工程师该交付的系统。

三、 时间的诡计:Event Time与乱序处理

在银行数据中,时间就是金钱,字面意义上的。

但网络是不可靠的。用户在地铁里刷了卡(10:00:01),信号不好,数据传到你服务器可能已经是10:00:05了。如果你按照服务器时间(Processing Time)来算“1分钟内的交易次数”,那你就错了。

我们必须严格使用Event Time(事件时间)。但在风控里,Event Time有个致命弱点:Watermark(水位线)的等待代价

1. 迟到数据的抉择

标准的Flink做法是设置一个Watermark,比如延迟2秒。这意味着系统会等2秒,确保大部分数据都到了再计算窗口。

但在反欺诈场景,你等不起这2秒。

假如黑客在1秒内并发刷了10笔交易,你还在等水位线?钱早没了。

我的建议方案:

不要单纯依赖Flink的Window API(如TumblingEventTimeWindows),而是使用KeyedProcessFunction配合TimerValueState自己实现窗口逻辑。

为什么?因为原生的Window机制,通常是在窗口结束时才输出结果。而我们需要的是Trigger(触发)机制——即:

  • 每来一条数据,立即更新状态(比如count++)。

  • 立即检查当前count是否超限。

  • 如果超限,立刻报警,不需要等窗口结束。

  • 窗口结束的作用仅仅是清理过期的State,防止内存溢出。

2. 状态清理的艺术

这就要用到Flink的TTL(Time To Live)特性了。

比如我们要监控“过去24小时累计金额”。你可能会创建一个ValueState<Double>。 千万别忘了配置TTL:

StateTtlConfig ttlConfig = StateTtlConfig .newBuilder(Time.hours(25)) // 多留1小时buffer .setUpdateType(StateTtlConfig.UpdateType.OnCreateAndWrite) .setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired) .build(); Descriptor.enableTimeToLive(ttlConfig);

如果不配TTL,你的RocksDB会随着时间推移无限膨胀,最后把磁盘撑爆,运维半夜会提刀来找你。相信我,这种低级错误在很多大厂的代码库里都还存在。

四、 特征工程:CEP与复杂模式匹配

简单的“金额 > 10000”这种规则,用或者简单的Filter就能搞定。但真正的欺诈往往是隐蔽的模式。

比如一种经典的**“试探性盗刷”**模式:

  1. 先刷一笔1块钱的小额(测试卡是否有效)。

  2. 紧接着(5分钟内)刷一笔大额失败(余额不足)。

  3. 再尝试一笔中等金额成功。

这种A -> B -> C的时序关系,是Flink CEP(Complex Event Processing)的强项。

1. CEP不是银弹

很多教程吹嘘CEP多么强大,但在高吞吐(Millions of txns/day)的生产环境,CEP的性能开销是巨大的。每一个Pattern都是一个状态机,每条数据进来都要去匹配状态机的流转。

性能优化技巧:

  • 前置过滤(Pre-filter):不要把所有交易都扔给CEP。只有那些“可疑”的交易(比如异地、大额、高风险商户)才进入CEP流。

  • 严格限制模式的生命周期.within(Time.minutes(10))。不要试图去匹配跨度几天的模式,那会对State造成毁灭性打击。

2. 只有代码能说明白

用CEP定义上述的“试探性盗刷”大概长这样:

Pattern<Transaction, ?> fraudPattern = Pattern.<Transaction>begin("small-try") .where(new SimpleCondition<Transaction>() { @Override public boolean filter(Transaction tx) { return tx.getAmount() < 10.0; // 小额试探 } }) .next("big-fail") .where(new SimpleCondition<Transaction>() { @Override public boolean filter(Transaction tx) { return tx.getAmount() > 50000 && tx.getStatus() == FAILED; } }) .within(Time.minutes(10));

看起来很优雅对吧?但实际上,“next”(严格紧邻)和**“followedBy”**(非严格紧邻)的选择至关重要。

在信用卡流水中,两个操作之间可能会插入其他的杂项日志(比如查询余额)。所以,通常我们要用followedBy,但这又会增加状态匹配的复杂度。

更狂野的做法:对于顶级的高频交易系统,我们甚至会抛弃Flink CEP库,直接用KeyedProcessFunction手写状态机。虽然代码量多了三倍,但我们可以精准控制每一个Bit的状态存储,把性能压榨到极致。如果你是个追求极致的Geek,我会推荐你手写。

五、 异构计算的生死时速:如何在流中嵌入AI模型

在银行场景下,一个典型的风控模型(比如基于XGBoost或神经网络的评分模型)响应时间通常在10ms 到 50ms之间。

你可能会说:“这也挺快啊?”

对于Web服务来说是挺快,但对于Flink这种每秒处理几万、几十万条数据的流引擎来说,10ms 简直就是万年。如果你在MapFunction里直接同步调用一个 HTTP 接口去请求模型服务,整个 Pipeline 的吞吐量会瞬间跌到个位数,随之而来的就是背压(Backpressure)报警红成一片。

1. 救命稻草:Async I/O(异步I/O)

Flink 官方提供的AsyncDataStream是解决这个问题的标准答案,但很多人只知其一不知其二。

它的核心原理是:不阻塞主线程,发起请求后就把当前这一“帧”挂起,去处理下一条数据,等结果回调了再捡起来。

但在配置时,有两个参数决定了你是“救火”还是“纵火”:

  • OrderedWait(有序等待):必须严格按照数据进来的顺序输出。

    • 实战建议千万别用。在风控场景下,A用户的交易判定结果和B用户的交易谁先谁后根本不重要。强制有序会导致只要有一个请求超时,后面所有处理完的数据都得排队等着,这叫“队头阻塞(Head-of-line blocking)”。

  • UnorderedWait(无序等待):谁先跑完谁先出。

    • 实战建议必须用这个。但这会打乱时间戳的水位线吗?会一点,但在 Watermark 允许的容忍范围内,这点乱序换来的吞吐量提升是值得的。

2. 真正的“核武器”:模型本地化(JPMML)

虽然 Async I/O 解决了吞吐量问题,但网络延迟(Network Latency)依然存在。RPC调用哪怕再快,也不如本地调用快。

在顶级银行的高频交易风控中,我们通常会拒绝网络调用

怎么做?把模型“搬”到 Flink 里面去。

大多数数据科学家用 Python 训练模型,我们要求他们将模型导出为PMML (Predictive Model Markup Language)格式。这是一种跨语言的标准。

然后在 Flink 的RichMapFunction中,利用 的 JPMML 库加载这个文件。

public class ModelPredictionMap extends RichMapFunction<Transaction, TransactionWithScore> { private Evaluator evaluator; @Override public void open(Configuration parameters) { // 在作业启动时,将几百兆的模型文件加载到堆内存中 // 这一步虽然慢,但只发生一次 File modelFile = RuntimeContext.getDistributedCache().getFile("fraud-model.pmml"); this.evaluator = new LoadingModelEvaluatorBuilder().load(modelFile).build(); } @Override public TransactionWithScore map(Transaction tx) { // 纯内存计算,耗时从 20ms 压缩到 0.5ms // 没有网络IO,没有序列化开销 Map<FieldName, FieldValue> arguments = prepareArgs(tx); Map<FieldName, ?> results = evaluator.evaluate(arguments); return attachScore(tx, results); } }

这种架构的代价是什么?

  1. 内存爆炸:如果模型很大(比如深度学习模型),TaskManager 的堆内存压力会剧增。

  2. 更新麻烦:更新模型需要重启 Flink Job 或者利用广播流动态加载新的 PMML 字节流(这属于高阶骚操作,容易OOM,慎用)。

但为了那0.5ms的极致速度,这一切折腾都是值得的。

六、 RocksDB:驯服存储的野兽

当你的风控规则涉及到“过去3个月的交易行为”时,内存肯定放不下,必须开启 Flink 的 RocksDB StateBackend。

RocksDB 本质上是一个嵌入式的 KV 数据库,它把数据存在本地磁盘(通常是 NVMe SSD)。很多新手开启 RocksDB 后,发现性能从每秒 5万 跌到了 5千,为什么?

因为默认配置就是垃圾

1. 必须要懂的 BlockCache

RocksDB 读写分几层:MemTable(内存) -> SST Files(磁盘)。 如果每次读取状态都要去摸磁盘,你的系统就废了。

你必须显式配置state.backend.rocksdb.memory.managed: true,但这还不够。在代码里,你需要通过RocksDBOptionsFactory来调整BlockCache的大小。

简单粗暴的原则:把 TaskManager 堆外内存的一大半都喂给 BlockCache。我们希望 90% 的热点用户(比如刚才正在刷卡的人)的状态数据都能在内存缓存里找到,只有那些万年不用一次的冷数据才去读盘。

2. Bloom Filter(布隆过滤器)的魔法

在风控查重场景(比如“该设备是否在黑名单中”),大部分时候答案是“No”。

如果没有优化,RocksDB 会去磁盘里翻箱倒柜找这个 Key,最后告诉你“没找到”。这太蠢了。

开启布隆过滤器。它是一个很小的内存结构,能以 O(1) 的代价告诉你“这个 Key绝对不存在”或者“可能存在”。这就挡掉了 99% 无意义的磁盘 I/O。

// 这是让性能翻倍的一行代码 columnFamilyOptions.setBloomLocality(1);

不要小看这行配置,在日均亿级访问的场景下,它能救你的命。

3. Checkpoint 的性能杀手

银行系统要求Exactly-Once(精确一次),所以 Checkpoint(检查点)必须开。但在高负载下,Checkpoint 可能会超时失败。

如何优化?

  • 增量 Checkpoint:必须开。只备份修改过的状态,而不是全量备份。

  • 本地盘 vs 远程盘:RocksDB 的工作目录必须挂载在高性能的NVMe SSD上。千万别为了省钱用普通的云盘(EBS),IOPS 根本扛不住 Compaction(SST文件合并)带来的压力。

七、 所谓的“精确一次”与数据一致性

这是银行最敏感的话题。我们常说的 Flink "Exactly-Once",其实只保证了 Flink内部状态不丢、不重。

但如果你的 Sink(下游)是写入 My 或者 Redis,Flink 可不管那一套。

想象一下:Flink 处理完一笔交易,判定为欺诈,把结果写到了 Redis,然后 Update 了内部的状态 offset。就在这时,机器断电了。 Flink 重启,回滚到上一次 Checkpoint,重新消费这笔交易,再次判定为欺诈,再次写入 Redis

对于幂等的操作(比如Set Key=Value),重复写没问题。 但对于非幂等操作(比如Incr Counter累加计数),这就出大事了。数据直接翻倍。

1. 真正的端到端一致性(End-to-End Exactly-Once)

要做到这点,下游必须支持事务(Transaction)

最经典的方案是结合Kafka 的事务机制(Kafka 0.11+)。 Flink 开启TwoPhaseCommitSinkFunction(两阶段提交):

  1. Pre-Commit:数据写入 Kafka 的一个临时事务中,此时下游消费者(比如风控后台)是看不到这些数据的(设置isolation.level=read_committed)。

  2. Snapshot:Flink 全局做 Checkpoint。

  3. Commit:Checkpoint 成功后,Flink 通知 Kafka 提交事务,数据瞬间对下游可见。

2. 兜底方案:幂等性设计

说实话,两阶段提交太重了,延迟也高。

在实战中,我们更多采用**“业务幂等性”**设计。 我们在输出结果时,带上这笔交易的唯一 ID(TransactionID)。 下游系统(比如 My)在插入警报时,利用INSERT IGNORE或者ON DUPLICATE KEY UPDATE

宁可让数据库多承担一点压力,也不要让流计算逻辑过于复杂。简单往往意味着健壮。

八、 监控与大屏:让看不见的数据被看见

系统写好了,怎么证明它在工作?老板和监管机构只看大屏。

我们不仅要监控 Flink 的技术指标(Delay, Checkpoint Duration, Backpressure),更要监控业务指标

这里推荐一个Side Output(侧输出流)的模式。

不要把监控指标混在主业务流里。在计算过程中,随时把统计数据扔到侧输出流:

if (tx.getAmount() > 10000) { ctx.output(largeTxTag, tx); // 大额交易流 } // 实时计算 TPS ctx.output(metricTag, new Metric("TPS", 1));

然后起一个完全独立的 Flink Job 或者直接用 Telegraf + InfluxDB 来消费这些侧输出流,展示到 Grafana 上。

一定要监控的关键业务指标:

  • 拦截率:如果在某一分钟内拦截率突然从 0.1% 飙升到 20%,要么是遭受了大规模攻击,要么是你的规则写挂了(误杀)。此时必须要有熔断机制。

  • 规则命中分布:哪条规则杀得最狠?如果是某条新上的规则杀疯了,第一时间回滚它。

  • 处理延迟分位值(P99 Latency):不要看平均值,平均值是骗人的。我们要看 P99,也就是最慢的那 1% 的交易延迟了多久。这才是用户投诉的来源。

九、 容灾的残酷哲学:Fail Open 还是 Fail Close?

这是一个涉及几千万资金的哲学问题。

当你的 Flink 集群因为 Bug 崩溃了,或者 Kafka 发生了严重的积压,此时一笔用户的刷卡请求过来了。

你是选择: A.直接拒绝(Fail Close):为了安全,宁可杀错不放过。用户会看到“交易失败”,然后愤怒地打爆客服电话。 B.直接放行(Fail Open):为了用户体验,暂时放弃风控,让交易通过。这可能会放过几笔盗刷。

在 99% 的场景下,银行的答案是Fail Open,也就是“降级”。

1. 自动降级机制

你不能依赖人工去监控报警然后手动切开关,那太慢了。我们需要在交易接入层(API Gateway)做一个熔断器(Circuit Breaker)

  • 超时熔断:如果风控接口 200ms 还没返回结果,直接 Return Success。

  • 错误率熔断:如果过去 1 分钟内,风控接口报错超过 5%,自动跳过风控逻辑,直到系统恢复。

但在 Flink 内部,我们也要做自我保护。 比如在反序列化 JSON 失败时,或者调用模型抛出异常时,千万不要让整个 Job 挂掉(Failover)。

// 这种写法会被开除 try { Result r = analyze(transaction); } catch (Exception e) { throw new RuntimeException("Crash!"); // 整个集群重启,所有交易卡顿 } // 这种才是成熟的写法 try { Result r = analyze(transaction); } catch (Exception e) { // 记录错误指标,静默失败,输出一个“未知风险”的标记 // 此时由下游决策系统决定是放行还是转人工 metrics.inc("analysis_error"); out.collect(new RiskResult(tx.getId(), RiskLevel.UNKNOWN)); }

2. 双活架构(Active-Active)

对于核心中的核心,我们通常部署两套完全独立的 Flink 集群,甚至分布在不同的物理机房(比如上海和北京)。

Kafka 的数据会被镜像复制到两地。两套 Flink 同时消费,同时计算。

这就带来了一个棘手的问题:重复告警

如果两套系统都判定这笔交易是欺诈,你的 Redis 里会被写两次,用户会收到两条短信。这显得很业余。

解决方案:分布式锁或抢占式写入。

在最终写入 Redis 之前,利用 Redis 的SETNX(Set if Not Exists)指令。

  • 集群 A 算出结果,尝试写入SETNX alert:tx_12345 "FRAUD" EX 300。返回 1(成功),它负责发短信。

  • 集群 B 慢了 5 毫秒算出结果,尝试写入,返回 0(失败),它就闭嘴,什么都不做。

这种架构虽然烧钱(硬件成本翻倍),但它给了架构师睡个安稳觉的底气。

十、 时光机:回溯与仿真(Backtesting)

这是区分“玩具系统”和“工业级系统”的分水岭。

当数据科学家训练出了一个新的模型,或者风控专家想出了一条新规则(例如:半夜2点在异地买珠宝 > 90% 概率是盗刷),你敢直接上线吗?

一旦误判,拦截了 VIP 客户在巴黎买钻戒的交易,银行损失的不仅是手续费,更是声誉。

我们需要仿真(Simulation),或者叫Shadow Mode(暗中观察模式)

1. 影子规则(Shadow Rules)

在我们的规则引擎中,给每条规则打一个标签:Status: ACTIVEStatus: SHADOW

  • ACTIVE 规则:命中后,输出BLOCK信号,直接阻断交易。

  • SHADOW 规则:命中后,输出LOG_ONLY信号。交易继续通行,但在后台日志里记下一笔:“如果刚才用了这条规则,这笔交易就被拦了。”

Flink 跑了一周后,我们把 Shadow 规则的命中记录拿出来,和最终用户的投诉记录(True Labels)做比对:

  • 如果它命中的大部分真的是盗刷(Precision 高),那就转正。

  • 如果它命中了一堆正常人(False Positive 高),那就打回去重修。

2. 历史数据回放(Replay)

有些规则太紧急,等不了一周的影子测试。我们需要立刻知道:如果我在上个月用了这条规则,会拦截多少人?

这就利用了 Kafka 和 Flink 的时间旅行能力

  1. 准备环境:起一个新的 Flink Job,逻辑和线上一样,但规则配置成新的。

  2. 重置位点:在提交 Job 时,指定 Kafka 的start-from-timestamp为 30 天前。

  3. 加速处理:线上数据是一秒一秒来的,但回放时,因为数据已经都在 Kafka 里了,Flink 可以全速狂奔。本来 30 天的数据,可能 2 小时就跑完了。

这里有一个极其重要的技术细节:Event Time。

在回放模式下,千万不能用 Processing Time(处理时间)。 因为你是在 2 小时内跑完 30 天的数据,如果用 Processing Time,所有的Window(1 hour)都会失效,因为数据对于 Flink 来说都是“现在”到达的。

必须严格使用数据自带的时间戳作为 Event Time。这样,Flink 内部的逻辑时钟会随着读取的历史数据飞速向前拨动,完全复现当时的场景。

// 在回放作业中 env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime); // 此时,Watermark 会随着读取的历史数据疯狂上涨 // 所有的窗口计算逻辑与当初真实发生时一模一样
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/7 12:07:31

基于springboot + vue考勤管理系统

考勤管理 目录 基于springboot vue考勤管理系统 一、前言 二、系统功能演示 详细视频演示 三、技术选型 四、其他项目参考 五、代码参考 六、测试参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 基于springboot vue考勤管理系统 一、前言 博主介绍&am…

作者头像 李华
网站建设 2026/2/6 5:21:29

基于springboot + vue图书借阅管理系统

图书借阅 目录 基于springboot vue图书借阅管理系统 一、前言 二、系统功能演示 详细视频演示 三、技术选型 四、其他项目参考 五、代码参考 六、测试参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 基于springboot vue图书借阅管理系统 一、前言 博主…

作者头像 李华
网站建设 2026/2/5 16:13:29

淘宝天猫一键重装系统工具,智能装机助手,支持多版本系统傻瓜式安装,新手小白也能轻松上手!

温馨提示&#xff1a;文末有联系方式全能一键重装系统工具&#xff0c;专为新手打造这款专为淘宝、天猫用户设计的一键重装系统软件&#xff0c;又被称为“天猫装机助手”&#xff0c;是一款高效便捷的装机工具。 采用傻瓜式操作界面&#xff0c;即便是毫无电脑基础的小白用户&…

作者头像 李华
网站建设 2026/2/8 5:15:50

仿生记忆革命:字节跳动AHN技术突破大模型长文本处理瓶颈

仿生记忆革命&#xff1a;字节跳动AHN技术突破大模型长文本处理瓶颈 【免费下载链接】AHN-DN-for-Qwen-2.5-Instruct-14B 项目地址: https://ai.gitcode.com/hf_mirrors/ByteDance-Seed/AHN-DN-for-Qwen-2.5-Instruct-14B 导语 字节跳动推出的人工海马体网络&#xff…

作者头像 李华
网站建设 2026/2/8 2:02:04

云服务器新手必看:常见名词和知识整理,一文搞懂

第一次购买云服务器&#xff0c;面对控制台里一堆术语&#xff0c;很容易一头雾水。 内存、带宽、系统盘、按流量计费……这些词到底什么意思&#xff1f; 选错一项&#xff0c;可能多花钱&#xff0c;甚至影响网站运行。 今天我们就结合国内主流云厂商选择界面&#xff0c; 用…

作者头像 李华