OpenSRE 开发参考:从 CI 守门到代码规范的 Agent 协作工程指南

OpenSRE 开发参考:从 CI 守门到代码规范的 Agent 协作工程指南

【免费下载链接】opensre Build your own AI SRE agents. The open source toolkit for the AI era. 【免费下载链接】opensre 项目地址: https://gitcode.com/GitHub_Trending/op/opensre

OpenSRE(Build your own AI SRE agents)是一个面向 AI 时代的开源 SRE 工具包,其根目录的 AGENTS.md 是仓库的开发总纲:它面向所有自动化编码 Agent 与人类贡献者,定义了"必须闭环的 CI/测试纪律"、构建运行方式、代码风格、测试哲学、性能约束、文件放置策略、仓库地图与高频踩坑清单。本文以该文档为骨架,结合 MakefileCI.mddocs/ARCHITECTURE.md 与相关源码,完整展开这套工程规范,让读者既能照章提交合格 PR,也能理解每条规则背后的实现依据。

一、铁律:Agent 必须闭环 CI 与测试(每个 PR / 每次 Push)

AGENTS.md 开篇即立下基调:"推送了修复"或"打开了 PR"不等于完成。对自动化 Agent 而言,CI 是交付的一部分,必须盯到绿为止。

1.1 每次推送后的标准动作

只要分支上有打开的 PR,每次 push 后必须执行:

gh pr checks --watch
# 或:gh pr view --json statusCheckRollup,url

1.2 失败时的处理流程

任何检查失败(CI Gatequalitytest (*)、导入图等),按以下顺序闭环:

  1. 拉取失败任务日志:gh run view <id> --log-failed
  2. 修复产品代码或测试代码的根因——禁止通过跳过测试或"常量条件开关"(constant-condition toggles)来掩盖;
  3. 对涉及的模块重跑 CI.md 中规定的聚焦本地命令,再 push;
  4. 反复 gh pr checks,直到必需任务全绿(纯文档改动可跳过)。

1.3 三类必须当"真 bug"处理的情况

  • CI 负载下的测试失败(xdist、barrier、fan-out 并发):这是测试基础设施自身的缺陷,应加固同步逻辑,不能当作 flake 忽略;
  • 导入 / API 边界失败check_imports.pytest_integrations_api_border):说明用了错误的模块边缘,应改从 .importlinter.strict 或边界允许列表(border allowlist)中列出的包级公开 API 导入,而不是内部叶子模块——除非 ignore 列表明确点名了该边;
  • 合并后的失败:merge 之后仍要监控 main 分支 CI、完整 CodeQL 与 release 工作流。合并后失败等于交付未完成:必须先修复或回滚,再报告完成。

1.4 钩子自动化:把守则注入 Agent 的 stop 时刻

规范还落地为 Cursor 项目钩子 .cursor/hooks/check-ci-failures.sh,由 .cursor/hooks.jsonstop 事件注册(timeout 90 秒,loop_limit 3)。钩子在 Agent 停止时读取当前分支的 gh pr view --json statusCheckRollup,若存在 FAILURE / TIMED_OUT / ACTION_REQUIRED / STARTUP_FAILURE 结论的检查,就自动注入一条阻塞性 follow-up 消息,要求 Agent 继续修复而不是收工。脚本内部对状态为 aborted / error 或缺少 gh CLI 的情况直接放行,并用 loop_count 上限防止无限自修复循环。换句话说:这条守则不是建议,而是会重新打断 Agent 的阻塞工作项

二、构建与运行:三条基本命令

命令用途
make install通过 uv sync 建立项目环境并以 editable 模式安装本仓库(同时安装阻塞式 pre-push 钩子,见下文)
uv run opensre …开发期推荐入口,从仓库根目录运行,确保使用本 checkout 而非 PATH 上的其他 opensre
uv run python …执行任意 Python 命令的标准方式

