共计 2116 个字符,预计需要花费 6 分钟才能阅读完成。
背景痛点
在长对话场景中直接使用 ChatGPT API 会遇到几个典型问题:

- Token 限制 :GPT-3.5 模型有 4096 个 token 的上下文窗口限制,长对话容易截断
- 上下文丢失 :无状态 API 需要每次携带完整历史,网络传输开销大
- 响应延迟 :复杂问题需要等待完整生成,用户体验差
技术方案
1. Trae 中间件设计
通过自定义中间件实现对话状态机管理:
// 对话状态中间件
export const chatSession = (): TraeMiddleware => async (ctx, next) => {const sessionId = ctx.headers['x-session-id'] as string;
if (!sessionId) throw new Error('Missing session ID');
// 从 Redis 加载历史上下文
ctx.state.dialogContext = await redisClient.get(`chat:${sessionId}`);
await next();
// 保存更新后的上下文
if (ctx.state.replyContent) {
await redisClient.setex(`chat:${sessionId}`,
SESSION_TTL,
JSON.stringify(ctx.state.dialogContext)
);
}
};
2. Redis 缓存架构
采用两级存储策略:
graph TD
A[客户端] -->| 请求 | B[Trae 服务]
B -->| 读缓存 | C[(Redis)]
C -->| 命中 | D[返回缓存]
C -->| 未命中 | E[调用 ChatGPT API]
E -->| 写入 | C
关键实现细节:
- 使用 Hash 结构存储对话片段
- 设置动态 TTL(最近活跃会话延长有效期)
- 采用 MsgPack 压缩历史数据
3. 流式响应实现
通过 Trae 的 Transform 流处理:
app.post('/chat', async (ctx) => {const stream = new PassThrough();
ctx.body = stream;
const openaiStream = await chatCompletionStream({messages: ctx.state.dialogContext});
openaiStream.on('data', (chunk) => {stream.write(`data: ${chunk}\n\n`);
});
openaiStream.on('end', () => stream.end());
});
完整代码示例
路由配置(带 JWT 鉴权)
import trae from 'trae';
import jwt from 'jsonwebtoken';
export const router = trae.createRouter();
router.use(async (ctx, next) => {
try {const token = ctx.headers.authorization?.split(' ')[1];
ctx.state.user = jwt.verify(token, SECRET_KEY);
await next();} catch (err) {
ctx.status = 401;
ctx.body = {error: 'Invalid token'};
}
});
router.post('/v1/chat', chatSession(), async (ctx) => {// 处理逻辑});
Redis 操作类
class DialogCache {
private readonly PREFIX = 'chat:';
async get(sessionId: string): Promise<ChatMessage[]> {const data = await redis.getBuffer(this.PREFIX + sessionId);
return data ? msgpack.decode(data) : [];}
async set(sessionId: string, messages: ChatMessage[]): Promise<void> {
await redis.setex(
this.PREFIX + sessionId,
this.calculateTTL(messages),
msgpack.encode(messages)
);
}
private calculateTTL(messages: ChatMessage[]): number {return messages.length > 5 ? LONG_TTL : SHORT_TTL;}
}
性能优化
压测数据对比
| 方案 | QPS | P99 延迟 |
|---|---|---|
| 无缓存 | 82 | 1.2s |
| 有缓存 | 210 | 680ms |
优化策略
- 使用 pipeline 批量读取历史消息
- 对长对话启用渐进式加载
- 实现客户端缓存协商
避坑指南
合规性处理
- 对话数据加密存储
- 实现自动敏感词过滤
- 提供数据清除接口
冷启动优化
- 预热常见问答对
- 使用 LRU 缓存最近会话
- 异步加载用户历史
延伸思考
- 如何实现跨会话的知识关联?
- 在多租户场景下如何优化资源分配?
- 针对专业领域该如何扩展上下文理解能力?
这套方案在我们生产环境已稳定运行 6 个月,日均处理对话请求超过 50 万次。特别要注意对话隔离的实现,建议采用会话级 Redis 分片来避免热点问题。
正文完
