ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

AI Agent版本控制:代码、Prompt、模型与评估集的四层方案

AI Agent版本控制:代码、Prompt、模型与评估集的四层方案 这段时间一直在做 AI Agent 的工程化实践系列写到第四十五篇我越来越感觉到一个反直觉的事实Agent 项目最难维护的不是代码而是行为本身。版本控制对 AI Agent 来说管的绝不只是代码那部分。很多从传统软件开发转过来的工程师本能地把 Agent 项目丢进 Git 仓库以为提交、分支、回滚就万事大吉结果一上线就出各种诡异的问题。今天这篇就把这个问题彻底摊开聊一聊——Agent 的版本控制到底在控制什么以及为什么只控代码根本控不住。先讲一件我印象特别深的事。之前我们团队把一个客服类 Agent 从测试环境发到生产代码通过了全部的单测和集成测试Git 记录显示干净整洁。结果上线后用户反馈说这个机器人突然变得特别油腻明明是来做售后咨询的它却一直跟人套近乎、发表情、用感叹号。排查了大半天最后发现根源不在代码而是两个星期前有人微调过 system prompt 里的语气设定把专业克制改成了热情友好这个改动一直躺在本地文件里没有随着应用代码一起提交。那一刻我就明白了Agent 的行为由一堆代码之外的东西共同决定而这些东西如果不在版本控制体系里出问题只是时间早晚。这篇文章不适合还在跑 Demo 的人读它更适合那些已经开始在生产环境养 Agent、被行为漂移和回滚困难折磨过的开发者。我会把 Agent 系统里所有会变的东西拆开来看再给出我实践下来可落地的一套分层版本管理方案包括单人项目和团队协作分别怎么搞。读完你至少能回答一个问题当你说把这个 Agent 回滚到昨天的时候你到底要回滚什么。1. 一声回滚引发的思考为什么传统 Git 管不住 Agent1.1 一次失败的午夜回滚先继续说前面那个客服 Agent 的事故。那晚我们确认了油腻语气是 prompt 里的一段设定引入的之后立刻决定回滚。我当时的操作就是标准的 Git 流程——切回上一个 tag重新构建镜像推上去重启服务。表面上看代码回滚成功了但问题并没有解决因为出问题的 prompt 文件在我本地它压根没提交过仓库所以 tag 里既没有旧版本也没有新版本仓库里的 prompt 始终是上一个版本而服务实际加载的 prompt 是我本地那份热情友好版。这个事故的荒谬之处在于代码世界里回滚是一件确定性很强的事但在 Agent 世界里回滚的对象根本不是代码。那一晚我们在讨论的不是代码版本 A 还是 B而是到底哪些文件在决定服务行为。最后我用了一个土办法——从聊天记录里翻出两周前的 prompt 内容手工恢复了一份旧版本再重启服务。那一瞬间特别讽刺版本控制落在了一个 Word 式的手工整理行为上。1.2 传统版本控制的三大隐含假设我们在 Git 的世界里待了太多年很多人已经默认了以下三条假设成立但它们在 Agent 项目里全都不成立。假设一单一事实源。Git 假设仓库里的代码就是生产环境的真身一切变更都必须先进仓库再发到线上。但在 Agent 项目里prompt 经常被人在线上调试台直接改工具配置散落在一堆后台开关里模型微调的产物可能只存在于某台训练机的挂载盘里。这些东西都不在仓库这就意味着仓库从出生那天起就丢失了一部分事实。假设二代码是行为的唯一决定因子。传统软件的行为由代码决定变量赋值、逻辑分支在编译或启动时就固定了。Agent 则不同代码只是搭了一个框架具体怎么说话、怎么做决策很大程度取决于一段文本prompt和一个权重文件模型。同一套代码换一个模型版本甚至只换 prompt 里几个形容词行为都能变得面目全非。假设三版本之间的语义边界清晰。传统版本之间是可哈希、可比较的差异就是 diff。Agent 版本很难做 diff——你改了 5 个字但模型输出分布的变化是连续的、不可预期的你甚至没法回答这次行为和上次差了多少。这三条假设集体失效意味着照搬 Git 管理 Agent 从一开始就走错了方向。我们需要先在脑子里建立一个新的概念Agent 版本 代码 配置 数据 模型行为的联合快照。1.3 从 LLM、AI 模型到 Agent先把概念对齐聊版本控制之前必须先把几个高频词的关系理清楚因为它们经常被混着用。像 DeepSeek、GPT、Claude 这类属于AI 模型更准确说是大语言模型 LLM。它们是静态的推理引擎输入一段文本输出一段文本。而Agent是在 LLM 之上长出来的一个系统它有一个目标拆解的循环会调用工具会读取记忆会跟外部世界交互。所以当有人问你Agent 和 LLM 有什么区别答案很简单——LLM 是你的大脑引擎Agent 是装了这个大脑的完整躯干躯干还包括手工具、记忆上下文存储、神经编排逻辑。这个概念对齐对版本控制至关重要。因为如果你只把 Agent 当成一个 LLM 套壳那你管理版本时只会盯着模型版本换没换。但真正的 Agent 系统里工具的 Schema 改了、Prompt 里加了一句指引、评估数据集换了标注口径这些都是版本的变更都可能造成行为变化。换句话说版本控制的对象不是模型本身而是整个 Agent 系统的定义文件。2. 拆箱看货Agent 系统里到底有哪些会变的东西要搞清版本控制控制什么就得先把 Agent 系统的可变资产全部盘点出来。我习惯把 Agent 拆成五个层面每层有各自的变更频率和变更方式。2.1 工作流与编排逻辑代码层这是唯一我们能拿传统 Git 思路去管的部分。包括 Agent 的主循环、状态机、任务分解策略、工具调用后的结果处理逻辑、内存读写代码等等。这一层的特点是变更频率低语义清晰每次改动的影响可以被单元测试覆盖。拿我自己的一个自动化测试 Agent 举例编排代码里定义了一个先看用例优先级再决定要不要调用浏览器的规则。这个规则改没改可以用一个固定的输入去验证输出是可断言的。代码层的版本控制不需要太多创新规范的分支、PR、review、tag 流程在这层完全适用。2.2 提示词与角色设定文本层这是最容易被忽略、也是最让 Agent 工程团队头疼的一层。System Prompt、任务描述、Few-shot 示例、工具使用说明、安全护栏提示词全都属于这一层。它的特点是一次微小的改动就可能引发剧烈的行为变化而且经常无法预判是变好还是变坏。我见过一个团队管理 prompt 的方式是把 prompt 写在约定俗成的共享文档里谁要改就自己复制一份改完覆盖回去。听着吓人但在十几人的 Agent 团队里这是常态。问题在于共享文档没有 diff、没有作者签名、没有生效版本出了事你根本不知道是哪一次编辑引入了问题。后面我会详细讲这层的版本控制解法现在只需要记住文本层是 Agent 版本控制的重灾区也是整个体系的核心。2.3 工具定义与函数 Schema接口层Agent 要调用什么东西取决于注册给它的工具列表。每个工具有名称、描述、入参 Schema、实现代码、权限范围。工具定义变了Agent 的能力边界就变了描述变了Agent 的调用倾向就变了——它可能以前从来不主动查询订单加了句描述当用户订单量很大时优先分页查询之后就开始频繁调用这个工具了。这一层很有意思因为工具的实现代码属于代码层但工具的对外定义尤其是 LLM 能看到的描述文本属于文本层。也就是说一个工具变更可能要跨两层分别纳入版本管理。很多团队只改了工具实现忘了同步描述结果 Agent 按照旧描述去调用参数对不上整个链路就断了。2.4 模型版本与推理参数模型层Agent 用哪个基础模型哪个精调版本这是版本控制里绕不开的一环。同一个 Agent从 DeepSeek-V2 切到 DeepSeek-V3哪怕代码和 prompt 完全不动输出风格也会漂移temperature、top_p、max_tokens 这些推理参数同样会影响行为的一致性。这一层的控制策略其实很老派——锁定。生产环境用的模型必须是一个不可变的版本引用不能是最新版或推荐版这种动态标签。否则哪天模型 API 悄悄升级了底层版本你的 Agent 行为就变了而你完全不知道何时变的、为何而变。此外模型的评测报告、能接受的输入输出格式也要跟着版本走。2.5 评估集与标杆答案数据层Agent 项目里最昂贵、最不可替代的资产其实是数据用于评测的验证集、人工标注的标杆答案、历史会话里抽取出的优秀案例、用户反馈的负面样本。这套数据就是 Agent 的验收标准版本控制如果不把评估集管起来你根本没法判断一个版本更好还是更差。举个例子我们一起调优了一个内容总结 Agent。上一版我们用 200 条标注数据测出来准确率 92%这版代码和 prompt 一点没改只是评估集换了 200 条更难的数据结果分数直接掉到 76%。**如果评估集本身没有版本两个结果没有任何可比性。**数据层版本控制的核心就是把评估集和被测的 Agent 版本绑定存储让82%这句话自带上下文。2.6 五层可变资产速查表层面典型内容变更频率传统控制是否够用代码层编排逻辑、主循环、函数实现低够用文本层Prompt、系统设定、Few-shot、工具描述高完全不够接口层工具 Schema、权限范围中部分够用模型层基座模型版本、推理参数中必须新增约束数据层评估集、标注结果、案例库中往往缺失3. 分层版本控制怎么做我的四层台账方案知道了有哪些东西要管接下来就是实操。我在实践中逐步舍弃了一股脑全塞进 Git 仓库的做法转为按变更频率和影响范围分层治理核心是四个字台账、锁定、绑定、回放。下面按层拆开讲。3.1 代码层git 照常但依赖必须锁死代码层没什么花活老老实实用 Git 分支管理就行。但有一个很容易忽视的细节Agent 的依赖锁必须比普通项目更严格。普通 Web 项目锁requirements.txt或者package-lock.json就够了Agent 不行。因为 Agent 的运行涉及模型 API 的 SDK、工具插件的版本、向量数据库的客户端。这些依赖版本一变Agent 的调用行为就可能变。我把依赖锁细分成三份Python/Node 包的锁文件、模型 SDK 的版本戳、以及外部工具插件版本清单。每次发布前这三份必须固化成一个dependency-snapshot.json跟随发布物一起打包防止我的机器上能跑生产上跑出来结果不一样。3.2 文本层把 Prompt 当成源码管理文本层是整个方案的重心。最朴素的解法就是让 Prompt 像代码一样进 Git但给它单独开一块目录并且和代码的提交节奏解耦。我所在的项目里prompts/目录是独立于src/的各自有不同的提交历史。Prompt 的变更不走常规的 PR 流程因为评审人不一样而走专门的Prompt Review流程必须附带一份变更说明写明改了哪几个字、期望解决什么问题、和上一个版本的对比评估结果。具体操作上我会做三件事一个 Agent 版本对应一个 prompt 目录目录名就是版本号customer_agent_v12/system_prompt.md、few_shots.yaml。不搞final_v2_真的最终版.md这种命名。Prompt 变更必须绑定一个评估结果文件。哪怕是很小的改动也要给出旧版 92% vs 新版 93%这样的对比没有评估结果的 porompt 变更不允许合入。保留历史版本的完整文件夹包括所有失效的 prompt。因为它们代表了系统的试错经验库哪天问题复发翻旧版本比重新推导快太多。这里有个技巧我特别想分享Prompt 的版本描述要写行为意图而不是文字变更。别写把亲爱的改成您好要写降低开场白亲密度以应对老年用户群体投诉。因为改完 prompt 之后你还得靠这句话去判断新版行为是否符合预期而角色的文字本身无法承载这个判断。3.3 模型层锁定版本但不只看版本号模型层的版本台账至少要记录四样东西模型名比如 DeepSeek-V3、具体权重版本或 API 快照 ID、推理参数temperature 等、以及当次变更的实测评估对比。特别提醒一点用 API 的公开模型锁版本要做到API 提供方允许的最细粒度。很多模型服务商会提供日期后缀的快照 ID如deepseek-chat-20250115发布时一定要引用这个快照而不是引用deepseek-chat这种不带日期的别名。如果提供商不提供快照那就把一个固定日期的评测数据存下来作为替代基线。我的经验是没有锁定的模型引用Agent 的行为漂移是必然的只是时间问题。模型层版本控制还有一个容易漏的细节Agent 的召回模型和生成模型往往是两个不同的模型比如用一个小向量模型做检索用一个大语言模型做生成这两个模型要分别记录、分别锁定不能混在一起写模型版本V3。3.4 数据层评估集是 Agent 的验收标准必须可回溯评估集和标杆答案的版本控制我的做法是做成一个独立的eval/仓库和主应用代码完全分离。每个评估集版本有一个唯一的 ID包含输入样例集合最好是 jsonl 格式每行一个用例每道题的标杆答案与评分标准数据来源说明是人工标注还是线上抽取、标注人是谁、标注日期版本变更日志为什么加了这些用例是为了覆盖哪类失败场景有了这个体系之后回滚就多了一个决策依据**出了问题先看是代码回归、Prompt 漂移还是评估集口径变了。**另外我强烈建议每一条评估样例都要带标签比如订单查询类、多轮澄清类、工具调用失败恢复类。因为改了个 Prompt可能整体分数微涨但某一类标签的分数暴跌只有带标签的评估集才能发现这种局部劣化。3.5 绑定与回放把四层台账合成一个版本号单独的台账是碎片必须有一个机制把它们绑定成一个可回放的整体。我会在发布时生成一个agent-version.yaml文件四个 lock 字段version: v48 code: git_commit: a1b2c3d4e5f6 dependency_snapshot: dep-snap-20250603.json prompt: prompt_dir: customer_agent_v48 prompt_owner: lihua model: primary_model: deepseek-v3-snapshot-20250512 retriever_model: text-embedding-snapshot-20250420 inference_params: { temperature: 0.2, top_p: 0.9 } eval: eval_set_id: eval-valid-v14 eval_score: { accuracy: 0.94, tool_failure_rate: 0.02 }这个文件就是 Agent 版本的全息快照。回滚到 v44操作的其实是把这个 yaml 里的四个字段全部恢复切代码、恢复 prompt 目录、切模型快照引用、挂载 v14 的评估集。到这一步回滚才叫真正的回滚因为恢复的不只是代码是完整的行为指纹。4. 从单人到团队Agent 工程的提交流程与发布门禁单人项目用好上面的台账就够了但是一旦 Agent 项目进入团队协作甚至工业化流水线光有台账还不够得有配套的流程和门禁。这部分的经验来自我们转型过程中踩过的坑分享几个已经稳定跑了一年多的实践。4.1 分支模型Prompt 变更独立于代码分支我们主仓库采用 Trunk-based 模式但prompts/目录用一套特殊的分支策略。简单来说Prompt 的变更不要求跟代码同一个分支合并。具体做法是任何人要调 Prompt先基于当前生产版本拉一个prompt-review/chinese-warmth这种分支只改 Prompt 和相关评估文件。改完跑一遍变更前 vs 变更后的对比评估把结果贴到 PR 描述里。评审人是产品负责人 另一个资深工程师不是代码审查者。合并之后这个 Prompt 并不会立即生效而是生成一个候选版本等下一次 Agent 发布时一起上线。为什么这么设计因为代码改动和 Prompt 改动根本不在一个节奏上。代码可能一周合并 20 次Prompt 则是一个月只改 3 次每次都要慎重。让它们拥有独立的生命周期可以避免代码评审阻塞 Prompt 迭代也避免 Prompt 的随意改动污染代码历史的可读性。4.2 评估门禁没有人 Review 的 Prompt 不要上线我见过太多 Agent 团队死在人人都能改 Prompt上。客服团队觉得语气太冷可以自己偷偷改一句运营觉得答案不接地气又改一句三个星期后没人知道当前线上 prompt 是谁写的、为什么写成这样。所以必须给 Prompt 的变更装上门禁。我在流程里设了三道闸门可回溯没有关联评估集版本的 Prompt 变更一律打回。你要改一件事就得先能证明怎么测它。有对比必须填写旧 prompt 响应 vs 新 prompt 响应在同一个评估集上的表现。哪怕你说这个改动纯属措辞优化也得按同一个标杆题跑一遍告诉我看得出效果。责任到人每个 Prompt 变更都有 owner。出了行为问题owner 负责解释当初为什么这么改而不是众人都说我不知道谁改的。听起来有点重但这是防止 Agent 体系失控的最低配置。我们早期没有这套门禁靠的是人肉记忆结果上面那个油腻客服的事故我们定位了一个通宵。4.3 发布与回滚恢复的不只是代码有了统一的版本台账发布也就从发布代码变成发布一个 Version Entry。我们的发布流程如下构建产物时自动生成agent-version.yaml的候选版本。发布系统把代码、Prompt 目录、模型快照引用、评估集 ID 捆绑形成一个不可变的发布包。生产环境部署后开启一段金丝雀评估期流量切 5% 给新版本同时把线上请求的日志采样喂给评估集自动打分。效果达标后切全量同时把这次发布对应的agent-version.yaml打上production标签。回滚流程也一样不是切容器镜像而是把上一个production标签对应的整套配置重新部署。请注意代码可以秒回退但模型快照引用如果没记录回滚就没法执行。模型快照引用必须永远跟着发布包走不能只记在谁的聊天记录里。4.4 实验追踪当次的 Traces 比最终答案更值钱门禁和台账都是事前措施真正能帮你在线上定位问题的是事后的追踪数据。我要强烈建议每一条 Agent 的请求尤其是被评估集判定为失败的请求完整保留运行轨迹什么工具被调用了、调用的输入输出是什么、中间推理步骤是什么、最终回复是什么。这些 Trace 数据要按 Agent 版本号归档而不是按时间归档。为什么这么强调因为 Agent 的行为是非确定性的。同一个 prompt、同一道题跑五次可能是五种答案。你只有把当次完整的推理轨迹存下来才能在复盘时说清楚这个 bug 是 v47 引入的因为它的工具调用参数格式和 v46 不同。没有 Traces你所谓的版本对比只能停留在输入-输出黑盒层面而黑盒层面的对比无法告诉你该改哪一层。也可以理解成评估集是考卷Trace 是答题草稿纸。只看考卷分数你能判断涨跌但只有草稿纸能告诉你它因为哪一步做错了而丢分。5. 关于落地我还想说的三件事方法论讲得再多落地的时候总有一些没人提醒你、但踩了才知道的细节。挑三个最重要的分享出来希望能给你省掉几个通宵。5.1 小团队别一次上太重先补最痛的一层如果你的团队只有三五个人Agent 项目还在探索期我建议不要一次把五层台账全建起来太重了你的业务可能三天两头推翻重来。先挑最痛的那一层下手如果你天天被线上的 Agent 怎么突然变了一个人困扰就先管好 Prompt 层如果你天天被这个版本效果到底好不好困扰就先管好评估集。等这两层跑顺了再补模型快照和依赖锁。一个只有代码层版本管理的 Agent 项目是裸奔的但一个只建了数据层没建模型层的项目至少还有评估集兜底能看出变差了。渐进落地的顺序比一步到位的完美起飞靠谱得多。5.2 平台级资产统一的 Agent 仓库是终局团队的 Agent 多了以后我会强烈建议搭一个统一的Agent 资产中心不管是自研一个页面还是用现成的开发平台。这个中心的核心功能就一条把 agent-version.yaml 变成一条可查询的记录所有 Agent 的版本、评估报告、Trace 数据都能在一个界面里被检索和比对。维度包括每个 Agent 有多少个版本每个版本是谁在什么时间发布的当时的评估分数是什么生产环境当前引用的是哪个版本上次回滚是为哪个事件。当你的 Agent 数量超过 10 个靠人肉维护 Excel 台账是必崩的。我们当时就是用一张共享表格硬撑结果某天有人误删了一行导致一个 Agent 在生产跑了一个无法追溯的版本直接把整个发布链的信任度打没了。平台化建设不是开源的产物是 Agent 工程化路上避不开的关口。5.3 最终台账长什么样一个真实的版本条目最后给你看一条我们内部实际在用的版本台账记录删去了所有商业敏感内容保留了结构。你可以直接照抄这个模板建立自己的版本条目。字段值Agent 名称order-assistant版本号v48发布时间2025-06-03 14:22:08发布人lihua代码 Commita1b2c3d4e5f6依赖快照dep-snap-20250603.jsonPrompt 目录order_assistant_v48/模型组合deepseek-v3-snapshot-20250512 text-embedding-snapshot-20250420推理参数temperature0.2, top_p0.9评估集eval-valid-v14评估结果accuracy0.94, tool_failure_rate0.02生产状态已全量2025-06-03 15:30 切换回滚备注无有了这一条记录不管未来谁接手这个 Agent都能在一个文件里回答四个问题这系统由什么构成、它当时被验证过什么、它在线上表现如何、出事了我该恢复什么。关于 Agent 版本控制这件事我最初也天真地以为版本控制嘛就是 Git直到生产环境给了我几下重锤才慢慢梳理出代码 提示词 工具定义 模型 评估集这套框架。现在每次版本发布我唯一关注的不是代码合没合而是那个agent-version.yaml有没有完整生成——因为它才是 Agent 真正的身份证。如果你正在被 Agent 行为漂移、回滚失忆这些问题折磨不妨从本周就做一件事把你线上 Agent 正在用的 Prompt 目录整个 commit 进仓库建一个最朴素的版本号先把它纳入控制。后面的事我们随时可以再聊。
返回列表