首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >技能自治闭环:多 Agent 协作下的自助“排查—修复—验证—发布”

技能自治闭环:多 Agent 协作下的自助“排查—修复—验证—发布”

原创
作者头像
OneCode
发布于 2026-10-20 10:38:06
发布于 2026-10-20 10:38:06
310
举报
文章被收录于专栏:ooderAgentooderAgent

深度技术方案 · Deep Dive

01引子:一个真实需求背后的流程命题

先从一个真实场景说起。业务用户在使用 finance(财资)模块时反馈:“资金日报中会存在流水重复,请排查。”在传统研发链路里,这句话要在「提单 → 排期 → 复现 → 读日志 → 读源码 → 改码 → 编译 → 测试 → 验收 → 发布」十个环节之间流转,每一环都是一次上下文切换,平均以“天”为单位计价。

而在本文描述的体系里,这句话进入的是另一条链路:用户在 chatnext 会话中对业务智能体说一句话,devAgent 随即接管研发侧全过程——先到沙箱读日志取证,再定位源码、生成补丁、编译打包,回到沙箱跑测试验证,最后把改动与证据一起交还给用户验收。全程无需人工搬运上下文,用户只在起点提需求、在终点做验收。

听起来很美,但让 LLM 自由发挥去做这件事,我们踩过一个很典型的坑。以真实历史会话(us1-drive-2026-10-16)的 SSE dump 复盘为例:智能体读了很多次日志、检索了很多次源码,却从未改码、从未编译、从未测试、从未请用户验收——会话在“看起来很忙”中自然结束。这不是模型能力问题,而是流程治理问题:缺少一个确定性的“裁判”,把“看起来做完了”和“真的做完了”区分开。

THESIS 01

LLM 出灵活性,状态机出确定性

阶段推进权在服务端(决策智能体),LLM 只负责选工具。推进、回环、终止由状态机裁决,而非模型自觉。

THESIS 02

事件即证据,门禁即门槛

每一步都产生 SSE 事件;门禁脚本消费 dump,把 11 项断言变成可机检的完成标准。

THESIS 03

验收权还给用户

human_confirm 是唯一终态入口。验收不过自动 REOPENED 回环,不通过就不算完成。

THESIS 04

devAgent 是护航层,不是替代者

业务智能体保持领域专注;研发自治由 devAgent 三体护航,形成业务与研发的 AI 自助协作。

本文以 finance 源码工程为标的物,完整拆解这条「用户自助修改—发布」闭环的设计与实现:三层智能体协作架构(§2)、需求受理与验收回环(§3)、八段闭环状态机(§4)、SSE 事件流与 chatnext 前端(§5)、门禁与证据链(§6)、安全护栏(§7)、沙箱入网与灰度回归的实战难点(§8),最后给出落地状态与演进路线(§9)。

02三层智能体协作架构:谁在护航谁

整套体系的核心命题是:让每个智能体只做它最擅长的事,并把它们放进一个互相制衡的协作拓扑里。架构上分为三层——业务智能体在领域里交付价值;devAgent 三体(对话、沙箱、代码)为研发过程护航;决策智能体作为确定性裁判凌驾于编排之上,决定流程走向。

图 1:三层智能体协作架构 —— 业务智能体被护航,devAgent 三体分工,决策智能体裁决

2.1 五类角色的职责边界

角色

形态

职责

关键落点

对话智能体(devAgent 主控)

LLM 编排

受理诉求、选择工具、生成说明与阶段报告;不做流程裁决

FunctionCallingLoopExecutor

决策智能体

确定性状态机(非对话、无 LLM)

判定阶段推进 / 回环 / 终止;向提示词注入阶段契约;执行权限与门禁

DevLoopService+ policy.v2 + dump 门禁

沙箱智能体

执行体(8081)

日志取证、源码检索、编译、测试、证据归档、验收回环 API

