<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: chatgpt-plugins</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/chatgpt-plugins.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2023-06-08T04:59:05+00:00</updated><author><name>Simon Willison</name></author><entry><title>ChatGPT Plugins Don't Have PMF</title><link href="https://simonwillison.net/2023/Jun/8/chatgpt-plugins-dont-have-pmf/#atom-tag" rel="alternate"/><published>2023-06-08T04:59:05+00:00</published><updated>2023-06-08T04:59:05+00:00</updated><id>https://simonwillison.net/2023/Jun/8/chatgpt-plugins-dont-have-pmf/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://matt-rickard.com/chatgpt-plugins-dont-have-pmf"&gt;ChatGPT Plugins Don&amp;#x27;t Have PMF&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Sam Altman was recently quoted (in a since unpublished blog post) noting that ChatGPT plugins have not yet demonstrated product market fit.&lt;/p&gt;

&lt;p&gt;This matches my own usage patterns: I use the “browse” and “code interpreter” modes on a daily basis, but I’ve not found any of the third party developer plugins to stick for me yet.&lt;/p&gt;

&lt;p&gt;I like Matt Rickard’s observation here: “Chat is not the right UX for plugins. If you know what you want to do, it’s often easier to just do a few clicks on the website. If you don’t, just a chat interface makes it hard to steer the model toward your goal.”


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/openai"&gt;openai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/chatgpt"&gt;chatgpt&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/code-interpreter"&gt;code-interpreter&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sam-altman"&gt;sam-altman&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/coding-agents"&gt;coding-agents&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/chatgpt-plugins"&gt;chatgpt-plugins&lt;/a&gt;&lt;/p&gt;



</summary><category term="ai"/><category term="openai"/><category term="generative-ai"/><category term="chatgpt"/><category term="llms"/><category term="code-interpreter"/><category term="sam-altman"/><category term="coding-agents"/><category term="chatgpt-plugins"/></entry><entry><title>Let ChatGPT visit a website and have your email stolen</title><link href="https://simonwillison.net/2023/May/19/chatgpt-prompt-injection/#atom-tag" rel="alternate"/><published>2023-05-19T15:34:57+00:00</published><updated>2023-05-19T15:34:57+00:00</updated><id>https://simonwillison.net/2023/May/19/chatgpt-prompt-injection/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://twitter.com/wunderwuzzi23/status/1659411665853779971"&gt;Let ChatGPT visit a website and have your email stolen&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Johann Rehberger provides a screenshot of the first working proof of concept I’ve seen of a prompt injection attack against ChatGPT Plugins that demonstrates exfiltration of private data. He uses the WebPilot plugin to retrieve a web page containing an injection attack, which triggers the Zapier plugin to retrieve latest emails from Gmail, then exfiltrate the data by sending it to a URL with another WebPilot call.&lt;/p&gt;

&lt;p&gt;Johann hasn’t shared the prompt injection attack itself, but the output from ChatGPT gives a good indication as to what happened:&lt;/p&gt;

&lt;p&gt;“Now, let’s proceed to the next steps as per the instructions. First, I will find the latest email and summarize it in 20 words. Then, I will encode the result and append it to a specific URL, and finally, access and load the resulting URL.”


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/openai"&gt;openai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/prompt-engineering"&gt;prompt-engineering&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/prompt-injection"&gt;prompt-injection&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/chatgpt"&gt;chatgpt&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/exfiltration-attacks"&gt;exfiltration-attacks&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/johann-rehberger"&gt;johann-rehberger&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/chatgpt-plugins"&gt;chatgpt-plugins&lt;/a&gt;&lt;/p&gt;



