image
VincentWei

天地间,浩然正气长存,为天地立心,为生民立命,为往圣继绝学,为万世开太平!

免责声明:网站内容仅供个人学习记录,禁做商业用途,转载请注明出处。

版权所有 © 2017-2020 NEUSNCP个人学习笔记 辽ICP备17017855号-2

kgagent — A Temporal Knowledge Graph Agent

VincentWei    2026年7月31日 15:07:45

kgagent — A Temporal Knowledge Graph Agent

A faithful Python re-implementation of the Graphiti architecture, with first-class support for Ollama and vLLM as LLM providers.

What is a temporal knowledge graph? Every entity and relationship carries two timestamps: when it became true (valid_at) and when it stopped being true (expired_at). This lets the agent answer both "what is true now?" and "what was true on 2024-03-15?" — and handle real-time updates that invalidate stale facts.

Why kgagent?

Feature kgagent Graphiti
Temporal bi-indexing
Episode provenance
Custom ontology (Pydantic)
Hybrid search (vector + BM25 + graph)
RRF / MMR / node-distance reranking
Ollama support ✅ first-class
vLLM support ✅ first-class
Zero-server default (in-memory) ❌ (needs Neo4j)
Embedded DB option (Kùzu)
Pure Python CLI ✅ (Python)

Quick Start

1. Install

git clone <this-repo> && cd kgagent
python -m venv .venv && source .venv/bin/activate
pip install -e .
# Optional backends:
pip install -e ".[kuzu]"      # embedded graph DB
pip install -e ".[neo4j]"     # Neo4j server backend
pip install -e ".[anthropic]" # Claude support

2. Configure

Create a .env file (or export env vars):

# --- LLM ---
# Option A: OpenAI
KGAGENT_LLM_PROVIDER=openai_compatible
KGAGENT_LLM_MODEL=gpt-4o-mini
KGAGENT_LLM_API_KEY=sk-...
​
# Option B: Ollama (local, free)
KGAGENT_LLM_PROVIDER=openai_compatible
KGAGENT_LLM_MODEL=llama3.1:8b
KGAGENT_LLM_BASE_URL=http://localhost:11434/v1
KGAGENT_LLM_API_KEY=ollama
KGAGENT_LLM_SMALL_MODEL=llama3.1:8b
​
# Option C: vLLM (local, GPU)
KGAGENT_LLM_PROVIDER=openai_compatible
KGAGENT_LLM_MODEL=Qwen/Qwen2.5-7B-Instruct
KGAGENT_LLM_BASE_URL=http://localhost:8000/v1
KGAGENT_LLM_API_KEY=dummy
​
# --- Embedder ---
# Option A: local sentence-transformers (free, ~130MB)
KGAGENT_EMBEDDER_PROVIDER=sentence_transformers
KGAGENT_EMBEDDER_MODEL=BAAI/bge-small-en-v1.5
KGAGENT_EMBEDDER_DIM=384
​
# Option B: Ollama embeddings
KGAGENT_EMBEDDER_PROVIDER=ollama
KGAGENT_EMBEDDER_MODEL=nomic-embed-text
KGAGENT_EMBEDDER_BASE_URL=http://localhost:11434
KGAGENT_EMBEDDER_DIM=768
​
# --- Graph ---
KGAGENT_GRAPH_BACKEND=memory          # or kuzu / neo4j
KGAGENT_GROUP_ID=default

3. Use the CLI

# Initialize the graph backend (creates indexes)
kgagent migrate
​
# Ingest a text file as an episode
kgagent ingest --file notes.txt --source-description "my notes"
​
# Ingest from stdin
echo "Alice joined Acme as CTO in March 2024." | kgagent ingest --stdin
​
# Ingest a JSON record
kgagent ingest --json '{"name":"Acme","industry":"tech"}' --source json
​
# Search the graph
kgagent search "Who is the CTO of Acme?"
​
# Search with a specific recipe
kgagent search "Alice's role" --recipe mmr_diverse
​
# Ask the ReAct agent
kgagent agent "Who is the CTO of Acme and when did they join?"
​
# Show graph stats
kgagent count
​
# Check connectivity
kgagent health
​
# Print the resolved config
kgagent config

