<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="http://pointerfly.com/feed.xml" rel="self" type="application/atom+xml" /><link href="http://pointerfly.com/" rel="alternate" type="text/html" /><updated>2026-04-18T07:28:08+00:00</updated><id>http://pointerfly.com/feed.xml</id><title type="html">PointerFLY</title><subtitle>PointerFLY&apos;s Personal Website.</subtitle><entry><title type="html">A Theory of Vibe Coding</title><link href="http://pointerfly.com/2026/03/01/a-theory-of-vibe-coding.html" rel="alternate" type="text/html" title="A Theory of Vibe Coding" /><published>2026-03-01T13:25:00+00:00</published><updated>2026-03-01T13:25:00+00:00</updated><id>http://pointerfly.com/2026/03/01/a-theory-of-vibe-coding</id><content type="html" xml:base="http://pointerfly.com/2026/03/01/a-theory-of-vibe-coding.html"><![CDATA[<h1 id="overview">Overview</h1>

<p>This article is trying to propose a theoretic framework to think about Large Language Model (LLM) and the concept Vibe Coding concept through the lens of probability and stochastic process.</p>

<p>It is important to emphasize that this is merely one perspective. The true nature of LLMs is complex, multi-disciplinary and still underdevelopment, but mapping their behavior to stochastic processes helps software engineers demystify the mechanics of modern “vibe coding.”</p>

<h1 id="llm-probabilistic-models">LLM: Probabilistic Models</h1>

<p>To establish this framework, we must first accept a core premise: we are treating the Large Language Model strictly as a probabilistic model. Just as the broader field of machine learning matured by shifting its focus from biological mimicry to rigorous statistical frameworks like Empirical and Structural Risk Minimization, we must strip away anthropomorphic analogies from LLMs. When an agent writes code, it is fundamentally minimizing a loss function over a distribution of tokens, not “thinking” in the human sense.</p>

<p>Formally, an LLM learns a parameterized probability distribution $P_\theta(X)$ to approximate the true data distribution $P_{data}(X)$ over sequences of tokens $X$. During training, this is typically achieved via Maximum Likelihood Estimation (MLE), minimizing the cross-entropy loss:</p>

\[\mathcal{L}(\theta) = -\mathbb{E}_{X \sim P_{data}}[\log P_\theta(X)]\]

<p>This view is supported by recent research, such as studies highlighting the <em><a href="https://machinelearning.apple.com/research/illusion-of-thinking">Illusion of Thinking</a></em> in LLMs. Models often fail catastrophically when superficial details of a logic puzzle are altered, suggesting that what appears to be formal reasoning is actually sophisticated, probabilistic pattern matching.</p>

<p>By acknowledging this illusion, we can stop asking “why didn’t the AI understand my prompt?”, start asking “how do I shift the probability distribution $P_\theta(Y \mid X)$ to favor the correct output $Y$?”</p>

<h1 id="the-basic-autoregressive-token-generation">The Basic: Autoregressive Token Generation</h1>

<p>At the foundational level, an LLM defines a conditional probability distribution over a vocabulary $\mathcal{V}$. The generation of the output text is an autoregressive stochastic process, sampling from the following distribution iteratively until an End-of-Sequence (EOS) token is reached:</p>

\[P(w_{n+1} \mid w_1, \dots, w_n), \; w_{n+1} \in \mathcal{V}\]

<p>Each generated token $w_{n+1}$ depends on the entire preceding sequence, making it a highly complex, non-Markovian process at the token level (though bounded by the context window).</p>

<h1 id="conversation-autoregressive-text-generation">Conversation: Autoregressive Text Generation</h1>

<p>In the early ChatGPT era, interactions were purely conversational without tool use. The user provides an input sequence (prompt) $X = (x_1, \dots, x_m)$, and the model generates a response sequence $Y = (y_1, \dots, y_k)$.</p>

<p>Given the finite length of the input token stream due to the context window limit, we can simplify the generation into a conditional probability distribution over sequences. Let $S_t$ represent the entire context state at turn $t$ (including all previous conversation history). The transition to the next state $S_{t+1}$ (which includes the user’s new prompt and the model’s response) is given by:</p>

\[P(S_{t+1} \mid S_t), \; S_{t+1} \in \mathcal{S}\]

