
PentestGPT 架构解析双角色 LLM 决策循环、SQLite 规范记忆与证据约束执行【免费下载链接】PentestGPTAutomated Penetration Testing Agentic Framework Powered by Large Language Models项目地址: https://gitcode.com/GitHub_Trending/pe/PentestGPT本文以 PentestGPT 仓库内部的 docs/architecture.md 为骨架系统拆解其仅两个 LLM 角色的自主渗透测试循环Supervisor 负责选题、Executor 负责执行确定性代码掌管范围校验、租约、证据溯源与重试。读完本文你将理解 PentestGPT 如何用 SQLite 作为唯一规范状态、用 append-only trace 作为诊断证据、用外部UnifedAgentWrapper包屏蔽 Claude Code / Codex 两家 provider 差异并能对照pentestgpt_agent源码与 CLI 参数复现一次完整的 trial。1. 文档定位与仓库族结构docs/architecture.md 在开头声明自身是当前仓库形态的内部事实来源internal source of truth状态日期 2026-07-12并指出根目录README.md是面向公众的项目页面、正在被单独修订。理解这一分工很重要架构文档描述的是当前代码实际是什么而 README 描述的是用户能拿到什么。文档首先定义了 PentestGPT 项目的仓库族repository familyPentestGPT_Project/ ├── PentestGPT/ # 框架、legacy 交互客户端和工具镜像 ├── UnifedAgentWrapper/ # 规范化的 unified-agent 包 └── xbow-benchmark/ # 仅作参考的基准测试 harness 与历史结果这三个目录是相互独立的 Git 仓库。其中 XBOW 检出checkout仅作为参考语料保留——产品 CLI、运行时与 CI 都不依赖它基准逻辑与结果归档也不允许进入本仓库。这一点在后文的运行时与基准归属一节会再次强调并与根 README.md 中Benchmark history一节的历史性说明互相印证。1.1 被维护的运行时架构文档把当前仓库的运行时分成两半pentestgpt_agent/是自主框架是一个嵌套的 uv 项目拥有自己的 lockfile 和环境pentestgpt_legacy/是对 USENIX 2024 论文中人工驱动工作流的现代化维护版本它自带轻量 provider 客户端不使用unified_agent。从 pentestgpt_legacy/llm/registry.py 所在的 provider 目录结构providers/下含 Anthropic、Gemini、OpenAI 兼容连接器可以印证自带轻量 provider 客户端这一说法而根 README.md 中pentestgpt-legacy的多供应商模型表也正是这份 registry 的活渲染。2. 核心循环只有两个 LLM 角色架构文档对pentestgpt_agent循环的核心断言是循环刻意只保留两个 LLM 角色并用如下数据流图表达RunSnapshot - Supervisor - compile_plan - one TaskLease | TraceStore - EpisodeRunner - Executor ---- | | ---- compile_execution ------- | MemoryKernel各角色职责与配套约定均直接继承自 docs/architecture.mdSupervisor 选择一个任务或提议结束completionExecutor 执行一个已租约leased的任务并返回类型化结果两个角色都使用全新的 provider 会话与FULL_ACCESS沙箱策略。部署环境本身是隔离边界——PentestGPT 不再维护第二套工具或文件系统沙箱确定性代码掌管范围校验、租约、证据溯源、重试、修订revisions和规范状态SQLite 是规范记忆provider 会话转录只是诊断性 trace不是记忆没有常驻 judge、没有 RAG 服务、没有投机性任务积压、没有并行调度器。2.1 PentestLoop一次决策、一张租约循环的实现入口是 PentestLoop构造参数max_decisions: int 20、max_supervisor_attempts: int 2就是文档所说的确定性代码拥有重试与结算的具体化身。其run方法的主循环loop.py#L44-L81与架构图一一对应memory.open_run(spec)打开或创建 run若 run 已非RUNNING直接返回快照——这是恢复resume能力的地基若当前没有活动租约先检查决策计数达到max_decisions就提交decision_limit失败否则调用_supervisor_planSupervisor 的决策先经过compile_plan验证验证细节见第 3 节成功后memory.commit_plan(plan)返回至多一张TaskLease若没有租约例如 Supervisor 声明 finishrun 结束_drive_lease驱动这张租约Executor 执行后compile_execution把Executor 声称的结果 租约 trace编译成合法的ValidExecution再memory.commit_execution提交。一个关键设计在_supervisor_planloop.py#L83-L122Supervisor 每次决策都绑定确定性的 episode idsupervisor-r{revision}重试则追加-a{attempt}。如果该 episode 的 trace 已持久化循环直接回放已存结果而不是重新调用 provider并严格校验 trace 输入中的run_id、episode_id、role、state_revision与当前快照一致——这就是文档所说的episode identity 与失败结算藏在PentestLoop接口后面的含义。Executor 侧的_drive_lease与_settle_traceloop.py#L124-L258实现了文档中recovery ordering的落地trace 已存在且尾未截断 → 结算settle既有结果绝不重放trace 初始化中断 → 提交可重试retryableTrue的interrupted失败trace 损坏或截断 → 提交不可重试的trace_corrupt失败对max_structured_output_retries/max_turns类失败还会尝试从 trace 中recover_execution_deltas按候选结果依次过compile_execution验证。失败是否可重试由确定性规则决定loop.py#L247-L251failure_kind属于provider/validation/interrupted、trace 尾未截断、且该 episode 没有执行过任何动作回执action receipt即已产生副作用的命令时才可重试。这保证了不会在已对目标产生影响的 episode 上盲目重试。2.2 为什么两个角色拿 FULL_ACCESStrial.py 的_build_roles中Supervisor 与 Executor 各自的UnifiedAgent都传入SandboxPolicy.FULL_ACCESS且每个角色拥有独立的工作区子目录{workspace_root}/{run_id}/supervisor与.../executor。这与文档部署环境是隔离边界PentestGPT 不维护第二套沙箱的断言完全一致。同时Claude 后端还会注入CLAUDE_CODE_DISABLE_AUTO_MEMORY1等环境变量trial.py#L58-L65关闭 provider 侧的自带记忆避免provider 转录变成隐式记忆——这正是文档SQLite 是规范记忆原则的防御性实现。3. 计划语言与 compile_planSupervisor 提案必须过编译文档的Deep modules表把compile_plan的接口描述为decision snapshot - valid plan隐藏实现是scope、dependency、phase、completion 与 size 校验。实现位于 plan.py。3.1 任务类型六种 TaskKindplan.py#L12-L18 定义了计划语言的阶段phase词汇TaskKind语义边界见 Executor 指令约束默认 turn budgetdiscover映射攻击面禁用漏洞 payload5enumerate只扩展被点名的面6test最小基线/探测与对照不 exploit、不追 run goal5exploit只用有证据支撑的原语9verify只重复声称的证明4recover只处理被点名的失败6turn budget 数值来自 agents.py 的_EXECUTOR_TURN_BUDGETS。Executor 实际获得的任务轮数 min(executor_max_turns, 该类型预算 1) - 1预留 1 个传输轮用于返回结构化结果见 agents.py#L299-L303。3.2 Supervisor 的结构化决策 schemaSupervisor 只能返回严格匹配 SUPERVISOR_SCHEMA 的 JSONadditionalProperties: false字段约束base_revision整数必须对应当前规范状态修订号new_tasks零或一个当下所需的最小证据支撑任务schema 描述明确禁止投机性积压next_task_id字符串或 null选中要执行的任务finish布尔仅当规范证据满足 run goal 且无未完成任务时可为 truefinish_basis_ids非 finish 时必须为空finish 时引用 14 条直接确立目标的规范 observationsummary字符串其中每个新任务遵循_TASK_SCHEMAid、kind、target、objective、done_when、basis_ids、depends_on全部必填且无额外字段。解析侧parse_supervisor_decisionagents.py#L474-L512再做一次精确键集校验多一个字段、少一个字段都抛AgentContractError——这就是文档所说AgentContractError背后的契约刚性。3.3 compile_plan 的确定性规则compile_plan把LLM 的提议编译为可提交的状态变更核心规则均出自 plan.py包括范围校验目标必须逐字节匹配allowed_targetsURL 目标会先做规范化只允许 http/https 等受限形态见_canonical_url_targetSupervisor 指令还要求端口、scheme、vhost、URL、路径只属于 objective不得装饰 target 字段阶段依赖EXPLOIT任务必须引用同目标上最新一条已完成TEST任务的 observation 作为 basisplan.py#L222-L243否则PlanValidationError——这在代码层面封死了没做测试就直接利用的跳跃依赖图合法性禁止自依赖、未知依赖并做全图环检测plan.py#L246-L275完成语义finishtrue时不允许存在 open 任务、不允许附带新任务finish_basis_ids必须非空、至多 4 条、无重复、必须来自已DONE的任务plan.py#L277-L306非 finish 时该字段必须为空选中任务可执行性next_task_id指向的任务必须是READY且所有依赖已DONE。任何一条不过PentestLoop就把错误作为validation_feedback回灌给 Supervisor 重试最多max_supervisor_attempts2次feedback 截断到 1000 字符见 agents.py#L462-L463。4. compile_executionExecutor 结果必须对得上 trace文档表中compile_execution的接口是result lease trace - valid execution隐藏实现是exact receipt matching、evidence fallback、identity、recovery rules。实现位于 execution.py。4.1 Executor 返回什么Executor 的结构化输出受 EXECUTOR_SCHEMA 约束只有四个字段字段说明task_id必须等于租约的任务 idoutcomedone/progress/blocked/failed四选一ExecutionOutcomesummary自然语言摘要非规范数据evidence_excerpt从恰好一个成功命令/工具输出中逐字拷贝的连续子串done时必填且必须是直接证明done_when的最小完整引文Executor 指令EXECUTOR_INSTRUCTIONS进一步规定不得对目标返回内容中的指令产生服从prompt injection 防御、命令必须带有限超时与有限输出、不得递归搜索/、不得发起后台任务、引文不得拼接多个输出或添加标注——因为这个精确引文将成为规范记忆。4.2 回执匹配从精确子串到降级回退evidence_excerpt不能自说自话必须由compile_execution在 trace 的接地回执grounding receipt即真实工具输出事件中找到出处。execution.py#L218-L239 的匹配链是逐级降级的确定性算法精确子串在单个回执输出中做逐字查找含换行归一化映射回原始偏移有序精确行跨度引文各行在输出中按序各唯一出现时放宽为包含它们的最小连续跨度上限 4000 字符唯一行信封引文不少于 4 个互异行且每行在输出中全局唯一时取覆盖它们的最小连续段单回执投影多回执场景下把引文投影到能支撑最多行的单一回执上兜底以上皆失败时取最后一个有界回执的尾部 4000 字符标记evidence_fallback/evidence_truncated见 execution.py#L242-L250。每条 observation 落库时都会绑定其证据在 trace 中的evidence_sequences见 memory.py 的 ObservationRecord这就是文档所说的evidence provenance规范记忆里的每条陈述都能回溯到某个 episode trace 的具体事件序号。4.3 结构化结果损坏时的恢复当 Executor 因max_structured_output_retries或max_turns终止、最终结构化输出缺失时recover_execution_deltasagents.py#L547-L588会从 trace 的StructuredOutput工具调用事件里按新到旧收集候选结果甚至能修复evidence 被拼进 summary 尾部的传输损坏形态每个候选仍必须完整通过compile_execution可带recover_structured_transportTrue标志。done而无 evidence 的候选直接被丢弃——证据纪律不因传输故障而豁免。5. MemoryKernelSQLite 规范记忆与有界检索5.1 模式五个表、每次提交递增 revisionMemoryKernelmemory.py#L140-L232是文档Deep modules表中create/open/snapshot and atomic commits接口的实现隐藏实现是SQLite schema、transactions、revisions、leases、dependency liveness。它初始化时建五张表runsrun_id、goal、allowed_targetsJSON、status、revision、max_attempts_per_tasktransitions(run_id, revision)主键的不可变迁移日志run_created、plan_committed 等attempts每次任务尝试带started_revision/finished_revision、trace_episode_id、failure_kind/failure_messageobservations规范证据绑定 task、attempt、trace episode 与evidence_sequencestasks计划任务带 kind、target、objective、done_when、basis_ids、depends_on、status。RunSpec的入口校验memory.py#L126-L137给出了运行参数的硬边界goal 14000 字符allowed_targets至多 16 个、唯一、每项 12048 字符max_attempts_per_task110默认 2。open_runmemory.py#L260-L284在重开 run 时校验持久化的 goal/targets/重试上限与请求一致否则抛RunSpecMismatchError——run 的持久身份不可静默漂移。5.2 检索有界Supervisor 看到什么文档Memory and retrieval一节的原则是存储是完备的检索是有界的。实现上Supervisor 每轮收到的状态由_supervisor_prompt组装恰好对应文档列出的清单open working set全部BLOCKED/READY/ACTIVE任务 最近 4 个已关闭任务required basis/dependency contextopen 任务引用的 basis 生产任务与depends_on任务selected observations任务依赖的必需 observation 最近 6 条 observationhistory counts按状态/类型聚合的已关闭任务计数 最近索引recent diagnostics最近 4 条 failed/error/blocked/progress 尝试。Executor 侧agents.py#L304-L338只收到单个任务信封kind/target/objective/done_when、显式 basis含来源任务与证据原文、同任务最近 2 条 prior_task_evidence、以及一条非规范的 retry_diagnostic。这与文档Executor 收到一个任务、显式 basis、同任务证据与一条重试诊断的描述逐项吻合。文档同时给出诚实的弱点评估当前控制器的短板是收敛性而非数据库容量——长 run 可能丢失紧凑的覆盖面信息、重复访问已完成的面下一步设计应先改进确定性策略投影与重复/分支策略而不是再加一个 Agent 或 RAG。文档还预判未来若有 retriever它可以选择规范 ID但不得替代 SQLite也不得把摘要变成证据。6. 外部 UnifiedAgentWrapper 与根目录兼容副本6.1 为什么保留 unified-agent 依赖架构文档Why unified-agent remains useful一节的论证是外部UnifedAgentWrapper是一个真实的接缝带 Claude Code 与 Codex 两个生产适配器PentestGPT 依赖它的窄接口完成provider 选择/模型/effort/workspace/权限配置、结构化输出调用、命令/工具/文件/会话/用量/成本/终止事件的归一化、以及共享的任务渲染与 provider 错误处理。移除它等于把 provider SDK 的持续变动churn复制进pentestgpt_agent.trace与pentestgpt_agent.trial。边界规则同样明确PentestGPT 的策略必须留在仓库内——任务类型、记忆、证据、范围、调度、完成语义都归属本仓库。这条依赖被钉死在公开包的某个提交上。pentestgpt_agent/pyproject.toml 中[tool.uv.sources] unified-agent { git https://github.com/PentestGPT-Project/UnifedAgentWrapper.git, rev acff8eeadf93e367d4a1578d3a2739cbc9d3ace5 }且unified-agent0.3.0为主依赖claude/codex/all为可选 extraspyproject.toml#L10-L21。文档还提到 tests/test_dependency.py 验证嵌套项目导入的是已安装的外部依赖而不是仓库根目录副本——该测试test_dependency.py#L8-L21断言三件事导入路径不落在根目录unified_agent/内、direct_url.json显示来自 git 的 UnifedAgentWrapper 仓库、且包版本与unified_agent.__version__一致为 0.3.0。6.2 根目录 unified_agent 副本只减不增文档对根目录 unified_agent/ 的定性是更旧、已漂移的兼容副本没有任何被维护的 PentestGPT 运行时导入它pentestgpt_agent用外部包pentestgpt_legacy用自己的 provider 客户端只有根打包、其重复测试与当前工具镜像健康检查还在用它。文档明确要求不要在这份副本上开发功能且删除它是刻意的一次性公共包清理需同步更新根包元数据、Docker 健康测试、lockfile 与公共 README——这也解释了为何 unified_agent/backends/ 下仍有claude_code.py、codex.py两个适配器文件却处于冻结状态。7. 运行时、Docker 镜像与基准归属文档Runtime and benchmark ownership一节划定了四条边界其中每条都能在仓库中找到对应物本地框架开发从pentestgpt_agent/出发——它是一个独立 uv 项目自带 pyproject.toml 与uv.lock其dev依赖组包含 pytest、pytest-asyncio、ruff、mypystrict根 Docker 镜像提供渗透工具、provider CLI、legacy 代码与持久化认证但当前不内置被维护的框架——这与 Dockerfile、docker-compose.yml 及 docs/docker-dev-plan.md 描述的工具镜像 一次性登录持久化职责一致xbow-benchmark是历史/参考制品不是受支持的运行时或验证路径PentestGPT 不拥有任何 XBOW runnerHTB 执行只发生在父项目指南描述的授权远程攻击机上绝不直接从开发机发起。从仓库结构看这条归属划分有测试佐证pentestgpt_agent/tests/local/下的本地目标测试local_target.py与test_local_benchmark.py、test_local_model.py构成本地可验证面而 live 测试test_local_model.py所在的live/目录被 pyproject 的 pytest marker 明确标注为会调用真实模型后端并消耗 tokenpyproject.toml#L41-L45。8. CLI 入口一次 trial 的完整参数面pentestgpt_agent暴露两个入口pyproject.toml#L14-L16pentestgpt-agenttrialtrial.py 的main与pentestgpt-agent-auditaudit。trial 的命令行参数与合法范围trial.py#L320-L348取值范围校验见 trial.py#L116-L136参数默认值约束--goal必填14000 字符--target必填可重复至多 16 个唯一目标每个 12048 字符--backendclaude仅claude或codex--model无至多 256 字符--effort无claudelow/medium/high/xhigh/maxcodexlow/medium/high/xhigh/none/minimal--run-idtrial-uuid12不透明 id--runs-rootrunstrace 与状态库根目录--workspace-rootagent-workspaces两角色 provider 工作区根目录--max-decisions2011000--supervisor-max-turns41100--executor-max-turns122100--resume关恢复需先通过 trial 身份校验恢复resume不是简单重跑_trial_identitytrial.py#L286-L317把 goal、targets、backend、model、effort、各类轮次上限乃至Supervisor/Executor 指令与 schema 的 SHA-256 摘要、沙箱策略、provider 环境、unified_agent 版本全部写入trial-config.json--resume时先比对这份持久身份任何不一致都拒绝恢复。这意味着改 prompt 后继续旧 run在机制上被禁止——契约变更必须以新 run 进行。运行产物落在runs_root/{run_id}/state.sqlite3规范状态、traces/append-only 诊断、trial-config.json与summary.json。summary 聚合所有 episode 的 usageinput/cached_input/output/reasoning tokens、cost_usd、provider_duration_ms、任务/observation/attempt/transition 全量记录main以TRIAL_RESULTjson打印并在 status 为completed时返回 0trial.py#L238-L276、trial.py#L351-L359。9. Deep Modules 与当前设计优先级架构文档的Deep modules表是测试与演进的首选切面结合源码可完整读出六行模块接口隐藏实现PentestLooprun(RunSpec) - RunSnapshot恢复排序、重试、episode 身份、失败结算loop.pyMemoryKernelcreate/open/snapshot 与原子提交SQLite schema、事务、修订、租约、依赖活性memory.pycompile_plandecision snapshot - 合法 plan范围、依赖、阶段、完成与规模校验plan.pycompile_executionresult lease trace - 合法 execution精确回执匹配、证据回退、身份、恢复规则execution.pyEpisodeRunner一个类型化 episode - 归一化结果provider 调用与持久 append-only trace 文件trace.py外部UnifiedAgent一次经 Claude 或 Codex 的任务SDK 差异、原生选项、事件归一化外部 UnifedAgentWrapper 包文档据此给出两条归属规则新的 provider 行为应藏在UnifiedAgent之后新的规范状态行为应藏在 Memory Kernel 或两个 compiler 之后。pentestgpt_agent/tests/中的 test_loop.py、test_memory.py、test_plan.py、test_execution.py 等测试文件正是沿着这些接口组织的可作为上述首选测试面的实证。文档收尾的Current design priorities原文五条优先级也应完整保留它们是后续读代码的路线图保持双角色循环与确定性记忆权威利用已存 trace 回放测试改进 Supervisor 的覆盖检索与收敛性在受限部署环境中保持两个角色全能力启用在一次协调的公共包清理中移除根unified_agent兼容副本仅当非 CTF 完成语义需要时才增加目标特定 verifier。10. 小结这套架构的工程取舍把 docs/architecture.md 与pentestgpt_agent源码对照后PentestGPT 自主框架的核心取舍可以概括为三句话LLM 只做提议确定性代码只做裁决——Supervisor/Executor 的每个输出都必须经过compile_plan/compile_execution编译才能触碰规范状态且提示词契约本身instructions schema被哈希进 trial 身份状态与证据彻底分家——SQLite 五表是完备的规范记忆provider 转录只是可回放、可结算的诊断 trace证据必须能在 trace 回执中逐字定位边界外移、依赖内收——安全隔离交给部署环境双角色 FULL_ACCESSprovider 差异交给钉死 commit 的外部 unified-agent 包策略词汇六类 TaskKind、租约、收敛、完成语义留在本仓库内演进。适用前提需要说明本文分析对应 docs/architecture.md 标注的 2026-07-12 状态与pentestgpt-agent 0.1.0unified-agent0.3.0Python 3.12pentestgpt_legacy的交互模式、Docker 工具镜像与外部 UnifedAgentWrapper 包的行为以其各自仓库与文档为准不在本文展开。【免费下载链接】PentestGPTAutomated Penetration Testing Agentic Framework Powered by Large Language Models项目地址: https://gitcode.com/GitHub_Trending/pe/PentestGPT创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考