什么是模型上下文工程
什么是模型上下文工程
想象这样一个场景:你在机场候机时遇到一位陌生人,你向他请教一个关于企业管理的问题。这位陌生人学识渊博、思维敏捷,理论上完全有能力给出精彩的回答。然而,当你开口询问时,他一脸茫然——他不知道你是谁,不知道你的企业规模有多大,不了解你面临的具体困境,更不知道你问这个问题的真实目的。你得到的回答,可能是一番泛泛而谈的大道理,与你的实际情况相去甚远。
这个“聪明的陌生人”,正是当前人工智能系统在缺乏上下文信息时的真实写照。模型上下文工程要解决的,正是如何让这位“陌生人”变成一位“熟悉你的顾问”——他知道你是谁,记得你们之前聊过什么,理解你当下的处境,并能够据此提供真正有价值的建议。
上下文的本质
“上下文”(Context)这个词在计算机科学和语言学领域有着深厚的学术传统。追根溯源,“上下文”一词源于拉丁语“contextus”,意为“编织在一起”,强调的是事物之间的关联性和整体性。在语言学中,上下文指的是理解和解释某一语言片段所必需的周围语言环境——一个词的意义往往取决于它所处的语境。在计算机科学中,上下文则泛指系统或程序在特定时刻所处的状态和环境。
对于人工智能语言模型而言,上下文具有更加丰富的内涵。从功能层面来看,AI系统的上下文主要包括以下几个维度:
对话历史上下文是最容易理解的部分。当用户与AI进行多轮对话时,每一轮对话的内容都构成了上下文的一部分。AI需要知道之前讨论过什么、用户提出过什么问题、系统给出过什么回答,这些信息共同构成了理解的基石。缺乏对话历史,AI就如同一个只能记住当前一句话的“瞬间失忆者”,无法建立真正的对话连续性。
用户背景上下文包含关于用户的各种信息:用户的身份特征、专业领域、历史偏好、交流习惯等。这些信息帮助AI理解用户的知识水平,从而调整解释的深度和语气;了解用户的偏好,从而提供更加个性化的回答;预判用户的需求,从而主动提供可能有用但未被明确询问的信息。
任务场景上下文描述的是用户当前正在做什么、想做什么。用户可能正在写一份报告、调试一段代码、分析一份数据、规划一次旅行。不同的任务场景需要不同的知识、技能和策略。用户说“帮我看看”,在代码调试场景下意味着检查语法错误,在文档审阅场景下意味着评估内容质量,在数据分析场景下则意味着检验统计结论。
领域知识上下文是指与当前话题相关的专业知识、背景资料、参考资料等。当用户询问关于某个专业领域的问题时,AI需要相应的领域知识来提供准确的回答;当用户提交一份文档要求分析时,AI需要先理解文档的内容才能给出有价值的反馈。
上下文工程中有一个经典比喻:将AI模型比作一位记忆力有限但极其聪明的助手。这位助手非常聪明,给他任何任务都能找到解决方法;但他的记忆力有限,只能同时记住一定量的信息。这位助手需要什么才能有效工作?他需要知道自己要做什么任务、需要哪些背景材料、之前的进展如何、用户有什么特殊要求。所有这些信息——就是我们要精心管理的“上下文”。
为什么上下文如此关键
理解上下文的重要性,最好的方式是通过对比。相同的用户提问,在有无上下文的情况下,AI给出的回答可能有着天壤之别。
场景一:无上下文的情况
用户打开一个新的AI对话窗口,直接输入:
> “帮我写一个函数,判断一个数是否为质数。”
AI的回答:
> ```python > def is_prime(n): > if n < 2: > return False > for i in range(2, int(n**0.5) + 1): > if n % i == 0: > return False > return True > ``` > > 这是一个判断质数的函数。对于小于2的数返回False,从2到平方根逐一检查是否有因数。
场景二:有上下文的情况
用户在同一对话中,但之前已经进行了大量交流。在当前对话开始时,用户描述道:
> “我正在准备技术面试,需要系统复习算法知识。目前在学习基础数论模块。我是一个Python初学者,希望代码既简洁易懂,又能看到背后的原理。”
然后用户输入同样的问题:
> “帮我写一个函数,判断一个数是否为质数。”
AI的回答:
> ```python > def is_prime(n): > """ > 判断n是否为质数 > > 质数的定义:大于1的自然数,除了1和它本身以外不再有其他因数 > 例如:2, 3, 5, 7, 11, 13... > > 思路:不需要检查所有可能的因数,只需检查到√n即可 > 原因:如果n = a × b,其中a ≤ b,那么a ≤ √n > 这样可以把检查次数从O(n)降低到O(√n) > """ > if n < 2: > return False # 质数必须大于1
> # 只需要检查从2到√n的范围 > for i in range(2, int(n**0.5) + 1): > if n % i == 0: > return False # 找到了因数,说明不是质数 > return True # 没有找到因数,说明是质数 > ``` > > 这是一个质数判断函数,特别适合面试准备。让我解释几个要点: > > 为什么从2开始检查? 质数的定义要求大于1,所以1和0直接返回False。 > > 为什么只检查到平方根? 这是面试中经常被问到的优化点。如果n = a × b,那么较小的那个因数一定不超过√n。比如100 = 10 × 10,7 × 14 = 98,较小因数7 < √98 ≈ 10。 > > 时间复杂度分析 这是面试必考点。优化前是O(n),优化后是O(√n)。当n很大时,比如判断10007是否为质数,优化后只需检查到100左右,而不是检查到10006。 > > 面试扩展问题 面试官可能会追问:如果要生成一定范围内的所有质数呢?这时应该使用埃拉托斯特尼筛法(Sieve of Eratosthenes),时间复杂度可以进一步优化到O(n log log n)。
这两段回答的技术准确性可能相当,但用户体验和实用价值却截然不同。第一段回答是一个标准答案,简洁但冰冷,不知道用户是谁、水平如何、用来做什么。第二段回答则是一位贴心的面试教练,他知道用户在学习数论模块,特意讲解了时间复杂度的分析,预测了可能的追问方向,还用了“面试必考点”这样的贴心标签。
这种差异的根本原因在于上下文信息的缺失。没有上下文时,AI只能给出一个“标准答案”,至于这个答案是否真正适合用户的需要,它无从知晓。加上完整的上下文后,AI就能够“量体裁衣”,提供真正有价值的帮助。
这个对比揭示了上下文在三个核心层面的关键作用。
第一,上下文决定回答的相关性。 用户的提问表面上看是一个独立的问题,但实质上总是嵌入在特定的背景中。一个看似简单的代码问题,对于正在准备面试的学生和正在修复生产环境Bug的工程师,需要完全不同的回答——前者需要原理解释和复杂度分析,后者需要快速定位和稳妥修复。没有上下文,AI无法判断用户处于什么场景,也就无法给出最相关的回答。
第二,上下文决定回答的准确性。 人类的表达天然具有省略性和模糊性。当用户说“看看这个文件有什么问题”,我们省略了“看看”的目的、“问题”的类型、“文件”的内容。没有上下文,AI只能猜测这些被省略的信息,猜对的概率并不比掷骰子高多少。有了上下文——比如用户之前说“我在审核供应商合同”——AI就能够准确理解用户的真实意图。
第三,上下文决定用户体验。 想象你向一位顾问求助,每次开口都要重新介绍自己的情况、复述之前的讨论、解释自己的需求。这种重复劳动带来的挫败感,不言而喻。有了良好的上下文管理,AI能够记住之前说过什么、讨论到哪里、用户偏好是什么,用户不需要重复自己,交流变得自然流畅。
上下文工程的技术支柱
模型上下文工程并非单一技术,而是一套系统性的技术体系。从功能实现的角度,这套体系可以分解为四大技术支柱:长上下文、压缩摘要、检索记忆、状态管理。它们各有分工、相互配合,共同支撑起AI系统的上下文能力。
长上下文:扩展模型的阅读能力
当代大型语言模型在设计时都会定义一个参数,称为上下文窗口(Context Window),这个参数规定了模型单次能够处理的最大文本量,通常以“Token”为单位计量。Token可以理解为文本处理的基本单位,对于英文大约相当于4个字符或3/4个单词,对于中文则大约相当于1到2个汉字。
上下文窗口的大小直接决定了模型能够“阅读”多长的文本。早期的GPT-3模型上下文窗口约为2000个Token,这意味着它最多只能同时处理相当于几页纸的文本量。到了GPT-4,上下文窗口扩展到了32K Token(约等于25000个单词),足以处理一篇中长篇论文。而Anthropic公司在2024年推出的Claude 3.5模型,更是将上下文窗口提升到了200K Token——这意味着模型可以一次性阅读并理解一部《战争与和平》这样的长篇巨著。
上下文窗口的扩展为什么重要?因为在许多真实应用场景中,用户需要AI处理的文本量远超早期模型的承载能力。
考虑这样一个场景:用户是一家大型企业的法务人员,需要审查一份数百页的采购合同,找出其中的风险条款和法律漏洞。如果AI的上下文窗口只有几千Token,它只能看到合同的一小部分,可能遗漏关键的风险条款,或者无法理解前后条款之间的关联关系。如果AI的上下文窗口达到200K Token,它就可以一次性“阅读”整份合同,理解合同的完整结构和逻辑关系,从而给出更加全面和准确的分析。
另一个典型场景是多轮长对话。用户可能与AI讨论一个复杂的技术项目,从项目背景聊到技术方案,从技术方案聊到代码实现,从代码实现聊到调试优化。这种讨论可能跨越几十甚至上百轮对话,总的文本量可能达到数万甚至数十万Token。没有足够大的上下文窗口,AI就无法“记住”早期讨论的内容,用户需要不断重复之前说过的信息,既费时又费力。
然而,扩展上下文窗口并非没有代价。计算成本随着上下文长度的增加而急剧上升——处理200K Token的计算量是处理8K Token的25倍。更重要的是,当上下文变得极长时,模型可能会出现所谓的“中间丢失”(Lost in the Middle)问题:模型对上下文开头和结尾的内容记得比较清楚,但对中间部分的内容却记忆模糊。
长上下文技术的发展,正是要解决这两个问题:一是通过算法优化和工程改进,降低长上下文的计算成本;二是通过更好的注意力机制设计,确保模型能够均匀地关注上下文的各个部分。这些技术细节,将在后续章节中深入探讨。
压缩摘要:信息的提炼与精简
即使上下文窗口在不断扩展,它终究是有限的。面对真正海量的信息——比如整个图书馆的藏书、企业的全部历史文档、一个人终生的记忆——再大的上下文窗口也会显得不够用。
这时候,就需要压缩摘要技术出场了。压缩摘要的核心思想是:当信息量超过模型的处理能力时,我们需要在保留最关键信息的前提下,对信息进行压缩精简。
想象你正在阅读一本800页的巨著,现在需要向朋友介绍这本书的核心内容。你不可能把整本书复述一遍,你需要提炼出最精华的部分——主要情节、核心人物、主题思想、重要观点——用几百字的篇幅呈现全书的精髓。压缩摘要要做的事情,本质上与此类似。
在AI系统的上下文中,压缩摘要有多种实现策略。递归摘要是最直观的方式:先将长文本分成若干段落,对每个段落进行摘要;然后将段落摘要组合起来,再次进行摘要,如此递归,直到得到一个长度合适的最终摘要。这种方法的好处是保持了层次结构,适合处理具有明确章节结构的文档。
层次摘要则更适合处理复杂的文档体系,比如一整个文件夹中的数百份文件。系统首先对每份文件单独摘要,然后按照主题、类别或时间线对文件进行聚类,对每个类别进行二次摘要,最终形成一个多层级的摘要结构。这样,用户既可以鸟瞰全部内容的概览,也可以深入某个类别查看细节。
动态摘要则针对上下文不断增长的场景。最典型的例子是长对话:当对话进行到几十轮后,累积的对话历史可能已经非常长。动态摘要的方法是,在保持完整历史的同时,系统性地对历史内容进行提炼——将多轮对话的核心内容合并成更简洁的表述,保留关键信息和重要结论,丢弃过渡性的寒暄和细节。这种方式让模型在保持对话连贯性的同时,不至于被历史负担压垮。
压缩摘要技术的难点在于“保真度”——如何在压缩的同时不丢失关键信息?如何判断哪些信息是重要的、哪些是可以舍弃的?这些问题没有简单的答案,需要根据具体应用场景精心设计。一个不当的摘要可能导致关键信息被遗漏,从而让AI给出错误或误导性的回答。
检索记忆:按需获取的外部知识库
压缩摘要是通过对信息进行“瘦身”来适应有限的上下文窗口,而检索记忆则采用了另一种思路:与其把所有信息都塞进模型的大脑,不如为模型配备一个“图书馆”,让它在需要时去检索所需的信息。
检索记忆的核心机制可以分为三个步骤。首先是索引构建:当用户提交大量文档或知识库时,系统使用嵌入模型(Embedding Model)将这些文本转换为向量——一种数值表示——并存储在向量数据库中。相似的文本会拥有相似的向量,这为后续的检索提供了数学基础。
然后是检索查询:当用户提出问题时,系统同样将问题转换为向量,然后在向量数据库中搜索与问题最相似的文档片段。这就像在图书馆中通过关键词或主题检索相关的书籍——只不过检索的依据是向量相似度而非传统的关键词匹配。
最后是结果注入:找到的相关文档片段被提取出来,作为上下文的一部分注入到模型的输入中。这样,模型就能够“看到”它原本不知道的信息,从而给出更加准确和详实的回答。
检索记忆的优势在于按需获取。用户不需要提前告诉AI它可能需要哪些信息,AI会在处理当前任务时自动判断需要什么信息,然后去检索获取。这大大减轻了用户管理上下文的负担。
一个典型的应用场景是个人知识库问答。想象用户将多年的笔记、邮件、文档全部导入系统,构建了一个个人知识库。当用户询问“去年第三季度我做过哪些重要项目”时,系统会检索知识库中相关的邮件和笔记,将这些材料作为上下文提供给AI。AI的回答将基于这些真实的个人材料,而非泛泛的通用知识。
另一个应用场景是企业文档智能。企业的规章制度、合同模板、历史决策、产品文档,这些信息量巨大且不断更新。通过检索记忆系统,AI可以实时查询最新的企业文档,为员工提供基于企业实际信息的咨询回答。
检索记忆技术也面临着挑战。检索质量是关键——如何确保检索到的内容真正相关?如何处理模糊或歧义的查询?延迟问题也需要考虑——检索增加了系统的响应时间,如何优化检索速度?多跳推理则更加复杂——有些问题需要综合多个文档的信息才能回答,这要求系统具备跨文档关联和推理的能力。
状态管理:维护对话的连续性
多轮对话是AI助手最基本的使用形态,而状态管理正是确保对话连续性的关键技术。
在一个有效的对话中,AI需要记住很多东西:用户之前说了什么、自己之前回答了什么、用户确认了什么信息、用户否定了什么信息、当前讨论的主题是什么、用户正在尝试完成什么任务。这些信息共同构成了对话的“状态”,状态管理就是要维护和更新这个状态。
举一个订餐助手的例子。用户说:“我想订一个今晚的位子,两个人。”AI回答后,用户说:“要靠窗的。”AI记住“两个人”“今晚”“靠窗”这些信息。用户又说:“有没有推荐?”AI结合已有的状态推荐适合两人用餐的餐厅或菜品。用户最终说:“就第二个吧,帮我预订。”AI需要综合之前所有的状态信息——人数、时间、位置偏好、选择的餐厅——完成预订操作。
在这个过程中,如果状态管理出了问题,比如忘记了“两个人”这个信息,AI就可能预订成单人位;如果忘记了“今晚”这个时间,可能预订成明晚。这种状态丢失会导致用户体验急剧下降。
状态管理的挑战主要来自几个方面。状态复杂性随着对话深入而增加。当对话只有两三轮时,状态很简单;但当对话涉及多个主题、分支逻辑、跨会话需求时,状态管理就变得相当复杂。状态一致性也是问题——如果用户在不同轮次中对同一事项给出了矛盾的信息,AI应该以哪一轮为准?可扩展性则关系到系统能否优雅地处理长期对话——随着对话进行,状态信息越来越多,如何避免状态膨胀导致的性能问题?
现代的状态管理实践通常采用显式状态表示与隐式状态推断相结合的方式。显式状态表示是指系统维护一个结构化的状态对象,记录关键信息的当前值;隐式状态推断则是指利用大模型本身的能力,根据对话历史自动推断当前状态的合理表示。这种结合既能保证状态信息的可靠性,又能灵活处理复杂的对话场景。
评估上下文工程的实践框架
理解了这四大技术支柱之后,我们需要进一步思考:什么样的上下文工程实践是好的?有哪些原则可以指导我们的设计决策?
上下文工程的核心目标是最大化AI系统的有效性和效率。基于这个目标,可以提炼出三个维度的评估框架。
有效性是第一位的。上下文必须准确——提供给AI的信息必须真实可靠,错误的上下文会导致AI给出错误的回答。上下文必须相关——只提供与当前任务相关的信息,过多无关信息会分散模型的注意力,降低回答质量。上下文必须完整——遗漏关键信息会导致回答不充分,用户得不到真正需要的帮助。
以文档分析为例。假设用户要求分析一份300页的技术白皮书,其中有一项关键技术指标。用户希望AI评估这项技术的市场竞争力,并给出投资建议。如果上下文只提供了白皮书的前几章,AI可能只了解技术原理,却不了解市场竞争格局和商业前景分析,自然无法给出有价值的投资建议。如果上下文提供了整份白皮书但遗漏了这部分关键技术指标,AI的分析同样是残缺的。有效的上下文,应该既完整覆盖又突出重点。
效率是第二个考量维度。上下文信息的增加会带来计算成本的上升——Token数量越多,模型处理的时间越长,消耗的资源越多。上下文工程需要在信息充分性和计算效率之间寻找平衡。
一个典型的效率考量例子是长文档处理。当用户提交一份100页的文档并要求总结时,是否需要把100页全部作为上下文?如果上下文窗口足够大,这当然可以做到,但计算成本会很高。更好的做法可能是:首先通过压缩摘要技术提炼出文档的核心内容;如果用户的具体问题涉及文档的某个部分,再针对性地检索那部分的内容作为补充。这样既保证了回答质量,又控制了计算成本。
可维护性是第三个维度,尤其对于复杂应用系统至关重要。上下文管理不应该是一个混乱的、难以调试的黑箱,而应该是清晰的、可追踪的、易于