Spring AI Alibaba 上下文工程(Context Engineering)深度实战
基于 Spring AI Alibaba 1.1.2.0,深入理解上下文工程的核心概念,并通过一个完整的智能客服工单系统示例,展示如何利用 Interceptor 和 Hook 动态控制 Agent 的模型上下文、工具上下文和生命周期上下文
Spring AI Alibaba Agent Framework Hooks 与 Interceptors 完整指南:
https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/162344775
一、什么是上下文工程?
构建一个能在生产环境中稳定运行、能解决实际问题的 Agent 并不容易。当 Agent 失败时,通常有两个原因:
- 底层 LLM 能力不足
- 没有向 LLM 传递"正确"的上下文
绝大多数情况下,第二个原因 是罪魁祸首。上下文工程正是以正确的格式 提供正确的信息和工具,使 LLM 能够完成任务的工程实践。
Spring AI Alibaba 的 Agent 抽象专门设计用于优化上下文工程,通过 Hook 和 Interceptor 机制挂接到 Agent 生命周期的任何步骤,实现上下文的动态更新与控制。
二、核心概念:三种上下文类型
| 上下文类型 | 控制内容 | 瞬态/持久 |
|---|---|---|
| 模型上下文(Model Context) | 模型调用中包含什么(指令、消息历史、工具、响应格式) | 瞬态(仅影响当前调用) |
| 工具上下文(Tool Context) | 工具可以访问和产生什么(对状态、存储、运行时上下文的读/写) | 持久(跨轮次) |
| 生命周期上下文(Lifecycle Context) | 模型和工具调用之间发生什么(摘要、防护栏、日志等) | 持久 |
2.1 瞬态 vs 持久
- 瞬态上下文 :LLM 在单次调用 中看到的内容。可以修改消息、工具或提示,而不改变状态 中保存的内容。使用 Interceptor 实现。
- 持久上下文 :跨轮次 保存在状态中的内容。生命周期钩子和工具写入会永久修改它。使用 Hook 实现。
2.2 数据源
Agent 在整个过程中访问(读/写)不同的数据源:
| 数据源 | 范围 | 示例 |
|---|---|---|
| 运行时上下文 | 会话范围 | 用户 ID、API 密钥、数据库连接、权限 |
| 状态(State) | 会话范围 | 当前消息、上传的文件、认证状态、工具结果 |
| 存储(Store) | 跨会话 | 用户偏好、提取的见解、记忆、历史数据 |
2.3 实现机制
| 机制 | 作用 | 修改类型 |
|---|---|---|
| Interceptor | 拦截和修改模型请求/响应,适合瞬态上下文的动态调整 | 瞬态 |
| Hook | 在 Agent 生命周期的特定节点执行操作,适合持久上下文的修改 | 持久 |
注:
博客:
https://blog.csdn.net/badao_liumang_qizhi
三、控制模型上下文(瞬态)
通过 ModelInterceptor 控制每次模型调用中包含的内容------指令、可用工具、使用哪个模型以及输出格式。
3.1 动态系统提示
根据对话状态或用户身份实时调整系统提示:
java
class DynamicPromptInterceptor extends ModelInterceptor {
@Override
public ModelResponse interceptModel(ModelRequest request, ModelCallHandler handler) {
String role = (String) request.getContext().get("userRole");
int msgCount = request.getMessages().size();
String prompt = "你是一个有用的助手。";
if ("VIP".equals(role)) prompt += " 用户是VIP,请提供优先服务。";
if (msgCount > 10) prompt += " 长对话,请简洁回复。";
SystemMessage enhancedSystem = new SystemMessage(prompt);
ModelRequest enhanced = ModelRequest.builder(request)
.systemMessage(enhancedSystem)
.build();
return handler.call(enhanced);
}
}
3.2 动态工具选择
根据用户角色决定 Agent 可以访问哪些工具(这是上下文工程最常见的实践):
java
class RoleBasedToolInterceptor extends ModelInterceptor {
@Override
public ModelResponse interceptModel(ModelRequest request, ModelCallHandler handler) {
UserRole role = getUserRole(request);
List<ToolCallback> allowedTools = getToolsForRole(role);
ModelRequest enhanced = ModelRequest.builder(request)
.dynamicToolCallbacks(allowedTools) // 本次调用生效
.build();
return handler.call(enhanced);
}
}
3.3 消息过滤
在单次调用中限制消息数量,防止上下文过长(但不修改持久状态):
java
class MessageFilterInterceptor extends ModelInterceptor {
private final int maxMessages = 10;
@Override
public ModelResponse interceptModel(ModelRequest request, ModelCallHandler handler) {
List<Message> messages = request.getMessages();
if (messages.size() > maxMessages) {
messages = messages.subList(messages.size() - maxMessages, messages.size());
}
ModelRequest enhanced = ModelRequest.builder(request)
.messages(messages)
.build();
return handler.call(enhanced);
}
}
四、控制工具上下文(持久)
工具可以读取和修改 Agent 的持久状态和运行时上下文。
4.1 工具中访问状态
通过 ToolContext 读取 Agent 的持久状态:
java
class StatefulTool implements BiFunction<String, ToolContext, String> {
@Override
public String apply(String query, ToolContext toolContext) {
OverAllState state = (OverAllState) toolContext.getContext().get("state");
Optional<Object> messages = state.value("messages");
// 使用状态信息处理...
return "处理结果";
}
}
4.2 工具修改状态
工具可以将处理结果持久化到状态中,供后续步骤使用:
java
class StateModifyingTool implements BiFunction<Map<String, Object>, ToolContext, String> {
@Override
public String apply(Map<String, Object> request, ToolContext toolContext) {
Map<String, Object> extraState = (Map<String, Object>) toolContext.getContext().get("extraState");
extraState.put("processed_data", process(request));
return "数据已保存";
}
}
五、控制生命周期上下文(持久)
使用 Hook 在 Agent 生命周期的关键节点执行操作。
5.1 Hook 位置
BEFORE_AGENT/AFTER_AGENTBEFORE_MODEL/AFTER_MODEL
5.2 消息摘要 Hook(压缩上下文)
当消息数量超过阈值时,自动生成摘要并替换历史消息(持久修改):
java
@HookPositions({HookPosition.BEFORE_MODEL})
class SummarizationHook extends MessagesModelHook {
private final int triggerLength = 8;
@Override
public AgentCommand beforeModel(List<Message> previousMessages, RunnableConfig config) {
if (previousMessages.size() <= triggerLength) {
return new AgentCommand(previousMessages);
}
// 生成摘要...
String summary = generateSummary(previousMessages);
// 构建新消息列表:保留系统消息 + 摘要 + 最近5条
List<Message> newMessages = new ArrayList<>();
newMessages.add(systemMsg);
newMessages.add(new UserMessage("【摘要】" + summary));
newMessages.addAll(recentMessages);
return new AgentCommand(newMessages, UpdatePolicy.REPLACE);
}
}
六、完整实战示例:智能客服工单系统
我们将构建一个电商智能客服系统,根据不同用户身份(普通用户/VIP/管理员)动态控制 Agent 的行为,展示上下文工程的核心能力。
6.1 业务需求
- 普通用户:只能查询订单、提交售后咨询
- VIP 用户:额外可查询积分、申请会员升级
- 管理员:拥有全部权限,可查询所有订单、处理退款
- 对话过长时自动压缩上下文
6.2 项目结构
spring-ai-context-engineering-demo/
├── pom.xml
├── src/main/
│ ├── java/com/example/ai/
│ │ ├── ContextEngineeringDemoApplication.java
│ │ ├── config/
│ │ │ └── AgentConfig.java
│ │ ├── controller/
│ │ │ └── CustomerController.java
│ │ ├── service/
│ │ │ └── CustomerService.java
│ │ ├── model/
│ │ │ ├── UserRole.java
│ │ │ └── UserContext.java
│ │ ├── tool/
│ │ │ └── CustomerServiceTools.java
│ │ ├── interceptor/
│ │ │ ├── ContextAwareToolInterceptor.java
│ │ │ └── DynamicPromptInterceptor.java
│ │ └── hook/
│ │ └── SummarizationHook.java
│ └── resources/
│ └── application.yml
6.3 完整代码
pom.xml
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath/>
</parent>
<groupId>com.example.ai</groupId>
<artifactId>spring-ai-context-engineering-demo</artifactId>
<version>1.0.0</version>
<properties>
<java.version>17</java.version>
<spring-ai-alibaba.version>1.1.2.0</spring-ai-alibaba.version>
<jackson.version>2.17.2</jackson.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson</groupId>
<artifactId>jackson-bom</artifactId>
<version>${jackson.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-agent-framework</artifactId>
<version>${spring-ai-alibaba.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
<version>${spring-ai-alibaba.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml
yaml
server:
port: 885
spring:
ai:
dashscope:
api-key: ${DASHSCOPE_API_KEY}
chat:
options:
model: deepseek-v4-flash
logging:
level:
com.alibaba.cloud.ai: debug
com.example.ai: debug
用户角色枚举
java
package com.example.ai.model;
public enum UserRole {
GUEST, // 游客:只能咨询
USER, // 普通用户
VIP, // 会员用户
ADMIN // 管理员
}
package com.badao.ai.model;
import java.util.List;
public class UserContext{
private String userId;
private UserRole role;
private String name;
private List<String> orderIds;
private int vipPoints;
public UserContext(String userId, UserRole role, String name, List<String> orderIds, int vipPoints) {
this.userId = userId;
this.role = role;
this.name = name;
this.orderIds = orderIds;
this.vipPoints = vipPoints;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public UserRole getRole() {
return role;
}
public void setRole(UserRole role) {
this.role = role;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getOrderIds() {
return orderIds;
}
public void setOrderIds(List<String> orderIds) {
this.orderIds = orderIds;
}
public int getVipPoints() {
return vipPoints;
}
public void setVipPoints(int vipPoints) {
this.vipPoints = vipPoints;
}
}
工具定义
java
package com.example.ai.tool;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.function.FunctionToolCallback;
import com.example.ai.model.UserRole;
import java.util.ArrayList;
import java.util.List;
public class CustomerServiceTools {
// ===== 所有用户可用 =====
public static ToolCallback queryOrderTool() {
return FunctionToolCallback.builder("query_order", (String orderId) -> {
return "订单 " + orderId + " 状态:已发货,预计 3 天后送达。";
}).description("根据订单号查询订单状态和物流信息").inputType(String.class).build();
}
public static ToolCallback consultAfterSalesTool() {
return FunctionToolCallback.builder("consult_after_sales", (String question) -> {
return "售后咨询已记录,客服将在 24 小时内回复您。问题:" + question;
}).description("提交售后咨询问题").inputType(String.class).build();
}
// ===== VIP 会员专属 =====
public static ToolCallback queryPointsTool() {
return FunctionToolCallback.builder("query_points", (String userId) -> {
return "用户 " + userId + " 当前积分:2580 分";
}).description("查询用户积分余额").inputType(String.class).build();
}
public static ToolCallback applyUpgradeTool() {
return FunctionToolCallback.builder("apply_upgrade", (String userId) -> {
return "用户 " + userId + " 的会员升级申请已提交,预计 1 个工作日内审核。";
}).description("提交会员升级申请").inputType(String.class).build();
}
// ===== 管理员专属 =====
public static ToolCallback queryAllOrdersTool() {
return FunctionToolCallback.builder("query_all_orders", (String userId) -> {
return "用户 " + userId + " 的所有订单:ORD-001(已签收),ORD-002(运输中)";
}).description("查询指定用户的所有订单").inputType(String.class).build();
}
public static ToolCallback processRefundTool() {
return FunctionToolCallback.builder("process_refund", (String orderId) -> {
return "订单 " + orderId + " 退款已处理,金额 299.00 元将在 3 个工作日内退回。";
}).description("处理退款申请").inputType(String.class).build();
}
/**
* 根据用户角色获取可用工具列表
*/
public static List<ToolCallback> getToolsForRole(UserRole role) {
List<ToolCallback> tools = new ArrayList<>();
tools.add(queryOrderTool());
tools.add(consultAfterSalesTool());
if (role == UserRole.VIP || role == UserRole.ADMIN) {
tools.add(queryPointsTool());
tools.add(applyUpgradeTool());
}
if (role == UserRole.ADMIN) {
tools.add(queryAllOrdersTool());
tools.add(processRefundTool());
}
return tools;
}
}
核心 Interceptor:动态工具选择
java
package com.example.ai.interceptor;
import com.alibaba.cloud.ai.graph.agent.interceptor.ModelInterceptor;
import com.alibaba.cloud.ai.graph.agent.interceptor.ModelRequest;
import com.alibaba.cloud.ai.graph.agent.interceptor.ModelResponse;
import com.alibaba.cloud.ai.graph.agent.interceptor.ModelCallHandler;
import com.example.ai.model.UserRole;
import com.example.ai.tool.CustomerServiceTools;
import org.springframework.ai.tool.ToolCallback;
import java.util.List;
/**
* 上下文工程核心组件:根据用户角色动态选择可用工具
*/
public class ContextAwareToolInterceptor extends ModelInterceptor {
@Override
public ModelResponse interceptModel(ModelRequest request, ModelCallHandler handler) {
String roleStr = (String) request.getContext().getOrDefault("userRole", "GUEST");
UserRole role = UserRole.valueOf(roleStr);
List<ToolCallback> roleTools = CustomerServiceTools.getToolsForRole(role);
System.out.println("🔧 用户角色:" + role + ",可用工具数:" + roleTools.size());
ModelRequest enhancedRequest = ModelRequest.builder(request)
.dynamicToolCallbacks(roleTools) // 仅本次调用生效
.build();
return handler.call(enhancedRequest);
}
@Override
public String getName() {
return "ContextAwareToolInterceptor";
}
}
动态提示 Interceptor
java
package com.example.ai.interceptor;
import com.alibaba.cloud.ai.graph.agent.interceptor.ModelInterceptor;
import com.alibaba.cloud.ai.graph.agent.interceptor.ModelRequest;
import com.alibaba.cloud.ai.graph.agent.interceptor.ModelResponse;
import com.alibaba.cloud.ai.graph.agent.interceptor.ModelCallHandler;
import com.example.ai.model.UserRole;
import org.springframework.ai.chat.messages.SystemMessage;
public class DynamicPromptInterceptor extends ModelInterceptor {
@Override
public ModelResponse interceptModel(ModelRequest request, ModelCallHandler handler) {
String roleStr = (String) request.getContext().getOrDefault("userRole", "GUEST");
UserRole role = UserRole.valueOf(roleStr);
int messageCount = request.getMessages().size();
StringBuilder prompt = new StringBuilder();
prompt.append("你是一个专业的电商客服助手。请用友好、专业的态度回复用户。");
if (role == UserRole.VIP) {
prompt.append(" 用户是VIP会员,请提供优先服务。");
} else if (role == UserRole.ADMIN) {
prompt.append(" 用户是管理员,请提供完整的后台数据。");
}
if (messageCount > 10) {
prompt.append(" 这是一个长对话,请保持回复简洁精准。");
}
SystemMessage enhancedSystem = new SystemMessage(prompt.toString());
ModelRequest enhanced = ModelRequest.builder(request)
.systemMessage(enhancedSystem)
.build();
return handler.call(enhanced);
}
@Override
public String getName() {
return "DynamicPromptInterceptor";
}
}
摘要 Hook(持久上下文压缩)
java
package com.example.ai.hook;
import com.alibaba.cloud.ai.graph.RunnableConfig;
import com.alibaba.cloud.ai.graph.agent.hook.HookPosition;
import com.alibaba.cloud.ai.graph.agent.hook.HookPositions;
import com.alibaba.cloud.ai.graph.agent.hook.messages.AgentCommand;
import com.alibaba.cloud.ai.graph.agent.hook.messages.MessagesModelHook;
import com.alibaba.cloud.ai.graph.agent.hook.messages.UpdatePolicy;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@HookPositions({HookPosition.BEFORE_MODEL})
public class SummarizationHook extends MessagesModelHook {
private static final Logger log = LoggerFactory.getLogger(SummarizationHook.class);
private final int triggerLength;
public SummarizationHook(int triggerLength) {
this.triggerLength = triggerLength;
}
@Override
public String getName() {
return "summarization_hook";
}
@Override
public AgentCommand beforeModel(List<Message> previousMessages, RunnableConfig config) {
if (previousMessages.size() <= triggerLength) {
return new AgentCommand(previousMessages);
}
log.info("📝 消息数量 {} 超过阈值 {},触发上下文压缩", previousMessages.size(), triggerLength);
// 提取对话历史文本(简化摘要)
String history = previousMessages.stream()
.filter(m -> !(m instanceof SystemMessage))
.map(Message::getText)
.collect(Collectors.joining("\n"));
// 保留系统消息
SystemMessage systemMsg = (SystemMessage) previousMessages.stream()
.filter(m -> m instanceof SystemMessage)
.findFirst().orElse(null);
// 创建摘要消息(实际可用 LLM 生成)
String summary = "【对话摘要】用户与客服进行了多轮对话,涉及订单查询和售后咨询。";
UserMessage summaryMsg = new UserMessage(summary);
// 保留最近5条
int keep = Math.min(5, previousMessages.size());
List<Message> recent = previousMessages.subList(previousMessages.size() - keep, previousMessages.size());
// 构建新消息列表
List<Message> newMessages = new ArrayList<>();
if (systemMsg != null) newMessages.add(systemMsg);
newMessages.add(summaryMsg);
newMessages.addAll(recent);
log.info("📝 压缩后消息数:{} → {}", previousMessages.size(), newMessages.size());
return new AgentCommand(newMessages, UpdatePolicy.REPLACE);
}
}
Agent 配置
java
package com.example.ai.config;
import com.alibaba.cloud.ai.graph.agent.ReactAgent;
import com.alibaba.cloud.ai.graph.checkpoint.savers.MemorySaver;
import com.example.ai.hook.SummarizationHook;
import com.example.ai.interceptor.ContextAwareToolInterceptor;
import com.example.ai.interceptor.DynamicPromptInterceptor;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AgentConfig {
@Bean
public ReactAgent customerServiceAgent(ChatModel chatModel) {
return ReactAgent.builder()
.name("customer_service_agent")
.model(chatModel)
.saver(new MemorySaver())
.interceptors(
new ContextAwareToolInterceptor(), // 瞬态:动态工具
new DynamicPromptInterceptor() // 瞬态:动态提示
)
.hooks(
new SummarizationHook(8) // 持久:消息压缩
)
.build();
}
}
Service 层
java
package com.example.ai.service;
import com.alibaba.cloud.ai.graph.RunnableConfig;
import com.alibaba.cloud.ai.graph.agent.ReactAgent;
import com.alibaba.cloud.ai.graph.exception.GraphRunnerException;
import com.example.ai.model.UserRole;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.stereotype.Service;
@Service
public class CustomerService {
private final ReactAgent customerServiceAgent;
public CustomerService(ReactAgent customerServiceAgent) {
this.customerServiceAgent = customerServiceAgent;
}
public String chat(String userMessage, String sessionId, UserRole role, String userId) {
RunnableConfig config = RunnableConfig.builder()
.threadId(sessionId)
.addMetadata("userRole", role.name())
.addMetadata("userId", userId)
.build();
try {
AssistantMessage response = customerServiceAgent.call(userMessage, config);
return response.getText();
} catch (GraphRunnerException e) {
throw new RuntimeException("客服系统暂时不可用:" + e.getMessage(), e);
}
}
}
Controller
java
package com.example.ai.controller;
import com.example.ai.model.UserRole;
import com.example.ai.service.CustomerService;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@RestController
@RequestMapping("/api/customer")
public class CustomerController {
private final CustomerService customerService;
public CustomerController(CustomerService customerService) {
this.customerService = customerService;
}
@PostMapping("/chat")
public Map<String, Object> chat(
@RequestParam String message,
@RequestParam(required = false, defaultValue = "default") String sessionId,
@RequestParam(defaultValue = "GUEST") String role,
@RequestParam(required = false, defaultValue = "anonymous") String userId) {
UserRole userRole = UserRole.valueOf(role.toUpperCase());
String response = customerService.chat(message, sessionId, userRole, userId);
return Map.of(
"success", true,
"response", response,
"sessionId", sessionId,
"role", userRole.name()
);
}
}
启动类
java
package com.example.ai;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ContextEngineeringDemoApplication {
public static void main(String[] args) {
SpringApplication.run(ContextEngineeringDemoApplication.class, args);
}
}
七、测试与验证
7.1 启动应用
bash
export DASHSCOPE_API_KEY="你的API密钥"
mvn spring-boot:run
7.2 测试不同角色的工具权限
bash
# 普通用户:只有基础工具
curl -X POST "http://localhost:885/api/customer/chat?message=查询订单ORD-001&sessionId=test&role=USER&userId=u001"
# VIP 用户:多了积分和升级工具
curl -X POST "http://localhost:885/api/customer/chat?message=查询我的积分&sessionId=test&role=VIP&userId=u001"
# 管理员:拥有全部工具
curl -X POST "http://localhost:885/api/customer/chat?message=处理退款ORD-002&sessionId=test&role=ADMIN&userId=admin"
观察日志:
🔧 用户角色:USER,可用工具数:2
🔧 用户角色:VIP,可用工具数:4
🔧 用户角色:ADMIN,可用工具数:6
7.3 测试长对话压缩
连续发送 10 条消息后,触发摘要 Hook:
bash
for i in {1..10}; do
curl -X POST "http://localhost:885/api/customer/chat?message=消息$i&sessionId=test&role=USER&userId=u001"
done
观察日志:
📝 消息数量 9 超过阈值 8,触发上下文压缩
📝 压缩后消息数:9 → 7
7.4 验证动态提示
询问 Agent 对用户的认知,不同角色应得到不同回应(因为系统提示不同)。
八、核心知识点总结
| 组件 | 作用 | 本示例中的应用 |
|---|---|---|
| 运行时上下文 | 通过 RunnableConfig.addMetadata() 注入静态配置 |
注入 userRole、userId |
| 模型上下文(瞬态) | 单次调用的消息/工具/提示 | ContextAwareToolInterceptor 动态注入工具 DynamicPromptInterceptor 动态注入提示 |
| 持久上下文 | 跨轮次保存的状态 | SummarizationHook 修改消息列表并持久化 |
| Interceptor | 拦截模型请求/响应,瞬态修改 | 工具选择、提示调整 |
| Hook | 生命周期节点执行操作,持久修改 | 消息摘要压缩 |
九、最佳实践
- 优先使用 Interceptor 处理瞬态上下文(工具、提示、消息过滤),避免污染持久状态。
- 使用 Hook 处理持久上下文(摘要、PII 脱敏),修改消息历史或状态。
- 通过运行时上下文传递静态信息(用户身份、权限),避免在工具或 Hook 中重复查询。
- 适时压缩上下文,防止超出模型的上下文窗口。
- 动态工具选择可以减少 LLM 的工具选择错误,提高准确率。
十、总结
上下文工程是构建生产级 Agent 的核心能力。通过合理使用 Interceptor (瞬态控制)和 Hook(持久控制),可以精细控制 Agent 的每一次行为,使其:
- 正确理解用户意图(动态提示)
- 使用恰当的工具(动态工具选择)
- 不超出模型能力边界(上下文压缩)
- 适应不同用户场景(角色感知)
本文的智能客服示例涵盖了上下文工程的主要实践场景,你可以将其推广到更多业务领域,构建更强大、更可控的 AI Agent 应用。
参考资源: