Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 35 additions & 47 deletions README.ko.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ LLM 에이전트용 지식 그래프 + MCP 도구 서버. 하이브리드 검색

```bash
pip install "synaptic-memory[sqlite,korean,vector]"
python examples/quickstart.py
synaptic-quickstart --db quickstart.db
```

위 두 줄로 [`examples/data/products.csv`](examples/data/products.csv)를
SQLite 기반 그래프로 인제스트하고 3개 쿼리를 실행합니다. 전 과정 **LLM 호출 0회**.
전체 소스: [`examples/quickstart.py`](examples/quickstart.py).
위 두 줄로 작은 SQLite 기반 그래프를 만들고 3개 쿼리를 실행합니다. 전 과정
**LLM 호출 0회**입니다. `--db`를 빼면 의존성 없는 인메모리 smoke test로
실행됩니다. 확장 예제: [`examples/quickstart.py`](examples/quickstart.py).

---

Expand All @@ -32,36 +32,31 @@ from synaptic import SynapticGraph

async def main():
# 아무 데이터 → 지식 그래프 (CSV, JSONL, 디렉터리)
graph = await SynapticGraph.from_data("./내_데이터/")

# 또는 DB에서 바로 — SQLite / PostgreSQL / MySQL / Oracle / MSSQL
graph = await SynapticGraph.from_database(
"postgresql://user:pass@host:5432/dbname"
)

# 라이브 DB? CDC 모드로 변경분만 다시 읽기
graph = await SynapticGraph.from_database(
"postgresql://user:pass@host:5432/dbname",
db="knowledge.db",
mode="cdc", # deterministic node ID + sync state 기록
)
result = await graph.sync_from_database(
"postgresql://user:pass@host:5432/dbname"
)
print(result.added, result.updated, result.deleted)

# 또는 직접 청킹한 문서 전달 (LangChain, Unstructured, 자체 OCR 등)
chunks = my_parser.split("manual.pdf")
graph = await SynapticGraph.from_chunks(chunks)

# 검색
result = await graph.search("내 질문", engine="evidence")
graph = await SynapticGraph.from_data("./내_데이터/", preset="rag")
try:
result = await graph.search("내 질문", engine="evidence")
print(result.nodes[0].node.title if result.nodes else "결과 없음")
finally:
await graph.close()

asyncio.run(main())
```

파일 형식 또는 DB 스키마 자동 감지, 온톨로지 프로파일 자동 생성, 인제스트, 인덱싱, FK 엣지 구축까지 전부 자동.

자주 쓰는 옵션은 preset으로 줄일 수 있습니다.

```python
# local: 기본값, 외부 서비스 없음
graph = await SynapticGraph.from_chunks(chunks, preset="local")

# rag: SYNAPTIC_EMBED_URL / SYNAPTIC_RERANK_URL 환경변수를 읽음
graph = await SynapticGraph.from_data("./docs/", preset="rag")

# agent: rag + 멀티턴 탐색용 deterministic component bridging
graph = await SynapticGraph.from_data("./docs/", preset="agent")
```

> **라이브 DB 동기화 (CDC)** — `mode="cdc"`로 증분 업데이트:
> `updated_at`류 컬럼이 있으면 워터마크 필터로 읽고, 없으면 row 내용 해시로 폴백.
> 삭제는 TEMP TABLE + LEFT JOIN으로 감지, FK 변경 시 RELATED 엣지 재연결.
Expand All @@ -83,7 +78,7 @@ asyncio.run(main())
├─ 문서: Category → Document → Chunk
└─ 정형: 테이블 row → ENTITY 노드 + RELATED 엣지 (FK)
42개 MCP 도구 → LLM 에이전트가 그래프 기반 멀티턴으로 탐색
MCP 도구 → LLM 에이전트가 그래프 기반 멀티턴으로 탐색
```

**라이브러리가 하는 건 딱 두 가지:**
Expand Down Expand Up @@ -133,35 +128,28 @@ from synaptic import SynapticGraph
async def main():
# CSV 파일
graph = await SynapticGraph.from_data("products.csv")

