面向六个月后的 AI Code,也许影响的不只是前端
程序员 code 流程:需求评审 - 技术方案设计 - 企业/社区方案完成代码框架 - 代码实现 - 单元测试 - 项目验收。
不可取代性主要集中在需求理解,技术设计和代码框架对企业内部知识有依赖,AI 无法全面完成,其余的工作 Agent 在程序员的监督下可以代劳。
现在,Cursor 的 Codebase Indexing 理解项目全文,参考项目中已有的代码模式和风格,生成更符合项目实际情况的代码。RAG + Function Call 让模型更懂企业,但 Function Call 每次调用需将 API 返回数据全量注入提示词,导致上下文长度线性膨胀。同时 Function Call 的生态极其碎片化,不同模型厂商定义各自的函数调用格式(如 OpenAI 的 JSON 结构),导致跨平台开发需重复适配,同时因为开发者需手动实现三阶段流程(函数定义→模型适配→结果解析),每新增一个 API 需投入大概 20+ 小时开发。
MCP 是 Anthropic 提出的一个用于标准化应用程序如何向大语言模型提供上下文的开放协议,相当于模型与各种应用程序之间的 USB-C。MCP 使用 C/S 模式,它们之间用一种标准的消息格式(基于 JSON-RPC)交流:
- MCP Client:嵌入在 AI 应用内(比如 Cursor),负责跟服务器“聊天”,根据用户自然语言,智能发起 MCP 服务调用,获取数据、资源或命令执行。
- MCP Server 器:开发者提供的向模型暴露内部数据、资源、功能的服务。
MCP 带来了几个核心优势
- 协议标准化驱动生态统一: MCP 通过统一的协议简化了 AI 与外部工具的连接,开发者无需为每个工具单独编写接口代码,实现一次开发多工具复用。
这里有数千开源的 MCP Server 实现可以使用、借鉴,Cursor、Windsurf 等 IDE 均已支持: https://glama.ai/mcp/tools、 https://smithery.ai/
- 开发效率:MCP 官方提供了开发工具包 & 调试工具,相对于兼容各种 AI 模型的 Function Call,实现一个通用的 MCP Server 极其简单。
- 根治上下文爆炸:MCP 采用模块化上下文管理,将外部数据源抽象为独立模块,模型仅在需要时激活指定模块,同时通过增量索引,MCP 仅同步变更数据,相比 Function Call 的全量注入模式,Token 消耗显著降低。
- 动态发现与灵活性:MCP 支持动态发现可用工具,AI 可自动识别并调用新接入的数据源或功能,无需提前配置。
Fuction Call 与 MCP
- Function Call:用户输入 → 模型识别意图 → 生成工具参数 → 执行外部函数 → 返回结果整合。
- MCP:用户输入 → Client 向 MCP Server 请求可用工具列表 → 模型生成自然语言指令 → Client 解析指令并调用工具 → 返回结果 → 模型根据结果更好的响应用户输入。
Function Call 依赖模型层面的支持,而 MCP 更像是模型的外挂,只要有 Client 负责提供可用服务列表并对模型发起询问,任何模型都可以使用 MCP,no magic, just chat。
阿里妈妈搜索广告大模型2024思考与实践
K8S异常诊断之俺的内存呢
认知推荐(二):基于LLM的淘宝推荐算法显著提升发现性比例
什么?!redis也可以是成本优化利器
Redis Stream 适用于消息量级较大成本较高的业务,但需要接受可能的消息丢失,由于 redis 内存有限,不支持存储大量消息,所以通常不支持有追数据需求的业务,除此之外,使用 Redis Stream 作为中间件需要投入运维资源,需要提前合理预估好资源用量,必要时需要进行手动扩缩容。
从一个事故中理解Redis(几乎)所有知识点
Java Web应用升级故障案例解析
Web 性能优化|了解 HTTP 协议后才能理解的预加载
如何对付一个耗时6h+的ODPS任务:慢节点优化实践
快速止血方案:
- 提高 join 任务的资源分配
- 倾斜热点主要是由空值带来的,这种情况比较好处理,直接对空值加随机值打散就好。
计算堆积
首先造成任务产出较晚的最直接的原因,就是计算堆积。该节点引用了不少外部空间视图,并且这些视图不是简单的 “select * from xxx;” 形式的的简单语句,而是包含了多张表进行 join 的逻辑。这就导致了,虽然视图相关的上游表早早就产出了,但视图 DDL 内包含的计算任务,却落到了该节点上,造成该节点计算量的堆积。
解决:将节点中涉及到的视图进行物化落表,并让我们的慢节点任务,从调用视图变成调用实体表。这一步的操作主要是为了缓解计算堆积的问题,让一部分可以提前进行的计算,尽早进行调度,不必等到大宽表所有的上游依赖都产出之后再开始。
数据倾斜
在定位耗时卡点的时候我们已经发现了空值带来的倾斜问题,并且做了加盐打散的方法来快速止血。但事实上,分析了多个日期分区的数据发现,除了空值以外,偶尔还会出现部分热点用户/热点主播/热点内容带来的数据倾斜(更要命的是,这些热点值每天都不相同)。虽然倾斜程度不如空值带来的影响严重,但仍然对计算任务造成了一定阻塞。
解决:SkewJoin vs MapJoin。SkewJoin:针对这些倾斜的键,采用特殊的处理方式。比如,将这些键的数据单独拿出来,分配更多的计算资源进行处理;或者把这些数据拆分到多个节点上并行处理,避免单个节点负载过重。MapJoin:适用于其中一个参与连接的表是小表的情况,在 Map 阶段开始前,将小表的数据加载到内存中,并广播到每个计算节点上,每个计算节点在处理大表数据时,直接在本地内存中与小表数据进行连接操作,无需进行数据的 Shuffle 过程,从而减少了数据传输和网络开销。
回刷成本高昂
除了上面两个比较明显的问题以外,我们翻看该节点的历史发布记录,可以发现 140 多个发布版本,有至少一半以上的变更内容是和埋点参数解析相关的。针对埋点解析正确性的验证,往往需要补数据回刷确认,单一节点动辄 6、7 个小时的回刷成本,给数据验证也带来了不小的麻烦。
解决:把宽表节点拆分成两部分:关联维表进行标签补全的部分(中间临时表)、埋点解析&字段格式处理的部分(叶子结点)。这样拆分之后,在数据结构没有较大调整的情况下,未来新增埋点参数解析类的需求,只需要变更回刷相对简单的叶子结点即可,无需回刷 join 关联的部分,从而减少了回刷成本。
Java日常反常识踩坑
- 转 BigDecimal 类型时精度丢失。
- Arrays.asList 添加异常。
- Double 除以 0 不抛异常。
- switch 传入 null 会抛出异常。
- Steam filter 后集合修改导致数据变化。
如何优雅地编写缓存代码
缓存用于解决高并发问题,但应用端调用缓存 API 存在诸多问题,如逻辑分散、与业务代码耦合、API 升级等。
@Cacheable(value = "user_cache", unless = "#result == null")
public User getUserById(Long id) {
return userMapper.getUserById(id);
}
@CachePut(value = "user_cache", key = "#user.id", unless = "#result == null")
public User updateUser(User user) {
userMapper.updateUser(user);
return user;
}
@CacheEvict(value = "user_cache", key = "#id")
public void deleteUserById(Long id) {
userMapper.deleteUserById(id);
}Spring Cache 利用 AOP 和动态代理实现基于注解的缓存功能,适合对数据实时性要求不高的场景,但在高并发大数据量场景下需功能扩展。
可以基于 SpringCache 进行功能扩展,如计数、缓存刷新、列表缓存、分布式锁、多级缓存等。
Java 22 新增利器: 使用 Java Stream Gather 优雅地处理流中的状态
Java对象头压缩—永久为Java应用“降本增效”
对象头压缩技术,将 hash+age 等放到类指针后面,使得内存占用从 24 bytes 减少到 16 bytes。由于原始 layout 的 java 对象头需要支持 biased locking 以及 CMS GC,需要预留更多的 unused bits,所以使用对象头压缩无法支持 biased locking 以及 CMS。(注:biased locking 在 JDK17 中默认关闭,JDK21+中删除,CMS GC 在 JDK17+中删除)
在支持该功能的 Dragonwell 11 的 JDK 版本中,增加启动参数 -XX:+UseCompactObjectHeaders,仅支持 -XX:+UseG1GC (默认) 和 -XX:+UseParallelGC。目前的 Compact object headers 的实现无法支持ZGC。
技术领导力之路 - 正反馈
TRE 部门组织氛围调研显示,管理者给予员工正反馈不足是公司普遍现象,这影响员工工作热情。
每天一个摆脱if-else工程师的技巧——优雅的参数校验
Spring Bean Validation 来进行参数校验,类似于 Python 中 Pydantic 的形式。
可以进行参数校验、分组校验、自定义校验注解等等。
记一次mysql问题排查
删除大量的 group 为 bad_group 的数据,由于不能直接 delete 全量数据,文中选择了下面逻辑:
-- 将正常数据复制到临时表
CREATE TABLE TEMP_TABLE AS SELECT * FROM MY_TABLE WHERE group <> 'bad_group';
-- 删除原表
DROP TABLE MY_TABLE;
-- 将临时表重命名为原表
RENAME TABLE TEMP_TABLE TO MY_TABLE;一些隐藏问题:
- 并发操作:在执行这些语句期间,如果有其他事务正在对
MY_TABLE进行读写操作,就可能造成数据不一致。例如,在创建临时表之后、删除原表之前,有新的数据插入到MY_TABLE,这些新数据不会被复制到临时表,从而导致数据丢失。 - 外键约束:若
MY_TABLE存在外键关联到其他表,删除原表会破坏这些外键约束。当其他表尝试引用已经删除的MY_TABLE时,会出现引用错误。 - 索引:在创建临时表时,
CREATE TABLE ... AS SELECT语句只会复制表的数据,不会复制原表的索引。当把临时表重命名为原表后,原表的索引就丢失了,这可能会影响查询性能。 - 约束:同样,该语句不会复制原表的约束(如唯一约束、检查约束等)。这可能会导致数据完整性无法得到保证,例如原本不允许重复的字段,在重命名后的表中可能会出现重复值。
比较合适的,或许?分批删除数据
DECLARE @BatchSize INT = 1000;
WHILE EXISTS (SELECT 1 FROM MY_TABLE WHERE group = 'bad_group')
BEGIN
DELETE TOP (@BatchSize)
FROM MY_TABLE
WHERE group = 'bad_group';
-- 可以添加延时,减少对系统的压力
WAITFOR DELAY '00:00:01';
END扩展:CREATE TABLE LIKE 语句可以复制一个表的结构,包含表的列定义、索引、主键、外键约束等,但不会复制表中的数据。
一次由于八股文引起的内存泄漏
Spring Bean生命周期图。
线上出现大量 FullGC,发现严重内存泄漏。有 11 万个 PoolingHttpClientConnectionManager 实例,占用了 80.42%的堆内存,通过内存发现由 OSS 间接依赖进来的。
每次 new OSSClient 的时候,都会往 List 中放入 HttpClientConnectionManager,但是没有主动调用 OSSClient 的 shutdown 的方法,所以 List 只会增大不会变小。反观代码,每次接口调用都会创建一个 OSSClient 对象,但却在使用完之后,没有调用 OSSClient 的 shutdown 方法,导致未调用 IdleConnectionReaper 的 removeConnectionManager 方法,使得 IdleConnectionReaper 中静态列表存储的 PoolingHttpClientConnectionManager 实例数据一直会增长,一直都不会被回收,最终带来的结果就是 OOM。
@Component
public class OssClient implements BeanPostProcessor {
private OSS ossClient = null;
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// 省略代码……
// 一下是阻塞代码行
ossClient = new OSSClientBuilder().build(ossProperty.getString("endpoint"),
ossProperty.getString("accessKeyId"),
ossProperty.getString("accessKeySecret"),
configuration);
// 省略代码……
return bean;
}
}根据代码,结合 SpringBean 的生命周期,发现实现错了接口导致的 OSS 初始化被重复调用,最终导致系统 OOM。
@Component
public class OssClient implements InitializingBean {
private OSS ossClient = null;
/**
* 初始化OSS客户端
**/
@Override
public void afterPropertiesSet() throws Exception {
// 省略代码……
// 以下是阻塞代码行
ossClient = new OSSClientBuilder().build(ossProperty.getString("endpoint"),
ossProperty.getString("accessKeyId"),
ossProperty.getString("accessKeySecret"),
configuration);
// 省略代码……
}
}afterPropertiesSet:该方法来自InitializingBean接口。当一个 Bean 实现了InitializingBean接口,就需要实现afterPropertiesSet方法。在 Spring 容器完成 Bean 的属性注入之后,会调用这个方法,从而允许 Bean 在属性设置完成后进行一些自定义的初始化操作。postProcessAfterInitialization:它是BeanPostProcessor接口里的一个方法。BeanPostProcessor是 Spring 提供的一个强大的扩展点,允许开发者在 Bean 的初始化前后进行额外的处理。postProcessAfterInitialization会在 Bean 的初始化方法(像afterPropertiesSet或者自定义的init-method)执行之后被调用。
以 BeanPostProcessor 接口的 postProcessAfterInitialization 方法为例,Spring 容器会在每个 Bean 执行完自身的初始化逻辑(如实现 InitializingBean 接口的 afterPropertiesSet 方法,或者自定义的 init - method 指定的方法)之后,调用所有注册的 BeanPostProcessor 的 postProcessAfterInitialization 方法。因此,出现 OSS client 被大量生成。
软件架构一致性 —— 被忽视的研发成本
广义软件研发活动,包含不得不付出的成本。广义软件研发活动包括需求分析、源码阅读、代码编写等多方面工作,可分为两类,第一类是价值创造活动,第二类是为了价值创造不得不付出的成本,如发布运维、安全漏洞修复,各种基础软件升级等等。
软件研发的供应链设计很多模块。软件研发涉及供应链管理,以 Java 应用为例,完整的软件供应链包括开发框架、各类 library、编程语言、操作系统、调度系统及服务、容器环境、云服务、业务服务、配置、网络配置等。
软件研发的供应链管理由必要性。如安全漏洞快速修复、硬件适配、提升研发体验、降低维护成本、去除脆弱依赖。
降低软件供应链管理。几乎所有的软件供应链管理问题都可以理解成为:把一个或者多个目标软件/服务/配置升级到期望的版本。降低软件供应链管理工作成本可从显式或隐式(显式声明管理成本低)、结构化或无结构(结构化内容管理成本低)、一处修改或处处修改(一处修改成本低)、自动验证或手工验证(自动验证成本低)四个角度分析。
架构一致性问题:架构一致性问题是 Scalability 问题,期望随着代码量、服务使用量、应用数增长,维护成本不线性增长。Scalable 方案模式诱因是业务增长 Growth,需引入技术 Tech,同时实现服务水平保持 Keep Service Level(如在可接受时间内完成代码修改)和人员投入亚线性 Sublinear Human Interaction(代码量增长时人员投入增长小)两个目标。
处理架构一致性问题的方法:
- 专家服务:对于大型技术团队,让少数专家处理如 JDK 升级等问题更高效,专家可积累知识形成文档,并结合大模型技术以 AI 服务形式提供。
- IaC(基础设施代码化):将基础设施数据交还给用户,实现基础设施显式和结构一致的描述,避免重复劳动,便于提取通用功能函数。
- Serverless:将应用分为 App 和 Runtime 两层并单独维护演进,使大量 App 复用相同 Runtime,实现基础设施收敛和 Runtime 独立升级。
- Mono Repo(大库):在编译期间确保不重复(DRY),将多个应用代码合并,统一处理 infra 相关代码,简化版本升级,但需进行大量代码重构。
「我在淘天做技术」2024年看AIGC是如何让1688主图焕发新春的
背景:主打品质的 1688 严选,当时的主图质量参差不齐,视觉上很难让买家信服这是 1688 严选过的商品,因为看上去与其他的 1688 商品无异。
目标:提升严选商品主图品质感,同时,解决合图带来的效率和成本问题,我们既要规模又要效率还要效果。
方案:品质主图任务中心,整体分为两块,一是品质主图生产,二是主图投放、管理和数据回流。
品质主图生产侧,主要负责:1688 商品主图图源获取(目前主要使用商家上传的白底图)、合图前准入机审、卖点定义与聚合、商品范围(选品)、打通 AIGC 合图能力进行主图+卖点+风格模板选择的品质主图合成、合成图的准出机审。
品质主图投放侧,主要负责:1688 商品模型对品质主图的扩展存储、支持品质主图对不同渠道做投放(推荐/搜索/严选频道/PLUS 会员店/营销会场)、实验接入与数据回流(持续迭代不同渠道/卖点/模板的灵活度设计)。