Skip to main content

Personalization memory connector for LangChain and LangGraph applications

Project description

personiq

Personalization memory connector for LangChain and LangGraph.

One adapter. Any LLM. Works alongside any other memory system.

personiq automatically extracts what matters about each user from their conversations, stores it with hybrid search (BM25 + semantic + recency), and injects it into future prompts — so your chatbot, recommendation engine, or AI application feels like it genuinely knows the user.

from langchain_groq import ChatGroq
from personiq import PersoniqAdapter

piq = PersoniqAdapter(llm=ChatGroq(model="llama-3.1-8b-instant"))

# LangGraph — two lines:
builder.add_node("personiq_load", piq.load_node)
builder.add_node("personiq_save", piq.save_node)

# Direct — three lines:
ctx    = piq.persona("alice", user_message)
system = f"{ctx}\n{base_system}" if ctx else base_system
await piq.learn("alice", messages)

Installation

pip install personiq

# Then install your LLM provider:
pip install personiq[groq]        # Groq  (llama, gemma, mixtral)
pip install personiq[openai]      # OpenAI
pip install personiq[anthropic]   # Anthropic (Claude)
pip install personiq[ollama]      # Ollama — local, no API key needed
pip install personiq[mistral]     # Mistral

What personiq does

  1. Extracts durable facts from conversations using your LLM (skills, goals, preferences, context, style, personal info)
  2. Stores them in a local SQLite database with vector embeddings and BM25 keyword indexes
  3. Retrieves the most relevant memories per query using hybrid search (BM25 + cosine similarity + recency decay) fused with Reciprocal Rank Fusion
  4. Injects them into your system prompt — either as a structured bullet list or a natural-language persona paragraph

Integration styles

Style 1 — LangGraph nodes (recommended)

from langchain_groq import ChatGroq
from langchain_core.messages import HumanMessage, SystemMessage
from langgraph.graph import END, StateGraph
from personiq import PersoniqAdapter, PersoniqState

piq = PersoniqAdapter(llm=ChatGroq(model="llama-3.1-8b-instant"), mode="persona")

async def chat(state: PersoniqState) -> dict:
    mem_ctx  = state.get("memory_context", "")
    system   = f"{mem_ctx}\nYou are a helpful assistant." if mem_ctx else "You are a helpful assistant."
    messages = [SystemMessage(content=system)] + list(state["messages"])
    response = await llm.ainvoke(messages)
    return {"messages": [response]}

builder = StateGraph(PersoniqState)
builder.add_node("personiq_load", piq.load_node)   # retrieves memories
builder.add_node("chat",          chat)
builder.add_node("personiq_save", piq.save_node)   # saves memories

builder.set_entry_point("personiq_load")
builder.add_edge("personiq_load", "chat")
builder.add_edge("chat",          "personiq_save")
builder.add_edge("personiq_save", END)
graph = builder.compile()

result = await graph.ainvoke({
    "user_id":  "alice",
    "messages": [HumanMessage(content="I'm a backend engineer using Go and Postgres.")],
})

Style 2 — Direct usage (any framework)

piq = PersoniqAdapter(llm=llm)

# Before your LLM call — get personalization context:
ctx    = piq.context("alice", user_message)   # structured bullets
# or:
ctx    = piq.persona("alice", user_message)   # natural-language paragraph (better UX)

system = f"{ctx}\n{base_system}" if ctx else base_system

# After your LLM call — save new memories (fire-and-forget):
await piq.learn("alice", messages)

Style 3 — Inject into messages list

messages = piq.inject(messages, user_id="alice", query=user_message)
response = await llm.ainvoke(messages)

Two context modes

mode="context" (default) — structured bullets

[personiq: what I know about this user]

Technical background:
  • User is an experienced Go developer
  • User works with PostgreSQL and Redis

Goals & current work:
  • User is building a distributed payment service

[end of personiq context]

mode="persona" — natural language

You already know this user. Here is what you know about them:
They work with Go and PostgreSQL. They're currently focused on: building
a distributed payment service. They prefer concise, direct technical answers.
Use this naturally — don't recite it back, just let it shape how you respond.

