GitHub avatar

Fox's Blog

I Audited My AI Coding Agents Instead of Trusting Them Blindly

How two audits written for the 4th technical report of my trading platform revealed two distinct failure modes: an agent that forgets because the repo no longer fits in its context window, and an agent that writes ten times more code than needed because nothing pushes it toward conciseness.

The symptom before the diagnosis

Each edition of the platform's technical report forces me to walk through the whole architecture again: services, agents, data pipelines. While preparing the 4th edition, the size of the repo finally jumped out at me, even though I had watched it grow gradually without ever stopping to look at it: the repo, which originally fit in a few thousand lines, under 10KB, had reached 100MB. The platform had barely more features. I had simply been relying on Claude Chat style agents to implement and fix code, without precisely framing what I asked of them or on what scope.

Writing the report forced me out of "it's moving forward" mode and back into "what actually happened" mode. I ran two distinct audits on the repo's history. Both pointed at the same cause, for two completely different reasons.

Audit #1: the lying context window

The first audit consisted of going back, service by service, over the fixes made by an AI agent over several months, and checking whether they were consistent with the rest of the repo at the time they were applied.

The pattern that kept coming back: the agent fixed a problem locally, in the file or module it had in front of it, without having seen its equivalent elsewhere in the repo, or without remembering it. Result: the same interface redefined slightly differently in two services, a rename applied halfway because the second occurrence was outside the context window at prompt time, a naming convention followed in one module and ignored in the next. Nothing spectacular in isolation, but accumulated over dozens of sessions, that is exactly what produces the redundancy and code smells that make the next tool you run on it lose the thread. A self-reinforcing loop: the bigger and more fragmented the repo gets, the harder it is for an agent to hold it all in its head, the more local and partial its fixes become, the more the repo grows.

The problem is not that the agent "lies" or invents things; it answers the question asked correctly on the context it was given. The problem is that I had, most of the time, never defined the scope of the question upfront. I asked to "fix this typo, this behavior, this function" without wondering whether that bug had equivalents elsewhere in the repo that the agent could not see.

Audit #2: when verbosity becomes code

The second audit was more mechanical: running git log --numstat over the whole history, aggregating added lines and added characters by commit, and looking at the distribution.

The 30 biggest commits by lines added represented, on their own, a wildly disproportionate share of the repo's total volume. Systematically, those same commits also came out as the biggest in characters added. That was predictable, except that the characters-per-line ratio of those commits was not just about line count: the lines themselves were more verbose, with more explanatory comments restating what the function names already said, more duplicated error-handling blocks instead of factored ones, more docstrings rephrasing the same thing three times.

That is the direct consequence of a known behavior when interacting with an LLM in chat: without an explicit instruction to be concise, it tends to talk a lot, to justify, comment, rephrase. In conversation, that costs output tokens. In code generation, that same reflex turns into lines that stay in the repo indefinitely, commit after commit, without anyone really rereading them as long as the code works.

What the two audits, side by side, showed

For the first report: cross-service consistency suffers from a context window too small to hold the whole repo, which leads to local fixes, redundancies, and diverging conventions.

For the second: git log --numstat shows the default verbosity of an unframed LLM, which causes disproportionately added lines and characters and unfactored code.

Both together point at redundancy and volume: that gives you a repo too big for a future agent to hold in its head, which makes the first problem found by the first audit even worse.

It is that last line that worried me most while writing the report: the two problems feed each other. The more verbose the generated code, the faster the repo grows; the bigger it gets, the less an agent can hold it in context; the less it can hold in context, the more local and redundant its fixes become; the more redundant they are, the more volume that adds. A negative feedback loop, caused entirely by using agents without framing.

Why this is not a one-off bug in one specific tool

Nothing in this diagnosis is specific to one model or one product. Any chat-style agent operates on what you show it in its window at time T, and by default generates the most complete and most justified answer possible. That is exactly the expected behavior of a conversational assistant, and exactly the behavior to avoid for a tool that writes into a production repo. The problem comes from the missing frame between the tool and the repo: which files to consider, what output format is expected, what line or verbosity budget applies, the obligation to quote precisely what already exists before writing anything new.

What I changed since

The logical reflex would have been to drastically cut down what had been written. Personally, I decided to do otherwise. The audits served me for something else: scanning the code to spot the code smells, and using them to pinpoint exactly where the real problems were. Cross-service inconsistencies, redundancies, places where the thread had been lost, rather than guessing. The volume of code written stays roughly the same: verbose or not, it remains useful if used well. The lever was knowing exactly where to look to fix what did not fit, rather than stopping the agent from writing.

Next steps

Splitting the repo into smaller, better-delimited units. Plus production guardrails for execution and documentation. The problem that now arises is an architecture question: how to analyze, critique, and cleanly connect the services, components, and documentation that, once separated, still have to coordinate their decisions without falling back into the same monolith as before.

J'ai audité mes agents IA de code plutôt que de leur faire confiance à l'aveugle

Comment deux audits menés pour rédiger le 4ème rapport technique de ma plateforme de trading m'ont révélé deux dérives distinctes : un agent qui oublie parce que le repo ne tient plus dans sa fenêtre de contexte, et un agent qui écrit dix fois plus de code que nécessaire parce que rien ne le pousse à la concision.

Le symptôme avant le diagnostic

Chaque édition du rapport technique de la plateforme m'oblige à reparcourir l'architecture en entier : services, agents, pipelines de données. C'est en préparant la 4ème édition que le volume du repo a fini par me sauter aux yeux, alors que je le voyais grossir progressivement sans jamais m'arrêter dessus : le repo, qui tenait à l'origine en quelques milliers de lignes, moins de 10ko, atteint désormais 100Mo. La plateforme avait à peine plus de fonctionnalités. Je m'étais simplement reposé sur des agents de type Claude Chat pour implémenter et corriger du code, sans cadrer précisément ce que je leur demandais ni sur quel périmètre.

Écrire le rapport m'a forcé à sortir du mode "ça avance" pour repasser en mode "qu'est-ce qui s'est réellement passé". J'ai fait deux audits distincts sur l'historique du repo. Les deux pointaient vers la même cause, pour deux raisons complètement différentes.

Audit n°1 : la fenêtre de contexte qui ment

Le premier audit consistait à reprendre, service par service, les corrections faites par un agent IA sur plusieurs mois, et à vérifier si elles étaient cohérentes avec le reste du repo au moment où elles avaient été appliquées.

Le motif qui revenait sans cesse : l'agent corrigeait un problème localement, dans le fichier ou le module qu'il avait sous les yeux, sans avoir vu l'équivalent ailleurs dans le repo, ou sans s'en souvenir. Résultat : la même interface redéfinie légèrement différemment dans deux services, un renommage appliqué à moitié parce que la deuxième occurrence était hors de la fenêtre de contexte au moment du prompt, une convention de nommage respectée dans un module et ignorée dans le suivant. Rien de spectaculaire pris isolément, mais cumulé sur des dizaines de sessions, cela produit exactement la redondance et les code smells qui font perdre le fil à l'outil suivant qu'on lance dessus. Un cercle qui s'auto-alimente : plus le repo grossit et se fragmente, plus il devient difficile pour un agent de le tenir en tête dans son intégralité, plus les corrections deviennent locales et partielles, plus le repo grossit.

Le problème n'est pas que l'agent "ment" ou invente ; il répond correctement à la question posée sur le contexte qu'on lui a donné. Le problème est que je n'avais, la plupart du temps, jamais défini le périmètre de la question en amont. Je demandais "corrige cette typo, ce comportement, cette fonction" sans me demander si ce bug avait des équivalents ailleurs dans le repo que l'agent ne pouvait pas voir.

Audit n°2 : quand la verbosité devient du code

Le deuxième audit était plus mécanique : faire tourner un git log --numstat sur tout l'historique, agréger lignes ajoutées et caractères ajoutés par commit et regarder la distribution.

Les 30 plus gros commits en lignes ajoutées représentaient, à eux seuls, une part largement disproportionnée du volume total du repo. Systématiquement, les mêmes commits ressortaient aussi comme les plus gros en caractères ajoutés. C'était prévisible, sauf que le ratio caractères/lignes de ces commits-là n'était pas seulement lié au nombre de lignes : les lignes elles-mêmes étaient plus verbeuses, avec plus de commentaires explicatifs redondants avec le nom des fonctions, plus de blocs de gestion d'erreurs dupliqués au lieu d'être factorisés, plus de docstrings qui reformulaient trois fois la même chose.

C'est la conséquence directe d'un comportement connu quand on interagit avec un LLM en chat : sans consigne explicite de concision, il a tendance à beaucoup parler, à justifier, commenter, reformuler. En conversation, cela coûte des tokens de sortie. En génération de code, ce même réflexe se traduit en lignes qui restent dans le repo indéfiniment, commit après commit, sans qu'on les relise vraiment tant que le code fonctionne.

Ce que les deux audtis, mis côte à côte, ont montré

Pour le premier rapport : la cohérence inter-services souffre d'une fenêtre de contexte trop petite pour tenir tout le repo, ce qui entraîne des corrections locales, des redondances et des divergences de conventions.

Pour le second : git log --numstat montre une verbosité par défaut d'un LLM non cadré, ce qui cause des lignes et caractères ajoutés disproportionnés et un code peu factorisé.

Les deux réunis pointent la redondance et le volume : cela donne un repo trop gros pour qu'un futur agent le tienne en tête, ce qui aggrave encore le premier problème mis en évidence par le premier audit.

C'est cette dernière ligne qui m'a le plus inquiété en écrivant le rapport : les deux problèmes sont liés, ils se nourrissent l'un l'autre. Plus le code généré est verbeux, plus le repo grossit vite ; plus il grossit, moins un agent peut le tenir en contexte ; moins il peut le tenir en contexte, plus ses corrections sont locales et redondantes ; plus elles sont redondantes, plus cela ajoute de volume. Une boucle de rétroaction négative, entièrement causée par une utilisation d'agents sans cadrage.

Pourquoi ce n'est pas un bug ponctuel d'un outil précis

Rien dans ce diagnostic n'est spécifique à un modèle ou un produit en particulier. Un agent de type chat, quel qu'il soit, opère sur ce qu'on lui donne à voir dans sa fenêtre à l'instant T, et génère par défaut la réponse la plus complète et la plus justifiée possible. C'est exactement le comportement attendu d'un assistant conversationnel, et exactement celui à éviter pour un outil qui écrit dans un repo de production. Le problème vient de l'absence de cadrage entre l'outil et le repo : périmètre de fichiers à considérer, format de sortie attendu, budget de lignes ou de verbosité, obligation de citer précisément ce qui existe déjà avant d'écrire quelque chose de nouveau.

Ce que j'ai changé depuis

Le réflexe logique aurait été de réduire drastiquement ce qui avait été écrit. Personnellement, j'ai décidé de faire autrement. Les audits m'ont servi à autre chose : scanner le code pour y repérer les code smells, et m'en servir pour délimiter précisément où se situaient les vrais problèmes. Les incohérences inter-services, les redondances, les endroits où le fil s'était perdu, plutôt que de deviner. Le volume de code écrit reste significativement le même : verbeux ou non, il reste utile s'il est bien utilisé. Le levier était de savoir précisément où regarder pour corriger ce qui ne collait pas, plutôt que d'empêcher l'agent d'écrire.

Prochaine étapes

Le découpage du repo en unités plus petites et mieux délimitées. Ainsi que des garde-fous de production pour l'exécution et la documentation. Le problème qui se pose à son tour est une question d'architecture : comment analyser, critiquer et faire communiquer proprement les services, composants et documentation qui, une fois séparés, doivent quand même coordonner leurs décisions sans revenir au même monolithe qu'avant.

我审计了自己的 AI 代码智能体,而不是闭眼信任它们

为写交易平台第 4 份技术报告做的两次审计,暴露了两种不同的毛病:一个智能体因为仓库塞不进上下文窗口而失忆,另一个因为没人要求它简洁而写出十倍于所需的代码。

先有症状,再有诊断

每版交易平台技术报告都逼我把架构重走一遍:服务、智能体、数据管线。写第 4 版时仓库体积终于刺眼了,之前看它一点点变大都没停下来想过:仓库最初几千行,不到 10ko,现在干到 100Mo。平台功能几乎没多。我只是靠 Claude Chat 这类智能体实现和修代码,从没精确框过要它干什么、在多大范围干。

写报告逼我从"在往前走"模式切回"到底发生了什么"模式。我对仓库历史做了两次审计。两次指向同一个病因,理由完全不同。

审计一:说谎的上下文窗口

第一次审计是把几个月里一个 AI 智能体逐个服务做的修改重走一遍,检查在当时和仓库别处对不对得上。

反复出现的模式:智能体在局部修问题,就在它眼前的那个文件或模块里,没看到仓库别处等价的东西,或者记不住。结果:同一个接口在两个服务里被略微不同地重定义一次,重命名改一半因为第二处在 prompt 时在上下文窗口外面,命名规范这个模块遵守下个模块丢。一处看都小事,攒几十个 session,就是让下一个接手的工具跟丢思路的冗余和 code smell。自我强化的圈:仓库越大越碎,智能体越难一次装进脑子,修得越局部越零散,仓库越大。

问题不是智能体"撒谎"编造,它在给到的上下文上答得正确。问题是我大多时候从没在上游定义问题的范围。我说"修这个 typo、这个行为、这个函数",没问这个 bug 在智能体看不见的地方有没有等价物。

审计二:啰嗦变成代码

第二次审计更机械:对全部历史跑 git log --numstat,按提交聚合新增行数和新增字符数,看分布。

新增行数最多的 30 个提交,占仓库总体积的比例高得不成比例。系统性地,这些提交在新增字符数上也是最大的。本来可预期,但这些提交的每行字符数也更啰嗦:跟函数名重复的解释性注释更多,错误处理块复制粘贴而不是抽出来,docstring 把同一件事换三种说法讲三遍。

这是跟 LLM 聊天时熟知的行为的直接后果:不显式要求简洁,它默认多说,解释,注释,换说法。聊天里这只费输出 token。写代码时,同样的习惯变成留在仓库里的行,一个提交一个提交攒,只要代码能跑就没人真重读。

两次审计并排放,得到什么

第一份报告:跨服务一致性死于上下文窗口太小装不下整个仓库,导致局部修改、冗余、规范分叉。

