def analyze_sentiment(review: str, _: dict) -> dict:
response = client.messages.create(
model="claude-haiku-4-5", # простая задача — дешёвая модель
max_tokens=128,
system="Отвечай только JSON. Без пояснений.",
messages=[{
"role": "user",
"content": f"""Определи тональность отзыва.
JSON: {{"sentiment": "positive|negative|neutral", "score": 1-10, "is_urgent": true|false}}
Отзыв: {review}"""
}]
)
import json, re
text = re.sub(r'```(?:json)?|```', '', response.content[0].text).strip()
return json.loads(text)
def extract_issues(review: str, context: dict) -> list[str]:
sentiment = context.get("analyze_sentiment", {})
# Пропускаем если позитивный отзыв
if sentiment.get("sentiment") == "positive":
return []
response = client.messages.create(
model="claude-haiku-4-5",
max_tokens=256,
messages=[{
"role": "user",
"content": f"""Извлеки конкретные проблемы из отзыва.
Отвечай JSON-массивом строк: ["проблема 1", "проблема 2"]
Отзыв: {review}"""
}]
)
import json, re
text = re.sub(r'```(?:json)?|```', '', response.content[0].text).strip()
return json.loads(text)
def generate_response(review: str, context: dict) -> str:
sentiment = context.get("analyze_sentiment", {})
issues = context.get("extract_issues", [])
issues_text = "\n".join(f"- {issue}" for issue in issues) if issues else "нет"
response = client.messages.create(
model="claude-sonnet-4-5", # важный шаг — более качественная модель
max_tokens=512,
system="""Пишешь ответы службы поддержки.
Тон: дружелюбный, конкретный, без шаблонных фраз.
Не обещай то что не можешь выполнить.""",
messages=[{
"role": "user",
"content": f"""Напиши ответ на отзыв.
Тональность отзыва: {sentiment.get('sentiment')}
Выявленные проблемы: {issues_text}
Отзыв: {review}"""
}]
)
return response.content[0].text
def churn_risk(review: str, context: dict) -> dict:
sentiment = context.get("analyze_sentiment", {})
response = client.messages.create(
model="claude-haiku-4-5",
max_tokens=128,
messages=[{
"role": "user",
"content": f"""Оцени риск ухода клиента.
JSON: {{"churn_risk": "high|medium|low", "reason": "краткое объяснение"}}
Тональность: {sentiment}
Отзыв: {review}"""
}]
)
import json, re
text = re.sub(r'```(?:json)?|```', '', response.content[0].text).strip()
return json.loads(text)
# Собираем pipeline
pipeline = LLMPipeline()
pipeline\
.add_step("analyze_sentiment", analyze_sentiment)\
.add_step("extract_issues", extract_issues)\
.add_step("generate_response", generate_response, model="claude-sonnet-4-5")\
.add_step("churn_risk", churn_risk)
review = "Приложение постоянно вылетает при оплате. Уже третий раз теряю корзину. Очень расстроен."
results = pipeline.run(review)
print(f"Тональность: {results['analyze_sentiment']}")
print(f"Проблемы: {results['extract_issues']}")
print(f"Риск ухода: {results['churn_risk']}")
print(f"\nОтвет:\n{results['generate_response']}")