AI 工具

核查 AI 代码回答的引用来源:验证链接、API 与弃用信息

Devv 现在的定位: 截至 2026-10-21,devv.ai 首页和官方文档把 Devv 介绍为“用自然语言构建 AI 网页应用”的编程智能体(Devv Code),并内置数据库、登录、LLM 等集成;页脚的产品列表中仍有 Devv Search,devv.ai/search 也能打开。本组教程中,A、B 篇针对 Devv Search 这类“带来源的

BINBHO · 图文教程

Devv 现在的定位: 截至 2026-10-21,devv.ai 首页和官方文档把 Devv 介绍为“用自然语言构建 AI 网页应用”的编程智能体(Devv Code),并内置数据库、登录、LLM 等集成;页脚的产品列表中仍有 Devv Search,devv.ai/search 也能打开。本组教程中,A、B 篇针对 Devv Search 这类“带来源的技术回答”,C 篇适用于向 Devv Code 粘贴报错信息的场景。

Devv Search 的回答会附上参考链接,但链接可能已经失效、版本不对,或根本没有提到回答使用的 API。 这篇做 cite_check.py:逐个打开引用链接,判断是不是官方文档、是哪个版本、页面是否提到回答中的 API、有没有弃用说明。

先看清成品

  • 真实访问 3 个链接:DataFrame.append 的官方文档页 404(该方法在 pandas 2.0 删除);Stack Overflow 返回 403(拒绝脚本访问,不是死链)。
  • concat 页面含“Deprecated since version 3.0.0”,脚本附上前文,看出弃用的是 copy 参数,不是 concat 本身。
  • 发现并修复:只报“页面含 Deprecated”会误导。pytest 4 项通过(离线)。

合规提醒:不要把公司私有代码、密钥、内部地址和用户数据粘贴给 Devv 或其他 AI 工具;引用 AI 给出的代码时注意开源许可证。本文只使用 Devv 官方网页功能,不调用非官方接口,不自动化操作 Devv 网站。额度和套餐以官网为准(本文不列价格)。

运行说明:box 上没有使用 Devv 账号,没有向 Devv 提问。示例“回答”(answer.md)是我按 AI 搜索回答常见的样子写的,不是 Devv 的真实输出。脚本和测试都在 box 上真实运行过(Python 3.13;pandas 3.0.6,另一个虚拟环境中为 pandas 2.2.3)。B 篇真实访问了回答中引用的 3 个链接。

做完之后你会得到什么?

成果 说明
cite_check.py 检查引用链接
answer.md 与 A 篇相同的示例回答
test_cite.py 4 项离线测试

需要准备哪些环境?

项目 说明
Python 3.9 以上,pip install requests pytest pandas
Devv 浏览器访问 devv.ai,登录账号(本文没有实际使用)
第二个虚拟环境(可选) A 篇用来对比不同库版本,例如 pip install "pandas==2.2.3"

关键事实

事实 来源
pandas 2.0 删除了 DataFrame.append() pandas 2.0.0 发布说明
pandas 3.0 中 concat 的 copy 参数已被忽略并弃用 pandas.concat 官方文档(实测页面内容)

文件结构

73-devv-B-src/
├── cite_check.py
├── answer.md
└── test_cite.py

第 1 步:脚本

"""检查 AI 回答中引用的链接:能否打开、是不是官方文档、文档是哪个版本、页面里是否提到回答所用的 API、有没有“deprecated / removed”字样。
链接打不开(404)往往说明 API 已被删除或改名;403/429 多半是网站拒绝脚本访问,要用浏览器手动看,不能直接当成死链。"""
import html, re, sys, time, requests

OFFICIAL = {"pandas.pydata.org": "pandas 官方文档", "docs.python.org": "Python 官方文档", "nextjs.org": "Next.js 官方文档",
            "react.dev": "React 官方文档", "developer.mozilla.org": "MDN", "numpy.org": "NumPy 官方文档"}
UA = {"User-Agent": "binbho-tutorial/1.0 (citation check)"}

def links(text): return sorted(set(re.findall(r"https?://[^\s)>\]]+", text)))

def symbols(text):
    """回答正文中用反引号标出的 API 名(代码块之外)。"""
    body = re.sub(r"```.*?```", "", text, flags=re.S)
    return sorted({s for s in re.findall(r"`([A-Za-z_][\w.]*)`", body)})

def version_of(url):
    m = re.search(r"/version/([\d.]+)/|/(\d+\.\d+)/", url)
    return m.group(1) or m.group(2) if m else ("stable/最新版" if "/docs/" in url or "/stable/" in url else "")

def check(url, syms, get=requests.get):
    host = re.sub(r"^www\.", "", url.split("/")[2]); kind = OFFICIAL.get(host, "第三方")
    try: r = get(url, headers=UA, timeout=30, allow_redirects=True)
    except requests.RequestException as e: return {"url": url, "kind": kind, "verdict": f"无法连接({type(e).__name__})"}
    res = {"url": url, "kind": kind, "status": r.status_code, "version": version_of(url) if kind != "第三方" else ""}
    if r.status_code == 404: res["verdict"] = "404:页面不存在(API 可能已删除或改名)"
    elif r.status_code in (401, 403, 429): res["verdict"] = f"{r.status_code}:网站拒绝脚本访问,请用浏览器手动查看"
    elif r.status_code >= 400: res["verdict"] = f"HTTP {r.status_code}"
    else:
        page = html.unescape(re.sub(r"\s+", " ", re.sub(r"<[^>]+>", " ", r.text)))
        res["mentions"] = [s for s in syms if s.split(".")[-1] in page]
        dep = re.search(r"[Dd]eprecated since version [\d.]+|has been removed|Deprecated", page)
        # 只报“页面含 Deprecated”会误导:pandas.concat 页面中弃用的是 copy 参数,不是 concat 本身。所以附上前文
        res["verdict"] = "可以打开" + (f";页面含弃用说明:“…{page[max(0, dep.start() - 140):dep.end()].strip()}”" if dep else "")
    return res

