Новости ChatGPT

Как я создала ИИ-агента для анализа отзывов, потому что мне было лень читать 200+ строк в гугл таблице

Или история о том, как лень двигатель прогресса.

Когда мне на курсе дали домашку проанализировать больше 200 отзывов о кофейне "Great Grounds", я поняла одно: читать это всё вручную я точно не буду.

У меня был выбор: потратить несколько часов на монотонное чтение однотипных "кофе супер" и "цены кусаются", загрузить это в NotebookLM (что я сделала в последствии, для сравнения результатов) или потратить время на что-то интересное. Например, создать своего мини ИИ-помощника, который сделает это за меня. Спойлер: я выбрала второй вариант, и вот что из этого вышло.

Моя уровень:

Давайте сразу расставим точки над i : я не программист. Поэтому это будет история про вайб кодинг.

Поехали!

У меня был пример кода с интенсива по ИИ-агентам, базовая болванка, как создать агента с помощью Google ADK. Но он был для других задач, а мне нужно было адаптировать его под мои отзывы в таблице.

Поэтому я составила промпт из скриншота, чтобы было видно название таблицы, колонок и примеры данных, вставила код с курса, и дала задание Вот пример кода агента, вот моя таблица (скрин), адаптируй код, чтобы он анализировал отзывы"

И знаете что? Сработало. Claude посмотрел на структуру моих данных (колонки: Mention, Sentiment, Gender, Region), взял базовый код агента и переделал его под мою задачу. Рабочий вариант кода я получила спустя 6 итераций и 20 мин. Все лучше чем читать кучу отзывов.

Разбираем код: что там вообще происходит

!pip install -q google-generativeai google-adk gspread google-auth pandas

import gspread
from google.colab import auth, userdata
from google.auth import default
from google.genai import types
from google.adk.agents import LlmAgent
from google.adk.models.google_llm import Gemini
from google.adk.runners import InMemoryRunner
import pandas as pd
import google.generativeai as genai
import os

print("✅ Imports done")

# AUTH
auth.authenticate_user()
creds, _ = default()

try:
GOOGLE_API_KEY = userdata.get('GOOGLE_API_KEY')
except:
GOOGLE_API_KEY = input("Paste API key: ")

os.environ['GOOGLE_API_KEY'] = GOOGLE_API_KEY
genai.configure(api_key=GOOGLE_API_KEY)
print("✅ Auth done")

# CONNECT TO SHEETS
gc = gspread.authorize(creds)
SPREADSHEET_NAME = "Great Grounds social listening data"

try:
sheet = gc.open(SPREADSHEET_NAME).sheet1
except:
SPREADSHEET_URL = input("Paste Google Sheets URL: ")
sheet = gc.open_by_url(SPREADSHEET_URL).sheet1

print("✅ Sheet connected")

# DATA FUNCTION
def get_sheet_data():
data = sheet.get_all_records()
return pd.DataFrame(data)

# ANALYSIS TOOL
def analyze_social_listening_data(query_type: str) -> dict:
"""Get data from Great Grounds social listening.

query_type options:
- positive_mentions
- negative_mentions
- sentiment_summary
- sentiment_by_gender
- sentiment_by_region
"""
try:
df = get_sheet_data()
result = {"status": "success"}

if query_type == "positive_mentions":
positive_df = df[df['Sentiment'].str.lower() == 'positive']
mentions = []
for _, row in positive_df.iterrows():
mentions.append({
"mention": row['Mention'],
"gender": row['Gender'],
"region": row['Region']
})
result["data"] = mentions
result["count"] = len(mentions)

elif query_type == "negative_mentions":
negative_df = df[df['Sentiment'].str.lower() == 'negative']
mentions = []
for _, row in negative_df.iterrows():
mentions.append({
"mention": row['Mention'],
"gender": row['Gender'],
"region": row['Region']
})
result["data"] = mentions
result["count"] = len(mentions)

elif query_type == "sentiment_summary":
counts = df['Sentiment'].value_counts().to_dict()
total = len(df)
percentages = {k: f"{(v/total)*100:.1f}%" for k, v in counts.items()}
result["data"] = counts
result["percentages"] = percentages