Makefile 的源码看,install 目标实际执行 uv sync --frozen --extra dev$(MAKE) install-hooks,并运行 uv run python -m infrastructure.analytics.install 完成安装期埋点;pre-push 目标则调用 .github/ci/run_checks.py --scope $(ARGS),即一套由仓库脚本驱动的统一质量闸门,与 GitHub Actions 使用同一套检查定义(详见 CI.md)。开发中所有 Python 命令都建议通过 uv run 前缀执行,避免污染全局环境。

三、代码风格:让模块边界清晰可审

3.1 总原则

  • 严格类型标注(strict typing),遵循 DRY;
  • 每个文件只有一个清晰职责(separation of concerns)。

3.2 __init__.py 必须是轻量门面

每个 Python 包的 __init__.py 只做两件事:声明公开接口(imports + __all__)。实现、编排、副作用全部放在聚焦模块中,再只 re-export 预期公开 API,绝不允许 __init__.py 变成 god file

仓库中最典型的范例是 config/constants/init.py:它通过 from config.constants.exports import __getattr__ 实现运行时惰性属性解析,只在 TYPE_CHECKING 分支下做静态 re-export 以便 mypy 看到真实类型。这样调用方 from config.constants import NAME 时不会因为想取一个常量而把全部 vendor 模块拉进内存——这正是"轻量门面"的工程化落地。

3.3 docstring 精简且有契约感

  • 简单 API 用一句话说明;
  • 仅在必要时补充非显而易见的不变量、失败行为、分层约束
  • bug 历史与实现叙事放进测试、commit 或 PR 描述,而不是 docstring——但也不要为了缩短而删掉有意义的设计理由。

3.4 HTTP 状态码必须用命名常量

源码与测试中一律使用 http.HTTPStatus 命名常量(如 HTTPStatus.PAYMENT_REQUIRED),禁止硬编码 402 这类数字字面量

3.5 环境变量与共享常量只放 config/constants/

  • 环境变量名与共享静态常量一律收进 config/ 下的领域模块(如 config/constants/billing.pyconfig/constants/llm.py),通过 config/constants/init.py re-export;不得内联在功能模块里或跨文件复制;
  • 特别地,不要在 config/llm_settings.py 里定义共享环境变量名:因为它会导入 config.llm_auth.*,若某个名字同时被它和这些模块需要,就会形成循环导入。只有当某个名字只被 config/llm_settings.py 自己使用(它导入的任何模块都不需要)时,才可以放在那里。

这一约束在 config/constants/llm.py 的模块 docstring 中有直接印证:LLM_PROVIDER_ENVAZURE_OPENAI_BASE_URL_ENV 等连接类变量放在这个"只依赖标准库的叶子模块"中,正是因为 config.llm_settings 导入的 config.llm_auth.provider_catalog 也需要它们——放在 config.llm_settings 里会循环。同理可参考 config/constants/billing.pyORGANIZATION_ID_ENVWEBAPP_URL_ENVCREDITS_IDEMPOTENCY_HEADER 等常量的组织方式。

3.6 重构后不留兼容转发模块

重构迁移完导入与测试后,要在同一次变更中删除旧模块路径,只保留一个 canonical 导入路径,避免代码库出现"兼容性残留"。

3.7 测试替身的写法

禁止在 monkeypatch.setattr / patch 里内联一个构建临时 type(...) 对象的 lambda(或嵌套 lambda)。应抽出具名 def 再传入——函数体内使用 type(...) 是允许的:

def _build_harness() -> Any:
    return type("H", (), {"resolve_env_variables": lambda _self: None})()


monkeypatch.setattr(startup, "_build_harness", _build_harness)

平凡 lambda(如 lambda **_kw: Nonelambda: sentinel)可以保持内联。仓库既有范例见 tests/infrastructure/safety/guardrails/test_llm_integration.py_anthropic_fake_response)与 tests/cli/test_integrations_setup_github.py_prompt_answering)。

3.8 Protocol 方法体:只用 docstring,不用 ...

新增或修改的 Protocol 方法,方法体必须只有 docstring——不允许 ...passraise NotImplementedError,也不允许 docstring 后再跟 .../pass

class ObjectStore(Protocol):
    def put_object(self, key: str, data: bytes) -> None:
        """Store ``data`` under ``key``."""