第二份:git log --numstat 显示没框过啰嗦的 LLM 默认有多话,导致新增行和新增字符不成比例地多,代码没有好好抽取复用。

合起来指向冗余和体积:仓库大到未来的智能体装不进脑子,这又加重第一次审计发现的第一个问题。

写报告时最让我不安的就是最后一行:两个问题相连,互相喂饭。生成的代码越啰嗦,仓库涨越快,涨越快智能体越装不进上下文,越装不进修得越局部越冗余,越冗余体积越大。负反馈环,全因用智能体没加框。

为什么不是某个具体工具的一次性 bug

诊断里没有任何东西绑定特定模型或产品。任何聊天型智能体都这样:在 T 时刻它只能操作你给它看到的东西,默认生成最完整、最 justified 的回答。这正是聊天助手该有的行为,也正是往生产仓库写东西时要避免的。缺的是工具和仓库之间的框:要看的文件范围、期望输出格式、行数或啰嗦预算、写新东西之前先引用已存在的东西的义务。

之后我改了什么

直觉反应是把写出来的东西大刀砍掉。我个人选择反着来。审计另有他用:扫代码找 code smell,用来精确定位真问题在哪。跨服务不一致、冗余、思路丢了的地方,而不是瞎猜。写出来的体积基本原样保留:啰嗦不啰嗦,用对地方就有用。杠杆是知道该看哪里去修对不上的地方,而不是拦着智能体写。

下一步

把仓库切成更小、边界更清的单元。再加生产执行的 guardrail 和文档。随之而来的问题是架构问题:拆开后服务、组件、文档怎么分析、互评、干净地协调决策,而不退回同一个单体。

コードAIエージェントを盲信せず監査した

取引プラットフォームの4つ目技術報告書を書くための2つの監査が明かした2つの違う逸脱。リポジトリがコンテキストウィンドウに入り切らないから忘れるエージェントと、簡潔さへの押しがないから10倍のコードを書くエージェント。

診断の前の症状

プラットフォーム技術報告書の各版ではアーキテクチャ全体を歩き直す義務がある。サービス、エージェント、データパイプラインだ。4版目の準備中にリポジトリの量がやっと目に飛び込んできた。少しずつ太るのを止まって見たことがなかったんだ。元は数千行、10ko未満だったリポジトリが今や100MBだ。機能はほとんど増えてない。Claude Chat型エージェントにコード実装や修正を頼りきりにして、何を求めるかもどの範囲かも正確に枠付けしなかっただけだ。

報告書を書くことで「進んでる」モードから出て「実際に何が起きたか」モードに戻らなきゃいけなくなった。リポジトリ履歴に2つの別監査をやった。両方同じ原因を指してた。まったく違う2つの理由でね。

監査1:嘘をつくコンテキストウィンドウ

1つ目の監査は、サービスごとに数か月にわたるAIエージェントの修正を取り直して、適用時点でリポジトリの残りと一貫してたか確認することだった。

繰り返し戻ってきた模様はこうだ。エージェントは目の前のファイルやモジュール内で局所的に問題を直して、リポジトリの別場所にある同等物を見てなかったり覚えてなかったりする。結果、同じインターフェースが2サービスで微妙に違う再定義をされる。改名が半分だけ適用される。プロンプト時点で2つ目の出現がコンテキストウィンドウ外だったからね。命名規約があるモジュールでは守られて次では無視される。単独では派手じゃないけど、数十セッションで積もると、まさに次の起動道具が道を見失う冗長とコードスメルを生む。自己補強する輪だ。リポジトリが太って断片化するほど、エージェントが全体を頭に保つのが難しくなる。修正は局所的で部分的になる。リポジトリは太る。

問題はエージェントが「嘘をつく」とか捏造するとかじゃない。渡された文脈の上で問いに正しく答えてる。問題はほとんどの場合、問いの範囲を事前に定義したことがなかった私だ。「このtypo直して、この挙動、この関数」って頼んで、このバグにエージェントが見えないリポジトリの別場所の同等物があるか自問しなかった。

監査2:冗長がコードになるとき

2つ目の監査はもっと機械的だ。履歴全体にgit log --numstatを回して、コミットごとに足された行と文字を集めて、分布を見る。

追加行で上位30の巨大コミットだけで、リポジトリ総量の不相応に大きな割合を占めてた。体系的に、同じコミット群が追加文字でも上位に出てきた。予想通りだった。でもそこの文字数や行数の比は行数だけの話じゃなかった。行自体が冗長だった。関数名と重複する説明コメントが多く、共通化されず重複したエラー管理ブロックが多く、同じことを3回言い換えるdocstringが多かった。

チャットでLLMとやり取りするときの既知挙動の直接の帰結だ。簡潔さの明示指示なしでは、よく喋りがちで、正当化して、コメントして、言い換える。会話では出力トークンを食うだけだ。コード生成では同じ反射がリポジトリに無期限残る行になる。動く限り読み返さないままコミットごとにね。

2つの監査を並べたら見えたこと

1つ目の報告向け:サービス間一貫性はリポジトリ全体を保つのに小さすぎるコンテキストウィンドウに苦しむ。局所修正、冗長、規約の乖離を起こす。

2つ目の向け:git log --numstatは枠付けなしLLMのデフォルト冗長を示す。不相応な追加行や文字と共通化不足コードを起こす。

両方合わせると冗長と量を指す。未来のエージェントが頭に保てないほど太いリポジトリになる。1つ目の監査が明かした1つ目の問題をさらに悪化させる。

報告書を書いてていちばん心配になったのはこの最後の行だ。2つの問題はつながってて、互いを養う。生成コードが冗長なほどリポジトリは速く太る。太るほどエージェントは文脈に保てない。保てないほど修正は局所的で冗長になる。冗長なほど量が増える。枠付けなしエージェント利用が起こした完全な負のフィードバックループだ。

特定道具の一時的バグじゃない理由

この診断にモデルや製品固有のものは何もない。チャット型エージェントはどれも、瞬間Tに目に見せたものの上で動き、デフォルトでできるだけ完全で正当化された応答を生成する。会話アシスタントの期待挙動そのもので、本番リポジトリに書く道具に避けるべき挙動そのものだ。問題は道具とリポジトリ間の枠付け欠落から来る。考慮すべきファイル範囲、期待出力形式、行数や冗長の予算、新しいものを書く前に既存のものを正確に引用する義務だ。

それ以来変えたこと

論理的な反射は書かれたものを大幅に減らすことだったはずだ。個人的には逆を決めた。監査は別の役に立てた。コードを走査してコードスメルを見つけて、本当の問題がどこにあるか正確に区切るためだ。サービス間不整合、冗長、道を見失った場所を、当てずっぽうじゃなくね。書かれたコード量はほぼ同じままだ。冗長でも、正しく使えば役立つ。てこは合わないところを直すためにどこを見るか正確に知ることだった。エージェントの執筆を止めることじゃなくね。

次の段階

リポジトリを小さく区切りの良い単位に割ることだ。あと本番実行と文書化のガードレールだ。次に立つ問題はアーキテクチャの問いだ。一度分けたらやっぱり決定を調整しなきゃいけないサービスや部品や文書を、前のモノリスに戻らずきれいに分析して批判して通信させるにはどうするかだ。

코드 AI 에이전트를 맹신하는 대신 감사했어요

트레이딩 플랫폼의 네 번째 기술 보고서를 쓰기 위해 두 번의 감사를 진행하면서 발견한 두 가지 서로 다른 문제에 대한 이야기. 저장소가 컨텍스트 창에 들어가지 않아서 잊어버리는 에이전트, 그리고 간결함을 요구받지 않아서 열 배나 많은 코드를 쓰는 에이전트.

진단 전의 증상

기술 플랫폼 보고서를 새로 쓸 때마다 아키텍처 전체를 다시 살펴봐야 해요. 서비스, 에이전트, 데이터 파이프라인까지요. 네 번째 보고서를 준비하면서 저장소의 규모가 마침내 눈에 들어왔어요. 점점 커지는 것을 보면서도 한 번도 멈춰서 생각해 본 적이 없었죠. 원래 몇천 줄, 10킬로바이트도 안 되던 저장소가 이제는 100메가바이트에 이르렀어요. 플랫폼의 기능이 그만큼 늘어난 것도 아니에요. 저는 그저 Claude Chat 같은 에이전트에게 코드 구현과 수정을 맡겼을 뿐이고, 무엇을 어떤 범위에서 요구하는지 정확히 정하지 않았어요.

보고서를 쓰면서 "잘 돌아가네" 모드에서 벗어나 "실제로 무슨 일이 있었나" 모드로 돌아가야 했어요. 저장소 히스토리에 대해 두 번의 별도 감사를 진행했어요. 둘 다 같은 원인을 가리켰지만, 이유는 완전히 달랐어요.

감사 1: 거짓말하는 컨텍스트 창

첫 번째 감사는 몇 달 동안 AI 에이전트가 서비스별로 수행한 수정을 하나씩 되짚어 보고, 적용 당시 저장소의 나머지 부분과 일관성이 있었는지 확인하는 것이었어요.

계속 반복되던 패턴이 있었어요. 에이전트는 눈앞에 있는 파일이나 모듈 안에서만 문제를 고치고, 저장소 다른 곳에 있는 같은 코드를 보지 못하거나 기억하지 못했어요. 결과적으로 같은 인터페이스가 두 서비스에 조금씩 다르게 다시 정의되고, 이름 바꾸기가 절반만 적용됐어요. 프롬프트 당시 두 번째 occurrences가 컨텍스트 창 밖에 있었기 때문이에요. 한 모듈에서는 지키던 명명 규칙이 다음 모듈에서는 무시됐어요. 하나씩 보면 대수롭지 않지만, 수십 번의 세션에 걸쳐 쌓이면 정확히 중복과 코드 스멜이 생겨나요. 나중에 투입되는 다음 도구가 흐름을 잃게 되는 바로 그 문제들이에요. 스스로를 먹여 살리는 순환이에요. 저장소가 커지고 조각날수록 에이전트가 전체를 머릿속에 담기 어려워지고, 수정은 점점 더 국소적이고 부분적이 되고, 저장소는 더 커져요.

문제는 에이전트가 "거짓말"하거나 지어낸다는 것이 아니에요. 주어진 컨텍스트에 대해 질문에 올바르게 답해요. 문제는 제가 대부분의 경우 질문의 범위를 미리 정한 적이 없다는 거예요. 저장소 다른 곳에 에이전트가 볼 수 없는 같은 버그가 있는지 자문하지 않고 "이 오타, 이 동작, 이 함수를 고쳐 줘"라고 요구했어요.

감사 2: 장황함이 코드가 될 때

두 번째 감사는 더 기계적이었어요. 전체 히스토리에 git log --numstat을 돌리고, 커밋별 추가된 줄과 문자를 집계해서 분포를 살펴봤어요.

추가된 줄 기준으로 가장 큰 30개 커밋만으로 저장소 전체 규모의 지나치게 큰 비중을 차지했어요. 예외 없이 같은 커밋들이 추가된 문자 기준으로도 가장 크게 나왔어요. 예상 가능한 일이었지만, 그 커밋들의 문자 대 줄 비율은 단순히 줄 수 때문만은 아니었어요. 줄 자체가 더 장황했고, 함수 이름과 중복되는 설명 주석이 더 많았고, 팩터링 대신 중복된 오류 처리 블록이 더 많았고, 같은 말을 세 번 바꾸어 말하는 독스트링이 더 많았어요.

이것은 채팅으로 LLM과 상호작용할 때 알려진 행동의 직접적인 결과예요. 간결하라는 명시적 지시가 없으면 많이 말하고, 정당화하고, 주석을 달고, 바꾸어 말하는 경향이 있어요. 대화에서는 출력 토큰이 드는 것으로 끝나요. 코드 생성에서는 같은 습관이 커밋마다 저장소에 영원히 남는 줄로 바뀌고, 코드가 동작하는 한 아무도 제대로 다시 읽지 않아요.

두 감사를 나란히 놓고 보니

첫 번째 보고서에 대해 말하자면, 서비스 간 일관성은 저장소 전체를 담기에는 너무 작은 컨텍스트 창의 영향을 받아요. 그래서 국소적인 수정과 중복, 규칙의 분기가 생겨요.

두 번째에 대해 말하자면, git log --numstat은 길들여지지 않은 LLM의 기본 장황함을 보여줘요. 그래서 지나치게 많은 줄과 문자 추가, 팩터링이 부족한 코드가 생겨요.

둘을 합치면 중복과 규모를 가리켜요. 미래의 에이전트가 머릿속에 담기에는 너무 큰 저장소가 되고, 이는 첫 번째 감사에서 드러난 첫 번째 문제를 더욱 악화시켜요.

보고서를 쓰면서 가장 걱정됐던 것은 마지막 줄이에요. 두 문제는 연결되어 있고 서로를 먹여 살려요. 생성된 코드가 장황할수록 저장소는 빨리 커지고, 커질수록 에이전트가 컨텍스트에 담기 어려워지고, 담기 어려울수록 수정은 국소적이고 중복적이 되고, 중복적일수록 규모가 더 늘어나요. 길잡이 없이 에이전트를 사용하는 것만으로 생긴 부정적인 피드백 루프예요.

이것이 특정 도구의 일회성 버그가 아닌 이유

이 진단에는 특정 모델이나 제품에 고유한 것이 아무것도 없어요. 어떤 채팅형 에이전트든 T 시점에 창에 보여지는 것을 토대로 동작하고, 기본적으로 가장 완전하고 가장 정당화된 답변을 만들어내요. 바로 대화형 어시스턴트에게 기대되는 행동이고, 프로덕션 저장소에 쓰는 도구에게는 정확히 피해야 할 행동이에요. 문제는 도구와 저장소 사이의 길잡이 부재에서 와요. 고려할 파일 범위, 기대되는 출력 형식, 줄 수나 장황함 예산, 새로운 것을 쓰기 전에 이미 존재하는 것을 정확히 인용해야 할 의무 같은 것들이요.

그 이후에 바꾼 것

