主题
面对财报、合同、发票这类复杂文件,Llama Extract 可以借助大模型,按你要的结构化格式抽出与你相关的信息。
本例用 LlamaExtract 从一份 SEC 文件(具体是 Nvidia 的 2025 财年申报)里抽取结构化数据。
在基础的数据抽取之上,我们为每个抽取字段开启引用。这让我们能把取值对照到源文档核实,也看得出哪些字段描述或系统提示词还需要收紧。
下面走的这个例子在 Llama Cloud 里也能复现,而且在那里你还可以从若干预置 schema 中挑一个,不必自己从零构建。
- Python
- TypeScript
- Go
- Java
- CLI
!pip install "llama-cloud>=2.8"npm install @llamaindex/llama-cloud zod终端窗口
go get github.com/run-llama/llama-parse-goimplementation("ai.llamaindex:llama-cloud:1.3.0")终端窗口
go install github.com/run-llama/llama-parse-cli/cmd/llp@latest连接 Llama Cloud
开始前,请先提供你的 Llama Cloud API key。
- Python
- TypeScript
- Go
- Java
- CLI
import os
from llama_cloud import LlamaCloud, AsyncLlamaCloud
# Could use async or sync clients, this page will use the sync client
client = LlamaCloud(api_key=os.environ["LLAMA_CLOUD_API_KEY"])import LlamaCloud from "@llamaindex/llama-cloud";
const client = new LlamaCloud({
apiKey: process.env.LLAMA_CLOUD_API_KEY!,
});import (
"context"
llamacloud "github.com/run-llama/llama-parse-go"
)
ctx := context.Background()
// Reads LLAMA_CLOUD_API_KEY from the environment
client := llamacloud.NewClient()import ai.llamaindex.llamacloud.client.LlamaCloudClient;
import ai.llamaindex.llamacloud.client.okhttp.LlamaCloudOkHttpClient;
// Reads LLAMA_CLOUD_API_KEY from the environment
LlamaCloudClient client = LlamaCloudOkHttpClient.fromEnv();终端窗口
export LLAMA_CLOUD_API_KEY=llx-xxxxxx用 LlamaExtract 抽取数据
提供你自己的 schema
通过 API 使用 LlamaExtract 时,你要提供一份描述「想从文档里抽出什么」的 schema。这里我们定义了一份用于从 SEC 文件里抽取关键信息的 schema。
- Python
- TypeScript
- Go
- Java
- CLI
from pydantic import BaseModel, Field
from enum import Enum
class FilingType(str, Enum):
ten_k = '10 K'
ten_q = '10-Q'
ten_ka = '10-K/A'
ten_qa = '10-Q/A'
class FinancialReport(BaseModel):
company_name: str = Field(description="The name of the company")
description: str = Field(description="Short description of the filing and what it contains")
filing_type: FilingType = Field(description="Type of SEC filing")
filing_date: str = Field(description="Date when filing was submitted to SEC")
fiscal_year: int = Field(description="Fiscal year")
unit: str = Field(description="Unit of financial figures (thousands, millions, etc.)")
revenue: int = Field(description="Total revenue for period")import { z } from "zod";
const FilingType = z.enum(['10 K', '10-Q', '10-K/A', '10-Q/A']);
const FinancialReportSchema = z.object({
company_name: z.string().describe("The name of the company"),
description: z.string().describe("Short description of the filing and what it contains"),
filing_type: FilingType.describe("Type of SEC filing"),
filing_date: z.string().describe("Date when filing was submitted to SEC"),
fiscal_year: z.number().describe("Fiscal year"),
unit: z.string().describe("Unit of financial figures (thousands, millions, etc.)"),
revenue: z.number().describe("Total revenue for period"),
});import llamacloud "github.com/run-llama/llama-parse-go"
// Define the schema as a JSON Schema literal
dataSchema := map[string]*llamacloud.ExtractConfigurationDataSchemaUnionParam{
"type": {OfString: llamacloud.String("object")},
"properties": {OfAnyMap: map[string]any{
"company_name": map[string]any{"type": "string", "description": "The name of the company"},
"description": map[string]any{"type": "string", "description": "Short description of the filing and what it contains"},
"filing_type": map[string]any{"type": "string", "enum": []any{"10 K", "10-Q", "10-K/A", "10-Q/A"}, "description": "Type of SEC filing"},
"filing_date": map[string]any{"type": "string", "description": "Date when filing was submitted to SEC"},
"fiscal_year": map[string]any{"type": "integer", "description": "Fiscal year"},
"unit": map[string]any{"type": "string", "description": "Unit of financial figures (thousands, millions, etc.)"},
"revenue": map[string]any{"type": "integer", "description": "Total revenue for period"},
}},
"required": {OfAnyArray: []any{"company_name", "description", "filing_type", "filing_date", "fiscal_year", "unit", "revenue"}},
}import ai.llamaindex.llamacloud.core.JsonValue;
import ai.llamaindex.llamacloud.models.extract.ExtractConfiguration;
import java.util.List;
import java.util.Map;
// Define the schema as a JSON Schema literal
ExtractConfiguration.DataSchema dataSchema = ExtractConfiguration.DataSchema.builder()
.putAdditionalProperty("type", JsonValue.from("object"))
.putAdditionalProperty("properties", JsonValue.from(Map.of(
"company_name", Map.of("type", "string", "description", "The name of the company"),
"description", Map.of("type", "string", "description", "Short description of the filing and what it contains"),
"filing_type", Map.of("type", "string", "enum", List.of("10 K", "10-Q", "10-K/A", "10-Q/A"), "description", "Type of SEC filing"),
"filing_date", Map.of("type", "string", "description", "Date when filing was submitted to SEC"),
"fiscal_year", Map.of("type", "integer", "description", "Fiscal year"),
"unit", Map.of("type", "string", "description", "Unit of financial figures (thousands, millions, etc.)"),
"revenue", Map.of("type", "integer", "description", "Total revenue for period"))))
.putAdditionalProperty("required", JsonValue.from(List.of(
"company_name", "description", "filing_type", "filing_date", "fiscal_year", "unit", "revenue")))
.build();终端窗口
# Define the schema as a JSON Schema literal
DATA_SCHEMA='{
"type": "object",
"properties": {
"company_name": {"type": "string", "description": "The name of the company"},
"description": {"type": "string", "description": "Short description of the filing and what it contains"},
"filing_type": {"type": "string", "enum": ["10 K", "10-Q", "10-K/A", "10-Q/A"], "description": "Type of SEC filing"},
"filing_date": {"type": "string", "description": "Date when filing was submitted to SEC"},
"fiscal_year": {"type": "integer", "description": "Fiscal year"},
"unit": {"type": "string", "description": "Unit of financial figures (thousands, millions, etc.)"},
"revenue": {"type": "integer", "description": "Total revenue for period"}
},
"required": ["company_name", "description", "filing_type", "filing_date", "fiscal_year", "unit", "revenue"]
}'下载 PDF 并带引用抽取
我们在抽取配置里开启 cite_sources,这样每个取值都能追溯到它在文档中的出处。
- Python
- TypeScript
- Go
- Java
- CLI
import time
import requests
url = 'https://raw.githubusercontent.com/run-llama/llama_cloud_services/refs/heads/main/examples/extract/data/sec_filings/nvda_10k.pdf'
response = requests.get(url)
response.raise_for_status()
with open('nvda_10k.pdf', 'wb') as f:
f.write(response.content)
file_obj = client.files.create(
file="nvda_10k.pdf",
purpose="extract",
)
file_id = file_obj.id
job = client.extract.create(
file_input=file_id,
configuration={
"data_schema": FinancialReport.model_json_schema(),
"tier": "agentic",
"cite_sources": True,
},
)
# Poll for completion
while job.status not in ("COMPLETED", "FAILED", "CANCELLED"):
time.sleep(2)
job = client.extract.get(job.id)
print(job.extract_result)const url = "https://raw.githubusercontent.com/run-llama/llama_cloud_services/refs/heads/main/examples/extract/data/sec_filings/nvda_10k.pdf"
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Download failed: ${response.status}`);
}
// Upload the file first
const fileObj = await client.files.create({
file: response,
purpose: "extract",
});
const fileId = fileObj.id;
let job = await client.extract.create({
file_input: fileId,
configuration: {
data_schema: z.toJSONSchema(FinancialReportSchema),
tier: 'agentic',
cite_sources: true,
},
});
// Poll for completion
while (!['COMPLETED', 'FAILED', 'CANCELLED'].includes(job.status)) {
await new Promise((r) => setTimeout(r, 2000));
job = await client.extract.get(job.id);
}
console.log(job.extract_result);import (
"fmt"
"io"
"log"
"net/http"
"os"
"time"
llamacloud "github.com/run-llama/llama-parse-go"
)
url := "https://raw.githubusercontent.com/run-llama/llama_cloud_services/refs/heads/main/examples/extract/data/sec_filings/nvda_10k.pdf"
// Download the sample filing
resp, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
log.Fatalf("download failed: %s", resp.Status)
}
out, err := os.Create("nvda_10k.pdf")
if err != nil {
log.Fatal(err)
}
if _, err := io.Copy(out, resp.Body); err != nil {
log.Fatal(err)
}
out.Close()
// Upload the file first
f, err := os.Open("nvda_10k.pdf")
if err != nil {
log.Fatal(err)
}
defer f.Close()
fileObj, err := client.Files.New(ctx, llamacloud.FileNewParams{
File: f,
Purpose: "extract",
})
if err != nil {
log.Fatal(err)
}
// Extract with cite_sources enabled
job, err := client.Extract.New(ctx, llamacloud.ExtractNewParams{
ExtractV2JobCreate: llamacloud.ExtractV2JobCreateParam{
FileInput: fileObj.ID,
Configuration: llamacloud.ExtractConfigurationParam{
DataSchema: dataSchema,
Tier: llamacloud.ExtractConfigurationTierAgentic,
CiteSources: llamacloud.Bool(true),
},
},
})
if err != nil {
log.Fatal(err)
}
// Poll for completion
for job.Status != "COMPLETED" && job.Status != "FAILED" && job.Status != "CANCELLED" {
time.Sleep(2 * time.Second)
job, err = client.Extract.Get(ctx, job.ID, llamacloud.ExtractGetParams{})
if err != nil {
log.Fatal(err)
}
}
fmt.Println(job.ExtractResult.RawJSON())import ai.llamaindex.llamacloud.models.extract.ExtractCreateParams;
import ai.llamaindex.llamacloud.models.extract.ExtractGetParams;
import ai.llamaindex.llamacloud.models.extract.ExtractV2Job;
import ai.llamaindex.llamacloud.models.extract.ExtractV2JobCreate;
import ai.llamaindex.llamacloud.models.files.FileCreateParams;
import ai.llamaindex.llamacloud.models.files.FileCreateResponse;
import java.io.InputStream;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
String url = "https://raw.githubusercontent.com/run-llama/llama_cloud_services/refs/heads/main/examples/extract/data/sec_filings/nvda_10k.pdf";
// Download the sample filing
Path pdfPath = Paths.get("nvda_10k.pdf");
try (InputStream in = URI.create(url).toURL().openStream()) {
Files.copy(in, pdfPath);
}
// Upload the file first
FileCreateResponse fileObj = client.files().create(
FileCreateParams.builder()
.file(pdfPath)
.purpose("extract")
.build());
// Extract with cite_sources enabled
ExtractV2Job job = client.extract().create(
ExtractCreateParams.builder()
.extractV2JobCreate(
ExtractV2JobCreate.builder()
.fileInput(fileObj.id())
.configuration(
ExtractConfiguration.builder()
.dataSchema(dataSchema)
.tier(ExtractConfiguration.Tier.AGENTIC)
.citeSources(true)
.build())
.build())
.build());
// Poll for completion
while (!job.status().equals("COMPLETED")
&& !job.status().equals("FAILED")
&& !job.status().equals("CANCELLED")) {
Thread.sleep(2000);
job = client.extract().get(ExtractGetParams.builder().jobId(job.id()).build());
}
System.out.println(job.extractResult());终端窗口
URL="https://raw.githubusercontent.com/run-llama/llama_cloud_services/refs/heads/main/examples/extract/data/sec_filings/nvda_10k.pdf"
# Download the sample filing
curl -fL -o nvda_10k.pdf "$URL"
# Upload the file first
FILE_ID=$(llp files create --file nvda_10k.pdf --purpose extract | jq -r '.id')
# Extract with cite_sources enabled
JOB_ID=$(llp extract create \
--file-input "$FILE_ID" \
--configuration "{\"data_schema\": $DATA_SCHEMA, \"tier\": \"agentic\", \"cite_sources\": true}" \
| jq -r '.id')
# Poll for completion
while true; do
JOB=$(llp extract get --job-id "$JOB_ID") || break
STATUS=$(printf '%s\n' "$JOB" | jq -r '.status')
case "$STATUS" in COMPLETED|FAILED|CANCELLED) break ;; esac
sleep 2
done
printf '%s\n' "$JOB" | jq -r 'if .status == "COMPLETED" then .extract_result
else "Extract job failed: \(.error_message // .)" end'你得到的输出应类似于:
{
'company_name': 'NVIDIA Corporation',
'description': "The filing provides a detailed overview of NVIDIA's business as a full-stack computing infrastructure company, discusses various technologies including digital avatars and autonomous vehicles, outlines numerous risk factors affecting operations such as supply chain issues and geopolitical tensions, and describes employee stock purchase plans and related compliance requirements.",
'filing_type': '10 K',
'filing_date': 'February 26, 2025',
'fiscal_year': 2025,
'unit': 'millions',
'revenue': 130497
}查看引用
- Python
- TypeScript
- Go
- Java
- CLI
# Fetch metadata (not returned by default)
detailed = client.extract.get(job.id, expand=["extract_metadata"])
print(detailed.extract_metadata)// Fetch metadata (not returned by default)
const detailed = await client.extract.get(job.id, { expand: ["extract_metadata"] });
console.log(detailed.extract_metadata);// Fetch metadata (not returned by default)
detailed, err := client.Extract.Get(ctx, job.ID, llamacloud.ExtractGetParams{
Expand: []string{"extract_metadata"},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(detailed.ExtractMetadata.RawJSON())// Fetch metadata (not returned by default)
ExtractV2Job detailed = client.extract().get(
ExtractGetParams.builder()
.jobId(job.id())
.addExpand("extract_metadata")
.build());
System.out.println(detailed.extractMetadata());终端窗口
# Fetch metadata (not returned by default)
llp extract get --job-id "$JOB_ID" --expand extract_metadata | jq '.extract_metadata'引用位于 field_metadata.document_metadata 之下。下面的示例展示每个抽取字段的引用,重复的位置已省略。
{
"field_metadata": {
"document_metadata": {
"company_name": {
"citation": [
{"page": 1, "matching_text": "NVIDIA CORPORATION"},
{"page": 2, "matching_text": "NVIDIA Corporation"}
]
},
"filing_type": {
"citation": [
{"page": 1, "matching_text": "FORM 10-K"},
{"page": 2, "matching_text": "Item 16. | Form 10-K Summary"}
]
},
"fiscal_year": {
"citation": [
{"page": 1, "matching_text": "For the fiscal year ended January 26, 2025"},
{"page": 6, "matching_text": "In fiscal year 2025, we launched the NVIDIA Blackwell architecture"}
]
},
"description": {
"citation": [
{"page": 4, "matching_text": "NVIDIA is now a full-stack computing infrastructure company with data-center-scale offerings that are reshaping industry."}
]
},
"filing_date": {
"citation": [
{"page": 51, "matching_text": "February 26, 2025"},
{"page": 86, "matching_text": "on February 26, 2025."}
]
},
"unit": {
"citation": [
{"page": 38, "matching_text": "($ in millions, except per share data)"},
{"page": 42, "matching_text": "($ in millions)"}
]
},
"revenue": {
"citation": [
{"page": 38, "matching_text": "Revenue for fiscal year 2025 was $130.5 billion"},
{"page": 52, "matching_text": "Revenue | $ 130,497"}
]
}
}
}
}响应字段与用量 credit 见 Extract 响应形态。
下一步做什么?
本例演示了如何用 LlamaExtract 从财务文档里带引用地抽取数据。想进一步定制并改善结果,你还可以在抽取配置里加一段 system_prompt。