elif query_type == "sentiment_by_gender":
grouped = df.groupby(['Gender', 'Sentiment']).size().unstack(fill_value=0)
result["data"] = grouped.to_dict()

elif query_type == "sentiment_by_region":
grouped = df.groupby(['Region', 'Sentiment']).size().unstack(fill_value=0)
result["data"] = grouped.to_dict()

return result
except Exception as e:
return {"status": "error", "error_message": str(e)}

print("✅ Tool created")

# CREATE AGENT
retry_config = types.HttpRetryOptions(
attempts=5,
exp_base=7,
initial_delay=1,
http_status_codes=[429, 500, 503, 504]
)

agent = LlmAgent(
name="analyst",
model=Gemini(
model="gemini-2.5-flash-lite",
api_key=GOOGLE_API_KEY,
retry_options=retry_config
),
description="Social media analyst",
instruction="""You analyze Great Grounds social listening data.

Use analyze_social_listening_data(query_type) with:
- "positive_mentions" for positive feedback
- "negative_mentions" for negative feedback
- "sentiment_summary" for overall sentiment

Analyze mentions and identify trends and patterns.""",
tools=[analyze_social_listening_data],
)

runner = InMemoryRunner(agent=agent)
print("✅ Agent ready")

# CLEAN QUESTION FUNCTION - NO DEBUG OUTPUT
async def ask(question):
"""Ask a question with clean output only."""
print("\n" + "="*70)
print(f"❓ QUESTION: {question}")
print("="*70)
print("\n? Analyzing...\n")

response = await runner.run_debug(question)

# Extract and print only the final answer
print("? ANSWER:")
print("="*70)

for msg in response:
if hasattr(msg, 'content') and hasattr(msg.content, 'parts'):
for part in msg.content.parts:
if hasattr(part, 'text') and part.text:
print(part.text)

print("="*70 + "\n")

print("\n" + "="*70)
print("? YOUR AI AGENT IS READY!")
print("="*70)
print("\nUse: await ask('your question here')")
print("\nExamples:")
print(" await ask('What do people like most?')")
print(" await ask('What are the main complaints?')")
print(" await ask('How does sentiment vary by region?')")
print("="*70 + "\n")

# EXAMPLE QUESTIONS - Uncomment to run
# await ask("What do people like most about Great Grounds?")
# await ask("What are the main complaints from customers?")
# await ask("How does sentiment differ between male and female customers?")
Объяснить код с

Как это работает на практике

Я просто пишу: await ask("balbalabalab?")

И агент выдает нужный мне ответ:

Вместо того, чтобы читать 200 отзывов, я получаю выжимку за 10 секунд.

Но это не идеальный результат так как, ИИ-агенты могут галлюцинировать, особенно когда дело касается цифр и расчётов. Например, если агент видит в данных, что позитивных отзывов 127, а негативных 89, и ему нужно посчитать процент, он может просто выдумать цифру. Тип "ну, примерно 60%", хотя на самом деле это 58.8% или вообще другое число.

Чтобы этого избежать, в примере с интенсива агенту давали дополнительные инструменты, например, калькулятор. Это буквально простая функция на Python, которая умеет складывать, вычитать, умножать и делить. Звучит смешно, да? Но когда агенту нужно что-то посчитать, он вызывает эту функцию вместо того, чтобы галлюцинировать ответ.

Ещё можно было добавить инструмент для работы с датами, для поиска по тексту, для сортировки, и тд. Чем больше инструментов, тем меньше агент полагается на галлюцинации и больше на реальные вычисления.

Но мне было лень. Серьёзно. Я подумала: "У меня там простые данные,и простое задание, не квантовая физика, пройдёт и так".

Но удобнее всего для меня это NotebookLM.

Загружаем туда нашу таблицу.

И задаем вопросы по нашим данным в таблице.


И получаем готовый удобный отчет.

И если нужно, что-то посчитать, то и тут без проблем.

Поэтому пока я буду использовать уже готовые решения, как блокнот от гугла, и изучать питон.