Fuck you, show me the prompt Hamel Husain, a software engineer, published a blog post arguing that developers should inspect the final prompts that LLM abstraction tools like DSPy, guidance, and instructor send to language models, and demonstrates how to intercept these API calls using mitmproxy. He warns that such frameworks can introduce accidental complexity and obscure the natural-language interaction with LLMs, and encourages users to evaluate whether the abstraction is necessary or if the prompt can be used directly. python import os The location of my CA File cert file = '/Users/hamel/Downloads/mitmproxy-ca-cert.pem' os.environ 'REQUESTS CA BUNDLE' = cert file os.environ 'SSL CERT FILE' = cert file os.environ 'HTTPS PROXY' = 'http://127.0.0.1:8080' Fuck You, Show Me The Prompt. Background There are many libraries that aim to make the output of your LLMs better by re-writing or constructing the prompt for you . These libraries purport to make the output of your LLMs: - safer ex: guardrails https://github.com/guardrails-ai/guardrails - deterministic ex: guidance https://github.com/guidance-ai/guidance - structured ex: instructor https://github.com/jxnl/instructor - resilient ex: langchain https://www.langchain.com/ - … or even optimized for an arbitrary metric ex: DSPy https://github.com/stanfordnlp/dspy . A common theme among some of these tools is they encourage users to disintermediate themselves from prompting. DSPy : “This is a new paradigm in which LMs and their prompts fade into the background …. you can compile your program again DSPy will create new effective prompts” guidance “guidance is a programming paradigm that offers superior control and efficiency compared to conventional prompting …” Even when tools don’t discourage prompting, I’ve often found it difficult to retrieve the final prompt s these tools send to the language model. The prompts sent by these tools to the LLM is a natural language description of what these tools are doing, and is the fastest way to understand how they work. Furthermore, some tools have dense terminology https://github.com/stanfordnlp/dspy?tab=readme-ov-file 4-two-powerful-concepts-signatures--teleprompters to describe internal constructs which can further obfuscate what they are doing. For reasons I’ll explain below, I think most people would benefit from the following mindset: In this blog post, I’ll show you how you can intercept API calls w/prompts for any tool, without having to fumble through docs or read source code. I’ll show you how to setup and operate mitmproxy https://mitmproxy.org/ with examples from the LLM the tools I previously mentioned. Motivation: Minimize accidental complexity Before adopting an abstraction, its important to consider the dangers of taking on accidental complexity https://dev.to/alexbunardzic/software-complexity-essential-accidental-and-incidental-3i4d . This danger is acute for LLM abstractions relative to programming abstractions. With LLM abstractions, we often force the user to regress towards writing code instead of conversing with the AI in natural language, which can run counter to the purpose of LLMs: Programming abstraction - a human-like language you can use to translate your task into machine code — Hamel Husain @HamelHusain LLM abstraction - an unintelligible framework you can use to translate your task into human language February 5, 2024 While this is a cheeky comment, it’s worth keeping this in mind while evaluating tools. There are two primary types of automation that tools provide: Interleaving code and LLMs: Expressing this automation is often best done through code, since code must be run to carry out the task. Examples include routing, executing functions, retries, chaining, etc. Re-Writing and constructing prompts : Expressing your intent is often best done through natural language. However, there are exceptions For example, it is convenient to express a function definition or schema from code instead of natural language. Many frameworks offer both types of automation. However, going too far with the second type can have negative consequences. Seeing the prompt allows you decide: - Is this framework really necessary? - Should I just steal the final prompt a string and jettison the framework? - Can we write a better prompt than this shorter, aligned with your intent, etc ? - Is this the best approach do the of API calls seem appropriate ? In my experience, seeing the prompts and API calls are essential to making informed decisions. Intercepting LLM API calls There are many possible ways to intercept LLM API calls, such as monkey patching source code or finding a user-facing option. I’ve found that those approaches take far too much time since the quality of source code and documentation can vary greatly. After all, I just want to see API calls without worrying about how the code works A framework agnostic way to see API calls is to setup a proxy that logs your outgoing API requests. This is easy to do with mitmproxy https://mitmproxy.org/ , an free, open-source HTTPS proxy. Setting Up mitmproxy This is an opinionated way to setup mitmproxy that’s beginner-friendly for our intended purposes: Follow the installation instructions on the website https://mitmproxy.org/ Start the interactive UI by running mitmweb in the terminal. Pay attention to the url of the interactive UI in the logs which will look something like this: Web server listening at http://127.0.0.1:8081/ Next, you need to configure your device i.e. your laptop to route all traffic through mitproxy , which listens on http://localhost:8080 . Per the documentation:We recommend to simply search the web on how to configure an HTTP proxy for your system. Some operating system have a global settings, some browser have their own, other applications use environment variables, etc. In my case, A google search for “set proxy for macos” https://www.google.com/search?q=set+proxy+for+macos&sca esv=c51a80de1a7d45f0&rlz=1C5CHFA enUS1048US1049&sxsrf=ACQVn0 ysjr6Kma2 lX8WbB06iPbDi5gUQ%3A1707764982232&ei=9mzKZYXoDcfy0PEPpJqb2Ao&ved=0ahUKEwiFu4CpwKaEAxVHOTQIHSTNBqsQ4dUDCBA&uact=5&oq=set+proxy+for+macos&gs lp=Egxnd3Mtd2l6LXNlcnAiE3NldCBwcm94eSBmb3IgbWFjb3MyBBAjGCcyBhAAGBYYHjIGEAAYFhgeMgYQABgWGB4yBhAAGBYYHjILEAAYgAQYigUYhgMyCxAAGIAEGIoFGIYDSMk-UMU7WMU7cAd4AZABAJgBVaABVaoBATG4AQPIAQD4AQHCAgoQABhHGNYEGLAD4gMEGAAgQYgGAZAGCA&sclient=gws-wiz-serp returned these results:choose Apple menu System Settings, click Network in the sidebar, click a network service on the right, click Details, then click Proxies. I then insert localhost and 8080 in the following places in the UI:Next, navigate to http://mitm.it http://mitm.it and it will give you instructions on how to install the mitmproxy Certificate Authority CA , which you will need for intercepting HTTPS requests. You can also do this manually here https://docs.mitmproxy.org/stable/concepts-certificates/ quick-setup . Also, take note of the location of the CA file as we will reference it later.You can test that everything works by browsing to a website like https://mitmproxy.org/ https://mitmproxy.org/ , and seeing the corresponding output in the mtimweb UI which for me is located at http://127.0.0.1:8081/ http://127.0.0.1:8081/ look at the logs in your terminal to get the URL .Now that you set everything up, you can disable the proxy that you previously enabled on your network. I do this on my mac by toggling the proxy buttons in the screenshot I showed above. This is because we want to scope the proxy to only the python program to eliminate unnecessary noise. Networking related software commonly allows you to proxy outgoing requests by setting environment variables. This is the approach we will use to scope our proxy to specific Python programs. However, I encourage you to play with other types of programs to see what you find after you are comfortable Environment variables for Python We need to set the following environment variables so that the requests and httpx libraries will direct traffic to the proxy and reference the CA file for HTTPS traffic: Make sure you set these environment variables before running any of the code snippets in this blog post. You can do a minimal test by running the following code: python import requests requests.post 'https://httpbin.org/post', data={'key': 'value'}