正在学习
使用示例
将源文件路径映射到测试。在实际项目中,你可能需要解析导入图。
mapping = { "app/app.py": ["tests/test_app.py"] }
changed_json = sys.stdin.read() changed = json.loads(changed_json)["changed"] selected = set()
for path in changed: if path in mapping: for t in mapping[path]: if Path(t).exists(): selected.add(t)
如果没有匹配到任何内容,则回退到完整测试套件
if not selected: selected = {"tests"}
print(" ".join(sorted(selected)))
scripts/build_image.sh
```bash
#!/usr/bin/env bash
set -euo pipefail
APP_NAME="opt-pipeline-demo"
IMAGE="{IMAGE:-ghcr.io/{GITHUB_REPOSITORY}/${APP_NAME}}"
TAG="{TAG:-{GITHUB_SHA::7}}"
echo "[build] 正在构建 TAG (使用缓存)"
docker build \
--file - \
--tag "TAG" \
--tag "$IMAGE:latest" \
--cache-from "$IMAGE:latest" \
. <<'DOCKER'
FROM python:3.11-slim
WORKDIR /app
COPY app/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app/ .
EXPOSE 8000
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
DOCKER
.github/workflows/ci.yml
name: 优化的 CI
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
workflow_dispatch: {}
concurrency:
group: opt-ci-${{ github.ref }}
cancel-in-progress: true
env:
PYTHON_VERSION: "3.11"
CLAUDE_MODEL: claude-3.5-sonnet
CLAUDE_BUDGET_USD: "0.05"
EXPECTED_OUTPUT_TOKENS: "1800"
jobs:
prepare:
runs-on: ubuntu-latest
outputs:
changed: ${{ steps.diff.outputs.changed }}
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- id: diff
run: |
python3 scripts/changed_paths.py > changed.json
echo "changed=GITHUB_OUTPUT
test:
needs: prepare
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- uses: actions/setup-python@v5
with: { python-version: ${{ env.PYTHON_VERSION }} }
- name: 缓存 pip
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: pip-{{ env.PYTHON_VERSION }}-${{ hashFiles('app/requirements.txt') }}
restore-keys: pip-{{ env.PYTHON_VERSION }}-
- name: 安装依赖 + pytest
run: |
python -m pip install --upgrade pip
pip install -r app/requirements.txt pytest
- name: 选择性测试列表
id: select
run: |
echo '{{ needs.prepare.outputs.changed }}' '{changed:$changed}' \
| python scripts/selective_tests.py > tests_to_run.txt
echo "tests=GITHUB_OUTPUT
- name: 运行测试
run: |
echo "正在运行: ${{ steps.select.outputs.tests }}"
pytest -q ${{ steps.select.outputs.tests }}
build:
needs: test
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: 登录 GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: 拉取最新镜像以供缓存使用
run: |
docker pull ghcr.io/${{ github.repository }}/opt-pipeline-demo:latest || true
- name: 使用缓存构建并推送
env:
GITHUB_REPOSITORY: ${{ github.repository }}
GITHUB_SHA: ${{ github.sha }}
run: |
bash scripts/build_image.sh
docker push ghcr.io/${{ github.repository }}/opt-pipeline-demo:latest
docker push ghcr.io/{GITHUB_SHA::7}
docs_with_claude:
needs: [test]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 准备提示词
run: |
cat > .prompt.txt <<'PROMPT'
总结 FastAPI 服务并生成一个简洁的 README 章节,内容包括:
- 用途和接口
- 本地运行说明
- 健康检查示例
PROMPT
- name: 估算 Claude 成本并执行门控
id: estimate
env:
CLAUDE_MODEL: ${{ env.CLAUDE_MODEL }}
CLAUDE_BUDGET_USD: ${{ env.CLAUDE_BUDGET_USD }}
EXPECTED_OUTPUT_TOKENS: ${{ env.EXPECTED_OUTPUT_TOKENS }}
run: |
python3 scripts/estimate_tokens.py .prompt.txt > estimate.json || exit_code=$?
cat estimate.json
echo "decision=GITHUB_OUTPUT
echo "model=GITHUB_OUTPUT
echo "est_cost=GITHUB_OUTPUT
exit ${exit_code:-0}
- name: 使用 Claude 生成文档(模拟)
if: steps.estimate.outputs.decision == 'allow'
run: |
echo "## README(自动生成)" > README.md
echo "" >> README.md
echo "- 模型: ${{ steps.estimate.outputs.model }}" >> README.md
echo "- 预估成本: $${{ steps.estimate.outputs.est_cost }}" >> README.md
echo "" >> README.md
echo "### 服务" >> README.md
echo "FastAPI 应用暴露 /health 接口,并使用 Uvicorn 运行。" >> README.md
- name: 回退到更便宜的模型结果(模拟)
if: steps.estimate.outputs.decision == 'switch'
run: |
echo "## README(自动生成,预算回退至 Haiku)" > README.md
echo "FastAPI 应用暴露 /health 接口,并使用 Uvicorn 运行。" >> README.md
- uses: actions/upload-artifact@v4
with:
name: 生成的 README
path: README.md
此工作流展示了组合优化:
- 基于 requirements.txt 哈希的确定性依赖缓存。
- 在构建前拉取 :latest 镜像并确定性打标签,以实现 Docker 层复用。
- 基于变更的测试选择,必要时回退到完整测试套件。
- Token 成本估算,自动限流或降级 Claude 使用。
- 并发取消机制,确保只有最新提交的流水线能运行完成。
说明表格:优化、机制与效果
| 优化项 | 机制 | 实施位置 | 预期影响 |
|---|---|---|---|
| 确定性依赖缓存 | 按 requirements 的哈希值缓存 | 测试作业中的 actions/cache | 安装速度提升 2–10 倍 |
| Docker 层缓存 | 拉取最新镜像并复用层 | 构建作业的 pull + cache-from | 构建时间减少 30–80% |
| 基于变更的执行 | 将变更文件映射到测试 | selective_tests.py 和 changed_paths.py | 跳过无关测试,反馈更快 |
| 并发取消 | 同一引用上的先前运行被取消 | concurrency 块 | 节省 runner 分钟数和成本 |
| AI 支出门控 | 估算 token 并与预算比较 | docs_with_claude 中的 estimate_tokens.py | Claude 成本可预测 |
| 回退策略 | 切换到更便宜的模型或存根 | docs_with_claude 的决策分支 | 在预算内保持流水线通过 |
| 制品复用 | 上传生成的文档 | upload-artifact | 输出清晰,无需重跑 |
通过将缓存复用、路径感知执行、Docker 层缓存、并行化以及 Claude token 门控层层叠加,你把一条既昂贵又缓慢的流水线转变成了一个可预测、速度快且尊重预算的系统。该方法具备可扩展性:可以添加更多映射以细化选择性测试、将镜像缓存提升到远程注册表缓存,或扩展成本门控以在多个 Claude 模型及最大输出大小之间进行选择。借助这些模式,你的 CI 既对开发者友好,又对财务友好,同时保持代码和文档的相同质量标准。
第 13 章 – Claude Code 故障排查与调优
练习题
在 CI 工作流中,当 scripts/estimate_tokens.py 脚本与 docs_with_claude 作业集成时,其主要目的是什么?
A. 计算仓库中已更改文件的数量
B. 根据 token 数量和模型定价估算调用 Claude API 的成本
C. 构建 Docker 镜像并将其推送到镜像仓库
D. 根据已更改的文件运行选择性测试
以下哪些是前述知识点中提到的、且适用于所述CI工作流的AI可观测性最佳实践?
A. 集中日志:将所有使用日志存储在单个存储库或数据库中,以便进行分析和审计。
B. 自动告警:配置成本阈值、高延迟响应或异常活动激增的告警。
C. 对所有微服务使用FastAPI以确保一致性。
D. 集成仪表板:使用Prometheus + Grafana或Elastic Stack等工具获取实时可视化洞察。
E. 始终使用最昂贵的Claude模型以确保高质量输出。
CI 工作流中的 build 任务依赖于 test 任务的成功完成,以确保只有经过测试和验证的代码才会被构建并推送到镜像仓库。
在 CI 工作流中,___ 作业负责准备已更改文件的列表,以确定需要选择性地运行哪些测试。
登录后解锁笔记、知识点解析、AI 问答
立即登录