Skip to content

Spring AI生产治理、SLO、成本与事故排查

Spring AI 接口能够返回一句回答,只证明模型链路基本连通,不代表可以上线。商业 AI 系统同时面对概率性输出、秒级延迟、按 Token 计费、第三方限流、Prompt Injection、RAG 越权、Tool 写操作、流式中断和模型版本漂移。治理目标不是让模型永不失败,而是让失败可以被限制、发现、解释、降级和恢复。

生产治理需要覆盖五个平面:流量与容量、可靠性、质量与评估、安全与权限、成本与运营。任何一项缺失,都可能出现“接口 200 但答案不可用”的假健康。

学习目标

完成本页后,你应该能够:

  1. 为 AI 接口分别定义可用性、延迟、质量、安全和成本 SLO。
  2. 把一次请求拆成鉴权、RAG、Rerank、模型、Tool 和后处理时间预算。
  3. 设计请求数、并发、Token 和金额四类配额。
  4. 区分可重试、不可重试和结果未知错误,避免重试雪崩。
  5. 正确使用超时、退避、抖动、Bulkhead、Circuit Breaker、排队和降级。
  6. 设计模型路由和能力兼容的 Fallback。
  7. 设计同步、流式和异步 AI 接口的错误语义。
  8. 建立模型、Prompt、RAG索引、Embedding、Tool和安全策略的版本矩阵。
  9. 设计离线评估、灰度、线上反馈和回滚门槛。
  10. 记录可排障又不泄密的日志、指标和 Trace。
  11. 分析成本突增、质量下降、429、延迟、越权和Tool误执行事故。

一、AI生产可用不等于HTTP 200

一个请求可能 HTTP 200,但仍然失败:

  • 模型编造不存在的制度。
  • JSON 不能解析。
  • 引用不支持答案。
  • RAG 召回了其他租户资料。
  • Tool 查询了错误订单。
  • 回答耗时 40 秒,用户早已离开。
  • 输入 2 万 Token,成本超过业务价值。

需要拆分 SLI:

维度示例SLI说明
技术可用性请求获得受控成功/拒答比例不把模型胡编算成功
TTFT首个Token时间P95影响流式体感
总耗时完整响应时间P95/P99影响完成率和资源占用
质量正确性、Faithfulness、格式通过率依场景评估
安全越权率、注入突破率、敏感泄露率高风险通常硬门槛
Tool正确性参数/权限/幂等/结果成功率写操作尤其严格
成本每成功任务Token和金额不能只看请求平均
拒答应答/应拒答准确率错误拒答和错误回答都要看

二、一次生产请求的治理链

mermaid
flowchart TD
    A["认证请求"] --> B["参数、大小、内容类型校验"]
    B --> C["租户、场景和数据权限"]
    C --> D["用户/租户/全局配额与并发门禁"]
    D --> E["风险分级和场景路由"]
    E --> F["RAG权限过滤、召回和重排"]
    F --> G["Prompt与上下文Token预算"]
    G --> H["模型路由、超时、Bulkhead和重试"]
    H --> I{"是否请求Tool"}
    I -->|"是"| J["工具权限、参数、确认和幂等"]
    J --> H
    I -->|"否"| K["结构化解析、引用和安全校验"]
    K --> L["响应、拒答、降级或人工审核"]
    L --> M["日志、指标、Trace、成本和反馈"]

三、先为场景分级

风险级别场景可接受策略
文案改写、内部头脑风暴可直接生成,标记AI内容
企业制度问答、客服建议RAG引用、拒答、抽样审核
医疗建议、法律结论、支付/删除Tool强规则、人工确认、最小工具权限、完整审计

同一个模型不能使用一套治理策略处理所有场景。高风险请求即使模型“看起来很确定”也不能跳过人工/规则门槛。

四、请求时间预算怎样拆

总延迟近似:

text
T_total = T_auth
        + T_rewrite
        + T_embedding
        + T_retrieve
        + T_rerank
        + T_model
        + ΣT_tool
        + T_validate

