news 2026/10/1 14:03:48

Flink实时湖仓实操:从Socket到Kafka再到Hive的完整链路

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Flink实时湖仓实操:从Socket到Kafka再到Hive的完整链路

简介:面向大数据入门与进阶用户的阿里云实时计算 Flink 实时湖仓配套原始业务数据脚本包,特别适合正在学习 Flink SQL、实时数仓搭建或湖仓一体实践,并希望用真实业务数据验证链路效果的开发者。压缩包共 4 个文件,整体仅 623KB,包含 2 个 SQL 脚本和 2 个 TXT 脚本;SQL 脚本负责生成原始业务数据及对应表结构,TXT 脚本则覆盖 ECS 上 JDK、ZooKeeper、Kafka、MySQL 的安装配置,以及 DataLoader 数据装载流程,与课程示例中的环境准备和造数环节一一对应。目前已有 241 人学习下载。脚本命名清晰,可按需单独使用,也可组合复现完整链路。借助这些脚本,可以免去手工搭建环境的繁琐步骤,快速复现课堂中的建表、造数与联调场景,也能在练习中直观理解 Flink 实时湖仓的数据流转脉络,适合边学边练并希望沉淀实操能力的开发者。

1. 这包脚本到底解决什么问题:5小时上手Flink实时湖仓的实操路线

看到这个资源的第一眼,我其实有点怀疑:5小时能把实时湖仓玩转?毕竟Flink入门到放弃的案例太多了。但把压缩包里的脚本过了一遍后,我理解了它的定位——不是一个讲概念的教程,而是一套能直接跑通的业务数据脚本集,从原始业务数据模拟、Kafka接入、Flink SQL建表到Hive落地,每一步都是可执行的文件,不是PPT截图。它适合两类人:一是被Flink安装配置折腾到怀疑人生的新手,照着脚本把环境踩通;二是正在做实时湖仓选型、想快速验证技术栈能不能落地的一线工程师。这套脚本把"从零到一"补齐了,剩下的"一到十"是你自己的业务。

2. DataStream API 打底:从Socket到Kafka的链路怎么搭才算真会

2.1 为什么先走DataStream而不是直接上Flink SQL

很多新手容易犯一个毛病:上来就写Flink SQL,觉得SQL简单。实际工作中,真实业务数据脚本往往带着脏数据、乱序、schema演化的包袱,纯SQL拿捏不住。这个资源里先安排了DataStream API的链路,我理解是故意的——让你先看清数据是怎么流进算子、怎么序列化、怎么被分区的,再去学SQL时,你才明白为什么某个SQL会莫名地数据倾斜。

用最小的代价达成这个目标,是Socket端口。不需要依赖Kafka集群,本地起一个nc命令就能当上游。这种方式适合做环境连通性验证,我一般在接手新集群时也会先跑一遍Socket链路,确认Flink环境本身没问题,再换生产组件。

2.2 第一个可运行的流任务:Socket源 + 处理 + 打印

脚本里第一个核心文件就是SocketWordCount,这就像编程语言的Hello World,但别因为它简单就跳过。它的真正价值是验证三件事:任务管理器资源是否正常、数据交换格式是否通、Web UI的JobManager地址能不能访问。

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); DataStreamSource<String> socketStream = env.socketTextStream( "127.0.0.1", 9000, "\n", 3 ); DataStream<Tuple2<String, Integer>> wordCount = socketStream .flatMap(new Tokenizer()) .keyBy(0) .sum(1); wordCount.print().setParallelism(1); env.execute("socket-wordcount");

这个片段参数有几个值得改的点。9000端口我建议改成你自己方便记忆的,但一定得跟nc启动时一致;3是重试次数,它控制着Socket源断开后Job的重连行为,注意这个参数不是断线重连间隔,是最大重试次数,设为-1才是无限重连。setParallelism(1)这里我吃过亏——打印算子并行度不设1的话,多个并行子任务会分别输出,结果看起来就像重复计算了。

跑起来之后,打开Flink Web UI看算子背压状态,这是判断链路是否健康的第一个观察点。如果背压为HIGH,先别急着调并行度,看看是不是下游print算子太慢——print的IO开销在生产环境里其实是个隐藏瓶颈。

2.3 换成Kafka源:反序列化与并行度配合