4. Use the Python API

import asyncio
from kgagent import Graphiti, Settings, Episode, EpisodeType
​
async def main():
    settings = Settings()  # reads from env / .env
    kg = await Graphiti.create(settings)
​
    # Ingest
    await kg.add_episode(Episode(
        name="hiring-note",
        content="Alice joined Acme as CTO in March 2024.",
        source=EpisodeType.TEXT,
        source_description="hr-notes",
    ))
​
    # Search
    results = await kg.search("Who is the CTO of Acme?")
    for nr in results.nodes:
        print(f"  node: {nr.node.name} (score={nr.score:.3f})")
    for er in results.edges:
        print(f"  edge: {er.edge.fact} (score={er.score:.3f})")
​
    # Agent
    answer = await kg.agent_ask("Who is the CTO of Acme?")
    print("Agent:", answer)
​
    await kg.close()
​
asyncio.run(main())

Architecture

┌─────────────────────────────────────────────────────────┐
│                        CLI (Typer)                       │
│   ingest · search · agent · schema · migrate · health   │
├─────────────────────────────────────────────────────────┤
│                    Graphiti (facade)                     │
├──────────┬──────────┬──────────┬──────────┬─────────────┤
│  Ingest  │  Search  │  Update  │  Agent   │  Semantic   │
│ Pipeline │  Engine  │  Engine  │ (ReAct)  │   Layer     │
├──────────┴──────────┴──────────┴──────────┴─────────────┤
│         LLM Client       │      Embedder Client         │
│  OpenAI/vLLM/Ollama      │  ST/OpenAI/Ollama            │
├──────────────────────────┴──────────────────────────────┤
│                Graph Client (pluggable)                  │
│      Memory (NetworkX) · Kùzu · Neo4j · FalkorDB        │
└──────────────────────────────────────────────────────────┘

Semantic Layer

The semantic layer is the type system that constrains the LLM extractor. Define custom entity and edge types as Pydantic models:

from kgagent.semantic.ontology import Ontology, Entity, Edge
​
class Person(Entity):
    name: str
    age: int | None = None
    role: str | None = None
​
class Company(Entity):
    name: str
    industry: str | None = None
​
class Employment(Edge):
    source_type: type[Entity] = Person
    target_type: type[Entity] = Company
    title: str | None = None
    since: str | None = None
​
ontology = Ontology(entities=[Person, Company], edges=[Employment])
kg = await Graphiti.create(settings, ontology=ontology)

The extractor generates a JSON schema from these models and passes it to the LLM via function-calling (or response_format=json_schema for vLLM with --guided-decoding-backend outlines).

Temporal Bi-Indexing

Every EntityEdge carries:

Field Meaning
valid_at When the fact became true in the real world
expired_at When the fact stopped being true (None = still true)
created_at When the edge was first written to the graph
episodes List of episode UUIDs that established this fact (provenance)

When a new episode contradicts an existing fact, the update engine sets expired_at on the old edge and writes a new one — the old fact is never deleted, just invalidated.

Incremental Update Engine

The ingestion pipeline runs this sequence for every episode:

  1. Chunk the episode if it exceeds ingest_chunk_size.

  2. Persist an EpisodicNode for provenance.

  3. Extract entities + edges via LLM (constrained by ontology).

  4. Embed entity names and edge facts.

  5. Deduplicate extracted entities against existing graph entities (embedding similarity → LLM confirmation).

  6. Detect contradictions between new edges and existing edges (LLM judges).

  7. Invalidate stale edges (expired_at = now).

  8. Save new entities, edges, and MENTIONS links.

Hybrid Search