例:交互式知识问答总预算 12 秒:

阶段预算示例
鉴权/配额100ms
Query改写800ms
Embedding+检索500ms
Rerank700ms
模型TTFT2.5s
模型完整生成6s
校验/引用500ms
网络抖动余量900ms

预算只是示例。外层超时应大于内部阶段预算之和,但不能无限大:

text
内部HTTP连接超时 < 单阶段超时 < 服务总超时 < 网关超时 < 客户端超时

如果 Nginx 30 秒断开,而应用和模型仍执行 120 秒,会产生无用户接收的成本和资源浪费。

五、同步、流式和异步怎么选

模式适用风险
同步分类、抽取、短回答线程/连接等待,长尾明显
SSE流式长回答、聊天中途错误、断连、代理缓冲
异步Job大文档分析、批量评估最终一致、任务状态和取消

同步

成功前不返回,错误可用标准 HTTP 状态/业务码表达,但需要严格总超时。

流式

HTTP Header 已发送后,中途失败不能再改为 500。需要发送结构化 error event,并记录 partial output 是否展示/保存。

异步

提交返回 202 + jobId,Worker 执行,客户端轮询/Webhook。任务表要有幂等 requestId、状态、租约、重试和取消语义。

六、四种限额不能混为一个QPS

6.1 请求速率

防止单位时间请求过多。

6.2 并发数

AI 请求慢,即使 QPS 不高也可能占满连接、线程和 Provider 并发。

6.3 Token额度

同样一个请求可能是 100 Token 或 100000 Token。只限 QPS 无法控制成本和上下文压力。

6.4 金额/业务额度

按用户、租户、场景和日期控制预算,保留管理配额和应急余量。

mermaid
flowchart TD
    A["请求进入"] --> B{"用户速率是否超限"}
    B -->|"是"| C["429或排队"]
    B -->|"否"| D{"租户并发是否有槽位"}
    D -->|"否"| E["快速失败/短队列"]
    D -->|"是"| F{"估算Token和金额是否超预算"}
    F -->|"是"| G["拒绝、压缩上下文或降级模型"]
    F -->|"否"| H["预留额度并调用"]
    H --> I["按实际Usage结算差额"]

七、配额数据怎样并发更新

不要“先查余额,再更新余额”,并发请求可能一起通过。

条件更新示例:

sql
UPDATE ai_tenant_quota
SET reserved_tokens = reserved_tokens + ?,
    row_version = row_version + 1,
    updated_at = CURRENT_TIMESTAMP
WHERE tenant_id = ?
  AND quota_date = ?
  AND used_tokens + reserved_tokens + ? <= token_limit;

更新行数为 1 才获得额度。请求结束后按实际 Token 结算;崩溃未结算的 Reservation 需要过期回收和对账。

云 Provider Usage 可能缺失或延迟,应用还应保存估算值和账单对账。

八、本地Semaphore为什么不等于全局并发限制

java
private final Semaphore semaphore = new Semaphore(20);

单实例有效;部署 10 个 Pod 后全局可能达到 200。全局配额需要 Redis/数据库/网关或集中 AI Gateway,且要处理租约过期和节点崩溃。

本地 Semaphore 仍可作为每实例 Bulkhead,防止模型调用占满全部线程。

九、Bulkhead解决什么

将不同场景/Provider隔离:

text
知识库问答池
合同抽取池
低优先级批处理池
高风险Tool池

批量评估流量不应耗尽在线客服并发。Bulkhead 可以是独立线程池、连接池、队列、Pod或Provider配额。

十、什么错误可以重试

错误是否自动重试原因
400参数/模型不支持请求本身错误
401/403密钥/权限错误,重试放大流量
404模型不存在配置错误
409/Provider特定冲突视语义先理解错误码
429条件重试尊重Retry-After和总预算
5xx有限重试可能瞬时故障
连接超时有限重试可能尚未发送成功
读取超时谨慎Provider可能已生成并计费
输出Schema失败可有限修复重试需不同Prompt/修复策略
Tool写操作超时默认不盲重试外部可能已成功,先按幂等键确认

