VBScript 通过 Adodb.Stream 生成 UTF-8 CSV再用 MySQL 的 LOAD DATA INFILE 导入结果首行首列多出一个问号这个现象在旧项目里很常见。排查时可以直接把现场交给 Codex让 Codex 借道 TaoToken官网https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content作为模型通道来协助定位。TaoToken 在这里只负责 Codex 的模型请求不参与 VBScript 的文件读写也不替代任何编辑器或数据库工具。本文从 Adodb.Stream 的二进制读写切入说明如何确认 EF BB BF BOM如何配置 Codex 的 config.toml以及如何验证跳过 BOM 后的 CSV 导入结果。一、Adodb.Stream 导出的 CSV 首列问号现场问题通常出现在这样的链路里VBScript 脚本先用 Adodb.Stream 把数据写成 UTF-8 格式的 CSV文件在普通编辑器里打开时肉眼看不到异常表头、字段、换行都正常。接着用 MySQL 的 LOAD DATA INFILE 命令导入导入完成后查表第一行第一列的值前面却多了一个问号。这个问号不是数据本身的内容也不是 MySQL 显示编码错误时那种整列乱码而是文件开头被写入的不可见字节被当成了普通字符。继续用十六进制方式查看 CSV 文件就能看到文件起始位置是 EF BB BF 三个字节。这三个字节正是 UTF-8 BOM。UTF-8 文件分为带 BOM 和不带 BOM 两种Adodb.Stream 在生成 UTF-8 文件时可能自动写入 BOM。MySQL 的 LOAD DATA 并不会因为连接字符集是 utf8mb4 就自动忽略文件头的 BOM它会把 EF BB BF 当成数据的一部分插入第一列于是首行首列就出现了问号或其他不可见字符。这里要区分两件事一是文件内容是否真的写错了二是文件头部是否多了 BOM。文本编辑器看不出问题是因为它把 BOM 当作文件编码标记处理不会显示成可见字符。要确认现场必须用十六进制编辑方式或者用 VBScript 以二进制方式读取前三个字节。老版本十六进制编辑器有时会把 UTF-8 文件显示成 FFFE这容易误导判断建议用较新的工具或直接以字节值为准。二、BOM 定位为什么是 EF BB BF而不是文件内容损坏UTF-8 的存储顺序与编码顺序一致所以判断 BOM 本质上就是看文件最前面有没有三个固定字节。EF BB BF 的十进制值分别是 239、187、191。如果 CSV 文件开头是这三个值说明文件带了 UTF-8 BOM如果开头是普通字段内容比如字母、数字或逗号则文件大概率是无 BOM 的。在 VBScript 里操作 Adodb.Stream 时关键属性是 Type。Type 设为 1 表示二进制方式Type 设为 2 或默认文本方式时Read 和 Position 的行为会不同。二进制方式下Position 按字节偏移计算Read(-1) 可以读取当前位置之后的全部字节。文本方式下Position 可能按字符计算直接用来跳 BOM 并不可靠甚至可能让 Read 报错。所以标题里说的“查 BOM”实际排查点就是确认 stm.Type1、stm.Position3 以及读取顺序是否正确。如果只关心怎么去掉 BOM思路很直接用二进制方式打开源文件把读取位置移到第 4 个字节也就是跳过前三个字节然后把剩余字节写入新文件。新文件保存时同样要用二进制方式并且确认保存参数是覆盖写入避免旧文件残留。这样生成的 CSV 文件就是无 BOM 的 UTF-8再交给 MySQL 导入首行首列就不会再多出问号。但生产环境不建议无脑写 Position3。因为并不是所有 CSV 都带 BOM如果源文件本身没有 BOM强行跳过三个字节会把正常字段的前三个字符吃掉。更稳妥的做法是先读取前三个字节判断是否为 EF BB BF如果是再把 Position 设为 3如果不是就把 Position 归零从文件开头正常读取。三、TaoToken 前置把 Codex 的模型通道接到 https://taotoken.net/api当现场已经明确是 BOM 问题但 VBScript 代码里还有细节拿不准时可以把“CSV 首列问号 EF BB BF”的现场交给 Codex 诊断。这里使用 TaoToken 作为 Codex 的模型通道。先打开官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 创建 KeyKey 在配置里用 YOUR_API_KEY 占位。然后在 Codex 的 config.toml 中把 Base URL 填成 https://taotoken.net/api。注意 API 地址不加 UTM 参数保持为纯接口地址。TaoToken 只负责模型请求转发不参与 VBScript 的文件读写也不直接修改 CSV。Codex 拿到你贴出的代码片段和报错现象后可以帮你判断 Position 是否设置得太早、Type 是否在 Open 之后才改、SaveToFile 的第二个参数是否正确、MySQL 导入语句是否需要额外处理。这样排障的边界很清晰文件操作仍然由 VBScript 完成模型通道只用于分析和检查逻辑。如果你还没有创建 Key可以到控制台 API Keys 页面操作https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentapi-keys。接入细节和字段说明可以参考文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentdoc。配置前先确认本地 Codex 版本支持的 provider 字段避免把不同版本的配置项混用。四、可复制配置Codex 的 config.tomlCodex 使用 config.toml 作为配置文件。下面是一份可复制的模板核心是把 base_url 指向 https://taotoken.net/api并通过环境变量传入 YOUR_API_KEY。MODEL_ID 请以 TaoToken 控制台或模型列表里实际可用的名称为准不要直接把示例名称当成固定值。model MODEL_ID model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY wire_api responses如果你的本地 Codex 版本使用 chat completions 接口可以把 wire_api 改为 chat。如果版本对 provider 的字段名有差异以本地 Codex 文档为准但 base_url 和 env_key 这两个核心项不要写错。base_url 必须是 https://taotoken.net/api不要带 UTM也不要写成官网首页地址。接下来设置环境变量。Windows CMD 可以用set TAOTOKEN_API_KEYYOUR_API_KEYPowerShell 可以用$env:TAOTOKEN_API_KEYYOUR_API_KEYmacOS 或 Linux 可以用export TAOTOKEN_API_KEYYOUR_API_KEY不要把真实 Key 写进 config.toml 后提交到仓库也不要把 Key 贴在公开的 issue 或聊天记录里。配置完成后启动 Codex确认它读取的是当前终端的环境变量。如果 Codex 返回 401 或提示缺少 API Key优先检查 env_key 名称和环境变量是否一致。五、VBScript 二进制跳过 BOMType1 与 Position3 的写法下面这段 VBScript 用 Adodb.Stream 以二进制方式读取源文件跳过 UTF-8 BOM 后另存为无 BOM 文件。示例里把源文件写成 e:\tmp\apachelog.txt输出文件写成 e:\tmp\apachelog22.txt实际项目按你的路径替换。Dim inStm, outStm, raw Set inStm CreateObject(Adodb.Stream) inStm.Type 1 inStm.Open inStm.LoadFromFile e:\tmp\apachelog.txt inStm.Position 3 raw inStm.Read(-1) inStm.Close Set outStm CreateObject(Adodb.Stream) outStm.Type 1 outStm.Open outStm.Write raw outStm.SaveToFile e:\tmp\apachelog22.txt, 2 outStm.Flush outStm.Close这段代码里有几个点需要核对。第一Type 必须设为 1表示二进制方式如果这里是文本方式Position 和 Read 的语义会变。第二Position 必须在 LoadFromFile 之后设置因为加载文件后位置会被重置先设 Position 再 Load 等于白设。第三Read(-1) 表示从当前位置读到末尾返回的是剩余字节。第四SaveToFile 的第二个参数 2 表示覆盖已有文件避免旧文件内容残留。第五输出流同样要设置 Type1否则写入时可能按文本处理重新引入编码差异。如果不想固定跳过三个字节可以先读前三个字节判断 BOM。思路是先把 Position 归零读取三个字节判断字节值是否为 EF BB BF如果是再把 Position 设为 3 继续读剩余内容如果不是就把 Position 归零从开头读全部内容。这样既能处理带 BOM 的 CSV也不会误伤无 BOM 文件。判断字节时要注意 VBScript 里字节数组的取值方式必要时用 AscB 或十六进制比较来完成。完成处理后用十六进制方式打开原文件和新文件对比。原文件开头应该是 EF BB BF 加正常内容新文件开头应该直接是正常字段内容不再有 BOM。只有确认新文件头部没有 EF BB BF后续 MySQL 导入才有意义。六、验证请求把 CSV 问号现场交给 Codex 判断Codex 配置完成后可以把现场整理成一段 prompt 发给它。建议包含这些信息Adodb.Stream 生成 UTF-8 CSV导入 MySQL 后首行首列多问号十六进制看到 EF BB BF当前代码使用了 Type1、Position3、Read(-1)以及 SaveToFile 的路径和参数。再贴出 MySQL 的 LOAD DATA 语句和表结构让 Codex 对照检查。示例 prompt 可以这样写我有一个 VBScript 用 Adodb.Stream 生成 UTF-8 CSVMySQL LOAD DATA 后首行首列多一个问号。用十六进制查看文件开头是 EF BB BF。下面是我用 Type1、Position3、Read(-1) 跳过 BOM 的代码以及 LOAD DATA 语句。请判断为什么导入后还可能带 BOM并逐项检查 Position 设置顺序、Type 设置、SaveToFile 覆盖参数、MySQL 字符集和 IGNORE 1 LINES 的影响。如果 TaoToken 通道配置正确Codex 会基于你贴出的片段进行分析而不是返回连接超时或鉴权失败。验证通道是否可用可以到模型对话页面单独测试https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmodel-chat。成功结果不是 Codex 直接修改你的文件而是它指出代码里可能被忽略的细节比如 Position 在 LoadFromFile 之前设置、输出流没有用二进制模式、或者 MySQL 导入时 BOM 被当成第一列数据。最终验证仍要回到文件本身。用处理后的 CSV 重新执行 LOAD DATA再查询第一行第一列。如果问号消失并且用 HEX 函数查看该列开头不再是 EFBBBF说明 BOM 已经跳过。如果仍有问号就要检查是否导入了旧文件、是否有多余的空行、或者 CSV 中间列是否存在编码不一致。七、本篇常见错排查Position、Type 与 LOAD DATA第一类错误是 Type 没有设为 1。Adodb.Stream 默认不是二进制模式Position 和 Read 的行为会随模式变化。跳 BOM 必须用二进制方式否则 Position3 可能不是跳过三个字节Read 也可能报错。第二类错误是 Position 设置顺序不对。必须 Open、LoadFromFile 之后再设置 Position先设置再加载会被覆盖。第三类错误是不判断 BOM 就固定跳三个字节。这样只适合确定带 BOM 的文件。如果某天上游改成无 BOM 输出固定 Position3 会吃掉首行前三个字符。第四类错误是只处理了读取没有处理写入。输出流如果用了文本模式或者保存时又写了 BOM新文件仍然会带 EF BB BF。第五类错误是 MySQL 侧忽略检查。LOAD DATA 的 IGNORE 1 LINES 只跳表头不会自动跳 BOM连接字符集设为 utf8mb4 也不会让 MySQL 忽略文件头的 BOM。第六类错误是十六进制查看工具版本太旧把 UTF-8 BOM 显示成 FFFE导致判断方向跑偏。遇到这种情况换用较新的十六进制工具或者直接用 VBScript 读取前三个字节并输出十进制值确认。第七类错误是路径和权限问题比如源文件路径写错、输出目录不存在、SaveToFile 参数没有用 2 导致覆盖失败。第八类错误是导入时字段分隔符、换行符和 CSV 实际格式不一致导致首行解析错位看起来像 BOM 没处理干净。排查时建议按顺序做先确认源文件十六进制开头再确认 VBScript 是否以 Type1 读取再确认 Position 设置时机再确认输出文件是否无 BOM最后检查 MySQL 的 LOAD DATA 参数和表字段类型。每一步都用十六进制或 SELECT HEX 验证不要只靠文本编辑器肉眼判断。八、接入与排障入口如果你也在处理 VBScript 二进制读写、Adodb.Stream 生成 CSV、MySQL 导入首列问号或者 Codex 接入 config.toml 的排障建议先在 TaoToken 控制台创建 Key再把 Codex 的 Base URL 配成 https://taotoken.net/api然后对照接入文档检查 provider、env_key 和 wire_api 字段。创建 Key 入口https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentapi-keys。接入文档入口https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentdoc。如果只是想先验证模型通道是否连通可以到模型对话页面发一条简单请求https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmodel-chat。长期在终端里做编码、脚本排障和 Agent 工作流可以了解 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentcoding-plan。把文件读写留给 VBScript把模型分析交给 CodexTaoToken 只做通道整个排障链路会更清晰。