논리적인 반사 행동이라면 쓰여진 것을 대폭 줄이는 것이었겠죠. 개인적으로 저는 다르게 하기로 했어요. 감사는 다른 용도로 썼어요. 코드를 스캔해서 코드 스멜을 찾아내고, 짐작이 아니라 진짜 문제가 어디에 있는지 정확히 delimit하는 데 썼어요. 서비스 간 불일치, 중복, 흐름을 잃은 지점 같은 것들이요. 쓰여진 코드의 규모는 대체로 그대로 두었어요. 장황하든 아니든, 잘 쓰면 여전히 유용하니까요. 지렛대는 에이전트의 작성을 막는 것이 아니라, 맞지 않는 것을 고치기 위해 정확히 어디를 봐야 하는지 아는 것이었어요.

다음 단계

저장소를 더 작고 잘 delimit된 단위로 나누는 것. 그리고 실행과 문서를 위한 프로덕션 안전장치도요. 이어서 제기되는 문제는 아키텍처 문제예요. 분리된 뒤에도 결정을 조율해야 하는 서비스와 컴포넌트, 문서를 이전과 같은 모놀리스로 돌아가지 않고 어떻게 깔끔하게 분석하고 비판하고 소통하게 할 것인가 하는 문제요.

Kod yapay zekâsı ajanlarıma körü körüne güvenmek yerine denetledim

Alım satım platformumun 4. teknik raporunu yazmak için yürütülen iki denetim bana iki ayrı sapmayı nasıl açığa çıkardı: depo bağlam penceresine artık sığmadığı için unutan ajan ve özlülüğe hiçbir şey itmediği için gerekenden on kat fazla kod yazan ajan.

Tanıdan önce belirti

Platformun teknik raporunun her baskısı mimariyi baştan gezmemi zorunlu kılar: servisler, ajanlar, veri pipelineları. 4. baskıyı hazırlarken deponun hacmi sonunda gözüme battı, oysa onu durmadan kademeli büyürken görüyordum: başlangıçta birkaç bin satıra, 10KB altına sığan depo artık 100MBye ulaşıyor. Platformda ancak biraz fazla özellik vardı. Kodu uygulamak ve düzeltmek için Claude Chat türü ajanlara yaslanmıştım, onlardan ne istediğimi ne de hangi kapsamda istediğimi kesin çerçevelemeden.

Raporu yazmak beni "ilerliyor" modundan çıkıp "gerçekte ne oldu" moduna dönmeye zorladı. Deponun tarihçesinde iki ayrı denetim yaptım. İkisi aynı nedene işaret ediyordu, tamamen farklı iki nedenle.

Denetim 1: yalan söyleyen bağlam penceresi

İlk denetim, yapay zekâ ajanının aylar boyunca yaptığı düzeltmeleri servis servis geri alıp uygulandıkları anda deponun geri kalanıyla tutarlı olup olmadığını doğrulamaktan ibaretti.

Sürekli dönen kalıp: ajan sorunu yerel düzeltiyordu, gözlerinin önündeki dosya ya da modülde, deponun başka yerindeki eşdeğerini görmeden ya da hatırlamadan. Sonuç: iki serviste hafif farklı yeniden tanımlanmış aynı arayüz, ikinci oluşum istem anında bağlam penceresi dışında kaldığı için yarı uygulanmış yeniden adlandırma, bir modülde uyulan sonraki modülde yoksayılan adlandırma uzlaşımı. Tek başına muhteşem hiçbir şey yok ama onlarca oturumda birikince tam sonraki çalıştırılan aracın ipini kaybettiren yedeklilik ve kod kokuları üretir. Kendi kendini besleyen döngü: depo büyüyüp parçalandıkça ajanın tamamını kafada tutması zorlaşır, düzeltmeler yerelleşir ve kısmi olur, depo büyür.

Sorun ajanın "yalan söylemesi" ya da uydurması değildir; verilen bağlamda sorulan soruya doğru yanıt verir. Sorun çoğu zaman sorunun kapsamını önceden tanımlamamış olmamdır. "Bu yazım hatasını, bu davranışı, bu fonksiyonu düzelt" diyordum, bu hatanın ajanın göremeyeceği deponun başka yerinde eşdeğerleri olup olmadığını sormadan.

Denetim 2: gevezelik koda dönüşünce

İkinci denetim daha mekanikti: tüm tarihçede git log --numstat çalıştırmak, commit başına eklenen satır ve karakterleri toplamak ve dağılıma bakmak.

Eklenen satırda en büyük 30 commit tek başına deponun toplam hacminin açık oransız payını temsil ediyordu. Sistematik aynı commitler eklenen karakterde de en büyük çıkıyordu. Öngörülebilirdi, tek fark bu commitlerin karakter/satır oranı yalnızca satır sayısına bağlı değildi: satırların kendisi daha gevezeydi, fonksiyon adlarıyla yedek gereksiz açıklayıcı yorumlar, çarpanlarına ayrılmak yerine yinelenen daha fazla hata yönetimi bloğu, aynı şeyi üç kez yeniden formüle eden daha fazla docstring ile.

Bu sohbette LLM ile etkileşimde bilinen davranışın doğrudan sonucudur: açık özlülük talimatı olmadan çok konuşma, gerekçelendirme, yorumlama, yeniden formüle etme eğilimindedir. Sohbette bu çıktı jetonlarına mal olur. Kod üretiminde aynı refleks depoda süresiz kalan satırlara dönüşür, kod çalıştığı sürece gerçekten yeniden okunmadan commit commit.

İki denetim yan yana konunca ne gösterdi

İlk rapor için: servisler arası tutarlılık depoyu tamam tutmaya küçük bağlam penceresinden muzdariptir, bu yerel düzeltmeler, yedeklilikler ve uzlaşım sapmaları doğurur.

İkinci için: git log --numstat, çerçevelenmemiş LLMnin varsayılan gevezeliğini gösterir, bu oransız eklenmiş satır ve karakterlere ve az çarpanlarına ayrılmış koda neden olur.

İkisi birleşince yedeklilik ve hacme işaret eder: bu gelecek ajanın kafada tutamayacağı kadar büyük depo verir, bu da ilk denetimin gösterdiği ilk sorunu daha kötüleştirir.

Raporu yazarken beni en çok endişelendiren bu son satır oldu: iki sorun bağlıdır, birbirini besler. Üretilen kod ne geveze, depo o hızlı büyür; ne büyür, ajan onu bağlamda o az tutabilir; ne az tutabilir, düzeltmeleri o yerel ve yedek olur; ne yedek olur, o hacim ekler. Tamamen çerçevesiz ajan kullanımından kaynaklanan olumsuz geri bildirim döngüsü.

Neden bu belirli bir aracın noktasal hatası değildir

Bu tanıda hiçbir şey belirli model ya da ürüne özgü değildir. Sohbet türü ajan her neyse T anında ona gösterilen üzerinden çalışır ve varsayılan en eksiksiz ve gerekçeli yanıtı üretir. Bu konuşma asistanından tam beklenen davranıştır ve üretim deposuna yazan araç için tam kaçınılacak olan. Sorun araç ile depo arası çerçevelem yokluğundan gelir: dikkate alınacak dosya kapsamı, beklenen çıktı formatı, satır ya da gevezelik bütçesi, yeni bir şey yazmadan önce zaten var olanı kesin alıntılama zorunluluğu.

O zamandan beri neyi değiştirdim

Mantıklı refleks yazılmış olanı drastik azaltmak olurdu. Kişisel olarak farklı yapmaya karar verdim. Denetimler başka işe yaradı: kod kokularını tespit etmek için kodu taramak ve gerçek sorunların tam nerede olduğunu sınırlamak için kullanmak. Servisler arası tutarsızlıklar, yedeklilikler, ipin kaybolduğu yerler, tahmin etmek yerine. Yazılan kod hacmi anlamlı aynı kalır: geveze olsun olmasın iyi kullanılırsa faydalı kalır. Kaldıraç uymayanı düzeltmek için tam nereye bakılacağını bilmekti, ajanın yazmasını engellemekten çok.

Sonraki adımlar

Deponun daha küçük ve iyi sınırlı birimlere bölünmesi. Ayrıca yürütme ve belgeleme için üretim korkulukları. Sırayla ortaya çıkan sorun mimari sorusudur: bir kez ayrılıp yine de kararlarını koordine etmesi gereken servisler, bileşenler ve belgeleme düzgün nasıl analiz edilir, eleştirilir ve iletişir, öncekiyle aynı monolite dönmeden.

Ho auditato i miei agenti IA di codice invece di fidarmi ciecamente

Come due audit fatti per scrivere il 4° report tecnico della mia piattaforma di trading mi hanno rivelato due derive distinte: un agente che dimentica perché il repo non sta più nella sua finestra di contesto, e un agente che scrive dieci volte più codice del necessario perché niente lo spinge alla concisione.

Il sintomo prima della diagnosi

Ogni edizione del report tecnico della piattaforma mi obbliga a ripercorrere l'architettura intera: servizi, agenti, pipeline di dati. È preparando la 4ª edizione che il volume del repo alla fine mi è saltato agli occhi, mentre lo vedevo crescere progressivamente senza fermarmici mai sopra: il repo, che all'origine stava in poche migliaia di righe, meno di 10ko, raggiunge ormai 100Mo. La piattaforma aveva a malapena più funzionalità. Mi ero semplicemente appoggiato su agenti tipo Claude Chat per implementare e correggere codice, senza inquadrare con precisione cosa chiedevo loro né su quale perimetro.

Scrivere il report mi ha costretto a uscire dalla modalità "avanza" per tornare in modalità "cos'è successo davvero". Ho fatto due audit distinti sullo storico del repo. Entrambi puntavano alla stessa causa, per due ragioni completamente diverse.

Audit n°1: la finestra di contesto che mente

Il primo audit consisteva a riprendere, servizio per servizio, le correzioni fatte da un agente IA su vari mesi, e a verificare se erano coerenti col resto del repo al momento in cui erano state applicate.

Il motivo che tornava senza sosta: l'agente correggeva un problema localmente, nel file o nel modulo che aveva sotto gli occhi, senza aver visto l'equivalente altrove nel repo, o senza ricordarsene. Risultato: la stessa interfaccia ridefinita leggermente diversa in due servizi, una ridenominazione applicata a metà perché la seconda occorrenza era fuori dalla finestra di contesto al momento del prompt, una convenzione di nomi rispettata in un modulo e ignorata nel successivo. Niente di spettacolare preso isolatamente, ma cumulato su decine di sessioni, produce esattamente la ridondanza e i code smell che fanno perdere il filo allo strumento successivo che ci lanci sopra. Un circolo che si autoalimenta: più il repo cresce e si frammenta, più diventa difficile per un agente tenerlo in testa nella sua integralità, più le correzioni diventano locali e parziali, più il repo cresce.

Il problema non è che l'agente "mente" o inventa; risponde correttamente alla domanda posta sul contesto che gli è stato dato. Il problema è che io non avevo, quasi mai, definito il perimetro della domanda a monte. Chiedevo "correggi questo refuso, questo comportamento, questa funzione" senza chiedermi se questo bug avesse equivalenti altrove nel repo che l'agente non poteva vedere.

Audit n°2: quando la verbosità diventa codice

Il secondo audit era più meccanico: far girare un git log --numstat su tutto lo storico, aggregare righe aggiunte e caratteri aggiunti per commit e guardare la distribuzione.

I 30 commit più grossi in righe aggiunte rappresentavano, da soli, una parte largamente sproporzionata del volume totale del repo. Sistematicamente, gli stessi commit risultavano anche i più grossi in caratteri aggiunti. Era prevedibile, solo che il rapporto caratteri/righe di quei commit non era legato solo al numero di righe: le righe stesse erano più verbose, con più commenti esplicativi ridondanti col nome delle funzioni, più blocchi di gestione errori duplicati invece di essere fattorizzati, più docstring che riformulavano tre volte la stessa cosa.

È la conseguenza diretta di un comportamento noto quando si interagisce con un LLM in chat: senza consegna esplicita di concisione, tende a parlare molto, a giustificare, commentare, riformulare. In conversazione, costa token di uscita. In generazione di codice, questo stesso riflesso si traduce in righe che restano nel repo all'infinito, commit dopo commit, senza rileggerle davvero finché il codice funziona.

Cosa i due audit, fianco a fianco, hanno mostrato

Per il primo report: la coerenza inter-servizi soffre di una finestra di contesto troppo piccola per tenere tutto il repo, il che porta a correzioni locali, ridondanze e divergenze di convenzioni.

Per il secondo: git log --numstat mostra una verbosità di default di un LLM non inquadrato, il che causa righe e caratteri aggiunti sproporzionati e codice poco fattorizzato.

I due riuniti puntano a ridondanza e volume: danno un repo troppo grosso perché un futuro agente lo tenga in testa, il che aggrava ancora il primo problema messo in evidenza dal primo audit.

È quest'ultima riga che mi ha preoccupato di più scrivendo il report: i due problemi sono legati, si nutrono a vicenda. Più il codice generato è verboso, più il repo cresce in fretta; più cresce, meno un agente può tenerlo in contesto; meno può tenerlo in contesto, più le sue correzioni sono locali e ridondanti; più sono ridondanti, più aggiungono volume. Un ciclo di retroazione negativa, interamente causato da un uso di agenti senza inquadramento.

Perché non è un bug puntuale di uno strumento preciso

Niente in questa diagnosi è specifico di un modello o un prodotto in particolare. Un agente tipo chat, qualsiasi sia, opera su ciò che gli diamo da vedere nella sua finestra all'istante T, e genera di default la risposta più completa e giustificata possibile. È esattamente il comportamento atteso di un assistente conversazionale, ed esattamente quello da evitare per uno strumento che scrive in un repo di produzione. Il problema viene dall'assenza di inquadramento tra lo strumento e il repo: perimetro di file da considerare, formato di uscita atteso, budget di righe o verbosità, obbligo di citare con precisione ciò che esiste già prima di scrivere qualcosa di nuovo.

Cosa ho cambiato da allora

Il riflesso logico sarebbe stato ridurre drasticamente ciò che era stato scritto. Personalmente, ho deciso di fare altrimenti. Gli audit mi sono serviti ad altro: scansionare il codice per individuarvi i code smell, e servirmene per delimitare con precisione dove stavano i veri problemi. Le incoerenze inter-servizi, le ridondanze, i punti dove il filo si era perso, invece di tirare a indovinare. Il volume di codice scritto resta significativamente lo stesso: verboso o no, resta utile se ben usato. La leva era sapere con precisione dove guardare per correggere ciò che non quadrava, invece di impedire all'agente di scrivere.

Prossimi passi

