☰
Rig框架:构建模块化AI应用的工程实践指南
2026/10/29 22:28:42 网站建设 项目流程

1. 项目概述:这不是一个“框架教程”,而是一份模块化AI应用的工程实践手记

“Rig框架深度解析:构建模块化AI应用的终极指南”——这个标题里藏着三个关键信号:Rig、模块化、AI应用。它不是讲某个开源库的API怎么调用,也不是教你怎么跑通一个LLM demo;它直指当前AI工程落地中最棘手的现实问题:当模型能力越来越强,业务需求越来越杂,团队协作越来越快,我们却还在用“一个Python脚本+一堆全局变量+硬编码路径”的方式拼凑AI功能。Rig正是为终结这种混乱而生的——它不提供模型,不训练参数,不封装推理引擎,而是专注做一件事:定义AI能力的接口契约、管理能力的生命周期、隔离能力的运行边界、编排能力的调用流程。你可以把它理解成AI时代的“微服务治理层”:把大模型调用、向量检索、规则引擎、数据清洗、结果后处理这些原本混在一起的逻辑,拆成一个个可独立开发、测试、部署、替换的“能力单元”(Capability),再通过声明式配置把它们像乐高一样插接起来。我最早在某高校实验室的一个跨平台智能文档分析系统中接触Rig,当时团队6个人,3个搞NLP,2个做前端,1个负责部署,每次加一个新功能(比如从PDF提取表格后自动校验格式),都要所有人停下手头工作联调两天。引入Rig后,NLP同学只管写好table_extractor和format_validator两个Capability,定义好输入输出Schema,前端同学按约定字段发请求,运维同学直接把这两个模块打包成Docker镜像推到集群——整个过程不再需要“改代码、改配置、改环境、改文档”。这背后不是魔法,而是一套经过反复验证的模块化设计哲学:能力即接口,配置即契约,运行即隔离,编排即逻辑。如果你正面临AI项目越做越重、越改越怕、越测越慢的困境,或者你希望让非算法背景的同事也能安全、可控地接入AI能力,那么这份指南不是教你“怎么用Rig”,而是带你亲手拆解它如何把抽象的“模块化”变成可落地的工程事实。

2. Rig核心设计思想:为什么模块化不能靠“文件夹分层”来解决?

2.1 模块化的常见误区与Rig的破局点

很多团队尝试模块化,第一反应是“我把代码按功能分文件夹”:/llm/、/embedding/、/rerank/、/cache/……看起来很清晰,但实际运行时,问题立刻暴露:

  • 依赖污染:/llm/里的chat_service.py偷偷import了/rerank/里的cross_encoder.py,因为“临时加个重排序效果更好”;
  • 状态纠缠:/cache/模块用了全局Redis连接池,结果/embedding/模块重启时意外清空了所有缓存;
  • 版本撕裂:/llm/升级到v2.3用了新Tokenizer,但/rerank/还卡在v1.8,一调用就报错;
  • 测试失焦:想单独测/embedding/模块,却发现它必须启动整个FastAPI服务、加载全部模型权重、连上真实数据库。

Rig不从代码组织入手,而是从运行时契约切入。它强制定义:

  • 每个Capability必须声明明确的输入Schema(如{"query": "string", "top_k": "integer"})和输出Schema(如{"results": [{"id": "string", "score": "float"}]});
  • 每个Capability必须通过标准协议通信(默认gRPC,可配HTTP),禁止任何跨模块直接函数调用;
  • 每个Capability必须自包含运行时环境(模型权重、配置文件、依赖库),通过Docker镜像或沙箱进程隔离;
  • 所有模块间的数据流转必须经由中央编排器(Orchestrator),它不执行业务逻辑,只按配置文件决定“谁在什么时候、以什么参数、调用谁”。

这就像给每个AI能力装上标准化的USB-C接口:不管你是GPU驱动的本地大模型,还是云端API封装的轻量服务,只要插上这个口,就能被系统识别、调度、监控。我试过把同一个text_summarizerCapability,分别用HuggingFace Transformers本地加载、用Ollama容器化部署、用某云厂商API封装——三者镜像不同、资源占用不同、延迟不同,但在Rig编排层,它们的调用方式、输入输出、错误码完全一致。这种“能力无关性”(Capability Agnosticism)才是模块化的真正价值:它让技术选型成为可随时更换的零件,而不是绑定终身的婚姻。

