Prompt-Engineering

type
Post
status
Published
date
Mar 2, 2026
slug
prompt-engineering
summary
tags
category
LLM
icon
password
Place
我是谁 →我要干嘛 → 执行步骤(SOP) → 输出成什么样 (结构化输出)→ 还有什么不能干(负向约束) → 提供的实例(Few shot)
补充:CoT(Chain Of Thought)

角色设定

专业身份
定位模型的专业领域
"你是一名资深数据工程师"
经验背景
增加可信度和深度
"专注 Hive SQL 优化 5 年"
行为风格
控制输出的风格
"你工作风格保守,宁可漏报不误报"
核心原则
约束模型的决策边界
"遵循最小修改原则"

任务说明

格式:[动词] + [对象] + [约束/范围]
原则
含义
你的任务
Specific
具体
✅ 明确是 browser → is_baiduapp
Measurable
可衡量
✅ 能判断是否改完
Achievable
可达成
✅ 模型能做到
Relevant
相关
✅ 和 SQL 重构相关
Time-bound
有边界
✅ 只改目标表的代码

SOP

这里我觉得没有一个明显的框架,只要求一个核心,你写给模型的,必须同时可以让一个小白按照1这个流程也可以解决,举个例子看最明显

结构话输出

规定它必须以什么格式返回数据
在业界,让大模型极其稳定、不带任何废话地输出结构化数据(如纯 JSON 或 XML),早就不是单纯在 Prompt 里大喊一句“请严格输出 JSON”就能解决的了。
尤其是引入了类似 LangChain4j 这样的 Agent 框架后,标准的工业级处理流水线(Pipeline)是一套从代码端到大模型端的全链路防御体系
整个标准的业界流程通常包含以下 4 个核心环节:

环节 1:契约定义层 (Data Contract) —— 用代码定义结构

业界绝对不会在 Prompt 里用自然语言去描述 JSON 长什么样(比如“你需要输出一个包含 status 和 reason 的 JSON”)。大模型对自然语言的边界理解很模糊。
标准做法:直接在后端用强类型语言定义好数据结构。
在 Java 中,就是直接写一个标准的 POJO 类或 Record 类,利用 @Description 等注解为字段补充语义说明。框架(如 LangChain4j)会在底层自动利用反射,将这个 Java 类精准翻译成标准的 JSON Schema 格式。

环节 2:API 约束层 (API-Level Enforcement) —— 开启底层锁

不要仅仅依赖 Prompt,要利用各大模型 API 提供的底层能力。
标准做法
在向大模型发起 HTTP/RPC 请求时,在参数里显式指定输出格式。
  • 如果调用 OpenAI/Azure,会开启 response_format: { "type": "json_object" } 甚至最新的 Strict Structured Outputs
  • 如果是国内的千帆、百川等大模型,也会在 API 请求体中挂载之前生成的 JSON Schema。一旦开启这个模式,大模型在生成下一个 Token 时,它的概率分布(Logits)会被底层强行干预,极其有效地逼迫它按照 Schema 生成合法的 JSON 键值对。

环节 3:Prompt 补丁层 (Prompt Reinforcement) —— 斩断幻觉尾巴

即使开启了 API 级别的 JSON Mode,大模型依然有概率犯老毛病:给你加上 Markdown 的反引号,或者在开头加一句“好的,这是你要的结果:”。
标准做法:在 Prompt 的绝对末尾(紧贴用户输入前),加入极其严厉的负向约束。

环节 4:防御性解析层 (Defensive Parsing & Retry) —— 后端最后一道防线

这是最体现工程经验的一环。永远不要默认大模型返回的字符串可以直接交给 ObjectMapper 去反序列化。
标准做法
在接收到大模型的返回值后,进入反序列化前,必须经过一个“清洗与重试拦截器”:
  1. 清洗 (Sanitization):暴力正则刮骨疗毒。
  1. 重试机制 (Auto-Retry):将 JSON 解析包裹在 try-catch 中。如果捕获到 JsonParseException,拦截器会自动将报错信息(甚至把解析失败的具体位置)拼接成一条新的 Prompt 发回给大模型:“你的输出导致了 JSON 解析异常,报错信息为 xxx,请修复格式后重新输出纯 JSON”。通常设置最大重试次数为 2-3 次。

负项约束

这是为了让你的 LangChain4j 程序不报错的关键,明确划定红线。(例如:严禁修改表名不匹配的 SQL、如果没修改不要输出废话) 在工业界,负向约束(Negative Constraints)往往比正向指令更重要,它是保命的底线。
业界在制定负向约束时,通常会遵循以下几个标准做法:

1. 绝对化的语气与“后置原则” (Absolute Language & Recency Bias)

大模型存在“注意力衰减”和“近期偏差(Recency Bias)”。如果你把红线写在 Prompt 的最开头,它读到最后可能就忘了。
  • 业界做法:使用极其严厉的词汇(如 MUST NOT, STRICTLY FORBIDDEN, 绝对严禁),并且把这些红线约束放在整个 Prompt 的最末尾,也就是紧挨着用户输入(Input)的地方。

2. 提供明确的“逃生通道” (Explicit Escape Hatch)