十一、指数退避和抖动

text
delay = min(maxDelay, baseDelay * 2^attempt) + randomJitter

还要限制:

  • 最大尝试次数。
  • 单请求总截止时间。
  • 全局重试预算,例如重试流量不超过正常流量10%。
  • Retry-After。
  • 可重试错误白名单。

没有抖动时,大量请求会在同一时间再次冲击 Provider。

十二、重试为什么会重复计费

读取超时不代表 Provider 没生成。第一次可能已经完成并计费,客户端只是没收到响应;重试会再次生成。

记录 clientRequestId/providerRequestId,Provider支持幂等键时使用;不支持时把重复成本纳入预算,并避免对长生成无脑重试。

十三、Circuit Breaker是什么

当 Provider 持续失败时,继续请求只会占用资源和放大故障。Circuit Breaker 状态:

mermaid
flowchart TD
    A["CLOSED正常调用"] -->|"失败率/慢调用超过阈值"| B["OPEN快速失败"]
    B -->|"等待窗口到期"| C["HALF_OPEN放少量探测"]
    C -->|"探测成功"| A
    C -->|"探测失败"| B

断路器按 Provider/模型/区域区分,不能一个小模型失败就熔断全部 AI 能力。

十四、降级不是随便换个模型

模型 Fallback 必须满足场景能力:

场景降级可行性
普通摘要可切更便宜模型或模板摘要
JSON抽取备用模型必须通过Schema评估
Tool Calling备用模型必须支持相同Tool Schema
多模态OCR文本模型不能直接替代图片能力
高风险医疗问答更适合拒答/人工,不应降级到低质量模型

每个路由版本要记录 primary/fallback、能力、价格、区域和评估分。

十五、模型路由

mermaid
flowchart TD
    A["识别场景、风险、语言和输入模态"] --> B{"是否需要Tool/JSON/多模态"}
    B -->|"是"| C["过滤不支持能力的模型"]
    B -->|"否"| D["候选模型集合"]
    C --> D
    D --> E["按质量门槛过滤"]
    E --> F["按延迟、成本、区域和配额选择"]
    F --> G["记录routeVersion和实际模型"]

模型路由属于后端策略,不接受用户直接传任意模型名绕过预算和数据区域。

十六、Prompt版本不是唯一版本

一次回答由版本矩阵决定:

text
applicationVersion
modelProvider/modelName/modelRevision
modelOptions
promptVersion
advisorChainVersion
embeddingModelVersion
chunkStrategyVersion
ragIndexVersion
retrieval/rerankConfigVersion
toolSchemaVersion/toolImplementationVersion
safetyPolicyVersion

事故复现必须拿到整个矩阵。只说“Prompt没改”无法证明系统没变。

十七、Prompt注册表示例

sql
CREATE TABLE ai_prompt_release (
    prompt_key VARCHAR(128) NOT NULL,
    prompt_version VARCHAR(64) NOT NULL,
    content_hash VARCHAR(128) NOT NULL,
    content_location VARCHAR(500) NOT NULL,
    model_route_version VARCHAR(64) NOT NULL,
    evaluation_run_id VARCHAR(64) NOT NULL,
    release_status VARCHAR(32) NOT NULL,
    released_by VARCHAR(64),
    released_at TIMESTAMP,
    PRIMARY KEY (prompt_key, prompt_version)
);

真实 Prompt 内容可能包含内部规则,不应无权限暴露到前端或普通日志。

十八、结构化输出必须校验

mermaid
flowchart TD
    A["模型输出JSON文本"] --> B["JSON语法解析"]
    B --> C["Schema/Bean Validation"]
    C --> D["业务规则校验"]
    D --> E{"是否通过"}
    E -->|"是"| F["进入业务流程"]
    E -->|"否"| G["修复重试、人工或失败"]