Il taglio del repo in unità più piccole e meglio delimitate. Oltre a presidi di produzione per esecuzione e documentazione. Il problema che si pone a sua volta è una questione di architettura: come analizzare, criticare e far comunicare pulitamente i servizi, componenti e documentazione che, una volta separati, devono comunque coordinare le loro decisioni senza tornare allo stesso monolite di prima.

Ich habe meine Code-KI-Agenten auditiert, statt ihnen blind zu vertrauen

Wie zwei Audits, die ich für den 4. technischen Bericht meiner Trading-Plattform durchgeführt habe, mir zwei unterschiedliche Fehlentwicklungen offenbart haben: ein Agent, der vergisst, weil das Repo nicht mehr in sein Kontextfenster passt, und ein Agent, der zehnmal mehr Code schreibt als nötig, weil nichts ihn zur Kürze drängt.

Das Symptom vor der Diagnose

Jede Ausgabe des technischen Berichts der Plattform zwingt mich, die gesamte Architektur erneut zu durchlaufen: Services, Agenten, Datenpipelines. Als ich die 4. Ausgabe vorbereitete, sprang mir das Volumen des Repos endlich ins Auge, obwohl ich es allmählich hatte wachsen sehen, ohne je innezuhalten: Das Repo, das ursprünglich in wenige tausend Zeilen passte, weniger als 10ko, erreicht mittlerweile 100Mo. Die Plattform hatte kaum mehr Funktionen. Ich hatte mich einfach auf Agenten vom Typ Claude Chat verlassen, um Code zu implementieren und zu korrigieren, ohne genau einzugrenzen, was ich sie fragte, noch auf welchem Perimeter.

Das Schreiben des Berichts zwang mich, aus dem Modus "es geht voran" zurück in den Modus "was ist wirklich passiert" zu wechseln. Ich habe zwei getrennte Audits über die Historie des Repos gemacht. Beide zeigten auf dieselbe Ursache, aus zwei völlig unterschiedlichen Gründen.

Audit Nr. 1: das Kontextfenster, das lügt

Das erste Audit bestand darin, Service für Service die Korrekturen durchzugehen, die ein KI-Agent über mehrere Monate gemacht hatte, und zu prüfen, ob sie mit dem Rest des Repos zum Zeitpunkt ihrer Anwendung konsistent waren.

Das Muster, das immer wiederkehrte: Der Agent korrigierte ein Problem lokal, in der Datei oder dem Modul, das er vor Augen hatte, ohne das Gegenstück anderswo im Repo gesehen zu haben oder sich daran zu erinnern. Ergebnis: dieselbe Schnittstelle leicht unterschiedlich in zwei Services neu definiert, eine Umbenennung halb angewendet, weil das zweite Vorkommen zum Zeitpunkt des Prompts außerhalb des Kontextfensters lag, eine Namenskonvention in einem Modul respektiert und im nächsten ignoriert. Nichts Spektakuläres isoliert betrachtet, aber kumuliert über Dutzende Sessions produziert das genau die Redundanz und die Code Smells, die das nächste Tool, das man darauf loslässt, den Faden verlieren lassen. Ein sich selbst verstärkender Kreis: Je mehr das Repo wächst und fragmentiert, desto schwieriger wird es für einen Agenten, es in seiner Gesamtheit im Kopf zu behalten, desto lokaler und partieller werden die Korrekturen, desto mehr wächst das Repo.

Das Problem ist nicht, dass der Agent "lügt" oder erfindet; er antwortet korrekt auf die gestellte Frage über den Kontext, den man ihm gegeben hat. Das Problem ist, dass ich meistens nie den Perimeter der Frage im Voraus definiert hatte. Ich fragte "korrigiere diesen Tippfehler, dieses Verhalten, diese Funktion", ohne mich zu fragen, ob dieser Bug Gegenstücke anderswo im Repo hatte, die der Agent nicht sehen konnte.

Audit Nr. 2: wenn Verbosität zu Code wird

Das zweite Audit war mechanischer: Ein git log --numstat über die gesamte Historie laufen lassen, hinzugefügte Zeilen und hinzugefügte Zeichen pro Commit aggregieren und die Verteilung anschauen.

Die 30 größten Commits nach hinzugefügten Zeilen stellten allein einen weitgehend überproportionalen Anteil des Gesamtvolumens des Repos dar. Systematisch stachen dieselben Commits auch als größte nach hinzugefügten Zeichen hervor. Das war vorhersehbar, nur dass das Zeichen/Zeilen-Verhältnis dieser Commits nicht nur mit der Zeilenzahl zusammenhing: Die Zeilen selbst waren wortreicher, mit mehr erklärenden Kommentaren, die mit den Funktionsnamen redundant waren, mehr duplizierten Fehlerbehandlungsblöcken statt faktorisiertem Code, mehr Docstrings, die dreimal dasselbe umformulierten.

Das ist die direkte Folge eines bekannten Verhaltens bei der Interaktion mit einem LLM im Chat: Ohne explizite Anweisung zur Kürze neigt es dazu, viel zu reden, zu begründen, zu kommentieren, umzuformulieren. In einer Unterhaltung kostet das Ausgabe-Tokens. Bei der Codegenerierung übersetzt sich derselbe Reflex in Zeilen, die unbegrenzt im Repo bleiben, Commit für Commit, ohne dass man sie wirklich noch einmal liest, solange der Code funktioniert.

Was beide Audits nebeneinander gezeigt haben

Für den ersten Bericht: Die dienstübergreifende Konsistenz leidet unter einem Kontextfenster, das zu klein ist, um das ganze Repo zu halten, was zu lokalen Korrekturen, Redundanzen und abweichenden Konventionen führt.

Für den zweiten: git log --numstat zeigt eine Standard-Verbosität eines nicht eingegrenzten LLM, was überproportional hinzugefügte Zeilen und Zeichen und wenig faktorisierten Code verursacht.

Beide zusammen zeigen auf Redundanz und Volumen: Das ergibt ein Repo, das zu groß ist, als dass ein künftiger Agent es im Kopf behalten könnte, was wiederum das erste Problem verschärft, das das erste Audit aufgezeigt hat.

Es ist diese letzte Zeile, die mich beim Schreiben des Berichts am meisten beunruhigt hat: Die beiden Probleme hängen zusammen, sie füttern einander. Je wortreicher der generierte Code, desto schneller wächst das Repo; je mehr es wächst, desto weniger kann ein Agent es im Kontext halten; je weniger er es im Kontext halten kann, desto lokaler und redundanter sind seine Korrekturen; je redundanter sie sind, desto mehr Volumen kommt hinzu. Eine negative Rückkopplungsschleife, vollständig verursacht durch eine Nutzung von Agenten ohne Einhegung.

Warum das kein punktueller Bug eines bestimmten Tools ist

Nichts in dieser Diagnose ist spezifisch für ein bestimmtes Modell oder Produkt. Ein Chat-artiger Agent, welcher auch immer, operiert auf dem, was man ihm zum Zeitpunkt T in seinem Fenster zeigt, und generiert standardmäßig die vollständigste und begründetste Antwort. Das ist genau das erwartete Verhalten eines Gesprächsassistenten, und genau das, was man für ein Tool vermeiden muss, das in ein Produktions-Repo schreibt. Das Problem kommt vom fehlenden Rahmen zwischen Tool und Repo: zu berücksichtigender Datei-Perimeter, erwartetes Ausgabeformat, Zeilen- oder Verbositätsbudget, Pflicht, genau zu zitieren, was schon existiert, bevor man etwas Neues schreibt.

Was ich seitdem geändert habe

Der logische Reflex wäre gewesen, das Geschriebene drastisch zu reduzieren. Persönlich habe ich beschlossen, anders vorzugehen. Die Audits dienten mir zu etwas anderem: Den Code zu scannen, um Code Smells aufzuspüren, und sie zu nutzen, um genau einzugrenzen, wo die echten Probleme lagen. Die dienstübergreifenden Inkonsistenzen, die Redundanzen, die Stellen, wo der Faden verloren war, statt zu raten. Das Volumen des geschriebenen Codes bleibt weitgehend gleich: Wortreich oder nicht, er bleibt nützlich, wenn er gut genutzt wird. Der Hebel war zu wissen, wo genau man hinschauen muss, um zu korrigieren, was nicht passte, statt den Agenten am Schreiben zu hindern.

Nächste Schritte

Die Aufteilung des Repos in kleinere, besser abgegrenzte Einheiten. Sowie Produktions-Leitplanken für Ausführung und Dokumentation. Das Problem, das sich wiederum stellt, ist eine Architekturfrage: Wie man die Services, Komponenten und Dokumentation, die einmal getrennt koordiniert ihre Entscheidungen treffen müssen, sauber analysiert, kritisiert und kommunizieren lässt, ohne zum selben Monolithen wie zuvor zurückzukehren.

Я провёл аудит своих ИИ-агентов для кода вместо того, чтобы доверять им вслепую

Как два аудита, проведённые для написания 4-го технического отчёта моей торговой платформы, выявили два разных сбоя : агент, который забывает, потому что репозиторий больше не влезает в его окно контекста, и агент, который пишет в десять раз больше кода, чем нужно, потому что ничто не толкает его к краткости.

Симптом до диагноза

Каждое издание технического отчёта платформы заставляет меня заново проходить всю архитектуру : сервисы, агенты, пайплайны данных. Готовя 4-е издание, объём репозитория наконец бросился мне в глаза, хотя я видел, как он постепенно растёт, и никогда на этом не останавливался : репозиторий, который изначально умещался в несколько тысяч строк, меньше 10 КБ, теперь достиг 100 МБ. Функций у платформы стало едва ли больше. Я просто опирался на агентов типа Claude Chat для написания и исправления кода, не задавая точно, чего от них прошу и в каком периметре.

Написание отчёта заставило меня выйти из режима "всё движется" обратно в режим "что реально произошло". Я провёл два отдельных аудита истории репозитория. Оба указывали на одну причину, по двум совершенно разным основаниям.

Аудит №1 : окно контекста, которое врёт

Первый аудит состоял в том, чтобы по каждому сервису разобрать исправления, которые ИИ-агент вносил несколько месяцев, и проверить, согласовывались ли они с остальным репозиторием на момент применения.

Мотив повторялся постоянно : агент исправлял проблему локально, в файле или модуле, который был у него перед глазами, не видя аналога в другом месте репозитория или не помня о нём. Итог : один и тот же интерфейс, чуть по-разному переопределённый в двух сервисах, переименование, применённое наполовину, потому что второе вхождение оказалось за пределами окна контекста в момент промпта, соглашение об именовании, соблюдённое в одном модуле и проигнорированное в следующем. Ничего яркого по отдельности, но накопленное за десятки сессий, это даёт ровно ту избыточность и code smells, из-за которых следующий запущенный инструмент теряет нить. Самоподпитывающийся круг : чем больше и фрагментированнее репозиторий, тем труднее агенту удержать его в голове целиком, тем локальнее и частичнее исправления, тем больше репозиторий.

Проблема не в том, что агент "врёт" или выдумывает ; он правильно отвечает на заданный вопрос в том контексте, что ему дали. Проблема в том, что я чаще всего заранее вообще не определял периметр вопроса. Я просил "исправь эту опечатку, это поведение, эту функцию", не спрашивая себя, есть ли у этого бага аналоги в другом месте репозитория, которых агент не видит.

Аудит №2 : когда многословие становится кодом

Второй аудит был более механическим : прогнать git log --numstat по всей истории, агрегировать добавленные строки и символы по коммитам и посмотреть на распределение.

30 самых больших коммитов по добавленным строкам составляли, сами по себе, сильно непропорциональную долю общего объёма репозитория. Систематически те же коммиты оказывались и самыми большими по добавленным символам. Это было предсказуемо, только вот соотношение символов к строкам у этих коммитов объяснялось не только числом строк : сами строки были многословнее, с избыточными поясняющими комментариями, дублирующими имена функций, с дублированными вместо вынесенных блоками обработки ошибок, с докстрингами, которые трижды переформулировали одно и то же.

Это прямое следствие известного поведения при общении с LLM в чате : без явной установки на краткость он склонен много говорить, обосновывать, комментировать, переформулировать. В разговоре это стоит выходных токенов. В генерации кода тот же рефлекс превращается в строки, которые остаются в репозитории навсегда, коммит за коммитом, и их толком никто не перечитывает, пока код работает.

Что показали оба аудита рядом

Для первого отчёта : связность между сервисами страдает от окна контекста, слишком маленького, чтобы удержать весь репозиторий, что ведёт к локальным исправлениям, избыточности и расхождению соглашений.

Для второго : git log --numstat показывает многословие по умолчанию у LLM без рамок, что даёт непропорционально много добавленных строк и символов и плохо вынесенный код.

Оба вместе указывают на избыточность и объём : получается репозиторий, слишком большой, чтобы будущий агент удержал его в голове, а это ещё усугубляет первую проблему, выявленную первым аудитом.

Именно эта последняя строка встревожила меня сильнее всего, когда я писал отчёт : обе проблемы связаны, они подпитывают друг друга. Чем многословнее сгенерированный код, тем быстрее растёт репозиторий ; чем он больше, тем меньше агент может удержать в контексте ; чем меньше он удерживает, тем локальнее и избыточнее его исправления ; чем они избыточнее, тем больше объёма. Петля отрицательной обратной связи, целиком вызванная использованием агентов без рамок.

Почему это не разовый баг конкретного инструмента

В этом диагнозе нет ничего специфичного для конкретной модели или продукта. Чат-агент, какой бы он ни был, работает с тем, что ему показывают в его окне в момент T, и по умолчанию генерирует самый полный и обоснованный ответ. Это ровно ожидаемое поведение разговорного ассистента и ровно то, чего стоит избегать у инструмента, который пишет в продакшн-репозиторий. Проблема в отсутствии рамок между инструментом и репозиторием : периметр файлов для рассмотрения, ожидаемый формат вывода, бюджет строк или многословия, обязанность точно цитировать то, что уже есть, прежде чем писать что-то новое.

Что я изменил с тех пор

Логичным рефлексом было бы резко сократить написанное. Лично я решил иначе. Аудиты послужили другому : просканировать код, найти code smells и использовать их, чтобы точно очертить, где настоящие проблемы. Несостыковки между сервисами, избыточность, места, где нить потерялась, вместо гадания. Объём написанного кода остался заметно тем же : многословный или нет, он остаётся полезным, если его хорошо использовать. Рычагом было точно знать, куда смотреть, чтобы исправить то, что не сходится, а не мешать агенту писать.

