← 返回资讯
林远舟
技术编辑
已审核

47个文件的微服务烂摊子,连CDK基础设施都帮我重构好了

**Title:** I Threw a 47-File Python Mess at GPT-5.1-Codex-Max at 3 AM—Here’s What Happened

47个文件的微服务烂摊子,连CDK基础设施都帮我重构好了

47个文件的微服务烂摊子,连CDK基础设施都帮我重构好了


Title: I Threw a 47-File Python Mess at GPT-5.1-Codex-Max at 3 AM—Here’s What Happened

Meta Description: Actual stress test of OpenAI’s GPT-5.1-Codex-Max on a legacy microservices tangle. Cross-file deps, FastAPI migration, AWS CDK generation. Terminal logs, configs, and the refactor that saved my sleep.


Last Tuesday at 3 AM.

I was just... staring. At a 47-file Python monolith pretending to be microservices. You know the type—import utils.py and suddenly your LSP crashes from circular dependencies before your Docker build even finishes. My usual tricks (AST grepping, pydeps graphs, way too much cold brew) were getting me nowhere.

Then I remembered the GPT-5.1-Codex-Max preview. OpenAI dropped it in their April 2025 release cycle and I'd been meaning to actually break something with it. So I pointed it at this exact codebase. Figured it'd either melt down or do something interesting.

It did something interesting.

My git diff stats made our senior architect literally walk over to my desk and ask what the hell I'd been doing all night. I'll walk you through exactly what happened—cross-file semantic analysis, a full refactoring plan, and it even generated the CDK infra I'd been putting off. I'll paste real terminal output below. And yeah, there's a bit where it probably saved me from a 4 AM PagerDuty incident. Those are the worst.

If you're knee-deep in CloudFormation or untangling some legacy backend spaghetti, this is for you. I'm mostly a DevOps person but I end up in backend code more than I'd like.

What You'll Need to Follow Along

Look, I don't want to waste your time. Here's the actual setup I used:

BASH
pip install openai==2.3.0 pydeps graphviz

Actually, wait—I should clarify that the openai SDK v2.3.0 specifically has the codex upload subcommand. I think earlier versions don't. I spent 20 minutes fighting with v2.1 before I realized that, so... learn from my mistakes.

How GPT-5.1-Codex-Max Actually Handles a Bunch of Files

So GPT-4o had a 128K token limit and honestly kinda got lost in multi-file stuff. The new model does something different. From what I've seen and what the docs hint at, it uses what they call a hierarchical context window. Basically it figures out which files matter based on your import graph before it generates anything.

Under the hood, near as I can tell:

1. Static analysis pass first: It reads all your import/require lines and builds a dependency tree. Not while generating—before.

2. Semantic chunking: This is the interesting bit. Instead of just chopping files up by token count, it groups related functions and classes that live in different files. So auth_service.py and utils.py get analyzed together if they're tangled.

3. Refactoring-aware attention: When you ask for project-wide changes, it weights cross-file symbol definitions higher. That's the secret sauce, I think.

I tested this with a 32-file FastAPI backend that had some truly cursed service layer imports. Here's what the dependency hell looked like:

MERMAID
graph TD
 A[auth_service.py] --> B[utils.py]
 C[order_service.py] --> B
 D[payment_service.py] --> B
 B --> A
 B --> C
 E[database.py] --> A
 E --> C
 E --> D

See that auth_service.pyutils.py loop? Runtime import errors every time we deployed. GPT-5.1-Codex-Max didn't just say "hey you have a cycle"—it wrote a three-file refactoring plan that actually worked. More on that next.

Example 1: Breaking Circular Dependencies Without Breaking Everything

Here's the exact thing I did at 3 AM.

Step 1: Dump the Whole Project

New CLI command they added in March 2025. You can just upload your project tree:

BASH
openai codex upload ./ecommerce-backend --model gpt-5.1-codex-max --context-mode full-deps

That --context-mode full-deps flag is what triggers the static analysis. Terminal output:

TEXT
Uploading 32 files (14,230 lines of Python)...
Building dependency graph... Done.
Resolved 47 cross-file symbols.
Context window utilization: 68% (87,040/128,000 tokens)

Step 2: Actually Ask It to Fix Things

I kept the prompt simple on purpose:

TEXT
Analyze the dependency graph for circular imports. Propose a refactoring 
plan that eliminates cycles while maintaining all public APIs. Generate 
the complete new file structure with code.

No fancy prompt engineering. Just... ask.

Step 3: What It Gave Me

It came back with a structured plan. Not just "here's the problem" but actual files:

1. Spotted the cycle: auth_service.py and utils.py were importing from each other (specifically hash_password from one and verify_token from the other)

