正在学习

12.5 Monitoring Usage with Metrics and Logs

12.6 Example: Optimizing an Expensive Build Pipeline

Even a well-structured CI pipeline can become slow and costly once container builds, dependency installs, long test suites, and Claude-powered documentation/generation steps pile up. This example shows how to turn a sluggish, expensive pipeline into a fast, budget-aware workflow. You will implement deterministic caching, change-based execution, token-cost gating for Claude tasks, and parallelized tests. The result is a pipeline that ships the same quality artifacts with less wall-clock time and lower AI spend.

Concept Development

Performance and cost in CI hinge on four levers. First, avoid redundant work by reusing caches and skipping jobs when nothing relevant changed. Second, make expensive steps (container builds, dependency installs) incremental and deterministic so caches actually hit. Third, bound AI costs: estimate tokens before calling Claude and short-circuit to a cheaper model or a local fallback when the budget would be exceeded. Fourth, run what remains in parallel with minimal coordination, then merge artifacts.

We will apply those levers using a small FastAPI project and a GitHub Actions workflow. The build will cache Python wheels and Docker layers, only run tests affected by recent changes, preflight Claude calls using a token estimator, and push artifacts when all gates pass.

Hands-On Example

Create this minimal project structure:

app/

app.py

requirements.txt

tests/

test_app.py

scripts/

estimate_tokens.py

changed_paths.py

selective_tests.py

build_image.sh

.github/

workflows/

ci.yml

app/requirements.txt

fastapi==0.114.0
uvicorn==0.30.5

app/app.py

from fastapi import FastAPI

app = FastAPI(title="Optimized Pipeline Demo")

@app.get("/health")
def health():
    return {"status": "ok"}

tests/test_app.py

from fastapi.testclient import TestClient
from app.app import app

def test_health():
    c = TestClient(app)
    r = c.get("/health")
    assert r.status_code == 200
    assert r.json()["status"] == "ok"

scripts/estimate_tokens.py

import math
import json
import os
import sys

PRICING = {
    "claude-3.5-haiku": {"in": 0.0008, "out": 0.004},
    "claude-3.5-sonnet": {"in": 0.003, "out": 0.015},
    "claude-3-opus": {"in": 0.010, "out": 0.050},
}

def approx_tokens(text: str) -> int:
    # ~4 chars per token heuristic
    return math.ceil(len(text) / 4)

def main():
    model = os.getenv("CLAUDE_MODEL", "claude-3.5-sonnet")
    budget = float(os.getenv("CLAUDE_BUDGET_USD", "0.05"))
    expected_output_tokens = int(os.getenv("EXPECTED_OUTPUT_TOKENS", "1500"))
    prompt_path = sys.argv[1] if len(sys.argv) > 1 else "-"
    prompt = sys.stdin.read() if prompt_path == "-" else open(prompt_path, "r", encoding="utf-8").read()

    tin = approx_tokens(prompt)
    tout = expected_output_tokens
    rate_in = PRICING[model]["in"]
    rate_out = PRICING[model]["out"]
    cost = (tin/1000)*rate_in + (tout/1000)*rate_out
    decision = "allow" if cost <= budget else "switch"

    print(json.dumps({
        "model": model,
        "input_tokens": tin,
        "output_tokens": tout,
        "estimated_cost": round(cost, 4),
        "budget": budget,
        "decision": decision
    }, indent=2))

    # Exit code communicates gating to CI
    if decision == "allow":
        sys.exit(0)
    else:
        sys.exit(42)

if __name__ == "__main__":
    main()

scripts/changed_paths.py

import subprocess
import sys
import json

# Determine changed files against the base ref (default: origin/main)
base = sys.argv[1] if len(sys.argv) > 1 else "origin/main"
cmd = ["git", "diff", "--name-only", f"{base}...HEAD"]
out = subprocess.check_output(cmd, text=True)
files = [f.strip() for f in out.splitlines() if f.strip()]
print(json.dumps({"changed": files}, indent=2))

scripts/selective_tests.py

import json
import sys
from pathlib import Path

练习题

Which of the following is NOT one of the four levers for performance and cost optimization in CI pipelines?

A. Avoid redundant work by reusing caches and skipping jobs when nothing relevant changed
B. Make expensive steps incremental and deterministic so caches actually hit
C. Use faster hardware for all CI jobs to reduce execution time
D. Bound AI costs by estimating tokens before calling Claude and short-circuiting to cheaper models when the budget would be exceeded

What is the purpose of the approx_tokens function in scripts/estimate_tokens.py?

A. To calculate the exact number of tokens in a text using a complex algorithm
B. To estimate the number of tokens in a text using a heuristic of ~4 characters per token
C. To count the number of words in a text
D. To calculate the cost of calling Claude based on the number of tokens

Which of the following are valid model names in the PRICING constant in scripts/estimate_tokens.py? (Select all that apply)

A. claude-3.5-haiku
B. claude-3.5-sonnet
C. claude-3-opus
D. claude-2-sonnet

Which of the following are part of the minimal project structure for the example? (Select all that apply)

A. app/app.py
B. app/requirements.txt
C. tests/test_app.py
D. scripts/build_image.sh
E. .github/workflows/ci.yml

The scripts/changed_paths.py script uses git diff --name-only to determine the files that have changed between the current branch and origin/main.

The scripts/estimate_tokens.py script exits with code 0 if the estimated cost of calling Claude is within the budget, and exits with code 42 if the cost exceeds the budget.

In the scripts/estimate_tokens.py script, the heuristic used to approximate the number of tokens in a text is ___ characters per token.

The default value for EXPECTED_OUTPUT_TOKENS in the scripts/estimate_tokens.py script is ___.

What is the purpose of the scripts/changed_paths.py script in the CI pipeline?

How does the scripts/estimate_tokens.py script help bound AI costs in the CI pipeline?

Which of the following is a benefit of monitoring Claude Code usage through structured metrics and logs?

A. It helps managers track overall token consumption and cost per developer
B. It enables proactive optimization by identifying trends and bottlenecks
C. It ensures transparency and accountability across teams
D. All of the above

Which of the following are categories of metrics for monitoring Claude Code usage? (Select all that apply)

A. Usage Metrics
B. Performance Metrics
C. Audit Logs
D. Cost Metrics

Which combination of strategies would best optimize both performance and cost in a CI pipeline that frequently calls Claude for documentation generation?

A. Use caching for repeated Claude prompts and implement token-cost gating
B. Increase the number of parallel CI jobs and use the most powerful Claude model
C. Disable caching and always use the maximum output token limit for Claude
D. Run all tests sequentially and use Claude only for error reporting

Which metrics would be most valuable to monitor when implementing the token estimation script (estimate_tokens.py) in a CI pipeline?

A. Tokens per request
B. Response latency
C. Requests per user
D. Cost per session
E. Prompt-response ratio

The changed_paths.py script could be enhanced to skip running tests for files that haven't changed by integrating with the selective_tests.py script, improving both performance and cost in the CI pipeline.

To implement the 'bound AI costs' lever from kp_12_6_001, the estimate_tokens.py script should calculate cost using the formula , where is ___, is ___, is ___, and is ___.

How would you modify the test_app.py script to help reduce Claude token usage when generating documentation from test results?

登录后解锁笔记、知识点解析、AI 问答

立即登录