Casos de uso y soluciones

Analizar reseñas de clientes con IA local: sentimiento, aspectos y principales quejas por producto

6 pasos 21 min de lectura 58 vistas 0
Contenido

Los productos acumulan cientos de reseñas en Shopee, Lazada, Amazon, TikTok Shop y su propia tienda, a menudo en varios idiomas. Las estrellas indican que algo va mal, pero no qué. Esta guía usa un modelo de lenguaje local para leer cada reseña y registrar su sentimiento general, los aspectos del producto que elogia o critica y los problemas concretos que menciona. Después, un informe por producto muestra los aspectos más criticados, las reseñas cuya valoración no coincide con el texto y un resumen de IA de los principales problemas con mejoras sugeridas. Todo se ejecuta en su propio servidor, por lo que los textos de los clientes no se envían a terceros.

Recopile reseñas solo de las formas que permita la plataforma, como las exportaciones del centro de vendedores, las API oficiales o la base de datos de su propia tienda. Hacer scraping de los marketplaces puede infringir sus condiciones. Elimine los datos personales que no necesite antes del análisis.

Paso 1: Instalar las herramientas

apt install -y python3-venv
python3 -m venv /opt/reviews
/opt/reviews/bin/pip install ollama numpy scikit-learn
ollama pull qwen2.5:7b

La configuración de Ollama se explica en ejecutar un LLM local con Ollama. numpy y scikit-learn no son necesarios para esta guía, pero los usa el análisis de temas de la guía complementaria.

Paso 2: Preparar las reseñas

Exporte sus reseñas a un archivo CSV en UTF-8. Las columnas id y text son obligatorias; sku, rating (de 1 a 5) y date son opcionales, pero hacen que el informe sea más útil:

id,sku,rating,date,text
R1001,LS-01,2,2026-09-14,"The stand wobbles when I type, screws came loose after a week."
R1002,LS-01,5,2026-09-15,"Sturdy, looks great on my desk, easy to fold."
R1003,BT-07,1,2026-09-15,"左耳机三天就没声音了,客服也没回复。"

Paso 3: Crear el script de análisis

cat > /opt/reviews/reviews.py <<'EOF2'
import csv, json, os, sys
from collections import Counter, defaultdict
import ollama

MODEL = os.environ.get("MODEL", "qwen2.5:7b")
LANGUAGE = os.environ.get("REPORT_LANG", "English")       # language of issues, summaries and the report
ASPECTS = ["quality", "size_fit", "function", "durability", "ease_of_use",
           "delivery", "packaging", "price_value", "customer_service", "other"]
SENT = {"type": "string", "enum": ["positive", "neutral", "negative"]}
SCHEMA = {
    "type": "object",
    "properties": {
        "sentiment": SENT,
        "aspects": {"type": "array", "items": {"type": "object", "properties": {
            "aspect": {"type": "string", "enum": ASPECTS}, "sentiment": SENT}, "required": ["aspect", "sentiment"]}},
        "issues": {"type": "array", "items": {"type": "string"}},
        "summary": {"type": "string"},
    },
    "required": ["sentiment", "aspects", "issues", "summary"],
}
SYSTEM = ("You analyse customer reviews for an online shop. The review can be in any language. "
          "Give the overall sentiment, and the sentiment of each product aspect the review actually mentions. "
          f"List concrete problems as short phrases in {LANGUAGE} (empty list if there are none) "
          f"and write a one-sentence summary in {LANGUAGE}. Do not invent anything that is not in the review.")

def ask(system, text, schema=None):
    r = ollama.chat(model=MODEL, format=schema, options={"temperature": 0}, messages=[
        {"role": "system", "content": system}, {"role": "user", "content": text}])
    return r.message.content

src, out = sys.argv[1], "reviews_tagged.csv"
done = {}
if os.path.exists(out):
    with open(out, encoding="utf-8-sig") as f:
        done = {r["id"]: r for r in csv.DictReader(f)}
with open(src, encoding="utf-8-sig") as f:
    reviews = [r for r in csv.DictReader(f) if r.get("text", "").strip()]

fields = ["id", "sku", "rating", "sentiment", "aspects", "issues", "summary", "text"]
new_file = not os.path.exists(out)
with open(out, "a", newline="", encoding="utf-8-sig") as f:
    w = csv.DictWriter(f, fieldnames=fields)
    if new_file:
        w.writeheader()
    for r in reviews:
        if r["id"] in done:
            continue
        d = json.loads(ask(SYSTEM, r["text"][:4000], SCHEMA))
        row = {"id": r["id"], "sku": r.get("sku", ""), "rating": r.get("rating", ""), "sentiment": d["sentiment"],
               "aspects": "; ".join(f"{a['aspect']}:{a['sentiment']}" for a in d["aspects"]),
               "issues": "; ".join(i.strip() for i in d["issues"] if i.strip()), "summary": d["summary"], "text": r["text"]}
        w.writerow(row)
        f.flush()
        done[r["id"]] = row
        print(r["id"], d["sentiment"], flush=True)

by_sku = defaultdict(list)
for row in done.values():
    by_sku[row["sku"] or "-"].append(row)
