QwenPaw

一句话定位

QwenPaw(原名 CoPaw,~/.copaw 仍作为遗留工作目录 fallback 保留于代码中)是阿里 AgentScope 团队维护的开源 “Agent OS” 应用层:它不是从零实现的 agent 循环,而是 构建在独立仓库 AgentScope 2.0agentscope==2.0.2pyproject.toml 第 8 行固定 版本)之上——AgentScope 提供 ReAct 循环基类、Msg/AgentState 序列化契约、工具调用层与 流式事件模型;QwenPaw 自己贡献的是操作系统层:workspace 边界、多模式(普通/Goal/ Mission/Coding)请求生命周期、Gate 停机系统、Scroll 上下文压缩策略、五层治理/沙箱信任 栈,以及技能/插件生态。长期记忆默认走内嵌的 ReMe(“ReMeLight”,同样是独立仓库 agentscope-ai/ReMe,本轮未克隆),其设计文档明确致谢 OpenClaw 的记忆机制启发 (memory.en.md 第 7 行)。

核心架构总览(目录结构关键路径 + 引用的 commit)

克隆方式:git clone --depth 1 https://github.com/agentscope-ai/QwenPaw(浅克隆, main HEAD)。commit 085d6b2eaa3030e0e53d68514c23c9ea77480ecb(commit message feat(ci): add QwenPaw review bot (#5736),2026-07-06 18:18:47 +0800),2026-07-07 拉取分析。