模型输出:

json
{"amount": -100, "currency": "ABC"}

JSON 合法但业务非法。必须校验金额非负、币种白名单、ID是否存在、用户是否有权限。

十九、Tool Calling生产边界

Tool 参数全部视为不可信输入:

  • userId/tenantId从认证上下文注入,不信模型参数。
  • 查询做数据权限和字段最小化。
  • 写操作有requestId、幂等、二次确认和审计。
  • 金额使用BigDecimal。
  • 超时后先查询执行结果,不能无条件重试。
  • Tool返回内容先脱敏再交给模型。

Tool详细原理见:Spring AI Tool Calling

二十、RAG缓存Key为什么必须包含权限和版本

危险 Key:

text
hash(question)

用户 A 的答案可能被返回给无权限用户 B。

安全 Key 至少考虑:

text
tenantId
permissionScopeVersion/roleSetHash
scene
normalizedQuestion
promptVersion
modelRouteVersion
ragIndexVersion
retrievalConfigVersion
safetyPolicyVersion
language

高风险实时业务不应只依赖语义缓存。缓存值还要有引用、生成时间、资料版本和安全结果。

二十一、什么可以缓存

对象是否适合注意
公共低风险FAQ适合版本化和TTL
Embedding适合Key含模型和规范化文本Hash
文档解析结果适合Key含文件Hash和解析器版本
Rerank结果条件适合Key含候选集、模型和ACL
用户私有RAG答案谨慎严格权限Key与删除同步
账户余额/库存不适合普通AI缓存走实时Tool
Tool写操作结果不是普通缓存使用幂等记录

二十二、日志怎样既可排查又不泄密

推荐记录:

text
requestId, traceId, tenantScopeHash, userScopeHash,
scene, riskLevel, routeVersion,
provider, model, promptVersion, advisorVersion,
ragIndexVersion, retrievedChunkIds,
toolNames, toolCallIds, toolResultCodes,
inputTokens, outputTokens, estimatedCost,
queueMs, retrieveMs, rerankMs, ttftMs, totalMs,
finishReason, responseValidationResult,
safetyResult, refusalReason, errorCode

不记录:API Key、密码、完整身份证/病历、完整 Prompt、完整 Tool 结果和可逆敏感映射。

需要保留原文用于质量复现时,放在访问受控、加密、有限保留期的评估/审计存储,不是普通应用日志。

二十三、Trace怎样拆Span

mermaid
flowchart TD
    A["ai.request"] --> B["auth.quota"]
    A --> C["query.rewrite"]
    A --> D["embedding"]
    A --> E["vector.retrieve"]
    A --> F["rerank"]
    A --> G["chat.model"]
    G --> H["tool.call"]
    A --> I["output.validate"]

Span 属性使用低敏感、低基数分类。requestId 在 Trace/日志中可查,但不要把 Prompt 正文放 Span Attribute。

二十四、核心指标

流量和容量

  • requests/s、concurrent requests、queue depth。
  • input/output Token/s。
  • Provider/模型并发和配额剩余。

延迟

  • queue、retrieval、rerank、TTFT、generation、tool、total P50/P95/P99。

错误

  • 4xx、401/403、429、5xx、timeout、cancel、parse/schema、tool error。
  • retry attempts、circuit state、fallback count。

质量和安全

  • evaluation score、refusal accuracy、citation validity。
  • ACL violation、prompt injection detected、sensitive output blocked。

成本

  • Token/金额按tenant、scene、model、promptVersion聚合。
  • 每成功业务任务成本,不只每请求成本。

指标 Label 不放 userId/requestId/conversationId。

二十五、Spring AI可观测性边界

Spring AI 可以接入 Spring Observability/Micrometer,帮助产生模型、Embedding、VectorStore 等 Observation。仍需确认:

  • 当前版本默认启用哪些 Observation。
  • Prompt/Completion是否默认不导出,避免误开启敏感内容。
  • Provider Token Usage是否完整。
  • 自定义 Advisor/Tool/Rerank是否有独立 Span。
  • 采样后是否仍能保留事故请求。