<p>where $\mathcal{S}$ is the space of all valid token sequences within the context window. The model generates the response $Y_t$ autoregressively:</p>

\[P(Y_t \mid S_t) = \prod_{i=1}^{|Y_t|} P_\theta(y_{t,i} \mid S_t, y_{t,&lt;i})\]

<p>This process is a straightforward sequence-to-sequence mapping, heavily reliant on the internal weights $\theta$ to hallucinate or recall correct information.</p>

<h1 id="agent-interaction-beyond-the-llm">Agent: Interaction Beyond the LLM</h1>

<p>Agents complicate the base process by extending the capabilities of the LLM through the introduction of external tools. A tool can be modeled as a deterministic or stochastic function $T: \mathcal{X} \to \mathcal{Y}$ that accepts a string $x$ and generates a new string $y$:</p>

\[y = T(x)\]

<p>When an LLM decides to emit a special token sequence denoting a tool call action $A_t$, the autoregressive generation pauses. The environment executes $T(A_t)$ and returns an observation $O_t$.</p>

<p>In early agent frameworks, updating the state was a naive sequence concatenation (where $\oplus$ represents appending tokens):</p>

\[S_{t+1} = S_t \oplus A_t \oplus O_t\]

<p>This fundamental shift alters the loop of the LLM. It is no longer a closed-system generative model relying solely on $P_\theta$; it is now an open system where external computational entropy and deterministic facts are injected into the context window, dynamically shifting the conditional probabilities for subsequent generation.</p>

<p>It’s worthy to note that modern coding agents may have complex context management techniques, the state transition is managed by a <strong>Context Management Function</strong> $M$:</p>

\[S_{t+1} = M(S_t, A_t, O_t)\]

<p>By intelligently managing the state representation, $M$ prevents context overflow and maximizes the signal-to-noise ratio of the information fed back into the LLM’s probability distribution $P_\theta$ for the next generation step.</p>

<h1 id="agent-loop-markov-decision-process">Agent Loop: Markov Decision Process</h1>

<p>When we introduce “iterations” (e.g., compiling, running tests, reading error logs, and refining code), the system evolves from a simple random walk into a Markov Decision Process (MDP), or more accurately, a Partially Observable Markov Decision Process (POMDP):</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">state</span> <span class="o">=</span> <span class="n">build_initial_context</span><span class="p">(</span><span class="n">prompt</span><span class="p">,</span> <span class="n">codebase</span><span class="p">)</span>

<span class="k">while</span> <span class="ow">not</span> <span class="n">has_reached_absorbing_state</span><span class="p">(</span><span class="n">state</span><span class="p">):</span>
    <span class="c1"># LLM acts based on current context: A_t ~ \pi_\theta(A_t | S_t)
</span>    <span class="n">action</span> <span class="o">=</span> <span class="n">llm</span><span class="p">.</span><span class="n">sample_action</span><span class="p">(</span><span class="n">state</span><span class="p">)</span> 

    <span class="c1"># Environment evaluates the action deterministically: O_t = T(A_t)
</span>    <span class="n">observation</span> <span class="o">=</span> <span class="n">environment</span><span class="p">.</span><span class="n">execute</span><span class="p">(</span><span class="n">action</span><span class="p">)</span> 
    
    <span class="c1"># Context update: S_{t+1} = M(S_t, A_t, O_t)
</span>    <span class="n">state</span> <span class="o">=</span> <span class="n">context_manager</span><span class="p">.</span><span class="n">update</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">action</span><span class="p">,</span> <span class="n">observation</span><span class="p">)</span> 
</code></pre></div></div>

<ul>
  <li><strong>State ($S_t$)</strong>: The current context window. This includes the initial natural language prompt, the current draft of the codebase, and the latest environmental feedback (error logs, test results, or linter output).</li>
  <li><strong>Action ($A_t$)</strong>: The LLM sampling a new sequence from its policy $\pi_\theta(A_t \mid S_t)$. This could be writing a patch, replacing a file, or executing a tool call.</li>
  <li><strong>Transition Dynamics ($P(S_{t+1} \mid S_t, A_t)$)</strong>: The feedback from the environment. The environment evaluates the action and transitions the system to a new state. Since the environment (e.g., a test suite) is deterministic, the transition is largely defined by the tool’s output.</li>
  <li><strong>Reward ($R_t$)</strong>: A sparse, environmental signal, such as +1 for passing all tests and 0 otherwise.</li>
