From 5327f88ebc651ce730a9d139f5d303e8ec1a8f25 Mon Sep 17 00:00:00 2001 From: Autumn-27 <53844290+Autumn-27@users.noreply.github.com> Date: Wed, 9 Sep 2026 13:59:47 -0400 Subject: [PATCH] =?UTF-8?q?refactor(worker):=20=E6=94=B6=E6=95=9B=20work?= =?UTF-8?q?=20agent=20=E9=BB=98=E8=AE=A4=E5=B7=A5=E5=85=B7=E9=9B=86?= =?UTF-8?q?=E4=B8=8E=E8=B5=84=E4=BA=A7=E5=86=99=E5=9B=9E=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit work agent 只负责单条意图的执行与写回,读上下文/跨 work 复盘属规划职责: - 从 WorkerTools() 移除 list_facts / node_detail / list_companies 及跨 work 检索 (search_all_worker_traces / list_worker_traces / get_worker_trace),只留 list_findings(报漏洞前查重) + add_finding/record_fact + insert_assets/list_assets。 - 旧库迁移 seedWorkerReadToolsUnbind(flag worker_readtools_unbind_v1):逐个 RemoveAgentFromTool 把上述工具从 worker 默认绑定剥离,planner/main 同名绑定不动。 - worker 提示词「查上下文」段收敛为 list_assets/list_findings;insert_assets 段删掉 与工具 schema 冲突的陈旧字段(type=tech/on_url/props/props.http),字段填法交回工具 自身说明,只留路由与边界。reseedWorkerPrompt 版本 bump v3→v4 下发旧库。 --- agent/tools_insert.go | 10 ++++++---- agent/worker.go | 4 +--- server/orchestration.go | 29 +++++++++++++++++++++++++++-- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/agent/tools_insert.go b/agent/tools_insert.go index 4396921..c66c882 100644 --- a/agent/tools_insert.go +++ b/agent/tools_insert.go @@ -610,13 +610,15 @@ func splitLines(s string) []string { // WorkerTools returns the tool set for a work agent. func (t *ToolSet) WorkerTools() []actool.CoreTool { return []actool.CoreTool{ - t.listFindings(), t.listFacts(), t.nodeDetail(), + // list_findings 保留:报漏洞前先查本任务已确认漏洞,避免重复上报同一漏洞。 + t.listFindings(), t.addFinding(), t.recordFact(), - // cross-work retrieval - t.searchAllWorkerTraces(), t.listWorkerTraces(), t.getWorkerTrace(), // asset management (handlers guard nil store internally)。 // add_company_scope 不给 worker:定义企业资产范围属规划/主控/Auto 的职责,worker 只执行探索。 - t.insertAssets(), t.listAssets(), t.listCompanies(), + t.insertAssets(), t.listAssets(), + // 以下工具【不给】worker,只留给 planner/main(读上下文、跨 work 复盘是规划职责, + // worker 只做单条意图的执行与写回):list_facts / node_detail / list_companies / + // 跨 work 检索 search_all_worker_traces / list_worker_traces / get_worker_trace。 } } diff --git a/agent/worker.go b/agent/worker.go index 5822cd7..1151f47 100644 --- a/agent/worker.go +++ b/agent/worker.go @@ -202,12 +202,10 @@ const workerDefaultTmpl = `你是一个 ARTEX 平台授权渗透测试系统的" 3. 只在授权范围内操作。系统提示顶部若附【操作约束】,那是最高优先级红线:每条命令/探测执行前先自检,违反即不做(哪怕它落在你领到的意图里)。 **边发现边写回**(写进图才算数,脑子/文字里的不算;每得一个结果立刻写,别攒到最后被步数耗尽丢掉)。三种写回,别串图: -- **新资产/资源 → insert_assets(资产图)**:endpoint / parameter / tech 指纹 / service / 凭据 / 子域 等。你只传原始信息,key 与父子关联由代码算:新接口传完整 url+method(代码自动建 domain→site→endpoint、抽 URL query 参数,body/header 参数放 params);指纹传 type=tech,name=技术名,on_url=站点地址,props={version,category}。结构化属性写在资产自己的 props 上(状态码/标题/body 长/content_type 放 props.http),探索结论不写这里。多资产用 assets 数组一次批量登记。 +- **新资产/资源 → insert_assets(资产图)**:子域 / service / endpoint / 指纹 / 凭据 等一切资产【本身】。**这里只登记资产;探索结论/判断不写这里,用 record_fact。** - **探索结论/事实 → record_fact(探索图,传 intent_id)**:都用它。**多个观察汇总成【一条】事实**(summary 一句总结 + detail写对总结的拓展,依靠真实的执行过程),不要一个属性一条、一意图通常只一条,拆碎会让图谱无限膨胀——**默认就写一条,能并进 detail 的都并进去**;仅当确有【彼此完全独立、无法归并】的结论时才用 facts 数组分条,这是极少数例外,不是常规。**只写增量**:只记这次【新得到】的,别把已有事实换措辞重记(只印证已有、无新增就不必记)。**只写真实看到的**:给 evidence(一行:命令+最能证明的一两行输出,简洁,细节在 detail)、标 confidence(observed=直接看到 / inferred=据现象推断)。 - **确认漏洞 → report_finding(探索图,含 PoC,传 intent_id)**:**只有你本次真实触发过、拿到可复现证据(请求/响应或命令输出)才用**。严禁把"版本/指纹匹配到 CVE""参数看起来可注入""外部漏洞库/更新日志/代码 diff 推断"当已确认,也不要用查 CVE 库或对比补丁版本替代实际触发。触发不了但有嫌疑 → 用 record_fact 记一条 inferred 事实(嫌疑点+为何未触发)交规划者,别硬记成 finding。 -**查上下文(按需)**:list_assets / asset_neighbors / list_facts(探索事实,分页最新在前,默认 20,可 q 过滤、before 翻页)/ list_findings / node_detail(探索节点 id,非资产 id)。 - 完成本意图后用一句话总结你做了什么、写回了哪些事实。务实、克制、聚焦这一条意图。` // workerTrafficBlock is 段 [B]: the traffic-tool note, code-injected only when diff --git a/server/orchestration.go b/server/orchestration.go index c1addf0..56ead66 100644 --- a/server/orchestration.go +++ b/server/orchestration.go @@ -450,6 +450,7 @@ func (s *Server) seedOrchestrationTools() { s.seedPlannerDefaultBindings() s.seedPlannerListAssetsBinding() s.seedCompanyScopeRebind() + s.seedWorkerReadToolsUnbind() // list_facts/node_detail/list_companies/跨 work 检索从 worker 默认解绑(一次性) s.seedAutoReportFindingBinding() s.unbindGoalMetDefault() s.reseedGoalsPrompt() // goals 提示词加入「抽操作约束」步 → 旧库追加一版新默认(一次性) @@ -614,7 +615,7 @@ func (s *Server) reseedPlannerPrompt() { // SeedPromptIfEmpty 首插入only,旧库已有版本收不到,故用版本管理【追加一个新版本】并切过去,旧版本仍保留在历史里可找回。 // settings flag 守卫 → 只做一次。全新库无需处理。与 reseedGoalsPrompt 完全同构。 func (s *Server) reseedWorkerPrompt() { - const flag = "worker_prompt_compact_v3" + const flag = "worker_prompt_compact_v4" if v, _, _ := s.m.pg.GetSetting(flag); v == "true" { return } @@ -635,7 +636,7 @@ func (s *Server) reseedWorkerPrompt() { log.Printf("[prompts] worker 提示词重刷为新默认失败: %v", err) return } - log.Printf("[prompts] worker 提示词已追加新默认版本(record_fact 删否定结论段+confidence 与穷尽解耦+facts 分条收紧,一次性)") + log.Printf("[prompts] worker 提示词已追加新默认版本(查上下文段收敛为 list_assets/list_findings,去掉 list_facts/node_detail/asset_neighbors,一次性)") } // seedReporterAgent 预置一个「报告撰写」自定义 agent(builtin=false,可在 UI 编辑/删除): @@ -760,6 +761,30 @@ func (s *Server) seedCompanyScopeRebind() { _ = s.m.pg.SetSetting(flag, "true") } +// seedWorkerReadToolsUnbind strips the read-context / cross-work tools off worker's +// default binding ONCE on existing DBs (guarded by a settings flag): a worker executes +// one intent and writes back — reading facts/nodes/companies and pulling other workers' +// traces is a planning/main concern, not the executor's. Fresh DBs already lack these via +// WorkerTools(); this only backfills old rows without overriding a user who deliberately +// re-binds worker. Each RemoveAgentFromTool is per-tool + membership-guarded, so +// planner/mainagent bindings of the same tool are untouched. +func (s *Server) seedWorkerReadToolsUnbind() { + const flag = "worker_readtools_unbind_v1" + if v, _, _ := s.m.pg.GetSetting(flag); v == "true" { + return + } + for _, k := range []string{ + "list_facts", "node_detail", "list_companies", + "search_all_worker_traces", "list_worker_traces", "get_worker_trace", + } { + if err := s.m.pg.RemoveAgentFromTool("worker", k); err != nil { + log.Printf("[worker] %s 从 worker 解绑失败: %v", k, err) + return // 出错则不落 flag,下次启动重试 + } + } + _ = s.m.pg.SetSetting(flag, "true") +} + // seedAutoDefaultBindings adds "auto" to the task-op + platform tools' bindings // ONCE (guarded by a settings flag), so existing DBs whose tool rows were seeded // before Auto existed still give Auto its default toolset — without re-adding it