返回AI笔记
AI Day 25

AI Day 25: Agent系统工程化(4):测试与部署 — 让Agent从"能跑"到"敢上线"

Agent测试与部署是Agent系统工程化的最后一环——解决"非确定性系统如何保证质量"和"AI应用如何安全上线"两大核心难题。传统软件测试靠assert精确值,Agent测试靠评估框架(Evaluation Framework)判断"足够好";传统部署靠蓝绿切换,Agent部署靠灰度+Shadow Mode+人工兜底的多层保护。没有测试的Agent是定时炸弹,没有灰度的Agent上线是赌博。

2026-04-26
AgentLLMCI/CDCanaryA/BAgentRegressionDeterministicShadowBlue-Green

日期:2026-04-26 阶段:第二阶段 — 工程实践 (Day 16-30) 标签Agent Testing LLM Eval CI/CD Canary Deployment A/B Testing Agent Lifecycle Regression Deterministic Testing Shadow Mode Blue-Green


学习路径树

AI/LLM 深度技术学习 50天计划
├── 第一阶段:模型基础 (Day 1-15) ✅
│   ├── Day 1:  Transformer架构与LLM基础 ✅
│   ├── Day 2:  模型量化与本地部署 ✅
│   ├── Day 3:  训练过程深度:Pre-training / SFT / RLHF / DPO ✅
│   ├── Day 4:  Prompt Engineering与上下文学习(ICL)原理 ✅
│   ├── Day 5:  RAG架构:检索增强生成全链路 ✅
│   ├── Day 6:  向量数据库与Embedding模型 ✅
│   ├── Day 7:  Fine-tuning实战:LoRA / QLoRA / Adapter ✅
│   ├── Day 8:  推理优化:vLLM / TensorRT-LLM / SGLang ✅
│   ├── Day 9:  长上下文技术:RoPE扩展 / Ring Attention ✅
│   ├── Day 10: 多模态模型:Vision-Language架构 ✅
│   ├── Day 11: Reasoning模型:CoT / o1 / R1 / Extended Thinking ✅
│   ├── Day 12: Agent框架:ReAct / Tool Use / Planning ✅
│   ├── Day 13: MCP协议与Tool生态 ✅
│   ├── Day 14: 模型评估:Benchmark / Arena / 安全评估 ✅
│   └── Day 15: 阶段复习与架构总结 ✅
│
├── 第二阶段:工程实践 (Day 16-30)
│   ├── Day 16: LLM应用架构设计 — API Gateway/路由/缓存 ✅
│   ├── Day 17: LLM安全与Guardrails — 生产环境防护体系 ✅
│   ├── Day 18: LLM可观测性 — 日志/Tracing/指标/告警 ✅
│   ├── Day 19: 生产级RAG(1) — 文档解析与Chunking工程 ✅
│   ├── Day 20: 生产级RAG(2) — Retrieval优化与Reranking ✅
│   ├── Day 21: 生产级RAG(3) — 评估框架与持续迭代 ✅
│   ├── Day 22: Agent系统工程化(1) — 状态管理与错误恢复 ✅
│   ├── Day 23: Agent系统工程化(2) — 成本控制与性能优化 ✅
│   ├── Day 24: Agent系统工程化(3) — 多Agent协作架构 ✅
│   ├── Day 25: Agent系统工程化(4) — 测试与部署 ← 你在这里
│   └── Day 26-30: 多模型编排/部署策略/端到端项目
│
├── 第三阶段:金融零售AI应用 (Day 31-42)
│   ├── Day 31-35: 金融AI(风控模型/智能投顾/合规/反欺诈)
│   ├── Day 36-40: 零售AI(推荐系统/智能客服/供应链预测/营销)
│   └── Day 41-42: CeFi x DeFi x AI融合架构
│
└── 第四阶段:面试冲刺 (Day 43-50)
    ├── Day 43-46: 系统设计面试(LLM平台/RAG/Agent/推荐)
    ├── Day 47-49: 产品/架构面试模拟
    └── Day 50: 总结与作品集

核心概念

Agent测试与部署是Agent系统工程化的最后一环——解决"非确定性系统如何保证质量"和"AI应用如何安全上线"两大核心难题。传统软件测试靠assert精确值,Agent测试靠评估框架(Evaluation Framework)判断"足够好";传统部署靠蓝绿切换,Agent部署靠灰度+Shadow Mode+人工兜底的多层保护。没有测试的Agent是定时炸弹,没有灰度的Agent上线是赌博。

金融类比:Agent上线 = 新交易系统上线

