1. 项目概述:从“提示词驱动”到“程序驱动”的范式转变

最近在跟几个做AI应用落地的朋友聊天,大家普遍有个共同的感受:现在搞AI项目,越来越像是在玩一个“提示词工程”的无限游戏。我们花大量时间在琢磨怎么把需求“翻译”成一段完美的英文提示词,反复调试、微调,试图让大模型一次性吐出我们想要的结果。这个过程充满了不确定性,就像在跟一个理解能力飘忽不定的天才实习生沟通,你永远不知道它这次会给你惊喜还是惊吓。

这个现象背后,其实指向了一个更深层的问题:我们是不是过度依赖“提示词”作为人机交互的核心接口了?或者说,我们是不是把大模型用错了地方?我越来越认同一个观点: AI的真正价值,不在于它直接执行一个复杂的、模糊的提示词,而在于它能生成清晰、确定、可复用的程序(代码),然后由传统的、可靠的执行环境来运行这些程序。

这就是“Programs Beat Prompts”(程序优于提示词)的核心主张。它不是一个简单的技术选型,而是一种思维范式的转变。过去,我们试图让AI“理解”并“执行”任务;未来,我们应该让AI“设计”并“生成”执行任务的蓝图(即代码),然后由更擅长精确执行的系统去跑这个蓝图。前者是把AI当“全能员工”,后者是把AI当“顶级架构师”。哪个更靠谱?显然是后者。

这篇文章,我想结合我最近在自动化工作流、数据分析以及智能体(Agent)构建中的实际踩坑经验,深入聊聊为什么这个范式如此重要,它具体解决了哪些痛点,以及我们该如何在实际项目中落地这种“让AI写代码,而不是跑代码”的思路。无论你是正在尝试用大模型解决业务问题的产品经理,还是在一线编码的工程师,相信都能从中获得一些启发。

2. 核心痛点:为什么“提示词驱动”模式走不远?

在深入探讨新范式之前,我们必须先认清旧范式的天花板和瓶颈。单纯依赖提示词驱动大模型完成任务,在概念验证(PoC)阶段或许很酷,但一旦进入严肃的生产环境,以下几个问题就会变得异常突出。

2.1 可靠性与一致性的“阿喀琉斯之踵”

大模型本质上是概率模型,它的输出具有内在的随机性。即使你使用了相同的提示词、相同的模型版本、相同的温度(temperature)参数,你也无法100%保证两次调用的输出格式和内容完全一致。这种不确定性对于生产系统是致命的。

一个真实的踩坑案例 :我曾尝试用GPT-4 API构建一个从用户自然语言描述中提取结构化合同条款的功能。提示词精心设计了,要求输出JSON格式,包含“甲方”、“乙方”、“金额”、“交付日期”等字段。在测试的100次中,可能有95次都能完美解析。但剩下的5次,它可能把“金额”字段输出为字符串带上了货币符号“$10000”,而不是纯数字“10000”;或者把日期写成了“下个月15号”这种非标准格式。为了处理这些“意外”,你不得不在下游写大量的后处理代码和异常捕获逻辑,这本质上是在用代码去弥补提示词的不确定性,成本极高。

注意 :很多人会想到通过降低“温度”参数来增加确定性。这确实有帮助,但无法根除问题。模型在遇到训练数据中不常见的表述或复杂逻辑时,依然可能“自由发挥”。

2.2 复杂逻辑与状态管理的“表达困境”

提示词本质上是一段自然语言文本,它擅长描述意图,但极不擅长表达复杂的、多步骤的、带有状态转移的逻辑。当你试图用一个提示词让模型完成“读取数据库A表的数据,进行聚合计算,将结果与B表关联,筛选出异常值,最后生成报告并发送邮件”这一系列操作时,你会发现提示词变得无比冗长且容易出错。

模型需要在一个上下文窗口内,同时理解你的全部意图、记住所有中间步骤的结果、并准确执行下一步。这相当于要求一个人在不做任何笔记的情况下,只听一遍指令就完成一个十步的精密手术,出错的概率可想而知。更糟糕的是,一旦某一步出错,整个流程无法回滚或从错误点恢复,只能推倒重来。

2.3 调试、测试与版本控制的“噩梦”

