AI Accountant: Automate Document Processing & Accounting

We design and deploy artificial intelligence systems: from prototype to production-ready solutions. Our team combines expertise in machine learning, data engineering and MLOps to make AI work not in the lab, but in real business.
Showing 1 of 1All 1564 services
AI Accountant: Automate Document Processing & Accounting
Complex
from 2 weeks to 3 months
Frequently Asked Questions

AI Development Areas

AI Solution Development Stages

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1357
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1250
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    956
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1188
  • image_logo-advance_0.webp
    B2B Advance company logo design
    646
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    929

AI Digital Accountant: Automate Your Document Processing and Accounting

Imagine: 300 documents per day, 4 accountants, 40% of time spent on manual entry and reconciliation. A typical manufacturing company loses up to 2.5 million rubles per year due to errors and delays. We solved this problem with an AI accountant—a digital employee based on a neural network that automates accounting: processes primary documents (invoices, acts, waybills), reconciles accounts, prepares postings, monitors accounts receivable. This is not an RPA robot but an intelligent VLM system that understands context and adapts without retraining. It does not replace the chief accountant but removes up to 60-70% of the operational load, allowing the team to focus on complex tasks. Our team: 10+ years in accounting automation, over 50 AI solution implementations, official 1C partners. Our accumulated experience allows us to guarantee data extraction quality of 99% and a reduction in input errors of at least 90%. Get a consultation on implementing an AI accountant.

AI Accountant Implementation Stages

Stage Duration Result
Process survey 1-2 weeks Document flow map, requirements
OCR pipeline setup 2-3 weeks Extraction model with 99% accuracy
Verification development 1-2 weeks Automatic check of TIN, amounts
1C integration 2-3 weeks XML posting loading
AR monitoring setup 1 week Automatic reminders
Training and support 1 week Documentation, testing

How Does the AI Accountant Process Primary Documents?

Data extraction from scans and PDFs is built on Vision Language Models. We use Claude Vision and GPT-4o—they understand the structure of Russian documents: TIN, KPP, numbers, dates, and amounts. Unlike classic OCR, VLM considers context: it recognizes not only characters but also the semantics of fields. The result is parsed into a strict Pydantic model.

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"]  # 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 (no VAT)
    vat_amount: Optional[float]
    total_amount: float
    items: list[dict]                 # Document lines
    payment_purpose: Optional[str]   # Payment purpose
    contract_reference: Optional[str]

def extract_document_data(file_path: str) -> InvoiceData:
    """Extract data from scan/PDF document via 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": """Extract all details of the financial document.