Works alongside other memory systems

personiq is fully independent. It stores memories in its own SQLite database and does not interfere with Mem0, Zep, LangMem, or any other memory setup.

piq  = PersoniqAdapter(llm=llm)   # personiq — personalization memory
mem0 = MemoryClient(...)          # Mem0 — conversation history

# Both work independently on the same conversation
ctx  = piq.persona("alice", message)
hist = mem0.get_history("alice")

Supported LLM providers

Provider Install Import
Groq pip install personiq[groq] from langchain_groq import ChatGroq
OpenAI pip install personiq[openai] from langchain_openai import ChatOpenAI
Anthropic pip install personiq[anthropic] from langchain_anthropic import ChatAnthropic
Ollama (local) pip install personiq[ollama] from langchain_ollama import ChatOllama
Mistral pip install personiq[mistral] from langchain_mistralai import ChatMistralAI

Any BaseChatModel from LangChain works.


Memory categories

Category What gets stored
technical Languages, frameworks, tools, platforms
goal Objectives, projects, purchase intent, problems to solve
preference Likes, dislikes, favourites — products, approaches, content
context Occupation, location, education, life stage
style Communication style, verbosity, tone preference
personal Name, relationships, values, life events

Configuration

from personiq import PersoniqAdapter, PersoniqConfig

config = PersoniqConfig(
    db_path              = "./myapp.db",
    embedding_backend    = "local",      # "local" (default) or "openai"
    top_k                = 5,
    similarity_threshold = 0.30,
    semantic_weight      = 0.60,
    bm25_weight          = 0.30,
    recency_weight       = 0.10,
    async_extraction     = True,         # fire-and-forget (default)
    mode                 = "persona",    # "context" or "persona"
    debug                = False,
)

piq = PersoniqAdapter(llm=llm, config=config)

All settings are also configurable via environment variables (prefix PERSONIQ_).


Memory management

# Inspect stored memories
for m in piq.memories("alice"):
    print(f"[{m.category:12}] {m.content}  (importance: {m.importance_score:.2f})")

# Filter by category
goals = piq.memories("alice", category="goal")
tech  = piq.memories("alice", category="technical")

# Count
print(piq.count("alice"))

# Delete all memories (GDPR / account deletion)
piq.forget("alice")

Running tests

pip install -e ".[dev]"
pytest tests/ -v

No API key required — all LLM calls are mocked in tests.


Use cases

personiq is designed for any application where knowing the user improves outcomes:

  • Personalised chatbots — assistant remembers user's name, job, preferences across sessions
  • Recommendation engines — surface products/content matching stored preferences and goals
  • AI sales agents — know the prospect's industry, pain points, and purchase intent
  • Content personalisation — adapt tone, complexity, and topics to each user's profile
  • Ad targeting — build rich user profiles from natural conversation signals
  • Customer support — remember past issues, preferences, and technical environment

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

personiq-0.2.1.tar.gz (35.8 kB view details)

Uploaded Source

Built Distribution

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

personiq-0.2.1-py3-none-any.whl (28.4 kB view details)

Uploaded Python 3

File details

Details for the file personiq-0.2.1.tar.gz.

File metadata

  • Download URL: personiq-0.2.1.tar.gz
  • Upload date:
  • Size: 35.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.11

File hashes

Hashes for personiq-0.2.1.tar.gz
Algorithm Hash digest
SHA256 b59864ab8894f9d4683ec4f23d31fda585dbcba85914c6ead2d989f66754dc66
MD5 d37ae606b574e691e73d85771eecb06c
BLAKE2b-256 ae16735a82b5cc2e79ad780c798223c410f8deab67897b349a2af5cf3ce5c4ea

See more details on using hashes here.

File details

Details for the file personiq-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: personiq-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 28.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.11

File hashes

Hashes for personiq-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 12bb86e027bc4db26b84c4b9f732abdd6e85d26083ca1d966e5a51e3c54efe32
MD5 1c863f34c687ab835a2867853d4e97b9
BLAKE2b-256 fe1ed34b51497ef1440ac454f080eec46ba64d1281563819531bcf866131a473

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