框架指标不能替代业务质量指标。

二十六、健康检查怎样设计

不要让 Liveness 依赖外部模型:Provider 短暂故障会让所有 Pod 被重启,形成重启风暴。

Readiness 也要谨慎。如果全部实例因共享 Provider 不可用而 NotReady,入口没有任何后端。更常见做法:应用保持 Ready,AI 接口根据 Circuit/Provider状态返回受控降级,健康详情供告警而非直接摘除全部服务。

二十七、流式响应治理

事件格式示例:

text
event: meta
data: {"requestId":"...","model":"..."}

event: delta
data: {"text":"第一段"}

event: error
data: {"code":"MODEL_TIMEOUT","retryable":true}

event: done
data: {"finishReason":"STOP","totalTokens":1234}

必须考虑:

  • 客户端断开取消上游模型订阅。
  • 已输出部分文本是否通过安全检查。
  • Tool Call期间前端显示什么状态。
  • Nginx proxy_buffering、idle timeout 和心跳。
  • 重连不能自动再次执行写 Tool。
  • done 未到达时如何结算和记录 partial response。

二十八、异步任务表

sql
CREATE TABLE ai_job (
    job_id VARCHAR(64) PRIMARY KEY,
    request_id VARCHAR(64) NOT NULL UNIQUE,
    tenant_id VARCHAR(64) NOT NULL,
    scene VARCHAR(64) NOT NULL,
    job_status VARCHAR(32) NOT NULL,
    lease_owner VARCHAR(128),
    lease_until TIMESTAMP,
    retry_count INT NOT NULL DEFAULT 0,
    route_version VARCHAR(64) NOT NULL,
    input_ref VARCHAR(500) NOT NULL,
    output_ref VARCHAR(500),
    error_code VARCHAR(128),
    created_at TIMESTAMP NOT NULL,
    updated_at TIMESTAMP NOT NULL
);

大文本不直接塞任务行;使用受控对象存储引用,带权限、加密和生命周期。

二十九、离线评估与上线门槛

mermaid
flowchart TD
    A["冻结候选版本矩阵"] --> B["运行普通、边界、拒答、权限和攻击集"]
    B --> C["按场景/风险分组评分"]
    C --> D["比较当前生产基线"]
    D --> E{"质量、安全、延迟、成本是否达标"}
    E -->|"否"| F["拒绝发布并归因"]
    E -->|"是"| G["小流量Shadow/Canary"]
    G --> H["线上质量和安全门禁"]
    H --> I["扩大流量或回滚"]

不能只看平均分:普通问题提高 2%,但越权样例从 0 变 1 次,应阻止上线。

三十、Shadow和Canary区别

Shadow

复制真实请求给候选版本,但结果不返回用户。要确保数据合规和成本可控,写 Tool 必须禁用或模拟。

Canary

少量真实流量使用候选版本并返回结果。按 tenant/用户稳定分流,避免同一会话版本漂移。

三十一、回滚单位是什么

回滚不能只改模型名。应回滚版本矩阵指针:

text
modelRouteVersion
promptVersion
advisorVersion
ragIndexVersion
retrievalConfigVersion
toolSchemaVersion
safetyPolicyVersion

Tool 已产生的写操作、用户已看到的错误答案和外部通知不能通过配置回滚自动撤销,需要补偿和事故处置。

三十二、成本核算

单请求成本近似:

text
Cost = inputTokens * inputUnitPrice
     + outputTokens * outputUnitPrice
     + embeddingTokens * embeddingPrice
     + rerankRequests * rerankPrice
     + tool/搜索/向量库资源
     + 计算与网络成本

更有意义指标:

  • 每个成功抽取文档成本。
  • 每个自助解决客服问题成本。
  • 每个有效 Tool 任务成本。
  • 每个正确高风险回答成本。

低成本但错误率高不是优化。