软件开发有一整套成熟的工程实践:单元测试、集成测试、版本控制(Git)、CI/CD。这些实践的核心前提是:代码是确定的、可静态分析的、可差异比较的。

提示词呢?你怎么对一段自然语言描述做“单元测试”?你怎么用Git来管理提示词的迭代? git diff 显示你从“请总结这篇文章”改成了“请用三点总结这篇文章的核心观点”,这个改动的影响范围有多大?你无法量化评估。当提示词失效时,调试过程更像是在做心理侧写:“是不是我这个词它理解有歧义?我换个说法试试?” 整个过程缺乏科学的、可复现的调试手段。

2.4 成本与延迟的“不可控增长”

对于复杂的任务,为了获得可靠输出,你往往需要在提示词中加入大量的示例(Few-Shot Learning)、详细的规则描述和格式要求。这会导致提示词极其冗长,消耗大量的Tokens。在按Token计费的API调用中,这意味着单次调用成本高昂。

更重要的是,大模型生成文本的速度是线性的,输出越长,耗时越久。让模型直接生成一篇长篇报告,其延迟和成本远高于让模型生成一个能生成报告的Python脚本,然后在本机快速运行这个脚本。后者将一次性的、昂贵的“推理成本”,转化为了可重复使用的、廉价的“计算成本”。

3. 范式解析:“程序生成”如何解决这些问题?

理解了痛点,我们再来看看“让AI写代码”这个范式是如何精准打击这些弱点的。它的核心思想可以概括为: 将不确定性的边界从“任务执行”阶段,前移到“任务规划与工具生成”阶段

3.1 确定性执行环境的引入

当我们让大模型生成代码(如Python脚本、SQL查询、Shell命令)时,我们实际上是为任务选择了一个 确定性 的执行环境。Python解释器、数据库引擎、操作系统Shell,这些环境的运行结果是完全确定的,相同的输入必然产生相同的输出(在不考虑极端外部因素的情况下)。

这样一来,大模型只需要承担它最擅长的部分: 理解意图,并将其“翻译”成另一种确定性语言的规范描述(即代码) 。一旦代码生成,它的执行就交给了可靠的传统环境。即使生成的代码有Bug,那也是确定的、可复现的、可以用传统调试工具(如断点、日志)来定位的Bug,这比调试一段模糊的自然语言输出要容易得多。

3.2 复杂逻辑的“分而治之”与“状态外置”

代码天生就是为表达复杂逻辑而生的。循环、条件判断、函数封装、模块化、变量存储状态——这些编程语言的基本构件,使得我们可以将复杂任务分解为一系列简单的、可测试的步骤。

在“程序生成”范式下,大模型可以生成一个包含多个函数的脚本。主函数负责流程控制,子函数负责具体操作。所有的中间状态都存储在变量或外部系统中,而不是依赖模型的“记忆”。如果流程中断,我们可以从保存的状态点重新开始,或者只重新执行失败的那一部分。这实现了任务的 可组合性 可恢复性

3.3 工程化实践的完美适配

生成的代码可以无缝融入现有的软件工程体系:

  • 版本控制 :代码文件可以直接用Git管理,每一次提示词的调整导致的代码变化,都可以通过 git diff 清晰看到。
  • 测试 :可以为生成的代码编写单元测试和集成测试,确保其行为符合预期。你甚至可以测试“代码生成器”(即提示词+大模型)本身,通过输入一批标准用例,检查其生成的代码是否能通过测试套件。
  • 调试 :代码运行出错会有明确的堆栈跟踪(Stack Trace),指向具体的行号和错误类型。你可以使用IDE进行单步调试,观察变量状态,这比猜测模型的“心理活动”要高效无数倍。
  • 安全与审计 :生成的代码在运行前可以进行静态分析,检查是否有危险操作(如删除文件、访问网络)。代码本身也作为一份“审计日志”,清晰地记录了系统到底执行了哪些操作。

3.4 成本与性能的优化

生成一段代码的成本是固定的(一次API调用)。一旦代码生成,它可以被反复执行无数次,而无需再调用昂贵的大模型。对于需要频繁执行或处理大量数据的任务,这种“一次生成,多次运行”的模式将边际成本降到了近乎为零。

在性能上,本地运行优化过的Python脚本或SQL查询,其速度通常远快于等待大模型逐字生成同样体量的文本输出。这对于需要低延迟响应的应用场景至关重要。