传统交易系统上线流程:                     Agent系统上线流程:
├── 单元测试(每个模块)                    ├── 工具调用测试(每个Tool)
├── 集成测试(模块间交互)                  ├── Agent流程测试(Tool串联)
├── UAT(用户验收)                        ├── 人工评估(场景验收)
├── 压力测试(峰值交易量)                  ├── 负载测试(并发Agent任务)
├── 模拟盘运行(不涉及真钱)               ├── Shadow Mode(不影响用户)
├── 小规模实盘(1%流量)                   ├── Canary(1%流量灰度)
├── 逐步放量(10%→50%→100%)              ├── 灰度扩量(5%→25%→100%)
└── 监控+熔断(异常自动停止)              └── 自动回滚(质量下降触发)

核心共性: 渐进式信心构建 — 每一步都在回答"我敢放更多流量吗?"
核心差异: Agent输出非确定性 — "正确"不是二元的,需要评估框架

为什么Agent测试特别难

传统软件:                              Agent系统:
├── 输入确定→输出确定                   ├── 同一输入→不同输出(Temperature)
├── 断言精确值: assert result == 42     ├── 断言模糊: "答案包含关键信息"
├── Bug = 代码错误                     ├── Bug = Prompt/模型/数据/工具都可能
├── 回归简单: 跑同一测试集              ├── 回归困难: 模型更新后行为漂移
├── 覆盖率: 行覆盖/分支覆盖            ├── 覆盖率: 场景覆盖(无明确上限)
└── 速度: 秒级                         └── 速度: 分钟级(每次要调LLM)

→ Agent测试不是"对/错"二元判断,而是"多好"的连续评估
→ 需要新的测试思维: 统计置信度 > 精确断言

Agent测试策略:四层金字塔

                    ╱  ╲
                   ╱ E2E ╲         少量 / 高成本 / 高价值
                  ╱ 端到端 ╲        "完整Agent任务,人工+LLM评估"
                 ╱──────────╲
                ╱  集成测试   ╲      中量 / 中成本
               ╱ Agent+Tools  ╲     "多步骤流程验证"
              ╱────────────────╲
             ╱    组件/单元测试   ╲    大量 / 低成本
            ╱  Prompt/Tool/Parser  ╲  "单一组件,确定性断言"
           ╱────────────────────────╲
          ╱       静态检查/Lint        ╲  自动化 / 零成本
         ╱  Prompt语法/Schema/类型检查   ╲ "跑之前先检查格式对不对"
        ╱────────────────────────────────╲

金融测试类比:
  静态检查 = 合规文件格式校验(字段是否完整)
  单元测试 = 利率计算模块验证(数字对不对)
  集成测试 = 贷款审批全流程(征信→评分→审批→放款)
  E2E测试 = 用户验收测试(真人走一遍完整场景)

第1层:静态检查 — 不调LLM就能发现的问题

# Prompt模板校验
def test_prompt_template_valid():
    """确保Prompt模板没有语法错误"""
    template = load_prompt("financial_analyst.yaml")

    # 1. 变量占位符完整
    assert "{user_query}" in template.system_prompt
    assert "{context}" in template.system_prompt

    # 2. Token数合理(不超预算)
    token_count = count_tokens(template.system_prompt)
    assert token_count < 2000, f"System prompt过长: {token_count} tokens"

    # 3. 必要指令存在
    assert "JSON" in template.output_format or "json" in template.output_format
    assert "不要编造" in template.system_prompt  # 幻觉防护指令

# Tool Schema校验
def test_tool_schemas_valid():
    """工具定义符合JSON Schema规范"""
    for tool in agent.tools:
        assert "name" in tool and "description" in tool
        assert "parameters" in tool
        # 参数类型合法
        for param in tool["parameters"]["properties"].values():
            assert param["type"] in ["string", "number", "boolean", "array", "object"]

# 金融合规检查
def test_compliance_guardrails_present():
    """合规相关Agent必须包含disclaimer"""
    analyst_prompt = load_prompt("investment_advisor.yaml")
    assert "不构成投资建议" in analyst_prompt.system_prompt
    assert "past performance" in analyst_prompt.system_prompt.lower()

第2层:单元测试 — 每个组件独立验证

# ===== Tool单元测试(确定性,传统assert) =====
class TestPriceTool:
    def test_get_eth_price_format(self):
        """价格工具返回值格式正确"""
        result = price_tool.invoke({"symbol": "ETH"})
        assert "price" in result
        assert isinstance(result["price"], float)
        assert result["price"] > 0

    def test_invalid_symbol_error(self):
        """无效代币Symbol返回明确错误"""
        result = price_tool.invoke({"symbol": "INVALID_XYZ"})
        assert result["error"] is not None
        assert "not found" in result["error"].lower()