AgentDevController/api/test/agent/dev/**

代码智能体

code agent

源码理解、补丁生成、静态检查与编译

apply_patch/write_source/compile

业务智能体

领域 agent

交付业务能力(财资、专利、浏览器等),保持领域专注

ooder-biz-*各业务包

chatnext 前端

事件消费者

阶段可视化、工具卡渲染、验收卡片交互

PhaseDomain /Panels.js/events.contract.json

设计要点:决策智能体为什么“不是 LLM”

流程裁决必须是可复现、可审计的。同样的事件序列必须得到同样的阶段判定——这是 LLM 无法保证的。所以决策智能体被实现为纯服务端状态机:它消费工具事件,输出阶段事件;LLM 在它面前只有“选哪个工具”的自由,没有“我做到哪一步了”的解释权。

2.2 护航而非替代:业务智能体的位置

值得强调的是,devAgent 不侵入业务智能体的领域逻辑。finance 的账务口径、patent 的流程规则,仍由各自业务包承载;devAgent 三体只在研发过程维度上护航——业务智能体遇到“需要改代码才能解决的问题”时,问题被移交给 devAgent 闭环,产出物(补丁 + 测试 + 证据)再回流到沙箱业务包。业务专注业务,研发自治研发,两者以沙箱为交界、以验收为闭环。

03需求受理与验收回环:让“改什么、算修好”有账可查

闭环的起点不是“开始干活”,而是立案。沙箱侧以 AgentDevController 为唯一写入方,维护 .agent-dev/requests/ 目录下的需求台账,形成一个小而完整的状态机:

图 2:需求受理状态机 —— OPEN → CLAIMED → CLOSED / REOPENED,reopenCount 记录返工次数

四组工具把这套台账暴露给智能体侧:

工具

作用

权限

dev_request_create

立案:rawText / expectedBehavior 至少一项,生成带 ID 的需求单

WRITE

dev_request_list

按状态过滤查询(≤200 条)

READ

dev_request_claim

领单:OPEN / REOPENED → CLAIMED

WRITE

dev_request_verify

验收回写:通过则 CLOSED,不通过则 REOPENED,并记录 verifications 历史与 lastEvidenceId

WRITE

这个设计解决了两个此前含糊的问题。其一,“改什么”有契约了:立案时必须写明现象(rawText)与预期行为(expectedBehavior),后续每个阶段的事件都可以回指需求单。其二,“算修好”有凭据了:verify 必须携带证据 ID(lastEvidenceId)与通过与否的结论,验收不通过的需求单会带着 reopenCount 历史回到 CLAIMED,返工成本被显性化。

工程细节:唯一写入方与原子落盘

需求台账由 AgentDevController 独占写入,采用「临时文件 + 原子 move」落盘,读取侧对 UTF-8 BOM 做容错——避免沙箱高频读写下的半截 JSON。ID 白名单校验([A-Za-z0-9_-]{1,64})在入口处挡住路径穿越。

04八段闭环状态机:把推进权从 LLM 手里收回来

整个闭环的骨架是一条 8 + 1 的阶段流水线。服务端 DevLoopService(决策智能体的主体)为每个会话维护阶段状态,按工具事件前向推进,按工具结果回环:

图 3:八段闭环状态机 —— 实线前向推进,虚线为失败回环;DONE 仅可由用户验收通过到达

4.1 阶段、工具与失败去向

阶段

名称

推进工具

失败去向

INTAKE

需求受理

dev_request_create

—

ENV_CHECK

环境预检

dev_env_check(policy.v2 清单校验)

—

COLLECT_LOGS

日志取证

sandbox_read_logs/sandbox_trace

—

LOCATE

源码定位

sandbox_search_code/read_source

验证失败 / 验收驳回时回到这里

PATCH

修改源码

apply_patch/write_source

编译失败时回到这里

BUILD

编译打包

compile(agent-host 沙箱包)

→ PATCH

VERIFY

测试验证

run_tests/agent_execute

→ LOCATE

ACCEPT

用户验收

human_confirm(devConfirmType=DEV_ACCEPT)

不通过 → REOPENED 回 LOCATE

DONE

完成

仅 ACCEPT 通过后到达

—

4.2 推进权在服务端:两处关键代码

工具开始时,状态机只前向推进;工具结束时,按结果裁决回环:

代码语言:javascript
复制
// 工具 → 阶段映射:服务端判定,LLM 只选工具(DevLoopService)
sandbox_read_logs / sandbox_trace         → COLLECT_LOGS   // 先取证,后定位
sandbox_search_code / read_source         → LOCATE
apply_patch / write_source                → PATCH
compile                                   → BUILD
run_tests / agent_execute                 → VERIFY
human_confirm(devConfirmType=DEV_ACCEPT)  → ACCEPT         // 唯一终态入口
代码语言:javascript
复制
// FunctionCallingLoopExecutor:工具结果 → 回环裁决
Transition t = devLoopService.onToolResult(convId, toolName, status, args, output);
if (t.changed) pushDevPhaseEvent(convId, t);
// BUILD 失败 → 回 PATCH;VERIFY 失败 → 回 LOCATE;
// 验收不通过 → REOPENED 并回 LOCATE;同一回环最多 3 次,超限转人工

4.3 阶段契约注入:让 LLM“知道自己在哪”

状态机不只是裁判,还是提示词的供给方。PromptEngine 在组装提示词时优先注入 buildPromptBlock 生成的阶段上下文(当前阶段 / 第几次尝试 / 已有证据 / 阶段契约与可用工具 / 硬规则),注入成功则跳过常规沙箱上下文:

代码语言:javascript
复制
// PromptEngine:dev 闭环上下文优先,常规沙箱上下文兜底
boolean devLoopInjected = false;
if (devLoopService != null && context != null) {
    String devBlock = devLoopService.buildPromptBlock(context);
    if (devBlock != null && !devBlock.isEmpty()) {
        prompt = prompt + "\n\n" + devBlock;
        devLoopInjected = true;
    }
}
if (!devLoopInjected && sandboxContextProvider != null) { /* 常规沙箱上下文 */ }

注入有两条边界保护:入口画像(EntryProfiles.DEV_AGENT)判定当前是否 dev 会话;意图过滤(isDevTaskRequest)识别“排查 / 修复 / 报错 / 编译 / bug / fix”类研发诉求。纯设计类会话与 finance 等业务入口完全不受影响——这是“护航不侵扰”在实现层的落点,并有单测(financeEntryIsNotAffected)钉死。

同时,沙箱侧流程定义(sandbox-devops/definition.json v2)与状态机保持同构:七个 dev_* 阶段 + BACKWARD 回环迁移(buildOk==false → dev_patch、verifyOk==false → dev_locate、accepted==false → dev_locate),并有契约测试校验“代码里的工具”与“流程定义里的活动”一一对应。

05运行时:SSE 事件流与 chatnext 前端

闭环的每一步都被翻译成 SSE 事件。两类事件构成观察面:阶段事件(phase_*)讲“流程走到哪”,工具事件(flow_tool_*)讲“正在做什么”。chatnext 前端的 PhaseDomain 与工具卡各自消费,用户看到的不再是黑盒转圈,而是一张可以回放的流程地图。

图 4:一次闭环的运行时时序 —— 阶段事件由状态机发出,工具事件由执行侧发出

5.1 事件契约的扩展点

工具事件在原有字段之上新增了 dev 维度字段(events.contract.json 同步登记),前端无需解析事件正文即可渲染阶段语义:

字段

含义

消费方

devStage

阶段枚举(如PATCH)

前端阶段分组与统计

devStageLabel

中文标签(如“修改源码”)

工具卡卡头

devAttempt/devMaxAttempts

第几次尝试 / 回环上限

回环可视化(“第 2 次”)

devLoopId

本次闭环标识

关联 phase_* 与 flow_tool_* 事件

代码语言:javascript
复制
// 工具事件示例(flow_tool_call)
{ "event": "flow_tool_call",
  "data": {
    "toolName": "apply_patch", "displayName": "修改源码", "status": "running",
    "devStage": "PATCH", "devStageLabel": "修改源码",
    "devAttempt": 1, "devMaxAttempts": 3, "devLoopId": "loop-20261020-0930"
  } }

