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的运行

最近,在硅谷又多了一个流行新词,Loop Engineering。而伴随Loop Engineering的爆火,Anthropic Claude Code 负责人 Boris Cherny、OpenClaw的创始人Peter在内诸多大神开始公开发声:loop会彻底取代prompt,成为人与LLM交互的新范式。这里可能很多人还不清楚发生了什么。翻译一下,所谓Loop,就是你设计一套系统,让它自己发现问题、分派任务、检查结果、记录状态,并决定下一步的思路。而Prompt Engineering 只能你不断告诉模型下一步做什么。在 coding 场景里,这套模式已经跑起来了。比如每天自动扫描 CI 失败、issue、commit,让 agent 修复代码,再让另一个 agent 审查,通过后自动提 PR。但 loop 不只适合写代码。RAG 系统的数据运维,也同样非常适合用 loop 的方式重新组织。因为 RAG 系统最大的问题,往往不是第一次把知识库建起来,而是后面每天都要维护它:灌文档、刷索引、换模型、清过期、故障恢复……很多团队今天还是靠脚本处理这些事,等到下次再出问题,再改脚本。而这些任务,其实非常适合用 loop 循环去做优化,因为无论是coding场景,还是RAG场景,其实都需要持续触发、隔离执行、状态记录、结果验证和失败恢复。但如何从向量数据库层面去支撑Loop Engineering的运行?以下是我们对Loop Engineering的一些理解,以及我们在Milvus 3.0 中的思考与针对性能力建设,希望可以帮你做好RAG建设。01 Loop Engineering 到底是什么,为什么RAG需要它
过去两年,很多人使用 coding agent 的方式是这样的:你写一个 prompt—模型返回结果—你看结果—你再写下一个 prompt。这个过程里,人是循环的一部分。每一轮都需要人在场。agent 能走多远,取决于人的判断力。agent 能跑多快,取决于人的时间。这就是典型的 Prompt Engineering。在Loop Engineering 行业彻底换了一个思路:人类设计一个循环系统,这个循环会自动触发任务,调用 agent,检查输出,记录状态,然后决定下一步。这个系统自动发现需要做的工作,把工作分派给 agent,检查 agent 的输出,记录结果,然后决定下一步做什么。人类从循环中,跳到了循环外,变成设计循环的人。
举个 coding agent 的例子。每天早上,系统自动读取昨天失败的 CI、扫描新开的 issue、检查最近的 commit。对每一个值得处理的问题,它都会新开一个隔离工作区,让一个 agent 去修复。修完之后,再让另一个 agent 审查。审查通过,就自动提 PR、关联 issue、通知相关人。审查不过,就进入人工 triage 队列。不难发现, loop engineering 的适用范围不止于写代码。任何需要持续运行、多步骤、有判断、需要记住上下文的 agent 工作流,都可以用 loop 的框架来组织。RAG 系统看起来和 coding agent 不一样,但它们都有一个共同点:工作不是一次性的。在这些系统中,文档会更新、数据源会增加、业务规则会变化、embedding 模型会升级、旧内容会污染结果……系统中的数据运维天然是一个持续循环。手动处理,在数据量小、更新频率低的时候可以接受。但一旦系统持续运行,数据量增加,就会出现:全量重灌的成本越来越高脚本要自己记住哪些数据处理过哪些没处理过过期内容如果不清理,会一直污染检索结果写入和查询同时发生时,很难判断读到的是不是最新数据(这对agent尤其重要)每次改 embedding 模型或索引策略都缺少清晰的版本边界(数据量变大之后,引入embedding是必须的)系统故障后如果没有 checkpoint只能重跑一遍02 Loop 的五个构件,对RAG有什么启发
Addy Osmani 在 Loop Engineering 一文中把 loop engineering 拆成了五个构件加一个记忆层:Automations:按节奏自动触发任务,是 loop 的心跳Worktrees:让多个 agent 在隔离环境里并行工作。Skills:把项目知识写下来,agent 不用每次从零猜Connectors:连接 issue tracker、CI、Slack、代码仓库等外部系统。Sub-agents:把执行和检查拆开,不让同一个 agent 自写自审。Memory:记录跨轮状态,知道什么做完了、什么失败了、下一轮从哪里继续。
换到 RAG 的数据运维里,这些组件要重新翻译。Automations 对应持续的数据与索引的持续刷新;Memory 对应 checkpoint 和版本状态;Sub-agents 对应写入、验证、线上读取之间的职责拆分。Skills 对应数据处理规则,比如 chunking 策略、metadata 提取规则、字段索引规则、数据源优先级等。Connectors 对应数据源和下游应用(Milvus 3.0 的 External Collection 本身就承担了部分 connector 的角色,下文会展开)。此外,RAG 的数据 loop 还有两个 coding agent 不太操心的问题:第一,数据会不断变多,过期内容必须自动清理。第二,向量库一旦故障,恢复成本远高于重跑一个 coding task。下面会结合Milvus 3.0的能力逐一展开。03 Heartbeat:数据灌入成为持续任务后,要如何处理索引
在 coding agent 的 loop 里,Automations 是心跳,它会每天早上自动跑一轮 CI triage,读昨天的失败、issue、commit,把发现写进状态文件,触发下游修复。没RAG 系统的心跳是持续的数据灌入。传统做法是把数据搬进向量库。数据在对象存储或数据库里有一份,在 Milvus 里又有一份。然后你还要维护两边的同步关系。这个过程中,全量重灌的成本随数据量线性增长,不可持续。因此,在Milvus 3.0 中,我们在 External Collection 设计上换了一个思路:数据不搬家,索引去数据那里。
External Collection 可以直接引用外部存储里的数据,比如 S3 上的数据,Parquet、Lance、Vortex、Iceberg 格式都可以。这个过程中,Milvus 不需要把数据复制进自己的存储,而是在外部数据上建立映射和索引,然后提供查询能力。当源数据发生变化时,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,然后手动切换。更糟糕的情况是没有备份,只能把旧模型重新跑一遍。
Milvus 3.0 的 Snapshot 可以被理解为 RAG 数据 loop 的 checkpoint。Snapshot 是 collection 在某个时间点的只读视图。它记录向量数据、元数据、索引和 schema 在某个时间点的完整状态。关键是,create 操作是轻量的,创建通常在毫秒级完成,不复制实际数据:发现问题需要回滚时,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 那些步骤。
但 loop 化是有成本的。你需要设计心跳节奏、checkpoint 策略、一致性级别选择、过期策略、容错拓扑。上面讲的每一个能力都增加了系统复杂度。- 因此,如果你的知识库是一次性构建,内容稳定,几个月都不更新,那手动灌一次就够了。
- 如果你还是单人单 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
Perplexity据悉获2亿美元融资:估值升至200亿美元
-
07.13
AI时代的教育之问Ⅶ:就业转型
-
07.13
华人工程师被疯抢:世界第一AI创业公司走进覆灭前夜
-
07.13
专注负氧离子纳米材料研发:氧宜居完成5000万元A轮融资
-
07.13
GPT-4o宁让人类陷入危险 也不愿被关闭:OpenAI前高管敲响警钟
-
07.13
AI眼镜:大厂和小厂的生存之道
-
-
下载
- |
-
-
下载
- 《行尸走肉第一章》免安装中文汉化硬盘版下载
- 单机|436 MB
- 一款以动作冒险为主题的游戏
-
-
下载
- 《街头霸王X铁拳》免安装中文汉化硬盘版下载
- 单机|111MB
- 一款非常好玩的格斗游戏
-
-
下载
- |
-
-
下载
- 《暗黑破坏神3》免安装繁体中文正式版下载
- 单机|7630 MB
- 一款以角色扮演为主题的游戏
-
-
下载
- 《马克思佩恩3》免安装硬盘版下载
- 单机|27033 MB
- 一款以第三人称射击为主题的游戏