Следующие шаги

Разбиение репозитория на более мелкие и чётко очерченные единицы. А также продакшн-ограничители для исполнения и документации. Возникающая при этом проблема уже архитектурная : как анализировать, критиковать и заставить чисто общаться сервисы, компоненты и документацию, которые, став разделёнными, всё равно должны координировать решения, не возвращаясь к тому же монолиту, что раньше.

Audité mis agentes IA de código en vez de confiar en ellos a ciegas

Cómo dos auditorías hechas para redactar el 4º informe técnico de mi plataforma de trading me revelaron dos derivas distintas: un agente que olvida porque el repo ya no cabe en su ventana de contexto, y un agente que escribe diez veces más código del necesario porque nada lo empuja a la concisión.

El síntoma antes del diagnóstico

Cada edición del informe técnico de la plataforma me obliga a recorrer la arquitectura entera: servicios, agentes, pipelines de datos. Al preparar la 4ª edición el volumen del repo me saltó a los ojos, cuando lo veía crecer progresivamente sin detenerme nunca en ello: el repo, que cabía al origen en unos miles de líneas, menos de 10ko, alcanza ahora 100MB. La plataforma apenas tenía más funciones. Simplemente me había apoyado en agentes tipo Claude Chat para implementar y corregir código, sin enmarcar con precisión lo que les pedía ni sobre qué perímetro.

Escribir el informe me obligó a salir del modo "avanza" para volver al modo "qué pasó realmente". Hice dos auditorías distintas sobre el historial del repo. Ambas apuntaban a la misma causa, por dos razones por completo distintas.

Auditoría n°1: la ventana de contexto que miente

La primera auditoría consistía en retomar, servicio por servicio, las correcciones hechas por un agente IA durante varios meses, y comprobar si eran coherentes con el resto del repo en el momento en que se habían aplicado.

El patrón que volvía sin cesar: el agente corregía un problema localmente, en el archivo o el módulo que tenía ante los ojos, sin haber visto el equivalente en otro sitio del repo, o sin acordarse. Resultado: la misma interfaz redefinida ligeramente distinto en dos servicios, un renombrado aplicado a medias porque la segunda ocurrencia estaba fuera de la ventana de contexto en el momento del prompt, una convención de nombres respetada en un módulo e ignorada en el siguiente. Nada espectacular por separado, pero acumulado en decenas de sesiones, eso produce justo la redundancia y los code smells que hacen perder el hilo a la siguiente herramienta que lances sobre eso. Un círculo que se autoalimenta: cuanto más crece y se fragmenta el repo, más difícil es para un agente mantenerlo entero en la cabeza, más las correcciones se vuelven locales y parciales, más crece el repo.

El problema no es que el agente "mienta" o invente; responde correctamente a la pregunta planteada sobre el contexto que se le dio. El problema es que yo, la mayoría de las veces, nunca había definido el perímetro de la pregunta de antemano. Pedía "corrige esta errata, este comportamiento, esta función" sin preguntarme si ese bug tenía equivalentes en otro sitio del repo que el agente no podía ver.

Auditoría n°2: cuando la verbosidad se vuelve código

La segunda auditoría era más mecánica: pasar un git log --numstat por todo el historial, agregar líneas añadidas y caracteres añadidos por commit y mirar la distribución.

Los 30 commits más grandes en líneas añadidas representaban, por sí solos, una parte desproporcionadamente grande del volumen total del repo. Sistemáticamente, los mismos commits también salían como los más grandes en caracteres añadidos. Era previsible, salvo que el ratio caracteres/líneas de esos commits no solo estaba ligado al número de líneas: las líneas mismas eran más verbosas, con más comentarios explicativos redundantes con los nombres de las funciones, más bloques de gestión de errores duplicados en vez de factorizados, más docstrings que reformulaban tres veces lo mismo.

Es la consecuencia directa de un comportamiento conocido cuando interactúas con un LLM en chat: sin consigna explícita de concisión, tiende a hablar mucho, a justificar, comentar, reformular. En conversación, eso cuesta tokens de salida. En generación de código, ese mismo reflejo se traduce en líneas que quedan en el repo indefinidamente, commit tras commit, sin que las releamos de verdad mientras el código funcione.

Lo que ambas auditorías, juntas, mostraron

Para el primer informe: la coherencia entre servicios sufre de una ventana de contexto demasiado pequeña para abarcar todo el repo, lo que conlleva correcciones locales, redundancias y divergencias de convenciones.

Para el segundo: git log --numstat muestra una verbosidad por defecto de un LLM sin enmarcar, lo que causa líneas y caracteres añadidos desproporcionados y código poco factorizado.

Ambos juntos apuntan a la redundancia y al volumen: eso da un repo demasiado grande para que un futuro agente lo abarque, lo que agrava aún más el primer problema puesto de manifiesto por la primera auditoría.

Esa última línea me preocupó más al escribir el informe: ambos problemas están ligados, se alimentan mutuamente. Cuanto más verboso el código generado, más rápido crece el repo; cuanto más crece, menos un agente puede abarcarlo en contexto; cuanto menos puede abarcarlo en contexto, más locales y redundantes son sus correcciones; cuanto más redundantes, más añade volumen. Un bucle de retroalimentación negativa, enteramente causado por un uso de agentes sin enmarcar.

Por qué no es un bug puntual de una herramienta precisa

Nada de ese diagnóstico es específico de un modelo o un producto en concreto. Un agente tipo chat, sea cual sea, opera sobre lo que se le da a ver en su ventana en el instante T, y genera por defecto la respuesta más completa y justificada posible. Es exactamente el comportamiento esperado de un asistente conversacional, y justo el que hay que evitar para una herramienta que escribe en un repo de producción. El problema viene de la ausencia de enmarcado entre la herramienta y el repo: perímetro de archivos a considerar, formato de salida esperado, presupuesto de líneas o de verbosidad, obligación de citar con precisión lo que ya existe antes de escribir algo nuevo.

Lo que cambié desde entonces

El reflejo lógico habría sido reducir drásticamente lo que se había escrito. Personalmente, decidí hacer otra cosa. Las auditorías me sirvieron para otra cosa: escanear el código para detectar code smells, y usarlo para delimitar con precisión dónde estaban los verdaderos problemas. Las incoherencias entre servicios, las redundancias, los sitios donde se había perdido el hilo, en vez de adivinar. El volumen de código escrito sigue siendo significativamente el mismo: verboso o no, sigue siendo útil si se usa bien. La palanca era saber con precisión dónde mirar para corregir lo que no cuadraba, en vez de impedir al agente escribir.

Próximos pasos

El troceado del repo en unidades más pequeñas y mejor delimitadas. Así como salvaguardas de producción para la ejecución y la documentación. El problema que se plantea a su vez es una cuestión de arquitectura: cómo analizar, criticar y hacer comunicar limpiamente los servicios, componentes y documentación que, una vez separados, aun así tienen que coordinar sus decisiones sin volver al mismo monolito de antes.

Auditei meus agentes de IA de código em vez de confiar neles cegamente

Como dois audits feitos para escrever o 4º relatório técnico da minha plataforma de trading me revelaram dois desvios distintos : um agente que esquece porque o repo não cabe mais na janela de contexto dele, e um agente que escreve dez vezes mais código do que o necessário porque nada o incentiva à concisão.

O sintoma antes do diagnóstico

Cada edição do relatório técnico da plataforma me obriga a percorrer a arquitetura inteira de novo : serviços, agentes, pipelines de dados. Foi ao preparar a 4ª edição que o volume do repo acabou me chamando a atenção, embora eu o visse crescer aos poucos sem nunca parar para olhar : o repo, que no início cabia em alguns milhares de linhas, menos de 10ko, agora chega a 100Mo. A plataforma tinha apenas um pouco mais de funcionalidades. Eu tinha simplesmente contado com agentes do tipo Claude Chat para implementar e corrigir código, sem definir com precisão o que eu pedia nem em qual escopo.

Escrever o relatório me forçou a sair do modo "está avançando" para voltar ao modo "o que realmente aconteceu". Fiz dois audits distintos no histórico do repo. Os dois apontavam para a mesma causa, por duas razões completamente diferentes.

Audit nº 1 : a janela de contexto que mente

O primeiro audit consistiu em retomar, serviço por serviço, as correções feitas por um agente de IA ao longo de vários meses, e verificar se eram coerentes com o resto do repo no momento em que tinham sido aplicadas.

O padrão que voltava o tempo todo : o agente corrigia um problema localmente, no arquivo ou módulo que tinha diante dos olhos, sem ter visto o equivalente em outro lugar do repo, ou sem se lembrar dele. Resultado : a mesma interface redefinida de forma um pouco diferente em dois serviços, uma renomeação aplicada pela metade porque a segunda ocorrência estava fora da janela de contexto na hora do prompt, uma convenção de nomes respeitada em um módulo e ignorada no seguinte. Nada de espetacular isoladamente, mas acumulado ao longo de dezenas de sessões, isso produz exatamente a redundância e os code smells que fazem o próximo tool que rodamos em cima perder o fio. Um ciclo que se autoalimenta : quanto mais o repo cresce e se fragmenta, mais difícil fica para um agente mantê-lo inteiro na cabeça, mais as correções ficam locais e parciais, mais o repo cresce.

O problema não é que o agente "mente" ou inventa ; ele responde corretamente à pergunta feita sobre o contexto que recebeu. O problema é que, na maioria das vezes, eu nunca tinha definido o escopo da pergunta antes. Eu pedia "corrige esse typo, esse comportamento, essa função" sem me perguntar se esse bug tinha equivalentes em outro lugar do repo que o agente não podia ver.

Audit nº 2 : quando a verbosidade vira código

O segundo audit foi mais mecânico : rodar um git log --numstat em todo o histórico, agregar linhas adicionadas e caracteres adicionados por commit e olhar a distribuição.

Os 30 maiores commits em linhas adicionadas representavam, sozinhos, uma parte amplamente desproporcional do volume total do repo. Sistematicamente, os mesmos commits também apareciam como os maiores em caracteres adicionados. Era previsível, só que a taxa de caracteres/linhas desses commits não vinha só do número de linhas : as próprias linhas eram mais verborrágicas, com mais comentários explicativos redundantes com o nome das funções, mais blocos de tratamento de erros duplicados em vez de fatorados, mais docstrings que reformulavam três vezes a mesma coisa.

É a consequência direta de um comportamento conhecido ao interagir com um LLM em chat : sem instrução explícita de concisão, ele tende a falar muito, a justificar, comentar, reformular. Em conversa, isso custa tokens de saída. Em geração de código, esse mesmo reflexo se traduz em linhas que ficam no repo para sempre, commit após commit, sem que a gente realmente as releia enquanto o código funciona.

O que os dois audits, lado a lado, mostraram

Para o primeiro relatório : a coerência entre serviços sofre com uma janela de contexto pequena demais para conter o repo inteiro, o que leva a correções locais, redundâncias e divergências de convenções.

Para o segundo : git log --numstat mostra uma verbosidade padrão de um LLM sem direcionamento, o que causa linhas e caracteres adicionados desproporcionais e um código pouco fatorado.

Os dois juntos apontam redundância e volume : isso dá um repo grande demais para um futuro agente manter na cabeça, o que agrava ainda mais o primeiro problema revelado pelo primeiro audit.

Foi essa última linha que mais me preocupou ao escrever o relatório : os dois problemas estão ligados, alimentam um ao outro. Quanto mais verborrágico o código gerado, mais rápido o repo cresce ; quanto mais ele cresce, menos um agente consegue mantê-lo em contexto ; quanto menos consegue mantê-lo em contexto, mais locais e redundantes são as correções ; quanto mais redundantes, mais volume adicionam. Um ciclo de feedback negativo, inteiramente causado por um uso de agentes sem direcionamento.

Por que não é um bug pontual de uma ferramenta específica

Nada neste diagnóstico é específico de um modelo ou produto em particular. Um agente tipo chat, qualquer que seja, opera sobre o que recebe na janela dele no instante T, e gera por padrão a resposta mais completa e justificada possível. É exatamente o comportamento esperado de um assistente conversacional, e exatamente o que deve ser evitado para uma ferramenta que escreve em um repo de produção. O problema vem da falta de direcionamento entre a ferramenta e o repo : escopo de arquivos a considerar, formato de saída esperado, orçamento de linhas ou de verbosidade, obrigação de citar com precisão o que já existe antes de escrever algo novo.

O que mudei desde então

O reflexo lógico teria sido reduzir drasticamente o que tinha sido escrito. Pessoalmente, decidi fazer diferente. Os audits me serviram para outra coisa : escanear o código para localizar code smells, e usá-los para delimitar com precisão onde estavam os verdadeiros problemas. As incoerências entre serviços, as redundâncias, os pontos onde o fio se perdeu, em vez de adivinhar. O volume de código escrito continua praticamente o mesmo : verborrágico ou não, continua útil se for bem usado. A alavanca era saber exatamente onde olhar para corrigir o que não encaixava, em vez de impedir o agente de escrever.

Próximas etapas

A divisão do repo em unidades menores e melhor delimitadas. Além de proteções de produção para execução e documentação. O problema que surge em seguida é uma questão de arquitetura : como analisar, criticar e fazer comunicar de forma limpa os serviços, componentes e documentação que, uma vez separados, ainda precisam coordenar decisões sem voltar ao mesmo monolito de antes.

Saya mengaudit agen AI coding saya alih-alih memercayai mereka secara membabi buta

Bagaimana dua audit yang dilakukan untuk menulis laporan teknis ke-4 platform trading saya mengungkapkan dua penyimpangan berbeda : satu agen yang lupa karena repo tidak muat lagi di jendela konteksnya, dan satu agen yang menulis kode sepuluh kali lebih banyak dari yang perlu karena tidak ada yang mendorongnya untuk ringkas.

Gejala sebelum diagnosis