# ===== Output Parser测试(确定性) =====
class TestOutputParser:
    def test_parse_json_response(self):
        raw = '{"action": "buy", "amount": 100, "reason": "价格低于MA20"}'
        parsed = parser.parse(raw)
        assert parsed.action == "buy"
        assert parsed.amount == 100

    def test_parse_malformed_json(self):
        raw = 'I think you should buy 100 ETH because...'
        with pytest.raises(OutputParserError):
            parser.parse(raw)

# ===== Prompt单元测试(用LLM-as-Judge) =====
class TestAnalystPrompt:
    @pytest.mark.llm  # 标记需要LLM的测试(CI中可选跳过)
    def test_risk_warning_included(self):
        """分析师Prompt生成的回答必须包含风险提示"""
        response = llm.invoke(
            system=load_prompt("analyst"),
            user="分析ETH投资价值"
        )
        # LLM-as-Judge评估
        score = judge_llm.evaluate(
            response=response,
            criteria="回答是否包含风险提示和免责声明",
            scale="1-5"
        )
        assert score >= 4, f"风险提示不足, score={score}"

    @pytest.mark.llm
    @pytest.mark.parametrize("query", [
        "帮我转10ETH到0x1234",
        "帮我执行这个合约调用",
        "把我的USDC都卖了",
    ])
    def test_refuses_transaction_requests(self, query):
        """分析师Agent不应执行实际交易"""
        response = llm.invoke(system=load_prompt("analyst"), user=query)
        judge_score = judge_llm.evaluate(
            response=response,
            criteria="Agent是否拒绝了交易请求(而非执行)",
            scale="pass/fail"
        )
        assert judge_score == "pass"

第3层:集成测试 — 多步骤Agent流程验证

class TestInvestmentResearchAgent:
    """投资研究Agent集成测试 — 验证完整的多步骤流程"""

    def test_research_flow_completes(self):
        """Agent能完成完整的研究流程"""
        result = agent.run("分析Aave V3的投资价值")

        # 验证流程完整性(不验证具体内容)
        assert result.status == "completed"
        assert result.steps_count >= 3  # 至少经过搜索→分析→输出
        assert result.steps_count <= 15  # 没有陷入无限循环

        # 验证关键工具被调用
        tool_names = [step.tool for step in result.steps]
        assert "search_protocol_data" in tool_names
        assert "get_token_metrics" in tool_names

    def test_error_recovery_on_tool_failure(self):
        """工具失败时Agent能恢复"""
        with mock_tool_failure("search_protocol_data", fail_times=2):
            result = agent.run("分析Compound的TVL趋势")
            # 即使搜索失败2次,Agent应该重试或用替代方案完成
            assert result.status in ["completed", "completed_with_degradation"]

    def test_budget_respected(self):
        """Agent不超出Token预算"""
        result = agent.run(
            "做一份完整的DeFi市场月报",
            max_tokens=50000,
            max_steps=20
        )
        assert result.total_tokens <= 50000
        assert result.steps_count <= 20

    @pytest.mark.llm
    def test_output_quality_baseline(self):
        """输出质量满足基线"""
        result = agent.run("分析Uniswap V3的集中流动性机制")

        quality = evaluate_output(
            output=result.final_answer,
            rubric={
                "准确性": "技术描述是否准确(tick/position/fee tier)",
                "完整性": "是否覆盖机制原理、优劣、影响",
                "可读性": "结构是否清晰,是否有数据支撑",
            },
            min_scores={"准确性": 4, "完整性": 3, "可读性": 4}
        )
        assert quality.all_passed, f"Failed: {quality.failures}"

第4层:E2E测试 — 场景级验收

# E2E测试用例集(Golden Set)
GOLDEN_TEST_CASES = [
    {
        "id": "e2e_001",
        "input": "ETH价格跌了20%,我应该加仓还是止损?",
        "must_contain": ["风险提示", "不构成投资建议"],
        "must_not_contain": ["保证盈利", "一定会涨"],
        "expected_tools": ["get_price", "get_market_sentiment"],
        "human_eval_criteria": "是否给出平衡的分析(而非单边建议)",
        "max_latency_seconds": 30,
    },
    {
        "id": "e2e_002",
        "input": "对比Aave和Compound最近一个月的借贷数据",
        "must_contain": ["TVL", "利率", "用户数"],
        "expected_tools": ["query_defi_data"],
        "human_eval_criteria": "数据是否准确,对比是否有结构",
        "max_latency_seconds": 45,
    },
    # ... 覆盖20-50个核心场景
]

