上下文工程:让你的AI对话不再“失忆”

前言

在大型语言模型(LLMs)领域,Context Engineering(上下文工程)是一项至关重要的精细艺术,尤其在构建高效能AI智能体时更显其价值。这项技术专注于精心筛选信息,并将其精准置入LLM有限的“内容窗口”中,为模型后续处理提供最优的信息环境。

LLM的核心工作区正是其“内容窗口”。然而,这个工作区的容量是有限的——上下文工程的精髓就在于为这个有限的空间进行信息筛选,确保LLM获得执行任务所需的“恰到好处”的信息:既要包含完成任务的所有必要元素,又要避免冗余信息的干扰。

什么是上下文?为什么它如此重要?

想象一下,如果你走进办公室,突然对同事说:“那个项目怎么样了?”同事肯定会一脸茫然。但如果你先说:“我上个月负责的客户服务升级项目”,再问“那个项目怎么样了?”,同事立即明白你在问什么。

这就是上下文的力量——它为对话提供了背景和理解的基础。

在AI对话中,上下文就是我们提供给AI的背景信息、对话历史和相关知识。它决定了AI是否能真正理解我们的意图。

AI的“记忆”有什么特点?

每个AI都有一个工作记忆区,就像我们的短期记忆。但这个记忆区有两个重要特点:容量有限,不能无限存储信息,智能系统的上下文窗口也有固定大小。主流模型的上下文长度从4K到128K token不等(1个token约等于0.75个英文单词);需要引导,需要我们提供合适的背景线索,既要包含必要元素,又要避免冗余。。

这就好比给一个新同事交代工作:说得太简单,他听不懂;说得太详细,他可能抓不住重点。

代码实战

就拿有上下文跟没有上下文模型的反馈来看效果(show me code)

import requests
import json
import time

# ==================== 全局配置 ====================
# 请根据你的聚合平台信息修改以下配置
BASE_URL = "https://api.ufunai.cn/v1"  # 替换为你的平台地址
API_KEY = "sk-xxxxx"  # 替换为你的API密钥
MODEL_NAME = "gpt-4-turbo"  # 指定要测试的模型名称


def test_without_context():
    """无上下文测试"""
    print("=== 无上下文测试 ===")

    # 直接提问,不提供任何背景
    prompt = "介绍一下这位作家"

    response = call_model(prompt)
    print(f"问题: {prompt}")
    print(f"回答: {response}")
    print()

    return response


def test_with_context():
    """有上下文测试"""
    print("=== 有上下文测试 ===")

    # 提供充分的上下文
    prompt = """
    背景信息:
    - 鲁迅(1881年9月25日-1936年10月19日),原名周树人,浙江绍兴人
    - 他是中国现代文学的奠基人之一,代表作有《狂人日记》、《阿Q正传》等
    - 他的作品对中国社会和文化产生了深远影响

    问题:介绍一下这位作家
    """

    response = call_model(prompt)
    print(f"问题: 介绍一下这位作家")
    print(f"回答: {response}")
    print()

    return response


def test_conversation():
    """对话式上下文测试"""
    print("=== 对话式上下文测试 ===")

    # 模拟多轮对话
    conversation = [
        {"role": "user", "content": "我想了解中国现代文学"},
        {"role": "assistant",
         "content": "好的,中国现代文学有很多杰出的作家,比如鲁迅、茅盾、巴金等。您对哪位作家特别感兴趣?"},
        {"role": "user", "content": "鲁迅"},
        {"role": "assistant",
         "content": "鲁迅是中国现代文学的奠基人之一,他的作品深刻反映了当时的社会现实。您想了解他的哪方面?"},
        {"role": "user", "content": "他的代表作有哪些?"}
    ]

    response = call_model_with_history(conversation)

    print("对话历史:")
    for msg in conversation:
        print(f"{msg['role']}: {msg['content']}")
    print(f"最终回答: {response}")
    print()

    return response