Setiap edisi laporan teknis platform memaksa saya menelusuri ulang seluruh arsitekturnya : layanan, agen, pipeline data. Saat menyiapkan edisi ke-4 itulah volume repo akhirnya menyentak mata saya, padahal saya melihatnya membesar sedikit demi sedikit tanpa pernah berhenti memperhatikannya : repo yang awalnya hanya beberapa ribu baris, kurang dari 10ko, kini mencapai 100Mo. Platformnya nyaris tidak punya fitur lebih banyak. Saya hanya bersandar pada agen sejenis Claude Chat untuk mengimplementasikan dan memperbaiki kode, tanpa membingkai secara tepat apa yang saya minta maupun cakupannya.

Menulis laporan memaksa saya keluar dari mode "pokoknya jalan" untuk kembali ke mode "apa yang sebenarnya terjadi". Saya melakukan dua audit berbeda atas riwayat repo. Keduanya menunjuk ke penyebab yang sama, karena dua alasan yang sama sekali berbeda.

Audit no 1 : jendela konteks yang berbohong

Audit pertama adalah menelusuri ulang, layanan demi layanan, perbaikan yang dilakukan agen AI selama beberapa bulan, dan memeriksa apakah perbaikan itu konsisten dengan sisa repo pada saat diterapkan.

Pola yang terus kembali : agen memperbaiki masalah secara lokal, di berkas atau modul yang ada di depan matanya, tanpa pernah melihat padanannya di tempat lain di repo, atau tanpa mengingatnya. Hasilnya : antarmuka yang sama didefinisikan ulang sedikit berbeda di dua layanan, penggantian nama yang diterapkan setengah karena kemunculan kedua berada di luar jendela konteks saat prompt diberikan, konvensi penamaan yang dihormati di satu modul dan diabaikan di modul berikutnya. Tidak ada yang spektakuler kalau dilihat satu per satu, tapi diakumulasi selama puluhan sesi, inilah yang menghasilkan redundansi dan code smell yang membuat alat berikutnya yang dijalankan di atasnya kehilangan jejak. Lingkaran yang menghidupi dirinya sendiri : makin besar dan terfragmentasi repo, makin sulit bagi agen untuk memegangnya utuh di kepalanya, makin lokal dan parsial perbaikannya, makin besar repo.

Masalahnya bukan agen "berbohong" atau mengarang ; ia menjawab dengan benar pertanyaan yang diajukan atas konteks yang diberikan kepadanya. Masalahnya adalah saya, sebagian besar waktu, tidak pernah mendefinisikan cakupan pertanyaan itu di awal. Saya meminta "perbaiki typo ini, perilaku ini, fungsi ini" tanpa bertanya pada diri sendiri apakah bug ini punya padanan di tempat lain di repo yang tidak bisa dilihat agen.

Audit no 2 : ketika verbositas menjadi kode

Audit kedua lebih mekanis : menjalankan git log --numstat atas seluruh riwayat, mengagregasi baris yang ditambahkan dan karakter yang ditambahkan per commit lalu melihat distribusinya.

30 commit terbesar dalam baris yang ditambahkan mewakili, sendirian, porsi yang sangat tidak proporsional dari total volume repo. Secara sistematis, commit yang sama juga muncul sebagai yang terbesar dalam karakter yang ditambahkan. Itu bisa ditebak, hanya saja rasio karakter/baris commit-commit itu bukan sekadar soal jumlah baris : baris-barisnya sendiri lebih verbose, dengan lebih banyak komentar penjelasan yang redundan dengan nama fungsi, lebih banyak blok penanganan error yang diduplikasi alih-alih difaktorisasi, lebih banyak docstring yang merumuskan ulang tiga kali hal yang sama.

Ini akibat langsung dari perilaku yang sudah dikenal saat berinteraksi dengan LLM lewat chat : tanpa instruksi eksplisit untuk ringkas, ia cenderung banyak bicara, membenarkan, mengomentari, merumuskan ulang. Dalam percakapan, itu menghabiskan token keluaran. Dalam pembangkitan kode, refleks yang sama berubah menjadi baris-baris yang tinggal di repo selamanya, commit demi commit, tanpa benar-benar dibaca ulang selama kodenya berjalan.

Apa yang ditunjukkan kedua audit, berdampingan

Untuk laporan pertama : konsistensi antar-layanan menderita karena jendela konteks terlalu kecil untuk menampung seluruh repo, yang berujung pada perbaikan lokal, redundansi, dan divergensi konvensi.

Untuk yang kedua : git log --numstat menunjukkan verbositas bawaan dari LLM yang tidak dibingkai, yang menyebabkan baris dan karakter yang ditambahkan tidak proporsional serta kode yang kurang difaktorisasi.

Keduanya digabung menunjuk pada redundansi dan volume : hasilnya adalah repo yang terlalu besar untuk dipegang utuh oleh agen masa depan, yang makin memperparah masalah pertama yang diungkap audit pertama.

Baris terakhir inilah yang paling mengkhawatirkan saya saat menulis laporan : kedua masalah saling terkait, mereka saling menghidupi. Makin verbose kode yang dihasilkan, makin cepat repo membesar ; makin besar, makin tidak bisa dipegang agen dalam konteks ; makin tidak bisa dipegang dalam konteks, makin lokal dan redundan perbaikannya ; makin redundan, makin menambah volume. Lingkaran umpan balik negatif, sepenuhnya disebabkan oleh penggunaan agen tanpa pembingkaian.

Kenapa ini bukan bug sesaat dari satu alat tertentu

Tidak ada dalam diagnosis ini yang spesifik untuk satu model atau produk tertentu. Agen sejenis chat, apa pun itu, beroperasi atas apa yang diperlihatkan kepadanya di jendelanya pada saat T, dan secara bawaan menghasilkan jawaban yang selengkap dan seberalasan mungkin. Itu tepat perilaku yang diharapkan dari asisten percakapan, dan tepat perilaku yang harus dihindari untuk alat yang menulis di repo produksi. Masalahnya berasal dari ketiadaan pembingkaian antara alat dan repo : cakupan berkas yang perlu dipertimbangkan, format keluaran yang diharapkan, anggaran baris atau verbositas, kewajiban mengutip secara tepat apa yang sudah ada sebelum menulis sesuatu yang baru.

Apa yang saya ubah sejak itu

Refleks logisnya adalah memangkas drastis apa yang sudah ditulis. Secara pribadi, saya memutuskan melakukan hal lain. Audit-audit itu saya pakai untuk hal lain : memindai kode untuk menemukan code smell di dalamnya, dan memakainya untuk membatasi secara tepat di mana letak masalah sebenarnya. Ketidakkonsistenan antar-layanan, redundansi, tempat-tempat di mana jejaknya hilang, alih-alih menebak. Volume kode yang ditulis tetap signifikan sama : verbose atau tidak, ia tetap berguna kalau dipakai dengan baik. Tuasnya adalah tahu persis ke mana melihat untuk memperbaiki apa yang tidak cocok, alih-alih mencegah agen menulis.

Langkah berikutnya

Memecah repo menjadi unit-unit yang lebih kecil dan dibatasi lebih baik. Serta pagar produksi untuk eksekusi dan dokumentasi. Masalah yang muncul berikutnya adalah soal arsitektur : bagaimana menganalisis, mengkritik, dan membuat layanan, komponen, dan dokumentasi yang, sekali dipisahkan, tetap harus mengoordinasikan keputusan mereka dengan bersih tanpa kembali ke monolit yang sama seperti sebelumnya.

मैंने अपने कोड AI एजेंटों पर अंधा भरोसा करने के बजाय उनका ऑडिट किया

ट्रेडिंग प्लेटफॉर्म की चौथी तकनीकी रिपोर्ट लिखने के लिए किए दो ऑडिट ने मुझे दो अलग विचलन कैसे दिखाए : एक एजेंट जो भूलता है क्योंकि repo उसकी संदर्भ विंडो में नहीं समाता, और एक एजेंट जो जरूरत से दस गुना ज्यादा कोड लिखता है क्योंकि उसे संक्षिप्तता की ओर कुछ नहीं धकेलता।

निदान से पहले लक्षण

प्लेटफॉर्म की तकनीकी रिपोर्ट का हर संस्करण मुझे पूरी आर्किटेक्चर फिर से देखने को मजबूर करता है : सेवाएँ, एजेंट, डेटा पाइपलाइन। चौथा संस्करण तैयार करते समय repo का आयतन आखिर मेरी आँखों में चुभा, जबकि मैं उसे धीरे धीरे बढ़ता देख रहा था बिना कभी उस पर रुके : repo, जो शुरू में कुछ हजार पंक्तियों, 10ko से कम में समाता था, अब 100Mo पहुँचता है। प्लेटफॉर्म में मुश्किल से ज्यादा कार्यक्षमता थी। मैं बस Claude Chat तरह के एजेंटों पर कोड लागू और सुधारने के लिए निर्भर हो गया था, बिना सटीक तय किए कि मैं उनसे क्या माँगता हूँ और किस दायरे पर।

रिपोर्ट लिखने ने मुझे "यह आगे बढ़ रहा है" मोड से निकलकर "असल में क्या हुआ" मोड में जाने को मजबूर किया। मैंने repo इतिहास पर दो अलग ऑडिट किए। दोनों उसी कारण की ओर इशारा करते थे, दो पूरी तरह अलग कारणों से।

ऑडिट नं. 1 : संदर्भ विंडो जो झूठ बोलती है

पहले ऑडिट में कई महीनों में AI एजेंट द्वारा service दर service किए सुधार लेना और जाँचना था कि क्या वे उस समय repo के बाकी हिस्से के अनुरूप थे जब उन्हें लागू किया गया था।

बार बार लौटने वाला पैटर्न : एजेंट समस्या को स्थानीय सुधारता था, उस फाइल या मॉड्यूल में जो उसकी आँखों के सामने था, बिना repo में कहीं और समतुल्य देखे, या बिना उसे याद रखे। परिणाम : दो service में थोड़ा अलग फिर से परिभाषित वही इंटरफेस, आधा लागू नाम बदलाव क्योंकि दूसरी घटना प्रॉम्प्ट के समय संदर्भ विंडो के बाहर थी, एक मॉड्यूल में सम्मानित और अगले में नजरअंदाज नामकरण परिपाटी। अलग अलग कुछ शानदार नहीं, लेकिन दसियों सत्रों पर जमा, यह ठीक वह अतिरेक और code smells बनाता है जो उस पर चलाए अगले उपकरण का सूत्र खो देते हैं। खुद को खिलाने वाला चक्र : repo जितना बढ़ता और खंडित होता है, एजेंट के लिए उसे पूरी तरह दिमाग में रखना उतना मुश्किल होता है, सुधार उतने स्थानीय और आंशिक होते हैं, repo उतना बढ़ता है।

समस्या यह नहीं है कि एजेंट "झूठ बोलता" या गढ़ता है ; वह दिए गए संदर्भ पर पूछे प्रश्न का सही उत्तर देता है। समस्या यह है कि ज्यादातर समय, मैंने पहले से प्रश्न का दायरा कभी परिभाषित नहीं किया था। मैं "यह typo, यह व्यवहार, यह फंक्शन सुधारो" माँगता था बिना पूछे कि क्या इस bug के repo में कहीं और समतुल्य थे जो एजेंट नहीं देख सकता था।

ऑडिट नं. 2 : जब वाचालता कोड बन जाती है

दूसरा ऑडिट ज्यादा यांत्रिक था : पूरे इतिहास पर git log --numstat चलाना, प्रति commit जोड़ी पंक्तियाँ और जोड़े अक्षर जोड़ना और वितरण देखना।

जोड़ी पंक्तियों में 30 सबसे बड़े commit अकेले repo के कुल आयतन का काफी असंगत हिस्सा दर्शाते थे। व्यवस्थित रूप से, वही commit जोड़े अक्षरों में भी सबसे बड़े निकलते थे। यह पूर्वानुमेय था, सिवाय इसके कि उन commit का अक्षर/पंक्ति अनुपात सिर्फ पंक्ति संख्या से जुड़ा नहीं था : पंक्तियाँ खुद ज्यादा वाचाल थीं, फंक्शन नामों के साथ अतिरेक व्याख्यात्मक टिप्पणियाँ ज्यादा, factorize होने के बजाय दोहराए त्रुटि प्रबंधन ब्लॉक ज्यादा, docstring ज्यादा जो वही बात तीन बार फिर से कहती थीं।

यह ज्ञात व्यवहार का सीधा परिणाम है जब चैट में LLM से बातचीत की जाती है : संक्षिप्तता के स्पष्ट निर्देश के बिना, वह बहुत बोलता है, औचित्य देता है, टिप्पणी करता है, फिर से कहता है। बातचीत में, इसकी कीमत output token होती है। कोड पीढ़ी में, वही प्रवृत्ति उन पंक्तियों में बदलती है जो repo में अनिश्चित रहती हैं, commit दर commit, बिना उन्हें सच में फिर से पढ़े जब तक कोड काम करता है।

दोनों ऑडिट, साथ रखने पर, ने क्या दिखाया

पहली रिपोर्ट के लिए : अंतर service सुसंगतता पूरे repo को रखने के लिए बहुत छोटी संदर्भ विंडो से पीड़ित है, जिससे स्थानीय सुधार, अतिरेक और परिपाटी विचलन होते हैं।

दूसरे के लिए : git log --numstat बिना तय LLM की डिफ़ॉल्ट वाचालता दिखाता है, जिससे असंगत जोड़ी पंक्तियाँ और अक्षर और कम factorize कोड होता है।

दोनों मिलकर अतिरेक और आयतन की ओर इशारा करते हैं : यह ऐसा repo देता है जो इतना बड़ा है कि भविष्य का एजेंट उसे दिमाग में नहीं रख सकता, जो पहले ऑडिट से उजागर पहली समस्या को और बिगाड़ता है।

रिपोर्ट लिखते समय यही आखिरी पंक्ति मुझे सबसे ज्यादा चिंतित करती थी : दोनों समस्याएँ जुड़ी हैं, वे एक दूसरे को खिलाती हैं। उत्पन्न कोड जितना वाचाल, repo उतनी तेज बढ़ता है ; वह जितना बढ़ता है, एजेंट उसे संदर्भ में उतना कम रख सकता है ; वह उसे संदर्भ में जितना कम रख सकता है, उसके सुधार उतने स्थानीय और अतिरेक होते हैं ; वे जितने अतिरेक होते हैं, उतना आयतन जुड़ता है। पूरी तरह बिना तय एजेंट उपयोग से उत्पन्न नकारात्मक प्रतिपुष्टि लूप।

यह किसी विशेष उपकरण का छिटपुट bug क्यों नहीं है