三十三、成本突增常见原因

  • 输入历史无限增长。
  • RAG TopK/Chunk突然变大。
  • 输出 maxTokens 失控。
  • 重试导致重复生成。
  • Agent循环终止条件失效。
  • Tool结果过大反复回传。
  • 新模型价格或Tokenizer不同。
  • 恶意用户/Key泄露。
  • 评估/批任务误走生产高价路由。

三十四、成本预算代码结构

java
public record AiBudget(
        int maxInputTokens,
        int maxOutputTokens,
        int maxToolCalls,
        Duration deadline,
        BigDecimal maxEstimatedCost) {
}

public record AiRequestContext(
        String requestId,
        String tenantId,
        String userId,
        String scene,
        String riskLevel,
        AiBudget budget) {
}

JDK 8 使用普通不可变类。Budget 应由服务端场景策略生成,不接受前端任意增大。

三十五、受治理调用Service骨架

java
@Service
public class GovernedChatService {

    private final ChatClient chatClient;
    private final AiQuotaService quotaService;
    private final AiPolicyService policyService;
    private final AiAuditService auditService;

    public GovernedChatService(
            ChatClient chatClient,
            AiQuotaService quotaService,
            AiPolicyService policyService,
            AiAuditService auditService) {
        this.chatClient = chatClient;
        this.quotaService = quotaService;
        this.policyService = policyService;
        this.auditService = auditService;
    }

    public AiAnswer answer(
            AiRequestContext context,
            String userInput) {

        long startNanos = System.nanoTime();
        policyService.validateInput(context, userInput);

        TokenEstimate estimate = policyService.estimateTokens(
                context,
                userInput);

        QuotaReservation reservation = quotaService.reserve(
                context,
                estimate);

        try {
            ChatResponse response = chatClient.prompt()
                    .user(userInput)
                    .options(policyService.chatOptions(context))
                    .call()
                    .chatResponse();

            ValidatedAnswer validated = policyService
                    .validateResponse(context, response);

            Usage usage = Usage.from(response, estimate);
            quotaService.settle(reservation, usage);
            auditService.success(
                    context,
                    usage,
                    elapsedMillis(startNanos),
                    validated.auditMetadata());

            return AiAnswer.from(validated);
        } catch (RuntimeException ex) {
            quotaService.markUncertain(reservation);
            auditService.failure(
                    context,
                    classify(ex),
                    elapsedMillis(startNanos));
            throw ex;
        }
    }
}

markUncertain 是因为超时后 Provider 可能已计费;后续账单/Usage 对账再结算。代码中的 Usage.from 等是项目治理抽象,需要按当前 Spring AI Metadata API 实现。

三十六、异常不能统一catch后返回一句繁忙

至少分类业务码:

text
AI_INPUT_REJECTED
AI_QUOTA_EXCEEDED
AI_PROVIDER_UNAUTHORIZED
AI_PROVIDER_RATE_LIMITED
AI_PROVIDER_TIMEOUT
AI_PROVIDER_UNAVAILABLE
AI_OUTPUT_INVALID
AI_RAG_INSUFFICIENT
AI_RAG_ACCESS_DENIED
AI_TOOL_CONFIRMATION_REQUIRED
AI_TOOL_FAILED
AI_SAFETY_BLOCKED

前端可以据此显示重试、补充资料、确认操作或联系管理员。日志保存内部根因,响应不暴露 Key、Provider敏感信息和系统 Prompt。

三十七、事故一:回答质量突然下降

mermaid
flowchart TD
    A["确认下降开始时间和场景"] --> B["对齐发布/配置/Provider变更"]
    B --> C["提取失败样例和完整版本矩阵"]
    C --> D["拆检索、Prompt、模型、Tool和后处理"]
    D --> E["用生产基线重放相同样例"]
    E --> F{"能否复现并定位"}
    F -->|"能"| G["回滚对应版本指针"]
    F -->|"不能"| H["检查Provider漂移、数据和随机性"]
    G --> I["补回归样例和复盘"]
    H --> I

