首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Codex AI 工程实践:从上下文打包到代理循环的工程化实现

Codex AI 工程实践:从上下文打包到代理循环的工程化实现

原创
作者头像
用户12339161
发布于 2026-10-01 16:55:04
发布于 2026-10-01 16:55:04
190
举报

Codex 类 AI 编程工具已经不只是"补全一行代码",而是可以读取仓库、执行命令、修改多文件、跑测试的编码代理。工程视角下,真正决定它能不能用于生产交付的,不是模型能力上限,而是三件事:上下文是否准确、执行是否有边界、产物是否可审查。

本文从代码库上下文打包、代理执行循环、差异审查与 CI 门禁四个环节,拆解 Codex AI 工程的落地骨架。


一、上下文打包:给代理一个"可理解的仓库"

代理最常见的问题是"看不到关键文件"或"看到太多无关文件"。工程上需要先做仓库索引和文件筛选。

代码语言:javascript
复制
from pathlib import Path
from dataclasses import dataclass

IGNORE_DIRS = {".git", "node_modules", "__pycache__", ".venv", "dist", "build"}
ALLOW_EXT = {".py", ".ts", ".tsx", ".go", ".java", ".md", ".toml", ".yaml", ".yml"}

@dataclass
class FileMeta:
    path: str
    size: int
    tokens: int

def scan_repo(root: Path, max_files: int = 2000) -> list[FileMeta]:
    files: list[FileMeta] = []
    for p in root.rglob("*"):
        if not p.is_file() or p.suffix not in ALLOW_EXT:
            continue
        if any(part in IGNORE_DIRS for part in p.parts):
            continue
        text = p.read_text(encoding="utf-8", errors="ignore")
        tokens = len(text) // 4  # 粗略估算
        files.append(FileMeta(str(p.relative_to(root)), p.stat().st_size, tokens))
        if len(files) >= max_files:
            break
    return files

def select_context(files: list[FileMeta], keywords: list[str], budget: int = 60000) -> list[str]:
    scored = []
    for f in files:
        score = sum(1 for k in keywords if k.lower() in f.path.lower())
        scored.append((score, f))
    scored.sort(key=lambda x: (-x[0], x[1].tokens))
    chosen, used = [], 0
    for _, f in scored:
        if used + f.tokens > budget:
            continue
        chosen.append(f.path)
        used += f.tokens
    return chosen

关键点:按关键词相关性排序,再按 token 预算裁剪。不要无脑把整个仓库塞进上下文,成本高且容易引入噪声。


二、代理执行循环:计划、执行、验证

代理不能"一次生成就结束",需要计划—执行—验证的闭环。

代码语言:javascript
复制
import subprocess, json
from dataclasses import dataclass, field

@dataclass
class Step:
    goal: str
    files: list[str] = field(default_factory=list)
    status: str = "pending"
    result: str = ""

def run_cmd(cmd: list[str], timeout: int = 60) -> dict:
    try:
        p = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
        return {"code": p.returncode, "out": p.stdout[-4000:], "err": p.stderr[-2000:]}
    except subprocess.TimeoutExpired:
        return {"code": -1, "out": "", "err": "timeout"}

def verify(repo: Path) -> dict:
    checks = {
        "lint": run_cmd(["ruff", "check", "."]),
        "type": run_cmd(["mypy", "."]),
        "test": run_cmd(["pytest", "-q"]),
    }
    checks["ok"] = all(c["code"] == 0 for c in checks.values())
    return checks

def agent_loop(plan: list[Step], repo: Path, apply_fn, max_rounds: int = 5):
    for rnd in range(max_rounds):
        for step in plan:
            if step.status == "done":
                continue
            patch = apply_fn(step)          # 调用模型生成补丁
            step.result = patch
            check = verify(repo)
            if check["ok"]:
                step.status = "done"
            else:
                step.status = "retry"
                step.goal += f"\n上次失败:{check['test']['err'][:500]}"
        if all(s.status == "done" for s in plan):
            return plan
    return plan

要点:每步都要跑 lint、类型检查、测试;失败信息回填到下一步提示词,让代理自我修正。轮次要有上限,避免无限循环烧钱。


三、差异审查:代理产物必须可读

代理生成的多文件改动,必须先转成可审查的 diff,再决定是否合并。

代码语言:javascript
复制
import difflib
from pathlib import Path

def make_diff(old: str, new: str, path: str) -> str:
    return "".join(difflib.unified_diff(
        old.splitlines(keepends=True),
        new.splitlines(keepends=True),
        fromfile=f"a/{path}",
        tofile=f"b/{path}",
    ))

def summarize(diff: str) -> dict:
    added = sum(1 for l in diff.splitlines() if l.startswith("+") and not l.startswith("+++"))
    removed = sum(1 for l in diff.splitlines() if l.startswith("-") and not l.startswith("---"))
    return {"added": added, "removed": removed, "files": diff.count("--- ")}

审查清单:是否改了无关文件、是否引入新依赖、是否绕过权限校验、是否吞异常、是否删除测试、是否包含硬编码密钥。


四、CI 门禁与安全边界

代理提交同样要过 CI,不能有"AI 特权"。

代码语言:javascript
复制
name: ci
on: [push, pull_request]
jobs:
  quality:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with: { python-version: "3.12" }
      - run: pip install ruff mypy pytest pytest-cov bandit pip-audit
      - run: ruff check .
      - run: mypy .
      - run: pytest --cov=app --cov-fail-under=80
      - run: bandit -r app
      - run: pip-audit

安全边界:

  • 代理只允许在沙箱或独立分支执行,不直连生产。
  • 禁止读取 .env、密钥、用户数据目录。
  • 命令白名单,禁止 rm -rf、curl | sh 等危险操作。
  • 所有工具调用记录 trace_id,日志脱敏。
  • 合并必须有人类负责人。

五、工程化要点与合规

  1. 幂等:同一任务重复执行结果一致,用分支和锁隔离。
  2. 可观测:记录模型、token、耗时、工具调用、失败原因。
  3. 成本控制:上下文预算、缓存、轮次上限。
  4. 版本管理:提示词、上下文选择策略、代理配置都留档。
  5. 合规:不把密钥、用户数据、内部源码提交给外部模型;确认服务条款;尊重开源许可;AI 生成内容按平台要求标注。

六、总结

Codex AI 工程的专业性,不在于让模型写多少代码,而在于把代理放进一条可控的工程链路:上下文准确打包、执行有边界、失败可回填、产物可审查、CI 可拦截。代码可以简单,但权限、日志、测试、门禁和合规不能省。先把最小闭环跑通,再扩展到多仓库、多语言和复杂任务编排。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、上下文打包:给代理一个"可理解的仓库"
  • 二、代理执行循环:计划、执行、验证
  • 三、差异审查:代理产物必须可读
  • 四、CI 门禁与安全边界
  • 五、工程化要点与合规
  • 六、总结
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档