【AgentScope Java新手村系列】(14)人机交互

简介: 人机交互 — Permission 系统五种模式配合 ALLOW/DENY/ASK 规则,运行时 HITL 自动拦截与决策收集。

第十四章 人机交互:Permission 系统 ALLOW/DENY/ASK 规则,运行时 HITL 自动拦截

"用户让 agent 删数据库——我们不希望它'问都不问就执行'。1.x 时代用 Hook.stopAgent()onActing 阶段抛异常中断;2.0 推荐用 Permission 系统——为每个 tool 配 ALLOW / DENY / ASK 规则,运行时自动拦截、提示用户、收集决策。这比 hook 优雅得多。"

本章你将学到:PermissionMode 5 种模式、PermissionRule 4 个字段、ASK 模式下如何给前端推送确认请求、以及 Middleware 在 HITL 中的辅助角色。

14.1 1.x 时代怎么拦截工具?

1.x 时代要在工具调用前拦下来,业务方在 Hook.onActingthrow new StopAgentException()。问题:

  • 异常语义不直观
  • 不能区分"想确认" vs "直接拒绝"
  • 没法让前端弹"是否放行"对话框,只能字符串错误

2.0 用 Permission 系统替代了这套写法:

决策 含义
ALLOW 直接执行
DENY 直接拒绝 + 错误反馈给 LLM
ASK 暂停工具执行,推送确认请求给用户;用户回 ALLOW/DENY 后继续
PASSTHROUGH 跳过本条规则,看下一条

14.2 第一个 Permission 例子

这个例子在演示什么?

你有一个 DB 管理员 agent,它有 drop_table 这种危险工具。你不希望它"问都不问就删表"——所以给 drop_table 配了一条 ASK 规则:agent 想删表时,Permission 引擎会暂停执行,把确认请求推给前端,等用户点了"允许"才继续。

import io.agentscope.core.agent.RuntimeContext;
import io.agentscope.core.message.UserMessage;
import io.agentscope.core.model.DashScopeChatModel;
import io.agentscope.core.permission.*;
import io.agentscope.harness.HarnessAgent;

import java.util.List;

public class Chapter14_Permission {
   

    public static void main(String[] args) {
   
        // 1. 准备 PermissionContext:ACCEPT_EDITS 模式,大部分操作放行
        //    但 drop_table 必须人工确认(ASK)
        PermissionContextState perms = PermissionContextState.builder()
                .mode(PermissionMode.ACCEPT_EDITS)
                .addAskRule("drop_table",
                        new PermissionRule(
                                "drop_table",
                                null,              // null = 匹配所有 drop_table 调用
                                PermissionBehavior.ASK,
                                "userSettings"))
                .build();

        // 2. 构造 agent
        HarnessAgent agent = HarnessAgent.builder()
                .name("db_admin")
                .sysPrompt("你是一个 DB 管理员;可以查表,但删表必须先问。")
                .model(DashScopeChatModel.builder()
                        .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                        .modelName("qwen-plus")
                        .build())
                .workspace(Path.of("./workspace"))
                .permissionContext(perms)
                .build();

        agent.call(
                List.of(new UserMessage("user", "把 orders_2024 表 drop 掉。")),
                RuntimeContext.empty())
                .block();
        // 跑到 drop_table 时,Permission 会发出 ConfirmRequest,前端需要回应
    }
}

