目录

MACC — 面向多智能体协作的低开销通信、状态传递与共享记忆机制

第三届中国研究生操作系统开源创新大赛暨开放原子大赛操作系统专项赛 赛道:应用创新 · 赛题 9(社区赛题)

MACC(Multi-Agent Collaboration Core)为多智能体协作提供系统层基础设施: 用结构化协议替代自然语言通信、用共享内存直接传递中间状态、用可检索记忆实现跨任务复用。

它不是又一个 Agent 编排框架。现有框架解决的是”如何组织 Agent”, MACC 往下一层,约束消息如何编码、状态如何传递、结果如何复用 —— 这三件事恰好都是操作系统层面的老问题:序列化开销、进程间数据搬运、缓存与复用。 我们把它们放回系统层解决,而不是继续堆在 prompt 里。

一句话事实 取值
核心运行时第三方依赖 0 个(纯 Python 标准库)
目标环境 openEuler 24.03-LTS-SP3(自带 Python 3.11,无需 pip)
代码规模 macc/ 18,743 行 · tests/ 14,547 行
测试用例 1,597 个,全部通过(另有 12 个需真实模型,默认不跑)
实测通信开销 线上字节 ↓80.01% · prompt token ↓100%
实测记忆复用 命中率 72.73% · 跳过重算 16 次 · 执行步数 ↓22.22%
许可 Apache License 2.0

目录:演示视频 · 30 秒跑起来 · 给评审的复核路径 · 三端形态 · 仓库结构导览 · 解决什么问题 · 相关工作与差异定位 · 系统架构 · 三套机制怎么工作 · Agent 桌面执行环境 · 命令清单 · 实验设计 · 完整实测数据 · 工程质量 · 赛题符合性对照 · 关键设计取舍 · 依赖 · 文档 · 常见问题 · 已知限制 · 原创性说明


演示视频

演示视频为一次完整演示的连续录制,分三段存放, 请按 1 → 2 → 3 的顺序连续观看(三段合计 14:41)。 文件已随仓库提交在根目录,可直接下载:

顺序 文件 时长 大小
上集 演示视频1.mp4 9:59 62 MB
中集 演示视频2.mp4 1:12 26 MB
下集 演示视频3.mp4 3:30 18 MB

备用下载(网盘):https://pan.baidu.com/s/16guTLfWgAfPnB2YIOHeqJw 提取码 t223

分段只是为了控制单文件体积,内容前后衔接、不可跳看 —— 后一段的操作建立在前一段已完成的状态之上(例如已安装的扩展、 已积累的会话与记忆、已产出的工作区文件)。

三段以桌面客户端实机运行为准,整体覆盖:多轮对话与会话管理、 长短期记忆与上下文压缩、多模态解析(PDF / 视频 / 图片 / 音频)、 工具调用、工作区文件读写与执行、Skills 与 Plugins 的安装管理及对话内调用、 三个子 Agent 分工协作,以及赛题三套机制(ACP / STX / SMEM)的验证视图。

三个文件均在赛事 100 MB/文件 的上限内,未使用 Git LFS。 其中视频 1 与视频 3 的原始录屏分别为 263 MB 与 77 MB,超过上限, 已用 tools/compress_video.py 压缩: 保持原 2560×1600 分辨率不缩放(屏幕录制需保证界面文字可读), 仅提高 CRF 与降低音频码率,抽样 SSIM 0.996,肉眼无差异。 视频 2 本身未超限,未做压缩。

演示脚本与逐步操作见 docs/09-demo-script.md。


30 秒跑起来

openEuler 24.03-LTS-SP3 自带 Python 3.11,无需安装任何第三方包:

python3 -m macc.cli desktop     # ① 桌面客户端 MACC Studio(推荐,图形界面)
python3 -m macc.cli agent-smoke # Agent 全栈冒烟(18 项,不需要网络)
python3 -m macc.cli doctor      # 环境自检
python3 -m macc.cli smoke       # 冒烟测试 → SMOKE OK
python3 -m macc.cli demo        # 六步演示(纯命令行)
python3 -m macc.cli bench       # 12 轮 A/B 实验 + 生成报告

桌面端需要 Tk 支持;openEuler 上一条命令即可:sudo dnf install -y python3-tkinter。 命令行部分不需要 Tk。

完成后打开 reports/latest/report.html 查看全部对比数据与图表。 一键复现全流程:sh scripts/run_all.sh

环境要求

项 要求 说明
操作系统 openEuler 24.03-LTS-SP3(主目标) 其他 Linux / Windows / macOS 亦可运行
Python ≥ 3.9 openEuler 24.03 自带 3.11,开箱可用
第三方包 不需要 可选增强见依赖一节,缺失自动降级
共享内存 /dev/shm 可写 容器内需 --shm-size=256m,否则 STX 降级
图形界面 Tk(仅桌面端需要) dnf install python3-tkinter
大模型凭据 可选 不配置时机制验证与全部实验照常可用

doctor 会把上面每一项逐条检查并打印结论,末行输出 DOCTOR OK。 它同时会真的调一次模型接口验证凭据连通性(离线环境可加 --no-llm-probe 跳过, 录屏或正式演示前建议加 --require-llm 强校验)。

配置大模型(可选)

复制 .env.example 为 .env,填入 OPENAI_BASE_URL / OPENAI_API_KEY / MACC_LLM_MODEL。任何 OpenAI 兼容端点均可。

优先级提醒:真实环境变量会覆盖 .env 中的同名项 —— 这是刻意设计, 但如果 shell 里残留一个失效的旧 key,就会出现”.env 明明填对了却一直 401”。 见常见问题第 1 条。


给评审的复核路径

本项目所有对外声明的数字都可以在本地当场复核,报告中没有任何手工填写的数值。 下表给出”主张 → 命令 → 预期输出”的一对一映射,全程离线、约 5 分钟:

