1|
引言:从"调 Prompt"到"调函数"
2|
如果你在过去两年里一直在关注 AI 开发,一定对"Prompt Engineering"这个词不陌生。从最初把 prompt 当作咒语一样精雕细琢,到如今用 function calling / tool use 让模型自主完成任务,AI 应用的开发范式已经经历了一次深刻的转变。
3|
这篇文章试图梳理这条脉络,帮助开发者理解这一演变的本质:我们不是在抛弃 prompt engineering,而是在把它工程化、系统化。
4| 5|
第一阶段:Prompt 即一切
6|
2022 年底 ChatGPT 刚问世时,开发者能做的事情其实非常有限------把精心设计的一段文本发送给模型,然后祈祷回复符合预期。这就是"Prompt Engineering"的起源。
7| 8|
1.1 纯文本 prompt 的局限
9|
早期的典型 prompt 是这样的:
10|
你是一个优秀的 Python 工程师。请编写一个函数来...
11|要求:
12|1. 使用类型注解
13|2. 包含完整注释
14|3. 处理边界情况
15|
这种方式的痛点显而易见:
16|
- 17|
- 缺乏结构:所有约束混在同一个文本流里,模型容易遗漏
- 18|
- 不确定性高:同样的 prompt 在不同温度下结果可能天差地别
- 19|
- 难以复用:每次都要重写或复制黏贴
- 20|
- 无法编程控制:prompt 是静态文本,无法做条件判断或循环
- 21|
22| 23|
1.2 早期优化手段
24|
为了弥补这些短板,社区想出了各种技巧:
25|
- 26|
- Few-shot 示例:在 prompt 里塞入输入输出对,让模型模仿格式
- 27|
- Chain-of-Thought:引导模型"一步步思考",提升推理准确率
- 28|
- 角色扮演:System prompt 里定义"你是一个... ",利用预训练的角色映射
- 29|
- 模板化:用 Jinja2/string.Template 把变量插入固定的 prompt 模板
- 30|
31|
但这些本质上都是文本层面的优化,没有触及交互范式的变革。
32| 33|
第二阶段:Chat Completions 的进化
34|
2023 年,OpenAI 引入了 Chat Completions API,把单一的 prompt 拆解为 system、user、assistant 三条消息。虽然看起来只是 API 格式的调整,但它带来了质的飞跃。
35| 36|
2.1 角色分离带来的结构化
37|
开发者可以把「系统指令」「用户输入」「模型回复」分开管理:
38|
messages = [
39| {"role": "system", "content": "你是一个代码审查助手,请用中文回复"},
40| {"role": "user", "content": file_content},
41|]
42|
这意味着:
43|
- 44|
- System prompt 可以独立维护:作为"永远不变的行为基线"
- 45|
- 多轮对话成为可能:模型可以记住上下文,在后续轮次中持续改善
- 46|
- 角色混合:可以在对话中切换角色,实现更复杂的交互
- 47|
48| 49|
2.2 从"一次性"到"对话式"
50|
Chat Completion 催生了最早的"Agent"雏形:
51|
- 52|
- 用户提问 → 模型思考 → 用户追问 → 模型修正
- 53|
- 但模型仍然只能返回文本,无法自主行动
- 54|
55|
这个阶段,prompt engineering 的复杂度从"写一个好 prompt"变成了"管理一整段对话上下文"。一个典型的 prompt 可能包含几千字的 system message、十几轮历史对话、以及各种 few-shot 示例。上下文窗口的消耗成了一个新问题。
56| 57|
第三阶段:Function Calling ------ 范式的分水岭
58|
2023 年 6 月,OpenAI 发布了 Function Calling(后来改名为 Tool Use)功能。这不仅是API 功能的补丁,更是一次交互范式的根本转变。
59| 60|
3.1 What is Function Calling?
61|
Function Calling 允许开发者在请求中注册一组"可调用函数"的 JSON Schema,模型在需要时自主选择调用哪个函数,并返回结构化的参数。开发者再执行函数,将结果回传给模型。
62|
这是一个里程碑:模型不再只能"说",它开始能够"做"。
63| 64|
3.2 一个直观的对比
65|
没有 Function Calling:
66|
用户:"北京的天气怎么样?"
67|模型回复:"我无法实时获取天气数据,请查天气预报应用。"
68|
有了 Function Calling:
69|
用户:"北京的天气怎么样?"
70|模型返回:{"function": "get_weather", "args": {"city": "北京"}}
71|→ 开发者执行函数 → 返回结果给模型
72|模型回复:"北京目前 22°C,晴,空气质量良好。"
73| 74|
3.3 核心能力对比
75| 76| 77| 78| 79| 80| 81| 82| 83| 84| 85| 86| 87| 88| 89| 90| 91| 92| 93| 94| 95| 96| 97| 98| 99| 100| 101| 102| 103| 104| 105| 106| 107| 108|
|--------|------------------------|------------------------------|
| 维度 | Prompt Engineering | Function Calling |
| 输出形式 | 自然语言文本 | 结构化 JSON(可程序消费) |
| 与代码的边界 | 模糊,结果需二次解析 | 清晰,Schema 定义即契约 |
| 可靠度 | 高度依赖 prompt 文本质量 | 依赖 Schema 设计 + 模型能力 |
| 可测试性 | 低------"感觉对了"就是通过 | 高------JSON Schema 校验 + 单元测试 |
| 组合能力 | 文本拼接 | 多个 function 自由组合 |
109| 110|
第四阶段:从 Function Calling 到 Agent 框架
111|
Function Calling 打开了潘多拉魔盒------既然模型可以调用函数 ,那为什么不能让它自我循环呢?
112| 113|
4.1 ReAct 模式:思考→行动→观察
114|
2024 年,几乎所有主流 Agent 框架(LangChain、AutoGen、CrewAI、Hermes 等)都采用了 ReAct(Reasoning + Acting)模式。其核心循环是:
115|
- 116|
- 模型收到用户请求
- 117|
- 模型进行推理(Thought),决定下一步行动
- 118|
- 模型调用函数(Action),传入参数
- 119|
- 开发者执行函数,返回结果(Observation)
- 120|
- 模型根据结果调整思路,回到第 2 步
- 121|
- 直到模型认为任务完成,返回最终答案
- 122|
123|
这本质上就是一个 while 循环。Prompt Engineering 在这个框架里的角色发生了根本变化:
124| 125|
4.2 Prompt 的新角色
126|
在 Agent 框架中,prompt 不再是"告诉模型答案",而是定义模型的决策逻辑:
127|
- 128|
- System prompt 描述 Agent 的边界(能做什么、不能做什么)
- 129|
- Function schema 描述工具接口(输入是什么、输出是什么)
- 130|
- Runtime context 提供当前状态(已经做了什么、还需要做什么)
- 131|
132|
换句话说,函数调用处理了"怎么做",而 prompt 处理了"要不要做"和"下一步做什么"。两者各司其职。
133| 134|
4.3 现实中的例子
135|
以 Hermes Agent 自身为例------当一个用户说"帮我写一篇 CSDN 文章并发布"时,背后的流程是:
136|
1. LLM 通过 ReAct 决定:需要调用 generate_article 函数
137|2. generate_article 返回一篇 HTML 格式的文章
138|3. LLM 评估文章质量,决定进一步调用 publish_csdn 函数
139|4. publish_csdn 函数使用 Playwright 操作浏览器
140|5. 浏览器返回发布结果
141|6. LLM 将结果整理为用户可读的回复
142|
全程开发者不需要写任何 if-else 逻辑,LLM 的推理能力就是控制流本身。
143| 144|
第五阶段:MCP 与标准化工具生态
145|
进入 2025 年,业界最大的变化是工具生态的标准化。Anthropic 推出的 MCP(Model Context Protocol)让 function calling 从"每个项目自定协议"走向了"通用标准协议"。
146| 147|
5.1 从独占到开放
148|
早期每个 Agent 框架都自己定义 tool 接口:
149|
- 150|
- LangChain: @tool 装饰器 + Tool 类
- 151|
- OpenAI: function 参数的 JSON Schema
- 152|
- AutoGen: 自定义 register_function()
- 153|
154|
MCP 的贡献在于统一了服务端和客户端的交互协议:
155|
# 任何 MCP 服务器暴露的工具都可以被任何 MCP 客户端消费
156|# 不需要适配层,不需要桥接代码
157| 158|
5.2 对开发者的影响
159|
这意味着:
160|
- 161|
- 你写一个 MCP 服务器 = 所有支持 MCP 的 Agent 都能用
- 162|
- 多工具链组合不再是噩梦------MCP 天然支持多个服务器
- 163|
- 非 AI 开发者也能提供"AI 可消费的 API"------只需写一个 MCP 服务端
- 164|
165| 166|
总结:范式迁移的本质
167|
回顾这两年多的演变,我们可以看到一个清晰的趋势:
168| 169|
三个转变
170|
- 171|
- 从<用词>到<用结构>:不再追求 prompt 中的某个关键词,而是设计清晰的交互结构(角色、消息、函数)
- 172|
- 从<写提示>到<写系统>:AI 应用开发越来越像传统后端开发------定义 API(function schema)、写业务逻辑(tool implementation)、配置路由(Agent 循环)
- 173|
- 从<一次性>到<循环>:单次问答 → 多轮对话 → Agent 自主循环,模型的自主性每提升一层,开发者控制的方式就向更高抽象层退一层
- 174|
175| 176|
对你意味着什么?
177|
如果你仍在专注于"怎么写一个好 prompt",建议拓宽视野:
178|
- 179|
- 学一点 JSON Schema:Function calling 的参数定义比 prompt 文本更影响结果质量
- 180|
- 理解 MCP 协议:它会像 REST API 一样成为基础设施
- 181|
- 把 Agent 看作一个微服务:给它定义清晰的输入输出、状态管理和错误处理
- 182|
- 不要放弃 Prompt Engineering:它仍然是 system prompt 和 agent 行为的核心,只是从"前台"退到了"后台"
- 183|
184|
Prompt Engineering 没有死,它被工程化了。
185|
这句话大概是对这两年 AI 应用范式演变最好的总结。
186| 187|
188|
(完)