For Russian documents: TIN, KPP, document number, date, amounts with and without VAT.
Return JSON according to the InvoiceData schema. If a field is missing—null.""",
                },
            ],
        }],
    )

    return InvoiceData.model_validate_json(response.content[0].text)

Why Vision Language Models Instead of Classic OCR?

Classic OCR engines (Tesseract, ABBYY) often make errors on non-standard layouts and poor scans. VLM models see the entire document: they understand that the amount in the bottom right corner is the total, not a separate line. Extraction accuracy on Russian documents reaches 99% with moderate quality. Moreover, the model adapts to new templates without retraining—just show 2-3 examples in the prompt.

Verification and Matching with Contracts

Extracted data is automatically checked: TIN is verified with the Federal Tax Service (via API), amounts with contracts and limits. If a discrepancy is found, the document is flagged for manual review. Duplicates are eliminated by number and supplier TIN.

Invoice Verification Algorithm

The system simultaneously checks the TIN via the Federal Tax Service API, the amount against the contract, and duplicates by number and TIN. All checks are performed asynchronously. If a discrepancy of more than 5% in amount or a TIN mismatch is detected, the document is marked manually_review. Minor discrepancies (up to 1 ruble for VAT) are corrected automatically.

class DocumentVerifier:

    async def verify_invoice(
        self,
        invoice: InvoiceData,
        contract_id: str,
    ) -> dict:
        """Check invoice against contract and reference books"""

        # Parallel checks
        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 = []

        # Check supplier TIN
        if vendor and vendor.inn != invoice.vendor_inn:
            issues.append(f"Supplier TIN mismatch: document={invoice.vendor_inn}, reference={vendor.inn}")

        # Check amount against contract
        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% tolerance
            issues.append(f"Contract amount exceeded: paid {total_paid}, new invoice {invoice.total_amount}, limit {contract.max_amount}")

        # Check VAT
        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:  # Tolerance 1 rub
                issues.append(f"VAT calculation error: expected {expected_vat:.2f}, document {invoice.vat_amount:.2f}")

        # Duplicate?
        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"Duplicate document: number {invoice.document_number} already processed {duplicate.processed_date}")

        return {
            "valid": len(issues) == 0,
            "issues": issues,
            "requires_manual_review": len(issues) > 0,
            "vendor_verified": vendor is not None,
        }

Processing Documents with Errors

The system does not simply discard problematic documents—it classifies the type of error and suggests actions. Minor discrepancies (up to 1 ruble for VAT) are automatically corrected. Serious discrepancies are sent to a manual review queue with the reason indicated. Contact us for a demonstration on your documents.

Generating Postings and Integration with 1C

A classifier based on LLM determines the type of expense (materials, services, goods) and selects the corresponding accounts. Postings with analytics are loaded into 1C via XML. The ready code block is below.

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]:
        """Generate postings for 1C"""

        # LLM classifies expense type
        classification = await client.messages.create(
            model="claude-opus-4-5",
            max_tokens=200,
            messages=[{
                "role": "user",
                "content": f"""Classify the expense for accounting entries.
Supplier: {invoice.vendor_name}
Items in document: {[item['name'] for item in invoice.items[:5]]}

Return 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 = []

        # Main posting
        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} from {invoice.document_date}",
            "cost_center": cost_center,
            "analytic": invoice.vendor_inn,
        })

        # VAT
        if invoice.vat_amount and classification_data.get("vat_deductible"):
            entries.append({
                "debit": "19.03",
                "credit": "60.01",
                "amount": invoice.vat_amount,
                "description": f"VAT / {invoice.vendor_name} / {invoice.document_number}",
                "cost_center": cost_center,
            })

        return entries

    async def post_to_1c(self, entries: list[dict]) -> str:
        """Load postings into 1C via COM object or API"""
        # Generate XML for 1C
        xml_data = self.format_1c_xml(entries)
        result = await onec_api.post_document(xml_data)
        return result["document_id"]

Accounts Receivable Monitoring

Daily, the AI checks overdue accounts and automatically sends reminders with escalation by degree of delay. Personalization of emails is via GPT-4o-mini.

class ReceivablesMonitor:

    async def daily_ar_check(self) -> dict:
        """Daily overdue receivables check"""

        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:
                # Friendly reminder
                await self.send_reminder(invoice, tone="friendly")
                report["actions_taken"].append(f"Reminder: {invoice.customer_name}")

            elif days_overdue <= 30:
                # Formal demand
                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"Formal demand: {invoice.customer_name}")

            elif days_overdue > 30:
                # Escalate to CFO
                await self.escalate_to_cfo(invoice)
                report["actions_taken"].append(f"ESCALATION: {invoice.customer_name}, {days_overdue} days")

        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"Write a payment reminder. Tone: {tone}. Official business style. 2-3 paragraphs."
            }, {
                "role": "user",
                "content": f"Invoice No. {invoice['number']} from {invoice['date']} for {invoice['amount']:,.0f} RUB, overdue {invoice['days_overdue']} days, client: {invoice['customer_name']}"
            }],
        )
        return response.choices[0].message.content

Practical Case: Our Project for a Manufacturing Company

Situation: 4 accountants processed 300 documents per day (invoices, acts, waybills). 40% of time was manual entry and reconciliation. The AI accountant processed scans and PDFs via OCR + Claude Vision, automatic TIN verification via Federal Tax Service API, matching with contracts, generating postings in 1C (XML upload), and a weekly AR report.

Results:

  • Documents processed without accountant involvement: 68%
  • Data entry errors reduced by 94%
  • Average processing time per document: 12 min → 40 sec (18 times faster)
  • Accountants focus on complex documents, tax issues, audit
