把小龙虾、爱马仕都“接入多智能体系统”居然能成为热词,说明这一轮多智能体热潮已经进入了万物皆可 Agent 的调侃期。热闹背后有一个问题反而容易被忽略:多智能体系统能不能不是“调用工具、走流程、拼提示词”,而是真正自主发现新知识?如果再进一步,把这个场景放在“开放世界”里,让 Agent 自己去提出猜想、找反例、互相批判,最后沉淀出一条可复用的数学规律,这件事要怎么设计?
这篇文章想聊的就是这个:开放世界多智能体环境中的自主数学发现。我会先交代清楚什么是开放世界多智能体环境,为什么数学发现是很好的试验场,然后给出一个可运行的最小系统:一个由“猜想者—验证者—批判者—知识库”组成的多智能体框架,跑通“自主发现一条数论小规律”的完整闭环。读完以后,你可以直接拿去改造成自己的实验。
1. 这篇文章真正要解决的问题
很多开发者学多智能体,学到的其实是“多 Agent 编排”:把任务拆给几个 Agent,让他们分别调用工具、写代码、汇总结果。这类系统的知识从哪来?还是人来定,Agent 只是在执行。它的问题在于:如果目标不是“完成一个已知任务”,而是“发现一个还不知道答案的问题”,你怎么把任务描述给 Agent?
这就是自主数学发现的特殊之处。
数学发现是一个高度开放的问题。公理是明确的,但推理路径是无限的。一个结论是不是成立,不取决于某个人说了算,而在于能不能被严格验证。如果用多智能体模拟一个“科学社区”,有人负责大胆提出猜想,有人负责找反例,有人负责检查边界条件,最后达成共识的结论沉淀进知识库——这就比单纯的任务编排往前多走了一步:系统开始产生自己的知识。
本文要解决的问题有三个:
- 开放世界多智能体环境到底是什么,和平时说的“聊天 Agent 组队干活”有什么区别。
- 在多智能体系统里设计“自主数学发现”要拆成哪些角色、哪些交互模式。
- 用 Python 写一个最小实现,让读者真实跑通一条“假设—验证—批判—入库”的完整链路。
2. 基础概念与核心原理
2.1 什么是开放世界多智能体环境
“开放世界”这个词来自游戏,但用在 AI 环境里,指的是:环境状态不会一次性给全,规则允许探索出新玩法,任务不是固定清单,世界不会因为 Agent 不知道某件事就不存在那块内容。
多智能体环境就是多个独立决策主体共享同一个环境,互相通信,共同影响环境状态。
把两者结合,开放世界多智能体环境就有几个关键特征:
- 局部可观测:每个 Agent 只能看到环境的一部分,需要靠通信补齐信息。
- 动态演化:环境不是静态题库,Agent 的行为会改变环境状态。
- 任务不可穷举:不存在一个预先标注好的“所有任务集合”。
- 知识可以涌现:Agent 通过交互发现的新结论,可能超出设计者预先枚举的范围。
数学符号世界恰好符合这些特征。公理和推理规则是确定的,但定理空间是无限的。对 Agent 来说,它看到的不是“已知的所有数学事实”,而是自己接到的消息、自己算过的结果、自己验证过的断言。它必须自己判断往哪里探索。
2.2 为什么数学发现适合做“开放世界”测试床
数学发现相比其他开放世界任务,有一个无可替代的优势:验证结果可判定。
在游戏里,一个 Agent 的行为“好不好”很依赖人工设计的奖励函数;在文本生成里,一个结论“对不对”往往要靠另一个大模型来打分。但在数学环境里,只要你把性质定义清楚,计算程序就能严格判断一个反例是否成立。
这意味着:
- 多智能体的“协作质量”可以用客观标准衡量。
- 系统不会出现“看起来很合理但实际是幻觉”的结论。
- 如果一个 Agent 提出了一个错误猜想,另一个 Agent 找到了反例,这个冲突是清晰可仲裁的。
所以,数学发现既保留了开放世界的探索复杂度,又避免了结果评价的模糊性。它非常适合用来研究多智能体的知识涌现机制。
2.3 常见误区:自主数学发现不等于“会做题”
这里一定要先说清楚。文章讲的“自主数学发现”,不是让 Agent 做一道数学题。做题是给定条件和问题,求一个解;发现是给定公理和探索工具,让系统自己找到值得研究的问题,并最终形成结论。
一个只会做“鸡兔同笼”的 Agent,不会主动去思考“有没有一个数,它的平方减 1 总被 8 整除”。自主发现要求系统具备提出假设的能力,然后通过批判性交互过滤掉错误假设,最终留下可复用的知识。这个能力门槛比“解题”高得多。
3. 多智能体交互模式与角色设计
3.1 多智能体的四种交互模式
当前讨论多智能体系统时,经常提到四种交互模式。这四种模式不是唯一标准,但在设计时很有参考价值:
| 交互模式 | 核心特征 | 典型场景 | 在数学发现中的体现 |
|---|---|---|---|
| 协作模式 | 多个 Agent 朝同一个目标努力,共享中间结果 | 多智能体共同完成一次代码迁移 | 多个 Agent 合作验证同一个猜想的边界 |
| 竞争模式 | Agent 目标互相冲突,结果取决于对抗 | 博弈对抗、攻防演练 | 反驳者与猜想者对抗,试图找出反例 |
| 协商模式 | Agent 通过交换条件达成一致 | 多智能体资源分配 | 猜想者、验证者、批判者对结论达成共识后入库 |
| 共存模式 | 目标互不干扰,共享环境但各做各的 | 开放世界中的多个独立 NPC | 多个猜想者各自独立探索不同数域 |
在自主数学发现场景里,这四种模式会同时出现。猜想者和验证者之间是协作关系,反驳者和猜想者之间是竞争关系,结论是否可沉淀需要协商,而多个猜想者之间完全可以互不干扰地共存。
3.2 数学发现场景下的角色映射
一个最小可用的系统,至少要包含这几个角色:
| 角色 | 对应科学社区角色 | 核心职责 |
|---|---|---|
| 猜想者 | 研究员 | 提出新的数学假设 |
| 验证者 | 实验员 | 在小范围数值空间内验证假设 |
| 批判者 | 审稿人 | 检查边界条件、特殊值、验证范围是否充分 |
| 知识库 | 期刊数据库 | 只保存通过验证和批判的结论 |
系统里的核心不是某个 Agent 的智能,而是角色之间的不对称。
猜想者不必验证自己提出的假设,验证者不必为猜想的质量负责,批判者则专门用怀疑的视角审查验证过程。这种职责分离能有效抑制单 Agent 系统常见的“确认偏误”——一个人提出想法时,往往会下意识忽略反例;但一个专门找茬的 Agent 不会。
4. 核心架构与流程拆解
4.1 总体架构
整个系统可以分成四层:
- 环境层:定义探索边界、数值空间、可用的数学运算。
- 智能体层:猜想者、验证者、批判者等独立进程或线程。
- 通信层:Agent 之间通过消息传递假设、验证结果、批判意见。
- 知识层:记录哪些假设被提出、被拒绝、被接受,以及接受时的证据链。
这里的通信层很关键。在真实分布式多智能体系统里,通信层需要支持异步消息、消息路由、历史追溯;在本文的最小演示里,用一个简单的“信箱”就能模拟。
4.2 一条知识是如何被“发现”的
用一条已知结论举例。假设系统最终想发现的是“任意奇数的平方除以 8 余 1”。
真实流程是:
- 猜想者生成假设:“如果 n 是奇数,那么 n 平方后取模 8,余数等于 1。”
- 验证者收到假设后,随机挑选 500 个奇数,分别计算
n^2 % 8,全部等于 1,没有找到反例。 - 批判者收到验证通过的结果后,检查特殊边界:n=1、n=3、n=999,以及一个很大的奇数。仍然没有反例。
- 知识库接受该结论,附带验证范围和批判日志,完成沉淀。
这只是一条知识的宏流程。把它放大到整个系统:每轮会有多个猜想者提出各种假设,有的因为验证者发现反例被拒绝,有的通过验证但被批判者发现边界漏洞,只有少数能走到入库环节。这个过程模拟的正是科学社区里“大胆假设、小心求证”的基本方法。
4.3 为什么不能只用一个 Agent 做这件事
单 Agent 也能生成假设、验证假设、写结论。但它在数学发现上有一个致命弱点:缺少独立性。
如果同一个 Agent 既提出假设,又负责验证,那么验证策略会不自觉地偏向“确认假设成立”。这不是模型有主观恶意,而是单一角色很难同时维持“创新”和“怀疑”两种认知状态。
多智能体的价值不在于“人多力量大”,而在于通过结构化的数据隔离,制造认知多样性。验证者不关心假设是谁提出来的,批判者不知道猜想者之前哪些假设被拒绝过。信息的不对称,恰好成为系统自我纠错的基础。
5. 环境准备与前置条件
本文的代码是教学简化版,不依赖任何重量级框架。建议环境如下:
- Python 3.9 及以上版本,版本请以实际可用为准。
- 项目依赖:仅需标准库,不需要额外的第三方包。
- 操作系统:Windows、macOS、Linux 均可。
- 项目目录建议如下:
math-discovery/ ├── experiment.py └── README.md如果你只想先跑通流程,新建一个experiment.py文件,把下面章节的代码复制进去即可运行。
本文代码模拟的是“受限环境中的数值规律发现”,不涉及形式化定理证明。任何通过验证的结论都只是“在采样空间内成立”,真正的数学证明需要借助 Lean、Coq 或人工证明,这一点在总结部分会再次强调。
6. 完整示例与代码实现
6.1 环境与消息定义
先定义基础的数据结构:消息、知识库、环境。消息是 Agent 之间唯一的信息载体;知识库负责沉淀结论;环境负责提供数值采样和验算功能。
# 文件路径:math-discovery/experiment.py import random from dataclasses import dataclass, field from typing import Callable, Optional @dataclass class Message: sender: str receiver: str msg_type: str # hypothesis / verify_result / criticize_result / accepted content: dict @dataclass class KnowledgeBase: facts: list = field(default_factory=list) def add(self, fact: dict) -> None: self.facts.append(fact) def __len__(self) -> int: return len(self.facts)环境提供了两种采样方法:
sample_values:随机生成普通测试样本。special_values:生成边界样本,包括 0、1、2、大质数等。
class MathEnvironment: def __init__(self, max_n: int = 100000): self.max_n = max_n def sample_values(self, size: int = 500) -> list: return [random.randint(1, self.max_n) for _ in range(size)] def special_values(self) -> list: candidates = [0, 1, 2, 3, 4, 7, 8, 13, 997, 10007, self.max_n] return list(set(candidates))6.2 假设生成器与猜想者
假设生成器从参数模板中随机组合,生成候选数学断言。这样设计是为了模拟“提出新想法”的过程:系统预先定义了可以探索的数学结构,但具体结论是随机组合出来的,设计者也不知道哪一条能成立。
def generate_hypothesis(rng: random.Random) -> dict: power = rng.choice([1, 2, 3]) mod = rng.choice([2, 3, 4, 5, 7, 8, 9, 12, 16]) remainder = rng.randint(0, mod - 1) constraint_type = rng.choice(["all", "odd", "even"]) if constraint_type == "all": constraint_desc = "所有整数" constraint = lambda n: True elif constraint_type == "odd": constraint_desc = "奇数" constraint = lambda n: n % 2 == 1 else: constraint_desc = "偶数" constraint = lambda n: n % 2 == 0 def func(n: int) -> bool: if not constraint(n): return True return pow(n, power, mod) == remainder return { "description": f"对于{constraint_desc} n,n^{power} % {mod} == {remainder}", "func": func, "constraint": constraint, "power": power, "mod": mod, "remainder": remainder, }猜想者 Agent 的任务就是生成候选假设,并广播出去。
class HypothesisAgent: def __init__(self, name: str, rng: random.Random): self.name = name self.rng = rng def propose(self) -> Message: hypothesis = generate_hypothesis(self.rng) return Message( sender=self.name, receiver="*", msg_type="hypothesis", content=hypothesis, )6.3 验证者与批判者
验证者负责找反例。它对假设进行独立验证,如果样本空间内存在反例,直接返回拒绝结果。
class VerifierAgent: def __init__(self, name: str, env: MathEnvironment): self.name = name self.env = env def verify(self, hypothesis: dict, sample_size: int = 300) -> Message: samples = self.env.sample_values(sample_size) for n in samples: if not hypothesis["func"](n): return Message( sender=self.name, receiver="*", msg_type="verify_result", content={ "hypothesis": hypothesis, "passed": False, "counterexample": n, }, ) return Message( sender=self.name, receiver="*", msg_type="verify_result", content={ "hypothesis": hypothesis, "passed": True, "counterexample": None, }, )批判者负责做第二轮审查。它不重复验证者的随机采样,而是检查边界特殊值,并增加一个“符号结构抽查”,例如检查是否存在极端特殊情况。
class CriticAgent: def __init__(self, name: str, env: MathEnvironment): self.name = name self.env = env def criticize(self, hypothesis: dict) -> Message: specials = self.env.special_values() for n in specials: if not hypothesis["func"](n): return Message( sender=self.name, receiver="*", msg_type="criticize_result", content={ "hypothesis": hypothesis, "passed": False, "reason": f"边界反例 n={n}", }, ) return Message( sender=self.name, receiver="*", msg_type="criticize_result", content={ "hypothesis": hypothesis, "passed": True, "reason": "边界与特殊值检查通过", }, )这里还需要一个简单的消息分发机制。由于是演示代码,直接用一个列表模拟全局消息总线。
class MessageBus: def __init__(self): self.messages = [] def publish(self, message: Message) -> None: self.messages.append(message) def consume(self) -> list: messages = self.messages self.messages = [] return messages6.4 主流程:多智能体协作发现
主流程把整个系统串起来。设置固定随机种子,保证可复现;运行多轮发现循环;最后输出知识库。
def main(): random.seed(42) env = MathEnvironment(max_n=100000) bus = MessageBus() kb = KnowledgeBase() rng = random.Random(42) proposer = HypothesisAgent("proposer-1", rng) verifier = VerifierAgent("verifier-1", env) critic = CriticAgent("critic-1", env) max_rounds = 30 for round_idx in range(max_rounds): # 1. 猜想者提出假设 bus.publish(proposer.propose()) # 2. 验证者处理假设 for message in bus.consume(): if message.msg_type == "hypothesis": hypothesis = message.content verify_msg = verifier.verify(hypothesis) bus.publish(verify_msg) if not verify_msg.content["passed"]: print(f"[Round {round_idx:02d}] 假设被拒绝: " f"{hypothesis['description']} | 反例: {verify_msg.content['counterexample']}") else: print(f"[Round {round_idx:02d}] 验证通过: {hypothesis['description']}") # 3. 批判者审查通过验证的假设 for message in bus.consume(): if message.msg_type == "verify_result" and message.content["passed"]: criticize_msg = critic.criticize(message.content["hypothesis"]) bus.publish(criticize_msg) # 4. 入库 for message in bus.consume(): if message.msg_type == "criticize_result": if message.content["passed"]: hypothesis = message.content["hypothesis"] fact = { "description": hypothesis["description"], "verifier": "verifier-1", "critic": "critic-1", "round": round_idx, } kb.add(fact) print(f"[Round {round_idx:02d}] ★ 新知识入库: {fact['description']}") else: hypothesis = message.content["hypothesis"] print(f"[Round {round_idx:02d}] 批判者拒绝: {hypothesis['description']} | 原因: {message.content['reason']}") print("\n===== 最终知识库 =====") for idx, fact in enumerate(kb.facts, start=1): print(f"{idx}. {fact['description']}") print(f"共发现 {len(kb.facts)} 条被接受的知识")7. 运行结果与效果验证
运行代码:
python experiment.py由于代码中固定了随机种子random.seed(42)和相同的rng,理论上每次运行会得到相同的结论序列。不过不同 Python 版本的随机数算法可能略有差异,更稳妥的判断方式是看日志结构。
预期运行后会看到类似这样的输出:
[Round 00] 假设被拒绝: 对于奇数 n,n^1 % 8 == 3 | 反例: 5 [Round 01] 假设被拒绝: 对于所有整数 n,n^2 % 8 == 4 | 反例: 1 [Round 02] 验证通过: 对于奇数 n,n^2 % 8 == 1 [Round 02] ★ 新知识入库: 对于奇数 n,n^2 % 8 == 1 ... ===== 最终知识库 ===== 1. 对于奇数 n,n^2 % 8 == 1 共发现 1 条被接受的知识需要强调,具体的被接受结论数量取决于随机种子和假设空间配置。演示代码中人为配置了mod=8, power=2, remainder=1这个组合,它有概率被随机生成出来。如果运气不好,一次运行可能一条结论也发现不了——这在真实的自主发现系统里是完全正常的。
验证成功与否,看两个对照组:
- 知识库非空:说明系统成功完成了“提出假设—验证—批判—入库”闭环。
- 日志中同时包含“被拒绝”和“被接受”:说明系统不是只会全盘接受,而是真的有批判机制。
如果运行报错,先检查代码是否有复制遗漏;再确认 Python 版本;最后看括号、缩进是否完整。
8. 常见问题与排查思路
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 运行后一条知识都没入库 | 随机种子和假设空间没有组合出真命题 | 查看日志中是否有“验证通过”和“批判者拒绝” | 调整generate_hypothesis中的power、mod、remainder候选集合,或增加轮次 |
| 某些已被验证的假设被批判者拒绝 | 验证者只做了随机采样,遗漏边界特殊值 | 查看拒绝原因是否为“边界反例” | 这是设计预期的纠错行为,说明批判机制生效 |
| 不同机器运行结果不一致 | Python 随机数算法版本差异 | 对比日志中第一条消息 | 如果追求严格一致,可将随机种子改为自定义伪随机算法 |
| 想要探索更大的数学空间 | 当前模板只有乘方和取模 | 扩展假设生成器 | 增加多项式、级数、同余方程组等生成模板 |
| 担心 Agent 会执行危险操作 | 当前示例中 Agent 只操作数值 | 检查是否调用了系统命令或外部资源 | 在真实系统中,Agent 的计算任务应放入沙箱执行 |
9. 最佳实践与工程建议
9.1 职责分离是系统纠错的前提
哪怕在做最小实验,也尽量保证“提出假设”和“验证假设”由不同对象完成。自主发现系统的设计核心不是让每个 Agent 更聪明,而是让错误的结论无法通过多环节审查。
9.2 每一条知识都要有证据链
知识库中不应该只存结论,还要存下这条结论是谁提出的、谁验证的、验证范围是什么、批判者是谁。这样当后续发现某条知识与新结论冲突时,可以回溯整个过程,定位是哪一步出了问题。
9.3 随机性是可复现性的敌人
使用固定随机种子、记录 Agent 收到的全部消息,是保证实验可复现的基本功。在更复杂的系统里,建议把所有 Agent 的输入输出以事件流形式落盘,而不是只打印最终结论。
9.4 明确“数值验证”和“数学证明”的边界
本文演示的系统只能做数值规律发现。任何一条知识都只在采样空间内成立,不等于数学定理。如果目标是做真正的自主数学发现,下一步必须接入形式化验证工具,比如 Lean、Coq 或 Isabelle,让机器可读的证明成为知识入库的前提。
9.5 安全与授权边界
如果将来把假设生成器换成大模型驱动的 Agent,务必注意:
- 大模型只能生成假设文本或代码,不能直接执行系统命令。
- 所有计算任务放沙箱执行,限制资源占用。
- Agent 之间的通信需要做权限隔离,避免某个 Agent 伪造其他 Agent 的验证结果。
10. 总结与后续学习方向
回到开头的问题。多智能体系统如果只能编排任务、调用工具,那它本质上还是一个“自动化流水线”;当系统里的 Agent 开始提出猜想、互相反驳、独立验证、最终沉淀知识时,它才真正从“执行工具”变成了“认知系统”。自主数学发现恰好提供了一个规则清晰、验证严格、结果可观测量化的开放世界测试床。
这篇文章写清楚了几件事:开放世界多智能体环境的定义,四种交互模式在数学发现场景下的角色映射,以及一条知识从假设到入库的完整链路。你可以基于这套最小实现,把随机假设生成器替换成大模型或者符号回归算法,把数值验证替换成定理证明器,把通信层替换成真实的消息队列,逐步构建一个更接近真实的自主科学发现系统。
至于那些“把小龙虾集成进多智能体系统”的梗,当个段子听听挺好;但真正值得研究的,始终是这个系统能否产生它自己都没想到过的知识。