AI Programming in Practice: Delivering Hundreds of Thousands of Lines of Code, Fixing Stubborn Bugs, and Controlling Costs
Over the past few months, an independent developer leveraged multiple AI programming tools to deliver a medium-sized system comprising approximately 270,000 lines of code across nearly 3,000 commits. This article shares a reusable engineering methodology focused on code quality, troubleshooting efficiency, and cost control. Rather than reviewing specific models, it explores how to evaluate models for long-chain programming tasks, design a structured workflow for resolving stubborn bugs, manage token costs effectively, and establish practical criteria for integrating AI into production delivery pipelines.
AI Programming in Practice: Delivering Hundreds of Thousands of Lines of Code, Fixing Stubborn Bugs, and Controlling Costs
Over the past few months, as an independent developer, I collaborated with multiple AI programming tools to develop and maintain a medium-sized system. The project yielded roughly 270,000 lines of code across nearly 3,000 commits. The process wasn’t simply about offloading tasks to the model; instead, it involved building a reusable workflow centered around three core objectives: code quality, troubleshooting efficiency, and cost control.
This article is not a benchmark review of specific models or service providers. Instead, from a general engineering perspective, it shares how to evaluate whether a model is fit for long-chain programming tasks, how to design a workflow for fixing stubborn bugs, and how to make AI programming genuinely delivery-ready—rather than just a demo trick—under a constrained annual budget.
1. Why Model Evaluation Cannot Rely Solely on Benchmark Scores
When selecting a programming model, many teams instinctively look at the total scores on benchmark leaderboards. While these scores provide a reference, real-world engineering environments are far more complex than fixed test sets. A model might excel in simple conversational tasks but fail to locate issues consistently within a large codebase. It might generate isolated functions smoothly yet suffer from context drift when modifying multiple modules consecutively.
Therefore, I prefer to evaluate a model’s suitability for long-term engineering development across three dimensions:
1. Continuous Coding Capability
Real-world projects rarely involve modifying just a single file. A single requirement often spans data models, business logic, API layers, frontend displays, and test cases. The model must continuously understand the project structure over time, remember previous modifications, and ensure that subsequent changes do not break existing features.
This capability aligns with long-horizon task evaluations. Compared to single-turn generation, continuous coding heavily tests the model’s context retention and better reflects its stability in actual development.
2. Agentic Task Completion
Agentic tasks require more than generating a code snippet; the model must autonomously complete a closed loop: understanding the problem, formulating a plan, locating files, modifying code, running validations, and executing secondary modifications. A model suited for engineering delivery should adjust its strategy based on terminal error outputs without requiring manual intervention at every step.
This is the critical threshold for teams transitioning from “assisted code completion” to “automated bug fixing.”
3. Performance in Constrained Environments
Development environments typically have finite resources. The model must perform operations given specific tools, commands, and file structures. Examples include executing tests inside a container, reviewing logs, analyzing dependency conflicts, or rolling back versions. These tasks closely resemble daily troubleshooting, as opposed to open-ended free generation.
2. Token Cost: Cheaper Is Not Always Better
With an annual budget of around 17,000 RMB (roughly $2,350 USD) for AI tools, I do not exclusively opt for the cheapest APIs. The core of cost control is not minimal usage, but ensuring that every expense generates actual delivery value.
Typically, token consumption in programming scenarios comes from the following areas:
1. Input Side: Long Context Reading
Key files in a large project can span thousands of lines. Combined with documentation, configurations, and historical commit data, the input tokens for a single request can increase rapidly. If the model supports a large context window, it can fully grasp module relationships in a single read, reducing the extra overhead of breaking context into chunks.
2. Cache Hits: Reducing Repetitive Costs
During continuous debugging, a large amount of prefix content is repetitive—such as project structures, utility functions, and configuration files. If the API provider supports prompt caching, subsequent requests can process identical prefixes at a significantly lower price, which is highly beneficial for long-running projects.
3. Output Side: Generating Complete Solutions
Output token costs are typically higher than input costs. However, if the output quality is sufficiently high—passing compilation and tests in a single generation—it ultimately saves more total cost than multiple low-quality generations. Therefore, cost evaluation should focus on the comprehensive price of a “single usable output” rather than simply comparing cost per million tokens.
A simple calculation illustrates this:
- Assume a single bug fix requires reading approximately 200,000 tokens.
- Outputting around 3,000 tokens.
- If caching performs well, input costs for subsequent retries will drop significantly.
- The factor that most impacts total cost is usually the number of failed retries.
Thus, a model that reduces retry frequency may yield a lower overall cost, even if its unit price is slightly higher.
3. Workflow Design for Fixing Stubborn Bugs
I dealt with a long-standing legacy bug. The symptom was straightforward: under specific data conditions, a certain dispatch task would intermittently stall, but the logs only showed a vague timeout message. Previous attempts with different models had failed to resolve it completely.
Instead of simply feeding the error logs to the model, I redesigned the resolution workflow:
Step 1: Establish a Minimal Reproduction Scenario
First, I asked the model to infer potential trigger conditions based on existing code and logs, and to generate a repeatable minimal test case. This case did not rely on production data and could consistently reproduce the issue locally.
Step 2: Structured Localization
Rather than just providing an error stack trace, I supplied the model with relevant module files, call chains, and data flow descriptions. I required it to output its “reasoning basis” before suggesting “modification locations.” This prevented the model from making direct guesses and forced it to expose its reasoning process first.
Step 3: Implement Modifications and Run Validations
After the model completed the code modifications, it automatically executed the minimal reproduction case to verify if it passed. If it failed, the model would read the new error output and continue to the next round of adjustments.
Step 4: Regression Check
Beyond the reproduction case, it also ran basic tests for adjacent modules to confirm that the new modifications did not introduce additional issues.
This entire process, from start to successful resolution, took about nine minutes. I did not write a single line of code manually, but it wasn’t a “one-click fix” either. It was a designed short loop: Reproduce → Locate → Modify → Validate → Regress.
4. Prerequisites for Helping Models Read Large Codebases
Long context support does not mean dumping all source code into a single prompt. Even if the context window is large enough, the model can easily be distracted by excessive noise. My approach begins with a lightweight structural summary.
For example, I use a simple logical description to outline module relationships:
src/core/dispatcher.py # Main task dispatch processmatcher.py # Rule matchingretry.py # Retry strategyadapter/source_a.py # Data source A integrationsource_b.py # Data source B integrationcommon/logger.pyconfig.py
Combined with a list of key functions for each file and recent change records, the model can locate the problem area much faster. This approach is more stable and consumes fewer tokens than directly reading raw files.
5. Generating Frontend Landing Pages with Engineering Constraints
Beyond bug fixes, I used a similar workflow to generate frontend pages. It is crucial to emphasize that without constraints, models tend to produce inconsistent styles and structures. To avoid results that “look functional but are unmaintainable,” I predefined several principles:
- Component boundaries must be clear, with no duplicated structures.
- Styles must use unified variables, avoiding scattered color values.
- Interaction states must be complete: loading, empty data, error state, and success state.
- The page structure should output a skeleton first, then fill in the content.
These principles do not belong to any specific tool; they are basic requirements of standard frontend engineering. Embedding them into the prompt significantly improves the maintainability of the generated output.
6. How to Determine if a Model is Ready for Long-Term Projects
After several practical tasks, I developed a set of criteria:
- Can it reliably execute the “modify then auto-validate” cycle?
- Can it continue making progress after encountering an error, rather than stopping to wait for manual confirmation?
- Is it sensitive to module relationships within a long context?
- Can it maintain style consistency after multiple consecutive modifications?
- Does the output code pass basic tests, rather than just “looking correct”?
These standards are more telling than any single benchmark score. They are derived from real delivery scenarios, not isolated tests.
7. Advice for Independent Developers
If you plan to integrate AI programming tools into your daily delivery system, my recommendations are:
- Build your own library of task types, such as bug fixing, API integration, refactoring, and test generation.
- Prepare fixed prompt templates and validation scripts for each task type.
- Log the time spent, token consumption, and success rate for every task.
- Periodically review which processes are worth automating and which still require human judgment.
- Do not distribute your budget evenly; concentrate it on the areas that most impact delivery efficiency.
The value of AI programming does not lie in replacing developers, but in compressing high-frequency, mechanical, trial-and-error work into incredibly short timeframes. True engineering benefits stem from workflow design and validation loops, not merely the generation speed of the model.
When a model can locate and fix a long-standing bug in nine minutes, it evolves beyond a code completion tool into something closer to a continuous engineering collaborator. The key is whether you have prepared sufficiently clear inputs, a stable validation environment, and a rational approach to cost evaluation.
