ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

大模型只是模式补全:AI Agent 编程的安全实践

大模型只是模式补全:AI Agent 编程的安全实践 最近有一个传播很广的说法OpenAI 用一次演示证明了 AI“根本不知道自己在做什么”。这个标题很有冲击力但对做技术的读者来说它其实只提出了问题没有给出答案。真正值得追问的是如果大模型没有真正的理解能力为什么它又能写出能运行的代码、能通过复杂的测试、能在对话里给出看起来很有逻辑的回答这篇文章想讨论的不是“AI 是否有意识”这类哲学问题而是三个更实际的工程问题。第一大模型的能力边界到底在哪它在什么情况下会可靠什么情况下会毫不犹豫地犯错第二从普通聊天工具到 AI Agent工具链的自主性变强之后风险是如何被放大的第三作为开发者我们应该用什么样的流程、规范和验证手段把 AI 接入真实项目同时不让自己被“看起来正确”的结果坑进去。我先把结论放在前面大模型的本质是模式补全不是因果推理。它能通过大量测试不代表它理解了系统它能在对话里给出完美解释不代表它真的“知道”自己在说什么。对开发者来说这既不是否定 AI 的价值也不是鼓励盲目信任而是一个信号——我们需要把 AI 当作一个能力很强、但需要被验证的组件来接入系统而不是把它当成一个什么都知道的协作者。1. 大模型“不知道自己在做什么”到底是什么意思先从技术原理说起。当前主流的大语言模型核心任务只有一个给定前面的 token 序列预测下一个 token 的概率分布。你在 ChatGPT 里输入一段话模型做的事情不是“理解”你的意图然后检索知识库回答问题而是根据训练数据里出现的模式生成一段在统计上最自然的后续文本。这个过程有一个非常关键的后果模型输出的所有内容本质上都是“看起来合理”的文本而不是“经过验证为真”的事实。只要训练数据里出现过类似的表达方式它就会用同样的方式继续写下去。这也解释了为什么模型能写出结构完整的代码、能给出语法正确的函数——因为它见过太多这样的代码片段。但它没有能力在生成过程中真正运行一次代码看看结果对不对。这里就是标题那句话的真正含义AI 可以完成任务但它并不知道自己为什么要这么做也不知道这么做的后果是什么。它没有内在的因果模型来验证自己的输出。这就像一个人背熟了整本驾驶手册能在笔试里拿满分但从来没摸过方向盘你让他描述“遇到路口应该怎么做”他可以回答得头头是道但你不会放心让他真的开车上路。这个判断对开发者来说非常重要。因为在日常使用中我们很容易把“回答流畅”和“推理正确”混为一谈。模型给出的代码能运行我们就默认它逻辑正确模型给出的解释听起来合理我们就默认它理解了这个系统。但从工程角度看这两件事之间没有必然联系。更准确地讲大模型的能力可以拆成三层。第一层是语言生成能力这是它的强项它能生成语法正确、结构清晰的文本。第二层是模式迁移能力当任务和训练数据里的模式高度相似时它能给出非常可靠的结果比如写一个常见的排序算法。第三层是真正的因果推理能力这是模型最薄弱的地方当任务需要多步逻辑推导、需要理解系统状态、需要判断外部世界的真实变化时它经常犯错而且犯错的方式非常隐蔽——它会用自信的语气说出错误结论。所以对“AI 不知道自己在做什么”这个说法我的判断是它说得对但不够完整。模型确实没有真正的理解能力但它具备极强的模式匹配能力这足以让它胜任很多任务。关键是我们要知道什么时候可以信任这种模式匹配什么时候必须加验证环节。2. “看起来理解”的错觉是怎么产生的既然模型只是在做模式补全为什么我们和它对话时会强烈地感觉到它“懂”我们这个错觉来自三个技术环节的叠加。第一个环节是 RLHF基于人类反馈的强化学习。OpenAI 在训练 ChatGPT 时通过人类标注者对多个回答进行排序让模型学会偏向那些“更像人类专家”的表达方式。这个过程的本质不是教模型变得更聪明而是教模型在表达上更像一个自信、有条理、考虑周全的助手。结果就是模型生成的内容在结构上很有说服力即使事实是错的它也会用完整的逻辑把它包装起来。第二个环节是海量训练数据带来的领域覆盖。模型读过的代码、文档、技术讨论数量远超任何人类开发者。当你在提示词里描述一个常见需求时它能从记忆里找到大量相似片段然后用一种“特别懂行”的方式组合起来。对一个经验不足的开发者来说这种输出非常容易让人信服因为它的用词、结构和细节处理都太像资深工程师了。第三个环节是上下文学习能力。你在对话里补充了错误信息模型会顺着你的语境继续生成而且不会指出你的错误。这不是因为它情商高而是因为在模式补全的逻辑里顺着用户的话往下说才是“最自然”的延续。所以你会看到一种典型现象用户带着一个错误前提提问模型给出了一个逻辑自洽但基于错误前提的回答。这三个环节叠加起来产生了一个非常危险的错觉模型不是在回答问题而是在扮演一个知道答案的角色。它把“看起来正确”优化到了极致这恰恰是我们在工程化使用它时最需要警惕的地方。这里要特别提到一个概念幻觉。所谓幻觉就是指模型生成的内容与事实不符但表达方式非常流畅自然。它不是模型“撒谎”而是模型在模式补全时没有足够的相关模式可以依赖于是用最合理的语言填补了空白。在代码场景里幻觉的典型表现是使用了一个不存在的 API 函数、假设了一个不存在的配置项、或者在一个看似完整的实现里漏掉了关键的边界条件。理解了幻觉的成因你就明白为什么不能直接让 AI 生成代码然后直接上线。不是因为它能力不够而是因为它的输出本质上是一个“未经测试的假设”。你需要用工程手段去验证这个假设而不是默认它成立。3. 从 Copilot 到 Agent能力升级风险也在升级过去两年AI 编程工具经历了一个明显的演进过程。最早是代码补全工具比如 Copilot 的前身它在你写代码时提供下一行建议。这个阶段的特点是人类掌握控制权AI 只负责补全错误的影响范围有限一个错误的补全顶多让你改一行代码。接下来是聊天式助手比如 ChatGPT、Claude 这类通用模型。你可以把整个文件贴给它让它重构、解释、加注释。这个阶段的特点是AI 开始处理更大范围的代码但仍然没有执行能力。它生成代码你负责复制、粘贴、运行、验证。问题开始出现但风险还可控因为任何错误都要经过你的手才能进入项目。现在到了第三个阶段AI Agent。这类工具不仅能生成代码还能自己执行命令、读取文件、运行测试、修改代码、提交变更。OpenAI 的 Codex 就是典型代表。从热搜词可以看出OpenAI 已经把 Codex 的 harness 部分开源开发者可以在自己的环境里跑一个完整的编码 Agent。这个变化是本质性的——AI 从“建议者”变成了“执行者”。为什么说风险升级了举个具体的例子。在聊天助手里AI 说“你需要安装这个依赖”然后你手动运行pip install如果装错了你立刻能看到报错。但在 Agent 模式下AI 会自己运行pip install然后继续执行下一步。如果它安装了一个有安全漏洞的包或者在错误的目录里删除了文件这些操作的反馈非常延迟甚至不会反馈给你。等发现问题时你可能已经丢失了宝贵的工作成果。还有一个更隐蔽的问题Agent 的多步操作会累积错误。聊天助手的一次回答就像一个单步操作错了可以马上纠正。但 Agent 会连续执行几十个步骤每步都可能基于上一步的错误结果继续推理。一步错步步错而且错误会随着步骤增加而放大。这就是为什么很多人在试用 Agent 时会遇到“越改越乱”的情况——不是 Agent 不聪明而是它的错误修正机制不够可靠。从安全角度看还有一个关键区别AI Agent 可能接触到你的真实环境。如果它在你的生产服务器上执行命令或者访问了包含密钥的配置文件一旦它的行为偏离预期可能造成的影响就不只是“代码质量差”那么简单了。这也是为什么在工程化使用 Agent 时第一原则是限制它的权限范围而不是让它“放手去做”。我的观点是Agent 是 AI 编程的未来方向但它对工程规范的要求比 Copilot 时代高了一个数量级。你现在不能再用“生成代码然后人工审查”的思路来使用 Agent你需要的是“给它一个受限环境、明确的验收标准、以及随时可以中止的机制”。4. Agent 是如何“行动”的架构拆解要理解为什么 Agent 会出问题先得知道它内部是怎么运转的。虽然不同产品的实现细节不同但主流编码 Agent 的架构高度相似通常包含四个核心组件。第一个组件是模型本身。负责理解任务、生成操作指令它是一个决策核心但它不直接执行操作。第二个组件是工具集。Agent 通过调用工具来与环境交互常见的工具包括读取文件、写入文件、执行 shell 命令、运行测试、搜索网络、调用 API。第三个组件是上下文管理负责维护当前任务的状态包括已经读过的文件、生成过的代码、执行过的命令、以及得到的输出。第四个组件是执行沙箱负责实际运行 Agent 生成的操作指令并把结果返回给上下文。整个工作流程是这样的。用户给 Agent 一个任务描述模型把这个描述拆解成一些列操作步骤然后逐步执行。每执行一步工具集把真实的结果返回给上下文模型再根据新的上下文决定下一步操作。这个循环会一直持续直到任务完成、用户手动中止、或者达到预设的步骤上限。这个架构有一个关键特征模型看到的每一步结果都是“文本描述”不是真实的系统状态。比如 Agent 运行了一个测试它看到的只是测试输出的文字Agent 删除了一个文件它看到的只是rm命令的成功返回。模型无法直接感知文件系统、网络、权限这些真实世界的状态它只能通过工具返回的文本间接推断。这意味着什么意味着 Agent 对环境的理解是“二手”的。如果测试输出因为环境原因被截断了或者一个命令在静默失败后返回了成功状态Agent 就会基于错误的信息继续行动。这不是模型的推理能力问题而是 Agent 架构本身的局限性——它和真实世界之间隔着一层文本接口而这层接口会丢失信息也会产生误导。了解了这个架构你就能理解为什么需要在工程上对 Agent 做约束。你不能指望模型自己“判断”某个命令是否危险因为你看到的只是命令文本模型看到的也只是命令文本。你需要在架构层面加上边界哪些命令允许执行哪些文件允许修改哪些操作必须经过人工确认。这些约束不能依赖模型的自觉必须由外部机制强制保证。5. 工程实战如何安全地让 AI 替你写代码理解了原理之后我们来看具体实践。这里我用一个最小可运行的方案展示如何把一个 AI 编程 Agent 接入项目同时保持足够的风险控制。这个方案不依赖任何特定付费产品只需要 Python 和一个 OpenAI 兼容的 API 接口。第一步搭建一个受控的工作目录。不要把 Agent 直接放在项目根目录里操作而是给它一个独立的子目录让它的所有修改都限制在这个范围里。# 创建受控实验目录 mkdir -p ai-agent-workspace # 把项目代码复制到工作目录而不是让 Agent 直接改原文件 cp -r your-project/* ai-agent-workspace/这个步骤的目的是隔离风险。即使 Agent 在工作目录里乱改也不会影响你的主代码。确认 Agent 行为可靠之后再手动合并有效变更。第二步定义一个明确的任务描述。这里最容易犯的错误是任务太模糊。注意Agent 没有“常识”来判断你的真实意图它只能根据你给的文字来行动。# 在一次会话中只给一个具体任务不要包含多个隐含需求 任务在 ai-agent-workspace/src/utils.py 中添加一个函数 format_bytes(size: int) - str把字节数格式化为人类可读的大小。 要求 1. 使用二分单位KBMBGB保留两位小数 2. 小于 1024 字节时直接返回 xx B 3. 添加类型注解 4. 不要修改其他文件。如果你给的是“优化这个项目的性能”那 Agent 很可能自作主张地改动大量文件而且你无法判断它是否偏离了目标。具体的任务描述是控制 Agent 行为的第一道防线。第三步用代码去调用 API而不是直接在某个聊天界面里操作。这样你可以记录完整的对话上下文方便回溯和排查问题。下面是一个简化版的 Python 调用示例。# 文件路径scripts/run_agent.py import os import json from openai import OpenAI client OpenAI( api_keyos.environ.get(OPENAI_API_KEY), base_urlos.environ.get(OPENAI_BASE_URL, https://api.openai.com/v1), ) messages [ { role: user, content: ( 请阅读 ai-agent-workspace/src/utils.py 文件 然后按照任务描述添加函数。任务描述如下\n 1. 添加 format_bytes 函数\n 2. 使用二进制单位\n 3. 保留两位小数\n 4. 添加类型注解\n 5. 不要修改其他文件。 ), } ] response client.chat.completions.create( modelgpt-4o-mini, messagesmessages, temperature0, ) # 把模型返回的完整内容保存到文件方便审查 with open(agent_output.txt, w, encodingutf-8) as f: f.write(response.choices[0].message.content) print(Agent 输出已保存到 agent_output.txt)这段代码里有几个值得注意的工程细节。第一API key 通过环境变量读取绝不硬编码在代码里。第二temperature0让输出尽量确定减少随机性。第三模型返回的内容先保存到文件而不是直接应用这给了你一个人工审查的环节。第四任务描述明确指定了文件路径、函数名和约束条件。第四步审查并验证输出。这是整个流程里最重要的一步也是最容易被省略的一步。无论 Agent 给的代码看起来多么完美你都要把它当作“一个陌生开发者的代码提交”来审查运行测试、手动检查逻辑、确认没有改动额外文件。# 检查 Agent 是否只修改了指定文件 git diff --name-only # 运行项目测试 pytest tests/如果测试全部通过且git diff只显示你预期修改的文件你才可以把变更合并到主分支。任何一步失败都要回到上一步重新调整任务描述而不是试图“说服” Agent 修复问题。这个流程看起来很简单但它体现了工程化使用 AI 的核心原则把 AI 当作一个需要验证的组件而不是一个可以信任的协作者。你不必理解它内部怎么思考但你必须验证它的输出是否满足要求。6. 如何判断 AI 的输出是否可信在真实项目中AI 输出的验证比“跑通一个示例”复杂得多。这里涉及到验证的层次问题我把它分成四级。第一级是语法验证。AI 生成的代码能不能被解释器正确解析、能不能被编译器编译通过。这一级的验证是最基础的通常由语法错误立刻暴露问题。比如 Python 的缩进错误、Java 的括号不匹配这类问题在运行前就能发现。第二级是运行验证。代码能不能跑通函数能不能返回预期结果。这一级需要你准备测试用例。注意测试用例应该由你或者项目里已有的测试来定义而不是由 AI 自己生成。因为 AI 生成的测试用例通常会和它的实现共享同样的盲区——它不会测试自己遗漏的边界条件。第三级是逻辑验证。代码在给定的输入下是否真的满足了业务需求。这一级最难自动化因为它需要理解业务上下文。一个常见的场景是AI 生成了一个明显是 O(n²) 的算法但测试数据量太小性能问题没有暴露。这时候你需要的不是更多的测试而是代码评审。第四级是系统验证。变更是否影响了其他模块是否引入了安全漏洞是否符合项目的架构规范。这一级需要结合整个项目的上下文来评估通常依赖 CI/CD 流水线和团队的代码评审机制。一个很典型的错误做法是开发者在本地运行了一次示例看到输出正确就认为 AI 的解决方案是完备的。这不叫验证这叫做“看到了一个成功样本”。在大模型时代你需要的不是一次成功而是可重复的成功以及对失败模式的理解。这也是为什么我强烈建议把 AI 生成的代码纳入和人类开发者一样的评审流程静态检查、单元测试、集成测试、代码评审一个都不能少。这里还要提一个概念自测陷阱。你让 AI 写代码然后让 AI 自己写测试它会写一个和实现思路完全一致的测试然后用这个测试“证明”代码正确。这在逻辑上是一个循环论证。正确做法是测试用例和验收标准应该独立于 AI 的实现。你可以先把测试写好再让 AI 去实现功能最后跑测试验证。这种“测试优先”的思路比让 AI 自证清白可靠得多。如果代码里有不可信的依赖或者需要调用外部服务更稳妥的方案是先 mock 掉外部依赖确认核心逻辑正确再在真实环境里做集成验证。你要时刻记住AI 的验证文档本身也可能是幻觉的一部分——它可能生成一份看起来很完整的测试报告但那份报告的数据是编出来的。判断信息可信度的最终依据永远是你的运行结果和日志而不是 AI 的文字描述。7. 常见问题与排查思路在使用 AI 编程工具和 Agent 的过程中大部分问题不是“AI 不会做”而是“AI 做得太自然以至于你没发现它做错了”。下面整理几类高频问题和对应的排查思路。问题现象可能原因排查方式解决方案AI 生成了不存在的 API 函数训练数据中存在相似的 API 写法模型按模式补全在官方文档里搜索该函数运行代码查看报错提示 AI 使用文档中已确认的 API以官方文档为准不信任模型记忆AI 修改了额外的文件任务描述不够明确Agent 自行扩大改动范围用git diff --name-only查看变更文件列表任务描述中显式声明“只修改指定文件”取消 Agent 的全局写权限测试用例通过但逻辑有误测试用例和实现使用相同的错误假设检查测试数据是否覆盖边界条件独立编写测试先写好测试再让 AI 实现引入人工代码评审Agent 执行命令后环境被破坏Agent 直接在真实环境中执行了危险命令查看 shell 历史和变更日志使用容器或隔离工作目录限制 Agent 可执行的命令白名单多次对话后输出质量下降上下文累积了太多错误中间结果检查对话历史里的错误节点分析是哪一步开始偏离及时中止任务清理上下文重新描述目标AI 给出了看似专业的错误解释模型优化目标是流畅表达不是事实正确交叉验证关键结论查看官方文档或源码对关键信息进行独立验证把 AI 当助手而不是权威排查这类问题有一个基本原则先怀疑再验证。AI 的输出默认是“未经证实”的直到你通过运行、测试或文档检索确认了它的正确性。这个原则在初学者阶段显得很繁琐但对于生产环境来说它是必须的。在实际排查中还有一个非常实用的技巧让 AI 给结论的同时给出它得出这个结论的依据。如果它无法提供具体的代码路径或文档来源那这个结论的可信度要大打折扣。不过要注意模型可能会编造一个看起来合理的文档来源所以这个技巧只能作为初步筛选不能替代真正的验证。8. 最佳实践把 AI 接入开发流程的工程约束聊了这么多原理和风险最后落到实践上。一个有工程素养的团队应该怎么把 AI 编程工具接入日常开发流程我总结了六条建议。第一条最小权限原则。AI 能访问的数据和能执行的操作永远限制在完成任务所需的最小范围。不要让一个编码 Agent 拥有生产环境的密钥不要让它访问不必要的数据库。即使它是内部工具也要当作潜在风险来对待。第二条人工确认节点。对于不可逆操作比如删除文件、覆盖代码、发布版本必须设置人工确认点。你可以通过配置 Agent 的需要审批模式或者在流程中手动执行这些操作而不是完全交给 Agent。第三条测试先行。先写测试再让 AI 补实现代码是当前最可靠的协作模式之一。测试是你定义行为的工具AI 的工作是满足这些测试。这个模式既能约束 AI 的输出也能给你一个客观的验收标准。第四条版本控制兜底。任何 AI 的改动都要经过版本控制系统的记录确保可以随时回滚。在使用 Agent 之前先确认当前代码库处于一个可恢复的状态。不要在代码库有未提交的改动时让 Agent 开始工作。第五条日志与审计。保存 AI 的操作记录和对话上下文。一旦出现问题你可以回溯到出错的那一步理解是什么导致 AI 做出了错误的决策。这个习惯在 Agent 时代尤其重要因为 Agent 的操作往往不是一步两布而是几十个步骤的连续行动。第六条建立组织的 AI 使用规范。团队里应该有明确的文档规定哪些场景允许使用 AI 生成代码哪些场景必须人工编写AI 生成的代码需要经过什么样的评审流程哪些数据不能提交给外部 AI 服务。这不是限制效率而是保护团队不踩坑。这六条建议看起来都是常识但实际执行时很容易被忽略。原因很简单当 AI 给出的代码真的能运行、真的节省了时间你就会倾向于减少审查步骤。而这种“节省”往往是错觉——上线的代码如果出现问题修复成本远高于省下的那几分钟。9. 总结与后续学习方向回到开头的问题。OpenAI 的演示确实从某种角度暴露了 AI 缺乏真正的理解能力。它可以在测试里表现良好但面对真实世界的复杂系统时它只是在执行模式匹配。这个结论对技术人的价值不在于否定 AI而在于帮助我们建立一个更准确的心智模型AI 是强大的模式引擎不是可靠的推理引擎。如果你打算在日常项目里使用 AI 编程工具我建议你从今天开始做三件事。第一为你的项目建立一个独立的 AI 工作目录让 AI 的改动先落在隔离区验证通过后再合并。第二养成“先写测试、再让 AI 实现”的习惯让测试成为你和 AI 之间的契约。第三无论 AI 的输出看起来多么完美都把它当作一个陌生开发者的代码提交来审查。后续值得深入的方向包括Agent 的上下文管理策略、工具调用的安全边界设计、AI 生成代码的性能优化、以及如何利用评估集来衡量 AI 在特定代码库上的表现。这些都是大模型应用工程化往后必然要面对的问题。你现在建立起的验证意识、风险意识和流程意识会让你在接下来的 AI 工程化浪潮里比那些只会复制粘贴的人走得更稳。
返回列表