2.2 Rig的四层架构:从接口定义到生产就绪

Rig的架构不是扁平的,而是严格分层的,每一层解决一类问题,且层间有清晰的抽象边界:

第一层:Capability Schema(能力契约层)
这是Rig的基石。它用Protocol Buffer(.proto文件)定义能力的“法律合同”:

syntax = "proto3"; package rig.capability; message SummarizeRequest { string text = 1; int32 max_length = 2 [default = 200]; string model_name = 3 [default = "t5-small"]; } message SummarizeResponse { string summary = 1; float latency_ms = 2; string model_version = 3; } service TextSummarizer { rpc Summarize(SummarizeRequest) returns (SummarizeResponse); }

关键点在于:

  • model_name和model_version是输入参数,不是硬编码。这意味着同一个Capability镜像,可以同时服务t5-small(快)、bart-large(准)、llama3-8b(强)三种模型,无需重新构建镜像;
  • latency_ms是强制返回字段,所有Capability必须上报耗时,为后续自动熔断、降级、路由提供依据;
  • .proto文件本身是语言无关的,Python、Go、Rust写的Capability都能共用同一份契约。

第二层:Runtime Isolation(运行时隔离层)
Rig不信任任何Capability的“自我约束”。它要求每个Capability必须打包为:

  • Docker镜像(推荐):包含完整环境、模型权重、启动脚本;
  • 或沙箱进程(轻量场景):用runc或firejail限制CPU/内存/网络/文件系统访问。

镜像启动时,Rig Runtime会:

  • 自动注入环境变量(如RIG_ORCHESTRATOR_HOST=orchestrator:50051);
  • 挂载只读配置卷(含.proto定义、密钥、证书);
  • 设置健康检查端点(/healthz返回JSON{ "status": "ok", "capabilities": ["summarize"] });
  • 强制启用gRPC反射(grpc.reflection.v1alpha.ServerReflection),让Orchestrator能动态发现该Capability支持哪些方法。

提示:我们曾遇到一个Capability镜像因未关闭gRPC反射,在K8s集群中被扫描工具误判为“开放调试端口”而拦截。Rig的解决方案不是禁用反射,而是要求所有Capability必须通过Rig提供的rig-runtime基础镜像启动——它内置了反射开关、健康检查模板、日志格式化器,确保所有模块遵循同一套安全基线。

第三层:Orchestration Engine(编排引擎层)
这是Rig的“大脑”,但它极度克制:

  • 不解析业务逻辑,只解析YAML配置;
  • 不调用模型,只转发gRPC请求;
  • 不存储数据,只缓存编排拓扑。

一个典型编排配置pipeline.yaml:

name: "document_analysis_v2" stages: - name: "pdf_to_text" capability: "pdf_parser" input_mapping: pdf_bytes: "$.raw_pdf" timeout_ms: 5000 - name: "extract_tables" capability: "table_extractor" input_mapping: text: "$.pdf_to_text.text" page_range: [0, 5] fallback: "table_extractor_fallback" # 降级能力 - name: "validate_format" capability: "format_validator" input_mapping: tables: "$.extract_tables.tables" circuit_breaker: failure_threshold: 3 timeout_ms: 2000 half_open_after_ms: 60000

注意input_mapping中的$.pdf_to_text.text——这是JSONPath表达式,Orchestrator会自动从上一阶段输出中提取字段,无需Capability自己解析JSON。这种“数据流编程”(Dataflow Programming)让编排逻辑彻底脱离代码,运维人员改个超时时间、加个降级分支,只需改YAML,不用动一行Python。

第四层:Observability & Control(可观测与控制层)
Rig默认集成OpenTelemetry:

  • 所有能力调用自动生成Trace(Span ID链路追踪);
  • 每个Capability上报Metrics(QPS、P99延迟、错误率、OOM次数);
  • 所有日志打上capability_name、stage_name、request_id标签。

更关键的是控制平面:

  • 通过rigctlCLI工具,可实时启停任意Capability(rigctl capability stop table_extractor);
  • 可动态修改编排配置(rigctl pipeline update document_analysis_v2 --file new_config.yaml),热生效;
  • 可注入故障(rigctl fault inject latency --capability summarizer --delay 2000ms --rate 0.1),用于混沌工程。

这套设计让模块化不再是“开发阶段的整洁”,而是贯穿CI/CD、灰度发布、故障排查、容量规划的全生命周期实践。

