Skip to main content

Context proxy for AI agents. Enriches LLM context from a knowledge graph, extracts knowledge from responses.

Project description

acervo

Context proxy for AI agents.
Enriches context before. Extracts knowledge after. Remembers everything.

Version License Python Docs


Every conversation your AI agent has starts from scratch. Every context is forgotten. Your agent asks the same questions, loses the same insights, and has no idea who it's talking to.

Acervo fixes that. It sits between the user and the LLM as a context proxy — building a knowledge graph that grows with every conversation, and assembling only the relevant context before each LLM call.

How it works

User message
    │
    ▼
acervo.prepare(message, history)     ← Acervo enriches context from graph
    │  topic detection → query planning → context assembly
    │  returns: context_stack (ready for LLM) + plan (GRAPH / WEB_SEARCH / READY)
    │
    ▼
Your app calls the LLM              ← You control the LLM, streaming, tools
    │
    ▼
acervo.process(message, response)    ← Acervo extracts knowledge from response
    │  entity extraction → relation detection → fact persistence
    │
    ▼
Knowledge accumulates. Token usage stays flat.

Acervo does not call the LLM itself. Your app controls the model, streaming, and tool execution. Acervo only enriches context and extracts knowledge.

Installation

pip install acervo

Or install from source:

git clone https://github.com/sandyeveliz/acervo.git
cd acervo
pip install -e .

Requirements

  • Python 3.11+
  • An OpenAI-compatible LLM server (LM Studio, Ollama, OpenAI, etc.)

Quick start

1. Start your LLM server

Acervo needs a small utility model for extraction, planning, and topic detection. Any OpenAI-compatible endpoint works.

With LM Studio: Load qwen2.5-3b-instruct (or any 3B+ model) and start the server on port 1234.

With Ollama:

ollama run qwen2.5:3b

2. Use the prepare/process API

import asyncio
from acervo import Acervo, OpenAIClient

async def main():
    # Connect to your LLM (any OpenAI-compatible endpoint)
    llm = OpenAIClient(
        base_url="http://localhost:1234/v1",
        model="qwen2.5-3b-instruct",
        api_key="lm-studio",
    )

    memory = Acervo(llm=llm, owner="Sandy")
    history = [{"role": "system", "content": "You are a helpful assistant."}]

    # --- Turn 1: user asks something ---
    user_msg = "I work at Altovallestudio, we build software"
    history.append({"role": "user", "content": user_msg})

    # Acervo prepares context from graph
    prep = await memory.prepare(user_msg, history)
    # prep.context_stack → messages with injected graph context
    # prep.plan.tool → "READY" (no search needed)
    # prep.has_context → False (first time, nothing in graph yet)

    # Your app calls the LLM (use your own client, streaming, etc.)
    assistant_msg = "Nice! Tell me more about your projects."
    history.append({"role": "assistant", "content": assistant_msg})

    # Acervo extracts knowledge from the conversation
    await memory.process(user_msg, assistant_msg)
    # Graph now has: Altovallestudio (Organización), Sandy (Persona)

    # --- Turn 2: ask about something stored ---
    user_msg2 = "What do you know about my company?"
    history.append({"role": "user", "content": user_msg2})

    prep2 = await memory.prepare(user_msg2, history)
    # prep2.has_context → True!
    # prep2.context_stack includes: "Altovallestudio (Organización) - Sandy works here"

    print("Context for LLM:", prep2.context_stack)

asyncio.run(main())

3. Use the low-level API

If you don't need the full pipeline (topic detection, planning), you can use commit() and materialize() directly:

# Store knowledge
await memory.commit(
    "Batman was created by Bill Finger and Bob Kane in 1939",
    "He first appeared in Detective Comics #27.",
)

# Retrieve relevant context
context = memory.materialize("Batman")
# Returns: "# Batman (Personaje)\nEl usuario mencionó:\n- was created by Bill Finger..."

Tested setup

This is the stack we use daily for development and testing:

Component Tool Model
LLM server LM Studio unsloth/qwen3.5-9b (chat) + qwen2.5-3b-instruct (utility)
Embeddings Ollama qwen3-embedding (optional, for topic detection L2)
Client app AVS-Agents Python TUI with Textual