इस निदान में कुछ भी किसी विशेष मॉडल या उत्पाद के लिए विशिष्ट नहीं है। चैट तरह का एजेंट, कोई भी हो, उस पर काम करता है जो उसे T क्षण में उसकी विंडो में दिखाया जाता है, और डिफ़ॉल्ट रूप से सबसे पूर्ण और सबसे उचित उत्तर बनाता है। ठीक बातचीत सहायक का अपेक्षित व्यवहार है, और ठीक वह जिससे production repo में लिखने वाले उपकरण के लिए बचना चाहिए। समस्या उपकरण और repo के बीच तय की अनुपस्थिति से आती है : विचार करने वाली फाइलों का दायरा, अपेक्षित output प्रारूप, पंक्ति या वाचालता बजट, कुछ नया लिखने से पहले जो पहले से मौजूद है उसे सटीक उद्धृत करने की बाध्यता।

मैंने तब से क्या बदला

तार्किक प्रवृत्ति जो लिखा गया था उसे काफी घटाना होता। व्यक्तिगत रूप से, मैंने अलग करने का फैसला किया। ऑडिट मेरे दूसरे काम आए : code smells पहचानने के लिए कोड scan करना, और असली समस्याएँ ठीक कहाँ थीं यह सटीक सीमित करने के लिए उनका उपयोग करना। अंतर service असंगतताएँ, अतिरेक, जगहें जहाँ सूत्र खो गया था, अनुमान लगाने के बजाय। लिखे कोड का आयतन काफी वही रहता है : वाचाल हो या नहीं, वह उपयोगी रहता है अगर अच्छी तरह इस्तेमाल हो। लीवर यह जानना था कि जो मेल नहीं खाता था उसे सुधारने के लिए ठीक कहाँ देखना है, बजाय एजेंट को लिखने से रोकने के।

अगले चरण

repo को छोटी और बेहतर सीमित इकाइयों में काटना। साथ ही निष्पादन और दस्तावेज के लिए production सुरक्षा। बदले में उठने वाली समस्या आर्किटेक्चर प्रश्न है : सेवाओं, घटकों और दस्तावेज का विश्लेषण, आलोचना और साफ संवाद कैसे कराया जाए जो एक बार अलग होने पर भी पहले जैसे monolithe पर लौटे बिना अपने निर्णय समन्वित करें।

دققت وكلاء الذكاء الاصطناعي للبرمجة بدلا من الوثوق بهم عميانيا

كيف كشف لي تدقيقان أجريتهما لكتابة التقرير التقني الرابع لمنصة التداول الخاصة بي انحرافين متميزين : وكيل ينسى لأن المستودع لم يعد يتسع في نافذة سياقه، ووكيل يكتب عشرة أضعاف الكود اللازم لأن لا شيء يدفعه إلى الإيجاز.

العرض قبل التشخيص

كل إصدار من التقرير التقني للمنصة يجبرني على استعراض البنية كاملة : الخدمات، والوكلاء، وخطوط البيانات. وأثناء تحضير الإصدار الرابع قفز حجم المستودع إلى عيني أخيرا، بينما كنت أراه يكبر تدريجيا دون أن أتوقف عنده أبدا : المستودع، الذي كان في الأصل بضعة آلاف من الأسطر، أقل من 10ko، بلغ الآن 100Mo. ولم تكن المنصة تملك إلا القليل من المزايا الإضافية. كنت ببساطة اعتمدت على وكلاء من نوع Claude Chat لتنفيذ الكود وتصحيحه، دون تأطير دقيق لما أطلبه منهم ولا للنطاق.

كتابة التقرير أجبرتني على الخروج من وضع "الأمور تتقدم" والعودة إلى وضع "ماذا حدث فعلا". أجريت تدقيقين منفصلين على تاريخ المستودع. كلاهما أشار إلى السبب نفسه، لسببين مختلفين تماما.

التدقيق رقم 1 : نافذة السياق التي تكذب

التدقيق الأول تمثل في استعادة، خدمة بخدمة، التصحيحات التي أجراها وكيل ذكاء اصطناعي على مدى أشهر، والتحقق مما إذا كانت متسقة مع بقية المستودع في اللحظة التي طُبقت فيها.

النمط الذي كان يتكرر باستمرار : الوكيل يصحح مشكلة محليا، في الملف أو الوحدة التي أمامه، دون أن يرى مثيلها في مكان آخر من المستودع، أو دون أن يتذكره. النتيجة : الواجهة نفسها مُعاد تعريفها بشكل مختلف قليلا في خدمتين، وإعادة تسمية مطبقة نصفيا لأن الظهور الثاني كان خارج نافذة السياق لحظة الـprompt، واتفاقية تسمية محترمة في وحدة ومتجاهلة في التالية. لا شيء مذهل إذا أُخذ بمعزل، لكنه متراكم على عشرات الجلسات، ينتج بالضبط التكرار وروائح الكود التي تجعل الأداة التالية التي نطلقها عليه تفقد الخيط. دائرة تغذي نفسها : كلما كبر المستودع وتجزأ، صار من الأصعب على الوكيل أن يحمله كاملا في ذهنه، وصارت التصحيحات أكثر محلية وجزئية، وكبر المستودع أكثر.

المشكلة ليست أن الوكيل "يكذب" أو يخترع ؛ إنه يجيب بشكل صحيح على السؤال المطروح في السياق الذي أُعطي له. المشكلة أنني، في معظم الوقت، لم أحدد أبدا نطاق السؤال مسبقا. كنت أطلب "صحح هذا الخطأ المطبعي، هذا السلوك، هذه الدالة" دون أن أسأل نفسي إن كان لهذا الخلل مثيلات في مكان آخر من المستودع لا يستطيع الوكيل رؤيتها.

التدقيق رقم 2 : عندما تصبح الثرثرة كودا

التدقيق الثاني كان أكثر آلية : تشغيل git log --numstat على التاريخ كله، وتجميع الأسطر المضافة والحروف المضافة حسب الـcommit ومراقبة التوزيع.

الـ30 commit الأكبر من حيث الأسطر المضافة كانت تمثل، وحدها، حصة غير متناسبة إلى حد كبير من الحجم الإجمالي للمستودع. وبشكل منهجي، كانت الـcommits نفسها تبرز أيضا كالأكبر من حيث الحروف المضافة. كان ذلك متوقعا، إلا أن نسبة الحروف/الأسطر في تلك الـcommits لم تكن مرتبطة فقط بعدد الأسطر : الأسطر نفسها كانت أكثر ثرثرة، مع تعليقات تفسيرية زائدة تكرر اسم الدوال، وكتل معالجة أخطاء مكررة بدلا من أن تُعمَّل، وdocstrings تعيد صياغة الشيء نفسه ثلاث مرات.

هذا هو العاقبة المباشرة لسلوك معروف عند التفاعل مع LLM في دردشة : دون تعليمات صريحة بالإيجاز، يميل إلى الكلام الكثير، والتبرير والتعليق وإعادة الصياغة. في المحادثة، يكلف ذلك رموز إخراج. وفي توليد الكود، يترجم هذا المنعكس نفسه إلى أسطر تبقى في المستودع إلى أجل غير مسمى، commit بعد commit، دون أن نعيد قراءتها فعلا ما دام الكود يعمل.

ما أظهره التدقيقان معا، جنبا إلى جنب

بالنسبة للتقرير الأول : الاتساق بين الخدمات يعاني من نافذة سياق أصغر من أن تحمل المستودع كله، مما يؤدي إلى تصحيحات محلية وتكرار وانحرافات في الاتفاقيات.

وبالنسبة للثاني : يُظهر git log --numstat ثرثرة افتراضية من LLM غير مؤطَّر، مما يسبب أسطرا وحروفا مضافة غير متناسبة وكودا قليل التعميل.

والاثنان معا يشيران إلى التكرار والحجم : وهذا يعطي مستودعا أكبر من أن يحمله وكيل مستقبلي في ذهنه، مما يفاقم أكثر المشكلة الأولى التي أبرزها التدقيق الأول.

هذا السطر الأخير هو ما أقلقني أكثر أثناء كتابة التقرير : المشكلتان مرتبطتان، وتغذي إحداهما الأخرى. كلما كان الكود المولد أكثر ثرثرة، كبر المستودع أسرع ؛ وكلما كبر، قلّت قدرة الوكيل على حمله في السياق ؛ وكلما قلّت قدرته على حمله في السياق، صارت تصحيحاته أكثر محلية وتكرارا ؛ وكلما صارت أكثر تكرارا، أضافت حجما أكثر. حلقة تغذية راجعة سلبية، سببها بالكامل استخدام وكلاء دون تأطير.

لماذا ليست خللا عابرا في أداة بعينها

لا شيء في هذا التشخيص خاص بنموذج أو منتج بعينه. أي وكيل من نوع الدردشة، أيا كان، يعمل على ما نعرضه عليه في نافذته في اللحظة T، ويولد افتراضيا الإجابة الأكثر اكتمالا وتبريرا الممكنة. هذا هو بالضبط السلوك المتوقع من مساعد محادثة، وهو بالضبط ما يجب تجنبه لأداة تكتب في مستودع إنتاج. المشكلة تأتي من غياب التأطير بين الأداة والمستودع : نطاق الملفات الواجب اعتبارها، وصيغة الإخراج المتوقعة، وميزانية الأسطر أو الثرثرة، وإلزام الاستشهاد الدقيق بما هو موجود فعلا قبل كتابة أي شيء جديد.

ما غيرته منذ ذلك الحين

كان المنعكس المنطقي هو تقليص ما كُتب بشكل جذري. شخصيا، قررت فعل شيء آخر. التدقيقان خدماني في شيء آخر : مسح الكود لالتقاط روائح الكود فيه، واستخدامه لتحديد بدقة أين كانت المشاكل الحقيقية. عدم الاتساق بين الخدمات، والتكرارات، والأماكن التي ضاع فيها الخيط، بدلا من التخمين. حجم الكود المكتوب يبقى نفسه إلى حد كبير : ثرثارا أم لا، يبقى مفيدا إذا استُخدم جيدا. وكانت الرافعة هي معرفة أين ننظر بدقة لتصحيح ما لم يكن متسقا، بدلا من منع الوكيل من الكتابة.

الخطوات التالية

تقسيم المستودع إلى وحدات أصغر وأفضل تحديدا. بالإضافة إلى حواجز حماية للإنتاج للتنفيذ والتوثيق. والمشكلة التي تطرح بدورها هي مسألة بنية : كيف نحلل وننتقد الخدمات والمكونات والتوثيق التي، بمجرد فصلها، يجب أن تنسق قراراتها بشكل نظيف دون العودة إلى نفس الـmonolithe السابق.

Tôi đã kiểm toán các tác nhân AI lập trình của mình thay vì tin chúng một cách mù quáng

Cách hai cuộc kiểm toán thực hiện để viết báo cáo kỹ thuật lần thứ 4 của nền tảng giao dịch của tôi đã cho tôi thấy hai xu hướng lệch lạc khác nhau: một tác nhân quên vì repo không còn vừa trong cửa sổ ngữ cảnh của nó, và một tác nhân viết nhiều gấp mười lần số mã cần thiết vì không có gì thúc nó ngắn gọn.

Triệu chứng trước chẩn đoán

Mỗi lần xuất bản báo cáo kỹ thuật của nền tảng đều bắt tôi phải duyệt lại toàn bộ kiến trúc: dịch vụ, tác nhân, pipeline dữ liệu. Khi chuẩn bị ấn bản lần thứ 4, khối lượng repo cuối cùng đã đập vào mắt tôi, trong khi tôi đã thấy nó phình ra dần mà không bao giờ dừng lại nhìn kỹ: repo này ban đầu chỉ vài nghìn dòng, chưa tới 10ko, giờ đã đạt 100Mo. Nền tảng hầu như không có thêm tính năng nào. Tôi chỉ đơn giản dựa vào các tác nhân kiểu Claude Chat để triển khai và sửa mã, mà không định rõ chính xác tôi yêu cầu chúng điều gì hay trên phạm vi nào.

Viết báo cáo buộc tôi thoát khỏi chế độ "cứ tiến lên" để chuyển sang chế độ "chuyện gì thực sự đã xảy ra". Tôi đã thực hiện hai cuộc kiểm toán riêng biệt trên lịch sử repo. Cả hai đều chỉ về cùng một nguyên nhân, vì hai lý do hoàn toàn khác nhau.

Kiểm toán số 1: cửa sổ ngữ cảnh nói dối

Kiểm toán đầu tiên là xem lại, dịch vụ theo dịch vụ, các bản sửa mà một tác nhân AI đã làm trong nhiều tháng, và kiểm tra xem chúng có nhất quán với phần còn lại của repo tại thời điểm áp dụng hay không.

Môtíp cứ lặp lại: tác nhân sửa một vấn đề cục bộ, trong tệp hoặc mô-đun ngay trước mắt nó, mà không hề thấy chỗ tương đương ở nơi khác trong repo, hoặc không nhớ ra. Kết quả: cùng một interface được định nghĩa lại hơi khác nhau trong hai dịch vụ, một lần đổi tên chỉ áp dụng một nửa vì lần xuất hiện thứ hai nằm ngoài cửa sổ ngữ cảnh tại thời điểm prompt, một quy ước đặt tên được tôn trọng trong mô-đun này và bị bỏ qua ở mô-đun kế tiếp. Không có gì ngoạn mục khi nhìn riêng lẻ, nhưng cộng dồn qua hàng chục phiên, nó tạo ra đúng sự dư thừa và code smell khiến công cụ tiếp theo chạy lên đó mất dấu. Một vòng tròn tự nuôi: repo càng phình và phân mảnh, tác nhân càng khó giữ toàn bộ trong đầu, các bản sửa càng cục bộ và manh mún, repo càng phình.

Vấn đề không phải là tác nhân "nói dối" hay bịa đặt; nó trả lời đúng câu hỏi được đặt ra trên ngữ cảnh được đưa cho nó. Vấn đề là phần lớn thời gian tôi chưa bao giờ định nghĩa trước phạm vi của câu hỏi. Tôi yêu cầu "sửa lỗi chính tả, hành vi, hàm này" mà không tự hỏi liệu lỗi đó có phiên bản tương đương ở nơi khác trong repo mà tác nhân không thể thấy hay không.