PermissionRule 四个字段:

  • toolName — 工具名
  • ruleContent — 匹配模式,null 表示对所有调用匹配
  • behaviorALLOW / DENY / ASK / PASSTHROUGH
  • source — 规则来源,便于审计("userSettings" / "projectSettings" / "session" / "suggested"

14.3 5 种 PermissionMode

Mode 行为 适用场景
DEFAULT 所有未命中规则都 ASK 最安全,推荐默认值
ACCEPT_EDITS 自动放行工作目录内的文件操作 用户在场的活跃开发
EXPLORE 只读:放行读、拒绝所有写与命令 代码探索、规划
BYPASS 放行一切(deny / ask 规则仍生效) 完全可信的沙箱
DONT_ASK 把所有 ASK 转为 DENY 无人值守 / 计划任务

注意EXPLORE 模式下 deny 是不可绕过的——即使在 BYPASS 模式下也照常生效。这是 2.0 的"危险工具不可绕过"原则。

14.3.1 PermissionContextState——整个权限系统的"配置单"

前面一直用 .builder().mode(...).addAskRule(...).build(),这个构建出来的对象就是 PermissionContextState。它是 agent 权限的全部配置,一张对象里包了三样东西:

PermissionContextState
├── mode          ← 一个 PermissionMode(DEFAULT / ACCEPT_EDITS / EXPLORE / BYPASS / DONT_ASK)
├── allowRules    ← Map<工具名, List<PermissionRule>> — 哪些工具直接放行
├── denyRules     ← Map<工具名, List<PermissionRule>> — 哪些工具直接拒绝
└── askRules      ← Map<工具名, List<PermissionRule>> — 哪些工具暂停问用户

核心地位PermissionContextState 是 agent 能做什么、不能做什么的唯一配置文件。它不属于某个 session,不属于某个工具——它是整个 agent 的权限配置,在 HarnessAgent.builder().permissionContext(perms) 时注入,之后不可变。

你可以把它理解为"agent 的权限清单"——清单上写了哪些工具要问、哪些直接放、哪些打死不能用。PermissionEngine(权限引擎)在每次工具调用前照着清单判定。

14.4 ASK 的完整流程

  1. LLM 想调 drop_table
  2. Permission 引擎查规则 → ASK
  3. 引擎生成"建议规则"——基于本次调用入参(drop_table('orders_2024')
  4. 引擎把 ConfirmRequest 推给前端(通过 streamEvents()PermissionAskEvent
  5. 前端弹"是否放行"对话框
  6. 用户回 ALLOW + 接受建议规则
  7. 后端调 agent.call(...) 时把 ConfirmResult 注入回 session
  8. 工具执行 + 自动把"建议规则"加入 PermissionContextState
import io.agentscope.core.event.ConfirmResult;
import io.agentscope.core.event.ConfirmRequest;

public Map<String, Object> handleAsk(ConfirmRequest req) {
   
    // 1. 推送给前端
    sendToFrontend(req);

    // 2. 等用户回 ALLOW
    boolean userAllowed = waitForUserDecision();

    // 3. 构造 ConfirmResult
    ConfirmResult result = new ConfirmResult(
            userAllowed,
            req.getToolCall(),
            userAllowed ? req.getSuggestedRules() : List.of()  // 接受建议
    );

    return Map.of("decision", result);
}

14.5 Middleware 在 HITL 中的辅助角色

Permission 只解决"能不能跑",Middleware 解决"跑之前 / 之后还要做什么"。HITL 场景里常见的 Middleware 用法:

class HitlAuditMiddleware extends MiddlewareBase {
   
    @Override
    public Mono<HookEvent> onActing(MiddlewareContext ctx, HookEvent event) {
   
        event.getToolCalls().forEach(tc -> {
   
            auditLog.info("user={} tool={} input={}",
                    ctx.runtime().getUserId(),
                    tc.getName(),
                    tc.getInput());
        });
        return Mono.just(event);
    }
}

Permission 给"能不能跑"的答案;Middleware 记"谁、什么时候、跑了什么"。

14.6 与前端 SSE 的协作

streamEvents() 会发出 PermissionAskEvent

event: permission-ask
data: {"toolCallId":"tc-1","toolName":"drop_table","input":{"table":"orders_2024"},"suggestedRules":[...]}

前端订阅后弹窗;用户决策通过另一个 HTTP 端点回传(POST /api/agent/permission/respond),后端用 agent.resume(sessionId, confirmResult) 继续。

agent.resume(...) 2.0 新增——专门用于 ASK 暂停后的恢复。

14.7 1.x Hook.stopAgent 还能用吗?

能,但不推荐。io.agentscope.core.hook.Hook 在 2.0 标 @Deprecated,但语义保留:

class LegacyHitlHook implements Hook {
   
    @Override
    public void onActing(HookEvent event) {
   
        if (event.getToolCalls().stream().anyMatch(t -> "drop_table".equals(t.getName()))) {
   
            throw new StopAgentException("drop_table is forbidden");
        }
    }
}

新代码请统一用 Permission 系统;Hook 只用来"写日志/埋点"等不需要 ASK 的场景。

14.8 完整可运行示例

这个例子在演示什么?

你有一个客服 agent,配了 3 个工具:query_order(查订单)、refund_order(退款)、drop_table(删表——危险操作)。我们希望:

  • 查订单:直接放行,不打扰用户(ALLOW)
  • 退款:弹窗问用户"是否确认退款?"(ASK)
  • 删表:直接拒绝,agent 根本没机会删(DENY)

下面用一个 agent 配 3 条 PermissionRule,连续问 3 次,每次触发不同行为:

public class Chapter14_FullHitl {
   

    public static void main(String[] args) {
   
        PermissionContextState perms = PermissionContextState.builder()
                .mode(PermissionMode.DEFAULT)
                .addAllowRule("query_order", new PermissionRule(
                        "query_order", null, PermissionBehavior.ALLOW, "userSettings"))
                .addAskRule("refund_order", new PermissionRule(
                        "refund_order", null, PermissionBehavior.ASK, "userSettings"))
                .addDenyRule("drop_table", new PermissionRule(
                        "drop_table", null, PermissionBehavior.DENY, "userSettings"))
                .build();

        HarnessAgent agent = HarnessAgent.builder()
                .name("customer_service")
                .sysPrompt("你是客服,可以查订单,但退款需要用户确认,删表绝对禁止。")
                .model(model())
                .workspace(Path.of("./workspace"))
                .permissionContext(perms)
                .build();

        // 查订单 → ALLOW:工具直接执行,无任何中断
        agent.call(List.of(new UserMessage("user", "查订单 123")),
                RuntimeContext.empty()).block();

        // 退款 → ASK:Permission 引擎暂停,发出 ConfirmRequest 等前端回应
        agent.call(List.of(new UserMessage("user", "给订单 123 退款 100 元")),
                RuntimeContext.empty()).block();

        // 删表 → DENY:工具调用被直接拒绝,agent 收到错误反馈
        agent.call(List.of(new UserMessage("user", "删掉 orders 表")),
                RuntimeContext.empty()).block();
    }
}

注意addAllowRule / addAskRule / addDenyRule 的第一个参数是精确工具名,不支持通配符。必须写 "query_order" 而非 "query_*"

14.9 本章小结

  • 2.0 用 Permission 系统做工具调用级 HITL,比 1.x Hook.stopAgent 优雅。
  • 5 种 PermissionMode 适配不同部署场景;4 种行为 ALLOW / DENY / ASK / PASSTHROUGH
  • ASK 模式:PermissionAskEvent 推前端 + 用户回 ConfirmResult
  • Deny 规则和危险路径检查不可绕过——BYPASS 模式也拦不住。
  • Middleware 留给"日志/埋点"等不需要决策的副作用。
目录
相关文章
|
4天前
|
人工智能 定位技术 SEO
我学 GEO 第 15 天:终于知道AI GEO该如何做?
我是暴走的莉莉酱,边旅行边研究AI GEO的数字游民。专注普通人如何提升“AI可见度”——让AI在回答用户问题时准确识别、理解并推荐你。不讲玄学,只做可测、可调、可持续的GEO实践。
377 124
|
6天前
|
机器学习/深度学习 人工智能 调度
🐴 HappyHorse 1.1 现已上线阿里云百炼!快来查收模型使用指南,现在调用享 6 折~
HappyHorse 1.1 是新一代视频生成大模型,全面升级动态表现力、角色一致性、指令遵循、视觉质感与音画协同能力。支持I2V/T2V/R2V三类生成,适配短剧、电商广告、品牌营销等场景,提供高质、流畅、可控的AI视频生产力。
648 4
🐴 HappyHorse 1.1 现已上线阿里云百炼!快来查收模型使用指南,现在调用享 6 折~
|
2天前
|
人工智能 自然语言处理 API
阿里云Token Plan团队版解析:功能、三档套餐与省钱订阅指南
阿里云百炼平台推出的Token Plan团队版,是面向企业与团队的AI大模型订阅服务,以Credits为统一计量单位,整合文本与图像生成模型,提供团队管理、数据安全、多工具兼容等核心能力,解决团队零散订阅AI服务的管理混乱、成本失控、数据安全等痛点。本文将从核心定位、套餐详情、计费规则、团队管理、工具兼容、便宜订阅技巧等方面,全面解析Token Plan团队版,帮助企业与团队高效、低成本地使用AI服务。
288 108
|
4天前
|
缓存 人工智能 运维
阿里云618百炼大模型Qwen3.7-Max功能、免费试用、订阅计费、配置接入详解
Qwen3.7-MAX是阿里云百炼平台推出的通义千问3.7系列旗舰大语言模型,专为智能体时代复杂任务打造,依托阿里云全域算力与自研技术,在逻辑推理、长文本处理、代码工程、长周期自主执行等领域达到行业顶尖水平。2026年618期间,该模型推出多重免费试用权益、按量计费5折、订阅套餐优惠等专属福利,覆盖个人开发者、团队与企业全场景需求,以下从核心功能、免费试用、订阅计费、配置接入四方面展开详细解析。
377 123
|
17天前
|
缓存 测试技术 API
Qwen 3.7 Plus 与 Max 实测:性价比与多模态能力差异解析(2026)
2026 年 6 月 1 日,阿里悄无声息地发布了 Qwen 3.7 Plus,距 Qwen 3.7 Max 上线刚好 11 天。同样的 1M 上下文,同样的 35 小时自治上限。但价格才是头条:Plus 是 0.40/M输入,Max是 2.50/M——便宜约 6 倍——并且还能看图、看视频。Vision Arena 上 Plus 已经排到 #16。所以这周真正值得讨论的问题不是”要不要为视觉能力买单”,而是”Max 凭什么用 6 倍价格换来 2 个百分点的 benchmark 领先”。
|
3天前
|
存储 人工智能 数据可视化
别再手动复制 Skill 了:多 Agent 时代的 Skill 管理方案
多 Agent 场景下 Skill 的统一管理与同步。
207 121
|
10天前
|
缓存 人工智能 运维
GLM 5.2自托管全流程实战:硬件选型、vLLM/SGLang部署与成本盈亏测算
2026年智谱发布GLM 5.2超大混合专家模型,区别于以往仅开放API的闭源大模型,该模型权重以MIT开源协议对外发布,企业与开发者可完整下载、本地审计、私有化部署,实现数据不出环境、自定义微调、自主调度推理资源。GLM 5.2拥有753B总参数,原生支持百万级上下文窗口,在代码生成、长文档推理、数学逻辑等多项基准测试中对标国际顶尖商用模型,是首款可完整自托管的前沿代码向大模型。
793 0
|
3天前
|
SQL 存储 运维
日志能不能改?SLS LogStore 原生支持更新和删除了
随着日志承载的业务语义越来越多,数据订正、回填、清理等需求变得越来越常见。SLS 现已为 LogStore 提供原生 update/delete 能力——支持按 RowID 精确修改,按查询条件批量操作,类似计费调账、标签刷新、反馈回填等场景都可以直接在 LogStore 内完成闭环。
180 123

热门文章

最新文章