</ul>

<p><strong>Crucial Distinction: In-Context Traversal vs. RL Training</strong>
It is vital to clarify that in standard Vibe Coding, the LLM’s weights $\theta$ are <strong>frozen</strong>. The agent is <em>traversing</em> this POMDP using its pre-trained, fixed policy $\pi_\theta$. There is no reinforcement learning, gradient descent, or backpropagation happening during the loop. The “learning” is entirely <strong>in-context</strong>. The agent reaches the goal not by updating its internal parameters to maximize a reward function, but by exploring the state space via context accumulation until it discovers an action trajectory that triggers the termination signal (success).</p>

<h1 id="iterative-refinement-as-bayesian-inference">Iterative Refinement as Bayesian Inference</h1>

<p>Every iteration where the agent writes code, executes it, and receives an error message can be viewed as a Bayesian update.</p>

<p>Let $\mathcal{C}$ be the space of all possible code implementations. Initially, the LLM has a prior distribution $P(\mathcal{C} \mid S_0)$ based solely on the prompt and its pre-training.</p>

<p>When the agent executes the code action $A_t$, it receives an observation $O_t$ (e.g., a stack trace or a failed unit test). The likelihood of observing this specific output given a code implementation is $P(O_t \mid \mathcal{C})$.</p>

<p>The agent updates its belief over the correct code using Bayes’ Theorem:</p>

\[P(\mathcal{C} \mid S_t, O_t) \propto P(O_t \mid \mathcal{C}) P(\mathcal{C} \mid S_t)\]

<ul>
  <li><strong>Prior</strong>: The agent’s current distribution over the correct implementation, $P(\mathcal{C} \mid S_t)$.</li>
  <li><strong>Observation</strong>: The execution output $O_t$.</li>
  <li><strong>Posterior</strong>: The updated distribution over possible correct codes, $P(\mathcal{C} \mid S_{t+1})$. By feeding the observation back into the context window, the agent conditions its next sample on the fact that its previous hypothesis was incorrect. The observation $O_t$ acts as evidence, collapsing the probability mass around hypotheses that are consistent with resolving the error. This iteratively reduces the entropy $H(\mathcal{C})$ of the solution space.</li>
</ul>

<h1 id="convergence">Convergence</h1>

<p>In the context of Vibe Coding, convergence is defined as the agent reaching an <strong>absorbing state</strong> $S^\ast$ where the task is complete. Mathematically, an absorbing state is one where the transition probability to any other state is zero: $P(S^\ast \mid S^\ast, A) = 1$, and the agent’s policy outputs a “terminate” action with probability 1.</p>

<p>Practically, convergence means the code meets a predefined termination criteria:</p>

<ol>
  <li><strong>Functional Completeness</strong>: All unit, integration, and e2e tests pass (the environment returns a success signal).</li>
  <li><strong>Human Approval</strong>: The code passes visual and architectural inspection by a human developer.</li>
</ol>

<p>It is crucial to note that for any set of functional requirements, there are theoretically infinitely many valid code implementations $\mathcal{C}_{valid} \subset \mathcal{C}$ that satisfy the automated test suite. A naive MDP process might converge to any random absorbing state within $\mathcal{C}_{valid}$. However, a well-steered MDP process aims to converge the end state strictly into a much smaller, optimal subset $\mathcal{C}_{optimal} \subset \mathcal{C}_{valid}$. This subset represents implementations that yield a high Value function from a software engineering perspective—characterized by low structural entropy, high maintainability, and scalability.</p>

<p>The efficiency of vibe coding is measured by the <strong>expected hitting time</strong> $\mathbb{E}[T_{S^\ast}]$, which is the expected number of iterations (tool calls and generations) required to reach the absorbing state $S^\ast$. A lower hitting time implies a faster and more efficient agent loop.</p>

<h1 id="hitl-human-in-the-loop">HITL (Human-in-the-Loop)</h1>