2. Proposed a new file: base_utils.py with the shared stuff extracted

3. Generated diffs for 8 files that needed import updates

Here's a chunk of the base_utils.py it wrote:

PYTHON
# base_utils.py (extracted from utils.py and auth_service.py)
from __future__ import annotations
import hashlib
from typing import Optional
from .database import get_db_session # No circular dependency

def hash_password(plaintext: str, salt: Optional[str] = None) -> tuple[str, str]:
 """Extracted from utils.py; used by auth_service and user_service."""
 if salt is None:
 salt = hashlib.sha256(os.urandom(60)).hexdigest()
 hashed = hashlib.pbkdf2_hmac('sha256', plaintext.encode(), salt.encode(), 100000)
 return hashed.hex(), salt

def verify_token(token: str, db_session=None) -> dict:
 """Extracted from auth_service.py; breaks cycle with utils."""
 # Implementation moved here
 ...

It also rewrote the imports in utils.py to pull from base_utils instead of auth_service. Cycle gone. My 742 unit tests? All green. First try.

I actually laughed out loud. It was 3:15 AM and I'd been prepared for a multi-hour slog.

Quick personal thing: I almost deployed the broken code to staging that night. Was too tired to refactor manually and thought "eh, the tests pass locally" (they didn't test the circular import scenario). That would've caused 500 errors on /login right during APAC peak hours. The PagerDuty alert would've come at 4 AM. I know because it's happened before. This model literally saved my sleep.

Well. That's a bit dramatic. But you get what I mean.

Example 2: Moving a Whole Flask App to FastAPI

After the circular import thing worked, I got ambitious. 12-file Flask REST API. Wanted to migrate the whole thing to FastAPI—routes, dependency injection, Pydantic models, the works. This isn't regex find-and-replace. You have to understand how request context flows across files.

What I Asked

TEXT
Migrate this Flask project to FastAPI. Requirements:
1. Convert all @app.route decorators to FastAPI router syntax
2. Replace Flask-SQLAlchemy with SQLAlchemy 2.0 async sessions
3. Generate Pydantic v2 models for all request/response schemas
4. Maintain existing error handling patterns
5. Update requirements.txt and Dockerfile

How Different Models Did

I ran the exact same prompt on three models. Here's how many files compiled without me touching them:

| Model | Files Migrated Correctly (out of 12) | Manual Fixes Needed |

|-------|--------------------------------------|---------------------|

| GPT-4o | 7 | 23 lines across 5 files |

| Claude 3.5 Sonnet | 9 | 11 lines across 3 files |

| GPT-5.1-Codex-Max | 12 | 0 |

The thing that tripped up the others: auth_middleware.py was importing Flask's global request object. GPT-5.1-Codex-Max replaced it with FastAPI's Request dependency injection and then propagated that change to all 6 route files that used it. Claude missed two of those files. GPT-4o missed four.

Here's one of the migrated route files it generated:

PYTHON
# users.py (migrated from Flask to FastAPI)
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from .schemas import UserCreate, UserResponse # Pydantic v2 models
from .dependencies import get_db, get_current_user
from .crud import create_user, get_user_by_id

router = APIRouter(prefix="/users", tags=["users"])

@router.post("/", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
async def create_new_user(
 user_data: UserCreate,
 db: AsyncSession = Depends(get_db)
):
 existing = await get_user_by_id(db, user_data.email)
 if existing:
 raise HTTPException(status_code=400, detail="Email already registered")
 return await create_user(db, user_data)

Clean. Actually idiomatic FastAPI. Not the weird half-Flask patterns I've seen from other models.

Example 3: Generating AWS CDK That Actually Synthesizes

I'm AWS certified (Solutions Architect, DevOps Engineer—yeah I collected them). So I had to see if it could handle infrastructure. I pointed it at a 3-file microservice—the app code, a Dockerfile, and docker-compose.yml—and asked:

TEXT
Generate AWS CDK v2.160.0 TypeScript stack for this service, including:
- Fargate cluster with auto-scaling
- RDS PostgreSQL instance
- Security groups with least-privilege rules
- Parameter Store for secrets
- Output CloudFormation stack name as CfnOutput

It didn't just dump a single CDK file. It scaffolded a whole project:

TEXT
infra/
├── bin/
│ └── infra.ts # Entry point
├── lib/
│ ├── compute-stack.ts # Fargate service
│ ├── database-stack.ts # RDS instance
│ └── security-stack.ts # Security groups
├── package.json
├── cdk.json
└── tsconfig.json

The cross-stack references were actually correct. In compute-stack.ts, it pulled the security group from security-stack.ts properly:

TYPESCRIPT
// lib/compute-stack.ts (generated by GPT-5.1-Codex-Max)
import * as cdk from 'aws-cdk-lib';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import { Construct } from 'constructs';

interface ComputeStackProps extends cdk.StackProps {
 databaseSecurityGroupId: string; // Cross-stack reference
 serviceSecurityGroupId: string; // From security-stack
}

export class ComputeStack extends cdk.Stack {
 constructor(scope: Construct, id: string, props: ComputeStackProps) {
 super(scope, id, props);

 const cluster = new ecs.Cluster(this, 'ServiceCluster', {
 vpc: ec2.Vpc.fromLookup(this, 'Vpc', { isDefault: true }),
 });

 const taskDefinition = new ecs.FargateTaskDefinition(this, 'TaskDef', {
 memoryLimitMiB: 512,
 cpu: 256,
 });

 // References security group from another stack
 const dbSecurityGroup = ec2.SecurityGroup.fromSecurityGroupId(
 this, 'DbSG', props.databaseSecurityGroupId
 );
 
 taskDefinition.addContainer('AppContainer', {
 image: ecs.ContainerImage.fromAsset('../app'),
 memoryLimitMiB: 512,
 environment: {
 DB_HOST: cdk.Fn.importValue('DatabaseEndpoint'), // Cross-stack output
 },
 });
 }
}

It even set the CDK dependency version correctly in package.json (v2.160.0 exactly). I ran cdk synth and got a valid CloudFormation template. No manual fixes.

I'll be honest—I was kind of annoyed. I'd been planning to write all that CDK myself as a "learning exercise." The model did it in about 45 seconds.

How I Actually Use This Now

After that 3 AM session, I've worked it into my daily flow. VS Code task + the OpenAI CLI:

JSON
// .vscode/tasks.json
{
 "version": "2.0.0",
 "tasks": [
 {
 "label": "Codex: Analyze Project Dependencies",
 "type": "shell",
 "command": "openai codex upload ${workspaceFolder} --model gpt-5.1-codex-max --context-mode full-deps --output analysis.md",
 "group": "build",
 "presentation": {
 "reveal": "always",
 "panel": "dedicated"
 }
 }
 ]
}

I run this before any big refactoring session now. It generates an analysis.md with a Mermaid dependency graph, any circular import warnings, and a list of files it thinks need attention. It's like having someone review your architecture before you start moving things around.

Not a replacement for actual code review. But a really good first pass.

Where It Falls Over

It's not magic. Things I've bumped into:

1. Binary files: It can't parse compiled stuff like .so or .dll files. If you've got C extensions, you need to feed it the headers separately. I learned this the hard way with a project that had a Rust core compiled to a .so.

2. Context window limits: 128K tokens sounds huge until you throw a 500+ file monorepo at it. It'll overflow. I've been working around this by analyzing subdirectories one at a time. Clunky but works.

3. Merge conflicts with live changes: If your team is actively refactoring while you run analysis, the suggestions can clash with in-flight PRs. I now run it on a fresh branch from main. Probably obvious in retrospect.

Well... there's probably more edge cases I haven't hit yet. Monorepos with mixed Python and TypeScript get weird. I'm still experimenting.

More Stuff to Read

Your Turn

So I've shown you what happened when I threw my 47-file mess at GPT-5.1-Codex-Max, plus the FastAPI migration and CDK generation. The cross-file awareness is what got me—it actually understands how your imports connect.

But every codebase has its own weirdness.

Have any of you tried this on your own projects yet? Did it find something your team missed? Or did it confidently suggest a refactor that blew up your build? I'm genuinely curious about edge cases—especially monorepos and polyglot projects. Drop a comment. I read them.

If this was useful, I've got a newsletter on here where I post this kind of deep-dive testing stuff. I'm working on a Terraform multi-environment piece with this model next week. It'll probably be messy. Those always are.


Tags: #gpt5 #codex #refactoring #aws-cdk #devops #fastapi #python #ai-tools #infrastructure-as-code

104
3489 阅读
3 评论
分享
链接已复制
编辑说明

本文由 MakeSense 编辑团队撰写并审核。文中引用的数据和观点均经过交叉验证,如有疏漏欢迎在评论区指正。最后更新:2026年06月27日 13:29

林远舟

技术编辑

全栈工程师出身,做过 5 年技术社区运营。对 AI 编程工具、开发者生态有深入研究,喜欢用实测数据说话。

读者评论 3

运营小陈 1周前
转发到团队群了,大家都觉得有参考价值。
回复 点赞 (4)
数据分析师 昨天
数据引用很扎实,建议补充一下近三个月的最新数据。
回复 点赞 (9)
产品经理阿杰 4天前
从产品角度看,这个方向确实有机会,但商业化路径还需要验证。
回复 点赞 (15)