1np0rx9 R4b1utpfk00q9kw.png

He creado métricas personalizadas con mayor frecuencia para mis propios casos de uso, pero me encontré con estas métricas integradas para herramientas de IA en LangChain repetidamente antes de comenzar a usar RAGAS y/o DeepEval para la evaluación de RAG, así que finalmente sentí curiosidad por saber cómo Estas métricas se crean y ejecutan un análisis rápido (con todos los sesgos inherentes, por supuesto).

TLDR proviene de la siguiente matriz de correlación:

  • Utilidad y Coherencia (correlación 0,46): Esta fuerte correlación sugiere que el LLM (y, por delegación, los usuarios) podrían encontrar respuestas coherentes más útiles, enfatizando la importancia de la estructuración lógica en las respuestas. Es sólo una correlación, pero esta relación abre la posibilidad de esta conclusión.
  • Controversialidad y Criminalidad (correlación 0,44): Esto indica que incluso el contenido controvertido podría considerarse delictivo, y viceversa, reflejando quizás la preferencia del usuario por material atractivo y que haga reflexionar.
  • Coherencia versus profundidad: A pesar de que la coherencia se correlaciona con la utilidad, la profundidad no. Esto podría sugerir que los usuarios (nuevamente, asumiendo que las preferencias de los usuarios son inherentes al resultado del LLM; esto por sí solo es una presunción y un sesgo que es importante tener en cuenta) podrían preferir respuestas claras y concisas a las detalladas, particularmente en contextos donde Se valoran las soluciones rápidas frente a las integrales.

Las métricas integradas se encuentran aquí (eliminando una que se relaciona con la verdad básica y se maneja mejor en otros lugares):

# Listing Criteria / LangChain's built-in metrics
from langchain.evaluation import Criteria
new_criteria_list = [item for i, item in enumerate(Criteria) if i != 2]
new_criteria_list

Las métricas:

  • Concisión
  • Detalle
  • Relevancia
  • Coherencia
  • Nocividad
  • Insensibilidad
  • Utilidad
  • Controversialidad
  • Criminalidad
  • Profundidad
  • Creatividad

Primero, ¿qué significan y por qué fueron creados?

La hipótesis:

  • Estos se crearon en un intento de definir métricas que pudieran explicar el resultado en relación con los objetivos teóricos de los casos de uso, y cualquier correlación podría ser accidental, pero generalmente se evitó siempre que fue posible.

Tengo esta hipótesis después de ver este código fuente aquí.

En segundo lugar, algunos de ellos parecen similares y/o vagos; entonces, ¿en qué se diferencian?

Utilicé un conjunto de datos SQuAD estándar como base para evaluar las diferencias (si las hubiera) entre la salida del modelo GPT-3-Turbo de OpenAI y la verdad fundamental en este conjunto de datos, y comparar.

# Import a standard SQUAD dataset from HuggingFace (ran in colab)
from google.colab import userdata
HF_TOKEN = userdata.get('HF_TOKEN')

dataset = load_dataset("rajpurkar/squad")
print(type(dataset))

Obtuve un conjunto aleatorio de filas para evaluación (no podía permitirme el lujo de calcular el tiempo y todo), por lo que este podría ser un punto de entrada para más ruido y/o sesgo.

# Slice dataset to randomized selection of 100 rows
validation_data = dataset['validation']
validation_df = validation_data.to_pandas()
sample_df = validation_df.sample(n=100, replace=False)

Definí una película usando ChatGPT 3.5 Turbo (para ahorrar costos aquí, esto es rápido).

import os

# Import OAI API key
OPENAI_API_KEY = userdata.get('OPENAI_API_KEY')
os.environ['OPENAI_API_KEY'] = userdata.get('OPENAI_API_KEY')
# Define llm
llm = ChatOpenAI(model_name='gpt-3.5-turbo', openai_api_key=OPENAI_API_KEY)

Luego, recorrió las filas muestreadas para realizar una comparación: había umbrales desconocidos que LangChain usó para la «puntuación» en los criterios de evaluación, pero se supone que están definidos de la misma manera para todas las métricas.

# Loop through each question in random sample
for index, row in sample_df.iterrows():
try:
prediction = " ".join(row['answers']['text'])
input_text = row['question']

# Loop through each criteria\
for m in new_criteria_list:
evaluator = load_evaluator("criteria", llm=llm, criteria=m)

eval_result = evaluator.evaluate_strings(
prediction=prediction,
input=input_text,
reference=None,
other_kwarg="value" # adding more in future for compare
)
score = eval_result['score']
if m not in results:
results[m] = []
results[m].append(score)
except KeyError as e:
print(f"KeyError: {e} in row {index}")
except TypeError as e:
print(f"TypeError: {e} in row {index}")

