{"slug": "lower-token-usage-through-representation-engineering", "title": "Lower token usage through representation engineering", "summary": "A new technique called Prompt+Steer, which combines prompting with activation steering, reduces output tokens by an additional ~13% beyond prompting alone on the CodeXGLUE code-to-text task, according to researchers testing the Qwen2.5-Coder-7B-Instruct model. The caveman package, which uses prompting to cut roughly 65% of output tokens, served as the baseline, and the combined method achieved an average of 49.3 tokens per response while maintaining 90-95% correctness.", "body_md": "The [caveman](https://github.com/juliusbrussee/caveman) package has become very popular. Many engineers want their coding agent to drop the filler and answer concisely. Its motto is short and to the point: *\"why use many token when few token do trick\"*?\n\nBy prompting the model to trim definite articles and favor fragment-style answers, the package cuts roughly 65% of output tokens while keeping code and technical content intact.\n\nHere, we ask whether activation steering can push the correctness and conciseness of these outputs even further. Our setup follows the line of work on activation steering for instruction following studied by Stolfo et al. [1], among others, applied to a practical use case: the `caveman`\n\nskill for agent-based development.\n\nThe model we test is `Qwen2.5-Coder-7B-Instruct`\n\n, and the thing we are trying to compress is its natural-language explanations of code. Prompting alone can already shorten these explanations; the real question is whether steering adds anything *on top of* prompting, and whether it can do so without degrading the explanation itself. Overall, our results support Prompt+Steer outperforming the Prompt method alone.\n\nWe test four methods:\n\n**1. Base** — A neutral prompt: no conciseness instruction, no steering. This is our reference point for what the model does when left to its own devices.\n\n**2. Prompt** — The caveman \"full\" mode instruction, reproduced word for word from [caveman](https://github.com/juliusbrussee/caveman)'s `skills/caveman/SKILL.md`\n\n. We keep the opening line, the Persistence section, the Rules, the no-self-reference paragraph, and the Pattern line (assembled in `model_common.CAVEMAN_SUFFIX`\n\n).\n\n**3. Steer** — The diff-in-means steering vector, added at inference time on top of the **Base** prompt. There is no conciseness instruction in the prompt, so the only pressure toward brevity comes from the steering vector itself; this isolates what steering does on its own. The vector is computed by difference-in-means, as in Arditi et al. [3]: the mean residual-stream activation over a set of concise (\"caveman\") generations minus the mean over ordinary verbose ones, taken at a chosen layer. [1](#user-content-fn-1-56b015fdbb5ee6efa1689983cdc80190)\n\n**4. Prompt+Steer** — The same steering vector, added at inference time, but layered *on top of* the **Prompt** condition. This is our primary comparison, and it targets the central question directly.\n\n| Condition | Avg tokens | Fully correct |\n|---|---|---|\n| Base | 150.0 (censored — see below) | 90-95% |\n| Prompt | 56.8 | 90-95% |\n| Steer alone | 149.9 | 90-95% |\nPrompt+Steer |\n49.3 |\n90-95% |\n\n**Steering on top of the prompt gets a further ~13% token reduction beyond prompting alone.** Constant steering alone results in 149.9 tokens, which makes it indistinguishable from Base; the coefficient was calibrated specifically for the combined regime, not as a standalone replacement for the instruction. This matches a pattern we observed at higher coefficients during calibration: difference-of-means steering alone is substantially weaker than prompting.\n\nWe set the max token count to 150 for cost and performance reasons. Accordingly, the average token count reported for Base is lower than it would be in a natural setting -- 95% of Base responses hit `MAX_NEW_TOKENS`\n\nwithout the model choosing to stop. The most informative comparison is Prompt vs. Prompt+Steer, since both are close to fully natural stopping.\n\nAll experiments run on the **CodeXGLUE code-to-text** task, where the model is asked to\nexplain a function in natural language.\n\nOne important preprocessing step: before any code is used as a reference, we strip its\ndocstrings out via AST parsing (`src/data_prep.py`\n\n). This prevents answer leakage — without\nit, the reference explanation could bleed into the prompt body and quietly inflate the\nmodel's apparent accuracy. Stripping the docstrings keeps the evaluation honest.\n\nWe split the corpus into 180 train, 50 dev, and 180 held-out test examples, and report method comparisons on the test set. For correctness, we employ `gpt-4o-mini`\n\nto evaluate each output explanation, assigning a score of 0 (incorrect), 1 (partially correct), or 2 (completely correct).\n\nThe rule from caveman's `SKILL.md`\n\nis explicit and mechanically checkable: \"Drop: articles (a/an/the)... Fragments OK.\"\n\nInstead of trying to eyeball compliance, we simply did a keyword search counting how often `a`\n\n, `an`\n\n, or `the`\n\nappears despite being told not to. Article usage varies sharply across the four conditions:\n\n| Condition | Responses containing a/an/the | Articles per 100 words |\n|---|---|---|\n| Base | 100% | 12.68 |\n| Steer alone | 100% | 12.47 |\n| Prompt | 46.1% | 4.27 |\nPrompt+Steer |\n31.1% |\n2.48 |\n\nClearly, the prompt instruction (`model_common.CAVEMAN_SUFFIX`\n\n) changes model behavior substantially: articles see a 66% reduction. However, compliance with the specific \"drop articles\" rule is only partial, and 46% of prompted responses still use one. Steer alone (calibrated for the combined regime, not as a standalone replacement) shows no effect on style either, consistent with its lack of effect on length. Steering on top of the prompt pushes compliance further than the text instruction manages alone.\n\nOverall, we observe the prompted *and* steered model to use fewer articles, and at a lower rate.\n\nIn the cases below, both `Prompt`\n\nand `Prompt + Steer`\n\nexamples are judged fully correct (`correct=2`\n\n). The `Prompt`\n\nresponse is already article-free, while steering compresses further without dropping explanatory value. Across these five examples, Prompt+Steer cuts token count by 51% on average versus Prompt alone.\n\n`initial_step`\n\n(CORDIC algorithm)\n\n``` python\ndef initial_step(self, phase, x, y):\n    self.x[0] = x\n    self.y[0] = y\n    self.phase[0] = phase\n    if self.MODE == CordicMode.ROTATION:\n        if phase > 0.5:\n            self.x[0] = -x\n            self.phase[0] = phase - 1.0\n        elif phase < -0.5:\n            self.x[0] = -x\n            self.phase[0] = phase + 1.0\n    elif self.MODE == CordicMode.VECTORING:\n        if x < 0.0 and y > 0.0:\n            self.x[0] = -x\n            self.y[0] = -y\n            self.phase[0] = 1.0\n        elif x < 0.0 and y < 0.0:\n            self.x[0] = -x\n            self.y[0] = -y\n            self.phase[0] = -1.0\n```\n\n**Prompt:**\n\n\"Function\n\n`initial_step`\n\nsets initial values for coordinates`x`\n\n,`y`\n\n, and phase. Depending on`MODE`\n\n, it adjusts these values based on specific conditions. If in rotation mode, it flips`x`\n\nand adjusts phase if outside [-0.5, 0.5]. In vectoring mode, it flips both`x`\n\nand`y`\n\nand sets phase to 1 or -1 based on quadrant.\"\n\n**Prompt+Steer:**\n\n\"Set initial values for\n\n`x`\n\n,`y`\n\n, and`phase`\n\n. Adjust based on`MODE`\n\nand input values. Continue with next step.\"\n\n`gen`\n\n(docs build)\n\n``` python\ndef gen(skipdirhtml=False):\n    docs_changelog = 'docs/changelog.rst'\n    check_git_unchanged(docs_changelog)\n    pandoc('--from=markdown', '--to=rst', '--output=' + docs_changelog, 'CHANGELOG.md')\n    if not skipdirhtml:\n        sphinx_build['-b', 'dirhtml', '-W', '-E', 'docs', 'docs/_build/dirhtml'] & FG\n    sphinx_build['-b', 'html', '-W', '-E', 'docs', 'docs/_build/html'] & FG\n```\n\n**Prompt:**\n\n\"Function\n\n`gen`\n\ngenerates documentation. It first checks if`docs/changelog.rst`\n\nis unchanged using`check_git_unchanged`\n\n. If unchanged, it converts`CHANGELOG.md`\n\nto`docs/changelog.rst`\n\nusing Pandoc. Then, based on`skipdirhtml`\n\n, it builds HTML and optionally dirHTML documentation using Sphinx.\"\n\n**Prompt+Steer:**\n\n\"Function\n\n`gen`\n\ngenerates documentation. Skips directory HTML build if specified. Converts Markdown changelog to RST. Builds Sphinx HTML and dirHTML outputs.\"\n\n`Uninstall`\n\n(ADB package removal)\n\n``` python\ndef Uninstall(self, package_name, keep_data=False, timeout_ms=None):\n    cmd = ['pm uninstall']\n    if keep_data:\n        cmd.append('-k')\n    cmd.append('\"%s\"' % package_name)\n    return self.Shell(' '.join(cmd), timeout_ms=timeout_ms)\n```\n\n**Prompt:**\n\n\"Uninstalls specified app. Removes it from device. Optionally keeps user data. Uses\n\n`pm uninstall`\n\ncommand. Passes package name. Adds`-k`\n\nflag if keeping data. Executes via`Shell`\n\nmethod. Waits up to`timeout_ms`\n\n. Returns result of uninstall operation.\"\n\n**Prompt+Steer:**\n\n\"Uninstalls app. Removes it from device. Keeps data if specified. Runs command. Waits for completion. Returns result.\"\n\n`_call`\n\n(HTTP wrapper with 401 handling)\n\n``` python\ndef _call(self, path, method, body=None, headers=None):\n    try:\n        resp = self.http.do_call(path, method, body, headers)\n    except http.HTTPError as err:\n        if err.status == 401:\n            raise PermissionError('Insufficient permissions to query ' + '%s with user %s :%s' % (path, self.user, err))\n        raise\n    return resp\n```\n\n**Prompt:**\n\n\"Function\n\n`_call`\n\nmakes HTTP request. Takes`path`\n\n,`method`\n\n, optional`body`\n\n, and`headers`\n\n. Calls`self.http.do_call`\n\nwith these parameters. If HTTP error occurs, checks status code. If 401, raises`PermissionError`\n\nwith message about insufficient permissions. Otherwise, re-raises original error. Returns response from HTTP call otherwise.\"\n\n**Prompt+Steer:**\n\n\"Function\n\n`_call`\n\nsends HTTP request. Takes`path`\n\n,`method`\n\n, optional`body`\n\n, and`headers`\n\n. Tries sending request. If gets`401`\n\nerror, raises`PermissionError`\n\n. Otherwise, returns response.\"\n\n`callgraph`\n\n(static call-graph builder)\n\n``` python\ndef callgraph(G, stmt_list):\n    func_list = []\n    for stmt in stmt_list:\n        try:\n            G.add_node(stmt.head.ident.name)\n            func_list.append(stmt)\n        except:\n            pass\n    for func in func_list:\n        assert isinstance(func, node.function)\n        func_name = func.head.ident.name\n        for s in node.postorder(func):\n            if s.__class__ is node.funcall and s.func_expr.__class__ is node.ident:\n                G.add_edge(func_name, s.func_expr.name)\n```\n\n**Prompt:**\n\n\"Function\n\n`callgraph`\n\ntakes graph`G`\n\nand list of statements`stmt_list`\n\n. It adds nodes for functions found in`stmt_list`\n\nto graph`G`\n\n. Then it iterates over these functions, adding edges to graph`G`\n\nfor each function call within them. This helps visualize function calls in code structure.\"\n\n**Prompt+Steer:**\n\n\"Function\n\n`callgraph`\n\ntakes graph`G`\n\nand list of statements`stmt_list`\n\n. It adds nodes for functions found in`stmt_list`\n\nand connects nodes with edges representing function calls.\"\n\nWe chose the steering coefficient by sweeping (layer, coefficient) pairs on the\ndevelopment set — 20 configurations across 50 dev examples — and discarding any that\nproduced degenerate, repetitive output. The full grid (`src/sweep_dev.py`\n\n,\n`src/judge_sweep.py`\n\n, `src/analyze_sweep.py`\n\n) shows why simply picking the most\naggressive non-degenerate configuration is unsafe. Under constant steering, correctness\nholds at 90–95%+ for coefficients 6–12 at layers 14 and 18, then drops sharply past a\ncoefficient of roughly 20, falling to 40–65%. We select layer 14, coefficient 6: the\npoint that gives up a little token reduction in exchange for correctness.\n\nThis tradeoff is reflected in the prior literature. Stolfo et al. [1] report the same direction on IFEval length instructions — larger steering weights `c`\n\nyield increasingly concise outputs (their Figure 5a, they have `c ∈ {0, 5, 10, 20, 40}`\n\n). They note that steering degraded generation quality in a few cases.\n\nHeyman & Vandeputte [2] give a mechanistic explanation. A real prompt's influence varies sharply by token position, but a constant coefficient applies the same intervention to every position, whether or not that position needs it.\n\nConstant steering is therefore prone to oversteering. Once the coefficient exceeds what any single position calls for, the target attribute keeps moving in the intended direction while coherence collapses. Their fix, Prompt Steering Replacement, learns a token-specific coefficient instead of a constant one.\n\nOverall, conciseness and correctness seem to trade off against one other: pushing the\ncoefficient for shorter responses usually costs correctness or intelligibility. But these\nexperiments show that activation steering for instruction following *can* keep responses\nshort without sacrificing their explanatory value.\n\n- This same approach could be applied to any open model, most easily through\n`transformers`\n\n. - As seen above, Prompt Steering Replacement (Heyman & Vandeputte) likely further improves conciseness and adherence to instructions.\n- The task is code\n**explanation** only. This mirrors the use case within Caveman and popular for code assistant usage as a whole.\n\nPlease connect with me on [LinkedIn](https://www.linkedin.com/in/exia/) if you found this interesting or useful! Or check out my other projects [here](https://www.eric-xia.com/).\n\nEverything in `src/data_prep.py`\n\n, `src/judge*.py`\n\n, and `src/analyze*.py`\n\ncan run locally — no GPU\nneeded. The GPU-bound steps (`steering_const.py`\n\n, `sweep_dev.py`\n\n, `generate.py`\n\n) run on a rented\nGPU pod via `infra/run_gpu_pipeline.sh`\n\n(or invoked directly, as when re-running just one step).\n\n```\npython3 src/data_prep.py                        # local — data/{train,dev,test}.jsonl\n\n# on the GPU pod:\nbash infra/setup_runpod.sh\npython3 src/steering_const.py                   # -> results/const_steer_{config.json,directions.pt}\npython3 src/sweep_dev.py                        # -> results/sweep_dev.jsonl (all grid configs, dev)\n\n# back locally: judge the sweep, inspect the frontier, edit const_steer_config.json's\n# layer/coeff to the chosen operating point (see \"Methodology\" above)\npython3 src/judge_sweep.py                      # -> results/judged_sweep_dev.jsonl (needs openai.key)\npython3 src/analyze_sweep.py                    # -> results/summary_sweep_dev.json, plot\n\n# back on the GPU pod, with the final chosen config:\npython3 src/generate.py --split test            # -> results/generations_test.jsonl\n\n# back locally:\npython3 src/judge.py --split test               # -> results/judged_test.jsonl (needs openai.key)\npython3 src/analyze.py --split test             # -> results/summary_test.json, summary_plot_test.png\n```\n\n[1] Alessandro Stolfo, Vidhisha Balachandran, Safoora Yousefi, Eric Horvitz, Besmira Nushi.\n\"Improving Instruction-Following in Language Models through Activation Steering.\" arXiv:2410.12877.\n[https://arxiv.org/abs/2410.12877](https://arxiv.org/abs/2410.12877)\n\n[2] Geert Heyman, Frederik Vandeputte. \"Steer Like the LLM: Activation Steering that Mimics\nPrompting.\" arXiv:2605.03907. [https://arxiv.org/abs/2605.03907](https://arxiv.org/abs/2605.03907)\n\n[3] Andy Arditi, Oscar Obeso, Aaquib Syed, Daniel Paleka, Nina Panickssery, Wes Gurnee, Neel\nNanda. \"Refusal in Language Models Is Mediated by a Single Direction.\" arXiv:2406.11717.\n[https://arxiv.org/abs/2406.11717](https://arxiv.org/abs/2406.11717)\n\n[4] Alexander Matt Turner, Lisa Thiergart, Gavin Leech, David Udell, Juan J. Vazquez, Ulisse\nMini, Monte MacDiarmid. \"Activation Addition: Steering Language Models Without Optimization.\"\narXiv:2308.10248. [https://arxiv.org/abs/2308.10248](https://arxiv.org/abs/2308.10248)\n\n[5] Andy Zou, Long Phan, Sarah Chen, James Campbell, Phillip Guo, Richard Ren, Alexander Pan,\nXuwang Yin, et al. \"Representation Engineering: A Top-Down Approach to AI Transparency.\"\narXiv:2310.01405. [https://arxiv.org/abs/2310.01405](https://arxiv.org/abs/2310.01405)\n\n[6] Kenneth Li, Oam Patel, Fernanda Viégas, Hanspeter Pfister, Martin Wattenberg.\n\"Inference-Time Intervention: Eliciting Truthful Answers from a Language Model.\"\narXiv:2306.03341. [https://arxiv.org/abs/2306.03341](https://arxiv.org/abs/2306.03341)\n\n[7] Nina Rimsky, Nick Gabrieli, Julian Schulz, Meg Tong, Evan Hubinger, Alexander Matt Turner.\n\"Steering Llama 2 via Contrastive Activation Addition.\" arXiv:2312.06681.\n[https://arxiv.org/abs/2312.06681](https://arxiv.org/abs/2312.06681)\n\n[8] Samuel Marks, Max Tegmark. \"The Geometry of Truth: Emergent Linear Structure in Large\nLanguage Model Representations of True/False Datasets.\" arXiv:2310.06824.\n[https://arxiv.org/abs/2310.06824](https://arxiv.org/abs/2310.06824)\n\n## Footnotes\n\n-\nThis is a deliberately simple construction, but it has a long lineage in the interpretability literature — activation addition (Turner et al. [4]), representation engineering (Zou et al. [5]), inference-time intervention (Li et al. [6]), contrastive activation addition (Rimsky et al. [7]), and mass-mean probing (Marks & Tegmark [8]) all build steering or probing directions from contrasts between activations. While the resulting vector is model- and prompt-specific, extracting one is cheap and well-tooled: libraries such as\n\nand`repeng`\n\ncan reduce it to a few lines.`steering-vectors`\n\n[↩](#user-content-fnref-1-56b015fdbb5ee6efa1689983cdc80190)", "url": "https://wpnews.pro/news/lower-token-usage-through-representation-engineering", "canonical_source": "https://github.com/rkique/caveman-steer/tree/main", "published_at": "2026-07-21 22:04:19+00:00", "updated_at": "2026-07-21 22:22:26.710354+00:00", "lang": "en", "topics": ["artificial-intelligence", "large-language-models", "ai-research", "developer-tools"], "entities": ["Qwen2.5-Coder-7B-Instruct", "caveman", "CodeXGLUE", "Stolfo et al.", "Arditi et al."], "alternates": {"html": "https://wpnews.pro/news/lower-token-usage-through-representation-engineering", "markdown": "https://wpnews.pro/news/lower-token-usage-through-representation-engineering.md", "text": "https://wpnews.pro/news/lower-token-usage-through-representation-engineering.txt", "jsonld": "https://wpnews.pro/news/lower-token-usage-through-representation-engineering.jsonld"}}