TensorZero 逆向解析 Cursor 的 LLM 客户端
Reverse Engineering Cursor's LLM Client · TensorZero
TensorZero 团队把自研开源框架作为自托管代理接入 Cursor,成功观测并改写 Cursor 发往 LLM 的 API 调用。他们发现 Cursor 会先请求自家服务器再发起 LLM 调用,因此本地网关无法直连,最终用 Ngrok 加 Nginx 反向代理并处理 CORS 才打通链路。作者看到 Cursor 用于问答的系统提示词仅 642 token,并已用 Claude 4.0 Sonnet、GPT-4.1、o4 Mini 和 Gemini 2.5 Pro 做等比例随机分流测试。
推荐理由
AI 评分 54
作者用自建代理完整还原了 Cursor 的 LLM 调用链路,读者可据此复现观测与模型 A/B 实验。
主题
正文
当前显示原文,中文全文译文尚未就绪。
What happens under the hood at Cursor?
We wired 11.5KTensorZero between Cursor and the LLMs to see every token fly by… and bend those API calls to our own will.
TensorZero is an open-source framework that helps engineers optimize LLM applications with downstream feedback signals (e.g. production metrics, human feedback, user behavior), and we figured it would be interesting to see whether we could use TensorZero on the LLM application we use most heavily ourselves: Cursor.
With our gateway between Cursor and the LLM providers, we can observe the LLM calls being made, run evaluations on individual inferences, use inference-time optimizations, and even experiment with and optimize the prompts and models that Cursor uses.
Cursor is optimized for its population of users as a whole — beyond .cursorrules, is there room for improvement by diving deeper and tailoring it to individual users?
What would it look like to be able to empirically experiment with and optimize Cursor for your individual usage patterns?
Beyond optimization, Cursor still operates as a black box. Wouldn’t it be interesting to see what’s actually being sent to the models?
Nearly all LLM optimization, evaluation, and experimentation techniques require data on what inferences were made and their real-world consequences. In this post, we’ll focus on the former and dive into how we set up TensorZero as a self-hosted proxy between Cursor and the LLMs that it calls. If you’d like to try it yourself, check out the example in our repository. We’ll follow up with a blog post on how we collect feedback and close the optimization loop.
Wiring Things Together
The first thing we noticed was that Cursor lets you override the OpenAI base URL and model names. Perfect. TensorZero exposes an OpenAI-compatible inference endpoint, so we can easily configure Cursor to call TensorZero instead of OpenAI.
In the TensorZero configuration, we define a TensorZero function cursorzero so that we can automatically experiment with different models and prompts while storing provider-agnostic inference and feedback data in our database for observability and optimization.
Cursor was initially unable to connect to TensorZero running locally. It turns out that Cursor first sends a request to its own servers, where additional processing happens before making the LLM call, so it couldn’t connect to our gateway on localhost. (This also means that your credentials must be forwarded to Cursor’s servers, allowing them to collect data on your inferences and codebase.)
As a test that our plan could work in the first place, we pointed Cursor to OpenRouter and realized we could use its models for the Ask, Agent, and Cmd+K interactions in Cursor. We were also still able to use the normal Cursor Tab completions, which rely on a proprietary model Cursor serves for inline completions (it is very good, so we’re glad to be able to keep it).
The solution was to set up a reverse proxy to expose a public endpoint that would forward requests back to our machine. We used Ngrok to keep things simple. Since we were exposing a gateway with LLM credentials to the public Internet, we added Nginx in front of our gateway to authenticate requests. We set Cursor’s base URL to our Ngrok endpoint, added the credentials we set up in Nginx, turned off built-in models, and finally added our new TensorZero function under the model name tensorzero::function_name::cursorzero.
In the end, the workflow looked like this: Cursor → Ngrok → Nginx (self-hosted) → TensorZero (self-hosted) → LLM providers
But it didn’t work.
The Second Roadblock: CORS
The authentication process had failed.
Nginx logs showed that there was an OPTIONS request hitting our endpoint, so we configured Nginx to return headers on OPTIONS requests and incrementally added headers we saw in responses from the OpenAI API. This is the initial verification request that comes from the local Cursor IDE. The CORS requirement likely comes from Electron.
After the initial verification, all requests come from Cursor’s servers.
You can find the entire codebase for “CursorZero” on GitHub.
It finally worked!
Finally: Observability for Cursor
We could finally see everything coming in and out of Cursor — including its prompts.
For example, here’s what we saw after asking Cursor “how do I get nginx to get the key from an environment variable in my .env?”
This example paints a picture of what prompt engineering looks like for a state-of-the-art AI coding assistant.
This prompt and others like it (there were different prompts used for asking questions, editing source code, and working in the shell) are all Cursor uses to answer questions and generate code. We find it remarkable that there isn’t more here and that all of software engineering has been internalized enough by the current generation of LLMs that you can get the brains behind Cursor with a 642-token system prompt. This must be due to extensive post-training efforts by the big labs.
An Explicit AI Hierarchy?
We find the following snippet particularly intriguing:
It’s common to mix different models to optimize cost and latency, but Cursor explains this hierarchy to the models themselves? Interesting.
A/B Testing Models
With TensorZero in place, we have the full Cursor experience with control over observability and experimentation of our LLM requests. We’ve been running CursorZero for days of heavy software engineering: it’s been stable and there has been no noticeable additional latency.
We’re currently running an even random split of Claude 4.0 Sonnet, GPT-4.1, o4 Mini, and Gemini 2.5 Pro — and it feels as good as Cursor ever has.
Try It Yourself
Interested in analyzing your own usage of AI coding assistants? You can find instructions on GitHub to reproduce this work with Cursor and OpenAI Codex.
TensorZero helps you understand — and optimize — your LLM agents, even if you didn’t build them yourself!
But Wait… There’s More!
This blog post demonstrates how we successfully reverse-engineered Cursor’s LLM client by setting up TensorZero as a self-hosted proxy service, enabling us to observe, analyze, and experiment with different LLM models while maintaining the full Cursor experience.
In our next post of this series, we’ll explain how we’re evaluating real-world usage of AI coding assistants, along with the results of our internal A/B testing between models. Sneak peek: git hooks, tree-sitter, and more.
Then, we’ll explore if this feedback signal might be able to improve Cursor by optimizing models and inferences through your individual usage patterns.
Stay tuned by subscribing below.