# JSONL 문서
graph = await SynapticGraph.from_data("documents.jsonl")

# 디렉터리 전체 (CSV/JSONL 자동 스캔)
graph = await SynapticGraph.from_data("./내_코퍼스/")

# 임베딩 추가 (선택, 의미 검색 품질 향상)
graph = await SynapticGraph.from_data(
"./내_코퍼스/",
embed_url="http://localhost:11434/v1",
)

# 검색
result = await graph.search("내 질문", engine="evidence")
for activated in result.nodes[:5]:
print(activated.node.title, activated.activation)
try:
result = await graph.search("내 질문", engine="evidence")
for activated in result.nodes[:5]:
print(activated.node.title, activated.activation)
finally:
await graph.close()

asyncio.run(main())
```

`preset="rag"`를 넘기면 `SYNAPTIC_EMBED_URL`, `SYNAPTIC_RERANK_URL`을 읽습니다.
여러 `from_data()`, `from_chunks()`, `from_database()` 호출에 같은 설정을 쓰고
싶다면 `GraphBuildOptions`를 사용할 수 있습니다.

### 방법 B: MCP 서버 (Claude Desktop / Code)

```bash
synaptic-mcp --db my_graph.db
synaptic-mcp --db my_graph.db --embed-url http://localhost:11434/v1
```

Claude가 42개 도구로 그래프를 직접 탐색합니다. 검색, 인제스트, CDC 동기화까지 CLI로 내려가지 않고 대화 안에서.
Claude가 MCP 도구로 그래프를 직접 탐색합니다. 검색, 인제스트, CDC 동기화까지 CLI로 내려가지 않고 대화 안에서.

복붙 가능한 `claude_desktop_config.json` 샘플:
[`examples/mcp_claude_desktop.json`](examples/mcp_claude_desktop.json).
Expand Down
84 changes: 37 additions & 47 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ CDC-based live database sync, and Korean FTS built in.

```bash
pip install "synaptic-memory[sqlite,korean,vector]"
python examples/quickstart.py
synaptic-quickstart --db quickstart.db
```

That command ingests [`examples/data/products.csv`](examples/data/products.csv)
into a SQLite-backed graph and runs three searches — all **without calling
any LLM** at indexing time. Full source: [`examples/quickstart.py`](examples/quickstart.py).
That command builds a tiny SQLite-backed graph and runs three searches — all
**without calling any LLM** at indexing time. Omit `--db` for an in-memory,
zero-dependency smoke test. Full source for the expanded example:
[`examples/quickstart.py`](examples/quickstart.py).

---

Expand All @@ -33,36 +34,31 @@ from synaptic import SynapticGraph

async def main():
# Any data → knowledge graph (CSV, JSONL, directory)
graph = await SynapticGraph.from_data("./my_data/")

# Or directly from a database — SQLite / PostgreSQL / MySQL / Oracle / MSSQL
graph = await SynapticGraph.from_database(
"postgresql://user:pass@host:5432/dbname"
)

# Live database? Use CDC mode and only re-read what changed.
graph = await SynapticGraph.from_database(
"postgresql://user:pass@host:5432/dbname",
db="knowledge.db",
mode="cdc", # deterministic node IDs + sync state recorded
)
result = await graph.sync_from_database(
"postgresql://user:pass@host:5432/dbname"
)
print(result.added, result.updated, result.deleted)

# Or bring your own chunker (LangChain, Unstructured, custom OCR, ...)
chunks = my_parser.split("manual.pdf")
graph = await SynapticGraph.from_chunks(chunks)

# Search
result = await graph.search("my question", engine="evidence")
graph = await SynapticGraph.from_data("./my_data/", preset="rag")
try:
result = await graph.search("my question", engine="evidence")
print(result.nodes[0].node.title if result.nodes else "no result")
finally:
await graph.close()

asyncio.run(main())
```

That's it. Auto-detects file format or DB schema, generates an ontology profile, ingests, indexes, builds FK edges.

Presets keep the common knobs compact:

```python
# local: deterministic, no external services (default)
graph = await SynapticGraph.from_chunks(chunks, preset="local")

# rag: reads SYNAPTIC_EMBED_URL / SYNAPTIC_RERANK_URL if set
graph = await SynapticGraph.from_data("./docs/", preset="rag")

# agent: rag + deterministic component bridging for multi-turn exploration
graph = await SynapticGraph.from_data("./docs/", preset="agent")
```

> **Live database sync (CDC)** — `mode="cdc"` enables incremental
> updates: tables with an `updated_at`-style column are read with a
> watermark filter, others fall back to per-row content hashing.
Expand All @@ -86,7 +82,7 @@ Knowledge Graph
├─ Documents: Category → Document → Chunk
└─ Structured: table rows as ENTITY nodes + RELATED edges (FKs)
42 MCP tools → LLM agent explores via graph-aware multi-turn tool use
MCP tools → LLM agent explores via graph-aware multi-turn tool use
```

**Two jobs, nothing else:**
Expand Down Expand Up @@ -135,35 +131,29 @@ from synaptic import SynapticGraph
async def main():
# CSV file
graph = await SynapticGraph.from_data("products.csv")

# JSONL documents
graph = await SynapticGraph.from_data("documents.jsonl")

# Entire directory (scans all CSV/JSONL)
graph = await SynapticGraph.from_data("./my_corpus/")

# With embedding (optional, improves semantic search)
graph = await SynapticGraph.from_data(
"./my_corpus/",
embed_url="http://localhost:11434/v1",
)

# Search
result = await graph.search("my question", engine="evidence")
for activated in result.nodes[:5]:
print(activated.node.title, activated.activation)
try:
result = await graph.search("my question", engine="evidence")
for activated in result.nodes[:5]:
print(activated.node.title, activated.activation)
finally:
await graph.close()

asyncio.run(main())
```

You can pass `preset="rag"` to read `SYNAPTIC_EMBED_URL` and
`SYNAPTIC_RERANK_URL`, or use `GraphBuildOptions` when you want one reusable
configuration object across `from_data()`, `from_chunks()`, and
`from_database()`.

### Option B: MCP server (Claude Desktop / Code)

```bash
synaptic-mcp --db my_graph.db
synaptic-mcp --db my_graph.db --embed-url http://localhost:11434/v1
```

Claude can now call 42 tools to explore your graph — search, ingest
Claude can now call MCP tools to explore your graph — search, ingest
new files into the graph mid-conversation, and sync from a live
database without dropping to a CLI.

Expand Down
81 changes: 81 additions & 0 deletions docs/ADOPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Adoption Guide

This guide is for developers adding Synaptic Memory to an existing RAG or
agent application.

## Fast Smoke

```bash
pip install synaptic-memory
synaptic-quickstart
```

The default quickstart uses an in-memory graph and has no optional dependency.
Persist the sample graph with SQLite:

```bash
pip install "synaptic-memory[sqlite]"
synaptic-quickstart --db quickstart.db
```

## Recommended Installs

```bash
pip install "synaptic-memory[sqlite,korean,vector]"
pip install "synaptic-memory[mcp]"
pip install "synaptic-memory[langchain]"
pip install "synaptic-memory[all]"
```

Use the narrowest extra set that matches your deployment. Core install stays
zero-dependency for tests and in-memory prototypes.

## Python API

```python
from synaptic import SynapticGraph

graph = await SynapticGraph.from_data("./docs/", preset="rag")
try:
result = await graph.search("refund policy exception", engine="evidence")
finally:
await graph.close()
```

For pre-chunked data:

```python
graph = await SynapticGraph.from_chunks(
[{"content": "...", "title": "Manual", "source": "manual.pdf"}],
preset="local",
)
```

## Presets

| Preset | Use when | Behavior |
|---|---|---|
| `local` | tests, local smoke, deterministic baseline | no external endpoints |
| `rag` | normal RAG app | reads `SYNAPTIC_EMBED_URL` / `SYNAPTIC_RERANK_URL` |
| `agent` | multi-turn graph exploration | `rag` plus deterministic component bridging |
| `scale` | large ingest with external indexing plan | endpoint-aware, index/router configured separately |