Acervo works with any OpenAI-compatible endpoint. The LLMClient protocol is simple:

class LLMClient(Protocol):
    async def chat(
        self,
        messages: list[dict[str, str]],
        *,
        temperature: float = 0.0,
        max_tokens: int = 500,
    ) -> str: ...

Features

Knowledge graph with two layers

  • UNIVERSAL — world knowledge (cities, characters, technologies). Shared across users.
  • PERSONAL — user-specific context (projects, preferences). Trusted within that user's session.

Auto-registering ontology

Built-in types: Persona, Personaje, Organización, Lugar, Tecnología, Obra, Universo, Editorial

Built-in relations: IS_A, CREATED_BY, ALIAS_OF, PART_OF, SET_IN, DEBUTED_IN, PUBLISHED_BY

When the LLM extracts a type or relation that doesn't exist yet, Acervo registers it automatically. No code changes needed.

Pipeline components

All behind a single LLMClient protocol — one small model handles everything:

Component What it does
Topic detector 3-level cascade: keywords → embeddings → LLM classification
Query planner LLM decides: use graph, search web, or respond directly
Context index 3-layer stack (system + warm graph + hot messages) with token budgeting
Extractor Entities, semantic relations, and facts from conversations and web results
Synthesizer Renders graph nodes into compact text for context injection

Constant token usage

Without Acervo:   turn 1 → 200tk  |  turn 50 → 9000tk  |  turn 100 → limit
With Acervo:      turn 1 → 200tk  |  turn 50 → 400tk   |  turn 100 → 420tk

Project status

v0.1.0 — first public release.

Feature Status
Knowledge graph (JSON persistence) ✅ Working
Two-layer architecture (UNIVERSAL / PERSONAL) ✅ Working
prepare() / process() context proxy API ✅ Working
Auto-registering ontology ✅ Working
Semantic relations (IS_A, CREATED_BY, ALIAS_OF, etc.) ✅ Working
Topic detector (keywords → embeddings → LLM) ✅ Working
Query planner (GRAPH_ALL / WEB_SEARCH / READY) ✅ Working
Context index with token budgeting ✅ Working
Built-in OpenAIClient (zero external deps) ✅ Working
LLMClient + Embedder protocols ✅ Working
Unit tests (56 passing) ✅ Working
MCP server 📋 Planned
REST API (acervo serve) 📋 Planned
PyPI package (pip install acervo) 📋 Planned
acervo init directory indexer 📋 Planned
Community knowledge packs 📋 Planned
Vector search 📋 Planned

Documentation

Why "Acervo"?

In library science, an acervo is the complete collection of a library — every book, document, and record it holds, organized so anything can be found when needed.

An agent's memory should work like a well-run library: knowledge organized by subject, filed in the right place, and retrieved by a librarian who knows exactly which shelf to go to — not by someone who reads every book from cover to cover every time you ask a question.

Contributing

Acervo is open source under Apache 2.0. See CONTRIBUTING.md to get started.

License

Apache 2.0 — see LICENSE. Copyright 2026 Sandy Veliz.


Built by Sandy Veliz · AltoValleStudio

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

acervo-0.1.1.tar.gz (55.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

acervo-0.1.1-py3-none-any.whl (42.2 kB view details)

Uploaded Python 3

File details

Details for the file acervo-0.1.1.tar.gz.

File metadata

  • Download URL: acervo-0.1.1.tar.gz
  • Upload date:
  • Size: 55.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for acervo-0.1.1.tar.gz
Algorithm Hash digest
SHA256 a873107b18d71cf082457700707d832cff2f8aa06d39aa3f4455f99ae50a7ad6
MD5 921775138e6ec96b2208bc7055eba3af
BLAKE2b-256 34700e27aca716314a51a82f2e9195980445f05e09e6105161547edbd05989a8

See more details on using hashes here.

File details

Details for the file acervo-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: acervo-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 42.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for acervo-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 980974720094767b015450e93d2378cdb3e699d377c630a7bf0544c12aa3a01b
MD5 470b6418976b62db9e73ef360e6c9fe8
BLAKE2b-256 e6f7781cdefd42cf6b87e5c6145635bd0aa5bd673b197a9621f0aae60327cace

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page