<p>Without human steering, an autonomous coding agent is highly susceptible to converging on a “local minimum”—an absorbing state where the unit tests pass and the code compiles, but the architecture is an unmaintainable disaster (e.g., spaghetti code, hardcoded values). In an MDP landscape, the agent has reached a state that satisfies the automated environment’s sparse reward signal (passing tests) but fails on unstated, long-term objectives (maintainability).</p>

<p>The human developer acts as an external <strong>Oracle</strong> and a <strong>Control Mechanism</strong>, forcefully altering the transition probabilities of the MDP. By reviewing the code and injecting a mid-prompt (e.g., “Refactor this to use the Strategy pattern”), the human:</p>

<ol>
  <li><strong>Shifts the Prior</strong>: Injects strong structural priors into the context window, radically altering $P(C \mid S_t)$.</li>
  <li><strong>Escapes Local Minima</strong>: Forces a state transition away from the suboptimal absorbing state, $P(S_{new} \mid S_{local}, A_{human}) = 1$, pushing the agent back into exploration.</li>
  <li><strong>Acts as a Surrogate Reward</strong>: Since the agent cannot be trained via RL on a complex reward function on the fly, the human provides heuristic “pseudo-rewards” directly in natural language. These constraints for Code Quality, Security, Maintainability and Scalability act as new deterministic rules in the context window.</li>
</ol>

<p>Through human steering, the search space is pruned, drastically reducing the expected hitting time $\mathbb{E}[T_{S^\ast}]$ and ensuring the final state is a global optimum rather than a local one.</p>

<h1 id="experienced-software-engineer">Experienced Software Engineer</h1>

<p>An experienced software engineer possesses a highly refined internal prior distribution $P_{experienced}(\mathcal{C})$ over optimal software architectures. Because they deeply understand the long-term implications of design choices, they act as an accurate <strong>Value Function</strong> estimator for the intermediate state of the codebase:</p>

\[V_{experienced}(S_t) \approx V^\ast(S_t)\]

<p>By injecting strategic prompts $A_{experienced}$, they provide heuristic guidance that substitutes for the dense reward signals an RL agent would normally require during training. This intervention effectively collapses the uncertainty, drastically reducing the entropy of the remaining solution space:</p>

\[H(\mathcal{C} \mid S_t, A_{experienced}) \ll H(\mathcal{C} \mid S_t)\]

<p>Through this precise Bayesian updating, the senior engineer prunes massive branches of the search tree early on. This accelerates the loop, reducing the expected hitting time compared to an unguided, autonomous agent:</p>

\[\mathbb{E}[T_{S^\ast} \mid A_{experienced}] \ll \mathbb{E}[T_{S^\ast} \mid \text{autonomous}]\]

<p>More importantly, their guidance forces the MDP transition dynamics to avoid suboptimal absorbing states, guaranteeing with high probability that the final implementation belongs to the highly maintainable, optimal subset:</p>

\[P(S^\ast \in \mathcal{C}_{optimal} \mid A_{experienced}) \to 1\]

<h1 id="starters-or-layman">Starters or Layman</h1>

<p>Conversely, a starter or layman possesses an uncalibrated prior $P_{starter}(\mathcal{C})$ and a value function with extremely high variance, meaning they cannot reliably estimate the long-term cost of a drafted pull request:</p>

\[\text{Var}(V_{starter}(S_t)) \gg 0\]

<p>When a starter attempts to steer the agent, their prompts $A_{starter}$ often fail to provide the precise Bayesian updates needed. Instead of collapsing the probability mass around the correct solution, they may introduce noise, leaving the entropy of the solution space largely unchanged:</p>

\[H(\mathcal{C} \mid S_t, A_{starter}) \approx H(\mathcal{C} \mid S_t)\]

<p>Without an accurate internal value function to foresee architectural dead-ends, the starter may accept an implementation simply because it satisfies the immediate functional requirements (e.g., automated unit tests pass). Consequently, the agent is prone to converging on a suboptimal local minimum $S_{local}$:</p>

\[P(S^\ast \in \mathcal{C}_{valid} \setminus \mathcal{C}_{optimal} \mid A_{starter}) \to 1\]

<p>Because the search space is not effectively pruned by human steering, this unguided traversal increases the expected hitting time and often leads to the loop diverging into endless iterations of broken or unmaintainable code.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Overview]]></summary></entry></feed>