def main(argv=None):
    argv = argv or sys.argv[1:]; text = open(argv[0], encoding="utf-8").read(); syms = symbols(text)
    print("回答中提到的 API:", ", ".join(syms) or "无"); bad = 0
    for u in links(text):
        r = check(u, syms); time.sleep(0.5)
        bad += not r["verdict"].startswith("可以打开")
        extra = f",版本 {r['version']}" if r.get("version") else ""
        print(f"[{r['kind']}{extra}] {u}\n    {r['verdict']}" + ((";页面提到 " + ", ".join(r["mentions"]) if r["mentions"] else ";页面未提到回答所用的 API") if "mentions" in r else ""))
    print(f"{bad} 个链接需要人工处理"); return 1 if bad else 0

if __name__ == "__main__":
    sys.exit(main())

第 2 步:测试

import cite_check as C

class R:
    def __init__(self, code, text=""): self.status_code = code; self.text = text

def fake(table):
    return lambda url, **k: table[url]

TEXT = open("answer.md", encoding="utf-8").read()

def test_extract():
    assert len(C.links(TEXT)) == 3 and C.symbols(TEXT) == ["append"]       # 代码块里的内容不算

def test_404_and_403():
    g = fake({"https://x.org/a": R(404), "https://stackoverflow.com/q": R(403)})
    assert C.check("https://x.org/a", [], g)["verdict"].startswith("404")
    assert "浏览器手动查看" in C.check("https://stackoverflow.com/q", [], g)["verdict"]

def test_deprecation_context():
    page = "<dt>copy</dt><dd>bool, default False. This keyword is now ignored. <p>Deprecated since version 3.0.0: will be removed</p></dd>"
    r = C.check("https://pandas.pydata.org/docs/reference/api/pandas.concat.html", ["concat"], fake({"https://pandas.pydata.org/docs/reference/api/pandas.concat.html": R(200, page)}))
    assert "copy bool" in r["verdict"] and r["kind"] == "pandas 官方文档" and r["version"] == "stable/最新版"
    assert r["mentions"] == []

def test_versions():
    assert C.version_of("https://pandas.pydata.org/pandas-docs/version/1.5/reference/x.html") == "1.5"
    assert C.version_of("https://docs.python.org/3.12/library/re.html") == "3.12"

第 3 步:运行

$ python cite_check.py answer.md
回答中提到的 API: append
[pandas 官方文档,版本 stable/最新版] https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.append.html
    404:页面不存在(API 可能已删除或改名)
[pandas 官方文档,版本 stable/最新版] https://pandas.pydata.org/docs/reference/api/pandas.concat.html
    可以打开;页面含弃用说明:“…lways sorted lexicographically. copy bool, default False This keyword is now ignored; changing its value will have no impact on the method. Deprecated since version 3.0.0”;页面未提到回答所用的 API
[第三方] https://stackoverflow.com/questions/75956209/error-dataframe-object-has-no-attribute-append
    403:网站拒绝脚本访问,请用浏览器手动查看
2 个链接需要人工处理
$ python -m pytest -q
4 passed

怎么检查结果?

  • 404 的官方文档链接:去旧版本文档或发布说明中确认 API 是否已删除。
  • 403/429:用浏览器打开看,不要直接当成死链。
  • “页面未提到回答所用的 API”说明这个引用可能只是相关,而不是依据。

调试示例

弃用提示误导。 第一版发现页面中有 “Deprecated” 就提示“页面含 Deprecated since version 3.0.0”。concat 页面得到这个提示,看起来像 concat 也被弃用了,而 concat 正是 append 的官方替代方案。

我去掉 HTML 标签后查看上下文:

copy bool, default False This keyword is now ignored; changing its value will have no impact on the method. Deprecated since version 3.0.0: This keyword is ignored and will be removed in pandas 4.0.

被弃用的只是 copy 参数。修复:提示中附上弃用说明前面约 140 个字符(第一次取 90 个字符,正好截掉了 “copy”,又加长了一次)。

常见问题

现象 原因 处理
大量 403 网站拒绝脚本 手动打开;不要绕过网站的限制
官方域名没有被识别 OFFICIAL 表中没有 补充你常用的文档域名
页面提到 API 但版本不对 引用的是旧版本文档 看 URL 中的版本号

模板规则

  • 每个引用至少打开一次。
  • 优先看官方文档,并确认版本。
  • 403 不等于死链。

项目资源

用途 地址
Devv 官网 https://devv.ai/
Devv Search https://devv.ai/search
Devv 官方文档 https://docs.devv.ai/introduction
pandas 2.0.0 发布说明 https://pandas.pydata.org/docs/whatsnew/v2.0.0.html
pandas.concat 官方文档 https://pandas.pydata.org/docs/reference/api/pandas.concat.html

引用能打开,还要看它说的是不是你要的那件事。