Socket链路跑通后,脚本会带你把数据源换成Kafka。这一步跳过了中间所有的"伪实时",直接进入真正的流式场景。Kafka的partition数直接决定你Flink源算子能开多少并行度,这是个常见的玄学问题:明明把并行度调到16,吞吐就是上不去,一查Kafka topic只有3个partition,剩下13个并行子任务空转。

Properties kafkaProps = new Properties(); kafkaProps.setProperty("bootstrap.servers", "localhost:9092"); kafkaProps.setProperty("group.id", "flink-lakehouse-demo"); kafkaProps.setProperty("auto.offset.reset", "earliest"); DataStreamSource<String> kafkaStream = env.addSource( new FlinkKafkaConsumer<>( "ods_business_data", new SimpleStringSchema(), kafkaProps ) );

这里auto.offset.reset的值值得较真:earliest和latest的区别在作业重启时会直接体现。如果你用latest,在脚本启动到Kafka数据开始生产的间隙里写入的数据全都会被跳过,看起来就是"丢数据"了。对离线补数场景我习惯用earliest,多消费一点旧数据无妨;对追实时指标的场景,latest更合适。脚本里用earliest是有道理的,毕竟它承担的是教学验证,不能因为启动时机不对就少数据。

SimpleStringSchema虽然简单,但也要知道它不是万能解。如果上游业务系统用的是Avro或者JSON嵌套结构,这个schema会直接反序列化失败。脚本之所以敢用,是因为配套的原始业务数据脚本生成的正是纯文本格式。

2.4 自定义DataSource/Sink的边界:什么场景才值得写

网上搜Flink实时计算进阶篇,总绕不开"如何自定义DataSource与DataSink",这套脚本里也确实给了自定义的样例。但作为一线工程师,我得说实话:能不用就别用。

需要自定义Source的场景很明确——数据源不再Kafka、Socket、文件这老三样里,比如公司内部的消息中间件、某个自研的RPC接口,或者需要周期性下拉数据库增量数据。自定义Sink同理,比如你要把结果写进自研存储,或者要附加事务逻辑。

自定义Source的核心是搞清楚SourceFunction两个方法的语义:

public class BusinessDataGenerator implements SourceFunction<String> { private volatile boolean running = true; @Override public void run(SourceContext<String> ctx) throws Exception { while (running) { ctx.collect(generateBusinessRecord()); Thread.sleep(1000); } } @Override public void cancel() { running = false; } }

cancel()方法别小看,它负责优雅停止。生产环境里任务做checkpoint时,如果running变量没用volatile修饰,就会出现在高并发场景下标志位不可见的诡异问题——作业倒是停了,但状态一直没存上。脚本里这么写是对的,这个volatile就是血泪经验。

自定义Sink容易踩的坑在invoke方法里:不要在里面做重量级的I/O等待,否则下游背压直接打满。我看到过的翻车案例,是自己写的Sink里每来一条数据都建一次数据库连接,活活把任务拖死。正确做法是复用连接,或者干脆走Flink自带的JDBC连接器。

3. Flink SQL + Hive Catalog 打通实时湖仓:脚本里最核心的那段配置

3.1 实时湖仓在Flink里是什么:一张Hive表的两副面孔

这套资源的标题是"实时湖仓",落点其实是Flink SQL + Hive的集成。实时湖仓在工程上可以拆成两条腿:一条是流式数据实时写入Hive表对应的分区,另一条是下游分析引擎直接读Hive表。难点在于你怎么让Flink觉得它在写一张流表,而Hive觉得它只是一张普通分区表。

答案是Hive Catalog。在脚本里,你会发现一个公共配置片段被反复复用:hive-conf-dir、default-database、hive-version。这三项必须对应你实际安装的Hive版本,配错了直接连不上MetaStore,报错信息还特含糊,就一句"Could not establish connection"。

CREATE CATALOG hive_catalog WITH ( 'type' = 'hive', 'default-database' = 'default', 'hive-conf-dir' = '/opt/hive-conf', 'hive-version' = '3.1.0' ); USE CATALOG hive_catalog;

这段配置我有过真实的翻车经历。hive-conf-dir指向的目录里必须放完整的hive-site.xml,注意是必须,缺一个javax.jdo.option.ConnectionURL配置,Flink连MetaStore的方式就会完全不同。另外hive-version这个参数在部分开源版本里是错的写法,需要先看Flink对应版本源码里的校验逻辑,不匹配会抛出"Invalid hive version"的奇葩错误。

3.2 Hive Catalog + 连续读取:一句话切换读写模式