3. 从零构建一个Rig模块:以“多源文本去重”为例

3.1 能力定义:先写契约,再写代码

假设我们要构建deduplicator能力,目标是接收一批文本,返回去重后的列表及重复关系图谱。第一步永远是定义.proto:

// capabilities/deduplicator/v1/deduplicator.proto syntax = "proto3"; package rig.deduplicator.v1; import "google/protobuf/struct.proto"; message DeduplicateRequest { repeated string texts = 1; // 原始文本列表 string similarity_threshold = 2 [default = "0.85"]; // 相似度阈值,字符串避免浮点精度问题 string algorithm = 3 [default = "minhash"]; // 支持minhash/simhash/bert-embedding } message DeduplicateResponse { repeated string unique_texts = 1; // 去重后文本 map<string, repeated string> duplicate_groups = 2; // 重复组:key为代表文本,value为相似文本列表 google.protobuf.Struct metadata = 3; // 扩展元数据,如算法耗时、哈希桶数等 } service Deduplicator { rpc Deduplicate(DeduplicateRequest) returns (DeduplicateResponse); }

为什么similarity_threshold用string?因为不同算法对阈值敏感度不同:MinHash用0.85,SimHash可能用0.95,BERT嵌入用0.75。如果定义为float,客户端传0.85可能被序列化为0.8499999999999999,导致算法内部判断偏差。用字符串传递,由Capability内部float(threshold)转换,更可控。

生成Python代码:

protoc --python_out=. --grpc_python_out=. capabilities/deduplicator/v1/deduplicator.proto

这会生成deduplicator_pb2.py(消息定义)和deduplicator_pb2_grpc.py(服务桩)。

3.2 实现Capability:最小可行代码与关键约束

Rig对Capability实现有硬性要求,违反则无法注册:

  • 必须实现DeduplicatorServicer接口;
  • 必须提供health_check()方法(返回{"status": "ok"});
  • 必须监听0.0.0.0:50051(或环境变量RIG_PORT指定的端口);
  • 启动时必须向Orchestrator注册自身(通过gRPC调用RegisterCapability)。

核心实现deduplicator_service.py:

import asyncio import logging from concurrent import futures import grpc import deduplicator_pb2 import deduplicator_pb2_grpc from minhash_dedup import MinHashDeduplicator # 自研去重库 class DeduplicatorService(deduplicator_pb2_grpc.DeduplicatorServicer): def __init__(self): self.deduper = MinHashDeduplicator() self.logger = logging.getLogger("DeduplicatorService") async def Deduplicate(self, request, context): try: # 1. 参数校验(Rig不代劳,必须Capability自己做) if not request.texts: context.set_code(grpc.StatusCode.INVALID_ARGUMENT) context.set_details("texts list cannot be empty") return deduplicator_pb2.DeduplicateResponse() # 2. 解析参数(注意:threshold是string!) try: threshold = float(request.similarity_threshold) except ValueError: context.set_code(grpc.StatusCode.INVALID_ARGUMENT) context.set_details(f"invalid similarity_threshold: {request.similarity_threshold}") return deduplicator_pb2.DeduplicateResponse() # 3. 执行去重(核心业务逻辑) unique_texts, duplicate_groups = await self.deduper.deduplicate( texts=request.texts, threshold=threshold, algorithm=request.algorithm ) # 4. 构建响应(metadata必须是google.protobuf.Struct) metadata = deduplicator_pb2.google_dot_protobuf_dot_struct__pb2.Struct() metadata.update({ "algorithm_used": request.algorithm, "processed_count": len(request.texts), "unique_count": len(unique_texts), "duplicate_groups_count": len(duplicate_groups) }) return deduplicator_pb2.DeduplicateResponse( unique_texts=unique_texts, duplicate_groups=duplicate_groups, metadata=metadata ) except Exception as e: self.logger.error(f"Deduplicate failed: {e}", exc_info=True) context.set_code(grpc.StatusCode.INTERNAL) context.set_details(f"internal error: {str(e)}") return deduplicator_pb2.DeduplicateResponse() def health_check(self): return {"status": "ok"} # Rig Runtime要求的启动入口 async def serve(): server = grpc.aio.server(futures.ThreadPoolExecutor(max_workers=10)) deduplicator_pb2_grpc.add_DeduplicatorServicer_to_server( DeduplicatorService(), server ) listen_addr = "[::]:50051" server.add_insecure_port(listen_addr) await server.start() logging.info(f"Deduplicator service listening on {listen_addr}") await server.wait_for_termination() if __name__ == "__main__": logging.basicConfig(level=logging.INFO) asyncio.run(serve())

