让 Codex 写出一个脚本并不难,难的是判断:它有没有改错输入、漏掉坏数据,或者把约定好的退出码当成程序故障。
这次用 JSONL 数据检查器串起安装、项目指令、开发、验收和续接。它适合采集结果、语料清洗前的格式检查,与此前 CSV 入门练习不同。重点是把“请帮我检查数据”变成可以独立判断的交付条件。
一、先准备对应系统的 CLI
本文讲 Codex CLI。桌面应用、IDE 扩展有各自的安装与界面,不把它们的步骤混在终端命令里。以下命令于 2026-09-20 对照官方资料核查。
Windows 在 PowerShell 中安装;官方当前同一命令也用于更新:
powershell -ExecutionPolicy ByPass -c "irm https://chatgpt.com/codex/install.ps1 | iex"
macOS、Linux 在各自终端中安装或更新:
curl -fsSL https://chatgpt.com/codex/install.sh | sh
如果已经用 npm 或 Homebrew 管理 Codex,就继续用原来的渠道更新,避免装出两个不同版本。官方入口及替代安装方法见 Codex CLI。
安装后重新打开终端,执行 codex --version。Windows 用 Get-Command codex 检查命令位置;macOS/Linux 用 command -v codex。命令找不到先查 PATH 与当前终端,不要立刻改项目代码。
Windows 可以原生运行,WSL 不是必选。如果项目依赖 Linux 工具链,可以选择 WSL 2,在 Linux 环境内安装工具,并把仓库放在 Linux 主目录;Windows 终端与 WSL 的安装位置和 Python 环境应分别核对。参见 Windows 原生环境 和 WSL 指南。
二、进入练习目录,再登录和确认权限
新建一个空目录 jsonl-lab,进入该目录执行 codex,按官方界面完成适用的账号登录。不要把凭据写进项目指令文件。
会话内先用 /status 查看当前状态,再用 /permissions 确认允许的文件与命令范围。项目只需读写这个练习目录,不需要因为一个报错就扩大到整个磁盘。常用命令可查 CLI 命令说明。
本例额外需要 Python 3;这是示例脚本的运行依赖,不是把 Python 当成 Codex 的安装依赖。Windows 可先试 py -3 --version,macOS/Linux 可先试 python3 --version。如果你的环境使用其他解释器入口,后面的命令要相应调整。
在项目根目录准备 AGENTS.md,可写成:
本项目使用 Python 标准库,不增加第三方依赖。
输入 JSONL 只读;输出报告必须使用新文件名,不覆盖旧报告。
先说明当前目录、拟修改文件和验收方法,再实现。
数据不合格的退出码为 1;文件或参数错误的退出码为 2。
不要通过放宽校验规则或修改输入,让测试表面通过。
交付时列出实际执行的命令、结果和未验证环境。
这是一份工作约定;实际权限仍要看工具的权限设置。
三、给出能验收的任务
把下面四行保存为 UTF-8 的 sample.jsonl:
{"id":"a","text":"你好"}
{"id":" a ","text":"重复"}
not-json
{"id":"b","text":"第二条有效数据"}
可直接交给 Codex 的任务描述:
实现 audit_jsonl.py,仅使用标准库。
提供 audit(text) 函数及命令行 input --output report.json。
逐个物理行读取 JSON 对象,忽略空白行但保留原始行号。
id 与 text 必须是去除两端空白后非空的字符串。
id 去除两端空白后判重;不合格记录不占用 id。
拒绝重复 JSON 键以及 NaN、Infinity 等非标准常量。
每条坏记录只记第一项错误,输出 valid、invalid、errors。
errors 只含 line 和 code,不复制原文;不修改输入。
已有输出文件必须拒绝覆盖。
退出码:全部有效 0,有坏记录但报告已生成 1,文件/参数错误 2。
补充正常、重复、坏 JSON、空白行、Unicode 分隔符、编码及文件保护测试。
先给计划,再实现并运行检查。不要把预期退出码 1 当作失败去“修复”。
这里先约定了坏记录是否占用 ID、错误优先级和报告写入行为。少了这些条件,两个都“能运行”的实现也可能给出不同结果。
四、一份可直接运行的参考实现
下面代码保存为 audit_jsonl.py。这是本次离线验证使用的参考程序;不是宣称某次 Codex 模型会话自动生成了它。
import argparse
import json
import sys
from pathlib import Path
def reject_constant(value):
raise ValueError('nonstandard JSON constant: ' + value)
def unique_object(pairs):
result = {}
for key, value in pairs:
if key in result:
raise ValueError('duplicate JSON key')
result[key] = value
return result
def audit(text):
seen, errors = set(), []
for line_no, line in enumerate(text.split('\n'), 1):
if not line.strip():
continue
try:
row = json.loads(line, parse_constant=reject_constant,
object_pairs_hook=unique_object)
except ValueError:
code = 'invalid_json'
else:
if not isinstance(row, dict):
code = 'not_object'
elif not isinstance(row.get('id'), str) or not row['id'].strip():
code = 'invalid_id'
elif not isinstance(row.get('text'), str) or not row['text'].strip():
code = 'invalid_text'
elif row['id'].strip() in seen:
code = 'duplicate_id'
else:
seen.add(row['id'].strip())
continue
errors.append({'line': line_no, 'code': code})
return {'valid': len(seen), 'invalid': len(errors), 'errors': errors}
def main(argv=None):
parser = argparse.ArgumentParser()
parser.add_argument('input', type=Path)
parser.add_argument('--output', required=True, type=Path)
args = parser.parse_args(argv)
try:
if args.input.resolve() == args.output.resolve():
raise ValueError('input and output must differ')
report = audit(args.input.read_text(encoding='utf-8-sig'))
with args.output.open('x', encoding='utf-8', newline='\n') as stream:
json.dump(report, stream, ensure_ascii=False, indent=2)
stream.write('\n')
except (OSError, UnicodeError, ValueError) as error:
print(type(error).__name__ + ': ' + str(error), file=sys.stderr)
return 2
print(f"valid={report['valid']} invalid={report['invalid']}")
return 1 if report['invalid'] else 0
if __name__ == '__main__':
raise SystemExit(main())
错误优先级是 JSON 格式、对象类型、ID、文本、重复 ID。额外字段允许存在。这个程序只报告问题,不清洗、不导出有效记录。
split('\n') 有一个容易忽略的原因:字符串中的 U+2028 可以是 JSON 内容,不应被 splitlines() 当作另一条记录。Windows 文件读取时的 CRLF 会由文本读取处理;开头的 UTF-8 BOM 用 utf-8-sig 接受。空白行虽然不参与计数,但仍占物理行号。
五、Windows、macOS、Linux 如何验收
在练习目录,Windows PowerShell 执行:
py -3 audit_jsonl.py "sample.jsonl" --output "report-01.json"
$LASTEXITCODE
macOS/Linux 执行:
python3 audit_jsonl.py "sample.jsonl" --output "report-01.json"
echo $?
读取退出码要紧接上一条命令。若解释器入口不同,换成你核对过的 Python 3。
预期终端统计为 valid=2 invalid=2,退出码是 1,报告为:
{
"valid": 2,
"invalid": 2,
"errors": [
{"line": 2, "code": "duplicate_id"},
{"line": 3, "code": "invalid_json"}
]
}
第 2 行的 ID 去空白后与第 1 行相同,第 3 行不是 JSON。退出码 1 表示按约定发现了数据问题,报告已经生成。再次使用同一报告名会返回 2;请指定新文件名,不要让工具自动覆盖上一次证据。
本次在 macOS arm64、Python 3.13.13 下,17 个 unittest 测试方法通过;另外实际运行四行样本,得到上述统计、退出码及行号,输入字节未变。本机核对到 Codex CLI 0.154.0,未发起 Codex 模型会话。Windows/Linux 的步骤属于官方文档核查,没有冒充跨系统实测。
六、审阅、续接与排障
让 Codex 交付“改了哪些文件、执行了哪些检查、哪些还没验证”。如果是 Git 项目,结合状态和差异看改动,同时留意新文件;不能只听它说测试通过。
会话中断后,可以在项目目录运行 codex resume 选择会话,或用 codex resume --last 续接当前目录最近会话。恢复对话后,再核对工作目录和实际文件,不把聊天记录当作磁盘快照。命令细节以 resume 说明 为准。
常见情况可以这样区分:命令不存在查安装与 PATH;输入找不到查当前目录和带空格路径;退出 1 查报告中的坏记录;退出 2 查终端错误、编码、输入和输出路径;权限拒绝先确认目标是否确实属于任务范围。
这个练习整文件读入内存,报告写入也不是原子事务;不适合作为超大文件或任意不可信深层 JSON 的生产防护组件。迁移到生产前,还要设计资源限制、输出事务和完整数据契约。先把小样本、错误含义和验收证据做对,再扩大处理规模。
本文使用 AI 辅助整理与编写;上述本地检查有记录,未验证的工具会话及操作系统已明确区分。

435

被折叠的 条评论
为什么被折叠?



