LLM is all you need – Telegram
Решил тут разобраться в великом множестве локальных UI-клиентов для LLM.
Поставил себе 10 штук и опробовал их.
Результатом проб стала статься на Хабре: Краткий обзор 10 локальных UI для LLM
10🔥8👏2🤝1
Когда LLM печатает текст она делает это последовательно - токен за токеном. И на каждом шаге модель считает вероятность появления следующего токена (среди всех токенов в словаре).

Используя эти вероятности можно посчитать "уверенность" модели в ответе. Через OpenAI API это делается так...

Сначала получаем ответ:
import os
import numpy as np
from openai import OpenAI

client = OpenAI(
base_url='http://192.168.0.108:8000/v1',
api_key='any'
)

prompt = 'Самая вкусная рыба? Одним предложением.'

response = client.chat.completions.create(
model = '/Qwen3-14B',
messages = [
{'role': 'user', 'content': prompt}
],
logprobs = True, # Запрашиваем логиты
top_logprobs = 5, # Запрашиваем топ-5 наиболее вероятных токенов для каждого шага
temperature = 0.9,
max_tokens = 500,
extra_body = {'chat_template_kwargs': {'enable_thinking': False}}
)

content = response.choices[0].message.reasoning_content
print(content)

При этом обязательно ставим параметр logprobs = True.
З.Ы. А с помощью top_logprobs можно получить вероятности и других топовых токенов для каждой позиции.

Затем проходимся по токенам и собираем вероятности:
logprobs_content = response.choices[0].logprobs.content

tokens = []
probs = []

for l in response.choices[0].logprobs.content:
tokens.append(l.token)
probs.append(np.exp(l.logprob)*100)

print('Средняя вероятность:', np.mean(probs))

Помимо средней можно посчитать и другие статистики (мин/макс, медиану и т.д.).

А красиво вывести их можно так:
import seaborn as sns
import matplotlib.pyplot as plt

plt.figure(figsize=(7,6))
ax = sns.barplot(x=probs, y=tokens)
ax.set_noscript("Уверенность модели в токенах", fontsize=10)
ax.set_xlabel("Вероятность", fontsize=10)
ax.set_ylabel("Токены", fontsize=10)
plt.xticks(fontsize=8)
plt.yticks(fontsize=8);


Метод довольно топорный и имеет очевидные минусы. Например:
- Чем длиннее текст тем более шумной будет средняя оценка.
- Всякие предлоги и знаки препинания также учитываются в общей массе.
👍91
logit_bias это параметр генерации, который позволяет контролировать какие токены и с какой вероятностью должна печатать модель.

Как он работает...

Рассмотрим такой запрос: Столица Франции? Одним словом.. Скорее всего мы получим ответ: Париж.
Но мы хотим "услышать" от модели что-то другое.

Сначала выясним из каких токенов состоит слово Париж.
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained('/models/qwen/Qwen3-14B')
token_ids = tokenizer.encode('Париж')
token_text = [tokenizer.decode([token_id]) for token_id in token_ids]
print("ID токенов:", token_ids) # [16854, 125947, 16964]
print("Текст токенов:", token_text) # ['П', 'ари', 'ж']


Итак, за букву П отвечает токен 16854. Занулим его:
from openai import OpenAI

client = OpenAI(
base_url='http://192.168.0.108:8000/v1',
api_key='any'
)

prompt = 'Столица Франции? Одним словом.'

response = client.chat.completions.create(
model = '/Qwen3-14B',
messages = [
{'role': 'user', 'content': prompt}
],
temperature = 0.9,
max_tokens = 500,
logit_bias = {16854:-100}, # Выкручиваем вероятность появления токена в 0
extra_body = {'chat_template_kwargs': {'enable_thinking': False}}
)

content = response.choices[0].message.reasoning_content
print(content)


После этого модель не сможеть начать текст с буквы "П" (да и вообще ее напечатать) и мы сможем увидеть в ответе что-то вроде "Ницца", "Версаль" и много чего еще :)

Измеряется logit_bias от -100 до 100. При -100 вероятность появления токена около нулевая, а при 100 модель только его и будет печатать :)
В logit_bias можно передать сразу несколько токенов: {16854:-100, 125947:-100, 16964:-100}
👍7🤔5
#RAG

Мне нравится рассматривать RAG как воронку продаж.

Воронка продаж — это маркетинговая модель, которая описывает путь потенциального клиента от первого контакта с продуктом до совершения покупки.


Почему именно воронка? Потому что RAG "сужается" по мере своего продвижения словно воронка продаж. Рассмотрим на примере...

Допустим у нас есть 100 тестовых вопросов, которые мы пропускаем через RAG:
1. На первом шаге ретривер возвращает 300 чанков (на каждый вопрос). Но, т.к. ретривер у нас не идеальный, он вернет правильные чанки только для 90 вопросов из 100.
2. Дальше в дело вступает реранкер. Он переранжирует 300 чанков и передает дальше только 15 из них. Реранкер у нас тоже не идеальный и из 90 вопросов правильные чанки останутся только для 80.
3. Чанки поступают на обработку в LLM. Ну и конечно же LLM тоже может глючить. Из 80 вопросов она правильно отвечает только на 70.

В итоге имеем классическую воронку продаж:
100 -> 90 -> 80 -> 70

Какой из этого можно сделать вывод:
- Какой бы умной не была LLM, она ничего не сможет ответить если ретривер не передаст ей правильные чанки. Поэтому нельзя улучшить RAG-систему улучшая только одну ее чаcть.
- Тестировать нужно каждую часть RAG-пайплайна по отдельности.

Здесь мы рассмотрели не самый сложный пайплайн RAG'а. На практике он может состоять как из меньшего, так и из большего числа шагов и компонентов.
👍8
Решил я тут на выходных прокачаться в говновайб-кодинге :) Результатом стала статья на Хабре, в которой я кратко рассмотрел ряд инструментов AI-кодина:
50 оттенков вайб-кодинга
👍21🔥1🫡1
Написал на Хабре статью: Пример реализации агентного RAG'а

В ней разобрал как с помощью marker'а, Qwen3-14B, MCP-сервера, энкодера FRIDA и библиотеки Agno создать несложный агентный RAG.

З.Ы. Агентный RAG это такая система, которая может: анализировать сложные запросы, составлять план действий и вызвать внешние инструменты. И все это для выполнения поставленной задачи.
5👍4🔥3
Написал на Хабре статью, в которой описал какими способами можно добиться от LLM вывода в строго заданном формате (Structured Output):
https://habr.com/ru/articles/978534/
🔥1