AI 写代码总在“乱拉屎”?可能因为它一开始就看了太多代码

8 阅读5分钟

先说一个可能不太受欢迎的观点:

上下文不是越多越好。

很多人用 AI 写代码的方式,是把整个仓库打开,或者让 Agent 自己到处 grep。结果 呢?它确实看到了很多代码,但也看到了很多不该模仿的东西:

  • 三个模块里各有一份相似的工具函数;
  • 一个早就该废弃的旧实现;
  • 一堆跨层调用;
  • 一些“能跑就行”的临时代码。

Agent 很擅长从上下文里找模式。你给它看什么,它就可能学什么。

所以问题不只是“模型够不够聪明”,还包括:你给它的是一张地图,还是一仓库杂物?

一、为什么“多给点代码”反而容易写烂?

1. 无关代码会稀释重点

一个需求可能只涉及两个模块,但你塞进去几十个文件。Agent 要花注意力判断哪些 相关,哪些不相关。上下文越长,早期信息越容易被淹没。

2. 它会模仿最近看到的模式

Agent 看到某个模块里有一个“临时绕过”的写法,可能就照着写。它不知道那是历史 包袱,还是团队约定。

3. 它缺少全局结构

只读局部代码,很容易做出局部最优:

  • 这个工具函数放这里也能跑;
  • 这个依赖直接 import 也能跑;
  • 这个实体塞进当前模块也能跑。

每一处都能跑,但结构越来越乱。

这就是很多人说的“AI 乱拉屎”:不是它不会写函数,而是它不知道边界、复用和归属。

二、架构是给 Agent 的“目录”,不是给领导看的海报

Jin 把架构做成两层:

  • L0:系统、包、模块、分层、外部依赖、约束;
  • L1:每个模块的实体、位置、字段、方法、关系。

你可以把它理解成一份给 Agent 看的目录:

  1. 先看系统有哪些模块,模块之间允许怎么依赖;
  2. 再看某个模块对外暴露什么实体;
  3. 然后根据实体位置,只读相关文件;
  4. 最后才进入具体实现。

这就是渐进式披露:先给地图,再给街区,最后给门牌号。

而不是一上来把整个城市的监控录像塞给它。

三、Jin 里具体怎么用?

Agent 可以先调用 jin_arch_read,拿到当前 L0/L1 和校验摘要。它不需要猜项目 结构,也不需要一上来读完整仓库。

需要提案时,jin_proposal_create 会返回目标快照路径。Agent 只编辑当前版本的 目标 L0/L1,再用 jin_validate 校验。

审阅时,jin_proposal_read 可以返回目标、元数据、决策和结构化差异。人看到的是 结构变化,而不是所有代码。

这里有一个关键点:Jin 不会自动帮你裁剪上下文。

它提供的是结构索引,不是魔法。Agent 仍然要决定读哪些文件、读多少。但有了 L0/L1, 它可以按模块和实体定位,而不是靠猜。

比如它要改订单取消逻辑:

  • 从 L0 知道 orders 模块的路径和依赖;
  • 从 L1 知道 cancelOrder 的位置和关系;
  • 只读 orders 和相关的 audit 实体;
  • 不需要把整个 payment、notifications、前端页面都读一遍。

这就是省 context 的来源:不是压缩文本,而是减少无关输入。

四、一个“乱拉屎”的反例

假设你要加一个“订单取消后发通知”的功能。

没有架构约束时,Agent 可能会:

  • 在 orders 里直接 import 邮件 SDK;
  • 新建一个 utils/notify.ts,把重试逻辑又写一遍;
  • 把通知模板塞进订单实体;
  • 顺手在支付模块里加一个“以后可能用得上”的钩子。

代码能跑,但结构上多了:

  • 一条 orders -> email 的外部依赖;
  • 一份重复的通知逻辑;
  • 一个职责不清的实体;
  • 一条没人要求的跨模块关系。

有架构时,Agent 先看到:

  • 已经有 notifications 模块;
  • 已经有 NotificationService;
  • 邮件是 external,不应该由 orders 直接接;
  • 订单和通知之间应该通过事件或公开接口连接。

它更可能做的是:

  • 在 notifications 里扩展实体;
  • 在 orders 里发布事件;
  • 复用已有的通知接口;
  • 不新增跨层依赖。

这不保证代码一定优雅,但至少不会从结构上就开始歪。

五、为什么“先看懂架构”更容易写出好代码?

因为好代码不只是格式漂亮,它通常满足几个结构条件:

  • 放在正确的模块;
  • 复用已有的抽象;
  • 不破坏公开边界;
  • 依赖方向清楚;
  • 命名和职责一致;
  • 不把临时逻辑塞进长期结构。

这些条件,恰恰是架构能提供的。

Agent 先看懂架构,就像新人先看项目说明再动手。它仍然可能写出平庸的实现,但 更少出现那种“功能能用,结构灾难”的代码。

架构不能保证漂亮,但能减少一类最常见的丑:放错地方、重复造轮子、跨层乱连。

六、省 context 的真正含义

省 context 不只是省钱。

上下文越干净,Agent 越容易:

  • 找到正确的参考实现;
  • 避免复制历史包袱;
  • 保持命名和分层一致;
  • 在提案里只改相关模块;
  • 让 review 的人只看相关 diff。

反过来说,如果你把整个仓库塞进去,Agent 可能确实“看到了更多”,但也更容易被 无关模式带偏。

这和人类工程师一样:你给新人一个 10 万行的仓库,不如先给他一张模块图,再告诉他 “先看这两个文件”。

七、边界

渐进式披露不是万能的:

  • 架构声明可能过时,地图错了,Agent 也会走错;
  • 扫描器是声明级的,不是完整语义索引;
  • Jin 不会自动限制 Agent 读多少文件;
  • 架构不能替代测试、lint、代码 review;
  • 省 context 的效果取决于项目结构和 Agent 的使用方式。

但至少,它把“先看全局,再看局部”变成了一件有工具支撑的事,而不是靠提示词里 写一句“请先理解项目结构”。

项目地址:

github.com/ZYF93/openc…

v2.0.32-jin.1 下载:

github.com/ZYF93/openc…

中文完整指南:

github.com/ZYF93/openc…

Jin 是 OpenCode 的社区分支,不是 OpenCode 官方产品。它不内置模型,模型由用户 通过 OpenCode 配置。