QwenPaw/ (Apache-2.0, PyPI 包名 qwenpaw)
├── src/qwenpaw/
│   ├── agents/
│   │   ├── react_agent.py         — QwenPawAgent(CodingModeMixin, Agent),762 行,
│   │   │                            覆盖 _reasoning(),Gate 挂接,工具超时注册
│   │   ├── prompt.py / prompt_builder.py / templates.py — 系统提示组装
│   │   ├── md_files/{en,zh,ru,id}/{AGENTS,SOUL,BOOTSTRAP,HEARTBEAT,MEMORY,PROFILE}.md
│   │   ├── context/scroll/        — manager.py(431行) + eviction_index.py 等,
│   │   │                            "Scroll strategy" 上下文压缩
│   │   ├── memory/                — ReMeLight/ADBPG 长期记忆管理器
│   │   ├── tools/                 — 内建工具(shell/browser_control/agent_management/
│   │   │                            delegate_external_agent/file_search 等)
│   │   ├── skill_system/, skills/ — 技能系统
│   │   ├── model_factory.py, routing_chat_model.py — 模型路由
│   │   └── acp/                   — QwenPaw 作为 ACP server
│   ├── loop/gates/                — Gate 停机系统(iteration/budget/doom_loop/rubric)
│   ├── modes/{goal,mission,coding}/ — Goal Mode / Mission Mode / Coding Mode
│   ├── governance/                — policy.py(1317行)/audit.py(380行)/detectors.py 等
│   ├── security/tool_guard/, security/skill_scanner/, security/secret_store.py
│   ├── sandbox/                   — linux/macos/windows/bubblewrap/local 后端
│   ├── plugins/                   — PluginApi 六类扩展点
│   ├── local_models/              — llama.cpp 本地运行时(QwenPaw Local)
│   ├── observability/langfuse.py  — 可选 Langfuse 集成
│   └── cli/main.py                — click LazyGroup CLI 入口
└── website/public/docs/*.en.md    — 官方设计文档,随仓库一并发布(本页主要证据来源之一)

Agent Loop(主循环 / 何时继续何时停)

  • 基础 ReAct 循环本身在 AgentScope 2.0(agentscope.agent.AgentReActConfig)里, 不在本仓库;QwenPaw 通过 QwenPawAgent(CodingModeMixin, Agent)react_agent.py 第 46 行)子类化/包装它。
  • QwenPaw 自身的核心贡献是 Gate 系统,在覆写的 _reasoning() 方法内每轮 ReAct 迭代后运行(react_agent.py 第 365-505 行):
    • 模型响应后调用 _run_stop_handlers()(第 683 行),按优先级顺序遍历所有注册的 StopHandlerRegistrationloop/gates/runner.py run_stop_handlers,第 62-131 行)。
    • 每个 Gate(StopGate 抽象基类,loop/gates/base.py)实现 check(ctx) -> StopHandlerResult|None,返回 STOPCONTINUE(可携带 continuation_message)或 None(“无意见,交给下一个 gate”)——首个非 None 结果生效(文档称为”流水线”模型)。
    • 内建默认 gate:IterationGate(优先级 10,文档默认 max 50 / 代码常量默认 max_iterations=20——文档层与代码常量层默认值不一致,本轮未进一步核实哪个是实际 生效值)、BudgetGate(优先级 20,默认 30 万 token)、DoomLoopGate(优先级 5, 滑动窗口工具调用重复检测,见下)、StandaloneRubricGate(优先级 90,纯文本输出 时重新提示,最多 max_interventions 次,默认关闭)。
    • 延迟执行语义:若模型正处于工具调用中途,STOP 信号不会立即生效——暂存在 agent._gate_pending_stop,下一轮迭代才消费(apply_stop_resultcheck_pending_gatesrunner.py 第 134-195 行),确保正在执行的工具调用永不被 打断。
    • 作用域隔离:gate 携带 scope 字段(StopHandlerRegistration.scope);当非 默认作用域的 handler(如 Goal Mode 的)处于激活态时,默认作用域 handler 被过滤掉 (_filter_by_scoperunner.py 第 16-59 行)——即 Goal/Mission 模式期间完全替换 默认 gate 集合,模式会话结束后默认 gate 自动恢复。
    • 会话隔离LoopGate 基类通过 activate()/_state()/deactivate() 维护 per-session 状态,确保同一 agent 的并发用户不共享 doom-loop/budget/iteration 计数器。
  • Doom-loop 检测loop/gates/doom_loop.py,272 行全读):滑动窗口(默认 window_size=3,文档默认配置 6)记录 (tool_name, md5(args)[:8]) 签名;相似度公式 1 - (unique-1)/(total-1);相似度达到阈值(代码默认 1.0 / 文档默认 0.8)且持续多个 窗口后,按配置的 stages(每个 {after: N, action: "modify_prompt"|"stop", message})升级——例如 2 次命中注入警告(CONTINUE),4 次命中强制 STOP。每轮自动 从 agent.state.context 记录最新工具调用,常见路径无需手动调用 record()
  • Goal Modemodes/goal/):单 agent、跨多个 HTTP 请求级 turn 的持久循环,靠 GoalTurnGate(跨请求,区别于 IterationGate 的单请求内 ReAct 迭代)、 GoalBudgetGate、包装可插拔 RubricStrategyRubricGateGoalStatusRubric 检查 session.active,由 update_goal 工具置 false)。自我审计是文档记载的 提示工程纪律(“从需求推导具体检查项,逐条对照证据,未验证视为未完成”),叠加在 机械 gate 之上,而非代码里另一个独立的验证模型调用。
  • Mission Modemodes/mission/):master→worker→verifier 流水线;Phase 1 产出 含 user stories 的 PRD(human-in-the-loop 确认),Phase 2 自主执行——master 被工具 限制(不能直接编辑文件/浏览器,必须委派),verifier agent 独立核对每条验收标准, 失败的 story 自动重试直至通过或迭代预算耗尽。文档明确记载的安全代价:worker/ verifier agent “自动绕过安全守卫,因为后台会话无法响应 /approve”——文档明确警告 仅在完全可信的代码库中使用 Mission Mode。
  • 循环系统可通过插件扩展:第三方插件可通过 PluginApi/StopHandler.register() 注册自定义 StopGate 子类(loop-engineering.en.md 给出 TimeoutGate 示例)。

记忆与上下文管理(压缩、长期记忆、会话持久化)

  • 官方文档(architecture.en.md “Memory and context” 节)明确区分两个概念: memory(跨会话、可插拔后端、基于 ReMe)vs context(当前模型窗口能装下什么、 可插拔策略:默认”摘要压缩”或选装的”Scroll strategy”)。
  • 长期记忆(默认后端 = 内嵌 ReMe/“ReMeLight”,agents/memory/ reme_light_memory_manager.py 524 行,仅目录列出未逐行读,架构来自官方文档):
    • 管线:Auto Memory(对话 → 每日 Markdown 笔记 memory/YYYY-MM-DD/*.md,每 N 个 用户轮触发一次,默认 auto_memory_interval=5)→ Auto Dream(每日笔记 → digest/*.md 长期节点 + interests.yaml 主动话题,cron 触发,默认 dream_cron="0 23 * * *")→ Proactive(兴趣话题推送到 Inbox 供 agent/用户处理)。
    • 混合检索(memory_search 工具)= BM25 关键词(权重 0.3)+ 可选向量检索(权重 0.7),按加权 Reciprocal Rank Fusion 融合:vector_contrib = 0.7/(60+rank)keyword_contrib = 0.3/(60+rank),逐 chunk 求和后降序排序。
    • 备选后端:ADBPG(阿里云 AnalyticDB for PostgreSQL,仅 REST API,无直接 SQL 模式)——用于跨设备/多实例共享;热切换需要重启(不支持热重载)。
    • 全部以纯 Markdown/YAML 落盘——设计上刻意要求应用不运行时也能人工阅读/编辑。
  • 上下文(“Scroll strategy”)——这是 QwenPaw 在 AgentScope 原生上下文压缩之上的 自研贡献,也是本轮读到代码级别的部分(agents/context/scroll/manager.py,431 行 全读):
    • ScrollContextManager.on_save()——写穿(write-through):每个进入上下文窗口的 活跃 turn 立即持久化到 durable history.db(SQLite),在任何驱逐发生之前—— 即便进程中途崩溃也不会丢失未持久化的 turn。
    • ScrollContextManager.compress()——当 token 数超过 trigger_ratio * model.context_size 时触发(复用 AgentScope 自身的 count_tokens/配对安全切分):将上下文切分为固定头部 + 可驱逐中段 + 最近尾部; 被驱逐的中段折叠进上下文内的 EvictionIndex,作为新的”Tier 0”块(不是摘要——该块 记录精确的 seq 区间,原始 turn 可逐字节恢复);重建 agent.state.context = head + [index_placeholder] + tail。若折叠一次后上下文仍 过大,EvictionIndex.compact() 会在一个”始终收敛”的循环里进一步压缩索引本身 (非无限循环)。
    • 恢复通过工具暴露给 agent:recall_history_python(在持久历史之上的沙箱化 Python REPL——manager.py 模块 docstring 提及,REPL 实现在 agents/context/scroll/repl.py,仅目录列出未全读)。
    • 检查点:to_dict()/load_state() 往返所有去重记账信息(persisted_idspersisted_tcidsseq_by_idleaf_by_idEvictionIndex 本身),确保恢复的 会话不会重复追加已恢复的窗口。
    • 留存:purge_old(retention_days) 在 agent close() 时删除 history.db 中早于 截止日期的行。
    • 这正是 README “Never forgets” 声明的具体实现:“旧 turn 被驱逐但仍可按需召回; 没有东西被摘要掉或丢失”——在代码级别验证为真(仅针对 Scroll 策略;默认压缩模式 则会做摘要,保留可召回性——Scroll 是可选项,非默认)。
  • 会话持久化:QwenPawAgent.state_dict()/load_state_dict()react_agent.py 第 173-240 行)同时处理原生 AgentScope 2.0 AgentState pydantic 模型往返遗留 1.x 格式 {"memory": {"content": [...], "_compressed_summary": ...}} 的迁移路径—— 证明这是真实生产环境中的格式迁移,而非仅设计文档声明。

工具体系(定义/调用协议/注册/权限)

  • 定义/注册:@tool_descriptor 装饰器在 import 时自动将函数收集进全局注册表 (agents/tools/__init__.py docstring + discover_builtin_tool_funcs() 委托给 runtime.tool_registry.get_builtin_tool_funcs())。新增内建工具 = 装饰 + 在 __init__.py 中 import,无需手动维护列表。
  • 调用协议:标准 AgentScope Toolkit/工具调用块格式(tool_call/tool_use 块含 name+inputtool_result 块以 tool_call_id 关联)——继承自 AgentScope,非 自研。
  • 权限包装是全局且 agent 不可绕过的:每个工具在交给 agent 之前都被包装进 PolicyGuardedToolreact_agent.py 第 105-114 行,内存工具注册处可见具体调用: PolicyGuardedTool(tool_fn, governor=..., request_context=...))。 QwenPawAgent.__init__ 显式将 self.state.permission_context.mode = PermissionMode.BYPASS(第 137 行)以关闭 AgentScope 自带的权限引擎,因为 QwenPaw 自己的 tool-guard/governance 栈(PolicyGuardedTool.check_permissions) 完全取代了它——即 QwenPaw 不是叠加两套权限系统,而是把 AgentScope 的换成了自己的。
  • 单工具调用超时集中配置(_register_tool_call_hooksreact_agent.py 第 607-659 行)经由 ToolCoordinatorrequest_context["tool_coordinator"])——例如 execute_shell_command 60 秒,chat_with_agent 300 秒,check_agent_task 30 秒, grep_search 30 秒,glob_search 15 秒,ast_search 35 秒, desktop_screenshot 30 秒,LSP 工具 20 秒,browser_use 最长 3600 秒。 agent 配置级 builtin_tools[...].timeout_seconds 可覆盖单 agent 设置。
  • 每次工具调用的治理决策流程(governance/policy.py):ToolRegistry 类型检查 → builtin_rules(不可变,系统所有)→ user_rules(审批流程生成,“批准时智能泛化”: 首 token+glob 泛化,高风险命令保持精确匹配)→ 全局兜底。规则格式: GovernanceRule(match="Bash(git *)", action=ALLOW) 风格的 glob-on-target 匹配, 区分”显式资源工具”(allow=直接执行)与”Bash 类工具”(allow=即便预授权也在沙箱内 执行,因为任意 shell 永远无法被完全预先审查)。四种可能动作: ALLOW/DENY/ASK/SANDBOX_FALLBACK
  • 每次受治理的调用都写入 SQLite audit.dbgovernance/audit.py,含 tool_name/target/decision/reason)——详见可观测性章节。
  • Access Policy(独立的文档记载层,目前仅针对 MCP):按 subject(身份)× principal(来源渠道/用户)× target(工具名/类型)匹配的 per-MCP-client default_effect + 优先级规则,最具体规则优先解析(security.en.md “Policy evaluation” 节)——这是声明式 YAML,独立于命令式的 Tool Guard 正则规则。

Prompt 设计(系统提示结构、动态组装)

  • 系统提示在请求时由 agent 工作目录下最多 3 个 markdown 文件按固定顺序拼装: AGENTS.mdSOUL.mdPROFILE.mdagents/prompt.py PromptConfig.DEFAULT_FILES)。均为可选——缺失文件被静默跳过。
    • AGENTS.md——行为规则(安全、内部/外部动作之间的”先问”边界、表情回应等社交行为、 heartbeat 块、工具/技能指引)。
    • SOUL.md——未全读;按命名惯例与文档交叉引用,承载 agent 的人格/身份设定。
    • PROFILE.md——由系统自动生成,来自 agent 名称+描述+技能+persona 文件(据 multi-agent.en.md);供其他 agent 判断是否要委派任务给该 agent 使用。
  • 通过 HTML 注释区段标记做动态拼接:<!-- heartbeat:start -->...<!-- heartbeat:end --><!-- memory:start -->...<!-- memory:end --> 正则 (PromptBuilder.HEARTBEAT_PATTERNMEMORY_PATTERN)让构建器按条件剥离/注入这些 块(例如仅当 heartbeat_enabled=True 时才包含 heartbeat 块)。
  • 无论 persona 文件如何都会注入的硬编码系统级指令:DRIVER_POLICY_RECHECK_HINTprompt.py 第 29-40 行)——明确告诉模型此前 driver_policy_denied 的工具结果是 某个时间点的快照,若用户再次请求必须重新尝试,因为策略可能在对话中途变化。这是 harness 通过 prompt 工程(而非代码)修补一个具体观察到的 LLM 失败模式(过度泛化一次 过时拒绝)的具体例子。
  • 本地化:默认 md 模板文件以 4 种语言发布(enzhruid),外加角色专属变体 (qa/local/),均位于 agents/md_files/ 下。
  • 内置示例插件 plugins/bundle/cloudpaw/ 展示了多 persona 捆绑模式:按角色 (orchestrationverifierexecutor)× 语言各自独立的 SOUL.md/PROFILE.md 对——即提示组装机制被复用来构建一个固定的多 agent 团队,而非单一 persona。

Router / 编排(任务分解、多 agent、子 agent)

  • 三种不同的多 agent 机制(据 multi-agent.en.md,源码仅目录列出未逐行读):
    1. Multi-Agent Workspace——一个 QwenPaw 安装内 N 个独立 agent,各自隔离的 workspace(独立 memory/skills/history/channels)。配置拆分:全局 (config.json:provider 密钥、环境变量)vs 单 agent (workspaces/{agent_id}/agent.json:channels、skills、history、cron、 persona)。
    2. Inter-Agent Collaborationmulti_agent_collaboration 技能,选装)—— agent A 调用 qwenpaw agents list 发现其他 agent 的 Description + 自动生成 的 PROFILE.md,然后通过 chat_with_agent/submit_to_agent 委派;支持前台 (阻塞)与 --background(返回 task_id,通过 check_agent_task 轮询,状态流 submitted→pending→running→finished)。
    3. In-Workspace Subagentsspawn_subagent,v1.1.10 引入)——同 agent 配置下 的临时性子会话,用于项目内任务。fork=False(默认):空白会话,同一项目目录, 无对话历史。fork=True:继承父会话完整对话上下文;若开启 Coding Mode(或 workspace 是 git 仓库),会在 <project>/.qwenpaw/worktrees/ 下创建隔离的 git worktree,使文件改动在手动合并前不触及主工作树(有改动才保留,无改动 自动清理);非 git 仓库时退化为原地 fork(继承上下文,无文件隔离)。 .worktreeinclude 文件可让 .gitignore 掉的配置(如 .env)自动复制进 worktree。子 agent 永不可恢复——始终一次性。
  • Mission Mode(见 Agent Loop 章节)是最接近真正任务分解的机制:master agent 写出含 user stories 的 PRD(Phase 1,人工确认),随后固定的 master→worker→verifier 流水线逐 story 执行、逐 story 重试(Phase 2)。
  • **ACP(Agent Client Protocol)**用于跨运行时编排(acp-integration.en.mdagents/acp/ 目录 + delegate_external_agent 工具,1022 行仅目录列出):
    • QwenPaw 作为 ACP client:delegate_external_agent(action= start|message|respond|close, runner=...) 驱动外部 ACP 兼容 agent 运行时(内建 示例:opencodeqwen_codeclaude_codecodex——即 QwenPaw 可以字面意义上 shell out 到并编排 Claude Code 作为子运行时)。委派方提出的权限请求会转交人类 决定,从不自动决策。
    • QwenPaw 作为 ACP server:qwenpaw acp 命令通过 stdio JSON-RPC 将 QwenPaw 自身 暴露出去(方法:initialize/new_session/load_session/resume_session/ list_sessions/close_session/prompt/set_session_model/set_config_option/ cancel),供 Zed/OpenCode 等编辑器驱动。
  • 本轮未发现独立的”规划器模型”或经典层级任务分解算法的证据——除 Mission Mode 的 “先 PRD 后执行”模式与基于 gate 的循环外,编排更接近”agent 通过工具调用 agent”, 而非专门的路由组件。

Skill / 插件体系

  • Skills = 文件夹(SKILL.md + 可选脚本),两层结构:共享 Skill Pool$WORKING_DIR/skill_pool/)vs 各 Workspace 的运行时副本 (workspaces/{agent_id}/skills/)。Pool 中的条目不会直接执行——必须先”广播”到某个 workspace。skill_paths 配置允许外部目录(git 仓库、团队共享)不经复制直接读入同一 pool 视图(优先级:pool 优先,其次按配置顺序;名称冲突 = 先到者优先,后到者被遮蔽 并记录日志)。
    • Frontmatter:name + description 必填;metadata.requires.{bins, env} 声明 外部二进制/环境依赖,暴露为 require_bins/require_envs——仅声明自动强制 校验(依赖缺失不会自动禁用该技能)。
    • 引入来源:skills.shclawhub.aiskillsmp.comlobehub.com/market.lobehub.comgithub.commodelscope.cn/skills
    • /make-skill(Beta)——把一次完整的对话会话转成新技能,agent 根据对话记录写出 计划 + SKILL.md。
    • Skill Market:4 个内建 provider(QwenPaw、ClawHub、ModelScope 始终开启;Aliyun 需要阿里云 AK/SK),并行搜索,部分失败可容忍。
    • 单技能运行时配置以环境变量形式注入,匹配声明的 requires.env 键,加上始终可用的 QWENPAW_SKILL_CONFIG_<NAME> JSON blob;宿主环境变量永不被覆盖;配置解析顺序: 宿主 env > workspace 配置 > pool 配置。
    • 通过目录列出确认 20+ 内建技能(en/zh 本地化配对),多个明确移植自 github.com/anthropics/skills(docx、pdf、pptx、xlsx)与 github.com/openclaw/openclaw(himalaya 邮件技能)。
  • Pluginssrc/qwenpaw/plugins/PluginApi——仅目录列出,行为通过 plugins.en.md 的可运行示例核实):六种扩展类型——Provider、Middleware (register_middleware,包装 AgentScope on_acting/on_reasoning 钩子, priority = 洋葱式分层顺序)、Hook(startup/shutdown/uninstall/ workspace-created,应用生命周期级)、Command(/slash 命令,经 BaseControlCommandHandler)、HTTP API(在 /api/<prefix> 下挂载 fastapi.APIRouter,一个插件一个前缀,卸载时自动卸挂)、Frontend(浏览器端 JS, 共享宿主 React/antd 运行时,经 window.QwenPaw.*,可通过 dispose() 撤销注册)。
    • 通过 CLI 安装(qwenpaw plugin install <path-or-url-or-zip>),仅限离线时; 热安装/卸载据文档也支持”应用运行期间”经 API(安全文档标记这是一个需要留意状态 一致性的风险点)。
    • Manifest(plugin.json)携带 qwenpaw_version: {min, max} 兼容范围(遗留 min_version/max_version 仍被接受)。
    • 仓库内具体的示例插件:plugins/bundle/cloudpaw(云运维多 agent 团队 + terraform/alicloud-cli 技能)、plugins/middleware-demo(tracing + 思考日志 middleware 示例,与文档 Example 8/9 逐字对应)、plugins/tool/gpt-image2 (OpenAI 图片生成工具插件)。

自进化能力(自我改进 / 学习型记忆 / eval 驱动纠错)

  • 本仓库未发现权重级自我微调或训练循环式自我改进的证据(若存在,会在独立的 ReMe/AgentScope 仓库中,本轮未核实)。
  • 最接近的类比,均为记忆驱动或 gate 驱动,而非模型训练驱动
    1. Auto Dreammemory-evolving-and-proactive.en.md):一个 cron 任务(默认 每晚 0 23 * * *)读取近期每日记忆笔记,针对每个变化的记忆单元,在 digest/{personal,procedure,wiki}/ 下”创建、佐证、修正或纠正”一个摘要节点—— 即记忆内容会随新证据被修订,明确包含一个”纠正”操作(与先前信念矛盾/更新)。这是 文档中唯一使用”自愈”/“自我纠正”记忆这类措辞的地方。
    2. Goal Mode 的自我审计 gateRubricGate + GoalStatusRubric/可插拔 RubricStrategy)——循环不会终止,直到出现明确的验证信号(update_goal 工具 调用或自定义 rubric 的 SATISFIED 判定);文档称之为”agent 必须证明任务完成, 而非仅仅感觉完成”。SubAgentRubric 目前是个 stub(rubric.py 第 121-151 行, 明确标注 TODO: implement file-based state verification,当前始终返回 GRADER_ERROR),引用了一种”oh-my-claudecode/ralph 模式”——生成验证子 agent 并 读取状态文件判定结果——已规划,未实现
    3. Mission Mode 的 verifier agent——独立对照验收标准校验每条 user story,触发 失败 story 的自动重试——是一个 eval 驱动的纠正循环,但仅限于单次 mission 运行内, 不会作为通用学习信号被持久化。
    4. model_capability_cacheproviders/model_capability_cache.pyreact_agent.py 中引用,未独立全读)——在真实的 bad-request 错误发生后,为 每个模型键学习一个布尔 rejects_media 标记,并在后续调用中主动避免向该模型发送 媒体内容。这是 harness 基于观察到的模型失败调整自身行为的一个小而真实的例子 (基础设施层面的”eval 驱动纠错”,而非推理层面)。
  • 未在源码中发现针对 harness 自身代码的 CI/benchmark 驱动自我改进循环,除了克隆时 HEAD 恰好指向的新增提交本身:QwenPaw review botscripts/review-bot/{setup_review_workspace.py, review_runner.py, prompts.py})——即 commit 085d6b2e(“feat(ci): add QwenPaw review bot (#5736)”) 给仓库自身 CI 添加了一个基于 LLM 的 PR 审查 bot。这是对代码库的 eval 驱动纠正, 而非对agent 自身运行时行为的纠正——与经典意义上的”轨迹强化”相邻但不同,仅作为 留意点标注,未详细读。

可观测性(日志 / trace 格式)

  • 结构化的单次工具调用审计轨迹:SQLite ~/.qwenpaw/audit.db,单一全局单例,schema audit_events(ts INTEGER ms-epoch-UTC, workspace_dir, agent_id, session_id, tool_name, target, decision, reason, extra JSON)governance/audit.py 第 32-48 行,schema 部分全读)。record() 同步写入(无内存缓冲);query() 支持 过滤+分页;总行数达到 10 万时自动清理最旧的 1 万行。这是治理决策 (allow/deny/ask/sandbox_fallback 结果)专属的”轨迹”追踪,不是完整的 agent 推理轨迹。
  • 可选 Langfuse 集成observability/langfuse.py,90 行全读):除非安装了 langfuse 包且设置了 LANGFUSE_SECRET_KEY 环境变量,否则是纯 no-op;激活时通过 ContextVar 传递 LangfuseTraceContext(trace_id, parent_observation_id, name, metadata),使嵌套 span 可关联;README v1.1.12 更新日志明确声称”Langfuse agent loop grouping”是已发布功能(即一个 turn 内多轮 ReAct 迭代被归并到同一 trace 下)—— 除更新日志这一行 + 这个薄封装模块外未独立验证。
  • 通过插件 middleware 的自定义 tracing 是被认可的扩展点(非核心硬编码): plugins.en.md Example 8 展示一个 on_actingMiddlewareBase 子类写入 <workspace>/.qwenpaw/trace.log,格式 [HH:MM:SS] tool_name(input_prefix) — elapsed_ms,受 QWENPAW_TRACE 环境变量控制;与仓库内真实示例 plugins/middleware-demo/tracing-middleware/tracing_plugin.py 目录结构对应, 未与文档代码块逐行 diff。
  • 纯文本日志文件 ~/.qwenpaw/logs/qwenpaw.log 在多篇文档(故障排查节)中被引用为标准 Python-logging 落点,例如 security.en.md 建议用户 grep 该文件寻找 governance decision: tool=Bash target="..." action=sandbox_fallback sandbox=bubblewrap ... 这类行以验证沙箱是否被激活——即治理层也会为每个决策发出一条 结构化的单行日志,独立于 SQLite 审计表。

安全与权限(审批门、密钥管理)

  • 五层安全栈(据 security.en.md;每层代码目录已列出、关键文件行数已确认,核心策略 引擎 governance/policy.py 读了开头部分):
    1. Governance Policygovernance/policy.py)——实时工具调用拦截, builtin_rules(系统所有)+ user_rules(审批流程生成,“智能泛化”:首 token+glob,高风险命令保持精确匹配)+ 正则/shell 规避检测,解析为 ALLOW/DENY/ASK/SANDBOX_FALLBACK。
    2. File Guard——独立于 Tool Guard(即便 Tool Guard 被禁用也照常运行,只要 file_guard.enabled);敏感路径拒绝列表(~/.qwenpaw.secret/ 默认受保护——存放 API 密钥/凭证),支持递归目录保护(尾部加 /),路径归一化(~ 展开、 相对→绝对)。
    3. Sandbox——操作系统内核级隔离,按平台自动探测后端:macOS Seatbelt (sandbox-exec)、Linux Bubblewrap(优先,mount+user+PID 命名空间)或 Landlock(回退,内核 5.13+)、Windows AppContainer(+icacls ACL,安装需管理员 权限,需 build 10240+)。默认拒绝的白名单模型:仅显式 writable=True 的挂载点 可写;deny_paths 即便原本可读也被阻断(在 Bubblewrap 上表现为不挂载因而不可见, 在 Seatbelt/Landlock/AppContainer 上表现为 Permission denied)。明确记载的 当前局限:网络隔离尚未实现(沙箱化进程无论 network_allow 如何都拥有完整 网络),max_processes/max_memory_mb 字段存在但任何后端都不强制执行, Windows AppContainer 无法 ACL 某些 TrustedInstaller 所有的系统目录(实际影响有限, 因为这些目录默认全局可读)。
    4. Skill Scanner——激活前静态扫描(YAML 正则签名,类别涵盖 command_injection/data_exfiltration/hardcoded_secrets/prompt_injection/ social_engineering/supply_chain_attack/obfuscation/resource_abuse/ unauthorized_tool_use);模式 Block/Warn(默认)/Off;基于 mtime 的扫描缓存; SHA-256 内容哈希白名单(技能文件内容变化即失效——“版本锁定”)。
    5. Access Policy(目前仅限 MCP)——声明式的按 (subject × principal/来源 × target) 三元组 allow/deny/ask,最具体规则优先解析顺序(target 名称 > target 类型 > principal 具体度 > subject 具体度 > 严格度 deny>ask>allow)。
    • 另有可选的 Web Authentication(面向 Console,默认禁用;单管理员账号模型; HMAC-SHA256 签名的 7 天 token;加盐 SHA-256 密码哈希;localhost 自动绕过; auth.json0o600 权限写入)。
  • 单 agent 字段 approval_level:STRICT(始终询问)/ SMART(低风险自动允许)/ AUTO(默认——仅 guard 标记的调用才询问)/ OFF(该 agent 完全禁用 Tool Guard)。
  • 明确记载的安全代价:Mission Mode 的 worker/verifier 子 agent”自动绕过安全 守卫”,因为后台会话无法响应交互式 /approve——文档明确表示仅在完全可信的代码库中 使用 Mission Mode。这是自动化与审批门之间一个真实的、有名字的权衡,而非隐藏缺陷。
  • 密钥:security/secret_store.py(466 行,仅目录列出未读)——provider API 密钥 + 连接器(MCP)凭证的加密存储;{WORKING_DIR}.secret/ 是磁盘位置,默认受 File Guard 保护。

沙箱与执行隔离

(详见上面”安全与权限”第 3 层——源码中这是统一的一个子系统,此处不重复展开) 概要:4 个真实后端(Seatbelt/Bubblewrap/Landlock/AppContainer)+ 一个 none 直通兜底,启动时按平台固定优先级顺序自动探测(Linux:bubblewrap > Landlock > none),每次工具调用都创建全新沙箱实例、调用结束后销毁,配合 MountSpec (path/writable/executable)声明与各后端基于 stderr 模式的违规检测。治理层决定是否 需要 sandbox_fallback;沙箱本身只在该决策做出后强制内核级边界——按设计是两个独立的层 (security.en.md:“Governance Policy = 执行前的模式检测 + 策略评估……Sandbox = 运行时内核隔离”)。

与模型的协同设计

  • 模型被抽象在稳定的 ChatModelBase 接口(AgentScope)之后,使 provider 可替换而 无需改动 agent 代码(architecture.en.md “Models” 节)。
  • 据文档支持的云端 provider:OpenAI、Anthropic、Google Gemini、DashScope (Qwen)、OpenRouter(+ 必要时的登录流程)。本地:Ollama、LM Studio,以及完全 端上运行的 llama.cpplocal_models/llamacpp.py,935 行,仅目录列出)。
  • 能力探测/对模型的自适应行为(代码级,读自 react_agent.py):
    • model_capability_cache 在真实 API 错误发生后为每个模型键学习 rejects_media 标记(_is_bad_request_or_media_error 刻意将内容安全拒绝、以及尺寸/上下文长度 错误排除在”不支持媒体”的误判之外——据行内注释第 524-566 行,是为避免假阳性污染 缓存的刻意窄化启发式),随后在对该模型的后续调用中主动从 memory/formatter 剥离 媒体块。
    • 重试一次再剥离模式:遇到真实的媒体拒绝错误时,agent 会在剥离媒体后重试同一调用 一次(_reasoning() 中对 super()._reasoning() 的 try/except 包裹),而非直接 让该轮失败。
  • RoutingChatModel(129 行全读)——按 AgentsLLMRoutingConfig.mode 在预先构建 好的 local_endpointcloud_endpoint 之间路由每次模型调用。当前实现是静态 全局开关,非按请求自适应路由RoutingPolicy.decide() 接受 text/channel/tools_available 参数但立即丢弃它们(del text, channel, tools_available),仅当 mode == "cloud_first" 时返回 cloud,否则始终返回 local。参数接口暗示内容感知路由是计划中/意图中的功能,但在这个 commit 尚未实现。
  • README 声称 QwenPaw-Flash(2B/4B/9B)是”为 agent 任务训练的模型”,由内建的 “QwenPaw Local runtime” 提供服务——这个产品声明本轮未能独立核实(需要在 HF/ModelScope 上找到 QwenPaw-Flash 的 model card/训练报告/论文,超出仅克隆本仓库的 调研范围)。标注为未验证而非已确认。
  • 本仓库未发现针对该 harness 的 RLHF/微调管线(若存在,会在模型自身的训练仓库中, 不在此处)。

轨迹利用(session/trajectory 是否反哺训练/评测)

  • 本仓库未发现会话轨迹被导出用于模型训练或微调的证据。现存的持久化存储 (Scroll 上下文的 history.db,ReMe 记忆的 mem_session/dialog/*.jsonl)在架构上 被定位为同一 agent 的运行时记忆基底,而非训练数据管线产物——未找到把轨迹指向 外部训练或评测系统的导出/上传代码。
    • mem_session/dialog/<session_id>.jsonl 被文档明确描述为在作为 ReMe 抽取源之前 先经过”净化”(剥离工具结果块与 base64 数据块)——即它是专门为记忆抽取清洗的, 而非作为原始 RL/SFT 轨迹数据保留。
    • Scroll 的 history.db 被定位为纯粹的 recall_history_python 工具召回基底—— 未发现或记载任何导出路径。
  • 最接近”轨迹被复用于评测”的机制是 Mission Mode 的 verifier agent 对每个 worker 产出按验收标准打分(见自进化章节)——但这是运行内评测,mission 完成后即丢弃(未发现 将 verifier 判定持久化用于后续分析/训练的证据)。
  • 审计日志(audit.db)无限期持久化治理决策(allow/deny/ask,直到 10 万行滚动清理 触发)——更接近合规/调试轨迹,而非 ML 轨迹数据集;它记录的是决策元数据,不是完整的 推理轨迹或 reward。
  • 结论:在这个 commit,轨迹反哺训练/评测不是 QwenPaw 的内建能力。 若这类能力存在 于更广泛的 AgentScope/ReMe 生态中,会在那些独立仓库里,本轮未克隆核实。

与同类 harness 的关键差异(1-3 条,可以先留一句概述,后续 synthesis 阶段会做跨 harness 对比)

  • QwenPaw 是本系列中少见的”应用层而非内核层”harness:ReAct 循环本身、权限引擎、 上下文压缩的基础实现都来自独立的 AgentScope 2.0 依赖,QwenPaw 自己只贡献 Gate 停机 系统、Scroll 记忆策略、治理/沙箱信任栈与多模式(Goal/Mission)编排——这种”host framework + OS layer”分层在同类 harness 中较为独特,值得跨 harness 对比时重点标注。
  • Scroll 策略的”写穿持久化 + 驱逐折叠为可召回索引”设计,与常见的”摘要后丢弃原文”压缩 策略形成明确对比——具体差异留待 synthesis 阶段与其他 harness 的压缩机制并列分析。
  • Mission Mode 显式记载的”后台子 agent 绕过审批门”是一个罕见的、被文档而非代码审查 发现的、公开承认的安全权衡,可作为跨 harness 安全设计对比的一个案例。

原始源码定位

  • repo: https://github.com/agentscope-ai/QwenPaw
  • commit/version analyzed: 085d6b2eaa3030e0e53d68514c23c9ea77480ecb (“feat(ci): add QwenPaw review bot (#5736)“,2026-07-06 18:18:47 +0800)
  • 关键文件列表(相对路径):
    • src/qwenpaw/agents/react_agent.py
    • src/qwenpaw/loop/gates/{__init__,base,runner,doom_loop,rubric,budget,iteration,handler_registry,handler,loop_gate,file_loop_gate}.py
    • src/qwenpaw/modes/goal/{gates,goal_mode,tools,helpers,prompts,contributor}.py
    • src/qwenpaw/modes/mission/{gates,handler,state,prompts,contributor,hooks}.py
    • src/qwenpaw/modes/coding/{mixin,hooks}.py
    • src/qwenpaw/agents/context/scroll/{manager,eviction_index,history,serialize,memoryspace,sync,_as_internals,repl,cap_middleware,prompt}.py
    • src/qwenpaw/agents/memory/{reme_light_memory_manager,reme_config,adbpg_memory_manager}.py
    • src/qwenpaw/agents/tools/__init__.py(+ shell.pybrowser_control.pyagent_management.pydelegate_external_agent.py 等)
    • src/qwenpaw/agents/{prompt,prompt_builder,templates}.py
    • src/qwenpaw/agents/md_files/{en,zh,ru,id}/{AGENTS,SOUL,BOOTSTRAP,HEARTBEAT,MEMORY,PROFILE}.md
    • src/qwenpaw/governance/{policy,audit,tool_registry,resource_governor,generalize,tool_adapter,detectors}.py
    • src/qwenpaw/security/tool_guard/{engine,models,approval,execution_level,i18n,utils}.py
      • guardians/{rule_guardian,shell_evasion_guardian,file_guardian}.py
    • src/qwenpaw/security/skill_scanner/{scanner,scan_policy,models}.py + analyzers/pattern_analyzer.py
    • src/qwenpaw/security/secret_store.py
    • src/qwenpaw/sandbox/{config,linux_sandbox,windows_sandbox,macos_sandbox,bubblewrap_sandbox,local_sandbox}.py
    • src/qwenpaw/agents/tools/agent_management.pysrc/qwenpaw/agents/tools/delegate_external_agent.pysrc/qwenpaw/agents/acp/
    • src/qwenpaw/plugins/{architecture,registry,api}.py
    • src/qwenpaw/agents/skill_system/src/qwenpaw/agents/skills/
    • plugins/bundle/cloudpaw/plugins/middleware-demo/plugins/tool/gpt-image2/
    • src/qwenpaw/cli/main.py
    • src/qwenpaw/agents/model_factory.pysrc/qwenpaw/agents/routing_chat_model.py
    • src/qwenpaw/local_models/{llamacpp,model_manager,download_manager,tag_parser,manager}.py
    • src/qwenpaw/observability/langfuse.py
    • scripts/review-bot/{setup_review_workspace,review_runner,prompts}.py

一手源存档(sources/)

/Users/zhao/projects/self-wiki/ai-research/sources/harness/qwenpaw/ 下保存:

  • NOTES.md(830 行)——完整调研笔记,本页所有论断的原始出处(含精确文件路径/行号)
  • docs/——从仓库 website/public/docs/*.en.md 拷出的 10 份官方一手设计文档: acp-integration.en.mdarchitecture.en.mdcontext.en.mdloop-engineering.en.mdmemory-evolving-and-proactive.en.mdmemory.en.mdmulti-agent.en.mdplugins.en.mdsecurity.en.mdskills.en.md
  • code_excerpts/——从仓库摘录的关键源码片段: agent_tools_registry_init.pyreact_agent.pyrouting_chat_model.py, 以及 context_scroll/governance/loop_gates/modes_goal/prompt/ 子目录(分别对应 Scroll 管理器、治理策略、Gate 系统、Goal Mode、Prompt Builder 的 代码摘录)

(注:仓库本体已按调研流程克隆读取后删除,未保留完整 clone;上述存档是本轮调研的 可复核证据。)