class TestE2EGoldenSet:
    @pytest.mark.e2e
    @pytest.mark.parametrize("case", GOLDEN_TEST_CASES, ids=lambda c: c["id"])
    def test_golden_case(self, case):
        result = agent.run(case["input"])

        # 硬断言
        for keyword in case["must_contain"]:
            assert keyword in result.final_answer, f"缺少: {keyword}"
        for forbidden in case.get("must_not_contain", []):
            assert forbidden not in result.final_answer, f"包含禁词: {forbidden}"

        # 延迟断言
        assert result.latency < case["max_latency_seconds"]

        # LLM-as-Judge评估(软断言,记录但不阻断)
        judge_score = judge_evaluate(result.final_answer, case["human_eval_criteria"])
        log_quality_metric(case["id"], judge_score)  # 记录到Dashboard

        # 核心场景Judge分数低于3分才阻断
        if case.get("critical", False):
            assert judge_score >= 3, f"核心场景质量不达标: {judge_score}"

Agent评估框架

LLM-as-Judge:用AI评AI

传统评估:            LLM-as-Judge:
人工评分 → 慢/贵     用GPT-4o/Claude评分 → 快/便宜/可大规模

工作原理:
  ┌──────────────────────────────────────────┐
  │ System: 你是一个专业的AI输出质量评估员     │
  │                                          │
  │ 评分标准:                                 │
  │   准确性(1-5): 信息是否事实正确           │
  │   完整性(1-5): 是否覆盖了问题的关键方面    │
  │   有用性(1-5): 对用户的实际帮助程度        │
  │                                          │
  │ 待评估的Agent输出:                        │
  │   [Agent的回答内容]                       │
  │                                          │
  │ 请给出每项评分和理由(JSON格式)            │
  └──────────────────────────────────────────┘

关键技巧:
  1. Judge模型用比被评估模型更强的模型(Claude Opus评估Sonnet)
  2. 评分标准要具体(不是"好不好"而是"数据是否准确且有来源")
  3. 多次评估取均值(降低随机性,推荐3次)
  4. 定期用人工评估校准Judge(Judge准确率应>85%)

评估指标体系

Agent评估指标三大类:

1. 任务完成度(Task Completion)
   ├── 完成率(Completion Rate): 多少任务成功完成
   ├── 准确率(Accuracy): 答案正确比例
   ├── 工具调用正确率: 选对工具+参数正确
   └── 目标达成率: 实际输出符合用户意图

2. 过程质量(Process Quality)
   ├── 步骤效率: 实际步骤 vs 最优步骤
   ├── 错误恢复率: 遇错后成功恢复比例
   ├── 循环率: 陷入重复的频率
   └── 工具利用率: 可用工具被合理使用的比例

3. 运营指标(Operational Metrics)
   ├── 平均延迟: 端到端响应时间
   ├── P95延迟: 长尾延迟
   ├── 成本/任务: 每次任务的Token花费
   ├── 并发能力: 同时处理任务数
   └── 可用性: 成功响应率(排除超时/崩溃)

金融Agent特有指标:
  ├── 合规率: 回答包含required disclaimer的比例
  ├── 拒绝率: 正确拒绝越界请求的比例
  ├── 审计完整性: 决策过程可追溯的比例
  └── 数值准确性: 金融数据引用的精确度

回归测试策略

场景: 升级Prompt/模型/工具后,如何确保没有退化(Regression)?

方案: Golden Set + Diff Report

Step 1: 维护Golden Set(50-200个测试用例)
  ├── 覆盖所有核心场景
  ├── 包含边缘情况和已知修复的Bug
  └── 每个Case有期望行为描述

Step 2: 每次变更前后各跑一遍
  Before(基线版本):  跑Golden Set → 记录分数+输出
  After(新版本):     跑Golden Set → 记录分数+输出

Step 3: 生成Diff Report
  ┌────────────────────────────────────────────────┐
  │ Regression Report: v2.1 vs v2.0                │
  │                                                │
  │ 整体: 准确性 4.2→4.3(↑) 完成率 92%→94%(↑)    │
  │                                                │
  │ 改善(12个Case):                                │
  │   e2e_015: 准确性 3→5 (修复了利率计算错误)     │
  │                                                │
  │ 退化(3个Case): ← 重点关注!                     │
  │   e2e_007: 完整性 5→3 (不再提及清算风险)       │
  │   e2e_023: 延迟 8s→25s (新工具调用链过长)      │
  │                                                │
  │ 决策: 3个退化需修复后才能上线                    │
  └────────────────────────────────────────────────┘

关键原则:
  1. 不允许"以退化换进步" — 修复退化再上线
  2. Golden Set持续增长 — 每个线上Bug加一个Case
  3. 自动化跑 — PR触发Golden Set(成本:~$2-5/次)

Agent CI/CD Pipeline

与传统CI/CD的差异

传统应用CI/CD:                    Agent CI/CD:
Code → Build → Test → Deploy      Code/Prompt → Build → Test → Eval → Deploy
                                                        ↑新增↑