合规范例见 infrastructure/filestorage/contracts.pycore/agent/loop_host.pyinfrastructure/turn_host/turn_output.pycore/llm/types.py

重要现实:整个代码库尚未完全合规,而且没有任何工具会主动告诉你。对产品代码做 AST 扫描发现:89 个 docstring-only Protocol 方法 vs 23 个文件中的 108 个 raise NotImplementedError stub(集中在 core/agent_harness/ports.pyinfrastructure/harness_providers/gateway/core/storage/session/binding_store.py 等)。这些是既有存量、不属于顺手改造的范围——不要批量转换,也不要未经检查就把某个文件当作先例引用。

合规只靠 review 执行:

  • CodeQL py/ineffectual-statement 只抓... 形式;
  • passraise NotImplementedError 不会触发任何告警;
  • mypy 豁免 Protocol 方法体的"缺 return",所以 -> list[str] 签名下写 pass 也能通过 make typecheck

四、测试哲学:高信号优先,拒绝穷举式覆盖

"小而精、钉住真实失败模式"优先于"宽泛的行覆盖率":每个不同的 bug 类别写一个测试,不要用不同字面量重复覆盖同一分支的用例。

应当编写/保留的测试:

  • 安全与授权:allowlist、request-scoped authority、跨 actor / 跨 channel 隔离;
  • 并发、崩溃、关闭场景下的正确性:cursor、in-flight 工作、ack vs replay、drain vs approval wait;
  • 防止静默耦合的包 / 传输边界(无 peer import、会话键形状对 surface 唯一);
  • 已经咬过 review 或生产的回归(曾经迫使修复的 P1)。

应当跳过或精简的测试(除非它是某个契约的唯一覆盖):

  • 纯 happy-path 的"mock 被调用一次"包装(客户端发送、初始化时发状态);
  • 纯字符串 / 词汇表,且 approve/deny/leave-open 路径已覆盖该辅助函数;
  • 已被 fail/cancel/on_handled 覆盖的 ack/dispatch 路径上的冗余成功变体;
  • 不移动持久状态的防御性解析 /"抓取失败返回空"边界;
  • 只复述控制流意图、不真正走循环或接线的"占位测试"(例如"create_task 不会阻塞创建者")。

五、面向用户的文档纪律(docs/ 下)

docs/用户可见的,因此要求:逐句检验——这句话是否改变读者的行为? 不改变就删掉。

  • 砍掉:vendor API 端点名(如 getMe)、内部函数名、值落在哪个凭据层级、某次变更修了什么 bug——这些属于 PR 描述或模块 docstring;
  • 保留:必选 vs 可选、真正省力的捷径、看不见直到踩中的坑、读者要原样输入的精确命令与环境变量;
  • 用行为语言而非内部 API 语言表述,例如说"机器人从未被添加到的会话在 setup 阶段会失败",而不是"getChat 返回 ok: false"。

六、性能规范:热路径上的算法与数据结构

性能约束只强加在热路径(每个请求 / 每次迭代 / 每次工具调用);冷代码保持简单。复杂度必须是有意为之——选择满足渐进需求的最简结构。

场景正确做法理由
循环内做成员判断 / 去重set / dict,绝不 x in listlist 的 in 是 O(n),set 是 O(1);frozen dataclass 可哈希,可直接入 set
已经查过的对象直接读其字段,不再二次线性扫描;构建 {name: obj} 的 O(1) 映射消除重复查找
构造后不变的结果计算一次(functools.cached_property 或存字段),只读使用热路径上禁止 deepcopy / json.dumps;先确认没有调用方会改共享缓存对象
排序只排轻量物(key/name 字符串)而非重对象,同一集合不要为两个输出排两次最小化开销
队列 / top-k / 有序查找 / 有界缓存collections.deque / heapq / bisect / OrderedDict.move_to_endfunctools.lru_cache选对结构
字符串拼接"".join(parts),绝不在循环里 +=避免二次复杂度

