基于RAG与向量数据库的法律AI咨询平台:从零构建实战指南

发布时间:2026/8/10 13:21:00
基于RAG与向量数据库的法律AI咨询平台:从零构建实战指南 这次我们来看一个结合了AI大模型、向量数据库和即时通讯技术的法律援助在线咨询平台。这个项目不是简单的聊天机器人而是通过PostgreSQL的pgvector扩展实现法律知识库的智能检索再结合LLM进行推理生成最后用WebSocket提供实时交互。对于想了解如何将RAG检索增强生成技术落地到垂直领域特别是对延迟和准确性都有要求的法律咨询场景的开发者来说这个架构很有参考价值。它的核心思路很清晰用户提问时系统先从向量化的法律条文、案例库中精准检索出相关片段然后将这些片段作为上下文喂给大模型让模型生成专业、有据可依的回复并通过WebSocket实时推送给前端。这解决了大模型“胡言乱语”和“知识陈旧”两大痛点。本文将带你从零开始理解这个平台的技术栈选型、核心模块拆解并提供一个可运行的、简化的本地部署与测试方案。你会看到如何搭建PostgreSQL向量搜索环境、如何接入LLM API、如何构建WebSocket服务以及最终如何将它们串联成一个能回答法律问题的Demo系统。1. 核心能力速览能力项说明项目类型基于检索增强生成RAG的垂直领域AI应用核心功能法律知识智能检索、LLM生成专业回复、WebSocket实时对话技术栈PostgreSQL (pgvector), LLM API (如OpenAI/DeepSeek), WebSocket (Spring Boot/Node.js), 前端Vue/React硬件门槛无GPU要求。核心是数据库和网络服务普通开发机即可运行。LLM推理通常调用云端API。数据存储使用PostgreSQL存储结构化数据用户、会话和向量数据法律知识嵌入。实时性WebSocket保障咨询对话的低延迟、全双工通信。可扩展性知识库易于更新重新生成嵌入并入库LLM可替换支持批量知识文档处理。适合场景法律科技初创产品原型、企业内部法务助手、法律教育工具、RAG技术学习案例。2. 适用场景与使用边界这个平台适合以下几类人群或场景法律科技开发者需要快速构建一个具备专业知识库的AI法律咨询原型验证技术可行性。企业法务部门希望建立一个内部问答系统帮助员工快速查询公司规章制度、合同模板或基础法律问题。法律学习者与教育者作为辅助学习工具通过问答形式加深对法律条文的理解。全栈/后端工程师学习如何将LLM、向量数据库和实时通信技术整合到一个完整项目中。使用边界与重要提醒非正式法律意见平台生成的回复基于训练数据和知识库不能替代执业律师的专业法律意见。必须在前端显著位置添加免责声明。知识库质量决定上限回答的准确性严重依赖于向量库中法律知识的准确性、完整性和时效性。需要定期更新法律条文和案例。数据安全与隐私咨询内容可能涉及用户隐私。必须采取数据加密、访问控制等措施并明确用户协议。如果使用第三方LLM API需关注其数据隐私政策。性能与成本向量检索和LLM API调用均有延迟和成本。需针对并发用户量进行服务优化和成本测算。3. 环境准备与前置条件在开始部署之前请确保你的开发环境满足以下要求操作系统Windows 10/11, macOS, 或 Linux (如Ubuntu 20.04)均可。本文以Linux/macOS命令为例Windows用户可使用WSL或相应PowerShell命令。Java环境(如果后端使用Spring Boot)JDK 8 或 11 (推荐11)Maven 或 GradleNode.js环境(如果前端使用Node或后端使用Node.js)Node.js 16npm 或 yarnPostgreSQL数据库PostgreSQL 12必须安装pgvector扩展。这是实现向量搜索的关键。Python环境(用于知识库处理、嵌入生成等脚本)Python 3.8pipLLM API访问权限准备一个可用的LLM API Key例如OpenAI GPT系列DeepSeek文心一言、通义千问等国内大模型网络能够访问所选LLM的API服务地址。开发工具IDE如IntelliJ IDEA, VSCode、Postman或Apifox测试API、pgAdmin或DBeaver管理数据库。4. 安装部署与启动方式我们将项目拆解为几个核心部分进行部署数据库、知识库处理、后端服务、前端服务。4.1 部署PostgreSQL与pgvector首先安装并配置支持向量搜索的数据库。# 1. 安装PostgreSQL (以Ubuntu为例) sudo apt update sudo apt install postgresql postgresql-contrib # 2. 登录PostgreSQL sudo -u postgres psql # 3. 创建数据库和用户 CREATE DATABASE law_ai_db; CREATE USER law_ai_user WITH PASSWORD your_secure_password; GRANT ALL PRIVILEGES ON DATABASE law_ai_db TO law_ai_user; # 4. 连接到新数据库并安装pgvector扩展 \c law_ai_db CREATE EXTENSION IF NOT EXISTS vector; # 退出 \q4.2 构建法律知识向量库这是RAG系统的“大脑”。我们需要将法律文本如《民法典》条款转化为向量并存入数据库。准备知识文档将法律条文、司法解释等整理成文本文件如knowledge.txt每行一条或一个自然段。编写Python处理脚本(generate_embeddings.py)import psycopg2 from psycopg2.extras import execute_values import openai # 或使用其他嵌入模型如sentence-transformers import os # 配置 DATABASE_URL postgresql://law_ai_user:your_secure_passwordlocalhost/law_ai_db OPENAI_API_KEY your_openai_api_key EMBEDDING_MODEL text-embedding-3-small # 根据实际情况选择 # 初始化OpenAI客户端 (示例) client openai.OpenAI(api_keyOPENAI_API_KEY) # 连接数据库 conn psycopg2.connect(DATABASE_URL) cur conn.cursor() # 创建存储知识片段的表如果不存在 cur.execute( CREATE TABLE IF NOT EXISTS law_knowledge ( id BIGSERIAL PRIMARY KEY, content TEXT NOT NULL, embedding vector(1536), -- OpenAI text-embedding-3-small 维度为1536 metadata JSONB ); CREATE INDEX IF NOT EXISTS law_knowledge_embedding_idx ON law_knowledge USING ivfflat (embedding vector_cosine_ops); ) conn.commit() # 读取知识文本 def load_knowledge(file_path): with open(file_path, r, encodingutf-8) as f: # 简单按行分割实际可根据需要按句或按段分割 return [line.strip() for line in f if line.strip()] # 生成嵌入向量 def get_embedding(text): response client.embeddings.create( modelEMBEDDING_MODEL, inputtext ) return response.data[0].embedding # 主流程 knowledge_file ./knowledge.txt texts load_knowledge(knowledge_file) data_to_insert [] for text in texts: embedding get_embedding(text) data_to_insert.append((text, embedding, {source: civil_code})) # 示例元数据 # 批量插入数据库 execute_values( cur, INSERT INTO law_knowledge (content, embedding, metadata) VALUES %s, data_to_insert ) conn.commit() print(f成功插入 {len(data_to_insert)} 条知识记录。) cur.close() conn.close()运行脚本确保已安装psycopg2和openai库然后执行脚本。pip install psycopg2-binary openai python generate_embeddings.py4.3 启动后端服务Spring Boot示例后端负责协调向量检索、LLM调用和WebSocket通信。项目结构创建一个标准的Spring Boot项目包含以下核心依赖pom.xmldependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-websocket/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-jpa/artifactId /dependency dependency groupIdorg.postgresql/groupId artifactIdpostgresql/artifactId scoperuntime/scope /dependency !-- 用于向量相似度计算可能需要自定义函数 -- dependency groupIdcom.vladmihalcea/groupId artifactIdhibernate-types-52/artifactId version2.21.1/version /dependency !-- HTTP客户端用于调用LLM API -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-webflux/artifactId /dependency !-- 或使用OkHttp -- dependency groupIdcom.squareup.okhttp3/groupId artifactIdokhttp/artifactId version4.12.0/version /dependency /dependencies核心服务类(RagService.java)处理检索与生成。Service public class RagService { PersistenceContext private EntityManager entityManager; Value(${llm.api.key}) private String llmApiKey; Value(${llm.api.url}) private String llmApiUrl; // 1. 向量检索根据用户问题查找最相关的法律知识 public ListString searchRelevantLaws(String query, int topK) { // 首先需要将用户问题也转化为向量这里简化实际需调用嵌入API // 假设我们已获得queryEmbedding (float[]类型) // String sql SELECT content FROM law_knowledge ORDER BY embedding ?::vector LIMIT ?; // 使用原生查询执行余弦相似度计算 // 返回topK条最相关的法律文本 // 此处为伪代码实际查询依赖于pgvector和自定义方言 return Arrays.asList(《民法典》第一千零三十二条自然人享有隐私权。..., 《个人信息保护法》第四条个人信息是以电子或者其他方式记录的与已识别或者可识别的自然人有关的各种信息。...); } // 2. 构造Prompt并调用LLM public String generateAnswer(String userQuestion, ListString contexts) { String prompt buildPrompt(userQuestion, contexts); // 使用WebClient或OkHttp调用LLM API (如DeepSeek) String llmResponse callLlmApi(prompt); return extractAnswer(llmResponse); } private String buildPrompt(String question, ListString laws) { StringBuilder sb new StringBuilder(); sb.append(你是一个专业的法律AI助手请根据以下提供的法律条文准确、简洁地回答用户的问题。\n\n); sb.append(【相关法律依据】\n); for (int i 0; i laws.size(); i) { sb.append(i 1).append(. ).append(laws.get(i)).append(\n); } sb.append(\n【用户问题】\n).append(question).append(\n\n); sb.append(【请回答】\n); return sb.toString(); } private String callLlmApi(String prompt) { // 使用OkHttp或WebClient发送POST请求到LLM API // 构造JSON请求体包含prompt、model等参数 // 解析返回的JSON提取回复内容 // 此处返回模拟结果 return 根据《民法典》第一千零三十二条隐私权是自然人享有的私人生活安宁和不愿为他人知晓的私密空间、私密活动、私密信息依法受到保护不被他人侵扰、知悉、收集、利用和公开的权利。因此未经您同意拍摄您在家中的照片并传播可能构成对您隐私权的侵害。; } }WebSocket配置与处理器(WebSocketConfig.java,ChatWebSocketHandler.java)建立实时通信通道。启动应用# 在项目根目录下 mvn spring-boot:run默认情况下Spring Boot应用会在http://localhost:8080启动WebSocket端点可能是ws://localhost:8080/ws。4.4 启动前端服务Vue示例前端负责收集用户问题并通过WebSocket与后端交互实时显示回复。创建Vue项目并安装依赖npm create vuelatest law-ai-frontend cd law-ai-frontend npm install npm install axios核心聊天组件(Chat.vue)template div classchat-container div classmessage-list div v-formsg in messages :keymsg.id :class[message, msg.sender] {{ msg.content }} /div /div div classinput-area input v-modelinputMessage keyup.entersendMessage placeholder请输入您的法律问题... / button clicksendMessage发送/button /div /div /template script setup import { ref, onMounted, onUnmounted } from vue; const inputMessage ref(); const messages ref([]); let socket null; const connectWebSocket () { socket new WebSocket(ws://localhost:8080/ws); socket.onopen () { console.log(WebSocket连接成功); messages.value.push({ id: Date.now(), sender: system, content: 已连接到法律AI助手。 }); }; socket.onmessage (event) { const data JSON.parse(event.data); if (data.type answer) { messages.value.push({ id: Date.now(), sender: ai, content: data.content }); } }; socket.onerror (error) { console.error(WebSocket错误:, error); }; socket.onclose () { console.log(WebSocket连接关闭); }; }; const sendMessage () { if (!inputMessage.value.trim() || !socket || socket.readyState ! WebSocket.OPEN) return; const userMsg inputMessage.value; messages.value.push({ id: Date.now(), sender: user, content: userMsg }); // 发送消息到后端 socket.send(JSON.stringify({ question: userMsg })); inputMessage.value ; }; onMounted(() { connectWebSocket(); }); onUnmounted(() { if (socket) { socket.close(); } }); /script启动前端开发服务器npm run dev访问http://localhost:5173(或提示的其他地址) 即可看到聊天界面。5. 功能测试与效果验证部署完成后我们需要验证整个流程是否跑通。5.1 数据库与知识库验证测试目的确认法律知识已成功向量化并存入数据库支持相似度检索。操作使用psql或图形化工具连接law_ai_db数据库。输入SQL-- 检查表和数据 SELECT COUNT(*) FROM law_knowledge; -- 测试向量检索假设已有查询向量的函数这里用占位符 -- SELECT content FROM law_knowledge ORDER BY embedding [0.1,0.2,...]::vector LIMIT 3;预期结果COUNT返回大于0的数字表示数据已入库。向量检索查询能返回与测试向量最相关的几条法律文本。5.2 后端API与WebSocket连通性测试测试目的确保后端服务正常运行且WebSocket连接可以建立。操作使用Postman或curl测试REST API如果存在使用在线WebSocket测试工具如websocketking.com测试WebSocket。输入REST APIGET http://localhost:8080/health(假设有健康检查端点)。WebSocket连接ws://localhost:8080/ws。预期结果REST API返回成功状态如200 OK。WebSocket连接成功建立可以发送和接收消息。5.3 端到端法律咨询测试测试目的模拟真实用户完成一次完整的法律问答。操作在启动的前端页面中输入一个具体的法律问题例如“别人未经我同意拍了我家的照片并发到网上这违法吗”预期结果前端消息列表立即显示用户问题。几秒后收到AI助手的回复。回复内容应包含明确的结论如“可能构成侵权”。引用的具体法律条文如“根据《民法典》第一千零三十二条...”。简要的分析或解释。回复不应是通用闲聊而应体现从知识库中检索到了相关法律依据。判断成功标准整个流程无报错前端无红字后端控制台无异常栈。回复内容与问题相关且包含了法律条文引用格式可能为《法律名称》第XX条。响应时间在可接受范围内通常3-10秒取决于LLM API速度。5.4 批量问题压力测试可选测试目的验证系统在连续问答下的稳定性和资源占用。操作编写一个简单的脚本模拟10-20个连续的法律问题通过WebSocket接口依次发送。观察点后端服务的内存和CPU占用是否平稳。PostgreSQL数据库的连接数是否正常。是否有请求失败或超时。回答的质量是否因负载而下降。预期结果系统能稳定处理批量请求无内存泄漏或连接耗尽响应时间保持相对稳定。6. 接口API与批量任务除了实时WebSocket系统通常也需要提供异步API接口以支持批量咨询或与其他系统集成。6.1 异步REST API设计在后端增加一个Controller提供HTTP POST接口。RestController RequestMapping(/api/v1) public class LawConsultationController { Autowired private RagService ragService; PostMapping(/consult) public ResponseEntityConsultationResponse consult(RequestBody ConsultationRequest request) { // 1. 检索 ListString relevantLaws ragService.searchRelevantLaws(request.getQuestion(), 5); // 2. 生成 String answer ragService.generateAnswer(request.getQuestion(), relevantLaws); // 3. 返回 ConsultationResponse response new ConsultationResponse(); response.setAnswer(answer); response.setReferenceLaws(relevantLaws); response.setRequestId(UUID.randomUUID().toString()); return ResponseEntity.ok(response); } } // 请求和响应DTO class ConsultationRequest { private String question; // getters and setters } class ConsultationResponse { private String answer; private ListString referenceLaws; private String requestId; // getters and setters }6.2 批量任务处理对于需要处理大量法律文档如批量合同审查或问题列表的场景可以引入任务队列。方案使用Redis Spring Boot的Async注解或集成RabbitMQ、Kafka等消息队列。流程客户端提交一个包含多个问题的批量任务。后端将任务拆解放入消息队列。多个工作线程从队列中消费问题调用RagService处理并将结果写入数据库或文件。客户端通过另一个接口轮询或通过WebSocket推送获取批量结果。Python调用示例import requests import json url http://localhost:8080/api/v1/consult headers {Content-Type: application/json} questions [问题1, 问题2, 问题3] results [] for q in questions: payload json.dumps({question: q}) try: response requests.post(url, headersheaders, datapayload, timeout30) if response.status_code 200: results.append(response.json()) else: results.append({error: f请求失败: {response.status_code}}) except Exception as e: results.append({error: str(e)}) print(json.dumps(results, indent2, ensure_asciiFalse))7. 资源占用与性能观察由于本项目核心是服务集成资源占用主要集中在数据库和网络I/O。PostgreSQL资源内存pgvector索引如IVFFlat会占用额外内存。知识库越大内存需求越高。监控命令pg_top或SELECT * FROM pg_stat_activity;。CPU向量相似度计算余弦距离是CPU密集型操作。并发查询高时CPU使用率会上升。优化建议为law_knowledge表的embedding字段创建合适的索引如HNSW并在检索时合理设置probes参数以平衡速度与精度。后端服务Spring Boot资源内存JVM堆内存默认约占用256MB-1GB取决于并发和缓存。线程WebSocket和HTTP请求会占用线程。监控线程池状态。观察方式使用jconsole、jvisualvm或Spring Boot Actuator的/actuator/metrics端点。网络延迟最大瓶颈调用外部LLM API的网络延迟。国内用户调用海外API或反之延迟可能高达数百毫秒到数秒。优化选择地理位置上更近的API端点使用HTTP连接池考虑对回答进行缓存对于常见问题。整体性能指标端到端响应时间 (P95)从用户发送问题到收到完整回答的时间。目标应控制在5-10秒内。检索时间向量数据库检索相关条文的时间通常在几十到几百毫秒。生成时间LLM API的响应时间占大头。8. 常见问题与排查方法问题现象可能原因排查方式解决方案前端连接WebSocket失败1. 后端服务未启动。2. WebSocket端点路径错误。3. 防火墙/端口阻止。1. 检查后端控制台日志。2. 用curl或在线工具测试ws://localhost:8080/ws。3. 检查浏览器控制台Network标签页。1. 启动后端服务。2. 核对前端连接的URL与后端ServerEndpoint注解路径。3. 开放对应端口。知识检索结果不相关1. 知识库嵌入模型与查询嵌入模型不一致。2. 知识文本分割不合理。3. 向量索引未创建或类型不佳。1. 确认生成嵌入和查询嵌入使用同一模型。2. 检查知识文本是否过于冗长或碎片化。3. 在数据库执行\d law_knowledge查看索引。1. 统一嵌入模型。2. 优化文本分割策略按语义段落。3. 为向量列创建HNSW索引。调用LLM API超时或失败1. API Key无效或额度不足。2. 网络不通。3. 请求格式错误或频率过高。1. 检查API Key配置。2. 使用curl直接测试API端点。3. 查看后端日志中的HTTP响应码和Body。1. 更换或充值API Key。2. 配置网络代理如需。3. 调整请求参数增加重试机制降低频率。数据库连接失败1. PostgreSQL服务未运行。2. 连接字符串用户名、密码、数据库名错误。3.pgvector扩展未安装。1. 执行systemctl status postgresql或pg_isready。2. 使用psql手动连接测试。3. 在目标数据库执行CREATE EXTENSION vector;。1. 启动PostgreSQL服务。2. 修正application.properties或环境变量中的配置。3. 安装pgvector扩展。回答内容空洞或未引用法条1. 检索到的相关条文数量topK太少或质量差。2. 构造的Prompt指令不清晰。3. LLM本身“幻觉”或未遵循指令。1. 检查searchRelevantLaws方法返回的条文列表。2. 打印出最终发送给LLM的完整Prompt进行审查。3. 尝试更换LLM或调整温度temperature参数。1. 增加topK值或优化检索算法。2. 强化Prompt指令如“必须严格依据提供的条文回答”。3. 使用更可靠的LLM或在后处理中增加事实性检查。高并发下服务崩溃1. 数据库连接池耗尽。2. JVM内存溢出。3. 外部API调用达到限流。1. 监控数据库连接数(SHOW max_connections;)。2. 查看JVM崩溃日志hs_err_pid文件。3. 查看LLM API返回的429等错误码。1. 调整连接池配置如HikariCP。2. 增加JVM堆内存优化代码内存使用。3. 实现请求队列、熔断降级机制。9. 最佳实践与使用建议要让这个法律援助平台更健壮、可用可以参考以下建议知识库构建来源权威确保法律条文来自官方发布渠道。结构化处理除了全文可以提取“法条编号”、“主旨摘要”、“关键词”等元数据存入metadata字段便于混合检索。定期更新建立自动化流程当新法规发布时能重新生成嵌入并更新数据库。RAG流程优化重排序 (Re-ranking)在向量检索出topK结果后可以使用一个更精细的交叉编码器模型对结果进行重排序提升最终送入LLM的上下文质量。上下文窗口管理LLM有上下文长度限制。需设计策略当检索出的条文总长度超限时进行智能截取或摘要。系统可靠性缓存策略对常见问题的答案进行缓存如Redis可以极大降低LLM API调用成本和响应延迟。降级方案当LLM API不可用时可以降级为仅返回检索到的相关法律条文列表。监控告警对服务健康度、API调用成功率、响应时间、数据库连接数等关键指标进行监控。安全与合规输入过滤对用户输入进行敏感词过滤和内容审核防止恶意提问。输出审核对于高风险领域如刑事、国家安全考虑对AI生成的内容进行人工或规则复核。日志审计记录所有问答会话脱敏后满足合规审计要求。前端体验流式输出改造WebSocket接口支持LLM的流式响应让答案逐字显示提升用户体验。引用高亮在前端界面中将回答里引用的法律条文部分高亮显示并支持点击查看原文。这个基于AI的法律援助平台Demo清晰地展示了如何将pgvector、LLM和WebSocket这三项技术组合起来解决垂直领域的智能问答需求。从技术验证的角度你已经可以跑通全流程看到RAG如何让大模型的回答“有据可查”。最值得尝试的下一步是优化检索部分。你可以尝试不同的文本分割策略、不同的向量索引如HNSW、甚至加入关键词检索进行混合搜索观察对答案准确性的提升。另一个重点是Prompt工程通过设计更严谨的指令可以进一步约束LLM的回复格式和质量。最容易踩的坑除了环境配置就是法律知识库的质量。垃圾进垃圾出。花时间整理一份干净、结构化的法律条文数据集比盲目调整模型参数更有效。