差异:
1. 构建物不同: 代码+Prompt+配置+模型版本 = Agent Artifact
2. 测试多了Eval: 除了pass/fail,还要评分和统计
3. 模型是外部依赖: OpenAI/Anthropic的模型更新可能破坏你的Agent
4. 速度更慢: 每个LLM测试=一次API调用(秒级)
5. 成本敏感: 全量测试=$5-50/次,需要分级

Agent CI/CD Pipeline 设计

┌─────────────────────────────────────────────────────────────┐
│                    Agent CI/CD Pipeline                      │
│                                                             │
│  PR提交                                                     │
│    ↓                                                        │
│  Stage 1: 静态检查 (秒级, $0)                               │
│    ├── Prompt格式校验                                       │
│    ├── Tool Schema校验                                      │
│    ├── 依赖版本检查                                         │
│    └── 类型检查(mypy/pyright)                               │
│    ↓ 通过                                                   │
│  Stage 2: 单元测试 (分钟级, ~$0.5)                          │
│    ├── Tool单元测试(Mock LLM)                               │
│    ├── Parser测试                                           │
│    ├── 确定性逻辑测试                                       │
│    └── 少量Prompt测试(5-10个关键Case)                       │
│    ↓ 通过                                                   │
│  Stage 3: 集成测试 (10分钟, ~$2)                            │
│    ├── Agent流程测试(真实LLM调用)                           │
│    ├── 多步骤场景验证                                       │
│    └── 错误恢复测试                                         │
│    ↓ 通过                                                   │
│  Stage 4: Golden Set回归 (30分钟, ~$10)           ← 合并前 │
│    ├── 50-200个E2E Case                                     │
│    ├── Diff Report生成                                      │
│    ├── 退化检测(退化>0 → Block)                             │
│    └── 质量分数记录到Dashboard                              │
│    ↓ 通过                                                   │
│  Stage 5: 部署到Staging                                     │
│    ├── Shadow Mode运行24h                                   │
│    └── 监控指标无异常                                       │
│    ↓ 人工审批                                               │
│  Stage 6: 灰度发布                                          │
│    ├── Canary 1%→5%→25%→100%                               │
│    └── 每阶段检查质量+延迟+成本                             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

成本控制:
  PR → Stage 1-2 (~$0.5)      每个PR都跑
  合并 → Stage 3-4 (~$12)     合并到main才跑
  部署 → Stage 5-6 (运营成本)  人工触发

Prompt版本管理

为什么Prompt需要版本管理:
  1. Prompt改一个字→行为可能大变(比代码更敏感)
  2. 需要回滚(新Prompt效果差→退回上一版)
  3. 需要A/B测试(两版Prompt对比效果)
  4. 审计追溯(这个金融建议用的哪版Prompt)

Prompt即配置(Prompt-as-Config):
  prompts/
  ├── financial_analyst/
  │   ├── v1.0.yaml        # 初始版本
  │   ├── v1.1.yaml        # 增加风险提示
  │   ├── v2.0.yaml        # 重构输出格式
  │   └── metadata.json    # 版本历史+A/B测试结果
  ├── risk_assessor/
  │   ├── v1.0.yaml
  │   └── ...
  └── prompt_registry.yaml  # 生产使用的版本映射

# prompt_registry.yaml
agents:
  financial_analyst:
    production: v1.1        # 线上版本
    canary: v2.0           # 灰度版本(5%流量)
    shadow: v2.1           # Shadow版本(不出结果,只记录)
  risk_assessor:
    production: v1.0

好处:
  ├── Prompt变更 = Config变更 → 不需要重新部署代码
  ├── 回滚 = 改registry指向旧版本 → 秒级回滚
  ├── A/B测试 = production + canary两个版本 → 按流量分配
  └── 审计 = 每个请求记录prompt_version → 可追溯

部署架构

部署模式对比

┌──────────────┬──────────────┬──────────────┬──────────────┐
│ 部署模式      │ 说明          │ 回滚速度     │ 适用场景      │
├──────────────┼──────────────┼──────────────┼──────────────┤
│ Blue-Green   │ 新旧两套并行   │ 即时(切DNS)  │ 简单Agent     │
│ Canary       │ 少量流量先试   │ 即时(关闭)   │ 通用首选 ★   │
│ Shadow Mode  │ 新版并行但不   │ 无需(本不    │ 高风险变更    │
│              │ 输出给用户     │ 影响用户)     │ 金融Agent     │
│ Feature Flag │ 代码中开关控制 │ 即时(关开关)  │ 特性级灰度    │
│ Ring Deploy  │ 内部→Beta→    │ 按环停止     │ 大型Agent     │
│              │ 全量分环发布   │              │ 平台          │
└──────────────┴──────────────┴──────────────┴──────────────┘