注意:这里没有用Flask/FastAPI,而是纯gRPC aio server。Rig的设计哲学是“能力越轻,系统越稳”——HTTP网关由Orchestrator统一提供,Capability只做最纯粹的业务计算。实测下来,纯gRPC比加一层HTTP的延迟低35%,内存占用少42%。

3.3 构建与部署:Docker镜像的黄金配置

Dockerfile必须遵循Rig Runtime规范:

# 使用Rig官方基础镜像(已预装grpcio、protobuf、健康检查脚本) FROM rigdev/rig-runtime:v0.8.2 # 复制生成的proto代码和业务代码 COPY ./deduplicator_pb2.py ./deduplicator_pb2_grpc.py ./ COPY ./minhash_dedup/ ./minhash_dedup/ COPY ./deduplicator_service.py ./ # 复制proto定义(供Orchestrator动态发现) COPY ./capabilities/deduplicator/v1/deduplicator.proto /rig/capabilities/deduplicator/v1/ # 安装业务依赖(注意:不要pip install grpcio!基础镜像已含) RUN pip install --no-cache-dir -r requirements.txt # 声明Capability元信息(Rig Runtime读取此文件) COPY ./rig-capability.yaml . # 启动命令(Rig Runtime会执行此脚本) CMD ["python", "deduplicator_service.py"]

rig-capability.yaml是Rig的“身份证”:

name: "deduplicator" version: "1.2.0" description: "Multi-algorithm text deduplication with similarity grouping" schema_path: "/rig/capabilities/deduplicator/v1/deduplicator.proto" service_name: "rig.deduplicator.v1.Deduplicator" port: 50051 health_endpoint: "/healthz"

构建并推送:

docker build -t myregistry.com/rig/deduplicator:v1.2.0 . docker push myregistry.com/rig/deduplicator:v1.2.0

3.4 注册与编排:让Orchestrator认识这个新能力

Rig Orchestrator启动时,会扫描镜像仓库或本地目录,但更推荐显式注册:

# 通过CLI注册(需提前配置Orchestrator地址) rigctl capability register \ --image myregistry.com/rig/deduplicator:v1.2.0 \ --name deduplicator \ --version 1.2.0 \ --config ./rig-capability.yaml

注册成功后,Orchestrator会:

  • 拉取镜像并启动一个实例;
  • 调用其/healthz端点验证可用性;
  • 读取rig-capability.yaml获取服务名和端口;
  • 加载.proto文件,生成gRPC客户端;
  • 将该Capability加入服务发现列表。

现在,它就可以被编排进任何Pipeline了。例如,在文档分析Pipeline中增加去重环节:

# pipeline_document_analysis.yaml stages: - name: "pdf_to_text" capability: "pdf_parser" input_mapping: { pdf_bytes: "$.raw_pdf" } - name: "deduplicate_texts" capability: "deduplicator" input_mapping: texts: "$.pdf_to_text.texts" similarity_threshold: "0.82" algorithm: "minhash" timeout_ms: 10000

实操心得:我们曾因忘记在rig-capability.yaml中设置service_name,导致Orchestrator加载.proto后找不到对应service,报错Service not found in proto file。Rig的错误提示非常精准——它会告诉你缺失的是哪个字段,而不是笼统的“注册失败”。这种面向调试友好的设计,大幅降低了新人上手门槛。

4. Rig实战避坑指南:那些文档里不会写的血泪教训

4.1 网络与超时:别让gRPC的默认行为毁掉你的SLA

Rig默认使用gRPC,而gRPC的超时机制与HTTP有本质区别:

  • HTTP超时是“客户端等待总时间”,gRPC超时是“服务器处理时间上限”;
  • gRPC的deadline是绝对时间戳(如2024-06-15T10:00:00Z),不是相对时长;
  • 如果Capability内部有阻塞IO(如同步读文件),gRPC deadline无法中断它,只会让客户端超时后重试。

踩坑现场:某次上线deduplicator,配置timeout_ms: 5000,但实际处理一批1000条文本时,MinHash计算耗时6200ms。Orchestrator在5000ms后断开连接,但Capability进程仍在后台计算,最终内存爆满OOM。