Luego calculé las medias y el IC con intervalos de confianza del 95%.

# Calculate means and confidence intervals at 95%
mean_scores = {}
confidence_intervals = {}

for m, scores in results.items():
mean_score = np.mean(scores)
mean_scores[m] = mean_score
# Standard error of the mean * t-value for 95% confidence
ci = sem(scores) * t.ppf((1 + 0.95) / 2., len(scores)-1)
confidence_intervals[m] = (mean_score - ci, mean_score + ci)

Y trazó los resultados.

# Plotting results by metric
fig, ax = plt.subplots()
m_labels = list(mean_scores.keys())
means = list(mean_scores.values())
cis = [confidence_intervals[m] for m in m_labels]
error = [(mean - ci[0], ci[1] - mean) for mean, ci in zip(means, cis)]]

ax.bar(m_labels, means, yerr=np.array(error).T, capsize=5, color='lightblue', label='Mean Scores with 95% CI')
ax.set_xlabel('Criteria')
ax.set_ylabel('Average Score')
ax.set_title('Evaluation Scores by Criteria')
plt.xticks(rotation=90)
plt.legend()
plt.show()

Posiblemente sea intuitivo que la ‘Relevancia’ sea mucho más alta que las demás, pero es interesante que en general sean tan bajas (¡quizás gracias a GPT 3.5!), y que la ‘Ayuda’ sea la siguiente métrica más alta (posiblemente reflejando técnicas y optimizaciones de RL) .

Para responder a mi pregunta sobre la correlación, calculé una matriz de correlación simple con el marco de datos de comparación sin procesar.

# Convert results to dataframe
min_length = min(len(v) for v in results.values())
dfdata = {k.name: v[:min_length] for k, v in results.items()}
df = pd.DataFrame(dfdata)

# Filtering out null values
filtered_df = df.drop(columns=[col for col in df.columns if 'MALICIOUSNESS' in col or 'MISOGYNY' in col])

# Create corr matrix
correlation_matrix = filtered_df.corr()

Luego graficó los resultados (los valores p se crean más abajo en mi código y todos estaban por debajo de .05)

# Plot corr matrix
mask = np.triu(np.ones_like(correlation_matrix, dtype=bool))
plt.figure(figsize=(10, 8))
sns.heatmap(correlation_matrix, mask=mask, annot=True, fmt=".2f", cmap='coolwarm',
cbar_kws={"shrink": .8})
plt.title('Correlation Matrix - Built-in Metrics from LangChain')
plt.xticks(rotation=90)
plt.yticks(rotation=0)
plt.show()

Fue sorprendente que la mayoría no se correlacione, dada la naturaleza de las descripciones en el código base de LangChain; esto da como resultado algo un poco más pensado y me alegro de que estén integradas para su uso.

De la matriz de correlaciones surgen relaciones notables:

  • Utilidad y Coherencia (correlación 0,46): Esta fuerte correlación sugiere que el LLM (ya que es un sustituto para los usuarios) podría encontrar respuestas coherentes más útiles, enfatizando la importancia de la estructuración lógica en las respuestas. Aunque se trata de una correlación, esta relación allana el camino para ello.
  • Controversialidad y Criminalidad (correlación 0,44): Esto indica que incluso el contenido controvertido podría considerarse delictivo, y viceversa, reflejando quizás la preferencia del usuario por material atractivo y que invite a la reflexión. Una vez más, esto es sólo una correlación.

Conclusiones:

  1. Coherencia versus profundidad en la utilidad: A pesar de que la coherencia se correlaciona con la utilidad, la profundidad no. Esto podría sugerir que los usuarios podrían preferir respuestas claras y concisas a las detalladas, particularmente en contextos donde se valoran las soluciones rápidas a las integrales.
  2. Aprovechando la controversia: La correlación positiva entre controversia y criminalidad plantea una pregunta interesante: ¿se pueden discutir temas controvertidos de una manera que no sea criminal? Potencialmente, esto podría aumentar la participación de los usuarios sin comprometer la calidad del contenido.
  3. Impacto del sesgo y elección del modelo: El uso de GPT-3.5 Turbo y los sesgos inherentes al diseño métrico podrían influir en estas correlaciones. Reconocer estos sesgos es esencial para una interpretación y aplicación precisas de estas métricas.

A menos que se indique lo contrario, todas las imágenes de este artículo fueron creadas por el autor.