当 AI 搜索开始「自我进化」,谁来进化它的核实?------「已核实」结论复核器:3 条结论挖出 2 个洞(附可运行代码)
今天(10 月 30 日),百度 APP 开产品升级沟通会,宣布搜索实现**「递归自我进化」:从"一次提问、一次回答"走向"一项任务、一份交付"------复杂问题交给搜索做多步查找与整理, "直接返回核实汇总后的结论"**;同时搜索 AI API 限时降到每千次 4.9 元,比 DeepSeek 搜索 API 还低。(以上是发布会口径,以官方为准。)
这个"递归自我进化"很值钱:百度把每一次真实检索和用户反馈沉淀成训练信号,经"检索---反馈---再训练"回流,驱动模型持续迭代,整体效率提升 80% 以上。
但我盯上的是另一句------"直接返回核实汇总后的结论"。
核心洞察:搜索负责找,「核实」谁来核?
搜索说自己"核实过了",可"核实"这个动作,也是模型做的。多步查找、汇总整理、下结论,每一步都是概率的。搜索会自我进化,进化的是"找得准、答得好";而"核实得对"这件事,进化管线里恰恰没人管------它核错的概率,是这套流程里最黑的那一环。
而且这不是百度一家的问题。让 AI 做多步查找再汇总出"已核实结论",是现在主流搜索/问答的标准做法。所以这篇不是要跟谁顶牛,是讲一个通用道理:
任何"AI 帮你核实过了"的结论,都值得再核一遍。
再核一遍用两层,各管一摊:
| 层 | 管什么 | 特点 |
|---|---|---|
| 本地对账 | 结论里的数字,用证据里的原始数复算 | 机器算的,确定性,不会判错 |
| 联网裁判 | 结论里的事实(年份、定义、归属) | LLM + 多源搜索取证,概率性,会波动 |
注意第二层也得多留意一下:AIHCC /detect 本身也是 LLM 判的,它不是神仙。所以两层要搭配------数字归本地计算,事实归联网取证,谁也别越界。
代码 1:安全求值------先别用 eval,和接口头一起
python
"""搜索核实结论复核器:AI 搜索说「已核实」,谁来核它的核实?
AI 搜索把「直接返回核实汇总后的结论」当卖点,可「核实」这个动作
也是模型做的------它核错的概率,恰恰是没人管的那一环。
这个脚本把 AI 搜索风格的「已核实结论」再核一遍,两层:
1) 本地数字对账:结论里的关键数,用证据里的原始数复算(确定性)
2) 联网事实裁判:结论句送 AIHCC /detect,数 refuted(概率性)
本地对不上、或联网判错,都算「核过的结论有洞」。
纯标准库(urllib)。用法:
export HALLUCC_API_KEY=hc_你的key # https://aihcc.cloud/keys 免费注册生成
python searchcheck.py
"""
from __future__ import annotations
import ast
import json
import os
import urllib.error
import urllib.request
API_URL = "https://aihcc.cloud/api/detect"
API_KEY = os.environ.get("HALLUCC_API_KEY", "").strip()
# ---------- 0. 安全求值(只用 AST 白名单,别用 eval) ----------
def arith(expr: str) -> float:
def walk(n):
if isinstance(n, ast.Expression):
return walk(n.body)
if isinstance(n, ast.Constant) and isinstance(n.value, (int, float)):
return float(n.value)
if isinstance(n, ast.BinOp):
a, b = walk(n.left), walk(n.right)
if isinstance(n.op, ast.Add):
return a + b
if isinstance(n.op, ast.Sub):
return a - b
if isinstance(n.op, ast.Mult):
return a * b
if isinstance(n.op, ast.Div):
return a / b
raise ValueError(f"非法表达式:{ast.dump(n)}")
return walk(ast.parse(expr.strip(), mode="eval"))
arith 只放行数字和四则运算,其它语法树节点直接拒------文本是数据,不是代码,这是所有处理 AI 输出代码的底线。
代码 2:样本------3 条 AI 搜索「已核实」的结论
三条结论模仿真搜索的风格:团建预算、择校学费、技术选型。每条都埋了不同性质的雷,看两层各自能抓哪个:
python
# ---------- 1. AI 搜索「已核实」的结论样本 ----------
# 每条:claim 结论句(送联网裁判),evidence 搜索给出的证据,
# checks 本地可复算的「表达式→结论声称值」对账项。
CONCLUSIONS: list[dict] = [
{
"name": "三亚团建预算",
"claim": "三亚 5 晚行程,团建总价 15400 元,比原价省下 2100 元。",
"evidence": "证据:原价 3500 元/晚,协议价 3080 元/晚,共 5 晚。",
"checks": [("3080*5", 15400), ("3500*5-3080*5", 2100)],
},
{
"name": "择校学费",
"claim": "A 校性价比最高:月均学费 8000 元,三年总学费 21.6 万元。",
"evidence": "证据:学费 8000 元/月,按 12 个月/年、共 3 年计。",
"checks": [("8000*12*3", 216000)],
},
{
"name": "技术选型",
"claim": "选型已核实:该项目基于 Go 开发,Go 1.0 稳定版于 2015 年发布。",
"evidence": "证据:无内部数字可复算,属事实声明,交联网裁判。",
"checks": [],
},
]
代码 3:本地对账------数字归机器算,确定性的一层
python
# ---------- 2. 本地数字对账(确定性,不花调用) ----------
def local_check(c: dict) -> tuple:
"""返回 (状态, 说明):状态 None=跳过 / True=一致 / False=有洞。"""
if not c["checks"]:
return None, "无内部数字可复算,转联网裁判"
bad = []
for expr, claimed in c["checks"]:
actual = arith(expr)
if abs(actual - claimed) > 1e-9:
bad.append(f"{expr} = {actual:g},结论却写 {claimed:g}")
if bad:
return False, ";".join(bad)
return True, "复算一致"
这一层的关键词是确定性:数字对不对,机器一算就是定论,不存在"可能判错"。
代码 4:联网裁判------事实句送 AIHCC /detect
python
# ---------- 3. 联网事实裁判(AIHCC /detect) ----------
def detect(text: str) -> tuple:
"""返回 (red 数, refuted 明细)。失败抛 RuntimeError,带人话原因。"""
if not API_KEY:
raise RuntimeError(
"缺少 HALLUCC_API_KEY:去 https://aihcc.cloud/keys 免费注册生成一个,"
"然后 export HALLUCC_API_KEY=你的key 再跑"
)
body = json.dumps({"text": text, "speed": "standard"}).encode("utf-8")
req = urllib.request.Request(
API_URL, data=body,
headers={"Content-Type": "application/json",
"Authorization": f"Bearer {API_KEY}"},
)
try:
with urllib.request.urlopen(req, timeout=180) as resp:
data = json.loads(resp.read().decode("utf-8"))
except urllib.error.HTTPError as e:
raise RuntimeError(f"HTTP {e.code}:{e.read().decode('utf-8', 'ignore')[:120]}")
except json.JSONDecodeError:
raise RuntimeError("响应不是 JSON(疑似网关错误页),稍后再试")
s = data.get("summary") or {}
refuted = [
(c["claim"].get("text", "")[:40],
str(c.get("verification", {}).get("reason", ""))[:60])
for c in data.get("claims", [])
if c.get("verification", {}).get("status") == "refuted"
]
return s.get("red", 0), refuted
两个细节:key 从环境变量读,不写死在代码里 ;json.JSONDecodeError 不是 URLError 的子类,网关回 HTML 时 json.loads 抛的是它,必须单独接,不然网络异常你以为没接住。
代码 5:主流程------两层合起来报洞
python
# ---------- 4. 复核主流程 ----------
def main() -> None:
print("=" * 66)
print("搜索核实结论复核器:AI 说「已核实」,我们核它的核实")
print(f"两层:本地数字对账 + AIHCC /detect 联网裁判 样本:{len(CONCLUSIONS)} 条结论")
print("=" * 66)
holes = 0
for i, c in enumerate(CONCLUSIONS, 1):
print(f"[{i}/{len(CONCLUSIONS)}] {c['name']}")
print(f" AI 搜索「已核实」结论:{c['claim']}")
print(f" {c['evidence']}")
ok, msg = local_check(c)
if ok is None:
print(f" ① 本地对账:跳过------{msg}")
elif ok:
print(f" ① 本地对账:✅ {msg}")
else:
print(f" ① 本地对账:❌ {msg}")
holes += 1
red, refuted = detect(c["claim"])
print(f" ② 联网裁判:/detect red={red}")
for t, rsn in refuted:
print(f" ❌ {t}")
print(f" ↳ {rsn}...")
if red:
holes += 1
print()
print("=" * 66)
print(f"AI 搜索声称「已核实」的 {len(CONCLUSIONS)} 条结论,复核出 {holes} 条有洞。")
print("搜索负责找,核验负责验------「已核实」三个字,本身也该被核一遍。")
print("=" * 66)
if __name__ == "__main__":
main()
串起来跑一遍(本地实测,Python 3.12.2)
export HALLUCC_API_KEY=你的key 后 python searchcheck.py,实际输出:
==================================================================
搜索核实结论复核器:AI 说「已核实」,我们核它的核实
两层:本地数字对账 + AIHCC /detect 联网裁判 样本:3 条结论
==================================================================
[1/3] 三亚团建预算
AI 搜索「已核实」结论:三亚 5 晚行程,团建总价 15400 元,比原价省下 2100 元。
证据:原价 3500 元/晚,协议价 3080 元/晚,共 5 晚。
① 本地对账:✅ 复算一致
② 联网裁判:/detect red=0
[2/3] 择校学费
AI 搜索「已核实」结论:A 校性价比最高:月均学费 8000 元,三年总学费 21.6 万元。
证据:学费 8000 元/月,按 12 个月/年、共 3 年计。
① 本地对账:❌ 8000*12*3 = 288000,结论却写 216000
② 联网裁判:/detect red=0
[3/3] 技术选型
AI 搜索「已核实」结论:选型已核实:该项目基于 Go 开发,Go 1.0 稳定版于 2015 年发布。
证据:无内部数字可复算,属事实声明,交联网裁判。
① 本地对账:跳过------无内部数字可复算,转联网裁判
② 联网裁判:/detect red=1
❌ Go 1.0 稳定版于 2015 年发布
↳ 多个证据一致显示 Go 1.0 稳定版于 2012 年发布(如证据[1]称"Go 1.0 (2012): 第一个稳定版本...
==================================================================
AI 搜索声称「已核实」的 3 条结论,复核出 2 条有洞。
搜索负责找,核验负责验------「已核实」三个字,本身也该被核一遍。
==================================================================
看懂这个结果,就读懂了今天这篇的一半:
- 第 1 条:两组复算全对,联网也干净------对照组,证明复核器不是漫无目的检查。
- 第 2 条 :本地抓到洞------
8000×12×3 = 288000,结论却写 21.6 万 (少了 7.2 万)。而联网裁判 red=0,放过了它。这就是为什么必须要有本地确定性对账这一层:LLM 裁判对算术是宽容的,机器复算不是。 - 第 3 条 :本地没数字可算,交给联网------Go 1.0 稳定版"于 2015 年发布",被 refuted:多个证据一致显示是 2012 年。这就是为什么也得有联网裁判:本地只能管数,管不了事实。
两条有洞,一条是算术、一条是事实,恰好各被一层抓到。 这就是"再核一遍"的意义:AI 说核过了,两层一上,2/3 有洞。
适用范围也得说清楚
- 联网裁判是概率性的。 /detect 靠搜索取证 + LLM 判定,同一条结论今天和明天可能不同。重要结论别只看一次,跑 2~3 次看稳定的那面;判据看
summary.red总量,别抠单句。 - 本地对账是确定性的,但只管数字。 它算死的,不会"判错";可它也管不了"Go 是 2012 年发布"这种事------那是事实层,得联网。
- 样本要像你真搜的结论。 我放的是团建、择校、选型,你把它换成你业务里让 AI 搜索去查的东西,结论才有用。
现成裁判:AIHCC /detect
上面联网那一层,就是 AIHCC 的 /detect:逐句抽取声明、分类,数字和日期走确定性复算,事实声明走多源搜索取证 ,最后逐句标注并给出存疑句数(summary.red)。也有 MCP 可以直接挂进你的 Agent 或 CI。
它有 Duet 定时任务:自动生成的晨报/巡检先过核验,有存疑句或没核验成的转人工审批,点头才发布。把本文的复核器挂进你接入 AI 搜索的流程里,每次拿到"已核实"的结论先过一遍两层------这就是把"信 AI"变成"核 AI"。
写在最后
搜索进化得越快,我们越容易把"AI 已核实"当成事实。可"核实"本身也是 AI 干的,它那一步,也在概率上。
所以下次再看到"AI 已核实"四个字,多问一句:
核实过了吗?谁核的?用什么核的?
要是答案是"AI 自己核的"------那值得再核一遍。
代码说明:全文合并为
searchcheck.py,基于 Python 3.10+ 标准库(ast / json / os / urllib),无第三方依赖;demo 输出为本地实测结果(Python 3.12.2,standard 档,3 次真实调用)。运行前需自备HALLUCC_API_KEY(https://aihcc.cloud/keys 免费注册生成),代码中不含任何真实 key。结论样本为演示用合成内容;Go 1.0 稳定版实际于 2012 年发布,用作对照。百度搜索升级为 2026-10-30 发布会口径,以官方为准。
#大模型 #AI搜索 #AI幻觉 #Python #Agent安全