使用表格行提取技术提取重复实体
此示例演示了如何使用 PER_TABLE_ROW 提取目标,从包含重复实体(如表格、列表或目录)的文档中提取结构化数据。
PER_DOC(请参阅下表快速了解不同的提取目标)是LlamaExtract中的默认提取目标,它在执行提取时会考虑整个文档的上下文。当提取实体列表时,基于LLM的提取存在一个关键故障模式——它经常仅从长列表中提取前几十个条目。这是因为LLM对重复数据的注意力有限。文档级提取不能保证完全覆盖,长列表会导致提取不完整。
解决方案:PER_TABLE_ROW通过单独或分批处理每个实体来解决这个问题,确保无论列表长度如何都能彻底提取所有条目。
当使用 extraction_target=ExtractTarget.PER_TABLE_ROW 时,您需要为单个实体(例如一家医院、一个产品、一个发票行项目)定义模式,而不是整个文档。LlamaExtract 会自动:
- 检测用于区分各个实体(表格行、列表项、章节标题等)的格式化模式
- 将您的模式应用于每个已识别的实体
- 返回一个
list[YourSchema],每个实体对应一个对象
当每个实体本地包含您的模式所需的全部信息时,这种方法非常理想。
| 提取目标 | 最适合 | 返回值 |
|---|---|---|
PER_DOC | 单实体文档、摘要或简短列表 | 整个文档对应一个JSON对象 |
PER_PAGE | 多页文档,其中每页内容相互独立 | 每页一个JSON对象 |
PER_TABLE_ROW | 包含重复实体的长列表、表格、目录 | JSON对象列表(每个实体对应一个) |
📖 更多详细信息,请参阅提取目标文档。
from dotenv import load_dotenvfrom llama_cloud_services import LlamaExtract
# Load environment variables (put LLAMA_CLOUD_API_KEY in your .env file)load_dotenv(override=True)
# Optionally, add your project id/organization idllama_extract = LlamaExtract()我们有一份PDF文档,其中按县列出了医院列表以及加州蓝盾提供的不同保险计划。
你可以在此处获取
BSC-Hospital-List-by-County.pdf

