字节跳动把 LLM 关进离线笼子,让线上推理零延迟——LLM-BlockFE 的"离线炼丹,线上执行"哲学
一个"反 AI Agent"的架构选择
2025 年下半年,AI Agent 最热的方向是"让 LLM 在线上做决策"——实时调用 LLM 做推理、做规划、做工具调用。整个行业都在往"更多线上 LLM 调用"的方向狂奔。
字节跳动的工程师们做了一个看起来"逆潮流"的选择:把 LLM 的所有复杂推理关进离线阶段,线上推理时完全不调用 LLM。
结果?在五个真实金融风控应用中,覆盖 269 万真实用户,坏账率从 8.0% 降到 7.7%。线上推理延迟是毫秒级——因为线上根本不跑 LLM,只跑 LLM 在离线阶段"写好"的特征代码。
这个系统叫 LLM-BlockFE,它解决的是一个看似矛盾的问题:LLM 擅长理解长文本,但线上推理太慢太贵;传统特征工程快但不懂语义。能不能两全?
长文本特征工程的"三座大山"
金融风控场景有大量长文本数据:用户备注、催收报告、投诉记录。这些文本对风险评估极有价值,但传统方法处理不好。
第一座大山:TF-IDF 只看词频,不懂语义。"用户表示会尽快还款"和"用户拒绝还款"在 TF-IDF 看来可能只差几个词,但语义完全相反。
第二座大山:传统语言模型(Longformer、BigBird)能编码长文本,但特征不可控、不可解释。金融风控要求每个特征都能审计——你不能给一个"黑箱嵌入"作为拒绝贷款的理由。
第三座大山:在线调用 LLM 做特征提取太慢。一次 GPT-4 调用几百毫秒,风控场景要求毫秒级响应。更不用说成本——每天几千万次调用,账单会让人心碎。
LLM-BlockFE 的解法是:让 LLM 在离线阶段写代码,把"理解长文本"的能力固化成可执行的特征提取程序,线上只跑代码不跑 LLM。
种子程序与代码块的增量生长
LLM-BlockFE 的核心数据结构是"特征程序"(Feature Program)。它从一个"种子程序" P₀ 开始——一个空壳,只定义了输入、输出和代码插入点。
然后 LLM 以"完整生成 + 增量提取"的方式往程序里添加代码块。这里有一个精妙的设计:
LLM 每次生成的是完整程序,但系统只提取新增的代码块。
为什么要这样?因为如果你让 LLM "只写新增部分",它经常写出和现有代码不兼容的东西——变量名冲突、调用未定义的接口、语义断裂。让 LLM 看到完整程序再生成,能保证新增代码和现有代码的兼容性。但如果你直接接受 LLM 生成的完整程序,又无法做增量回滚——你不知道哪部分是新的、哪部分是旧的。
解法是用标记:LLM 在生成时用 标记新增区域,系统用正则提取出新增代码块,再拼接到现有程序上。同时严格检查标记外的代码是否被修改——任何对原始代码的改动都会被拒绝。
这就像 Git 的 diff 机制:LLM 生成的是完整文件,但系统只接受 diff。这样既保证了上下文一致性,又保留了增量回滚的能力。
信用引导的深度校准回溯
光会"加代码"还不够,还得会"退回去"。LLM-BlockFE 的第二个创新是"深度校准的信用引导回溯"(Depth-calibrated Credit-guided Backtracking)。
想象你在走迷宫。每到一个岔路口,你选一条路走。走了几步发现是死路,你退回上一个岔路口。但问题是:什么时候该退?退到哪一步?
简单方案:连续失败 3 次就退。但这个"3 次"是拍脑袋定的——不同深度、不同任务的最优阈值不同。
LLM-BlockFE 的方案是:根据当前节点在当前深度的"历史表现"和"近期扩展结果"动态决定。如果一个深度上的节点历史上扩展成功率低,近期又连续失败,就回溯;如果历史成功率高,只是近期运气不好,就继续尝试。
这叫"信用引导"——每个代码块都有一个"信用分",基于它对下游模型 AUC 的贡献。信用分高的节点,扩展时更宽容;信用分低的节点,扩展时更严格。
"深度校准"则是另一个维度:不同深度的节点有不同的基线表现。浅层节点(程序开头)的代码块通常信用分高,因为它们处理的是基础特征;深层节点的代码块信用分低,因为它们处理的是细粒度调整。回溯决策要考虑"你在这个深度应该期望多高的成功率"。
下游 AUC 闸门:最关键的组件
消融实验揭示了一个反直觉的事实:整个系统最重要的组件不是 LLM 生成的代码,而是"下游 AUC 闸门"。
什么是下游 AUC 闸门?每当 LLM 生成一个新的代码块,系统不是直接接受,而是先用一个轻量级 XGBoost 模型评估:加了这个代码块后,下游任务的 AUC 是否提升?如果不提升,代码块被拒绝。
去掉这个闸门,AUC 从 0.6760 掉到 0.6268——几乎和不用 LLM 的基线一样。这意味着 LLM 生成的代码块,有相当一部分是"看起来合理但对下游任务没用"的。
这是一个"标量幻觉"的经典案例:代码块的"合理性"和"有用性"是两个独立维度。LLM 能生成合理的代码(语法正确、逻辑通顺),但不一定能生成对下游任务有用的代码。下游 AUC 闸门就是在拆解这个标量——只接受"既合理又有用"的代码块。
其他消融结果也很有意思:
- 去掉回溯机制:AUC 掉 0.029(单路径搜索受早期选择约束)
- 去掉信用引导(改用固定 3 次失败阈值):AUC 掉 0.019
- 去掉深度校准:AUC 掉 0.012
- 去掉贝叶斯优化(不调参):AUC 掉 0.038
- 去掉只增不删约束:AUC 掉 0.040
线上零 LLM:架构解耦的胜利
LLM-BlockFE 最具工程价值的决策是把 LLM 完全关在离线阶段。
线上推理时,系统执行的是"冻结"的特征程序——纯 Python 代码,无 LLM 调用。这意味着:
- 延迟:毫秒级(和传统特征工程一样快)
- 成本:几乎为零(只跑 Python 代码)
- 可审计:每个特征都是可读的代码,监管要求完全满足
- 可复现:同样的代码对同样的输入永远给出同样的输出
这是"组件-互动解耦"的典型实践:LLM 的"理解能力"和"推理延迟"被解耦到不同阶段。离线阶段用 LLM 的理解能力生成代码,线上阶段用代码的执行速度做推理。两者不再耦合——你不需要在每次推理时都"重新理解"文本。
生产部署:269 万用户的实证
最让人信服的数据来自生产环境。LLM-BlockFE 被部署到五个真实的金融风控应用中,覆盖 2025 年 9-11 月的 269 万真实用户。
在所有 15 个应用-月份对比中,LLM-BlockFE 的 KS 值都高于原有人工策略。绝对提升在 0.02-1.56 个百分点之间。
更有说服力的是在线 A/B 测试:在约 10 亿元贷款发放的评估中,实验组的坏账率从 8.0% 降到 7.7%,而审批通过人数不变。这意味着特征提升的不是"拒绝更多人",而是"更准确地识别风险"——好用户不被误拒,坏用户被更精准地拦截。
公司已经用这个框架构建了 200 多条特征链,覆盖几乎所有客户分群。
一个更深的洞察
LLM-BlockFE 的成功揭示了一个被忽视的架构选择:
LLM 最有价值的用法可能不是"在线做决策",而是"离线写程序"。
整个行业都在往"Agent 化"方向走——让 LLM 在线上做规划、做工具调用、做决策。但字节跳动的工程师们发现,在很多实际场景中,你不需要 LLM 在线上做决策,你需要的是 LLM 帮你"写好决策程序",然后程序在线上跑。
这和"被动控制哲学"异曲同工。放屁甲虫不靠更快的神经控制阀门,而是设计一个不需要控制的被动结构。LLM-BlockFE 不靠更快的线上 LLM 做实时推理,而是设计一个不需要线上 LLM 的离线-在线分离架构。
当任务复杂度超出在线推理的速度极限,不要用更快的 LLM,而是把 LLM 的能力固化成代码。
这个思路适用于所有"LLM 理解能力强但推理速度慢"的场景:
- 法律合同审查:LLM 离线生成审查规则代码,线上只跑规则
- 医疗诊断辅助:LLM 离线生成诊断逻辑代码,线上只跑逻辑
- 教育评估:LLM 离线生成评分标准代码,线上只跑标准
结语
LLM-BlockFE 给我们的启示不是"LLM 不能在线上用",而是"我们太急于把 LLM 放在线上了"。
在很多场景中,LLM 的最大价值不是作为实时推理引擎,而是作为"程序生成器"——把它的理解能力固化成可执行的代码,让代码在毫秒级延迟下运行。
这不是倒退,这是成熟。就像编译器取代了逐行解释——不是解释器不好,而是编译后的代码更快。LLM-BlockFE 把 LLM 的"理解"编译成代码,让"理解"和"执行"各司其职。
离线炼丹,线上执行。这才是 LLM 在生产系统中的正确姿势。
---
*论文:Long Text to Predictive Features: LLM-Guided Blockwise Feature Engineering, arXiv:2610.12390* *作者来自字节跳动,无独立开源代码仓库*