with open("report.md", "w", encoding="utf-8") as f:
    for sku, rows in sorted(by_sku.items(), key=lambda x: -len(x[1])):
        sent = Counter(r["sentiment"] for r in rows)
        neg = Counter(a.split(":")[0] for r in rows for a in r["aspects"].split("; ") if a.endswith(":negative"))
        issues = [i for r in rows for i in r["issues"].split("; ") if i]
        odd = [r["id"] for r in rows if r["rating"].isdigit() and ((int(r["rating"]) >= 4 and r["sentiment"] == "negative")
               or (int(r["rating"]) <= 2 and r["sentiment"] == "positive"))]
        f.write(f"## {sku}: {len(rows)} reviews\n\n")
        f.write(f"- Positive {sent['positive']}, neutral {sent['neutral']}, negative {sent['negative']}\n")
        f.write("- Most criticised aspects: " + (", ".join(f"{a} ({n})" for a, n in neg.most_common(5)) or "none") + "\n")
        f.write("- Rating does not match the text: " + (", ".join(odd) or "none") + "\n\n")
        if issues:
            f.write(ask(f"You are a product manager. Group these customer complaints into the main problems, "
                        f"most frequent first, and suggest one concrete fix for each. Answer in {LANGUAGE}, briefly.",
                        "\n".join(issues[:300])) + "\n\n")
        print("report:", sku, flush=True)
print("done: reviews_tagged.csv, report.md")
EOF2

El esquema JSON obliga al modelo a responder con una estructura fija: uno de tres sentimientos, aspectos de su lista y una lista de problemas. Las reseñas procesadas se guardan de inmediato y una segunda ejecución las omite, así que puede detener y reanudar el proceso en cualquier momento, o añadir más adelante reseñas nuevas al mismo CSV.

Paso 4: Ejecutar el análisis

cd /data/reviews
REPORT_LANG="Simplified Chinese" nohup /opt/reviews/bin/python /opt/reviews/reviews.py reviews.csv > reviews.log 2>&1 &
tail -f reviews.log

En un servidor con CPU, un modelo de 7B necesita desde unos segundos hasta varias decenas de segundos por reseña, según su longitud; ejecute las exportaciones grandes durante la noche o use un modelo más pequeño como qwen2.5:3b con MODEL=qwen2.5:3b. Los resultados son reviews_tagged.csv (una fila por reseña) y report.md (una sección por producto).

Paso 5: Interpretar los resultados

  • Los aspectos más criticados muestran dónde decepciona un producto: los problemas de durabilidad, talla y ajuste, entrega o embalaje requieren soluciones distintas y equipos distintos.
  • La valoración no coincide con el texto enumera, por ejemplo, reseñas de cinco estrellas que aun así contienen quejas, a menudo sobre la entrega, y reseñas de una estrella que en realidad son positivas. Conviene revisar ambas.
  • El resumen de IA agrupa las quejas en problemas principales con una mejora sugerida para cada uno; envíelo al equipo de desarrollo de producto o a su proveedor.
  • Filtre reviews_tagged.csv por producto y sentimiento negativo para leer las reseñas originales que hay detrás de cada problema.

Adapte la lista ASPECTS a su categoría, por ejemplo fabric (tejido), size_fit (talla y ajuste) y colour (color) para ropa, o battery (batería), connectivity (conectividad) y sound (sonido) para electrónica.

Paso 6: Convertirlo en una rutina

Exporte las reseñas nuevas cada mes, ejecute el script sobre el mismo archivo y compare los informes a lo largo del tiempo. Para descubrir problemas que no esperaba, agrupe las reseñas por temas como se describe en descubrir de qué hablan los clientes con embeddings. Para responder antes a las reseñas, consulte redactar respuestas a reseñas de clientes con IA. Lo que más elogian los clientes también es un buen material para sus fichas de producto.

Preguntas frecuentes

¿Qué precisión tiene el análisis?

En reseñas claras, el sentimiento y los aspectos son fiables. El sarcasmo, las reseñas mixtas y los textos muy cortos como "ok" son más difíciles. Compare 20 reseñas al azar con los resultados antes de confiar en las cifras y mantenga la temperatura en 0 para obtener respuestas coherentes.

¿Puedo analizar tickets de soporte o chats de la misma forma?

Sí. Ponga cada ticket o conversación en la columna text y sustituya los aspectos por sus categorías de soporte, como facturación, entrega, configuración o cuenta.

¿Puedo usar un modelo de IA en la nube?

Muchas API de IA admiten salida estructurada, pero en ese caso las reseñas salen de su servidor. Compruebe primero sus obligaciones de privacidad, las condiciones del proveedor y las regiones donde ofrece servicio.

¿Sigue sin resolverlo después de seguir estos pasos? Abra un ticket de soporte y el equipo técnico de IMIDC, disponible 24/7, le ayudará. Incluya la IP del servidor, el modelo que usa, las primeras líneas de su CSV sin datos personales y la salida del error para que podamos localizar el problema más rápido.

¿Fue útil la respuesta?

Tutoriales relacionados