4. 实战架构:构建一个“AI代码生成器”工作流

理论说再多,不如看实战。下面我以一个具体的场景为例,拆解如何构建一个“程序生成”范式的工作流。假设我们要做一个“智能数据分析助手”:用户用自然语言提问,系统自动生成并执行相应的数据分析代码,返回结果和图表。

4.1 系统组件设计

整个系统可以分为三个核心层:

  1. 意图理解与规划层 :接收用户自然语言查询,理解其意图,并规划出需要执行的数据操作步骤序列。
  2. 代码生成层 :根据规划好的步骤,结合数据集的元信息(表结构、列名、类型),生成可执行的数据分析代码(如Pandas代码)。
  3. 安全执行与反馈层 :在一个受控的沙箱环境中安全地执行生成的代码,捕获结果和错误,并将执行结果(或错误信息)反馈给用户或上一层用于迭代优化。
用户提问
    ↓
[意图理解与规划层] -> 任务步骤列表
    ↓
[代码生成层] -> 可执行的Python代码
    ↓
[安全执行层] -> 执行结果/图表/错误信息
    ↓
返回给用户

4.2 核心实现细节与提示词设计

这个系统的核心在于给大模型的“提示词”设计。此时,提示词的目标不再是直接得到答案,而是得到一份高质量的“制造答案的说明书”(即代码)。

第一步:意图理解与规划提示词 这个提示词需要引导模型进行任务分解。它应该包含:

  • 系统角色定义 :明确告诉模型,你是一个数据分析专家,负责将问题分解为具体的数据操作步骤。
  • 输出格式约束 :严格要求模型以指定的结构化格式(如JSON)输出规划。
  • 能力范围定义 :列出可用的数据操作“原子能力”,如“数据加载”、“筛选过滤”、“分组聚合”、“列计算”、“可视化”等。
  • 示例 :提供1-2个从问题到规划步骤的完整示例。

示例提示词片段:

你是一个数据分析专家助理。用户会提出一个关于数据集`sales_data.csv`的问题。你的任务是将这个问题分解为一系列具体、可执行的数据操作步骤。

数据集`sales_data.csv`包含以下列:`date`(日期), `product_category`(产品类别), `region`(地区), `sales_volume`(销量), `revenue`(收入)。

可用的操作步骤类型包括:
1. LOAD: 加载数据
2. FILTER: 根据条件筛选行
3. GROUPBY: 按列分组
4. AGGREGATE: 对分组进行聚合计算(如求和、平均)
5. CALCULATE: 创建新的计算列
6. PLOT: 生成图表(需指定图表类型和坐标轴)

请以以下JSON格式输出你的规划:
{
  "steps": [
    {"step_type": "LOAD", "details": {...}},
    {"step_type": "FILTER", "details": {"condition": "..."}},
    ...
  ]
}

示例:
用户问题:“计算2023年每个产品类别的总销售收入。”
输出规划:
{
  "steps": [
    {"step_type": "LOAD", "details": {"file_path": "sales_data.csv"}},
    {"step_type": "FILTER", "details": {"condition": "date >= '2023-01-01' and date <= '2023-12-31'"}},
    {"step_type": "GROUPBY", "details": {"by_column": "product_category"}},
    {"step_type": "AGGREGATE", "details": {"column": "revenue", "operation": "sum"}}
  ]
}

第二步:代码生成提示词 这个提示词接收上一步的“规划”和数据集元信息,生成具体的Pandas代码。

  • 上下文注入 :将规划步骤作为输入。
  • 代码风格要求 :要求代码包含必要的注释、使用安全的编程实践(如使用 pd.read_csv 的参数处理异常)、并预留结果输出的方式(如将最终结果赋值给变量 result )。
  • 错误处理引导 :提示模型考虑可能的数据异常(如空值、类型错误),并添加基本的健壮性代码。

实操心得 :在这一步,一个非常有效的技巧是让模型生成代码时, 同时生成针对这段代码的“测试用例”或“预期输出描述” 。这可以作为后续验证代码正确性的一个基准,虽然不能完全替代真正的测试,但能极大提高生成代码的可靠性。

4.3 安全执行沙箱的实现

