AI Бухгалтер — цифровий працівник для фінансового обліку
AI Бухгалтер автоматизує рутинні облікові операції: обробку первинних документів (рахунки-фактури, акти, накладні), звірку даних, підготовку проводок, формування звітів, моніторинг дебіторської заборгованості. Не замінює головного бухгалтера, але знімає з нього 60–70% операційного навантаження.
Обробка первинних документів
import anthropic
import base64
from pathlib import Path
from pydantic import BaseModel
from typing import Optional, Literal
client = anthropic.Anthropic()
class InvoiceData(BaseModel):
document_type: Literal["invoice", "act", "waybill", "upd"]
vendor_name: str
vendor_inn: Optional[str]
vendor_kpp: Optional[str]
document_number: str
document_date: str
amount_without_vat: float
vat_rate: Optional[float] # 20, 10, 0, None (без ПДВ)
vat_amount: Optional[float]
total_amount: float
items: list[dict] # Рядки документу
payment_purpose: Optional[str] # Призначення платежу
contract_reference: Optional[str]
def extract_document_data(file_path: str) -> InvoiceData:
"""Вилучення даних зі сканованого/PDF документу через Claude Vision"""
with open(file_path, "rb") as f:
file_content = base64.standard_b64encode(f.read()).decode("utf-8")
ext = Path(file_path).suffix.lower()
media_type = "application/pdf" if ext == ".pdf" else "image/jpeg"
response = client.messages.create(
model="claude-opus-4-5",
max_tokens=2000,
messages=[{
"role": "user",
"content": [
{
"type": "document" if ext == ".pdf" else "image",
"source": {
"type": "base64",
"media_type": media_type,
"data": file_content,
},
},
{
"type": "text",
"text": """Вилучи всі реквізити фінансового документу.
Для документів: ІД лікаря, код податку, номер документу, дату, суми з ПДВ та без.
Поверни JSON за схемою InvoiceData. Для відсутніх полів — null.""",
},
],
}],
)
return InvoiceData.model_validate_json(response.content[0].text)
Верифікація та Відповідність контрактам
class DocumentVerifier:
async def verify_invoice(
self,
invoice: InvoiceData,
contract_id: str,
) -> dict:
"""Перевіряє рахунок проти контракту та довідкових даних"""
# Паралельна перевірка
contract_task = contracts_db.get(contract_id)
vendor_task = vendor_db.get_by_inn(invoice.vendor_inn)
previous_invoices_task = invoices_db.get_for_contract(contract_id)
contract, vendor, previous = await asyncio.gather(
contract_task, vendor_task, previous_invoices_task
)
issues = []
# Перевірка ІД постачальника
if vendor and vendor.inn != invoice.vendor_inn:
issues.append(f"Невідповідність ІД постачальника: документ={invoice.vendor_inn}, довідка={vendor.inn}")
# Перевірка суми проти контракту
total_paid = sum(p.amount for p in previous if p.status == "approved")
if total_paid + invoice.total_amount > contract.max_amount * 1.05: # 5% допуск
issues.append(f"Перевищена сума контракту: сплачено {total_paid}, новий рахунок {invoice.total_amount}, ліміт {contract.max_amount}")
# Перевірка ПДВ
if invoice.vat_amount and invoice.vat_rate:
expected_vat = invoice.amount_without_vat * invoice.vat_rate / 100
if abs(expected_vat - invoice.vat_amount) > 1: # 1 грн допуск
issues.append(f"Помилка розрахунку ПДВ: очікується {expected_vat:.2f}, в документі {invoice.vat_amount:.2f}")
# Перевірка дублікату
duplicate = next(
(p for p in previous if p.document_number == invoice.document_number and p.vendor_inn == invoice.vendor_inn),
None,
)
if duplicate:
issues.append(f"Дублікат документу: № {invoice.document_number} уже оброблений {duplicate.processed_date}")
return {
"valid": len(issues) == 0,
"issues": issues,
"requires_manual_review": len(issues) > 0,
"vendor_verified": vendor is not None,
}
Генерування проводок
class AccountingEntryGenerator:
ACCOUNT_MAPPING = {
"materials": {"debit": "10.01", "credit": "60.01"},
"services": {"debit": "26", "credit": "60.01"},
"goods": {"debit": "41.01", "credit": "60.01"},
"vat_input": {"debit": "19.03", "credit": "60.01"},
}
async def generate_entries(
self,
invoice: InvoiceData,
cost_center: str,
) -> list[dict]:
"""Генерує записи в журналі"""
# LLM класифікує тип видатків
classification = await client.messages.create(
model="claude-opus-4-5",
max_tokens=200,
messages=[{
"role": "user",
"content": f"""Класифікуй видатки для облікових записів.
Постачальник: {invoice.vendor_name}
Найменування в документі: {[item['name'] for item in invoice.items[:5]]}
Поверни JSON: {{"expense_type": "materials|services|goods|fixed_assets", "account": "26|44|10|08", "vat_deductible": true|false}}"""
}],
)
classification_data = json.loads(classification.content[0].text)
entries = []
# Основна проводка
account_map = self.ACCOUNT_MAPPING.get(classification_data["expense_type"], self.ACCOUNT_MAPPING["services"])
entries.append({
"debit": account_map["debit"],
"credit": account_map["credit"],
"amount": invoice.amount_without_vat,
"description": f"{invoice.vendor_name} / {invoice.document_number} від {invoice.document_date}",
"cost_center": cost_center,
"analytic": invoice.vendor_inn,
})
# Запис ПДВ
if invoice.vat_amount and classification_data.get("vat_deductible"):
entries.append({
"debit": "19.03",
"credit": "60.01",
"amount": invoice.vat_amount,
"description": f"ПДВ / {invoice.vendor_name} / {invoice.document_number}",
"cost_center": cost_center,
})
return entries
async def post_to_1c(self, entries: list[dict]) -> str:
"""Завантажує записи через API"""
xml_data = self.format_1c_xml(entries)
result = await onec_api.post_document(xml_data)
return result["document_id"]
Моніторинг дебіторської заборгованості
class ReceivablesMonitor:
async def daily_ar_check(self) -> dict:
"""Щоденна перевірка прострочених рахунків"""
overdue_invoices = await invoices_db.get_overdue()
report = {
"total_overdue": sum(i.amount for i in overdue_invoices),
"by_aging_bucket": self.group_by_aging(overdue_invoices),
"actions_taken": [],
}
for invoice in overdue_invoices:
days_overdue = invoice.days_overdue
if days_overdue <= 7:
# Дружелюбне нагадування
await self.send_reminder(invoice, tone="friendly")
report["actions_taken"].append(f"Нагадування: {invoice.customer_name}")
elif days_overdue <= 30:
# Офіційне повідомлення
await self.send_reminder(invoice, tone="formal")
await crm.create_task(customer_id=invoice.customer_id, title="AR Follow-up")
report["actions_taken"].append(f"Офіційне повідомлення: {invoice.customer_name}")
elif days_overdue > 30:
# Масштабування до CFO
await self.escalate_to_cfo(invoice)
report["actions_taken"].append(f"МАСШТАБУВАННЯ: {invoice.customer_name}, прострочено {days_overdue} днів")
return report
async def generate_ar_reminder(self, invoice: dict, tone: str) -> str:
response = await openai_client.chat.completions.create(
model="gpt-4o-mini",
messages=[{
"role": "system",
"content": f"Напиши нагадування про сплату. Тон: {tone}. Професійний діловий стиль. 2-3 абзаци."
}, {
"role": "user",
"content": f"Рахунок № {invoice['number']} від {invoice['date']} на {invoice['amount']:,.0f}, прострочено {invoice['days_overdue']} днів, клієнт: {invoice['customer_name']}"
}],
)
return response.choices[0].message.content
Практичний кейс: виробнича компанія, 300 документів/день
Ситуація: 4 бухгалтери обробляли 300 документів на день (рахунки-фактури, акти, накладні). 40% часу — ручний ввід даних та звірки.
AI Бухгалтер обробляв:
- Сканування та PDF через OCR + Claude Vision
- Автоматична верифікація постачальника
- Відповідність контрактам
- Генерування проводок (завантаження XML)
- Щотижневий звіт AR
Результати:
- Документів обробленост без участі бухгалтера: 68%
- Помилки вводу даних: -94%
- Середній час обробки 1 документу: 12 хв → 40 сек
- Бухгалтери зосереджуються на: складних документах, податкових питаннях, аудиті
Примітка щодо відповідності: потрібна інтеграція з реєстром постачальників, системами податкової верифікації та дотримання стандартів фінансових документів.
Часова шкала
- OCR + вилучення документів: 2–3 тижні
- Логіка верифікації та довідники: 1–2 тижні
- Генератор записів + класифікатор видатків: 2 тижні
- Інтеграція системи: 2–3 тижні
- Моніторинг AR та комунікації: 1–2 тижні
- Разом: 8–12 тижнів







