在我最近对生成人工智能的几乎所有探索中,我逐渐意识到提示是多么重要。这并不一定能让我一直写出更好的提示,但意识到问题至少是纠正问题的第一步,对吗?我认为对我个人有帮助的一件事是拥有一个工具来快速比较和对比不同的提示。
显然,我可以在浏览器中打开多个选项卡,但我真的想要一些更直接和简化的东西来实现我的目的。考虑到这一点,让我分享一下我所构建的内容。
Prompt Tester 是我的一个非常富有想象力的命名工具,用于……嗯……测试提示。它以一个提示开始:
这个想法是,您输入初始提示,然后单击一次或多次以添加更多提示。准备好后,您只需单击“生成结果”即可:
在展示一些示例结果之前,让我先谈谈它是如何构建的。
后端是一个极其简单的 Node.js 服务器,负责处理静态 HTML 并响应前端 API 请求。我再次感谢 Todd Sharp 与我分享他的初始代码。这是无聊的简单处理部分:
async function handler(req, res) { console.log('Entered handler.', req.method, req.url); if(req.method === 'GET' && req.url.indexOf('favicon.ico') === -1) { res.writeHead(200, { 'Content-Type':'text/html' }); res.write(fs.readFileSync('./demo.html')); res.end(); } else if(req.method === 'POST' && req.url === '/api') { let body = ''; req.on('data', chunk => { body += chunk.toString(); }); req.on('end', async () => { body = JSON.parse(body); console.log('BODY:\n', JSON.stringify(body, null, '\t')); let result = await callGemini(body.prompt); res.writeHead(200, { 'Content-Type':'application/json' }); res.write(JSON.stringify(result)); res.end(); }); } } const server = http.createServer(handler); server.listen(3000); console.log('Listening on port 3000');
callGemini
部分只是将提示传递给 Google 的Gemini API 。理论上,这可以更改为 ChatGPT 或任何其他服务。
const MODEL_NAME = "gemini-pro"; const API_KEY = process.env.GOOGLE_AI_KEY; const genAI = new GoogleGenerativeAI(API_KEY); const model = genAI.getGenerativeModel({ model: MODEL_NAME }); async function callGemini(text) { const generationConfig = { temperature: 0.9, topK: 1, topP: 1, maxOutputTokens: 2048, }; const safetySettings = [ { category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, }, { category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, }, { category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, }, { category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, }, ]; const parts = [ {text}, ]; const result = await model.generateContent({ contents: [{ role: "user", parts }], generationConfig, safetySettings, }); try { if(result.response.promptFeedback && result.response.promptFeedback.blockReason) { return { error: `Blocked for ${result.response.promptFeedback.blockReason}` }; } const response = result.response.candidates[0].content.parts[0].text; return { response }; } catch(e) { // better handling return { error:e.message } } }
我很自豪地说,我现在终于在做一些基本的错误处理,并试图向用户(我)揭示提示被阻止的原因。
前端比较简单。我使用Milligram作为核心 CSS(再次感谢 Todd)和一些普通 JavaScript 来处理添加新提示和拨打电话。这是 HTML(减去内联 CSS):
<h1>Prompt Tester</h1> <p> This tool helps you see the result of multiple prompts at the same time. The idea is to use similar prompts with different phrasing to see how it impacts the result. </p> <div id="prompts"> </div> <template id="promptRow"> <div class="row"> <div class="column column-33"><textarea placeholder="Enter your prompt."></textarea></div> <div class="column column-67 result"></div> </div> <hr> </template> <div class="float-right"> <button id="addPrompt">Add Prompt</button> <button id="generateResults">Generate Results</button> </div>
然后是 JavaScript。请注意,我使用上面的<template>
来处理提示布局。这是我第一次使用该标签,而且相对容易。
let $template, $prompts, $addPromptsBtn, $generateResultsBtn; let promptCount = 0; document.addEventListener('DOMContentLoaded', init, false); async function init() { $addPromptsBtn = document.querySelector('#addPrompt'); $addPromptsBtn.addEventListener('click', addPrompt, false); $generateResultsBtn = document.querySelector('#generateResults') $generateResultsBtn.addEventListener('click', generateResults, false); $template = document.querySelector('#promptRow'); $prompts = document.querySelector('#prompts'); addPrompt(); } function addPrompt() { promptCount++; const newPrompt = $template.content.cloneNode(true); $prompts.append(newPrompt); } async function generateResults() { // disable add prompt and generate $addPromptsBtn.setAttribute('disabled', 'disabled'); $generateResultsBtn.setAttribute('disabled', 'disabled'); let $results = document.querySelectorAll('div.result'); // clear any previous results $results.forEach(r => r.innerHTML = ''); /* gather prompts from the inputs */ let prompts = []; let $fields = document.querySelectorAll('#prompts textarea'); for(f of $fields) prompts.push(f.value); let promises = []; for(p of prompts) promises.push(getResult(p)); let results = await Promise.all(promises); // assign results to result area for each, handle errors - later // there's a one to one correspondance between our array of results and the result div for(let i=0;i<results.length;i++) { if(results[i].response) $results[i].innerHTML = marked.parse(results[i].response); else if(results[i].error) $results[i].innerHTML = `<strong>Error with Prompt: </strong> ${results[i].error}`; } $addPromptsBtn.removeAttribute('disabled'); $generateResultsBtn.removeAttribute('disabled'); } async function getResult(p) { console.log('get result for',p); // quick return on empty prompt if(p.trim() === '') return { response:'<strong>Enter a prompt.</strong>' }; let req = await fetch('/api', { method:'POST', body: JSON.stringify({prompt:p.trim()})}); let result = await req.json(); return result; }
我认为这都是非常简单的 DOM 操作和 API 调用,但如果有什么不明白的地方,请在下面的评论中告诉我。请注意,我立即触发了所有 API 调用,并且Promise.all
等待它们完成。
另外,请注意我使用marked
库。 Google 的结果通常带有 Markdown,这有助于在我的小型网络应用程序中很好地呈现它们。
我认为所有这些都不是很有趣,但让我们看一些测试。正如我所说,我知道提示的风格很重要。将其通过工具直接呈现给我,对强化这一点大有帮助。
让我们从一个简单的想法开始 - 解释不同年龄段的重力。由于结果很大,我将在这里使用一些 CSS 来帮助保持理智。
提示:向我解释重力,但使其适合一年级的孩子
重力是我们星球拥有的超能力!它就像一种无形的力量,让地球上的一切都停留在地面上。
想象一下你手里有一个球。当你放下它时,会发生什么?它掉下来了,对吗?那是因为重力。重力将球拉向地球中心,因此它落到地面上。
重力也使我们保持在地面上。它让我们的脚牢牢地扎在地球上,防止我们飘走!
重力是一种非常重要的力。它使一切保持在适当的位置,并帮助事物按其应有的方式工作。如果没有重力,我们都会在太空中漂浮,事情会变得非常混乱!
这是一种思考重力的有趣方式:想象地球是一个巨大的磁铁,地球上的一切都是由金属制成的。磁铁将金属物体拉向它,这就是将它们保持在地面上的原因。
重力是一种非常重要且有趣的力。这是使我们的星球成为如此独特且特别的居住地的原因之一!
提示:向我解释重力,但使其适合七年级的孩子
想象一下你正在玩一个球。你把它抛到空中,它就会落回你身上。这是因为重力。重力是一种将物体相互拉近的力量。它让你站在地面上,也让东西掉下来。
两个物体之间的重力大小取决于它们的质量。物体的质量越大,其引力就越强。这就是为什么行星和恒星等物体比人和汽车等物体具有更大的引力。
重力也是使行星绕太阳运行的原因。太阳的引力比地球的引力大得多,所以它把地球拉向它。这使得地球围绕太阳做圆周运动。
引力是我们宇宙中非常重要的力。它使事物保持原位并使事物移动。如果没有重力,行星就会飞向太空,而我们都会飘走。
以下是一些关于重力的有趣事实:
请注意下面提示中的拼写错误。双子座处理得很好。
提示:向我解释重力,但使其适合大学生
重力:吸引力
引力是宇宙中的一种基本力,负责保持行星、卫星和恒星等天体的运动。它还使我们牢牢地固定在地面上,并允许物体在掉落时掉落。
牛顿万有引力定律:
万有引力定律指出,宇宙中的每个物体都以与其质量的乘积成正比且与它们之间距离的平方成反比的力吸引其他所有物体。在数学上,它可以表示为:
F = Gm1m2/r^2
在哪里:
F是两个物体之间的引力。 G 是引力常数 (6.674 × 10^-11 N m^2/kg^2)。 m1 和 m2 是两个物体的质量。 r是两个物体中心之间的距离。
重力的意义:
使天体保持在轨道上:较大天体的引力使较小天体围绕它们旋转。例如,地球的引力使月球保持在轨道上,而太阳的引力使地球和其他行星保持在各自的轨道上。
潮汐的原因:地球和月球之间的重力导致海洋潮汐。当月球绕地球运行时,它的引力使面向月球的一侧的海水产生隆起。由于惯性力,在地球的另一侧形成了另一个凸起。随着地球自转,这些凸起在地球表面移动,导致高潮和低潮。
将物体保持在地球上:重力将物体拉向地球中心,防止它们飘走。这种现象使我们能够行走、站立并与环境互动。
恒星和星系的形成:引力在恒星和星系的形成中起着至关重要的作用。大量气体和尘埃云的引力坍缩导致了新恒星的产生。同样,星系的引力将它们束缚在一起,防止它们分散。
相对论:阿尔伯特·爱因斯坦的广义相对论提供了对引力更全面的理解。它解释说,引力不是一种力,而是由质量或能量的存在引起的时空弯曲。这种曲率会影响物体的运动,使它们遵循弯曲的路径而不是直线。
总之,引力是维持天体运动、潮汐和地球上物体行为的基本力。这是一个复杂的现象,几个世纪以来一直被广泛研究,至今仍然让科学家和研究人员着迷。
对于我的第二次测试,我从一个基本提示开始,然后是一个更好的版本,要求提供特定类型的详细信息:(快速编者注 - 下面的表格数据有点混乱,但在原始输出中并不混乱。)
提示:为什么猫比狗好很多?
猫和狗都是受欢迎的宠物,关于哪一种更好的问题没有明确的答案。猫和狗都有自己独特的优点和缺点,最适合您的宠物将取决于您的个人需求和喜好。
有些人更喜欢猫,因为它们通常比狗更独立。猫通常很乐意自娱自乐,不需要散步或带它们出去锻炼。对于住在公寓或日程繁忙的人来说,这可能是一个很大的优势。
猫也以干净整洁而闻名。他们定期梳理自己,并且通常使用垃圾箱没有任何问题。对于那些不想处理狗的脏乱和气味的人来说,这可能是一个很大的优势。
当然,养猫也有一些缺点。猫可能比狗更贵,而且训练起来也更困难。猫也更有可能抓伤家具和其他家居用品。
最终,养猫还是狗是个人的决定。没有正确或错误的答案,最适合您的宠物将取决于您的个人需求和喜好。
下表总结了猫和狗之间的主要区别:
特征 | 猫 | 狗 |
---|---|---|
独立 | 更独立 | 不太独立 |
运动需求 | 不需要步行或带到外面 | 需要步行或带到外面 |
清洁度 | 定期自我清洁 | 需要经常洗澡 |
训练 | 可能很难训练 | 更容易训练 |
抓挠 | 可能会划伤家具和其他家居用品 | 通常不会划伤家具 |
成本 | 更贵 | 不会那么贵 |
提示:为什么猫比狗好很多?用涵盖情绪健康和财务方面的项目符号列表进行解释
情感福祉:
财务方面:
以下测试来自 AWS re:Invent的精彩演示: AWS re:Invent 2023 - 针对 Amazon Bedrock 上的 LLM 的提示工程最佳实践 (AIM377) 。我从本次会议中发现了很多很好的建议,包括对思维链提示的良好概述,其中的想法是您提供有关解决问题的步骤的信息,以帮助 GenAI 引擎更好地解决提示。
现在,该演示文稿中给出的示例如下所示:
Q: Roger has 5 tennis balls. he buys 2 more cans of tennis balls. Each can has 3 tennis balls. How many tennis balls does he have now? A: The answer is 11. Q. The cafeteria had 23 apples. If they used 20 to make lunch and bought 6 more, how many apples do they have?
在演示中,使用的模型错误地返回了 27。在我的测试中,它工作正常,但当我去年 11 月构建生成式 AI 二十一点建议演示时,我绝对看到了数学问题。
正如我所说,Gemini 处理得很好: A: The answer is 9.
但是在 Prompt Tester 中,我尝试了建议的 CoT 提示:
Q: Roger has 5 tennis balls. he buys 2 more cans of tennis balls. Each can has 3 tennis balls. How many tennis balls does he have now? A: Roger started with 5 balls. 2 cans of 3 tennis balls each is 6 tennis balls. 5 + 6 = 11. The answer is 11. Q. The cafeteria had 23 apples. If they used 20 to make lunch and bought 6 more, how many apples do they have?
结果得到了改进,显示了它是如何得到答案的:
A: The cafeteria had 23 apples. They used 20 apples for lunch, which means they have 3 apples left. They then bought 6 more apples, so they now have a total of 3 + 6 = 9 apples. The answer is 9.
差异非常显着。
如果这对您来说很有用,请随时从这里获取代码:https: //github.com/cfjedimaster/ai-testingzone/tree/main/prompt_tester 。正如我所提到的,添加callChatGPT
或其他类似服务并使用不同的服务应该不会那么困难。如果你这样做,请告诉我!