Metric Human AI Accountant
Processing time 12 minutes 40 seconds
Data entry errors 1-2% <0.1%
Daily volume 75 documents 300+ documents

Economic effect: reduction in accounting payroll by 40-60% through workload redistribution. With average document flow, payback occurs within 4-6 months.

What Is Included in the AI Accountant Implementation

  1. Survey of current processes and document types
  2. OCR pipeline setup for your templates
  3. Development of verification logic and reference books
  4. Integration with 1C (COM / REST API)
  5. AR monitoring setup and email templates
  6. Documentation and employee training
  7. Technical support during the first month

Timeline and Cost

Estimated implementation time: from 8 to 12 weeks depending on integration complexity. Cost is calculated individually based on your document volume and requirements. Contact us for a project assessment—we will propose the optimal solution. Get a consultation on implementing an AI accountant.

LLM Development: Fine-Tuning, RAG, Agents, and Production Deployment

Using GPT‑4 or Claude 3.5 Sonnet through a public API is not a solution — it's just a tool. When the requirement is to "make it like ChatGPT, but on our data," there is a real engineering challenge behind it: from prompt engineering to training a 70B model on your own infrastructure. End-to-end LLM solution development is a complex stack, and we have been doing it for over 5 years. During this time, we have completed over 20 projects in generative AI: from RAG systems for legal departments to custom support agents. Where exactly your task falls depends on data, latency requirements, budget, and how critical confidentiality is.

A typical situation: the client has already tried ChatGPT, but results are unstable — sometimes accurate, sometimes hallucinating. Or they need integration into a corporate portal while complying with security policies. Let's break down each layer of the stack in detail — from RAG to production deployment.

Why Do RAG Systems Break and How to Fix It?

RAG (Retrieval-Augmented Generation) looks simple: find relevant documents, put them in context, get an answer. In practice, it fails in several places.

Chunking without overlap. Classic mistake: chunk_size=512, overlap=0. If the answer lies across two chunks, retrieval won't find either with sufficient confidence. Solution: overlap 15–25% of chunk_size, or better yet, sentence-aware splitting with spaCy or NLTK instead of naive character splitting.

Poor embedder. text-embedding-ada-002 is good for general use, but on legal or medical texts, specialized models like E5-large-v2, BGE-M3, or fine-tuned sentence-transformers on domain data outperform it. Recall@5 differences can be 15–25%.

No re-ranking. Vector search optimizes for speed, not relevance. A cross-encoder re-ranker (ms-marco-MiniLM-L-6-v2, bge-reranker-large) after initial retrieval improves top-3 accuracy with acceptable latency (+50–150ms). This is often more impactful than improving the embedding model.

Hybrid search. Dense vectors alone work poorly on exact queries: names, SKUs, codes. BM25 (sparse) finds exact matches but misses semantics. Hybrid via RRF (Reciprocal Rank Fusion) is the optimal compromise. Qdrant, Weaviate, and pgvector 0.7+ support hybrid search natively.

Typical production architecture for a corporate knowledge base
  1. Documents → preprocessing (PyMuPDF, Unstructured)
  2. Chunking → embedding (BGE-M3)
  3. Qdrant (hybrid dense+sparse)
  4. Cross-encoder re-ranking
  5. Context → LLM (vLLM or OpenAI API)
  6. Answer with sources (RAGAS for quality evaluation)

When to Fine-Tune Instead of Prompt Engineering?

Prompt engineering solves ~70% of LLM adaptation tasks for a domain. The remaining 30% require fine-tuning. Three indicators: the model ignores a specific output format even with detailed prompting; the task requires deep knowledge of specialized vocabulary (medicine, law); you need to significantly reduce token costs by replacing a large model with a smaller specialized one.

LoRA and QLoRA are the standard for SFT. LoRA adds trainable low-rank matrices to attention layers. A typical configuration for Llama-3 8B: r=64, lora_alpha=128, target_modules=["q_proj","v_proj","k_proj","o_proj"] yields ~0.8% trainable parameters, training on one A100 40GB. QLoRA adds 4-bit quantization (NF4) and allows fine-tuning 70B models on two A100 40GB, though speed drops by half compared to bf16.

