说到 LLM 写代码,我最常被问的不是某个模型好不好用,而是“我们团队现在代码量暴涨,为什么越来越没人能接手维护”。这个现象正好对应一个概念:Programmatic Stagnation,中文可以理解成程序化停滞。它不是在说 LLM 能力不行,而是在说人和生产流程在大模型时代会暴露出来的卡点:生成代码的速度上去了,理解、调试、测试、维护和架构决策的能力没跟上。
如果你正在用 LLM 辅助开发,或者团队已经引入了 AI 编程,这篇文章值得看完。我会先讲清楚程序化停滞的具体信号,再给一套个人和团队都能落地的对抗方法,然后继续拆到应用落地时最容易卡住的编排、部署与验收环节。整体思路很简单:LLM 代替的是重复劳动,不是人的理解能力。
1. 程序化停滞到底卡在哪:不是模型不够强,是生产链路没有跟着变
1.1 先从现象认识“程序化停滞”
最典型的场景长这样:一个需求下来,开发者把需求复制给 LLM,模型生成几百行代码,开发者本地跑一遍,没问题,提交了。过了两天,另一个需求要改其中一段逻辑,没有人能说清原来那段代码为什么这么写。于是又让 LLM 重新生成一个版本,可能整个函数被推倒重来。代码仓库里的文件越来越多,但模块之间的边界越来越模糊。这就是程序化停滞:程序在持续生产,编程能力却原地徘徊。
它也可以表现为文档缺失。注释都写得像模像样,但设计文档为空;函数都能跑,但没人知道为什么拆成这些函数;接口都能调通,但接口之间的数据流向只存在于某次对话记录里。等到模型升级、依赖升级、人员变动,这些问题会集中爆发。
程序化停滞不是某一个人独有的问题。它更像一种团队状态:每个节点都在用 LLM 产出代码,但真正能把代码从“能跑”推进到“可维护”的环节没人负责。生成速度越快,积压的不可控代码越多,项目反而越难推进。
1.2 为什么 LLM 会让这种停滞更容易发生
很多人在使用 AI 编程工具之后会有一个直觉:代码长得越来越像正确答案。以前从论坛复制粘贴的代码,多少还残留着调试痕迹、奇怪的临时变量、缺一半的异常处理;LLM 输出通常结构完整、命名规范、注释齐全。这种“专业感”会让人放松警惕,默认它是对的。
但真正决定代码能不能长期维护的,往往不是格式,而是业务约束、边界条件和异常路径。这些恰恰需要人去读、去测、去验证。模型生成代码时,缺少对真实业务场景的确认,它只是在概率上补全一段看起来合理的文本。如果开发者不补上验证环节,就相当于把不确定的复杂度直接放进生产环境。
另一个原因是反馈回路变短了。传统编程里,写错要经过编译、运行、报错、修复,这个过程虽然痛苦,但会逼着人理解每一步。用 LLM 之后,从需求到产出只要几分钟,中间的冲突和试错被抹平了,人没有机会积累那部分直觉。短期的感觉是效率变高,长期来看,调试经验、代码阅读能力、问题定位能力都会退化。
还有一个容易被忽视的点:技能结构发生了位移。以前老手和新手的差距,很多体现在代码阅读能力和调试能力上;现在这两项能力恰恰是最容易被 AI 代劳的。如果一个人长期只写 prompt、只复制结果,他的调试能力会钝化。一旦失去这个能力,遇到复杂问题时,就只会不断换 prompt 重试,而不是打开日志找原因。
1.3 识别停滞的几个信号
如果你不确定自己有没有进入这个状态,可以先对照几个信号来看:
- 离开 LLM 提示,连一个短小函数都不会起笔。
- 模型生成的代码报错,第一反应是重新生成,而不是打开日志找原因。
- 功能能跑,但没有为它补测试用例。
- 你能把模型生成的代码贴出来,但讲不清楚它为什么这么设计。
- 代码评审里,所有人只看结果能不能运行,没有人讨论接口契约和模块边界。
反过来,健康的信号也很明确:你能改掉模型生成的一部分逻辑而不怕出问题;你能为新场景补上边界测试;你能在半小时内说清一段代码的输入、输出和风险。
可以用下面这个表格做快速判断:
| 停滞信号 | 健康信号 |
|---|---|
| 离开模型不会写小函数 | 能独立写出短小清晰的函数 |
| 报错后重新生成 | 先看日志和调用栈定位原因 |
| 不写测试 | 至少为关键分支补测试 |
| 贴代码但讲不清 | 能解释模块边界和异常处理方案 |
| 只关心能否运行 | 关心可测试性和可维护性 |
这些信号不需要全部命中才算停滞。只要中了三条,就该调整使用 LLM 的姿势了。
2. 对抗个人停滞:把 LLM 当成结对搭档,而不是自动结账机
2.1 “读-改-测-讲”四步闭环
我这里有一个很笨但很有效的办法:每次让 LLM 生成代码后,不要直接接受,先做四步。
第一步,读。把生成代码从头到尾读一遍,不是看有没有语法错误,而是看它把逻辑分成了哪几段,哪些地方你没想到。读的时候可以问自己:如果下次换一个需求,我要改哪里?
第二步,改。随便挑一个变量名、一个边界值或一个分支条件,主动改一下,跑一遍测试,看结果是否按预期变化。这个动作是为了确认你真的理解了这段代码,而不是只会看。
第三步,测。补一组用例,至少覆盖空输入、正常输入、异常输入。模型生成的代码往往只覆盖了正常路径的前半段,边界测试是最容易暴露问题的地方。
第四步,讲。把你读到的实现思路讲给别人听,或者带着结论写到周报和笔记里。讲不出来的部分,就是你的知识盲区,也是程序化停滞最常发生的地方。
这个闭环的价值不在于效率,而在于把使用 LLM 的过程重新变成学习过程。你仍然用模型省掉搭建骨架的时间,但你必须为结果负责。模型可以帮你完成初稿,但不能替你建立对代码的所有权。
2.2 用 LLM wiki 的思路建个人知识库
近年开发者圈子里经常出现 LLM wiki 这个提法。它的核心不是让模型替你写文档,而是把大模型当作一个可以随时问话的对话式知识库,同时由你自己维护知识结构。换句话说,模型负责检索和表达,你负责判断哪些东西值得沉淀。
我自己的做法很简单:遇到一个能跑通但不太理解的方案,我会在本地 Markdown 文件里记录三件事——问题是什么、我做了什么尝试、最终为什么这么选。LLM 可以辅助生成记录草稿,但目录和标签由我自己维护。这样下次遇到类似问题,我不必重新让模型从头推理,只需翻看自己的 wiki。
工具层面,Obsidian 或其他本地笔记工具都只是容器。真正重要的是内容是否围绕你的实践展开。长期积累下来,个人 wiki 会越来越像一份专属架构手册,而不是收藏夹里越堆越多的文章链接。程序化停滞的一个典型表现,就是反复让模型回答同一个问题,却从不把答案变成自己的知识资产。
2.3 把 LLM 放进代码审查流程
我建议团队把 LLM 放进代码审查里,但不要把审查权交给它。具体做法是:当开发者提交代码时,让 LLM 负责三类检查。
第一,边界条件有没有遗漏。比如空列表、超长输入、并发写、文件不存在这些情况,模型生成代码时经常只处理正常分支。
第二,错误处理有没有收敛。是不是只管返回 null,没有日志;是不是把所有异常都吞掉,导致线上问题无法定位。
第三,能不能基于现有代码生成一批测试用例。不是简单跑通主流程,而是补覆盖率和边界分支。
开发者收到这些建议后,再对照业务需求做判断。为什么不能让 LLM 全权把关?因为模型缺少项目上下文和长期演进目标。它看得见局部代码,却看不见模块之间为什么这么划分。真正应该由人拍板的,是接口契约、数据流方向、兼容性策略和重构边界。把这些交给模型,等于把架构决策外包给一个没有全局视图的助手。
3. 从“写代码”到“搭应用”:工程化编排才是真正拉开差距的地方
3.1 为什么单次生成不等于应用落地
很多初学者第一次接触 LLM 应用开发时,会以为“调用模型接口返回结果”就是应用的全部。实际上,一个能稳定上线的 LLM 应用,除了模型调用,还要处理三件事:上下文怎么组织、工具怎么接入、失败怎么兜底。这就是越来越多人提到 LLM 编排框架的原因。不是说必须用复杂框架,而是说单次调用无法覆盖真实场景。
真实场景长什么样?用户提出一个问题,这个问题的答案可能在文档库里,需要先检索;也可能需要通过工具查询系统数据,而不是直接靠模型记忆;更可能第一遍回答不完整,需要模型反复纠偏。如果只是把用户输入拼进 prompt,然后拿模型输出返回,很多场景会直接翻车。
LLM 应用开发领域会看到 RAG、MCP、Agent、SpringAI 这些词,它们不是同一层的东西,解决的问题也不一样。把这几个概念放对位置,比背熟某个框架 API 更重要。
3.2 理解 RAG、MCP、Agent 各自的位置
我一般会跟团队这样解释这几个概念。
RAG,检索增强生成,解决的问题是给模型补充外部知识。你有一个企业内部文档库,模型没有训练过这些内容,于是先检索相关文档,再把文档内容放进上下文,最后让模型基于这些内容回答。判断任务是否需要 RAG,就看答案是不是依赖私有、动态更新的知识。如果回答只需要模型通用能力,就不需要引入检索链路。
MCP,模型上下文协议,解决的问题是让模型能够调用外部工具。可以把工具理解成接口:搜索网页、查询数据库、创建工单、解析文件。MCP 提供了一套统一连接方式,让模型不需要为每个工具写一套私有协议。判断任务是否需要 MCP,就看模型是否需要去外部系统拿数据或执行动作。
Agent,智能体,解决的问题是让模型在一个循环里做规划、调用工具、观察结果、继续决策。它适合多步骤任务,比如“查一下最近几天数据异常的原因,并把结论整理成邮件”。判断任务是否需要 Agent:如果只是单轮问答,那不需要;如果模型要连续做两三次工具调用,并且依赖中间结果决定下一步,那才需要考虑 Agent。
SpringAI 这类框架,是在 Java 生态里把这些能力封装成统一入口。具体 API 每个版本差异很大,所以我这里不给精确代码,只给一条通用的处理链路:
# 伪代码:一条带检索和工具调用的问答链路 def handle(user_input): docs = retriever.search(user_input) # RAG:检索外部知识 context = build_prompt(user_input, docs) plan = agent.plan(context) # Agent:决定是直接回答还是调用工具 if plan.action == "tool": result = tool_client.call(plan.tool) # MCP:调用外部工具 final_context = build_prompt(user_input, docs, result) return agent.finish(final_context) return agent.answer(context)这是流程示意,实际落地时你需要关心向量库和 embedding API 的配置,工具调用要设超时,Agent 要限制最大循环次数,防止模型在工具之间反复横跳。
很多 RAG 项目报错并不是模型调不起来,而是 embedding API 未配置。记住:RAG 的检索依赖向量化,如果 embedding 服务没有配置好,后面的检索结果就是空的,模型拿着空上下文回答问题,答案自然不靠谱。遇到这类问题,先确认三件事:embedding 服务的地址和密钥能不能通,向量维度与集合设置是否一致,插入向量时有没有报错。
3.3 从简到繁的选型梯度
做 LLM 应用不要一上来就上全套框架。我的建议是分四档:
第一档,单次问答或文本摘要。直接调模型接口,不需要 RAG,不需要 Agent。先把模型调用、日志、异常处理写好。
第二档,带知识库的问答。加入 RAG,引入向量库和 embedding API,排查点也会增加一个检索链路。
第三档,需要调用外部工具。加入 MCP 和 Agent,处理工具调用的权限、超时和重试。
第四档,复杂业务流程。多个 Agent 协作,需要任务队列、人工审核、审计日志、权限隔离和监控告警。
判断标准很简单:当前任务不依赖外部知识,就不要加 RAG;不需要多步决策,就不要上 Agent。过度编排和没有编排一样,都会让项目快速进入停滞。
4. 部署与资源分配:哪些环节最容易让项目跑起来就卡住
4.1 本地跑 LLM,先看精度、显存和推理引擎
很多项目在 Demo 阶段没问题,一换成自己本地部署就各种启动失败。最常见的原因不是代码写得不好,而是模型精度和设备资源不匹配。这里把几个关键精度聊聊。
| 精度 | 位数 | 权重占用 | 数值范围 | 主要用途 | 常见注意点 |
|---|---|---|---|---|---|
| FP32 | 32 | 最高 | 大 | 训练、基准测试 | 显存要求高,推理不一定需要 |
| FP16 | 16 | 约为 FP32 一半 | 较小 | 常见推理 | 可能出现精度损失、上下溢出 |
| BF16 | 16 | 约为 FP32 一半 | 比 FP16 更大 | 大模型训练与推理 | 部分旧硬件不支持,速度要看算子优化 |
举个简单估算方法:一个 7B 参数的模型,如果以 FP16 加载,权重文件大约是 14GB;BF16 也接近这个体积,FP32 会翻倍。推理时还要加上 KV cache 和中间激活值,所以实际需要的内存会更高。这不是说一定要用最低精度,而是要根据显卡、内存、框架支持一起判断。
在 NVIDIA 显卡上常见的量化格式和 Mac 上的推理引擎支持情况不同。落地时先查你用的框架文档,不要照搬别人的参数。尤其是 Mac 用户,统一内存架构下显存和内存共用,具体能用多大窗口、多长上下文,完全取决于引擎对模型格式的支持程度。
注意:调并发前先确认资源占用。显存接近上限时,优先降上下文长度和并发数,再考虑换精度。
4.2 ComfyUI 和 LLM 不是必须在同一台电脑
这个问题经常被问到,回答很明确:不用。ComfyUI 本身是图像生成工作流,它加载的是图像模型;LLM 是语言模型推理服务。两者都需要显存和内存,但不是同一个进程。
如果你的机器显卡很强,可以都在本机跑,但建议不要同时开大任务。先用一个跑完再调另一个,否则很容易显存交换频繁,速度反而更慢。如果机器配置一般,更合理的方案是分开放。一台图像工作站专门跑 ComfyUI,另一台带 GPU 的服务器跑 LLM 推理服务,通过本机网络调用接口。没有 GPU 也一样能用,前提是你接受 API 服务的成本和数据传递方式。
判断标准很简单:同一时间会不会并发跑两类大模型任务,会不会互相抢占显存,延迟能不能容忍。
有个容易误解的配置点:ComfyUI 的 extra_model_paths.yaml 是用来扩展 ComfyUI 自己读取模型目录的,并不是配置 LLM 模型位置的地方。如果你在 YAML 里写了一个 llm_path,ComfyUI 本身也不会去加载这个模型。想要让 ComfyUI 里的工作流调用 LLM,通常是通过自定义节点或外部 HTTP 请求,而不是把 LLM 塞进它的模型路径配置。不要在这个文件上花太多时间。
4.3 本地部署排查顺序
我总结一个通用排查顺序,遇到跑起来就卡住的问题,按这个顺序走:
先看启动阶段。模型文件是否完整,路径是否写对,依赖是否装齐,端口有没有冲突。
再看资源占用。用系统监控看显存和内存,如果接近上限,优先降并发、降上下文长度,或者换低精度。
再看生成阶段。生成很慢,先看输入长度、并行数量、模型参数量和硬件是不是匹配;输出乱码,先查精度和后处理,不一定是模型坏了。
最后看链路。如果接入了 RAG 或工具调用,先单独测 embedding 和工具接口,确认没有报错,再回到总流程。
这个顺序不复杂,但能避开很多“表面上是模型问题,实际是路径、权限、依赖版本”的坑。
5. 用工程标准验收 LLM 产出的代码
5.1 验收清单
如果团队每天合并很多 AI 生成的代码,但又没有统一的验收标准,那么代码量越大,系统越不稳定。我建议至少用这张清单做检查:
| 维度 | 检查点 |
|---|---|
| 功能正确性 | 主流程能跑通,定义的输入输出与实际一致 |
| 边界情况 | 空输入、超长输入、重复调用、并发调用是否有兜底 |
| 错误处理 | 失败时有明确日志,而不是静默返回空值 |
| 可重复性 | 同一输入在相同上下文下,结果和副作用可控 |
| 可测试性 | 核心逻辑可以被测试用例覆盖,不依赖外部服务 |
| 可维护性 | 代码结构清晰,命名直接,无明显重复和过深嵌套 |
这六项不是每行代码都要做到,但一个功能模块如果连前三项都不满足,就不应该合并。
5.2 多数生成代码最缺的部分
让 LLM 生成代码,很多时候它会把正常路径写得非常完整,却在边界和异常路径上漏掉细节。这也是