AI 工具

运行并核验 AI 搜索回答中的 Python 代码:隔离进程与依赖版本

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 粘贴报错信息的场景。

AI 搜索给出的代码经常基于旧版本的库。 这篇做 run_snippets.py:把回答(Markdown)中的 Python 代码块逐个在独立进程中运行,显示所用库的版本,并能指定项目自己的虚拟环境来运行。

先看清成品

  • 示例回答 3 个代码块:pandas 3.0.6 下 2 个失败(DataFrame.append 已删除;infer_datetime_format 参数已删除)。
  • 同一份回答在 pandas 2.2.3 下只有 1 个失败,另一个通过但给出 FutureWarning。版本不同,结论不同。
  • 发现并修复:正则漏掉 import pandas as pd, io 中的 io,改用 ast 解析。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 个链接。

做完之后你会得到什么?

成果 说明
run_snippets.py 运行回答中的代码块
answer.md 示例回答(我写的)
test_snippets.py 4 项测试

需要准备哪些环境?

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

关键事实

事实 来源
pandas 2.0 删除了 Series.append() 和 DataFrame.append(),改用 concat() pandas 2.0.0 发布说明
Devv 官方 FAQ:项目出错时可以把开发者控制台中的报错信息复制给 Devv;AI 把项目改坏时,最佳做法是手动回退,而不是让 AI 继续修 Devv 官方 FAQ / Getting started

run_snippets.py 带超时并在临时目录中运行,但不是安全沙箱:只运行你看得懂的代码。

文件结构

73-devv-A-src/
├── run_snippets.py
├── answer.md
└── test_snippets.py

第 1 步:保存回答(手动)

在 Devv Search 中提问后,把回答复制保存为 answer.md(保留代码块的 ```python 标记)。

第 2 步:示例回答

<!-- 示例:我按 AI 搜索回答常见的样子写的,不是 Devv 的真实输出 -->
## 问题:pandas 里怎么把一行字典追加到 DataFrame?

可以用 `append`:

```python
import pandas as pd
df = pd.DataFrame({"name": ["Ann"], "score": [90]})
df = df.append({"name": "Bob", "score": 85}, ignore_index=True)
print(len(df))
```

如果要追加很多行,更高效的做法是先收集成列表,再一次性构造:

```python
import pandas as pd
rows = [{"name": "Ann", "score": 90}, {"name": "Bob", "score": 85}]
df = pd.DataFrame(rows)
print(len(df))
```

读取时指定日期列:

```python
import pandas as pd, io
df = pd.read_csv(io.StringIO("d,v\n2026-01-02,1\n"), parse_dates=["d"], infer_datetime_format=True)
print(df["d"].dt.year.iloc[0])
```

参考:
- https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.append.html
- https://pandas.pydata.org/docs/reference/api/pandas.concat.html
- https://stackoverflow.com/questions/75956209/error-dataframe-object-has-no-attribute-append

第 3 步:脚本

"""把 AI 回答(Markdown)里的 Python 代码块逐个在独立子进程中运行,并报告所用库的版本。
AI 搜索给出的代码可能基于旧版本;先在你项目实际使用的版本上跑一遍,再复制到项目里。
注意:只运行你看得懂的代码。每段代码都在临时目录中、带超时运行,但这不是安全沙箱。"""
import ast, re, subprocess, sys, tempfile

BLOCK = re.compile(r"```(?:python|py)\n(.*?)```", re.S)

def blocks(text): return [b.strip() for b in BLOCK.findall(text)]

def imports(code):
    """用 ast 解析 import;正则无法处理 `import pandas as pd, io` 这种写法(调试时漏掉了 io)。"""
    try: tree = ast.parse(code)
    except SyntaxError: return set()
    names = set()
    for n in ast.walk(tree):
        if isinstance(n, ast.Import): names |= {a.name.split(".")[0] for a in n.names}
        elif isinstance(n, ast.ImportFrom) and n.module and not n.level: names.add(n.module.split(".")[0])
    return names

PY = sys.executable

def version(pkg):
    """查询运行代码所用解释器中的版本(可能是 --python 指定的另一个虚拟环境)。"""
    r = subprocess.run([PY, "-c", f"import importlib.metadata as m; print(m.version({pkg!r}))"], capture_output=True, text=True)
    return r.stdout.strip() if r.returncode == 0 else None

def run(code, timeout=60):
    with tempfile.TemporaryDirectory() as d:
        p = subprocess.run([PY, "-W", "default", "-c", code], cwd=d, capture_output=True, text=True, timeout=timeout)
    err = p.stderr.strip().splitlines()
    last = next((l for l in reversed(err) if re.match(r"\w+(Error|Exception|Warning)\b", l) or "Warning:" in l), err[-1] if err else "")
    return p.returncode, p.stdout.strip(), last, [l.strip() for l in err if "Warning" in l]

def main(argv=None):
    global PY
    argv = list(argv or sys.argv[1:])
    if "--python" in argv: i = argv.index("--python"); PY = argv[i + 1]; del argv[i:i + 2]      # 用项目自己的虚拟环境运行
    text = open(argv[0], encoding="utf-8").read(); bad = 0
    for i, code in enumerate(blocks(text), 1):
        vers = {n: version(n) for n in sorted(imports(code)) if version(n)}
        rc, out, last, warns = run(code); bad += rc != 0
        print(f"代码块 {i}({', '.join(f'{k} {v}' for k, v in vers.items()) or '仅标准库'}):{'通过' if rc == 0 else '失败'}")
        if out: print("   输出:", out)
        if rc: print("   错误:", last)
        for w in warns: print("   警告:", w)
    print(f"{bad} 个代码块失败"); return 1 if bad else 0

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

第 4 步:测试

import os, pytest, run_snippets as R

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

def test_extract():
    b = R.blocks(TEXT)
    assert len(b) == 3 and R.imports(b[2]) == {"pandas", "io"}

def test_run_current_env():
    rc, out, last, _ = R.run(R.blocks(TEXT)[0])
    assert rc == 1 and last.startswith("AttributeError: 'DataFrame' object has no attribute 'append'")
    assert R.run(R.blocks(TEXT)[1])[:2] == (0, "2")

def test_syntax_error_and_timeout():
    assert R.run("print(")[2].startswith("SyntaxError")
    with pytest.raises(Exception): R.run("while True: pass", timeout=1)

@pytest.mark.skipif(not os.path.exists("/tmp/p/v73p2/bin/python"), reason="需要装有 pandas 2.2.3 的第二个虚拟环境")
def test_other_interpreter(monkeypatch):
    monkeypatch.setattr(R, "PY", "/tmp/p/v73p2/bin/python")
    assert R.version("pandas") == "2.2.3"
    rc, out, _, warns = R.run(R.blocks(TEXT)[2])
    assert rc == 0 and out == "2026" and "FutureWarning" in warns[0]

第 5 步:运行

$ python run_snippets.py answer.md
代码块 1(pandas 3.0.6):失败
   错误: AttributeError: 'DataFrame' object has no attribute 'append'
代码块 2(pandas 3.0.6):通过
   输出: 2
代码块 3(pandas 3.0.6):失败
   错误: TypeError: read_csv() got an unexpected keyword argument 'infer_datetime_format'
2 个代码块失败
$ python run_snippets.py answer.md --python ~/venvs/pandas22/bin/python
代码块 1(pandas 2.2.3):失败
   错误: AttributeError: 'DataFrame' object has no attribute 'append'. Did you mean: '_append'?
代码块 2(pandas 2.2.3):通过
   输出: 2
代码块 3(pandas 2.2.3):通过
   输出: 2026
   警告: <string>:2: FutureWarning: The argument 'infer_datetime_format' is deprecated and will be removed in a future version. A strict version of it is now the default, see https://pandas.pydata.org/pdeps/0004-consistent-to-datetime-parsing.html. You can safely remove this argument.
1 个代码块失败
$ python -m pytest -q
4 passed

怎么检查结果?

  • 每个代码块都标出了实际运行时的库版本。
  • 失败的代码块:把错误信息连同版本号再问一次,或直接查官方文档。
  • 通过但有 FutureWarning 的代码,在下一个大版本中可能失败。

调试示例

1. 漏掉了 io。 第一版用正则提取 import,import pandas as pd, io 只得到 pandas,因为正则在 as pd 处停止了匹配。测试发现后改用 Python 自带的 ast 模块解析,各种写法都能正确识别。

2. 版本号取错了环境。 加入 --python 参数时我发现,第一版的版本号是在脚本自己的环境中查询的,而代码却在另一个环境中运行,结果会显示 pandas 3.0.6,而实际运行的是 2.2.3。改为在目标解释器中查询版本。

3. 同一份回答,两种结论。 第 3 个代码块在 pandas 2.2.3 下能运行,只有 FutureWarning;在 3.0.6 下直接 TypeError。所以检查 AI 代码时,一定要用项目实际使用的版本来运行。

常见问题

现象 原因 处理
全部失败:ModuleNotFoundError 运行环境里没装这个库 用 --python 指向项目的虚拟环境
代码块没被识别 代码块没有标注 python 补上 ```python
运行超时 代码在等待输入或网络 这类代码不适合自动运行,手动检查

模板规则

  • AI 给的代码,先在项目的版本上运行。
  • 失败时带上版本号再问。
  • 不运行看不懂的代码。

项目资源

用途 地址
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
Devv 官方 FAQ https://docs.devv.ai/FAQ

代码能不能用,运行一次就知道。