纯干货!Agentic AI上下文工程架构设计的6个关键步骤
关键词
Agentic AI、上下文工程、记忆机制、多模态融合、向量检索、动态优化
摘要
Agentic AI(智能代理AI)的核心能力是自主感知-决策-行动,而支撑这一能力的“隐形地基”正是上下文工程——它让Agent像人类一样“记住过去、理解现在、预判未来”。如果把Agent比作餐厅里的优秀服务员,上下文就是他记住的“顾客忌口、之前点的菜、当前餐厅座位状态”;如果把Agent比作自动驾驶汽车,上下文就是它感知的“当前路况、之前的行驶路线、乘客的目的地偏好”。
本文将拆解Agentic AI上下文工程架构设计的6个关键步骤,从“需求建模”到“迭代优化”,覆盖从0到1的全流程。你将学到:
- 如何定义Agent需要的“上下文类型”?
- 如何融合多源数据(文本/传感器/第三方系统)成统一上下文?
- 如何设计“短期记忆+长期记忆”的双存储机制?
- 如何让Agent在决策时精准检索有用上下文?
- 如何用数学模型和代码实现这些逻辑?
无论你是Agent系统设计师、AI开发者还是产品经理,这篇纯干货都能帮你搭建“可落地的上下文工程架构”。
1. 背景:为什么Agentic AI离不开上下文工程?
1.1 从“单次交互”到“持续行动”:Agentic AI的核心变化
传统AI(比如ChatGPT的单次对话)是“输入-输出”的单次交互——用户问“天气怎么样”,AI返回结果,任务结束。但Agentic AI是持续行动的闭环系统:它需要感知环境→根据历史信息决策→执行行动→再感知新环境→调整决策……循环往复。
比如:
- 智能学习助手Agent:需要记住你“昨天学了第3章、喜欢视频讲解”,今天你问“第4章重点”时,它能推荐视频版重点;
- 自动驾驶Agent:需要记住“之前路过这个路口时堵车”,今天再到这里时提前变道;
- 客服Agent:需要记住“用户上周投诉过物流慢”,今天用户问“我的快递呢”时,直接关联历史投诉,快速响应。
没有上下文工程,Agent会变成“金鱼”——每一步行动都像第一次交互,完全“失忆”。
1.2 上下文工程的核心挑战
Agentic AI的上下文不是“堆数据”,而是要解决3大矛盾:
1.3 目标读者与价值
本文目标读者:
- AI开发者:需要落地Agent系统,却不知道如何设计上下文存储/检索逻辑;
- Agent设计师:想让Agent更“聪明”,但不懂如何将用户偏好、环境状态转化为决策依据;
- 产品经理:需要理解Agent的技术边界,定义合理的产品功能。
读完本文,你将掌握:
- 一套“可复制的上下文工程流程”;
- 用代码实现“短期记忆+长期记忆”的方法;
- 用数学模型量化上下文的“相关性”与“价值”。
2. 核心概念解析:Agentic AI与上下文工程的“底层逻辑”
2.1 什么是“Agentic AI”?
Agentic AI的官方定义是:能自主感知环境、设定目标、决策行动、学习进化的AI系统。它的核心组件是“感知-决策-行动-记忆”闭环(见图2-1):
#mermaid-svg-WTA2OQsV5w053V8w{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-WTA2OQsV5w053V8w .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-WTA2OQsV5w053V8w .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-WTA2OQsV5w053V8w .error-icon{fill:#552222;}#mermaid-svg-WTA2OQsV5w053V8w .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-WTA2OQsV5w053V8w .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-WTA2OQsV5w053V8w .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-WTA2OQsV5w053V8w .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-WTA2OQsV5w053V8w .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-WTA2OQsV5w053V8w .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-WTA2OQsV5w053V8w .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-WTA2OQsV5w053V8w .marker{fill:#333333;stroke:#333333;}#mermaid-svg-WTA2OQsV5w053V8w .marker.cross{stroke:#333333;}#mermaid-svg-WTA2OQsV5w053V8w svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-WTA2OQsV5w053V8w p{margin:0;}#mermaid-svg-WTA2OQsV5w053V8w .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-WTA2OQsV5w053V8w .cluster-label text{fill:#333;}#mermaid-svg-WTA2OQsV5w053V8w .cluster-label span{color:#333;}#mermaid-svg-WTA2OQsV5w053V8w .cluster-label span p{background-color:transparent;}#mermaid-svg-WTA2OQsV5w053V8w .label text,#mermaid-svg-WTA2OQsV5w053V8w span{fill:#333;color:#333;}#mermaid-svg-WTA2OQsV5w053V8w .node rect,#mermaid-svg-WTA2OQsV5w053V8w .node circle,#mermaid-svg-WTA2OQsV5w053V8w .node ellipse,#mermaid-svg-WTA2OQsV5w053V8w .node polygon,#mermaid-svg-WTA2OQsV5w053V8w .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-WTA2OQsV5w053V8w .rough-node .label text,#mermaid-svg-WTA2OQsV5w053V8w .node .label text,#mermaid-svg-WTA2OQsV5w053V8w .image-shape .label,#mermaid-svg-WTA2OQsV5w053V8w .icon-shape .label{text-anchor:middle;}#mermaid-svg-WTA2OQsV5w053V8w .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-WTA2OQsV5w053V8w .rough-node .label,#mermaid-svg-WTA2OQsV5w053V8w .node .label,#mermaid-svg-WTA2OQsV5w053V8w .image-shape .label,#mermaid-svg-WTA2OQsV5w053V8w .icon-shape .label{text-align:center;}#mermaid-svg-WTA2OQsV5w053V8w .node.clickable{cursor:pointer;}#mermaid-svg-WTA2OQsV5w053V8w .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-WTA2OQsV5w053V8w .arrowheadPath{fill:#333333;}#mermaid-svg-WTA2OQsV5w053V8w .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-WTA2OQsV5w053V8w .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-WTA2OQsV5w053V8w .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WTA2OQsV5w053V8w .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-WTA2OQsV5w053V8w .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WTA2OQsV5w053V8w .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-WTA2OQsV5w053V8w .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-WTA2OQsV5w053V8w .cluster text{fill:#333;}#mermaid-svg-WTA2OQsV5w053V8w .cluster span{color:#333;}#mermaid-svg-WTA2OQsV5w053V8w div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-WTA2OQsV5w053V8w .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-WTA2OQsV5w053V8w rect.text{fill:none;stroke-width:0;}#mermaid-svg-WTA2OQsV5w053V8w .icon-shape,#mermaid-svg-WTA2OQsV5w053V8w .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WTA2OQsV5w053V8w .icon-shape p,#mermaid-svg-WTA2OQsV5w053V8w .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-WTA2OQsV5w053V8w .icon-shape rect,#mermaid-svg-WTA2OQsV5w053V8w .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WTA2OQsV5w053V8w .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-WTA2OQsV5w053V8w .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-WTA2OQsV5w053V8w :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
感知新环境
记忆模块(上下文存储)
决策模块(用上下文推理)
行动模块(执行决策)
图2-1:Agentic AI的核心闭环
简单来说,Agent就像“有目标的机器人”:
- 感知模块:用传感器、API获取环境/用户信息(比如“用户说‘我冷’”“当前温度10℃”);
- 记忆模块:存储这些信息(上下文);
- 决策模块:用上下文推理(“用户冷+温度低→需要推荐羽绒服”);
- 行动模块:执行决策(“给用户发羽绒服链接”)。
2.2 上下文工程的定义与核心要素
上下文工程:设计、管理、优化Agent用于决策的“上下文信息”的全流程。它的核心要素是**“3W1H”**:
- What:上下文的内容(用户偏好、环境状态、任务进度);
- Where:上下文的来源(用户输入、传感器、第三方系统);
- When:上下文的生命周期(临时/长期);
- How:上下文的存储、检索、更新方式。
2.3 上下文的“3种类型”:用“餐厅服务员”类比
为了更直观,我们用“餐厅服务员”类比Agent,看看上下文的3种类型:
| 用户上下文 | 用户的长期偏好、历史交互记录 | 记住顾客“不吃辣、上次点了红烧肉” | 用户A喜欢视频讲解、上周投诉过物流 |
| 环境上下文 | 当前的环境状态(时间、地点等) | 记住“现在是晚餐高峰、2号桌有空位” | 当前时间20:00、用户在手机端访问 |
| 任务上下文 | 当前任务的目标、进度、子任务 | 记住“顾客点了鱼香肉丝、还没上汤” | 当前任务是“处理用户投诉”、进度50% |
这3类上下文不是孤立的——比如服务员要给顾客推荐菜品,需要结合“用户上下文(不吃辣)+ 环境上下文(晚餐高峰→推荐快炒)+ 任务上下文(顾客在等汤→先上汤)”。
2.4 传统Prompt Engineering vs Agentic上下文工程:核心差异
很多人会把“上下文工程”和“Prompt Engineering”混淆,其实两者有本质区别:
| 交互模式 | 单次交互(输入Prompt→输出) | 持续交互(闭环行动) |
| 上下文范围 | 固定(Prompt里写死的信息) | 动态(随时间/环境变化) |
| 优化目标 | 单次响应质量(比如“回答准确”) | 长期行动效果(比如“用户满意度”) |
| 关键技术 | Prompt Tuning、Few-Shot Learning | 记忆机制、向量检索、动态更新 |
| 例子 | 让ChatGPT写文案,Prompt里加“要幽默” | 智能助手记住你“喜欢幽默”,每次回复都带点梗 |
3. 数学模型:用“向量+概率”量化上下文
3.1 上下文的“向量表示”:让Agent“理解”信息
Agent无法直接“理解”文本/图像,需要将上下文转化为向量(Vector)——一种高维空间中的点,相似的信息在空间中距离更近。
比如:
- “用户喜欢视频讲解”→ 编码成向量V1;
- “用户喜欢动画演示”→ 编码成向量V2;
- V1和V2的距离很近,Agent能识别出“这两个都是‘视觉偏好’”。
数学模型1:上下文的向量表示
假设上下文由N个实体(比如“用户偏好”“环境温度”)组成,每个实体有M个属性(比如“偏好类型”“温度值”),那么上下文向量C可以表示为:
C=∑i=1Nwi⋅E(ei,ai1,ai2,…,aiM) C = \\sum_{i=1}^N w_i \\cdot E(e_i, a_{i1}, a_{i2}, …, a_{iM}) C=i=1∑Nwi⋅E(ei,ai1,ai2,…,aiM)
其中:
- ( e_i ):第i个实体(比如“用户偏好”);
- ( a_{ij} ):实体i的第j个属性(比如“偏好类型=视频”);
- ( E(\\cdot) ):实体-属性的嵌入函数(比如用SentenceTransformer将文本转化为向量);
- ( w_i ):实体i的权重(比如“用户偏好”的权重比“环境温度”高)。
3.2 上下文的“相关性计算”:过滤冗余信息
Agent需要判断“新信息是否值得加入上下文”,核心是计算相关性——新信息与当前任务的匹配度。
数学模型2:余弦相似度(Cosine Similarity)
两个上下文向量C1和C2的相似度计算:
sim(C1,C2)=C1⋅C2∣∣C1∣∣⋅∣∣C2∣∣ sim(C1, C2) = \\frac{C1 \\cdot C2}{||C1|| \\cdot ||C2||} sim(C1,C2)=∣∣C1∣∣⋅∣∣C2∣∣C1⋅C2
其中:
- ( C1 \\cdot C2 ):向量点积(衡量方向一致性);
- ( ||C1|| ):向量的L2范数(衡量长度)。
结果范围是[-1, 1]:
- 1:完全相同(比如“用户喜欢视频”和“用户偏好视频”);
- 0:完全无关(比如“用户喜欢视频”和“今天下雨”);
- -1:完全相反(比如“用户喜欢视频”和“用户讨厌视频”)。
3.3 上下文的“加权融合”:多源数据的统一
当上下文来自多个源(比如用户输入、传感器、CRM系统),需要给每个源分配可信度权重,融合成统一向量。
数学模型3:多源上下文融合
假设上下文来自K个源,每个源的向量是( C_k ),权重是( \\lambda_k )(( \\sum_{k=1}^K \\lambda_k = 1 )),则融合后的向量:
Cfused=∑k=1Kλk⋅Ck C_{fused} = \\sum_{k=1}^K \\lambda_k \\cdot C_k Cfused=k=1∑Kλk⋅Ck
比如:
- 用户输入(文本)的权重( \\lambda_1=0.6 )(可信度高);
- 传感器数据(温度)的权重( \\lambda_2=0.3 )(可信度中);
- 第三方系统(CRM中的旧记录)的权重( \\lambda_3=0.1 )(可信度低);
- 融合后的向量更偏向用户当前的输入。
4. 关键步骤1:上下文需求建模——明确“Agent需要什么信息”
4.1 核心问题:Agent的“上下文需求”不是拍脑袋定的
很多开发者的误区是“先采集数据,再想怎么用”,结果采集了一堆无用信息。正确的顺序是:先明确Agent的应用场景→再定义需要的上下文类型。
4.2 3步完成上下文需求建模
步骤1:定义Agent的“核心目标”与“应用场景”
首先回答:你的Agent是做什么的?它的核心目标是什么?
比如:
- 智能学习助手Agent:核心目标是“帮助用户高效完成学习任务”;
- 自动驾驶Agent:核心目标是“安全、高效到达目的地”;
- 客服Agent:核心目标是“快速解决用户问题,提高满意度”。
步骤2:拆解“上下文类型”与“属性”
根据核心目标,拆解需要的3类上下文(用户/环境/任务),并定义每个上下文的属性(即“具体要记什么”)。
以“智能学习助手Agent”为例:
| 用户上下文 | 学习偏好(视频/文字)、历史进度(学过的章节)、知识薄弱点(比如“函数题经常错”) | 长期有效,跨任务保留 |
| 环境上下文 | 当前时间(是否是学习时间)、设备(手机/电脑)、网络状态(4G/Wi-Fi) | 临时有效,单次任务内更新 |
| 任务上下文 | 当前课程名称、进度(第5章)、未完成作业(作业ID:123) | 临时有效,任务结束后归档 |
步骤3:定义上下文的“生命周期”
上下文不是“永久存储”的,需要明确生命周期(Life Cycle):
- 临时上下文(Transient Context):仅在单次任务内有效,任务结束后删除(比如当前课程的进度);
- 短期上下文(Short-Term Context):保留最近一段时间的信息(比如最近7天的学习记录);
- 长期上下文(Long-Term Context):跨任务、长期保留(比如用户的学习偏好)。
比如:
- 智能学习助手Agent:
- 临时上下文:当前正在做的作业ID;
- 短期上下文:最近7天的学习时长;
- 长期上下文:用户的“视频偏好”。
4.3 工具:用“上下文需求矩阵”落地
为了避免遗漏,建议用上下文需求矩阵整理结果:
| 用户上下文 | 学习偏好 | 用户问卷 | 长期 | 10 |
| 用户上下文 | 历史进度 | LMS系统 | 短期 | 8 |
| 环境上下文 | 当前时间 | 前端JS | 临时 | 5 |
| 任务上下文 | 当前课程进度 | 学习系统API | 临时 | 9 |
注:权重越高,说明该上下文对决策的影响越大。
5. 关键步骤2:上下文采集与多源融合——从“数据”到“可用信息”
5.1 上下文的“4大来源”
Agent的上下文来自4类数据源(见图5-1):
#mermaid-svg-MsE5EDf4Z6XO5WoY{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MsE5EDf4Z6XO5WoY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MsE5EDf4Z6XO5WoY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MsE5EDf4Z6XO5WoY .error-icon{fill:#552222;}#mermaid-svg-MsE5EDf4Z6XO5WoY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MsE5EDf4Z6XO5WoY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MsE5EDf4Z6XO5WoY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MsE5EDf4Z6XO5WoY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MsE5EDf4Z6XO5WoY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MsE5EDf4Z6XO5WoY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MsE5EDf4Z6XO5WoY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MsE5EDf4Z6XO5WoY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MsE5EDf4Z6XO5WoY .marker.cross{stroke:#333333;}#mermaid-svg-MsE5EDf4Z6XO5WoY svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MsE5EDf4Z6XO5WoY p{margin:0;}#mermaid-svg-MsE5EDf4Z6XO5WoY .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-MsE5EDf4Z6XO5WoY .cluster-label text{fill:#333;}#mermaid-svg-MsE5EDf4Z6XO5WoY .cluster-label span{color:#333;}#mermaid-svg-MsE5EDf4Z6XO5WoY .cluster-label span p{background-color:transparent;}#mermaid-svg-MsE5EDf4Z6XO5WoY .label text,#mermaid-svg-MsE5EDf4Z6XO5WoY span{fill:#333;color:#333;}#mermaid-svg-MsE5EDf4Z6XO5WoY .node rect,#mermaid-svg-MsE5EDf4Z6XO5WoY .node circle,#mermaid-svg-MsE5EDf4Z6XO5WoY .node ellipse,#mermaid-svg-MsE5EDf4Z6XO5WoY .node polygon,#mermaid-svg-MsE5EDf4Z6XO5WoY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MsE5EDf4Z6XO5WoY .rough-node .label text,#mermaid-svg-MsE5EDf4Z6XO5WoY .node .label text,#mermaid-svg-MsE5EDf4Z6XO5WoY .image-shape .label,#mermaid-svg-MsE5EDf4Z6XO5WoY .icon-shape .label{text-anchor:middle;}#mermaid-svg-MsE5EDf4Z6XO5WoY .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MsE5EDf4Z6XO5WoY .rough-node .label,#mermaid-svg-MsE5EDf4Z6XO5WoY .node .label,#mermaid-svg-MsE5EDf4Z6XO5WoY .image-shape .label,#mermaid-svg-MsE5EDf4Z6XO5WoY .icon-shape .label{text-align:center;}#mermaid-svg-MsE5EDf4Z6XO5WoY .node.clickable{cursor:pointer;}#mermaid-svg-MsE5EDf4Z6XO5WoY .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MsE5EDf4Z6XO5WoY .arrowheadPath{fill:#333333;}#mermaid-svg-MsE5EDf4Z6XO5WoY .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MsE5EDf4Z6XO5WoY .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MsE5EDf4Z6XO5WoY .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MsE5EDf4Z6XO5WoY .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MsE5EDf4Z6XO5WoY .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MsE5EDf4Z6XO5WoY .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MsE5EDf4Z6XO5WoY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MsE5EDf4Z6XO5WoY .cluster text{fill:#333;}#mermaid-svg-MsE5EDf4Z6XO5WoY .cluster span{color:#333;}#mermaid-svg-MsE5EDf4Z6XO5WoY div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MsE5EDf4Z6XO5WoY .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MsE5EDf4Z6XO5WoY rect.text{fill:none;stroke-width:0;}#mermaid-svg-MsE5EDf4Z6XO5WoY .icon-shape,#mermaid-svg-MsE5EDf4Z6XO5WoY .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MsE5EDf4Z6XO5WoY .icon-shape p,#mermaid-svg-MsE5EDf4Z6XO5WoY .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MsE5EDf4Z6XO5WoY .icon-shape rect,#mermaid-svg-MsE5EDf4Z6XO5WoY .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MsE5EDf4Z6XO5WoY .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MsE5EDf4Z6XO5WoY .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MsE5EDf4Z6XO5WoY :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
用户输入
上下文采集
传感器数据
第三方系统
Agent行动记录
多源融合
图5-1:上下文的来源与采集流程
来源1:用户输入
- 形式:文本(提问、反馈)、语音(录音)、图像(比如用户上传的作业照片);
- 采集方式:前端界面(输入框、麦克风、摄像头)→ 后端接口→ 存储到临时队列。
来源2:传感器数据
- 形式:GPS(位置)、温度传感器(环境温度)、加速度传感器(设备运动状态);
- 采集方式:IoT设备→ MQTT协议→ 后端数据管道。
来源3:第三方系统
- 形式:结构化数据(CRM中的用户投诉记录)、非结构化数据(LMS中的课程视频链接);
- 采集方式:API调用(比如调用LMS的“用户进度”接口)、ETL工具(抽取-转换-加载)。
来源4:Agent行动记录
- 形式:Agent之前执行的行动(比如“给用户发了视频链接”“推荐了第5章重点”);
- 采集方式:后端日志→ 定期同步到上下文存储系统。
5.2 多源融合:解决“数据异构”问题
多源数据的最大问题是异构性(比如文本是字符串,温度是数字,图像是像素矩阵),需要将它们转化为统一的向量格式。
技术1:结构化数据→向量
结构化数据(比如“用户ID:123,偏好:视频”)可以直接用One-Hot编码或Embedding转化为向量:
- One-Hot编码:“偏好=视频”→ [1,0](假设偏好有“视频”“文字”两种);
- Embedding:用Word2Vec或GloVe将“视频”转化为100维向量。
技术2:非结构化数据→向量
非结构化数据(文本、图像、语音)需要用预训练模型编码:
- 文本:用SentenceTransformer(比如all-MiniLM-L6-v2)转化为384维向量;
- 图像:用CLIP(OpenAI的多模态模型)转化为512维向量;
- 语音:用Wav2Vec2(Facebook的语音模型)转化为768维向量。
技术3:多模态融合
如果上下文包含多模态数据(比如“用户说‘我冷’+ 上传了一张穿薄外套的照片”),需要将文本向量和图像向量融合:
- 方法:加权平均(见3.3节的数学模型);
- 例子:文本向量V_text(384维)+ 图像向量V_image(512维)→ 融合成V_fused(比如取前384维为V_text,后512维为V_image,或用Transformer融合)。
5.3 代码示例:多源融合的实现
以“智能学习助手Agent”为例,采集用户输入(文本)、LMS系统(结构化数据)、设备状态(传感器),并融合成上下文向量:
from sentence_transformers import SentenceTransformer
import numpy as np
# 初始化模型
text_model = SentenceTransformer('all-MiniLM-L6-v2') # 文本编码模型
struct_model = SentenceTransformer('paraphrase-MiniLM-L6-v2') # 结构化数据编码模型
# 1. 采集多源数据
user_input = "我觉得这章的文字讲解太枯燥了" # 用户输入(文本)
lms_data = {"user_id": 123, "course": "数学", "progress": 50} # LMS系统(结构化)
device_data = {"time": "2024-05-20 19:00", "device": "手机"} # 设备状态(传感器)
# 2. 编码各源数据
# 文本编码:用户输入→向量
text_vector = text_model.encode(user_input) # 384维
# 结构化数据编码:将字典转为字符串→向量
struct_str = f"user_id={lms_data['user_id']}, course={lms_data['course']}, progress={lms_data['progress']}"
struct_vector = struct_model.encode(struct_str) # 384维
# 传感器数据编码:将字典转为字符串→向量
device_str = f"time={device_data['time']}, device={device_data['device']}"
device_vector = struct_model.encode(device_str) # 384维
# 3. 多源融合(加权平均,权重根据可信度设定)
weights = [0.6, 0.3, 0.1] # 文本(0.6)> 结构化(0.3)> 传感器(0.1)
fused_vector = np.average([text_vector, struct_vector, device_vector], axis=0, weights=weights)
print(f"融合后的上下文向量维度:{fused_vector.shape}") # 输出:(384,)
6. 关键步骤3:上下文存储与记忆机制设计——打造Agent的“大脑”
6.1 记忆机制的核心:“短期记忆+长期记忆”双系统
人类的记忆分为“短期记忆(STM)”和“长期记忆(LTM)”——Agent的记忆机制也需要模仿这一点(见图6-1):
#mermaid-svg-CkMImP3DFjYVTgrZ{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-CkMImP3DFjYVTgrZ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-CkMImP3DFjYVTgrZ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-CkMImP3DFjYVTgrZ .error-icon{fill:#552222;}#mermaid-svg-CkMImP3DFjYVTgrZ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CkMImP3DFjYVTgrZ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-CkMImP3DFjYVTgrZ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CkMImP3DFjYVTgrZ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CkMImP3DFjYVTgrZ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-CkMImP3DFjYVTgrZ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CkMImP3DFjYVTgrZ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CkMImP3DFjYVTgrZ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CkMImP3DFjYVTgrZ .marker.cross{stroke:#333333;}#mermaid-svg-CkMImP3DFjYVTgrZ svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CkMImP3DFjYVTgrZ p{margin:0;}#mermaid-svg-CkMImP3DFjYVTgrZ .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-CkMImP3DFjYVTgrZ .cluster-label text{fill:#333;}#mermaid-svg-CkMImP3DFjYVTgrZ .cluster-label span{color:#333;}#mermaid-svg-CkMImP3DFjYVTgrZ .cluster-label span p{background-color:transparent;}#mermaid-svg-CkMImP3DFjYVTgrZ .label text,#mermaid-svg-CkMImP3DFjYVTgrZ span{fill:#333;color:#333;}#mermaid-svg-CkMImP3DFjYVTgrZ .node rect,#mermaid-svg-CkMImP3DFjYVTgrZ .node circle,#mermaid-svg-CkMImP3DFjYVTgrZ .node ellipse,#mermaid-svg-CkMImP3DFjYVTgrZ .node polygon,#mermaid-svg-CkMImP3DFjYVTgrZ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-CkMImP3DFjYVTgrZ .rough-node .label text,#mermaid-svg-CkMImP3DFjYVTgrZ .node .label text,#mermaid-svg-CkMImP3DFjYVTgrZ .image-shape .label,#mermaid-svg-CkMImP3DFjYVTgrZ .icon-shape .label{text-anchor:middle;}#mermaid-svg-CkMImP3DFjYVTgrZ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-CkMImP3DFjYVTgrZ .rough-node .label,#mermaid-svg-CkMImP3DFjYVTgrZ .node .label,#mermaid-svg-CkMImP3DFjYVTgrZ .image-shape .label,#mermaid-svg-CkMImP3DFjYVTgrZ .icon-shape .label{text-align:center;}#mermaid-svg-CkMImP3DFjYVTgrZ .node.clickable{cursor:pointer;}#mermaid-svg-CkMImP3DFjYVTgrZ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-CkMImP3DFjYVTgrZ .arrowheadPath{fill:#333333;}#mermaid-svg-CkMImP3DFjYVTgrZ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-CkMImP3DFjYVTgrZ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-CkMImP3DFjYVTgrZ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CkMImP3DFjYVTgrZ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-CkMImP3DFjYVTgrZ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CkMImP3DFjYVTgrZ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-CkMImP3DFjYVTgrZ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-CkMImP3DFjYVTgrZ .cluster text{fill:#333;}#mermaid-svg-CkMImP3DFjYVTgrZ .cluster span{color:#333;}#mermaid-svg-CkMImP3DFjYVTgrZ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-CkMImP3DFjYVTgrZ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-CkMImP3DFjYVTgrZ rect.text{fill:none;stroke-width:0;}#mermaid-svg-CkMImP3DFjYVTgrZ .icon-shape,#mermaid-svg-CkMImP3DFjYVTgrZ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CkMImP3DFjYVTgrZ .icon-shape p,#mermaid-svg-CkMImP3DFjYVTgrZ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-CkMImP3DFjYVTgrZ .icon-shape rect,#mermaid-svg-CkMImP3DFjYVTgrZ .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CkMImP3DFjYVTgrZ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-CkMImP3DFjYVTgrZ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-CkMImP3DFjYVTgrZ :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
是
否
采集的上下文
编码为向量
短期记忆(STM):缓存最近信息
是否长期有用?
长期记忆(LTM):向量数据库
到期删除
检索时调用
图6-1:Agent的记忆机制流程
6.2 短期记忆(STM):存储“最近的、临时的”信息
短期记忆的核心是**“快”**——需要低延迟读取,用于支撑Agent的实时决策。
设计要点:
- 存储内容:临时上下文(比如当前对话的最后5条消息)、短期上下文(最近7天的学习记录);
- 存储介质:缓存数据库(比如Redis)——读写速度快(毫秒级);
- 过期策略:设置TTL(Time To Live,存活时间),比如“最后5条消息”的TTL是1小时,过期自动删除。
代码示例:用Redis实现短期记忆
import redis
import json
# 初始化Redis客户端
redis_client = redis.Redis(host='localhost', port=6379, db=0)
def store_stm(user_id, context_data, ttl=3600):
"""
存储短期记忆
:param user_id: 用户ID
:param context_data: 上下文数据(字典,比如{"progress": 50, "device": "手机"})
:param ttl: 存活时间(秒),默认1小时
"""
key = f"stm:{user_id}"
# 将字典转为JSON字符串存储
redis_client.set(key, json.dumps(context_data), ex=ttl)
def retrieve_stm(user_id):
"""
检索短期记忆
:param user_id: 用户ID
:return: 上下文数据(字典)或None
"""
key = f"stm:{user_id}"
data = redis_client.get(key)
if data:
return json.loads(data)
return None
# 测试:存储用户123的短期记忆(进度50%,设备手机)
store_stm(123, {"progress": 50, "device": "手机"})
# 检索用户123的短期记忆
stm_data = retrieve_stm(123)
print(stm_data) # 输出:{'progress': 50, 'device': '手机'}
6.3 长期记忆(LTM):存储“长期的、有用的”信息
长期记忆的核心是**“准”**——需要高效的相似性检索,用于支撑Agent的长期决策(比如“用户喜欢视频讲解”)。
设计要点:
- 存储内容:长期上下文(用户偏好、历史投诉记录);
- 存储介质:向量数据库(比如Pinecone、Weaviate、Chroma)——专门用于存储向量,并支持快速相似性检索;
- 编码方式:用预训练模型将文本/结构化数据编码为向量(见5.2节)。
代码示例:用Pinecone实现长期记忆
import pinecone
from sentence_transformers import SentenceTransformer
# 初始化Pinecone
pinecone.init(api_key="your-api-key", environment="us-west1-gcp")
index_name = "user-preferences"
# 初始化编码模型
model = SentenceTransformer('all-MiniLM-L6-v2')
# 创建索引(如果不存在)
if index_name not in pinecone.list_indexes():
pinecone.create_index(
name=index_name,
dimension=384, # 模型输出的向量维度
metric="cosine" # 相似性度量(余弦相似度)
)
# 连接索引
index = pinecone.Index(index_name)
def store_ltm(user_id, preference):
"""
存储长期记忆(用户偏好)
:param user_id: 用户ID
:param preference: 用户偏好(比如“喜欢视频讲解”)
"""
# 编码偏好为向量
vector = model.encode(preference).tolist()
# 存储到Pinecone:ID=user_id,向量=vector,元数据=偏好内容
index.upsert([(str(user_id), vector, {"preference": preference})])
def retrieve_ltm(user_id, query):
"""
检索长期记忆(根据查询词找相似偏好)
:param user_id: 用户ID
:param query: 查询词(比如“我喜欢视觉化的讲解”)
:return: 相似的偏好列表
"""
# 编码查询词为向量
query_vector = model.encode(query).tolist()
# 搜索Top3相似的偏好(过滤用户ID)
results = index.query(
vector=query_vector,
top_k=3,
filter={"user_id": str(user_id)} # 只找该用户的偏好
)
# 提取元数据中的偏好内容
return [match["metadata"]["preference"] for match in results["matches"]]
# 测试:存储用户123的偏好“喜欢视频讲解”
store_ltm(123, "喜欢视频讲解")
# 检索用户123的偏好(查询词“我喜欢视觉化的讲解”)
ltm_data = retrieve_ltm(123, "我喜欢视觉化的讲解")
print(ltm_data) # 输出:['喜欢视频讲解']
6.4 边界与外延:短期vs长期记忆的“分界线”
如何判断“信息是否要存入长期记忆”?可以用**“价值-频率”矩阵**:
| 高频(经常用到) | 存长期记忆(比如用户偏好) | 存短期记忆(比如最近的天气) |
| 低频(很少用到) | 存长期记忆(比如用户的过敏史) | 到期删除(比如临时的作业ID) |
7. 关键步骤4:上下文检索与动态更新——让Agent“按需取信息”
7.1 上下文检索:从“记忆”中找“有用的”信息
Agent做决策时,不需要“遍历所有记忆”,而是要**“精准检索”**——找到与当前任务最相关的上下文。
2种核心检索策略:
策略1:基于向量的相似性检索
适用于非结构化上下文(比如用户的偏好、历史对话)——用向量数据库的“相似性搜索”功能,找到与当前查询最像的信息。
比如:
- 用户问“这章的重点是什么”,查询词编码为向量Q;
- 向量数据库搜索Top3与Q最相似的用户偏好(比如“喜欢视频讲解”);
- Agent根据偏好推荐视频版重点。
策略2:基于规则的过滤检索
适用于结构化上下文(比如用户的进度、设备状态)——用SQL或NoSQL的过滤条件,找到符合要求的信息。
比如:
- 用户问“我的作业呢”,过滤条件是“user_id=123 AND 作业状态=未完成”;
- 从短期记忆中检索出未完成的作业ID,直接回复。
代码示例:结合“向量检索+规则过滤”
以“智能学习助手Agent”为例,用户问“第4章重点”,检索流程:
def retrieve_context(user_id, query):
"""
结合短期记忆和长期记忆检索上下文
:param user_id: 用户ID
:param query: 用户的问题(比如“第4章重点”)
:return: 整合后的上下文
"""
# 1. 检索短期记忆:当前课程进度
stm_data = retrieve_stm(user_id)
current_course = stm_data.get("course", "未知") if stm_data else "未知"
current_progress = stm_data.get("progress", 0) if stm_data else 0
# 2. 检索长期记忆:用户偏好
ltm_preferences = retrieve_ltm(user_id, query)
# 3. 整合上下文
context = {
"user_id": user_id,
"query": query,
"current_course": current_course,
"current_progress": current_progress,
"preferences": ltm_preferences
}
return context
# 测试:用户123问“第4章重点”
context = retrieve_context(123, "第4章重点")
print(context)
# 输出:
# {
# "user_id": 123,
# "query": "第4章重点",
# "current_course": "数学",
# "current_progress": 50,
# "preferences": ["喜欢视频讲解"]
# }
7.2 上下文动态更新:让Agent“保持清醒”
上下文不是“一成不变”的——当用户的偏好、环境状态变化时,需要及时更新记忆,否则Agent会“过时”。
3种更新场景与策略:
场景1:用户输入更新
比如用户之前说“喜欢文字讲解”,今天说“我觉得视频更清楚”——需要更新长期记忆中的偏好。
策略:
- 编码新偏好为向量;
- 调用Pinecone的upsert接口,用新向量覆盖旧向量(因为ID=user_id,所以会替换)。
场景2:环境状态更新
比如用户的设备从“手机”变成“电脑”——需要更新短期记忆中的设备状态。
策略:
- 调用Redis的set接口,覆盖旧的设备状态;
- 保持TTL不变(比如1小时)。
场景3:任务进度更新
比如用户完成了第4章,进度从50%变成60%——需要更新短期记忆中的进度。
策略:
- 从Redis中获取旧的短期记忆;
- 修改进度字段,重新存入Redis(覆盖旧值)。
代码示例:动态更新用户偏好
# 之前存储的用户123的偏好是“喜欢文字讲解”
store_ltm(123, "喜欢文字讲解")
# 用户现在说“我觉得视频更清楚”,更新偏好
new_preference = "喜欢视频讲解"
store_ltm(123, new_preference)
# 检索更新后的偏好
updated_preferences = retrieve_ltm(123, "我喜欢视觉化的讲解")
print(updated_preferences) # 输出:['喜欢视频讲解']
8. 关键步骤5:上下文推理与意图增强——让Agent“会思考”
8.1 从“信息”到“决策”:上下文推理的核心
上下文本身没有价值,只有通过推理转化为“行动依据”才有价值。
比如:
- 上下文:用户偏好“喜欢视频”+ 当前课程进度“第4章”+ 环境时间“晚上10点”;
- 推理:用户可能需要“简短的视频重点”(因为时间晚,不想看长视频);
- 行动:给用户发“第4章重点视频(5分钟版)”。
8.2 2种推理方式:规则推理vs大模型推理
方式1:基于规则的推理
适用于逻辑明确、流程固定的场景——用“if-else”或一阶逻辑(First-Order Logic)实现。
比如:
- 规则:如果(用户偏好=视频)且(时间>21:00),则推荐“简短视频”;
- 代码实现:def rule_based_reasoning(context):
preference = context.get("preferences", [])
time = context.get("current_time", "")
if "喜欢视频" in preference and time > "21:00":
return "推荐简短视频重点"
elif "喜欢视频" in preference:
return "推荐完整视频重点"
else:
return "推荐文字重点"
方式2:基于大模型的推理
适用于逻辑复杂、需要理解语义的场景——用LLM(比如GPT-4、Claude 3)将上下文转化为决策。
比如:
- 给LLM的Prompt:你是一个智能学习助手,需要根据用户的上下文推荐学习内容。上下文如下:
– 用户偏好:喜欢视频讲解
– 当前课程:数学第4章
– 当前时间:2024-05-20 22:00(晚上10点)
请推荐合适的学习内容,并说明理由。 - LLM的输出:推荐“数学第4章重点视频(5分钟版)”。理由:用户喜欢视频讲解,且当前时间较晚,简短视频更符合用户的学习节奏。
代码示例:用大模型实现上下文推理
以OpenAI的GPT-4为例:
from openai import OpenAI
# 初始化OpenAI客户端
client = OpenAI(api_key="your-api-key")
def llm_based_reasoning(context):
"""
用大模型推理上下文,生成决策建议
:param context: 整合后的上下文(字典)
:return: 决策建议
"""
# 构造Prompt
prompt = f"""
你是一个智能学习助手,需要根据以下上下文推荐学习内容:
– 用户ID:{context['user_id']}
– 用户的问题:{context['query']}
– 当前课程:{context['current_course']}
– 当前进度:{context['current_progress']}%
– 用户偏好:{', '.join(context['preferences'])}
– 当前时间:{context.get('current_time', '未知')}
请遵循以下规则:
1. 如果时间晚于21:00,推荐简短内容;
2. 优先推荐用户偏好的形式(视频/文字);
3. 建议要具体(比如“第4章重点视频(5分钟版)”)。
"""
# 调用GPT-4
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}]
)
# 提取结果
return response.choices[0].message.content.strip()
# 测试:用户123的上下文
context = {
"user_id": 123,
"query": "第4章重点",
"current_course": "数学",
"current_progress": 50,
"preferences": ["喜欢视频讲解"],
"current_time": "2024-05-20 22:00"
}
# 推理结果
reasoning_result = llm_based_reasoning(context)
print(reasoning_result)
# 输出示例:
# 推荐“数学第4章重点视频(5分钟版)”。理由:用户偏好视频讲解,当前时间为晚上10点,简短视频更符合深夜的学习节奏,帮助快速掌握重点。
8.3 意图增强:从“表面问题”到“深层需求”
很多时候,用户的问题是“表面的”,需要通过上下文推理出“深层意图”。
比如:
- 用户问“我的快递呢”(表面问题);
- 上下文:用户上周投诉过物流慢(历史记录)+ 当前时间“周一上午”(物流高峰期);
- 深层意图:用户担心快递又延迟,需要安抚+ 提供具体的物流进度。
代码示例:意图增强推理
def enhance_intent(context):
"""
从上下文推理用户的深层意图
:param context: 整合后的上下文
:return: 深层意图
"""
# 表面问题
query = context["query"]
# 历史上下文:是否有过投诉
has_complaint = context.get("has_complaint", False)
# 环境上下文:当前时间是否是物流高峰期
is_peak = context.get("is_peak", False)
if query == "我的快递呢" and has_complaint and is_peak:
return "用户担心快递再次延迟,需要安抚并提供具体进度"
elif query == "我的快递呢" and has_complaint:
return "用户担心快递问题,需要快速响应"
else:
return "用户想知道快递的当前状态"
# 测试上下文
context = {
"query": "我的快递呢",
"has_complaint": True, # 上周投诉过物流慢
"is_peak": True # 周一上午是高峰期
}
# 推理深层意图
intent = enhance_intent(context)
print(intent) # 输出:用户担心快递再次延迟,需要安抚并提供具体进度
9. 关键步骤6:上下文评估与迭代优化——让Agent“越用越聪明”
9.1 评估的核心:“行动效果”与“上下文质量”绑定
上下文工程的效果不能“拍脑袋”,需要用数据量化——核心是“上下文质量→Agent行动效果→用户价值”的因果链。
9.2 3类评估指标
指标1:上下文质量指标
- 完整性:是否覆盖了Agent决策需要的所有上下文(比如“用户偏好”是否存在);
- 准确性:上下文是否正确(比如“用户进度”是否是最新的);
- 相关性:上下文与当前任务的匹配度(用余弦相似度衡量,见3.2节)。
指标2:Agent行动效果指标
- 行动准确率:Agent根据上下文做出的决策是否正确(比如“推荐视频讲解”后,用户完成作业的正确率);
- 行动效率:Agent做出决策的时间(比如“检索上下文+推理”的总时间是否<1秒);
- 用户满意度:用户对Agent响应的评价(比如“满意”“一般”“不满意”)。
指标3:系统性能指标
- 存储成本:短期记忆和长期记忆的存储容量(比如Redis占用的内存、Pinecone的向量数量);
- 检索延迟:上下文检索的时间(比如Redis的读取时间<10ms,Pinecone的搜索时间<100ms)。
9.3 迭代优化:用A/B测试找到“最优解”
评估的目的是优化——通过A/B测试对比不同上下文策略的效果,找到最优方案。
示例:优化“上下文检索的Top-K值”
假设你想测试“检索Top3 vs Top5相似偏好”对用户满意度的影响:
- 分组:将用户随机分成A组(Top3)和B组(Top5);
- 运行:A组用户的Agent检索Top3偏好,B组检索Top5;
- 评估:统计两组的用户满意度(比如A组85%,B组90%);
- 结论:Top5的效果更好,将策略切换为Top5。
代码示例:A/B测试的分组逻辑
import random
def assign_ab_group(user_id):
"""
将用户分配到A组或B组(随机)
:param user_id: 用户ID
:return: 分组结果(A/B)
"""
# 用用户ID的哈希值取模,确保同一用户始终在同一组
hash_value = hash(str(user_id))
return "A" if hash_value % 2 == 0 else "B"
def retrieve_ltm_ab(user_id, query):
"""
根据A/B分组检索不同数量的偏好
:param user_id: 用户ID
:param query: 查询词
:return: 偏好列表
"""
group = assign_ab_group(user_id)
top_k = 3 if group == "A" else 5
# 调用Pinecone的query接口,Top-K=top_k
results = index.query(
vector=model.encode(query).tolist(),
top_k=top_k,
filter={"user_id": str(user_id)}
)
return [match["metadata"]["preference"] for match in results["matches"]]
# 测试:用户123的分组(假设哈希后是偶数→A组)
group = assign_ab_group(123)
print(f"用户123的分组:{group}") # 输出:A
# 检索Top3偏好
preferences = retrieve_ltm_ab(123, "我喜欢视觉化的讲解")
print(f"检索到的偏好数量:{len(preferences)}") # 输出:3
10. 实际案例:用6个步骤设计“智能学习助手Agent”
10.1 案例背景
目标:设计一个智能学习助手Agent,帮助用户高效完成在线课程学习,核心功能包括:
- 推荐个性化学习内容(视频/文字);
- 跟踪学习进度,提醒未完成作业;
- 解答课程问题,结合用户偏好提供针对性解释。
10.2 6个步骤的落地实践
步骤1:上下文需求建模
- 核心目标:帮助用户高效学习;
- 上下文类型:
- 用户上下文:学习偏好(视频/文字)、历史进度(学过的章节)、知识薄弱点(比如“函数题经常错”);
- 环境上下文:当前时间(是否是学习时间)、设备(手机/电脑)、网络状态(4G/Wi-Fi);
- 任务上下文:当前课程名称、进度(第5章)、未完成作业(作业ID:123);
- 生命周期:
- 临时:作业ID;
- 短期:最近7天的学习时长;
- 长期:学习偏好。
步骤2:上下文采集与融合
- 采集来源:
- 用户输入:课程评价(文本)、偏好设置(问卷);
- 第三方系统:LMS(学习管理系统)的进度数据、作业系统的未完成作业;
- 传感器:前端JS获取的设备类型、时间;
- 融合方式:
- 文本(用户评价)→ SentenceTransformer编码;
- 结构化数据(进度、作业)→ One-Hot编码;
- 多源融合→ 加权平均(文本0.6、结构化0.3、传感器0.1)。
步骤3:记忆机制设计
- 短期记忆:Redis存储最近7天的学习时长、当前作业ID(TTL=1天);
- 长期记忆:Pinecone存储用户偏好(向量维度384,余弦相似度)。
步骤4:检索与更新
- 检索:
- 用户问“第4章重点”→ 向量检索Top3偏好(喜欢视频)+ 规则过滤当前进度(第5章);
- 更新:
- 用户完成作业→ 更新Redis中的作业状态;
- 用户修改偏好→ 更新Pinecone中的向量。
步骤5:推理与意图增强
- 推理:
- 上下文:用户偏好“视频”+ 时间“22:00”→ 推荐“5分钟视频重点”;
- 意图增强:
- 用户问“我的作业呢”→ 结合历史投诉(物流慢)→ 推理“用户担心作业截止时间”→ 提醒“作业截止到明天,当前进度80%”。
步骤6:评估与优化
- 指标:
- 行动准确率:用户完成作业的正确率(目标≥90%);
- 用户满意度:问卷调查(目标≥4.5/5);
- 检索延迟:<100ms;
- 优化:
- A/B测试发现“Top5偏好”比“Top3”满意度高→ 切换为Top5;


