在 Show HN 上看到 Sixb 的介绍时最值得留意的其实不是某个模型也不是某个 Agent 框架而是它的自我定位enterprise AI 的 operating layer。这个定位意味着Sixb 并不想只做一次模型调用封装而是想接管企业 AI 能力的整个运行过程包括请求入口、权限策略、成本控制、上下文管理、可观测性和效果评估。这个思路值得认真拆解因为很多企业 AI 项目真正卡住的地方恰恰不是模型选型而是模型接入之后没有人能说清楚一次请求到底经过了哪些环节、消耗了多少成本、为什么回答质量忽高忽低。这篇文章不打算复述 Sixb 的内部实现因为外部资料有限也没有必要。更有价值的问题是如果把“operating layer”当成一种企业 AI 基础架构模式我们应该如何设计、实现和验证这样一个层。文章会从一个最小可运行的操作层入手给出项目结构、核心代码、数据模型、运行验证方式和常见故障排查路径。读完这些内容你可以在自己的业务系统里复现同样的工程思路也可以把同一套评判标准用来评估 Sixb 或其他类似产品。1. 先理解 operating layer 解决什么问题1.1 问题的起点不是模型而是模型背后的运营成本早期接入大模型团队最兴奋的是模型能力本身给它一段输入它能输出一段似乎很懂业务的回复。可一旦进入企业环境问题立刻变成另一副样子。模型调用的账号密钥放在哪里哪些团队能用哪些模型同一个问题被重复请求多少次上下文窗口被谁填满请求失败后是否会自动重试线上回答质量如何评估。这些问题不在模型参数里也不在应用业务代码里它们出现在模型和应用之间需要一个专门的位置来承接。这就是 operating layer 的出发点。它像操作系统管理硬件资源那样管理企业 AI 的运行资源包括模型提供方、API Key、Token 成本、请求配额、缓存命中、prompt 模板、上下文状态、链路追踪和质量评分。没有这个层AI 功能仍然可以跑但它的运行状态会变成一个黑盒。业务方只会看到接口偶尔慢、回答偶尔错、成本偶尔超却没有任何机制去定位是哪一层出了问题。1.2 操作层、模型层和应用层的边界要设计操作层先要分清它和模型层、应用层的边界。模型层解决“理解和生成能力”的问题它由大模型提供方或私有化部署环境构成。应用层解决“用户需要什么功能”的问题它负责页面交互、业务流程、数据读写。操作层处在两者之间负责把模型能力安全、稳定、可控地交付给应用层。这三层之间的依赖关系是单向的。应用层不能直接碰模型 API而是统一访问操作层操作层不执行业务逻辑只负责模型请求的治理和运行保障模型层不关心上层业务只提供推理服务。很多团队一开始没有这层应用代码里直接写 OpenAI SDK 或本地模型 HTTP 调用短期内能跑但一旦模型从实验模型换成新版、从公有云切到私有化、从单个模型变成多模型路由所有应用都要跟着改。操作层把这种变化收敛在一个地方应用层只需要面向稳定的内部接口编程。下面用一个表格概括三层的职责差异层次核心职责典型组件变化频率常见故障应用层交互、流程、数据Web 端、服务端、数据库高参数错误、权限不足操作层路由、策略、观测、评估网关、限流器、缓存、追踪中超时、限流失效、上下文溢出模型层推理、生成、语义理解LLM API、私有化推理服务低模型故障、配额不足、响应超时操作层在整个链路里处于“服务应用、治理模型”的位置。它的设计目标不是让响应更快而是让响应“可预期、可控制、可解释”。1.3 操作层必须解决的五类核心问题一个企业级 operating layer 至少要覆盖五类问题。第一类是接入管理所有模型提供方统一接入统一管理 API Key、访问地址和可用模型列表。第二类是策略控制包括调用权限、限流规则、Token 预算、内容合规检查防止个别业务线把整个账号额度打满。第三类是运行优化包括缓存命中、上下文裁剪、模型路由、失败重试目标是降低成本和延迟。第四类是观测追踪每个请求要有唯一的 trace_id记录模型名称、Token 消耗、耗时、前置 Prompt 和后置输出。第五类是质量评估将离线测试集、线上反馈、人工评分统一沉淀下来形成可比较的质量基线。这五类问题共同构成 operating layer 的功能骨架。实际产品不一定要五类全做但至少要清楚自己在哪一个维度上取舍。后面章节就按这个骨架实现一个最小可运行的操作层。2. 设计一个最小可运行的企业 AI 操作层2.1 不要一上来就做 Agent 编排先做模型访问治理很多 AI 项目喜欢直接上 Agent 编排规划、工具调用、多轮记忆、自动执行。这个方向并不错但对于一个操作层来说第一步应该是把模型访问治理做扎实。治理意味着任何一次模型请求都要经过统一入口并在入口处完成身份识别、策略检查、模型路由、日志埋点。这些能力是 Agent 编排的基础没有治理的 Agent 只是把不可控放大成不可追踪。这一节用一个 Python 示例来落地最小操作层。技术栈选择 FastAPI因为它轻量、容易写异步、天然适合作为网关。外部依赖只使用数据库用于存储配置和记录请求日志缓存使用 Redis 或内存字典。这里给出的是学习环境版本不引入 Kubernetes、服务网格和复杂消息队列以免把主题淹没在部署细节里。2.2 学习环境与生产环境的差异要先说清楚学习环境可以在单机上把 Python 进程跑起来用 Flask 或 FastAPI 直接暴露 8000 端口。生产环境则要额外考虑多实例部署、配置中心、Redis 集群、日志采集、监控告警和权限审计。最小示例为了可读性把配置写进 YAML 文件生产环境应当把这些配置外置化并通过环境变量或配置中心注入。下面这个表格用于在动手前确认环境基线环境模型层操作层数据存储可观测性学习环境兼容 OpenAI 协议的本地服务或测试账号FastAPI 单进程SQLite控制台日志测试环境固定模型版本FastAPI 多进程PostgreSQLOpenTelemetry 导出生产环境多模型路由与故障切换无状态多副本PostgreSQL Redis集中日志 指标告警本文代码可以直接在 macOS 或 Linux 上运行Python 版本建议 3.10 以上。开始前先安装依赖mkdir ai-operating-layer cd ai-operating-layer python3 -m venv .venv source .venv/bin/activate pip install fastapi uvicorn pydantic pyyaml httpx如果后续要操作 SQLite建议再安装 SQLAlchemypip install sqlalchemy2.3 项目结构要按模块边界拆分操作层最容易犯的错是把所有逻辑塞进一个main.py。为了后续维护建议至少拆成以下目录ai-operating-layer/ ├── app/ │ ├── main.py # FastAPI 入口 │ ├── config.py # 读取 YAML 配置 │ ├── schemas.py # 请求与响应模型 │ ├── router.py # 统一请求入口 │ ├── policies.py # 权限、限流、成本策略 │ ├── llm_client.py # 模型调用适配层 │ └── observability.py # 日志、指标、追踪 ├── config/ │ └── config.yaml # 环境配置 ├── tests/ │ └── test_router.py # 接口测试 └── requirements.txt这个结构的学习成本很低但已经能看出操作层的职责边界router.py只做转发编排policies.py负责判断能不能放行llm_client.py负责模型调用observability.py负责记录。每个文件都可以单独测试后面替换模型或增加策略时不会相互干扰。2.4 数据模型需要记录什么操作层的数据库不能只存业务数据它还需要记录“模型请求画像”。最小数据表包括模型路由表、请求日志表、策略配置表。这里先给出一个精简的数据访问层用 SQLite 文件库演示。# app/db.py import sqlite3 import uuid from datetime import datetime, timezone def get_connection(): conn sqlite3.connect(operating_layer.db) conn.row_factory sqlite3.Row conn.execute( CREATE TABLE IF NOT EXISTS request_log ( id TEXT PRIMARY KEY, app_name TEXT, model_name TEXT, prompt_tokens INTEGER, completion_tokens INTEGER, latency_ms INTEGER, status TEXT, trace_id TEXT, created_at TEXT ) ) conn.execute( CREATE TABLE IF NOT EXISTS model_route ( id TEXT PRIMARY KEY, route_name TEXT, model_name TEXT, provider TEXT, weight INTEGER, enabled INTEGER ) ) return conn def insert_request_log(record: dict): conn get_connection() conn.execute( INSERT INTO request_log (id, app_name, model_name, prompt_tokens, completion_tokens, latency_ms, status, trace_id, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) , ( record[id], record[app_name], record[model_name], record[prompt_tokens], record[completion_tokens], record[latency_ms], record[status], record[trace_id], datetime.now(timezone.utc).isoformat(), ), ) conn.commit() conn.close()这里记录的核心不是业务内容而是请求元数据。token 数量、耗时、状态、trace_id 是整个操作层能否被观测的基础。没有这些字段后续任何质量评估和成本分析都无从谈起。3. 核心实现路由、策略、缓存、观测和评估3.1 统一请求入口先把一次调用抽象成“会话”操作层的核心是把每一次模型访问抽象成一个内部会话。会话包含应用名、会话 ID、请求 ID、消息列表、模型路由名、业务元数据。应用层关心的是业务语义操作层关心的是这次会话应该如何被治理。下面用 Pydantic 定义请求体# app/schemas.py from typing import List, Optional from pydantic import BaseModel, Field class ChatMessage(BaseModel): role: str content: str class ChatRequest(BaseModel): app_name: str Field(..., description应用标识例如 crm) session_id: str Field(default, description会话标识用于上下文管理) route_name: str Field(defaultdefault, description模型路由名) messages: List[ChatMessage] max_tokens: int Field(default1024, ge64, le8192) temperature: float Field(default0.3, ge0.0, le2.0) trace_id: Optional[str] None class ChatResponse(BaseModel): reply: str model_name: str prompt_tokens: int completion_tokens: int trace_id: strapp_name是策略治理的最小单位它决定下一层该使用什么权限、配额和缓存策略。route_name是模型路由的抽象应用不需要关心真正调用哪一个模型只需要声明自己需要的路由。trace_id是贯穿整个链路的追踪标识由客户端生成或由操作层自动生成。3.2 策略注入权限、限流和预算要一起判断在模型请求发出之前操作层必须完成三件事确认应用是否有权限使用该路由检查当前限流是否允许放行检查预算是否还有余额。这三件事如果放在业务代码里每个应用都要重复实现放在操作层里则只需要维护一份策略配置。策略配置使用 YAML# config/config.yaml apps: crm: allowed_routes: [default, fast] rate_limit: 100 # 每分钟请求数 monthly_budget_usd: 200 hr: allowed_routes: [default] rate_limit: 20 monthly_budget_usd: 50 routes: default: models: - provider: openai-compatible model_name: your-model-a weight: 80 - provider: openai-compatible model_name: your-model-b weight: 20 fast: models: - provider: openai-compatible model_name: your-model-fast weight: 100 observability: log_level: INFO metrics_enabled: true策略代码只做判断不掺入模型调用逻辑# app/policies.py import time from dataclasses import dataclass from collections import defaultdict rate_window defaultdict(list) budget_usage defaultdict(float) dataclass class PolicyResult: allowed: bool reason: str def check_rate_limit(app_name: str, limit: int) - PolicyResult: now time.time() window_start now - 60 recent [t for t in rate_window[app_name] if t window_start] rate_window[app_name] recent if len(recent) limit: return PolicyResult(False, rate_limit_exceeded) rate_window[app_name].append(now) return PolicyResult(True, ok) def check_budget(app_name: str, estimated_cost: float, budget: float) - PolicyResult: if budget_usage[app_name] estimated_cost budget: return PolicyResult(False, budget_exceeded) budget_usage[app_name] estimated_cost return PolicyResult(True, ok)这里为了教学采用了进程内字典模拟限流和预算生产环境一定要换成 Redis 的原子计数或专门的配额服务。否则多实例部署后每个实例各自统计限流会被放大到实例数倍。3.3 模型路由按权重分配失败时自动切换模型路由的价值在于不让应用层绑定某一个模型。同一套逻辑可以按权重访问多个模型也可以根据延迟、成本或可用性动态切换。这里实现一个按权重路由 失败降级的最小版本# app/llm_client.py import random import httpx from typing import Dict, List def choose_model(route_models: List[Dict]) - Dict: total_weight sum(item[weight] for item in route_models) roll random.uniform(0, total_weight) running 0 for item in route_models: running item[weight] if roll running: return item return route_models[-1] async def call_model(route_models: List[Dict], messages, max_tokens, temperature): last_error None for _ in range(2): candidate choose_model(route_models) try: payload { model: candidate[model_name], messages: [m.model_dump() for m in messages], max_tokens: max_tokens, temperature: temperature, } async with httpx.AsyncClient(timeout30) as client: resp await client.post( http://localhost:8001/v1/chat/completions, jsonpayload, ) resp.raise_for_status() data resp.json() return { model_name: candidate[model_name], reply: data[choices][0][message][content], prompt_tokens: data[usage][prompt_tokens], completion_tokens: data[usage][completion_tokens], } except Exception as exc: last_error exc continue raise RuntimeError(fmodel call failed: {last_error})上面的代码把真实模型地址写成了本地 8001 端口这是为了方便单机演示。实际项目中provider应当映射为可配置的 Base URL。模型调用失败时代码会重新选择一台模型服务降级而不是直接返回错误。这里的取舍是快速失败比无限重试更安全。因此循环只重试一次避免模型层故障时操作层自己被打满。3.4 上下文与缓存防止 Token 成本失控操作层还应该负责上下文管理。一个常见误区是让应用层无限追加历史消息导致每次请求的 prompt_tokens 越来越大。最小操作层可以做两件事一是按会话缓存最近 N 条消息二是对完全相同的请求做结果缓存。上下文裁剪的示意代码如下# app/context.py MAX_HISTORY 10 def trim_messages(messages: list, max_history: int MAX_HISTORY): if len(messages) max_history: return messages system_parts [m for m in messages if m.role system] other_parts [m for m in messages if m.role ! system] return system_parts other_parts[-max_history:]这个实现比看起来更重要。很多线上事故不是模型出错而是上下文里的旧消息太多模型把旧内容当成当前指令或者 Token 费用暴涨。默认只保留最近 10 轮能显著降低成本和噪音。同时可以增加一个简单缓存相同 app_name 加上相同消息列表在短时间内直接返回历史结果。这能减少重复计算但要注意缓存 key 不能包含温度或随机参数否则会破坏结果多样性。下面是一个最小内存缓存思路# app/cache.py import hashlib import json import time CACHE_TTL_SECONDS 300 _cache_store {} def make_cache_key(app_name: str, route_name: str, messages: list) - str: raw json.dumps({ app: app_name, route: route_name, messages: messages, }, ensure_asciiFalse) return hashlib.sha256(raw.encode(utf-8)).hexdigest() def get_cached(key: str): item _cache_store.get(key) if not item: return None if time.time() - item[ts] CACHE_TTL_SECONDS: _cache_store.pop(key, None) return None return item[value] def set_cached(key: str, value: dict): _cache_store[key] {value: value, ts: time.time()}生产环境请用 Redis 替代进程内字典并给 key 设置 TTL防止缓存无限膨胀。缓存命中后要单独记录日志方便成本分析。3.5 观测与评估没有数据就无法改进操作层的最后一个核心模块是观测与评估。观测不只是打印日志还要把模型名、token、耗时、状态、trace_id 串成一条完整记录。评估则是把人工反馈、线上点赞点踩、离线测试集结果写回到一个统一评分表。一个极简观测函数如下# app/observability.py import time import uuid from app.db import insert_request_log def start_trace() - str: return uuid.uuid4().hex def record_request(app_name, model_name, prompt_tokens, completion_tokens, latency_ms, status, trace_id): record { id: uuid.uuid4().hex, app_name: app_name, model_name: model_name, prompt_tokens: prompt_tokens, completion_tokens: completion_tokens, latency_ms: latency_ms, status: status, trace_id: trace_id, } insert_request_log(record)评估部分可以简单设计成一张反馈表包含请求 ID、用户、评分和评语。离线测试集则单独存放每次模型升级后跑一遍对比回答质量防止“模型一升级业务就变怪”的情况。操作层在这里的作用不是自动改进模型而是让改进过程有数据支撑。4. 本地运行与指标验证4.1 把网关入口串起来完成上述模块后需要用 FastAPI 把它们串成一个可调用接口。这里给出main.py的完整最小版本# app/main.py import time from fastapi import FastAPI, HTTPException from app.schemas import ChatRequest, ChatResponse from app.policies import check_rate_limit, check_budget, PolicyResult from app.llm_client import call_model from app.context import trim_messages from app.cache import make_cache_key, get_cached, set_cached from app.observability import start_trace, record_request app FastAPI(titleAI Operating Layer) app.post(/v1/chat/completions, response_modelChatResponse) async def chat(req: ChatRequest): trace_id req.trace_id or start_trace() start time.time() app_config load_app_config(req.app_name) if app_config is None: raise HTTPException(status_code403, detailapp_not_allowed) if req.route_name not in app_config[allowed_routes]: raise HTTPException(status_code403, detailroute_not_allowed) rate check_rate_limit(req.app_name, app_config[rate_limit]) if not rate.allowed: raise HTTPException(status_code429, detailrate.reason) cache_key make_cache_key(req.app_name, req.route_name, [m.model_dump() for m in req.messages]) cached get_cached(cache_key) if cached: elapsed_ms int((time.time() - start) * 1000) record_request(req.app_name, cached[model_name], 0, 0, elapsed_ms, cache_hit, trace_id) return ChatResponse( replycached[reply], model_namecached[model_name], prompt_tokenscached[prompt_tokens], completion_tokenscached[completion_tokens], trace_idtrace_id, ) route_models load_route_models(req.route_name) if not route_models: raise HTTPException(status_code500, detailroute_not_found) messages trim_messages(req.messages) try: result await call_model(route_models, messages, req.max_tokens, req.temperature) except Exception: elapsed_ms int((time.time() - start) * 1000) record_request(req.app_name, unknown, 0, 0, elapsed_ms, failed, trace_id) raise HTTPException(status_code502, detailmodel_call_failed) set_cached(cache_key, result) elapsed_ms int((time.time() - start) * 1000) record_request(req.app_name, result[model_name], result[prompt_tokens], result[completion_tokens], elapsed_ms, ok, trace_id) return ChatResponse( replyresult[reply], model_nameresult[model_name], prompt_tokensresult[prompt_tokens], completion_tokensresult[completion_tokens], trace_idtrace_id, )完整的load_app_config和load_route_models需要根据 YAML 解析实现这里核心是展示请求的完整链路权限检查、限流检查、缓存检查、上下文裁剪、模型调用、观测记录。控制台的日志顺序就能看到每一步是否正常。4.2 启动网关和模拟模型服务为了不依赖外部模型账号可以在另一个终端启动一个模拟模型服务返回固定文本和模拟 token 数# mock_model.py from fastapi import FastAPI from pydantic import BaseModel app FastAPI() class Payload(BaseModel): messages: list app.post(/v1/chat/completions) async def mock_chat(payload: Payload): content payload.messages[-1][content] return { choices: [{message: {content: fmock reply: {content}}}], usage: {prompt_tokens: 1, completion_tokens: 2}, }启动顺序如下uvicorn mock_model:app --port 8001再启动操作层网关uvicorn app.main:app --port 8000然后发送一个请求curl -X POST http://localhost:8000/v1/chat/completions \ -H Content-Type: application/json \ -d { app_name: crm, route_name: default, messages: [ {role: user, content: 帮我总结今天的客户反馈} ] }预期会得到类似响应{ reply: mock reply: 帮我总结今天的客户反馈, model_name: your-model-a, prompt_tokens: 1, completion_tokens: 2, trace_id: a1b2c3... }4.3 用日志和数据库验证运行结果请求完成后观察控制台日志和 SQLite 中的request_log表。可以用命令行查看sqlite3 operating_layer.db select app_name, model_name, prompt_tokens, completion_tokens, latency_ms, status, trace_id from request_log;正常结果应该能看到一条statusok的记录。第二次发送同样的请求会看到statuscache_hit且 prompt_tokens 和 completion_tokens 都是 0。这说明缓存生效成本没有重复消耗。对于指标验证可以用简单的聚合 SQLselect status, count(*) as cnt, avg(latency_ms) as avg_latency from request_log group by status;如果看到rate_limit_exceeded状态说明限流策略已经拦截了超量请求。这是操作层已经工作的直接证据。5. 常见故障排查从日志倒推根因5.1 为什么请求一直 403当一个请求返回 403不要先怀疑模型。问题通常出在app_name或route_name配置上。检查顺序是YAML 里是否存在该应用段落应用是否配置了该路由操作层是否读取到了最新配置文件。本地调试时最常见的错误是保存了 YAML 但没重启进程。生产环境则需要确认配置中心是否已发布以及节点是否拉取到最新配置。问题现象可能原因检查方式处理建议返回 403 app_not_allowedYAML 缺少 app 配置检查config.yaml的apps段落补充应用配置并重新加载返回 403 route_not_allowed应用未授权该路由检查应用的allowed_routes在策略配置中追加路由修改配置后仍 403进程未重新读取配置查看启动日志中的配置加载时间重启进程或触发配置热更新5.2 模型调用失败但日志里没有有效信息如果返回 502model_call_failed最外层看到的信息是不够的。排查链条应该是模拟模型服务是否还在运行端口是否正确模型服务返回的 HTTP 状态码是什么操作层的record_request是否记录了failed状态。如果request_log里没有这条记录说明异常发生在更早的解析阶段需要看请求参数是否合法。推荐在call_model的异常分支里把异常类型和请求地址一并输出except Exception as exc: last_error exc log.error(model call error, route%s, error%s, route_name, exc)这一步能避免“只看得到失败看不到失败在哪一环节”的窘境。5.3 缓存命中率低或成本突然上涨缓存命中率低的原因通常是缓存 key 设计不合理。如果请求里包含随机参数、当前时间戳、用户 ID 等变化频繁的字段缓存永远无法命中。成本上涨则可能是上下文裁剪失效或某条业务消息里被写入了超长文档。排查方法是先在request_log里按prompt_tokens排序找出单次消费最高的请求再看具体的消息内容。另一个常见坑是缓存的 key 没有包含route_name。如果同一个请求在使用不同模型路由时返回相同结果就会污染数据。上面的示例已经考虑了这一点实际项目扩展时也要保持这个字段。5.4 多实例下的限流和预算为什么失准本地运行限流正常部署到多实例后限流失效这是经典的“进程内状态”问题。rate_window存放在单进程内存里多实例各自统计总请求量会翻倍。预算也是同样道理budget_usage没有共享存储。解决方式是把计数放入 Redis并使用INCR和EXPIRE实现窗口计数。排查限流问题时可以观察request_log中同一秒的请求数如果明显高于配置的限流阈值基本可以确认计数状态没有共享。6. 生产环境落地检查清单与扩展方向6.1 发布前检查清单从演示到生产操作层还需要补齐很多细节。下面这份清单可以直接用于上线前走查[ ] 所有模型 Base URL、API Key 通过环境变量或配置中心注入不写入代码仓库[ ] 限流和预算计数改用 Redis 或分布式计数服务[ ] 每个请求都生成或透传 trace_id并在前端、应用层、操作层保持一致[ ] 请求日志写入集中存储避免日志散落在本地文件[ ] 缓存设置 TTL并监控缓存命中率和缓存存储占用[ ] 模型路由具备故障切换和人工熔断开关[ ] prompt 内容和模型输出经过合规检查与敏感信息过滤[ ] 模型升级前先在离线测试集上跑分再按比例灰度[ ] 建立线上质量反馈入口并定期人工抽检[ ] 记录单次请求成本和月度成本按应用维度拆分这份清单每一项都能在出现问题时追溯到具体责任模块避免上线后又回到“谁都不清楚 AI 系统内部发生了什么”的状态。6.2 用同一套标准评估 Sixb 这类产品如果你正在评估 Sixb 或其他企业 AI 操作层产品可以带着上面的技术框架去看它的功能边界。重点看几个维度是否提供统一模型接入和路由策略控制是否支持权限、限流、预算和合规观测链路能否贯穿应用层到模型层评估体系是否有闭环反馈以及它是否提供了可接入现有基础设施的接口。任何产品都可能在某个维度做得深、其他维度做得浅关键是和你的业务痛点对齐。对于自研团队也可以把这一章的实现当作起点先跑通最小操作层再逐步补足生产级组件。不要一开始就追求 Agent 编排先把模型访问治理做好后续加什么能力都会更顺。6.3 实际落地中的几个关键判断操作层的实现深度要和企业规模匹配。小团队、少数应用接入时一个 FastAPI 网关加数据库日志就够用。应用数量多了以后自然要引入配置中心、分布式限流、消息队列和集中监控。真正值得投资的是三个位置统一配置管理、统一可观测性、统一成本核算。这三个位置一旦打通后续新增模型、新增应用、调整路由都可以在不改业务代码的情况下完成。给新手的练习建议是先不要接真实模型用模拟模型服务把操作层的请求链路跑通再逐步加入限流、缓存、路由、评估。每一步都通过request_log验证是否生效。等你能够准确解释“某一次模型响应的完整处理链路”时你对操作层的理解就已经超过大多数只写 prompt 调用的开发者了。在此基础上再接触 Sixb评价会准确得多。