Упрощение юридических исследований с помощью RAG, Milvus и Ollama
В этой статье блога мы увидим, как можно применить RAG к юридическим данным.
Юридическое исследование может занимать много времени. Обычно вам нужно просмотреть большое количество документов, чтобы найти нужные ответы. Retrieval-Augmented Generation (RAG) может помочь оптимизировать ваш исследовательский процесс.
Что такое RAG?
Retrieval Augmented Generation (RAG) — это техника, которая улучшает LLM за счет интеграции дополнительных источников данных. Типичное приложение RAG включает:
Индексирование — пайплайн для получения данных из источника и их индексирования, который обычно состоит из загрузки, разделения и сортировки данных в Milvus.
Поиск и генерация — Во время выполнения RAG обрабатывает запрос пользователя, извлекает релевантные данные из индекса, хранящегося в Milvus, а LLM генерирует ответ на основе этого обогащенного контекста.
В этом практическом руководстве мы рассмотрим, как настроить систему Retrieval Augmented Generation (RAG) с использованием Ollama, уделяя основное внимание юридическим данным и используя Milvus в качестве нашей векторной базы данных.
Инструменты:
Ollama: Переносит возможности LLM на ваш ноутбук, упрощая локальную работу.
Milvus: Векторная база данных, которую мы используем для эффективного хранения и извлечения ваших данных.
Llama 3: Новейшая итерация линейки больших языковых моделей от Meta.
Voyage AI - Предоставляет модели эмбеддингов, специализированные для конкретных доменов. Мы используем их специализированный юридический эмбеддинг, оптимизированный для юридического поиска и поиска в длинном контексте.
Подготовка
Зависимости и данные
Сначала установите необходимые зависимости:
! pip install --upgrade pymilvus ollama tqdm pypdf voyageai openai wget
Импорт API-ключей
Если ваш API-ключ задан в файле .env, вы можете загрузить его с помощью dotenv, чтобы избежать утечки ключа при отправке вашего notebook.
import os
from dotenv import load_dotenv
load_dotenv()
VOYAGE_API_KEY = os.getenv('VOYAGE_API_KEY')
Если у вас нет файла .env, просто пропустите импорт dotenv.
Подготовка данных
В этом руководстве мы будем использовать данные из Royal Courts of Justice в Лондоне. Загрузите их с помощью wget и сохраните локально:
! wget https://www.judiciary.uk/wp-content/uploads/2024/07/Final-Judgment-CA-2023-001978-BBC-v-BBC-Pension-Trust-another.pdf
Затем прочитайте PDF-файл и извлеките его содержимое для использования в нашем приложении RAG:
from pypdf import PdfReader
reader = PdfReader("Final-Judgment-CA-2023-001978-BBC-v-BBC-Pension-Trust-another.pdf")
pages = [page.extract_text() for page in reader.pages]
print(pages[0])
Это должно дать вам следующий вывод:
Neutral Citation Number [2024] EWCA Civ 767
Case No: CA-2023 -001978
IN THE COURT OF APPEAL ( CIVIL DIVISION)
ON APPEAL FROM THE HIGH COURT OF JUSTICE
BUSINESS AND PROPERTY COURTS OF ENGLAND AND WALES
BUSINESS LIST : PENSIONS (ChD)
The Hon Mr Justice Adam Johnson
[2023] EWHC 1965 (Ch)
Royal Courts of Justice
Strand, London, WC2A 2LL
Date: 09/07 /2024
Before :
LORD JUSTICE LEWISON
LADY JUSTICE FALK
and
SIR CHRISTOPHER FLOYD
Создание эмбеддингов для ваших документов
Мы будем использовать voyage-law-2, модель эмбеддингов, специализированную для юридического домена.
Сначала определите функцию для генерации текстовых эмбеддингов с использованием API Voyage AI:
import voyageai
voyage_client = voyageai.Client()
def embed_text(text: str) -> str:
return voyage_client.embed([text], model="voyage-law-2").embeddings[0]
Сгенерируйте тестовый эмбеддинг и выведите его размерность и первые несколько элементов.
result = voyage_client.embed(["hello world"], model="voyage-law-2")
embedding_dim = len(result.embeddings[0])
print(embedding_dim)
print(result.embeddings[0][:10])
1024
[0.000756315013859421, -0.02162403240799904, 0.0052010356448590755, -0.02917512319982052, -0.00796651840209961, -0.03238343447446823, 0.0660339742898941, 0.03845587745308876, -0.01913367211818695, 0.05562642216682434]
Загрузка данных в Milvus
Создание коллекции в Milvus
from pymilvus import MilvusClient
milvus_client = MilvusClient(uri="./milvus_legal.db")
collection_name = "my_rag_collection"
Задание URI в виде локального файла, например ./milvus_legal.db, удобно, поскольку при этом автоматически используется Milvus Lite для хранения всех данных в этом файле. Для крупномасштабных данных можно настроить более производительный сервер Milvus в Docker или Kubernetes.
Удалите коллекцию, если она уже существует, затем создайте новую:
if milvus_client.has_collection(collection_name):
milvus_client.drop_collection(collection_name)
milvus_client.create_collection(
collection_name=collection_name,
dimension=embedding_dim,
metric_type="IP", # Inner product distance
consistency_level="Strong", # Strong consistency level
)
Если мы не укажем информацию о полях, Milvus автоматически создаст поле id по умолчанию для первичного ключа и векторное поле для хранения векторных данных. Зарезервированное поле JSON используется для хранения полей, не определенных схемой, и их значений.
Вставка данных
Пройдитесь по страницам нашего документа, создайте эмбеддинги, а затем вставьте данные в Milvus.
Мы вводим новое поле под названием text, не определенное поле в схеме коллекции. Оно будет автоматически добавлено в зарезервированное динамическое поле JSON, которое на высоком уровне можно рассматривать как обычное поле.
from tqdm import tqdm
data = []
for i, page in enumerate(tqdm(pages, desc="Creating embeddings")):
data.append({"id": i, "vector": embed_text(page), "text": page})
milvus_client.insert(collection_name=collection_name, data=data)
Creating embeddings: 100%|███████████████████████████████████████████████████████████████████████████████████████| 20/20 [00:08<00:00, 2.45it/s]
{'insert_count': 20,
'ids': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
'cost': 0}
Построение базовой системы RAG
Далее давайте определим вопрос о содержании судебного слушания:
question = "who are the lawyers?"
Мы будем использовать Milvus для поиска по нашим проиндексированным данным. Позже мы интегрируем это с LLM.
search_res = milvus_client.search(
collection_name=collection_name,
data=[
embed_text(question)
], # Use the `embed_text` function to convert the question to an embedding vector
limit=3, # Return top 3 results
search_params={"metric_type": "IP", "params": {}}, # Inner product distance
output_fields=["text"], # Return the text field
)
Выведите найденные строки с их расстояниями:
import json
retrieved_lines_with_distances = [
(res["entity"]["text"], res["distance"]) for res in search_res[0]
]
print(json.dumps(retrieved_lines_with_distances, indent=4))
```
Текст, связанный с нашими эмбеддингами, довольно длинный, но вот пример того, что возвращает Milvus
[" n nНомер нейтральной цитаты [2024] EWCA Civ 767 n nДело №: CA-2023 -001978 nВ АПЕЛЛЯЦИОННОМ СУДЕ ( ГРАЖДАНСКОЕ ОТДЕЛЕНИЕ) nПО АПЕЛЛЯЦИИ ИЗ ВЫСОКОГО СУДА ПРАВОСУДИЯ nСУДЫ ПО ДЕЛАМ БИЗНЕСА И СОБСТВЕННОСТИ АНГЛИИ И УЭЛЬСА nСПИСОК ДЕЛ ПО КОММЕРЧЕСКИМ ВОПРОСАМ : ПЕНСИИ (ChD) nДостопочтенный судья Adam Johnson n[2023] EWHC 1965 (Ch) nКоролевские суды правосудия nStrand, London, WC2A 2LL n nДата: 09/07 /2024 nПеред : n nЛОРД-СУДЬЯ LEWISON nЛЕДИ-СУДЬЯ FALK nи nСЭР CHRISTOPHER FLOYD n n- - - - - - - - - - - - - - - - - - - - - n nМежду : n n BRITISH BROADCASTING CORPORATION Заявитель апелляции n - и - n (1) BBC P ENSION TRUST LIMITED n(2) CHRISTINA BURNS nОтветчик и n n- - - - - - - - - - - - - - - - - - - - - n n Michael Tennet KC и Edward Sawyer (по поручению Linklaters LLP ) nдля Заявителя апелляции n Brian Green KC и Joseph Steadman (по поручению Slaughter and May Solicitors ) nдля Первого ответчика nAndrew Spink KC и Saul Margo (по поручению Stephenson Harwood LLP ) nдля Второго ответчика n nДаты слушания: 25, 26 & 27/06/2024 n- - - - - - - - - - - - - - - - - - - - - n nУтвержденное судебное решение n nЭто судебное решение было вынесено дистанционно в 11.00 утра 09/07/2024 путем рассылки nсторонам или их представителям по e -mail и путем передачи в Nat ional Archives. n n............................. n",
0.1101425364613533
],
Использование LLM для получения ответа RAG
Объедините извлеченные документы в контекст и определите системные и пользовательские промпты для языковой модели:
context = "n".join(
[line_with_distance[0] for line_with_distance in retrieved_lines_with_distances]
)
SYSTEM_PROMPT = """
Human: You are an AI assistant. You are able to find answers to the questions from the contextual passage snippets provided.
"""
USER_PROMPT = f"""
Use the following pieces of information enclosed in <context> tags to provide an answer to the question enclosed in <question> tags.
<context>
{context}
</context>
<question>
{question}
</question>
"""
У Ollama есть полностью совместимый OpenAI API, что означает, что мы можем использовать OpenAI Python SDK для вызова Ollama:
from openai import OpenAI
client = OpenAI(
base_url = 'http://localhost:11434/v1',
api_key='ollama', # required, but unused
)
response = client.chat.completions.create(
model="llama3",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": USER_PROMPT},
],
)
print(response.choices[0].message.content)
Согласно тексту, юристы, участвующие в этом деле:
* Andrew Spink KC (по поручению Stephenson Harwood LLP) для Первого ответчика
* Saul Margo (также по поручению Stephenson Harwood LLP) для Первого ответчика
* Mr. Tennet (представляющий Второго ответчика)
* Mr. Spink KC (также представляющий Второго ответчика)
* Arden LJ (упомянута как вынесшая предыдущее судебное решение в Stena Line)
Обратите внимание, что «KC» означает King's Counsel — почетное звание, присваиваемое некоторым старшим барристерам в Англии и Уэльсе.
Заключение
Настройка RAG с Milvus и Ollama для юридических данных может сделать юридические исследования намного проще и эффективнее.
Не стесняйтесь ознакомиться с Milvus, кодом на Github и поделиться своим опытом с сообществом, присоединившись к нашему Discord.
Больше ресурсов по Milvus и Ollama:
Читать далее

Introducing Functions and Model Inference on Zilliz Cloud: Automatic Embedding and Reranking with Hosted Models
Zilliz Cloud Functions auto-generate embeddings via OpenAI, Voyage AI, Cohere, or Zilliz Hosted Models. Built-in reranking — just insert text and search.

My Wife Wanted Dior. I Spent $600 on Claude Code to Vibe-Code a 2M-Line Database Instead.
Write tests, not code reviews. How a test-first workflow with 6 parallel Claude Code sessions turns a 2M-line C++ codebase into a daily shipping pipeline.

Why I’m Against Claude Code’s Grep-Only Retrieval? It Just Burns Too Many Tokens
Learn how vector-based code retrieval cuts Claude Code token consumption by 40%. Open-source solution with easy MCP integration. Try claude-context today.



