第 21 章:科学发现——Scientific discovery
第 21 章:科学发现——Scientific discovery
官方 use-case-map 把"科学发现"列为一个独立行业方向,它落在四类判断上:从海量论文里筛出相关的、给若干候选假设排序、决定该做哪个实验、以及在流水线里做可并行的分块判定。本章以官方要点为主干,配通用示例代码讲清每一种判定,并如实交代当前社区的实现状况。
先说一个诚实的现状
必须先把话说在前面:在 awesome-jev 的 scientific-pipelines 分类里,目前还没有收录任何具体项目(分类文件中只有一行"暂无直接相关的 Jev 示例"的占位注释)。这不奇怪——科研流水线通常是实验室内部系统,不像浏览器插件或小游戏那样容易开源成 demo。
因此本章不虚构任何项目名,而是回到官方 use-case-map 对 Scientific discovery 的要点,把它当成一段"理解问题本身是什么"的说明,再用通用示例代码演示"如果我来搭,会长什么样"。唯一的真实数据来自社区实践记录:有人报告用 Jev 整理约 2,300 篇 AI 研究论文,耗时约 83 秒、总花费 0.14 美元。这一个数字,足以说明科研场景里"大批量语义判定"的经济性。
科学发现里的三种重复判定
科研工作里有一类判断,研究者每天都在做,但它们的本质其实是语义判定而非"提出新东西":
- 分诊(triage):这篇论文跟我的课题相关吗?这条摘要值得精读吗?这个结论支持还是反对我的假设?
- 排序(ranking):这几个候选假设里,哪个更新颖、更可信、更可验证?先追哪一条?
- 取舍(selection):下一批实验做哪一个?参数按哪种方案设?这条失败的结果是该放弃还是该复查?
这三件事有个共同点:判断的量很大,而每次判断本身很轻。一篇论文"相关不相关"是个布尔;一个假设的"可信度"是个有序分;一个实验的"优先级"是个选择。它们全落在 Jev 的三种类型化输出里——Noul、Score、Choice。这正是决策层与生成模型分工的地方:生成模型负责提出假设、写摘要、拟实验方案;判定哪些值得看、哪个更靠谱,交给决策层。
判定一:文献筛选与分诊
科研里最先遇到的瓶颈是"读不完"。每天新出的预印本成百上千,你得先决定"哪些值得花时间"。这一步不需要生成任何文字,只需要对每篇论文问一个封闭问题。用 Noul 逐篇判定:
def is_relevant(paper_abstract: str, topic: str) -> tuple[bool, float]:
d = client.systemone(
state=f"课题:{topic}\n论文摘要:{paper_abstract}",
questions={
"relevant": {
"type": "noul",
"question": "这篇论文的方法或结论,是否直接服务于上述课题?",
}
},
instructions="只看摘要里陈述的方法与结论,不要因为关键词重合就判相关。",
)
return d["relevant"].value, d["relevant"].probability关键在于概率的用法:0.9 以上直接放进精读列表,0.5 到 0.9 之间进入待复核队列,0.5 以下放下。
p = is_relevant(abstract, topic)[1]
if p >= 0.9:
reading_list.append(paper)
elif p >= 0.5:
review_queue.append(paper) # 人工快速扫一眼当你的候选是"完全相关 / 方法相关 / 主题相邻 / 无关"这类分层时,就把 Noul 换成 Choice——注意"多选"是从分层里选一个。这一层筛完之后,真正进入精读的论文量往往能降一个数量级,而这一步的成本低到可以忽略(参考那条 2.3K 论文 0.14 美元的记录)。
判定二:假设排序与取舍
筛选之后是取舍:手上有几个候选假设,资源只够先追一两个。这里的判断是"程度",用 Score 比 Choice 更合适,因为你要的是相对次序,不是"哪个是唯一正确"。
def rank_hypotheses(hypotheses: list[str], context: str) -> list[tuple[str, float]]:
questions = {
f"h_{i}": {
"type": "score",
"question": "这个假设值得优先投入的程度?",
"labels": ["很低", "偏低", "中等", "偏高", "很高"],
}
for i, _ in enumerate(hypotheses)
}
state = context + "\n\n" + "\n".join(
f"H{i}: {h}" for i, h in enumerate(hypotheses)
)
d = client.systemone(
state=state,
questions=questions,
instructions=(
"从新颖性、与已有证据的一致性、可验证性三方面综合评估。"
"可验证性低、或与已有强证据冲突的假设,应给较低分。"
),
)
scored = [(h, d[f"h_{i}"].score) for i, h in enumerate(hypotheses)]
return sorted(scored, key=lambda x: x[1], reverse=True) # score = Σ i·p_i注意 score = Σ i·p_i 得到的是一个连续值,五个档位对应 1–5,于是排序就有了细粒度依据,而不是"谁被标成了高"这种粗判断。这里的 instructions 是重点:把"新颖性/一致性/可验证性"这三个维度写清楚,模型才知道你在权衡什么。多维度打分也可以拆成多道 Score 题,各给一个分,再由代码加权——这比让模型自己"综合一下"更可控,因为权重握在你手里。
判定三:实验设计的判定
到了实验环节,判断又变成"选一个动作"。该做哪一组实验、参数往哪个方向调,本质是一道 Choice。
def pick_experiment(candidates: list[dict], constraints: str) -> str:
d = client.systemone(
state="候选实验:\n" + "\n".join(
f"- {c['id']}: {c['desc']}(预计成本 {c['cost']})" for c in candidates
) + f"\n约束:{constraints}",
questions={
"next": {
"type": "choice",
"question": "在给定约束下,下一个应该做哪个实验?",
"choices": [c["id"] for c in candidates],
},
"informative": {
"type": "noul",
"question": "所选实验的结果,是否能有效区分当前的主要竞争假设?",
},
},
instructions="优先选择信息增益最大、且在约束内可完成的实验。",
)
if d["informative"].probability < 0.6:
escalate_to_human(candidates) # 判别力不足,交回研究者
return d["next"].choice这里配了一道 Noul 作为自我检查:"这个实验真的能区分竞争假设吗?"——这是科研场景里很实用的护栏。一个实验如果对区分假设没有信息增益,做了也是浪费。当这个 Noul 的概率偏低时,代码把决定交回给人,而不是盲目执行。
判定四:把筛选做成 Map Reduce
科学发现最典型的规模化形态,就是"对一大批材料逐个做同一个判定,再聚合"。这正是第 22 章要展开的 Map Reduce 模式,只是它在这里的落地对象是文献库、候选分子集或实验日志。
import asyncio
async def triage_batch(papers: list[dict], topic: str) -> dict:
# Map:把每篇论文(或每小批)作为一个独立判定并发发出
async def one(p):
return p["id"], await client.systemone_async(
state=f"课题:{topic}\n摘要:{p['abstract']}",
questions={"relevant": {"type": "noul",
"question": "是否直接服务于该课题?"}},
instructions="只依据摘要陈述的方法与结论判断。",
)
results = await asyncio.gather(*[one(p) for p in papers])
# Reduce:用代码聚合,而不是再问一次模型
kept, review = [], []
for pid, d in results:
p = d["relevant"].probability
if p >= 0.9:
kept.append(pid)
elif p >= 0.5:
review.append(pid) # 概率中等,进待复核队列
return {"keep": kept, "review": review}Map 阶段是并发的语义判定,Reduce 阶段是纯代码的聚合。 聚合逻辑(阈值怎么切、怎么归类)不交给模型,因为它是确定的、需要可复现的。这条流水线跑起来的样子,就是那条被记录下来的真实数据——约 2,300 篇论文、约 83 秒、0.14 美元:83 秒主要花在批量的并发判定上,0.14 美元摊到每篇论文上是万分之六美分。
flowchart LR
P["论文/候选/日志
(海量条目)"] --> T{"Map:逐条或分批
做类型化判定"}
T -- Noul --> F["筛选:相关?”"]
T -- Score --> R["排序:优先度"]
T -- Choice --> S["取舍:做哪个"]
F --> AGG["Reduce:代码聚合
(阈值/分类,确定)"]
R --> AGG
S --> AGG
AGG --> H["研究者:读清单、定方案"]
AGG -.低置信/判别力不足.-> H一个务实的边界
关于科学发现,有几点必须说清,以免读者被"AI 做科研"的叙事带跑:
- Jev 不提出假设。 它擅长的是判定"这个已有假设值不值得追"。提出新想法是生成任务,交给 chat 模型或人。
- Jev 不下结论。 它给的是"相关/不相关""优先度高低"这种辅助判断,终审权在研究者手里。上面代码里那些
escalate_to_human和低阈值分支,就是这条原则的落实。 - 领域知识是瓶颈。 在非常专门的领域里,判断新颖性与一致性需要深厚的背景知识,模型的世界知识是否够用,是公开讨论里反复被质疑的点。把它当"高效的初筛助手"而不是"决策者",风险最小。
- 目前社区尚无高星开源实现。 本章的四段代码是通用做法演示,不是某个已发布项目的复刻;它的价值在于展示判定该怎么切分,而非给出一个可直接跑的生产系统。等 awesome-jev 的
scientific-pipelines分类积累出真实项目后,这里可以补上具体案例与实测。
小结
- 科学发现落在四类重复的语义判定上:文献分诊、假设排序、实验取舍、可并行的分块判定,分别对应
Noul、Score、Choice与 Map Reduce。 - 分诊用
Noul逐篇问"是否直接服务于课题",用概率做三档分流;排序用Score,score = Σ i·p_i给出细粒度次序;取舍用Choice,并可配一道Noul自检实验的判别力。 - 科研流水线的规模化形态是 Map Reduce:Map 阶段并发做类型化判定,Reduce 阶段用纯代码聚合,保证可复现。
- 唯一可引用的真实数据是社区记录:Jev 整理约 2,300 篇 AI 论文、约 83 秒、0.14 美元,印证了大批量判定的经济性。
- 必须交代的边界:awesome-jev 的
scientific-pipelines分类目前为空,尚无高星开源实现;本章代码为通用做法,不指向任何具体项目。 - 定位要克制:Jev 负责"筛选与排序",不负责"提出假设"与"下结论",终审权始终在研究者手里。
至此,第四部分"垂直领域与实时场景"告一段落。下一章开始进入第五部分,看这套判定思路如何在真正的大数据规模上以 Map Reduce 的方式展开。