我们希望从此表中提取每家医院以及适用的保险计划列表。
这是 PER_TABLE_ROW 提取的理想用例:
- 清晰的结构: 文档采用明确的表格格式,包含行和列
- 重复实体: 每行代表一个具有一致属性的医院
- 本地信息:每家医院的所有数据(县区、名称、计划)都包含在其行内
请注意,我们的 Hospital 模式描述的是单个医院,而非完整文档。LlamaExtract 将返回一个 list[Hospital],其中每个表格行对应一个条目。
from pydantic import BaseModel, Field
class Hospital(BaseModel): """List of hospitals by county available for different BSC plans"""
county: str = Field(description="County name") hospital_name: str = Field(description="Name of the hospital") plan_names: list[str] = Field( description="List of plans available at the hospital. One of: Trio HMO, SaveNet, Access+ HMO, BlueHPN PPO, Tandem PPO, PPO" )from llama_cloud_services.extract import ExtractConfig, ExtractMode, ExtractTarget
result = await llama_extract.aextract( data_schema=Hospital, files="BSC-Hospital-List-by-County.pdf", config=ExtractConfig( extraction_mode=ExtractMode.PREMIUM, extraction_target=ExtractTarget.PER_TABLE_ROW, parse_model="anthropic-sonnet-4.5", ),)len(result.data) 380result.data[:10] [{'county': 'Alameda', 'hospital_name': 'Alameda Hospital', 'plan_names': ['Trio HMO', 'SaveNet', 'Access+ HMO', 'BlueHPN PPO', 'Tandem PPO', 'PPO']}, {'county': 'Alameda', 'hospital_name': 'Alta Bates Med Ctr Herrick Campus', 'plan_names': ['Trio HMO', 'Access+ HMO', 'BlueHPN PPO', 'Tandem PPO', 'PPO']}, {'county': 'Alameda', 'hospital_name': 'Alta Bates Summit Med Ctr Alta Bates Campus', 'plan_names': ['Trio HMO', 'Access+ HMO', 'BlueHPN PPO', 'Tandem PPO', 'PPO']}, {'county': 'Alameda', 'hospital_name': 'Alta Bates Summit Med Ctr Summit Campus', 'plan_names': ['Trio HMO', 'Access+ HMO', 'BlueHPN PPO', 'Tandem PPO', 'PPO']}, {'county': 'Alameda', 'hospital_name': 'Alta Bates Summit Medical Center', 'plan_names': ['Trio HMO', 'Access+ HMO', 'BlueHPN PPO', 'Tandem PPO', 'PPO']}, {'county': 'Alameda', 'hospital_name': 'BHC Fremont Hospital', 'plan_names': ['Trio HMO', 'SaveNet', 'Access+ HMO', 'BlueHPN PPO', 'Tandem PPO', 'PPO']}, {'county': 'Alameda', 'hospital_name': 'Centre For Neuro Skills San Francisco', 'plan_names': ['Trio HMO', 'SaveNet', 'Access+ HMO', 'BlueHPN PPO', 'Tandem PPO', 'PPO']}, {'county': 'Alameda', 'hospital_name': 'Eden Medical Center', 'plan_names': ['Trio HMO', 'Access+ HMO', 'PPO']}, {'county': 'Alameda', 'hospital_name': 'Fairmont Hospital', 'plan_names': ['Trio HMO', 'SaveNet', 'Access+ HMO', 'BlueHPN PPO', 'Tandem PPO', 'PPO']}, {'county': 'Alameda', 'hospital_name': 'Highland Hospital', 'plan_names': ['Trio HMO', 'SaveNet', 'Access+ HMO', 'BlueHPN PPO', 'Tandem PPO', 'PPO']}]
成功! 我们从多页PDF中提取了全部380家医院。每个实体都正确解析了其所属县区、医院名称和适用的保险计划。若使用PER_DOC,我们可能只能获取前20-30条条目。
PER_TABLE_ROW 提取目标同样适用于非显式表格但具有相似属性的文档:
- 有序列表: 玩具按顺序排列,并带有视觉分隔(章节标题、间距)
- 重复模式: 每个玩具条目都具有一致的结构(代码、名称、规格、描述)
- 本地信息:每个玩具的所有属性在其条目中被分组在一起
尽管这不是传统的表格格式,但每个玩具实体在本地都包含了我们模式所需的全部信息。LlamaExtract 检测区分每个玩具的格式模式,并将它们提取为独立的实体。

