29.4 代码理解模块
第 29 章 · 构建自己的编程 Agent · 第8部分:Claude Code 原理与技术
29.4.1 代码理解概述#
代码理解模块是编程 Agent 的另一个核心能力,它能够分析、解释和理解现有代码的功能、结构和设计。代码理解涉及代码解析、语义分析、依赖分析等多个环节。
代码理解流程#
输入代码 ↓ 代码解析 ↓ 结构分析 ↓ 语义分析 ↓ 依赖分析 ↓ 功能推断 ↓ 生成解释
29.4.2 代码解析#
代码解析器#
python复制python classCodeParser:"""代码解析器""" def__init__(self): self.parsers ={'python': PythonParser(),'javascript': JavaScriptParser(),'java': JavaParser(),'cpp': CppParser()} defparse(self, code:str, language:str)-> ParsedCode:"""解析代码""" parser = self.parsers.get(language.lower()) ifnot parser:raise ValueError(f"Unsupported language: {language}") return parser.parse(code) classPythonParser:"""Python 解析器""" defparse(self, code:str)-> ParsedCode:"""解析 Python 代码"""try: tree = ast.parse(code) parsed_code = ParsedCode( language='python', original_code=code, ast=tree ) # 提取类 parsed_code.classes = self._extract_classes(tree) # 提取函数 parsed_code.functions = self._extract_functions(tree) # 提取导入 parsed_code.imports = self._extract_imports(tree) # 提取全局变量 parsed_code.global_variables = self._extract_global_variables(tree) return parsed_code except SyntaxError as e:raise ValueError(f"Invalid Python code: {e}") def_extract_classes(self, tree: ast.AST)-> List[ClassInfo]:"""提取类信息""" classes =[] for node in ast.walk(tree):ifisinstance(node, ast.ClassDef): class_info = ClassInfo( name=node.name, bases=[self._get_name(base)for base in node.bases], methods=[self._extract_method(m)for m in node.body ifisinstance(m, ast.FunctionDef)], attributes=[self._extract_attribute(a)for a in node.body ifisinstance(a, ast.Assign)], docstring=ast.get_docstring(node)) classes.append(class_info) return classes def_extract_functions(self, tree: ast.AST)-> List[FunctionInfo]:"""提取函数信息""" functions =[] for node in ast.walk(tree):ifisinstance(node, ast.FunctionDef):# 跳过类中的方法ifnotany(isinstance(parent, ast.ClassDef)for parent in ast.walk(tree)if node in ast.iter_child_nodes(parent)): function_info = FunctionInfo( name=node.name, arguments=[arg.arg for arg in node.args.args], return_type=self._get_return_type(node), docstring=ast.get_docstring(node), decorators=[self._get_name(d)for d in node.decorator_list]) functions.append(function_info) return functions def_extract_imports(self, tree: ast.AST)-> List[ImportInfo]:"""提取导入信息""" imports =[] for node in ast.walk(tree):ifisinstance(node, ast.Import):for alias in node.names: import_info = ImportInfo( module=alias.name, alias=alias.asname,type='import') imports.append(import_info)elifisinstance(node, ast.ImportFrom):for alias in node.names: import_info = ImportInfo( module=node.module, name=alias.name, alias=alias.asname,type='from') imports.append(import_info) return imports def_extract_global_variables(self, tree: ast.AST)-> List[VariableInfo]:"""提取全局变量""" variables =[] for node in ast.walk(tree):ifisinstance(node, ast.Assign):# 只提取模块级别的变量ifisinstance(node, ast.Module):for target in node.targets:ifisinstance(target, ast.Name): var_info = VariableInfo( name=target.id,type=self._infer_type(node.value), value=self._get_value(node.value)) variables.append(var_info) return variables def_extract_method(self, node: ast.FunctionDef)-> MethodInfo:"""提取方法信息"""return MethodInfo( name=node.name, arguments=[arg.arg for arg in node.args.args], return_type=self._get_return_type(node), docstring=ast.get_docstring(node), is_static=any(isinstance(d, ast.Name)and d.id=='staticmethod'for d in node.decorator_list), is_classmethod=any(isinstance(d, ast.Name)and d.id=='classmethod'for d in node.decorator_list)) def_extract_attribute(self, node: ast.Assign)-> AttributeInfo:"""提取属性信息""" target = node.targets[0]ifisinstance(target, ast.Name):return AttributeInfo( name=target.id,type=self._infer_type(node.value), value=self._get_value(node.value))returnNone def_get_name(self, node: ast.AST)->str:"""获取节点名称"""ifisinstance(node, ast.Name):return node.idelifisinstance(node, ast.Attribute):returnf"{self._get_name(node.value)}.{node.attr}"returnstr(node) def_get_return_type(self, node: ast.FunctionDef)->str:"""获取返回类型"""if node.returns:return self._get_name(node.returns)return"None" def_infer_type(self, node: ast.AST)->str:"""推断类型"""ifisinstance(node, ast.Constant):returntype(node.value).__name__ elifisinstance(node, ast.List):return"list"elifisinstance(node, ast.Dict):return"dict"elifisinstance(node, ast.Call):return self._get_name(node.func)return"Any" def_get_value(self, node: ast.AST)-> Any:"""获取值"""ifisinstance(node, ast.Constant):return node.value returnNone ```## 29.4.3 结构分析 ### 结构分析器 classStructureAnalyzer:"""结构分析器"""defanalyze(self, parsed_code: ParsedCode)-> StructureAnalysis:"""分析代码结构"""analysis = StructureAnalysis()# 分析类的层次结构analysis.class_hierarchy = self._analyze_class_hierarchy(parsed_code.classes )# 分析函数调用关系analysis.call_graph = self._analyze_call_graph(parsed_code)# 分析模块依赖analysis.dependencies = self._analyze_dependencies(parsed_code)# 分析代码复杂度analysis.complexity = self._analyze_complexity(parsed_code)return analysis def_analyze_class_hierarchy(self,classes: List[ClassInfo])-> Dict[str, List[str]]:"""分析类层次结构"""hierarchy ={}for cls in classes:hierarchy[cls.name]= cls.bases return hierarchy def_analyze_call_graph(self,parsed_code: ParsedCode)-> Dict[str, List[str]]:"""分析函数调用关系"""call_graph ={}# 分析函数调用for func in parsed_code.functions:calls = self._extract_function_calls(func, parsed_code)call_graph[func.name]= calls # 分析方法调用for cls in parsed_code.classes:for method in cls.methods:calls = self._extract_method_calls(method, cls, parsed_code)call_graph[f"{cls.name}.{method.name}"]= calls return call_graph def_extract_function_calls(self, func: FunctionInfo,parsed_code: ParsedCode)-> List[str]:"""提取函数调用"""calls =[]# 这里需要更复杂的 AST 分析# 简化实现:从函数体中提取调用return calls def_extract_method_calls(self, method: MethodInfo,cls: ClassInfo,parsed_code: ParsedCode)-> List[str]:"""提取方法调用"""calls =[]# 这里需要更复杂的 AST 分析# 简化实现:从方法体中提取调用return calls def_analyze_dependencies(self,parsed_code: ParsedCode)-> List[Dependency]:"""分析依赖关系"""dependencies =[]# 分析导入依赖for imp in parsed_code.imports:dependency = Dependency(type='import',source=parsed_code.language,target=imp.module,strength='external')dependencies.append(dependency)# 分析类继承依赖for cls in parsed_code.classes:for base in cls.bases:dependency = Dependency(type='inheritance',source=cls.name,target=base,strength='strong')dependencies.append(dependency)return dependencies def_analyze_complexity(self,parsed_code: ParsedCode)-> ComplexityMetrics:"""分析代码复杂度"""
metrics = ComplexityMetrics()
计算圈复杂度
metrics.cyclomatic_complexity = self._calculate_cyclomatic_complexity( parsed_code )
计算认知复杂度
metrics.cognitive_complexity = self._calculate_cognitive_complexity( parsed_code )
计算维护性指数
metrics.maintainability_index = self._calculate_maintainability_index( parsed_code ) return metrics def _calculate_cyclomatic_complexity(self, parsed_code: ParsedCode) -> float: """计算圈复杂度""" complexity = 1 # 基础复杂度
遍历 AST,计算决策点
for node in ast.walk(parsed_code.ast): if isinstance(node, (ast.If, ast.While, ast.For, ast.ExceptHandler)): complexity += 1 elif isinstance(node, ast.BoolOp): complexity += len(node.values) - 1 return complexity def _calculate_cognitive_complexity(self, parsed_code: ParsedCode) -> float: """计算认知复杂度"""
简化实现
return self._calculate_cyclomatic_complexity(parsed_code) * 1.5 def _calculate_maintainability_index(self, parsed_code: ParsedCode) -> float: """计算维护性指数"""
简化实现
loc = len(parsed_code.original_code.split('\n')) complexity = self._calculate_cyclomatic_complexity(parsed_code)
MI = 171 - 5.2 * ln(V) - 0.23 * G - 16.2 * ln(L)
V = 圈复杂度, G = 代码行数, L = 代码行数
mi = 171 - 5.2 * math.log(complexity) - 0.23 * loc - 16.2 * math.log(loc) return max(0, min(100, mi))
bash复制## 29.4.4 语义分析 ### 语义分析器 ```python ```python class SemanticAnalyzer: """语义分析器""" def __init__(self, llm_client: LLMClient): self.llm_client = llm_client async def analyze(self, parsed_code: ParsedCode, structure: StructureAnalysis) -> SemanticAnalysis: """分析代码语义""" analysis = SemanticAnalysis() # 分析代码意图 analysis.purpose = await self._analyze_purpose(parsed_code) # 分析算法 analysis.algorithms = await self._analyze_algorithms(parsed_code) # 分析设计模式 analysis.design_patterns = await self._analyze_design_patterns( parsed_code, structure ) # 分析数据流 analysis.data_flow = await self._analyze_data_flow(parsed_code) return analysis async def _analyze_purpose(self, parsed_code: ParsedCode) -> str: """分析代码目的""" prompt = f""" 分析以下代码的主要目的和功能: {parsed_code.original_code} 请用简洁的语言描述这段代码的主要功能。 """ return await self.llm_client.complete(prompt) async def _analyze_algorithms(self, parsed_code: ParsedCode) -> List[AlgorithmInfo]: """分析算法""" prompt = f""" 识别以下代码中使用的算法: {parsed_code.original_code} 请识别: 1. 使用的主要算法(排序、搜索、图算法等) 2. 算法的时间复杂度 3. 算法的空间复杂度 以 JSON 格式返回结果。 """ response = await self.llm_client.complete(prompt) return self._parse_algorithms(response) async def _analyze_design_patterns(self, parsed_code: ParsedCode, structure: StructureAnalysis) -> List[str]: """分析设计模式""" prompt = f""" 识别以下代码中使用的设计模式: 类:{parsed_code.classes} 函数:{parsed_code.functions} 类层次结构:{structure.class_hierarchy} 请识别使用的设计模式。 """ response = await self.llm_client.complete(prompt) return self._parse_design_patterns(response) async def _analyze_data_flow(self, parsed_code: ParsedCode) -> DataFlowAnalysis: """分析数据流""" analysis = DataFlowAnalysis() # 分析输入 analysis.inputs = self._identify_inputs(parsed_code) # 分析输出 analysis.outputs = self._identify_outputs(parsed_code) # 分析转换 analysis.transformations = self._identify_transformations(parsed_code) return analysis def _identify_inputs(self, parsed_code: ParsedCode) -> List[str]: """识别输入""" inputs = [] # 函数参数 for func in parsed_code.functions: inputs.extend(func.arguments) # 方法参数 for cls in parsed_code.classes: for method in cls.methods: inputs.extend(method.arguments) return list(set(inputs)) def _identify_outputs(self, parsed_code: ParsedCode) -> List[str]: """识别输出""" outputs = [] # 函数返回值 for func in parsed_code.functions: if func.return_type != "None": outputs.append(f"{func.name}() -> {func.return_type}") # 方法返回值 for cls in parsed_code.classes: for method in cls.methods: if method.return_type != "None": outputs.append(f"{cls.name}.{method.name}() -> {method.return_type}") return outputs def _identify_transformations(self, parsed_code: ParsedCode) -> List[str]: """识别数据转换""" transformations = [] # 这里需要更复杂的分析 # 简化实现:基于函数名推断 for func in parsed_code.functions: if any(keyword in func.name.lower() for keyword in ['transform', 'convert', 'process', 'compute']): transformations.append(func.name) return transformations ```## 29.4.5 代码解释生成 ### 解释生成器 class ExplanationGenerator: """解释生成器""" def __init__(self, llm_client: LLMClient): self.llm_client = llm_client async def generate_explanation(self, parsed_code: ParsedCode, structure: StructureAnalysis, semantic: SemanticAnalysis) -> CodeExplanation: """生成代码解释""" explanation = CodeExplanation() # 生成总体概述 explanation.overview = await self._generate_overview( parsed_code, semantic ) # 生成类解释 explanation.class_explanations = await self._generate_class_explanations( parsed_code.classes, structure ) # 生成函数解释 explanation.function_explanations = await self._generate_function_explanations( parsed_code.functions, structure ) # 生成算法解释 explanation.algorithm_explanations = await self._generate_algorithm_explanations( semantic.algorithms ) # 生成使用示例 explanation.usage_examples = await self._generate_usage_examples( parsed_code ) return explanation async def _generate_overview(self, parsed_code: ParsedCode, semantic: SemanticAnalysis) -> str: """生成总体概述""" prompt = f""" 为以下代码生成总体概述: 代码目的:{semantic.purpose} 类:{[c.name for c in parsed_code.classes]} 函数:{[f.name for f in parsed_code.functions]} 请生成一个清晰的总体概述,包括: 1. 代码的主要功能 2. 主要组件 3. 整体架构 """ return await self.llm_client.complete(prompt) async def _generate_class_explanations(self, classes: List[ClassInfo], structure: StructureAnalysis) -> Dict[str, str]: """生成类解释""" explanations = {} for cls in classes: prompt = f""" 为以下类生成详细解释: 类名:{cls.name} 父类:{cls.bases} 方法:{[m.name for m in cls.methods]} 属性:{[a.name for a in cls.attributes if a]} 文档字符串:{cls.docstring} 请生成详细的类解释,包括: 1. 类的职责 2. 主要方法的功能 3. 使用场景 """ explanation = await self.llm_client.complete(prompt) explanations[cls.name] = explanation return explanations async def _generate_function_explanations(self, functions: List[FunctionInfo], structure: StructureAnalysis) -> Dict[str, str]: """生成函数解释""" explanations = {} for func in functions: prompt = f""" 为以下函数生成详细解释: 函数名:{func.name} 参数:{func.arguments} 返回类型:{func.return_type} 文档字符串:{func.docstring} 请生成详细的函数解释,包括: 1. 函数的功能 2. 参数说明 3. 返回值说明 4. 使用示例 """ explanation = await self.llm_client.complete(prompt) explanations[func.name] = explanation return explanations async def _generate_algorithm_explanations(self, algorithms: List[AlgorithmInfo]) -> Dict[str, str]: """生成算法解释""" explanations = {} for algo in algorithms: prompt = f""" 为以下算法生成详细解释: 算法名称:{algo.name} 时间复杂度:{algo.time_complexity} 空间复杂度:{algo.space_complexity} 请生成详细的算法解释,包括: 1. 算法原理 2. 实现细节 3. 优缺点分析 4. 适用场景 """ explanation = await self.llm_client.complete(prompt) explanations[algo.name] = explanation return explanations async def _generate_usage_examples(self, parsed_code: ParsedCode) -> List[str]: """生成使用示例""" examples = [] # 为每个类生成示例 for cls in parsed_code.classes: prompt = f""" 为以下类生成使用示例: 类名:{cls.name} 方法:{[m.name for m in cls.methods]} 请生成 2-3 个实用的使用示例。 """ example = await self.llm_client.complete(prompt) examples.append(example) # 为主要函数生成示例 for func in parsed_code.functions[:3]: # 只生成前 3 个函数的示例 prompt = f""" 为以下函数生成使用示例: 函数名:{func.name} 参数:{func.arguments} 请生成 1-2 个实用的使用示例。 """ example = await self.llm_client.complete(prompt) examples.append(example) return examples