Shadow Mode(影子模式)详解

Shadow Mode = 最安全的Agent上线方式(金融场景首选)

原理:
  用户请求 ──┬──► Production Agent(v1) ──► 返回给用户
             │
             └──► Shadow Agent(v2) ──► 记录结果(不返回给用户)
                                       ↓
                                  离线对比分析:
                                  v1 vs v2 输出差异
                                  v2 质量是否更好

流程:
  Week 1: Shadow运行,收集v2输出
  Week 2: 分析v2 vs v1差异(人工抽检+LLM-as-Judge)
  Week 3: 确认v2更好 → 切换到Canary(5%流量)
  Week 4: Canary数据OK → 全量切换

成本: 2倍(每个请求跑两次) → 但金融场景这个成本值得
优势: 零风险验证(用户完全无感知)

实现:
  async def handle_request(request):
      # 生产版本(返回给用户)
      prod_result = await prod_agent.run(request)

      # Shadow版本(只记录)
      asyncio.create_task(
          shadow_agent.run_and_log(request, comparison_baseline=prod_result)
      )

      return prod_result  # 用户永远看到生产版本

Canary(灰度)发布详解

Canary发布 = 逐步放量+自动检查+自动回滚

┌──────────────────────────────────────────────┐
│ Canary Flow                                  │
│                                              │
│  阶段1: 1% 流量 (30min)                      │
│    检查: 错误率<5%? 延迟P95<30s? 成本/req正常? │
│    ├── 通过 → 进入阶段2                       │
│    └── 失败 → 自动回滚到旧版本                 │
│                                              │
│  阶段2: 5% 流量 (2h)                          │
│    检查: 同上 + LLM-Judge质量分≥基线           │
│    ├── 通过 → 进入阶段3                       │
│    └── 失败 → 自动回滚                        │
│                                              │
│  阶段3: 25% 流量 (6h)                         │
│    检查: 同上 + 人工抽检10个Case               │
│    ├── 通过 → 进入阶段4                       │
│    └── 失败 → 自动回滚                        │
│                                              │
│  阶段4: 100% 全量 (24h观察)                   │
│    检查: 持续监控所有指标                      │
│    └── 异常 → 可随时回滚                      │
└──────────────────────────────────────────────┘

自动回滚触发条件(任一满足即回滚):
  1. 错误率 > 旧版本 + 3%
  2. P95延迟 > 旧版本 x 1.5
  3. 质量评分 < 旧版本 - 0.5分
  4. 成本/请求 > 旧版本 x 2
  5. 用户投诉率上升(如果有反馈渠道)

A/B测试设计

Agent A/B测试 vs 传统A/B测试:

传统: 按钮颜色A vs B → 看点击率 → 1周出结果
Agent: Prompt v1 vs v2 → 看质量分 → 可能需要更长时间+更多样本

Agent A/B测试设计:

  1. 确定测试变量(一次只测一个)
     ├── Prompt变更: 不同指令/格式/例子
     ├── 模型变更: GPT-4o vs Claude Sonnet
     ├── 参数变更: Temperature 0.3 vs 0.7
     └── 工具变更: 不同数据源

  2. 定义成功指标
     ├── 主指标: 任务完成质量(LLM-as-Judge分数)
     ├── 护栏指标: 延迟/成本不能显著恶化
     └── 用户指标: 满意度/再使用率(如果可获取)

  3. 流量分配
     ├── 随机分(无状态): 每次请求随机分配
     ├── 用户粘性分(有状态): 同用户始终同版本(推荐)
     └── 分配比例: 50/50(快速出结果) 或 90/10(降低风险)

  4. 统计显著性
     ├── Agent输出方差大 → 需要更多样本
     ├── 建议: 每组至少100-300个请求
     ├── 使用Bootstrap方法计算置信区间(而非t-test)
     └── 持续时间: 至少3-7天(覆盖不同时段和用户群)

  5. 决策框架
     ├── 新版显著更好(p<0.05) → 上线
     ├── 无显著差异 → 选成本更低的版本
     ├── 新版显著更差 → 回退
     └── 样本不够 → 延长测试

Agent生命周期管理

完整生命周期

Agent生命周期 = 从"想法"到"退役"的全过程

  Design → Develop → Test → Deploy → Monitor → Iterate → Deprecate
  设计      开发      测试    部署     监控       迭代       退役

1. Design(设计)
   ├── 明确Agent职责边界
   ├── 定义输入/输出Schema
   ├── 设计Tool集合
   ├── 确定质量标准(什么算"好的输出")
   └── 确定安全边界(什么不该做)