Use `GraphBuildOptions` when the same configuration should be reused across
`from_data()`, `from_chunks()`, and `from_database()`.

```python
from synaptic import GraphBuildOptions, SynapticGraph

options = GraphBuildOptions.rag().with_overrides(connect=True)
graph = await SynapticGraph.from_data("./docs/", options=options)
```

## Optional MCP Server

```bash
pip install "synaptic-memory[mcp]"
synaptic-mcp --db knowledge.db
```

Without the `mcp` extra, `synaptic-mcp --help` still works and prints the
install command instead of failing with a Python traceback.
10 changes: 7 additions & 3 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ Synaptic Memory가 **무엇이고, 왜 필요하고, 어떻게 쓰는지** 친
30분 안에 따라할 수 있는 단계별 실습. CSV 한 개부터 멀티 테이블 FK 관계,
LLM 에이전트, MCP 서버까지 순서대로 경험합니다.

### [ADOPTION.md](ADOPTION.md)
기존 RAG/agent 애플리케이션에 붙일 때 필요한 설치 옵션, quickstart,
`preset`, `GraphBuildOptions`, MCP 진입점을 한 장으로 정리한 적용 가이드.

---

## 🧠 내부 동작이 궁금한 분
Expand Down Expand Up @@ -46,9 +50,9 @@ Flash live eval 준비 상태를 정리합니다.
## 🗺 계획 / 로드맵

### [ROADMAP.md](ROADMAP.md)
버전별 기능 추가 계획. 현재 PyPI 최신은 **v0.17.2** (Apache-2.0 라이선스
전환 + agent_loop ID-extraction fix). **v0.18-alpha** 에서 `graph.chat()`
agent-loop 가 공개 API 로 승격됨.
v0.17~v0.18 시점의 역사적 로드맵과 측정 근거. 현재 설치/사용 흐름은
루트 [`README.md`](../README.md), 변경 이력은 [`CHANGELOG.md`](../CHANGELOG.md),
최신 고도화 계획은 `PLAN-v0.30+` / `PLAN-v0.31+` 문서를 기준으로 보세요.

### [PLAN-v0.17-ontology.md](PLAN-v0.17-ontology.md)
v0.17 ontology/정형 데이터 파이프라인 설계. MuSiQue 한계 논의 포함.
Expand Down
12 changes: 7 additions & 5 deletions docs/ROADMAP.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# Synaptic Memory — Roadmap
# Synaptic Memory — Historical Roadmap

> 마지막 업데이트: 2026-04-20 (v0.17.2 PyPI + v0.18-alpha 진행 중)
> 마지막 업데이트: 2026-04-20. 이 문서는 v0.17~v0.18 시점의 역사적
> 로드맵입니다. 현재 설치/사용 흐름은 루트 README, 최신 변경 이력은
> CHANGELOG, 이후 고도화 계획은 PLAN-v0.30+ / PLAN-v0.31+ 문서를 보세요.

## 현재 상태
## 당시 상태

- **PyPI stable**: [`synaptic-memory==0.17.2`](https://pypi.org/project/synaptic-memory/0.17.2/)
- **진행 트랙**: v0.18-alpha (`graph.chat()` agent-loop public API)
- **PyPI stable 당시 기준**: [`synaptic-memory==0.17.2`](https://pypi.org/project/synaptic-memory/0.17.2/)
- **당시 진행 트랙**: v0.18-alpha (`graph.chat()` agent-loop public API)
- **라이선스**: Apache-2.0 (v0.17.2 에서 MIT → Apache-2.0 전환)
- **테스트**: **942** 단위 테스트 통과
- **MCP 도구**: 36개
Expand Down
4 changes: 1 addition & 3 deletions examples/langchain_retriever.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,7 @@ async def main() -> None:
print(f" metadata keys: {sorted(doc.metadata.keys())}")
print()
finally:
close = getattr(graph._backend, "close", None)
if close is not None:
await close()
await graph.close()


if __name__ == "__main__":
Expand Down
Loading
Loading