跳到主要内容

AgentScope — 架构与原理

30 秒导读: AgentScope 2.0 是一个 Python agent 框架。你给它一个模型、一个系统提示、一组工具,它就在一个**「想一步、做一步、看结果、再想」的循环**(reasoning-acting,也叫 ReAct)里跑,直到模型不再要求调工具、给出最终答复。它最有特色的三件事:(1) 不返回一坨文本,而是流式吐出一串细粒度事件(文字开始/增量/结束、工具调用、工具结果……),前端可以边收边渲染;(2) 工具能不能执行,由一个和循环解耦的权限引擎说了算,支持「探索只读」「自动接受改动」「绕过」等模式;(3) 循环的每个关键节点都能被洋葱中间件拦截,不改源码就能加日志、限预算、做 RAG。


1. 这是什么(零基础也能懂)

一句话定义。 AgentScope 是一个把「只会续写文本的大模型」包装成「能在循环里调工具、感知结果、并能被安全运营」的 Python 程序的框架。

解决什么问题 / 给谁用。 假设你想做一个能帮你改代码、查资料、跑命令的 AI 助手。模型本身只能输出文字,它说「我要运行 ls」并不会真的去运行。你需要一层程序来:把模型这句话解析成一次真实的工具调用、执行它、把结果喂回模型、让它接着想下一步——而且执行危险命令前最好能先问问你。AgentScope 就是这层程序,面向要把 agent 真正部署上线的开发者(它自带多租户、多会话的 FastAPI 服务层)。

它能做什么。

  • 跑一个 reasoning-acting 循环(默认最多 20 轮),自动处理「模型要调工具 → 执行 → 回喂」的往返。
  • 把整个过程拆成流式事件推给调用方(做前端、做人机交互、做 UI 都靠它)。
  • 用一个权限引擎在每次工具执行前判定:放行 / 拒绝 / 问用户。
  • 支持 human-in-the-loop:某个工具要用户点头时,循环能干净地暂停、把控制权交出去,等用户答复了再无缝续上。
  • 上下文快满时自动压缩旧对话成摘要,超长工具结果截断并 offload 到文件。
  • 多家模型(DashScope/Qwen、Anthropic、OpenAI、Gemini、DeepSeek、Moonshot、xAI、Ollama)+ 故障时回退到备用模型

用起来什么样。 最小例子(摘自 README.md):

from agentscope.agent import Agent
from agentscope.tool import Toolkit, Bash, Read, Write
from agentscope.model import DashScopeChatModel
from agentscope.message import UserMsg
from agentscope.event import EventType

agent = Agent(
name="Friday",
system_prompt="You're a helpful assistant named Friday.",
model=DashScopeChatModel(credential=..., model="qwen3.6-plus"),
toolkit=Toolkit(tools=[Bash(), Read(), Write()]),
)

# 不是 await agent.reply() 拿一段文本,而是 async-for 收一串事件
async for evt in agent.reply_stream(UserMsg("Tony", "Hi, Friday!")):
match evt.type:
case EventType.TEXT_BLOCK_DELTA:
print(evt.delta, end="") # 模型吐字,边收边打印
case EventType.TOOL_RESULT_END:
... # 一次工具执行收尾

一句话直觉/类比。 把 AgentScope 想成一个带安检的工厂流水线:模型是「设计师」,不停画图纸(要调哪个工具);流水线把图纸送去车间(工具)加工,但每件图纸进车间前都要过安检闸机(权限引擎);整条线上每个工位旁都装了摄像头直播(事件流),你在控制室能实时看到每一步;闸机拦下危险件时,流水线会停下来等你拍板(human-in-the-loop),你点头后它从停的地方继续,不用重启整条线。


2. 顶层全景(它大概怎么转)

2.1 主要部件

