639 lines
23 KiB
Markdown
639 lines
23 KiB
Markdown
# LLM 代码生成工具(自举版 · 增强版)
|
||
|
||
本项目是一个基于大语言模型的智能代码生成与维护工具。它不仅能够根据项目 `README.md` 描述**自动生成完整的 Python 包代码**,还支持**在现有项目上增量添加功能**和**自动修复 Bug**。工具采用 `uv` 管理依赖,包含单元测试、并行检查、断点续写等特性,并通过一个**面向 LLM 的中间设计层**来提升生成质量和可维护性。
|
||
|
||
|
||
## 特别说明
|
||
我已经实现了一个简易版本,请在此基础上修改、拓展、开发:
|
||
|
||
```
|
||
#!/home/songsenand/env/.venv/bin/python
|
||
"""
|
||
基于LLM的自动化代码生成工具
|
||
根据README.md文件,自动生成项目文件结构并填充代码,执行必要命令。
|
||
"""
|
||
|
||
import json
|
||
import os
|
||
import subprocess
|
||
import sys
|
||
from typing import List, Dict, Optional, Any, Tuple
|
||
from pathlib import Path
|
||
|
||
import typer
|
||
from rich.console import Console
|
||
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TaskID
|
||
from loguru import logger
|
||
from openai import OpenAI
|
||
|
||
# ==================== 配置 ====================
|
||
DANGEROUS_COMMANDS = ["rm", "sudo", "chmod", "dd", "mkfs", "> /dev/sda", "format"]
|
||
ALLOWED_COMMANDS = [] # 可设置白名单,为空则只检查黑名单
|
||
|
||
app = typer.Typer(help="基于LLM的自动化代码生成工具")
|
||
console = Console()
|
||
|
||
# ==================== 工具函数 ====================
|
||
def is_dangerous_command(cmd: str) -> Tuple[bool, str]:
|
||
"""
|
||
判断命令是否危险
|
||
返回 (是否危险, 原因)
|
||
"""
|
||
cmd_lower = cmd.lower()
|
||
for danger in DANGEROUS_COMMANDS:
|
||
if danger in cmd_lower:
|
||
return True, f"包含危险关键词 '{danger}'"
|
||
return False, ""
|
||
|
||
# ==================== 核心类 ====================
|
||
class CodeGenerator:
|
||
"""代码生成器,封装所有逻辑"""
|
||
|
||
def __init__(
|
||
self,
|
||
api_key: Optional[str] = None,
|
||
base_url: str = "https://api.deepseek.com",
|
||
model: str = "deepseek-reasoner",
|
||
output_dir: str = "./generated",
|
||
log_file: Optional[str] = None,
|
||
):
|
||
"""
|
||
初始化生成器
|
||
|
||
Args:
|
||
api_key: OpenAI API密钥,默认从环境变量DEEPSEEK_APIKEY读取
|
||
base_url: API基础URL
|
||
model: 使用的模型
|
||
output_dir: 输出根目录
|
||
log_file: 日志文件路径,默认自动生成
|
||
"""
|
||
self.api_key = api_key or os.getenv("DEEPSEEK_APIKEY")
|
||
if not self.api_key:
|
||
raise ValueError("必须提供API密钥,或设置环境变量DEEPSEEK_APIKEY")
|
||
|
||
self.client = OpenAI(api_key=self.api_key, base_url=base_url)
|
||
self.model = model
|
||
self.output_dir = Path(output_dir)
|
||
self.output_dir.mkdir(parents=True, exist_ok=True)
|
||
|
||
# 配置日志
|
||
if log_file is None:
|
||
log_file = self.output_dir / "generator.log"
|
||
logger.remove() # 移除默认handler
|
||
logger.add(sys.stderr, level="WARNING") # 控制台输出INFO及以上
|
||
logger.add(log_file, rotation="10 MB", level="DEBUG") # 文件记录DEBUG
|
||
logger.info(f"日志已初始化,保存至: {log_file}")
|
||
|
||
self.readme_content = None
|
||
|
||
self.progress: Optional[Progress] = None
|
||
self.tasks: Dict[str, TaskID] = {} # 任务ID映射
|
||
|
||
def _call_llm(
|
||
self,
|
||
system_prompt: str,
|
||
user_prompt: str,
|
||
temperature: float = 0.2,
|
||
expect_json: bool = True,
|
||
) -> Dict[str, Any]:
|
||
"""
|
||
调用LLM并返回解析后的JSON
|
||
"""
|
||
logger.debug(f"调用LLM,模型: {self.model}")
|
||
logger.debug(f"System: {system_prompt[:200]}...")
|
||
logger.debug(f"User: {user_prompt[:200]}...")
|
||
|
||
try:
|
||
response = self.client.chat.completions.create(
|
||
model=self.model,
|
||
messages=[
|
||
{"role": "system", "content": system_prompt},
|
||
{"role": "user", "content": user_prompt},
|
||
],
|
||
temperature=temperature,
|
||
response_format={"type": "json_object"} if expect_json else None,
|
||
)
|
||
|
||
message = response.choices[0].message
|
||
content = message.content
|
||
|
||
# 记录思考过程(如果存在)
|
||
if hasattr(message, "reasoning_content") and message.reasoning_content:
|
||
logger.info(f"模型思考过程: {message.reasoning_content}")
|
||
|
||
logger.debug(f"LLM原始响应: {content[:500]}...")
|
||
|
||
if expect_json:
|
||
result = json.loads(content)
|
||
else:
|
||
result = {"content": content}
|
||
|
||
return result
|
||
|
||
except json.JSONDecodeError as e:
|
||
logger.error(f"JSON解析失败: {e}")
|
||
raise ValueError(f"LLM返回的不是有效JSON: {content[:200]}")
|
||
except Exception as e:
|
||
logger.error(f"LLM调用失败: {e}")
|
||
raise
|
||
|
||
def parse_readme(self, readme_path: Path) -> str:
|
||
"""
|
||
读取README文件内容
|
||
"""
|
||
logger.info(f"读取README文件: {readme_path}")
|
||
try:
|
||
with open(readme_path, "r", encoding="utf-8") as f:
|
||
content = f.read()
|
||
logger.debug(f"README内容长度: {len(content)} 字符")
|
||
return content
|
||
except Exception as e:
|
||
logger.error(f"读取README失败: {e}")
|
||
raise
|
||
|
||
def get_project_structure(self) -> Tuple[List[str], Dict[str, List[str]]]:
|
||
"""
|
||
根据README内容,让LLM生成文件列表和依赖关系
|
||
|
||
Returns:
|
||
(files, dependencies)
|
||
files: 按顺序需要生成的文件路径列表
|
||
dependencies: 字典 {file: [依赖文件路径]}
|
||
"""
|
||
system_prompt = (
|
||
"你是一个软件架构师。请根据README描述,分析需要生成哪些源代码文件,并确定它们的生成顺序,"
|
||
"同时给出每个文件生成时最少需要读取哪些已有文件作为上下文。"
|
||
"返回严格的JSON对象,包含两个字段:\n"
|
||
"- files: 数组,按生成顺序排列的文件路径(相对于项目根目录)\n"
|
||
"- dependencies: 对象,键为文件路径,值为该文件依赖的已有文件路径列表(可为空)\n"
|
||
"注意:依赖文件必须是已存在的参考文件,不要包含待生成的文件。"
|
||
)
|
||
user_prompt = f"README内容如下:\n\n{self.readme_content}"
|
||
|
||
result = self._call_llm(system_prompt, user_prompt)
|
||
|
||
files = result.get("files", [])
|
||
dependencies = result.get("dependencies", {})
|
||
|
||
if not files:
|
||
raise ValueError("LLM未返回任何文件列表")
|
||
|
||
logger.info(f"解析到 {len(files)} 个待生成文件")
|
||
logger.debug(f"文件列表: {files}")
|
||
logger.debug(f"依赖关系: {dependencies}")
|
||
|
||
return files, dependencies
|
||
|
||
def generate_file(
|
||
self,
|
||
file_path: str,
|
||
prompt_instruction: str,
|
||
dependency_files: List[str],
|
||
) -> Tuple[str, str, List[str]]:
|
||
"""
|
||
生成单个文件,返回 (代码, 描述, 命令列表)
|
||
"""
|
||
# 读取依赖文件内容
|
||
context_content = []
|
||
|
||
if self.readme_content:
|
||
context_content.append(f"### 项目 README ###\n{self.readme_content}\n")
|
||
|
||
for dep in dependency_files:
|
||
dep_path = Path(dep)
|
||
if not dep_path.exists():
|
||
# 尝试相对于当前目录或输出目录查找
|
||
alt_path = self.output_dir / dep
|
||
if alt_path.exists():
|
||
dep_path = alt_path
|
||
else:
|
||
raise FileNotFoundError(f"依赖文件不存在: {dep}")
|
||
|
||
with open(dep_path, "r", encoding="utf-8") as f:
|
||
content = f.read()
|
||
context_content.append(f"### 文件: {dep_path.name} (路径: {dep}) ###\n{content}\n")
|
||
|
||
full_context = "\n".join(context_content)
|
||
|
||
system_prompt = (
|
||
"你是一个专业的编程助手。根据用户指令和提供的上下文文件,生成完整的代码。"
|
||
"返回严格的JSON对象,包含三个字段:\n"
|
||
"- code: (string) 生成的完整代码\n"
|
||
"- description: (string) 简短的中文功能描述\n"
|
||
"- commands: (array of string) 生成此文件后需要执行的操作系统命令列表(如编译、安装依赖等),若无则返回空数组"
|
||
)
|
||
user_prompt = f"{prompt_instruction}\n\n参考文件上下文:\n{full_context}"
|
||
|
||
result = self._call_llm(system_prompt, user_prompt)
|
||
|
||
code = result.get("code", "")
|
||
description = result.get("description", "")
|
||
commands = result.get("commands", [])
|
||
|
||
if not isinstance(commands, list):
|
||
commands = []
|
||
|
||
return code, description, commands
|
||
|
||
def execute_command(self, cmd: str, cwd: Optional[Path] = None) -> None:
|
||
"""
|
||
执行单个命令,检查风险
|
||
"""
|
||
dangerous, reason = is_dangerous_command(cmd)
|
||
if dangerous:
|
||
logger.error(f"危险命令被阻止: {cmd},原因: {reason}")
|
||
raise RuntimeError(f"危险命令: {cmd} ({reason})")
|
||
|
||
logger.info(f"执行命令: {cmd}")
|
||
try:
|
||
result = subprocess.run(
|
||
cmd,
|
||
shell=True,
|
||
cwd=cwd or self.output_dir,
|
||
capture_output=True,
|
||
text=True,
|
||
timeout=300, # 5分钟超时
|
||
)
|
||
logger.debug(f"命令返回码: {result.returncode}")
|
||
if result.stdout:
|
||
logger.debug(f"stdout: {result.stdout[:500]}")
|
||
if result.stderr:
|
||
logger.warning(f"stderr: {result.stderr[:500]}")
|
||
if result.returncode != 0:
|
||
raise subprocess.CalledProcessError(result.returncode, cmd)
|
||
except subprocess.TimeoutExpired:
|
||
logger.error(f"命令执行超时: {cmd}")
|
||
raise
|
||
except Exception as e:
|
||
logger.error(f"命令执行失败: {e}")
|
||
raise
|
||
|
||
def run(self, readme_path: Path):
|
||
"""
|
||
主执行流程
|
||
"""
|
||
logger.info("=" * 50)
|
||
logger.info("开始代码生成流程")
|
||
logger.info(f"README: {readme_path}")
|
||
logger.info(f"输出目录: {self.output_dir}")
|
||
|
||
# 初始化阶段:用rich输出状态(不会被日志级别过滤)
|
||
console.print("[bold yellow]🔍 正在解析README...[/bold yellow]")
|
||
self.readme_content = self.parse_readme(readme_path)
|
||
|
||
console.print("[bold yellow]📋 正在分析项目结构...[/bold yellow]")
|
||
files, dependencies = self.get_project_structure()
|
||
|
||
console.print(f"[green]✅ 解析完成,共 {len(files)} 个文件待生成[/green]")
|
||
|
||
# 3. 创建进度条
|
||
with Progress(
|
||
SpinnerColumn(),
|
||
TextColumn("[progress.description]{task.description}"),
|
||
BarColumn(),
|
||
TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
|
||
console=console,
|
||
) as progress:
|
||
self.progress = progress
|
||
# 创建总任务
|
||
total_task = progress.add_task("[cyan]整体进度...", total=len(files))
|
||
|
||
# 依次生成每个文件
|
||
for idx, file in enumerate(files, 1):
|
||
logger.info(f"处理文件 [{idx}/{len(files)}]: {file}")
|
||
|
||
# 创建子任务(可选)
|
||
file_task = progress.add_task(f"生成 {file}", total=None)
|
||
|
||
try:
|
||
# 获取依赖文件
|
||
deps = dependencies.get(file, [])
|
||
|
||
# 构造生成指令
|
||
instruction = f"请根据README描述和依赖文件,生成文件 '{file}' 的完整代码。"
|
||
|
||
# 调用LLM生成代码
|
||
code, desc, commands = self.generate_file(file, instruction, deps)
|
||
|
||
logger.info(f"生成完成: {file} - {desc}")
|
||
|
||
# 写入文件
|
||
output_path = self.output_dir / file
|
||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||
with open(output_path, "w", encoding="utf-8") as f:
|
||
f.write(code)
|
||
logger.info(f"已写入: {output_path}")
|
||
|
||
# 执行命令
|
||
for cmd in commands:
|
||
logger.info(f"准备执行命令: {cmd}")
|
||
self.execute_command(cmd, cwd=self.output_dir)
|
||
|
||
except Exception as e:
|
||
logger.error(f"处理文件 {file} 失败: {e}")
|
||
# 可选:继续或终止
|
||
raise
|
||
finally:
|
||
progress.remove_task(file_task)
|
||
progress.update(total_task, advance=1)
|
||
|
||
logger.success("所有文件处理完成!")
|
||
|
||
# ==================== CLI入口 ====================
|
||
@app.command()
|
||
def main(
|
||
readme: Path = typer.Argument(..., exists=True, file_okay=True, dir_okay=False, help="README.md文件路径"),
|
||
output_dir: Optional[Path] = typer.Option(None, "--output", "-o", help="输出根目录,默认为readme所在目录"),
|
||
api_key: Optional[str] = typer.Option(None, "--api-key", envvar="DEEPSEEK_APIKEY", help="API密钥,也可通过环境变量DEEPSEEK_APIKEY设置"),
|
||
base_url: str = typer.Option("https://api.deepseek.com", "--base-url", help="API基础URL"),
|
||
model: str = typer.Option("deepseek-reasoner", "--model", "-m", help="使用的模型"),
|
||
log_file: Optional[str] = typer.Option(None, "--log", help="日志文件路径(默认输出目录下generator.log)"),
|
||
):
|
||
"""
|
||
根据README自动生成项目代码
|
||
"""
|
||
if output_dir is None:
|
||
output_dir = readme.parent
|
||
|
||
try:
|
||
generator = CodeGenerator(
|
||
api_key=api_key,
|
||
base_url=base_url,
|
||
model=model,
|
||
output_dir=output_dir,
|
||
log_file=log_file,
|
||
)
|
||
generator.run(readme)
|
||
except Exception as e:
|
||
logger.error(f"程序异常退出: {e}")
|
||
raise typer.Exit(code=1)
|
||
|
||
if __name__ == "__main__":
|
||
app()
|
||
```
|
||
|
||
|
||
## ✨ 核心特性
|
||
|
||
- 📦 **自动生成**:解析 `README.md`,分析需要生成的文件列表及依赖关系,按顺序生成每个文件的代码。
|
||
- 📋 **中间设计层**:生成一个 `design.json` 文件,包含项目结构、文件关联、功能摘要等信息。后续所有代码生成均以该 JSON + README 作为上下文,确保 LLM 始终理解全局设计。
|
||
- 🧩 **增量功能开发**:通过编写**需求工单**(如 `feature.issue`),描述新增功能,工具自动分析现有代码并生成新增或修改的文件。
|
||
- 🐞 **自动 Bug 修复**:通过编写**Bug 工单**(如 `bug.issue`),描述问题现象,工具结合代码和错误信息生成修复补丁。
|
||
- 🔧 **命令执行**:生成文件后可自动执行建议命令(如安装依赖、运行构建),内置危险命令拦截(执行命令失败不会终止任务,仅记录错误)。
|
||
- ✅ **单元测试**:使用 `pytest` 编写测试用例,支持测试覆盖率统计。
|
||
- 🔍 **并行检查**:生成代码后并行运行多个检查工具(`pylint`、`mypy`、`black` 等),收集错误信息。
|
||
- 🔄 **自修复**:将检查错误、README、design.json 和相关代码提交给 LLM,自动生成修复补丁并应用。
|
||
- ⏯️ **断点续写**:生成过程中断后可自动从上次中断处继续,状态保存在 `.llm_generator_state.json`。
|
||
- 🖥️ **命令行工具**:提供 `llm-codegen` 命令,支持多种操作模式。
|
||
- 📝 **详细日志**:所有操作、LLM 响应、错误均通过 `loguru` 记录到文件。
|
||
- 🎨 **美观输出**:使用 `rich` 显示进度条和彩色状态。
|
||
|
||
## 🚀 安装
|
||
|
||
### 依赖
|
||
- Python 3.9+
|
||
- 使用 `uv` 管理包
|
||
|
||
```bash
|
||
# 安装依赖
|
||
uv add [dev]
|
||
```
|
||
|
||
### 配置 API 密钥
|
||
设置环境变量(推荐):
|
||
```bash
|
||
export DEEPSEEK_APIKEY="your-api-key"
|
||
```
|
||
或在命令行中通过 `--api-key` 传入。
|
||
|
||
## 📖 使用方法
|
||
|
||
工具支持三种操作模式,通过子命令区分:
|
||
|
||
```bash
|
||
llm-codegen init README.md # 从零初始化项目
|
||
llm-codegen enhance feature.issue # 根据需求工单增强项目
|
||
llm-codegen fix bug.issue # 根据Bug工单修复项目
|
||
```
|
||
|
||
### 1. 初始化项目 (`init`)
|
||
|
||
根据 `README.md` 生成完整的项目骨架和代码。
|
||
|
||
```bash
|
||
llm-codegen init path/to/README.md -o ./generated
|
||
```
|
||
|
||
**流程**:
|
||
- 读取 `README.md`,调用 LLM 生成**中间设计文件** `design.json`(位于输出目录)。
|
||
- 基于 `design.json` 和 `README.md` 按顺序生成每个文件。
|
||
- 生成完成后执行可选命令、检查和自动修复。
|
||
|
||
### 2. 增强项目 (`enhance`)
|
||
|
||
当已有项目需要添加新功能时,编写一个**需求工单**(如 `add-logging.issue`),然后运行:
|
||
|
||
```bash
|
||
llm-codegen enhance add-logging.issue -o ./project
|
||
```
|
||
|
||
**需求工单模板**(`feature.issue`):
|
||
```yaml
|
||
# 需求工单示例
|
||
name: 添加日志记录功能
|
||
description: 为所有核心函数增加日志输出,记录调用参数和执行时间。
|
||
affected_files:
|
||
- src/llm_codegen/core.py
|
||
- src/llm_codegen/utils.py
|
||
acceptance_criteria:
|
||
- 每个公共函数应记录开始和结束日志
|
||
- 日志级别为 INFO,包含函数名和参数
|
||
- 使用 loguru 记录
|
||
```
|
||
|
||
工具会自动:
|
||
- 读取现有项目的 `design.json` 和代码。
|
||
- 分析需求,确定需要修改的文件。
|
||
- 生成代码变更(新增或修改文件)。
|
||
- 执行检查和修复。
|
||
|
||
### 3. 修复 Bug (`fix`)
|
||
|
||
发现 Bug 时,编写一个**Bug 工单**(如 `crash-on-empty.issue`),然后运行:
|
||
|
||
```bash
|
||
llm-codegen fix crash-on-empty.issue -o ./project
|
||
```
|
||
|
||
**Bug 工单模板**(`bug.issue`):
|
||
```yaml
|
||
# Bug 工单示例
|
||
name: 当输入为空时程序崩溃
|
||
description: 调用 parse_readme 时若 README 为空文件,抛出未处理的 IndexError。
|
||
steps_to_reproduce:
|
||
- 创建空文件 empty.md
|
||
- 运行 llm-codegen init empty.md
|
||
expected_behavior: 应给出友好提示并退出。
|
||
actual_behavior: 抛出 IndexError 并打印堆栈。
|
||
affected_files:
|
||
- src/llm_codegen/core.py
|
||
```
|
||
|
||
工具会自动:
|
||
- 定位相关代码。
|
||
- 结合错误信息生成修复方案。
|
||
- 应用补丁,并重新运行测试验证。
|
||
|
||
## 🧠 中间设计层 (`design.json`)
|
||
|
||
`design.json` 是工具与 LLM 之间的“通用语言”,它记录了项目的完整设计蓝图,结构如下:
|
||
|
||
```json
|
||
{
|
||
"project_name": "MyProject",
|
||
"version": "1.0.0",
|
||
"description": "项目简短描述",
|
||
"files": [
|
||
{
|
||
"path": "src/llm_codegen/core.py",
|
||
"summary": "核心生成逻辑,包含 CodeGenerator 类",
|
||
"dependencies": ["src/llm_codegen/utils.py"],
|
||
"functions": [
|
||
{
|
||
"name": "generate_file",
|
||
"summary": "生成单个文件,返回代码和命令",
|
||
"inputs": ["file_path", "prompt", "deps"],
|
||
"outputs": ["code", "commands"]
|
||
}
|
||
],
|
||
"classes": [...]
|
||
}
|
||
],
|
||
"commands": [
|
||
"pip install -e .",
|
||
"pytest tests/"
|
||
],
|
||
"check_tools": ["pytest", "pylint", "mypy"]
|
||
}
|
||
```
|
||
|
||
该文件由 LLM 在 `init` 阶段生成,并在后续所有操作中作为上下文提供给 LLM,确保每次生成都符合整体设计。
|
||
|
||
|
||
## 🔄 核心工作流
|
||
|
||
### 初始化流程
|
||
1. 读取 `README.md`,调用 LLM 生成 `design.json`。
|
||
2. 解析 `design.json`,获得文件列表和依赖关系。
|
||
3. 按顺序生成每个文件,生成时上下文包括:
|
||
- `README.md`
|
||
- `design.json`
|
||
- 已生成的依赖文件内容
|
||
4. 执行文件关联的命令(如安装依赖)。
|
||
5. (可选)运行检查工具,若有错误则触发自修复。
|
||
|
||
### 增强/修复流程
|
||
1. 读取项目根目录下的 `design.json` 和现有代码。
|
||
2. 解析需求/缺陷工单,识别受影响文件。
|
||
3. 调用 LLM 生成代码变更(可新增文件或修改现有文件),上下文包括:
|
||
- `README.md`
|
||
- `design.json`
|
||
- 所有受影响文件的当前内容
|
||
- 工单内容
|
||
4. 应用变更,更新 `design.json` 中的摘要(如果新增了函数/类)。
|
||
5. 执行检查与修复。
|
||
|
||
## 📝 工单模板
|
||
|
||
### 需求工单 (`feature.issue`)
|
||
```yaml
|
||
name: <功能名称>
|
||
description: <详细描述>
|
||
affected_files: # 可能影响到的文件(可选,留空则让 LLM 自动分析)
|
||
- path/to/file1.py
|
||
- path/to/file2.py
|
||
acceptance_criteria: # 验收条件(列表)
|
||
- 条件1
|
||
- 条件2
|
||
```
|
||
|
||
### Bug 工单 (`bug.issue`)
|
||
```yaml
|
||
name: <Bug 标题>
|
||
description: <详细描述>
|
||
steps_to_reproduce: # 复现步骤
|
||
- 步骤1
|
||
- 步骤2
|
||
expected_behavior: <期望行为>
|
||
actual_behavior: <实际行为>
|
||
affected_files: # 可能相关的文件(可选)
|
||
- path/to/file.py
|
||
```
|
||
|
||
## ⚙️ 配置
|
||
|
||
通过 `pyproject.toml` 的 `[tool.llm-codegen]` 部分自定义行为:
|
||
|
||
```toml
|
||
[tool.llm-codegen]
|
||
check_tools = ["pytest", "pylint", "mypy", "black"]
|
||
max_retries = 3
|
||
dangerous_commands = ["rm", "sudo", "chmod", "dd"]
|
||
```
|
||
|
||
## 🛠️ 开发指南
|
||
|
||
### 环境设置
|
||
```bash
|
||
# 安装 uv
|
||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||
|
||
# 创建虚拟环境并激活
|
||
uv venv
|
||
source .venv/bin/activate
|
||
|
||
# 安装项目(可编辑模式)和开发依赖
|
||
uv pip install -e ".[dev]"
|
||
```
|
||
|
||
## 项目结构
|
||
|
||
生成的项目将包含以下文件和目录:
|
||
```txt
|
||
.
|
||
├── README.md # 项目说明(原始输入)
|
||
├── pyproject.toml # 项目元数据、依赖、脚本入口
|
||
├── src/
|
||
│ └── llm_codegen/ # 主代码包
|
||
│ ├── __init__.py
|
||
│ ├── cli.py # 命令行入口(typer)
|
||
│ ├── core.py # 核心生成逻辑(CodeGenerator 类)
|
||
│ ├── checker.py # 并行检查与修复模块
|
||
│ ├── utils.py # 工具函数(危险命令判断、文件操作)
|
||
│ └── models.py # 数据模型(Pydantic)
|
||
├── tests/ # 单元测试
|
||
│ ├── __init__.py
|
||
│ ├── test_cli.py
|
||
│ ├── test_core.py
|
||
│ └── test_checker.py
|
||
└── logs/ # 运行日志(自动创建)
|
||
```
|
||
|
||
### 运行测试
|
||
```bash
|
||
pytest tests/
|
||
```
|
||
|
||
### 编写工单示例
|
||
项目生成后,`issues/` 目录下会包含示例工单文件,可参考编写。
|
||
|
||
## 📌 注意事项
|
||
|
||
- 中间设计文件 `design.json` 是核心资产,请勿手动修改(除非你完全理解设计意图),否则可能导致后续生成偏差。
|
||
- 断点续写状态文件 `.llm_generator_state.json` 自动管理,无需手动干预。
|
||
- 若 `README.md` 或 `design.json` 发生重大变更导致结构不一致,工具会提示并建议重新初始化。
|
||
|
||
---
|
||
|
||
通过引入中间设计层和工单驱动机制,本工具不仅实现了从零生成,更成为项目的“AI 协作者”,能够持续参与功能迭代与缺陷修复,大幅提升开发效率。
|