我们的主张 复核命令 预期看到
环境与依赖声明为真 python -m macc.cli doctor 逐项检查 + 末行 DOCTOR OK
≥3 个 Agent、四类角色、DAG ≥5 步、零共享内存泄漏 python -m macc.cli smoke 14 项逐条 [PASS] + SMOKE OK (14/14 项通过)
Agent 侧七层能力齐备(会话/记忆/工具/编排/ACP) python -m macc.cli agent-smoke 18 项逐条 [OK] + AGENT SMOKE OK (18/18 项通过)
同一条消息在四种编码下的真实开销差异 python -m macc.cli demo 四种 codec 的字节/token 实测对照
通信 ↓80%、token ↓100%、步数 ↓22% python -m macc.cli bench --rounds 12 --seed 20260729 重新生成 reports/latest/,数字与本文一致
同种子结果完全可复现 上条命令跑两次,diff 两份 report.json 十项核心指标逐字节相同
记忆确实被检索到并被复用 python -m macc.cli memory search --query "账单科目错配" 命中条目 + matched_by 归因
1,597 个用例全绿 python -m pytest tests -q passed(live 标记的 12 个默认不跑)
文档与代码不脱节 python tools/check_docs.py DOCS OK(模块/命令/指标名/交付文件四类一致性)
仓库内无第三方项目源码 python tools/originality_check.py 无他方版权声明、无异种技术栈
材料不含可识别信息(匿名评审要求) python tools/anonymity_check.py ANONYMITY OK

一条命令跑完全部:sh scripts/run_all.sh,或 make verify。

我们也把不利数据留在了报告里。 例如协作层新增的记忆检索开销(约 0.8 ms/轮)、 端到端时延方向随平台变化、LoCoMo 上与 BM25 的差异未达统计显著 —— 这些都写在正文而不是脚注,理由见已知限制。


三端形态

形态 入口 定位
桌面客户端 python -m macc.desktop 主交付界面:交互式演示、评审现场、录屏
命令行 python -m macc.cli 自动化、脚本、CI、批量实验
可嵌入库 import macc 二次开发与集成

桌面端是一个完整的 Agent 桌面执行环境(对标 ChatGPT Desktop / Claude Desktop / Trae / 通义灵码 一类产品),同时保留赛题机制的验证视图。左侧导航共 12 个页面, 分成”Agent 能力”与”机制验证”两组:

分组 页面 作用
Agent 能力 对话 多轮对话、附件上传、工具调用轨迹、权限切换、扩展引用
工作区 文件树与预览、运行/编辑工作区文件、权限档位
子 Agent 五类角色编排,支持流水线 / 并行两种拓扑
Skills / 插件 粘贴 git 链接即检索安装、清单管理、卸载
共享记忆 三路混合检索现场演示与 matched_by 归因
机制验证 机制工作台 执行多步骤协作任务,观察调度与复用门控
协作时间线 Agent 间消息瀑布图
通信开销 同一消息四种 codec 的字节/token 对比
状态传递 共享内存零拷贝张量的发布/映射/校验
A/B 实验 双模式可复现对比与图表
CodeAct 沙箱 安全执行与 32 种逃逸手法的拦截演示
关于 赛题符合性自查表

Agent 侧七层架构齐备:多轮会话与 Session 管理、长短期记忆(含上下文压缩与跨会话引用)、 ReAct 推理行动循环、17 个工具(+记忆读写共 19)、工作区四档权限(默认 YOLO 完全放开,等价 Codex YOLO / Claude Code --dangerously-skip-permissions)、 多模态解析(PDF/Word/Excel/PPT/音视频/图片,带页码与时间点定位)、 Skills 与 Plugins、五类子 Agent 编排。 详见 docs/14-agent-desktop-guide.md。

关键设计:Agent 的长期记忆直接建在本项目 SMEM 之上;主/子 Agent 通信走 ACP 结构化协议(二进制、0 prompt token);代码执行走 CodeAct 沙箱 —— 赛题三套机制 在这里从”被展示”变成”被真实使用”。这一点值得强调:如果三套机制只是跑在评测脚本里, 它们的价值就只能靠数字说明;而当整个桌面端的记忆、通信、执行都压在它们身上时, “能用”本身就是一条证据。

运行截图见 docs/screenshots/(25 张:机制验证 16 张 + Agent 9 张, 均由脚本驱动真实窗口抓取并做内容去重校验 —— 有测试断言任意两张截图内容不得相同, 防止把过期画面当证据)。


仓库结构导览

project/
├── macc/                    ← 全部运行时代码(18,743 行,零第三方依赖)
│   ├── protocol/            ACP 结构化协议:schema 强校验 · 四种 codec ·
│   │                        能力描述 · 文本⇄结构映射 · 增量上下文
│   ├── state/               STX 状态传递:POSIX 共享内存总线 · TensorRef ·
│   │                        零拷贝视图 · CRC32 校验 · embedder
│   ├── memory/              SMEM 共享记忆:六类记忆单元 · BM25 倒排 ·
│   │                        标签索引 · 向量索引 · 混合检索 · 复用门控
│   ├── sandbox/             CodeAct 沙箱:AST 白名单 guard · 子进程 runner
│   ├── transport/           帧协议(长度+CRC)· 进程内队列 · UNIX socket · TCP
│   ├── runtime/             Registry 能力发现 · Broker 握手与计量 ·
│   │                        Scheduler DAG 调度 · Session 生命周期
│   ├── agents/              四类协作角色:planner / retriever / executor / summarizer
│   ├── engine/              推理引擎:deterministic(默认)· llm(OpenAI 兼容)
│   ├── eval/                指标采集 · 任务族 · A/B 实验台 · 报告与 SVG 图表
│   ├── agent/               Agent 桌面端后端:会话 · 记忆 · ReAct 循环 · 工具 ·
│   │                        多模态 · Skills/Plugins · 扩展安装器 · 子 Agent 编排
│   ├── desktop/             tkinter 桌面客户端(12 个页面 + 主题 + 截图脚本)
│   ├── app/                 服务层(桌面端与 CLI 共用)
│   └── cli.py               9 个子命令的命令行入口
├── tests/                   1,593 个用例(14,547 行)unit / integration / e2e
├── docs/                    16 份设计与交付文档 + 25 张运行截图
├── tools/                   lint · 文档一致性 · 匿名性 · 原创性 · 交付物生成
├── scripts/                 setup.sh · run_all.sh(一键复现)
├── reports/latest/          实验产物:report.json/md/html + 5 张 SVG 图表
├── skills/ plugins/         内置 3 个技能与 1 个示例插件
├── 项目说明书.pdf            提交材料(.docx 为源文件)
├── 原创承诺书.pdf            提交材料(.docx 为源文件)
├── 演示PPT.pptx              提交材料
└── 演示视频1~3.mp4           演示视频(串联,按序观看)

interface/ 为参考用的外部项目,不属于 MACC 运行时,未被本项目任何代码引用, 已在 tools/originality_check.py 的 ALLOWED 中登记并注明理由。


