AI ScriptBoy 问题分享

项目背景

  1. 运营给出一批歌单 Excel
  2. AI 打标,导出 JSON
  3. 不同格式 JSON 转 不同格式 Excel 文件,反复编写脚本
  4. 业务只使用 Excel

目前方案:

  1. 通用提示词设计:通过 JSON 描述和目标 Excel 描述,让 AI 生成数据转换脚本代码
  2. 远程执行:将原始 JSON 和生成的脚本上传到 E2B 代码沙盒
  3. 自动化处理:远端运行脚本生成 Excel 文件,并返回下载链接

一. 性能挑战:当 AI "思考"变成负担

问题现象

在使用 AI 编写脚本时,我们经常会遇到响应速度慢的问题。这个问题主要来自两个方面:

  1. 内置 Thinking 机制:许多现代 AI 模型(如 Claude、GPT-4o 等)都内置了思考过程,虽然提升了输出质量,但明显增加了响应时间。
  2. 链式思维提示词(Chain of Thought, CoT):为了获得更好的代码质量,我们往往在提示词中要求 AI "分步思考"、"详细分析需求"等,这进一步延长了响应时间。

时间概览

从上到下分别为:

  1. DeepSeek V3 0324
  2. DeepSeek R1 0528
  3. Claude Sonnet 4 0604
  4. Gemini 2.5 Flash Preview 0520

解决策略

  1. 场景分离:简单脚本使用快速模式,复杂逻辑才启用思考模式
  2. 模型选择:针对不同复杂度选择不同响应速度的模型/模式
    • 模型是否支持手动关闭 Thinking 模式,或者独立调用 No Thinking 模式(如 Claude Sonnet 4、Gemini 2.5 Flash)
    • 简单任务可以直接使用 非推理模型

二. 成本陷阱:低单价不等于低成本

隐藏的单价陷阱

在选择 AI 模型时,很容易被表面的单价误导。以 Gemini 2.5 Pro 和 Claude Sonnet 3.7 为例:

模型 输入单价 输出单价
Gemini 2.5 Pro $1.25/M tokens $10/M tokens
Claude Sonnet 3.7 $3/M tokens $15/M tokens

实际成本分析

Gemini 2.5 Pro 的问题:

代码生成长度对比

实测:GPT、Claude 生成代码 ~110 行,而 Gemini 2.5 Pro 则达到 ~190 行。Gemini 2.5 Pro 因为注释原因,token 消耗爆炸,导致成本爆炸。

成本优化建议

  1. 控制输出:要求"简洁的代码,必要的注释" (生产环境可要求移除注释以节省 token)
  2. 语言选择:英文提示词比中文提示词更节省 token(中文提示词翻译成英文时长度会增加,但多数模型 输出单价比输入单价高,总体仍可能更经济)
  3. 模型测试:针对常见任务测试不同模型的实际消耗

三. 输出格式的一致性挑战

指令遵循能力差异

要求 AI 输出"直接可以运行的纯代码"时,不同模型的表现差异显著:

模型 指令遵循度 输出格式稳定性 纯代码输出 主要问题
Claude Sonnet 3.5+ ✅ 优秀 ✅ 稳定一致 ✅ 无额外内容 几乎无问题
Gemini 2.0 Flash ⚠️ 中等 ❌ 随机性强 ❌ 经常包裹代码块 随机添加 '```python' 等标记
DeepSeek ❌ 较差 ❌ 不稳定 ❌ 有额外内容 随机在顶部添加预期外文本

常见的格式问题

期望输出(纯代码):

print("Hello World")

Markdown 代码块包裹 实际输出:

```python  
print("Hello World")  
```

额外的声明和注释 实际输出:

#!/usr/bin/env python3  
# -*- coding: utf-8 -*-
print("Hello World")

解决方案

强化提示词策略

请输出纯代码,不要包含任何 Markdown 格式标记,不要添加说明文字,
不要包含 shebang 行,直接从第一行代码开始输出。

反向包裹策略

请将生成的代码包裹在 <code></code> 标签中,
我会在处理时提取其中的内容。

明文指定 可预期且固定的输出格式,规避后处理时的不可预测性。

四. 提示词编写的权衡:描述需求 vs 描述实现方案

在提示词设计中遇到一个核心选择:是描述需求,还是指定代码生成实现方案?

描述需求风格

要求:多行文本完整显示,列宽自适应,整体需要美观

描述实现方案风格

使用openpyxl设置Alignment(wrap_text=True)
设置行高:row_dimensions[i].height = 行数*15

Claude 升级到 4 后,为了测试 LLM 能力边界,进行了一次提示词优化尝试,发现了一些意料之外的收获。

指标 描述需求 描述实现方案
响应时间 ~12s ~17s
输入Token 1044 3673
输出Token 1076 1343

生成脚本同样可用的情况下,描述需求的风格,除了 Token 占用减少外,响应时间出乎意料的也更短。猜测是触发了 CoT,及更多约束,导致响应时间增加。

测试模型:Claude Sonnet 4 和 Gemini 2.5 Flash No Thinking

使用哪种方案,取决于实际场景:

五. 工程化验证:从代码生成到实际应用

AI 生成脚本的验证主要面临以下挑战:

解决方案:代码执行沙盒

近两个月,代码沙盒类服务冒出来很多,仅从 TS SDK 来说,个人偏爱 E2B 的简练。

使用示例:

// 使用 E2B TypeScript SDK
import { Sandbox } from '@e2b/code-interpreter'

const sandbox = await Sandbox.create({
  apiKey: c.env.E2B_API_KEY,
})

// 把 AI 生成的代码(scriptContent),和传入的 JSON 文件,写入到沙盒里的文件系统
await sandbox.files.write('/task/script.py', scriptContent);
await sandbox.files.write('/task/input.json', jsonContent);

// 像在命令行一样运行脚本,指定保存到沙盒里的 /task/output.xlsx 文件
const execution = await sandbox
  .commands.run('python /task/script.py /task/input.json /task/output.xlsx');

// 对生成的文件进行消费,转存/直接读取并通过接口返回等
fileContent = await sandbox.files.read('/task/output.xlsx', {
  format: 'bytes',
});

实测:全流程花费大概 7s 左右。打日志会发现,大量开销是在网络层,和文件读写的 IO 层

延伸:沙盒本身甚至可以作为生成代码的测试工具,本身具备完整的 stdout

Blog