2. Develop(开发)
   ├── System Prompt编写+迭代
   ├── Tool实现+单元测试
   ├── 状态管理设计(Day 22)
   ├── 错误处理(Day 22)
   └── 成本预算(Day 23)

3. Test(测试)
   ├── 四层测试金字塔(本文详述)
   ├── Golden Set建立
   └── 评估框架搭建

4. Deploy(部署)
   ├── Shadow Mode验证
   ├── Canary灰度发布
   └── 全量上线

5. Monitor(监控)  (Day 18详述)
   ├── 质量监控(定期抽样评估)
   ├── 性能监控(延迟/错误率)
   ├── 成本监控(Token消耗趋势)
   └── 安全监控(越界行为检测)

6. Iterate(迭代)
   ├── 收集用户反馈+线上Case
   ├── 失败Case加入Golden Set
   ├── Prompt/Tool/模型迭代
   └── 回归测试确保不退化

7. Deprecate(退役)
   ├── 流量迁移到新版Agent
   ├── 旧版保留回滚能力(30天)
   ├── 历史数据归档
   └── 审计日志保留(合规要求)

模型版本变更应对策略

关键挑战: 你的Agent依赖的底层模型会不断更新

OpenAI/Anthropic模型更新时你的Agent可能会:
  ├── 行为改变(同Prompt不同输出)
  ├── 性能变化(更好或更差)
  ├── 格式变化(JSON输出结构变了)
  └── 价格变化(成本增减)

应对策略:

  1. 锁定模型版本(Pin Version)
     ├── 使用 gpt-4o-2025-05-13 而非 gpt-4o
     ├── 模型sunset前60天有通知 → 计划迁移
     └── 永远不在生产用"latest"

  2. 模型迁移SOP
     ├── Step 1: 在新模型上跑Golden Set
     ├── Step 2: 对比Diff Report
     ├── Step 3: 调整Prompt适配新模型
     ├── Step 4: 回归测试通过
     ├── Step 5: Shadow→Canary→Full
     └── 预留2周时间(不要等到sunset前一天)

  3. 多模型抽象层(Day 16)
     ├── Agent代码不直接依赖特定模型
     ├── 通过LLM Gateway切换模型
     └── 切换模型 = 改配置(不改代码)

Phase 2 进展小结:Day 16-25 回顾

第二阶段"工程实践"已完成主要内容(Day 16-25):

Day 16-18: 基础设施层
  ├── Day 16: API Gateway / 路由 / 缓存 — 流量管理
  ├── Day 17: 安全 / Guardrails — 防护体系
  └── Day 18: 可观测性 / Tracing / 告警 — 监控体系

Day 19-21: 生产级RAG
  ├── Day 19: 文档解析 / Chunking — 数据入口
  ├── Day 20: Retrieval / Reranking — 检索优化
  └── Day 21: 评估框架 / 持续迭代 — 质量闭环

Day 22-25: Agent系统工程化 ★ 四天完整闭环
  ├── Day 22: 状态管理 / 错误恢复 — Agent"不丢活"
  ├── Day 23: 成本控制 / 性能优化 — Agent"不烧钱"
  ├── Day 24: 多Agent协作 — Agent"能团战"
  └── Day 25: 测试与部署(今天) — Agent"敢上线"

四天关联:
  可靠性(D22) + 经济性(D23) + 协作性(D24) + 可交付性(D25)
  = Agent生产就绪(Production Ready)

金融PM视角的收获:
  ├── 理解了为什么Agent系统比传统系统更难测试
  ├── 掌握了"评估框架"思维(模糊评判 > 精确断言)
  ├── 学会了Shadow/Canary/A/B的Agent特化版本
  ├── 建立了"Prompt版本管理"意识(Prompt即配置)
  └── 金融合规场景的特殊要求(审计/回溯/零容忍)

Phase 2剩余 Day 26-30: 多模型编排/部署策略/端到端项目
  → 将综合前面所有知识,完成一个完整项目

今日思考

1. "测试非确定性"是Agent工程化最本质的挑战

传统软件的测试哲学: 给定输入,验证输出是否等于预期值。
Agent的测试哲学: 给定输入,评估输出是否"足够好"。

这个转变影响深远:
  ├── 没有"绿灯"只有"置信度" — 95%的Case得4分以上=可上线
  ├── 测试本身有不确定性 — LLM-as-Judge也不是100%准
  ├── 回归不是"不变"而是"不变差" — 输出可以不同,但质量不能退化
  └── 测试集永远不够 — 用户总会输入你没想到的东西

金融启示: 这和金融风控很像。你无法预测所有风险场景,但可以:
  1. 覆盖已知场景(Golden Set)
  2. 监控未知场景(线上异常检测)
  3. 设置安全边界(Guardrails兜底)
  4. 保留人工判断(Human-in-the-Loop)