部件干什么在哪
Agent中枢:跑 reasoning-acting 循环,把一切串起来agent/_agent.py
Toolkit注册/分组/执行工具(含 MCP、技能),把工具结果流式化tool/_toolkit.py
PermissionEngine每次工具执行前判定 allow/deny/ask,和循环解耦permission/_engine.py
AgentEvent(一族事件类)框架的「输出协议」:start/delta/end 流式事件event/_event.py
MiddlewareBase洋葱钩子:在 reply/reasoning/acting/model_call/system_prompt 处拦截middleware/_base.py
ChatModelBase模型抽象:统一各家 LLM 的调用、重试、token 计数model/_base.py
AgentState可存可读的状态:对话上下文、摘要、权限上下文、工具缓存state/_state.py
Offloader把压缩掉的上下文 / 超长工具结果落到工作区文件workspace/_offload_protocol.py
Msg / 各种 Block消息与内容块(文本/思考/工具调用/工具结果/数据)message/_base.pymessage/_block.py

2.2 主线走一遍(高层,不进代码)

输入 Msg


┌──────────────────────── Agent.reply_stream ────────────────────────┐
│ │
│ while 迭代数 < max_iters: │
│ │
│ ┌── reasoning ──┐ ┌──────── acting ────────┐ │
│ │ 调模型,流式 │ 有工具 │ 把工具调用分批 │ │
│ │ 吐 text/think/ │ ───────▶│ (顺序 or 并发) │ │
│ │ tool_call 事件 │ 调用? │ 每个: 权限闸 → 执行 │ │
│ └──────┬────────┘ └───────────┬────────────┘ │
│ │ 没有工具调用 │ 工具结果回喂上下文 │
│ ▼ │ │
│ 给出最终 AssistantMsg ──► return └──► 回到 while 顶部继续想 │
│ │
└─────────────────────────────────────────────────────────────────────┘


事件流(给前端) + 最终 Msg(给程序)

怎么读这张图:reasoning 和 acting 交替。每轮先 reasoning(调模型);模型若要求调工具就进 acting(执行工具、把结果写回上下文),然后回到循环顶继续 reasoning;模型若不再要工具,就产出最终消息退出。每一步都在往外流式吐事件

这条主线的细节(分批、并发、暂停续跑、最大迭代兜底)在 01-reasoning-acting-loop.md

2.3 一个关键设计:_xxx / _xxx_impl 的中间件夹层

读源码会发现一个反复出现的模式:每个核心方法都有一对 _reply/_reply_impl_reasoning/_reasoning_impl_acting/_acting_impl外层(无 _impl)只负责把中间件像洋葱一样套上去,内层(_impl)才是真逻辑。 没有注册对应中间件时直接走 _impl,零开销。这个夹层是 AgentScope「不改源码就能扩展」的承重墙,详见 04-middleware-context-deepdive.md


3. 阅读地图(建议顺序)

  1. 01-reasoning-acting-loop.md — 先把主线吃透:一次 reply 到底怎么走,reasoning 和 acting 怎么决定下一步,工具调用怎么分批并发,human-in-the-loop 怎么暂停。这是理解一切的地基。
  2. 02-event-stream-protocol.md — 再看框架的「输出长什么样」:为什么是事件流不是文本,start/delta/end 三段式,block_id 怎么把流式碎片重组成块。做前端/UI 必读。
  3. 03-permission-and-hitl.md — 安全这一支:权限引擎 5 种模式各自的判定顺序、工具自检、bypass-immune 安全门,以及工具调用的状态机怎么支撑暂停续跑。
  4. 04-middleware-context-deepdive.md — 深入:洋葱中间件的实现、上下文压缩与 offload 的省 token 技巧、巧妙之处、边界、横向对比、代码地图。

4. 一分钟记住 AgentScope 的「精华」

  • 循环 = reasoning ↔ acting 的状态机,不是写死的步骤。 下一步做什么由「上一条消息里有没有未完成的工具调用、它们处于什么状态」推导出来(_check_next_action),而不是 if-else 流水账。
  • 输出是协议化的事件流,不是返回值。 这让「边生成边渲染」「人机交互暂停」「多端订阅」天然成立。
  • 权限和循环解耦。 PermissionEngine 是独立模块,工具自己也能 check_permissions,两者按模式组合——安全策略可以独立演进。
  • 扩展靠洋葱中间件,不靠改源码。 5 个钩子点把横切关注点(日志/预算/RAG/tracing)织进循环。
  • 省 token 是一等公民。 上下文压缩 + 工具结果截断 + offload 到文件,都内建在循环里。