auto-sync: 2026-04-02 08:55:06

This commit is contained in:
cfdaily
2026-04-02 08:55:07 +08:00
parent 64fa4b08b0
commit f2fe17a075
626 changed files with 6877 additions and 102 deletions
@@ -0,0 +1,53 @@
# TASK-20260401-a2a-multiagent-research - A2A/多代理方案调研
## 任务背景
总军师诸葛亮交办:调研市面主流A2A/多代理方案,分析哪个能完美适配我们的需求:
> **需求:** "所有 A2A 消息都进入目标 agent 的 main 会话,避免业务会话爆炸"
我们当前的架构:
- 每个agent有一个固定的 **main 会话**(如 `agent:zhaoyun-data:main`
- 所有A2A消息都应该路由到这个固定的main会话
- 避免每次消息都创建新的临时会话,导致会话爆炸
- 保持对话连续性,main会话可以接收排队的任务
## 调研目标
挨个精读以下方案的文档和代码:
1. Network-AI(多代理协调层)
2. ClawTeam(团队协作 A2A
3. OpenAkita(轻量 A2A 执行框架)
4. 之前调研过的其他 A2A 方案(openclaw-a2a-gateway
## 调研维度
每个方案从以下维度分析:
| 维度 | 说明 |
|------|------|
| **会话模型** | 是否支持固定main会话/还是每次新建会话 |
| **路由机制** | 消息路由到固定agent主会话还是动态新建 |
| **会话爆炸风险** | 是否容易产生大量闲置临时会话 |
| **适配我们需求** | 是否能直接适配"所有消息进main会话" |
| **代码复杂度** | 集成难度 |
| **结论** | 是否推荐 |
## 预期输出
- 每个方案单独分析报告
- 总体对比表格
- 推荐方案结论
- 集成建议
## 负责人
赵云 子龙(数据护军)
## 进度
- [ ] 调研 Network-AI
- [ ] 调研 ClawTeam
- [ ] 调研 OpenAkita
- [ ] 调研其他方案
- [ ] 对比分析
- [ ] 最终结论
@@ -0,0 +1,262 @@
# A2A/多代理方案调研报告:"所有A2A消息进入目标agent的main会话"
## 任务背景
**需求:** 在三国量化团队架构中,我们需要一个A2A/多代理方案满足:
> "所有 A2A 消息都进入目标 agent 的 main 会话,避免业务会话爆炸"
具体来说:
- 每个agent有一个固定的**main会话**(如 `agent:zhaoyun-data:main`
- 所有A2A消息都应该路由到这个固定的main会话
- 避免每次消息都创建新的临时会话,导致会话爆炸
- 保持对话连续性,main会话可以接收排队的任务
## 调研对象
| # | 方案 | 说明 |
|---|------|------|
| 1 | **Network-AI** | 多代理协调层,带共享黑板和并发控制 |
| 2 | **ClawTeam** | 团队协作A2A,专为OpenClaw设计 |
| 3 | **OpenAkita** | 轻量A2A执行框架,成熟开源 |
| 4 | **openclaw-a2a-gateway** | 我们已经修复的方案 |
---
## 逐个方案分析
### 1️⃣ Network-AI(多代理协调层)
**项目地址:** https://github.com/jovanSAPFIONEER/Network-AI
#### 架构概述
Network-AI 是一个**多代理协调层**,核心特点:
- 提供 `LockedBlackboard` 共享状态,原子提交防止竞态条件
- `SwarmOrchestrator` 协调多个代理并行工作
- 内置质量检查、权限控制、预算管理
- 支持14+种AI框架适配器(含OpenClaw
#### 会话模型分析
| 维度 | 分析 |
|------|------|
| **会话模型** | 每个agent一个固定身份,支持有状态会话 |
| **路由机制** | AdapterRegistry按agentId路由,支持复用现有会话 |
| **会话爆炸风险** | 低 — 协调层不主动新建会话,由下层处理 |
| **适配我们需求** | ⚠️ 可以适配,但较重 |
| **代码复杂度** | 中等,架构清晰 |
**关键发现:**
- Network-AI 本身是协调层,**不负责sessionId的生成和复用**
- 它提供 `OpenClawAdapter`,会调用下层 `callSkill`
- session管理还是由OpenClaw处理
- Network-AI 最大价值在**并发控制和共享状态**,对我们"固定main会话"需求帮助不大
#### 适配结论
Network-AI 不冲突,但它解决的是**并发协调问题**,不是**会话路由问题**。我们的问题在A2A网关层,不是协调层。
---
### 2️⃣ ClawTeam(团队协作 A2A
**项目地址:** https://github.com/win4r/ClawTeam-OpenClaw
#### 架构概述
ClawTeam 是专为 OpenClaw 设计的**团队多代理协作框架**:
- 支持团队自组织,任务拆分委派
- 文件系统持久化存储会话状态
- 支持多种后端(subprocess/tmux
- 专为OpenClaw优化
#### 会话模型分析
| 维度 |分析 |
|------|------|
| **会话模型** | ✅ **每个agent持久化保存sessionId,支持复用** |
| **路由机制** | `SessionStore``(team_name, agent_name)` 保存sessionId |
| **会话爆炸风险** | ✅ 极低 — 同一个agent复用同一个session |
| **适配我们需求** | ✅ **完美适配!** |
| **代码复杂度** | 低,Python实现,简洁清晰 |
**关键代码:`clawteam/spawn/sessions.py`**
```python
class SessionStore:
"""File-based session store.
Each agent's session is stored at:
``{data_dir}/sessions/{team}/{agent}.json``
"""
def save(agent_name, session_id, ...): ...
def load(agent_name) -> SessionState | None: ...
```
**设计非常符合我们需求:**
- 每个agent(如赵云)的sessionId**持久化保存**
- 下次发送A2A消息时**直接加载复用**,不会新建
- 完全满足"所有消息进同一个main会话"
#### 适配结论
**ClawTeam 原生设计就符合我们需求!** 它本身就是为"团队固定agent + 持续协作"设计的,session持久化复用是内置功能。
---
### 3️⃣ OpenAkita(轻量 A2A 执行框架)
**项目地址:** https://github.com/openakita/openakita
#### 架构概述
OpenAkita 是一个成熟开源的**AI助手框架**,内置完整的多代理支持:
- `SessionManager` 统一管理所有会话
-`(channel, chat_id, user_id)` 索引会话
- 完整的持久化和生命周期管理
- 支持过期清理
#### 会话模型分析
| 维度 |分析 |
|------|------|
| **会话模型** | ✅ **完全按key复用会话** |
| **路由机制** | `get_session()` 先查缓存,存在就复用,不存在才新建 |
| **会话爆炸风险** | ✅ 极低 — 相同key永远复用同一个会话 |
| **适配我们需求** | ✅ **完美适配!** |
| **代码复杂度** | 中等,TypeScript架构清晰 |
**核心代码 `src/openakita/sessions/manager.py`**
```python
def get_session(channel, chat_id, user_id):
session_key = f"{channel}:{chat_id}:{user_id}"
# ✅ 先检查缓存,存在就复用
if session_key in self._sessions:
session = self._sessions[session_key]
session.touch()
return session
# ❌ 只有不存在才新建
if create_if_missing:
session = self._create_session(...)
self._sessions[session_key] = session
return session
```
**这个设计完全就是我们需要的!**
- 相同 `(channel, agentId, ...)` → 同一个session
- 不新建,只复用
- 完全避免会话爆炸
#### 适配结论
**OpenAkita 原生完美满足我们需求!** 它的会话管理设计从第一天就是"相同key复用会话",完全符合我们需求。
---
### 4️⃣ openclaw-a2a-gateway(我们已修复)
**项目地址:** https://github.com/win4r/openclaw-a2a-gateway
#### 架构概述
专为OpenClaw设计的A2A网关,让OpenClaw agents可以互相发消息。
#### 问题背景
**原问题:** 每次对话都会产生一个新session
**根因:**`client.ts/doSendMessage()` 中,发送消息时:
- ✅ 每次正确生成新 `messageId`
-**没有传递已有的 `contextId`**
- 所以A2A SDK每次都会生成一个新的 `contextId = uuidv4()`
- 导致每次新建session
#### 修复方案
我们已经找到并修复了问题:在 `outboundMessage` 添加一行:
```typescript
const outboundMessage: any = {
kind: "message",
messageId: (message.messageId as string) || uuidv4(),
contextId: (message.contextId as string) || uuidv4(), // ✅ 添加这行
role: ...,
parts: ...,
};
```
**修复效果:**
- 如果调用方提供 `contextId` → 复用它
- 如果没有提供 → 新建
- 完全符合需求
**第三次测试验证:** ✅ 已经通过!消息正确进入赵云main会话,不新建session。
#### 适配结论
**已经修复,完全满足我们需求!** 修复后工作正常,就是我们现在正在使用的方案。
---
## 对比总结表
| 方案 | 会话模型 | 是否支持固定main会话 | 是否避免会话爆炸 | 适配我们需求 | 复杂度 | 推荐度 |
|------|----------|----------------------|------------------|--------------|--------|--------|
| **Network-AI** | 协调层,不管理session | ⚠️ 可以适配,但不直接解决 | ✅ 低风险 | ⚠️ 间接适配 | 中 | ⭐⭐⭐ |
| **ClawTeam** | 每个agent持久化保存sessionId | ✅ 原生支持 | ✅ 完全避免 | ✅ 完美适配 | 低 | ⭐⭐⭐⭐⭐ |
| **OpenAkita** | 按key索引,存在就复用 | ✅ 原生支持 | ✅ 完全避免 | ✅ 完美适配 | 中 | ⭐⭐⭐⭐⭐ |
| **openclaw-a2a-gateway (fixed)** | contextId复用 | ✅ 修复后支持 | ✅ 完全避免 | ✅ 完美适配 | 低 | ⭐⭐⭐⭐⭐ |
---
## 结论与推荐
### 推荐方案优先级
| 优先级 | 方案 | 理由 |
|--------|------|------|
| 1️⃣ | **openclaw-a2a-gateway (已修复)** | 我们已经在使用,修复验证完成,工作正常,最贴合OpenClaw原生架构 |
| 2️⃣ | **ClawTeam** | 专为OpenClaw团队协作设计,session持久化复用原生支持,非常轻量 |
| 3️⃣ | **OpenAkita** | 开源成熟,设计完美,如果需要更完整的框架可以选 |
| 4️⃣ | **Network-AI** | 如果需要并发协调和共享黑板才需要,否则不需要额外层 |
### 当前最佳选择
**推荐继续使用 `openclaw-a2a-gateway` 修复后的版本**
理由:
1. **已经修复并验证** — 第三次测试通过,工作正常
2. **最贴合OpenClaw** — 专为OpenClaw A2A网关设计
3. **轻量无侵入** — 只做A2A路由,不改变现有架构
4. **完全满足需求** — 修复后正确复用contextId,不会新建session,避免会话爆炸
5. **我们已经在生产使用** — 赵云主会话就是例子,工作正常
### 如果需要更完整的团队协作
如果未来需要更完整的**多代理团队协作功能**,推荐:
- **ClawTeam** — 专为OpenClaw设计,原生支持session复用,轻量简洁
- **OpenAkita** — 如果需要全功能AI助手框架,会话管理设计完美
---
## 已完成工作
- [x] Network-AI 文档代码精读 ✓
- [x] ClawTeam 文档代码精读 ✓
- [x] OpenAkita 文档代码精读 ✓
- [x] openclaw-a2a-gateway 回顾 ✓
- [x] 对比分析 ✓
- [x] 推荐结论 ✓
---
## 负责人
**赵云 子龙** 数据护军 🐎⚔️📊
**调研完成时间:** 2026-04-01
@@ -0,0 +1,12 @@
import akshare as ak
import pandas as pd
df = ak.stock_zh_index_daily(symbol="sh000300")
print("📊 DataFrame info:")
print(df.info())
print("\n📋 First 5 rows:")
print(df.head())
print("\n🔍 Index type:", type(df.index))
print("🔍 First index value:", df.index[0], type(df.index[0]))
print("\n🔍 Last 5 index values:")
print(df.tail().index)
@@ -0,0 +1,94 @@
"""
ZYJ-20260401-001 - edict集成测试任务
获取沪深300指数(000300.SH)最近5个交易日收盘价
计算每日涨跌幅和5日平均收盘价
"""
import akshare as ak
import pandas as pd
from datetime import datetime
# 获取沪深300指数历史数据
print("🚀 开始获取沪深300指数(000300.SH)数据...")
# 用akshare获取
df = ak.stock_zh_index_daily(symbol="sh000300")
# 将date列转为datetime并设置为索引
df['date'] = pd.to_datetime(df['date'])
df = df.set_index('date')
# 获取最近5个交易日
df_last5 = df.tail(5).copy()
# 计算每日涨跌幅
df_last5['pct_change'] = df_last5['close'].pct_change() * 100
# 计算5日平均收盘价
avg_close_5d = df_last5['close'].mean()
# 格式化输出
print("\n📊 沪深300指数最近5个交易日数据:")
print("=" * 80)
print(f"{'日期':<12} {'收盘价':>12} {'涨跌幅(%)':>10}")
print("-" * 80)
result_data = []
for idx, row in df_last5.iterrows():
date_str = idx.strftime("%Y-%m-%d")
close = float(row['close'])
pct = float(row['pct_change']) if not pd.isna(row['pct_change']) else None
pct_str = f"{pct:.2f}" if pct is not None else "-"
print(f"{date_str:<12} {close:>12.2f} {pct_str:>10}")
result_data.append({
'date': date_str,
'close': close,
'pct_change': pct
})
print("-" * 80)
print(f"{'5日平均收盘价':<12} {avg_close_5d:>12.2f}")
print("=" * 80)
# 分析趋势
last_close = result_data[-1]['close']
first_close = result_data[0]['close']
total_change = (last_close - first_close) / first_close * 100
print(f"\n📈 趋势分析:")
print(f"- 起始日期: {result_data[0]['date']}")
print(f"- 起始收盘价: {first_close:.2f}")
print(f"- 最新日期: {result_data[-1]['date']}")
print(f"- 最新收盘价: {last_close:.2f}")
print(f"- 5日累计涨跌幅: {total_change:.2f}%")
if total_change > 1:
trend = "明显上行趋势"
elif total_change < -1:
trend = "明显下行趋势"
else:
trend = "横盘震荡整理"
print(f"- 趋势判断: {trend}")
# 保存结果到文件
output_file = "/Users/chufeng/.openclaw/sanguo_projects/sanguo_quant_live/zhaoyun-data/research/task-20260401-edict-test/result.csv"
df_save = pd.DataFrame(result_data)
df_save.to_csv(output_file, index=False)
print(f"\n💾 结果已保存到: {output_file}")
# 输出json格式结果
result_json = {
'task_id': 'ZYJ-20260401-001',
'symbol': '000300.SH',
'name': '沪深300指数',
'data': result_data,
'avg_close_5d': round(avg_close_5d, 2),
'total_change_pct': round(total_change, 2),
'trend': trend,
'generated_at': datetime.now().isoformat()
}
print("\n📋 JSON结果:")
import json
print(json.dumps(result_json, indent=2, ensure_ascii=False))
@@ -0,0 +1,6 @@
date,close,pct_change
2026-03-25,4537.466,
2026-03-26,4477.534,-1.320825324090602
2026-03-27,4502.57,0.5591470662199338
2026-03-30,4491.95,-0.2358652947094586
2026-03-31,4450.049,-0.9328020124890091
1 date close pct_change
2 2026-03-25 4537.466
3 2026-03-26 4477.534 -1.320825324090602
4 2026-03-27 4502.57 0.5591470662199338
5 2026-03-30 4491.95 -0.2358652947094586
6 2026-03-31 4450.049 -0.9328020124890091