QwenPaw 2.0 Driver:统一的外部能力接入层
声明:本文转载自 QwenPaw,资料仅供学习参考使用。
为什么要做 Driver
Agent 系统正在快速演进。今天的 Agent 不再局限于调用几个内置工具——它需要对接 MCP Server、远程 Agent (A2A)、ACP 服务,以及未来更多的外部协议。
这些能力在通信方式(stdio / HTTP / WebSocket)、认证机制(静态 Token / OAuth2 / AK/SK)和协议格式(JSON-RPC / REST / gRPC)上各不相同。如果 Agent 直接耦合这些差异,每新增一种外部能力就要修改 Agent 核心代码。这违反了 Open-Closed 原则,也让系统的安全治理变得碎片化。
我们需要回答一个根本问题:Agent 系统应该如何感知和管理异构的外部能力?
Driver 是什么
Driver 将对外部能力的访问抽象为统一的、协议无关的资源模型,使 Agent 系统可以统一地声明(Declarative)、调用(Invocable)和治理(Governable)。
三个关键词定义了 Driver 的价值:
- 可声明 — 系统知晓哪些外部能力存在、如何到达
- 可调用 — 通过标准接口发起调用,屏蔽底层协议差异
- 可治理 — 控制谁在什么条件下可以调用,精确到单个工具
Driver 不拥有外部服务。外部服务独立存在、独立部署、拥有自己的生命周期。Driver 抽象的是连接与调用,而非服务本身。
MCP 是我们交付的第一个具体协议实现。A2A、ACP 等后续协议通过 register_handler_type() 即可扩展接入。
架构概览
Driver Layer 由五个核心组件构成:

┌────────────────────────────────────────────────────────────────┐
│ Driver Layer │
│ │
│ DriverManager ──builds──▶ DriverHandler │
│ │ │ │
│ │ reads/persists │ holds ref │
│ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ DriverCard (YAML) │ │
│ │ name · protocol · endpoint · credentials · policy │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Capability: capability_id + kind + action + schema │
│ Access Policy: ABAC (Subject × Principal × Target → Effect) │
└────────────────────────────────────────────────────────────────┘
▲ invoke_capability()
│
┌─────────────────────────┴──────────────────────────────────────┐
│ Agent Runtime │
│ build_agent() → Toolkit: [DriverCapabilityTool(cap, invoker)] │
│ LLM → tool_call → invoker → Handler → 协议执行 → 结果返回 │
└─────────────────────────────────────────────────────────────────┘
核心设计决策
1. Card 与 Handler 分离
DriverCard 是纯静态声明(YAML 文件),Handler 是运行时实例。这个分离带来三个好处:
- Card 可版本控制、人类可审计
- Handler 可独立重建而不丢失配置
- 同一 Card 格式可对接不同的 Handler 实现
2. 治理管线不可绕过
所有调用必经 _authorize_invocation() 治理管线——先裁决访问策略,再执行协议操作。这不是一个可选的中间件,而是内嵌于 Handler 调用路径的强制约束。
invoke_capability()
└─ _authorize_invocation() ← 必经
├─ evaluate_policy(ctx) → allow / deny / ask
└─ _request_approval(ctx) → 委托给 ApprovalGate(ask 时)
└─ protocol_execute(...) ← policy 通过后才执行
3. Capability URI 统一标识
每个 capability 通过 URI 唯一标识,跨会话可持久引用:
driver://{protocol}/{driver_name}/{kind_plural}/{name}#{action}
例如:
driver://mcp/github-mcp/tools/create_issue#invokedriver://a2a/translate-agent/agents/translate#invoke
Agent 不需要知道 capability 来自 MCP 还是 A2A——它只看到统一的 DriverCapability 描述和 invoke_capability() 入口。
4. 凭证四层解耦
凭证管理采用四层架构,实现声明与秘密的完全分离:
Layer 1: CredentialRef (Card 中的引用声明)
Layer 2: AsyncCredentialStore (加密存储)
Layer 3: CredentialProvider (解析 + 刷新)
Layer 4: ResolvedCredential (注入 Handler 的运行时凭证)
Card 中永远不会出现明文秘密——只有引用。Provider 层支持动态注册,DingTalk/飞书等非标准 OAuth 通过注入自定义 TokenExchanger 适配。
5. Open-Closed 扩展
新增协议只需三步:
- 实现
XxxDriverHandler— 覆写_setup/_teardown+list_capabilities/invoke_capability - 注册:
manager.register_handler_type("xxx", XxxDriverHandler) - 声明:新建 YAML(
protocol: xxx)
无需修改现有代码。protocol 为字符串(非枚举),保证了真正的 Open-Closed。
Access Policy:精细到每个工具的访问控制
Access Policy 采用 ABAC(基于属性的访问控制)模型,四维裁决:
三种裁决效果:
- allow — 立即执行
- deny — 阻止并返回错误
- ask — 挂起等待人工审批(通过注入的
ApprovalGate协议实现)
优先级裁决:多条规则匹配时,按 Target 精确度 > Principal 精确度 > Subject 精确度 > 严格程度排序,最具体的规则胜出。
这意味着你可以:
- 默认
ask所有调用,但allow来自 Console 的 admin 用户 - 对特定危险工具
deny所有人,即使默认策略是allow - 工作日白天
allow,其余时间ask
Quick Start: MCP Driver
以下是一个完整的 MCP Driver 配置示例,展示如何声明一个带凭证绑定和工具级访问策略的 MCP 服务:
# drivers/mcp/hello-mcp.yaml
name: hello-mcp
protocol: mcp
endpoint:
transport: stdio
command: python
args: ["./mcp_servers/hello_server.py"]
env:
ECHO_SECRET:
source: credential
credential: static
field: ECHO_SECRET
config:
display_name: Hello MCP
description: 本地 stdio MCP 演示服务,提供 print_content 和 get_secret_status 两个工具
enabled: true
policy:
default_effect: ask
rules:
- subject: "*"
effect: deny
target: { kind: tool, name: get_secret_status }
这份配置做了三件事:
- 声明连接方式:通过 stdio 启动本地 Python MCP Server
- 绑定凭证:环境变量
ECHO_SECRET从凭证存储中解析注入,Card 中无明文 - 定义访问策略:默认所有调用需要审批(
ask),但get_secret_status工具被完全禁止(deny)
Console 管理
在 Console 的 智能体 → MCP 页面中,点击任意 MCP 客户端卡片上的 工具&权限 即可可视化管理访问策略:

- 设置客户端级默认效果(Ask / Allow / Deny)
- 为特定来源渠道和用户添加覆盖规则
- 为单个工具设置独立的访问策略
- 保存后立即生效,无需重启
端到端调用流程
一次完整的 Driver 调用经历以下阶段:
用户请求 → list_capabilities() → build_agent(toolkit)
→ LLM 决策调用工具
→ DriverCapabilityTool.__call__()
→ DriverManager.invoke_capability()
→ parse capability_id → 路由到正确 Handler
→ Handler._authorize_invocation() [策略裁决]
→ Handler.protocol_execute() [协议执行]
→ DriverInvocationResult → Agent 继续推理
Driver 连接在 Workspace 级别保持持久化(进程内维持 MCP client session),而 Agent 和 Toolkit 则随每次请求重建。这确保了资源复用与隔离安全之间的平衡。
展望
Driver 模块为 QwenPaw Agent 系统建立了统一的外部能力接入基座。当前已交付 MCP 协议支持,A2A 和 ACP 的 Handler 骨架已就绪。未来的演进方向包括:
- 更多协议:完整的 A2A(Agent-to-Agent)和 ACP 协议实现
- 可观测性:调用链路追踪、策略裁决审计日志
Driver 的设计哲学是:让 Agent 专注于推理,让 Driver 处理连接的复杂性。 无论外部世界的协议如何变化,Agent 看到的始终是统一的 Capability 模型。