ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

第4讲:自然语言转代码

2026/8/8 5:01:53 拓冰建站 浏览量
第4讲:自然语言转代码 第3讲我们实现了代码补全——当开发者敲代码时MiniCopilot 能预测接下来要写什么。但有时候开发者不想逐行敲代码而是想用自然语言描述需求让 AI 直接生成代码。这一讲我们要实现 MiniCopilot 的第二个核心能力自然语言转代码NL2Code。一、NL2Code 的核心挑战挑战说明意图理解​用户的自然语言描述可能模糊、不完整代码准确性​生成的代码必须语法正确、逻辑合理上下文感知​要理解项目现有的代码风格、使用的框架多轮迭代​用户可能不满意第一次结果需要修改NL2Code 流程用户输入写一个函数读取 CSV 文件并返回平均值 ↓ 1. 意图分析Orchestrator Agent ├── 任务类型函数生成 ├── 输入CSV 文件路径 ├── 输出数值平均值 └── 约束需要错误处理 ↓ 2. 上下文收集Research Agent ├── 项目中已有的 CSV 处理方式 ├── 常用的库pandas / csv └── 代码风格约定 ↓ 3. 代码生成Coding Agent ├── 生成初始版本 ├── Review Agent 审查 └── 迭代修改 ↓ 4. 返回结果 插入位置建议二、意图分析模块2.1 任务分类器# engine/nl2code/intent_classifier.py from enum import Enum from typing import Optional import re class TaskType(Enum): CREATE_FUNCTION create_function CREATE_CLASS create_class WRITE_TEST write_test FIX_BUG fix_bug REFACTOR refactor ADD_COMMENT add_comment EXPLAIN_CODE explain_code QUERY_DATA query_data OTHER other class IntentClassifier: 意图分类器识别用户想要做什么 # 关键词模式 PATTERNS { TaskType.CREATE_FUNCTION: [ r写(一?个)?函数, r创建(一?个)?函数, r定义(一?个)?函数, r实现.*功能, r写一段代码.*(用于|来), r生成.*函数, r编写.*方法, ], TaskType.CREATE_CLASS: [ r写(一?个)?类, r创建(一?个)?类, r定义(一?个)?类, r实现.*类, r设计.*类, ], TaskType.WRITE_TEST: [ r(写|生成|创建)(单元)?测试, rtest.*用例, r为.*写测试, r测试.*函数, ], TaskType.FIX_BUG: [ r(修|改|修复).*(bug|错误|问题|异常), r这个.*不对, r出错了, r报错, ], TaskType.REFACTOR: [ r重构, r优化, r改写, r重写, r改进.*代码, r让.*更好, ], TaskType.ADD_COMMENT: [ r加(注?释|评论), r写(注?释|文档), r生成.*文档, r添加.*说明, ], TaskType.EXPLAIN_CODE: [ r解释.*代码, r这段代码.*意思, r说明.*作用, r分析.*代码, ], } def classify(self, user_input: str) - tuple[TaskType, dict]: 分类用户意图 返回(任务类型, 提取的参数) user_input user_input.lower() for task_type, patterns in self.PATTERNS.items(): for pattern in patterns: if re.search(pattern, user_input): params self._extract_params(user_input, task_type) return task_type, params return TaskType.OTHER, {} def _extract_params(self, text: str, task_type: TaskType) - dict: 提取任务参数 params {} # 提取函数名 func_match re.search(r(?:函数|方法|功能)\s*[叫称]?\s*[\《]?(\w)[\》]?, text) if func_match: params[function_name] func_match.group(1) # 提取类名 class_match re.search(r(?:类)\s*[叫称]?\s*[\《]?(\w)[\》]?, text) if class_match: params[class_name] class_match.group(1) # 提取输入输出 input_match re.search(r(?:输入|传入|接收|参数)[:\s]*(\w), text) if input_match: params[input] input_match.group(1) output_match re.search(r(?:输出|返回|结果)[:\s]*(\w), text) if output_match: params[output] output_match.group(1) # 提取文件名 file_match re.search(r[\《]([\w./\\])[\》], text) if file_match: params[file] file_match.group(1) return params2.2 需求细化器# engine/nl2code/requirement_refiner.py import requests import json class RequirementRefiner: 需求细化器将模糊的自然语言转化为结构化需求 def __init__(self, api_key: str): self.api_key api_key def refine(self, user_input: str, context: dict None) - dict: 细化用户需求 返回结构化需求 { task: create_function, name: calculate_average, inputs: [{name: file_path, type: str}], output: {type: float}, logic: 读取 CSV 文件计算某一列的平均值, constraints: [处理文件不存在的情况, 支持指定列名], language: python, libraries: [csv, pandas] } prompt self._build_prompt(user_input, context) response requests.post( https://api.deepseek.com/v1/chat/completions, headers{Authorization: fBearer {self.api_key}}, json{ model: deepseek-chat, messages: [ {role: system, content: 你是一个软件需求分析师。将用户的自然语言需求转化为结构化的代码生成规格说明。输出 JSON 格式。}, {role: user, content: prompt} ], response_format: {type: json_object}, temperature: 0.2 } ) result response.json() content result[choices][0][message][content] try: return json.loads(content) except: return { task: unknown, raw_description: user_input, error: 无法解析需求 } def _build_prompt(self, user_input: str, context: dict None) - str: 构建细化需求的 prompt context_str if context: context_str f 项目上下文 - 语言: {context.get(language, python)} - 框架: {context.get(framework, 无)} - 已有代码风格: {context.get(style, 未知)} return f请将以下用户需求细化为结构化的代码生成规格。 用户需求{user_input} {context_str} 请输出 JSON 格式包含 - task: 任务类型 (create_function/create_class/write_test/fix_bug/refactor) - name: 生成的代码实体名称 - inputs: 输入参数列表 [{name, type, description}] - output: 输出 {{type, description}} - logic: 核心逻辑描述 - constraints: 约束条件列表 - language: 编程语言 - libraries: 需要用到的库列表 - edge_cases: 需要考虑的边界情况 三、代码生成器3.1 基础代码生成器# engine/nl2code/generator.py import requests import json from typing import Optional class CodeGenerator: 代码生成器 def __init__(self, api_key: str): self.api_key api_key def generate(self, requirement: dict, context_code: str ) - dict: 根据需求生成代码 返回 { code: 生成的代码, explanation: 代码说明, insertion_point: 建议插入位置, dependencies: [需要的依赖] } prompt self._build_generation_prompt(requirement, context_code) response requests.post( https://api.deepseek.com/v1/chat/completions, headers{Authorization: fBearer {self.api_key}}, json{ model: deepseek-coder, messages: [ {role: system, content: self._get_system_prompt(requirement[language])}, {role: user, content: prompt} ], temperature: 0.3, max_tokens: 2048 } ) result response.json() content result[choices][0][message][content] return self._parse_response(content) def _get_system_prompt(self, language: str) - str: 获取系统提示词 return f你是一个专业的 {language} 开发者。请根据需求生成高质量的代码。 要求 1. 代码必须语法正确可直接运行 2. 遵循 {language} 的最佳实践和命名规范 3. 包含完整的类型注解如果语言支持 4. 包含 docstring/注释说明 5. 处理边界情况和错误 6. 代码风格统一 输出格式{language}// 代码--- 简要说明代码的设计思路和用法 --- 需要的依赖包如果有 def _build_generation_prompt(self, requirement: dict, context_code: str) - str: 构建生成 prompt parts [f请生成以下需求的代码\n] parts.append(f任务类型{requirement.get(task, unknown)}) parts.append(f名称{requirement.get(name, unnamed)}) if requirement.get(inputs): parts.append(\n输入参数) for inp in requirement[inputs]: parts.append(f - {inp.get(name)}: {inp.get(type)} ({inp.get(description, )})) if requirement.get(output): parts.append(f\n输出{requirement[output].get(type)} - {requirement[output].get(description, )}) parts.append(f\n核心逻辑{requirement.get(logic, )}) if requirement.get(constraints): parts.append(\n约束条件) for c in requirement[constraints]: parts.append(f - {c}) if requirement.get(libraries): parts.append(f\n推荐库{, .join(requirement[libraries])}) if requirement.get(edge_cases): parts.append(\n边界情况) for e in requirement[edge_cases]: parts.append(f - {e}) if context_code: parts.append(f\n\n现有代码上下文\n{requirement.get(language, python)}\n{context_code}\n) return \n.join(parts) def _parse_response(self, content: str) - dict: 解析 LLM 响应 result { code: , explanation: , dependencies: [] } # 提取代码块 code_match re.search(r(?:\w)?\n(.*?), content, re.DOTALL) if code_match: result[code] code_match.group(1).strip() # 提取说明在 --- 之后 parts content.split(---) if len(parts) 1: result[explanation] parts[-1].strip() # 提取依赖 dep_match re.search(r(?:依赖|requirements|dependencies)[:]\s*(.?)(?:\n|$), content) if dep_match: deps dep_match.group(1).strip() result[dependencies] [d.strip() for d in deps.split(,)] return result3.2 代码生成器增强版带审查# engine/nl2code/enhanced_generator.py from .generator import CodeGenerator class EnhancedCodeGenerator: 增强版代码生成器带自我审查 def __init__(self, api_key: str): self.generator CodeGenerator(api_key) def generate_with_review(self, requirement: dict, context_code: str , max_iterations: int 3) - dict: 生成代码并进行自我审查和改进 流程 1. 生成初始版本 2. 审查代码检查 Bug、安全问题、性能问题 3. 如果需要改进重新生成 4. 重复直到满意或达到最大迭代次数 best_result None best_score -1 for i in range(max_iterations): print(f 第 {i1} 轮生成...) # 生成代码 result self.generator.generate(requirement, context_code) # 审查代码 review self._review_code(result[code], requirement[language]) result[review] review result[iteration] i 1 # 评分 score self._calculate_score(review) result[score] score if score best_score: best_score score best_result result # 如果评分足够高提前结束 if score 90: print(f✅ 代码质量优秀{score}分停止迭代) break # 将审查意见加入需求用于下一轮改进 if i max_iterations - 1: requirement[_previous_feedback] review[issues] print(f 发现 {len(review[issues])} 个问题继续改进...) return best_result def _review_code(self, code: str, language: str) - dict: 审查代码质量 issues [] suggestions [] # 1. 语法检查简单 if not code or len(code.strip()) 0: issues.append(代码为空) return {issues: issues, suggestions: [], quality: 0} # 2. 缺少 docstring if language python and not in code and not in code: suggestions.append(建议添加 docstring 说明函数用途) # 3. 缺少类型注解 if language python: func_defs re.findall(rdef \w\((.*?)\):, code) for params in func_defs: if params and : not in params: suggestions.append(建议为参数添加类型注解) # 4. 硬编码值 hardcoded re.findall(r(?![\])\b\d{4,}\b(?![\]), code) if hardcoded: suggestions.append(f存在硬编码数值: {hardcoded[:3]}建议定义为常量) # 5. 空的 except if re.search(rexcept\s*:, code): issues.append(使用裸 except建议指定异常类型) # 6. 过长的函数 lines code.split(\n) if len(lines) 50: suggestions.append(f函数过长{len(lines)}行建议拆分为多个小函数) # 计算质量分数 quality max(0, 100 - len(issues) * 15 - len(suggestions) * 5) return { issues: issues, suggestions: suggestions, quality: quality } def _calculate_score(self, review: dict) - int: 计算综合评分 return review.get(quality, 0)四、上下文集成4.1 项目上下文收集# engine/nl2code/context_collector.py import os from typing import Optional class ProjectContextCollector: 项目上下文收集器 def __init__(self, project_root: str): self.project_root project_root def collect(self, current_file: str ) - dict: 收集项目上下文 返回 { language: python, framework: fastapi, style: google style, imports: [os, sys, fastapi], recent_files: [...], similar_functions: [...] } context { language: self._detect_language(current_file), framework: self._detect_framework(), style: self._detect_code_style(), imports: [], recent_files: [], similar_functions: [] } # 收集 imports if current_file and os.path.exists(current_file): with open(current_file, r) as f: content f.read() context[imports] self._extract_imports(content) # 收集最近修改的文件 context[recent_files] self._get_recent_files() return context def _detect_language(self, file_path: str) - str: 检测编程语言 ext_map { .py: python, .js: javascript, .ts: typescript, .java: java, .go: go, .rs: rust, .cpp: cpp, .c: c, } _, ext os.path.splitext(file_path) return ext_map.get(ext, python) def _detect_framework(self) - str: 检测使用的框架 indicators { fastapi: [fastapi, FastAPI], flask: [flask, Flask], django: [django, Django], react: [react, React, jsx], vue: [vue, Vue], } for framework, keywords in indicators.items(): for keyword in keywords: if self._search_in_project(keyword): return framework return unknown def _detect_code_style(self) - str: 检测代码风格 # 检查是否有类型注解 py_files self._find_files(*.py) has_types False has_google_docstring False for f in py_files[:10]: with open(f, r) as fh: content fh.read() if : in content and def in content: has_types True if Args: in content or Returns: in content: has_google_docstring True if has_google_docstring: return google style elif has_types: return modern python else: return simple def _extract_imports(self, content: str) - list[str]: 提取 import 语句 imports [] for line in content.split(\n): line line.strip() if line.startswith(import ) or line.startswith(from ): imports.append(line) return imports def _get_recent_files(self, count: int 5) - list[str]: 获取最近修改的文件 files [] for root, dirs, filenames in os.walk(self.project_root): for filename in filenames: if filename.endswith((.py, .js, .ts, .java)): filepath os.path.join(root, filename) files.append((filepath, os.path.getmtime(filepath))) files.sort(keylambda x: x[1], reverseTrue) return [f[0] for f in files[:count]] def _search_in_project(self, keyword: str) - bool: 在项目中搜索关键字 for root, dirs, filenames in os.walk(self.project_root): for filename in filenames: if filename.endswith((.py, .txt, .cfg, .toml)): filepath os.path.join(root, filename) try: with open(filepath, r, errorsignore) as f: if keyword in f.read(): return True except: continue return False def _find_files(self, pattern: str) - list[str]: 查找匹配的文件 import glob return glob.glob(os.path.join(self.project_root, **, pattern), recursiveTrue)五、完整 NL2Code 管道# engine/nl2code/pipeline.py from .intent_classifier import IntentClassifier from .requirement_refiner import RequirementRefiner from .generator import CodeGenerator from .enhanced_generator import EnhancedCodeGenerator from .context_collector import ProjectContextCollector class NL2CodePipeline: 自然语言转代码完整管道 def __init__(self, api_key: str, project_root: str .): self.classifier IntentClassifier() self.refiner RequirementRefiner(api_key) self.generator EnhancedCodeGenerator(api_key) self.context_collector ProjectContextCollector(project_root) def execute(self, user_input: str, current_file: str , selected_code: str ) - dict: 执行 NL2Code 完整流程 参数 user_input: 用户的自然语言描述 current_file: 当前编辑的文件路径 selected_code: 用户选中的代码如果有 返回 { requirement: {...}, # 结构化需求 code: ..., # 生成的代码 explanation: ..., # 代码说明 review: {...}, # 审查结果 insertion_point: ..., # 建议插入位置 confidence: 0.95 # 置信度 } print(f\n 用户需求: {user_input}) # 1. 意图分类 task_type, params self.classifier.classify(user_input) print(f 识别任务: {task_type.value}) # 2. 收集上下文 context self.context_collector.collect(current_file) if selected_code: context[selected_code] selected_code print(f 项目语言: {context[language]}, 框架: {context[framework]}) # 3. 需求细化 requirement self.refiner.refine(user_input, context) requirement[task] task_type.value requirement[language] context[language] print(f 需求规格: {requirement.get(name, 未命名)}) # 4. 代码生成带审查 result self.generator.generate_with_review(requirement, selected_code) # 5. 确定插入位置 result[insertion_point] self._determine_insertion_point( requirement, current_file, selected_code ) # 6. 计算置信度 result[confidence] self._calculate_confidence(result) return result def _determine_insertion_point(self, requirement: dict, current_file: str, selected_code: str) - str: 确定代码插入位置 if selected_code: return replace_selection if requirement.get(task) create_function: return end_of_file elif requirement.get(task) create_class: return end_of_file elif requirement.get(task) fix_bug: return replace_current else: return cursor_position def _calculate_confidence(self, result: dict) - float: 计算置信度 base 0.8 # 有审查且问题少则加分 review result.get(review, {}) issues_count len(review.get(issues, [])) base - issues_count * 0.05 # 有解释则加分 if result.get(explanation): base 0.05 # 有依赖信息则加分 if result.get(dependencies): base 0.02 return max(0.1, min(1.0, base))六、完整测试# test_nl2code.py from engine.nl2code.pipeline import NL2CodePipeline import json # 初始化 api_key your-api-key pipeline NL2CodePipeline(api_key, project_root./my_project) # 测试1创建函数 print( * 60) print(测试1创建函数) print( * 60) result pipeline.execute( 写一个函数读取 CSV 文件并计算某一列的平均值需要处理文件不存在的情况, current_file./my_project/data_processor.py ) print(f\n 置信度: {result[confidence]:.2%}) print(f 插入位置: {result[insertion_point]}) print(f\n 生成的代码:\n{result[code]}) if result.get(explanation): print(f\n 说明:\n{result[explanation]}) if result.get(review, {}).get(issues): print(f\n⚠️ 审查发现的问题:) for issue in result[review][issues]: print(f - {issue}) # 测试2修复 Bug print(\n * 60) print(测试2修复 Bug) print( * 60) buggy_code def divide(a, b): return a / b result pipeline.execute( 这个函数除以零会崩溃帮我加上错误处理, selected_codebuggy_code ) print(f\n 置信度: {result[confidence]:.2%}) print(f\n 修复后的代码:\n{result[code]}) # 测试3生成测试 print(\n * 60) print(测试3生成测试) print( * 60) target_code def fibonacci(n): if n 0: return 0 elif n 1: return 1 else: return fibonacci(n-1) fibonacci(n-2) result pipeline.execute( 为这个斐波那契函数生成单元测试覆盖正常情况和边界情况, selected_codetarget_code ) print(f\n 置信度: {result[confidence]:.2%}) print(f\n 生成的测试:\n{result[code]})七、性能优化与最佳实践7.1 流式输出对于较长的代码生成可以使用流式输出让用户看到生成过程# engine/nl2code/stream_generator.py import requests import json from typing import Generator class StreamCodeGenerator: 流式代码生成器 def __init__(self, api_key: str): self.api_key api_key def generate_stream(self, requirement: dict) - Generator[str, None, None]: 流式生成代码 prompt self._build_prompt(requirement) response requests.post( https://api.deepseek.com/v1/chat/completions, headers{Authorization: fBearer {self.api_key}}, json{ model: deepseek-coder, messages: [ {role: system, content: 你是一个代码生成器。生成完整可运行的代码。}, {role: user, content: prompt} ], stream: True, temperature: 0.3 }, streamTrue ) for line in response.iter_lines(): if line: line line.decode(utf-8) if line.startswith(data: ): data line[6:] if data ! [DONE]: try: chunk json.loads(data) if chunk[choices][0][delta].get(content): yield chunk[choices][0][delta][content] except: continue7.2 代码模板缓存# engine/nl2code/template_cache.py import hashlib import json from pathlib import Path class TemplateCache: 代码模板缓存 def __init__(self, cache_dir: str .cache/templates): self.cache_dir Path(cache_dir) self.cache_dir.mkdir(parentsTrue, exist_okTrue) def _make_key(self, requirement: dict) - str: content json.dumps(requirement, sort_keysTrue) return hashlib.md5(content.encode()).hexdigest() def get(self, requirement: dict) - dict: 获取缓存的代码 key self._make_key(requirement) cache_file self.cache_dir / f{key}.json if cache_file.exists(): with open(cache_file, r) as f: return json.load(f) return None def set(self, requirement: dict, result: dict): 缓存代码 key self._make_key(requirement) cache_file self.cache_dir / f{key}.json with open(cache_file, w) as f: json.dump(result, f)八、常见错误 排坑指南生成的代码不符合项目风格原因没有提供足够的项目上下文解决在 prompt 中包含更多项目代码示例生成的代码过于冗长原因LLM 倾向于生成完整的、带大量注释的代码解决在 prompt 中指定“保持简洁只生成必要的代码”多轮对话中遗忘上下文原因每次调用都是独立的没有维护历史解决将对话历史压缩后加入 prompt生成的代码使用了不存在的库原因LLM 的知识截止日期之后的新库解决在 prompt 中指定允许使用的库列表九、课后作业实现代码解释器让用户选中一段代码AI 用自然语言解释它的作用。添加代码转换功能支持“把这段 Python 代码转换成 JavaScript”。挑战题实现“多步代码生成”——用户说“创建一个 REST API包含用户 CRUD 操作”系统自动生成完整的项目结构路由、模型、控制器。十、总结这一讲我们实现了自然语言转代码的完整管道意图分类识别用户想做什么创建函数、修复 Bug、生成测试等需求细化将模糊的自然语言转化为结构化需求规格代码生成利用 LLM 生成高质量代码自我审查自动检查代码质量问题并迭代改进上下文集成理解项目使用的语言、框架、代码风格现在MiniCopilot 不仅能补全代码还能根据自然语言描述直接生成代码。下一讲我们将实现代码审查与 Bug 检测——让 MiniCopilot 能自动发现代码中的问题。