在实时湖仓链路里,Hive这张表同时承担读和写。Flink SQL里用scan.startup.metadata这个参数控制新分区是否实时可见,这是流读Hive表的核心开关。脚本里给的建议值是scan.startup.metadata与streaming-source.enable配合使用,因为Hive表流读本质上就是一个监听分区目录变化的通道。

CREATE TABLE hive_orders ( order_id STRING, user_id STRING, amount DECIMAL(10, 2), ts TIMESTAMP(3), dt STRING ) PARTITIONED BY (dt) WITH ( 'connector' = 'hive', 'streaming-source.enable' = 'true', 'streaming-source.monitor-interval' = '60s', 'streaming-source.partition-order' = 'create-time' );

streaming-source.monitor-interval=60s很重要。生产环境里如果上游写入频繁,可以调到10秒,但如果Hive表的分区是每小时一级,60秒够用,调太短反而会给NameNode增加压力。partition-order有三个可选值:create-time、partition-time、partition-name,脚本用create-time最稳,因为不需要额外解析分区名中的时间。

3.3 从Kafka到Hive的同步任务:值不值得用SQL实现

这个包的核心同步作业,其实就是一条Kafka到Hive的实时入仓链路。用Flink SQL实现,代码量会压缩到极短,脚本里也正是这么组织的——一段建Kafka源表、一段建Hive目标表、一段Insert Into。

INSERT INTO hive_catalog.default.hive_orders SELECT order_id, user_id, amount, ts, DATE_FORMAT(ts, 'yyyy-MM-dd') AS dt FROM kafka_orders_topic;

这段SQL里DATE_FORMAT(ts, 'yyyy-MM-dd')决定了Hive分区字段的粒度。脚本用的是天分区,如果业务需要小时级实时分析,改成yyyy-MM-dd-HH即可,但要注意分区字段的格式和下游查询的WHERE条件必须对得上,否则就是全表扫描。

值不值得用SQL实现,我的判断是:如果目标表只有一张,SQL够用;如果目标表有一堆,还有多流join、聚合、去重逻辑,SQL也能写,但排查问题会非常痛苦。这时我会把算子拆开,用DataStream API做主要的加工逻辑,最后再通过TableAPI写入Hive表,这种混合模式在真实项目里很常见。

3.4 参数调优:与Hive版本、分区写入强相关的几个配置

写入Hive表时,Flink有几个参数是默认值很坑的。sink.partition-commit.policy.kind控制分区提交策略,脚本里通常配的是success-file,意思是在分区目录里写一个_SUCCESS标记文件。别小看这个文件,下游很多调度系统就是靠它的存在来判断数据写完了没有。

参数名建议值为什么这么配
sink.partition-commit.policy.kindsuccess-file分区写完有明确标记,下游好判断
sink.partition-commit.triggerprocess-time按处理时间而不是事件时间提交分区,否则乱序数据会等很久
io.tmp.cache.dir本地磁盘路径写Orc/Parquet时临时文件目录,默认值在容器里可能没有写权限
partition.time-extractor.timestamp-patterndt分区提取的日期来源字段,写错数据会被丢进错误分区

process-time这个参数是"后悔药"级别的重要。我接手过一个案例,用的是partition-time触发,数据因为偶发性乱序,分区提交一直等不到对应事件时间的Watermark,结果Hive端两小时没出新分区,最后整个报表链路断掉。换成process-time之后,最多延迟几秒分区就提交了。

Hive版本这块,我强烈建议在跑这套脚本前先确认Flink的lib目录里存在匹配的flink-sql-connector-hive-版本号.jar。脚本不会替你解决这个问题,可能在README里写了"请手动添加依赖",这个属于理解成本最低但最容易被忽略的一步。

4. 原始业务数据脚本模块:模拟数据生成器与回放逻辑是怎么组织的

4.1 模拟业务数据要模拟到哪一层:字段、频率、乱序

这套资源最值钱的部分,我以为是那个"原始业务数据脚本"。实时湖仓链路里最缺的往往不是Flink知识,而是能持续、稳定、可控产生业务数据的上游。生产环境的业务数据属于公司敏感资产,不能随便拿出来教学;而脚本自己生成的数据,就可以自由地做各种破坏性实验。

