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(不需全量代码部署)
资源推荐
| 资源 | 说明 | 链接 |
|---|---|---|
| Braintrust | Agent评测+回归测试平台 | braintrust.dev |
| Promptfoo | 开源Prompt评测框架 | promptfoo.dev |
| DeepEval | 开源LLM评估框架 | github.com/confident-ai/deepeval |
| Ragas | RAG/Agent评估指标 | ragas.io |
| LangSmith | LangChain生态的监控+测试 | smith.langchain.com |
| Humanloop | Prompt版本管理+评估 | humanloop.com |
| Arize Phoenix | LLM可观测性+评估 | phoenix.arize.com |
| Hamel's Blog | LLM测试工程最佳实践 | hamel.dev |
明日预告
Day 26: 多模型编排与部署策略
预习问题:
1. 何时在同一个应用中使用多个不同的LLM? 如何路由?
2. 自托管模型 vs API模型的选型决策框架是什么?
3. 模型Fallback链如何设计?
连接点:
Day 22-25: Agent系统工程化完整闭环(可靠性/经济性/协作性/可交付性)
Day 26(明天): 跳出单模型思维 → 多模型协同的架构设计
→ 从"一个Agent用一个模型"到"一个系统用多个模型的最优组合"