循序渐进 · AIP 教学 · 文档智能(四)

把抽取策略部署到 Python 函数

如果需要按需、单次抽取(而不是批量跑),部署成函数更合适。这篇给出操作路径与生成的代码。

全部目录 AIP 首页 ← 上一篇 把抽取策略部署到 Python 函数 下一篇 →
本文来源 · Source 内容整理自 Palantir Foundry 官方文档:
https://www.palantir.com/docs/foundry/document-intelligence/deploy-to-python-functions/
原始标题:AIP Document Intelligence • Deploy extraction strategies to Python functions • Palantir · 所属:AIP Document Intelligence(读懂文档)

先记住这几条

① 适用按需场景
一次处理一份文档,而非批量。
② 用生成的代码起步
官方给出可参考的代码片段。
③ 与 transform 是互补关系
按业务形态选。
0

写在前面

按照 AIP Document Intelligence 中的 Deploy to functions 指南进行操作,并使用生成的代码片段,用你的抽取策略搭建一个 Python functions 仓库。

1

配置

要点:代码与参数设置。

要在 functions 中开始文档抽取,首先创建一个 Python functions 仓库,或使用已有的仓库。

使用正确的导入和权限来设置仓库,以便运行文档抽取:

  1. 安装平台 SDK(如果尚未安装):
  • 在左侧面板中选择 Libraries添加一个库
  • 安装 foundry-platform-sdk 版本 >= 1.78。
  • 如果你需要分块(chunking),安装 aip-workflows 版本 >= 0.40.0。
  • 如果你想做嵌入(embedding),安装 openai
  1. 对于基于 LLM 的抽取,将你选择的模型导入到仓库中。
  2. 将该 function 设置为具有更长的超时时间。我们建议选择你的注册所允许的最大值。要处理大量 PDF 以及页数很多的 PDF,你需要将这些 functions 作为抽取策略的一部分来使用。

以下各节解释了 Deploy to functions 指南中包含的各种代码片段。

2

辅助函数

要点:官方提供的工具函数。

辅助函数对所有抽取策略都相同。你可以将它们复制到与你的 function 相同的 Python 文件中,如果你有多个 function,也可以复制到一个共享的工具文件中。它们在平台内可用,下面也一并列出以供参考。

from dataclasses import dataclass
from time import sleep
from typing import Optional

from foundry_sdk import FoundryClient
from foundry_sdk._errors import PalantirException, PalantirQoSException, PalantirRPCException
from foundry_sdk._errors.palantir_qos_exception import QoSRetryHint
from foundry_sdk.v2.media_sets import models
from functions.api import function


@dataclass
class TransformResult:
    """The outcome of a transform. Functions return this instead of raising on failure so your
    orchestration can branch on the result.

    result: The extracted content (Markdown or JSON, depending on your configuration) on success,
        otherwise None.
    error: The specific error name on failure (or a human-readable reason for rate-limit and
        availability errors), otherwise None.
    retryable: True when the failure is transient (rate limits or service availability) and worth
        retrying, False when it is not, and None on success.
    """

    result: Optional[str]
    error: Optional[str]
    retryable: Optional[bool]


def _create_transform_job(
    media_set_rid: str, media_item_rid: str, transformation: models.DocumentToTextTransformation
) -> str:
    fc = FoundryClient()
    job_initiation_resp = fc.media_sets.MediaSet.transform(
        media_set_rid=media_set_rid,
        media_item_rid=media_item_rid,
        transformation=transformation,
        preview=True,
    )
    job_id = job_initiation_resp.job_id
    return job_id


def _is_transform_finished(media_set_rid: str, media_item_rid: str, job_id: str) -> bool:
    fc = FoundryClient()
    status = fc.media_sets.MediaSet.get_status(media_set_rid, media_item_rid, job_id, preview=True)
    return status.status in ("SUCCESSFUL", "FAILED")


def _get_transform_result(media_set_rid: str, media_item_rid: str, job_id: str) -> str:
    fc = FoundryClient()
    result = fc.media_sets.MediaSet.get_result(media_set_rid, media_item_rid, job_id, preview=True)
    return result.decode("utf-8")


def _run_transform_blocking(
    media_set_rid: str, media_item_rid: str, transformation: models.DocumentToTextTransformation
) -> str:
    job_id = _create_transform_job(media_set_rid, media_item_rid, transformation)
    while not _is_transform_finished(media_set_rid, media_item_rid, job_id):
        sleep(0.5)
    return _get_transform_result(media_set_rid, media_item_rid, job_id)


def _run_transform_error_handled(
    media_set_rid: str, media_item_rid: str, transformation: models.DocumentToTextTransformation
) -> TransformResult:
    try:
        result_text = _run_transform_blocking(media_set_rid, media_item_rid, transformation)
        return TransformResult(result=result_text, error=None, retryable=None)
    except PalantirQoSException as e:
        retryable = e.retry_hint != QoSRetryHint.DO_NOT_RETRY
        return TransformResult(result=None, error=e.reason, retryable=retryable)
    except PalantirRPCException as e:
        return TransformResult(result=None, error=e.name or type(e).__name__, retryable=False)
    except PalantirException as e:
        return TransformResult(result=None, error=type(e).__name__, retryable=False)