行为保持型重构必须用 TDD 守护:先加一个钉住可观察行为的表征测试(characterization test),确认它在重构的代码上通过,再让它在整个变更中保持绿色;优化之后才做,benchmark 留在 PR 里。

七、文件放置策略:归属模块优先

新增或修改行为时,代码先放进归属模块(owning module),而不是放进"恰好已经导入相似东西"的共享文件。

文件类型应包含不应包含
编排flow.pycontroller.pylifecycle.pyfactory.py阶段排序、接线、分发给专家模块vendor/provider/domain 逻辑、API 客户端、重型 UI
共享 UI / 提示词_ui.pyprompts.py、通用 validation.py可复用提示词、表格、渲染、薄分发某个 provider / integration / vendor 的逻辑
Domain / provider / vendor 模块providers/<name>.pysurfaces/cli/wizard/<name>.pyintegrations/<vendor>/该 provider / vendor / 功能区的全部行为无关 provider 或横切编排
Registry / catalogconfig.py*_catalog.pyprovider_registry.py元数据、默认值、发现表实时 API 调用、onboarding 提示词、重试循环

具体规则:

  1. 同一 provider / vendor / 功能区出现两个及以上函数 → 新增或扩展该区的专用模块(或子包),不要用 provider 分支去撑大共享编排 / UI 文件;
  2. 编辑共享文件前,先看同包内是否已有同类模式(local_llm/providers/azure_openai.pyintegrations/<vendor>/tools/ 等),先匹配既有布局再谈创新;
  3. 分发要薄:共享入口(validate_provider_credentialsget_llm、slash-command 处理器)应在几行内委派,实现留在下游;
  4. 尊重包边界(见 docs/ARCHITECTURE.md):surfaces 组合下层;core/integrations/ 不得从 surfaces/ 导入;
  5. 包内细节遵循该包自带的 AGENTS.md(如 surfaces/interactive_shell/AGENTS.mdcore/llm/AGENTS.md),在该树做结构变更前先读它;
  6. 工具位置遵循 docs/tool-placement-policy.md(vendor 专属 vs tools/system/ vs cross-vendor)。

如果某次改动要在"已服务多个 provider 的文件"里新增一个 provider 专属的 if provider.value == ... 分支,立即停下,抽独立模块。

这套"五层依赖只许向下"的架构在 docs/ARCHITECTURE.md 中有完整定义:Tier 1(surfacesgateway)→ Tier 2(bootstrap,唯一的组合根,可同时导入 toolsintegrations)→ Tier 3(toolsintegrations 互为 peer 不得互导)→ Tier 4(coreinfrastructure,唯一允许的双向对)→ Tier 5(config,叶子)。这些依赖规则由 make check-imports 在 CI 强制执行,是真实不变量而非愿景。

八、持久化与 PR 流程

  • 持久化归属、存储包布局、迁移边界、并发要求遵循 PERSISTENCE.md
  • 任何 push / 开 PR 前必须遵循 CI.md——lint、format、typecheck、test 命令都在其中;
  • 开 PR 必须填写 PR 模板:它不是可选样板,其中包含必填的 AI 使用披露(AI-usage disclosure)部分

8.1 CI.md 的关键机制补充

作为配套,CI.md 定义了本地推送闸门:克隆后运行 make install 会安装锁定依赖与阻塞式 pre-push 钩子(.github/ci/install_hooks.py);钩子会在临时 Git worktree 里用锁定依赖验证"被推送的已提交修订"——未提交的修复救不了已损坏的 commit。日常提交前运行:

make pre-push                 # 60 秒目标,覆盖工作树含未跟踪文件
make pre-push ARGS=--dry-run  # 只预览选中范围,不执行
make test-scope               # 只跑受影响测试(与推送闸门同一映射)

文档-only 的 diff 可跳过代码检查;运行时提示词、脚本、工作流、依赖变更享受该捷径。紧急情况下可用 git -c opensre.prePushOverride='理由' push 单次绕过(会在 pre-push-overrides.jsonl 留痕,且不豁免远端 CI 与合并要求)。

九、仓库地图(Repo Map)