Three retrievers run in parallel:

  • Semantic — cosine similarity over name_embedding / fact_embedding.

  • BM25 — full-text search over node names + summaries / edge facts.

  • Graph traversal — BFS from a focal node (optional).

Results are fused with one of:

  • RRF (Reciprocal Rank Fusion) — default, robust.

  • MMR (Maximal Marginal Relevance) — diversity-aware.

  • Node distance — boost nodes close to a focal entity.

  • Episode mentions — boost nodes corroborated by more episodes.

Prebuilt recipes: combined, node, edge, community, mmr_diverse, node_distance, episode_mentions.

Ollama Setup

# 1. Install Ollama: https://ollama.com
# 2. Pull models
ollama pull llama3.1:8b          # LLM
ollama pull nomic-embed-text      # embedder
​
# 3. Configure kgagent
export KGAGENT_LLM_PROVIDER=openai_compatible
export KGAGENT_LLM_MODEL=llama3.1:8b
export KGAGENT_LLM_BASE_URL=http://localhost:11434/v1
export KGAGENT_LLM_API_KEY=ollama
export KGAGENT_EMBEDDER_PROVIDER=ollama
export KGAGENT_EMBEDDER_MODEL=nomic-embed-text
export KGAGENT_EMBEDDER_BASE_URL=http://localhost:11434
export KGAGENT_EMBEDDER_DIM=768
​
# 4. Run
kgagent migrate
kgagent ingest --stdin <<< "Alice joined Acme as CTO in March 2024."
kgagent search "Who is the CTO of Acme?"

vLLM Setup

# 1. Start vLLM with guided decoding for strict JSON output
vllm serve Qwen/Qwen2.5-7B-Instruct \
    --guided-decoding-backend outlines \
    --port 8000
​
# 2. Configure kgagent
export KGAGENT_LLM_PROVIDER=openai_compatible
export KGAGENT_LLM_MODEL=Qwen/Qwen2.5-7B-Instruct
export KGAGENT_LLM_BASE_URL=http://localhost:8000/v1
export KGAGENT_LLM_API_KEY=dummy
export KGAGENT_EMBEDDER_PROVIDER=sentence_transformers
export KGAGENT_EMBEDDER_MODEL=BAAI/bge-small-en-v1.5
export KGAGENT_EMBEDDER_DIM=384
​
# 3. Run
kgagent migrate
kgagent ingest --file data.txt
kgagent agent "What entities are in the graph?"

Graph Backends

Backend Setup Best for
memory None Tests, small graphs (<100k nodes)
kuzu pip install kgagent[kuzu] Single-process apps, file-backed persistence
neo4j Run Neo4j server Production, multi-process, large graphs
falkordb Run FalkorDB Redis-based, high-throughput

Project Structure

kgagent/
├── pyproject.toml
├── README.md
├── kgagent/
│   ├── config.py              # Settings (env-driven)
│   ├── core.py               # Graphiti facade
│   ├── semantic/             # Semantic layer (nodes, edges, episodes, ontology)
│   ├── llm/                  # LLM clients (OpenAI/vLLM/Ollama/Anthropic)
│   ├── embedder/             # Embedder clients (ST/OpenAI/Ollama)
│   ├── graph/                # Graph backends (Memory/Kuzu/Neo4j)
│   ├── ingest/               # Episode ingestion pipeline
│   ├── update/               # Incremental update engine
│   ├── search/               # Hybrid search + rerankers + recipes
│   ├── agent/                # ReAct agent
│   └── cli/                  # Typer CLI
├── scripts/
│   └── smoke_test.py         # End-to-end test (mock LLM/embedder)
└── examples/
    └── demo.py               # Usage demo

License

MIT.


https://cdn.neusncp.com/public/file/20260731150742_fVpqb5UY.zip
最近更新: 2026年7月31日 15:07:45
浏览: 9

[[total]] 条评论

添加评论
  1. [[item.time]]
    [[item.user.username]] [[item.floor]]楼
  2. 点击加载更多……
  3. 添加评论