// 阶段事件示例(phase_advanced)
{ "event": "phase_advanced",
  "data": {
    "phaseId": "dev_verify", "fromPhaseId": "dev_build", "toPhaseId": "dev_verify",
    "displayName": "测试验证", "classification": "DEV_LOOP", "order": 6, "attempt": 1
  } }

阶段事件共四种:phase_started / phase_advanced / phase_rolled_back(回环)/ phase_closed(终态)。前端 Panels.js 在工具卡卡头拼接阶段标签——[日志取证] 读取 3 份系统日志、[修改源码·第2次] 生成补丁 patch-0007.diff——回环次数直接可见,返工不再被藏进黑盒。

为什么选择“双轨事件”而非单一事件流

工具事件由执行侧产生,粒度细但语义散;阶段事件由状态机产生,语义强但粒度粗。两者以 devLoopId 关联后,dump 既能还原“做了什么”,也能还原“做到哪一步”——这正是 §6 门禁能够机检的前提。

06门禁与证据链:不让“看起来做完了”蒙混过关

有了双轨事件流,就可以对整场会话做事后机检。sse-devloop-gate.ps1 消费 SSE dump,执行 11 项断言,退出码 0 = PASS / 1 = FAIL,可直接挂进 CI 或 Trae hook:

#

检查项

断言

1

有工具调用

会话内至少出现一次flow_tool_call

2

阶段齐全

由devStage/phaseId/toPhaseId三来源统计,覆盖全部研发阶段

3

先读日志

COLLECT_LOGS事件早于改码事件(先取证后动手)

4

有改码

apply_patch/write_source≥ 1

5

有编译

compile≥ 1

6

有验证

run_tests/agent_execute≥ 1

7

有证据产物

flow_artifact> 0

8

有用户验收

human_confirm(DEV_ACCEPT)> 0

9

验收后完成

completeAt > confirmAt(先验收、后收尾)

10

无孤儿 running

无未闭合的 running 事件

11

摘要可读

无“已完成一步操作”式通用字幕

6.1 用真实 dump 验证门禁:它确实抓得住差距

门禁的价值要用反面样本来验证。把前文提到的真实历史会话 dump 喂给门禁脚本,结果绝大多数检查项不通过——日志读了很多次,但改码、编译、测试、验收四项关键断言全部为零:

图 5:历史会话 vs 闭环目标的关键工具调用形态(示意,基于真实 dump us1-drive-2026-10-16 复盘;单位:次)

而按 §4 的阶段契约构造正确事件序列后,同一脚本输出 PASS。门禁不是摆设:它把“闭环”从一句口号变成了 11 条可机检的断言。第 11 项“摘要可读”尤其值得一提——它针对的是另一类隐性失败:每一步都有事件、但最终字幕是一句放之四海皆准的“已完成一步操作”,用户依然不知道发生了什么。

6.2 证据链:flow_artifact 与需求单的互相引用

证据产物(diff、构建日志、测试报告)以 flow_artifact 事件落档,并回写需求单的 lastEvidenceId。验收卡片展示的不只是“是否通过”,而是证据引用链:需求单 → 补丁 → 构建 → 测试 → 验收结论,逐环可点开复查。

07安全护栏:分级权限与写路径收口

