
1. 从“能跑通”到“靠得住”复杂代码库才是AI编程的真正考场这两年“AI编程”几乎是铺天盖地但很多人实际用下来会有一种落差写个函数、生成一段脚本、做个demoAI确实顶得上半个初级工程师可一旦把它丢进一个几十万行、模块间互相依赖、历史包袱沉重的真实项目里表现就急转直下。改一个东西它要么找不到关联代码要么改完A处弄坏B处要么凭空捏造一个不存在的API。问题不在模型不够聪明而在我们压根没教会它“怎么在这么大一坨代码里找到该看的东西并且只看该看的东西”。这就是上下文工程Context Engineering要解决的问题。它的核心不是调prompt不是换更强的模型而是把“喂给模型的上下文”当成一个需要刻意设计、持续维护的系统模型能看到什么、看不到什么、以什么顺序看、看到什么粒度这些都直接决定它在复杂代码库里的表现。这篇文章我会跳过那些“AI辅助编程工具推荐清单”直接讲我在真实项目里总结出来的上下文工程实践方法——包括上下文窗口怎么规划、代码库信息怎么分层压缩、检索和结构化解析怎么配套用、上下文污染怎么排查以及一套可以直接照着搭的最小实现。如果你正在做AI辅助编码工具、企业内部代码智能体或者只是想把AI接入自己那个历史悠久的祖传项目这篇文章应该能帮你少踩很多坑。2. 为什么AI在复杂代码库里“失灵”问题出在上下文不是模型2.1 窗口再大也装不下整个代码库先算一笔账。一个中型项目比如一个Spring Boot后端加上一个Vue前端代码总量轻松超过50万行。按平均每行30个token估算这就是1500万token。现在最强模型的上下文窗口也就几十万token级别中间还隔着两个数量级。哪怕未来窗口继续扩大把整个代码库粗暴地塞进去也不现实token成本吃不消检索时间变长更糟糕的是无关信息产生的干扰会让模型决策质量断崖式下降——这是有实验数据的不是玄学。所以上下文工程第一条铁律上下文不是越多越好而是越准越好。把模型比作一个新入职的工程师你不可能把公司全部代码打印出来摔到它桌上让它自己看。你会先告诉它业务背景带它看核心模块让它从一条具体的bug或者需求入手按图索骥地翻阅相关文件。上下文工程做的事情就是这个“带新人”的过程只不过把这些动作变成了一套可复现、可量化的技术流程。2.2 复杂代码库的“上下文陷阱”与信息冰期复杂代码库之所以难搞除了体量大还有几类非常阴险的上下文陷阱我踩过之后才意识到它们比“文件太多”更要命。**第一类是隐式依赖。**类A的方法里直接new了类BB的构造函数又依赖某个配置项这个配置项在yml文件的三层嵌套里。如果你只把A.java丢给AI它看到new B()但不知道B的构造参数从哪来就会自己脑补一个。更麻烦的是注解驱动的框架Spring Boot、MyBatis、Lombok大量逻辑藏在注解和约定里“源码就在眼前但关键信息全在源码之外”。**第二类是约定俗成的历史包袱。**项目里总有那么几个“祖传模块”命名混乱、职责不清但大家都在用。AI理解不了“为什么这里叫UserInfo但其实是订单”因为它看不到Git历史、看不到团队约定、看不到那些散落在docs目录里早就过时的设计文档。**第三类我管它叫“信息冰期”。**这是模块化设计带来的副作用为了让每个类职责单一代码把信息拆得极碎A模块只负责发事件、B模块只负责监听、C模块只负责落库单看任何一个文件都不知道一条完整业务链路长什么样。对AI来说这就是信息的“冰期”——冰面以下的部分才是主体但表面上只能看到几个互相调用的孤岛。这三类陷阱有一个共同点它们不是靠“多塞几个文件”就能解决的你需要主动地、有结构地帮模型重建那个“看不见”的上下文。这已经不光是上下文工程的问题而是关系到怎么设计一套能让AI“读懂潜台词”的信息通道。2.3 上下文工程的正确定位给模型修一条“信息高速公路”我见过不少团队试图用“魔法提示词”解决这个问题——把需求描述写得天花乱坠命令AI“你是一个资深工程师请仔细思考”。坦白说有一定效果但天花板很低。因为提示词只能影响模型“怎么用”你给它的信息无法解决“信息本身缺失或不准确”的问题。上下文工程换个思路与其逼模型在残缺信息里做推理不如主动控制信息流让模型在每一步都只接触它真正需要的高质量上下文。这不是prompt engineering的替代品而是它的上游——prompt像是给司机看的导航语音上下文工程则是决定把哪条路修通、在哪设立路标、在哪封路的高层规划。两者结合AI在代码库里的行为才会从“随机猜测”变成“有依据的定位”。3. 上下文工程的核心方法论分层、定向与动态组装3.1 三层上下文模型全局骨架、局部细节、即时任务我在实际项目里反复调整后沉淀出一个三层上下文模型它基本能覆盖从“让AI理解项目”到“让AI改一个具体函数”的全部场景。第一层是全局骨架上下文目标是让AI在动手之前知道这个项目是干什么的、有哪些顶层模块、模块之间怎么通信。内容包括项目README如果靠谱的话、模块目录结构到二级或三级目录就够不需要展开到文件、核心数据模型定义、模块间依赖关系的粗略描述。这一层的token预算控制在1万以内它的作用是“定位”——让AI知道该去哪个模块找答案。第二层是局部细节上下文是AI实际改代码时真正要“读”的内容。包括当前要修改的文件、直接相关的关联文件、以及这些文件用到的关键类型和函数的实现。这一层的token预算可以放到5万到10万具体取决于任务的复杂度和模型的上下文窗口。它的作用是“理解”——让AI知道这个函数的前因后果、输入输出约束、错误处理约定。第三层是即时任务上下文是当前这一步操作需要的最小信息集合。比如你要让AI实现一个REST接口即时上下文就包含控制器文件、服务接口定义、DTO类、数据库实体、以及路由注册约定。它的特征是一锤子买卖——用完即弃下一次任务重新组装。三层之间是动态流转的关系全局骨架告诉AI“去哪里”局部细节告诉AI“看什么”即时任务告诉AI“做什么”。每完成一个子任务局部和即时上下文都要重新组装而不是一直挂在对话里——否则就成了“把所有东西都塞进上下文”偏离了分层设计的初衷。3.2 定向上下文注入查得准比给得多更重要有了三层模型下一步是解决“怎么把对应层的上下文找出来”。复杂代码库里大概率没有一份现成的、准确的架构文档所以你需要一个“定向注入”机制我常用的组合是静态索引 语义检索 代码解析三件套。静态索引是最朴素但最可靠的解析代码库里的import关系、函数调用关系、文件之间的引用构建出一个调用图谱。它不涉及任何AI推理纯静态分析速度快到可以忽略不计。AI进场之前先查这个图谱能精准定位“谁调用了这个函数”、“这个类被谁实例化了”。语义检索则是为了对付那些“光靠关系图谱找不到”的问题——比如需求是“把用户登录后的积分逻辑改成异步”。关系图谱能告诉你积分模块在哪个文件但语义上的“异步改造为什么涉及消息队列、事务边界要怎么处理”是靠图谱看不出来的。用嵌入模型把代码片段和任务描述都向量化做top-k召回能把这些隐藏关联捞出来。代码解析负责把文件级别的信息压缩成“模型友好的摘要”。比如针对Java项目解析AST提取类签名、公共方法、注解、关键字段然后生成一段结构化的类摘要针对Python项目提取函数列表、装饰器、类型标注、导出符号。这个环节的价值在于它把动辄几百行的源文件压缩成几十行的语义摘要既省token又减少了噪声。这三件套加起来的目标只有一个在AI真正需要某段上下文之前用低成本的手段把它精准地捞出来。至于检索结果的排序、条数、以及怎么和后面的组装逻辑配合我在第5节给出一套完整的最小可跑实现。3.3 动态组装与迭代刷新让上下文跟着任务走静态的“一次性把所有上下文都塞给AI”在复杂需求上一定会翻车。因为复杂需求往往意味着十几步操作——改一个服务可能要连带改Controller、Service、Mapper、数据库迁移脚本、单元测试。如果第一步就把所有相关文件都塞进去中间任何一步发现“还需要看另一个文件”要么重新塞浪费token要么让AI硬着头皮猜质量下降。我的做法是建立“迭代式上下文刷新”机制。每一轮操作开始前先根据当前任务目标重新执行一次检索和组装上一步产生的中间结果比如新增的函数签名、修改的接口参数会被回灌进上下文作为下一步的输入。这就像是开车时不断刷新导航数据——路况变了导航也要跟着变。具体落地时一个很关键的技巧是“上下文快照snapshot管理”。每完成一个阶段性的改动就把当前对话的关键状态修改了哪些文件、新增了哪些类型、当前余额还剩多少压缩成一段结构化的摘要存起来。如果AI中途跑偏或者你想回退到某个状态直接恢复快照就行不需要重新从零开始喂信息。这个机制在长时间、多文件的重构任务里尤其好用我在第4节会给出一个具体的案例。4. 实操改造一个“祖传订单模块”的完整过程说得再多也不如跑一遍。我拿一个我实际改造过的订单模块来演示整套上下文工程怎么落地项目是Java 8 Spring Boot 2.x老代码大概3万行模块耦合比较严重没有单元测试。目标任务是把原有的同步订单回调逻辑改造为异步处理并保证事务一致性和幂等性。这是一个典型的“看起来简单、做起来到处是坑”的重构任务。4.1 第一轮构建全局骨架上下文找出“看不见”的依赖开始动代码之前我先跑了一遍静态分析生成了订单模块的调用关系图。这一步的产出不是给AI看的完整图而是一份摘要清单OrderController依赖OrderServiceOrderService里注入了PaymentClient、OrderMapper、PromoService、EventBus其中PaymentClient是一个Feign客户端PromoService在回调链路里会被同步调用。注意单看OrderService的源码这些依赖基本都能看到但有两个“看不见”的依赖是我通过静态分析之外的手段挖出来的OrderMapper的接口方法上有一堆XML里的自定义SQLIDEA里能看到跳转链接但纯文本AI看不到XML内容更不知道里面做了哪些表操作。所以我把OrderMapper.xml里涉及的表的增删改查字段整理成了一份摘要喂给了AI。EventBus.publish方法同事们在回调成功后都会调用用来发一个领域事件但这个事件有另一个监听器PromoListener在同步处理优惠券回滚。我顺着EventBus的注册表找到了这个监听器把它也列入了“局部细节上下文”的候选。这一步的产出是一份“订单模块依赖摘要”token大概3000上下。我把这份摘要和任务描述一起作为初始上下文让AI先输出一份改造方案而不是直接改代码。AI给的方案里正确指出了“事务边界需要从ControllerMethod下移到异步执行器内部”并且主动提醒“PaymentClient的回调确认需要放在异步任务成功之后”——这些信息如果我只丢一个OrderService.java给AI它绝对不会知道。4.2 第二轮定向注入局部细节让AI真正“读懂”改哪里有了方案就开始动代码。我先让AI基于即时任务上下文改动OrderService把回调核心逻辑抽取到一个新类AsyncOrderCallbackExecutor里原方法只负责提交任务。这一步涉及的局部上下文包括OrderService.java全文OrderMapper.java接口定义 OrderMapper.xml的关键SQL摘要Order.java实体类TransactionTemplate在项目里的使用约定这个项目统一用TransactionTemplate管理事务而不是Transactional因为前者在异步线程里更可控PaymentClient.java接口定义我把这些文件按“先接口后实现、先实体后方法”的顺序组装成一个上下文包再附上一句非常具体的要求只提取逻辑不改变对外方法签名保留原有的日志约定。这是我在实践里发现的一个小技巧——“不改变什么”比“要做什么”更容易被AI严格遵守。这一轮AI产出的代码质量不错基本上是一份可以直接跑的实现。唯一的问题在于它给幂等方案加了一个UNIQUE KEY在order_callback_record表上建表语句里字段类型跟我已有的order_no字段长度不一致。这里不是AI的错——我喂的局部上下文里没包含那张表现有字段的元数据。把这个信息补进去之后它立刻修正成了兼容现有字段长度的方案。4.3 第三轮上下文快照与多文件改动的一致性守护这次改造实际动了6个文件新增AsyncOrderCallbackExecutor、修改OrderService、修改OrderController接口不变、新增一个CallbackRecord实体和Mapper、加一张建表语句。每个文件改完之后我都会把当前快照压缩成一段摘要内容大致是[快照时间] 第2轮提交后 目标将回调主逻辑异步化位于AsyncOrderCallbackExecutor#execute 相关接口OrderCallbackService#handleCallback签名未变 已修改OrderService原同步调用替换为异步提交状态机流转 待处理CallbackRecord表结构order_no varchar(64)迁移脚本 已知问题PaymentClient在异常路径上需要补偿调用尚未处理然后每一轮新的AI请求我都会在上下文开头把快照原文带上。这样做的好处是即使AI因为对话轮数太多开始遗忘细节实际上大模型长对话的注意力确实会衰减我只要把快照重新注入它就立刻“想起来”前面发生了什么顺着当前进度继续干活而不是从头推理。这比依赖长对话记忆要可靠得多。4.4 第四轮测试阶段的上下文压缩与缺陷定位改造完成后这个模块没有现成测试框架我先补了集成测试。AI生成的测试用例覆盖了“回调成功”、“回调失败重试”、“重复回调幂等”三个场景逻辑基本正确但第二个用例断言失败。我没直接把整个测试日志丢给AI那样太长了而且大部分是框架噪音而是先自己看了一眼日志定位到“失败发生在PromoService.rollback被调用时抛了空指针”——然后我只把这个异常栈和相关代码传回给AI并问“为什么PromoService注入为null”。AI回答得很快AsyncOrderCallbackExecutor被new出来了没有交给Spring容器管理所以Autowired的PromoService自然是null。这其实是一个很经典的Spring异步化坑但如果我把日志和源码整个糊给AI它会跟上下文里的噪音做斗争给出各种奇怪解释。定向压缩后的上下文让AI在第一次回答就给出了正确结论。这一轮让我印象最深的不是AI多聪明而是上下文工程在这整个过程中实实在在起到了“信息过滤器”的作用它决定了AI在什么时间点接触什么信息从而把“AI幻觉”从根上降到了最低。5. 最小可复现的上下文工程实现一种轻量级方案如果你不想用那些重量级的Agent框架只想在公司项目里快速试验上下文工程我提供一套只需要三个文件就能跑起来的最小实现思路。不需要K8s不需要复杂编排一台普通开发机能跑就行。5.1 文件A代码库静态索引器Python tree-sitter第一步是生成代码库的“地图”我用的是tree-sitter它比正则表达式解析代码靠谱得多支持几十种语言能准确提取函数定义、类定义、导入语句和调用关系。# code_indexer.py # 依赖: pip install tree-sitter tree-sitter-java tree-sitter-python from tree_sitter import Language, Parser import os, json # 假设你用的是Java项目先编译语言库 JAVA_LANGUAGE Language(build/my-languages.so, java) parser Parser() parser.set_language(JAVA_LANGUAGE) def parse_java_file(filepath): 提取Java文件中的类名、方法签名、注解和import关系 with open(filepath, r, encodingutf-8) as f: source f.read() tree parser.parse(bytes(source, utf-8)) root tree.root_node info { file: filepath, imports: [], classes: [], methods: [] } def walk(node): if node.type import_declaration: text source[node.start_byte:node.end_byte] info[imports].append(text.strip()) elif node.type class_declaration: name_node node.child_by_field_name(name) if name_node: class_name source[name_node.start_byte:name_node.end_byte] # 提取class上的注解比如Service, RestController annotations [] if node.prev_named_sibling and node.prev_named_sibling.type annotation: annotations.append(source[node.prev_named_sibling.start_byte:node.prev_named_sibling.end_byte]) info[classes].append({name: class_name, annotations: annotations}) elif node.type method_declaration: # 这里不展开提取方法名和参数类型即可 pass for child in node.children: walk(child) walk(root) return info def scan_repository(root_dir): 递归扫描目录输出JSON索引 result {files: [], call_graph: {}} for dirpath, _, filenames in os.walk(root_dir): for fn in filenames: if fn.endswith(.java): full_path os.path.join(dirpath, fn) try: info parse_java_file(full_path) result[files].append(info) except Exception as e: print(f[warn] 解析失败 {full_path}: {e}) with open(code_index.json, w, encodingutf-8) as f: json.dump(result, f, ensure_asciiFalse, indent2) return result if __name__ __main__: scan_repository(./your_project)这段代码的价值不是写得漂亮而是它产出的code_index.json是一个稳定、低成本的“代码库地图”。不管AI工具怎么换这份地图都能复用。我用它在几个项目上验证过平均每个文件解析耗时不到50毫秒3万行代码的索引全量生成只要一两分钟。5.2 文件B局部上下文定向检索器BM25 向量召回检索器负责在AI动手前从code_index.json和源码库里挑出最相关的局部上下文。我试过纯向量检索也试过纯BM25最终结论是两者结合效果最好向量负责语义召回“跟异步化相关的代码”BM25负责精确匹配“OrderService”这种专属名词。# context_retriever.py # 依赖: pip install rank-bm25 sentence-transformers from rank_bm25 import BM25Okapi from sentence_transformers import SentenceTransformer import json, os class ContextRetriever: def __init__(self, index_pathcode_index.json, code_dir./your_project): with open(index_path, r, encodingutf-8) as f: self.index json.load(f) self.code_dir code_dir # 准备语义检索的文档库每个文件一段摘要 self.documents [] # 文档文本 self.doc_metadata [] # 对应的文件路径和类型 for file_info in self.index[files]: doc_text self._file_to_summary(file_info) self.documents.append(doc_text) self.doc_metadata.append(file_info[file]) # BM25索引 tokenized_docs [doc.split() for doc in self.documents] self.bm25 BM25Okapi(tokenized_docs) # 向量索引轻量方案用all-MiniLM也能跑 self.encoder SentenceTransformer(moka-ai/m3e-small) # 中文场景推荐m3e self.doc_embeddings self.encoder.encode(self.documents, normalize_embeddingsTrue) def _file_to_summary(self, file_info): 把文件索引压缩成两句话以内的语义摘要 class_names ,.join([c[name] for c in file_info[classes]]) imports ,.join(file_info[imports][:10]) # 只取前10行import防止超长 return f{file_info[file]} 类: {class_names} 依赖: {imports} def retrieve(self, query, top_k10): 混合检索BM25 向量加权融合 # BM25召回 tokenized_query query.split() bm25_scores self.bm25.get_scores(tokenized_query) # 向量召回 query_emb self.encoder.encode([query], normalize_embeddingsTrue) vec_scores (self.doc_embeddings query_emb.T).flatten() # 归一化后加权权重可按需调我常用0.6向量 0.4BM25 bm25_norm (bm25_scores - bm25_scores.min()) / (bm25_scores.max() - bm25_scores.min() 1e-6) vec_norm (vec_scores - vec_scores.min()) / (vec_scores.max() - vec_scores.min() 1e-6) combined 0.6 * vec_norm 0.4 * bm25_norm top_indices combined.argsort()[-top_k:][::-1] results [] for idx in top_indices: results.append({ file: self.doc_metadata[idx], score: float(combined[idx]), summary: self.documents[idx] }) return results if __name__ __main__: r ContextRetriever() results r.retrieve(用户登录后积分异步更新的实现, top_k5) for res in results: print(f{res[score]:.3f} {res[file]})这套检索器的核心思路是“先粗后精”先用摘要快速滤掉90%无关文件再对候选文件做“全文叠加”形成最终上下文包。实测在3万行的订单模块里检索时间一般在100毫秒以内top5命中率远超我拍脑袋手工选文件的准确率。5.3 文件C上下文组装与提示词构造器检索器捞出来的是候选文件但组装成什么样的上下文包也有讲究。我总结出来的经验是结构化上下文 明确指令比“一股脑把所有文件拼接起来”效果好非常多。原因很简单模型对“提示词结构”有很强的敏感性同样的信息换个排列顺序回答质量就有区别。# context_builder.py # 负责把检索结果组装成AI友好的Prompt上下文块 def build_context_for_task(task_description, code_index_pathcode_index.json): 任务描述 - 结构化上下文包 retriever ContextRetriever(code_index_path) # 1. 先执行检索拿到候选文件 candidates retriever.retrieve(task_description, top_k8) # 2. 对被选中的文件做“语义压缩”只提取类/方法签名和关键逻辑 compressed_files [] for cand in candidates: file_path cand[file] compressed compress_file_for_llm(file_path) # 具体实现见下 compressed_files.append(compressed) # 3. 组装上下文包 context_blocks [ # 任务目标, task_description, \n# 项目相关的文件摘要按相关性排序, ] for i, (cand, compressed) in enumerate(zip(candidates, compressed_files), 1): context_blocks.append(f\n## [{i}] {cand[file]} (相关性 {cand[score]:.2f})) context_blocks.append() context_blocks.append(compressed) context_blocks.append() context_blocks.append(\n# 指令) context_blocks.append(请基于以上代码摘要给出具体的修改方案。如果信息不足请明确说出缺少什么不要猜测。) return \n.join(context_blocks) def compress_file_for_llm(file_path): 将源码文件压缩为关键信息块 # 这一步可以用tree-sitter或者正则提取也可以直接截断 # 我常用的是提取所有public方法签名 类注释 关键字段 import # 对于核心方法保留前30行实现其余都折叠成“# 省略...” # 压缩率一般能做到30%~50%token大幅下降 pass这份代码的精髓有两点一是把源代码从“完整文件”变成“压缩摘要”让模型在token预算里看到更多文件二是每个候选文件都带着“相关性分”让模型对哪些文件是核心、哪些是辅助有预判。这不是玄学而是我在实验里发现当模型知道“第1、2个文件最重要”时它对这两个文件的关注度明显更高回答也更贴合项目实际。5.4 组装策略的实际效果与调参建议我这套实现跑下来有几个关键参数值得分享检索数量top_k我建议从5开始根据任务复杂度上调。太少了漏关键文件太多了模型会分散注意力。跟代码评审一样把最相关的8个文件喂给AI比把30个文件堆上去效果好得多。混合检索权重我默认0.6向量 0.4BM25但如果你的项目里专有名词很多比如类名、方法名都很独特BM25权重可以拉高到0.5甚至0.6。反过来如果项目里都是通用词process、handler、utils向量权重应该更高。压缩比一般控制在输出原文的40%-60%太狠了模型会丢失关键实现细节太宽容又起不到省token的作用。我在核心方法上选择“保留前30行”基本能把“方法入口”和“关键分支”都保留住同时把方法体后半段的基础逻辑折叠掉。这套实现的结构就是这么简简单单三个文件索引器负责“读”检索器负责“选”组装器负责“排”。加起来不到300行代码却能帮你把AI在复杂代码库里的表现提升一个等级。如果你的项目里已经有比较成熟的代码搜索工具比如Sourcegraph甚至可以把索引器替换成现成的API检索器本身只需要处理“搜索结果如何筛选、如何组装”就行。6. 上下文工程实践中的四个常见“坑”与排查思路6.1 上下文污染模型明明看到了无关代码却硬要拿它答题上下文污染是实际使用中最隐蔽的坑。我遇到过好几次AI给出的代码里突然冒出一个跟任务完全无关的JsonUtil调用仔细查了一下发现这个JsonUtil是我在top8候选文件里不小心带进去的工具类AI看到它在上下文里就“顺手”用了。排查思路很直接每次AI给出答案前把组装好的上下文包打印出来人工扫一眼有没有明显无关的文件。如果看到第6、7、8个文件跟任务八竿子打不着说明检索器的相关性阈值太低了或者压缩摘要抽出来的关键词偏了。解决办法不是粗暴地调低top_k而是给检索器加一道“过滤规则”排除掉测试文件、构建配置、静态资源等非业务代码因为这些文件经常在语义上一不小心就捞进来。6.2 信息冰期模型的推理链条比你想的更长前面提到过信息冰期这里再展开一个真实的失败案例。有一次我让AI实现一个“用户注册后自动发送欢迎邮件”的功能它找到了UserController和UserService完美地加了方法但完全没有意识到项目里已经有一套消息队列RabbitMQ在跑异步任务而按团队规范这种“注册后通知”应该走MQ而不是直接调邮件接口。原因很简单我的检索器上下文里没有包含MQ相关的任何信息而“发邮件”这个词在语义上跟“RabbitMQ”不沾边向量检索和BM25都捞不到。这个问题从检索器角度很难彻底解决我目前的应对手段是“项目约定注入”把团队规范、架构决策记录ADR里跟“什么场景用什么组件”相关的内容做成一个固定的全局上下文块每次组装时强制放在最前面。AI看到“项目里所有异步任务必须走RabbitMQ”这句话之后再遇到“注册后通知”的场景就能做正确联想。这本质上是在上下文层面补一个“显式业务规则层”弥补代码库里那些“约定俗成”的信息盲区。6.3 长任务漂移对话轮数越多AI越容易“忘记”约束长对话场景里模型对早期约束的记忆会指数级衰减——不是它“不记得”而是注意力会往后半段的token集中。最典型的表现是你在第2轮要求“不要修改Controller层”到了第8轮AI改着改着又在Controller里加了东西。对付这个问题我的经验是“频繁重置上下文 快照回灌”。每一轮子任务完成后不追求“接着聊”而是主动开启新会话把快照摘要 本轮上下文包重新注入。这样模型在每一轮都处于“新鲜的上下文”里而不是在一个逐渐膨胀、逐渐漂移的对话里挣扎。代价是你需要多写一点“快照维护”的代码但换来的是输出质量稳定绝对值。6.4 评估缺失不量化上下文效果就永远在“拍脑袋优化”上下文工程的很多选择——top_k调多少、压缩比多少、检索权重怎么配——如果没有一套量化评估手段很容易变成“我觉得这样可以”。我在自己的项目里搭了一套很轻量的评估流程准备一组固定的开发任务比如从Git历史里挑十几个真实commit对应的需求把每个任务喂给“默认上下文策略”和“待测上下文策略”然后对比AI产出的代码能不能通过单元测试。不需要人工评审测试用例就是裁判。跑一次大概一两个小时但能非常客观地告诉你新策略到底有没有用。没有这套评估你会发现每个策略听起来都很有道理但上线后表现跟纸面分析完全不是一回事。有了评估迭代上下文策略就变成了一个数据驱动的过程我今天调一个参数明天调一个参数每一步都心里有数。7. 从上下文工程到“AI原生代码库”这条路还可以走多远做到上面这些AI在复杂代码库里的表现已经算是“可用”了。但上下文工程的天花板远不止于此顺着这个思路往后推有几件事是我目前正在尝试也建议你做上下文工程时一定要留意的方向。**第一件是让上下文里的“代码事实”更加结构化。**现在上下文里大多是源码文本模型要自己去理解里面隐含的调用关系。但如果能把上下文从“源码片段”升级成“带语义标注的代码事实”——比如“OrderService依赖PaymentClient而PaymentClient在其他模块里被3个地方使用”——AI就可以少做很多从源码里反推信息的工作错误率自然下降。这需要索引器从“提取文本”进化到“构建知识图谱”代价更高但收益也更大。**第二件是上下文策略的自适应化。**目前top_k、压缩比、权重这些参数都是我拍脑袋定的跑完评估再微调。理论上可以训练一个轻量的策略网络甚至就是一套规则根据任务类型自动选择上下文参数——简单的bug修复就不需要带全局骨架大型重构就要多带几个层的上下文。这相当于是把上下文工程从“人工规则”升级成“自动化策略”是我眼中这个方向最性感的无人区。**第三件是跟代码库治理的联动。**上下文工程能做的再多也架不住代码库本身烂——命名混乱、架构腐化、依赖纠缠AI照样会被带偏。反过来想AI对某个模块的理解准确性其实可以当成这个模块“可维护性”的一个代理指标。如果AI老是在特定文件上犯错大概率是这些文件本身的职责边界有问题。顺着这个信号去做重构代码库会越来越“AI友好”而AI友好本质上就是“新开发者友好”——这已经不只是工程效率问题了更是团队知识沉淀的问题。我自己在实际操作中最深的体会是上下文工程不是给AI“打补丁”而是逼着开发团队重新审视“代码库里的信息到底是怎么流动的”。你为了给AI建上下文索引会第一次认真梳理模块依赖为了写上下文快照会第一次把“这次改动到底动了什么”说清楚为了做评估会第一次给代码补上真正能跑的测试。这些事无论有没有AI都该做AI只是把它们从“应该做”变成了“不做就真的没法用”。如果看完这篇你还是觉得抽象我建议你从一个小模块开始别一上来就改造核心系统。搭好索引器选一个手头真实存在的任务跑一遍看看AI的表现变化。等你第一次看到它精准地找到“那个你本来想手动指给它的文件”时你就会理解上下文工程的力量了。