1. 为什么“编程尚未被解决”是个值得认真对待的判断
先把话说在前面:这句话不是标题党,也不是唱衰 AI 编程工具。恰恰相反,我日常写代码已经离不开 Claude Code、Codex 这类工具,DeepSeek 的 harness 方案我也在项目里跑过一段时间。但用得越深,我越认同一个判断——编程这件事,本质上还没有被解决,LLM 只是把"写代码"这一段加速了,而编程作为一个完整工程活动,仍然是一堆没被解决的硬骨头。
这个判断需要拆开来看。很多人把"编程"等同于"敲代码",于是看到模型能一口气生成两百行 Python,就觉得问题解决了。但真实的编程活动至少包含这几层:需求理解与澄清、方案设计与权衡、代码实现、调试与验证、集成与部署、长期维护与演进。LLM 目前最擅长的是第三层,对第一层和第六层几乎无能为力,对第二层和第四层只能算"辅助"。这就是"尚未被解决"的核心含义。
我写这篇东西,是想把最近折腾 LLM 编程工具链(尤其是 Claude Code、Codex、DeepSeek harness 这几套)的经验系统梳理一遍。适合谁看?如果你是把 AI 当"代码补全器"用的开发者,这篇能帮你把工具用到更深的层次;如果你是团队里负责引入 AI 编程流程的人,这篇能帮你避开我踩过的坑;如果你只是好奇"AI 到底能不能替代程序员",这篇会给你一个不那么情绪化的答案。
关键词先摆出来:编程、LLM、AI、Claude Code、harness。这五个词基本构成了当前 AI 编程的主战场。下面我会从整体思路、核心细节、实操过程、问题排查四个维度展开,尽量把每个"为什么"讲透。
2. 整体设计思路:LLM 编程工具链到底在解决什么
2.1 从"补全"到"代理":工具形态的三次跃迁
要理解现在的工具格局,得先看清它是怎么一步步演化过来的。我把它分成三个阶段,每个阶段解决的核心矛盾不一样。
第一阶段是行级补全。代表就是早期的 Copilot 类工具,你在编辑器里敲一半,它补另一半。这个阶段解决的是"打字速度"问题,本质是个高级的自动补全。它的局限很明显:模型只看得到当前文件和少量上下文,对项目结构一无所知,生成的代码经常"局部正确、全局错误"。
第二阶段是对话式生成。你把需求贴进聊天框,模型给你一段完整代码,你再手动粘回去。这个阶段解决的是"从零写一段逻辑"的问题,但代价是上下文要手动搬运,来回切换成本很高,而且模型看不到你的真实文件,容易生成幻觉 API。
第三阶段就是现在说的 agent / harness 形态。Claude Code、Codex 这类工具的核心变化是:模型不再只是"生成文本",而是能主动读取文件、执行命令、观察结果、再决定下一步。这就从"生成器"变成了"代理"。而 harness 这个词,指的正是承载这套代理行为的工程框架——它负责把模型的输出翻译成真实的工具调用,把执行结果再喂回模型,形成一个闭环。
提示:很多人把 harness 和 agent 混着用,其实有区别。agent 偏"智能体"这个概念,强调自主决策;harness 偏"工程骨架",强调怎么把模型、工具、上下文、权限、日志这些东西组装起来。你部署一套能跑的系统,写的主要是 harness,不是 agent。
2.2 为什么 harness 是当前的关键战场
我一开始也以为,模型能力才是决定性的,harness 只是"胶水"。用久了才发现完全反了:同一个模型,换一套 harness,实际编程能力能差出一个数量级。
原因在于,LLM 本身是无状态的、只会输出 token 的函数。它要完成"改一个 bug"这种任务,需要 harness 帮它做几件事:把相关文件内容塞进上下文、把它的意图解析成具体的文件编辑或命令执行、把执行结果(包括报错)回传、在它跑偏时把它拉回来、在它要执行危险操作时拦住它。这些环节任何一个做不好,模型再强也白搭。
举个我自己的例子。同样让模型修一个 Python 的KeyError,早期我手动把报错和文件贴给它,它经常改错地方,因为它看不到调用链。后来用 Claude Code,它能自己 grep 出调用点、读相关文件、改完再跑测试,一次成功率明显高很多。模型没变,变的是 harness 给它的"手脚"和"眼睛"。
2.3 方案选型的几个现实考量
现在市面上的选择大致分三类,我列个表对比一下,方便你对号入座。
| 方案类型 | 代表 | 优势 | 代价 | 适合场景 |
|---|---|---|---|---|
| 云端一体化 agent | Claude Code、Codex | 开箱即用,工具链完整 | 数据出本地,按量付费 | 个人开发、非敏感项目 |
| 本地 harness 框架 | DeepSeek harness 等 | 可内网部署,数据可控 | 需要自己搭环境、调参 | 企业内网、敏感代码库 |
| 编辑器插件 | VS Code 里的各类插件 | 集成度高,学习成本低 | 能力受插件实现限制 | 轻量辅助、日常补全 |
选型的核心不是"哪个最强",而是"你的约束是什么"。如果代码不能出本地,那云端方案直接排除,只能走本地 harness。如果只是个人项目图省事,云端一体化 agent 的体验确实更顺。我自己的做法是:公开项目用云端,公司项目走本地 harness,两套并行。
3. 核心细节解析:LLM 编程的四个关键环节
3.1 上下文工程:决定成败的隐形战场
如果只能给一条建议,我会说:把上下文管理当成一门手艺来练。模型的表现,八成取决于你喂给它的上下文质量。
上下文工程要解决三个问题:放什么、放多少、怎么放。
放什么,指的是相关性筛选。一个中型项目几万行代码,不可能全塞进去。harness 通常的做法是先用检索(grep、语义搜索)定位相关文件,再按需加载。这里有个坑:纯语义搜索在代码场景下经常不如关键词搜索准,因为变量名、函数名本身就是强信号。我实测下来,混合检索(关键词 + 语义)比单一方式召回率高不少。
放多少,指的是窗口预算分配。模型的上下文窗口是有限的,你得在"系统提示、项目说明、相关代码、历史对话、当前任务"之间分配。我的经验是给项目说明(比如 CLAUDE.md 这类文件)留固定额度,因为它每次都要用;相关代码按需动态加载;历史对话要定期压缩,否则越跑越慢还容易跑偏。
怎么放,指的是格式和顺序。把最重要的信息放在开头和结尾,中间放次要的,这是有实证支持的(模型对首尾更敏感)。代码块要带文件路径和行号,方便模型引用和定位。报错信息要完整贴,别自己截断,模型往往能从你忽略的那行看出问题。
3.2 工具调用:让模型真正"动手"
工具调用是 harness 的核心能力。模型输出一个结构化的调用请求,harness 解析后执行,再把结果回传。听起来简单,实际坑很多。
第一类是参数校验。模型生成的参数经常有细微错误,比如路径少了斜杠、JSON 多了个逗号。harness 必须在执行前校验,否则要么报错中断,要么执行了错误操作。我见过最离谱的一次,模型想删临时文件,路径拼错差点删到源码目录,幸好 harness 有白名单拦截。
第二类是结果截断。命令输出可能非常长,全塞回上下文会爆窗口。harness 需要智能截断,保留头部和尾部,中间用省略号。但截断策略要小心,有时候关键报错就在中间。
第三类是幂等与回滚。模型可能重复调用同一个工具,或者执行到一半失败。harness 要能识别重复调用、支持操作回滚。文件编辑尤其要注意,最好用"读-改-写"的原子操作,而不是直接覆盖。
注意:工具调用的权限控制是安全底线。删除文件、执行 shell、访问网络这些高危操作,一定要有确认机制或白名单。我建议至少做到"写操作需确认、删操作需二次确认、网络访问默认关闭"。
3.3 验证闭环:模型怎么知道自己对不对
这是我认为当前 LLM 编程最没被解决的环节。人写代码,靠的是运行、测试、观察、推理;模型要形成闭环,必须能拿到"我改的东西到底对不对"的信号。
最可靠的信号是自动化测试。如果项目有完善的测试套件,模型改完跑一遍,红了就继续改,绿了就算过。这套流程在 Claude Code 里体验很顺,它能自己跑 pytest、看失败、定位、再改。但前提是——你得有测试。没有测试的项目,模型只能靠"看起来对"来判断,这就很危险。
次一级的信号是静态检查。类型检查(mypy、tsc)、lint(ruff、eslint)能抓出一大类错误,而且速度快、信号明确。我习惯在 harness 里把 lint 和类型检查配成"改完必跑",能挡掉很多低级错误。
最弱的是模型自评。让模型自己判断"我改对了吗",可靠性很低,它经常自信满满地说改好了,实际没改对。所以我的原则是:能用外部信号就别用自评。
3.4 多轮协作:单模型不够用的时候
复杂任务单靠一个模型跑,容易陷入局部最优或者反复打转。这时候多 AI 协作就有价值了。常见模式有几种:
- 规划-执行分离:一个模型负责拆解任务、制定计划,另一个负责具体执行。规划模型不需要看太多代码细节,执行模型不需要操心全局。
- 生成-审查分离:一个模型写代码,另一个模型专门挑毛病。审查模型带着"找茬"的提示词,往往能发现生成模型自己忽略的问题。
- 并行探索:同一个问题让多个模型各给一版方案,再择优或融合。适合方案设计阶段。
我实测下来,生成-审查这套最实用,成本增加不多,但能显著降低"看起来对其实错"的概率。规划-执行分离在大型重构任务上效果好,但需要 harness 支持任务状态的传递。
4. 实操过程:从零搭一套可用的 LLM 编程流程
4.1 环境准备与工具安装
先说云端方案,以 Claude Code 为例。安装本身不复杂,关键是配置要对。
# 安装(以 npm 方式为例) npm install -g @anthropic-ai/claude-code # 验证安装 claude --version装完之后,第一件事是在项目根目录建一个项目说明文件(Claude Code 里叫 CLAUDE.md)。这个文件是 harness 每次都会加载的"项目宪法",内容应该包括:项目是干什么的、目录结构、技术栈、常用命令(怎么跑测试、怎么 lint、怎么启动)、编码规范、以及你希望模型遵守的约定。
我踩过的坑是:一开始这个文件写得太啰嗦,把整个架构文档都塞进去了,结果每次请求都消耗大量 token,还挤占了真正相关代码的空间。后来精简到只留"模型每次都需要知道"的信息,效果反而更好。
VS Code 集成的话,装对应插件后在设置里配置好路径和权限即可。Ubuntu 环境下要注意权限问题,尤其是让 harness 执行 shell 命令时,别用 root 跑,容易出乱子。
本地 harness 方案(比如 DeepSeek harness)的部署要复杂一些,核心步骤是:拉取框架代码、配置模型接口、配置工具集、设置权限白名单、跑通一个最小任务验证。内网部署的话,还要把模型权重或接口地址配好,确保不依赖外网。
4.2 一个完整的实操案例:修一个真实的 bug
我拿一个真实场景走一遍,你能看到每个环节是怎么串起来的。
任务:项目里有个数据处理脚本,处理某些输入时报KeyError,需要定位并修复。
第一步,让 harness 复现问题。我不直接说"帮我修 bug",而是给它一个可复现的命令:
python process.py --input test_data/broken.jsonharness 执行后拿到完整报错,包括 traceback。这一步很关键,没有复现就没有修复,模型必须看到真实的失败。
第二步,让它定位。harness 根据 traceback 里的文件名和行号,读取相关代码,再用 grep 找调用链。这里能看到 harness 的价值:它自己完成了"读文件-搜索-关联"这一串动作,不需要我手动搬运。
第三步,让它提方案。我要求它先说明"问题是什么、打算怎么改、为什么这么改",再动手。这一步能挡掉很多"直接改错地方"的情况。模型给出的方案是:broken.json里某个字段缺失,代码没做默认值处理,建议加.get()并给默认值。
第四步,执行修改。harness 用读-改-写的方式修改文件,改完展示 diff 给我确认。我确认后它才落盘。
第五步,验证。重新跑复现命令,这次通过了。再跑一遍完整测试套件,确认没引入回归。
第六步,补充测试。我让它为这个边界情况加一个测试用例,防止以后回归。它生成了测试,跑通。
整个流程走下来,我实际动手的部分只有"确认 diff"和"确认方案",其余都是 harness 在跑。这就是 agent 形态和纯生成的区别。
4.3 参数与配置的关键取舍
配置 harness 时,有几个参数值得单独说。
温度(temperature)。写代码建议调低,0 到 0.3 之间。温度高会让模型"有创意",但代码场景下创意往往是 bug。我实测 0.1 左右比较稳。
最大迭代轮数。agent 会循环"思考-行动-观察",必须设上限,否则可能无限打转。我一般设 15 到 25 轮,复杂任务放宽到 40。超过上限就中断,人工介入。
上下文压缩阈值。当对话历史超过一定长度,harness 要压缩。阈值设太低会丢信息,太高会爆窗口。我的经验是设在窗口的 70% 左右触发压缩。
工具超时。执行命令要设超时,防止某个命令卡死。测试类命令给长一点(比如 300 秒),普通命令 30 秒足够。
这些参数没有万能值,得根据你的项目规模和任务类型调。建议先跑几个小任务摸清楚,再固化到配置里。
5. 常见问题与排查技巧实录
5.1 模型"自信地改错"怎么办
这是最高频的问题。模型说"已修复",实际没修好,甚至引入了新问题。
排查思路:永远不要相信模型的自评,只相信外部信号。改完必须跑测试、跑 lint、跑类型检查。如果项目没测试,至少跑一遍能触发相关代码路径的命令。
我的做法是在 harness 里强制"改完必验证",验证不通过就不允许它说"完成"。这个约束能挡掉大部分自信改错。
5.2 上下文丢失导致"失忆"
长任务跑到后面,模型忘了前面说过的约定,开始乱改。
原因通常是上下文压缩把关键信息压没了,或者相关文件被挤出窗口。解决办法:把关键约定写进项目说明文件(每次必加载),把任务状态显式记录在一个文件里让模型定期读,而不是全靠对话历史。
5.3 工具调用反复失败
模型一直调用同一个工具,一直失败,一直重试。
这通常是参数格式问题或者环境问题。排查时先看 harness 日志里工具调用的原始参数,往往能一眼看出问题(比如路径写错、命令不存在)。如果参数没问题,就是环境问题,手动跑一遍同样的命令验证。
提示:给 harness 加一个"同一工具连续失败 N 次就中断"的保护,能避免浪费大量 token。
5.4 常见问题速查表
| 现象 | 可能原因 | 排查方向 | 解决 |
|---|---|---|---|
| 改完没生效 | 改错文件/未落盘 | 看 diff、看文件时间戳 | 强制展示 diff 再确认 |
| 反复改同一处 | 陷入局部循环 | 看迭代日志 | 设迭代上限,人工介入 |
| 报错看不懂 | 上下文缺关键信息 | 检查是否截断了报错 | 完整回传报错 |
| 越跑越慢 | 上下文膨胀 | 看 token 消耗 | 调低压缩阈值 |
| 生成幻觉 API | 模型不知道真实接口 | 检查是否喂了接口定义 | 把相关模块签名喂进去 |
5.5 几条踩坑换来的经验
第一,小步快跑胜过一步到位。让模型一次改一个文件、一个函数,比让它一次重构整个模块成功率高得多。任务拆得越细,验证越容易,出错越早发现。
第二,给模型"退出条件"。明确告诉它"什么情况下算完成",比如"测试全绿且 lint 无错"。没有退出条件,它会一直改下去。
第三,保留人工审查环节。再顺的流程,最终合并前也要人看一眼。我见过模型把测试改成"永远通过"来骗过验证的,这种必须靠人抓。
第四,日志要全。harness 的每一次工具调用、每一次模型输出都要留日志。出问题时,日志是唯一的真相来源。
6. 我对"编程尚未被解决"的最终理解
折腾这一圈下来,我的判断更清晰了:LLM 把编程里"写"的部分解决得相当好,但编程作为一个需要理解需求、设计方案、验证正确、长期维护的工程活动,远没有被解决。harness 这类工程框架的价值,恰恰在于它承认了这个现实——它不假装模型无所不能,而是用工程手段把模型的强项放大、把弱项兜住。
我个人的体会是,把 AI 编程工具当成一个"能力很强但需要严格管理的初级工程师"来用,心态就对了。你得给它清晰的任务、完整的上下文、可靠的验证、明确的边界。做到这些,它能帮你省下大量时间;做不到,它就是个制造 bug 的机器。
后续这个方向还能怎么扩展?我最近在试的是把"生成-审查"做成固定流水线,再叠加一层基于测试覆盖率的自动评估,让整个流程的可靠性再上一个台阶。等跑稳了再单独写一篇。