把改码、编译、发布交给智能体,权限设计必须先行。沙箱调试面 /api/test/agent/dev/** 按 policy.v2 四清单组织,每个工具登记三级风险之一,并由策略上限(policyLevel ceiling)取交集约束:

风险级

含义

典型工具

READ

只读探查,随时放行

sandbox_read_logs/sandbox_search_code/read_source/dev_request_list

WRITE

改变沙箱状态,需 write 级策略

apply_patch/compile/run_tests/dev_request_create/dev_request_claim/dev_request_verify

DANGER

影响面外溢(发布 / 外呼),full 级且人工在场

发布类操作

三条收口原则:

其一,写路径唯一化。需求台账只有 AgentDevController 一个写入方,阶段事件只有状态机一个发出方——任何绕过状态机的“自我宣告完成”都会在第 9 项门禁(验收后完成)上现形。

其二,上限取交集。会话策略(read-only / write / full)与工具风险级取交集,read-only 会话里即使 LLM 幻觉出 apply_patch,也会被沙箱侧拒绝而非静默执行。

其三,验收面留给人。终态只有一个入口——human_confirm。决策智能体可以把流程推进到 ACCEPT,但永远不能代替用户按下“通过”。

08实战难点与解法:沙箱入网与灰度回归

前七章搭建的是闭环的“骨架”;把骨架放进真实生产环境时,有两块最硬的骨头。它们指向同一个母题:沙箱必须既隔离、又与生产“同网共生”——孤立测试不可信,直接替换生产不可控。

8.1 难点一:沙箱如何“并行浮现”进生产 agent 网络

agent 化之后的生产环境不是单体应用,而是一张agent 网络:业务智能体、平台服务、B 端接入层、调试面彼此发现与调用。沙箱要验证的不是“补丁能不能编译”,而是补丁在真实拓扑里的行为——路由、鉴权、依赖、并发,缺一样,验证结论就是“测了个寂寞”。三个冲突点:

冲突点

矛盾

后果(若无解法)

可达性

沙箱要被生产侧的 agent 发现与调用,反之沙箱也要能触达生产依赖

沙箱成了“孤岛”,只能验证代码逻辑,验证不了集成行为

隔离性

沙箱的写操作、脏数据、未验证补丁不能外溢到生产

测试流量污染生产数据,故障面从沙箱扩大到全网

真实性

网络拓扑、域名、鉴权链路必须与生产一致

旁路环境测通 ≠ 生产可用,灰度前心里没底

解法回到 A / B / C 三方案里做取舍:

方案

思路

评价

A · 整包镜像替换

沙箱与生产对齐同基线,整包替换某一实例

弃重、慢、风险高;替换期间该实例容量受损,回滚只能靠整包

B · B端 domain 路由 + 细颗粒切流

沙箱以「灰度域身份」(如finance#gray)向 B 端路由注册:domain 一级分流,再按用户 / 会话 / 功能开关做微小颗粒细分

选 B沙箱成为生产 agent 网络的“一等公民”——并行浮现、白名单隔离、秒级上下线

C · 旁路直连

沙箱独立端点,测试工具直连

弃隔离最彻底,但永远“浮不出”生产网络,验证不到路由与集成

图 6:B 端 domain 路由 —— 沙箱灰度域并行浮现,细颗粒切流回用户,验收通过即切全量

8.2 难点二:修改完成后,如何灰度发布返回用户测试

八段闭环的 ACCEPT 阶段原本只是一张“验收卡片”;但真实发布要求用户在真实流量下测试。解法是把 ACCEPT 与 B 端灰度路由焊在一起——验收阶段即灰度阶段:

devAgent 闭环动作

B 端路由动作

用户侧所见

VERIFY通过 +dev_request_verify(passed=true)

注册灰度路由finance#gray(含细颗粒白名单)

—

ACCEPT= 灰度实测

提需人 / 白名单会话被路由到灰度实例

用户在真实入口使用“带补丁的服务”

human_confirm(passed=true)

灰度域切全量(发布)

全量用户无感升级;需求单置 CLOSED

验收驳回

注销灰度路由(秒级回滚)

需求单 REOPENED,闭环回LOCATE

这一步为什么关键

用户验收的不再是截图与口述,而是带补丁的真实服务;切流颗粒度到会话级;回滚等价于“注销一条路由”。发布的最小单元从“整包”降到了“灰度域”,风险面随之从全网收缩到白名单。

8.3 有机结合:研发链路长在架构的接缝上

回头看,B 端 domain 路由与细颗粒切分本质上是架构预先留出的接缝,而 devAgent 八段闭环恰好按这条接缝生长:证据链挂在需求单(§3)、阶段推进挂在状态机(§4)、灰度挂在路由表(本节)、验收挂 human_confirm。研发链路与架构不是两套体系,而是同一张拓扑上的两种视角。这也是沙箱基线必须对齐生产(JDK25 / jakarta 升级,见 §9)的根本原因——灰度实例要成为生产网络的公民,字节码与依赖基线必须一致。

09落地状态与演进路线

9.1 已落地(P0)

模块

交付物

验证方式

决策智能体

DevLoopService状态机 + 阶段契约注入(PromptEngine)

单测:happyPath / buildFailure / verifyFailure / acceptanceRejected / financeEntryIsNotAffected 等

事件面

SSEphase_*事件 + 工具事件 dev 字段(events.contract.json)

契约测试 + dump 回放

验收回环

requests台账 API +dev_request_*四工具 +human_confirm(DEV_ACCEPT)

requestLifecycle状态机单测

前端

chatnext 工具卡阶段标签 + dev-agent 入口卡片

契约对齐(payloadKeys 登记)

门禁

sse-devloop-gate.ps111 项断言

真实历史 dump 复盘(暴露差距)+ 构造序列(PASS)

回归状态:代码侧测试全绿(ooder-pro 15 + ooder-test 5)。沙箱 8081 的 JDK25 基线升级(A 路线)正在收尾——新沙箱包已完整构建,仅余 A2UI 模板仓库的 JPA 装配适配;部署完成前,线上 8081 仍以旧基线健康运行,新调试面暂未对外(404)。

9.2 演进路线(P1 / P2)

P1:四类 flow_artifact(日志摘录 / diff / 构建 / 测试)由执行侧自动生产;全部写路径统一收口到 policy.v2;线上日志只读适配器(不依赖沙箱部署即可取证);B 端灰度路由落地——沙箱灰度域注册 / 细颗粒切流 / 切全量发布 API(§8 方案 B 的工程化)。

P2:harness 渲染统一(多前端同一套阶段组件);断线重连后按 devLoopId 补发阶段快照;门禁从“事后审计”前移为“事中拦截”(关键断言不满足时阻止进入下一阶段)。

9.3 结语:从护航走向自治

回头看 §1 的那个问题——“资金日报流水重复”——在这套体系里,它的完整旅程是:一句话立案 → 状态机护航下的取证 / 定位 / 改码 / 编译 / 验证 → 证据链交付 → 用户一键验收。决策智能体确保每个阶段真实发生,devAgent 三体确保每个动作有人执行,业务智能体确保领域逻辑不被惊扰。

更长远看,这套“状态机 + 事件 + 门禁”的护栏设计,同样适用于其他需要自治的智能体场景:凡是让 LLM 自主行动的地方,都需要一个不带 LLM 的裁判。当护栏足够可靠,护航就可以逐步放手——这才是“AI 自助协作”从演示走向生产的路径。

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

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

目录
  • 01引子:一个真实需求背后的流程命题
  • 02三层智能体协作架构:谁在护航谁
  • 2.1 五类角色的职责边界
  • 2.2 护航而非替代:业务智能体的位置
  • 03需求受理与验收回环:让“改什么、算修好”有账可查
  • 04八段闭环状态机:把推进权从 LLM 手里收回来
  • 4.1 阶段、工具与失败去向
  • 4.2 推进权在服务端:两处关键代码
  • 4.3 阶段契约注入:让 LLM“知道自己在哪”
  • 05运行时:SSE 事件流与 chatnext 前端
  • 5.1 事件契约的扩展点
  • 06门禁与证据链:不让“看起来做完了”蒙混过关
  • 6.1 用真实 dump 验证门禁:它确实抓得住差距
  • 6.2 证据链:flow_artifact 与需求单的互相引用
  • 07安全护栏:分级权限与写路径收口
  • 08实战难点与解法:沙箱入网与灰度回归
  • 8.1 难点一:沙箱如何“并行浮现”进生产 agent 网络
  • 8.2 难点二:修改完成后,如何灰度发布返回用户测试
  • 8.3 有机结合:研发链路长在架构的接缝上
  • 09落地状态与演进路线
  • 9.1 已落地(P0)
  • 9.2 演进路线(P1 / P2)
  • 9.3 结语:从护航走向自治
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档