RAG运维如何用好Loop Engineering?Milvus 3.0 对它有什么价值?
Loop Engineering正成为RAG运维的新范式,让系统自动发现问题、分派任务、检查结果,彻底改变传统脚本维护的繁琐模式。Milvus 3.0为这一变革提供了关键的向量数据库支撑。核心内容:1. Loop Engineering的核心原理及其在RAG运维中的优势2. 从Prompt Engineering到Loop Engineering的范式转变3. Milvus 3.0如何针对性支持Loop Engineering的运行
01 Loop Engineering 到底是什么,为什么RAG需要它
过去两年,很多人使用 coding agent 的方式是这样的:你写一个 prompt—模型返回结果—你看结果—你再写下一个 prompt。这个过程里,人是循环的一部分。每一轮都需要人在场。agent 能走多远,取决于人的判断力。agent 能跑多快,取决于人的时间。这就是典型的 Prompt Engineering。在Loop Engineering 行业彻底换了一个思路:人类设计一个循环系统,这个循环会自动触发任务,调用 agent,检查输出,记录状态,然后决定下一步。这个系统自动发现需要做的工作,把工作分派给 agent,检查 agent 的输出,记录结果,然后决定下一步做什么。人类从循环中,跳到了循环外,变成设计循环的人。02 Loop 的五个构件,对RAG有什么启发
Addy Osmani 在 Loop Engineering 一文中把 loop engineering 拆成了五个构件加一个记忆层:Automations:按节奏自动触发任务,是 loop 的心跳Worktrees:让多个 agent 在隔离环境里并行工作。Skills:把项目知识写下来,agent 不用每次从零猜Connectors:连接 issue tracker、CI、Slack、代码仓库等外部系统。Sub-agents:把执行和检查拆开,不让同一个 agent 自写自审。Memory:记录跨轮状态,知道什么做完了、什么失败了、下一轮从哪里继续。03 Heartbeat:数据灌入成为持续任务后,要如何处理索引
在 coding agent 的 loop 里,Automations 是心跳,它会每天早上自动跑一轮 CI triage,读昨天的失败、issue、commit,把发现写进状态文件,触发下游修复。没RAG 系统的心跳是持续的数据灌入。传统做法是把数据搬进向量库。数据在对象存储或数据库里有一份,在 Milvus 里又有一份。然后你还要维护两边的同步关系。这个过程中,全量重灌的成本随数据量线性增长,不可持续。因此,在Milvus 3.0 中,我们在 External Collection 设计上换了一个思路:数据不搬家,索引去数据那里。当源数据发生变化时,loop 可以调用 refresh_external_collection() 触发增量刷新。这个 API 是异步的,返回一个 job_id,你可以追踪刷新状态:schema = MilvusClient.create_schema(external_source="s3://my-bucket/path/to/data/",external_spec='{"format": "parquet"}')schema.add_field(field_name="text",datatype=DataType.VARCHAR,max_length=256,external_field="source_text_column" # 映射到外部 Parquet 文件的列名)schema.add_field(field_name="vector",datatype=DataType.FLOAT_VECTOR,dim=128,external_field="embedding_column")
这个动作就是 RAG 数据 loop 的心跳:帮助我们把“哪些数据已经处理过、哪些数据需要更新”这类状态管理交给基础设施,而不是散落在业务脚本里。需要注意的是,External Collection 更适合只读或以外部数据源为主的场景,不支持 insert、delete、upsert。数据修改必须发生在源头(对象存储上的文件),Milvus 通过 refresh 同步变化。这个约束价值在于:源数据只有一个写入点,避免 Milvus 和数据湖之间出现不一致的问题。job_id = client.refresh_external_collection(collection_name="my_external_collection")# 追踪刷新进度progress = client.get_refresh_external_collection_progress(job_id=job_id)# state: Pending / InProgress / Completed / Failed# progress: 百分比# reason: 失败时的错误信息
04 Checkpoint:Loop 跑了一百轮,出问题怎么回滚
Coding agent 里常用 worktree 做隔离。每个 agent 在自己的分支或工作区里改代码。改坏了,不影响主分支。验证通过,再合并。RAG的数据 loop 也需要类似能力,只是对象从代码变成了向量数据。比如你换了一个新的 embedding 模型,重新生成了几百万条向量,也重建了索引。上线后发现,新模型在某类 query 上效果变差了。这时你需要回到上一个好版本。传统做法是维护两套 collection,然后手动切换。更糟糕的情况是没有备份,只能把旧模型重新跑一遍。发现问题需要回滚时,restore 是异步操作,直接复制 segment 文件到新 collection,跳过索引重建:# loop 每轮跑完,打一个 checkpointclient.flush(collection_name="my_collection")client.create_snapshot(collection_name="my_collection",snapshot_name="loop_round_42",description="embedding model v2, index HNSW M=16")
这和 coding agent 的 worktree 逻辑是类似的:worktree 让你在不影响主分支的情况下实验,出问题可以丢掉分支回到主分支。Snapshot 让你在不影响线上 collection 的情况下打版本,出问题可以 restore 回到上一个好的状态。Snapshot 还有一个在 loop 场景下特别有用的能力:你可以在同一个 snapshot 上跑验证查询。你的 loop 可以先在新版本上跑一组测试 query,对比旧版本的检索效果。通过了再切到线上。没通过就保留旧版本。这也是数据管理 loop 里的 maker-checker 分离:写数据的环节和验证数据的环节不应该混在一起。# restore 到一个新collectionjob_id = client.restore_snapshot(snapshot_name="loop_round_42",collection_name="my_collection_rollback" # 恢复到的目标 collection)# 追踪恢复进度state = client.get_restore_snapshot_state(job_id=job_id)# state: InProgress / Completed / Failed
05 一致性:写数据的 Agent 和读数据的 Agent 看到的是不是同一份怎么办?
在 coding agent 里,worktree 主要解决文件隔离问题。两个 agent 不要同时改坏同一份代码。在 RAG的数据 loop 里,问题变成了数据可见性。一个 agent 刚写入一批新文档,另一个 agent 立刻发起查询,它能不能查到这批新数据?答案取决于一致性策略。传统做法是要么不管(灌完就查,查到什么算什么),要么加 sleep 等一下(灌完等5秒再查应该够了),要么轮询确认(反复查直到能查到)。这些做法在手动操作时勉强可以,但在 loop 化场景下,灌入和查询都是自动触发的,频率可能很高,不确定的可见性窗口会导致 loop 的行为不可预测。Milvus 的一致性合约在 loop 场景下可以提供明确的可见性保障。注:一致性级别(Strong / Bounded / Session / Eventually)是 Milvus 自2.x 以来就支持的能力,不是 3.0 新增。但在 loop 化运维场景下,理解和正确使用一致性级别变得尤为重要,因为 loop 的多个环节对数据新鲜度的要求不同。Milvus 3.0 的 Streaming WAL 架构(引入 Streaming Node 和基于 Woodpecker 的 WAL 实现)让一致性保障在高吞吐场景下更高效。
WAL(Write-Ahead Log)是 Milvus 所有数据变更的 single source of truth。每一条写入操作走 Append 路径进入 WAL,每一个 PChannel 上有一个单调递增的TimeTick作为逻辑时间戳。TimeTick 同时是 MVCC 的可见性边界:只有 TimeTick 已经推进到的数据,才对查询可见。这意味着在 loop 里,你可以用一致性级别来控制写完多久后读能看到:Strong:查询等待所有已写入的数据都可见后再返回。写后立刻读,保证能读到。适合 loop 里灌完立刻验证的环节。Bounded:查询允许一个可配置的时间窗口内的延迟。适合 loop 里不需要最新数据但不能太旧的环节。Session:同一个会话内的写入对后续查询可见。适合 loop 的同一轮内我写的数据我自己能看到。不同的 loop 环节用不同的一致性级别,不需要所有查询都付 Strong 的延迟成本。灌入后的验证查询用 Strong,常规的线上查询用 Bounded 或 Session就可以。06 垃圾回收:过期数据不该靠人记着删
RAG 数据 loop 还有一个 coding agent 不太操心的问题:数据会过期。代码仓库有 git history,旧代码被新 commit 覆盖后,不会继续参与运行。向量数据库不一样。旧文档、旧政策、旧产品说明、旧版本 embedding,如果不清理,仍然可能被召回。结果就是用户问一个新问题,系统答了一段旧知识。传统做法是定期跑删除脚本。按时间戳筛选过期数据,然后逐条删除。这个脚本要维护,要重试,要有人记得跑,还要处理失败情况。在agent场景,有时候甚至需要手动读取记忆完成增删改查。Milvus 的 TTL 把这件事变成了声明式配置。注:Collection 级别的 TTL(collection.ttl.seconds)在 Milvus 2.x 就已存在。Milvus 3.0 新增的是Entity-level TTL,支持为每条数据设置独立的过期时间,通过 TIMESTAMPTZ 字段实现。以下分别展示两种用法。Collection 级别 TTL,适合所有数据使用同一个过期时间:Entity 级别 TTL(3.0 新增,按条粒度过期):# 创建 collection 时设置 TTL:所有数据 7 天后自动过期client.create_collection(collection_name="rag_knowledge",schema=schema,index_params=index_params,properties={"collection.ttl.seconds": 604800})# 修改已有 collection 的 TTLclient.alter_collection_properties(collection_name="rag_knowledge",properties={"collection.ttl.seconds": 604800})
# schema 中声明一个 TIMESTAMPTZ 字段schema.add_field(field_name="expire_at",datatype=DataType.TIMESTAMPTZ)# 创建 collection 时指定该字段为TTL 字段client.create_collection(collection_name="rag_knowledge_v2",schema=schema,index_params=index_params,properties={"ttl_field": "expire_at"})# 插入时每条数据带独立的过期时间client.insert(collection_name="rag_knowledge_v2",data=[{"text": "...", "vector": [...], "expire_at": "2025-08-01T00:00:00Z"}, # 短期有效{"text": "...", "vector": [...], "expire_at": "2026-12-31T00:00:00Z"}, # 长期保留])
注意:两种 TTL 模式互斥,不能同时设置 collection.ttl.seconds 和 ttl_field。
07 容错:Loop 挂了不应该从零开始
在 coding agent 场景里,如果一个 loop 挂了,通常可以重跑。代码还在 git 里,状态也相对容易恢复。但这会导致整体的agent任务执行时间,被无限拉长,在RAG 中,数据 loop 的恢复成本更高。如果 Milvus 实例故障,里面可能有几百万、几千万条向量数据,还有已经构建好的索引。重新生成 embedding、重新导入、重新建索引,成本都很高。所以,RAG 数据 loop 需要的不只是逻辑回滚,还需要物理层面的容错。可以把这里分成两层来看:Snapshot 解决的是“我想回到某个历史版本”。Milvus 3.0 的 CDC Replication 解决的是“主集群出问题后,数据层怎么继续服务”。注:以下关于 CDC Replication 的拓扑描述基于 Milvus 的设计文档和 GitHub Issue(#47351)中的功能规划。该功能在持续迭代中,具体 API 和行为以官方文档正式发布为准。
在 primary-secondary 架构里,一个 PRIMARY 集群接受写入,一个或多个 SECONDARY 集群通过 WAL 复制持续同步。SECONDARY 记录自己的同步位置。发生故障后,可以通过 switchover (计划内切换,主备角色互换,数据不丢失)或 failover (非计划故障,SECONDARY 强制提升为 PRIMARY,从拓扑中移除故障节点)让备用集群接管。对 loop 来说,这意味着数据层的故障不会让整个循环从零开始。SECONDARY 一直在同步,切换后 loop 从上次的 checkpoint 继续跑。结合前面的 Snapshot,一个健壮的 RAG 数据循环的容错链路是:Snapshot 提供 point-in-time 回滚能力(逻辑层面),CDC Replication 提供持续同步和故障切换能力(物理层面)。前者解决我想回到某个版本,后者解决机器挂了怎么办。08 什么时候值得做 RAG 的数据 loop
其实,Loop engineering 的核心不是自动化本身,而是把人从循环中解放出来。你设计它一次,之后你不再 prompt 那些步骤。- 因此,如果你的知识库是一次性构建,内容稳定,几个月都不更新,那手动灌一次就够了。
- 如果你还是单人单 agent 使用,没有并发写入和查询,那一致性设计不是眼前最重要的问题。
- 如果数据量很小,全量重灌只需要几分钟,那 External Collection 和 Snapshot 的收益也不会特别明显。
- 如果检索效果本身还不稳定,第一步应该是把 chunking、embedding、rerank、评估集做好,而不是急着设计 loop。
- 知识库持续更新,数据源已经在对象存储或数据湖中。
- 团队频繁实验 embedding 模型、索引参数或 chunking 策略。
- 多个 agent 或服务同时读写同一个知识库。
- 不同类型内容有不同有效期,旧数据开始污染检索结果。
- 每次数据刷新都要人工盯着,出错后恢复成本很高。
注:Milvus 3.0 开源版目前处于 beta 阶段;在 Zilliz Cloud 上以 On-demand Cluster 形式提供 Public Preview 服务。文中 External Collection、Snapshot 为已发布能力,Entity-level TTL 为 3.0 新增能力,一致性级别为 Milvus 长期支持的核心能力,CDC Replication 处于功能迭代中。
作者介绍
Zilliz黄金写手:尹珉
如何理解On-demand,为什么每个做大数据语义分析、挖掘、回归的团队都需要它?观点|从Vector Database到Vector Lakebase,如何定义AI data infra的下一个十年为什么每个重复建设AI 数据pipeline的企业,都需要一个Vector Lakebase用8年时间将向量数据库做到极致后,我们为何又推出了Vector Lakebase?别让错配阶段的Data Infra,拖垮你的AI项目阅读推荐万字深度|做了8年向量数据库后,我们决定为Milvus重构AI时代的存储引擎Vector Lakebase对比Lakebase以及向量数据库,如何选型?官宣:Zilliz Vector Lakebase正式发布,作为向量数据库开创者,我们为何推出Vector Lakebase
-
07.13
雷霆霸业怎么赚钱-打金搬砖攻略
-
07.13
大话仙境0.05折版本下载—无限资源免费内购
-
07.13
云顶之弈S17赛季多少张五费卡 五费卡数量一览
-
07.13
原神四月最新兑换码—2026原石礼包码亲测可用
-
07.13
时尚百货城无限金币作弊菜单-内购破解下载
-
07.13
雷霆霸业最强职业选择—哪个职业最厉害
-
-
下载
- |
-
-
下载
- 《行尸走肉第一章》免安装中文汉化硬盘版下载
- 单机|436 MB
- 一款以动作冒险为主题的游戏
-
-
下载
- 《街头霸王X铁拳》免安装中文汉化硬盘版下载
- 单机|111MB
- 一款非常好玩的格斗游戏
-
-
下载
- |
-
-
下载
- 《暗黑破坏神3》免安装繁体中文正式版下载
- 单机|7630 MB
- 一款以角色扮演为主题的游戏
-
-
下载
- 《马克思佩恩3》免安装硬盘版下载
- 单机|27033 MB
- 一款以第三人称射击为主题的游戏