
1. 项目概述从“调参”到“治本”的思维跃迁如果你最近在捣鼓大语言模型是不是感觉陷入了“无限调Prompt”的怪圈精心设计的指令模型有时灵光一现有时却答非所问你反复修改措辞、调整格式甚至尝试各种“魔法咒语”效果却像开盲盒一样不稳定。这种感觉我太熟悉了。几年前当大家刚开始接触大模型时我也曾把全部精力都花在“提示词工程”上试图找到一个万能公式。但踩过无数坑之后我意识到一个更根本的问题Prompt只是指令而模型真正“吃进去”并赖以思考的“食物”是上下文Context。这个项目标题——“别再只调 Prompt 了真正决定 AI 应用质量的是上下文工程”——精准地戳中了当前AI应用开发的一个核心误区。我们往往过于关注如何“问得好”Prompt Engineering却忽略了如何“喂得好”Context Engineering。你可以把大模型想象成一个极其聪明但患有严重“短期记忆障碍”的专家。Prompt是你向他提出的问题而上下文则是你提前放在他手边的、与问题相关的所有参考资料。如果参考资料是混乱、无关甚至错误的无论你的问题提得多么精妙专家给出的答案也大概率不靠谱。上下文工程就是系统化地构建、筛选、组织和优化这些“参考资料”的学问。它决定了模型的知识边界、推理基础和最终输出的准确性与可靠性。无论是构建一个能精准回答公司内部政策的知识库助手还是开发一个能根据长文档自动生成摘要的工具甚至是打造一个能进行多轮复杂对话的智能体其成败的关键往往不在于最后那一句Prompt写得有多漂亮而在于你为模型准备了怎样的上下文。近年来大热的RAG和Agent技术其核心挑战与进阶之路本质上都是上下文工程在不同维度上的深化。RAG要解决的是如何从海量知识中精准检索出最相关的片段作为上下文Agent则要解决如何在多步决策中动态维护、更新和利用上下文。因此掌握上下文工程是突破当前AI应用开发瓶颈从“玩具demo”走向“生产级系统”的必经之路。2. 核心需求解析为什么Prompt工程开始“失灵”要理解为什么上下文工程变得如此关键我们需要先看看单纯依赖Prompt工程遇到了哪些天花板。这不仅仅是技术问题更是工程思维上的局限。2.1 Prompt工程的固有局限Prompt工程的核心是“在有限的输入窗口内通过精心设计的文本指令来引导模型行为”。它在以下场景表现优异创意写作、格式转换、简单分类、基于模型已有知识的问答等。然而它的局限性随着应用深入日益凸显知识时效性与专有性瓶颈大模型的训练数据有截止日期无法知晓之后的事件或你私有的、未公开的数据。仅靠Prompt你无法让模型回答“我司上周发布的Q2财报核心数据是什么”或“根据这份100页的技术白皮书总结其创新点”。“幻觉”与事实性错误当问题触及模型知识的边缘或盲区时模型倾向于“自信地编造”即幻觉。一个再精巧的Prompt比如“请确保答案准确引用来源”也无法阻止模型在缺乏事实依据时胡编乱造因为它根本没有“来源”可引用。长文本处理与信息过载模型的上下文窗口虽然越来越大但直接塞入一本电子书作为Prompt不仅成本剧增长上下文推理更贵而且模型很难从中精准定位关键信息性能会显著下降。这就像让专家在几分钟内读完一本百科全书再回答问题不现实。复杂、多步骤任务的管理对于需要查阅多个文档、进行条件判断、分步执行的任务单一的Prompt难以描述整个流程和状态。任务执行到哪一步了中间结果是什么这些“状态”信息无处安放。2.2 上下文工程要解决的核心问题基于以上局限上下文工程的目标就是为模型构建一个精准、可靠、结构化的“外部大脑”或“工作记忆”。它的核心需求可以分解为需求一知识增强与落地。如何将模型训练截止日期之后的新知识、非公开的专有知识公司文档、个人笔记、以及实时变化的信息天气、股价安全、高效地“注入”到模型的推理过程中这是RAG技术的主战场。需求二事实锚定与溯源。如何确保模型的每一个关键陈述都有据可查减少幻觉这需要上下文本身是可信的来源并且能建立答案与上下文片段的映射关系实现可解释性。需求三高效的信息利用。如何在浩如烟海的资料中快速找到与当前问题最相关的部分并以模型易于理解的方式组织起来这涉及到检索、重排序、信息压缩等一系列技术。需求四复杂任务的状态管理。如何在一个跨越多次模型调用的复杂工作流中保持对话历史、工具调用结果、中间决策等状态的连贯性和有效性这是智能体Agent框架的核心。注意上下文工程不是要取代Prompt工程而是为其提供坚实的基础。一个好的Prompt是“问对问题”而好的上下文是“给对材料”。两者结合才能发挥最大效能。很多开发者抱怨模型效果不好第一反应是“改Prompt”这其实是本末倒置。应该先检查我提供给模型的上下文是对的吗全吗组织得好吗3. 技术架构深度剖析从RAG到Agent的上下文流水线理解了“为什么”我们来看“怎么做”。一个完整的、生产级的上下文工程体系远不止是“把文档切块存进向量数据库”那么简单。它是一条精密的流水线我将其分为四个核心阶段这也是当前技术演进的热点方向。3.1 阶段一上下文的“原料准备”——摄取与预处理这是所有工作的起点目标是将原始数据文本、PDF、PPT、网页、数据库等转化为干净、结构化的“文本原料”。这一步的粗糙会直接导致后续环节的失效。文档解析与提取使用像Unstructured、PyMuPDF、Docling这样的库不仅要提取文字还要尽力保留标题、列表、表格结构、元数据作者、日期等。对于扫描件需要集成OCR。文本分块这是第一个关键决策点。分块策略直接影响检索精度。固定大小分块简单但可能割裂完整语义如一个段落被切成两半。基于语义的分块利用句子边界、标点、自然段落进行分割更符合人类阅读习惯。LangChain的RecursiveCharacterTextSplitter结合分隔符列表是常用方法。高级策略可以结合小模型进行句子嵌入在语义边界处切割或为法律、代码等特殊文档设计定制化的分块规则。实操心得不要盲目追求小块。对于需要全局理解的概括性问题块可以大一些如1000字对于需要精准定位细节的事实性问题块要小一些如200字。我通常会准备多种分块策略的索引根据查询类型动态选择。另外务必为每个块添加元数据如来源文件名、页码、章节标题这对后续的溯源至关重要。3.2 阶段二上下文的“智能检索”——召回与排序当用户提问时我们需要从海量“原料”中找出最相关的几块。这就是RAG的核心。向量检索召回将分块后的文本通过嵌入模型转换为向量存入向量数据库。查询时将问题也转换为向量进行相似度搜索。OpenAI的text-embedding-3系列、BGE、Voyage等都是不错的选择。向量数据库可选Pinecone、Weaviate、Qdrant或PGVector。关键词检索混合搜索单纯向量搜索对关键词匹配、缩写、特定术语可能不敏感。结合BM25等传统全文检索技术进行混合搜索能显著提升召回率。重排序初步检索可能返回几十个相关块我们需要一个更精细的模型对它们进行重新打分和排序选出Top-K个最相关的。可以使用像Cohere Rerank、BGE Reranker这样的专用重排序模型或者用小型的交叉编码器模型。查询理解与改写用户的原始查询可能模糊、简短。利用大模型对查询进行扩展补充同义词、相关概念、改写转化为更易于检索的陈述句或分解将复杂问题拆成多个子问题并行检索能极大提升检索质量。3.3 阶段三上下文的“精加工”——压缩与构建检索到的上下文可能仍然冗长或包含无关信息。直接塞给模型会浪费令牌、引入噪音。因此需要“精加工”。上下文压缩选择性压缩让模型判断检索到的文档中哪些句子与问题真正相关只保留这些。摘要性压缩让模型对长文档块进行概括保留核心信息。LangChain的ContextualCompressionRetriever提供了相关实现框架。提示模板构建这是连接上下文和最终Prompt的桥梁。一个健壮的提示模板应包含系统角色设定定义AI的职责和行为边界。上下文注入区清晰地将加工后的上下文内容放置于此通常用context.../context或### 参考资料 ###等标记包裹。用户问题区放置用户原始或改写后的问题。回答格式指令要求模型基于上下文回答注明“如果上下文未提供相关信息请明确说明不知道”并鼓励引用来源。# 一个简化的提示模板示例 PROMPT_TEMPLATE 你是一个专业的助手严格根据提供的参考资料回答问题。 如果资料不足以回答问题请直接说“根据现有资料无法回答该问题”不要编造信息。 参考资料如下 {context} 问题{question} 请基于以上参考资料用中文给出准确、清晰的回答。在回答中可以引用参考资料中的关键信息。 3.4 阶段四上下文的“动态管理”——Agent与循环对于需要多轮交互、调用工具、具有状态的复杂任务上下文就变成了一个动态的、不断演化的“工作记忆”。这就是Agent的范畴。思维链与执行历史Agent的每一步思考、调用工具、得到结果都需要被记录并作为后续步骤的上下文。这要求Prompt模板能动态纳入之前的“行动轨迹”。工具上下文集成当Agent调用一个搜索工具或计算器后工具返回的结果需要被格式化成模型易于理解的文本并插入到下一轮思考的上下文中。长程记忆与摘要在超长对话中需要定期对之前的对话历史进行摘要将精华压缩后作为新的上下文以节省令牌并聚焦重点避免模型遗忘关键早期信息。注意Agent对上下文工程的要求最高因为它涉及计划、执行、观察、循环的整个过程。一个健壮的Agent框架如LangGraph、AutoGen会提供状态管理机制但如何设计状态结构、如何将工具结果有效整合仍然是开发者需要精心设计的上下文工程问题。4. 实战构建一个基于上下文工程的智能文档QA系统理论说了这么多我们动手搭建一个简单的系统把上述流程串起来。假设我们要为一个产品团队构建一个技术文档问答机器人。4.1 环境准备与工具选型我们选择轻量且流行的技术栈嵌入模型BGE-M3。它支持多语言、长文本且开源免费性能接近闭源模型。向量数据库Chroma。简单易用适合原型和中小规模项目。LLMDeepSeek或Qwen的API。性价比高性能优秀。框架LangChain。它提供了上述大部分环节的组件能快速集成。原始文档一批Markdown格式的产品需求文档和API手册。# 环境安装 pip install langchain langchain-community chromadb pypdf unstructured sentence-transformers4.2 分块与嵌入细节决定成败from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_community.vectorstores import Chroma from langchain.document_loaders import DirectoryLoader, TextLoader import os # 1. 加载文档 loader DirectoryLoader(./产品文档/, glob**/*.md, loader_clsTextLoader) documents loader.load() # 2. 分块 - 这里采用递归字符分割优先按Markdown标题分割 text_splitter RecursiveCharacterTextSplitter( chunk_size500, # 块大小 chunk_overlap50, # 重叠部分避免语义割裂 separators[\n## , \n### , \n#### , \n\n, \n, , ] # 分割符优先级 ) chunks text_splitter.split_documents(documents) # 为每个块添加来源元数据 for i, chunk in enumerate(chunks): chunk.metadata[chunk_id] i # 3. 嵌入并存储 embeddings HuggingFaceEmbeddings(model_nameBAAI/bge-m3) vectorstore Chroma.from_documents( documentschunks, embeddingembeddings, persist_directory./chroma_db # 持久化存储 )关键参数解析chunk_size500对于技术文档500字符能容纳一个小节或几个紧密相关的段落平衡了信息量和检索精度。chunk_overlap50重叠部分确保了即使分割点在一个概念中间相邻的块也能通过重叠部分保持一定的语义连贯这对后续检索和模型理解有益。separators顺序优先按Markdown的二级、三级标题分割能最大程度保持文档的原有结构这对于“请介绍XX功能模块”这类问题至关重要。4.3 检索链的实现混合搜索与重排序单纯向量搜索不够我们实现一个混合检索器。from langchain.retrievers import BM25Retriever, EnsembleRetriever from langchain.vectorstores import Chroma # 重新加载向量库 vectorstore Chroma(persist_directory./chroma_db, embedding_functionembeddings) vector_retriever vectorstore.as_retriever(search_kwargs{k: 10}) # 召回10个 # 创建BM25检索器需要将文档转为纯文本列表 texts [chunk.page_content for chunk in chunks] bm25_retriever BM25Retriever.from_texts(texts) bm25_retriever.k 10 # 集成检索器 ensemble_retriever EnsembleRetriever( retrievers[vector_retriever, bm25_retriever], weights[0.7, 0.3] # 给向量检索更高权重BM25辅助 ) # 假设我们有一个重排序函数这里用简单模拟实际需调用重排序模型API def simple_rerank(query, retrieved_docs): # 模拟优先选择包含更多查询关键词的文档 query_terms set(query.lower().split()) def score(doc): doc_terms set(doc.page_content.lower().split()) return len(query_terms.intersection(doc_terms)) retrieved_docs.sort(keyscore, reverseTrue) return retrieved_docs[:5] # 返回Top-5 # 最终的检索函数 def retrieve_context(query): raw_docs ensemble_retriever.get_relevant_documents(query) ranked_docs simple_rerank(query, raw_docs) return ranked_docs4.4 提示工程与上下文注入现在将检索到的上下文注入到精心设计的Prompt中。from langchain.prompts import PromptTemplate from langchain.chains import LLMChain from langchain_community.llms import QianfanLLMEndpoint # 以千帆为例替换为你的LLM template 你是一位严谨的产品技术专家负责解答关于产品文档的问题。 请严格根据以下提供的参考资料进行回答。如果参考资料中没有相关信息请明确告知用户“在现有资料中未找到相关信息”。 参考资料 {context} 用户问题{question} 请按以下格式用中文回答 1. **核心答案**直接、简洁地回答用户问题。 2. **详细说明**结合参考资料对答案进行展开说明。 3. **参考来源**注明你的回答主要依据了哪部分资料例如来自“API接口文档-用户认证章节”。 prompt PromptTemplate(templatetemplate, input_variables[context, question]) llm QianfanLLMEndpoint(modelERNIE-4.0-8K) # 初始化你的LLM qa_chain LLMChain(llmllm, promptprompt) # 完整的问答函数 def answer_question(question): relevant_docs retrieve_context(question) context_text \n\n---\n\n.join([f【资料{i1}】{doc.page_content} for i, doc in enumerate(relevant_docs)]) answer qa_chain.run(contextcontext_text, questionquestion) return answer # 测试 question “用户登录接口的请求体需要哪些必填字段” result answer_question(question) print(result)这个流程实现了从文档处理、混合检索、到最终生成回答的完整上下文工程链路。你会发现当文档被良好地组织并检索时即使使用非常朴素的Prompt模板模型也能给出准确、有据可查的回答。5. 进阶挑战与优化策略构建基础系统只是第一步。要让其在生产环境中稳定、高效、可靠还需要解决一系列进阶问题。5.1 解决“检索不相关”与“信息缺失”这是RAG系统最常见的两大痛点。问题检索到的上下文不相关。排查首先检查嵌入模型是否与你的领域匹配。通用嵌入模型对专业术语可能不敏感。可以尝试在领域数据上微调嵌入模型或使用领域专用模型。优化强化查询改写。使用一个小型LLM如Qwen1.5-7B专门负责将用户口语化、简短的问题改写成包含核心术语、更利于检索的陈述句。例如将“怎么登录”改写成“用户登录认证的流程、接口和必填参数”。引入元数据过滤在检索时除了语义相似度同时利用文档的元数据如文档类型、产品模块、创建日期进行过滤。Chroma和Weaviate都支持元数据过滤检索。问题上下文信息足够但模型仍回答“不知道”或胡编乱造。排查检查Prompt模板是否明确指令模型“基于上下文回答”。模型可能忽略了你的指令转而调用其内部知识。优化在Prompt中使用更强的系统指令和格式化要求。例如在系统指令中强调“你必须且只能使用提供的参考资料来回答问题”。在上下文的格式上使用XML标签或特殊标记明确区分上下文和指令如document.../document。后处理验证实现一个简单的验证步骤让另一个轻量模型或规则判断生成的答案是否能在提供的上下文中找到明确支持。如果不能则触发重新检索或返回“信息不足”。5.2 长上下文与多文档处理的技巧当处理书籍、长报告等多文档时挑战更大。层次化索引不要只建一个平面的块索引。可以构建两级索引摘要级为每个文档或每个章节生成一个摘要单独建立索引。用于回答概括性问题。细节级标准的文本块索引。用于回答具体细节问题。 用户提问时先检索摘要级定位相关文档/章节再在该范围内进行细节级检索。图结构增强如果文档内部有强烈的引用关系如技术文档中A模块调用B接口可以将这些关系构建成知识图。检索时不仅检索相关块也检索其关联块提供更全面的上下文。迭代式检索与生成对于复杂问题采用“检索-阅读-生成-再检索”的循环。模型先根据初步检索生成一个初步答案或问题分解列表然后针对其中不确定的部分发起新一轮更精准的检索。5.3 评估与监控如何衡量上下文工程的好坏没有评估优化就无从谈起。需要建立一套评估体系。检索评估指标命中率对于一组有标准答案的问题检索到的Top-K个文档中包含正确答案的比例。平均排序倒数正确答案在检索结果列表中的平均排名的倒数。值越高说明正确答案排得越靠前。生成评估指标忠实度生成答案是否严格基于提供的上下文有无篡改或添加未提及信息。可以用NLI模型或让GPT-4充当裁判进行判断。答案相关性答案是否直接回答了问题。可溯源比例答案中的关键主张有多少比例能在上下文中找到明确出处。生产环境监控记录每次问答的检索到的文档ID、用户问题、生成答案。计算每次调用的令牌消耗特别是上下文令牌监控成本。设置人工反馈渠道收集“点赞/点踩”将bad case加入测试集用于持续优化。6. 常见陷阱与避坑指南在我和团队实施上下文工程的过程中踩过不少坑。这里分享几个最具代表性的希望能帮你绕开。陷阱一盲目追求最先进的嵌入模型。早期我们迷信某个评测榜单第一的模型但实际使用发现它对我们的行业术语很多是英文缩写嵌入效果很差。后来换了一个在通用榜单上排名稍后但在我们领域数据上微调过的模型效果立竿见影。教训嵌入模型一定要用你自己的业务数据做小规模测试比如100个问答对。评测榜单的“冠军”不一定适合你的具体场景。陷阱二分块大小“一刀切”。我们曾对所有文档使用256字符的小块结果在回答“请对比A方案和B方案”这类需要全局视野的问题时模型得到的都是碎片根本无法进行有效对比。教训采用多粒度分块索引。针对“概括性”问题和“细节性”问题从不同大小的块索引中检索。或者在检索后增加一个“上下文聚合”步骤将相关的小块合并成一个更大的语义单元再送给模型。陷阱三忽略元数据的力量。我们的文档包含多个产品版本但检索时没有过滤版本。导致用户问最新版功能模型却引用了旧版文档的内容造成严重错误。教训在文档解析阶段务必提取并保留所有有价值的元数据文档类型、产品、版本、创建日期、作者、章节标题等。在检索时将这些元数据作为强过滤器使用。陷阱四Prompt模板过于复杂。为了追求“完美”我们设计了一个包含七八条规则、各种格式要求的复杂Prompt。结果发现模型有时会困惑甚至开始“讨论”起Prompt本身的规则来。教训Prompt指令要清晰、简洁、重点突出。核心指令基于上下文回答、不要编造放在最前面。复杂的格式要求可以逐步添加并通过测试确保模型能稳定遵循。KISS原则同样适用于Prompt设计。陷阱五没有建立评估闭环。系统上线后我们只是被动处理用户反馈。直到一次季度复盘才发现某个核心模块的问答准确率已经悄然下降了15%原因是该模块的文档经历了大规模更新而我们的知识库没有及时同步。教训必须建立自动化的评估流水线。定期用标准问题集测试系统关键指标。建立文档更新与向量库重建的自动化触发机制。将上下文工程视为一个需要持续运维和迭代的“活系统”而不是一劳永逸的“一次性项目”。从“拼命调Prompt”到“系统做上下文”这种思维的转变是AI应用开发从手工作坊走向工程化的重要一步。它要求我们更深入地理解数据、更精细地设计流程、更全面地评估系统。这个过程充满挑战但当你看到自己构建的系统能够稳定、可靠地处理复杂问题时那种成就感远非调出一个“神奇Prompt”可比。上下文工程才是AI应用背后那个沉默的基石。