解决什么问题

赛题指出当前多 Agent 系统的三个痛点。MACC 针对每一个给出一套系统层机制:

痛点 传统做法 MACC 机制 实测效果
通信冗长、上下文重复、token 高 自然语言 / 大 JSON 全量透传 ACP 结构化协议:动作-参数-结果-能力四元语义单元 + 引用式载荷 + 增量上下文 + 二进制编码 线上字节 **↓80.01%**,prompt token ↓100%
中间结果在「内部状态→文本→内部状态」间反复转换 embedding 序列化进 prompt 再解析 STX 共享内存张量总线:数据写入 POSIX 共享内存,消息只带句柄 张量放大 1000 倍,消息大小差 <16 字节;跨进程零拷贝
中间知识难沉淀,相似任务从头再来 无记忆或仅对话历史 SMEM 共享记忆:统一记忆单元 + 三路混合检索 + 复用门控 命中率 **72.73%**,跳过重算 16 次,执行步数 ↓22.22%

(12 轮连续任务,种子 20260729,tiktoken 精确计量。24 轮时命中率升至 85.00%、执行步数 ↓27.78%)

为什么”少发 token”不等于”少办事”。 降开销最容易的做法是少传信息, 代价是答案变差 —— 那样的对比毫无意义。所以我们把”质量守恒”做成了断言: 端到端测试要求两种模式对同一任务产出的结论签名完全一致。 省下的 80% 字节和 100% token,没有以答案质量为代价换来。 这条断言在 tests/e2e/ 里,每次提交都会跑。


相关工作与差异定位

MACC 与现有工作并非只在单一算法指标上竞争,而是把控制面协议、数据/状态面载体、 知识面记忆复用统一进一个可在 openEuler 上执行和测量的运行时。相关工作的能力边界 与直接比较范围如下;完整论述、引用和实验口径见 technical supplement.pdf。

方向 代表工作 主要能力 与 MACC 的关系及差异
多 Agent 框架 AutoGen、CAMEL、MetaGPT、ChatDev Agent 抽象、角色分工、会话与工作流编排 解决“如何组织 Agent”;MACC 进一步约束“消息如何编码、状态如何传递、结果如何复用”,不声称替代这些框架
文本与拓扑压缩 LLMLingua-2、AgentPrune、AgentDropout 缩短单条文本或减少通信边 与固定消息图上的 ACP codec 优化正交;MACC 同时提供引用式载荷、增量上下文和二进制编码
latent / KV 通信 State Delta、LatentMAS、Interlat、KVCOMM、Cache-to-Cache 传递隐藏状态、latent 或 KV cache 通常依赖开放权重模型、GPU 或模型插桩;MACC 当前面向 CPU/Linux 用户态运行时,默认语义特征不等同于 hidden state 或 KV cache,因此不作跨硬件的直接排行
系统载体与运行时 Ray object store、Apache Arrow IPC、eRPC、zIO 对象存储、列式内存或低延迟/零拷贝 RPC MACC 的 STX 把 raw、POSIX 共享内存与 Arrow 纳入统一 TensorRef 生命周期,并计入发布、校验、传输和物化的端到端成本;Arrow 是本项目公开复现的 carrier baseline
长期记忆 Generative Agents、MemGPT、MemoryBank、ExpeL、HippoRAG、A-MEM 反思、分层存储、经验复用、图检索和动态记忆 MACC 的 SMEM 侧重统一记忆单元、混合检索、证据归因与复用门控,并额外验证“命中后是否真的跳过计算”
长记忆评测 LongMemEval、LoCoMo、RealMem 长对话/长期记忆的外部评测协议 属于 benchmark 而非竞品系统;当前 LoCoMo 与 LongMemEval 结果均按 retrieval-only 口径报告,不能替代 reader/答案级准确率

公平比较边界: nl/json/cjson/acp1 使用相同任务、Agent、DAG 和运行环境,属于 协议层同条件基线;Apache Arrow 属于状态载体同条件基线;SILO-BENCH 使用 Level-I exact-oracle replay 检查通信正确性和开销,不表述为完整端到端 SOTA 复现。 LoCoMo 的 1,977 个可评测问题上,MACC hybrid Recall@5 为 0.4977、BM25 为 0.4883,但 conversation-cluster 配对置信区间跨越 0,因此结论是“在显著降低 full-history 载荷的同时保持有竞争力的检索质量”,而不是“统计显著全面优于 BM25”。


系统架构

┌─────────────────────────────────────────────────────────────────────────┐
│ CLI / 评测      doctor · smoke · run · bench · memory · demo             │
├─────────────────────────────────────────────────────────────────────────┤
│ EVAL 评测层     指标采集 · 3 组关联任务族 · A/B 实验台 · 报告与 SVG 图表  │
├─────────────────────────────────────────────────────────────────────────┤
│ AGENT 角色层    Planner · Retriever · Executor · Summarizer(四类角色)  │
├─────────────────────────────────────────────────────────────────────────┤
│ RUNTIME 运行时  Registry(能力发现) · Broker(握手/路由/计量) ·            │
│                 Scheduler(DAG 调度/复用门控) · Session(生命周期)         │
├──────────────┬───────────────┬───────────────┬─────────────────────────┤
│ PROTOCOL ACP │ STATE  STX    │ MEMORY  SMEM  │ SANDBOX CodeAct         │
│ 四要素强校验 │ 共享内存段    │ 六类记忆单元  │ AST 白名单              │
│ 四种 codec   │ TensorRef 句柄│ BM25 倒排索引 │ 受限命名空间            │
│ 能力描述表   │ 零拷贝视图    │ 标签索引      │ 子进程隔离              │
│ 文本⇄结构映射│ 引用计数 GC   │ 向量索引      │ 时间/输出/内存限额      │
│ 增量上下文   │ CRC32 校验    │ 混合检索+归因 │ 结构化结果回传          │
├──────────────┴───────────────┴───────────────┴─────────────────────────┤
│ TRANSPORT      帧协议(长度+CRC) · 进程内队列 · UNIX socket · TCP        │
├─────────────────────────────────────────────────────────────────────────┤
│ 基础设施       config · logging(JSONL) · errors · ids/clock · tokens    │
└─────────────────────────────────────────────────────────────────────────┘

对应赛题「具体要求 9」的五大模块:多 Agent 运行时(runtime/+agents/)、 协议解析与调度(protocol/+runtime/scheduler.py)、状态交换(state/)、 共享记忆存储与检索(memory/)、评测(eval/)。