def  call_model(prompt):
    """调用模型(单轮对话)"""
    headers = {
        'Content-Type': 'application/json',
        'Authorization': f'Bearer {API_KEY}'
    }

    payload = {
        "model": MODEL_NAME,
        "messages": [{"role": "user", "content": prompt}],
        "max_tokens": 500,
        "temperature": 0.7
    }

    try:
        response = requests.post(
            f"{BASE_URL}/chat/completions",
            headers=headers,
            json=payload,
            timeout=30
        )

        if response.status_code == 200:
            try:
                result = response.json()
                content = result['choices'][0]['message']['content']
                return content
            except Exception:
                return f"响应非JSON: {response.text[:1000]}"
        else:
            return f"请求失败: HTTP {response.status_code} - {response.text[:1000]}"

    except Exception as e:
        return f"请求异常: {str(e)}"


def call_model_with_history(messages):
    """调用模型(带对话历史)"""
    headers = {
        'Content-Type': 'application/json',
        'Authorization': f'Bearer {API_KEY}'
    }

    payload = {
        "model": MODEL_NAME,
        "messages": messages,
        "max_tokens": 500,
        "temperature": 0.7
    }

    try:
        response = requests.post(
            f"{BASE_URL}/chat/completions",
            headers=headers,
            json=payload,
            timeout=30
        )

        if response.status_code == 200:
            try:
                result = response.json()
                content = result['choices'][0]['message']['content']
                return content
            except Exception:
                return f"响应非JSON: {response.text[:1000]}"
        else:
            return f"请求失败: HTTP {response.status_code} - {response.text[:1000]}"
    except Exception as e:
        return f"请求异常: {str(e)}"


def compare_results():
    """对比不同上下文情况下的回答"""
    print("上下文工程实战演示")
    print("=" * 50)

    # 无上下文测试
    result1 = test_without_context()

    # 有上下文测试
    result2 = test_with_context()

    # 对话式上下文测试
    result3 = test_conversation()

    # 分析对比
    print("=== 对比分析 ===")
    print(f"无上下文回答长度: {len(result1) if isinstance(result1, str) else 0} 字符")
    print(f"有上下文回答长度: {len(result2) if isinstance(result2, str) else 0} 字符")
    print(f"对话式回答长度: {len(result3) if isinstance(result3, str) else 0} 字符")

    # 简单的内容质量分析
    keywords = ["鲁迅", "周树人", "狂人日记", "阿Q正传"]

    print("\n关键词覆盖情况:")
    for keyword in keywords:
        count1 = result1.count(keyword) if isinstance(result1, str) else 0
        count2 = result2.count(keyword) if isinstance(result2, str) else 0
        count3 = result3.count(keyword) if isinstance(result3, str) else 0
        print(f"'{keyword}': 无上下文({count1}) 有上下文({count2}) 对话式({count3})")


if __name__ == "__main__":
    # 检查配置
    if BASE_URL is None or API_KEY is None:
        print("请先修改代码中的配置信息")
        print("需要修改的配置:")
        print(f"BASE_URL: {BASE_URL}")
        print(f"API_KEY: {API_KEY}")
    else:
        compare_results()

程序运行结果如下:

上下文工程实战演示
==================================================
=== 无上下文测试 ===
问题: 介绍一下这位作家
回答: 请问您可以提供这位作家的名字或者相关信息吗?这样我可以更详细地介绍他/她的作品和生平等信息。

=== 有上下文测试 ===
问题: 介绍一下这位作家
回答: 鲁迅,原名周树人,是中国现代文学的重要奠基人之一,出生于浙江绍兴。他的作品在中国文学史上具有划时代的意义,不仅因其深刻的社会批判和人性探索,也因其独特的文学风格和表现手法。鲁迅的文学创作涵盖了小说、散文、杂文、诗歌等多种体裁,其中《狂人日记》被视为中国现代文学的开端,通过讽刺和批判揭示了社会的种种问题和人性的扭曲。《阿Q正传》则通过主人公阿Q的形象,揭示了民众的愚昧和被压迫的悲哀,同时也批判了旧社会的残酷与不公。鲁迅的作品不仅在文学上具有高度成就,同时也对中国社会和文化产生了深远的影响,被誉为文化大革命的精神旗帜之一。

=== 对话式上下文测试 ===
对话历史:
user: 我想了解中国现代文学
assistant: 好的,中国现代文学有很多杰出的作家,比如鲁迅、茅盾、巴金等。您对哪位作家特别感兴趣?
user: 鲁迅
assistant: 鲁迅是中国现代文学的奠基人之一,他的作品深刻反映了当时的社会现实。您想了解他的哪方面?
user: 他的代表作有哪些?
最终回答: 鲁迅的代表作品有很多,其中比较著名的有:

1. 《呐喊》:这是鲁迅的第一部短篇小说集,收录了《狂人日记》、《阿Q正传》等经典作品,揭示了封建社会的种种弊端。

2. 《彷徨》:这也是一部短篇小说集,包括《孔乙己》、《药》等作品,同样展现了社会的黑暗和人性的复杂。

3. 《故事新编》:这是鲁迅晚期的创作,采用寓言和讽刺的形式,批判了当时的社会现实。

4. 杂文集《热风》、《坟》等,其中包含了鲁迅对文化、社会、政治等方面的深刻见解。

这些作品都是中国现代文学中的经典,对理解鲁迅的思想和中国现代社会的发展都有很大的帮助。

=== 对比分析 ===
无上下文回答长度: 46 字符
有上下文回答长度: 262 字符
对话式回答长度: 264 字符

关键词覆盖情况:
'鲁迅': 无上下文(0) 有上下文(3) 对话式(5)
'周树人': 无上下文(0) 有上下文(1) 对话式(0)
'狂人日记': 无上下文(0) 有上下文(1) 对话式(1)
'阿Q正传': 无上下文(0) 有上下文(1) 对话式(1)

从返回的结果可以看出

场景

回答与问题的相关性

说明

无上下文

0-20%

无法确定"这位作家"指谁,回答往往需要进一步澄清

有上下文提示词

80-90%

明确知道讨论对象是鲁迅,回答直接相关

多轮对话上下文

95-100%

不仅知道是鲁迅,还了解用户的学习意图和知识背景

有上下文能显著提升回答质量回答相关性提高4倍以上

常见的上下文问题

背景信息不足:AI的回答泛泛而谈,不够精准。比如你说“推荐几本书”,AI可能推荐大众畅销书。但如果你说“我是程序员,想学习项目管理,推荐几本书”,AI就能推荐更专业的书籍。

信息过多过杂:AI会“分心”,回答偏离核心。就像同时给新人交代10项工作,他反而不知道先做什么。

信息前后矛盾:AI会感到困惑,不知道以哪个为准。比如先说“客户预算有限”,后说“不用考虑价格”,AI就不知道该如何处理。

三个实用技巧,让你的对话更顺畅

先搭舞台,再唱戏:在问问题之前,先建立清晰的背景。

比如不要直接问“这个怎么样?”,而是说“我正在考虑买一台笔记本电脑,主要用于办公和偶尔的视频剪辑,预算5000左右。联想小新这个型号怎么样?”

保持对话的连续性:像真人聊天一样,让对话自然延续。

不要每次提问都当作全新的对话,而是基于之前的讨论继续深入。比如:“刚才我们讨论的营销方案,如果目标客户是年轻人,需要调整哪些部分?”

适时总结,轻装前行:当对话较长时,适时地进行总结。

比如:“我们来梳理一下目前确定的要点:1. 主打年轻人群 2. 侧重社交媒体 3. 预算10万。基于这三点,下一步具体怎么做?”

总结

上下文工程既是科学也是艺术。技术上,它涉及token管理信息架构对话状态维护;艺术上,它要求我们像与人交流一样,懂得如何铺垫、如何强调、如何收束。

一句话总结:把之前说过的话,作为前置条件给到大模型,让大模型在后续的对话中把这个前置条件作为事件背景,这样大模型就能更好的理解你了!

下次与AI对话时,不妨多想一步:我给的信息足够让AI理解我的真实需求吗?背景清晰吗?上下文连贯吗?

掌握了上下文的艺术,你会发现AI不再是机械地回答,而是真正理解你需求的智能助手。这不仅是技术,更是沟通的艺术——而这份艺术,完全掌握在你的手中。

好的对话,从好的上下文开始。从现在起,做个会“铺垫”的对话高手吧!

源代码如需获取,请关注公众号,发送消息ufunai-context获取,扫一扫即可获取!

创作不易,码字更不易,如果觉得这篇文章对你有帮助,记得点个关注、在看或收藏,给作者一点鼓励吧~

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

softkit

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值