
1. 为什么要在容器里跑 Gitea Drone以及 AI 步骤怎么接进来如果你手头有一台闲置的 NUC、旧笔记本或者云上最便宜的那档 2C2G 小机器想搭一套「代码托管 持续集成」的完整链路Gitea Drone 这套组合值得认真考虑。Gitea 是一个用 Go 写的轻量级 Git 仓库服务自带 Web 界面、Issue、Pull Request、Webhook二进制体积小、内存占用低Drone 是一个容器原生的 CI/CD 引擎服务端只负责调度和展示真正干活的是 Runner每个流水线步骤都跑在独立容器里。两者都编译成单一可执行文件日常空转内存加起来不到 200MB这是它相比 GitLab 这类全家桶最直观的优势。这套方案适合谁适合个人开发者、三五人的小团队、内网测试环境以及想在自己机器上跑通「提交代码自动构建」完整闭环的学习者。它不适合需要复杂权限矩阵、审计合规、大规模并行的企业场景那些场景 GitLab 或商业 CI 更合适。这篇要解决的核心问题是怎么用容器方式把 Gitea 和 Drone 最小可用地搭起来并且让 CI 流水线里的 AI 步骤比如自动生成提交摘要、代码审查、文档补全通过一个统一的 Key 通道调用模型而不是在每个仓库里散落一堆 API Key。这个统一通道我用的是 TaoToken它把模型调用收敛到一个 Base URL 加一个 KeyCI 里只需要注入两个环境变量就能用。整篇的交付物很具体一份可复制的 docker-compose 配置、Drone Runner 的注册命令、一次真实的流水线触发验证以及 AI 步骤接入的完整参数。你跟着做能在本地或测试环境把「仓库到 CI」这条链路跑通。先说清楚整体架构避免后面配置时迷路。Gitea 负责存代码、发 WebhookDrone Server 接收 Webhook、解析.drone.yml、把任务派给 RunnerDrone Runner 拉起容器执行每一步。三者通过一个外部 Docker 网络互通。AI 步骤作为流水线里的一个普通 step用 curl 或脚本调用 TaoToken 的 APIKey 通过 Drone 的 Secrets 注入不落盘、不进代码库。我试过在一台 4GB 内存的旧笔记本上跑这套Gitea 常驻约 150MBDrone Server 约 10MBRunner 约 6MB加上系统本身日常占用很轻松。真正吃资源的是 CI 执行时拉起的构建容器但那部分是按需的跑完就释放。下面从环境准备开始一步步来。每一步我都会给出完整配置和验证方法你复制粘贴就能用遇到报错也有排查章节兜底。2. 前置准备Docker 环境、目录结构与 TaoToken Key 获取2.1 系统与 Docker 要求这套方案对系统只有一个硬要求能跑 Docker。Linux推荐 Ubuntu 22.04 或更新、macOS装 Docker Desktop、WindowsWSL2 Docker Desktop都可以。我下面所有命令以 Linux 为准macOS 把docker compose换成docker-compose视版本而定逻辑一样。先确认 Docker 和 Compose 可用docker --version docker compose version输出类似Docker version 24.x和Docker Compose version v2.x就 OK。如果docker compose报错试试docker-compose带横杠老版本用的是这个。2.2 目录结构规划我习惯把每个服务放独立目录各自有.env和docker-compose.yml互不干扰升级时也好单独操作。规划如下~/infra/ ├── traefik/ # 反向代理可选但强烈建议 │ ├── docker-compose.yml │ └── data/ ├── gitea/ │ ├── .env │ ├── docker-compose.yml │ ├── data/ │ └── repositories/ ├── drone-server/ │ ├── .env │ ├── docker-compose.yml │ └── data/ └── drone-runner/ ├── .env └── docker-compose.yml先建好这些目录mkdir -p ~/infra/{traefik/data,gitea,drone-server,drone-runner}2.3 创建共享 Docker 网络三个服务要互相通信先建一个外部网络。Traefik 也接在这个网络上统一入口docker network create traefik验证docker network ls | grep traefik看到traefik bridge local就对了。2.4 获取 TaoToken Key 与 Base URLAI 步骤要调模型先拿到统一通道的凭证。访问 TaoToken 控制台创建 API Key控制台入口https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentconsoleAPI Key 管理https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentapi-keys创建后你会得到两样东西记下来后面 CI 里要用项目值用途Base URLhttps://taotoken.net/api所有模型请求的统一入口API Keysk-xxxxxxxx...身份凭证注入到 Drone SecretsModel ID如claude-sonnet-4-5等指定调用哪个模型注意API Key 只显示一次创建后立刻复制保存。如果丢了就重新生成一个旧的作废。想先确认 Key 能用可以在本地用 curl 测一下这一步不依赖任何 CI 环境curl https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer sk-你的Key \ -H Content-Type: application/json \ -d { model: claude-sonnet-4-5, messages: [{role: user, content: 回复两个字可用}], max_tokens: 16 }返回 JSON 里choices[0].message.content有内容说明 Key 和通道都正常。这一步先跑通后面 CI 里出问题就能快速定位是环境问题还是配置问题。2.5 关于 Traefik 的取舍原文用了 Traefik 做反向代理和证书管理我沿用这个思路但把它标为可选。如果你只是本地测试、用 IP 加端口访问完全可以跳过 Traefik直接给 Gitea 和 Drone 映射端口。但一旦涉及域名、HTTPS、多服务统一入口Traefik 会让配置干净很多。Traefik 的配置这里不展开核心是它监听 80/443通过 Docker labels 自动发现后端服务并处理 HTTPS 跳转和证书。你只要保证 Traefik 接在traefik网络上后面 Gitea 和 Drone 的 labels 就能被它识别。如果你跳过 Traefik把下面配置里所有traefik.*的 labels 删掉改成ports: - 3000:3000这种直接映射即可其余逻辑不变。3. 可复制配置Gitea、Drone Server、Drone Runner 三件套这一章是全文的核心三份配置我都给全你按顺序复制、改域名、启动即可。每份配置后面附上关键参数说明方便你按需调整。3.1 Gitea 的 .env 与 docker-compose.yml先写.env把域名、镜像版本、SSH 端口暴露方式抽出来# ~/infra/gitea/.env SERVICE_NAMEGitea SERVICE_DOMAINgitea.example.com DOCKER_IMAGEgitea/gitea:1.21 # 仅允许本机通过 SSH 访问仓库更安全 SSH_PORT_EXPOSE127.0.0.1:2222SERVICE_DOMAIN换成你自己的域名。如果本地测试没域名可以写gitea.local并在/etc/hosts里指向127.0.0.1。SSH_PORT_EXPOSE用127.0.0.1:2222表示只监听本机 2222 端口外部访问不到 Git SSH适合单机场景如果要跨主机 clone改成2222:22。然后是docker-compose.yml# ~/infra/gitea/docker-compose.yml version: 3.6 services: gitea: image: ${DOCKER_IMAGE} container_name: ${SERVICE_DOMAIN} ports: - ${SSH_PORT_EXPOSE}:22 environment: - USER_UID1000 - USER_GID1000 - APP_NAME${SERVICE_NAME} - RUN_MODEprod - RUN_USERgit - SSH_DOMAIN${SERVICE_DOMAIN} - SSH_PORT22 - SSH_LISTEN_PORT22 - HTTP_PORT3000 - ROOT_URLhttps://${SERVICE_DOMAIN} - LFS_START_SERVERtrue - REQUIRE_SIGNIN_VIEWtrue - DB_TYPEsqlite3 - INSTALL_LOCKfalse - DISABLE_GRAVATARtrue networks: - traefik restart: unless-stopped labels: - traefik.enabletrue - traefik.docker.networktraefik - traefik.http.routers.giteaweb.middlewareshttps-redirectfile - traefik.http.routers.giteaweb.entrypointshttp - traefik.http.routers.giteaweb.ruleHost(${SERVICE_DOMAIN}) - traefik.http.routers.giteassl.middlewarescontent-compressfile - traefik.http.routers.giteassl.entrypointshttps - traefik.http.routers.giteassl.tlstrue - traefik.http.routers.giteassl.ruleHost(${SERVICE_DOMAIN}) - traefik.http.services.giteabackend.loadbalancer.server.schemehttp - traefik.http.services.giteabackend.loadbalancer.server.port3000 volumes: - ./repositories:/data/git/repositories - ./data:/data/gitea logging: driver: json-file options: max-size: 10m extra_hosts: - ${SERVICE_DOMAIN}:127.0.0.1 healthcheck: test: [CMD-SHELL, wget -q --spider --proxy off localhost:3000 || exit 1] interval: 5s networks: traefik: external: true几个关键点说明。HTTP_PORT3000是容器内 Gitea 的监听端口Traefik 的loadbalancer.server.port要跟它一致原文用的是 80我这里改成 3000 是因为新版 Gitea 镜像默认非 root 用户跑3000 更稳妥。ROOT_URL必须带https://且和域名一致否则 Webhook 回调地址会错。INSTALL_LOCKfalse表示首次启动走 Web 安装向导装完后 Gitea 会自动把它改成true。启动cd ~/infra/gitea docker compose up -d docker compose logs -f日志出现Listen: http://0.0.0.0:3000和Starting new server就绪。浏览器访问https://gitea.example.com会跳到安装页。3.2 Drone Server 的 .env 与 docker-compose.ymlDrone Server 的.env里OAuth 的 ClientID/Secret 要等 Gitea 装完才能拿到先留占位# ~/infra/drone-server/.env SERVICE_DOMAINdrone.example.com DOCKER_IMAGEdrone/drone:2.20 DRONE_RPC_SECRET换成你自己的随机串 DRONE_ADMIN_USERNAMEadmin GITEA_DOMAINgitea.example.com DRONE_GITEA_CLIENT_ID待Gitea生成后替换 DRONE_GITEA_CLIENT_SECRET待Gitea生成后替换DRONE_RPC_SECRET是 Server 和 Runner 之间的通信密钥两边必须一致。生成一个随机串openssl rand -hex 16把输出填进去。DRONE_ADMIN_USERNAME是 Drone 的超级管理员用户名第一次 OAuth 登录时如果用户名匹配就自动获得管理员权限。docker-compose.yml# ~/infra/drone-server/docker-compose.yml version: 3.6 services: drone: image: ${DOCKER_IMAGE} container_name: ${SERVICE_DOMAIN} environment: - DRONE_GITEA_SERVERhttps://${GITEA_DOMAIN} - DRONE_GITEA_CLIENT_ID${DRONE_GITEA_CLIENT_ID} - DRONE_GITEA_CLIENT_SECRET${DRONE_GITEA_CLIENT_SECRET} - DRONE_LOGS_TRACEtrue - DRONE_AGENTS_ENABLEDtrue - DRONE_RPC_SECRET${DRONE_RPC_SECRET} - DRONE_SERVER_HOST${SERVICE_DOMAIN} - DRONE_SERVER_PROTOhttps - DRONE_CLEANUP_INTERVAL60m - DRONE_CLEANUP_DISABLEDfalse - DRONE_CLEANUP_DEADLINE_RUNNING1h - DRONE_CLEANUP_DEADLINE_PENDING2h - DRONE_USER_CREATEusername:${DRONE_ADMIN_USERNAME},admin:true networks: - traefik restart: unless-stopped labels: - traefik.enabletrue - traefik.docker.networktraefik - traefik.http.routers.drone-web.middlewareshttps-redirectfile - traefik.http.routers.drone-web.entrypointshttp - traefik.http.routers.drone-web.ruleHost(${SERVICE_DOMAIN}) - traefik.http.routers.drone-ssl.middlewarescontent-compressfile - traefik.http.routers.drone-ssl.entrypointshttps - traefik.http.routers.drone-ssl.tlstrue - traefik.http.routers.drone-ssl.ruleHost(${SERVICE_DOMAIN}) - traefik.http.services.drone-backend.loadbalancer.server.schemehttp - traefik.http.services.drone-backend.loadbalancer.server.port80 volumes: - ./data:/data logging: driver: json-file options: max-size: 10m extra_hosts: - ${SERVICE_DOMAIN}:127.0.0.1 healthcheck: test: [CMD-SHELL, wget -q --spider --proxy off localhost:80/healthz || exit 1] interval: 5s networks: traefik: external: true注意DRONE_GITEA_SERVER用的是https://因为 Gitea 走 Traefik 的 HTTPS 入口。DRONE_SERVER_PROTOhttps同理。这两个值错了OAuth 回调会失败。先别启动等 Gitea 配置完 OAuth 再回来。3.3 Drone Runner 的 .env 与 docker-compose.ymlRunner 的.env# ~/infra/drone-runner/.env SERVICE_DOMAINrunner.example.com DOCKER_IMAGEdrone/drone-runner-docker:1.8 DRONE_RPC_SECRET和Server保持一致 DRONE_RUNNER_CAPACITY2 DRONE_SERVER_DOMAINdrone.example.comDRONE_RPC_SECRET必须和 Server 的完全一致这是两边握手的凭证。DRONE_RUNNER_CAPACITY2表示最多同时跑 2 个流水线小机器别设太大。docker-compose.yml# ~/infra/drone-runner/docker-compose.yml version: 3.6 services: drone-runner: image: ${DOCKER_IMAGE} container_name: ${SERVICE_DOMAIN} environment: - DRONE_RPC_PROTOhttps - DRONE_RPC_HOST${DRONE_SERVER_DOMAIN} - DRONE_RPC_SECRET${DRONE_RPC_SECRET} - DRONE_RUNNER_CAPACITY${DRONE_RUNNER_CAPACITY} - DRONE_RUNNER_NAME${SERVICE_DOMAIN} - DRONE_RUNNER_NETWORKStraefik networks: - traefik restart: always volumes: - /var/run/docker.sock:/var/run/docker.sock - ./data:/data logging: driver: json-file options: max-size: 10m extra_hosts: - ${SERVICE_DOMAIN}:127.0.0.1 healthcheck: test: [CMD-SHELL, wget -q --spider --proxy off localhost:3000/healthz || exit 1] interval: 5s networks: traefik: external: trueDRONE_RPC_PROTOhttps和DRONE_RPC_HOST指向 Drone Server 的域名。/var/run/docker.sock挂载是必须的Runner 靠它拉起构建容器。DRONE_RUNNER_NETWORKStraefik让构建容器也接入这个网络方便访问 Gitea。同样先别启动等 OAuth 配好。3.4 三件套配置对照表把关键参数集中列一下方便你核对参数GiteaDrone ServerDrone Runner域名gitea.example.comdrone.example.comrunner.example.com镜像gitea/gitea:1.21drone/drone:2.20drone/drone-runner-docker:1.8内部端口3000803000网络traefiktraefiktraefik关键密钥无DRONE_RPC_SECRETDRONE_RPC_SECRET同左数据卷./data, ./repositories./data./data, docker.sock三份配置都就位后先启动 Gitea完成安装和 OAuth 配置再启动 Drone Server 和 Runner。顺序不能乱因为 Drone 启动时要拿 Gitea 的 OAuth 信息去握手。4. 验证请求从 Gitea 安装到流水线跑通 AI 步骤这一章把链路走完每一步都有验证点。走完你能看到一条真实的流水线在 Drone 里跑起来并且 AI 步骤成功调用了模型。4.1 Gitea 初始化安装浏览器打开https://gitea.example.com会跳到/install。数据库选 SQLite3个人/小团队够用站点名称填你喜欢的管理员账号建议全小写英文比如admin密码设强一点。其余保持默认点「立即安装」。安装完成后自动跳转到登录页用刚设的管理员账号登录。登录后第一件事创建一个测试仓库比如ci-demo勾选「初始化仓库」。4.2 配置 Gitea OAuth 应用点右上角头像 → 设置 → 应用 → 创建新的 OAuth2 应用。名称填DroneCI重定向 URI 填https://drone.example.com/login提交后页面会显示 Client ID 和 Client Secret。把这两个值复制到~/infra/drone-server/.env里替换占位DRONE_GITEA_CLIENT_ID你复制的ClientID DRONE_GITEA_CLIENT_SECRET你复制的ClientSecret4.3 启动 Drone Server 与 Runnercd ~/infra/drone-server docker compose up -d docker compose logs -f日志出现starting the http server之类就绪。然后启动 Runnercd ~/infra/drone-runner docker compose up -d docker compose logs -fRunner 日志里应该出现类似successfully pinged the remote server和polling the remote server说明它和 Server 握手成功。如果一直报cannot ping the remote server检查DRONE_RPC_SECRET是否两边一致、DRONE_RPC_HOST是否可达。4.4 登录 Drone 并激活仓库浏览器打开https://drone.example.com会自动跳转到 Gitea 的授权页点「授权」。授权后以当前 Gitea 用户身份登录 Drone。如果你用的用户名和DRONE_ADMIN_USERNAME一致就是管理员。在 Drone 首页找到ci-demo仓库点进去点「Activate Repository」激活。激活后 Drone 会自动在 Gitea 仓库里加一个 Webhook指向 Drone 的地址。4.5 在 Drone 里配置 AI 步骤的 SecretsAI 步骤要用的 Key 不能写进.drone.yml用 Drone Secrets 注入。在 Drone 仓库页面 → Settings → Secrets新增两个NameValuetaotoken_api_key你的 TaoToken API Keytaotoken_base_urlhttps://taotoken.net/api保存后流水线里用from_secret引用值不会出现在日志里。4.6 编写 .drone.yml 并触发流水线在ci-demo仓库根目录新建.drone.ymlkind: pipeline type: docker name: default steps: - name: build image: alpine:3.19 commands: - echo 构建步骤开始 - echo 当前提交 ${DRONE_COMMIT_SHA:0:8} - echo 构建完成 - name: ai-summary image: curlimages/curl:8.5.0 environment: TAOTOKEN_API_KEY: from_secret: taotoken_api_key TAOTOKEN_BASE_URL: from_secret: taotoken_base_url commands: - | curl -sS ${TAOTOKEN_BASE_URL}/v1/chat/completions \ -H Authorization: Bearer ${TAOTOKEN_API_KEY} \ -H Content-Type: application/json \ -d { model: claude-sonnet-4-5, messages: [ {role: user, content: 用一句话总结这次提交的意义不超过30字。} ], max_tokens: 64 } | tee /tmp/ai_result.json - echo AI 步骤返回已保存 depends_on: - build提交并推送cd ci-demo git add .drone.yml git commit -m add drone pipeline with ai step git push origin main推送后回到 Drone 页面应该能看到一条新的构建记录自动触发。点进去build步骤先跑然后ai-summary步骤执行 curl日志里能看到返回的 JSON。4.7 验证 AI 步骤成功在ai-summary步骤的日志里找到类似这样的输出{ id: chatcmpl-xxx, object: chat.completion, choices: [ { index: 0, message: { role: assistant, content: 新增 CI 流水线并接入 AI 摘要步骤。 }, finish_reason: stop } ], usage: { prompt_tokens: 28, completion_tokens: 15, total_tokens: 43 } }看到choices[0].message.content有内容说明整条链路通了Gitea 提交 → Webhook 触发 Drone → Runner 拉起容器 → AI 步骤通过 TaoToken 统一通道调用模型 → 返回结果。至此仓库到 CI 的完整闭环跑通。如果你想让 AI 步骤的输出更实用比如把摘要写回 Gitea 的提交评论可以在 curl 之后再加一步调用 Gitea API把content作为评论提交。这部分留给你按需扩展核心通道已经打通。5. 本篇常见错误排查401、local proxy failed、reading choices、OAuth 回调失败配置过程中最容易卡在几个固定报错上这一章逐个拆解给出定位方法和修复步骤。5.1 401 UnauthorizedKey 或 Header 问题AI 步骤日志里出现{error:{message:Invalid API key,type:invalid_request_error}}或者 HTTP 401。原因通常是三类Key 没注入、Key 写错、Header 格式不对。先确认 Drone Secrets 里的taotoken_api_key值完整没有多余空格或换行。然后在.drone.yml里确认引用名一致environment: TAOTOKEN_API_KEY: from_secret: taotoken_api_keyfrom_secret后面的名字必须和 Drone 里创建的 Secret 名完全一致大小写敏感。Header 必须是Authorization: Bearer sk-xxxBearer 和 Key 之间一个空格别漏。如果 Secrets 确认没问题还是 401在本地用同样的 Key 跑一次第 2.4 节的 curl排除 Key 本身失效的可能。本地能通、CI 不通就是注入环节的问题。5.2 local proxy failedRunner 网络或 Docker socket 问题Runner 日志里出现cannot ping the remote server local proxy failed或者构建时容器拉不起来。这类问题多半是 Runner 和 Server 之间的网络不通或者 Docker socket 挂载有问题。先检查DRONE_RPC_SECRET两边是否完全一致一个字符都不能差。再确认DRONE_RPC_HOST指向的域名在 Runner 容器内能解析extra_hosts里有没有把域名指到127.0.0.1。如果 Server 和 Runner 不在同一台机器extra_hosts要改成 Server 的真实 IP。Docker socket 方面确认docker-compose.yml里有这行volumes: - /var/run/docker.sock:/var/run/docker.sock没有它Runner 无法拉起构建容器会报Cannot connect to the Docker daemon。另外确认 Runner 容器有权限访问 socketLinux 下通常需要把运行用户加入 docker 组或者用 root 跑。5.3 reading choices响应结构解析错误脚本里解析 AI 返回时出现jq: error (at stdin:1): Cannot index string with choices或者reading choices之类。这通常是把错误响应当成成功响应解析了。TaoToken 返回错误时结构是{error: {...}}没有choices字段。先看原始返回别急着 jqcurl -sS ${TAOTOKEN_BASE_URL}/v1/chat/completions \ -H Authorization: Bearer ${TAOTOKEN_API_KEY} \ -H Content-Type: application/json \ -d {model:claude-sonnet-4-5,messages:[{role:user,content:hi}],max_tokens:16}把返回原样打印出来看是error还是choices。如果是 error按 5.1 排查 Key如果是 choices说明请求本身没问题是后续解析脚本写错了。用 jq 时加个判断if jq -e .choices /tmp/ai_result.json /dev/null 21; then jq -r .choices[0].message.content /tmp/ai_result.json else echo AI 调用失败$(cat /tmp/ai_result.json) exit 1 fi5.4 OAuth 回调失败重定向 URI 或协议不匹配登录 Drone 时跳转回 Gitea 报错或者 Drone 日志里出现oauth2: cannot fetch token: 401 Unauthorized常见原因是 Gitea OAuth 应用里填的重定向 URI 和实际访问的地址不一致。检查三点重定向 URI 必须是https://drone.example.com/login协议、域名、路径都要对DRONE_GITEA_SERVER必须是https://gitea.example.com不能是httpDRONE_SERVER_PROTO必须是https。如果本地测试用http那三处都要统一改成http别混用。混用是 OAuth 失败最常见的原因。5.5 构建容器拉取镜像慢或失败流水线卡在pulling image很久或者报manifest unknown。这是镜像拉取问题和 Gitea/Drone 本身无关。确认 Runner 所在机器能正常docker pull alpine:3.19。如果网络受限可以提前把常用镜像拉到本地或者在.drone.yml里用私有镜像仓库的地址。5.6 排查速查表报错最可能原因修复401 UnauthorizedKey 未注入或格式错检查 Secret 名和 Bearer 格式local proxy failedRPC_SECRET 不一致或网络不通核对密钥、检查 extra_hostsreading choices把 error 当成功解析先打印原始返回再解析OAuth 401重定向 URI 或协议不匹配统一 http/https核对路径manifest unknown镜像拉取失败本地预拉或换镜像源排查的核心思路是先看原始日志别猜再分层定位是 Gitea 层、Drone 层还是 Runner 层最后用最小复现验证比如本地 curl 能通就说明 Key 没问题问题在 CI 环境。6. 把 AI 能力沉淀成 CI 里的标准步骤链路跑通之后真正有价值的是把 AI 步骤做成可复用的模板而不是每个仓库重写一遍。我的做法是在 Gitea 里建一个ci-templates仓库把常用的 AI 步骤片段存成 YAML 片段新项目直接引用。比如一个通用的「提交摘要」步骤参数化模型和提示词kind: pipeline type: docker name: ai-review steps: - name: ai-review image: curlimages/curl:8.5.0 environment: TAOTOKEN_API_KEY: from_secret: taotoken_api_key TAOTOKEN_BASE_URL: from_secret: taotoken_base_url MODEL_ID: from_secret: taotoken_model_id commands: - | DIFF$(git diff HEAD~1 HEAD --stat | head -20) curl -sS ${TAOTOKEN_BASE_URL}/v1/chat/completions \ -H Authorization: Bearer ${TAOTOKEN_API_KEY} \ -H Content-Type: application/json \ -d { \model\: \${MODEL_ID}\, \messages\: [ {\role\: \user\, \content\: \根据以下改动生成一句提交摘要${DIFF}\} ], \max_tokens\: 128 } | jq -r .choices[0].message.content这里多了一个taotoken_model_idSecret把模型 ID 也抽出来换模型不用改 YAML。这种参数化让同一套流水线能适配不同项目。另一个实用场景是「PR 自动审查」。在 Drone 里配置只在 Pull Request 事件触发trigger: event: - pull_request然后 AI 步骤读取 diff让模型给出审查意见再通过 Gitea API 发成 PR 评论。这样每次提 PR 都有 AI 先过一遍人工审查聚焦在真正需要判断的地方。关于长期跑 CI 和 Agent 类任务如果调用量比较大可以了解下 Coding Plan它针对持续编码场景做了额度优化Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentcoding-plan如果你用的是 Claude Code 这类工具做本地开发想把 CI 里的模型通道和本地打通可以参考接入文档接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentdocClaude Code 接入https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentclaudecode想直接在浏览器里验证模型返回用模型对话页面最快模型对话https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmodel-chat最后说个实际踩过的坑CI 里的 AI 步骤一定要设超时和失败容忍。模型调用偶尔会慢如果它卡住整个流水线就得不偿失。在步骤上加timeout或者用failure: ignore让 AI 步骤失败不阻塞主流程- name: ai-summary image: curlimages/curl:8.5.0 failure: ignore commands: - ...这样即使模型通道临时抖动构建本身照样通过AI 摘要只是锦上添花。把 AI 当成流水线里的增强项而非关键路径整套系统会稳很多。