一轮任务在系统里怎么流动

以任务族 billing 的第 2 轮「生成根因报告」为例,一次完整往返如下 —— 每一步都能在「协作时间线」页看到对应的消息条目:

① Session 开启,Broker 完成 HELLO/WELCOME 握手,版本协商通过
      ↓
② Scheduler 从任务族取出 DAG(6 步),逐步派发
      ↓
③ Planner 产出计划 → ACP Envelope{action="plan.task", params, result}
   经 acp1 二进制编码写入 transport(278 字节,0 prompt token)
      ↓
④ Retriever 收到后先查 SMEM:
   score = 0.5·BM25 + 0.2·Jaccard(tags) + 0.3·cosine
   命中第 1 轮沉淀的"证据链"记忆 → 复用门控判定 REUSE
   → 整步跳过,不再重算(`recompute_skipped` +1)
      ↓
⑤ 需要传向量时不进文本:Embedder 产出 float32 缓冲 →
   bus.publish() 写入 POSIX 共享内存 → 消息里只带 TensorRef 句柄
   下游 bus.attach() 映射同一物理页,CRC32 校验后零拷贝参与运算
      ↓
⑥ Executor 需要跑代码 → CodeAct 沙箱子进程执行,AST 白名单先过一遍,
   带时间/内存/输出三重限额,结构化结果回传
      ↓
⑦ Summarizer 汇总结论 → 写回 SMEM(六类记忆单元之一,五项必填元数据)
      ↓
⑧ Session 关闭:引用计数归零,共享内存段自动 unlink(12 轮后零泄漏)
   全过程指标进 metrics,落 JSONL 日志,供 eval 层生成报告

纯文本基线模式(--mode text)走的是同一条路径、同一套 Agent、同一个 DAG, 只把③的编码换成自然语言长文本、⑤的向量序列化进文本、④的记忆检索关掉。 差异只来自这三套机制 —— 这是整套 A/B 对比可信的前提。


三套机制怎么工作

1. ACP 结构化协议

一条消息把协作信息收敛为四个语义单元,大块数据只传引用:

Envelope
├── action   动作类型      "retrieve.docs"
├── params   输入参数      {"query": "...", "top_k": 4}
├── result   返回结果      {"docs": [...], "count": 4}
├── caps     能力描述      [Capability(...)]      ← 握手/发现时携带
├── refs     张量句柄      [TensorRef]            ← 大块数据走共享内存
└── memrefs  记忆引用      ["m-billing-0a1b2c3d"] ← 不内联记忆全文

同一条逻辑消息的四种线上形态(macc.cli demo 可现场复现):

codec 线上字节 prompt token 说明
nl 1,352 489 自然语言长文本(主流做法 / 基线)
json 587 238 标准 JSON
cjson 427 182 短键紧凑 JSON
acp1 278 0 自研二进制(本项目默认)

acp1 的 prompt token 为 0 不是取巧:结构化模式下 Agent 间不再经过语言模型 的上下文窗口,消息直接在运行时之间流动,因此没有任何 token 被消耗。 这也正是赛题要求”不得仅用自然语言长文本透传”的直接体现。

协议层强制执行这条要求:内联数值数组超 16 个元素、 单字段文本超 512 字符一律被 validate() 拒绝 —— 这是代码级约束,不是口头承诺。 想绕过它就得改 macc/protocol/schema.py 并让相应测试变红。

为什么保留 nl 与文本映射器? 因为可观测性不能牺牲。mapper 提供结构化 ⇄ 自然语言的双向映射并有往返语义等价测试:调试时人能读,运行时机器传二进制。 二者不是二选一。

2. STX 非文本状态传递

生成  Embedder.encode()          → float32 连续缓冲
传递  bus.publish(tensor)        → 写入 POSIX 共享内存,返回 TensorRef 句柄
                                   (消息内只有元数据,无任何数值)
接收  bus.attach(ref)            → 映射同一物理内存,零拷贝 memoryview + CRC32 校验
使用  view.cosine() / .topk()    → 直接参与运算,无文本解析

已验证:张量 8 → 8000 元素(放大 1000 倍),消息大小差 < 16 字节; 子进程仅凭句柄即可读出父进程张量(含切片视图);引用计数归零自动 unlink; 12 轮后零泄漏。

这里省掉的不只是字节,是两次格式转换。 传统做法把 embedding 序列化成文本 再由下游解析回浮点数,一来一回既耗 CPU 又损精度;共享内存路径下, 下游拿到的就是同一块物理内存上的 memoryview,没有拷贝、没有解析、没有精度损失。 本次实验中基线为此内联了 2,668 个字符的向量文本,结构化模式为 0。

安全性同样被钉住:段名注入、越界句柄、CRC 篡改、超大帧声明都有专门的拦截测试 —— 共享内存是把双刃剑,暴露物理内存就必须假定句柄可能是恶意的。

3. SMEM 共享记忆

score = 0.5 × BM25(关键词) + 0.2 × Jaccard(标签) + 0.3 × cosine(语义向量)

每条命中带 matched_by 归因,可解释”为什么被召回”。复用要过三道门: 分数达阈值、任务主题相关、content 含必备键。三档结论 REUSE(跳过计算)/ AUGMENT(作提示但仍计算)/ RECOMPUTE。

三道门是必要的,不是保守。 只看相似度分数会把”看起来像”的记忆当成”能用”, 一旦复用了不该复用的中间结果,错误会沿任务链传播且难以定位。 所以门控除了分数,还要求主题相关且 content 里确实有下游需要的键 —— 宁可退回 AUGMENT(拿来当提示但照样算一遍),也不赌一次。 AUGMENT 这一档的存在本身就是承认:检索到了不等于可以跳过。

质量守恒的证据:端到端测试断言两种模式对同一任务产出的结论签名完全一致 —— 省下的开销没有以答案质量为代价。

记忆单元支持赛题要求的六类内容(中间结果 / 摘要 / 经验 / 证据链 / 结论 / 策略), 每条强制五项元数据(记忆 ID、来源 Agent、创建时间、任务主题、摘要描述), 缺一即被 schema 拒绝写入。


Agent 桌面执行环境

赛题考核的是机制,但机制要有真实负载才能证明自己站得住。因此我们把 MACC 做成了一个能实际干活的 Agent 桌面端 —— 它的记忆层、通信层、执行层 就是上面三套机制本身。

