核心参数配置
要控制模型的输出质量,首先要理解 LLM 本质上是一个”预测引擎”, 它基于概率来预测下一个词(Token)
你可以通过以下参数来控制这种概率: 采样策略参数(温度(Temperature)、Top-K 与 Top-P), 这些参数可以帮助模型在生成时的输出,在确定性(生成相同结果的可能性)和随机性(生成更多样的输出)的平衡之间做出选择
温度(Temperature)
控制输出的随机性, 温度越低(如 0),输出越具确定性和事实准确性, 温度越高,输出越具创造性和多样性, 在实际应用方面: 对于质量保障(QA)等任务,我们可以设置更低的 temperature 值,以促使模型基于事实返回更真实和简洁的结果, 对于诗歌生成或其他创造性任务,你可以适当调高 temperature 参数值
Top-K 与 Top-P
Top-K:按”名次”录取, Top-K 采样直接从模型预测的词汇中,挑选出概率排名最高的 K 个词作为候选, 它设置的是一个数量上的硬性限制(例如:只看排名前 40 的词), Top-K 的值越高,进入候选的词就越多,模型的输出也就越具创造性和多样性, Top-K 的值越低,模型的输出就越受限制且越基于事实, 如果把 Top-K 设置为 1,就等同于”贪婪采样”, 也就是每次都毫无悬念地只选择概率最高的那一个词, 具体步骤为:从模型输出的logits中,找到概率最大的那个词,直接选择它作为输出, 这与语言模型中的 Top-K=1 和 Temperature=0 相对应
Top-P:按”总分”录取, Top-P 是基于累积概率进行限制, 它从概率最高的词开始按顺序挑选,直到这些词的概率加起来(总和) 不超过你设定的值 P, 举个例子:假设你设置基于概率总和的限制为 0.95(即 95%), 如果排名前两个词的概率加起来就达到了 95%,那么模型就只从这 2 个词里选, 如果前几十个词的概率加起来才达到 95%,那这几十个词都会成为候选
输出长度(Max Tokens)
可限制模型生成的词数, 注意:限制长度并不会让模型学会”简明扼要”的写作风格,它只会在达到字数上限时生硬地截断输出, 也就是说,如果你只要它输出 50 个Token,但它原本打算长篇大论,它并不会帮你总结成 50 个字, 而是会在写到第 50 个 Token 的时候戛然而止,哪怕话只说了一半, 在后端服务中,如果你预期某个任务只需要极短的回答, 设置一个合理的 Max Tokens 可以作为一种”兜底”机制,防止模型意外”发疯”长篇大论, 从而保护你的 API 额度被意外消耗,并控制接口的响应耗时
提示技巧
零样本、单样本与少样本(Zero/One/Few-shot)
提供样本案例是一种有效的沟通方式,能够直接向LLM模型显示我们期望的回答方式与回复格式, 样本案例能够明确界定任务的范围和脉络, 当我们提供一个或多个范例时,实际上是在建立一个参考架构,协助LLM模型理解特定任务的限制, 这对于LLM模型是否能够准确解读指令并提供有效回答至关重要, 想要与ChatGPT等LLM大语言模型进行有效互动的关键,在于精确使用Prompt
Prompt若以是否提供样本做分类,可分为: 零样本提示(Zero-Shot)、单样本提示(One-Shot)与少样本提示(Few-Shot)
零样本提示(Zero-Shot): 它仅提供任务描述和一些供模型开始使用的文本, “零样本”这个名称代表”没有示例”,代表直接下指令(不给示例), 当任务足够直白,或者模型本身的基础能力很强时,零样本就足够了
单样本提示(One-Shot): 当零样本不起作用时,可以在提示中提供演示或示例, 单样本提示提供单个示例,因此得名单样本, 其思想是模型有一个可以模仿的示例,以更好地完成任务, 这就好比你不仅下达了任务,还塞给它一个标准答案模板:”像我这样做一遍”
少样本提示(Few-Shot): 当你希望引导模型遵循特定的输出结构或模式时,示例尤其有用, 少样本提示向模型提供多个示例,多个期望模式的示例增加了模型遵循该模式的机会
系统、角色与上下文提示
系统提示(System Prompting):设定全局规则与大局, 系统提示用于设置语言模型的总体背景和目的,定义了模型应该做什么的”大局”(例如翻译语言、分类评论等), 它明确了模型的基本能力和总体目标
角色提示(Role Prompting):赋予”演员”身份与人设, 角色提示为语言模型分配一个特定的角色或身份供其采用, 它构建了模型输出的风格和语调,为回答增加了一层特异性和个性
上下文提示(Contextual Prompting):提供特定的场景细节, 上下文提示提供与当前对话或任务相关的特定细节或背景信息, 它把模型的回答限制在一个特定的环境中,防止它给出通用、空泛的废话
回退提示(Step-back Prompting)
核心运作机制:先抽象,后具体, 回退提示不会让模型一上来就解决眼前的具体问题, 而是提示它首先考虑与该任务相关的一个更普遍、更宏观的问题
获得这个宏观答案后,再将其作为上下文,喂给后续针对特定任务的提示词, 这种”向后退一步”的做法, 允许模型在尝试解决具体细节之前,先激活相关的背景知识和推理过程, 这种先剥离具体表象、回归底层基础概念的拆解方法(类似于运用第一性原理去剖析问题), 不仅能打破当前的思维局限,还能极大提升大模型输出的质量
回退提示的精髓就在于:不要急于求成, 当你发现模型给出的方案太水、太表面时,不妨让它先停下来, 帮你梳理一下这个领域的基础规律或核心架构, 然后再基于这些高维度的规律去推导具体的实现方案
回退提示(Step-back Prompting) 在实际操作中,并不是靠一句提示词就能搞定的, 而是需要通过两个连续的对话步骤来配合完成:
第一步:向后退(先抽象), 在这一步,你不要直接把最终的任务派发给模型, 而是要提出一个与当前任务相关的、更普遍或更宏观的问题, 这里的目的是迫使模型先去思考解决这类问题需要用到哪些”抽象原则”或”一般概念”, 这就像是让模型在动笔前,先去翻阅一下相关的底层知识库
第二步:向前进(后具体), 拿到了第一步的宏观答案后,你再把这个答案作为”背景上下文(Context)”喂给模型, 然后抛出你最初那个非常具体的任务要求
然后就是工程实现, 把底层的工程复杂度暴露给普通用户是反直觉的, 优秀的内部工具和产品体验,就应该把”提示词工程”封装在引擎盖下面, 作为开发者,我们要做的就是通过架构设计和工作流编排, 在后台悄悄地帮用户完成”回退”的过程, 让他们只需”傻瓜式”地输入具体问题,就能拿到专家级的输出
方案一:后端双节点编排, 核心思想:将一次用户请求,在后端拆解为两次连续的 API 调用
节点 1 (抽象提取节点):
- 拦截用户输入:获取用户输入的具体问题
- 后台静默组装提示词:将其包装进一个预设的“回退提示”模板中:”提取以下用户请求背后的核心抽象概念、原则或理论框架:[用户输入]”
- 执行与捕获:调用 LLM 获取抽象出来的通用概念
节点 2 (具体执行节点):
- 上下文注入:将节点 1 返回的”抽象框架”作为系统上下文,与用户的原始输入拼接
- 最终生成:再次调用 LLM,让其基于这个高级框架回答用户的具体问题
- 返回给用户:用户看到的只有最终的高质量答案,完全感知不到后台经过了两次推演
方案二:单次调用融合, 如果应用对响应延迟要求极高,不允许发起两次网络请求, 则可以利用系统提示,强迫大模型在一次调用内完成回退再前进的过程
- 系统提示设计:你可以设定极其严格的结构化指令,比如: “当用户提出请求时,你必须严格遵循以下两步:第一步(回退思考),先列出解决该问题依赖的 3-5 个最核心的底层原则;第二步(具体解答),基于上述原则,给出具体的解决方案.”
- 强制 JSON 输出进行前端隐匿:为了不让用户看到第一步的废话,你可以要求输出结构化的 JSON 数据
例如:
{"abstract_principles": "...", "final_answer": "..."} - 后端处理:你的后端服务接收到 JSON 后进行解析,只把
final_answer字段的内容展示在聊天助手的 UI 上
方案三:引入意图识别与路由 并不是所有的问题都需要”回退”, 如果用户只是问”今天天气怎么样”或者”解释一下这个报错”,强行回退反而会显得很蠢, 这里可以引入类似 ReAct 范式的轻量级路由机制
- 意图拦截器:用户输入问题后,先过一层极轻量级的分类模型或判别器 判断这是一个”简单事实查询”还是”复杂逻辑/创意构思”
- 动态挂载:如果判定为复杂任务,后端逻辑自动为其挂载”方案一”的回退工作流 如果判定为简单任务,则直接透传给基础大模型进行零样本响应
思维链(Chain of Thought, CoT)(逐步推理)
思维链提示是一种通过生成中间推理步骤来提高 LLM 推理能力的技术, 它不要求模型立刻给出最终答案,而是迫使模型将其推理过程”外化”到生成的词元(Token)序列中, 这有助于 LLM 生成更准确的答案
代价(你需要权衡的成本): LLM 响应包含思维链推理,意味着会生成更多的输出 Token,API 调用的预测成本更高,且响应耗时更长
核心应用场景: 通常,任何可以通过”逐步阐述”来解决的任务都适合使用思维链, 比如: 代码生成:将复杂的编码请求分解为几个步骤, 创建合成数据:给模型一个种子(例如:产品名称),引导模型按照步骤做出假设并生成描述
实现 CoT: 为了保证逻辑稳定,通常会使用”贪婪解码”(也就是把温度设为 0,只走概率最高的那一条路)
零样本思维链 (Zero-shot CoT): 极其简单,只需要在提示词的末尾加上一句魔法咒语:”让我们一步一步地思考”, 例子:直接问模型,模型给出了错误的答案, 但加上这句话后,模型自动列出了 6 个推导步骤,并得出了正确的最终答案
少样本思维链 (Few-shot CoT): 零样本 CoT 在复杂任务上仍有挑战, 最好将 CoT 与少样本(Few-shot)提示结合使用, 做法是:提供一个或多个包含 期望推理过程 的问答示例, 通过观察示例,模型不仅知道要按步骤来,还能学会为新问题遵循类似的结构和逻辑
自洽性 (Self-consistency)
前面提到:为了保证逻辑稳定,通常会使用”贪婪解码”(也就是把温度设为 0,只走概率最高的那一条路), 但这种单线思维有局限性:如果模型在推导的第一步就走歪了,后面全盘皆输, 自洽性就是为了打破这种局限,它结合了 “采样”和”多数投票” 的机制,以此来提高 LLM 生成响应的准确性和连贯性
工程实现: 步骤 1:生成多样化的推理路径:多次向 LLM 提供完全相同的提示词, 这里的关键技术点是:你需要使用高温度设置, 以此来鼓励模型在每次请求时,都生成不同的推理路径和看待问题的不同视角, 步骤 2:提取独立答案:从每个并发生成的响应中,把最终的答案(结论)提取出来, 步骤 3:多数投票 (Majority Voting):对比所有提取出的答案,选择最常见(出现次数最多)的那个作为系统的最终输出
为什么有效? 它的底层逻辑是:虽然单一的推理路径可能有缺陷,但正确的答案往往能通过多条不同的有效路径得出, 通过采样多条路径并寻找共识,系统就能自动过滤掉那些异常的”幻觉”推理,增加对最终答案的信心
付出的代价: 这本质上是:以计算成本换取鲁棒性, 代价就是原本调用 1 次 API 就能解决的事, 现在需要并发调用 3 次或 5 次,成本显然很高
实战案例: 设计一款”漏洞邮件分类系统”, 目标是将邮件分类为 “重要(IMPORTANT)” 或 “不重要(NOT IMPORTANT)”
在极高的温度配置下,系统向大模型发送了 3 次同样的思维链提示: 尝试 1:模型认为存在安全风险,结论是 重要(IMPORTANT), 尝试 2:模型被邮件里随意、甚至带点讽刺的友好语气欺骗了,认为缺乏紧迫感,结论是 不重要(NOT IMPORTANT), 尝试 3:模型再次评估了风险和黑客身份,结论是 重要(IMPORTANT), 如果不加自洽性,系统碰巧走到”尝试 2”的路径,就会漏掉一个严重的安全漏洞, 而引入自洽性后,经过多数投票(3次中有 2次认为是重要), 系统得出了更稳健、一致正确的最终答案
思维树 (Tree of Thoughts, ToT)
它其实是思维链(CoT)概念的一种泛化和升级, 与 CoT 只能遵循单一的线性思维链不同,ToT 允许大语言模型(LLM)同时探索多个不同的推理路径
核心运作机制:从”单行道”到”多岔路”
- 维护树状结构:ToT 的工作原理在底层是维护一个”思维树” 在这个树中,每一个”思想”都代表一个连贯的语言序列,作为解决问题的中间步骤
- 多路分支探索:模型不再是被动地往下走 而是可以通过从树中的不同节点分支出来,主动探索不同的推理路径
- 结构化策略:它将模型的解题过程从线性的、独立的推理路径 彻底转向了更结构化的探索策略
它更像人类的”深度思考” ToT 之所以强大,是因为它极大地模仿了人类在面对难题时更深思熟虑的解决问题的方法
具体体现在它赋予了模型以下能力:
- 考虑替代方案:允许模型在推导的每一步都停下来思考其他的可能性
- 评估与回溯:模型可以评估不同的分支路径
并在发现某条路走不通时”可能回溯”到上一个节点,重新选择方向
在工程化落地层面, 实现 ToT 的核心在于 不能再依赖大模型自己一口气把话说完, 而是必须在后端代码中引入经典的 数据结构(树) 和 控制流算法(搜索) 来”接管”大模型的大脑
ReAct (推理与行动)
传统的 LLM(大语言模型) 存在”纸上谈兵”的局限:它们只能生成文本,无法直接获取实时信息或操作外部系统
在 ReAct 出现之前,AI 处理任务的方式大致有两类: 一类是 “纯推理”,比如:让大模型直接输出答案, 但它可能脱离实际(比如:回答”今天北京的天气”时,用的是训练数据里的旧信息); 另一类是 “纯行动”,比如:按固定流程调用工具, 但遇到意外时无法灵活调整(比如:订票时发现航班取消,不知道该换哪趟), 这两种方式的共同问题是:推理与现实脱节,行动缺乏动态思考
2022年,谷歌团队在论文中正式提出 ReAct 范式, 其核心洞察是:人类解决问题时,从来不是先完美规划再行动,而是:”想一步、做一步、看结果、再调整”
ReAct (推理与行动 - reason & act) 提示是一种范式, 使 LLM 能够通过将自然语言推理与外部工具(搜索、代码解释器等)相结合来解决复杂任务, 这是迈向智能体建模的第一步, 它完美模仿了人类在现实世界中的运作方式, 因为我们可以进行口头推理并采取行动获取信息
核心运作机制: ReAct 并不是单向输出,而是构建了一个动态的迭代闭环, ReAct 提示通过将推理和行动结合到一个思想-行动循环中来工作:
- 思考 (Thought/Reason):LLM 首先对问题进行推理并生成行动计划
- 行动 (Act):LLM 决定调用外部工具(例如:发起搜索或查询数据库),并执行计划中的行动
- 观察 (Observe):外部工具返回真实世界的结果,LLM 接收这些观察结果
- 循环更新:LLM 使用观察结果更新其推理并生成新的行动计划;这个过程持续进行,直到 LLM 找到问题的解决方案
案例: 1.多步信息汇总: 要求模型:找出”ONXY 乐队成员共有多少个孩子?”, 模型首先思考乐队有 4 名成员, 接着它执行行动,去搜索第一位成员的孩子数量, 观察到结果为”三个孩子”后, 它再次思考,将进度更新为”1/4 的成员有 3 个孩子”,并继续搜索下一位, 最终它汇总出总数为 10
2.动态策略调整: 要求模型:计算商品最终价格, 模型首先查询原价(行动 1),接着查询优惠活动(行动 2), 此时进入关键分支: 如果模型观察到的是”满减券”,它的思考逻辑就是做减法, 如果观察到的是”8折券”,它的思考逻辑就会动态切换为做乘法, 这展现了极高的灵活性和极强的业务适应能力
工程演进:Function Calling 为什么会出现
Function Calling(函数调用) 由 OpenAI 于2023年正式提出
在实际业务开发中,纯 ReAct 面临着严重的工程瓶颈, Function Calling 并非替代 ReAct 的思想, 而是将其”推理-行动”范式进行了彻底的工程化升级, 它主要解决了以下痛点:
1.从”正则解析”到”强类型绑定”的稳定性:
原始 ReAct 的痛点:依赖自然语言描述工具,
后端需要通过复杂的正则表达式去解析模型输出的文本,
一旦模型格式稍有偏差(比如少个冒号),解析就会崩溃,
Function Calling:通过 API 原生支持结构化工具定义,
模型直接返回标准化的 tool_calls JSON 对象,
在后端服务中,可以直接将这些标准 JSON 反序列化绑定到预定义的数据结构体上,
彻底消除了文本解析的不确定性,
参数的结构化强制校验也避免了合规与类型错误
2.开发效率与交互轮次的优化:
降低提示词复杂度:ReAct 需要在 System Prompt 中花大量篇幅(Token)去教模型怎么调用工具,
而 Function Calling 通过独立的 tools 参数传递定义,
彻底解耦了业务逻辑与提示词,
减少交互轮次(并发执行):ReAct 每次只能执行一个”思考-行动”单线程循环,
速度慢且消耗大量 Token,
Function Calling 支持单次返回多个工具调用请求,
让后端可以并行执行,大幅提升了系统的响应速度
工程实现:Function Calling VS ReAct
在 Dify 等工程化平台上,为了让模型调用工具, 我们通常面临两条技术路线:Function Calling 和 ReAct, 理解它们的优劣,是架构设计的关键:
Function Calling (函数调用): 这是一种模型底层原生支持的强约束调用机制, 它不要求模型写出长篇大论的”思考过程”, 而是直接将用户的意图映射到你预先定义好的 JSON 函数结构中, 核心优势: 结构化与精确:直接输出结构化的 JSON 参数,极易与后端 API 完美集成,无需复杂的正则解析, 执行效率极高:因为省略了冗长的中间推理文本,响应速度极快,且极大地节省了 Token 成本; 致命弱点: 灵活性差:面对模糊的用户意图,或者需要多步试错才能找到正确工具的任务时,模型往往会”卡壳”或选错工具
特点:精确、执行效率高、易于集成外部功能、结构化输出
适用场景:
- 需要根据用户意图精确调用特定工具的自动化任务
- 需要与外部 API 服务进行高频、稳定交互的场景
- 对响应速度和 Token 成本极其敏感的线上业务
ReAct (纯文本的”思考-行动”流): 它利用Prompt Engineering, 强制模型用自然语言把每一步的所思所想打印出来,再由后端系统去截取文本里的”动作”指令, 核心优势:极高的灵活性与可解释性:因为推理和行动步骤交织在一起, 你能清晰地看到 Agent 决策的全过程(它是怎么想的,为什么决定用这个工具), 它能在遇到错误反馈时,自行调整思路重新尝试; 致命弱点:执行慢、成本高:需要反复调用模型,生成大量的”内心独白”文本, 解析极其脆弱:由于输出的是自然语言,后端系统提取指令时非常困难, 模型偶尔的格式错乱(比如少打一个空格),都可能导致整个 Agent 宕机
特点:灵活性高、可解释性好、能有效利用外部信息逐步探索,但执行速度慢、成本高、推理稳定性强依赖模型本身的智商
适用场景:
- 需要进行探索性研究、从多个非结构化来源收集和综合信息的任务
- 问题解决方案路径极度不明确,需要模型像人类一样通过”迭代尝试和调整策略”来找到答案的复杂问题
- 业务需要极高的”可解释性”,系统必须向排查人员展示 Agent 每一步决策过程的场景
自动提示工程 (APE)
核心理念:简单来说,就是”编写一个提示来编写提示”, 这种方法不仅极大地减轻了人工输入的需要和试错成本, 而且通常还能提高模型在各种任务中的客观性能
在后端架构或者脚本中,实现 APE 其实就是跑通一个 “生成 -> 评估 -> 迭代” 的自动化闭环;
第一步:批量生成变体, 需要先写一个初始的”母提示”, 让大模型为你生成多个后续可以使用的候选提示词, 假设要训练一个卖乐队周边 T 恤的客服机器人的意图识别能力: 为了收集用户可能的问法, 需要向大模型下达指令: “为了训练聊天机器人,我们需要多种订购方式来表达:’一件 Metallica T 恤,S码’;生成 10 个变体,语义相同但保持原意”, 模型就会自动吐出 10 种不同的说法(如:”我想要一件小码的 Metallica T 恤”、”你能给我拿一件小码的 Metallica T 恤吗?”等)
第二步:量化评估, 拿到这批候选提示词后,不能盲猜哪个好,而是要建立自动化的评估机制
第三步:优胜劣汰与循环迭代, 根据上一步的跑分结果,选择评估分数最高的那条候选指令, 这个”优胜者”就可以直接作为最终硬编码在软件应用程序或聊天机器人节点里的正式提示词, 你甚至可以把这个优胜者再丢回第一步, 让模型基于它继续微调生成下一代变体,不断循环
日常最佳实践
在日常编写提示时,有以下极具实操性的建议:
- 提供示例:这是最重要的一点,示例是极其强大的教学工具
- 使用”指令”而非”约束”:用积极的语气告诉模型”应该做什么”(指令),比用消极的语气告诉它”不要做什么”(约束)效果更好,更不容易产生冲突
- 保持简洁:避免使用复杂的术语或不必要的信息;如果你自己看着都觉得绕,模型也会觉得绕
- 明确输出要求:不要让模型去猜,明确告知长度、内容焦点和风格
- 使用变量:在提示中使用类似
{city}的变量可以方便复用 - 系统地记录尝试:像对待科学实验一样,用表格记录下你尝试的每一个提示版本、温度设置以及输出效果,以便复盘和优化