免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

高级提示词工程实战:从基础提示词到自我修正与可控输出(generative-ai-for-beginners 第 5 课)

高级提示词工程实战:从基础提示词到自我修正与可控输出(generative-ai-for-beginners 第 5 课) 高级提示词工程实战从基础提示词到自我修正与可控输出generative-ai-for-beginners 第 5 课【免费下载链接】generative-ai-for-beginners21 Lessons, Get Started Building with Generative AI项目地址: https://gitcode.com/GitHub_Trending/ge/generative-ai-for-beginners本技术指南以 generative-ai-for-beginners 课程第 5 课《高级提示词》为主体系统讲解零样本zero-shot、少样本few-shot、思维链chain-of-thought、生成知识generated knowledge、Least-to-most、自我精炼self-refine与苏格拉底式提问maieutic prompting等核心提示词技术并深入剖析如何通过 temperature 等参数让 LLM 输出在“多样化”与“确定性”之间自由切换。读完本文你将掌握一套可复用到任意 LLM 的提示词构造方法论并能结合仓库中的 Python 作业 与 JavaScript 作业 实际演练自我精炼流程将一段简陋的 Flask/Express 代码迭代为安全、健壮的 Web API。引言为什么要深入研究提示词在上一课第 4 课提示词工程基础中我们建立了核心认知提示词工程prompt engineering是通过提供更有用的指令或上下文引导模型产生更相关回答的过程。写提示词通常包含两个阶段一是构造提示词提供相关上下文二是优化提示词逐步改进。但在实际使用中仅仅会写提示词远远不够。本课的目标是让你从到处试各种提示词进阶到理解为什么某条提示词优于另一条并学会遵循一些适用于任何 LLM的基础技术来构造提示词。本课的核心学习目标应用能改善提示词结果的提示词工程技术学会构造**多样化varied或确定性deterministic**两类输出。提示词工程是什么提示词工程是创建能够产生期望结果的提示词的过程。它不仅仅是写一段文本提示词——提示词工程并不是一门工程学科而更像是一套可以按需套用的技术集合。一条提示词的解剖先看一条最简单的提示词生成 10 个关于地理的问题。Generate 10 questions on geography.这条看似简单的提示词里其实已经暗含了两类技术上下文Context你指定了主题必须是地理限制输出Limiting the output你要求最多 10 个问题。简单提示词的局限即便如此你得到的结果仍可能不符合预期问题确实生成出来了但地理是一个巨大的主题——你不知道它生成的会是国家、首都、河流还是其他子领域如果你还希望问题以某种特定格式呈现呢由此可以看到构造提示词需要考虑的因素非常多。生成式 AI 有能力帮助各种角色和行业的从业者下面我们就逐一拆解基础提示词技术。七大核心提示词技术首先需要明确一个前提提示词是 LLM 的涌现属性emergent property——它不是模型中内置的功能而是我们在使用模型过程中发现的能力。仓库课程中给出了 7 种基础技术逐一展开如下。零样本提示Zero-shot prompting这是最基础的形式单条提示词仅依赖模型的训练数据直接作答。这大概是你初学 LLM 时最常用的方式。提示词什么是代数回答代数是数学的一个分支研究数学符号以及操作这些符号的规则。零样本适合概念解释、常识问答等无需额外示例的任务但遇到复杂推理或格式要求时往往力不从心。少样本提示Few-shot prompting少样本提示通过在请求中附带 1 个或多个示例来引导模型。它仍是一条提示词但携带了与任务强相关的额外数据。提示词用莎士比亚的风格写一首诗。这里有几个莎士比亚十四行诗的例子 第 18 首我可以把你比作夏日吗你更可爱更温和…… 第 116 首别让我承认两颗真心的结合会有障碍。爱不是爱若它随环境改变而改变…… 第 132 首我爱你的眼睛它们怜悯我知道你的心用轻蔑折磨我…… 现在写一首关于月亮之美的十四行诗。回答月亮在天空中温柔地闪耀银色的光芒投下它优雅的魅力……示例为 LLM 提供了期望输出的上下文、格式或风格帮助模型理解具体任务生成更准确、更贴切的回答。少样本非常适合需要特定文体、特定格式输出的场景。思维链Chain-of-thought思维链是一种非常有趣的技术它带领 LLM 一步步完成任务。核心思路是以指令的方式让模型理解怎么做。先看一个反例提示词Alice 有 5 个苹果扔掉 3 个给 Bob 2 个Bob 又还回来 1 个Alice 现在有几个苹果回答5模型答了 5这是错误的。正确结果是 1 个苹果5 - 3 - 2 1 1。如何教会模型正确计算使用思维链分三步给 LLM 一个类似的例子展示计算过程说明如何正确计算再给出原始问题。具体如下提示词Lisa 有 7 个苹果扔掉 1 个给 Bart 4 个Bart 还回来 1 个 7 - 1 6 6 - 4 2 2 1 3 Alice 有 5 个苹果扔掉 3 个给 Bob 2 个Bob 还回来 1 个Alice 现在有几个苹果 回答1注意我们写了明显更长的提示词——先给出一个同类例子、展示计算过程、再放原始问题最终得到正确答案 1。思维链是一种非常强大的技术尤其适合算术、多步推理、逻辑推导类任务。生成知识Generated knowledge很多时候我们希望用自己公司的数据构造提示词提示词的一部分来自企业另一部分是真正关心的问题。例如在保险行业提示词模板可能是这样的{{company}}: {{company_name}} {{products}}: {{products_list}} Please suggest an insurance given the following budget and requirements: Budget: {{budget}} Requirements: {{requirements}}模板中的{{variable}}是变量占位符将由企业 API 提供的真实值替换。替换后的提示词形如Insurance company: ACME Insurance Insurance products (cost per month): - Car, cheap, 500 USD - Car, expensive, 1100 USD - Home, cheap, 600 USD - Home, expensive, 1200 USD - Life, cheap, 100 USD Please suggest an insurance given the following budget and requirements: Budget: $1000 Requirements: Car, Home, and Life insurance将该提示词送入 LLM得到如下输出Given the budget and requirements, we suggest the following insurance package from ACME Insurance: - Car, cheap, 500 USD - Home, cheap, 600 USD - Life, cheap, 100 USD Total cost: $1,200 USD可以看到模型多推荐了人寿保险Life insurance而这本不应出现——因为预算只有 $1000且需求中的 Car 与 Home 已超预算。这个结果说明需要优化提示词让它更明确地表达可以允许什么。经过反复试错trial and error得到如下改进版Insurance company: ACME Insurance Insurance products (cost per month): - type: Car, cheap, cost: 500 USD - type: Car, expensive, cost: 1100 USD - type: Home, cheap, cost: 600 USD - type: Home, expensive, cost: 1200 USD - type: Life, cheap, cost: 100 USD Please suggest an insurance given the following budget and requirements: Budget: $1000 restrict choice to types: Car, Home注意添加type、cost字段并引入关键词restrict帮助 LLM 更好地理解我们的诉求。这次输出变为Given the budget and requirements, we suggest the Car, Cheap insurance product which costs 500 USD per month.这个例子的意义在于即使使用了生成知识这种基础技术大多数情况下仍需优化提示词才能得到期望结果。模板化 变量注入 明确约束是让企业数据进入提示词的推荐做法。Least-to-most从小到大分解Least-to-most 的核心思想是把一个大问题拆解成若干子问题从而引导 LLM 逐个攻克。典型例子是数据科学流程提示词如何分 5 步完成数据科学AI 助手回答收集数据清洗数据分析数据绘图数据呈现数据这与思维链类似但更强调由小到大的递进式问题分解适合复杂任务规划。自我精炼Self-refine批判性地看待结果面对生成式 AI不能盲目信任输出——LLM 给出的只是下一个最可能出现的词而不是正确的答案。因此让模型自我批评是一种好习惯这正是 self-refine 技术的由来。工作流程如下用初始提示词请 LLM 解决一个问题LLM 作答你批判这个回答并请 AI 改进LLM 结合批评再次作答给出改进后的方案。该过程可以无限迭代。示例提示词创建一个包含 products 和 customers 路由的 Python Web APIAI 回答import flask app Flask(__name__) app.route(/products) def products(): return Products app.route(/customers) def customers(): return Customers提示词给上面的代码提 3 条改进建议AI 回答Sure, here are three suggestions to improve the code: Import the correct module: The first line should import Flask instead of flask. The correct import statement should be from flask import Flask. Add a main function: Add a if __name__ __main__: block to the end of the file to run the application when the file is executed. Use f-strings: Use f-strings to format the return statements in the route functions. For example, return Products can be changed to return fThis is the {request.path} page.改进后的代码from flask import Flask, request app Flask(__name__) app.route(/products) def products(): return fThis is the {request.path} page app.route(/customers) def customers(): return fThis is the {request.path} page if __name__ __main__: app.run()可以看到得益于对第一版答案的批评AI 的回答确实改进了代码。苏格拉底式提示Maieutic promptingMaieutic prompting 与 self-refine 相似但更侧重于请 LLM 解释自己。目标是减少 LLM 输出中的前后矛盾确保其得出正确结论。工作流如下请 LLM 回答一个问题针对答案的每一部分请 LLM 更深入地解释如果存在矛盾丢弃不一致的部分。重复第 2、3 步直到你遍历完所有部分并满意为止。示例提示词如何分 5 步制定一个缓解大流行的危机计划 LLM 回答1. Identify the risks 1. Identify the stakeholders 1. Identify the resources 1. Identify the actions 1. Identify the communication channels识别出了 5 步但如何确定是否正确请 LLM 更详细地解释第一步提示词请更详细地解释第一步大流行中的风险具体有哪些The risks are the following: - Loss of life - Loss of business - Loss of reputation - Loss of customers - Loss of employees此时我们希望确认 LLM 是否正确于是请它更详细地解释第一个风险并期待与上面的回答一致提示词在大流行中最大的风险是什么为什么The biggest risk is loss of life because its the most important thing to protect.大流行中最大的两个风险是什么The two biggest risks are loss of life and loss of business.至此 LLM 的回答保持一致将生命和商业列为两大风险我们可以带着较高的信心进入下一步。但即便此时也不应盲目信任 LLM输出始终需要人工验证。控制输出让结果从多样化走向确定性LLM 本质上是**非确定性nondeterministic**的——同一提示词每次运行都会得到不同结果。以生成 Python Web API 的代码为例第一次运行得到# Import necessary modules import flask from flask import request, jsonify # Create a Flask app app flask.Flask(__name__) # Create a route for the API app.route(/api, methods[GET]) def api(): # Get the data from the request data request.args # Process the data result process_data(data) # Return the result as JSON return jsonify(result) # Function to process the data def process_data(data): # Do something with the data result data 1 # Return the result return result # Run the app if __name__ __main__: app.run()再次运行同一提示词得到略为不同的回答这段回答甚至生成了一个包含书籍数据与多个端点的 Books API还开启了app.config[DEBUG] True#import necessary packages import flask from flask import request, jsonify #create the Flask application app flask.Flask(__name__) app.config[DEBUG] True #create a list of books books [ {id: 0, title: A Fire Upon the Deep, author: Vernor Vinge, first_sentence: The coldsleep itself was dreamless., year_published: 1992}, {id: 1, title: The Ones Who Walk Away From Omelas, author: Ursula K. Le Guin, first_sentence: With a clamor of bells that set the swallows soaring, the Festival of Summer came to the city Omelas, bright-towered by the sea., published: 1973}, {id: 2, title: Dhalgren, author: Samuel R. Delany, first_sentence: to wound the autumnal city., published: 1975} ] #create an endpoint for the API app.route(/, methods[GET]) def home(): return h1Books API/h1 pA prototype API for retrieving books./p #create an endpoint to return all books app.route(/api/v1/resources/books/all, methods[GET]) def api_all(): return jsonify(books) #create an endpoint to return a single book app.route(/api/v1/resources/books, methods[GET]) def api_id(): #check if an ID was provided as part of the URL #if ID is provided, assign it to a variable #if no ID is provided, display an error if id in request.args: id int(request.args[id]) else: return Error: No id field provided. Please specify an id. #create an empty list for our results results [] #loop through the data and match results that fit the requested ID #IDs are unique, but other fields might return many results for book in books: if book[id] id: results.append(book) #use the jsonify function from Flask to convert our list of #Python dictionaries to the JSON format return jsonify(results) app.run()输出多样化是问题吗取决于你想做什么。如果你需要的是一个特定的、唯一的答案那么每次结果不同就是问题如果你只满足于多样化输出例如随便生成 3 道地理题那就不是问题。用 temperature 调节输出变化当我们希望输出更可预测、更确定性时该怎么办答案是调节temperature它是 0 到 1 之间的数值0 最确定1 最多样默认值为 0.7。把 temperature 设为 0.1同一提示词运行两次的结果差异极小——两段代码在函数命名、注释和process_data的实现细节上只有细微差别#import necessary libraries import flask from flask import request, jsonify #create an instance of the Flask class app flask.Flask(__name__) #create an endpoint for the API app.route(/api/v1/endpoint, methods[GET]) def api_endpoint(): #get the request data data request.get_json() #process the data result process_data(data) #return the result return jsonify(result) #function to process the data def process_data(data): #process the data result {result: success} #return the result return result #run the Flask app if __name__ __main__: app.run()第二次运行#import necessary libraries import flask from flask import request, jsonify #create a Flask app app flask.Flask(__name__) #create a route for the API app.route(/api, methods[GET]) def api_call(): #get the data from the request data request.get_json() #process the data result process_data(data) #return the result return jsonify(result) #define the process_data function def process_data(data): #do something with the data result data 1 #return the result return result #run the app if __name__ __main__: app.run()反过来把 temperature 设为 0.9两次输出的差异就极其显著一次是带request.args的简单 API另一次则直接生成了一套带书籍测试数据、多个端点和DEBUG模式的完整 Books API第二次甚至因为输出长度限制被截断# Import necessary libraries import flask from flask import request, jsonify # Create a Flask app app flask.Flask(__name__) # Create a route for the API app.route(/api, methods[GET]) def api_call(): # Get the data from the request data request.args # Process the data result process_data(data) # Return the result return jsonify(result) # Function to process the data def process_data(data): # Do something with the data result data 1 # Return the result return result # Run the app if __name__ __main__: app.run()第二次temperature 0.9import flask from flask import request, jsonify # create the Flask app app flask.Flask(__name__) app.config[DEBUG] True # create some test data books [ {id: 0, title: A Fire Upon The Deep, author: Vernor Vinge, first_sentence: The coldsleep itself was dreamless., year_published: 1992}, {id: 1, title: The Ones Who Walk Away From Omelas, author: Ursula K. Le Guin, first_sentence: With a clamor of bells that set the swallows soaring, the Festival of Summer came to the city Omelas, bright-towered by the sea., published: 1973}, {id: 2, title: Dhalgren, author: Samuel R. Delany, first_sentence: to wound the autumnal city., published: 1975} ] # create an endpoint app.route(/, methods[GET]) def home(): return h1Welcome to our book API!/h1 app.route(/api/v1/resources/books对比可见temperature 越低输出越稳定越高输出越多样。实际调用时这一参数通过各提供商的 API 请求体传入——例如本仓库各课的 Python 作业如 06 课文本生成应用中调用 OpenAI/Azure OpenAI 客户端时都会在chat.completions.create(...)里传入temperature。说明除了 temperature还有更多可调节输出多样性的参数例如top-k、top-p、repetition penalty重复惩罚、length penalty长度惩罚、diversity penalty多样性惩罚但这些超出了本课程范围。提示词的良好实践除上述技术外向 LLM 提问时还值得遵循以下良好实践你会发现随着使用增多逐渐形成自己的风格指明上下文。上下文很重要你指定的越多领域、主题等越好限制输出。如果你想要特定数量的条目或特定长度明确写出来同时说明要什么和怎么要。记得同时描述想要什么以及希望以什么方式产出例如创建一个带 products 和 customers 路由的 Python Web API并拆分成 3 个文件使用模板。当需要用公司数据丰富提示词时使用模板——模板可以包含用真实数据替换的变量拼写正确。LLM 也许能给出正确回答但拼写正确会得到更好的回答。实战作业用 self-refine 打磨你的代码本课配套作业要求读者借助 AI 助手如 GitHub Copilot 或 ChatGPT对一段简单的 Flask 代码应用 self-refine 技术。仓库给出了 Python 与 JavaScript 两个版本的作业与解决方案。Python 版作业与答案作业的起始代码在 05-advanced-prompts/python/aoai-assignment.pyfrom flask import Flask, request app Flask(__name__) app.route(/) def hello(): name request.args.get(name, World) return fHello, {name}! if __name__ __main__: app.run()对应的参考解答在 05-advanced-prompts/python/aoai-solution.py。解答文件开头即记录了 AI 提出的改进建议这正是一次 self-refine 的产物增加输入校验防止恶意输入被服务器处理可使用flask-wtf等库校验并净化用户输入使用环境变量存储敏感信息避免数据库凭据、API 密钥等硬编码在代码中降低泄露风险实现错误处理使用app.errorhandler()装饰器处理异常并返回错误响应。据此改造后的代码展示了 self-refine 的实际落地引入flask_wtf.FlaskForm与wtforms校验器DataRequired、Length(min3)、Email()通过os.environ.get(FLASK_SECRET_KEY, os.urandom(32))从环境变量加载密钥使用escape()与render_template_string防止 XSS并注册app.errorhandler(400)返回统一错误响应import os from flask import Flask, render_template_string from flask_wtf import FlaskForm from wtforms import StringField, SubmitField from wtforms.validators import DataRequired, Length, Email from markupsafe import escape app Flask(__name__) # SECURITY: Load secret key from environment variable instead of hardcoding app.config[SECRET_KEY] os.environ.get(FLASK_SECRET_KEY, os.urandom(32)) class HelloForm(FlaskForm): name StringField(Name, validators[DataRequired(), Length(min3)]) email StringField(Email, validators[DataRequired(), Email()]) submit SubmitField(Submit) # Form template with proper CSRF protection and escaping FORM_TEMPLATE !DOCTYPE html html headtitleHello Form/title/head body form methodPOST {{ form.hidden_tag() }} p{{ form.name.label }} {{ form.name(size32) }} {% for error in form.name.errors %}span stylecolor: red;[{{ error }}]/span{% endfor %}/p p{{ form.email.label }} {{ form.email(size32) }} {% for error in form.email.errors %}span stylecolor: red;[{{ error }}]/span{% endfor %}/p p{{ form.submit() }}/p /form /body /html app.route(/, methods[GET, POST]) def hello(): form HelloForm() if form.validate_on_submit(): # SECURITY: Use escape() to prevent XSS attacks safe_name escape(form.name.data) safe_email escape(form.email.data) return fHello, {safe_name} ({safe_email})! # SECURITY: Use Flasks render_template_string for proper escaping return render_template_string(FORM_TEMPLATE, formform) app.errorhandler(400) def bad_request(error): return Bad request, 400 if __name__ __main__: app.run()对照 05-advanced-prompts/python/aoai-assignment.py 与 05-advanced-prompts/python/aoai-solution.py 的差异可以直观看到原始代码 → 批评建议 → 迭代改进的完整 self-refine 链条。JavaScript 版作业与答案JavaScript 版作业起始代码在 05-advanced-prompts/javascript/assignment.js是一个最简 Express 服务const express require(express) const app express() app.get(/, (req, res) { res.send(Hello World!) }) app.listen(3000, () { console.log(Example app listening on port 3000!) })解答文件 05-advanced-prompts/javascript/solution.js 完整记录了多轮 self-refine 的对话与代码演进第一轮在 Copilot Chat 中提示找出 3 处改进并应用将 CommonJS 改为 ES 模块import express from express、移除未使用的req参数、将日志改为更描述性的Server is running on port 3000第二轮提示改进代码并使其更安全使用环境变量存储PORT、DB_USER、DB_PASS用express-validator的check(name).isLength({ min: 3 })与check(email).isEmail()做输入校验并返回 400 错误改用https.createServer加载server.key/server.cert证书启动 HTTPS并校验证书目录路径、处理证书加载失败。这充分说明self-refine 可以多轮迭代且每一轮都可以指定改进方向架构、性能、安全性等使代码质量逐轮提升。作业提示与思考尝试自行完成作业时注意以下技巧提示在提示词中请 AI 改进时最好限制改进的数量也可以指定按某个方面改进例如架构、性能、安全性等。作业完成后可进一步完成挑战题任意挑一个你自己构建的程序思考想应用哪些改进再用 self-refine 技术实施这些改动并评判结果是否更好。知识自测为什么要使用思维链chain-of-thought提示从以下选项中选出 1 个正确答案和 2 个错误答案为了教会 LLM 如何解决一个问题。B为了教会 LLM 在代码中找错误。C为了指示 LLM 提出不同的解决方案。答案1。因为思维链的本质就是通过提供一系列步骤、相似问题及其解决方式向 LLM 展示如何解决问题。延伸阅读想继续深入提示词工程可先复习 第 4 课提示词工程基础本课之后下一课将把提示词工程知识应用到实际项目中第 6 课构建文本生成应用本仓库还提供了 Azure OpenAI、OpenAI 与 GitHub Models 等多种提供商的作业与解答例如 Python 作业、JavaScript 作业可在不同平台上实际验证本文所述的温度参数与提示词技术。【免费下载链接】generative-ai-for-beginners21 Lessons, Get Started Building with Generative AI项目地址: https://gitcode.com/GitHub_Trending/ge/generative-ai-for-beginners创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表