from pydantic import BaseModel, Field
class ToyCatalog(BaseModel): """Product information from a toy catalog."""
section_name: str = Field( description="The name of the toy section (e.g. Table Toys, Active Toys)." ) product_code: str = Field( description="The unique product code for the toy (e.g., GA457)." ) toy_name: str = Field(description="The name of the toy.") age_range: str = Field( description="The recommended age range for the toy (e.g., 6 +, 4 +).", ) player_range: str = Field( description="The number of players the toy is designed for (e.g., 2, 2-4, 1-6).", ) material: str = Field( description="The primary material(s) the toy is made of (e.g., wood, cardboard).", ) description: str = Field( description="A brief description of the toy and its components and dimensions.", )再次说明,我们的模式代表的是单个玩具产品,而非整个目录。系统将返回一个list[ToyCatalog],每个玩具对应一个条目。
你可以在此处获取
Click-BS-Toys-Catalogue-2024.pdf
result = await llama_extract.aextract( data_schema=ToyCatalog, files="Click-BS-Toys-Catalogue-2024.pdf", config=ExtractConfig( extraction_mode=ExtractMode.PREMIUM, extraction_target=ExtractTarget.PER_TABLE_ROW, parse_model="anthropic-sonnet-4.5", ),)len(result.data) 153result.data[:10] [{'section_name': 'Table Toys', 'product_code': 'GA457', 'toy_name': 'Dots and Boxes', 'age_range': '6+', 'player_range': '2', 'material': 'wood', 'description': 'base 17x17 cm\n50 border pieces 4x1,2x0,3 cm\n34 trees 2,6x1,4 cm'}, {'section_name': 'Table Toys', 'product_code': 'GA456', 'toy_name': '3 In a Row', 'age_range': '8+', 'player_range': '2', 'material': 'wood, pine, cardboard', 'description': 'base 24x22,5x2,5 cm\n30 cards 5,5x5 cm\n6 chips'}, {'section_name': 'Table Toys', 'product_code': 'GA467', 'toy_name': 'Which Cow am i?', 'age_range': '6+', 'player_range': '2', 'material': 'wood, beech', 'description': '2 cow bases 56x4x4,5 cm\n16 cards 4x5 cm'}, {'section_name': 'Table Toys', 'product_code': 'GA460', 'toy_name': 'Balance Bunnies', 'age_range': '4+', 'player_range': '2', 'material': 'wood', 'description': '1 base 35x12x25 cm\n7 bunnies 7 foxes\n1 dice 3 cm'}, {'section_name': 'Table Toys', 'product_code': 'GA462', 'toy_name': 'Color Combination Race', 'age_range': '4+', 'player_range': '2-4', 'material': 'wood, cardboard', 'description': 'base 6,5x6,5x15 cm, rings 5,5x5,5x0,5 mm\ncardholder 6x6x2 cm, cards 5,5x5,5 cm\ncolor cards Ø 15,5 cm - Ø 7 cm'}, {'section_name': 'Table Toys', 'product_code': 'GA465', 'toy_name': 'Plop It', 'age_range': '6+', 'player_range': '2-4', 'material': 'wood, elastic, cardboard', 'description': 'Catch the right balls and plop them in the net!\n* 2 ploppers 8x5 cm\n* 2 net holders Ø 5cm, length 55 cm\n* 6 cards 1,5x2,5 cm, 30 balls Ø 2,5 cm\n* 1 rope 120 cm'}, {'section_name': 'Table Toys', 'product_code': 'GA466', 'toy_name': 'Whack a Shape', 'age_range': '4+', 'player_range': '2-4', 'material': 'wood', 'description': '* base 38,5x15,5 cm\n* 2 stands 36 half balls, 4 hammers\n* 1 dice 2,5 cm\n* 4 cards'}, {'section_name': 'Table Toys', 'product_code': 'GA458', 'toy_name': 'Sling Puck | Table Hockey', 'age_range': '6+', 'player_range': '2', 'material': 'wood', 'description': '* double sides base 39x21x3 cm\n* 10 chips Ø 2,5 cm\n* 2 pushers 4x4x3 cm'}, {'section_name': 'Table Toys', 'product_code': 'GA039', 'toy_name': 'DIY Birdhouse', 'age_range': '3+', 'player_range': '1', 'material': 'wood', 'description': '* house 9x9x13 cm'}, {'section_name': 'Table Toys', 'product_code': 'GA319', 'toy_name': 'Triangle Domino', 'age_range': '6+', 'player_range': '2-4', 'material': 'wood', 'description': '* 35 triangles 10x10 x10 cm'}]
成功! 尽管采用半结构化格式,我们还是从目录中提取了所有152件玩具产品(附录部分有一个额外重复提取的玩具)。LlamaExtract自动检测到分隔每个玩具条目的视觉模式,并将我们的模式应用于每一个条目。
PER_TABLE_ROW 提取目标在从文档中提取重复的结构化实体方面非常强大。关键要点:
-
模式设计:为单个实体定义模式,而非整个文档。系统返回
list[YourSchema]。 -
支持多种格式:不仅限于传统表格——任何包含可区分重复实体(项目符号、编号、标题、视觉分隔等)的文档均可。通用要求是每个实体应在其本地上下文中包含模式所需的全部数据。
-
自动模式识别: LlamaExtract 识别区分实体的格式化模式,并将您的模式应用于每一个实体。