
“AI 是否真的能让普通人更容易获得应有的法律帮助在司法场景里这个问题会比技术演示复杂得多。它不是问“模型能不能写一篇文章”而是问“一个缺少法律知识的普通用户能否通过 AI 更快、更准确地找到自己适用的规则、了解可能的程序、判断下一步可以做什么”。要验证这一点最好的方式不是空谈概念而是做一个带检索增强的法律信息问答原型然后用量化指标检查它是否真的减少错误答案、提升引用质量。这篇文章会围绕“验证 AI 对司法可及性是否有改进”这一目标设计一个可复现的技术原型将公开的法律文书、办事指南切成片段用向量检索召回相关段落再交给大模型生成带来源的答复最后用一组典型问题评测系统表现。需要先说明边界。这篇文章讨论的是面向普通公众的法律信息检索与程序引导不是自动化裁判也不是代替律师出具正式法律意见。项目案例只使用公开、合规、非涉密的法律知识文本围绕“普通人能不能低成本地获取准确信息”这一核心问题展开。这样既能在技术层面深入也能避免把模型输出当成正式法律结论。1. 先厘清“司法可及性”在 AI 项目里到底是什么1.1 司法可及性不是一个抽象口号而是一组具体障碍Access to Justice中文通常译为“司法可及性”或“司法救助的可得性”。技术项目不能把这个问题当成一个笼统概念来处理需要拆成可度量的用户痛点。常见障碍至少有四类信息不知道去哪里找用户不清楚自己的问题属于劳动争议、消费维权、婚姻家事还是行政诉讼。找到文本但读不懂法律条文表述严谨普通用户容易误解“应当”“可以”“但有例外”的含义。知道规则不知道程序即使知道实体规则也不清楚管辖法院、申请材料、时效期限、举证责任。请律师门槛高专业咨询价格高偏远地区服务资源少导致很多诉求因为“不知道怎么启动”而放弃。AI 要改善 access to justice就要针对上述每一类障碍而不是简单做一个通用聊天框。普通用户需要的不是“泛泛的法律知识”而是“基于我的具体描述找到与之相关度最高的规范文本和办事指南并说明依据在哪里”。1.2 为什么是 RAG而不是单独让大模型回答问题大模型本身可以背下一些法律知识也能流畅地输出看起来很专业的回答。但在司法场景里记忆型问答有三个无法接受的缺陷知识过时法律会修订司法解释会更新模型训练数据里保存的是过去状态。编造法条模型无法准确记住所有条文的序号和措辞可能生成一个表面正常、实际不存在的条款。无法举证用户需要知道依据来自哪里但生成式模型回答问题时不天然携带可验证的出处。检索增强生成Retrieval-Augmented Generation, RAG解决的就是“先找到依据再回答问题”的问题。AI 先在一个受控的法律知识库中检索候选段落再把候选段落作为上下文交给大模型生成回复。这样回答的来源可以被追踪知识也可以随知识库更新而更新并不需要反复重新训练模型。用技术架构来表达RAG 链路包含四步把原始法律文本清洗、切块、向量化。将向量写入向量数据库并保留原文字段和来源元数据。用户提问时把问题向量化并在知识库中检索 Top-K 候选片段。将候选片段、用户问题、系统规则拼装成 prompt交给大模型生成带引用标记的回答。1.3 本文要完成的最小验证项目为了回答“AI 是否改善 access to justice”本文不是要开发一个上线产品而是建立一个最小可复用的实验框架完成三件事构建一个法律信息检索问答原型。准备一组贴近普通用户表达的评测问题。用检索命中率、答案正确率和引用完整率来量化系统表现。通过这个框架可以对比“纯大模型直接回答”和“RAG 回答”的差异也可以进一步评估不同切片策略、不同向量模型、不同 Top-K 参数对改善效果的影响。这个实验框架本身比某一次演示结果更有价值因为它让“是否改善”从主观感受变成可重复的技术指标。2. 环境准备与依赖先把受控知识库和模型跑起来2.1 需要准备哪些软件环境这里采用 Python 技术栈组件选择以本地可运行、便于调试为主。组件作用推荐工具语言环境编写脚本Python 3.10向量化把文本转成向量sentence-transformers 库 bge-small-zh-v1.5 模型向量数据库存储向量与原文Chroma大模型生成回答本地指令模型Qwen2.5-7B-Instruct 或同类中文指令模型推理服务降低接入成本vLLM 或 Transformers pipeline二选一即可开发环境调试脚本Jupyter Notebook 或 VS Code学习环境建议尽量使用本地或内网资源减少对公网 API 的依赖。如果电脑显存不足可以先用小模型如 Qwen2.5-3B-Instruct 跑通链路再在服务器上切换大模型。实验第一阶段不必追求最高准确率关键是链路完整、指标可统计。安装依赖的命令如下python -m venv justice_rag_env source justice_rag_env/bin/activate pip install -U chromadb sentence-transformers torch transformers pip install vllm如果下载模型比较慢建议先从模型仓库下载到本地目录再在代码中指定本地路径。模型文件体积较大检查磁盘空间要留足。vllm在 macOS 上支持不完全Windows 上推荐用 WSL 或 Linux 服务器运行学习环境可以直接使用transformers加载模型。2.2 准备合规的法律知识文本语料这一步在法律场景中非常关键。语料质量决定了系统上限。不建议爬取未授权或来源不明的文本。可以优先选择以下公开来源官方发布的法律文本、行政法规、司法解释。法院或司法行政机关发布的诉讼指南、立案指引、风险告知书。法律援助机构公开的办事流程说明。由版权方明确授权的法律知识库。演示项目需要避免把未经整理的大量原始 HTML 塞入系统。先把资料转换为 Markdown 或纯文本再抽取标题、来源、发布时间、正文正文。原始材料的名称、版本、修订日期要保留否则后续检索引用会失去可信度。建议建立以下目录结构access_to_justice_demo/ data/ legal_texts/ labor_law.md civil_suit_guide.md scripts/ 01_build_index.py 02_ask.py 03_evaluate.py eval_cases.json vector_store/ models/ requirements.txtdata/legal_texts/存放经过清洗的原文scripts/存放索引、问答和评测脚本vector_store/存放向量数据models/存放本地模型。模型文件不进版本库向量索引如果可重建也不必入库保存重建脚本即可。2.3 安装完成后先做一次基本健康检查安装完成后不要急着写业务代码先验证三件事python -c from sentence_transformers import SentenceTransformer; m SentenceTransformer(BAAI/bge-small-zh-v1.5); print(m.encode(测试).shape) python -c import chromadb; print(chromadb.__version__) python -c from transformers import AutoTokenizer; print(transformers ok)如果上述命令都能执行说明依赖基本可用。这里要注意不同包版本的 API 可能有差异运行报错时优先检查版本号。下面的示例代码基于当前常见版本写法落地时如果遇到 DeprecationWarning要按照官方 API 调整调用方式。3. 构造一个面向法律场景的 RAG 问答链路3.1 数据切片先解决“让检索一个片段包含完整语义”的问题法律文本与普通文章不同条文之间经常有“前款”“本法所称……”“除本法另有规定外”等关联表述直接按固定字符长度切分容易切断语义。因此要采用“标题感知”的切片策略。基础切分逻辑如下对一部法律优先按“第X条”切分保留条文编号。对指南类文本按二级或三级标题切分。超过长度限制的片段继续切分为小节但要在元数据中记录所属文书和章节。为每个片段生成稳定的唯一编号例如doc_id加chunk_index。写一个通用切片函数# scripts/common.py import re from dataclasses import dataclass dataclass class Chunk: chunk_id: str doc_id: str source_title: str text: str def split_law_text_by_article(doc_id: str, title: str, content: str) - list[Chunk]: # 按“第X条”拆分适用于法律条文类文本 pattern re.compile(r(第[一二三四五六七八九十百千0-9]条)) parts pattern.split(content) # parts[0] 是开头说明后续是“条文编号 正文”交替 chunks [] if parts[0].strip(): chunks.append(Chunk( chunk_idf{doc_id}_head, doc_iddoc_id, source_titletitle, textparts[0].strip(), )) for i in range(1, len(parts), 2): article_no parts[i] body parts[i 1].strip() if i 1 len(parts) else if not body: continue chunks.append(Chunk( chunk_idf{doc_id}_{article_no}, doc_iddoc_id, source_titletitle, textf{article_no} {body}, )) return chunks当一段条文过长时需要限制长度。常见做法是设置max_chunk_length为 500 到 800 个子目符并加入重叠区间避免关键句被切到两个片段而造成召回困难。法律原文中一个条文往往是完整语义优先“一个条文一个片段”超长再按句子切分。注意法律文本格式并不总是规整。有的 PDF 转文本后“第X条”前后出现大量空格、换行或页眉页脚。在切片前要做文本规范化例如压缩空白、去掉页眉行、修复断行。3.2 构建向量索引兼顾语义向量和元数据切片完成后进入索引构建脚本。这里使用 HuggingFace 的嵌入模型生成向量使用 Chroma 存储。Chroma 的collection.add接口要求ids、documents、metadatas和embeddings长度一致。为了避免文本过长导致模型处理缓慢可以先统一限制文本长度。# scripts/01_build_index.py import json from pathlib import Path import chromadb from sentence_transformers import SentenceTransformer EMBEDDING_MODEL ./models/bge-small-zh-v1.5 INPUT_DIR Path(./data/legal_texts) CHROMA_PATH ./vector_store COLLECTION_NAME legal_info # 加载本地模型 model SentenceTransformer(EMBEDDING_MODEL) client chromadb.PersistentClient(pathCHROMA_PATH) collection client.get_or_create_collection( nameCOLLECTION_NAME, metadata{hnsw:space: cosine} ) def build(): chunks [] for path in INPUT_DIR.glob(*.md): # 实际代码里需要结合自己的切片方案 text path.read_text(encodingutf-8) # 假设已经定义 split_by_article chunks.extend(split_document(str(path.stem), path.name, text)) ids [] documents [] metadatas [] embeddings [] for c in chunks: if not c.text.strip(): continue ids.append(c.chunk_id) documents.append(c.text[:1000]) metadatas.append({ doc_id: c.doc_id, source_title: c.source_title, }) embeddings.append(model.encode(c.text[:500])) collection.upsert( idsids, documentsdocuments, metadatasmetadatas, embeddingsembeddings, ) print(findexed {len(ids)} chunks) if __name__ __main__: build()这里使用余弦距离。对中文法律文本余弦相似度通常比欧氏距离更稳定。bge-small-zh-v1.5的向量维度为 512bge 系列模型默认情况下需要查询侧不再加 instruction可以通过官方文档确认。示例代码中切段后documents和embeddings分别截断是为了演示接口时避免异常实际正式项目中应保持写入内容一致。3.3 基于向量检索的召回逻辑用户提问时先把问题向量化再通过向量数据库检索最相关的片段。需要同时考虑两件事语义相似度要高来源要多样。如果 Top-K 检索结果来自同一部法律中的连续几条回答可能只覆盖一个侧面。更好的做法是先按相似度取出较多候选再按doc_id去重保留每个来源中分数最高的前几段。# scripts/02_ask.py def retrieve(query: str, k: int 4): query_vec embedding_model.encode(query) result collection.query( query_embeddings[query_vec], n_resultsk * 3, include[documents, metadatas, distances], ) # 对结果按来源分桶然后每个来源保留 top_1这里做简化处理 seen_doc set() final_docs [] for doc, meta, dist in zip( result[documents][0], result[metadatas][0], result[distances][0], ): doc_id meta[doc_id] if doc_id not in seen_doc: seen_doc.add(doc_id) final_docs.append({ score: 1 - dist, doc: doc, meta: meta, }) if len(final_docs) k: break return final_docs这里score 1 - dist只适用于 Cosine 距离配置。如果使用普通内积评分含义会不同。学习阶段更建议保留原始documents和metadatas打印出来人工确认召回内容是否合理再进入大模型生成环节。可以打印如下内容辅助调试for item in retrieve(拖欠工资应该向哪个机构投诉): print(item[meta][source_title], item[doc])如果这一步与预期相关文档不符后面 prompt 怎么写都没有用。RAG 系统的上限主要由检索决定。3.4 让大模型在限定上下文里生成带来源的回答召回完成后将候选片段拼接进 prompt。prompt 要明确几个约束只依据给定的资料回答。若资料不足明确说“在当前资料中没有找到具体规定”。说明只是法律信息参考不是正式法律意见。不要编造条文号和机构名称。引用资料时使用“依据《XX》”等句式。SYSTEM_PROMPT 你是一个面向普通公众的法律信息检索助手。 你只能参考“用户资料”中提供的内容回答问题不能调用资料之外的记忆。 回答规则 1. 回答必须简明、口语化方便非法律专业用户理解。 2. 如果资料不足直接回答“在当前资料中没有找到对应规定”。 3. 不要对案件结果作出承诺不要替代律师给出正式代理意见。 4. 在回答中注明依据来源例如“依据你提供的资料《劳动法》相关条文”。 def build_prompt(query, retrieved_chunks): context_text \n\n.join( f【来源{item[meta][source_title]}】\n{item[doc]} for item in retrieved_chunks ) return [ {role: system, content: SYSTEM_PROMPT}, {role: user, content: f用户问题{query}\n\n用户资料\n{context_text}}, ]使用 vLLM 部署模型时启动命令可以类似vllm serve Qwen/Qwen2.5-7B-Instruct \ --served-model-name legal_llm \ --dtype bfloat16 \ --max-model-len 4096 \ --gpu-memory-utilization 0.8学习阶段也可以直接使用transformers的pipeline但生成速度会明显低于 vLLM。判断一个答案是否可用需要先看“引用依据是否真的存在于检索结果中”再看“结论是否在逻辑上由依据推出”最后才看表达是否流畅。这三者是分开的不能因为答案通顺就认为可信。4. 用评测集验证 AI 是否真的提升了司法可及性4.1 评测集要模拟真实用户而不是模拟法律条文标题检验“是否改善”需要准备一组不按教科书口吻提问的题目。真实用户不会说“请检索劳动争议仲裁时效条款”而是会说“公司拖欠我两个月工资我还能要回来吗”。评测问题可以分为四类规则查询类验证模型能否找到具体规定。例如“起诉离婚需要准备什么材料”程序引导类验证模型能否说明步骤、时限和受理机构。例如“同事欠我钱不还去法院起诉的话应该去哪个法院”边界拒绝类验证模型在资料不足时能否不编造。例如“我的案子输了之后还能再告吗法院判决会不会自动无效”风险提示类验证模型是否在回答敏感事项时给出合规引导而不是直接教人钻程序漏洞。建议把评测用例保存为 JSON 文件[ { question: 公司拖欠我两个月工资我向哪里投诉, expected_keywords: [劳动监察, 仲裁, 拖欠工资], expected_source_titles: [劳动保障监察指南] }, { question: 我没有钱请律师有什么途径可以获得帮助, expected_keywords: [法律援助], expected_source_titles: [法律援助申请指南] } ]expected_keywords用来做快速规则判断expected_source_titles用来检查检索是否命中正确文书。此文件只是示例实际评估时每类至少准备 10 到 20 个问题覆盖不同法律关系。4.2 衡量“改善”需要拆成多项指标单一指标无法回答“是否改善”。至少要监控以下五个维度指标计算方式反映的问题检索命中率相关来源是否出现在 Top-K 召回结果中能否找到正确信息答案事实一致性人工或模型标注答案是否与检索片段一致是否忠实于依据引用完整率回答中是否包含至少一个来源用户能否查证拒答率资料不足时模型是否拒绝或说明是否避免幻觉有害输出率是否出现误导、绝对承诺或诱导规避规则是否安全可控实际评估时可以先用脚本快速过滤答案再进行人工抽检。规则先看有没有“依据”“资料”类词再看是否包含预期关键词。人工阶段重点看语义准确性。4.3 写一个轻量评测脚本# scripts/03_evaluate.py import json import re def load_data(path): with open(path, r, encodingutf-8) as f: return json.load(f) def evaluate_lite(cases, answers): hit 0 for case, ans in zip(cases, answers): if any(k in ans for k in case.get(expected_keywords, [])): hit 1 return hit / len(cases) if cases else 0 if __name__ __main__: cases load_data(eval_cases.json) # answers 由问答脚本逐条生成后保存 # 这里简化处理假设 answers 是字符串列表 answers [] print(命中率:, evaluate_lite(cases, answers))这个脚本只做最基础的规则检查。更完整的评测方案建议把问答结果落成表格记录问题、检索来源、模型答案、人工评分便于定位是哪一层出了问题。如果检索来源正确但答案是错的问题出在 prompt 或模型如果检索来源本身不对问题则出在切片、向量模型或 Top-K 参数。4.4 预期结果与解读方式在合理切片的实验环境里RAG 的检索命中率通常会明显高于纯模型记忆命中率因为纯 LLM 无法稳准确记录某个具体条款所在文书。但必须注意RAG 并不保证答案百分之百正确。可能的对比结果有三种检索正确、回答正确说明链路有效这是最常见的理想情况。检索正确、回答错误说明模型没有严格遵循上下文需要优化 prompt或使用更小的温度参数。检索错误、回答错误说明知识库、切片、向量模型或查询改写存在问题与 prompt 关系不大。这样“AI 是否改善 access to justice”就被转化成了一个可定位的技术问题改善发生在哪一层没改善又发生在哪一层。任何技术判断脱离了评测过程都不可靠。5. 常见问题与排查路径5.1 检索不到正确片段返回一堆无关内容现象问“拖欠工资向哪里投诉”检索结果返回的是民事诉讼法中的管辖条款而不是劳动保障监察指南。可能原因切片太碎导致一个片段只包含“投诉渠道”半句话法律名称与问题表述的词汇差异过大正文中机构名称是简称而用户问题使用全称向量检索 Top-K 太小。检查方式打印检索到的前 5 条片段看是否包含“劳动监察”字样。查看原文档是否被正确导入、是否被标题切分器错误处理。对问题进行关键词扩展改为“拖欠工资 投诉 劳动监察”再检索。解决建议为每个片段增加“关键词标签”元数据检索时先按关键词粗筛再按向量排序。不要只依赖向量检索。5.2 切片把一个完整条文切断模型只看到一半现象回答某法条是否适用时出现误判因为检索结果只有“可以依照本法有关规定执行”没有前面的条件。原因文本按固定字符长度切割没有按条文边界切分且没有设置重叠。检查方式查看documents字段中该片段首尾是否完整是否在条文中间直接截断。解决建议优先按“第X条”切分。对于超过长度上限的条文再按完整句子切分并保留前后各一句重叠区间。检索时不要把 OpenAI 最大 context 当切片长度切片长度要远小于模型窗口。5.3 模型回答看起来流利但把检索资料里没有的内容补上了现象资料中没有某条规定模型仍然回答“根据《XX法》第X条”且看起来十分具体。原因大模型在指令遵守上不稳定没有严格限制“只依据资料”。也可能 temperature 设置过高导致生成自由度大。检查方式在生成脚本中打印完整 prompt人工确认上下文里的确没有该内容。增加输出日志把每次生成的输入上下文和输出同时保存。解决建议温度调整为 0.1 或 0在 prompt 中使用更直接的限定对结构化强的问题要求模型先引用原文再解释。更可靠的方式是在代码层拦截先让模型只输出“是或否、可能原因、依据片段编号”再由模板生成讲解。5.4 本地模型推理很慢甚至内存崩溃现象还没有得到回答就 OOM多个用户同时请求时排队严重。原因本地模型在 CPU 上运行或 GPU 显存不足max_model_len设置过大并发处理时没有做队列或批次限制。检查方式用nvidia-smi查看显存占用。对比切换小模型后的速度和显存占用。查看日志中的CUDA out of memory是否出现在加载长上下文时。解决建议学习环境先切换到 1.5B 或 3B 模型生产环境使用 vLLM 部署并限制最大输入长度。把问题拆成“检索与生成两步”不要把超长知识库都塞进模型。5.5 评测指标看起来高但用户实际使用还是不满意现象关键词命中率很高但用户提问“对方打了我怎么申请伤情鉴定”时回答没有解释“需要去公安机关委托鉴定”等关键程序。原因关键词命中只证明出现了相关词语没有验证用户任务是否完成。任务导向型问题需要完整步骤而不是零散法条。解决建议评测集增加任务链路判定把“是否包含步骤A、步骤B、材料C”设成三个独立检查点。人工抽检至少覆盖 20% 的评测问题重点检查程序步骤是否遗漏。用一张表整理上述问题问题现象常见原因检查方式处理建议检索结果无关切片过碎、来源切分错误打印 Top-K 片段修切片逻辑增加关键词标签条文不完整固定长度切分无重叠查看片段首尾按条文边界切割并加重叠编造条款模型未受上下文约束保存完整 prompt 与答案降低温度强约束引用片段 ID推理慢或 OOM显存不足、窗口过大查看显存与模型大小换小模型使用 vLLM 限制长度关键词命中但任务不完整评测指标粗糙增加人工抽检评测集加入步骤级检查6. 把“是否改善”落到负责任的技术实践上6.1 区分“信息获取”与“正式法律服务”AI 系统可以提高普通人对法律信息的可获得性但不应模糊自己与正式法律服务的边界。比较稳妥的设计是让系统做如下四件事帮用户把生活语言转化为法律问题。展示相关法律条文和公开办事指南。说明常见程序、时限、材料和受理机构。提示用户在复杂或高风险场景寻求律师或法律援助。系统不应做下列事情对具体案件结果作大概率断言。教用户伪造证据、规避送达、隐藏财产、拖延执行。在没有授权的情况下替代律师签署文书。技术实现上可以在进入高风险对话时设置拦截。例如用户问题包含“怎么让法院找不到我”“怎么转移房产不影响赔偿”等表述时系统自动返回“此类问题不适合由本助手回答建议咨询正规法律专业人士”不再进入生成流程。这个规则可以放在检索之前也可以放在输出之后作为兜底。6.2 学习环境与生产环境的差异环节学习/实验环境生产/严肃场景知识库少量公开文本即可需要持续更新、版本管理、修订通知模型本地小模型或 API需要服务化、并发控制、降级方案日志可不开必须保存问题、检索依据、答案审计日志安全本地可控需要鉴权、限流、数据脱敏、敏感内容过滤评测固定测试集测试集滚动更新记录回归结果上线不做承诺需要法律专业人士参与内容审核生产环境还有一个容易被忽视的问题知识库更新后旧答案仍可能被缓存或记录传播。要在答案中注明最后更新时间来源并让用户明确看到“这里不是律师意见”。6.3 可复用的上线检查清单在把小范围原型向更严肃场景推进前建议逐项核对这份清单[ ] 是否已有明确的文本来源和授权记录。[ ] 每个切入点和答案是否能回溯到原文档。[ ] 是否建立版本管理法律修订后能否主动更新。[ ] 是否在 UI 层明确提示“参考信息非正式法律意见”。[ ] 是否覆盖至少三类高风险问题的安全拒绝规则。[ ] 是否保存检索上下文和模型日志便于事后核查。[ ] 是否有人工审核或法务审核流程。[ ] 是否对全量回答跑了至少一轮评测回归。[ ] 是否有明确回退方案模型异常时能否关闭或降级为普通文档检索。[ ] 是否准备用户投诉或反馈入口。这些项目不是做好看而是“AI 改善司法可及性”是否经得起验证的关键。技术演示可以关注答案质量真实服务则必须关注来源可信度、更新机制和风险边界。6.4 下一步扩展方向如果实验证明 AI 确实提高了信息查询效率可以继续做四类扩展更细粒度的地域化知识把各省市法院的立案材料、法律援助申请入口拆成可筛选的元数据加入“地区检索”。多轮追问的设计用户第一次提问往往不完整需要澄清“你所在的城市、事件是否已判决、是否已申请劳动仲裁”等信息。更严格的输出控制采用“先抽取证据链再生成回答”的架构而不是让模型自由发挥。可解释性增强在界面中显示命中的原文片段用户点击后可以展开完整条款或办事指南。技术之外也要记得一句话司法可及性的短板不一定全靠模型能力解决很多时候是“组织信息的方式”和“引导用户准确表达问题的方式”。对普通用户而言一个问题被问到“仲裁时效”之前还要先知道自己该不该走仲裁。这个前序引导比生成大段法条更能改善真实体验。回到最开始的问题AI 是否真正改善了 access to justice一个可验证的回答是它能改善信息获取层的可及性但前提是知识库可靠、检索能命中、回答有约束、风险有边界。用 RAG 搭建一个原型不算难难的是把这个原型放在真实服务链条里持续测、持续改。评价这套技术是否有效不要只看“答案听起来对不对”要看它能否帮助一个不懂法律的人在合理时间内找到依据、理解规则并作出下一步行动。