PHP中LangChain的上下文窗口管理:知识库应用实战案例 (2025年05月)

云信安装大师
90
AI 质量分
3 5 月, 2025
3 分钟阅读
0 阅读

PHP中LangChain的上下文窗口管理:知识库应用实战案例

引言

在构建知识库应用时,有效管理对话上下文是提升用户体验的关键。本文将介绍如何在PHP中使用LangChain框架实现智能的上下文窗口管理,让您的知识库应用能够记住对话历史,提供更连贯的交互体验。

准备工作

环境要求

  • PHP 8.1+
  • Composer (依赖管理工具)
  • LangChain PHP SDK (v0.5+)

安装依赖

代码片段
composer require langchain/langchain
composer require guzzlehttp/guzzle  # HTTP客户端

基础概念:什么是上下文窗口?

上下文窗口是指AI模型在生成响应时能”记住”的对话历史范围。合理管理上下文可以:
1. 保持对话连贯性
2. 避免超出模型token限制
3. 优化API调用成本

实现步骤

1. 初始化LangChain客户端

代码片段
<?php
require 'vendor/autoload.php';

use LangChain\LangChain;
use LangChain\Memory\ConversationBufferWindowMemory;

// 初始化LangChain实例
$langchain = new LangChain([
    'api_key' => 'your_api_key_here', // 替换为你的实际API密钥
    'model' => 'gpt-4-turbo'          // 使用GPT-4 Turbo模型
]);

// 创建带窗口的记忆系统(保留最近3轮对话)
$memory = new ConversationBufferWindowMemory(3);

参数说明
api_key: LangChain服务的访问密钥
model: 指定使用的AI模型版本
ConversationBufferWindowMemory(3): 创建一个保留最近3轮对话的记忆系统

2. 实现知识库查询功能

代码片段
class KnowledgeBase {
    private $memory;
    private $langchain;

    public function __construct($langchain, $memory) {
        $this->langchain = $langchain;
        $this->memory = $memory;
    }

    /**
     * 查询知识库并返回智能响应
     */
    public function query($userQuestion) {
        // 1. 从记忆系统中加载历史上下文
        $history = $this->memory->loadMemoryVariables();

        // 2. 构建包含上下文的提示词
        $prompt = "你是一个专业的知识库助手。根据以下对话历史和问题提供准确回答:\n\n";
        $prompt .= "历史对话:\n" . ($history['history'] ?? '无') . "\n\n";
        $prompt .= "新问题: " . $userQuestion;

        // 3. 调用LangChain获取响应
        try {
            $response = $this->langchain->generate($prompt);

            // 4. 保存当前交互到记忆系统
            $this->memory->saveContext([
                'input' => $userQuestion,
                'output' => $response['text']
            ]);

            return $response['text'];
        } catch (Exception $e) {
            return "抱歉,处理请求时出错: " . $e->getMessage();
        }
    }
}

3. 使用示例

代码片段
// 初始化知识库实例
$knowledgeBase = new KnowledgeBase($langchain, $memory);

// 模拟用户交互流程
$questions = [
    "PHP是什么?",
    "它有哪些主要特点?", // AI会记得前一个问题 
    "最新版本是多少?",
    "与Python相比如何?",
    "能给我一个简单的例子吗?" // AI只会记得最后3个问题(2-4)
];

foreach ($questions as $question) {
    echo "用户: " . $question . "\n";
    echo "AI助手: " . $knowledgeBase->query($question) . "\n\n";
}

高级技巧与优化

a.动态调整窗口大小

根据问题复杂度动态调整记忆窗口:

代码片段
public function query($userQuestion) {
    // ...前面的代码...

    //根据问题长度调整记忆窗口(简单问题记更多,复杂问题记更少)
    if(strlen($userQuestion) <20){
        //简单问题,记住更多上下文(5轮)
        if(!$this->memory instanceof ConversationBufferWindowMemory || 
           !$this->memory->getK() ===5){
            //重新创建记忆对象(注意这会清空当前记忆)
            echo "[系统]检测到简单问题,扩大记忆窗口到5轮\n";
            $this->memory = new ConversationBufferWindowMemory(5);
        }
    } else { 
        //复杂问题,减少记忆(2轮)以节省token 
        if(!$this->memory instanceof ConversationBufferWindowMemory || 
           !$this->memory->getK() ===2){
            echo "[系统]检测到复杂问题,缩小记忆窗口到2轮\n";
            $this->memory = new ConversationBufferWindowMemory(2);
        }
    }

    // ...继续处理...
}

b.关键信息持久化存储

对于重要信息,可以存储在数据库中:

代码片段
class PersistentKnowledgeBase extends KnowledgeBase {

    private PDO $db; //数据库连接

    public function __construct($langchain, PDO $dbConnection) {
        parent::__construct($langchain, new ConversationBufferWindowMemory(3));
        $this->db =$dbConnection;

        try{
            //创建存储表(如果不存在)
            $this->db->exec("CREATE TABLE IF NOT EXISTS chat_history (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                session_id TEXT NOT NULL,
                input TEXT NOT NULL,
                output TEXT NOT NULL,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 
            )");

            //从数据库加载历史记录(如果有)
            if(!empty($_SESSION['chat_session_id'])){
                this.loadHistoryFromDB($_SESSION['chat_session_id']);
            }

         } catch(PDOException e){
             error_log("数据库错误: ".e.getMessage());
         }
     }

     protected function loadHistoryFromDB(sessionId){
         stmt= this.db.prepare("SELECT input,output FROM chat_history WHERE session_id=? ORDER BY created_at DESC LIMIT ?");
         stmt.execute([sessionId, this.memory.getK()]);

         foreach(stmt.fetchAll() as row){
             this.memory.saveContext([
                 'input'=>row['input'],
                 'output'=>row['output']
             ]);
         }
     }

     public function query(userQuestion){
         response=parent.query(userQuestion);

         try{
             if(!empty(_SESSION['chat_session_id'])){
                 this.db.prepare("INSERT INTO chat_history (session_id,input,output) VALUES (?,?,?)")
                    ->execute([
                        _SESSION['chat_session_id'],
                        userQuestion,
                        response.text || response]);
             }
         } catch(e){/*忽略存储错误*/}

         return response;
     }  
}

常见问题与解决方案

Q1: API调用超时怎么办?

A:
1.增加超时设置:

代码片段
new LangChain([...], [
   'timeout'=>30,//秒数 
   'connect_timeout'=>10 
]);

2.实现重试机制:

代码片段
for(i=0;i<3;i++){
   try{ return langchain.generate(prompt); } 
   catch(e){ sleep(1); continue; }  
} throw e;//重试后仍失败则抛出异常  

Q2:如何防止敏感信息被记住?

A:
1.添加过滤逻辑:

代码片段
function filterInput(input){
   return preg_replace('/\b(密码|账号|身份证)\b.*?/','[已屏蔽]',input);  
}  

//在query方法中:
userQuestion=filterInput(userQuestion);  

2.定期清除记忆:

代码片段
//每小时自动清除一次  
if(time()-lastClearTime>3600){  
   memory.clear(); lastClearTime=time();  
}  

总结

本文介绍了在PHP中使用LangChain实现上下文管理的完整方案:

1.核心组件
ConversationBufferWindowMemory -控制记忆窗口大小
generate()方法 -生成智能响应

2.最佳实践
✔️根据场景动态调整窗口大小
✔️重要信息持久化存储到数据库
✔️添加敏感信息过滤机制

3.扩展思路
◉结合向量数据库实现长期记忆
◉添加多轮对话状态跟踪

通过合理管理上下文窗口,您的知识库应用将能提供更加智能、连贯的交互体验!

原创 高质量