不要只说“模型偶发”。先比较 Prompt Hash、RAG Index、Embedding、Model Revision、Options和Tool结果。

三十八、事故二:延迟和429同时升高

检查:

  • 入站请求/Token速率和并发。
  • 本地队列等待和Bulkhead占用。
  • Provider Retry-After和配额。
  • 重试流量占比。
  • 上下文/输出Token变化。
  • 是否新模型吞吐更低。
  • RAG/Rerank是否变慢导致请求重叠更多。

立即动作:限制新流量、关闭非关键重试、缩短输出、切合格备用路由、暂停批任务。单纯扩容应用 Pod 不能增加第三方 Provider 配额。

三十九、事故三:成本突然升高

按 tenant、user、scene、model、promptVersion、routeVersion 分解:

text
请求数增加?
每请求输入Token增加?
输出Token增加?
重试/Agent循环增加?
模型单价变化?
缓存命中下降?
Key是否泄露?

先止损:收紧配额、禁用异常租户/Key、暂停低优先级任务、回滚版本。不要直接清空全部日志,证据用于账单申诉和安全调查。

四十、事故四:RAG越权泄露

  1. 立即停止相关场景/索引流量。
  2. 保存授权快照、Filter、Chunk ID、缓存 Key、Prompt发送范围。
  3. 判断是否发送到第三方模型、日志或评估平台。
  4. 修复 metadata/Filter/缓存 ACL。
  5. 清理泄露数据和受影响缓存,轮换必要凭据。
  6. 通知安全/合规和受影响方,按制度处置。
  7. 将案例加入权限硬门槛评估集。

四十一、事故五:Tool执行了错误写操作

检查 toolCallId、requestId、操作者、权限决策、Schema、确认记录、下游幂等结果和事务状态。

先暂停该写 Tool,不暂停全部只读 AI 能力;按业务补偿或人工纠正,不能只删除聊天消息。修复后增加参数边界、二次确认和回归样例。

四十二、事故六:流式响应大量中断

分层检查:

  • 浏览器网络和主动取消。
  • CDN/Ingress/Nginx SSE 缓冲、空闲超时。
  • 应用连接池和事件循环是否阻塞。
  • Provider流式连接和模型队列。
  • 安全/Advisor是否把Flux聚合成完整响应。
  • 心跳是否存在。
  • 取消是否真正传播到上游。

四十三、上线检查清单

版本和质量

  • [ ] 记录完整版本矩阵和内容Hash。
  • [ ] 离线评估按场景/风险达标。
  • [ ] 安全、权限、格式为硬门槛。
  • [ ] Shadow/Canary与回滚指针已演练。

可靠性

  • [ ] 每阶段有超时和总Deadline。
  • [ ] 重试白名单、退避、抖动和预算明确。
  • [ ] Bulkhead、队列、Circuit和Fallback通过压测。
  • [ ] SSE取消、心跳和中途错误测试完成。
  • [ ] 异步任务租约、幂等、取消和对账完成。

安全

  • [ ] API Key在Secret系统并可轮换。
  • [ ] RAG ACL在检索前下推。
  • [ ] Tool参数、权限、确认和幂等完整。
  • [ ] Prompt/Tool日志脱敏、加密和保留期明确。
  • [ ] Prompt Injection和敏感输出测试通过。

成本和观测

  • [ ] 用户/租户/场景请求、并发、Token和金额配额。
  • [ ] Usage估算、结算和账单对账。
  • [ ] 分段Trace、低基数指标和质量反馈。
  • [ ] 成本、429、质量和安全告警有负责人/Runbook。

四十四、常见误区