AGENTS.md 用一张表给出仓库全局视图,下表按原意浓缩为目录与职责(更细的五层架构见 docs/ARCHITECTURE.md):

路径职责
bootstrap/组合根:共享进程启动(process.pyBootStep 表:env、Sentry、适配器、能力警告、LLM 预加载)与注册步骤(adapters.py)。每个 host 选择 ProcessProfile 而非自造启动顺序。唯一被允许同时导入 toolsintegrations 的包
core/Agent 编排、上下文组装、共享运行时工具调用循环、领域逻辑。core/tool/ 拥有工具契约 / schema / 注册表端口 / 执行与错误上报;core/tool_framework/ 提供 @tool、skill guidance 等作者辅助
surfaces/cli/CLI、onboarding 向导、本地 LLM 辅助。Provider onboarding → wizard/<provider>.py;新子命令 → commands/<name>.py
surfaces/interactive_shell/交互式终端(REPL)循环、slash 命令、chat/help 界面、行动规划 harness、终端 UI
integrations/每个集成的配置归一化、验证、客户端、辅助、store/catalog 逻辑,及 integrations/<vendor>/tools/ 下的 vendor 工具包
tools/工具注册表、非 vendor 专属的横切工具包(tools/system/fleet_monitoring/tools/system/sre_guidance_tool/ 等)、交互式 shell 行动工具
config/共享常量、提示词、UI 主题
tests/单元、集成、部署、e2e 与支撑测试
docs/用户文档、集成指南、文档站点资源
Dockerfile可选生产容器镜像(FastAPI health app,uvicorn 驱动)
pyproject.toml / Makefile项目元数据与依赖;本地安装、测试、验证、部署、清理的规范自动化

更深一层的关键子包infrastructure/analytics/(分析事件管道与 onboarding 安装辅助)、infrastructure/safety/auth/(本地/托管运行时访问的 JWT 与认证辅助)、infrastructure/safety/guardrails/(护栏规则与评估引擎)、infrastructure/harness_providers/(harness provider 层,启动时经 integrations/harness_adapters.pytools/harness_adapters.py 接线)、integrations/llm_cli/(子进程 LLM CLI,如 Codex)、core/llm/(托管 LLM provider 客户端与工具调用适配器)、core/state/(共享 Agent 状态与会话存储)、gateway/web/webapp.py(网关守护进程托管的 Web 健康应用,而 opensre CLI 是 surfaces/cli/app.py)。

十、入口点:如何新增一个 Tool 或 Integration

10.1 新增 Tool

工具注册表会自动发现 tools/ 下的模块,所以常规路径是:在那里新增一个模块或包,让发现机制接管。完整文件清单与"完成的定义"见 docs/adding-tools-and-integrations.md。步骤:

  1. 选最贴合工具形态的方式:复杂行为用 BaseTool 子类(来自 core.tool),轻量函数用 @tool(...)(来自 core.tool_framework)。必须通过这些层级公开 API 导入,而非内部子模块——边界测试 tests/shared/test_tool_api_border.py 强制这一约束;
  2. 声明清晰元数据:namedescriptionsourceinput_schema,以及按需的 use_casesrequiresoutputsretrieval_controls
  3. 开 / 审 PR 前,先过 docs/adding-tools-and-integrations.md

从源码看,core/tool_framework/tool_decorator.py@tool 重载签名完整支持上述元数据:input_schema / input_model(pydantic BaseModel)、evidence_typeside_effect_levelsurfacesToolSurface 元组)、use_cases / examples / anti_examplesrequiresoutputs / output_schemarequires_approvalapproval_reasonapproval_expiry_secondstags 等。这些字段既是 LLM 选工具的依据,也是护栏与审计的数据来源。

10.2 新增 Integration

集成工作通常横跨:配置归一化、验证、集成专属客户端 / 辅助、工具、文档、测试(Datadog、Grafana 是仓库内的现成范例)。步骤:

  1. 先加配置与归一化逻辑,让上层栈消费一致的数据形状;
  2. 配置路径稳定后再接工具层
  3. 开 / 审 PR 前遵循 docs/adding-tools-and-integrations.md(含 make verify-integrations 与最终 demo 门禁)。