模拟的层次决定了这个脚本的价值深度。只模拟字段齐全是第一层;模拟频率分布是第二层;模拟乱序是第三层。我看了脚本的组织方式,它是三层全包的——用一个Python脚本生成订单数据,同时提供了Shell包装脚本,能在Linux系统里循环执行,配合crontab就可以持续不断地喂数据给Kafka。

import json import random import time import datetime order_status = ["CREATED", "PAID", "SHIPPED", "COMPLETED"] def generate_order(order_id): # 构造与实际业务贴合的字段结构 return { "order_id": f"ORD{order_id:08d}", "user_id": f"U{random.randint(10000, 99999)}", "amount": round(random.uniform(10, 1000), 2), "status": random.choice(order_status), "order_time": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f") } if __name__ == "__main__": for i in range(1000): record = generate_order(i) print(json.dumps(record)) time.sleep(random.uniform(0.1, 1.5))

random.uniform(0.1, 1.5)这个区间是有讲究的。固定频率的数据在测试背压时完全没用,因为Flink的背压机制就是应对突刺的;而随机频率能制造出短时脉冲,更容易暴露并行度设置不合理的问题。脚本有意做了这个设计,不是随便写一个sleep的。

4.2 数据回放脚本:让同一批数据能重复验证

实时数据链路有个天然痛点:不可复现。同样一段代码,上午跑通下午跑挂,想查原因却找不到同一批输入。脚本里应该会带一个回放模块,把前面生成的原始数据落盘,Flink作业可以用--from-file方式重新消费历史文件。

#!/bin/bash # 回放脚本:把保存好的业务数据文件按原顺序重新发送 FILE_PATH=$1 SLEEP_INTERVAL=${2:-1} while IFS= read -r line do echo "$line" | kafka-console-producer.sh \ --broker-list localhost:9092 \ --topic ods_business_data sleep "$SLEEP_INTERVAL" done < "$FILE_PATH"

回放脚本的价值不只是调Bug。做实时湖仓技术验证时,你要给领导或同事展示效果,用真实数据又怕泄露,用现场生成的数据又怕关键时刻掉链子。回放脚本等于给你一次重来的机会——先录一段"完美数据",演示时原速回放,稳定出效果。这个脚本在面试中讲出来也是加分项。

4.3 与Flink作业的对接方式:直接发送还是落本地文件

原始业务数据脚本对上游的模拟分两种形态。一种是直接往Kafka topic发送消息,这在链路真实度上最高;另一种是把数据落到本地文件,让Flink用FileSystem connector去读取。脚本里两个都给,依据场景选。

我经验是验证阶段先走FileSystem形态,因为能明确看到数据文件的记录条数,排查"数据进没进到Flink"时少一层Kafka的干扰因素。链路稳定后,再切到Kafka形态,补上生产环境的完整环节。

# 方式一:数据落本地文件 python generate_business_data.py > /tmp/business_data.log # 方式二:直接写入Kafka python generate_business_data_stream.py | kafka-console-producer.sh \ --broker-list localhost:9092 \ --topic ods_business_data

两种方式切换时的注意点:落本地文件时,路径要和Flink端'path'参数完全一致,不要写相对路径;直接发Kafka时,acks默认值在测试环境下无所谓,但如果你改了Kafka服务端配置,脚本也需要对应调整。这些细节不会在错误日志里告诉你,得自己对着参数一个个查。

这里顺带提一个Linux脚本入门的坑:Windows下编辑的Shell脚本,拿到Linux上经常报\r命令找不到的错误。别急着查Shell语法,先用sed -i 's/\r$//' script.sh处理掉行尾符再说。这套脚本里如果有Windows版本,一定把换行符的问题提前处理完。

5. 避坑与排查:这包脚本在真实环境里最容易翻车的六个场景

5.1 Maven仓库下载缓慢导致环境起不来

现象:Flink项目构建时卡在下载依赖,半小时进度条不动,最后报超时。

原因:默认Maven中央仓库在国内访问极不稳定。这是做这套脚本复现时遇到的第一个普遍性问题,跟Flink本身没关系,但会直接拦住所有后续步骤。

解决:换阿里云Maven镜像仓库。在~/.m2/settings.xml里加一段mirror配置:

<mirror> <id>aliyun</id> <mirrorOf>central</mirrorOf> <name>aliyun central mirror</name> <url>https://maven.aliyun.com/repository/public</url> </mirror>

配置完先跑mvn clean compile -o验证离线编译能否通过。如果能过,说明依赖已经下载完整,后面再正常联网操作就快了。注意mirrorOf写成central比*更克制,不会把所有自定义仓库都劫持到阿里云。

