1. 从一次失败的天气查询说起
那天下午,我正在调试一个天气查询Agent,本以为是个简单的任务,结果被一个看似简单的问题卡了整整三小时。用户问"明天北京和上海温差多少",Agent直接调用API返回了两地温度,然后输出"温差是7度"——既没有计算过程,也没说明哪个城市温度更高。更糟的是,在连续测试中,我发现它偶尔会算错正负号。
这个经历让我意识到:表面能运行的Agent可能隐藏着严重的逻辑缺陷。就像一栋外表光鲜但地基不稳的建筑,平时看不出问题,遇到特殊情况就会崩塌。这促使我深入研究了Prompt设计的三个核心技巧:思维链、少样本学习和自洽性检查。
2. 思维链:让AI的思考过程透明化
2.1 从黑箱到白箱的转变
最初我以为是API数据解析的问题,经过仔细排查才发现是Prompt设计缺陷。原始指令只有简单的一句:"请计算两个城市的温差"。这导致模型直接跳到了答案生成阶段,中间的推理过程被完全压缩了。
改进后的Prompt如下:
text复制请按步骤思考:
1. 获取北京明日最高温和最低温
2. 获取上海明日最高温和最低温
3. 计算北京日平均温度:(最高温+最低温)/2
4. 计算上海日平均温度:(最高温+最低温)/2
5. 用北京平均温度减去上海平均温度
6. 输出计算结果,并说明哪个城市更暖
关键突破点在于"请按步骤思考"这个触发器。它就像给AI一个思考框架,强制其展示完整的推理链条。效果立竿见影——不仅准确率大幅提升,调试也变得简单了,因为可以清晰看到哪一步出了问题。
2.2 工程化的思维链实现
在实际项目中,我发展出了更工程化的标记方法:
text复制// 思考区(用户不可见)
<reasoning>
1. 用户问的是温差,需要先明确比较基准...
2. 需要同时查询两地天气,避免缓存偏差...
</reasoning>
// 执行区
<action>
调用weather_api(locations=["北京","上海"])
</action>
// 最终答案
<output>
北京平均温度15℃,上海平均温度22℃,上海比北京高7℃
</output>
这种结构化方法特别适合复杂任务,尤其是需要多步调用外部工具的场景。它带来了三个显著优势:
- 可调试性:每个环节的输出清晰可见
- 可维护性:不同功能区块分离
- 可扩展性:新增步骤不会破坏原有逻辑
经验提示:思维链步骤最好控制在5-7步内。超过这个数量,模型容易"走神"。对于复杂任务,应该拆分为多个子任务链。
3. 少样本学习:用例子引导模型理解
3.1 从失败案例中学习
思维链解决了单次推理的问题,但在复杂任务中,模型仍可能出现理解偏差。例如在电商客服场景中,用户问"帮我比较一下手机A和手机B的续航和拍照",模型却错误地比较了"手机A的续航"和"手机B的拍照"——典型的维度错位。
3.2 精心设计的少样本示例
解决这类问题需要少样本(Few-shot)技术。我在Prompt中嵌入了三个精心设计的示例:
text复制例1:
用户:对比产品X和产品Y的屏幕和电池
助理:我需要分别获取:
1. 产品X的屏幕参数和电池参数
2. 产品Y的屏幕参数和电池参数
然后对比屏幕方面(尺寸、分辨率),再对比电池方面(容量、快充)
例2:
用户:哪个笔记本更轻,而且CPU更强?
助理:我需要同时考虑重量和CPU性能:
1. 查询各笔记本重量
2. 查询各笔记本CPU型号和基准分数
3. 综合比较
例3:
用户:这两款相机在低光拍摄和对焦速度上谁更好?
助理:这是两个独立维度:
1. 低光拍摄性能(看传感器尺寸和最大ISO)
2. 对焦速度(看相位对焦点数和算法)
需要分别获取数据后对比
示例设计原则:
- 覆盖不同句式(对比/哪个更好/谁更...)
- 展示完整的思考过程
- 包含多维度比较的场景
- 数量控制在3-4个(太少不够引导,太多影响性能)
踩坑提醒:曾经为了省事直接使用历史对话作为示例,结果模型反而学会了用户的错误提问方式。少样本例子的质量远比数量重要。
4. 自洽性检查:让模型自我验证
4.1 金融计算中的教训
在开发金融计算Agent时,遇到一个典型问题:用户问"如果年化5%,投资3年,复利计算最终收益是多少",模型直接输出"增长15.76%",但用户实际可能需要的是绝对收益计算。
4.2 双重验证机制
现在的解决方案是加入验证层:
text复制请分两步处理:
第一步:计算并输出结果
第二步:检查以下方面:
- 单位是否一致(% vs 绝对值)
- 是否回答了问题的所有部分
- 数字计算是否重新验算过
如果发现不一致,重新计算
4.3 多路径投票验证
对于关键计算,可以采用更严格的多路径验证:
text复制请用三种不同方法计算:
方法1:直接复利公式
方法2:逐年计算
方法3:用对数计算
比较三种结果是否一致,取多数一致的结果
这种方法虽然会增加响应时间(约2-3倍),但能显著提高关键计算的可靠性。我的经验法则是:对数值计算、事实核对等高危操作启用完整检查,普通对话用简单验证即可。
5. 综合应用:构建健壮的文本处理Agent
5.1 标准模板结构
经过多次迭代,我的Prompt形成了标准结构:
text复制[少样本示例]
[思维链框架]
[关键点自洽检查]
以代码生成为例:
text复制(先给两个代码示例)
请按步骤思考:理解需求 -> 设计函数签名 -> 写测试用例 -> 实现代码
最后检查:函数是否处理了边界条件?变量命名是否一致?
5.2 工程化思维的应用
构建Agent时,Prompt更像技术规格书而非简单指令。对比以下两种写法:
模糊版本:
text复制"请分析这段日志里的错误信息"
工程化版本:
text复制你是一个日志分析Agent,需要严格按以下步骤工作:
1. 输入为纯文本日志内容
2. 识别所有包含"ERROR"或"FATAL"的行
3. 提取每行的时间戳(格式如[2024-03-15 14:22:31])
4. 按错误类型归类统计
5. 输出JSON格式:{"error_count": N, "details": [{"time": "...", "message": "..."}]}
如果时间戳格式不符,标记为"时间格式异常"。
不要猜测日志内容,只处理明确匹配的行。
关键转变:将AI视为需要明确指导的新手工程师,而非能理解潜台词的老手。
6. 实战案例:配置解析器的构建
6.1 需求背景
在嵌入式开发中,经常需要处理混合格式的配置文件。以下是一个实际应用于芯片配置项目的Prompt设计:
text复制角色:嵌入式配置解析专家
任务:解析混合格式的配置文本
输入:用户提供的任意长度文本,可能包含:
- KEY=VALUE 行
- JSON片段
- 以#或//开头的注释
- 空行和缩进混乱的文本
处理流程:
1. 第一遍过滤:删除所有注释行和空行
2. 第二遍识别:区分出键值对和JSON块
3. 第三遍提取:
- 键值对转为 {"key": "value"} 对象
- JSON块尝试解析,如果失败则保留原始字符串并标记解析失败
4. 输出要求:
- 最终合并为一个JSON对象
- 包含元信息:total_entries, parse_failed_count
- 保留原始行号便于追溯
边界情况处理:
- 等号两边有空格的情况要trim掉
- 遇到重复KEY,后者覆盖前者
- 遇到非ASCII字符记录警告但不中断
6.2 设计亮点
这个Agent的成功之处在于:
- 多级处理:分阶段过滤、识别和提取
- 容错机制:对解析失败的内容有妥善处理
- 追溯能力:保留原始行号便于调试
- 边界覆盖:考虑了各种现实中的异常情况
7. 常见陷阱与规避策略
7.1 过度依赖AI的"智能"
早期我曾让Agent"智能合并相似错误",结果它把"内存不足"和"内存分配失败"错误地合并统计。教训是:关键判断逻辑必须显式定义,相似度阈值、匹配规则要明确写死。
7.2 错误传播处理
在Prompt中必须明确错误处理策略:
text复制如果JSON解析失败,使用备用正则提取,仍失败则保留原始文本并记录错误,继续处理下一段。
健壮性原则:单个步骤的失败不应导致整个流程中断。
7.3 输出格式不一致
曾因输出JSON中某个字段有时是字符串有时是数字,导致下游脚本崩溃。现在强制规范:
text复制所有数字字段用字符串表示,除非需要数值计算。
布尔值统一为true/false,不用1/0。
8. 工作流设计与Agent协作
单个Agent能力有限,但可以构建工作流链:
text复制原始日志 → 结构化Agent → 统计Agent → 报告生成Agent
关键是在每个Agent的Prompt中明确接口约定:
text复制你的输出将被送往统计Agent,因此必须包含timestamp字段(ISO 8601格式)。
这类似于UNIX管道理念,但用自然语言定义接口规范。
9. 最佳实践与工作流程变革
使用这些技术后,我的工作方式发生了显著变化:
- Prompt优先开发:面对新任务,先花10-15分钟构思Prompt,快速验证思路可行性
- 人工复核机制:对关键输出保留人工审核环节,特别是低置信度部分
- 版本化管理:像管理代码一样管理Prompt迭代历史
- 渐进式复杂化:从小而具体的任务开始,逐步扩展功能范围
最深刻的体会是:Prompt工程极大降低了文本处理的原型验证成本。过去需要200行Python代码验证的想法,现在一段精心设计的Prompt就能快速验证。但记住,复杂逻辑最终仍需落实到代码——Agent是探索工具,不是生产解决方案。