DPO instead of RLHF. Direct Preference Optimization requires only (chosen, rejected) pairs, not scalar reward signals. DPOTrainer from the trl library (Hugging Face) implements it in a few dozen lines.

Common mistake. A dataset of 500 examples, 5 epochs, validation loss 0.8 — seems fine. But on test, the model degrades on general instructions. Cause: catastrophic forgetting. Solution: add 10–20% general instruction-following examples (Alpaca, FLAN) to the training set to preserve original capabilities.

How to Choose a Base Model: 8B or 70B?

Model Parameters Strengths Context
Llama-3.1 8B 8B Quality/speed balance 128k
Llama-3.1 70B 70B Complex reasoning 128k
Mistral 7B / Mixtral 8x7B 7B / 47B Efficiency for size 32k
Qwen2.5 72B 72B Code, multilingual 128k
Gemma 2 27B 27B Open license 8k

For most tasks, fine-tuning an 8B model is sufficient. 70B is needed when deep reasoning is required or the 8B baseline does not reach the required quality even after fine-tuning. Inference cost for Llama-3 8B via vLLM on A100 is efficient; the exact cost depends on volume.

What Does PagedAttention Bring to Production?

vLLM is the first choice for serving open-source models. PagedAttention is the key technical innovation: KV-cache is managed like virtual memory in an OS, without fragmentation. This yields 2–4x higher throughput compared to naive HuggingFace Transformers inference. The vLLM documentation confirms that continuous batching and PagedAttention are the standard for high-load LLM services.

Typical numbers on A100 80GB for Llama-3 8B (bf16): 400–600 req/s, P50 latency 200–400ms, P99 latency 600–900ms at concurrency 64. For 70B on two A100 with tensor parallelism: 80–120 req/s, P99 latency 1.5–2.5s. AWQ or GPTQ quantization reduces memory consumption by 2x with quality loss within 1–3%.

Multi-Agent Systems

Agents are LLMs with access to tools: search, code execution, API calls, database interaction. Common patterns:

  • ReAct (Reason + Act): the model reasons → chooses a tool → observes the result → reasons again. LangChain and LlamaIndex implement it out of the box.
  • Multi-agent orchestration: multiple specialized agents with a coordinator on top. Example: coordinator → researcher (search + summarization) → coder (code generation and execution) → critic (verification). Tools: AutoGen (Microsoft), CrewAI, custom implementation on LangGraph.

In production, agent systems are non-deterministic. Essential: guardrails, step limits, logging of each step, human-in-the-loop for critical actions.

How We Work: Stages, Timeline, Deliverables

Stage Duration What You Get
Audit and data collection 1–2 weeks Eval dataset of 100+ examples, task formalization
Baseline (prompt + RAG) 1–2 weeks Working prototype, quality metrics
Fine-tuning (if needed) 2–4 weeks Trained model, LoRA weights, model card
Deployment and monitoring 1–2 weeks vLLM server, Grafana + Prometheus
Documentation and training 1 week API documentation, team training

What Is Included

We deliver:

  • Technical documentation (model card, configs, deployment instructions)
  • Access to infrastructure (code repository, trained weights)
  • 1 month of post-deployment support (consultations, bug fixes)
  • Customer team training (2–3 sessions on system operation)

Timeline: basic RAG prototype — 1–2 weeks. Fine-tuning with customer data — 3–6 weeks (including data preparation). Production system with monitoring and retraining — 2–4 months. Cost is calculated individually based on data volume, model complexity, and infrastructure requirements.

We guarantee the quality of the final model with performance benchmarks and ongoing monitoring. Our engineers have hands‑on experience with dozens of production LLM systems.

Want to evaluate your project? Leave a request — we will prepare a preliminary summary within 1–2 business days. Or get a consultation on choosing the approach: RAG, fine-tuning, or hybrid — we will tell you what works best for you. Contact us to discuss your LLM development needs. Schedule a free consultation today.