深入浅出解读 PentestGPT 仓库的 improve-codebase-architecture 技能:用"深模块"重构扫描架构摩擦并生成可视化 HTML 审查报告
【免费下载链接】PentestGPTAutomated Penetration Testing Agentic Framework Powered by Large Language Models项目地址: https://gitcode.com/GitHub_Trending/pe/PentestGPT
导读
improve-codebase-architecture是 PentestGPT 仓库(Automated Penetration Testing Agentic Framework Powered by Large Language Models)中.agents/skills/目录下的一组 Agent 技能,其核心使命是:扫描代码库、找出架构摩擦点,把"浅模块"(shallow modules)重构为"深模块"(deep modules),并将所有候选重构建议渲染为一份可视化 HTML 报告。读完本文,你将掌握:如何用共享设计词汇(module / interface / depth / seam / adapter / leverage / locality)识别浅模块并运用"删除测试"(deletion test)验证判断;如何将候选方案输出为自包含 HTML 报告(Tailwind + Mermaid CDN)并打开给用户;以及如何通过 grilling 循环、domain-modeling 与 ADR 记录,把一次架构审查推进为真正落地的重构。
技能定位:扫描架构摩擦,提出"深化机会"
该技能被设计为一个由用户触发的命令式技能(frontmatter 中disable-model-invocation: true,表示不由模型自动调用,而是显式触发)。其description一句话概括了全部职责:
Scan a codebase for deepening opportunities, present them as a visual HTML report, then grill through whichever one you pick.
即:扫描 → 生成可视化报告 → 对选定候选进行追问式深入设计。它不承诺"自动重构",而是强调"提出重构机会并让用户决策",这是它与一般 lint 工具或重构助手最大的区别。
技能的运行被两条既有资产所约束,这也是它"不自说自话"的根基:
- 架构词汇来自
/codebase-design技能(module、interface、depth、seam、adapter、leverage、locality)及其原则(删除测试、"接口即测试面"、"一个适配器 = 假设性的缝,两个 = 真实的缝")。SKILL.md 明确要求:在每条建议中精确使用这些术语,不要漂移成 "component"、"service"、"API" 或 "boundary"。 - 领域语言来自项目根级或模块级的
CONTEXT.md(如 pentestgpt_agent/CONTEXT.md),它给"好的缝"命名;而docs/adr/下的架构决策记录(ADR)是本次审查不应重新翻案的既定决策。
第一阶段:探索(Explore)
技能要求先读两样东西再动手:
- 项目的领域术语表
CONTEXT.md; - 你将要触碰区域的 ADR。
然后使用 Agent 工具的subagent_type=Explore子代理走查代码库。刻意不遵循僵硬的启发式规则,而是有机地探索,并记录"感到摩擦"的地方:
- 理解一个概念是否需要在小模块之间反复跳转?
- 哪些模块是浅的——接口几乎和实现一样复杂?
- 哪些纯函数只是为了可测试性而被抽出,但真正的 bug 藏在调用方式里(缺少locality)?
- 哪些紧耦合模块在跨越接缝时发生泄漏(leakage)?
- 代码库哪些部分未被测试,或难以通过当前接口测试?
对任何疑似浅的模块,应用删除测试(deletion test,出自/codebase-design原则):想象删除这个模块——如果复杂度随之消失,说明它只是个透传(pass-through);如果复杂度在 N 个调用方身上重新出现,说明它在"挣它的饭钱"。SKILL.md 明确说:期望的信号是"删除它会让复杂度集中(concentrates)"——即删除反而是坏事、保留并加深它才是正解。
第二阶段:以 HTML 报告呈现候选(Present candidates as an HTML report)
输出位置与打开方式
报告必须是自包含的单个 HTML 文件,写入 OS 临时目录,绝不落进仓库:
- 从
$TMPDIR解析临时目录,回退到/tmp(Windows 回退到%TEMP%); - 文件名为
<tmpdir>/architecture-review-<timestamp>.html,每次运行都生成新文件; - 写完后为用户打开:Linux 用
xdg-open <path>,macOS 用open <path>,Windows 用start <path>,并告诉用户绝对路径。
技术栈:Tailwind + Mermaid 双 CDN
依据配套的 HTML-REPORT.md,报告用Tailwind via CDN做布局与样式,用Mermaid via CDN画图。关键取舍是:Mermaid 处理"图状关系"(调用图、依赖、时序),手写 div / 内联 SVG 处理"编辑感更强"的视觉(质量图、剖面图、折叠动画)。不要把所有图都交给 Mermaid,否则会显得千篇一律。
报告的 HTML 脚手架如下(摘自 HTML-REPORT.md):
<!doctype html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Architecture review — {{repo name}}</title> <script src="https://cdn.tailwindcss.com"></script> <script type="module"> import mermaid from "https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs"; mermaid.initialize({ startOnLoad: true, theme: "neutral", securityLevel: "loose" }); </script> <style> /* small custom layer for things Tailwind doesn't cover cleanly: dashed seam lines, hand-drawn-feeling arrow heads, etc. */ .seam { stroke-dasharray: 4 4; } .leak { stroke: #dc2626; } .deep { background: linear-gradient(135deg, #0f172a, #1e293b); } </style> </head> <body class="bg-stone-50 text-slate-900 font-sans"> <main class="max-w-5xl mx-auto px-6 py-12 space-y-12"> <header>...</header> <section id="candidates" class="space-y-10">...</section> <section id="top-recommendation">...</section> </main> </body> </html>其中自定义 CSS 层补齐 Tailwind 覆盖不好的细节:虚线接缝线(.seam)、红色泄漏边(.leak)、深模块深色渐变背景(.deep)。页头包含仓库名、日期和一个紧凑图例:实心框 = 模块,虚线 = 接缝,红色箭头 = 泄漏,粗深色框 = 深模块。不要引言段落,直接进候选卡片。
每个候选一张卡片
每个候选是一个<article>,包含:
- 标题——简短,点名深化动作,例如 "Collapse the Order intake pipeline";
- 徽章行——推荐强度徽章(
Strong= emerald 绿、Worth exploring= amber 琥珀、Speculative= slate 灰),外加一个依赖类别标签(in-process、local-substitutable、ports & adapters、mock,分类含义见下文"依赖类别"); - Files——等宽字体文件清单(
font-mono text-sm); - Before / After 图——核心主角,左右两栏并排,展示"浅"与"加深";
- Problem——一句话,哪里疼;
- Solution——一句话,改什么;
- Wins——每条不超过 6 个词的要点,例如 "Tests hit one interface"、"Pricing logic stops leaking"、"Delete 4 shallow wrappers";
- ADR callout(如适用)——琥珀色框里的一行说明。
HTML-REPORT.md 对文案纪律的要求很严:不要解释性段落——如果图需要一段话才能看懂,那就重新画图。
五种图表模式
| 模式 | 适用场景 | 要点 |
|---|---|---|
| Mermaid graph | 依赖 / 调用流的"主力图" | flowchart或graph,用classDef把泄漏边染红、把深模块染深;时序图适合"之前 6 次往返,之后 1 次" |
| 手绘盒子与箭头 | Mermaid 布局不听话时 | 模块用<div>加边框标签,箭头用绝对定位的内联 SVG<line>/<path>;适合"after"里那种厚边框深模块内灰化内部的效果 |
| 剖面图(Cross-section) | 分层式浅薄 | 水平色带(h-12 border-l-4)堆叠展示一次调用穿过的层:之前 6 条薄层各干点碎活,之后 1 条厚带承载合并后的职责 |
| 质量图(Mass diagram) | "接口宽如实现" | 每个模块画两个矩形——接口面积与实现面积:before 中接口矩形几乎和实现矩形一样高(浅),after 中接口矩形矮、实现矩形高(深) |
| 调用图折叠 | 函数调用树 | Before:嵌套盒子组成的调用树;After:整棵树塌缩进一个盒子,内部调用以淡色保留在盒内 |
一个可复制的 Mermaid 示例(依赖泄漏演示):
<div class="rounded-lg border border-slate-200 bg-white p-4"> <pre class="mermaid"> flowchart LR A[OrderHandler] --> B[OrderValidator] B --> C[OrderRepo] C -.leak.-> D[PricingClient] classDef leak stroke:#dc2626,stroke-width:2px; class C,D leak </pre> </div>风格纪律(来自 HTML-REPORT.md):
- 偏"编辑感"而非"公司仪表盘":充足留白,标题可选衬线字体(
font-serif搭配 stone/slate 很好看); - 颜色克制:一个主色调(emerald 或 indigo)+ 红色表示泄漏 + 琥珀表示警告;
- 图高控制在约 320px,保证 before/after 并排时不滚动;
- 图内模块标签用
text-xs uppercase tracking-wider——它们应读起来像示意图而不是 UI; - 全报告唯一脚本就是 Tailwind CDN 与 Mermaid ESM 导入,其余保持静态。
词汇纪律:精确到词
HTML-REPORT.md 明确规定了"必须用 / 不许用"的词汇表:
- 必须精确使用:module、interface、implementation、depth、deep、shallow、seam、adapter、leverage、locality;
- 严禁替换:component、service、unit(代替 module)· API、signature(代替 interface)· boundary(代替 seam)· layer、wrapper(代替 module)。
符合风格的例句:
- "Order intake module is shallow — interface nearly matches the implementation."
- "Pricing leaks across the seam."
- "Deepen: one interface, one place to test."
- "Two adapters justify the seam: HTTP in prod, in-memory in tests."
Wins 要点也必须用术语表语言说收益:"locality: bugs concentrate in one module"、"leverage: one interface, N call sites"、"interface shrinks; implementation absorbs the wrappers"。禁止写 "easier to maintain" 或 "cleaner code"——这些词不在术语表里,不值它们的版面。
Top recommendation 收尾
报告以Top recommendation部分结尾:一张更大的卡片,包含候选名、一句话理由、指向对应卡片的锚点链接——就这样,不做多余展开。
两个关键约束
- 领域词汇对齐:用
CONTEXT.md的词汇说领域,用/codebase-design的词汇说架构。如果CONTEXT.md定义了 "Order",就说 "the Order intake module",而不是 "the FooBarHandler",也不是 "the Order service"。 - ADR 冲突处理:候选若与既有 ADR 冲突,只有在摩擦真实到值得重开 ADR 时才呈现,并在卡片中明确标注(例如警告框:"contradicts ADR-0007 — but worth reopening because…")。不要罗列 ADR 禁止的每一个理论化重构。
写完文件后不要立即提接口方案,而是问用户:"Which of these would you like to explore?"(你想探索哪一个?)
第三阶段:Grilling 循环(Grilling loop)
用户选定候选后,进入追问式设计循环:
- 运行
/grilling技能(见 .agents/skills/grilling/SKILL.md)沿设计树与用户逐题过招——约束、依赖、加深后模块的形状、接缝后面是什么、哪些测试能存活。grilling 的纪律是:一次只问一个问题,等用户反馈再继续,且每个问题附上推荐答案;如果问题能通过探索代码库回答,就去探索而不是问。 - 决策在对话中逐步固化时,副作用(side effects)要内联执行——运行
/domain-modeling技能(见 .agents/skills/domain-modeling/SKILL.md)保持领域模型同步,具体触发条件有四条:
- 给不在
CONTEXT.md里的概念命名了加深后的模块?把该术语加进CONTEXT.md;文件不存在就惰性创建。 - 对话中磨亮了模糊术语?当场更新
CONTEXT.md。 - 用户以承重理由拒绝了候选?主动提供 ADR,措辞为:"Want me to record this as an ADR so future architecture reviews don't re-suggest it?" 只有当这个理由对未来的探索者避免重复建议确实有用时才提供——跳过一次性理由("现在不值当")和自明理由。
- 想为加深模块探索备选接口?运行
/codebase-design技能,使用其 "design-it-twice" 并行子代理模式(详见 DESIGN-IT-TWICE.md)。
domain-modeling 的配套纪律
CONTEXT.md必须完全不含实现细节——它是纯术语表,不是 spec、草稿纸或实现决策仓库;- 创建文件要惰性:有东西可写才建;
- ADR 只在三条件同时成立时提供:难以逆转(事后改主意成本高)、没有上下文会令人惊讶(未来读者会问"为什么这么干")、真实权衡的结果(存在真实备选且因特定理由选定)。三者缺一即跳过。
与共享设计词汇的关系:四个核心概念
improve-codebase-architecture全程建立在一套共享词汇上(codebase-design/SKILL.md),理解它们才能用好本技能:
- Module——任何拥有接口与实现的东西,刻意跨尺度:一个函数、类、包,或横跨多层的切片。避免说 unit、component、service。
- Interface——调用方正确使用模块所需知道的一切:类型签名之外还有不变量、排序约束、错误模式、所需配置与性能特征。避免用 API、signature(它们只覆盖类型层表面)。
- Depth——接口上的杠杆:调用方(或测试)每学一个单位接口能行使的行为量。深模块= 大行为藏在小接口后;浅模块= 接口几乎和实现一样复杂。
- Seam(Michael Feathers 定义)——不修改某处即可在那里改变行为的位置;是模块接口所居的"位置"。接缝放哪本身就是独立设计决策。避免用 boundary(与 DDD 的有界上下文语义过载)。
- Adapter——在接缝处满足接口的具体事物,描述角色而非实质。
- Leverage / Locality——深度给调用方的回报是 leverage(每学一点接口获得更多能力,一次实现回报 N 个调用点与 M 个测试);给维护者的回报是 locality(变更、bug、知识、验证集中在一处,修一次处处生效)。
四条核心原则(来自 SKILL.md):
- 深度是接口的属性,不是实现的属性。深模块内部可以由小、可 mock、可替换的部件组成——只是它们不属于接口;模块可以同时有内部接缝(实现私有、供自身测试用)与外部接缝。
- 删除测试:想象删除该模块,复杂度消失 = 透传;复杂度在 N 个调用方身上重现 = 它在挣饭钱。
- 接口即测试面:调用方与测试跨同一条缝。想测试"越过接口",多半是模块形状不对。
- 一个适配器 = 假设性的缝,两个 = 真实的缝:除非确有东西在缝两边变化,否则别引入接缝。
深化时的依赖分类与测试策略
DEEPENING.md 给出了评估深化候选时必须做的依赖分类——分类决定加深后的模块如何跨缝测试:
| 类别 | 含义 | 深化策略 |
|---|---|---|
| In-process | 纯计算、内存态、无 I/O | 总是可深化——合并模块直接测新接口,无需适配器 |
| Local-substitutable | 有本地测试替身(如 PGLite 之于 Postgres、内存文件系统) | 若替身存在则可深化;测试套件里跑替身;接缝在内部,模块外部接口不开端口 |
| Remote but owned(Ports & Adapters) | 自己跨网络的服务(微服务、内部 API) | 在接缝处定义port(接口),深模块持有逻辑,传输层以adapter注入;测试用内存适配器,生产用 HTTP/gRPC/队列适配器 |
| True external(Mock) | 不受控的第三方服务(Stripe、Twilio 等) | 深模块把外部依赖作为注入的 port 接收,测试提供 mock 适配器 |
对应的推荐措辞模板(供报告中直接套用):
"Define a port at the seam, implement an HTTP adapter for production and an in-memory adapter for testing, so the logic sits in one deep module even though it's deployed across a network."
接缝纪律:单适配器 = 假设性接缝,双适配器 = 真实接缝;不要在至少两个适配器(通常生产 + 测试)有正当理由之前引入 port。内部接缝 vs 外部接缝:深模块可以有内部接缝(实现私有、供自身测试),但不要因为测试在用就把内部接缝暴露进接口。
测试策略:替换(replace),不要叠层(layer):
- 浅模块上的旧单测,在深模块接口上的测试存在之后就是浪费——删掉它们;
- 在深模块接口上写新测试,接口即测试面;
- 测试断言通过接口可观察的结果,而非内部状态;
- 测试应在内部重构后存活——它们描述行为而非实现。如果实现一变测试就得改,说明你在测"越过接口"的东西。
在本仓库中的实际应用场景
PentestGPT 是一个由 LLM 驱动的自动化渗透测试框架,当前仓库含多个子系统:维护中的自主 Supervisor/Executor 框架(pentestgpt_agent/)、维护中的传统 USEN-2024 风格客户端(pentestgpt_legacy/)、以及仅用于兼容的unified_agent/拷贝。improve-codebase-architecture技能在这样一个仓库里的典型用法是:
- 先读 pentestgpt_agent/CONTEXT.md 获取领域词汇——它定义了 Supervisor、Executor、Memory Kernel、Provider Adapter、Decision Cycle、Agent Episode、Task、Attempt、Evidence、Trace、Finding 等概念及不变量(例如"Every episode is fresh (resume = null)"、"A canonical observation is one exact contiguous slice from one eligible receipt")。审查建议必须用这些词说话,例如称 "the Memory Kernel" 而不是 "the SQLite service"。
- 走查
pentestgpt_agent/src/(agents.py、loop.py、memory.py、plan.py、execution.py、trial.py、trace.py、audit.py、identifiers.py)与unified_agent/(agent.py、task.py、tools.py、tool_server.py、backends/),观察哪些模块浅、哪里发生跨缝泄漏、哪些纯函数为可测性而抽离但真正的 bug 在调用侧。 - 对照 AGENT.md 的约束(例如 "Keep the core at two LLM roles. Do not add an always-on judge, RAG layer, or scheduler without trace evidence")判断候选是否触碰了承重决策——触碰了就应在报告中按 ADR 冲突规则标注。
- 生成报告、让用户挑选,再进入 grilling 循环,用
/domain-modeling内联维护CONTEXT.md与 ADR。
常见误区与最佳实践清单
- 不要提议接口:报告阶段只呈现候选(Files / Problem / Solution / Benefits / Before-After / 推荐强度),接口设计留在用户挑选之后的 grilling 循环里。
- 不要用浅层词:
component、service、API、boundary一律禁用,统一用 module / interface / seam / adapter。 - 不要虚张声势地给建议强度:只有把握充分才标
Strong;不确信用Worth exploring;探索性想法用Speculative。 - 不要无视 ADR:与既有 ADR 冲突的候选要显式警告,且只在摩擦真实到值得重开时才提出。
- 不要把报告写进仓库:HTML 必须落在 OS 临时目录,仓库保持干净。
- 不要批量提问:grilling 一次只问一个问题,且每个问题带推荐答案。
- 不要让图都长一个样:混合 Mermaid 与手绘 div/SVG,按关系形状选模式。
- 内联维护领域模型:新术语进
CONTEXT.md、承重理由进 ADR,边聊边记,不攒批。
结语
improve-codebase-architecture之所以值得研究,不在于它"自动重构",而在于它把一次架构审查变成了一条有纪律的流水线:用共享词汇保证沟通精确,用删除测试与深度原则保证判断可靠,用自包含 HTML 报告保证呈现直观,用 grilling + domain-modeling 保证决策落地并沉淀为CONTEXT.md与 ADR。这套机制对任何希望把代码库改造成"对测试友好、对 AI 可导航"的团队都有直接借鉴价值——而这正是 PentestGPT 仓库在 AGENT.md 中反复强调的演进方向(保持核心为两个 LLM 角色、确定性代码拥有状态、按 trace 证据决策)。在实践中,把它与 codebase-design、grilling、domain-modeling 三个姊妹技能配合使用,才能发挥完整威力。
【免费下载链接】PentestGPTAutomated Penetration Testing Agentic Framework Powered by Large Language Models项目地址: https://gitcode.com/GitHub_Trending/pe/PentestGPT
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考