工具清单(19 个 + 插件提供)

类别 工具
文件(7) fs_read fs_write fs_edit fs_delete fs_list fs_grep workspace_tree
执行(2) python_exec(沙箱子进程) shell_run
网络(2) web_search(三源冗余) web_fetch
文档(1) doc_parse(PDF 带页码 / 音视频带时间点)
Git(5) git_status git_diff git_log git_add git_commit
记忆(2) memory_search memory_write ← 直接建在 SMEM 上

插件可再注册工具(内置示例插件提供 notes_append)。

四档权限 × 三档沙箱

权限档 询问 工作区边界 沙箱档位 用途
readonly — 只读 strict(AST 白名单,32 种逃逸手法全拦) 演示给不熟悉的人看
approve 每次 限工作区 trusted(30 个白名单模块) 谨慎操作
auto 不问 限工作区 trusted 日常使用
yolo(默认) 不问 不限 admin(无 AST 检查、完整 builtins、无限额) 等价 Codex YOLO / Claude Code --dangerously-skip-permissions

即便在 yolo 档,仍有三条无条件拦截:路径含空字节、删除工作区根、 删除文件系统根。”完全放开”不等于”允许自毁”。 两处切换入口(「对话」页右下角与「工作区」页)双向同步。

多模态解析(12 类)

PDF(带页码)· Word · Excel · PowerPoint · 图片 · 音频 · 音频元数据标签 · 视频 · 视频关键帧 · 文本/代码 · CSV · JSON。

能力边界如实声明:音频的曲目识别依据是 ffprobe 读出的 ID3 等元数据标签, 不是波形识别 —— 本项目所用网关的 18 个模型中没有任何音频模型。 文件不带标签时,正文会明确写”当前模型不具备音频波形识别能力, 无法据音频内容判定曲目”,不猜。这条有专门测试钉住。

Skills 与 Plugins:粘贴链接即可安装

「Skills / 插件」页贴入 git 链接后自动去抖检索(450 ms),有效才点亮 Install, 无效在下方黄字说明原因 —— “能不能装”在点击之前就已知。

检索不做整仓克隆:先 git ls-remote 确认可达,再做 blobless 无检出克隆取文件清单 判定类型(整仓克隆动辄数十 MB,而检索是交互动作必须快)。 归类按仓库实际内容而不是按用户填进哪个框:plugin.json 声明了非空 tools 才算工具插件,只有 SKILL.md 则按技能包安装,两者皆无判为无效。 把技能包填进 Plugin 框也能装成,但界面会如实标注「技能包,无可调用工具」—— 不虚构不存在的工具,也不粗暴拒绝用户的输入。

安装物落在 var/extensions/(已 gitignore),不混进参赛作品仓库; registry.json 记录 url / commit / 许可 / 条目清单,评审 clone 后可据此复现安装。 社区技能包正文实测可达 42,362 字(≈8.5 万 token),因此注入时按 6,000 字截断 并给出文件路径供模型按需 fs_read 读全文(实测 10,127 → 1,656 token)。

对话内调用:Skill list ▾ / Plugin list ▾ 选一项 → Invoke → 输入框插入高亮的 @skill:名称。显式引用优先于关键词自动匹配 —— 用户点选了哪个就用哪个,不让匹配算法再猜一次;引用了不存在的名字会被如实指出, 而不是静默忽略让用户误以为技能已生效。

子 Agent 编排

五类角色(研究 / 编码 / 测试 / 文档 / 审查),支持流水线与并行两种拓扑, 每个角色可填独立任务描述(留空回落到共同目标)。主/子 Agent 之间走 ACP 协议通信 —— 实测三个子 Agent 协作产出三份报告,ACP 侧仅 6 条消息 / 4,192 字节 / 0 prompt token。这是三套机制在真实负载下的直接体现。


命令清单

python -m macc.cli doctor                        # 环境自检(Python/共享内存/可选依赖/凭据连通性)
python -m macc.cli smoke                         # 14 项冒烟检查
python -m macc.cli agent-smoke                   # Agent 侧 18 项全栈冒烟(离线)
python -m macc.cli demo                          # 六步演示(录屏用)
python -m macc.cli run  --topic billing --goal "定位异常账单科目"
python -m macc.cli run  --mode text --json       # 纯文本基线模式
python -m macc.cli bench --rounds 12 --seed 20260729 --out reports/latest
python -m macc.cli memory list|search|stats --query "账单科目错配"
python -m macc.cli agent "把工作区里的 CSV 汇总成日报"   # 命令行版 Agent
python -m macc.cli desktop                       # 启动桌面客户端 MACC Studio
python -m macc.desktop                           # 同上(桌面端直接入口)

常用开关:

开关 作用
--mode text / --mode structured A/B 两种协作模式(run / bench)
--seed N 固定随机种子,保证可复现
--json 机器可读输出,便于接 CI
--require-llm / --no-llm-probe doctor 是否强校验 / 跳过模型连通性
--workspace PATH 指定工作区(agent / desktop)
--permission MODE 四档权限;--dangerously-skip-permissions 等价 yolo
--max-steps N / --attach PATH ReAct 步数上限 / 附件路径

桌面端的工作区可以在界面里随时切换(顶栏胶囊 / 📁 打开文件夹… / 最近 ▾), 不需要重启;切换会一起换掉工作区闸门、沙箱 cwd、工具注册表与编排器,并自动新建会话。

也可用 Makefile:make doctor|test|smoke|bench|demo|lint|verify|clean


实验设计

3 组关联任务族 × 4 轮 = 12 轮连续任务(满足”≥10 轮”要求):

任务族 任务链 复用点
billing 定位异常科目 → 生成根因报告 → 给出整改策略 → 复核有效性 证据链 + 结论 + 策略
logaudit 抽取错误模式 → 统计频次分布 → 输出告警规则 → 回归验证 错误模式 + 嵌入
codereview 找出高风险函数 → 生成检查项 → 汇总报告 → 二次巡检 风险函数集 + 策略

任务族内有关联是关键:只有后续任务确实需要前序产物,记忆复用才有意义。 如果任务两两独立,命中率再高也说明不了什么。

关于基线公平性:纯文本基线不是稻草人,它就是主流做法 —— 自然语言消息体、 每轮重发全量上下文、向量序列化进文本、无记忆检索。两侧共用同一套 Agent、 同一个引擎、同一份语料、同一随机种子、同一 DAG。差异只来自这三套机制。