十一、Footguns:必须避开的常见坑(全清单)

AGENTS.md 用最大篇幅列出的实践教训,每一条背后都有静态检查或真实事故:

  1. 常量条件开关(constant-condition toggles):绝不写 if False and …if True or …if False: 来让失败测试"闭嘴"。这会隐藏真实行为(如 cancel 短路)并以死代码形式上线。正确做法是保留真实条件并修测试,或删除分支。由 tests/quality/test_no_constant_condition_toggles.py 用 AST 遍历产品包(bootstrap/config/core/gateway/integrations/infrastructure/surfaces/tools)强制执行。
  2. 不要重新引入 fail-closed 计划护栏(v0.1 教训):交互式 shell 的行动规划器从不拒绝 turn——不要重新引入 planner 拒绝、mark_unhandledUNHANDLED: 约定。完整理由见 docs/interactive-shell-action-policy.md,包级规则见 surfaces/interactive_shell/AGENTS.md
  3. docs 导航:在 docs/ 下新增 .mdx 不够——Mintlify 只显示 docs/docs.json 中登记过的页面;漏了 pages 条目,文档在站点侧边栏就不可达。
  4. 工具 schema:draft-07 的宽松写法(如 "type": ["object", "null"])能过宽松检查,却会在首次调用时因全部工具被一起发送而触发 LLM API 失败。应在 provider adapter 中归一化,并扩展注册表契约测试。
  5. action-agent 路径:不要在 harness 编排器 / SessionGoal 循环 / evidence 层级策略中实现 regex / 关键词 / 模糊意图路由或确定性绕过。意图应留在 action turn 的结构化交接标签中(evidence_kind:…session_goal:…database_query:…),host 只对这些标签或显式 API 做反应(字面 /slash 是唯一批准的例外)。
  6. 异常信息外泄(CWE-209 / CodeQL py/stack-trace-exposure:绝不要把 str(exc)repr(exc)traceback.format_exc()exc.args、provider/model/field 内部细节发给外部 surface——外部 surface 指 HTTP 响应(gateway/web/ 中的 JSONResponse / HTTPException.detail)与发送给 Slack/Telegram 用户的聊天网关消息(gateway sink 上的 OutputSink.render_error)。完整细节只在服务端记录(logger + capture_exception),对外只返回通用消息或 type(exc).__name__。本地 CLI/终端 sink 不算外部,可展示细节。脱敏在 sink / 响应边界做,而不是每个调用点,这样共享 turn 引擎可为本地开发保留细节。
  7. 循环导入(CodeQL py/cyclic-import:CodeQL 把函数内局部导入和 TYPE_CHECKING 导入也算进环,所以"惰性导入"并不能消除告警。必须结构性地断环——把共享符号(类型、异常、辅助)移进双方共同导入的叶子模块,且永远不要从低层模块向上层模块加反向边。先例:surfaces/shared/llm_setup/validation_result.pysurfaces/shared/llm_setup/persist.py 仅用于承载共享符号,使 validationazure_openai_uiservice 保持无环。
  8. CodeQL 不建模 NoReturn:它把 pytest.skippytest.failsys.exittyper.Exit 及自定义 raise 辅助当作"会返回",导致其后的代码看起来可达,产生两类告警:py/uninitialized-local-variable(名字在 try 中绑定、except 只调这类函数)与 unreachable-code(with 体以裸 raise 结尾)。不要用注释压制:让名字在 CodeQL 能看到的每条路径上都绑定。普通"未找到"场景优先用哨兵而非异常控制流——next(iterable, None) 加显式 if x is None: 守卫,而不是 try: next(...) except StopIteration:(mypy 在守卫后能正确收窄,因为它确实尊重 NoReturn)。裸 raise 场景抽一个 _raise() 辅助。
  9. Protocol stub 方法体(CodeQL py/ineffectual-statement:裸 ... 是合法 PEP-544 惯用法但会被 CodeQL 当成无效语句。不要写 def foo(self) -> T: ...;用一行 docstring 作为唯一方法体,也不要同时保留 docstring 和尾部 ... / pass。注意范围:CodeQL 只抓 ...,所以扫描干净代表代码库合规——passraise NotImplementedError 对它不可见(存量 108 个)。
  10. py/ineffectual-statement 不理解 await:裸 await some_task 被 CodeQL 当成丢弃表达式——但它不是,await 本身就是副作用(如收割被取消的任务以保证 client.close() 执行)。不要删 await。优选绑定结果的小辅助(gateway/transports/discord/worker.py_reap_cancelled_task_finished = await task),而不是跳过 await 来"修复"。
  11. 列表内隐式字符串拼接(py/implicit-string-concatenation-in-list:list/tuple 显示里两个相邻字符串字面量与漏了逗号无法区分,跨行长消息会触发。不要用显式 + 压制——把文本提为模块常量再引用。在括号赋值里同款拼接没问题(那里本就不可能想写逗号)。先例:tools/system/python_execution_tool/__init__.py_RUNTIME_FACTS_ANTI_EXAMPLE。最容易咬到的是 use_cases / anti_examples / examples 工具元数据——散文式条目常常超 100 字符行宽。
  12. 混合导入风格(py/import-and-import-from:同一模块既 import X as aliasfrom X import name——即使 from 导入是函数内局部的——也会告警。通常发生在往已有文件追加代码时:沿用该文件既有的导入风格
  13. except 捕获 BaseException:应捕获 Exceptionrequests.exceptions.ConnectTimeoutException 子类,测试线程里收集请求/传输失败仍然有效;捕获 BaseException 还会吞掉 KeyboardInterrupt / SystemExit。不要用 noqa: BLE001 压制。
  14. 未使用的全局变量(CodeQL code-quality):CodeQL 经常不把跨模块导入算作模块级常量的使用。text.py 里只在别的文件通过 from …text import FOO 读取的 FOO = "..." 仍可能告警。优先把相关文案组织在定义模块中确实被使用的结构里(如 HANDOFF_GUIDANCE["database_query:"] 的 dict 项、前缀匹配由消费方完成),或让常量与其唯一读者同居一模块。不要加空自引用或 # noqa 压制。
  15. 并发 turn 下的共享客户端状态:LLM 客户端按 role 缓存(get_llm),网关并行跑 turn,所以一个客户端实例服务多个在途请求。在错误处理器里被改写的实例标志,会被"早已在旧值下构建"的请求读到。应基于当前请求携带的事实分支,而不是标志的现值——在请求构建处本地捕获事实(marked = strip_cache_markers(kwargs) != kwargs),在 except 里查它。先例:prompt-cache fallback 事故——首个 400 清掉了 _cache_markers_enabled,第二个已标记请求跳过了未缓存重试而失败。测试方法:让 fake 依赖在抛错前先改共享状态,即可无线程地确定性复现竞态。
  16. CI 的 typecheck 不覆盖 tests/make typecheck 只对 PYTHON_SOURCE_PATHSconfig core gateway integrations infrastructure surfaces tools)跑 mypy。测试文件里的类型错误永远不会让 CI 失败——别以为 make typecheck 干净就代表新写测试类型干净,必要时直接对测试路径跑 mypy。

结语:规范即产品的一部分

对 OpenSRE 这种"Agent 即用户"的开源项目,AGENTS.md 本质上是一份可执行的协作契约:CI 闭环由 .cursor 钩子机械化,代码风格由 config/constants 的叶子组织与 __init__.py 门面模式约束,包边界由 make check-imports 在 CI 强制,工具与集成入口由注册表自动发现与 docs/adding-tools-and-integrations.md 把关,而 footguns 清单则是把 CodeQL / mypy / 生产事故沉淀成可检索的工程经验。理解并遵守这份参考,是向 OpenSRE 提交高质量、可持续维护代码的前提,也是自动化 Agent 正确协作的底线。

【免费下载链接】opensre Build your own AI SRE agents. The open source toolkit for the AI era. 【免费下载链接】opensre 项目地址: https://gitcode.com/GitHub_Trending/op/opensre

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值