误区准确结论后果
HTTP 200就是成功还要质量、格式、安全、引用和业务结果假健康
只限QPS即可慢请求、Token和并发仍可打满资源成本/线程耗尽
超时都重试读取超时可能已生成/执行重复计费/写操作
扩Pod能解决429Provider配额不随Pod增加重试雪崩
小模型可无损降级能力、Tool、JSON、质量不同隐性错误
defaultSystem能保证安全Prompt不是权限边界越权/注入
流式会降低总计算成本主要改善TTFT成本误判
缓存只用问题Hash忽略租户、ACL和版本数据泄露/旧答
只记录Prompt版本可复现回答由完整版本矩阵决定无法复盘
平均评估分高就上线高风险退化会被平均掩盖安全事故
回滚配置能撤销Tool副作用外部写操作需补偿业务事实错误

四十五、面试标准回答

Spring AI从Demo到生产要补什么

要先按场景分风险,补认证、租户和RAG/Tool数据权限;按用户/租户做请求、并发、Token和金额配额;为检索、模型和工具拆超时预算,配置有限重试、退避抖动、Bulkhead、Circuit和能力兼容降级;对输出做Schema、业务、引用和安全校验;记录完整版本矩阵、Token、分段耗时和质量指标,并用评估集、灰度、回滚、成本告警和事故Runbook闭环。

AI接口怎样设计超时和重试

先设置请求总Deadline,再给鉴权、检索、Rerank、模型和Tool分配子预算,外层超时大于内部总预算但不能无限等待。只对白名单瞬时错误有限重试,429尊重Retry-After,使用指数退避和抖动,并限制总重试流量。401、参数错误不重试;读取超时和Tool写操作结果可能未知,应先按幂等键确认。

为什么AI限流还要看Token和并发

AI请求耗时长且输入输出大小差异巨大。只限QPS时,少量超长请求仍会占满并发和成本。生产要同时限制请求速率、在途并发、单次/周期Token和金额预算,先预留后按实际Usage结算,并对未结算Reservation做过期与账单对账。

模型降级要注意什么

备用模型必须满足场景能力和已评估门槛,例如Tool Schema、结构化输出、多模态和安全策略不能缺失。高风险医疗/支付场景宁可拒答或转人工,也不应降级到未验证模型。路由和回滚记录模型、Prompt、RAG、Tool和Safety完整版本矩阵。

AI质量下降怎样排查

先确定开始时间、场景和失败样例,对齐模型路由、Prompt、Advisor、Embedding、RAG索引、检索参数、Tool和Safety变更;用相同版本矩阵重放,拆分检索错、上下文错、模型生成错和后处理错。能定位就回滚对应版本指针,不能复现再查Provider漂移、数据变化和随机参数,并把事故样例加入回归集。

四十六、学习实验与验收

  1. 为知识问答定义技术、质量、安全和成本 SLO。
  2. 给 12 秒请求拆分阶段预算,故意让 Rerank超时验证总Deadline。
  3. 同时压测请求QPS、并发和超长Token,比较四类限额。
  4. 模拟 401、429、500、连接超时和读取超时,验证重试分类。
  5. 让100个请求同时429,验证退避抖动不会同步重试。
  6. 配置两个模型路由,验证备用模型结构化输出/Tool能力门槛。
  7. 建立包含tenant、ACL、Prompt和index版本的缓存Key,证明不同用户不串答。
  8. 中断 SSE 客户端,验证上游取消和成本记录。
  9. 执行 Shadow/Canary,按风险分组比较生产基线。
  10. 演练质量下降、成本突增、RAG越权和Tool误执行事故。

验收时必须能回答:

  • 为什么HTTP可用性不能代表AI业务可用性?
  • TTFT和总耗时分别受什么影响?
  • 为什么QPS、并发、Token和金额都要限制?
  • 哪些错误能重试,为什么读取超时结果未知?
  • Bulkhead、Circuit、Queue和Fallback分别解决什么?
  • 模型路由为什么需要能力和质量门槛?
  • AI缓存Key为什么必须包含ACL和版本?
  • 一次答案需要记录哪些版本才能复现?
  • Shadow和Canary怎样避免Tool副作用?
  • AI安全事故为什么不能只删除聊天记录?

关联知识点