指标口径(怎么量的)

指标 口径
wire_bytes 实际交给 transport 的编码后载荷字节数,含帧头与 CRC,不是估算
text_tokens tiktoken cl100k_base 精确计量;无 tiktoken 时退化为 CJK 感知估算并在报告中标注方式
messages Broker 实际路由的消息条数
tensor_transfers / tensor_bytes 经共享内存发布/映射的张量次数与字节数
memory_hit_rate memory_hits / memory_lookups,只统计真实发起的检索
recompute_skipped 因命中而整步跳过的计算步数(不是”检索到了”的次数)
steps_executed 实际执行的 DAG 步数
wall_ms 墙钟耗时,另分列协作层与沙箱层,便于剥离噪声
随机种子 20260729(固定)

可复现性:同种子两次运行,messages/text_tokens/wire_bytes/ tensor_transfers/memory_hits 等十项指标完全相等,由回归测试断言。

这条断言曾经真的抓到过缺陷:Executor 一度把沙箱的墙钟耗时(67~79 ms 抖动) 写进了消息载荷,导致文本模式下 wire_bytes 随机差 2 字节 —— 表面上像测试抖动,实际是可复现性被破坏。修复后 12 轮验证从 3 次不一致降为 0 次。 判断依据是失败是否与机器负载相关:可复现性断言在空载下也失败,就一定是代码问题。


完整实测数据

12 轮 / 3 任务族 / 种子 20260729 / tiktoken 精确计量。 原始数据 reports/latest/report.json, 图表报告 reports/latest/report.html:

指标 纯文本基线 结构化协议 变化
prompt token 总量 136,657 0 ↓100%
文本字符总量 220,872 0 ↓100%
线上字节总量 403,186 80,610 ↓80.01%
Agent 间消息条数 176 144 ↓18.2%
实际执行步数 72 56 ↓22.22%
记忆检索次数 / 命中 0 / 0 44 / 32 命中率 72.73%
记忆写入单元 0 46 —
因复用跳过的重算 0 16 次 —
非文本状态传递 0 次 64 次 / 120,832 字节 —
向量内联进文本的字符数 2,668 0 ↓100%
运行错误 0 0 —
泄漏的共享内存段 0 0 —
协作层耗时(剔除沙箱) 36 ms 32 ms ↓11.11%
沙箱执行耗时(模式无关) 1,301 ms 1,355 ms 两侧步数相同,属墙钟抖动
端到端总耗时 1,365 ms 1,419 ms +3.96%(见下)

关于耗时,必须如实说明。 本次 12 轮里结构化模式端到端慢了 3.96%(54 ms)。 拆开看就清楚了:两种模式跑了同样 6 次沙箱执行,而沙箱耗时差恰好也是 54 ms —— 也就是说这点差异全部落在沙箱子进程的墙钟抖动上,与三套机制无关。 剔除沙箱后的协作层反而快了 11.11%(复用整步跳过省下的时间超过了检索开销)。 即便如此,我们也不把它写成”时延下降 11%”: 记忆检索本身确实是新增开销(约 0.8 ms/轮),不应隐藏; 而端到端时延的方向依赖平台与负载(Windows 与 openEuler 容器上符号相反)。 因此本项目不宣称通用时延下降,只宣称跨平台一致成立的三项: **字节 ↓80%、token ↓100%、重复计算步数 ↓22%**。

轮次越多,复用效应越明显:24 轮时命中率 85.00%、跳过重算 40 次、 执行步数 ↓27.78%、线上字节 ↓81.98%。详见 docs/08-experiment-report.md。


工程质量

层次 用例数 覆盖
单元测试 1,161 各模块行为与边界
集成测试 273 模块协作、契约矩阵、安全、异常、性能门槛
端到端 38 任务族全链路、12/24 轮稳定性、可复现性回归
根级(交付物、追溯、匿名性) 125 材料完整性与赛题条款追溯
合计 1,597 全部通过

其中 Agent 桌面端相关 379 个(含 GUI 层 114 个,无显示环境下亦可跑)。 另有 12 个 live 标记用例需真实模型,默认不执行(pytest -m live 单独跑)。 用例数不是手写在文档里的 —— 由 tools/count_tests.py 采集到 reports/latest/testcount.json,并有测试断言《项目说明书》里的数字与采集值一致。 说明书定稿时的采集快照为 1,593 个,其后又补入 4 个交付物校验用例, 当前工作树 pytest --collect-only 为 1,597 —— 两个数字都是真的, 差异就是这 4 个用例,此处一并说明以免被当作笔误。

  • 接口契约矩阵:4 种 codec × 2 种记忆后端 × 3 种传输,参数化全组合验证。
  • 安全:32 条真实沙箱逃逸手法(import os、eval、 ().__class__.__bases__[0].__subclasses__() 等)全部在执行前被拒; 段名注入、越界句柄、CRC 篡改、超大帧声明均有拦截。
  • 异常:6 类故障(Agent 崩溃、能力缺失、段不存在、记忆损坏、沙箱超时、 传输超时)均验证不崩溃且返回结构化错误。
  • 交付物自检:说明书章节完整性、模板占位文字是否清除、文中指标是否与 report.json 一致、PDF 是否比 .docx 旧、截图是否重复、 是否误提交大文件、是否用了 Git LFS —— 全部由测试把关,而非人工核对。
  • 原创性守卫:tools/originality_check.py 从”他方版权声明”与”异种技术栈” 两个角度扫描仓库。这条检查源于一次真实事故:某次提交误把一个 8.3 MB 的 Go 项目带进了仓库,而当时没有任何检查能发现它 —— 而说明书声称 “自创部分占代码总量的 100%”。检查是补上的,事故是记下来的。
  • 静态检查:tools/lint.py 除常规规则外,还限制单文件行数上限(1,200 行), 超限就必须拆分 —— 本项目有两个工具脚本因此被拆开。

赛题符合性对照

赛题条款已逐条拆成 R-01 ~ R-35 可测需求,每条都绑定实现模块与测试文件, 由 tests/test_traceability.py 机器校验 “需求 ↔ 模块 ↔ 测试”三者不脱节;tools/check_docs.py 另行校验文档里的编号无遗漏。 按赛题「具体要求」归并如下:

赛题具体要求 需求编号 实现 达成情况
1 · ≥3 个 Agent、覆盖规划/检索/执行/总结、完成多步骤任务 R-01~R-03 runtime/ agents/ 4 类角色全覆盖,DAG 6 步
2 · 结构化通信含四要素,支持握手/能力发现/协议映射,禁止 NL 长文本透传 R-04~R-08 protocol/ runtime/broker.py 四要素 schema 强校验;NL 透传被代码拒绝
3 · 同时支持纯文本与结构化两种模式,可复现对比 R-09~R-10 config.py eval/harness.py --mode text/structured;十项指标同种子完全一致
4 · 非文本中间状态传递,说明生成/传递/接收/使用 R-11~R-12 state/ POSIX 共享内存 + TensorRef,四段齐备
5 · 统一记忆单元(六类内容 + 五项元数据) R-13~R-14 memory/unit.py 六类 kind 全有写入测试,缺元数据即拒
6 · 关键词 / 标签 / 语义三种检索 + 跨 Agent 跨任务复用 R-15~R-18 memory/ 三路混合检索 + 复用门控 + 跳过重算计数
7 · ≥2 组关联连续任务,验证减少重复计算与开销 R-19~R-20 eval/tasks.py 内置 3 组任务族
8 · 统计消息次数/开销/状态传递/耗时/命中率并展示提升 R-21~R-26 eval/metrics.py eval/reporter.py 全指标采集 + HTML 报告 + 5 张 SVG
9 · 架构含运行时/协议调度/状态交换/记忆/评测五大模块 R-27~R-31 见系统架构 五模块齐备,目录一一对应
10 · 稳定执行 ≥10 轮连续任务 R-32 runtime/session.py 12 轮与 24 轮均验证,零泄漏零错误
11 · 提交源码/设计/部署/实验/演示材料 R-33 本仓库 见仓库结构导览
12 · 结合 IPC / 共享内存 / Socket / 沙箱等系统技术 R-34~R-35 transport/ state/ sandbox/ POSIX 共享内存、UNIX socket、进程沙箱、setrlimit

「关于」页内置同一张自查表,可在桌面端现场逐条点开核对。


关键设计取舍

工程里没有免费的选择。这里列出几个可能被质疑的决定和我们的理由 —— 包括被否掉的方案,因为否掉的原因往往比选中的理由更能说明问题。

决定 理由 代价 / 被否方案
默认引擎是确定性规则引擎,不是真实 LLM 赛题考核系统层机制,LLM 采样噪声会淹没 A/B 信号;固定引擎让对比可复现、可复核 少了”看起来很智能”的演示效果。LLMEngine 已实现,配置即切换,缺凭证直接报错不静默降级
自研 acp1 二进制编码 要拿到”字节”与”token”两个维度的真实下限;通用序列化库无法做到 0 prompt token 需要自己写 codec 与校验。同时保留 json/cjson/nl 三种,任何人可换回来对比
桌面端用 tkinter,不用 Electron / Qt / Web 唯一能保住”核心运行时零第三方依赖”的选择,openEuler 上一条 dnf 即可 视觉上不如现代 Web 框架。被否:Electron(引入 Node 全套依赖)、PyQt(GPL 与体积)
状态载体用 POSIX 共享内存,不用 Ray / Arrow Flight 赛题明确鼓励结合系统技术;共享内存是延迟下限,且能演示零拷贝与引用计数 GC 天然限于单机。Arrow 已作为公开可复现的 carrier baseline 纳入对比
复用门控保留 AUGMENT 中间档 检索到了不等于能跳过;宁可多算一遍也不让错误沿任务链传播 命中率数字会比”只要检索到就算复用”更保守
默认权限档位 YOLO 演示与实机使用场景下,逐次批准会让每个操作都卡住 放宽了边界。保留三档收紧选项,且三条自毁类操作无条件拦截
web_search 用三源冗余,不换”更好的引擎” 免费检索入口普遍按 IP 限流,任何单源都会偶发不可用 —— 换引擎解决不了,只有冗余能解决 被否:Bing RSS(实测无视查询词,问「Fields Medal」返回日本日历),Mojeek / Startpage / SearXNG / Ecosia / Qwant(均会返回机器人校验页)
单源失败不算失败 “某个免费镜像被限流”不是本次检索的结论,不该在界面上冒红字 诊断信息移到 data['tried'] 里,排查时看那里
技能正文注入按 6,000 字截断 社区技能包正文实测 42,362 字 ≈ 8.5 万 token,整段注入会吃掉整个上下文 模型需要时得自己 fs_read 读全文(已在提示里告知路径)
交付物里的数字全部从 JSON 读取生成 手写数字必然脱节:测试数曾被硬编码为 1312,涨到一千五百多之后文档没跟上 生成链路更复杂,但错不了;且有测试断言文档与采集值一致

依赖

核心运行时零第三方依赖 —— 只用 Python 标准库 (multiprocessing.shared_memory、socket、sqlite3、array、struct、 zlib、ast)。可选增强(Python 包与系统工具)缺失时自动降级:

可选增强 用途 缺失时
numpy 向量运算加速 退化为 array + 纯 Python,结果一致
tiktoken 精确 token 计量 退化为 CJK 感知估算,报告标注方式
pytest 运行测试套件 功能不受影响
python-docx / python-pptx 生成交付文档 仅影响文档生成,不影响运行
certifi 补全 CA 证书链(Windows 上常缺中间证书) web_fetch 对少数站点报证书错误
ffmpeg / ffprobe 音视频关键帧与元数据 音视频解析降级,其余 10 类多模态照常

“自动降级”是有测试保障的:关键路径都有在无可选依赖环境下运行的用例, 确保降级后结果一致而不是悄悄出错。requirements-optional.txt 列出可 pip 安装的包, 但评审复现完全不需要装它们。

默认不接大模型:赛题考核系统层机制,而 LLM 采样噪声会淹没 A/B 信号。 默认使用确定性引擎保证离线可复现;LLMEngine(OpenAI 兼容)已实现, 配置 base_url + api_key 即可切换,缺凭证直接报错不静默降级。


文档