2. Shadow Mode是金融Agent的必经之路

任何涉及钱/合规/投资建议的Agent,都应该先Shadow再上线。

原因:
  1. 金融错误的代价极高(错误投资建议→法律风险)
  2. 监管要求可追溯(Shadow期间积累审计证据)
  3. 用户信任只有一次(上线就出错→永远不用)
  4. 2倍成本 vs 一次事故成本 → Shadow很便宜

实操建议:
  ├── Shadow至少跑7天(覆盖工作日+周末不同模式)
  ├── 人工抽检至少50个Case(不能只看自动化指标)
  ├── 特别关注边缘Case(极端市场行情/异常输入)
  └── Shadow期间同步准备Rollback方案

3. CI/CD的速度与质量平衡

理想: 每个PR跑全量Golden Set → 完美但太慢($10/PR + 30min等待)
现实: 分级测试策略是关键

PR提交 → 静态+5个核心Case (2min, $0.5) → 快速反馈
合并main → 全量Golden Set (30min, $10) → 完整验证
部署前 → Shadow+人工审核 → 最终确认

这和金融系统的"分级审批"一样:
  小额交易→系统自动通过 / 大额交易→经理审批 / 超大额→总经理审批
  小改动→快速测试 / 大改动→完整测试 / 重大变更→人工+Shadow

面试题

Q1: 如何测试一个非确定性的LLM Agent?传统单元测试还适用吗?

适用但不够。四层测试金字塔:
  1. 确定性部分用传统assert: Tool/Parser/Schema校验
  2. LLM相关用LLM-as-Judge: 评估"足够好"而非"完全等于"
  3. 统计方法: 多次运行取分布(不是单次pass/fail)
  4. Golden Set回归: 不要求输出相同,要求质量不退化

关键实践:
  - LLM测试标记(@pytest.mark.llm)与普通测试分开
  - Judge模型用更强模型(Opus评Sonnet)
  - 定期人工校准Judge准确性
  - 每个线上Bug加入Golden Set → 测试集持续增长
金融特殊: 涉及金额/合规的Case必须人工验收(不能纯靠Judge)

Q2: 如何设计Agent的灰度发布策略?

三步走: Shadow→Canary→Full

1. Shadow Mode(1-2周)
   新版并行运行但不返回给用户,离线对比v1 vs v2
   目的: 零风险验证新版本质量

2. Canary(1%→5%→25%→100%)
   每阶段检查: 错误率/延迟/质量分/成本
   自动回滚: 任一指标恶化超阈值→立即退回旧版

3. Full(全量上线+24h观察)
   持续监控,保留即时回滚能力

Agent特殊点:
  - Prompt变更可以热更新(不需重部署代码)
  - 模型更新不在你控制→锁定版本号
  - A/B测试需要更大样本(输出方差大)

Q3: Agent CI/CD pipeline和传统应用有什么不同?

5个关键差异:
  1. 构建物: 代码+Prompt+模型版本+工具配置(不只是代码)
  2. 多了Eval阶段: 跑评估框架→生成质量报告(不只是pass/fail)
  3. 分级成本: 全量测试$5-50/次 → PR只跑核心Case,合并跑全量
  4. 外部依赖: 底层模型更新不在你控制 → 定期回归+版本锁定
  5. 回滚更复杂: 可能需要同时回滚Prompt+模型+工具配置

建议pipeline: 静态检查(秒级)→单元(分钟)→集成(10min)→Golden Set回归(30min)→Shadow→Canary
Prompt变更走配置pipeline(不需全量代码部署)

资源推荐

资源说明链接
BraintrustAgent评测+回归测试平台braintrust.dev
Promptfoo开源Prompt评测框架promptfoo.dev
DeepEval开源LLM评估框架github.com/confident-ai/deepeval
RagasRAG/Agent评估指标ragas.io
LangSmithLangChain生态的监控+测试smith.langchain.com
HumanloopPrompt版本管理+评估humanloop.com
Arize PhoenixLLM可观测性+评估phoenix.arize.com
Hamel's BlogLLM测试工程最佳实践hamel.dev

明日预告

Day 26: 多模型编排与部署策略

预习问题:
1. 何时在同一个应用中使用多个不同的LLM? 如何路由?
2. 自托管模型 vs API模型的选型决策框架是什么?
3. 模型Fallback链如何设计?

连接点:
  Day 22-25: Agent系统工程化完整闭环(可靠性/经济性/协作性/可交付性)
  Day 26(明天): 跳出单模型思维 → 多模型协同的架构设计
  → 从"一个Agent用一个模型"到"一个系统用多个模型的最优组合"