你不能只告诉模型“不要做什么”,你必须精确地告诉它“如果不做这个,那你具体应该输出什么”。如果没有“逃生通道”,模型憋得慌,就会开始幻觉。
  • 业界做法:设定一个标准的回执字符串,当命中负向约束时,强迫模型只输出这个字符串。
  • 针对你的场景
    • “如果前置条件不满足(表名不匹配)或存在语义冲突,严禁输出任何重构建议,严禁解释原因。你必须且只能输出以下准确字符串:【保持原样】未命中重构规则。

3. 具体场景穷举,拒绝泛泛而谈 (Specificity over Generality)

不要让模型自己去猜什么是“废话”,什么是“无关代码”。把它可能犯的错具体指出来。
  • 业界做法:在约束模块中,把历史上出过 Bug 的情况抽象成具体的“红线”。
  • 针对你的场景
    • 差约束:“不要改变原有的业务逻辑。”
      好约束:“严禁合并具有不同返回值的 CASE WHEN 分支。严禁改动除 browser in/not in 之外的任何 WHERE 过滤条件。”

Few-shot

1. MECE 原则 (Mutually Exclusive, Collectively Exhaustive)

样本不需要多(通常 3-5 个即可),但必须相互独立且完全穷尽你所定义的 SOP 核心场景。你的样本不能全是“成功修改”的案例,必须包含触发豁免机制的“反面案例”。
  • 正样本(Positive):完美命中规则,执行标准重构。
  • 负样本(Negative):命中拦截规则(如表名不对、语义冲突),拒绝重构。
  • 边界样本(Edge Case):格式极其混乱的 SQL、嵌套极深的逻辑,展示模型如何保持“格式敏感”和“最小改动”。

2. 严格的格式对齐 (Strict Formatting Consistency)

Few-Shot 中的输入输出格式,必须与你在生产环境中期望模型接收和吐出的格式 100% 保持一致。目前大模型对于输出较为优秀的格式为JSON和XML

3. 隐式思维链 (Implicit Chain of Thought)

虽然在你的核心原则中写了“输出只包含实际修改,不解释未修改的原因”,但在构建复杂逻辑的 Few-Shot 时,业界通常会在 Prompt 内部演示一次“思考过程”,以引导模型。
  • 做法:在给定的样本输出中,先用特定的标签(如 <thought_process>)让模型模拟执行你的 Step 1 到 Step 4,然后再输出最终结果。这能大幅提升模型在“语义冲突检测(Step 3)”时的准确率。

4. 最小化干扰信息 (Minimal Noise)

在构造 SQL 样本时,避免引入与本次重构无关的超复杂业务逻辑。聚焦于 FROM 表名、CASE WHENWHERE 中的 browser 逻辑即可,这样能让模型把注意力完全集中在你的特征匹配上。

思维链 (CoT):

强迫它在给出最终答案前,先输出它的分析过程(例如要求它先输出 <thinking>我的分析步骤...</thinking>)。
在业界,CoT 的核心目的不仅仅是“让大模型多想一会”,更重要的是规范推理路径、便于后端解析、以及强制约束边界
以下是业界实际落地 CoT 的几个进阶维度:

1. 结构化约束 (Structured CoT)

在生产环境中,我们极少让模型“自由发挥”它的分析过程。如果只说“先输出分析过程”,模型可能会写小作文,导致 Token 浪费且容易跑题。
业界做法:强迫模型按照你设定的 SOP 检查清单(Checklist) 来填充它的思考标签。
通过把你的 SOP 转化为填空题,你能极大地降低它的幻觉。
 
 

2. 少样本思维链 (Few-Shot CoT)

这是目前最强大、最稳妥的做法。光在 Prompt 里规定怎么想还不够,你必须在刚才我们讨论的 Few-Shot 示例中,把标准答案的“思考过程”也写进去
大模型是极度依赖上下文模式匹配的。当它看到你的示例里,每一个完美的输出前面都有一个严密推导的 <analysis>,它就会完美模仿这种思维深度。
拿我们上一个话题的“示例 3(语义豁免)”举例,加入 CoT 后的 Few-Shot 应该长这样:

3. 系统级剥离与解析 (System-Level Parsing)

对于你用 LangChain4j 写的 Agent 来说,给用户(或者下游的 Git 评论机器人)展示的内容是不能包含 <analysis> 这一坨东西的。
业界做法
模型输出包含了 <analysis>...</analysis> 和最终的 Markdown 代码块。你的 Java 后端需要用正则表达式或者 XML 解析器,把 <analysis> 里的内容截取下来存入后台日志(用来做以后的 Bad Case 追溯和 Prompt 调优),只把标签之外的“重构建议”丢给下游系统。

4. 链路拆分 (Prompt Chaining / Multi-Agent)

当你的 SQL 审查规则从 1 条增加到 50 条时,让一个大模型在一个 Prompt 里跑完所有的 CoT 几乎一定会崩溃。
业界做法:把 CoT 从“一个 Prompt 里的思维过程”变成“实际的多次 API 调用”。
  • Agent 1 (侦察兵):只负责找表名和定位目标代码。输出:“发现第 15 行有目标逻辑”。
  • Agent 2 (审查员):接收 Agent 1 的片段,专注判断是否有“语义冲突”。
  • Agent 3 (重构师):负责把代码按格式改写出来。

总结来说,业界的 CoT 绝不是放任模型自己思考,而是用结构化的标签强迫它填表,用 Few-Shot 教它怎么填表,最后用代码把它的草稿纸(思考标签)藏起来。

实例

上一篇
Spark
下一篇
JUC
Loading...