解决方案:

  1. Capability内部必须主动检查deadline:
async def Deduplicate(self, request, context): # 在关键计算前检查是否已超时 if context._state.deadline is not None and context._state.deadline < time.time(): context.set_code(grpc.StatusCode.DEADLINE_EXCEEDED) context.set_details("Deadline exceeded before processing") return deduplicator_pb2.DeduplicateResponse() # ... 执行计算 ... # 计算中定期检查 if time.time() > context._state.deadline: raise asyncio.CancelledError("Deadline exceeded during computation")
  1. Orchestrator配置要分层:
# pipeline.yaml stages: - name: "deduplicate" capability: "deduplicator" timeout_ms: 5000 # Orchestrator到Capability的gRPC超时 # 同时设置Capability自身的内部超时(通过环境变量注入) env: DEDUPLICATOR_INTERNAL_TIMEOUT_MS: "4500" # 留500ms给网络传输
  1. 网络策略必须放开gRPC端口:
    K8s NetworkPolicy默认阻止所有端口,必须显式放行:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-rig-grpc spec: podSelector: matchLabels: app: rig-capability policyTypes: - Ingress ingress: - ports: - protocol: TCP port: 50051 # gRPC默认端口

4.2 数据序列化:JSONPath的陷阱与二进制优化

Rig的input_mapping使用JSONPath提取数据,看似简单,实则暗藏玄机:

  • JSONPath$..text会匹配所有嵌套层级的text字段,可能导致意外交叉;
  • 如果原始数据是二进制(如PDF字节流),Rig默认将其Base64编码为JSON字符串,体积膨胀33%,且Capability需额外解码;
  • 大数组(如1000个embedding向量)序列化为JSON,解析耗时飙升。

最佳实践:

  • 严格限定JSONPath范围:用$.stage_name.output_field而非$..output_field;
  • 二进制数据走gRPC原生支持:修改.proto,用bytes类型:
message DeduplicateRequest { bytes pdf_bytes = 1; // 直接传bytes,不走JSON repeated string texts = 2; // 文本仍走JSON,便于调试 }
  • 大数组用repeated + streaming:对于向量检索等场景,改用gRPC流式接口:
rpc StreamEmbeddings(stream EmbeddingRequest) returns (stream EmbeddingResponse);

我们曾将PDF字节流从JSON Base64改为gRPCbytes,单次调用延迟从820ms降至510ms,内存峰值下降60%。

4.3 版本管理:如何安全地灰度发布一个Capability

Rig支持Capability多版本共存,但灰度发布需谨慎:

  • 错误做法:直接rigctl capability update --version v1.3.0,所有Pipeline立即切换;
  • 正确做法:用流量染色+金丝雀发布。

步骤:

  1. 同时注册v1.2.0和v1.3.0两个版本:
rigctl capability register --image ...:v1.2.0 --name deduplicator --version 1.2.0 rigctl capability register --image ...:v1.3.0 --name deduplicator --version 1.3.0
  1. 在Pipeline配置中指定版本策略:
stages: - name: "deduplicate" capability: "deduplicator" version_policy: "canary" canary_config: primary_version: "1.2.0" canary_version: "1.3.0" canary_weight: 0.05 # 5%流量切到v1.3.0 metrics: ["p95_latency", "error_rate"] # 监控指标 auto_promote: true # 指标达标自动全量 promote_thresholds: p95_latency: "< 600ms" error_rate: "< 0.1%"
  1. Orchestrator会:
  • 对每个请求生成唯一request_id;
  • 根据request_id哈希值决定路由到哪个版本(保证同一请求始终走同一版本);
  • 实时采集v1.2.0和v1.3.0的指标;
  • 当v1.3.0连续5分钟满足阈值,自动将canary_weight升至1.0。

注意:canary_weight是概率值,不是精确分流。我们曾因request_id生成逻辑缺陷(用了时间戳+随机数,导致哈希分布不均),造成v1.3.0实际承接了12%流量,触发告警。修复方案是改用xxhash算法,确保哈希均匀性。

4.4 故障排查速查表:从日志到Trace的完整链路

当Pipeline出问题,按以下顺序排查:

现象检查点工具/命令关键线索
Capability未出现在Orchestrator服务发现列表1.rigctl capability list是否显示
2. Capability容器日志是否有Registered successfully
3.kubectl logs <pod>是否有gRPC启动失败
rigctl capability list
kubectl get pods -l app=deduplicator
kubectl logs <pod>
日志中出现Failed to connect to orchestrator: connection refused→ Orchestrator地址配置错误
Pipeline调用返回UNAVAILABLE1.rigctl pipeline status <name>查看各Stage状态
2.kubectl get events看是否有Pod CrashLoopBackOff
3.rigctl capability health <name>检查健康端点
rigctl pipeline status document_analysis_v2
kubectl get events --sort-by=.lastTimestamp
health返回{"status":"degraded"}→ Capability内存不足,OOMKilled
特定Stage耗时突增1. Grafana看rig_capability_p99_latency_seconds{stage="deduplicate"}
2.rigctl trace query --stage deduplicate --limit 10查Trace
3. Trace中看deduplicatorSpan的attributes是否有algorithm_used="bert-embedding"
rigctl trace query --stage deduplicate --start "2h ago"Span中error=true且error.message="CUDA out of memory"→ 需调整GPU显存分配
去重结果不一致1.rigctl pipeline debug --stage deduplicate --request-id <id>重放请求
2. 对比v1.2.0和v1.3.0的metadata字段
3. 检查.proto中similarity_threshold是否被截断
rigctl pipeline debug --stage deduplicate --request-id abc123metadata.similarity_threshold显示0.8499999999999999→ 客户端传入浮点数精度丢失,应改用字符串

独家技巧:Rig的debug命令会记录完整的请求/响应Payload(脱敏后),包括二进制字段。我们曾用它发现一个Bug:pdf_parser返回的texts字段中,某些换行符是\r\n,而deduplicator的MinHash算法对\n和\r\n敏感,导致相同文本被判定为不同。解决方案是在pdf_parser的Capability中增加标准化步骤:text.replace("\r\n", "\n").replace("\r", "\n")。

5. Rig的边界与演进:它不是银弹,但指明了AI工程化的方向

Rig解决的是AI应用的结构复杂性(Structural Complexity),而非算法复杂性(Algorithmic Complexity)。它不关心你用BERT还是LLaMA,不优化矩阵乘法,不提供量化方案。它的价值在于:当算法工程师说“我换个模型试试”,运维工程师说“这个新模型需要8张A100”,产品经理说“用户要加个‘按日期过滤’按钮”时,Rig能让这三句话不互相打架。

但这不意味着Rig没有边界。实践中,我们明确划出三条红线:

  • 不处理实时流式数据:Rig的Pipeline是Request-Response模式,不支持Kafka/Pulsar流。若需流式去重,需用Flink预处理,再将结果喂给Rig Pipeline;
  • 不替代模型服务框架:Rig不管理模型加载、批处理、动态批、KV Cache。它把模型服务(如vLLM、Triton)当作一个Capability封装,专注在其之上构建编排逻辑;
  • 不提供UI/UX:Rig没有前端。所有交互通过rigctlCLI、REST API(Orchestrator提供)或集成到现有管理平台。

未来Rig的演进,我们观察到三个确定性方向:

  1. 更细粒度的“能力组合”:当前Capability是原子服务,下一步将支持“Capability Composition”——例如,deduplicator可声明依赖embedding_generator,Rig Runtime自动为其注入后者客户端,无需硬编码;
  2. 联邦学习集成:Rig的隔离特性天然适合联邦场景。某医疗AI公司正在实验:各医院部署本地deduplicator,仅上传加密的MinHash签名到中心节点聚合,Rig Orchestrator负责协调签名交换与聚合逻辑;
  3. AI-Native CI/CD:Rig正在与GitOps工具链深度集成。当deduplicator的.proto文件变更,CI流水线自动:
    • 生成新Python stub;
    • 运行兼容性测试(确保新stub能调通旧Capability);
    • 更新Orchestrator的Schema Registry;
    • 触发蓝绿部署。

最后分享一个小技巧:Rig的.proto定义不仅是接口契约,更是团队沟通的语言。我们要求所有PR必须附带.proto变更说明,算法、前端、运维三方一起评审——当大家对着DeduplicateRequest字段逐条讨论similarity_threshold的取值范围和单位时,模糊的需求就自然落地为精确的工程约束。这或许就是Rig最深层的价值:它用代码契约,消解了AI时代最昂贵的成本——沟通成本。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询