Consensus 的结果好不好,很大程度取决于问题怎么问。 这篇做
question_lint.py:检查问题是否笼统、是否带预设立场、有没有写明人群和结果,并把“近 5 年”“随机对照试验”等要求转换成 Consensus API 的筛选参数。
先看清成品
- “咖啡好不好”给出 3 条建议;“间歇性禁食是否能改善成年人的胰岛素敏感性?”通过。
- “近 5 年随机对照试验:…”转换为
{"year_min": 2021, "study_types": ["rct"], "human": "true"}。- 发现并修复:英文 “improve” 中包含 “prove”,被误判为带预设立场。pytest 6 项通过。
合规提醒:Consensus 的回答和要点摘录是 AI 生成的,可能遗漏或误读论文;引用时必须引用原论文,并阅读原文核对。医疗、健康、法律问题请咨询专业人士,不要把检索结果当成诊疗建议。本文只使用官方功能:Consensus 网页版、官方 API(x-api-key),以及 Crossref 公开 REST API。不抓取网页,不共享账号。调用次数和套餐以官方页面为准(本文不列价格)。
运行说明:本篇是纯本地规则,不调用任何接口。规则是我按 PICO 思路总结的经验,不是 Consensus 官方规则。所有测试都在 box 上真实运行过。
做完之后你会得到什么?
| 成果 | 说明 |
|---|---|
question_lint.py |
检查问题并生成筛选参数 |
test_lint.py |
6 项测试 |
需要准备哪些环境?
| 项目 | 说明 |
|---|---|
| Python | 3.9 以上,pip install pytest |
关键事实
| 事实 | 来源 |
|---|---|
study_types 的取值包括 rct、meta-analysis、systematic review 等 |
Consensus Search 接口参考 |
human=true 只返回人类研究;year_min 排除更早的论文 |
同上 |
文件结构
71-consensus-C-src/
├── question_lint.py
└── test_lint.py
第 1 步:脚本
"""提问前检查研究问题(PICO 思路:人群 Population、干预 Intervention、对照 Comparison、结果 Outcome),
并把要求翻译成 Consensus API(GET /v1/search)的筛选参数。规则是我总结的经验,不是 Consensus 官方规则。"""
import json, re, sys
VAGUE = ["好不好", "有没有用", "怎么样", "好吗", "is it good", "does it work", "worth it"]
LEADING = ["证明", "证实", "为什么.*有效", "为什么.*有害", "危害有多大", r"\bprove\b", r"\bwhy does\b.*\bwork\b"] # 英文要加词边界:prove 会匹配 improve
POP = ["成人", "成年", "儿童", "老年", "孕妇", "患者", "学生", "大学生", "青少年", "女性", "男性", "adults?", "children", "older", "patients", "students", "women", "men"]
OUTCOME = ["风险", "发生率", "死亡率", "成绩", "体重", "血压", "血糖", "胰岛素", "敏感性", "睡眠", "焦虑", "抑郁", "risk", "mortality", "weight", "blood pressure", "insulin", "sleep", "anxiety", "depression", "score"]
STUDY = {"rct": ["随机对照", "rct", "randomi[sz]ed"], "meta-analysis": ["荟萃", "meta"], "systematic review": ["系统综述", "systematic review"]}
def has(text, words): return any(re.search(w, text, re.I) for w in words)
def lint(q):
tips = []
if has(q, VAGUE): tips.append("太笼统:把“好不好”换成具体结果,例如“与 2 型糖尿病风险的关系”")
if has(q, LEADING): tips.append("带有预设立场:改成中性问法“X 是否影响 Y”,否则容易只看到支持的证据")
if not has(q, POP): tips.append("没写研究人群(例如成年人、儿童、2 型糖尿病患者)")
if not has(q, OUTCOME): tips.append("没写关注的结果(例如死亡率、血压、睡眠质量)")
if len(q) > 120: tips.append("太长:一次只问一个问题")
return tips
def filters(q, since=None):
f = {}
m = re.search(r"(近|最近|过去)\s*(\d+)\s*年|last (\d+) years", q, re.I)
if m and since: f["year_min"] = since - int(m.group(2) or m.group(3))
types = [k for k, ws in STUDY.items() if has(q, ws)]
if types: f["study_types"] = types
if has(q, ["人类", "人群", "成人", "成年", "儿童", "患者", "humans?", "adults?", "patients"]): f["human"] = "true"
return f
def main(argv=None):
argv = argv or sys.argv[1:]; q = argv[0]; year = int(argv[1]) if len(argv) > 1 else None
tips = lint(q)
print("问题:", q); print("建议:" if tips else "通过检查"); [print(" -", t) for t in tips]
print("API 筛选参数:", json.dumps(filters(q, year), ensure_ascii=False))
return 1 if tips else 0
if __name__ == "__main__":
sys.exit(main())
第 2 步:测试
import question_lint as Q
def test_vague():
t = Q.lint("咖啡好不好")
assert len(t) == 3 and t[0].startswith("太笼统")
def test_good_question():
q = "间歇性禁食是否能改善成年人的胰岛素敏感性?"
assert Q.lint(q) == []
def test_leading():
assert any("预设立场" in t for t in Q.lint("请证明维生素 D 能降低成年人的抑郁风险"))
def test_filters():
f = Q.filters("近 5 年随机对照试验:间歇性禁食是否改善成年人胰岛素敏感性", since=2026)
assert f == {"year_min": 2021, "study_types": ["rct"], "human": "true"}
def test_english():
assert Q.lint("Does creatine supplementation improve sleep in older adults?") == []
assert Q.filters("meta-analysis of exercise and depression in adults") == {"study_types": ["meta-analysis"], "human": "true"}
def test_improve_is_not_prove():
# 调试时发现:“improve” 中包含 “prove”,被误判为带预设立场
assert not any("预设立场" in t for t in Q.lint("Does exercise improve sleep in adults?"))
assert any("预设立场" in t for t in Q.lint("Prove that exercise improves sleep in adults"))
第 3 步:在 Consensus 中使用
把通过检查的问题粘贴到 Consensus 搜索框;网页版中用年份、研究类型等筛选器实现同样的限制。用 API 时把输出的参数传给 71A 的脚本。
第 4 步:运行
$ python question_lint.py "咖啡好不好"
问题: 咖啡好不好
建议:
- 太笼统:把“好不好”换成具体结果,例如“与 2 型糖尿病风险的关系”
- 没写研究人群(例如成年人、儿童、2 型糖尿病患者)
- 没写关注的结果(例如死亡率、血压、睡眠质量)
API 筛选参数: {}
$ python question_lint.py "近 5 年随机对照试验:间歇性禁食是否改善成年人胰岛素敏感性" 2026
问题: 近 5 年随机对照试验:间歇性禁食是否改善成年人胰岛素敏感性
通过检查
API 筛选参数: {"year_min": 2021, "study_types": ["rct"], "human": "true"}
$ python -m pytest -q
6 passed
怎么检查结果?
- 通过检查的问题应该能回答:研究谁?做了什么?和什么比较?看什么结果?
- 带预设立场的问题(“证明…”)要改成中性问法。
- 关键词列表是示例,要按你的领域补充。
调试示例
英文 “improve” 被判为带预设立场。 测试 “Does creatine supplementation improve sleep in older adults?” 时,脚本提示“带有预设立场”。原因是规则中的 prove 匹配到了 improve 的后半部分。修复:英文规则加词边界 \bprove\b。中文没有这个问题,因为“证明”不会出现在常见词的中间。
常见问题
| 现象 | 原因 | 处理 |
|---|---|---|
| 合理的问题也被提示缺少人群 | 关键词表里没有你的人群词 | 在 POP 中补充 |
| 年份没有转换 | 没有提供当前年份参数 | 运行时传入年份 |
| 英文问题误报 | 规则没有加词边界 | 英文规则统一用 \b |
模板规则
- 一次只问一个问题。
- 写清人群、干预和结果。
- 用中性问法。
- 规则只是提示,最终由你判断。
项目资源
| 用途 | 地址 |
|---|---|
| Consensus 官网 | https://consensus.app/ |
| Consensus API 入门(官方) | https://docs.consensus.app/api-get-started |
| Consensus Search 接口参考(官方) | https://docs.consensus.app/api-reference/search |
问题问清楚了,Consensus 才能找到对的论文。