概述
本节实现对话历史的存储和管理,为多轮对话提供基础。
数据结构
Message 接口
1 2 3 4 5 6
| interface Message { role: 'system' | 'user' | 'assistant' | 'tool'; content: string; }
type ConversationHistory = Message[];
|
ConversationManager 类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| export class ConversationManager { private messages: Message[] = []; private systemPrompt: string; constructor(systemPrompt: string) { this.systemPrompt = systemPrompt; this.messages.push({ role: 'system', content: systemPrompt }); } addMessage(role: Message['role'], content: string): void { this.messages.push({ role, content }); } getMessages(): Message[] { return [...this.messages]; } getLastN(n: number): Message[] { return this.messages.slice(-n); } clear(): void { this.messages = [{ role: 'system', content: this.systemPrompt }]; } get length(): number { return this.messages.length; } }
|
集成到 Agent
更新后的 Agent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import { ConversationManager } from './conversation.js'; import { LLMClient } from './llm/client.js';
export class Agent { private llm: LLMClient; private conversation: ConversationManager; constructor(llm: LLMClient, systemPrompt: string) { this.llm = llm; this.conversation = new ConversationManager(systemPrompt); } async process(userInput: string): Promise<string> { this.conversation.addMessage('user', userInput); const messages = this.conversation.getMessages(); const response = await this.llm.chat(messages); this.conversation.addMessage('assistant', response); return response; } getHistory(): Message[] { return this.conversation.getMessages(); } clearHistory(): void { this.conversation.clear(); } }
|
更新 LLM Client
1 2 3 4 5 6 7 8 9 10 11 12
| export class LLMClient { async chat(messages: Message[]): Promise<string> { const response = await this.client.chat.completions.create({ model: this.model, messages: messages }); return response.choices[0].message.content || ''; } }
|
使用示例
基本使用
1 2 3 4 5 6 7 8 9 10 11 12 13
| const llm = new LLMClient(config); const agent = new Agent(llm, '你是一个友好的助手。');
let response = await agent.process('你好!'); console.log('助手:', response);
response = await agent.process('你刚才说了什么?'); console.log('助手:', response);
console.log('对话历史:', agent.getHistory());
|
清除历史
上下文窗口管理
Token 计数
1 2 3 4 5
| function estimateTokens(messages: Message[]): number { const text = JSON.stringify(messages); return Math.ceil(text.length / 4); }
|
自动裁剪
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| export class ConversationManager { private messages: Message[] = []; private readonly maxTokens: number = 8000; addMessage(role: Message['role'], content: string): void { this.messages.push({ role, content }); while (this.estimateTokens() > this.maxTokens && this.messages.length > 1) { const firstUserIndex = this.messages.findIndex(m => m.role !== 'system'); if (firstUserIndex > 0) { this.messages.splice(firstUserIndex, 1); } else { break; } } } private estimateTokens(): number { return Math.ceil(JSON.stringify(this.messages).length / 4); } }
|
完整示例
交互式多轮对话
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| import readline from 'readline'; import { Agent } from './agent.js'; import { LLMClient } from './llm/client.js'; import { loadConfig } from './config.js';
async function main() { const config = loadConfig(); const llm = new LLMClient(config.llm); const agent = new Agent(llm, '你是一个友好的 AI 助手。'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); console.log('=== 多轮对话 AI 助手 ==='); console.log('命令: /clear 清除历史, /exit 退出\n'); while (true) { const userInput = await question('你: '); if (userInput === '/exit') { break; } if (userInput === '/clear') { agent.clearHistory(); console.log('对话历史已清除\n'); continue; } const response = await agent.process(userInput); console.log('助手:', response); console.log(); } rl.close(); }
function question(prompt: string): Promise<string> { return new Promise((resolve) => { rl.question(prompt, (answer) => resolve(answer)); }); }
main();
|
输出示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| === 多轮对话 AI 助手 === 命令: /clear 清除历史, /exit 退出
你: 你好,我叫张三。 助手: 你好张三!很高兴认识你。有什么我可以帮助你的吗?
你: 我叫什么名字? 助手: 你叫张三。你刚才告诉我的。
你: /clear 对话历史已清除
你: 我叫什么名字? 助手: 抱歉,我不知道你的名字。我们能重新认识一下吗?
|
总结
Step 1 添加了对话历史管理:
- ✅ ConversationManager - 管理消息历史
- ✅ 上下文传递 - 将历史传给 LLM
- ✅ 窗口管理 - 自动裁剪超长历史
- ✅ 命令支持 - /clear, /exit
下一节将实现完整的多轮对话。
导航
上一篇: 3.1 上下文的重要性
下一篇: 3.3 多轮对话实现