🔥 QwenPaw 源码面试 100 题(含答案)
基于 QwenPaw v1.1.9 源码深度解析
出题人:小微
目录
- 架构与整体设计(Q1-Q10)
- Agent 系统与 ReAct 循环(Q11-Q25)
- 记忆系统(Q26-Q35)
- 技能系统(Q36-Q45)
- 工具系统(Q46-Q50)
- 频道系统(Q51-Q58)
- Cron 与 Heartbeat(Q59-Q66)
- 多 Agent 与 ACP(Q67-Q74)
- 安全体系(Q75-Q81)
- App 与 Console(Q82-Q88)
- 配置系统(Q89-Q93)
- CLI 与命令(Q94-Q97)
- 开放题(Q98-Q100)
1. 架构与整体设计
Q1. QwenPaw 的入口文件是哪个?描述从 python -m qwenpaw 到启动服务的完整链路。
答案:
入口是 __main__.py,它会调用 cli/main.py 中的 cli()。cli() 是一个 Click 命令组,支持 app、init、chat、cron 等子命令。启动服务的命令是 qwenpaw app,它通过 _app.py 创建 FastAPI 实例,在 lifespan 中初始化 MultiAgentManager 并启动监听端口。
__main__.py → cli/main.py cli() → app_cmd → _app.py (FastAPI lifespan)
→ MultiAgentManager → 各 Workspace 延时启动
Q2. constant.py 中的 _get_env 函数相比直接用 os.environ.get 多了什么能力?
答案:
提供 COPAW_ 前缀向后兼容。当查询的 key 以 QWENPAW_ 开头且找不到时,自动尝试同名的 COPAW_ 变体(如 QWENPAW_WORKING_DIR → COPAW_WORKING_DIR)。这是为了从旧版本 CoPaw 平滑迁移。
Q3. QwenPaw 的工作目录结构是怎样的?config.json 和 agent.json 有何区别?
答案:
默认工作目录是 ~/.qwenpaw。
config.json:全局配置(模型提供商、Agent 列表、全局设置)workspaces/{id}/agent.json:各 Agent 独立配置(频道、工具、心跳、安全)
~/.qwenpaw/
├── config.json ← 全局
├── workspaces/default/
│ ├── agent.json ← Agent 独立配置
│ ├── AGENTS.md / SOUL.md / PROFILE.md / MEMORY.md
│ ├── skills/ & skill.json
│ └── memory/
└── skill_pool/
配置优先级:agent.json > config.json。
Q4. WORKING_DIR 的解析优先级顺序是什么?
答案:
- 环境变量
QWENPAW_WORKING_DIR(或遗留COPAW_WORKING_DIR) - 目录
~/.copaw存在 → 兼容老版本 - 默认 →
~/.qwenpaw
Q5. QwenPaw 如何实现配置热加载?
答案:
通过 agent_config_watcher.py 启动后台异步任务,每 2 秒检测 agent.json 的修改时间。变化后自动重新加载并应用到运行时,无需重启服务。
Q6. 描述 QwenPawAgent 的 MRO 及其意义。
答案:
QwenPawAgent → CodingModeMixin → ToolGuardMixin → ReActAgent
每个 mixin 重写 _acting 并调用 super()。_acting(...) 保持链条完整。CodingModeMixin 负责内联 diff 编辑,ToolGuardMixin 负责工具鉴权拦截。
Q7. DynamicMultiAgentRunner 是做什么的?为什么需要它?
答案:
它是一个动态路由器,代理 AgentScope 的 AgentApp。AgentScope 原生只支持单工作区,而 QwenPaw 通过 DynamicMultiAgentRunner 检查 HTTP 头 X-Agent-Id,将请求动态路由到正确的 Workspace Runner,实现单服务多 Agent。
Q8. QwenPaw 如何确保跨平台 MIME 类型正确?
答案:
在 _app.py 中 mimetypes.init() 后显式 add_type 注册 .js、.mjs、.css、.wasm、.svg 等类型,避免 Windows 因缺少映射导致前端资源加载失败。
Q9. RULE.md 文件在 QwenPaw 中的用途是什么?
答案:
RULE.md 是可选的人设文件,存储硬性不可违背规则。如果存在,它会被加载到系统提示词中,优先级高于 AGENTS.md 和 SOUL.md。
Q10. PromptBuilder 类在处理人设文件时做了哪些处理?
答案:
- 读取文件内容(多编码回退)
- 去除 YAML frontmatter(
---...---) - 去除心跳标记块(
<!-- heartbeat:start-->...<!-- heartbeat:end-->) - 去除记忆标记块(
<!-- memory:start-->...<!-- memory:end-->) - 拼接为系统提示词
- 可选追加记忆管理器的记忆提示
2. Agent 系统与 ReAct 循环
Q11. QwenPawAgent 的 reply 方法执行流程是怎样的?
答案:
- 检查是否为系统命令(
/compact、/new等),是则直接处理 - 调用
reply_memory从历史加载上下文 - 执行 ReAct 循环(
_acting):模型推理 → 生成工具调用 → 执行工具 → 获得结果 - 达到
max_iters或模型返回最终回答后结束 - 调用记忆管理器总结并存储
- 返回最终回复
Q12. max_iters 的作用和默认值是什么?
答案:
控制 ReAct 循环的最大轮数。每轮 Agent 可以调用工具或生成回复。默认 50(running.max_iters)。超限时强制结束,返回已有内容。
Q13. CommandHandler 支持哪些系统命令?/plan 有什么特殊之处?
答案:
支持:compact, new, clear, history, compact_str, summarize_status, message, dump_history, load_history, proactive, plan
/plan 的特殊性:裸 /plan(无参数)是系统命令;/plan 开发天气应用(带参数)会传给 Runner 启用 Plan Mode,不走系统命令流程。
Q14. 描述 Agent 对话结束时的记忆总结流程。
答案:
如果 summarize_when_compact 启用,Agent 完成 reply 后:
- 调用
memory_manager.summarize()提取关键信息 - 生成摘要并写入
MEMORY.md - 下次对话时摘要被加载到系统提示词
Q15. CodingModeMixin 实现了什么功能?
答案:
实现内联差异编辑(Inline Diff)。Agent 在编写代码时,对于短文件可以直接在回复中展示 diff,减少 write_file/edit_file 工具调用次数。
Q16. reply_memory 与普通 reply 的区别是什么?
答案:
reply_memory 负责组装对话历史和记忆:将用户消息加入上下文,调用上下文管理器和记忆管理器封装完整消息列表。普通 reply 完成整个处理流程(思考→工具→回复)。
Q17. ToolGuardMixin 在工具调用链中扮演什么角色?
答案:
在工具执行前拦截,检查安全性:
- 根据
approval_level(STRICT/SMART/AUTO/OFF)决定策略 - 对 shell 命令检测注入攻击模式
- 可阻止执行、请求审批或自动放行
Q18. Agent 如何处理多模态消息(图片、视频)?
答案:
- 通过
get_capability_cache检查模型是否支持多模态 - 支持 → 将媒体内容传给 LLM
- 不支持 → 用占位符
[Media content removed - model does not support this media type]替换
Q19. HEARTBEAT.md 中 <!-- heartbeat:start--> 标记的作用是什么?
答案:
PromptBuilder 用正则匹配此标记块。心跳启用时保留;禁用时删除,避免 Agent 误认为自己有定时任务能力。
Q20. auto_continue_on_text_only 解决了什么问题?
答案:
当模型只返回文本而未调用工具时,Agent 自动重试最多两轮,迫使模型重新思考并正确调用需要的工具。
Q21. chat_with_agent 和 submit_to_agent 的区别是什么?
答案:
chat_with_agent(前台):同步等待目标 Agent 完成并返回结果submit_to_agent(后台):异步提交,立即返回 task_id,通过check_agent_task查询状态
Q22. Agent 中工具注册的机制和 NamesakeStrategy 是什么?
答案:
工具注册在 QwenPawAgent.__init__ 中完成:
- 导入内置工具函数
- 动态加载已启用的技能工具
- 调用
register_tool()注册 - 同名冲突策略(
NamesakeStrategy):override / skip / raise(默认)/ rename
Q23. ASMsgHandler 的作用是什么?
答案:
消息处理器,负责:
- AgentScope Runtime 消息格式 ↔ 内部消息格式的转换
- SSE 流式推送
- 工具调用中间结果展示
- 审批流程交互
Q24. /compact 命令内部做了什么?
答案:
- 读取当前对话历史
- 对历史进行摘要总结(保留关键信息)
- 压缩后的摘要替换原始长历史
- 释放上下文窗口空间
- 返回压缩前后的 token 数对比
Q25. _MemoryMark 的作用是什么?
答案:
AgentScope 的标记机制,在消息流中标记来自记忆而非本次对话的内容。带 _MemoryMark 的消息进入系统提示词,但不参与常规对话历史管理。
3. 记忆系统
Q26. QwenPaw 有几种记忆管理器?默认是哪个?
答案:
- ReMeLightMemoryManager(默认)— 轻量级,语义搜索 + 自动总结
- ADBPGMemoryManager — 基于阿里云 ADB PG 数据库
- AgentMdManager — 基于 MEMORY.md 文件
- BaseMemoryManager — 抽象基类
Q27. ReMeLightMemoryManager 的核心工作机制是什么?
答案:
- 写入:对话结束后调用 LLM 总结关键信息写入
MEMORY.md - 检索:对话前用 Embedding 语义搜索
MEMORY.md - 自动搜索:启用后每轮自动检索
- 压缩:超过阈值时压缩旧记忆(近期保留详细,远期摘要)
Q28. Embedding 缓存如何工作?
答案:
embedding_cache 目录缓存文本-向量对:
- 计算文本的 Embedding 向量
- 写入本地缓存文件
- 下次相同文本直接返回缓存
max_cache_size控制最大条目(默认 3000)
Q29. 什么是「梦境」记忆优化(Dream)?何时运行?
答案:
梦境(Dream)是记忆优化机制,默认每天 23:00(0 23 * * *)运行。从 MEMORY.md 和每日记忆中提取关键信息,交叉关联、去重、优化结构和表达后写回,类似人类睡眠记忆巩固。
Q30. auto_memory_interval 的作用是什么?
答案:
每隔 N 次用户查询触发一次自动记忆存储。例如 5 表示每 5 次用户消息后自动触发一次记忆总结。null 表示禁用(仅在上下文压缩时总结)。
Q31. memory_search 工具的 Query 参数有哪些?
答案:
memory_search 对 MEMORY.md 和 memory/*.md 做语义搜索。参数:
query(必填):搜索文本max_results(默认 5):最大结果数min_score(默认 0.1):最低相似度阈值
Q32. memory/YYYY-MM-DD.md 与 MEMORY.md 的关系?
答案:
memory/YYYY-MM-DD.md:原始日志,每天一个文件,记录当天对话事件MEMORY.md:精选长期记忆,是对每日记忆的提炼总结
关系:每日记忆 → 提炼 → MEMORY.md,再加梦境优化
Q33. Proactive(主动触发)功能的机制是什么?
答案:
Proactive 位于 agents/memory/proactive/:
- 每个会话独立维护
ProactiveConfig(启用状态、空闲阈值、最后交互时间) - 后台
_run_trigger_loop异步循环监控空闲时间 - 超时后
generate_proactive_response生成主动消息 - 每个会话对应一个
asyncio.Task
Q34. memory_manager_backend 和 context_manager_backend 的区别?
答案:
memory_manager_backend(默认remelight):管理跨会话的长期记忆context_manager_backend(默认light):管理当前会话的上下文(对话历史、组织、压缩、修剪)
长期记忆 vs 短期工作上下文。
Q35. compact_threshold_ratio 和 reserve_threshold_ratio 是什么?
答案:
compact_threshold_ratio(默认 0.8):当上下文占用超过max_input_length的 80% 时触发压缩reserve_threshold_ratio(默认 0.1):压缩时保留最后 10% 的原始内容
4. 技能系统
Q36. 一个 Skill 的本质是什么?必须包含什么文件?
答案:
每个 Skill 是一个目录,必须包含 SKILL.md。SKILL.md 用 Markdown 描述技能名称(name)、触发条件(description)和操作步骤。可附带 scripts/、images/ 等资源。
Q37. resolve_effective_skills 做了什么?
答案:
- 读取
skill.json确定已启用技能 - 从工作区
skills/和skill_pool/中找到这些技能 - 读取
SKILL.md注入系统提示词 - 注册技能定义的工具函数
Q38. 技能池(Skill Pool)和技能集(Skills)的区别?
答案:
- 技能池(
skill_pool/):全局共享,所有 Agent 可引用 - 技能集(
workspaces/{id}/skills/):Agent 专属
池 → 广播/加载 → 集。
Q39. materialize_skill 工具做了什么事?
答案:
将技能提案持久化到工作区:
- 格式验证和安全扫描
- 写入
SKILL.md - 更新
skill.json清单 - 启用该技能
常用于 /make-skill 命令流程。
Q40. ensure_skills_initialized 的职责是什么?
答案:
确保技能系统正确初始化:
- 检查
skills/目录(不存在则创建) - 验证
skill.json有效性 - 复制内置技能
- 返回初始化后的配置
Q41. 如何从 Skills Hub 导入技能?
答案:
Console 的 Workspace → Skills 页面点击 Import from Skills Hub,输入技能 URL,系统下载并自动启用。也支持上传 .zip 技能包。
Q42. 技能如何实现 Config 运行时注入?
答案:
通过 apply_skill_config_env_overrides:
- 技能声明需要的环境变量
- 系统从
envs.json读取对应值 - 注入到子进程环境(API Key、Base URL 等)
Q43. 两个已启用的技能定义同名工具怎么办?
答案:
NamesakeStrategy 决定处理方式:
override:后注册覆盖先注册skip:跳过同名rename:自动重命名raise(默认):报错
Q44. skill.json 的结构?
答案:
{
"skills": {
"guidance": { "enabled": true, "builtin": true },
"pdf": { "enabled": true, "builtin": true },
"my_custom": { "enabled": true, "builtin": false }
}
}
Q45. Skill 的 description 为什么重要?
答案:
description 是 Agent 决定使用技能的关键。Agent 在系统提示词中查看所有已启用技能的描述,当遇到匹配场景时按照 SKILL.md 的步骤操作。格式惯例:"Use this skill when [触发场景]"。
5. 工具系统
Q46. 内置工具定义在哪里?列举 10 个。
答案:
定义在 agents/tools/ 目录下。例如:
read_file(file_io)、write_file / edit_file(file_io)、execute_shell_command(shell)、browser_use(browser_control)、desktop_screenshot、grep_search / glob_search(file_search)、get_current_time、get_token_usage、chat_with_agent / submit_to_agent / check_agent_task(delegate_external_agent)、list_agents、materialize_skill、send_file_to_user、view_image / view_video、set_user_timezone。
Q47. browser_use 支持哪些浏览器启动模式?
答案:
三种:
- Headless(默认):无头运行
- Headed:打开真实窗口
- Managed CDP:通过 Chrome DevTools Protocol 管理,支持外部连接
由 headed、private_mode、cdp_port 参数控制。
Q48. execute_shell_command 的超时机制?
答案:
- 默认超时来自
agent.json的shell_command_timeout(默认 60 秒) - 每次调用可通过
timeout参数覆盖 - 超时后子进程被终止,返回超时错误
Q49. 文件守卫(File Guard)的工作原理?
答案:
文件守卫在 Agent 访问文件时:
- 检查路径是否在允许范围
- 检查是否访问敏感路径(
~/.ssh/、/etc/passwd等) - 判定危险则阻止操作
由 security.file_guard.enabled 控制。
Q50. get_token_usage 的数据来源和存储位置?
答案:
数据来自 AgentScope Runtime 的 LLM token 使用统计。保存在 workspaces/{id}/token_usage.json(可通过 QWENPAW_TOKEN_USAGE_FILE 自定义),按模型和日期分类。
6. 频道系统
Q51. QwenPaw 支持哪些频道?核心抽象是什么?
答案:
支持:Console、DingTalk、Feishu、Discord、Telegram、QQ、iMessage、WeChat、WeCom、XiaoYi、Matrix、Mattermost、MQTT、Voice、SIP。
核心抽象:app/channels/base.py 的 BaseChannel 基类 + ChannelType 枚举。所有频道继承 BaseChannel 实现收发逻辑。
Q52. 描述消息通道的流水线。
答案:
- 用户发送消息 → 触发
BaseChannel接收 - 封装为
AgentRequest→ 进入UnifiedQueueManager - 队列分发到 Workspace Runner
- Runner 调用 Agent → 生成
AgentResponse - 响应通过 SSE 流推回原频道
MessageRenderer格式化输出
Q53. UnifiedQueueManager 的作用?
答案:
统一消息队列管理器:
- 接收多频道的消息请求
- 有序/优先级分发到 Agent Runner
- 支持背压(back-pressure)和限流
- 保证消息处理顺序和可靠性
Q54. Console 频道和外部频道的实现区别?
答案:
Console 内置,通过 WebSocket/SSE 直连前端。外部频道需要:
- SDK/API 建立连接
- 注册 Webhook 或回调
- 实现消息格式转换
- 处理频道特有特性(卡片消息、交互组件等)
Q55. DEFAULT_CHANNEL 的值和用途?
答案:
值为 "console"。当没有特定频道上下文时(如心跳、Cron),系统使用默认频道发送消息。
Q56. access_control 模块做什么?
答案:
实现频道的访问控制:
- 用户 ID 白/黑名单
- 启用/禁用控制
- 消息频率限制
- 权限级别
Q57. MessageRenderer 的作用?
答案:
将内部消息格式渲染为各频道可展示的格式。支持多种 RenderStyle(Markdown、纯文本、富文本),处理工具调用结果、错误信息、流式输出等。
Q58. doctor_connectivity_notes 的用途?
答案:
BaseChannel 的类方法,用于频道连通性诊断。copaw doctor --deep 调用已启用频道的此方法,返回网络连接状态的自检信息。
7. Cron 与 Heartbeat
Q59. Cron 系统的后台调度器是什么?支持哪些触发器?
答案:
使用 APScheduler 的 AsyncIOScheduler。支持:
- IntervalTrigger:固定间隔(如每 5 分钟)
- CronTrigger:5 字段 Cron 表达式
- DateTrigger:指定时间单次执行
Q60. Cron 任务的调度类型和任务类型有哪些?
答案:
调度类型:Interval(间隔)、Cron(表达式)、RunAt(指定时间)
任务类型:Text(固定文本)、Agent(Agent 生成回复)
Q61. Heartbeat 与 Cron 的关系和区别?
答案:
关系:Heartbeat 是特殊的 Cron 任务(job_id 固定为 _heartbeat),由 CronManager 管理。
区别:
- 查询内容来自
HEARTBEAT.md - 支持活跃时段设置
- 结果可推送到 Inbox / Last / Main
Q62. Cron 执行失败的容错机制?
答案:
max_concurrency:限制同一任务并发数timeout:单次超时misfire_grace_time:错过触发宽限期- APScheduler 自动重试
- 执行记录保存于
CronExecutionRecord
Q63. is_cron_expression 如何区分 Cron 和间隔表达式?
答案:
- 分割为部分,不是 5 部分则返回 False
- 每部分匹配
^[\d\*\-/,]+$→ True - 否则 False。间隔表达式如
30m、1h由parse_heartbeat_every解析。
Q64. _heartbeat 作为 job_id 的特殊性?
答案:
_heartbeat 是系统保留 job_id,用于 Heartbeat。普通任务不能使用此 ID。Heartbeat 配置来自 agent.json 的 heartbeat 块,而非 jobs.json。
Q65. Heartbeat target 参数的取值?
答案:
main:主会话执行并推送last:推送到最近一次用户消息来源频道inbox:推送到 Inbox 管理中心
Q66. CronExecutor 的工作流程?
答案:
- 获取待执行 job
- 检查并发/超时限制
- Text 类型:直接发消息;Agent 类型:构造
AgentRequest提交 Runner - Runner 调用 Agent 处理
- 记录执行历史
- 推送到目标频道
8. 多 Agent 与 ACP
Q67. MultiAgentManager 如何实现懒加载?
答案:
使用 asyncio.Lock():
- 首次
get_agent(id)检查字典,不在内存则创建 - 加锁后再次确认(防竞态)
- 第一个调用者创建,其他等待者等 Event 通知
- 锁短暂保持(仅字典操作),不阻塞 WorkSpace 慢启动
Q68. Workspace 类封装了哪些运行时组件?
答案:
- Runner(AgentRunner):处理 Agent 请求
- ChannelManager:管理通信频道
- MemoryManager:管理对话记忆
- ContextManager:管理上下文
- MCPClientManager:管理 MCP 客户端
- CronManager:管理定时任务
- TaskTracker:跟踪任务状态
Q69. ACP(Agent Communication Protocol)的用途是什么?
答案:
ACP 是 Agent 间通信协议,位于 agents/acp/。允许不同 Agent 实例通过标准化协议互相发现和通信,支持:
- Client:发送请求到其他 Agent
- Server:接收并处理来自其他 Agent 的请求
- Service:注册和发现 Agent 服务
- Permissions:访问控制
- ToolAdapter:将远程 Agent 映射为本地工具
Q70. ACP Server 和 Client 的核心功能?
答案:
- Server(902 行):监听请求,解析 ACP 协议消息,路由到目标 Agent,返回结果
- Client(466 行):构造 ACP 请求,发送到目标 Agent,处理响应
- 两者通过
core.py定义的协议消息格式通信
Q71. ToolAdapter 在 ACP 中的作用?
答案:
ToolAdapter(241 行)将远程 Agent 的 ACP 服务映射为本地 Agent 的一个工具。这样当前 Agent 可以像调用本地工具一样调用远程 Agent 的能力,实现了跨 Agent 工具编排。
Q72. agent_id 在 HTTP 请求中如何传递?
答案:
通过 HTTP 头 X-Agent-Id。AgentContextMiddleware 从中提取当前请求的目标 Agent,然后 DynamicMultiAgentRunner 根据此 ID 路由到正确的 Workspace。
Q73. 配置文件(agent.json)中的 description 字段在多 Agent 协作中的作用?
答案:
description 在多 Agent 协作时描述各 Agent 的角色和能力。其他 Agent 通过查看此描述来决定委派什么任务给该 Agent。它是一个「自我介绍」。
Q74. 内置 QA Agent 的作用和 skill 配置?
答案:
内置的 QwenPaw_QA_Agent_0.2(QA Agent)用于回答关于 QwenPaw 自身的问题。默认技能:guidance + QA_source_index。首次创建时自动配置。
9. 安全体系
Q75. QwenPaw 的三层安全防护是什么?
答案:
- ToolGuard(工具守卫):运行时检测危险命令和注入
- FileGuard(文件守卫):保护敏感文件访问
- SkillScanner(技能扫描器):启用前扫描恶意代码
Q76. approval_level 有哪些取值?分别代表什么?
答案:
- STRICT:所有敏感操作都需要用户明确批准
- SMART:智能判断,低风险自动放行,高风险请求审批
- AUTO:完全自动,仅记录日志
- OFF:不进行安全检查
Q77. ToolGuard 检测哪些 shell 注入模式?
答案:
command_substitution:命令替换($(...)或`...`)obfuscated_flags:混淆参数backslash_escaped_whitespace:反斜杠转义空格backslash_escaped_operators:反斜杠转义操作符newlines:换行注入comment_quote_desync:注释/引号反同步quoted_newline:引号内换行
Q78. 技能扫描器(SkillScanner)在什么时机运行?
答案:
在技能启用时运行(materialize_skill 或 Console 启用技能时)。扫描模式:
block:发现恶意代码阻止启用warn:警告但允许(默认)off:不扫描
Q79. 认证功能如何启用?默认是否启用?
答案:
通过环境变量 QWENPAW_AUTH_ENABLED=true 启用,默认 false(不启用)。用户名和密码可通过 QWENPAW_AUTH_USERNAME/QWENPAW_AUTH_PASSWORD 设置。启用后 Web Console 需要登录才能访问。
Q80. allow_no_auth_hosts 的用途?
答案:
IP 白名单,默认 ["127.0.0.1", "::1"],允许 localhost 绕过 Web 登录认证。可以配置更多受信任的 IP。
Q81. 审批超时和心跳间隔的默认值?
答案:
- 审批超时:
TOOL_GUARD_APPROVAL_TIMEOUT_SECONDS,默认 300 秒 - 审批心跳间隔:
TOOL_GUARD_APPROVAL_HEARTBEAT_INTERVAL,默认 15 秒(保持 SSE 连接存活)
10. App 与 Console
Q82. FastAPI 应用(_app.py)的 lifespan 中做了什么?
答案:
- 加载环境变量(
load_envs_into_environ) - 加载配置
- 执行数据迁移(工作区、技能池、QA Agent)
- 恢复/清理备份工件
- 初始化
MultiAgentManager - 注册频道路由
- 注册认证中间件
- 启动心跳和梦境任务
- 按配置启动频道
Q83. Console 的 Files 页面支持哪些文件操作?
答案:
- 在线编辑人设文件(AGENTS.md、SOUL.md、PROFILE.md 等)
- 查看/编辑每日记忆(MEMORY.md 展开按钮)
- 下载整个工作空间(.zip)
- 上传恢复工作空间(.zip,最大 100MB)
Q84. Inbox 的用途是什么?
答案:
Inbox 是统一审批和执行结果中心:
- 审批待处理:工具执行的审批请求
- 推送消息:Cron/Heartbeat 的执行结果
- 超时机制:审批请求有倒计时,超时默认拒绝
Q85. 如何 Console 查看 Token 用量?
答案:
侧边栏 Settings → Token Usage,选择日期范围(默认 30 天),页面展示总 token 数、总调用数和按模型/日期分类的明细。也可在聊天中问「我用了多少 token」。
Q86. 环境变量页面(Environments)可以做什么?
答案:
管理工具和技能所需的运行时环境变量(如 TAVILY_API_KEY)。支持增删改、批量删除。变量值由用户保证有效性,QwenPaw 只负责存储和注入。
Q87. Console 的 Skills 页面有哪些操作?
答案:
启用/禁用、查看详情、编辑、创建、删除技能。从技能池加载、同步到技能池、从 Skills Hub 导入、上传 zip 技能包。
Q88. 多 Agent 模式下 Console 顶部有什么特殊组件?
答案:
一个 Agent 切换器,显示当前活跃的 Agent。点击可切换到其他已配置的 Agent。切换后侧边栏和控制台内容(频道、工具、配置等)自动切换到该 Agent 的设置。
11. 配置系统
Q89. 全局 config.json 中的 agents.profiles 结构是怎样的?
答案:
{
"agents": {
"active_agent": "default",
"profiles": {
"default": {
"id": "default",
"name": "默认智能体",
"description": "默认工作区智能体",
"enabled": true,
"workspace_dir": "~/.qwenpaw/workspaces/default"
}
}
}
}
每个 Agent 配置引用包含 id、name、description、enabled、workspace_dir。
Q90. agent.json 中部份关键配置项的作用?
答案:
| 配置 | 说明 |
|---|---|
language |
Agent 语言(zh/en/ru) |
system_prompt_files |
人设文件列表 |
active_model |
使用的模型(provider_id + model) |
running.max_iters |
ReAct 最大轮数 |
running.shell_command_timeout |
shell 命令默认超时 |
channels |
频道配置 |
mcp.clients |
MCP 客户端 |
heartbeat |
心跳配置 |
tools.builtin_tools |
工具开关 |
security |
安全策略 |
Q91. 模型提供商配置存在哪里?有哪些内置提供商?
答案:
存储在 ~/.qwenpaw.secret/providers.json(通过 QWENPAW_SECRET_DIR 自定义)。内置提供商包括:DashScope、OpenAI、Anthropic、DeepSeek、ModelScope、Ollama、LM Studio、SiliconFlow、Zhipu、Kimi、Gemini、OpenRouter 等,以及 Custom(自定义兼容)。
Q92. 环境变量的存储位置和加载时机?
答案:
存储在 ~/.qwenpaw.secret/envs.json。加载时机:
- 首次
import qwenpaw时(__init__.py→load_envs_into_environ()) - FastAPI lifespan 开始时再次加载
Q93. last_dispatch 配置项的作用?
答案:
记录了最近一次用户消息分发到的频道、用户 ID 和会话 ID。用于 Heartbeat 的 target="last" 模式——心跳结果会被发送到上次用户说话的频道。自动更新,无需手动配置。
12. CLI 与命令
Q94. Click CLI 中的 LazyGroup 解决了什么问题?
答案:
LazyGroup 是 click.Group 的子类,实现了子命令的懒加载。cli/main.py 中用 lazy_subcommands 字典将命令名映射到模块路径,只有用到时才 __import__ 加载。这大大缩短了 qwenpaw --help 的启动时间——不需要加载所有 30+ 个子命令的依赖。
Q95. CLI 中 app 命令的 _log_init_timings 是做什么的?
答案:
在设置好日志级别(debug)后重新输出 CLI 模块加载阶段的计时信息。因为模块加载发生在 setup_logger 之前,第一次导入时如果日志级别还不是 debug,那些 debug 消息会被丢弃。app_cmd 在完成日志初始化后调用 log_init_timings() 重新输出,确保调试信息不丢失。
Q96. CLI 如何确保 Windows 下能正确处理中文输出?
答案:
在 cli/main.py 开头:
- 调用
ensure_standard_streams()确保标准流对象有效 - 尝试
sys.stdout.reconfigure(encoding="utf-8")(Python 3.7+) - Linux 默认 UTF-8 无需处理
这样 cron 和其他命令在 Windows 终端也能输出中文。
Q97. qwenpaw init 命令的交互式向导提供哪些配置?
答案:
qwenpaw init 交互式配置:
- 模型提供商选择和 API Key 配置
- 工作目录选择
- 频道配置(可选)
- 环境变量配置(
TAVILY_API_KEY等) - 创建默认工作区和人设文件
13. 记忆加固与梦境
Q98. QwenPaw 的备份系统是如何工作的?
答案:
位于 app/routers/backup.py,提供:
- 手动备份:通过 API 或 CLI 触发,将整个工作空间打包
- 自动备份:配置定时备份策略
- 恢复:从备份文件恢复工作空间
- 备份存储在
QWENPAW_BACKUP_DIR(默认~/.qwenpaw.backups/)
14. 开放题
Q99. 如果你要扩展 QwenPaw 支持一个新的消息频道(如 Slack),你需要做哪些事?
答案:
- 在
app/channels/下创建slack/目录 - 继承
BaseChannel实现SlackChannel类:- 设置
channel = ChannelType.SLACK(或新增枚举值) - 实现消息接收(Webhook/WebSocket)
- 实现消息发送(SDK API 调用)
- 实现消息格式转换
- 可选重写
doctor_connectivity_notes做连通性检查
- 设置
- 在
agent.json的channels中增加 Slack 配置块 - 在
registry.py中注册新频道 - 在
schema.py添加ChannelType枚举值
Q100. 假设现在 QwenPaw 需要支持在多个 Agent 之间共享一个 MEMORY.md,你会如何设计?
答案:
设计思路:
方案一:中心化记忆共享
- 在
skill_pool/级别或全局配置新增shared_memory.md - 所有 Agent 的
ReMeLightMemoryManager在搜索时同时检索各自的MEMORY.md+shared_memory.md - 写入时,Agent 判断信息是否跨 Agent 相关,写入共享文件
方案二:ACP 式记忆查询
- 新增一个「记忆管家」Agent,专门管理共享记忆
- 其他 Agent 通过
chat_with_agent或 ACP 协议向它查询/写入共享信息 - 记忆管家负责冲突解决和去重
方案三:记忆路由层
- 在
BaseMemoryManager下层新增SharedMemoryRouter - 每个 Agent 的写入先经过 Router,判断是否广播到其他 Agent
- 读取时自动合并个人记忆 + 共享记忆的搜索结果
三种方案从简单到复杂,取决于一致性要求和性能需求。
🎯 全部 100 题到此结束!
小微出品,祝你面试顺利~ 🚀
评论区