5.2 Flink JDBC连接器异常:ClassNotFound与本该在的驱动

现象:作业启动时报ClassNotFoundException: com.mysql.cj.jdbc.Driver,或者Failed to load class org.slf4j.impl.StaticLoggerBinder。

原因:Flink的lib目录下缺少MySQL JDBC驱动包,或者驱动包与连接的MySQL版本不匹配。很多人习惯把依赖写在pom.xml里,但Flink分布式环境下,各TaskManager节点不共享本机Maven仓库,必须把jar部署到每个节点。

解决:把对应版本的驱动放进$FLINK_HOME/lib目录,同时确认pom.xml里scope设为provided或compile。我习惯用provided,避免把驱动打进Flink作业jar造成版本冲突。如果依然报ClassNotFound,用mvn dependency:tree查一下是否有其他依赖把旧版本的驱动带进来了,要特别留意。

5.3 Sink到Hive表数据不入表:分区目录存在但数据为空

现象:Flink作业成功执行,Hive表的分区目录也在,但SELECT COUNT(*)查出来是0。

原因:分区提交没有成功。数据其实已经写入临时目录,只是_SUCCESS文件没生成,Hive不认为这个分区可用。常见原因是filesystem的提交策略与Hive版本不兼容,或者checkpoint没开启——Flink写Hive表时,分区提交发生在checkpoint完成之后,环境里禁用checkpoint等于永远不提交。

解决:确认execution.checkpointing.interval大于0,并把分区提交策略改成success-file。同时检查目标表的存储格式,如果是Parquet/Orc,还要确认flink-parquet或flink-orc相关依赖在lib目录里——缺了依赖数据会静默写失败,这个坑非常隐蔽。

5.4 Windows下PowerShell脚本闪退

现象:双击运行脚本,窗口一闪而过,什么都看不到。

原因:脚本执行错误,但PowerShell窗口没来得及显示错误信息就关闭了。这在Windows上跑Flink作业脚本时很常见,尤其是包里的脚本最初是给Linux写的,在Windows上直接用会死得很惨。

解决:临时规避能在Command Prompt里执行:

cmd /k powershell -ExecutionPolicy Bypass -File .\run_flink_job.ps1

关键参数是-ExecutionPolicy Bypass。Windows默认执行策略限制脚本运行,这是初学者最容易栽的地方。从那以后,我只要在Windows环境跑任何脚本,第一件事就是查执行策略,而不是怪脚本写得有问题。如果你计划在Windows下长期开发Flink作业,装个WSL或者Git Bash会舒服得多。

5.5 Flink CDC Pipeline部署时的端口与权限问题

现象:flink-cdc-pipeline提交到集群后,源端连接正常但瞬间断连,或者权限不足报错。

原因:CDC连接器需要访问数据库的binlog和特定端口,而部署Flink的机器防火墙没有放行,或者数据库账号没有REPLICATION SLAVE权限。

解决:在源头数据库确认两个事——账号权限列表里有没有SELECT、REPLICATION SLAVE、REPLICATION CLIENT;被连数据库的IP白名单有没有包含Flink TaskManager的节点IP。这两个配置不在Flink端报错信息里直接体现,往往查半天代码都没用,不如直接找DBA确认权限来得快。

5.6 同一份jar在不同集群上的行为差异:认真看日志而不是看热闹

现象:本地Flink Standalone集群运行正常,提交到CDH或HDP集群后,行为完全不同——有的表能建,有的表不能建,各种NoSuchMethodError。

原因:不同发行版集群自带Flink/Hive版本不一致,公共依赖在集群里被强行替换了。比如CDH的Hive版本是1.1.0,而你本地编译用的Hive版本是3.1.0,二进制不兼容。

解决:先确认集群的Flink主版本和Hive版本,再用这套脚本时,把pom.xml里对应依赖改为集群版本。不要迷信"Flink版本一样就万事大吉"这种说法,版本兼容性从来不是一句版本号匹配就能解释的。

6. 验收这套脚本的最后一步:用Checkpoint历史与火焰图判断作业健康

6.1 五分钟看Checkpoint历史

脚本跑通不意味着作业健康。我的验收习惯是打开Flink Web UI,进入Checkpoints标签,重点看两个数字:End to End Duration和State Size。前者通常应在秒级,如果超过10秒,说明状态过大或磁盘I/O有问题;后者如果持续非线性上涨,说明状态设计有问题。

