Codex CLI实战

Codex CLI生产环境实战:从安装到自动化代码审查

Codex CLI 2026 现状 2026年,OpenAI Codex已不再是2021年那个代码生成模型,而是一套完整的AI编程智能体: CLI版本:v0.130.0(2026-05-08) GitHub Star:83,200+ 核心能力:读代码、改代码、跑命令、做审查 支持模型:gpt-5-codex、gpt-5.6 Sol 与GitHub Copilot相比,Codex CLI的优势在于直接操作本地文件的能力——不只是给你代码片段让你粘贴,而是直接改你的项目。 环境搭建 系统要求 要求 最低版本 推荐版本 操作系统 macOS 12+ / Ubuntu 20.04+ / Win11(WSL2) macOS 14+ / Ubuntu 22.04+ Node.js 18.0+ 22.0+ npm 10.0+ 最新版 Git 2.23+ 2.40+ 内存 4GB 8GB+ ⚠️ Windows注意:Codex CLI暂不支持原生Windows,需要通过WSL2或使用Codex App。 安装 # 方式一:npm安装(推荐) npm install -g @openai/codex # 国内加速 npm install -g @openai/codex --registry=https://registry.npmmirror.com # 方式二:Codex App(Windows用户) # 从OpenAI官网下载Codex App 认证配置 # 启动并登录 codex # 系统自动唤起浏览器进行ChatGPT账号授权 # Token自动保存,无需每次输入API Key # 配置默认模型 # ~/.codex/config.toml [model] default = "gpt-5-codex" reasoning = "high" # low/medium/high 三种使用模式 1. CLI交互模式 $ codex > 帮我审查src/auth目录下的代码,重点关注安全问题 # Codex会: # 1. 读取src/auth/下所有文件 # 2. 分析代码逻辑和安全风险 # 3. 输出审查报告和修改建议 # 4. 可选择直接应用修改 2. 非交互模式 # 直接执行任务 codex "创建一个Hello World的Python脚本" # 指定目录 codex --dir /path/to/project "修复所有TypeScript错误" # 管道输入 cat error.log | codex "分析这个错误日志,找出根本原因" 3. 云端网页版 访问 chatgpt.com/codex: ...

2026-07-08 · 3 min · 583 words · 硅基 AGI 探索者
模型版本管理

模型版本管理MLOps实践

LLM版本管理的挑战 传统的软件版本管理(Git)无法处理大模型文件(数十GB)。LLM的版本管理需要同时追踪代码、配置、数据、模型权重和评估结果。 版本管理工具链 MLflow模型注册 import mlflow # 记录模型版本 with mlflow.start_run(run_name="qwen3-32b-v2"): mlflow.log_params({ "base_model": "Qwen-3-32B", "fine_tune_method": "LoRA", "learning_rate": 2e-4, "epochs": 3, "dataset": "instruction-v3", }) mlflow.log_metrics({ "eval_loss": 0.45, "eval_accuracy": 0.89, "human_eval_score": 4.2, }) # 注册模型 mlflow.register_model( "runs:/abc123/model", "qwen3-32b-instruct", tags={ "version": "v2.1", "stage": "staging", "creator": "team-agi", } ) DVC管理大文件 # 初始化DVC dvc init # 添加模型文件到DVC dvc add models/qwen3-32b-v2.1/ # 推送到远程存储 dvc remote add -d storage s3://my-bucket/models dvc push # Git只追踪.dvc文件(指针),不追踪实际大文件 git add models/qwen3-32b-v2.1/.dvc git commit -m "Add qwen3-32b v2.1" 版本发布流程 灰度发布 class CanaryDeployment: def __init__(self, stable_version, canary_version, canary_ratio=0.1): self.stable = stable_version self.canary = canary_version self.ratio = canary_ratio self.metrics = {"stable": [], "canary": []} def route(self, request): """灰度路由""" import random if random.random() < self.ratio: self.metrics["canary"].append({"time": time.time()}) return self.canary else: self.metrics["stable"].append({"time": time.time()}) return self.stable def evaluate(self): """评估灰度结果""" canary_latency = self.get_avg_latency("canary") stable_latency = self.get_avg_latency("stable") canary_error = self.get_error_rate("canary") stable_error = self.get_error_rate("stable") # 灰度通过条件 if canary_latency > stable_latency * 1.2: return "rollback", "Canary latency too high" if canary_error > stable_error * 2: return "rollback", "Canary error rate too high" return "promote", "Canary performing well" A/B测试 class ABTest: def __init__(self, models, weights=None): self.models = models self.weights = weights or [1/len(models)] * len(models) self.results = {m: {"satisfied": 0, "total": 0} for m in models} def route(self, user_id): # 基于用户ID的确定性路由 hash_val = int(hashlib.md5(user_id.encode()).hexdigest(), 16) cumulative = 0 for model, weight in zip(self.models, self.weights): cumulative += weight if (hash_val % 1000) / 1000 < cumulative: return model def record_feedback(self, model, satisfied): self.results[model]["total"] += 1 if satisfied: self.results[model]["satisfied"] += 1 def get_winner(self): rates = {m: r["satisfied"]/r["total"] for m, r in self.results.items() if r["total"] > 0} return max(rates, key=rates.get) if rates else None CI/CD管线 # .github/workflows/model-deploy.yml name: Model Deploy Pipeline on: push: tags: ['v*'] jobs: evaluate: runs-on: gpu-runner steps: - uses: actions/checkout@v4 - name: Run evaluation run: | python eval.py --model checkpoints/latest --benchmark mmlu,gsm8k,humaneval - name: Check quality gates run: | python check_gates.py --min_accuracy 0.85 --max_regression 0.02 deploy_staging: needs: evaluate runs-on: deploy-runner steps: - name: Deploy to staging run: | ./deploy.sh --env staging --version ${{ github.ref_name }} - name: Run smoke tests run: | python smoke_test.py --env staging canary: needs: deploy_staging runs-on: deploy-runner steps: - name: Canary deployment (10%) run: | ./deploy.sh --env production --version ${{ github.ref_name }} --canary 0.1 - name: Monitor for 1 hour run: | python monitor.py --duration 3600 --check latency,error_rate full_deploy: needs: canary runs-on: deploy-runner steps: - name: Full deployment run: | ./deploy.sh --env production --version ${{ github.ref_name }} --promote 模型回滚 class ModelRollback: def __init__(self, deployment_manager): self.deployment = deployment_manager self.version_history = [] async def rollback(self, target_version=None): """回滚到指定版本或上一个稳定版本""" if target_version is None: target_version = self.get_previous_stable() logger.info(f"Rolling back to {target_version}") # 快速切换流量 await self.deployment.switch_traffic( from_version="current", to_version=target_version, ratio=1.0 # 100%切换 ) # 验证回滚 health = await self.deployment.health_check(target_version) if not health: logger.error("Rollback target also unhealthy!") return False return True 结语 LLM的版本管理需要结合MLflow(实验追踪)、DVC(大文件管理)和CI/CD(自动化部署)。灰度发布和快速回滚是降低部署风险的关键能力。建立完善的MLOps流程,可以让模型迭代从"手动谨慎"变为"自动自信"。 加入讨论 这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。 ...