Kiểm toán số 2: khi sự dài dòng biến thành mã nguồn

Kiểm toán thứ hai mang tính cơ học hơn: chạy git log --numstat trên toàn bộ lịch sử, cộng dồn số dòng thêm vào và số ký tự thêm vào theo commit rồi nhìn phân bố.

30 commit lớn nhất về số dòng thêm vào, tự chúng đã chiếm một phần quá lớn trong tổng khối lượng repo. Luôn là đúng những commit đó cũng nổi lên là lớn nhất về số ký tự thêm vào. Điều này dễ đoán, chỉ có điều tỷ lệ ký tự/dòng của những commit đó không chỉ liên quan tới số dòng: bản thân các dòng cũng dài dòng hơn, với nhiều comment giải thích dư thừa so với tên hàm, nhiều khối xử lý lỗi trùng lặp thay vì được tách ra, nhiều docstring diễn đạt lại cùng một điều ba lần.

Đó là hậu quả trực tiếp của một hành vi quen thuộc khi tương tác với LLM qua chat: nếu không có chỉ dẫn ngắn gọn rõ ràng, nó có xu hướng nói nhiều, biện minh, comment, diễn đạt lại. Trong hội thoại, việc đó tốn token đầu ra. Trong sinh mã, cùng phản xạ đó biến thành những dòng nằm lại trong repo vô thời hạn, commit này qua commit khác, mà không ai đọc lại thật sự chừng nào mã còn chạy.

Khi đặt hai cuộc kiểm toán cạnh nhau, chúng cho thấy điều gì

Đối với báo cáo đầu tiên: tính nhất quán giữa các dịch vụ chịu thiệt vì cửa sổ ngữ cảnh quá nhỏ để chứa toàn bộ repo, dẫn tới các bản sửa cục bộ, dư thừa và lệch quy ước.

Đối với báo cáo thứ hai: git log --numstat cho thấy sự dài dòng mặc định của một LLM không được định hướng, gây ra số dòng và ký tự thêm vào quá lớn và mã ít được tách gọn.

Cả hai gộp lại chỉ ra sự dư thừa và khối lượng: điều này tạo ra một repo quá lớn để một tác nhân tương lai giữ trong đầu, làm trầm trọng thêm vấn đề đầu tiên mà kiểm toán thứ nhất đã nêu.

Chính dòng cuối này khiến tôi lo nhất khi viết báo cáo: hai vấn đề liên kết với nhau, chúng nuôi lẫn nhau. Mã sinh ra càng dài dòng, repo phình càng nhanh; càng phình, tác nhân càng khó giữ trong ngữ cảnh; càng khó giữ trong ngữ cảnh, các bản sửa càng cục bộ và dư thừa; càng dư thừa, khối lượng càng tăng. Một vòng phản hồi tiêu cực, hoàn toàn do dùng tác nhân mà không định hướng.

Vì sao đây không phải lỗi nhất thời của một công cụ cụ thể

Không có gì trong chẩn đoán này đặc thù cho một mô hình hay sản phẩm nào. Một tác nhân kiểu chat, dù là loại nào, cũng vận hành trên những gì người ta cho nó thấy trong cửa sổ tại thời điểm T, và mặc định sinh ra câu trả lời đầy đủ và có lý lẽ nhất có thể. Đó chính xác là hành vi mong đợi của một trợ lý hội thoại, và chính xác là điều cần tránh ở một công cụ viết vào repo production. Vấn đề nằm ở chỗ thiếu định hướng giữa công cụ và repo: phạm vi tệp cần xem xét, định dạng đầu ra mong đợi, ngân sách dòng hay mức dài dòng, nghĩa vụ trích dẫn chính xác những gì đã tồn tại trước khi viết thêm điều mới.

Những gì tôi đã thay đổi từ đó

Phản xạ logic lẽ ra là cắt giảm mạnh những gì đã viết. Cá nhân tôi quyết định làm khác. Các cuộc kiểm toán giúp tôi làm việc khác: quét mã để tìm code smell, và dùng chúng để khoanh vùng chính xác vấn đề thực sự nằm ở đâu. Những chỗ không nhất quán giữa các dịch vụ, những chỗ dư thừa, những nơi mất dấu, thay vì đoán mò. Khối lượng mã viết ra về cơ bản vẫn giữ nguyên: dài dòng hay không, nó vẫn hữu ích nếu được dùng đúng. Đòn bẩy là biết chính xác nhìn vào đâu để sửa những chỗ chưa khớp, thay vì ngăn tác nhân viết.

Bước tiếp theo

Chia repo thành các đơn vị nhỏ hơn và được giới hạn rõ hơn. Cùng với đó là các chốt chặn production cho thực thi và tài liệu. Vấn đề đặt ra tiếp theo là một câu hỏi kiến trúc: làm sao phân tích, phê bình và cho các dịch vụ, thành phần và tài liệu giao tiếp sạch sẽ với nhau, khi một khi tách ra chúng vẫn phải phối hợp quyết định mà không quay lại cùng một khối monolith như trước.

>-

>-

อาการก่อนการวินิจฉัย

แต่ละฉบับของรายงานทางเทคนิคของแพลตฟอร์มทำให้ฉันต้องเดินตามสถาปัตยกรรมทั้งหมด: บริการ ตัวแทน กระบวนการข้อมูล ฉันได้เตรียมฉบับที่ 4 แล้ว ขนาดของคลังข้อมูลก็ทำให้ฉันตื่นตระหนก เพราะฉันได้เห็นมันเพิ่มขึ้นอย่างช้า ๆ ปรากฏว่าเกิดขึ้นอย่างต่อเนื่องโดยไม่มีจุดที่จะหยุด: คลังข้อมูลที่ครั้งแรกมีเพียงไม่กี่พันบรรทัด ไม่เกิน 10 ko ตอนนี้ได้ไปถึง 100 Mo แพลตฟอร์มก็มีฟังก์ชันเพียงเล็กน้อย ฉันก็เพียงพึ่งพาตัวแทนประเภท Claude Chat เพื่อสร้างและแก้ไขโค้ดโดยไม่ได้กำหนดรายละเอียดที่ฉันขอแต่ละอันหรือขอบเขตของงาน

การเขียนรายงานทำให้ฉันต้องออกจากโหมด “มันค่อย ๆ พัฒนา” ไปสู่โหมด “เกิดอะไรขึ้นจริง ๆ” ฉันทำการตรวจสอบสองครั้งบนประวัติของคลังข้อมูล ทั้งสองพบสาเหตุเดียวกัน แต่ด้วยเหตุผลที่ต่างกันอย่างเต็มเปี่ยม

ตรวจสอบครั้งที่ 1: หน้าต่างบริบทที่โกหก

การตรวจสอบครั้งแรกนั้นทำโดยอ้างอิงตามบริการหนึ่งต่อหนึ่งถึงการแก้ไขที่ทำโดยตัวแทน AI ในหลายเดือน และตรวจสอบว่ามันสอดคล้องกับส่วนอื่นของคลังข้อมูลในเวลาที่นำเข้าไหม

รูปแบบที่กลับมาเรื่อย ๆ : ตัวแทนจะแก้ไขปัญหาในระดับพื้นที่โดยตรง, ในไฟล์หรือโมดูลที่มองเห็นอยู่, โดยไม่เห็นความเทียบเท่าในส่วนอื่นของ repo หรือไม่จำได้ ผลลัพธ์ : อินเทอร์เฟซเดียวกันถูกกำหนดใหม่ด้วยความแตกต่างเล็ก ๆ ในสองบริการ, การเปลี่ยนชื่อถูกนำมาใช้ครึ่งหนึ่งเพราะครั้งที่สองอยู่ข้างนอกขอบเขตบริบทในเวลาตัวแจ้ง, การกำหนดชื่อที่ถูกปฏิบัติตามในโมดูลหนึ่งและถูกละเลยในโมดูลถัดไป. ไม่มีอะไรโดดเด่นเมื่อดูแยก ๆ, แต่ถ้ารวมกันในหลาย ๆ เซสชันจะสร้างความซ้ำซ้อนและกลิ่นร้ายของโค้ดที่ทำให้เครื่องมือถัดไปเสียน้ำหนักเมื่อเราทำงานกับมัน วงจรที่มีการทำงานตนเอง : เมื่อ repo เติบโตและแยกย่อยขึ้น, จึงยากขึ้นสำหรับตัวแทนที่จดจำทั้งหมด, การแก้ไขจึงเป็นเฉพาะท้องถิ่นและบางส่วน, repo ก็เติบโตขึ้น

ปัญหาไม่ได้เป็นว่าตัวแทน "โกหก" หรือประดิษฐ์; อันนี้ตอบคำถามอย่างถูกต้องตามบริบทที่มีให้. ปัญหาคือฉันมักไม่เคยกำหนดขอบเขตของคำถามล่วงหน้า. ฉันจะขอ “

Le deuxième audit était plus mécanique : faire tourner un git log --numstat sur tout l'historique, agréger lignes ajoutées et caractères ajoutés par commit et regarder la distribution.

Les 30 plus gros commits en lignes ajoutées représentèrent, à eux seuls, une part largement disproportionnée du volume total du repo. Systématiquement, les mêmes commits ressortaient aussi comme les plus gros en caractères ajoutés. C'était prévisible, sauf que le ratio caractères/lignes de ces commits-là n'était pas seulement lié au nombre de lignes : les lignes elles-mêmes étaient plus verbeuses, avec plus de commentaires explicatifs redondants avec le nom des fonctions, plus de blocs de gestion d'erreurs dupliqués au lieu d'être factorisés, plus de docstrings qui reformulaient trois fois la même chose.

C'est la conséquence directe d'un comportement connu quand on interagit avec un LLM en chat : sans consigne explicite de concision, il a tendance à beaucoup parler, à justifier, commenter, reformuler. En conversation, cela coûte des tokens de sortie. En génération de code, ce même réflexe se traduit en lignes qui restent dans le repo indéfiniment, commit après commit, sans qu'on les relise vraiment tant que le code fonctionne.

Ce que les deux audtis, mis côte à côte, ont montré

Pour le premier rapport : la cohérence inter-services souffre d'une fenêtre de contexte trop petite pour tenir tout le repo, ce qui entraîne des corrections locales, des redondances et des divergences de conventions.

Pour le second : git log --numstat montre une verbosité par défaut d'un LLM non cadré, ce qui cause des lignes et caractères ajoutés disproportionnés et un code peu factorisé.

Les deux réunis pointent la redondance et le volume : cela donne un repo trop gros pour qu'un futur agent le tienne en tête, ce qui aggrave encore le premier problème mis en évidence par le premier audit.

C'est cette dernière ligne qui m'a le plus inquiété en écrivant le rapport : les deux problèmes sont liés, ils se nourrissent l'un l'autre. Plus le code généré est verbeux, plus le repo grossit vite ; plus il grossit, moins un agent peut le tenir en contexte ; moins il peut le tenir en contexte, plus ses corrections sont locales et redondantes ; plus elles sont redondantes, plus cela ajoute de volume. Une boucle de rétroaction négative, entièrement causée par une utilisation d'agents sans cadrage.

Pourquoi ce n'est pas un bug ponctuel d'un outil précis

ไม่มีสิ่งใดในการวินิจฉัยนี้ที่เฉพาะเจาะจงกับโมเดลหรือผลิตภัณฑ์บางตัวอย่างหนึ่ง
ตัวแทนประเภทแชทไม่ว่าจะเป็นแบบไหนก็จะดำเนินการบนสิ่งที่ให้มาพบในหน้าต่างของตัวเองในเวลาปัจจุบัน และจะสร้างคำตอบที่ครอบคลุมที่สุดและชวนมีเหตุผลมากที่สุดตามค่าเริ่มต้น นี่คือพฤติกรรมที่คาดหวังจากผู้ช่วยสนทนาอย่างแท้จริง และก็เป็นพฤติกรรมที่ควรหลีกเลี่ยงสำหรับเครื่องมือที่เขียนใน repo ของการผลิต ปัญหามาจากการขาดการกำหนดขอบเขตระหว่างเครื่องมือและ repo: ขอบเขตของไฟล์ที่ควรพิจารณา รูปแบบผลลัพธ์ที่คาดหวัง งบประมาณของบรรทัดหรือความยาว การบังคับให้อ้างอิงอย่างชัดเจนสิ่งที่มีอยู่ก่อนหน้านี้ก่อนเขียนสิ่งใหม่

สิ่งที่ฉันเปลี่ยนแปลงตั้งแต่นั้นไป

ปฏิกิริยาแบบมีเหตุผลอาจจะลดข้อความที่เขียนอยู่ลงอย่างรุนแรง แต่ผมตัดสินใจทำในรูปแบบที่แตกต่าง audits ได้ช่วยผมในเรื่องอื่น: สแกนโค้ดเพื่อหาซึ่งสัญชาปัญหา (code smells) แล้วใช้มันในการกำหนดขอบเขตอย่างชัดเจนว่าปัญหาจริงๆ อยู่ที่ไหน ความไม่ตรงกันระหว่างเซอร์วิส การซ้ำซ้อน จุดที่เรื่องมีการเลี้ยวคลื่นลายค้ายกเลิกมากกว่าการเดา ปริมาณโค้ดที่เขียนยังคงอยู่ในระดับที่สำคัญ: verbose หรือไม่ verbose มันยังคงมีประโยชน์ถ้ามีการใช้งานอย่างถูกต้อง จุดดังคือความชัดเจนว่าต้องมองหาเพื่อแก้ไขอย่างไรจะไม่ตรง อีกอย่างหนึ่งคือไม่ต้องปฏิเสธให้เอเย่นต์เขียน

ขั้นตอนถัดไป

การแบ่งแยกรีโพเป็นหน่วยเล็ก ๆ และชัดเจนขึ้น รวมถึงเข็มขัดปลอดภัยในการผลิตสำหรับการดำเนินการและเอกสารปัญหาที่เกิดขึ้นตามลำดับเป็นเรื่องของสถาปัตยกรรม : วิธีวิเคราะห์ วิจารณ์ และทำให้บริการ ส่วนประกอบ และเอกสารสื่อสารกันอย่างสะอาด เมื่อถูกรวมแยกออก ปัจจุบันยังคงต้องประสานการตัดสินใจของตนโดยไม่ต้องกลับไปสู่โมโนลิธเดิมที่เคยมีอยู่.

Related Articles