拓冰建站拓冰建站
首页 / 资讯中心 / 正文

AI写代码怕幻觉?用Ledgerful给代码建本地账本

习惯用 AI 写代码之后我最怕的不是 AI 写不出代码而是它写出看起来完全合理、实际纯属虚构的代码。Claude Code、Cursor 这类工具一旦进入“自动完成”模式经常会在小函数里补一个根本不存在的配置项在调用接口时编一个从未出现过的参数甚至在注释里信誓旦旦地写“这里会自动重试三次”而底下那个方法压根没有重试逻辑。这种情况多了之后我对 AI 生成结果的信任方式发生了变化不是不让它写而是得有办法知道它刚才到底写了什么、在哪一步引入了可疑内容。Ledgerful 就是围绕这个需求出现的本地工具思路。它解决的核心问题不是“防止 AI 生成故障代码”而是“当 AI 在代码里发明东西时能把它记下来方便人回到现场去查”。适合的人群很明确经常让 AI 写代码、但又不放心直接提交的开发者以及想要在团队内建立 AI 代码审查机制的负责人。相比一整套复杂的 CI 流水线这类工具最大的价值是把“AI 幻觉”从模糊的直觉变成可以检索的记录。下面我按实际使用顺序把这个工具的定位、实现思路、验证方法和落地边界完整拆一遍。1. AI 写的代码为什么容易“一本正经地胡说八道”先得把问题说清楚不然很容易把 Ledgerful 理解成一个普通的“代码检查工具”。1.1 代码幻觉的三种常见表现我遇到过的 AI 编造代码问题基本可以归为三类。第一类是调用不存在的 API。模型在训练时见过很多类似的 SDK但记不清具体版本于是把某个旧版本方法名和另一个新版本模块拼在一起。你看着眼熟一运行直接AttributeError。如果是 Python 这种动态语言有时候连错误都延迟到运行时才暴露。第二类是引用不存在的文件或路径。比如 AI 在项目中生成了import data_utils但实际目录里根本没有这个模块或者在配置里写了一个models/weights.bin这个文件根本不存在。这类问题在本地开发时很容易被发现但放到 CI 里就是莫名其妙的失败。第三类比较隐蔽它给一段代码写了一长串解释性质的内容包括注释、日志、错误信息内容本身没有问题但对应逻辑并不存在。我在实际项目里见过 AI 在函数里加了# retry up to 3 times然后完全没写重试循环也见过它生成一个错误处理分支里面抛出的异常类型在代码库中根本找不到。这三种情况有一个共同点只要编译器不报错、测试用例没覆盖到它们就很难被发现。1.2 为什么编译通过不等于没有幻觉很多人在刚使用 AI 编程工具时会把“能跑”当成“没问题”。但代码能不能跑和代码是不是真实可靠是两个完全不同的概念。编译通过只能说明语法结构正确类型上基本兼容。但 AI 真正爱编造的是“业务语义”比如它写了一个get_user_statistics方法内部使用了一个UserAnalytics类这个类如果只存在于模型权重里不一定会立刻报错可能在某个参数组合下才会崩溃。更麻烦的是有些幻觉不是单点错误而是被 AI“自然补齐”的。代码里本来就有一个handle_payment的占位函数AI 看到之后自动补了verify_signature但项目里根本没有签名校验工具它也不会报编译错误因为最终的返回类型还是符合预期的。所以我一直认为对待 AI 生成的代码最重要的习惯不是“只看测试结果”而是建立一个“来源意识”这段代码来自哪个会话、基于什么上下文生成、有没有引用到不存在的符号。1.3 这类问题在什么项目里最容易翻车根据我的实际经验AI 代码幻觉在以下场景里特别致命。多语言混合项目容易翻车。AI 在 TypeScript 和 Python 之间来回生成很容易把两边生态里的包名搞混。比如在 Python 项目里建议你安装一个 JavaScript 风格的库名或者在 TS 类型声明里写了一个 Python-only 的对象结构。依赖不清晰的项目容易翻车。项目如果长期靠“运行一下缺什么装什么”来维护AI 就会觉得任何包都存在。它不会主动确认requirements.txt里有没有httpx不会检查package.json里有没有axios只会照着常见的库名生成代码。还有一个容易被忽略的场景大量使用动态特征的代码库。反射、字符串拼接调用、动态 import、宏、代码生成器这些功能本身很强大但也会让 AI 编造的内容更难被静态捕捉。Ledgerful 要想发挥作用恰恰需要对这些场景做专门设计。2. Ledgerful 的核心设计给 AI 输出建立本地账本从标题可以看出Ledgerful 这个工具的关键词是“ledger”也就是账本。它不把自己定位成一个“AI 代码拦截器”而是一个“AI 代码记账本”。2.1 账本记录什么代码、上下文、来源、改动时间真正落地的时候账本至少需要记录以下几类信息。第一代码变更本身。不能只记一个文件名和行号要记录完整的 diff包括 AI 新增了什么、删除了什么、改写了什么。这些信息是后续复核的基础。第二AI 生成这段代码时的上下文。比如用户输入了什么提示词、使用了哪个模型、当时打开了哪些文件、上下文窗口里包含了哪些相关代码。这些信息可以帮助判断“AI 是不是因为受到某个旧文件的误导才造出了新名字”。第三来源标记。如果代码完全由 AI 生成标记为ai_generated如果人类在 AI 生成之后做了修改要标记为ai_edited如果代码本来就在项目里只是被 AI 引用则标记为project_existing。这三种来源的审查优先级完全不一样。第四改动时间。记录什么时间生成了、什么时间被修改、什么时间被提交。这个在多人协作时尤其重要你能看出来一个疑似幻觉的符号是不是又被另一个开发者不小心继承了下去。2.2 本地运行到底解决了什么这个工具强调“local”我是很认同的。代码如果不能离开本机那审计逻辑就必须在本地完成。本地运行有一个很实际的好处可以把完整的代码库索引放在本地不需要担心把私有代码片段上传到某个服务。很多团队不愿意让 AI 编程工具把所有代码发送到云端其中一个原因就是害怕内部 API 名、表结构、业务路由被第三方模型记住。Ledgerful 这类工具的本地化设计正好补上了这一环。另外本地运行还能降低审计的延迟。它不需要网络请求不需要等待模型返回直接基于文件系统、Git 历史和静态分析结果生成报告。我在测试时发现稳定的本地索引比云端服务更适合高频调用。当然本地运行也有代价模型知识库更新需要自己维护。如果项目里新增了一个外部 SDKLedgerful 不会像联网服务那样自动知道需要你把新的 API 声明或依赖信息更新进去。这一点在后面实现方案里会详细说。2.3 从“拦代码”到“查记录”到底改变了什么传统代码检查工具的思路是“发现问题就阻止提交”。ESLint、类型检查、单测都属于这一层。它们确实重要但面对 AI 生成内容时有一个漏洞AI 很可能生成一套风格完全规范、语法完全正确、但引用了不存在的对象的代码。这种代码能通过所有形式校验。Ledgerful 的思路是换一个方向我不直接阻止你但我把生成链条记录清楚。它更像监控摄像头而不太像保安。保安会拦人摄像头会帮你复盘到底发生过什么。这个区别在协作时特别重要。你可以做一次 diff review看看 AI 新增的代码里是不是出现了一个奇怪的名字你可以查账本看看这个名字是不是只存在于某个很旧的会话里后来所有引用都来自 AI 的“记忆”。有了记录审查就不再依赖“凭感觉觉得哪里不对”。3. 一个可复现的本地实现方案由于 Ledgerful 本身是开发者自建工具公开的材料里没有完整源码所以这里我给出一个可复现的实现思路。它不复杂适合在个人项目里动手验证也适合当作团队基础工具去扩展。3.1 整体流程输入、解析、比对、告警我建议把整个工具拆成四个阶段这样每一步都能独立验证出了问题也好排查。第一阶段是采集。监听 Git 事件或者直接扫描指定目录下的文件改动。当检测到 AI 工具生成或修改了代码就把对应的文件内容、时间戳、会话标识记录下来。如果没有办法直接对接 Claude Code 或 Cursor 的日志最简单的方式是把 diff 作为输入源通过git diff拿到精确变更。第二阶段是解析。将代码字符串解析成抽象语法树提取函数名、类名、导入语句、调用关系、变量引用。这里建议用 tree-sitter不需要为每一种语言单独写正则既能处理语法错误也能在坏代码上继续解析。第三阶段是对比。把提取出来的符号分别放到两个名单里比对一个名单是项目内部确实存在的符号另一个名单是外部依赖提供的已知 API。如果代码中引用了某个符号但两个名单里都找不到就会触发“可疑符号”告警。第四阶段是输出。把所有告警整理成报告标注出问题类型、代码位置、上下文、严重级别。报告可以输出为 JSON、Markdown也可以直接打印到终端。3.2 用伪代码描述核心检测逻辑下面这个伪代码对应第三阶段的核心逻辑不绑定具体语言大家可以根据自己的项目改写。# 伪代码示例用于说明 Ledgerful 的核心检测流程 def analyze_diff(diff, project_index): findings [] # 提取变更后代码中的符号引用 symbols extract_symbols(diff.added_code) for sym in symbols: # 跳过原生语言自带的关键字和内建函数 if sym in LANGUAGE_BUILTINS: continue known project_index.is_known_symbol(sym) if not known: findings.append({ symbol: sym, line: sym.line_number, origin: ai_generated, level: warning, reason: symbol_not_found_in_project_or_dependencies }) return findings这个逻辑虽然是原型级别但效果已经比直接肉眼 review 好很多。它能把 AI 编造的符号名全部挑出来尤其是那种看起来像真的、实际上从未出现的类方法。3.3 需要维护哪些知识库和规则想让这个工具真正可用不能只靠一个内置名单。知识库要分三层维护。第一层是项目内部符号表。用 AST 解析器扫描整个代码库把所有的函数、类、变量、导出符号记录到 SQLite 或 JSON 里。这个表要随着项目更新建议在每次git commit后自动重建一次。第二层是外部依赖 API 表。根据requirements.txt、package.json、go.mod等文件把依赖清单记录下来。理想情况下还能通过包管理器拿到安装后的真实符号比如pip show或npm list。如果没有这个表工具就无法判断openai.OpenAI()到底是不是一个真实存在的类。第三层是用户自定义允许名单。项目里经常会有一些动态生成的符号比如eval()里拼接出来的函数名、代码生成器产生的类。这些不在 AST 静态扫描结果里但如果项目中明确就是故意使用就应该放入 allowlist避免每次提交都被误报。除了这些还可以配置规则引擎比如“不检查测试目录”“不检查第三方生成的 migrations”“超过 50 行的 AI 生成代码必须人工审核”。注意第一个版本不要把所有误报都当成工具 Bug。大多数误报来自知识库维护不完整而不是检测逻辑有问题。4. 能不能抓到真问题验证方法与验收标准工具写出来之后最需要做的不是直接拿真实项目试而是先造一个能稳定触发幻觉的测试样本。这样才能判断它到底有没有用。4.1 先造一个已知幻觉样本我在本地测试时准备了一个最小的 Python 项目结构大概是这样demo_project/ app.py utils.py requirements.txt然后我让 Claude Code 在app.py里调用一个不存在的load_config函数并引入一个实际上不在requirements.txt里的库magic_loader。同时让 AI 写代码时不要主动检查这些依赖故意模拟最真实的“幻觉生成”。跑完 Ledgerful 之后我需要看到两类告警符号load_config在项目内部符号表中不存在。符号magic_loader既不在项目源码中也不在依赖清单里。如果这两条都能报出来说明工具的主链路是通的。如果只报出一个说明某个阶段的解析或对比逻辑还需要修。我建议你测试的时候不要只测一个幻觉样本。至少准备三组引用不存在的模块。调用不存在的方法。使用了不存在但看起来合理的配置项或常量。这三类覆盖了 AI 编造代码最常见的形态也分别对应导入解析、方法解析和属性解析三条检测分支。4.2 看结果时不光看告警还要看误报和漏报很多人验证工具时只看“有没有报出来”这还不够。真正要评估的是两点误报率和漏报率。漏报率比误报率更可怕。如果一个 AI 编造的符号没有被工具检测到那它就会带着“工具已经检查过了”的安全感进入代码库反而可能造成更大的问题。所以要把上面造出来的幻觉样本随机混入一段正常代码里确保每次都能报出来才算过了第一关。误报率则决定工具能不能长期用。如果每次跑都报一堆实际上存在但工具不认识的符号开发者会很快关闭这个检查。我建议用真实项目做一次回归统计告警总数里有多少其实是误报目标是把误报控制在 20% 以内否则不太可能有耐心天天使用。判断标准的参考表可以这样列维度不好可以接受建议漏掉幻觉符号经常漏核心样本不漏保持核心样本持续回归误报比例超过 40%20% 左右完善知识库和 allowlist处理速度跑一次超过 5 分钟1 分钟内增量扫描不每次全量重建报告可读性只有符号名没有位置有行号、来源、原因支持 Markdown / JSON 输出4.3 判断工具是否值得进入日常流程如果只靠一个原型工具并不建议立刻接入到正式的 pre-commit hook 里。更好的方式是先在 daily review 阶段作为参考报告使用跑一周看看它对代码审查的作用。我自己的判断标准有三个。第一它能不能帮你发现至少一个“没有它就会漏掉”的问题。如果它报出来的所有内容你肉眼都能立刻看到那工具价值不大。但如果它能捕捉到那些藏在长文件、复杂调用链里的可疑符号就值得继续用。第二它能不能帮你节省时间。报告里如果真的存在大量可以跳过的告警时间反而会花在筛报告上。这时需要调整规则让告警更聚焦。第三它能不能成为团队统一的代码来源依据。如果所有人的 AI 生成代码都能进入账本后面任何一次代码审查、Bug 回溯都可以从账本里找到“这个函数是 AI 编的还是人写的”这个价值是长期的。5. 实际落地中的边界与排查顺序Ledgerful 确实能解决一部分问题但它不是银弹更不是“装上就安全”。有必要把边界条件也讲清楚。5.1 哪些场景不适合依赖 Ledgerful整个工具建立在“代码库本身是可靠的”这个前提上。如果项目里已经大量使用代码生成器、模板渲染、动态执行、宏展开那 AST 扫描结果和运行时实际情况会有很大偏差误报会很多检测价值也会下降。动态类型特别严重的项目也要谨慎。Python 里getattr(obj, method_name)这种写法运行时才知道方法名Ledgerful 在静态分析阶段很难判断method_name是不是真实存在。它可以标记为“需要人工确认”但不太可能做到精确告警。另一个边界是 AI 生成的纯数据片段。如果 AI 在 JSON、SQL、YAML、Markdown 里编造了一个字段名或表名它不会像代码符号那样容易被 AST 识别。比如它写了一个查询语句select user_name from users但表里根本没有user_name字段这需要另做一层 SQL 字段校验。这就是为什么我说Ledgerful 只能作为“代码幻觉检测器”的第一层而不是完整方案。5.2 报告异常时先查日志、规则还是知识库当你发现 Ledgerful 漏报了一个应该被标记的符号先不要急着改检测规则。排查顺序很重要。第一先看采集日志确认这次代码变更有没有被工具捕获。如果git diff解析时因为文件过大、二进制文件、编码问题而跳过那检测逻辑再强也没用。第二再看解析结果确认那个符号是不是真的被提取到了。如果是字符串拼接产生的符号比如get_ method_name解析器可能确实提取不到。这种情况不是规则 Bug而是机制限制。第三检查知识库。我遇到的大部分漏报原因都是项目依赖列表没有更新。新装了一个包之后工具仍然认为那个 API 不存在但实际上是依赖表过期。先把update_index跑一遍再复测。第四最后才考虑规则配置问题。如果前面三层都没有问题仍然漏报说明检测规则需要增加一条分支比如新增“允许访问类内部私有方法”或“允许 untyped 的全局变量”。5.3 和现有 CI / Code Review 怎么配合我不建议让 Ledgerful 直接拦截提交。更合理的配合方式是在 CI 里生成一份ai-ledger-report.json或 Markdown 报告提交到 PR 下方供 reviewer 参考。在 Code Review 阶段把“AI 生成的代码”和“人类手写的代码”用来源标签区分开。AI 生成的代码需要额外确认一次不是不信任而是因为生成过程没有人类的主观约束。在每日开发记录里保留账本作为后续定位问题的索引。这样它不会变成一道让人烦躁的“机械门禁”而更像一个审计员在背后默默记录所有变更痕迹。等你真的需要回溯一个问题时它的价值会成倍放大。注意接入 CI 时建议先跑一周“观察模式”只报告不阻塞。不要第一天就连到主分支提交检查上否则大概率会因为历史遗留符号产生大量告警大家都不愿意用了。6. 我的实操建议到这里工具怎么设计、怎么验证、怎么排查都讲完了。最后给几条更偏经验和习惯层面的建议希望对真正想落地 Ledgerful 的人有帮助。6.1 从单项目、单语言开始不要一开始就想做一个覆盖全公司、支持十种语言的检查平台。最稳的做法是挑一个自己最熟悉的业务项目用 Python 或 TypeScript 作为第一支持语言跑通完整链路AI 生成代码 - 记录变更 - 解析 AST - 生成报告 - 人工复核。单项目的好处是你不需要维护庞大的知识库。内部符号几百个外部依赖几十个手动整理也能完成。等稳定后再慢慢扩展第二语言。6.2 把告警分级不要一刀切如果所有可疑符号都标成红色开发者看三天就会麻木。建议把告警分成三类高风险引用了完全未知的模块且该模块不在任何依赖文件中。中风险引用了项目内部未知的类或函数可能是拼写错误或 AI 联想。低风险引用了跨文件动态生成的符号需要人工快速确认。只有高风险告警才强制阻断提交其他级别进入 PR 人工 review 清单。这样既不会漏掉真正重要的幻觉也不会让工具变成噪音制造者。6.3 长期使用要养成的三个习惯我建议长期使用 Ledgerful 的团队或个人养成下面这三个习惯。第一每次更新依赖清单后主动重建一次索引。否则工具会拿着旧知识库去审计新代码误报率会悄悄升高。第二每周挑一条告警做复盘。不要只看单次告警而是要追踪这个告警对应的代码最后是怎么处理的被修复了被允许了还是被忽略了。复盘结果反过来优化规则和 allowlist。第三把“AI 生成的代码”当作一个显式工作状态而不是默认状态。当 AI 写了很多代码后我通常会主动切割任务先让 AI 写完整代码再用 Ledgerful 做一次差异审计最后人工 review 那条 diff。这个过程很慢但长期来看比直接信任 AI 省时间。6.4 踩过几次坑之后的理解这个主题真正落地时最该盯住的不是功能列表而是输入格式、资源占用和失败重试。我见过很多工具在演示时效果很好一到真实项目就各种误报原因不是工具能力不够而是知识库没有维护好、输入材料没有处理干净。Ledgerful 这类工具给我最大的启发是面对 AI 编码生态重要的不是无限信任模型也不是完全禁止 AI 写代码而是建立一条可追溯的链路让“人”永远是最终责任人。代码可以交给 AI 生成但账本必须留在本地责任必须明确到人。这样的开发习惯比任何单一工具都更值得推广。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门