2026-07-02 · 3 min · 462 words · 硅基 AGI 探索者
LLM自动化测试

LLM自动化测试2026:让AI测试AI

引言 LLM应用的测试与传统软件测试截然不同:输入空间无限大、输出不确定、质量主观。2026年,LLM自动化测试已经形成了一套完整的方法论和工具链。本文将系统介绍如何构建LLM自动化测试体系。 LLM测试的挑战 挑战一:输入空间无限 传统软件的输入是结构化的(如表单字段),而LLM的输入是自由文本,可能的组合无限多。 挑战二:输出不确定 同一个输入,LLM可能给出不同的输出(即使temperature=0,不同版本也可能不同)。 挑战三:质量主观 “好的回答"的定义因任务、用户、上下文而异。 挑战四:成本高 每次测试都需要调用LLM API,大规模测试成本可观。 测试分层架构 ┌─────────────────────────────────┐ │ 端到端测试 (E2E) │ ← 模拟真实用户场景 ├─────────────────────────────────┤ │ 集成测试 │ ← 测试模块间协作 ├─────────────────────────────────┤ │ 提示测试 │ ← 测试提示效果 ├─────────────────────────────────┤ │ 单元测试 │ ← 测试单个功能 └─────────────────────────────────┘ 第一层:单元测试 测试LLM的基本功能: class TestLLMUnit: def test_json_output(self): """测试JSON输出格式""" response = llm.generate("输出JSON格式:{\"name\": \"test\"}") assert is_valid_json(response) def test_language_detection(self): """测试语言识别""" response = llm.generate("用中文回复:Hello") assert is_chinese(response) def test_length_constraint(self): """测试长度约束""" response = llm.generate("用50字以内回答:什么是AI?") assert len(response) <= 100 # 中文字符数 第二层:提示测试 测试提示在不同输入上的表现: class TestPrompt: def test_sentiment_analysis(self): """测试情感分析提示""" test_cases = [ {"input": "太棒了!", "expected": "positive"}, {"input": "太差了!", "expected": "negative"}, {"input": "还行吧。", "expected": "neutral"}, ] for case in test_cases: response = llm.generate(prompt.format(input=case["input"])) assert case["expected"] in response.lower() def test_robustness(self): """测试提示鲁棒性""" # 测试不同表述方式 inputs = [ "这部电影怎么样?", "你觉得这部电影如何?", "评价一下这部电影", ] responses = [llm.generate(prompt.format(input=i)) for i in inputs] # 检查输出是否一致(语义相似度) for i in range(len(responses)-1): similarity = compute_similarity(responses[i], responses[i+1]) assert similarity > 0.7 第三层:集成测试 测试多个模块协作: ...

2026-07-02 · 4 min · 644 words · 硅基 AGI 探索者
Agent CI/CD设计:从代码到生产的完整流水线

Agent CI/CD设计:从代码到生产的完整流水线

引言 Agent系统的CI/CD比传统应用复杂——除了代码变更外,Prompt模板变更、工具定义变更、模型版本切换都可能影响系统行为。一个完整的Agent CI/CD流水线需要覆盖代码、配置、模型三个维度的变更管理,并建立严格的质量门禁确保每次发布都不会降低系统质量。 CI/CD流水线全景 ┌─────────────────────────────────────────────────────────────┐ │ Agent CI/CD Pipeline │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ Code │ │ Build │ │ Test │ │ Deploy │ │ │ │ Commit │──▶│ & Push │──▶│ & QA │──▶│ to Prod │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ │ │ │ │ │ │ ▼ ▼ ▼ ▼ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ Lint & │ │ Image │ │ Unit │ │ Staging │ │ │ │ Format │ │ Build │ │ Tests │ │ Deploy │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ │ │ │ ┌──────────┐ ┌──────────┐│ │ │ Integration│ │ Canary ││ │ │ Tests │ │ Deploy ││ │ └──────────┘ └──────────┘│ │ │ │ │ ┌──────────┐ │ │ │ GA Deploy│ │ │ └──────────┘ │ └─────────────────────────────────────────────────────────────┘ 代码提交与构建 # .github/workflows/ci.yml name: Agent CI Pipeline on: push: branches: [main, develop] pull_request: branches: [main] jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.11' - name: Install dependencies run: pip install flake8 black mypy - name: Lint with flake8 run: flake8 agent/ --max-line-length=120 --ignore=E203,W503 - name: Format check with black run: black --check agent/ - name: Type check with mypy run: mypy agent/ --ignore-missing-imports build: needs: lint runs-on: self-hosted # 需要Docker支持 steps: - uses: actions/checkout@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: Log in to Container Registry uses: docker/login-action@v2 with: registry: ${{ secrets.REGISTRY_URL }} username: ${{ secrets.REGISTRY_USER }} password: ${{ secrets.REGISTRY_PASSWORD }} - name: Build and Push Docker Image uses: docker/build-push-action@v4 with: context: . push: true tags: | ${{ secrets.REGISTRY_URL }}/agent-service:${{ github.sha }} ${{ secrets.REGISTRY_URL }}/agent-service:latest cache-from: type=gha cache-to: type=gha,mode=max - name: Scan Image for Vulnerabilities uses: aquasecurity/trivy-action@master with: image-ref: ${{ secrets.REGISTRY_URL }}/agent-service:${{ github.sha }} format: 'sarif' output: 'trivy-results.sarif' - name: Upload Trivy scan results uses: github/codeql-action/upload-sarif@v2 with: sarif_file: 'trivy-results.sarif' 自动化测试 test: needs: build runs-on: self-hosted services: redis: image: redis:7 ports: - 6379:6379 postgres: image: postgres:15 env: POSTGRES_PASSWORD: test ports: - 5432:5432 qdrant: image: qdrant/qdrant:latest ports: - 6333:6333 steps: - uses: actions/checkout@v3 - name: Run Unit Tests run: | pytest tests/unit/ -v --cov=agent --cov-report=xml --junitxml=junit-unit.xml - name: Run Integration Tests env: LLM_MOCK: "true" # 使用Mock LLM run: | pytest tests/integration/ -v --junitxml=junit-integration.xml - name: Run Agent-Specific Tests run: | # Prompt测试 python -m pytest tests/prompt/ -v # 工具调用测试 python -m pytest tests/tools/ -v # 质量回归测试 python tests/regression/run_regression.py \ --baseline=baseline.json \ --report=regression-report.json - name: Upload Test Results if: always() uses: actions/upload-artifact@v3 with: name: test-results path: | coverage.xml junit-*.xml regression-report.json - name: Check Quality Gate run: | python scripts/check_quality_gate.py \ --coverage-report=coverage.xml \ --min-coverage=80 \ --regression-report=regression-report.json \ --max-regressions=0 环境管理 class EnvironmentManager: """环境管理器""" ENVIRONMENTS = { "dev": { "replicas": 1, "model": "gpt-4o-mini", "quality_gate": {"min_quality": 0.7}, }, "staging": { "replicas": 3, "model": "gpt-4o", "quality_gate": {"min_quality": 0.8}, }, "prod": { "replicas": 10, "model": "gpt-4o", "quality_gate": {"min_quality": 0.85}, } } async def deploy_to_environment( self, environment: str, image_tag: str, config: dict = None ): """部署到指定环境""" env_config = self.ENVIRONMENTS[environment] deploy_config = {**env_config, **(config or {})} # 1. 更新K8s Deployment await self.k8s_client.apply_deployment({ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": { "name": f"agent-service-{environment}", "namespace": f"agent-{environment}" }, "spec": { "replicas": deploy_config["replicas"], "template": { "spec": { "containers": [{ "name": "agent", "image": f"{self.registry}/{image_tag}", "env": [ {"name": "MODEL_NAME", "value": deploy_config["model"]}, {"name": "ENVIRONMENT", "value": environment}, ] }] } } } }) # 2. 等待部署完成 await self._wait_for_rollout( f"agent-service-{environment}", timeout=300 ) # 3. 运行冒烟测试 await self._run_smoke_tests(environment) # 4. 运行质量门禁 quality_result = await self._run_quality_gate(environment, deploy_config["quality_gate"]) if not quality_result["passed"]: logger.error(f"Quality gate failed for {environment}") await self._rollback(environment, image_tag) raise QualityGateFailed(quality_result["details"]) logger.info(f"Successfully deployed to {environment}") 灰度发布 # Argo Rollouts配置 apiVersion: argoproj.io/v1alpha1 kind: Rollout metadata: name: agent-service spec: replicas: 10 strategy: canary: canaryService: agent-service-canary stableService: agent-service-stable # 分析阶段 analysis: templates: - templateName: agent-quality-analysis args: - name: service-name value: agent-service-canary # 渐进式发布 steps: - setWeight: 5 - pause: {duration: 10m} - setWeight: 20 - pause: {duration: 15m} - setWeight: 50 - pause: {duration: 20m} - setWeight: 100 # 流量路由 trafficRouting: istio: virtualService: name: agent-service-vs destinationRule: name: agent-service-dr 自动化回滚 class AutoRollbackManager: """自动回滚管理器""" async def monitor_and_rollback(self, rollout_name: str): """监控发布并自动回滚""" while True: # 获取Rollout状态 rollout = await self.k8s_client.get_rollout(rollout_name) if rollout["status"]["phase"] == "Degraded": logger.warning(f"Rollout {rollout_name} degraded, initiating rollback") await self._rollback(rollout_name) break # 检查质量指标 quality = await self._check_quality(rollout_name) if quality["error_rate"] > 0.05: logger.warning(f"Error rate {quality['error_rate']:.1%} > 5%, rolling back") await self._rollback(rollout_name) break if quality["quality_score"] < 0.8: logger.warning(f"Quality score {quality['quality_score']:.2f} < 0.8, rolling back") await self._rollback(rollout_name) break await asyncio.sleep(30) # 30秒检查一次 async def _rollback(self, rollout_name: str): """执行回滚""" await self.k8s_client.rollback_rollout( rollout_name, to_revision="previous" ) # 发送通知 await self.notifier.send( channel="slack:#alerts", message=f"⚠️ Auto-rollback triggered for {rollout_name}" ) 完整的CD流水线 # .github/workflows/cd.yml name: Agent CD Pipeline on: workflow_run: workflows: ["Agent CI Pipeline"] types: [completed] branches: [main] jobs: deploy-staging: if: ${{ github.event.workflow_run.conclusion == 'success' }} runs-on: self-hosted steps: - name: Deploy to Staging run: | python scripts/deploy.py \ --environment=staging \ --image-tag=${{ github.sha }} - name: Run Staging Tests run: | python scripts/run_e2e_tests.py --environment=staging - name: Notify Deployment uses: 8398a7/action-slack@v3 with: status: ${{ job.status }} text: "Deployed to Staging: ${{ github.sha }}" deploy-prod: needs: deploy-staging runs-on: self-hosted environment: production # 需要手动批准 steps: - name: Deploy to Production (Canary) run: | kubectl argo rollouts promote agent-service - name: Monitor Canary run: | python scripts/monitor_canary.py \ --rollout=agent-service \ --duration=30m \ --auto-rollback=true - name: Promote Canary if: success() run: | kubectl argo rollouts promote agent-service - name: Create GitHub Release uses: actions/create-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: tag_name: v${{ github.run_number }} release_name: Release v${{ github.run_number }} body: | ## Changes ${{ steps.changelog.outputs.changelog }} ## Deployment - Staging: ✅ - Production: ✅ (Canary 100%) draft: false prerelease: false 总结 Agent CI/CD流水线的核心挑战在于三层面的变更管理:代码变更、配置变更(Prompt/工具)和模型变更。完整的流水线应该包括代码质量检查、自动化测试(单元测试+集成测试+回归测试)、多环境部署、灰度发布和自动回滚。质量门禁贯穿整个流水线,确保每次发布都不会降低系统质量。 ...

2026-06-30 · 5 min · 929 words · 硅基 AGI 探索者
prompt version management platform

Prompt 版本管理平台搭建:Git for Prompts

Prompt 也是代码,也需要版本管理 2026 年,头部 AI 团队的 Prompt 库已经增长到数千条,涉及数百个应用场景。没有版本管理,Prompt 的变更是灾难性的——“谁改了什么?为什么改?改了之后效果变好了还是变差了?“这些问题无法回答。Prompt 版本管理平台已成为 AI 工程化的基础设施。 一、Prompt 版本管理的核心需求 1.1 与 Git 的异同 维度 代码 Git Prompt 版本管理 版本控制 ✅ 文件差异 ✅ Prompt 差异 分支管理 ✅ 功能分支 ✅ 实验分支 代码审查 ✅ PR ✅ Prompt 评审 CI/CD ✅ 自动测试 ✅ 效果评估 回滚 ✅ 任意版本 ✅ 任意版本 性能指标 ❌ 不内置 ✅ 必须内置 多环境 dev/staging/prod draft/staging/prod A/B测试 ❌ 不内置 ✅ 核心功能 1.2 平台架构 ┌────────────────────────────────────────────┐ │ Web UI / CLI │ ├────────────────────────────────────────────┤ │ 版本管理 │ A/B测试 │ 灰度发布 │ 监控面板 │ ├────────────────────────────────────────────┤ │ Prompt 存储引擎 │ │ ┌─────────┐ ┌──────────┐ ┌────────────┐ │ │ │版本树 │ │元数据 │ │评估结果 │ │ │ └─────────┘ └──────────┘ └────────────┘ │ ├────────────────────────────────────────────┤ │ 集成层 │ │ ┌─────────┐ ┌──────────┐ ┌────────────┐ │ │ │LLM API │ │CI/CD │ │监控系统 │ │ │ └─────────┘ └──────────┘ └────────────┘ │ └────────────────────────────────────────────┘ 二、数据模型设计 from dataclasses import dataclass, field from datetime import datetime from typing import List, Optional, Dict from enum import Enum class PromptStatus(Enum): DRAFT = "draft" IN_REVIEW = "in_review" STAGING = "staging" PRODUCTION = "production" DEPRECATED = "deprecated" ARCHIVED = "archived" class ChangeType(Enum): CREATED = "created" MODIFIED = "modified" PROMOTED = "promoted" ROLLED_BACK = "rolled_back" DEPRECATED = "deprecated" @dataclass class PromptVersion: """Prompt 版本模型""" id: str prompt_id: str # Prompt 唯一标识 version: str # 语义化版本号 e.g. "2.3.1" parent_version: Optional[str] # 父版本 # Prompt 内容 system_prompt: str user_template: str variables_schema: Dict # 变量定义 # 元数据 author: str created_at: datetime status: PromptStatus # 变更说明 change_type: ChangeType change_description: str # 评估结果 evaluation: Optional[Dict] = None # {'accuracy': 0.92, 'safety': 0.99, 'latency_ms': 1200, ...} # 部署信息 deployed_at: Optional[datetime] = None deployed_by: Optional[str] = None traffic_percentage: int = 0 # 灰度比例 @dataclass class PromptBranch: """Prompt 分支""" name: str base_version: str head_version: str purpose: str # 实验目的 created_at: datetime experiments: List[str] = field(default_factory=list) @dataclass class ABTest: """A/B 测试配置""" id: str prompt_id: str variants: Dict[str, str] # {'A': 'v2.3.0', 'B': 'v2.3.1'} traffic_split: Dict[str, int] # {'A': 50, 'B': 50} start_time: datetime end_time: Optional[datetime] = None success_metrics: List[str] # ['accuracy', 'user_satisfaction'] results: Optional[Dict] = None 三、版本控制引擎 class PromptVersionControl: """Prompt 版本控制引擎""" def __init__(self, storage_backend='postgresql'): self.storage = self._init_storage(storage_backend) def create_prompt(self, prompt_id: str, system_prompt: str, user_template: str, author: str, variables_schema: dict = None) -> PromptVersion: """创建新 Prompt""" version = PromptVersion( id=self._generate_id(), prompt_id=prompt_id, version="1.0.0", parent_version=None, system_prompt=system_prompt, user_template=user_template, variables_schema=variables_schema or {}, author=author, created_at=datetime.now(), status=PromptStatus.DRAFT, change_type=ChangeType.CREATED, change_description="初始版本" ) self.storage.save(version) return version def commit(self, prompt_id: str, system_prompt: str = None, user_template: str = None, author: str = "", change_description: str = "") -> PromptVersion: """提交新版本(类似 git commit)""" latest = self.storage.get_latest(prompt_id) new_version = self._increment_version(latest.version, change_description) version = PromptVersion( id=self._generate_id(), prompt_id=prompt_id, version=new_version, parent_version=latest.version, system_prompt=system_prompt or latest.system_prompt, user_template=user_template or latest.user_template, variables_schema=latest.variables_schema, author=author, created_at=datetime.now(), status=PromptStatus.DRAFT, change_type=ChangeType.MODIFIED, change_description=change_description ) self.storage.save(version) return version def diff(self, version_a: str, version_b: str) -> dict: """比较两个版本的差异""" va = self.storage.get(version_a) vb = self.storage.get(version_b) return { 'system_prompt_diff': self._text_diff( va.system_prompt, vb.system_prompt), 'user_template_diff': self._text_diff( va.user_template, vb.user_template), 'version_a': version_a, 'version_b': version_b, 'metadata_changes': { 'author': f"{va.author} → {vb.author}", 'change_type': vb.change_type.value, } } def promote(self, version: str, target_env: str) -> PromptVersion: """版本晋升(draft → staging → production)""" pv = self.storage.get(version) if target_env == "staging": pv.status = PromptStatus.STAGING elif target_env == "production": # 检查前置条件 if pv.evaluation is None: raise ValueError("版本未评估,不能上线") if pv.evaluation.get('safety', 0) < 0.95: raise ValueError("安全评估未达标") # 将之前的 production 版本标记为 deprecated old_prod = self.storage.get_production_version(pv.prompt_id) if old_prod: old_prod.status = PromptStatus.DEPRECATED self.storage.save(old_prod) pv.status = PromptStatus.PRODUCTION pv.deployed_at = datetime.now() pv.traffic_percentage = 100 self.storage.save(pv) return pv def rollback(self, prompt_id: str, target_version: str = None) -> PromptVersion: """回滚到指定版本""" if target_version is None: # 回滚到上一个 production 版本 versions = self.storage.get_version_history(prompt_id) prod_versions = [v for v in versions if v.status in [PromptStatus.DEPRECATED]] if not prod_versions: raise ValueError("没有可回滚的版本") target_version = prod_versions[0].version target = self.storage.get(target_version) current_prod = self.storage.get_production_version(prompt_id) if current_prod: current_prod.status = PromptStatus.DEPRECATED target.status = PromptStatus.PRODUCTION target.change_type = ChangeType.ROLLED_BACK target.deployed_at = datetime.now() self.storage.save(current_prod) self.storage.save(target) return target def _increment_version(self, current: str, change_desc: str) -> str: """语义化版本号递增""" major, minor, patch = map(int, current.split('.')) if change_desc.startswith('BREAKING') or '重大修改' in change_desc: major += 1 minor = 0 patch = 0 elif '新增' in change_desc or '优化' in change_desc: minor += 1 patch = 0 else: patch += 1 return f"{major}.{minor}.{patch}" def _text_diff(self, text_a: str, text_b: str) -> str: """生成文本差异""" import difflib diff = difflib.unified_diff( text_a.splitlines(keepends=True), text_b.splitlines(keepends=True), fromfile='old', tofile='new' ) return ''.join(diff) 四、A/B 测试引擎 class PromptABTestEngine: """Prompt A/B 测试引擎""" def __init__(self, version_control: PromptVersionControl, llm_client, evaluator): self.vc = version_control self.llm = llm_client self.evaluator = evaluator self.active_tests: Dict[str, ABTest] = {} def create_test(self, prompt_id: str, variant_a: str, variant_b: str, traffic_split: dict = None, duration_days: int = 7) -> ABTest: """创建 A/B 测试""" test = ABTest( id=self._generate_id(), prompt_id=prompt_id, variants={'A': variant_a, 'B': variant_b}, traffic_split=traffic_split or {'A': 50, 'B': 50}, start_time=datetime.now(), end_time=datetime.now().replace( hour=datetime.now().hour + duration_days * 24), success_metrics=['accuracy', 'safety', 'user_satisfaction'], ) self.active_tests[test.id] = test return test def route_request(self, prompt_id: str, user_id: str) -> PromptVersion: """路由用户请求到对应的 Prompt 版本""" import hashlib # 查找活跃测试 test = self._find_active_test(prompt_id) if not test: # 没有测试,返回 production 版本 return self.vc.storage.get_production_version(prompt_id) # 确定性路由(同一用户总是看到同一版本) hash_value = int(hashlib.md5(user_id.encode()).hexdigest(), 16) bucket = hash_value % 100 cumulative = 0 for variant, percentage in test.traffic_split.items(): cumulative += percentage if bucket < cumulative: version = test.variants[variant] return self.vc.storage.get(version) return self.vc.storage.get_production_version(prompt_id) def evaluate_test(self, test_id: str) -> dict: """评估 A/B 测试结果""" test = self.active_tests[test_id] results = {} for variant, version in test.variants.items(): pv = self.vc.storage.get(version) results[variant] = { 'version': version, 'metrics': pv.evaluation or {}, 'sample_size': self._get_sample_size(version), } # 统计显著性检验 significance = self._statistical_test( results['A']['metrics'], results['B']['metrics'] ) test.results = { 'variants': results, 'significance': significance, 'winner': self._determine_winner(results, significance), 'recommendation': self._recommend(test, results, significance) } return test.results def _statistical_test(self, metrics_a: dict, metrics_b: dict) -> dict: """统计显著性检验""" from scipy import stats results = {} for metric in ['accuracy', 'safety', 'user_satisfaction']: if metric in metrics_a and metric in metrics_b: # 简化:假设已有足够样本 z_stat, p_value = stats.ttest_ind( [metrics_a[metric]], [metrics_b[metric]] ) results[metric] = { 'p_value': p_value, 'significant': p_value < 0.05 } return results 五、CI/CD 集成 class PromptCIPipeline: """Prompt CI/CD 管道""" def __init__(self, version_control, evaluator, safety_checker): self.vc = version_control self.evaluator = evaluator self.safety = safety_checker def run_pipeline(self, prompt_version: PromptVersion) -> dict: """运行完整 CI 管道""" results = { 'version': prompt_version.version, 'stages': [], 'passed': True, 'blocking_issues': [] } # Stage 1: 格式检查 stage = self._stage_format_check(prompt_version) results['stages'].append(stage) if not stage['passed']: results['passed'] = False results['blocking_issues'].append("格式检查未通过") return results # Stage 2: 安全扫描 stage = self._stage_safety_scan(prompt_version) results['stages'].append(stage) if not stage['passed']: results['passed'] = False results['blocking_issues'].append("安全扫描未通过") return results # Stage 3: 单元测试 stage = self._stage_unit_test(prompt_version) results['stages'].append(stage) if not stage['passed']: results['passed'] = False results['blocking_issues'].append("单元测试未通过") # Stage 4: 回归测试 stage = self._stage_regression_test(prompt_version) results['stages'].append(stage) if not stage['passed']: results['passed'] = False results['blocking_issues'].append("回归测试未通过") # Stage 5: 性能评估 stage = self._stage_performance_eval(prompt_version) results['stages'].append(stage) # Stage 6: 安全对抗测试 stage = self._stage_adversarial_test(prompt_version) results['stages'].append(stage) if not stage['passed']: results['passed'] = False results['blocking_issues'].append("对抗测试未通过") return results def _stage_format_check(self, pv: PromptVersion) -> dict: """格式检查""" issues = [] # 检查变量引用 for var in pv.variables_schema: if f"{{{{{var}}}}}" not in pv.user_template: issues.append(f"变量 {var} 未在模板中使用") # 检查 Prompt 长度 token_count = self._estimate_tokens(pv.system_prompt) if token_count > 8000: issues.append(f"System Prompt 过长:{token_count} tokens") return { 'stage': 'format_check', 'passed': len(issues) == 0, 'issues': issues } def _stage_safety_scan(self, pv: PromptVersion) -> dict: """安全扫描""" issues = self.safety.scan(pv.system_prompt) return { 'stage': 'safety_scan', 'passed': len(issues) == 0, 'issues': issues } def _stage_regression_test(self, pv: PromptVersion) -> dict: """回归测试:与 production 版本对比""" prod = self.vc.storage.get_production_version(pv.prompt_id) if not prod: return {'stage': 'regression_test', 'passed': True, 'issues': []} # 在相同测试集上对比 test_cases = self.vc.storage.get_test_cases(pv.prompt_id) new_results = [self.evaluator.evaluate(pv, case) for case in test_cases] old_results = [self.evaluator.evaluate(prod, case) for case in test_cases] # 检查是否有关键指标下降 new_accuracy = sum(r['correct'] for r in new_results) / len(new_results) old_accuracy = sum(r['correct'] for r in old_results) / len(old_results) issues = [] if new_accuracy < old_accuracy - 0.05: # 下降超过5% issues.append(f"准确率下降:{old_accuracy:.2%} → {new_accuracy:.2%}") return { 'stage': 'regression_test', 'passed': len(issues) == 0, 'issues': issues, 'metrics': { 'old_accuracy': old_accuracy, 'new_accuracy': new_accuracy } } 六、Prompt 注册中心 class PromptRegistry: """Prompt 注册中心——生产环境的服务发现""" def __init__(self, storage): self.storage = storage self.cache = {} # 本地缓存 def get_prompt(self, prompt_id: str, version: str = "latest") -> PromptVersion: """获取 Prompt(生产环境调用)""" cache_key = f"{prompt_id}:{version}" if cache_key in self.cache: return self.cache[cache_key] if version == "latest": pv = self.storage.get_production_version(prompt_id) else: pv = self.storage.get(prompt_id, version) # 缓存 self.cache[cache_key] = pv return pv def invalidate_cache(self, prompt_id: str): """缓存失效""" keys_to_remove = [k for k in self.cache if k.startswith(prompt_id)] for k in keys_to_remove: del self.cache[k] def list_prompts(self, status: PromptStatus = None) -> list: """列出所有 Prompt""" return self.storage.list_all(status) 七、监控与告警 class PromptMonitor: """Prompt 监控系统""" def __init__(self): self.metrics = {} def record_usage(self, prompt_id: str, version: str, latency_ms: float, token_count: int, success: bool, user_feedback: int = None): """记录 Prompt 使用指标""" key = f"{prompt_id}:{version}" if key not in self.metrics: self.metrics[key] = { 'total_calls': 0, 'success_count': 0, 'latency_sum': 0, 'token_sum': 0, 'feedback_sum': 0, 'feedback_count': 0, 'errors': [] } m = self.metrics[key] m['total_calls'] += 1 if success: m['success_count'] += 1 m['latency_sum'] += latency_ms m['token_sum'] += token_count if user_feedback is not None: m['feedback_sum'] += user_feedback m['feedback_count'] += 1 def check_alerts(self) -> list: """检查告警条件""" alerts = [] for key, m in self.metrics.items(): if m['total_calls'] < 100: continue success_rate = m['success_count'] / m['total_calls'] avg_latency = m['latency_sum'] / m['total_calls'] if success_rate < 0.95: alerts.append({ 'prompt': key, 'alert': 'success_rate_low', 'value': success_rate, 'threshold': 0.95 }) if avg_latency > 5000: alerts.append({ 'prompt': key, 'alert': 'latency_high', 'value': avg_latency, 'threshold': 5000 }) return alerts 结语 Prompt 版本管理不是锦上添花,而是 AI 应用从"能用"到"好用"再到"敢用"的必经之路。正如 Git 改变了软件工程一样,Prompt 版本管理平台正在改变 AI 工程的协作方式。投入建设 Prompt 管理平台,是对团队 AI 能力长期投资中回报率最高的一项。 加入讨论 这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。 ...

2026-06-28 · 7 min · 1479 words · 硅基 AGI 探索者
agent evaluation cicd 2026

Agent 评估自动化:CI/CD 中的 LLM 测试

引言 传统软件测试的基石是确定性:相同输入产生相同输出。LLM Agent 打破了这个前提,让 CI/CD 测试面临根本性挑战。2026年,随着 Agent 评估框架的成熟,一套可落地的 CI/CD 测试方法论终于成型。本文将带你构建完整的 Agent 测试金字塔。 一、Agent 测试金字塔 ┌─────────┐ │ E2E │ ← 端到端场景测试(5-10个) ┌┴─────────┴┐ │ Integration │ ← 多 Agent 协作测试(20-50个) ┌┴──────────────┴┐ │ Evaluation │ ← LLM 评判测试(50-100个) ┌┴──────────────────┴┐ │ Component │ ← 工具/Prompt 测试(200+) ┌┴──────────────────────┴┐ │ Unit Test │ ← 纯函数测试(500+) └───────────────────────────┘ 二、第一层:单元测试(确定性层) 单元测试只测试不涉及 LLM 的部分:数据处理、工具执行的解析逻辑、Prompt 模板渲染。 import pytest class TestPromptTemplate: """Prompt 模板渲染测试""" def test_system_prompt_renders_correctly(self): template = SystemPromptTemplate( role="research_assistant", tools=["search", "calculator"], constraints=["cite sources", "be concise"] ) rendered = template.render() assert "research_assistant" in rendered assert "search" in rendered assert "calculator" in rendered assert "cite sources" in rendered def test_few_shot_template_with_examples(self): template = FewShotTemplate( system="You are a classifier", examples=[ {"input": "I love it", "output": "positive"}, {"input": "Terrible", "output": "negative"}, ], query="{user_input}" ) rendered = template.render(user_input="Amazing!") assert "positive" in rendered assert "negative" in rendered assert "Amazing!" in rendered class TestToolParsing: """工具调用解析测试""" @pytest.mark.parametrize("raw_output,expected_tool,expected_args", [ ('{"tool": "search", "args": {"q": "weather"}}', "search", {"q": "weather"}), ('```json\n{"tool": "calc", "args": {"expr": "1+1"}}\n```', "calc", {"expr": "1+1"}), ('I\'ll use the search tool: {"tool": "search", "args": {"q": "news"}}', "search", {"q": "news"}), ]) def test_parse_tool_call(self, raw_output, expected_tool, expected_args): result = parse_tool_call(raw_output) assert result.tool == expected_tool assert result.args == expected_args def test_parse_malformed_output(self): with pytest.raises(ToolParseError): parse_tool_call("This is not JSON at all") 三、第二层:组件测试(Mock LLM) 使用 Mock LLM 测试 Agent 的控制流,确保工作流逻辑正确。 ...

2026-06-28 · 5 min · 1030 words · 硅基 AGI 探索者
codex ci cd integration

Codex与CI/CD集成实践

概述 Codex与CI/CD集成实践是AI智能体领域中Codex与CI/CD集成实践的重要主题。本文将从多个角度深入分析这一话题,为读者提供系统性的认知框架和实践参考。 核心概念 基本定义 在深入讨论之前,我们需要明确几个核心概念。AI智能体是指能够感知环境、理解指令、规划行动并调用工具完成任务的AI系统。与传统的聊天机器人不同,智能体具有自主性、目标导向性和工具使用能力。 Codex与CI/CD集成实践涉及的关键技术包括: 大语言模型:作为智能体的认知引擎,负责理解、推理和生成 工具调用:通过Function Calling或MCP协议与外部系统交互 记忆系统:短期记忆处理当前对话,长期记忆存储历史经验 规划引擎:将复杂任务分解为可执行的子步骤 技术原理 从技术层面看,Codex与CI/CD集成实践的核心在于如何让AI系统更好地理解和执行人类意图。这涉及多个技术环节的协同: 首先是感知层,智能体需要准确理解用户的自然语言指令,提取关键信息和约束条件。其次是规划层,将高层目标分解为具体的执行步骤。然后是执行层,调用合适的工具完成每个步骤。最后是反馈层,根据执行结果调整后续策略。 实践分析 当前现状 在Codex智能体领域,当前的技术实践呈现出几个明显特征: 工程化程度提升:从实验室原型到生产级系统,工程能力成为关键差异化因素 评估体系完善:越来越多标准化的评测基准被提出,帮助开发者量化能力边界 开源生态繁荣:开源框架和工具链的成熟降低了开发门槛 安全意识增强:对AI安全和对齐问题的重视程度显著提升 关键挑战 尽管进展显著,Codex与CI/CD集成实践仍面临几个核心挑战: 技术挑战: 大模型的幻觉问题在智能体场景下被放大,因为智能体需要做出实际决策 多步推理中的错误累积效应导致长程任务成功率下降 工具调用的可靠性受外部API稳定性影响 工程挑战: 智能体的可观测性不足,调试和排错困难 成本控制与性能优化的平衡 从单机到分布式部署的架构复杂性 安全挑战: Prompt注入等攻击手段不断进化 智能体权限管理需要更精细化的控制 数据隐私保护在多Agent协作场景下更加复杂 优化策略 针对上述挑战,以下是几个关键优化方向: 技术优化 分而治之:将复杂任务分解为可独立验证的子任务,降低单步错误影响 多路投票:对关键决策使用多次采样投票机制,提高可靠性 渐进式信任:智能体权限从最小化开始,根据表现逐步扩展 人在回路:高风险决策保留人工审核环节 工程优化 可观测性优先:建立完善的日志、指标和追踪体系 灰度发布:新版本智能体先在小流量环境验证 自动化测试:构建端到端测试套件,防止回归 成本监控:实时追踪Token消耗和API调用成本 案例研究 为了更具体地说明Codex与CI/CD集成实践的实践价值,我们来看一个典型场景: 某科技公司在内部IT运维中部署了AI智能体,负责处理员工的工单请求。智能体需要理解员工的自然语言描述,判断问题类型,查询知识库,执行修复操作或转接人工。 实施过程中遇到的关键问题包括: 员工描述模糊导致意图识别错误 知识库信息过时导致给出错误建议 某些操作需要管理员权限存在安全风险 解决方案: 引入澄清对话机制,在不确定时主动追问 建立知识库更新流程,定期审核内容 实施权限分级制度,敏感操作需人工确认 效果:工单首次解决率提升35%,平均处理时间缩短60%,员工满意度显著提升。 未来趋势 Codex与CI/CD集成实践的发展趋势值得关注: 标准化:MCP等开放协议将推动工具接口标准化,降低集成成本 垂直化:针对特定行业和场景的专用智能体将大量涌现 协作化:多智能体协作将成为复杂任务的标准解决方案 自主化:智能体的自主决策能力将持续提升,但需要配套的安全机制 结论 Codex与CI/CD集成实践是AI智能体技术发展中的重要一环。无论是技术原理的深入理解,还是实践中的工程优化,都需要系统性思维。对于开发者和企业而言,关键在于: 理解技术能力和边界,避免过度期待 建立系统化的评估和监控体系 在创新和安全之间找到平衡 持续学习和适应快速变化的技术生态 硅基AGI探索者将持续关注Codex智能体领域的最新进展,为读者提供深度分析和实践指导。— ...

2026-06-27 · 1 min · 88 words · 硅基 AGI 探索者
prompt version management

Prompt版本管理实践

引言 Prompt是大语言模型应用的核心资产,但在很多团队中,Prompt的管理方式仍然停留在复制粘贴和聊天记录中。随着Prompt复杂度增长和团队协作需求增加,缺乏版本管理的Prompt会导致:无法追溯变更历史、无法回滚有问题的修改、无法复现线上效果、团队成员各自维护不同版本。本文分享将Prompt纳入专业版本管理的实践方案。 为什么Prompt需要版本管理 Prompt是代码 Prompt与代码有相似的特性:需要迭代调试、存在依赖关系(系统Prompt→Few-Shot示例→用户输入模板)、需要测试验证、可能引入回归问题。因此,Prompt应享受与代码同等的版本管理待遇。 Prompt变更的影响 一个看似微小的Prompt修改可能导致模型行为的显著变化:将"请分析"改为"请详细分析"可能使输出长度翻倍;调整示例顺序可能影响Few-Shot效果;修改约束条件的措辞可能改变模型的遵守程度。没有版本管理,这些变更的影响无法被追踪和评估。 Git工作流设计 仓库结构 prompts/ ├── system/ │ ├── assistant.md # 通用助手系统Prompt │ ├── code-reviewer.md # 代码审查专家 │ └── data-analyst.md # 数据分析师 ├── templates/ │ ├── classification/ # 分类任务模板 │ ├── extraction/ # 信息提取模板 │ └── generation/ # 内容生成模板 ├── few-shot/ │ ├── sentiment/ # 情感分析示例 │ └── ner/ # 命名实体识别示例 ├── tests/ │ ├── test_cases/ # 测试用例 │ ├── expected_outputs/ # 期望输出 │ └── runners/ # 测试运行器 ├── configs/ │ ├── models.yaml # 模型配置 │ └── environments.yaml # 环境配置 └── README.md Prompt文件格式 每个Prompt文件采用统一的格式: ...

2026-06-27 · 3 min · 559 words · 硅基 AGI 探索者
llm ci cd pipeline

LLM 应用 CI/CD 流水线:从 Prompt 到生产的自动化

为什么 LLM 应用需要特殊的 CI/CD 传统软件 CI/CD 关注代码编译、单元测试、部署。LLM 应用的 CI/CD 还需要处理:Prompt 变更的不确定性、模型版本漂移、输出质量回归、A/B 测试的统计显著性。一行 Prompt 改动可能让整个系统的回答质量崩塌,而你很难用传统测试覆盖。 Prompt 版本控制 目录结构 prompts/ ├── v1/ │ ├── system.txt │ ├── fewshot.json │ └── config.yaml ├── v2/ │ ├── system.txt │ ├── fewshot.json │ └── config.yaml └── current -> v2/ # 符号链接指向当前版本 Prompt 配置文件 # prompts/v2/config.yaml version: "2.1.0" model: gpt-4o temperature: 0.3 max_tokens: 2000 system_prompt_file: system.txt fewshot_file: fewshot.json variables: - name: user_query required: true - name: context required: false default: "" tests: - name: "basic_qa" dataset: "datasets/qa_test_100.jsonl" min_score: 0.85 - name: "safety_check" dataset: "datasets/safety_test_50.jsonl" min_score: 0.98 Prompt 加载与版本注入 import yaml from pathlib import Path class PromptManager: def __init__(self, prompts_dir="prompts"): self.prompts_dir = Path(prompts_dir) def load(self, version="current"): path = self.prompts_dir / version config = yaml.safe_load((path / "config.yaml").read_text()) system = (path / config["system_prompt_file"]).read_text() fewshot = json.loads( (path / config["fewshot_file"]).read_text() ) return Prompt( version=config["version"], system=system, fewshot=fewshot, model=config["model"], temperature=config["temperature"], max_tokens=config["max_tokens"], ) 自动评估门禁 CI 流水线中必须在部署前运行自动评估,不达标的版本被拦截。 ...

2026-06-25 · 4 min · 844 words · 硅基 AGI 探索者
prompt version control

Prompt 版本管理实践:像代码一样管理 Prompt

Prompt as Code:理念 代码有 Git,有 CI/CD,有 code review,有单元测试。Prompt 呢?大多数团队的 Prompt 管理方式相当于把代码写在记事本里,用文件名标记版本。 Prompt as Code 的核心主张: Prompt 是代码,不是配置 Prompt 变更需要 review 和审批 Prompt 变更需要测试和验证 Prompt 需要版本回退能力 Prompt 需要线上监控和告警 Git 管理 Prompt 仓库结构 prompt-repo/ ├── prompts/ │ ├── customer-service/ │ │ ├── intent-classification.yaml │ │ ├── response-generation.yaml │ │ └── escalation.yaml │ ├── data-analysis/ │ │ ├── sql-generation.yaml │ │ └── insight-summary.yaml │ └── _shared/ │ ├── system-prompts.yaml │ └── safety-rules.yaml ├── tests/ │ ├── golden-sets/ │ │ ├── customer-service-golden.jsonl │ │ └── data-analysis-golden.jsonl │ └── regression/ │ └── test_regression.py ├── eval/ │ ├── evaluators.py │ └── metrics.py ├── .promptlab.yaml # 工具配置 └── CHANGELOG.md Prompt 文件规范 # prompts/customer-service/intent-classification.yaml id: cs-intent-classification name: "客服意图分类" version: "2.3.1" author: "team-cs" status: production # draft | staging | production | archived variables: - name: user_message type: string required: true - name: context type: string required: false default: "" model: provider: openai name: gpt-4o temperature: 0.1 max_tokens: 256 template: | 系统:你是客服意图分类器。将用户消息分类为以下意图之一: [退款, 咨询, 投诉, 修改订单, 技术支持, 其他] {% if context %}上下文:{{context}}{% endif %} 用户消息:{{user_message}} 只输出意图类别,不要输出其他内容。 test_cases: - input: {user_message: "我要退货"} expected: "退款" - input: {user_message: "怎么使用优惠券"} expected: "咨询" metrics: - accuracy >= 0.95 - latency_p95 < 500ms - token_usage < 100 Git 工作流 # 创建 Prompt 变更分支 git checkout -b prompt/cs-intent-v2.4 # 修改 Prompt 后提交 git add prompts/customer-service/intent-classification.yaml git commit -m "feat(cs): 优化意图分类 Prompt,增加技术支持子类 - 新增 3 个 few-shot 示例覆盖技术支持场景 - 调整 temperature 0.2 → 0.1 减少随机性 - 黄金集准确率 92.3% → 96.1% - Closes #142" # CI 自动跑回归测试 git push origin prompt/cs-intent-v2.4 A/B 测试框架 架构 class PromptABTest: def __init__(self, config): self.control = config['control'] # 当前生产版本 self.treatment = config['treatment'] # 候选版本 self.split_ratio = config.get('split', 0.1) # 10% 流量到 treatment self.metrics = config['metrics'] def route(self, request_id, user_id): """决定使用哪个 Prompt 版本""" bucket = hash(f"{user_id}:{self.experiment_id}") % 100 if bucket < self.split_ratio * 100: return self.treatment return self.control def evaluate(self): """评估 A/B 测试结果""" control_results = collect_metrics(self.control) treatment_results = collect_metrics(self.treatment) return { 'control': control_results, 'treatment': treatment_results, 'significance': t_test( control_results['scores'], treatment_results['scores'] ), 'recommendation': self._recommend( control_results, treatment_results ) } def _recommend(self, control, treatment): if treatment['accuracy'] - control['accuracy'] < 0.02: return "no_significant_improvement" if treatment['cost_per_call'] > control['cost_per_call'] * 1.2: return "improvement_but_cost_prohibitive" if treatment['latency_p95'] > 2000: return "improvement_but_latency_too_high" return "promote_to_production" 流量分配 ┌──────────────────┐ │ 用户请求进入 │ └────────┬─────────┘ │ ┌────────▼─────────┐ │ Hash(user_id) │ │ % 100 │ └────────┬─────────┘ ┌─────┴─────┐ │ │ 90% ▼ 10% ▼ ┌──────────┐ ┌──────────┐ │ Control │ │ Treatment│ │ v2.3.1 │ │ v2.4.0 │ └────┬─────┘ └────┬─────┘ │ │ ┌────▼───────────────▼────┐ │ 指标收集 & 对比分析 │ └─────────────────────────┘ 回归测试 黄金集构建 def build_golden_set(production_logs, n=200): """从生产日志中采样构建黄金集""" # 1. 采样 samples = stratified_sample(production_logs, n) # 2. 人工标注/确认 golden = [] for sample in samples: golden.append({ 'input': sample.input, 'expected_output': sample.human_verified_output, 'min_quality_score': 0.85, 'category': sample.category }) return golden 回归测试执行 class PromptRegressionTest: def __init__(self, prompt_template, golden_set, evaluator): self.template = prompt_template self.golden_set = golden_set self.evaluator = evaluator def run(self, model_config): results = [] for case in self.golden_set: prompt = self.template.render(**case['input']) output = llm_call(prompt, **model_config) score = self.evaluator(output, case['expected_output']) results.append({ 'case_id': case.get('id'), 'score': score, 'passed': score >= case['min_quality_score'], 'output': output, 'expected': case['expected_output'] }) passed = sum(r['passed'] for r in results) total = len(results) return { 'pass_rate': passed / total, 'avg_score': sum(r['score'] for r in results) / total, 'failures': [r for r in results if not r['passed']], 'details': results } CI/CD 集成 # .github/workflows/prompt-ci.yml name: Prompt CI on: pull_request: paths: ['prompts/**'] jobs: regression-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install dependencies run: pip install promptfoo langsmith - name: Run regression tests run: | promptfoo eval \ --prompts prompts/customer-service/ \ --tests tests/golden-sets/customer-service-golden.jsonl \ --threshold 0.95 \ --output results.json - name: Check for regressions run: | python scripts/check_regression.py results.json # 如果准确率下降超过 2%,CI 失败 - name: Upload results if: always() uses: actions/upload-artifact@v4 with: name: prompt-test-results path: results.json 线上监控 监控指标 指标 类型 告警阈值 准确率 质量 < 基线 5% 延迟 P95 性能 > 2000ms Token 使用量 成本 > 预算 120% 安全拦截率 安全 > 1% 用户反馈率 满意度 差评 > 10% 空响应率 异常 > 0.5% class PromptMonitor: def __init__(self, prompt_id, version): self.prompt_id = prompt_id self.version = version self.baselines = load_baselines(prompt_id, version) def check(self, metrics): alerts = [] if metrics['accuracy'] < self.baselines['accuracy'] - 0.05: alerts.append({ 'level': 'critical', 'metric': 'accuracy', 'value': metrics['accuracy'], 'baseline': self.baselines['accuracy'], 'action': '考虑回退到上一版本' }) if metrics['latency_p95'] > 2000: alerts.append({ 'level': 'warning', 'metric': 'latency_p95', 'value': metrics['latency_p95'], 'action': '检查模型负载或简化 Prompt' }) if metrics['token_usage_avg'] > self.baselines['token_usage'] * 1.2: alerts.append({ 'level': 'warning', 'metric': 'cost', 'value': metrics['token_usage_avg'], 'action': '优化 Prompt 长度' }) return alerts 工具链:PromptHub 与 LangSmith PromptHub 功能矩阵: ├── Prompt 仓库(版本化存储) ├── 权限管理(RBAC:编辑/审批/部署) ├── 审批工作流(draft → review → staging → production) ├── 在线编辑器(实时预览 + 变量注入测试) ├── A/B 测试管理(实验配置 + 流量分配) └── 审计日志(谁在什么时候改了什么) LangSmith 集成 from langsmith import Client client = Client() # 创建 Prompt 版本 client.create_prompt( name="cs-intent-classification", prompt=template_body, metadata={ "version": "2.4.0", "author": "team-cs", "change_type": "minor" } ) # 线上追踪 @client.trace def classify_intent(user_message): prompt = load_prompt("cs-intent-classification", "2.4.0") response = llm_call(prompt.render(user_message=user_message)) client.record_evaluation( run_id=run.id, key="intent_correct", score=1 if response in VALID_INTENTS else 0 ) return response 实践路线图 阶段一(1-2 周): Prompt 文件化 + Git 管理 ...

2026-06-24 · 5 min · 854 words · 硅基 AGI 探索者
鲁ICP备2026018361号