文档 内容
docs/00-index.md 文档索引与上手入口(建议从这里开始)
docs/01-requirements.md 赛题条款 → R-01~R-35 需求追溯矩阵
docs/02-acceptance-criteria.md 8 项验收闸门与拒收条件
docs/03-architecture.md 架构设计、三大机制、时序图
docs/04-interfaces.md 接口契约(改代码前必读)
docs/05-worklist.md 可执行 Worklist(23 个工作项)
docs/06-module-guide.md 逐模块导读:怎么改、怎么测
docs/07-deployment.md openEuler 部署、配置、常见问题
docs/08-experiment-report.md 实验报告(含对不利数据的说明)
docs/09-demo-script.md 演示录制脚本
docs/10-delivery-checklist.md 交付清单与已知限制
docs/11-dev-guide.md 二次开发指南
docs/12-desktop-plan.md 桌面端(机制验证部分)设计方案
docs/13-agent-desktop-plan.md Agent 桌面端七层能力实施方案
docs/14-agent-desktop-guide.md Agent 桌面端使用手册(权限/工具/扩展)
docs/15-competitive-research.md 同类产品与相关工作调研
handoff.md 交接说明:当前状态、已修缺陷、验证方式
technical supplement.pdf 技术补充材料(完整论述、引用与实验口径)

另有 项目说明书.pdf、原创承诺书.pdf、 演示PPT.pptx 三份提交材料在根目录(.docx/.pptx 为可编辑源文件)。


常见问题

1. .env 填对了但一直 401 / “调用模型失败”。 shell 里可能残留一个失效的旧 OPENAI_API_KEY —— 真实环境变量会覆盖 .env (刻意设计的优先级)。排查:

echo $env:OPENAI_API_KEY     # 有值就是它在遮挡
$env:OPENAI_API_KEY=''       # 清掉,让 .env 生效
python -m macc.cli doctor --require-llm

doctor 会真的打一次接口并在 401 时直接提示这条遮挡关系。

2. doctor 报 HTTP 502 / 503,说”凭据连通性 失败”。 先看 /models 通不通 —— 通了就不是凭据问题。实测同一 key、同一端点, 换个模型即可用(gpt-5.6-sol 返 502,而 gpt-5.6-terra、claude-opus-5 正常), 故障在网关侧。在 .env 里改 MACC_LLM_MODEL=<可用模型名> 即可。 只有 404 才需要核对端点与模型名。这不影响机制验证部分 —— 那部分默认离线运行。

3. 桌面端起不来,报找不到 Tk。 sudo dnf install -y python3-tkinter(openEuler / RHEL 系)。 命令行部分不需要 Tk,机制验证与全部实验照常可跑。

4. doctor 说共享内存不可用。 容器没挂 /dev/shm 或给得太小,加 --shm-size=256m。 宿主机上一般不会出现。

5. 联网检索返回”没有检索到结果”。 免费检索入口按 IP 限流。已用三源冗余覆盖(DuckDuckGo 镜像 → DDG Instant Answer API → Wikipedia API),单源被挡不影响使用,界面也不会冒红字。 三源同时不可用时会如实说明并给出替代方案(换关键词,或已知网址直接用 web_fetch)。

6. 某个性能测试偶发擦线失败。 test_codec_roundtrip_p95_under_one_ms[cjson] 在高负载机器上可能测到 1.009 ms。 单独重跑确认即可,不要因此调阈值。 反过来说,可复现性类断言在空载下也失败就一定是代码缺陷 —— 这个区分我们踩过坑,写在了 handoff.md。

7. 我想看看不装任何可选包是什么效果。 python -m macc.cli doctor 会列出每个可选包的安装状态与缺失时的降级方式。 全部不装也能跑完 smoke / bench / pytest,只是 token 计量转为估算、 向量运算走纯 Python。


已知限制

如实列出,不当 bug 修:

  1. 时延方向与平台相关,本项目不宣称普遍降低时延。本次 12 轮里结构化模式 端到端 +3.96%,而该差值几乎全部来自沙箱子进程的墙钟抖动(两侧沙箱步数相同、 耗时差 54 ms 已超过总差值);历史测量中 Windows 上曾为 ↓8.37%、 openEuler 容器上 ↑5.25%。根因:复用节省的时间正比于被跳过步骤的绝对耗时, 而记忆检索开销大致固定(约 0.8 ms/轮);Linux 上沙箱本身很便宜, 省下的时间不足以抵消检索开销。跨平台一致成立的是通信字节 ↓80%、 token ↓100%、重复计算步数 ↓22%。详见实验报告 §6 的双平台数据。
  2. 默认引擎为确定性规则引擎,非真实 LLM(理由见关键设计取舍)。
  3. 语料规模较小(12 篇 / 3 主题),向量索引为暴力扫描,十万级需换近邻索引。
  4. 单机多进程,未做跨主机分布式(共享内存机制天然限于单机)。
  5. 未使用 eBPF / WASM(赛题”鼓励”项)。已用系统技术:POSIX 共享内存、 UNIX domain socket、进程级沙箱、setrlimit 资源限额。
  6. 不含真实 MCP 协议栈,只有插件抽象层与预留适配位;不含实时语音对话 (音频走文件解析路径),且音频的曲目识别依据是元数据标签而非波形。
  7. 未提供容器镜像构建文件。项目在 openEuler 24.03-LTS-SP3 上原生运行并已 取得容器内的对比数据,但仓库未附 Dockerfile;此外桌面端为 GUI 程序, 容器内运行需要额外的 X11 / Wayland 转发配置。
  8. 免费搜索源按 IP 限流,已用三源冗余覆盖,极端情况下三源同挂时会如实 告知”没有检索到结果”。

原创性说明

全部代码为本队原创,未引用任何第三方开源项目的源代码。 BM25、余弦相似度等为公开算法,按公式自行实现。 numpy / tiktoken / pytest / python-docx / python-pptx 仅作为可选依赖 通过公开 API 调用,未复制其源码。详见项目说明书「代码原创说明」章节。

这一声明不只是文字承诺,还有机器守卫: tools/originality_check.py 从他方版权声明(许可证里出现非本队的 Copyright 持有者)与异种技术栈(go.mod / Gemfile / Cargo.toml 等)两个角度扫描仓库, 并接入 tests/test_deliverables.py::test_no_third_party_source_in_repo。 新增第三方内容必须写进该工具的 ALLOWED 并说明理由, 而不是把检查关掉。

许可

Apache License 2.0

关于
323.3 MB
邀请码
    Gitlink(确实开源)
  • 加入我们
  • 官网邮箱:gitlink@ccf.org.cn
  • QQ群
  • QQ群
  • 公众号
  • 公众号

版权所有:中国计算机学会技术支持:开源发展技术委员会
京ICP备13000930号-9 京公网安备 11010802047560号