数据截至 (上游 commit 38006dda2d96)
Agent 与模型:ReActAgent 之上的组装、prompt、provider
30 秒导读: 本章讲 QwenPaw 里"那个真正会思考、会调工具的 agent"到底是怎么拼出来的。核心一句话:
QwenPawAgent本体什么都不自己造——模型、系统 prompt、工具包、中间件全部由外部的AgentBuilder组装好、从构造函数塞进来;agent 类只负责在 agentscope 2.0 的ReActAgent之上,叠加几层 QwenPaw 特有的行为(coding mode、多模态降级、文本-only 自动续跑、上下文压缩接管)。往下是"模型接入层":一个统一的Provider抽象把 OpenAI/Anthropic/DashScope/Gemini 等各家 API 收成同一种ChatModelBase,再套上重试、限流、token 计量三层包装。
本章聚焦"agent 本体 + 模型接入"。上一层的运行时编排(谁在什么时候调 AgentBuilder)见 01-request-lifecycle.md;有哪些工具、skill→tool 的机制见 03-skills.md 与 04-channels-drivers-mcp.md;工具守卫与沙箱见 05-security.md。
1. 这是什么(零基础也能懂)
一句话定义
QwenPawAgent 是 QwenPaw 的主 agent 类:它继承 agentscope 2.0 的 Agent(即 ReAct 循环:推理 → 调工具 → 看结果 → 再推理),然后在外面包一圈"生产环境要的脏活"——模型不支持图片时怎么办、模型只回了一段文字没干活时要不要催它继续、上下文太长怎么压。
它解决什么问题
假设你要把"一个通用 LLM"变成"一个能在真实终端里连续干活好几十轮、还不崩"的助手。裸的 ReAct 循环干不了这些:
| 现实里会出的岔子 | QwenPawAgent 怎么兜 |
|---|---|
| 用户塞了张图,但当前模型是纯文本模型 | 调模型前先剥掉图片块,失败了再学一次"这模型拒收媒体" |
| 模型只回了句"好的我来规划一下"就停了,没调工具 | 注入一条 system-hint,让外层循环再转一轮(自动续跑) |
| 聊了几十轮,上下文超了模型窗口 | 交给上下文管理器压缩 / 把 老消息卸到磁盘 |
| 切换到另一个供应商,第一次调用必失败 | 用进程级"能力缓存"记住这个模型的怪癖 |
它的设计原则:自己不造零件
这是理解整章的钥匙。看构造函数签名(agents/react_agent.py:53 QwenPawAgent.__init__),几乎所有东西都是关键字入参:
# 示意,非源码 —— 说明"依赖全从外部注入"这个设计
agent = QwenPawAgent(
name=..., # 谁
model=..., # 已经包好重试/限流/计量的 ChatModelBase
system_prompt=..., # 已经拼好的整段文字
toolkit=..., # 已经装满工具的 Toolkit
react_config=..., # max_iters 等
middlewares=[...], # 洋葱圈中间件
... # offloader / context_manager / memory_manager / governor
)
模块 docstring 把话说死了:"Agent construction is fully delegated to AgentBuilder"(agents/react_agent.py:1-10)。谁来造这些零件?下一节的 AgentBuilder。
2. 顶层全景(它大概怎么转)
两个主角:装配工 vs 产品
QwenPaw 把"造 agent"和"agent 本体"拆成两个东西:
AgentBuilder(runtime/builder.py:23)——每次请求都跑一遍的装配工。它去各个注册表取零件、拼成一个完整 agent。QwenPawAgent(agents/react_agent.py:40)——被装出来的产品,只管跑 ReAct 循环 + 叠加行为。
一次装配的数据流
下图从上到下是 AgentBuilder.build()(runtime/builder.py:92)的真实顺序,命中即用:
AgentBuilder.build(ctx)
│
┌─────────────────────────┼─────────────────────────┐
▼ ▼ ▼
① 模型 + formatter ② 系统 prompt ③ 工具包 Toolkit
build_model() build_prompt() build_toolkit()
│ │ │
create_model_and_ PromptManager local_workspace
formatter() .build_sync() .list_tools()
│ (9 个 contributor + coding tools
Provider.get_chat_ 按 priority 拼) + driver/MCP tools
model_instance() + memory tools
│
套 3 层包装:
TokenRecording →
Retry → (router?)
│
└──────────────┬───────────────┬─────────────┘
▼
④ 中间件 middlewares(洋葱圈)
ToolCoordinator / Memory / ToolResultPruning / Langfuse
│
▼
QwenPawAgent(name, model, system_prompt,
toolkit, middlewares, ...) ← 全部注入
│
▼
agent.load_state_dict() ← 恢复历史会话