Skip to content

LLM-based tagging services - #351

Open
lmrodriguezr wants to merge 3 commits into
mainfrom
feature/name-tag-llm
Open

lmrodriguezr wants to merge 3 commits into
mainfrom
feature/name-tag-llm

Conversation

@lmrodriguezr

@lmrodriguezr lmrodriguezr commented Oct 26, 2026 •

Copy link
Copy Markdown
Member

A backend-only (rake task) system to propose tags via Anthropic API, as well as a front-end system for curators to review LLM-based tag proposals

@lmrodriguezr
lmrodriguezr requested a review from vangberg October 26, 2026 18:01

@vangberg vangberg left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice!

  1. I think it would be nice to generate the list of allowed tags by storing their description in the database.
  2. Using structured outputs from Claude, the code can be simplified a lot. See individual comments.
  3. When we have a good number of human-approved tags, we should add an eval, that scores the suggestions against the human-approved tags. That would make it easy to evaluate different models/see if prompt changes improve accuracy.

## Tag definitions

### Umbrella tags (assign the umbrella whenever you assign a sub-tag)
- geographic: name references a place or environment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We could add description to Tag and generate this list automatically.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I missed that tags already have their descriptions in the database, because it was a rich text association. Then I guess we should generate it automatically ;)

Rank: #{name.rank}
Etymology: #{etym}

## Required response format

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

With structured outputs you can force Claude to conform to a given schema.

end

def parse_response(body)
# The text may not be the first content block (e.g., after thinking)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

See previous comment about structured outputs. Then you get a guaranteed JSON response with specified format.

end

def filter_proposals(proposals)
proposals.select { |p| valid_slugs.include?(p['slug']) }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Setting slug to an enum structured output ensures that Claude only returns allowed tags:

"slug": {
  "type": "string",
  "enum": ["eponym", "geography", "person", "other", …]
}

@vangberg

Copy link
Copy Markdown
Contributor

I think this could be a great fit for Jev. When we have some real data to evaluate against, I will give that a try :)

@lmrodriguezr

Copy link
Copy Markdown
Member Author

I think this could be a great fit for Jev. When we have some real data to evaluate against, I will give that a try :)

That sounds great! Yes!

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.

2 participants