# 在Flink CLI里也可以直接看 ./bin/flink list -s -m localhost:8081

这条命令列出最近一次成功的checkpoint位置。如果长时间没有新的checkpoint产生,检查日志里是不是一直在报Checkpoint expired before completing。这两个信息合起来,基本能判断作业当下是否健康。

6.2 火焰图怎么看:热点是在反序列化还是在业务算子

脚本资源里碰巧提到Flink火焰图,这个工具在排查CPU型性能问题时非常有效。Flink Web UI的Profiler里能直接生成火焰图,主要看栈顶的采样占比。如果热点集中在KafkaConsumer.run的序列化方法里,说明反序列化是高消耗点,改造方案就是换成更轻量的序列化格式;如果热点在你的业务算子方法里,那就是业务逻辑本身的问题,该优化的是代码不是参数。

6.3 数据对账技巧:可以用外部命令验证上下游数据量一致性

假验收比不验收更坑。我的习惯是独立于Flink之外,再想一个办法去验证数据的正确性。对这套实时湖仓场景,最快的方式是Kafka消费端和生产端两侧同时计数。

# 统计Kafka里的数据量(粗略值) ./bin/kafka-run-class.sh kafka.tools.GetOffsetShell \ --broker-list localhost:9092 \ --topic ods_business_data \ --time -1 # 统计Hive表里的数据量(准确值) hive -e "SELECT COUNT(*) FROM hive_catalog.default.hive_orders;"

如果Kafka的消费滞后已经为0,而Hive表计数卡住不动,问题大概率出在分区提交或写入格式上。这套核对流程走完,再小的差异都能暴露出来。从那以后,我每次用这套脚本验证实时湖仓方案,都强制先跑一遍数据对账脚本,再谈优化。五个小时的玩转,真正让技术沉进手里的,就是这些你自己动手验证过的细节。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 14:02:54

Matlab机器学习实战:SVM模型训练与调参避坑指南

简介&#xff1a;面向计算机、电子信息工程与数学等专业学习者&#xff0c;基于Matlab的机器学习实战源码与数据包以实际代码为主线&#xff0c;覆盖机器学习从数据导入、模型训练到结果评估的常用流程与算法实现。压缩包共17个文件&#xff0c;其中14个m文件为Matlab源码&…

作者头像 李华
网站建设 2026/10/1 14:02:46

Vue 项目 tsconfig/jsconfig 配置避坑指南

在 Vue 项目里&#xff0c;jsconfig.json和tsconfig.json经常被当成“可有可无的编辑器配置文件”&#xff0c;直到某天/components/Foo.vue在 IDE 里能跳转&#xff0c;打包时却报模块找不到&#xff1b;或者tsconfig.json里加了compilerOptions.paths&#xff0c;vue-tsc通过…

作者头像 李华
网站建设 2026/10/1 14:02:31

13个图像标注工具选型:VOC/YOLO/COCO转换与预标注实践

标注这件事&#xff0c;只有真正做过的人才知道它有多磨人。我第一次系统性地栽跟头&#xff0c;是在一个工业表面缺陷检测项目上&#xff1a;团队用 LabelImg 标了将近两万张图&#xff0c;标注的同学干得很认真&#xff0c;框得也细&#xff0c;结果在训练前的格式转换环节发…

作者头像 李华
网站建设 2026/10/1 14:02:16

用友ERP二次开发实习总结:扩展字段与OpenAPI实战

用友ERP系统二次开发这几个字&#xff0c;我是入职实习第一天从带教师傅嘴里听到的。当时我脑海里只有「ERP系统」四个字的大致轮廓——大概是个管进销存、财务、生产的大软件——至于「二次开发」要开发什么、改哪里、拿什么工具改&#xff0c;我是一点概念都没有。两个月下来…

作者头像 李华
网站建设 2026/10/1 14:02:04

AI对齐与奖励黑客:从纸夹最大化器到目标函数错配

1. 纸夹的故事&#xff1a;一个看似无害的目标如何走向灾难 我第一次听到 "paperclip" 这个词被当成一个严肃的工程问题来讨论&#xff0c;是在一次关于 AI 安全的内部技术分享上。当时主讲人放了一张幻灯片&#xff1a;一个生产回形针的自动化工厂&#xff0c;画面干…

作者头像 李华