---
title: Resumen de documentos legales
url: https://platform.claude.com/docs/es/about-claude/use-case-guides/legal-summarization
description: Esta guía explica cómo aprovechar las capacidades avanzadas de procesamiento de lenguaje natural de Claude para resumir documentos legales de manera eficiente, extrayendo información clave y agilizando la investigación jurídica. Con Claude, puedes optimizar la revisión de contratos, la preparación de litigios y el trabajo regulatorio, ahorrando tiempo y garantizando la precisión en tus procesos legales.
---

> Visita el [cookbook de resumen](https://platform.claude.com/cookbook/capabilities-summarization-guide) para ver un ejemplo de implementación de resumen de documentos legales usando Claude.

## Antes de construir con Claude

### Decide si usar Claude para el resumen de documentos legales

Estos son algunos indicadores clave de que deberías emplear un "large language model" (modelo de lenguaje grande), o LLM, como Claude para resumir documentos legales:

<AccordionGroup>
  <Accordion title="Quieres revisar un gran volumen de documentos de manera eficiente y económica">
    La revisión de documentos a gran escala puede consumir mucho tiempo y ser costosa cuando se realiza manualmente. Claude puede procesar y resumir grandes cantidades de documentos legales rápidamente, reduciendo significativamente el tiempo y el costo asociados con la revisión de documentos. Esta capacidad es particularmente valiosa para tareas como la debida diligencia, el análisis de contratos o el descubrimiento en litigios, donde la eficiencia es crucial.
  </Accordion>

  <Accordion title="Requieres la extracción automatizada de metadatos clave">
    Claude puede extraer y categorizar de manera eficiente metadatos importantes de documentos legales, como las partes involucradas, fechas, términos contractuales o cláusulas específicas. Esta extracción automatizada puede ayudar a organizar la información, facilitando la búsqueda, el análisis y la gestión de grandes conjuntos de documentos. Es especialmente útil para la gestión de contratos, verificaciones de cumplimiento o la creación de bases de datos de información legal con capacidad de búsqueda. 
  </Accordion>

  <Accordion title="Quieres generar resúmenes claros, concisos y estandarizados">
    Claude puede generar resúmenes estructurados que siguen formatos predeterminados, facilitando que los profesionales del derecho comprendan rápidamente los puntos clave de diversos documentos. Estos resúmenes estandarizados pueden mejorar la legibilidad, facilitar la comparación entre documentos y mejorar la comprensión general, especialmente cuando se trata de lenguaje jurídico complejo o jerga técnica.
  </Accordion>

  <Accordion title="Necesitas citas precisas para tus resúmenes">
    Al crear resúmenes legales, la atribución y las citas adecuadas son cruciales para garantizar la credibilidad y el cumplimiento de los estándares legales. Se le puede indicar a Claude que incluya citas precisas para todos los puntos legales referenciados, facilitando que los profesionales del derecho revisen y verifiquen la información resumida.
  </Accordion>

  <Accordion title="Quieres optimizar y agilizar tu proceso de investigación jurídica">
    Claude puede asistir en la investigación jurídica analizando rápidamente grandes volúmenes de jurisprudencia, leyes y comentarios legales. Puede identificar precedentes relevantes, extraer principios jurídicos clave y resumir argumentos legales complejos. Esta capacidad puede acelerar significativamente el proceso de investigación, permitiendo que los profesionales del derecho se concentren en el análisis de alto nivel y el desarrollo de estrategias.
  </Accordion>
</AccordionGroup>

### Determina los detalles que quieres que el resumen extraiga

No existe un único resumen correcto para un documento dado. Sin una dirección clara, puede ser difícil para Claude determinar qué detalles incluir. Para lograr resultados óptimos, identifica la información específica que quieres incluir en el resumen.

Por ejemplo, al resumir un contrato de subarrendamiento, podrías querer extraer los siguientes puntos clave:

<CodeGroup exclude="shell">
  ```python Python
  details_to_extract = [
      "Parties involved (sublessor, sublessee, and original lessor)",
      "Property details (address, description, and permitted use)",
      "Term and rent (start date, end date, monthly rent, and security deposit)",
      "Responsibilities (utilities, maintenance, and repairs)",
      "Consent and notices (landlord's consent, and notice requirements)",
      "Special provisions (furniture, parking, and subletting restrictions)",
  ]
  ```

  ```typescript TypeScript
  const detailsToExtract = [
    "Parties involved (sublessor, sublessee, and original lessor)",
    "Property details (address, description, and permitted use)",
    "Term and rent (start date, end date, monthly rent, and security deposit)",
    "Responsibilities (utilities, maintenance, and repairs)",
    "Consent and notices (landlord's consent, and notice requirements)",
    "Special provisions (furniture, parking, and subletting restrictions)"
  ];
  ```

  ```csharp C#
  List<string> detailsToExtract =
  [
      "Parties involved (sublessor, sublessee, and original lessor)",
      "Property details (address, description, and permitted use)",
      "Term and rent (start date, end date, monthly rent, and security deposit)",
      "Responsibilities (utilities, maintenance, and repairs)",
      "Consent and notices (landlord's consent, and notice requirements)",
      "Special provisions (furniture, parking, and subletting restrictions)",
  ];
  ```

  ```go Go
  var detailsToExtract = []string{
  	"Parties involved (sublessor, sublessee, and original lessor)",
  	"Property details (address, description, and permitted use)",
  	"Term and rent (start date, end date, monthly rent, and security deposit)",
  	"Responsibilities (utilities, maintenance, and repairs)",
  	"Consent and notices (landlord's consent, and notice requirements)",
  	"Special provisions (furniture, parking, and subletting restrictions)",
  }
  ```

  ```java Java
  List<String> detailsToExtract = List.of(
          "Parties involved (sublessor, sublessee, and original lessor)",
          "Property details (address, description, and permitted use)",
          "Term and rent (start date, end date, monthly rent, and security deposit)",
          "Responsibilities (utilities, maintenance, and repairs)",
          "Consent and notices (landlord's consent, and notice requirements)",
          "Special provisions (furniture, parking, and subletting restrictions)");
  ```

  ```php PHP
  $detailsToExtract = [
      'Parties involved (sublessor, sublessee, and original lessor)',
      'Property details (address, description, and permitted use)',
      'Term and rent (start date, end date, monthly rent, and security deposit)',
      'Responsibilities (utilities, maintenance, and repairs)',
      "Consent and notices (landlord's consent, and notice requirements)",
      'Special provisions (furniture, parking, and subletting restrictions)',
  ];
  ```

  ```ruby Ruby
  details_to_extract = [
    "Parties involved (sublessor, sublessee, and original lessor)",
    "Property details (address, description, and permitted use)",
    "Term and rent (start date, end date, monthly rent, and security deposit)",
    "Responsibilities (utilities, maintenance, and repairs)",
    "Consent and notices (landlord's consent, and notice requirements)",
    "Special provisions (furniture, parking, and subletting restrictions)"
  ]
  ```
</CodeGroup>

### Establece criterios de éxito

Evaluar la calidad de los resúmenes es una tarea notoriamente difícil. A diferencia de muchas otras tareas de procesamiento de lenguaje natural, la evaluación de resúmenes a menudo carece de métricas objetivas y claras. El proceso puede ser altamente subjetivo, ya que distintos lectores valoran distintos aspectos de un resumen. Estos son algunos criterios que podrías considerar al evaluar qué tan bien Claude realiza el resumen de documentos legales.

<AccordionGroup>
  <Accordion title="Exactitud factual">
    El resumen debe representar con precisión los hechos, conceptos jurídicos y puntos clave del documento.
  </Accordion>

  <Accordion title="Precisión jurídica">
    La terminología y las referencias a leyes, jurisprudencia o regulaciones deben ser correctas y estar alineadas con los estándares legales.
  </Accordion>

  <Accordion title="Concisión">
     El resumen debe condensar el documento legal a sus puntos esenciales sin perder detalles importantes.
  </Accordion>

  <Accordion title="Consistencia">
    Si se resumen varios documentos, el LLM debe mantener una estructura y un enfoque consistentes en cada resumen.
  </Accordion>

  <Accordion title="Legibilidad">
    El texto debe ser claro y fácil de entender. Si la audiencia no está compuesta por expertos legales, el resumen no debe incluir jerga jurídica que pueda confundir a la audiencia.
  </Accordion>

  <Accordion title="Sesgo e imparcialidad">
    El resumen debe presentar una descripción imparcial y justa de los argumentos y posiciones legales.
  </Accordion>
</AccordionGroup>

Consulta la guía sobre [cómo establecer criterios de éxito](https://platform.claude.com/docs/es/test-and-evaluate/develop-tests) para obtener más información.

***

## Cómo resumir documentos legales usando Claude

### Selecciona el modelo de Claude adecuado

La precisión del modelo es extremadamente importante al resumir documentos legales. Claude Opus 5.5 es una excelente opción para casos de uso como este, donde se requiere alta precisión. Si el tamaño y la cantidad de tus documentos son tan grandes que los costos empiezan a ser una preocupación, también puedes intentar usar un modelo más pequeño como Claude Haiku 5.5.

Para ayudar a estimar estos costos, a continuación se presenta una comparación del costo de resumir 1,000 contratos de subarrendamiento usando los modelos Opus y Haiku:

* **Tamaño del contenido**

  * Número de contratos: 1,000
  * Caracteres por contrato: 300,000
  * Total de caracteres: 300M

* **Tokens estimados**

  * Tokens de entrada: 108M, aproximadamente 108,000 por contrato (aproximadamente 1 token por cada 2.8 caracteres, la proporción que ambos modelos mostraron con el contrato de ejemplo de esta guía)
  * Tokens de salida por resumen, incluidos los tokens de pensamiento, que se facturan como salida: aproximadamente 6,200 en Claude Opus 5.5 y 3,100 en Claude Haiku 5.5
  * Total de tokens de salida: 6.2M en Claude Opus 5.5 y 3.1M en Claude Haiku 5.5

* **Costo estimado de Claude Opus 5.5**

  * Costo de tokens de entrada: 108 MTok \* $4.00/MTok = $432.00 USD
  * Costo de tokens de salida: 6.2 MTok \* $20.00/MTok = $124.00 USD
  * Costo total: $432.00 + $124.00 = $556.00 USD

* **Costo estimado de Claude Haiku 5.5**, con sus precios para prompts de más de 100,000 tokens

  * Costo de tokens de entrada: 108 MTok \* $0.50/MTok = $54.00 USD
  * Costo de tokens de salida: 3.1 MTok \* $2.50/MTok = $7.75 USD
  * Costo total: $54.00 + $7.75 = $61.75 USD

<Tip>
  Los costos reales pueden diferir de estas estimaciones. Los recuentos de tokens provienen de ejecutar el ejemplo de la sección 

  [Construye un prompt sólido](https://platform.claude.com/docs/es/about-claude/use-case-guides/legal-summarization#build-a-strong-prompt)

   con el contrato de ejemplo de esta guía, de aproximadamente 105,000 tokens de entrada, y la longitud de la salida varía según el documento y de una ejecución a otra. Cada contrato aquí es un prompt de aproximadamente 108,000 tokens, por encima del umbral de 100,000 tokens de los 

  [precios para prompts largos](https://platform.claude.com/docs/es/about-claude/pricing#long-context-pricing)

   de Claude Haiku 5.5. Un documento cuyo prompt se mantiene en 100,000 tokens o menos paga en su lugar $0.10/MTok de entrada y $0.50/MTok de salida. Para ver qué precios aplican, cuenta los tokens de tus documentos con el 

  [conteo de tokens](https://platform.claude.com/docs/es/build-with-claude/token-counting)

   y 

  `model`

   establecido en 

  `claude-haiku-5-5`

  .
</Tip>

### Transforma los documentos a un formato que Claude pueda procesar

Antes de comenzar a resumir documentos, necesitas preparar tus datos. Esto implica extraer el texto de los PDF, limpiar el texto y asegurarte de que esté listo para ser procesado por Claude.

Aquí tienes una demostración de este proceso con un PDF de ejemplo:

<CodeGroup exclude="shell">
  <CodeGroupItem language="cURL">
    Extrae el texto del PDF en código.
  </CodeGroupItem>

  <CodeGroupItem language="CLI">
    Extrae el texto del PDF en código.
  </CodeGroupItem>

  ```python Python
  from io import BytesIO
  import re

  import pypdf
  import requests


  def get_llm_text(pdf_file):
      reader = pypdf.PdfReader(pdf_file)
      text = "\n".join([page.extract_text() for page in reader.pages])

      # Elimina los números de página
      text = re.sub(r"\n\s*\d+\s*\n", "\n", text)

      # Elimina los espacios en blanco sobrantes
      text = re.sub(r"\s+", " ", text)

      return text


  # Crea la URL completa a partir del repositorio de GitHub
  url = "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/capabilities/summarization/data/Sample Sublease Agreement.pdf"
  url = url.replace(" ", "%20")

  # Descarga el archivo PDF en memoria
  response = requests.get(url)

  # Carga el PDF desde la memoria
  pdf_file = BytesIO(response.content)

  document_text = get_llm_text(pdf_file)
  print(document_text[:50000])
  ```

  ```typescript TypeScript
  import { PDFParse } from "pdf-parse";

  async function getLlmText(pdfData: Uint8Array): Promise<string> {
    const parser = new PDFParse({ data: pdfData });
    const result = await parser.getText();
    await parser.destroy();
    let text = result.pages.map((page) => page.text).join("\n");

    // Elimina los números de página
    text = text.replace(/\n\s*\d+\s*\n/g, "\n");

    // Elimina los espacios en blanco sobrantes
    text = text.replace(/\s+/g, " ");

    return text;
  }

  // Descarga el contrato de subarrendamiento de ejemplo del cookbook de resúmenes
  const response = await fetch(
    "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/capabilities/summarization/data/Sample%20Sublease%20Agreement.pdf"
  );
  const pdfData = new Uint8Array(await response.arrayBuffer());

  const documentText = await getLlmText(pdfData);
  console.log(documentText.slice(0, 50000));
  ```

  ```csharp C#
  using System.Text.RegularExpressions;
  using UglyToad.PdfPig;
  using UglyToad.PdfPig.DocumentLayoutAnalysis.TextExtractor;

  string GetLlmText(byte[] pdfData)
  {
      using var document = PdfDocument.Open(pdfData);
      var text = string.Join("\n", document.GetPages().Select(page => ContentOrderTextExtractor.GetText(page)));

      // Elimina los números de página
      text = Regex.Replace(text, @"\n\s*\d+\s*\n", "\n");

      // Elimina los espacios en blanco sobrantes
      text = Regex.Replace(text, @"\s+", " ");

      return text;
  }

  // Descarga el contrato de subarrendamiento de ejemplo del cookbook de resúmenes
  using var httpClient = new HttpClient();
  var pdfData = await httpClient.GetByteArrayAsync(
      "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/capabilities/summarization/data/Sample%20Sublease%20Agreement.pdf"
  );

  var documentText = GetLlmText(pdfData);
  Console.WriteLine(documentText[..Math.Min(50000, documentText.Length)]);
  ```

  ```go Go
  import (
  	"bytes"
  	"io"
  	"net/http"
  	"regexp"

  	"github.com/ledongthuc/pdf"
  )

  // El texto del contrato de subarrendamiento de ejemplo
  var documentText string

  func getLLMText(pdfData []byte) (string, error) {
  	reader, err := pdf.NewReader(bytes.NewReader(pdfData), int64(len(pdfData)))
  	if err != nil {
  		return "", err
  	}

  	var pages []string
  	for pageIndex := 1; pageIndex <= reader.NumPage(); pageIndex++ {
  		pageText, err := reader.Page(pageIndex).GetPlainText(nil)
  		if err != nil {
  			return "", err
  		}
  		pages = append(pages, pageText)
  	}
  	text := strings.Join(pages, "\n")

  	// Eliminar los números de página
  	text = regexp.MustCompile(`\n\s*\d+\s*\n`).ReplaceAllString(text, "\n")

  	// Eliminar los espacios en blanco sobrantes
  	text = regexp.MustCompile(`\s+`).ReplaceAllString(text, " ")

  	return text, nil
  }

  // extractDocumentText descarga el contrato de subarrendamiento de ejemplo y extrae su texto.
  func extractDocumentText() {
  	// Descargar el contrato de subarrendamiento de ejemplo del cookbook de resumen
  	response, err := http.Get("https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/capabilities/summarization/data/Sample%20Sublease%20Agreement.pdf")
  	if err != nil {
  		log.Fatal(err)
  	}
  	defer response.Body.Close()

  	pdfData, err := io.ReadAll(response.Body)
  	if err != nil {
  		log.Fatal(err)
  	}

  	documentText, err = getLLMText(pdfData)
  	if err != nil {
  		log.Fatal(err)
  	}
  	fmt.Println(documentText[:min(50000, len(documentText))])
  }
  ```

  ```java Java
  import java.io.IOException;
  import java.net.URI;
  import java.net.http.HttpClient;
  import java.net.http.HttpRequest;
  import java.net.http.HttpResponse;
  import org.apache.pdfbox.Loader;
  import org.apache.pdfbox.pdmodel.PDDocument;
  import org.apache.pdfbox.text.PDFTextStripper;

  // El texto del contrato de subarrendamiento de ejemplo
  String documentText;

  String getLlmText(byte[] pdfData) throws IOException {
      try (PDDocument document = Loader.loadPDF(pdfData)) {
          String text = new PDFTextStripper().getText(document);

          // Elimina los números de página
          text = text.replaceAll("\\n\\s*\\d+\\s*\\n", "\n");

          // Elimina los espacios en blanco sobrantes
          return text.replaceAll("\\s+", " ");
      }
  }

  void extractDocumentText() throws IOException, InterruptedException {
      // Descarga el contrato de subarrendamiento de ejemplo del cookbook de resúmenes
      HttpRequest request = HttpRequest.newBuilder(URI.create(
                      "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/capabilities/summarization/data/Sample%20Sublease%20Agreement.pdf"))
              .build();
      byte[] pdfData;
      try (HttpClient httpClient = HttpClient.newHttpClient()) {
          pdfData = httpClient.send(request, HttpResponse.BodyHandlers.ofByteArray()).body();
      }

      documentText = getLlmText(pdfData);
      IO.println(documentText.substring(0, Math.min(50000, documentText.length())));
  }
  ```

  ```php PHP
  use Smalot\PdfParser\Parser;

  $getLlmText = function (string $pdfData): string {
      $document = (new Parser())->parseContent($pdfData);
      $text = implode("\n", array_map(fn ($page) => $page->getText(), $document->getPages()));

      // Elimina los números de página
      $text = preg_replace('/\n\s*\d+\s*\n/', "\n", $text);

      // Elimina los espacios en blanco sobrantes
      return preg_replace('/\s+/', ' ', $text);
  };

  // Descarga el contrato de subarrendamiento de ejemplo del cookbook de resúmenes
  $pdfData = file_get_contents(
      'https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/capabilities/summarization/data/Sample%20Sublease%20Agreement.pdf'
  );

  $documentText = $getLlmText($pdfData);
  echo substr($documentText, 0, 50000) . "\n";
  ```

  ```ruby Ruby
  require "net/http"
  require "pdf-reader"
  require "stringio"

  def get_llm_text(pdf_data)
    reader = PDF::Reader.new(StringIO.new(pdf_data))
    text = reader.pages.map(&:text).join("\n")

    # Elimina los números de página
    text = text.gsub(/\n\s*\d+\s*\n/, "\n")

    # Elimina los espacios en blanco sobrantes
    text.gsub(/\s+/, " ")
  end

  # Descarga el contrato de subarrendamiento de ejemplo del cookbook de resúmenes
  pdf_data = Net::HTTP.get(
    URI("https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/capabilities/summarization/data/Sample%20Sublease%20Agreement.pdf")
  )

  document_text = get_llm_text(pdf_data)
  puts document_text[0, 50_000]
  ```
</CodeGroup>

En este ejemplo, primero descargas un PDF de un contrato de subarrendamiento de ejemplo utilizado en el [cookbook de resumen](https://platform.claude.com/cookbook/capabilities-summarization-guide). Este contrato se obtuvo de un contrato de subarrendamiento disponible públicamente en el [sitio web sec.gov](https://www.sec.gov/Archives/edgar/data/1045425/000119312507044370/dex1032.htm).

El ejemplo usa la biblioteca `pypdf` (typescript: `pdf-parse`; csharp: `PdfPig`; go: `github.com/ledongthuc/pdf`; java: `org.apache.pdfbox:pdfbox`; php: `smalot/pdfparser`; ruby: `pdf-reader`) para extraer el contenido del PDF y convertirlo a texto. Luego, los datos de texto se limpian eliminando los números de página y los espacios en blanco adicionales.

### Construye un prompt sólido

Claude puede adaptarse a diversos estilos de resumen. Puedes cambiar los detalles del prompt para guiar a Claude a ser más o menos detallado, incluir más o menos terminología técnica, o proporcionar un resumen de mayor o menor nivel del contexto en cuestión.

Aquí tienes un ejemplo de cómo crear un prompt que garantice que los resúmenes generados sigan una estructura consistente al analizar contratos de subarrendamiento:

<CodeGroup exclude="shell">
  <CodeGroupItem language="cURL">
    Este flujo de trabajo necesita más lógica que un solo comando de shell. Usa el SDK de Claude para ejecutarlo.
  </CodeGroupItem>

  <CodeGroupItem language="CLI">
    Este flujo de trabajo necesita más lógica que un solo comando de shell. Usa el SDK de Claude para ejecutarlo.
  </CodeGroupItem>

  ```python Python
  # Inicializa el cliente de Anthropic
  client = anthropic.Anthropic()


  def summarize_document(
      text, details_to_extract, model="claude-opus-5-5", max_tokens=16000
  ):
      # Formatea los detalles a extraer para colocarlos en el contexto del prompt
      details_to_extract_str = "\n".join(details_to_extract)

      # Pide al modelo que resuma el contrato de subarrendamiento
      prompt = f"""Summarize the following sublease agreement. Focus on these key aspects:

      {details_to_extract_str}

      Provide the summary in bullet points nested within the XML header for each section. For example:

      <parties involved>
      - Sublessor: [Name]
      // Add more details as needed
      </parties involved>

      If any information is not explicitly stated in the document, note it as "Not specified". Do not preamble.

      Sublease agreement text:
      {text}
      """

      response = client.messages.create(
          model=model,
          max_tokens=max_tokens,
          system="You are a legal analyst specializing in real estate law, known for highly accurate and detailed summaries of sublease agreements.",
          messages=[
              {"role": "user", "content": prompt},
          ],
      )

      return next(block.text for block in response.content if block.type == "text")


  sublease_summary = summarize_document(document_text, details_to_extract)
  print(sublease_summary)
  ```

  ```typescript TypeScript
  // Inicializa el cliente de Anthropic
  const client = new Anthropic();

  async function summarizeDocument(
    text: string,
    detailsToExtract: string[],
    model: Anthropic.Model = "claude-opus-5-5",
    maxTokens = 16000
  ): Promise<string> {
    // Formatea los detalles a extraer para colocarlos en el contexto del prompt
    const detailsToExtractStr = detailsToExtract.join("\n");

    // Pide al modelo que resuma el contrato de subarrendamiento
    const prompt = `Summarize the following sublease agreement. Focus on these key aspects:

      ${detailsToExtractStr}

      Provide the summary in bullet points nested within the XML header for each section. For example:

      <parties involved>
      - Sublessor: [Name]
      // Add more details as needed
      </parties involved>

      If any information is not explicitly stated in the document, note it as "Not specified". Do not preamble.

      Sublease agreement text:
      ${text}
      `;

    const response = await client.messages.create({
      model,
      max_tokens: maxTokens,
      system:
        "You are a legal analyst specializing in real estate law, known for highly accurate and detailed summaries of sublease agreements.",
      messages: [{ role: "user", content: prompt }]
    });

    const textBlock = response.content.find((block) => block.type === "text");
    if (!textBlock) {
      throw new Error("Expected a text block in the response");
    }
    return textBlock.text;
  }

  const subleaseSummary = await summarizeDocument(documentText, detailsToExtract);
  console.log(subleaseSummary);
  ```

  ```csharp C#
  // Inicializa el cliente de Anthropic
  var client = new AnthropicClient();

  async Task<string> SummarizeDocument(
      string text,
      IReadOnlyList<string> detailsToExtract,
      Model model = Model.ClaudeOpus5_5,
      long maxTokens = 16000
  )
  {
      // Formatea los detalles a extraer para colocarlos en el contexto del prompt
      var detailsToExtractStr = string.Join("\n", detailsToExtract);

      // Pide al modelo que resuma el contrato de subarrendamiento
      var prompt = $"""
          Summarize the following sublease agreement. Focus on these key aspects:

              {detailsToExtractStr}

              Provide the summary in bullet points nested within the XML header for each section. For example:

              <parties involved>
              - Sublessor: [Name]
              // Add more details as needed
              </parties involved>

              If any information is not explicitly stated in the document, note it as "Not specified". Do not preamble.

              Sublease agreement text:
              {text}
          """;

      var response = await client.Messages.Create(
          new()
          {
              Model = model,
              MaxTokens = maxTokens,
              System = "You are a legal analyst specializing in real estate law, known for highly accurate and detailed summaries of sublease agreements.",
              Messages = [new() { Role = Role.User, Content = prompt }],
          }
      );

      foreach (var block in response.Content)
      {
          if (block.TryPickText(out var textBlock))
          {
              return textBlock.Text;
          }
      }
      throw new InvalidOperationException("Expected a text block in the response.");
  }

  var subleaseSummary = await SummarizeDocument(documentText, detailsToExtract);
  Console.WriteLine(subleaseSummary);
  ```

  ```go Go
  // Inicializar el cliente de Anthropic
  var client = anthropic.NewClient()

  func summarizeDocument(text string, detailsToExtract []string, model anthropic.Model, maxTokens int64) string {
  	// Formatear los detalles a extraer para colocarlos en el contexto del prompt
  	detailsToExtractStr := strings.Join(detailsToExtract, "\n")

  	// Pedir al modelo que resuma el contrato de subarrendamiento
  	prompt := fmt.Sprintf(`Summarize the following sublease agreement. Focus on these key aspects:

      %s

      Provide the summary in bullet points nested within the XML header for each section. For example:

      <parties involved>
      - Sublessor: [Name]
      // Add more details as needed
      </parties involved>

      If any information is not explicitly stated in the document, note it as "Not specified". Do not preamble.

      Sublease agreement text:
      %s
      `, detailsToExtractStr, text)

  	response, err := client.Messages.New(context.Background(), anthropic.MessageNewParams{
  		Model:     model,
  		MaxTokens: maxTokens,
  		System: []anthropic.TextBlockParam{
  			{Text: "You are a legal analyst specializing in real estate law, known for highly accurate and detailed summaries of sublease agreements."},
  		},
  		Messages: []anthropic.MessageParam{
  			anthropic.NewUserMessage(anthropic.NewTextBlock(prompt)),
  		},
  	})
  	if err != nil {
  		log.Fatal(err)
  	}

  	for _, block := range response.Content {
  		if textBlock, ok := block.AsAny().(anthropic.TextBlock); ok {
  			return textBlock.Text
  		}
  	}
  	panic("expected a text block in the response")
  }

  // printSubleaseSummary resume el contrato de subarrendamiento e imprime el resumen.
  func printSubleaseSummary() {
  	subleaseSummary := summarizeDocument(documentText, detailsToExtract, anthropic.ModelClaudeOpus5_5, 16000)
  	fmt.Println(subleaseSummary)
  }
  ```

  ```java Java
  // Inicializa el cliente de Anthropic
  AnthropicClient client = AnthropicOkHttpClient.fromEnv();

  String summarizeDocument(String text, List<String> detailsToExtract, Model model, long maxTokens) {
      // Formatea los detalles a extraer para colocarlos en el contexto del prompt
      String detailsToExtractStr = String.join("\n", detailsToExtract);

      // Pide al modelo que resuma el contrato de subarrendamiento
      String prompt = """
              Summarize the following sublease agreement. Focus on these key aspects:

                  %s

                  Provide the summary in bullet points nested within the XML header for each section. For example:

                  <parties involved>
                  - Sublessor: [Name]
                  // Add more details as needed
                  </parties involved>

                  If any information is not explicitly stated in the document, note it as "Not specified". Do not preamble.

                  Sublease agreement text:
                  %s
              """
              .formatted(detailsToExtractStr, text);

      Message response = client.messages().create(MessageCreateParams.builder()
              .model(model)
              .maxTokens(maxTokens)
              .system("You are a legal analyst specializing in real estate law, known for highly accurate and detailed summaries of sublease agreements.")
              .addUserMessage(prompt)
              .build());

      return response.content().stream()
              .flatMap(block -> block.text().stream())
              .findFirst()
              .orElseThrow()
              .text();
  }

  void printSubleaseSummary() {
      String subleaseSummary = summarizeDocument(
              documentText, detailsToExtract, Model.CLAUDE_OPUS_5_5, 16000);
      IO.println(subleaseSummary);
  }
  ```

  ```php PHP
  // Inicializa el cliente de Anthropic
  $client = new Client();

  $summarizeDocument = function (
      string $text,
      array $detailsToExtract,
      Model $model = Model::CLAUDE_OPUS_5_5,
      int $maxTokens = 16000,
  ) use ($client): string {
      // Formatea los detalles a extraer para colocarlos en el contexto del prompt
      $detailsToExtractStr = implode("\n", $detailsToExtract);

      // Pide al modelo que resuma el contrato de subarrendamiento
      $prompt = <<<PROMPT
          Summarize the following sublease agreement. Focus on these key aspects:

              {$detailsToExtractStr}

              Provide the summary in bullet points nested within the XML header for each section. For example:

              <parties involved>
              - Sublessor: [Name]
              // Add more details as needed
              </parties involved>

              If any information is not explicitly stated in the document, note it as "Not specified". Do not preamble.

              Sublease agreement text:
              {$text}
          PROMPT;

      $response = $client->messages->create(
          model: $model,
          maxTokens: $maxTokens,
          system: 'You are a legal analyst specializing in real estate law, known for highly accurate and detailed summaries of sublease agreements.',
          messages: [['role' => 'user', 'content' => $prompt]],
      );

      $textBlock = array_find($response->content, fn ($block) => $block instanceof \Anthropic\Messages\TextBlock)
          ?? throw new \RuntimeException('Expected a text block in the response.');

      return $textBlock->text;
  };

  $subleaseSummary = $summarizeDocument($documentText, $detailsToExtract);
  echo $subleaseSummary . "\n";
  ```

  ```ruby Ruby
  # Inicializa el cliente de Anthropic
  CLIENT = Anthropic::Client.new

  def summarize_document(text, details_to_extract, model: Anthropic::Model::CLAUDE_OPUS_5_5, max_tokens: 16_000)
    # Formatea los detalles a extraer para colocarlos en el contexto del prompt
    details_to_extract_str = details_to_extract.join("\n")

    # Pide al modelo que resuma el contrato de subarrendamiento
    prompt = <<~PROMPT
      Summarize the following sublease agreement. Focus on these key aspects:

          #{details_to_extract_str}

          Provide the summary in bullet points nested within the XML header for each section. For example:

          <parties involved>
          - Sublessor: [Name]
          // Add more details as needed
          </parties involved>

          If any information is not explicitly stated in the document, note it as "Not specified". Do not preamble.

          Sublease agreement text:
          #{text}
    PROMPT

    response = CLIENT.messages.create(
      model:,
      max_tokens:,
      system_: "You are a legal analyst specializing in real estate law, known for highly accurate and detailed summaries of sublease agreements.",
      messages: [{role: :user, content: prompt}]
    )

    response.content.find { |block| block.is_a?(Anthropic::Models::TextBlock) }.text
  end

  sublease_summary = summarize_document(document_text, details_to_extract)
  puts sublease_summary
  ```
</CodeGroup>

Este código implementa una función `summarize_document` (typescript, go, java: `summarizeDocument`; php: `$summarizeDocument`; csharp: `SummarizeDocument`) que usa Claude para resumir el contenido de un contrato de subarrendamiento. La función acepta como entradas una cadena de texto y una lista de detalles a extraer. En este ejemplo, el código llama a la función con las variables `document_text` (typescript, go, java, csharp: `documentText`; php: `$documentText`) y `details_to_extract` (typescript, go, java, csharp: `detailsToExtract`; php: `$detailsToExtract`) que se definieron en los fragmentos de código anteriores.

Dentro de la función, se genera un prompt para Claude que incluye el documento a resumir, los detalles a extraer e instrucciones específicas para resumir el documento. El prompt le indica a Claude que responda con un resumen de cada detalle a extraer anidado dentro de encabezados XML.

Dado que el código genera cada sección del resumen dentro de etiquetas, cada sección puede analizarse fácilmente como un paso de posprocesamiento. Este enfoque permite resúmenes estructurados que pueden adaptarse a tu caso de uso, de modo que cada resumen siga el mismo patrón.

### Evalúa tu prompt

El prompting a menudo requiere pruebas y optimización para estar listo para producción. Para determinar si tu solución está lista, evalúa la calidad de tus resúmenes mediante un proceso sistemático que combine métodos cuantitativos y cualitativos. Crear una [evaluación empírica sólida](https://platform.claude.com/docs/es/test-and-evaluate/develop-tests#build-evaluations) basada en tus criterios de éxito definidos te permite optimizar tus prompts. Estas son algunas métricas que podrías incluir en tu evaluación empírica:

<AccordionGroup>
  <Accordion title="Puntuaciones ROUGE">
    Esto mide la superposición entre el resumen generado y un resumen de referencia creado por expertos. Esta métrica se centra principalmente en la exhaustividad (recall) y es útil para evaluar la cobertura del contenido.
  </Accordion>

  <Accordion title="Puntuaciones BLEU">
    Aunque se desarrolló originalmente para la traducción automática, esta métrica puede adaptarse a tareas de resumen. Las puntuaciones BLEU miden la precisión de las coincidencias de n-gramas entre el resumen generado y los resúmenes de referencia. Una puntuación más alta indica que el resumen generado contiene frases y terminología similares a las del resumen de referencia. 
  </Accordion>

  <Accordion title="Similitud de embeddings contextuales">
    Esta métrica implica crear representaciones vectoriales (embeddings) tanto del resumen generado como del de referencia. Luego se calcula la similitud entre estos embeddings, a menudo usando la similitud del coseno. Puntuaciones de similitud más altas indican que el resumen generado captura el significado semántico y el contexto del resumen de referencia, incluso si la redacción exacta difiere.
  </Accordion>

  <Accordion title="Calificación basada en LLM">
    Este método implica usar un LLM como Claude para evaluar la calidad de los resúmenes generados según una rúbrica de puntuación. La rúbrica puede adaptarse a tus necesidades específicas, evaluando factores clave como la precisión, la completitud y la coherencia. Para obtener orientación sobre la implementación, consulta 

    [Consejos para la calificación basada en LLM](https://platform.claude.com/docs/es/test-and-evaluate/develop-tests#tips-for-llm-based-grading)

    .
  </Accordion>

  <Accordion title="Evaluación humana">
    Además de crear los resúmenes de referencia, los expertos legales también pueden evaluar la calidad de los resúmenes generados. Aunque esto es costoso y consume mucho tiempo a gran escala, a menudo se realiza con unos pocos resúmenes como verificación de validación antes de desplegar a producción.
  </Accordion>
</AccordionGroup>

### Despliega tu prompt

Estas son algunas consideraciones adicionales que debes tener en cuenta al desplegar tu solución a producción.

1. **Asegúrate de no incurrir en responsabilidad legal:** Comprende las implicaciones legales de los errores en los resúmenes, que podrían generar responsabilidad legal para tu organización o tus clientes. Proporciona avisos o notas legales que aclaren que los resúmenes son generados por IA y deben ser revisados por profesionales del derecho.

2. **Maneja diversos tipos de documentos:** Esta guía explica cómo extraer texto de archivos PDF. En el mundo real, los documentos pueden venir en una variedad de formatos (como PDF, documentos de Word y archivos de texto). Asegúrate de que tu pipeline de extracción de datos pueda convertir todos los formatos de archivo que esperas recibir.

3. **Paraleliza las llamadas a la API de Claude:** Los documentos largos con una gran cantidad de tokens pueden requerir hasta un minuto para que Claude genere un resumen. Para grandes colecciones de documentos, podrías querer enviar llamadas a la API de Claude en paralelo para que los resúmenes se completen en un plazo razonable. Consulta los [límites de velocidad](https://platform.claude.com/docs/es/api/rate-limits#rate-limits) de Anthropic para determinar la cantidad máxima de llamadas a la API que se pueden realizar en paralelo.

***

## Mejora el rendimiento

En escenarios complejos, puede ser útil considerar estrategias adicionales para mejorar el rendimiento más allá de las [técnicas de ingeniería de prompts](https://platform.claude.com/docs/es/build-with-claude/prompt-engineering/overview) estándar. Estas son algunas estrategias avanzadas:

### Realiza meta-resúmenes para resumir documentos largos

El resumen de documentos legales a menudo implica manejar documentos largos o muchos documentos relacionados a la vez, de modo que se supera la "context window" (ventana de contexto) de Claude. Puedes usar un método de fragmentación conocido como meta-resumen para manejar este caso de uso. Esta técnica implica dividir los documentos en fragmentos más pequeños y manejables, y luego procesar cada fragmento por separado. Después puedes combinar los resúmenes de cada fragmento para crear un meta-resumen de todo el documento.

Aquí tienes un ejemplo de cómo realizar un meta-resumen:

<CodeGroup exclude="shell">
  <CodeGroupItem language="cURL">
    Este flujo de trabajo necesita más lógica que un solo comando de shell. Usa el SDK de Claude para ejecutarlo.
  </CodeGroupItem>

  <CodeGroupItem language="CLI">
    Este flujo de trabajo necesita más lógica que un solo comando de shell. Usa el SDK de Claude para ejecutarlo.
  </CodeGroupItem>

  ```python Python
  def chunk_text(text, chunk_size=20000):
      return [text[i : i + chunk_size] for i in range(0, len(text), chunk_size)]


  def summarize_long_document(
      text, details_to_extract, model="claude-opus-5-5", max_tokens=16000
  ):
      # Formatea los detalles a extraer para colocarlos en el contexto del prompt
      details_to_extract_str = "\n".join(details_to_extract)

      # Itera sobre los fragmentos y resume cada uno
      chunk_summaries = [
          summarize_document(
              chunk, details_to_extract, model=model, max_tokens=max_tokens
          )
          for chunk in chunk_text(text)
      ]

      final_summary_prompt = f"""

      You are looking at the chunked summaries of multiple documents that are all related.
      Combine the following summaries of the document from different truthful sources into a coherent overall summary:

      <chunked_summaries>
      {"".join(chunk_summaries)}
      </chunked_summaries>

      Focus on these key aspects:
      {details_to_extract_str}

      Provide the summary in bullet points nested within the XML header for each section. For example:

      <parties involved>
      - Sublessor: [Name]
      // Add more details as needed
      </parties involved>

      If any information is not explicitly stated in the document, note it as "Not specified". Do not preamble.
      """

      response = client.messages.create(
          model=model,
          max_tokens=max_tokens,
          system="You are a legal expert that summarizes notes on one document.",
          messages=[
              {"role": "user", "content": final_summary_prompt},
          ],
      )

      return next(block.text for block in response.content if block.type == "text")


  long_summary = summarize_long_document(document_text, details_to_extract)
  print(long_summary)
  ```

  ```typescript TypeScript
  function chunkText(text: string, chunkSize = 20000): string[] {
    return Array.from({ length: Math.ceil(text.length / chunkSize) }, (_, index) =>
      text.slice(index * chunkSize, (index + 1) * chunkSize)
    );
  }

  async function summarizeLongDocument(
    text: string,
    detailsToExtract: string[],
    model: Anthropic.Model = "claude-opus-5-5",
    maxTokens = 16000
  ): Promise<string> {
    // Formatea los detalles a extraer para colocarlos en el contexto del prompt
    const detailsToExtractStr = detailsToExtract.join("\n");

    // Itera sobre los fragmentos y resume cada uno
    const chunkSummaries: string[] = [];
    for (const chunk of chunkText(text)) {
      chunkSummaries.push(await summarizeDocument(chunk, detailsToExtract, model, maxTokens));
    }

    const finalSummaryPrompt = `

      You are looking at the chunked summaries of multiple documents that are all related.
      Combine the following summaries of the document from different truthful sources into a coherent overall summary:

      <chunked_summaries>
      ${chunkSummaries.join("")}
      </chunked_summaries>

      Focus on these key aspects:
      ${detailsToExtractStr}

      Provide the summary in bullet points nested within the XML header for each section. For example:

      <parties involved>
      - Sublessor: [Name]
      // Add more details as needed
      </parties involved>

      If any information is not explicitly stated in the document, note it as "Not specified". Do not preamble.
      `;

    const response = await client.messages.create({
      model,
      max_tokens: maxTokens,
      system: "You are a legal expert that summarizes notes on one document.",
      messages: [{ role: "user", content: finalSummaryPrompt }]
    });

    const textBlock = response.content.find((block) => block.type === "text");
    if (!textBlock) {
      throw new Error("Expected a text block in the response");
    }
    return textBlock.text;
  }

  const longSummary = await summarizeLongDocument(documentText, detailsToExtract);
  console.log(longSummary);
  ```

  ```csharp C#
  IEnumerable<string> ChunkText(string text, int chunkSize = 20000) =>
      text.Chunk(chunkSize).Select(chars => new string(chars));

  async Task<string> SummarizeLongDocument(
      string text,
      IReadOnlyList<string> detailsToExtract,
      Model model = Model.ClaudeOpus5_5,
      long maxTokens = 16000
  )
  {
      // Formatea los detalles a extraer para colocarlos en el contexto del prompt
      var detailsToExtractStr = string.Join("\n", detailsToExtract);

      // Itera sobre los fragmentos y resume cada uno
      List<string> chunkSummaries = [];
      foreach (var chunk in ChunkText(text))
      {
          chunkSummaries.Add(await SummarizeDocument(chunk, detailsToExtract, model, maxTokens));
      }

      var finalSummaryPrompt = $"""

              You are looking at the chunked summaries of multiple documents that are all related.
              Combine the following summaries of the document from different truthful sources into a coherent overall summary:

              <chunked_summaries>
              {string.Concat(chunkSummaries)}
              </chunked_summaries>

              Focus on these key aspects:
              {detailsToExtractStr}

              Provide the summary in bullet points nested within the XML header for each section. For example:

              <parties involved>
              - Sublessor: [Name]
              // Add more details as needed
              </parties involved>

              If any information is not explicitly stated in the document, note it as "Not specified". Do not preamble.
          """;

      var response = await client.Messages.Create(
          new()
          {
              Model = model,
              MaxTokens = maxTokens,
              System = "You are a legal expert that summarizes notes on one document.",
              Messages = [new() { Role = Role.User, Content = finalSummaryPrompt }],
          }
      );

      foreach (var block in response.Content)
      {
          if (block.TryPickText(out var textBlock))
          {
              return textBlock.Text;
          }
      }
      throw new InvalidOperationException("Expected a text block in the response.");
  }

  var longSummary = await SummarizeLongDocument(documentText, detailsToExtract);
  Console.WriteLine(longSummary);
  ```

  ```go Go
  func chunkText(text string, chunkSize int) []string {
  	var chunks []string
  	for chunk := range slices.Chunk([]rune(text), chunkSize) {
  		chunks = append(chunks, string(chunk))
  	}
  	return chunks
  }

  func summarizeLongDocument(text string, detailsToExtract []string, model anthropic.Model, maxTokens int64) string {
  	// Formatear los detalles a extraer para colocarlos en el contexto del prompt
  	detailsToExtractStr := strings.Join(detailsToExtract, "\n")

  	// Iterar sobre los fragmentos y resumir cada uno
  	var chunkSummaries []string
  	for _, chunk := range chunkText(text, 20000) {
  		chunkSummaries = append(chunkSummaries, summarizeDocument(chunk, detailsToExtract, model, maxTokens))
  	}

  	finalSummaryPrompt := fmt.Sprintf(`

      You are looking at the chunked summaries of multiple documents that are all related.
      Combine the following summaries of the document from different truthful sources into a coherent overall summary:

      <chunked_summaries>
      %s
      </chunked_summaries>

      Focus on these key aspects:
      %s

      Provide the summary in bullet points nested within the XML header for each section. For example:

      <parties involved>
      - Sublessor: [Name]
      // Add more details as needed
      </parties involved>

      If any information is not explicitly stated in the document, note it as "Not specified". Do not preamble.
      `, strings.Join(chunkSummaries, ""), detailsToExtractStr)

  	response, err := client.Messages.New(context.Background(), anthropic.MessageNewParams{
  		Model:     model,
  		MaxTokens: maxTokens,
  		System: []anthropic.TextBlockParam{
  			{Text: "You are a legal expert that summarizes notes on one document."},
  		},
  		Messages: []anthropic.MessageParam{
  			anthropic.NewUserMessage(anthropic.NewTextBlock(finalSummaryPrompt)),
  		},
  	})
  	if err != nil {
  		log.Fatal(err)
  	}

  	for _, block := range response.Content {
  		if textBlock, ok := block.AsAny().(anthropic.TextBlock); ok {
  			return textBlock.Text
  		}
  	}
  	panic("expected a text block in the response")
  }

  // printLongSummary resume el contrato de subarrendamiento por fragmentos e imprime el resumen combinado.
  func printLongSummary() {
  	longSummary := summarizeLongDocument(documentText, detailsToExtract, anthropic.ModelClaudeOpus5_5, 16000)
  	fmt.Println(longSummary)
  }
  ```

  ```java Java
  List<String> chunkText(String text, int chunkSize) {
      return IntStream.iterate(0, start -> start < text.length(), start -> start + chunkSize)
              .mapToObj(start -> text.substring(start, Math.min(start + chunkSize, text.length())))
              .toList();
  }

  String summarizeLongDocument(String text, List<String> detailsToExtract, Model model, long maxTokens) {
      // Formatea los detalles a extraer para colocarlos en el contexto del prompt
      String detailsToExtractStr = String.join("\n", detailsToExtract);

      // Itera sobre los fragmentos y resume cada uno
      String chunkSummaries = chunkText(text, 20000).stream()
              .map(chunk -> summarizeDocument(chunk, detailsToExtract, model, maxTokens))
              .collect(Collectors.joining());

      String finalSummaryPrompt = """

                  You are looking at the chunked summaries of multiple documents that are all related.
                  Combine the following summaries of the document from different truthful sources into a coherent overall summary:

                  <chunked_summaries>
                  %s
                  </chunked_summaries>

                  Focus on these key aspects:
                  %s

                  Provide the summary in bullet points nested within the XML header for each section. For example:

                  <parties involved>
                  - Sublessor: [Name]
                  // Add more details as needed
                  </parties involved>

                  If any information is not explicitly stated in the document, note it as "Not specified". Do not preamble.
              """
              .formatted(chunkSummaries, detailsToExtractStr);

      Message response = client.messages().create(MessageCreateParams.builder()
              .model(model)
              .maxTokens(maxTokens)
              .system("You are a legal expert that summarizes notes on one document.")
              .addUserMessage(finalSummaryPrompt)
              .build());

      return response.content().stream()
              .flatMap(block -> block.text().stream())
              .findFirst()
              .orElseThrow()
              .text();
  }

  void printLongSummary() {
      String longSummary = summarizeLongDocument(
              documentText, detailsToExtract, Model.CLAUDE_OPUS_5_5, 16000);
      IO.println(longSummary);
  }
  ```

  ```php PHP
  $chunkText = fn (string $text, int $chunkSize = 20000): array => mb_str_split($text, $chunkSize);

  $summarizeLongDocument = function (
      string $text,
      array $detailsToExtract,
      Model $model = Model::CLAUDE_OPUS_5_5,
      int $maxTokens = 16000,
  ) use ($client, $chunkText, $summarizeDocument): string {
      // Formatea los detalles a extraer para colocarlos en el contexto del prompt
      $detailsToExtractStr = implode("\n", $detailsToExtract);

      // Itera sobre los fragmentos y resume cada uno
      $chunkSummaries = array_map(
          fn (string $chunk) => $summarizeDocument($chunk, $detailsToExtract, $model, $maxTokens),
          $chunkText($text),
      );
      $chunkSummariesStr = implode('', $chunkSummaries);

      $finalSummaryPrompt = <<<PROMPT

              You are looking at the chunked summaries of multiple documents that are all related.
              Combine the following summaries of the document from different truthful sources into a coherent overall summary:

              <chunked_summaries>
              {$chunkSummariesStr}
              </chunked_summaries>

              Focus on these key aspects:
              {$detailsToExtractStr}

              Provide the summary in bullet points nested within the XML header for each section. For example:

              <parties involved>
              - Sublessor: [Name]
              // Add more details as needed
              </parties involved>

              If any information is not explicitly stated in the document, note it as "Not specified". Do not preamble.
          PROMPT;

      $response = $client->messages->create(
          model: $model,
          maxTokens: $maxTokens,
          system: 'You are a legal expert that summarizes notes on one document.',
          messages: [['role' => 'user', 'content' => $finalSummaryPrompt]],
      );

      $textBlock = array_find($response->content, fn ($block) => $block instanceof \Anthropic\Messages\TextBlock)
          ?? throw new \RuntimeException('Expected a text block in the response.');

      return $textBlock->text;
  };

  $longSummary = $summarizeLongDocument($documentText, $detailsToExtract);
  echo $longSummary . "\n";
  ```

  ```ruby Ruby
  def chunk_text(text, chunk_size: 20_000)
    text.chars.each_slice(chunk_size).map(&:join)
  end

  def summarize_long_document(text, details_to_extract, model: Anthropic::Model::CLAUDE_OPUS_5_5, max_tokens: 16_000)
    # Formatea los detalles a extraer para colocarlos en el contexto del prompt
    details_to_extract_str = details_to_extract.join("\n")

    # Itera sobre los fragmentos y resume cada uno
    chunk_summaries = chunk_text(text).map do |chunk|
      summarize_document(chunk, details_to_extract, model:, max_tokens:)
    end

    final_summary_prompt = <<~PROMPT

          You are looking at the chunked summaries of multiple documents that are all related.
          Combine the following summaries of the document from different truthful sources into a coherent overall summary:

          <chunked_summaries>
          #{chunk_summaries.join}
          </chunked_summaries>

          Focus on these key aspects:
          #{details_to_extract_str}

          Provide the summary in bullet points nested within the XML header for each section. For example:

          <parties involved>
          - Sublessor: [Name]
          // Add more details as needed
          </parties involved>

          If any information is not explicitly stated in the document, note it as "Not specified". Do not preamble.
    PROMPT

    response = CLIENT.messages.create(
      model:,
      max_tokens:,
      system_: "You are a legal expert that summarizes notes on one document.",
      messages: [{role: :user, content: final_summary_prompt}]
    )

    response.content.find { |block| block.is_a?(Anthropic::Models::TextBlock) }.text
  end

  long_summary = summarize_long_document(document_text, details_to_extract)
  puts long_summary
  ```
</CodeGroup>

La función `summarize_long_document` (typescript, go, java: `summarizeLongDocument`; php: `$summarizeLongDocument`; csharp: `SummarizeLongDocument`) se basa en la función anterior `summarize_document` (typescript, go, java: `summarizeDocument`; php: `$summarizeDocument`; csharp: `SummarizeDocument`), dividiendo el documento en fragmentos más pequeños y resumiendo cada fragmento individualmente.

El código logra esto aplicando la función `summarize_document` (typescript, go, java: `summarizeDocument`; php: `$summarizeDocument`; csharp: `SummarizeDocument`) a cada fragmento de 20,000 caracteres del documento original. Luego, los resúmenes individuales se combinan y se crea un resumen final a partir de estos resúmenes de fragmentos.

Ten en cuenta que la función `summarize_long_document` (typescript, go, java: `summarizeLongDocument`; php: `$summarizeLongDocument`; csharp: `SummarizeLongDocument`) no es estrictamente necesaria para el PDF de ejemplo, ya que todo el documento cabe dentro de la ventana de contexto de Claude. Sin embargo, se vuelve esencial para documentos que exceden la ventana de contexto de Claude o al resumir varios documentos relacionados juntos. De todos modos, esta técnica de meta-resumen a menudo captura detalles importantes adicionales en el resumen final que se omitieron en el enfoque anterior de un solo resumen.

### Usa documentos indexados por resumen para explorar una gran colección de documentos

Buscar en una colección de documentos con un LLM generalmente implica "retrieval-augmented generation" (generación aumentada por recuperación), o RAG. Sin embargo, en escenarios que involucran documentos grandes o cuando la recuperación precisa de información es crucial, un enfoque RAG básico puede ser insuficiente. Los documentos indexados por resumen son un enfoque RAG avanzado que proporciona una forma más eficiente de clasificar documentos para su recuperación, usando menos contexto que los métodos RAG tradicionales. En este enfoque, primero usas Claude para generar un resumen conciso de cada documento de tu corpus, y luego usas Claude para clasificar la relevancia de cada resumen respecto a la consulta realizada. Para obtener más detalles sobre este enfoque, incluido un ejemplo basado en código, consulta la sección de documentos indexados por resumen en el [cookbook de resumen](https://platform.claude.com/cookbook/capabilities-summarization-guide).

### Haz fine-tuning de Claude para que aprenda de tu conjunto de datos

Otra técnica avanzada para mejorar la capacidad de Claude de generar resúmenes es el "fine-tuning" (ajuste fino). El fine-tuning implica entrenar a Claude con un conjunto de datos personalizado que se alinee específicamente con tus necesidades de resumen de documentos legales, garantizando que Claude se adapte a tu caso de uso. Aquí tienes una descripción general de cómo realizar el fine-tuning:

1. **Identifica errores:** Comienza recopilando casos en los que los resúmenes de Claude no cumplan las expectativas; esto podría incluir la omisión de detalles legales críticos, la mala interpretación del contexto o el uso de terminología jurídica inapropiada.

2. **Prepara un conjunto de datos:** Una vez que hayas identificado estos problemas, compila un conjunto de datos con estos ejemplos problemáticos. Este conjunto de datos debe incluir los documentos legales originales junto con tus resúmenes corregidos, garantizando que Claude aprenda el comportamiento deseado.

3. **Realiza el fine-tuning:** El fine-tuning implica volver a entrenar el modelo con tu conjunto de datos preparado para ajustar sus pesos y parámetros. Este reentrenamiento ayuda a Claude a adaptarse mejor a los requisitos específicos de tu dominio legal, mejorando su capacidad para resumir documentos según tus estándares.

4. **Mejora iterativa:** El fine-tuning no es un proceso de una sola vez. A medida que Claude continúa generando resúmenes, puedes agregar iterativamente nuevos ejemplos en los que haya tenido un rendimiento inferior, refinando aún más sus capacidades. Con el tiempo, este ciclo de retroalimentación continua dará como resultado un modelo altamente especializado para tus tareas de resumen de documentos legales.

<Tip>
  El fine-tuning actualmente solo está disponible a través de Amazon Bedrock. Hay detalles adicionales disponibles en el 

  [blog de lanzamiento de AWS](https://aws.amazon.com/blogs/machine-learning/fine-tune-anthropics-claude-3-haiku-in-amazon-bedrock-to-boost-model-accuracy-and-quality/)

  .
</Tip>

<CardGroup cols={2}>
  <Card title="Cookbook de resumen" icon="link" href="https://platform.claude.com/cookbook/capabilities-summarization-guide">
    Consulta un ejemplo basado en código completamente implementado sobre cómo usar Claude para resumir contratos.
  </Card>

  <Card title="Cookbook de citas" icon="link" href="https://platform.claude.com/cookbook/misc-using-citations">
    Explora la receta del cookbook de citas para obtener orientación sobre cómo garantizar la precisión y la explicabilidad de la información.
  </Card>
</CardGroup>