执行未知来源的代码是极度危险的。绝不能直接在主机环境或拥有数据库写权限的环境中运行生成的代码。必须使用沙箱(Sandbox)。

推荐方案

  1. 容器隔离 :使用Docker启动一个临时的、无网络(或受限网络)、文件系统只读(除了特定临时目录)的容器。在容器内安装最小化的Python和必要库(pandas, matplotlib等)。
  2. 资源限制 :对容器的CPU、内存、运行时间进行严格限制。
  3. 代码扫描 :在执行前,对生成的代码进行简单的静态分析,禁止导入如 os , subprocess , sys (部分)等危险模块,或检测是否有尝试访问文件系统、网络等敏感操作。
  4. 结果捕获 :代码执行后,通过标准输出、捕获的变量(需要代码配合,如将结果序列化为JSON字符串打印)或生成的图表文件(保存到临时目录)来获取结果。

一个简单的Docker沙箱执行示例(概念性):

# 将生成的代码写入文件 generated_code.py
echo "$generated_python_code" > /tmp/generated_code.py

# 在受限容器中运行
docker run --rm \
  --memory="256m" \
  --cpus="0.5" \
  --network="none" \
  -v /tmp/generated_code.py:/app/code.py:ro \
  -v /tmp/output:/output \
  python:3.9-slim \
  python /app/code.py > /tmp/output/result.txt 2> /tmp/output/error.log

重要警告 :上述示例仅为说明原理。生产环境需要更严密的安全设计,例如使用专门的安全沙箱库(如 PyPy 的沙箱,但已不维护)、或基于 seccomp 等系统调用过滤机制构建运行时。对于企业内部应用,这是一个必须投入资源解决的核心安全问题。

5. 进阶模式:从单次生成到迭代优化与智能体(Agent)

基本的“一次生成,直接执行”模式可能还不够。生成的代码第一次就可能出错,或者结果不满足用户需求。这就需要引入 迭代优化 的机制,这也是当前AI智能体(Agent)研究的核心。

5.1 构建“执行-观察-修正”循环

我们可以让系统具备自我修正能力。工作流变为:

  1. 生成代码。
  2. 在沙箱中执行代码。
  3. 观察执行结果 :包括程序输出、打印的日志、生成的图表,以及最关键的是否有 运行时错误 (Exception)。
  4. 原始问题、生成的代码、执行结果(或错误信息) 三者一起,再次喂给大模型,要求它分析问题所在,并修正代码。
  5. 重复步骤1-4,直到成功或达到最大迭代次数。

这个循环中,给模型的提示词需要引导它进行“调试”。例如:

刚才你为问题`{用户问题}`生成了以下代码:
```python
{生成的代码}

在执行时,遇到了以下错误:

{错误堆栈信息}

或者,执行虽然没有报错,但得到了以下结果:

{执行输出}

这个结果与预期不符。预期是:{描述预期}。

请分析代码中的错误或逻辑缺陷,并重新生成修正后的完整代码。请同时简要说明你发现的问题是什么。


通过这种方式,系统具备了初步的“调试”能力。我实践中发现,对于语法错误、简单的逻辑错误(如列名拼写错误、数据类型不匹配),模型通常能在1-2轮迭代内自行修正。

### 5.2 与工具(Tools)和知识(Knowledge)的结合

“程序生成”范式与**工具调用(Function Calling)** 和 **检索增强生成(RAG)** 是绝配,可以构建出能力更强的智能体。

- **工具集成**:与其让模型生成操作数据库的所有代码,不如让它生成调用某个已封装好的安全数据库查询函数的代码。例如,你提供一个安全的`query_database(sql)`工具函数。模型生成的代码就变成了调用这个函数的代码,而不是包含原始数据库连接字符串的危险代码。这进一步收窄了安全边界,提升了可控性。
- **知识增强**:当需要生成涉及特定领域知识的代码时(例如,生成某种特定算法的实现),可以让模型先检索内部的代码知识库或文档,然后基于检索到的范例来生成代码。这能显著提高生成代码的准确性和专业性。

**一个融合的智能体工作流示例**:
1.  用户提问:“对比一下我们A产品和B产品在上个季度的用户留存曲线。”
2.  模型规划:需要“查询A产品用户留存数据”、“查询B产品用户留存数据”、“绘制对比曲线”。
3.  模型生成代码:代码中不是直接写SQL,而是调用安全的工具函数 `get_user_retention(product_id, quarter)`。同时,从内部知识库检索“如何用Matplotlib绘制双线对比图”的最佳实践代码片段。
4.  执行并返回结果。

## 6. 适用场景与局限性

“Programs Beat Prompts”范式非常强大,但并非银弹,有其最适合的应用场景。

### 6.1 理想应用场景
1.  **数据分析与可视化**:如前文所述,将自然语言查询转为SQL或Pandas代码。
2.  **自动化脚本编写**:例如,“帮我写一个脚本,批量重命名某个文件夹下所有图片文件,按照拍摄日期排序。”
3.  **业务规则配置生成**:将业务人员描述的风控规则、促销规则,自动转换为可部署的规则引擎配置代码或SQL片段。
4.  **测试用例生成**:根据功能描述,自动生成单元测试或API测试用例代码。
5.  **代码补全与重构**:在IDE中,根据上下文和注释,生成小的代码片段或重构建议(这本身就是该范式的一种形式)。

### 6.2 当前局限性
1.  **生成代码的质量**:模型生成的代码可能效率不高、存在边缘情况处理缺失、或使用了不推荐的写法。需要人工审核或通过测试覆盖来保证。
2.  **复杂算法生成**:对于涉及复杂数学推导或新颖算法的任务,模型可能无法生成正确代码,因为它本质上是模仿现有模式。
3.  **安全沙箱的开销**:维护一个安全、高效的代码执行沙箱需要额外的开发和运维成本。
4.  **冷启动问题**:对于全新的、无范例的任务,模型可能无法生成有效代码。需要提供足够的上下文和示例。
5.  **调试循环的成本**:迭代生成-执行-调试的循环会增加API调用次数和总体响应延迟,不适合对实时性要求极高的场景。

## 7. 实施路线图与团队准备

如果你和你的团队认可这个方向,打算在实践中引入“程序生成”范式,我建议遵循一个循序渐进的路线:

**第一阶段:概念验证与场景选择**
- 选择一个明确的、高价值的、且逻辑相对确定的内部场景(如周报数据自动生成)。
- 手动模拟几次“人肉翻译”过程:作为人类,你会如何将需求写成代码?总结出固定的模式和需要的工具函数。
- 构建最简单的端到端流程,不追求全自动化,先验证“生成代码并执行”这个核心链路是否跑得通。

**第二阶段:提示词工程与可靠性提升**
- 针对选定的场景,深度优化提示词,重点提升生成代码的**首次成功率**。
- 建立代码的**验证机制**。例如,对生成的SQL,可以先在测试环境执行`EXPLAIN`或检查语法;对生成的数据处理代码,可以用小样本数据试运行。
- 开始设计**安全沙箱**的雏形。

**第三阶段:工程化与产品化**
- 将验证过的流程封装成API或内部工具。
- 完善安全沙箱,制定资源限制和风险控制策略。
- 加入**迭代优化**能力,让系统可以处理简单的执行错误。
- 建立**监控和评估体系**:记录每次生成的代码、执行结果、用户反馈,用于持续优化模型和提示词。

**第四阶段:扩展与生态集成**
- 将更多工具函数接入系统,扩展其能力范围。
- 与内部的代码知识库、API文档系统集成,实现检索增强生成。
- 探索更复杂的多智能体协作模式,例如一个智能体负责规划,一个负责生成代码,一个负责审查代码安全。

对于团队来说,这种范式转变要求成员不仅要有大模型应用的经验,更需要有扎实的软件工程基础,特别是对代码安全、系统设计、自动化测试有深刻理解。它更像是在用大模型赋能传统的自动化开发,而不是取代它。

我个人最深的一个体会是,这个范式最大的价值在于它**重新定义了人机协作的边界**。人负责定义问题、提供上下文、设定约束条件和审核最终结果;AI负责将模糊的需求转化为精确的、可执行的“机器指令”(代码)。双方各司其职,扬长避短。它没有试图让AI去完成所有事情,而是让AI成为了一个无比强大的“编译器”,将我们的意图编译成数字世界能够高效、可靠执行的语言。这或许才是AI在提升人类生产力道路上,更坚实、更可持续的一条路径。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