3

你的抽取策略

要点:核心逻辑怎么写。

此 function 对应你的抽取策略,需要一个媒体输入以及给定的页面。由于该 function 是动态生成的,请从应用内复制代码。你以任何名称发布它都会按该名称注册,因此你可以按需重命名。你可以将媒体输入以「媒体集 RID + 媒体项 RID 字符串」组合的形式提供,也可以作为对象属性提供;使用左上角的选择器来选择模板。对象属性模板要求你导入你的对象

AIP Document Intelligence 应用中展示的已部署 Python function 代码。
AIP Document Intelligence 应用中展示的已部署 Python function 代码。
4

分块与嵌入函数

要点:为下游检索做准备的环节。

你可以选择性地对抽取出的文本进行分块并生成嵌入,以供搜索或检索工作流的下游使用。下面的 functions 是静态的;分块大小、分块重叠量和嵌入模型在应用中配置,因此请将默认参数值替换为你所选的值。

from functions.api import function, Array, Boolean, Float, Integer, String
from aip_workflows.document_intelligence.transforms import DocumentChunker

@function(beta=True)
def chunk_text(
    texts: Array[String],
    chunk_size: Integer = 8192,
    chunk_overlap: Integer = 0,
    concat_before_chunk: Boolean = False,
    chunk_mode: String = "markdown",
) -> Array[Array[String]]:
    """
    Chunks a list of text strings.
    Args:
        texts: A list of text strings to chunk.
        chunk_size: Maximum number of characters per chunk.
        chunk_overlap: Number of overlapping characters between consecutive chunks.
        concat_before_chunk: If True, concatenates all texts into a single string before chunking,
            returning a single inner list. Recommended when input is per-page text of a document.
            If False, chunks each text independently, returning one inner list per input text.
        chunk_mode: The chunking strategy to use. Options:
            - "markdown": Recommended for Markdown text.
            - "recursive": Recommended for raw text without any format.
    Returns:
        A list of lists of chunk strings. Each inner list contains the chunks for one input text.
        When concat_before_chunk is True, input texts are concatenated into a single string so the
        output list has length of 1.
    """
    chunks = DocumentChunker.create_chunks(
        texts,
        chunk_mode=chunk_mode,
        chunk_size=chunk_size,
        chunk_overlap=chunk_overlap,
        strip_markdown=True,
        concat_before_chunk=concat_before_chunk,
    )
    if concat_before_chunk:
        return [chunks]
    return chunks

from foundry_sdk.v2.language_models.utils import (
    get_foundry_token,
    get_openai_base_url,
    get_http_client,
)
from openai import OpenAI

@function(beta=True)
def embed_text(
    texts: Array[String],
    embedding_model_rid: String = "<YOUR_EMBEDDING_MODEL_RID>",
) -> Array[Array[Float]]:
    """
    Generates embeddings for a list of text strings using the configured embedding model.
    Args:
        texts: A list of text strings to embed.
        embedding_model_rid: The RID of the embedding model to use.
    Returns:
        A list of vector embeddings, one per input text.
    """
    client = OpenAI(
        api_key=get_foundry_token(preview=True),
        base_url=get_openai_base_url(preview=True),
        http_client=get_http_client(preview=True),
    )

    response = client.embeddings.create(
        input=texts,
        model=embedding_model_rid,
    )

    return [response.data[i].embedding for i in range(len(texts))]

延伸阅读 · 相关页面

按主题横向跳转,不必顺着目录一篇篇读。

本组其他页面 · AIP Document Intelligence(读懂文档)

同一主题下的相邻内容。

常见问题速答 · FAQ

关于「把抽取策略部署到 Python 函数」,读者最常问的几个问题。

如何配置?
代码与参数设置。要在 functions 中开始文档抽取,首先创建一个 Python functions 仓库,或使用已有的仓库。
辅助函数是什么?
官方提供的工具函数。辅助函数对所有抽取策略都相同。你可以将它们复制到与你的 function 相同的 Python 文件中,如果你有多个 function,也可以复制到一个共享的工具文件中。它们在平台内可用,下面也一并列出以供参考。
你的抽取策略是什么?
核心逻辑怎么写。此 function 对应你的抽取策略,需要一个媒体输入以及给定的页面。由于该 function 是动态生成的,请从应用内复制代码。你以任何名称发布它都会按该名称注册,因此你可以按需重命名。
分块与嵌入函数是什么?
为下游检索做准备的环节。你可以选择性地对抽取出的文本进行分块并生成嵌入,以供搜索或检索工作流的下游使用。下面的 functions 是静态的;分块大小、分块重叠量和嵌入模型在应用中配置,因此请将默认参数值替换为你所选的值。