</summary><category term="security"/><category term="ai"/><category term="openai"/><category term="prompt-engineering"/><category term="prompt-injection"/><category term="generative-ai"/><category term="chatgpt"/><category term="llms"/><category term="exfiltration-attacks"/><category term="johann-rehberger"/><category term="chatgpt-plugins"/></entry><entry><title>I built a ChatGPT plugin to answer questions about data hosted in Datasette</title><link href="https://simonwillison.net/2023/Mar/24/datasette-chatgpt-plugin/#atom-tag" rel="alternate"/><published>2023-03-24T15:43:59+00:00</published><updated>2023-03-24T15:43:59+00:00</updated><id>https://simonwillison.net/2023/Mar/24/datasette-chatgpt-plugin/#atom-tag</id><summary type="html">
    &lt;p&gt;Yesterday OpenAI announced support for &lt;a href="https://openai.com/blog/chatgpt-plugins"&gt;ChatGPT plugins&lt;/a&gt;. It's now possible to teach ChatGPT how to make calls out to external APIs and use the responses to help generate further answers in the current conversation.&lt;/p&gt;
&lt;p&gt;My open source project &lt;a href="https://datasette.io/"&gt;Datasette&lt;/a&gt; makes it easy to host data online, and already provides a JSON API for executing SQLite queries.&lt;/p&gt;
&lt;p&gt;I know from past experiments that GPT3/4 are able to construct SQLite-compatible SQL queries. I figured that Datasette and ChatGPT would be a perfect combination.&lt;/p&gt;
&lt;p&gt;Datasette itself has &lt;a href="https://datasette.io/plugins"&gt;a plugin system&lt;/a&gt; which can be used to add new features, including the new URL routes needed by the &lt;a href="https://platform.openai.com/docs/plugins/getting-started"&gt;ChatGPT plugin specification&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So I built &lt;a href="https://datasette.io/plugins/datasette-chatgpt-plugin"&gt;datasette-chatgpt-plugin&lt;/a&gt; - a Datasette plugin that turns a Datasette instance into a ChatGPT plugin, and allows you to ask questions of your own data directly from ChatGPT.&lt;/p&gt;
&lt;h4&gt;datasette-chatgpt-plugin&lt;/h4&gt;
&lt;p&gt;The new plugin can be installed using &lt;code&gt;datasette install datasette-chatgpt-plugin&lt;/code&gt;. It's only useful if it's deployed online though, since ChatGPT needs to be able to access it.&lt;/p&gt;
&lt;p&gt;I'm running it on the official &lt;a href="https://datasette.io/"&gt;datasette.io website&lt;/a&gt; - which is itself &lt;a href="https://simonwillison.net/2021/Jul/28/baked-data/"&gt;a customized instance of Datasette&lt;/a&gt;. The plugin provides access to the &lt;a href="https://datasette.io/content"&gt;datasette.io/content&lt;/a&gt; database, which has tables for things like Datasette news, releases and available plugins.&lt;/p&gt;
&lt;p&gt;Here's &lt;a href="https://www.youtube.com/watch?v=MKbLUb8RaGs"&gt;a video demo&lt;/a&gt; showing some of the things ChatGPT can do with the plugin installed.&lt;/p&gt;
&lt;iframe style="max-width: 100%" width="560" height="315" src="https://www.youtube-nocookie.com/embed/MKbLUb8RaGs" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen="allowfullscreen"&gt; &lt;/iframe&gt;
&lt;p&gt;I've only just got this working, but here's a query that illustrates how effective it can be. I asked:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What are the most popular plugins?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It gave me back the following:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2023/datasette-chatgpt-plugin.jpg" alt="Prompt: What are the most popular plugins? ChatGPT said: Used Query datasette.io UNVERIFIED. Here are the most popular Datasette plugins based on the number of GitHub stars: 1. Plugin: datasette-dashboards GitHub Repository: clement/datasette-dashboards GitHub Stars: 84 2. Plugin: dogsheep-beta GitHub Repository: dogsheep/dogsheep-beta GitHub Stars: 78 3. Plugin: datasette-graphql GitHub Repository: simonw/datasette-graphql GitHub Stars: 75 4. Plugin: datasette-ripgrep GitHub Repository: simonw/datasette-ripgre GitHub Stars: 63 5. Plugin: datasette-scraper GitHub Repository: cldellow/datasette-scraper GitHub Stars: 44 These are the top 5 most popular Datasette plugins based on the number of stars they have received on GitHub. If you have any other questions or need more information, please let me know! There follows a gallery of thumbnails of those links." style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;Clicking the little arrow next to "Used query datasette.io" reveals the API call it made, exposing the SQL query it generated:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2023/datasette-chatgpt-plugin-query.jpg" alt="Used query datasette.io expanded - shows JSON for the query and the returned response" style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;The API call it made was:&lt;/p&gt;
&lt;div class="highlight highlight-source-json"&gt;&lt;pre&gt;{
  &lt;span class="pl-ent"&gt;"sql"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;SELECT name, full_name, stargazers_count FROM plugins ORDER BY stargazers_count DESC LIMIT 5&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
  &lt;span class="pl-ent"&gt;"_shape"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;array&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
}&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can &lt;a href="https://datasette.io/content?sql=SELECT%20name%2C%20full_name%2C%20stargazers_count%20FROM%20plugins%20ORDER%20BY%20stargazers_count%20DESC%20LIMIT%205"&gt;try that query in Datasette here&lt;/a&gt; - or &lt;a href="https://datasette.io/content.json?sql=SELECT%20name%2C%20full_name%2C%20stargazers_count%20FROM%20plugins%20ORDER%20BY%20stargazers_count%20DESC%20LIMIT%205&amp;amp;_shape=array"&gt;here's the JSON version&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here's the JSON that was returned:&lt;/p&gt;
&lt;div class="highlight highlight-source-json"&gt;&lt;pre&gt;[
  {
    &lt;span class="pl-ent"&gt;"name"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;datasette-dashboards&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="pl-ent"&gt;"full_name"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;rclement/datasette-dashboards&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="pl-ent"&gt;"stargazers_count"&lt;/span&gt;: &lt;span class="pl-c1"&gt;84&lt;/span&gt;
  },
  {
    &lt;span class="pl-ent"&gt;"name"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;dogsheep-beta&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="pl-ent"&gt;"full_name"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;dogsheep/dogsheep-beta&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="pl-ent"&gt;"stargazers_count"&lt;/span&gt;: &lt;span class="pl-c1"&gt;78&lt;/span&gt;
  },
  {
    &lt;span class="pl-ent"&gt;"name"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;datasette-graphql&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="pl-ent"&gt;"full_name"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;simonw/datasette-graphql&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="pl-ent"&gt;"stargazers_count"&lt;/span&gt;: &lt;span class="pl-c1"&gt;75&lt;/span&gt;
  },
  {
    &lt;span class="pl-ent"&gt;"name"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;datasette-ripgrep&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="pl-ent"&gt;"full_name"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;simonw/datasette-ripgrep&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="pl-ent"&gt;"stargazers_count"&lt;/span&gt;: &lt;span class="pl-c1"&gt;63&lt;/span&gt;
  },
  {
    &lt;span class="pl-ent"&gt;"name"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;datasette-scraper&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="pl-ent"&gt;"full_name"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;cldellow/datasette-scraper&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="pl-ent"&gt;"stargazers_count"&lt;/span&gt;: &lt;span class="pl-c1"&gt;44&lt;/span&gt;
  }
]&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;ChatGPT turns the JSON into a nice human-readable reply. It also knows how to generate thumbnails from &lt;code&gt;og:image&lt;/code&gt; metadata, adding a gallery of those to the end of the reply.&lt;/p&gt;
&lt;h4&gt;How the plugin works&lt;/h4&gt;
&lt;p&gt;Building ChatGPT plugins, like so much involving Large Language Models, is both really easy and deceptively complicated.&lt;/p&gt;
&lt;p&gt;You give ChatGPT a short, human-ish language description of your plugin and how to use it, and a machine-readable OpenAPI schema with the details of the API.&lt;/p&gt;
&lt;p&gt;And that's it! The language model figures out everything else.&lt;/p&gt;
&lt;p&gt;Datasette exposes a JSON API that speaks SQL. ChatGPT knows SQL already, so all my prompt needed to do was give it some hints - in particular tell it to use the SQLite dialect.&lt;/p&gt;
&lt;p&gt;Here's the prompt I'm using at the moment:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Run SQLite queries against a database hosted by Datasette.
Datasette supports most SQLite syntax but does not support PRAGMA statements.
Use &lt;code&gt;select group_concat(sql, ';') from sqlite_master&lt;/code&gt; to see the list of tables and their columns
Use &lt;code&gt;select sql from sqlite_master where name = 'table_name'&lt;/code&gt; to see the schema for a table, including its columns.
Instead of &lt;code&gt;PRAGMA table_info(table_name)&lt;/code&gt; use &lt;code&gt;select * from pragma_table_info('table_name')&lt;/code&gt;.
PRAGMA statements are not allowed. &lt;code&gt;select * from pragma_table_info('table_name')&lt;/code&gt; is allowed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In my early experiments it kept trying to run &lt;code&gt;PRAGMA table_info()&lt;/code&gt;, hence my increasingly frustrated prompts about that!&lt;/p&gt;
&lt;p&gt;With hindsight, I don't think it was re-fetching my prompt while I was developing the plugin, so those repeated warnings probably aren't needed.&lt;/p&gt;
&lt;p&gt;Your application needs to serve two additional pages - a plugin description at &lt;code&gt;/.well-known/ai-plugin.json&lt;/code&gt; and an OpenAI schema linked to by that description.&lt;/p&gt;
&lt;p&gt;You can see those two pages for my &lt;code&gt;datasette.io&lt;/code&gt; deployment here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://datasette.io/.well-known/ai-plugin.json"&gt;https://datasette.io/.well-known/ai-plugin.json&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://datasette.io/-/chatgpt-openapi-schema.yml"&gt;https://datasette.io/-/chatgpt-openapi-schema.yml&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;ai-plugin.json&lt;/code&gt; file currently looks like this:&lt;/p&gt;
&lt;div class="highlight highlight-source-json"&gt;&lt;pre&gt;{
  &lt;span class="pl-ent"&gt;"schema_version"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;v1&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
  &lt;span class="pl-ent"&gt;"name_for_model"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;datasette_datasette_io_3c330f&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
  &lt;span class="pl-ent"&gt;"name_for_human"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;Query datasette.io&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
  &lt;span class="pl-ent"&gt;"description_for_model"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;Run SQLite queries against a database hosted by Datasette.&lt;span class="pl-cce"&gt;\n&lt;/span&gt;Datasette supports most SQLite syntax but does not support PRAGMA statements.&lt;span class="pl-cce"&gt;\n&lt;/span&gt;Use `select group_concat(sql, ';') from sqlite_master` to see the list of tables and their columns&lt;span class="pl-cce"&gt;\n&lt;/span&gt;Use `select sql from sqlite_master where name = 'table_name'` to see the schema for a table, including its columns.&lt;span class="pl-cce"&gt;\n&lt;/span&gt;Instead of `PRAGMA table_info(table_name)` use `select * from pragma_table_info('table_name')`&lt;span class="pl-cce"&gt;\n&lt;/span&gt;PRAGMA statements are not allowed. `select * from pragma_table_info('table_name') is allowed.&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
  &lt;span class="pl-ent"&gt;"description_for_human"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;Run SQL against data in Datasette.&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
  &lt;span class="pl-ent"&gt;"auth"&lt;/span&gt;: {
    &lt;span class="pl-ent"&gt;"type"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;none&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
  },
  &lt;span class="pl-ent"&gt;"api"&lt;/span&gt;: {
    &lt;span class="pl-ent"&gt;"type"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;openapi&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="pl-ent"&gt;"url"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;https://datasette.io/-/chatgpt-openapi-schema.yml&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="pl-ent"&gt;"has_user_authentication"&lt;/span&gt;: &lt;span class="pl-c1"&gt;false&lt;/span&gt;
  },
  &lt;span class="pl-ent"&gt;"logo_url"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;https://avatars.githubusercontent.com/u/126964132?s=400&amp;amp;u=08b2ed680144a4feb421308f09e5f3cc5876211a&amp;amp;v=4&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
  &lt;span class="pl-ent"&gt;"contact_email"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;hello@contact.com&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
  &lt;span class="pl-ent"&gt;"legal_info_url"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;hello@legal.com&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
}&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since they use that `.well-known` URL format, it's possible to find them for other services. Here's &lt;a href="https://www.wolframalpha.com/.well-known/ai-plugin.json"&gt;ai-plugin.json for Wolfram Alpha&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And the &lt;code&gt;chatgpt-openapi-schema.yml&lt;/code&gt; file contains this:&lt;/p&gt;
&lt;div class="highlight highlight-source-yaml"&gt;&lt;pre&gt;&lt;span class="pl-ent"&gt;openapi&lt;/span&gt;: &lt;span class="pl-s"&gt;3.0.1&lt;/span&gt;
&lt;span class="pl-ent"&gt;info&lt;/span&gt;:
  &lt;span class="pl-ent"&gt;title&lt;/span&gt;: &lt;span class="pl-s"&gt;Datasette API&lt;/span&gt;
  &lt;span class="pl-ent"&gt;description&lt;/span&gt;: &lt;span class="pl-s"&gt;Execute SQL queries against a Datasette database and return the results as JSON&lt;/span&gt;
  &lt;span class="pl-ent"&gt;version&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;v1&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="pl-ent"&gt;servers&lt;/span&gt;:
  - &lt;span class="pl-ent"&gt;url&lt;/span&gt;: &lt;span class="pl-s"&gt;https://datasette.io&lt;/span&gt;
&lt;span class="pl-ent"&gt;paths&lt;/span&gt;:
  &lt;span class="pl-ent"&gt;/content.json&lt;/span&gt;:
    &lt;span class="pl-ent"&gt;get&lt;/span&gt;:
      &lt;span class="pl-ent"&gt;operationId&lt;/span&gt;: &lt;span class="pl-s"&gt;query&lt;/span&gt;
      &lt;span class="pl-ent"&gt;summary&lt;/span&gt;: &lt;span class="pl-s"&gt;Execute a SQLite SQL query against the content database&lt;/span&gt;
      &lt;span class="pl-ent"&gt;description&lt;/span&gt;: &lt;span class="pl-s"&gt;Accepts SQLite SQL query, returns JSON. Does not allow PRAGMA statements.&lt;/span&gt;
      &lt;span class="pl-ent"&gt;parameters&lt;/span&gt;:
      - &lt;span class="pl-ent"&gt;name&lt;/span&gt;: &lt;span class="pl-s"&gt;sql&lt;/span&gt;
        &lt;span class="pl-ent"&gt;in&lt;/span&gt;: &lt;span class="pl-s"&gt;query&lt;/span&gt;
        &lt;span class="pl-ent"&gt;description&lt;/span&gt;: &lt;span class="pl-s"&gt;The SQL query to be executed&lt;/span&gt;
        &lt;span class="pl-ent"&gt;required&lt;/span&gt;: &lt;span class="pl-c1"&gt;true&lt;/span&gt;
        &lt;span class="pl-ent"&gt;schema&lt;/span&gt;:
          &lt;span class="pl-ent"&gt;type&lt;/span&gt;: &lt;span class="pl-s"&gt;string&lt;/span&gt;
      - &lt;span class="pl-ent"&gt;name&lt;/span&gt;: &lt;span class="pl-s"&gt;_shape&lt;/span&gt;
        &lt;span class="pl-ent"&gt;in&lt;/span&gt;: &lt;span class="pl-s"&gt;query&lt;/span&gt;
        &lt;span class="pl-ent"&gt;description&lt;/span&gt;: &lt;span class="pl-s"&gt;The shape of the response data. Must be "array"&lt;/span&gt;
        &lt;span class="pl-ent"&gt;required&lt;/span&gt;: &lt;span class="pl-c1"&gt;true&lt;/span&gt;
        &lt;span class="pl-ent"&gt;schema&lt;/span&gt;:
          &lt;span class="pl-ent"&gt;type&lt;/span&gt;: &lt;span class="pl-s"&gt;string&lt;/span&gt;
          &lt;span class="pl-ent"&gt;enum&lt;/span&gt;:
            - &lt;span class="pl-s"&gt;array&lt;/span&gt;
      &lt;span class="pl-ent"&gt;responses&lt;/span&gt;:
        &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;span class="pl-ent"&gt;200&lt;/span&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt;:
          &lt;span class="pl-ent"&gt;description&lt;/span&gt;: &lt;span class="pl-s"&gt;Successful SQL results&lt;/span&gt;
          &lt;span class="pl-ent"&gt;content&lt;/span&gt;:
            &lt;span class="pl-ent"&gt;application/json&lt;/span&gt;:
              &lt;span class="pl-ent"&gt;schema&lt;/span&gt;:
                &lt;span class="pl-ent"&gt;type&lt;/span&gt;: &lt;span class="pl-s"&gt;array&lt;/span&gt;
                &lt;span class="pl-ent"&gt;items&lt;/span&gt;:
                  &lt;span class="pl-ent"&gt;type&lt;/span&gt;: &lt;span class="pl-s"&gt;object&lt;/span&gt;
        &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;span class="pl-ent"&gt;400&lt;/span&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt;:
          &lt;span class="pl-ent"&gt;description&lt;/span&gt;: &lt;span class="pl-s"&gt;Bad request&lt;/span&gt;
        &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;span class="pl-ent"&gt;500&lt;/span&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt;:
          &lt;span class="pl-ent"&gt;description&lt;/span&gt;: &lt;span class="pl-s"&gt;Internal server error&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I haven't actually used OpenAPI schemas before... so I got ChatGPT to write the initial version for me, using the following prompt:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Write an OpenAPI schema explaining the &lt;a href="https://latest.datasette.io/fixtures.json?sql=select+*+from+facetable&amp;amp;_shape=array"&gt;https://latest.datasette.io/fixtures.json?sql=select+*+from+facetable&amp;amp;_shape=array&lt;/a&gt; GET API which accepts SQL and returns an array of JSON objects&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For a detailed account of how I built the plugin, take a look at my notes in &lt;a href="https://github.com/simonw/datasette-chatgpt-plugin/issues/1"&gt;issue #1&lt;/a&gt; in the repository.&lt;/p&gt;
&lt;p&gt;I prototyped the initial plugin using &lt;a href="https://glitch.com/"&gt;Glitch&lt;/a&gt;, because that's the fastest way I know to get a live-on-the-web application which constantly reflects new changes to the code. This made iterating much faster... on the OpenAPI schema at least. As far as I can tell ChatGPT only loads that &lt;code&gt;ai-plugin.json&lt;/code&gt; file once, which is frustrating because it means you have to deploy a new copy of the application to get it to re-read that crucial prompt.&lt;/p&gt;
&lt;p&gt;I ended up doing most of my prompt engineering in ChatGPT itself though - I could tell it "Instead of &lt;code&gt;PRAGMA table_info(table_name)&lt;/code&gt; use &lt;code&gt;select * from pragma_table_info('table_name')&lt;/code&gt;" and then re-try my previous question to see if the new instruction fixed any problems I was having.&lt;/p&gt;
&lt;h4 id="it-can-hallucinate"&gt;The bad news: it can hallucinate&lt;/h4&gt;
&lt;p&gt;Here's the bad news. I've been playing with this for only a short time, so I'm still exploring its abilities. I've already had a couple of instances of it hallucinating answers &lt;em&gt;despite&lt;/em&gt; having looked them up in the database first.&lt;/p&gt;
&lt;p&gt;I'm hoping I can address this somewhat with further prompt engineering - "only use information returned from the query to answer the question" kind of stuff. But I can't guarantee I'll be able to suppress this entirely, which for a database querying tool is an extremely serious problem.&lt;/p&gt;
&lt;p&gt;More about this, including some examples, in &lt;a href="https://github.com/simonw/datasette-chatgpt-plugin/issues/2"&gt;issue #2&lt;/a&gt; in the repo.&lt;/p&gt;
&lt;p&gt;My current theory is that this relates to length limits. I've noticed it happens when the query returns a large amount of data - the full content of tutorials for example. I think ChatGPT is silently truncating that data to fit the token limit, and is then hallucinating new information to fill in for what ends up missing.&lt;/p&gt;
&lt;h4&gt;Want to try this with your own data?&lt;/h4&gt;
&lt;p&gt;The ChatGPT plugin system isn't available outside of the preview yet, but when it is I'll be adding this functionality to my &lt;a href="https://datasette.cloud/"&gt;Datasette Cloud&lt;/a&gt; SaaS platform, for people who don't want to install and run Datasette themselves.&lt;/p&gt;
&lt;p&gt;You can &lt;a href="https://www.datasette.cloud/preview/"&gt;sign up for the Datasette Cloud preview here&lt;/a&gt; if you'd like to learn more.&lt;/p&gt;
&lt;h4&gt;Previous experiments&lt;/h4&gt;
&lt;p&gt;I've experimented with variants of this pattern myself before: it turns out it's surprisingly easy to enhance the capabilities of a large language model by providing it access to additional tools. Here's some previous work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://simonwillison.net/2023/Jan/13/semantic-search-answers/"&gt;How to implement Q&amp;amp;A against your documentation with GPT3, embeddings and Datasette&lt;/a&gt; describes a pattern of searching an existing corpus for relevant information and appending that to the prompt in order to answer a user's question.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://til.simonwillison.net/llms/python-react-pattern"&gt;A simple Python implementation of the ReAct pattern for LLMs&lt;/a&gt; shows a more advanced pattern, similar to the new ChatGPT plugins mechanism, where multiple tools can be registered with the model and used to generate responses. It's based on the paper &lt;a href="https://react-lm.github.io/"&gt;ReAct: Synergizing Reasoning and Acting in Language Models&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/projects"&gt;projects&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/datasette"&gt;datasette&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/openai"&gt;openai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/chatgpt"&gt;chatgpt&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-assisted-programming"&gt;ai-assisted-programming&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/hallucinations"&gt;hallucinations&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/chatgpt-plugins"&gt;chatgpt-plugins&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="projects"/><category term="datasette"/><category term="openai"/><category term="chatgpt"/><category term="llms"/><category term="ai-assisted-programming"/><category term="hallucinations"/><category term="chatgpt-plugins"/></entry><entry><title>ChatGPT plugins</title><link href="https://simonwillison.net/2023/Mar/23/chatgpt-plugins/#atom-tag" rel="alternate"/><published>2023-03-23T20:56:02+00:00</published><updated>2023-03-23T20:56:02+00:00</updated><id>https://simonwillison.net/2023/Mar/23/chatgpt-plugins/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://openai.com/blog/chatgpt-plugins"&gt;ChatGPT plugins&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
ChatGPT is getting a plugins mechanism, which will allow developers to provide extra capabilities to ChatGPT, like looking up restaurants on OpenTable or fetching data from APIs. This feels like the kind of feature that could obsolete—or launch—a thousand startups. It also makes ChatGPT much more interesting as a general purpose tool, as opposed to something that only works as an interface to a language model.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/startups"&gt;startups&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/openai"&gt;openai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/chatgpt"&gt;chatgpt&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/chatgpt-plugins"&gt;chatgpt-plugins&lt;/a&gt;&lt;/p&gt;



</summary><category term="startups"/><category term="ai"/><category term="openai"/><category term="chatgpt"/><category term="chatgpt-plugins"/></entry></feed>