lili 2e5d0345df spike(agentscope-wg1): W-G1 三闸门验证——AgentScope 2.0.1 实测 verdict=继续
- 闸门①分布式 PASS(带 caveat):RedisMessageBus 跨 2 进程 3 agent 协作实测跑通;
  1.x RpcAgent/to_dist 已删,framework 原生多 worker serving 仍 Beta(#1722/#1868,取证未亲测)
- 闸门②持久化 PASS:AgentState→Redis,os._exit 与真 kill -9 两种硬崩后新进程恢复、记忆 3/3 无损
- 闸门③L1 开销 PASS:最小 Agent vs 裸 openai 本地+24.4ms/输入+11tok(几乎全 system_prompt),§5-⑤ 未被迫触发
- §5 无换轨触发器成立 → 继续 AgentScope,锁 2.0.1
- durable:VERDICT.md(含 §2 控制面↔worker 契约形状)+ artifacts 实测数据
- 关键坑:本机代理未旁路 Tailscale 网关致 SDK 全 502(_common 已修)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 20:37:03 -07:00

15 KiB
Raw Blame History

W-G1 spike · AgentScope 2.x 落地三闸门验证 · VERDICT

任务源:docs/agent-specs/2026-06-12-agentic基建框架选型-review.md(HJ-AGI-001,终选 A=AgentScope 2.x)。 本 spike = §5 换轨闸门的亲验门:分布式 / 持久化 / L1 开销,任一验不过即触发换轨。 执行:2026-06-13 · 本机 Apple M1 Pro 32GB · Python 3.12.13 · agentscope==2.0.1(锁版本)。 所有结论严格区分 【实测】(本机跑出)/ 【取证】(读 2.0.1 源码或 GitHub,高置信二手)/ 【推断】。


0. 结论速览(结论先行)

建议:继续 AgentScope 2.x,不触发换轨切 LangGraph。 三道闸门均通过其可测量门槛:

闸门 判定 一句话证据
①分布式 PASS(带重要 caveat) 3 个 agent 跨 2 个独立 OS 进程经 RedisMessageBus 协作产出一致产物(pid 56350/56351 实证跨进程)
②持久化/恢复 PASS AgentState→Redis,经 os._exit 与真 kill -9 两种硬崩后,全新进程恢复 8 条上下文、记忆 3/3 复述无损
③L1 退化开销 PASS(§5-⑤ 未被迫触发) 最小 Agent 相对裸 openai:本地封装开销中位 +24.4ms/次、输入 token +11/次(几乎全是 system_prompt,框架固有 token 税≈0)

最重要的一条判定(必须如实传达):AgentScope 2.0 的「分布式」与 1.x 完全不同——RpcAgent/to_dist() 进程级 actor 已整段删除。 2.0 跨进程靠 RedisMessageBus(Redis Streams 队列/pub-sub/锁)这套原语;原语本身实测可用(闸门①过),但框架并不提供开箱即用的「分布式 agent 运行时」——多 worker 编排要你自己写(我就是手写 worker 循环+队列接力把闸门①跑通的)。而官方那条「整机 serving 多 worker」路径(create_app FastAPI + 多 uvicorn worker + Agent Team)目前是 Beta、维护者自承单进程不可横向扩展(#1722),且有今日新开的多实例重复执行 bug(#1868)——这条我未亲测(只读到 issue,属【取证】),但它意味着 L3 多 agent 开发组若要真·多机多 worker,现在还不成熟,须盯版本。

为何仍判「继续」而非「换轨」:① §5 触发器④是「分布式/持久化验不过即切 B」——而本机实测两者都跑通了(分布式原语可用、持久化恢复无损),故④不成立;② §5-A 的风险敞口逻辑成立:L3 尚在数月之外、AgentScope 有半年+稳定窗、退出成本本来就低(普通 Python+状态字典+我们这套薄 worker 编排,换 LangGraph 只改 worker 内部);③ 三闸门的可测量门槛都过了。风险有界、可继续,但把「框架原生分布式 serving 成熟度」列为头号盯防项 + 锁版本盯 changelog。


1. 三闸门逐条(实测证据 + 复现命令)

闸门① 分布式 —— PASS(带 caveat)

方法:用 2.0 真实跨进程原语 agentscope.app.message_bus.RedisMessageBus(Redis Streams),把 3 个 agent 拆到 2 个独立 OS worker 进程,经本地 Redis 接力协作产出一个「游戏点子」产物。拓扑:Coordinator ─seed→[q_plan]→ W1:Planner →[q_design]→ W2:Designer →[q_name]→ W1:Namer →[q_done]→ Coordinator(job 流经 W1→W2→W1 两进程往返)。

【实测】证据(artifacts/gate1_distributed.json):

  • 3 个独立进程:W1 pid=56350、W2 pid=56351、Coordinator pid=56353。
  • 跨进程铁证:design_pid(56351) ≠ plan_pid(56350)(Designer 确在另一进程),plan_pid==name_pid(Planner/Namer 同进程)。
  • 协作产物自洽、层层叠加:concept=「猫咪经营小烘焙坊的休闲挂机游戏」→ mechanic=「顾客带来新配方,猫咪用心爱点心交换解锁」→ title=「Feline Bakes」。

复现:

export NEWAPI_KEY=<your-key>           # 见 README;密钥不入库
redis-server --port 6399 --daemonize yes --dir .redis-data --save "" --appendonly no
.venv/bin/python src/gate1_distributed.py worker W1 &   # 进程1:Planner+Namer
.venv/bin/python src/gate1_distributed.py worker W2 &   # 进程2:Designer
.venv/bin/python src/gate1_distributed.py coordinator   # 播种+收口+判定

关键坑/形态:

  • 【取证】1.x 分布式 API 整段删除:grep 安装源码,to_dist/RpcAgent/AgentServer/launch_server/rpc_meta 零命中;无 agentscope[distribute] extra;无 MsgHub/SequentialPipeline。别移植任何 1.x 分布式代码,导入即炸。
  • 【实测】跨进程要 agentscope[service,storage](FastAPI+redis),非 base。RedisMessageBus 是 async 上下文管理器(async with ... as bus),_client 在 __aenter__ 才建,直接调方法报 NoneType。
  • 【实测】queue_drain 是 xrange+xdel 两步、非原子:单队列单消费者安全(本 demo 即如此);若多 worker 抢同一队列需自加锁,否则可能重复消费。
  • 【取证·未亲测】官方整机多 worker 路径不成熟:维护者 issue #1722 自承 agent service 单进程、SessionManager 等需改 DB 后端才能横向扩展;#1868(2026-06-13 新开) 多实例共享一 Redis 时,一次 wake-up 会让同一 session 跑 N 次(重复执行)。→ 这是 L3 的头号盯防项,正式上多机前必须复测/等修复。

判定逻辑:「≥2 worker 进程 + 2~3 agent 协作」本机实测跑通 → 闸门①PASS,§5-④ 不触发。但「PASS」是靠原语自拼,不是框架原生 turnkey;framework 原生 serving 多 worker 仍 Beta/有 bug,作为 caveat 写死。

闸门② 持久化/恢复 —— PASS

方法:2.0.1 真实机制(已读源码验证)= agent.state(AgentState pydantic:含 context 对话历史、cur_iter 等)→ model_dump_json() 落 Redis;恢复 = Redis 读回 → AgentState.model_validate_json() → Agent(..., state=loaded) 续跑。等价于 app 层 RedisStorage(SessionRecord 内嵌 AgentState)的「每轮落盘」,但剥掉 FastAPI 整机使证据最小可审计。

【实测】证据(artifacts/gate2_persist.json),两种硬崩模式都过:

  • 场景A(os._exit 硬退出):进程A 注入 3 条记忆、逐轮落 Redis(快照 2257B→3100B),os._exit(137) 无清理硬崩;全新进程B 仅靠 Redis 恢复,复述 3/3(Alice/Zephyr/dark)。
  • 场景B(真 kill -9):worker(pid 56223)落盘 3 轮后阻塞,外部 kill -9 真 SIGKILL;全新进程恢复 8 条上下文(含 reasoning 块),复述 3/3 无损。
  • per-turn 边界佐证:故意只落 2 轮即崩,恢复后正确复述前 2 条、并正确回答「无 UI 偏好记录」——证明崩溃前已落盘的轮无损、未落盘的轮干净丢失(正是 per-turn checkpoint 应有语义)。

复现:

.venv/bin/python src/gate2_persist.py run1 --crash-after 3   # 注入+落盘+os._exit 硬崩
.venv/bin/python src/gate2_persist.py run2                   # 新进程恢复,判 PASS/FAIL
# 真 kill -9 版:python src/gate2_persist.py block & ; kill -9 <pid> ; python src/gate2_persist.py run2

关键坑:

  • 【取证】无 StateModule/register_state/state_dict/SessionBase——那是 1.x / AgentScope-Java 命名;§4 表述用了旧名,2.0.1 实物是 AgentState+RedisStorage。
  • 【取证】恢复是 per-turn,非字节级:turn 跑到一半被杀,该 turn 从上轮快照重跑,半成品不保;工具对工作区的副作用(写文件)不回滚——工具须设计成可重入/幂等(与我们 §2 验证门子进程 CLI 形态相容)。
  • 【取证·未亲测】开 context 压缩时 issue #1624:RedisMemory._compressed_summary 只在内存、不写 Redis → 重启丢失;短任务不触发,长会话须留意。

闸门③ L1 退化开销 —— PASS(§5-⑤ 未被迫触发)

方法:同一最小 LLM 调用,三路对照,各 N=20(warmup=3),模型 deepseek-v4-flash(L1 目标)。用 usage.time(框架自报 API 耗时)从 wall 中剔除网络耗时,净测框架本地 CPU 开销;并比对输入 token 膨胀。

【实测】数据(artifacts/gate3_overhead.json,中位数):

路径 wall 中位 本地开销中位 输入 token 输出 token
A 裸 openai SDK(§3 裸路) 0.934s 0(基准) 18 28.5
B AgentScope 模型客户端 0.920s 22.2ms 18 28
C AgentScope 最小 Agent 0.936s 24.4ms 29 27.5
  • 关键差值(Agent vs 裸路):输入 token +11/次、本地封装开销 +24.4ms/次、Agent 单次 reply 内部模型调用 恰 1 次(空 toolkit 不发散)。
  • 解读:+11 token 几乎全是 system_prompt(裸路没发 system,Agent 强制注入)——框架固有 token 税≈0~2;若 L1 裸路也带等量结构化指令,token 差会归零。+24.4ms 是事件对象/pydantic/count_tokens 的纯 CPU,占 ~930ms 单次调用的 ~2.6%,不构成「吃掉单价」。
  • 结论:框架不对 L1 施加致命开销 → §5-⑤ 不被迫触发。但 §3「L1 走裸通路」的预设依然正确并被本测佐证:裸路更简单、且省掉这 24ms×海量调用,L1 维持 §3 旁路不变(注意:这是 L1 旁路决策的实证,不等于 AgentScope 出局;L2/L3 仍用框架原语)。

复现:.venv/bin/python src/gate3_overhead.py(WG1_N=20)。


2. §5 换轨触发器逐条评估

触发器 是否触发 依据
④ A 路 spike 分布式/持久化验不过→切 B 否 分布式原语【实测】跑通、持久化恢复【实测】无损,两者均过门
⑤ 任何框架 L1 开销吃掉单价 → L1 退 §3 裸路 未被迫触发(但 §3 裸路本就保留) 框架开销 +24ms/+11tok【实测】不致命;§3 旁路维持
①②③(许可收紧 / 自建 Server / 出生产案例) 不适用本 spike 属 LangGraph 侧或时间触发,非本门范围

净结论:无任一换轨触发器成立 → 继续 AgentScope。


3. §2 控制面↔worker 契约形状(durable 产物)

本 spike 实证了 §2-⑤「框架躲在 worker 进程内、Java 控制面零感知、换轨零改动」的可成立性:三闸门里 AgentScope 全部活在 Python worker 进程内,对外只暴露「下发 job / 回调结果」这层稳定契约。建议契约最小形状(REST 下发 + 队列回调,二选一或并用):

# 下发(Java 控制面 → Python worker):POST /worker/jobs  或  入队 jobs:{tier}
{ "job_id":"uuid", "tier":"L1|L2|L3", "kind":"generate|design|review|...",
  "input":{...业务输入...}, "callback":{"type":"queue|http","target":"..."},
  "idempotency_key":"uuid", "deadline_ms":120000 }

# 回调(worker → 控制面):POST {callback}  或  入队 results:{job_id}
{ "job_id":"uuid", "status":"succeeded|failed|partial",
  "output":{...结构化产物 / 验证门 pass-fail JSON...},
  "usage":{"input_tokens":..,"output_tokens":..,"model":".."},
  "error":{"code":"..","retryable":true}, "worker":{"framework":"agentscope-2.0.1"} }

换轨零改动性:Java 侧只认上面两个 JSON;worker 内部把 AgentScope 换成 LangGraph,契约字节不变。worker.framework 字段仅作可观测标记。本 spike 的 gate1_distributed.py 已示范 worker 侧「队列接力 + 框架内编排」的形态,可直接抽象为该契约的 worker 实现骨架。


4. 关键坑总表(给主 agent / 创始人少踩半天)

  1. 【实测·最坑】本机代理吃掉所有 SDK 调用:本机 HTTP_PROXY/HTTPS_PROXY=127.0.0.1:7897(clash 类),NO_PROXY 未含 Tailscale 网关 → httpx/openai(含 AgentScope)默认 trust_env=True 把发往 100.64.0.8 的请求经代理转发 → 502;而 curl 只认小写 http_proxy 故直连成功,制造「curl 通、SDK 全挂」的假象,极易误判成「网关坏/框架坏」。修复:NO_PROXY 并入网关 host(src/_common.py 已内置)。网关本身一直健康。
  2. 【实测】new-api 网关对便宜模型有偶发 502 突发(数秒级 burst,代理坑排除后仍偶发):worker→模型出口必须带重试/超时/幂等(AgentScope max_retries 默认 3,实测自动重试生效)——印证 §2 对外部调用的容错要求。
  3. 【取证】2.0 是对仅几个月大的 1.x 的破坏式重写:ReActAgent 类没了(统一为 Agent);模型要 OpenAICredential 对象(base_url 在 credential 上,非 1.x 的 client_args);hooks→middleware;memory 独立模块、rag/evaluate/tts/realtime 被临时移除/降级。凭记忆/旧博客写 2.0 代码必炸,锁版本盯 changelog。
  4. 【实测】reasoning 模型(deepseek-v4-flash):小 max_tokens 会被 reasoning 烧光、content 空;MiniMax-M2 则直出内容。基准测试已用「净本地开销 + token 膨胀」绕开 reasoning 方差。
  5. 【取证·未亲测·须复检】影响本任务的 OPEN bug(GitHub agentscope-ai/agentscope,2026-06-13 快照):#1722 单进程不可横扩、#1868 多实例重复执行、#1860 流式零块时核心循环 None 崩、#1624 压缩摘要不落 Redis。正式上多机/长会话前请逐条复检是否已在 2.0.2+ 修复。

5. 早期采用者风险与版本锁(verdict 输入)

  • 【取证】版本时间线:v2.0.0=2026-05-25、v2.0.1=2026-06-05(今天起算 ~8 天);PyPI 分类仍是 Development Status :: 4 - Beta(README 却宣称 production-ready——信 Beta 分类);11 天内 ~25 个 PR,含破坏性改名,API 面高频抖动。
  • 【取证】仓库迁移:modelscope/agentscope → github.com/agentscope-ai/agentscope;文档用 docs.agentscope.io/v2(旧 doc.agentscope.io 是 1.0)。
  • 【实测】退出成本确低:我们这套 = 普通 Python + AgentState 字典 + 薄 worker 编排;换框架只动 worker 内部,§3 契约不变 → 印证 §5-A「风险敞口有界」。
  • 【实测】装配成本极低:uv pip install agentscope==2.0.1 解析 87 包 5.82s、装机 ~9s;+[service,storage] 5 包再 4s。

6. 给创始人 / 主 agent 的建议(可执行)

  1. 继续 AgentScope 2.x,锁死 2.0.1,建 changelog/issue 盯防清单(尤其 #1722/#1868)。
  2. L1 维持 §3 裸通路(本测佐证其更省更简),框架从 L2 起重度介入。
  3. L3 多机多 worker 暂缓押注:framework 原生 serving 多 worker 未成熟;若近期就要多机,先用本 spike 的 RedisMessageBus 自拼骨架(原语可用),或等 2.0.2+ 修 #1868 后复测。
  4. 把本 spike 的「代理旁路 / 容错重试 / worker 边界契约」沉淀进 .agents/,避免主弧再踩。
  5. 再评闸门(任一触即重审):#1868 等多 worker bug 半年内不修、或 2.0.x 持续破坏式抖动伤及我们 worker、或许可/生态出现 §5-①②③ 情形。

附:复现环境与版本(锁)

  • 机器:Apple M1 Pro 32GB · macOS 25.5 · Python 3.12.13 · uv 0.4.30。
  • 模型出口:new-api 网关 http://100.64.0.8:3000/v1(OpenAI 兼容,Tailscale),模型 deepseek-v4-flash(L1)。
  • 锁版本(requirements.lock 全量):agentscope==2.0.1 · openai==2.41.1 · redis==8.0.0(py)/ redis-server v8.8.0 · fastapi==0.136.3 · pydantic==2.13.4 · httpx==0.28.1。
  • 产物:artifacts/gate{1,2,3}_*.json(本机实测原始数据)。