Skip to content

#2093 LLM text extractor: keep page markers out of the prompt and clean the reply - #2181

Open
rzo1 wants to merge 1 commit into
apache:mainfrom
rzo1:fix-2093-llm-extractor
Open

rzo1 wants to merge 1 commit into
apache:mainfrom
rzo1:fix-2093-llm-extractor

Conversation

@rzo1

@rzo1 rzo1 commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

Fixes #2093.

Marker tokens of the form <|NAME|> found in the prompt template are now removed from the page HTML before it is substituted, and {REQUEST} is filled in before {HTML}. The reply is reduced to the content of its <content> envelope (or the whole reply if there is none), markup is removed, and the new textextractor.llm.text.maxlength (default -1) caps the length. The default prompt no longer tells the model to ignore its guidelines when a user instruction is present.

…nd clean the reply

replacePlaceholders() substituted the page HTML into the template with a
plain String.replace. Jsoup writes script and style contents and comments
out verbatim, so a page could carry the template's own marker lines, such
as <|HTML_CONTENT_END|>, and open its own instruction section. The marker
tokens of the form <|NAME|> found in the configured template are now
removed from the HTML before it is substituted, which also covers custom
templates. {REQUEST} is substituted before {HTML}, so a page containing
{REQUEST} no longer pulls in the configured request.

text() returned the reply as it came. It now takes the content of the
<content> envelope the default prompt asks for, or the whole reply if
there is none, keeps only its text nodes so that no markup is returned,
and truncates it to textextractor.llm.text.maxlength (default -1, no
limit).

The default prompt no longer tells the model to ignore its guidelines
when a user instruction is present. An operator who wants that can say so
in textextractor.llm.user_request or a custom template.
@rzo1
rzo1 requested review from dpol1 and jnioche September 23, 2026 17:35

@dpol1 dpol1 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One on the config key and two on the reply cleaning, inline.

public static final String USER_PROMPT = "textextractor.llm.prompt";
public static final String USER_REQUEST = "textextractor.llm.user_request";
public static final String LISTENER_CLASS = "textextractor.llm.listener.clazz";
public static final String TEXT_MAX_LENGTH = "textextractor.llm.text.maxlength";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we already have textextractor.skip.after on TextExtractor for this, can we reuse it? the README line saying it's unsupported here can then go

}

/** keeps the text nodes of the input and their line breaks, dropping elements and comments */
private static String stripMarkup(String text) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this eats the code blocks the prompt asks for: List<String> comes back as List, x<y and y>z as xz. strip only outside the ``` fences, or keep the envelope and skip the stripping?

return sb.toString();
}

private String removeMarkers(String html) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wouldn't html.replace("<|", "< |") do the same in one pass, whatever the template? no marker set, no loop, and nested markers stay linear

@rzo1

rzo1 commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

@dpol1 Feel free to directly push to this branch ;-)

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AbstractLLMTextExtractor pastes page HTML into the prompt unescaped and returns the reply unchecked

2 participants