nylonme-integrations 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nylonme_integrations-0.1.0/PKG-INFO +88 -0
- nylonme_integrations-0.1.0/README.md +63 -0
- nylonme_integrations-0.1.0/pyproject.toml +33 -0
- nylonme_integrations-0.1.0/setup.cfg +4 -0
- nylonme_integrations-0.1.0/src/nylonme_integrations/__init__.py +18 -0
- nylonme_integrations-0.1.0/src/nylonme_integrations/_core.py +63 -0
- nylonme_integrations-0.1.0/src/nylonme_integrations/langchain.py +114 -0
- nylonme_integrations-0.1.0/src/nylonme_integrations/llamaindex.py +69 -0
- nylonme_integrations-0.1.0/src/nylonme_integrations/py.typed +0 -0
- nylonme_integrations-0.1.0/src/nylonme_integrations.egg-info/PKG-INFO +88 -0
- nylonme_integrations-0.1.0/src/nylonme_integrations.egg-info/SOURCES.txt +12 -0
- nylonme_integrations-0.1.0/src/nylonme_integrations.egg-info/dependency_links.txt +1 -0
- nylonme_integrations-0.1.0/src/nylonme_integrations.egg-info/requires.txt +14 -0
- nylonme_integrations-0.1.0/src/nylonme_integrations.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nylonme-integrations
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: LangChain and LlamaIndex adapters for the NylonME memory engine
|
|
5
|
+
Author: NylonME contributors
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Keywords: memory,rag,langchain,llamaindex,nylonme
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
13
|
+
Requires-Python: >=3.10
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
Requires-Dist: nylon-sdk>=0.2
|
|
16
|
+
Provides-Extra: langchain
|
|
17
|
+
Requires-Dist: langchain-core>=0.3; extra == "langchain"
|
|
18
|
+
Provides-Extra: llamaindex
|
|
19
|
+
Requires-Dist: llama-index-core>=0.11; extra == "llamaindex"
|
|
20
|
+
Provides-Extra: all
|
|
21
|
+
Requires-Dist: langchain-core>=0.3; extra == "all"
|
|
22
|
+
Requires-Dist: llama-index-core>=0.11; extra == "all"
|
|
23
|
+
Provides-Extra: test
|
|
24
|
+
Requires-Dist: pytest; extra == "test"
|
|
25
|
+
|
|
26
|
+
# NylonME Integrations
|
|
27
|
+
|
|
28
|
+
LangChain 和 LlamaIndex 的 NylonME 适配器。核心共振逻辑只依赖
|
|
29
|
+
`nylon-sdk`,框架类在真正使用时才导入,避免强制安装框架。
|
|
30
|
+
|
|
31
|
+
## 安装
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# LangChain
|
|
35
|
+
pip install nylonme-integrations[langchain]
|
|
36
|
+
|
|
37
|
+
# LlamaIndex
|
|
38
|
+
pip install nylonme-integrations[llamaindex]
|
|
39
|
+
|
|
40
|
+
# 两者都要
|
|
41
|
+
pip install nylonme-integrations[all]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## LangChain
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from nylonme_integrations.langchain import NylonMeRetriever, NylonMeMemory
|
|
48
|
+
|
|
49
|
+
retriever = NylonMeRetriever(target="127.0.0.1:50051", owner="alice", budget=5)
|
|
50
|
+
docs = retriever.invoke("上次出差住在哪里?")
|
|
51
|
+
for d in docs:
|
|
52
|
+
print(d.page_content, d.metadata["resonance"])
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
对话记忆(在 prompt 里放一个 `{memory}` 占位符):
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
memory = NylonMeMemory(target="127.0.0.1:50051", owner="alice")
|
|
59
|
+
memory.save_context({"input": "我喜欢靠窗座位"}, {"output": "已记住"})
|
|
60
|
+
print(memory.load_memory_variables({"input": "出差选座"}))
|
|
61
|
+
# {'memory': '- 出差偏好:靠窗座位'}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## LlamaIndex
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from nylonme_integrations.llamaindex import NylonMeRetriever
|
|
68
|
+
|
|
69
|
+
retriever = NylonMeRetriever(target="127.0.0.1:50051", owner="alice", budget=5)
|
|
70
|
+
nodes = retriever.retrieve("上次出差住在哪里?")
|
|
71
|
+
for n in nodes:
|
|
72
|
+
print(n.node.text, n.score)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 配置
|
|
76
|
+
|
|
77
|
+
两个适配器都暴露同样的字段:
|
|
78
|
+
|
|
79
|
+
| 字段 | 默认值 | 说明 |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| `target` | `127.0.0.1:50051` | NylonME gRPC 地址(也读 `NYLON_SERVER`) |
|
|
82
|
+
| `owner` | `default` | 记忆归属(也读 `NYLON_OWNER`) |
|
|
83
|
+
| `tenant` | `default` | 租户(也读 `NYLON_TENANT`) |
|
|
84
|
+
| `budget` | `5` | 共振召回预算 |
|
|
85
|
+
| `task` | `None` | 可选任务上下文 |
|
|
86
|
+
|
|
87
|
+
引擎默认监听 `127.0.0.1:50051`(gRPC)和 `50052`(REST/UI)。用 Docker 一键起:
|
|
88
|
+
`docker compose up -d`。
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# NylonME Integrations
|
|
2
|
+
|
|
3
|
+
LangChain 和 LlamaIndex 的 NylonME 适配器。核心共振逻辑只依赖
|
|
4
|
+
`nylon-sdk`,框架类在真正使用时才导入,避免强制安装框架。
|
|
5
|
+
|
|
6
|
+
## 安装
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
# LangChain
|
|
10
|
+
pip install nylonme-integrations[langchain]
|
|
11
|
+
|
|
12
|
+
# LlamaIndex
|
|
13
|
+
pip install nylonme-integrations[llamaindex]
|
|
14
|
+
|
|
15
|
+
# 两者都要
|
|
16
|
+
pip install nylonme-integrations[all]
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## LangChain
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from nylonme_integrations.langchain import NylonMeRetriever, NylonMeMemory
|
|
23
|
+
|
|
24
|
+
retriever = NylonMeRetriever(target="127.0.0.1:50051", owner="alice", budget=5)
|
|
25
|
+
docs = retriever.invoke("上次出差住在哪里?")
|
|
26
|
+
for d in docs:
|
|
27
|
+
print(d.page_content, d.metadata["resonance"])
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
对话记忆(在 prompt 里放一个 `{memory}` 占位符):
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
memory = NylonMeMemory(target="127.0.0.1:50051", owner="alice")
|
|
34
|
+
memory.save_context({"input": "我喜欢靠窗座位"}, {"output": "已记住"})
|
|
35
|
+
print(memory.load_memory_variables({"input": "出差选座"}))
|
|
36
|
+
# {'memory': '- 出差偏好:靠窗座位'}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## LlamaIndex
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from nylonme_integrations.llamaindex import NylonMeRetriever
|
|
43
|
+
|
|
44
|
+
retriever = NylonMeRetriever(target="127.0.0.1:50051", owner="alice", budget=5)
|
|
45
|
+
nodes = retriever.retrieve("上次出差住在哪里?")
|
|
46
|
+
for n in nodes:
|
|
47
|
+
print(n.node.text, n.score)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## 配置
|
|
51
|
+
|
|
52
|
+
两个适配器都暴露同样的字段:
|
|
53
|
+
|
|
54
|
+
| 字段 | 默认值 | 说明 |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| `target` | `127.0.0.1:50051` | NylonME gRPC 地址(也读 `NYLON_SERVER`) |
|
|
57
|
+
| `owner` | `default` | 记忆归属(也读 `NYLON_OWNER`) |
|
|
58
|
+
| `tenant` | `default` | 租户(也读 `NYLON_TENANT`) |
|
|
59
|
+
| `budget` | `5` | 共振召回预算 |
|
|
60
|
+
| `task` | `None` | 可选任务上下文 |
|
|
61
|
+
|
|
62
|
+
引擎默认监听 `127.0.0.1:50051`(gRPC)和 `50052`(REST/UI)。用 Docker 一键起:
|
|
63
|
+
`docker compose up -d`。
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "nylonme-integrations"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "LangChain and LlamaIndex adapters for the NylonME memory engine"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "Apache-2.0" }
|
|
12
|
+
authors = [{ name = "NylonME contributors" }]
|
|
13
|
+
keywords = ["memory", "rag", "langchain", "llamaindex", "nylonme"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: Apache Software License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
20
|
+
]
|
|
21
|
+
dependencies = ["nylon-sdk>=0.2"]
|
|
22
|
+
|
|
23
|
+
[project.optional-dependencies]
|
|
24
|
+
langchain = ["langchain-core>=0.3"]
|
|
25
|
+
llamaindex = ["llama-index-core>=0.11"]
|
|
26
|
+
all = ["langchain-core>=0.3", "llama-index-core>=0.11"]
|
|
27
|
+
test = ["pytest"]
|
|
28
|
+
|
|
29
|
+
[tool.setuptools.packages.find]
|
|
30
|
+
where = ["src"]
|
|
31
|
+
|
|
32
|
+
[tool.setuptools.package-data]
|
|
33
|
+
nylonme_integrations = ["py.typed"]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""NylonME framework adapters.
|
|
2
|
+
|
|
3
|
+
A thin bridge from NylonME to the two most common Python agent/RAG
|
|
4
|
+
frameworks. The core resonance logic lives in ``_core.py`` and only depends
|
|
5
|
+
on ``nylon-sdk``; the framework modules import their framework lazily.
|
|
6
|
+
|
|
7
|
+
# LangChain
|
|
8
|
+
from nylonme_integrations.langchain import NylonMeRetriever, NylonMeMemory
|
|
9
|
+
|
|
10
|
+
# LlamaIndex
|
|
11
|
+
from nylonme_integrations.llamaindex import NylonMeRetriever
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from ._core import build_client, node_metadata, resonate_records
|
|
15
|
+
|
|
16
|
+
__version__ = "0.1.0"
|
|
17
|
+
|
|
18
|
+
__all__ = ["build_client", "node_metadata", "resonate_records", "__version__"]
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Framework-agnostic bridge between NylonME and RAG/agent frameworks.
|
|
2
|
+
|
|
3
|
+
This module only depends on ``nylon-sdk``. The LangChain and LlamaIndex
|
|
4
|
+
adapters import it, so the same resonate/weave semantics are shared and can
|
|
5
|
+
be tested without pulling in either framework.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Any, Optional
|
|
11
|
+
|
|
12
|
+
from nylon_sdk import NylonClient
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def build_client(
|
|
16
|
+
target: str,
|
|
17
|
+
owner: str,
|
|
18
|
+
tenant: str,
|
|
19
|
+
*,
|
|
20
|
+
timeout: float = 30.0,
|
|
21
|
+
) -> NylonClient:
|
|
22
|
+
"""Create a NylonME client from the values the adapters expose as fields."""
|
|
23
|
+
return NylonClient(target, owner=owner, tenant=tenant, timeout=timeout)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def node_metadata(record: dict[str, Any]) -> dict[str, Any]:
|
|
27
|
+
"""Flatten one ActivatedNode into stable, JSON-friendly metadata."""
|
|
28
|
+
f = record["filaments"]
|
|
29
|
+
return {
|
|
30
|
+
"node_id": record["node_id"],
|
|
31
|
+
"resonance": record["resonance"],
|
|
32
|
+
"relations": f["relations"],
|
|
33
|
+
"confidence": f["confidence"],
|
|
34
|
+
"emotion_valence": f["emotion_valence"],
|
|
35
|
+
"emotion_intensity": f["emotion_intensity"],
|
|
36
|
+
"mentions_7d": f["mentions_7d"],
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def resonate_records(
|
|
41
|
+
client: NylonClient,
|
|
42
|
+
query: str,
|
|
43
|
+
*,
|
|
44
|
+
budget: int = 5,
|
|
45
|
+
task: Optional[str] = None,
|
|
46
|
+
) -> list[dict[str, Any]]:
|
|
47
|
+
"""Return resonated memories as plain dictionaries."""
|
|
48
|
+
result = client.resonate(query, budget=budget, task=task)
|
|
49
|
+
return [
|
|
50
|
+
{
|
|
51
|
+
"node_id": a.node_id,
|
|
52
|
+
"resonance": a.resonance,
|
|
53
|
+
"filaments": {
|
|
54
|
+
"fact": a.filaments.fact,
|
|
55
|
+
"relations": list(a.filaments.relations),
|
|
56
|
+
"confidence": a.filaments.confidence,
|
|
57
|
+
"emotion_valence": a.filaments.emotion_valence,
|
|
58
|
+
"emotion_intensity": a.filaments.emotion_intensity,
|
|
59
|
+
"mentions_7d": a.filaments.mentions_7d,
|
|
60
|
+
},
|
|
61
|
+
}
|
|
62
|
+
for a in result.activated
|
|
63
|
+
]
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""LangChain adapter for NylonME.
|
|
2
|
+
|
|
3
|
+
Exposes:
|
|
4
|
+
|
|
5
|
+
* :class:`NylonMeRetriever` - RAG retrieval over resonated memories.
|
|
6
|
+
* :class:`NylonMeMemory` - conversational memory that weaves turns and
|
|
7
|
+
injects the most relevant memories into the prompt.
|
|
8
|
+
|
|
9
|
+
``langchain-core`` is a required dependency of this module; install it with
|
|
10
|
+
``pip install nylonme-integrations[langchain]``.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from typing import Any, Optional
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
from langchain_core.callbacks.manager import CallbackManagerForRetrieverRun
|
|
19
|
+
from langchain_core.documents import Document
|
|
20
|
+
from langchain_core.memory import BaseMemory
|
|
21
|
+
from langchain_core.retrievers import BaseRetriever
|
|
22
|
+
except ImportError as exc: # pragma: no cover
|
|
23
|
+
raise ImportError(
|
|
24
|
+
"This adapter requires langchain-core. "
|
|
25
|
+
"Install it with: pip install nylonme-integrations[langchain]"
|
|
26
|
+
) from exc
|
|
27
|
+
|
|
28
|
+
from ._core import build_client, node_metadata, resonate_records
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class NylonMeRetriever(BaseRetriever):
|
|
32
|
+
"""Retriever that maps a query to resonated NylonME memories as Documents."""
|
|
33
|
+
|
|
34
|
+
target: str = "127.0.0.1:50051"
|
|
35
|
+
owner: str = "default"
|
|
36
|
+
tenant: str = "default"
|
|
37
|
+
budget: int = 5
|
|
38
|
+
task: Optional[str] = None
|
|
39
|
+
|
|
40
|
+
def _get_relevant_documents(
|
|
41
|
+
self,
|
|
42
|
+
query: str,
|
|
43
|
+
*,
|
|
44
|
+
run_manager: CallbackManagerForRetrieverRun,
|
|
45
|
+
) -> list[Document]:
|
|
46
|
+
del run_manager
|
|
47
|
+
with build_client(self.target, self.owner, self.tenant) as client:
|
|
48
|
+
records = resonate_records(client, query, budget=self.budget, task=self.task)
|
|
49
|
+
return [
|
|
50
|
+
Document(page_content=r["filaments"]["fact"], metadata=node_metadata(r))
|
|
51
|
+
for r in records
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
async def _aget_relevant_documents(
|
|
55
|
+
self,
|
|
56
|
+
query: str,
|
|
57
|
+
*,
|
|
58
|
+
run_manager=None,
|
|
59
|
+
) -> list[Document]:
|
|
60
|
+
del run_manager
|
|
61
|
+
# The sync SDK call is the simplest correct path; async callers can
|
|
62
|
+
# use AsyncNylonClient directly if they need a truly async channel.
|
|
63
|
+
return self._get_relevant_documents(query, run_manager=run_manager)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class NylonMeMemory(BaseMemory):
|
|
67
|
+
"""Conversational memory: weaves each turn, injects recall into prompts.
|
|
68
|
+
|
|
69
|
+
Wire it into a prompt that contains a ``{memory}`` placeholder (or the
|
|
70
|
+
``memory_key`` you configure). On ``save_context`` the latest user input
|
|
71
|
+
and model output are woven into the engine; on ``load_memory_variables``
|
|
72
|
+
the engine resonates on the current input and returns the matched facts.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
target: str = "127.0.0.1:50051"
|
|
76
|
+
owner: str = "default"
|
|
77
|
+
tenant: str = "default"
|
|
78
|
+
budget: int = 4
|
|
79
|
+
memory_key: str = "memory"
|
|
80
|
+
input_key: str = "input"
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def memory_variables(self) -> list[str]:
|
|
84
|
+
return [self.memory_key]
|
|
85
|
+
|
|
86
|
+
def load_memory_variables(self, inputs: dict[str, Any]) -> dict[str, str]:
|
|
87
|
+
query = self._query_from(inputs)
|
|
88
|
+
if not query:
|
|
89
|
+
return {self.memory_key: ""}
|
|
90
|
+
with build_client(self.target, self.owner, self.tenant) as client:
|
|
91
|
+
records = resonate_records(client, query, budget=self.budget)
|
|
92
|
+
facts = [r["filaments"]["fact"] for r in records]
|
|
93
|
+
return {self.memory_key: "\n".join(f"- {f}" for f in facts)}
|
|
94
|
+
|
|
95
|
+
def save_context(self, inputs: dict[str, Any], outputs: dict[str, str]) -> None:
|
|
96
|
+
text = " ".join(
|
|
97
|
+
str(v) for v in list(inputs.values()) + list(outputs.values()) if v
|
|
98
|
+
).strip()
|
|
99
|
+
if text:
|
|
100
|
+
with build_client(self.target, self.owner, self.tenant) as client:
|
|
101
|
+
client.weave(text)
|
|
102
|
+
|
|
103
|
+
def clear(self) -> None:
|
|
104
|
+
# The community engine has no destructive clear; memories decay via
|
|
105
|
+
# the tension model rather than being force-deleted.
|
|
106
|
+
return None
|
|
107
|
+
|
|
108
|
+
def _query_from(self, inputs: dict[str, Any]) -> str:
|
|
109
|
+
if self.input_key in inputs:
|
|
110
|
+
return str(inputs[self.input_key])
|
|
111
|
+
return " ".join(str(v) for v in inputs.values() if v).strip()
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
__all__ = ["NylonMeRetriever", "NylonMeMemory"]
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""LlamaIndex adapter for NylonME.
|
|
2
|
+
|
|
3
|
+
Exposes :class:`NylonMeRetriever`, which wraps NylonME resonance recall as a
|
|
4
|
+
LlamaIndex retriever returning ``NodeWithScore`` objects.
|
|
5
|
+
|
|
6
|
+
``llama-index-core`` is a required dependency of this module; install it with
|
|
7
|
+
``pip install nylonme-integrations[llamaindex]``.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from typing import Any, Optional
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
from llama_index.core.retrievers import BaseRetriever
|
|
16
|
+
from llama_index.core.schema import NodeWithScore, QueryBundle, TextNode
|
|
17
|
+
except ImportError as exc: # pragma: no cover
|
|
18
|
+
raise ImportError(
|
|
19
|
+
"This adapter requires llama-index-core. "
|
|
20
|
+
"Install it with: pip install nylonme-integrations[llamaindex]"
|
|
21
|
+
) from exc
|
|
22
|
+
|
|
23
|
+
from ._core import build_client, node_metadata, resonate_records
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class NylonMeRetriever(BaseRetriever):
|
|
27
|
+
"""LlamaIndex retriever backed by NylonME resonance recall."""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
target: str = "127.0.0.1:50051",
|
|
32
|
+
owner: str = "default",
|
|
33
|
+
tenant: str = "default",
|
|
34
|
+
budget: int = 5,
|
|
35
|
+
task: Optional[str] = None,
|
|
36
|
+
**kwargs: Any,
|
|
37
|
+
) -> None:
|
|
38
|
+
# llama-index-core >= 0.11 BaseRetriever is a plain class with an
|
|
39
|
+
# explicit __init__ (no pydantic fields), so config must be stored
|
|
40
|
+
# as instance attributes after super().__init__.
|
|
41
|
+
super().__init__(**kwargs)
|
|
42
|
+
self.target = target
|
|
43
|
+
self.owner = owner
|
|
44
|
+
self.tenant = tenant
|
|
45
|
+
self.budget = budget
|
|
46
|
+
self.task = task
|
|
47
|
+
|
|
48
|
+
def _retrieve(self, query_bundle: QueryBundle) -> list[NodeWithScore]:
|
|
49
|
+
query = query_bundle.query_str
|
|
50
|
+
with build_client(self.target, self.owner, self.tenant) as client:
|
|
51
|
+
records = resonate_records(client, query, budget=self.budget, task=self.task)
|
|
52
|
+
return [
|
|
53
|
+
NodeWithScore(
|
|
54
|
+
node=TextNode(
|
|
55
|
+
text=r["filaments"]["fact"],
|
|
56
|
+
id_=str(r["node_id"]),
|
|
57
|
+
metadata=node_metadata(r),
|
|
58
|
+
),
|
|
59
|
+
score=float(r["resonance"]),
|
|
60
|
+
)
|
|
61
|
+
for r in records
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
async def _aretrieve(self, query_bundle: QueryBundle) -> list[NodeWithScore]:
|
|
65
|
+
# Sync SDK call on the event loop for a simple, correct default.
|
|
66
|
+
return self._retrieve(query_bundle)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
__all__ = ["NylonMeRetriever"]
|
|
File without changes
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nylonme-integrations
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: LangChain and LlamaIndex adapters for the NylonME memory engine
|
|
5
|
+
Author: NylonME contributors
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Keywords: memory,rag,langchain,llamaindex,nylonme
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
13
|
+
Requires-Python: >=3.10
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
Requires-Dist: nylon-sdk>=0.2
|
|
16
|
+
Provides-Extra: langchain
|
|
17
|
+
Requires-Dist: langchain-core>=0.3; extra == "langchain"
|
|
18
|
+
Provides-Extra: llamaindex
|
|
19
|
+
Requires-Dist: llama-index-core>=0.11; extra == "llamaindex"
|
|
20
|
+
Provides-Extra: all
|
|
21
|
+
Requires-Dist: langchain-core>=0.3; extra == "all"
|
|
22
|
+
Requires-Dist: llama-index-core>=0.11; extra == "all"
|
|
23
|
+
Provides-Extra: test
|
|
24
|
+
Requires-Dist: pytest; extra == "test"
|
|
25
|
+
|
|
26
|
+
# NylonME Integrations
|
|
27
|
+
|
|
28
|
+
LangChain 和 LlamaIndex 的 NylonME 适配器。核心共振逻辑只依赖
|
|
29
|
+
`nylon-sdk`,框架类在真正使用时才导入,避免强制安装框架。
|
|
30
|
+
|
|
31
|
+
## 安装
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# LangChain
|
|
35
|
+
pip install nylonme-integrations[langchain]
|
|
36
|
+
|
|
37
|
+
# LlamaIndex
|
|
38
|
+
pip install nylonme-integrations[llamaindex]
|
|
39
|
+
|
|
40
|
+
# 两者都要
|
|
41
|
+
pip install nylonme-integrations[all]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## LangChain
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from nylonme_integrations.langchain import NylonMeRetriever, NylonMeMemory
|
|
48
|
+
|
|
49
|
+
retriever = NylonMeRetriever(target="127.0.0.1:50051", owner="alice", budget=5)
|
|
50
|
+
docs = retriever.invoke("上次出差住在哪里?")
|
|
51
|
+
for d in docs:
|
|
52
|
+
print(d.page_content, d.metadata["resonance"])
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
对话记忆(在 prompt 里放一个 `{memory}` 占位符):
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
memory = NylonMeMemory(target="127.0.0.1:50051", owner="alice")
|
|
59
|
+
memory.save_context({"input": "我喜欢靠窗座位"}, {"output": "已记住"})
|
|
60
|
+
print(memory.load_memory_variables({"input": "出差选座"}))
|
|
61
|
+
# {'memory': '- 出差偏好:靠窗座位'}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## LlamaIndex
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from nylonme_integrations.llamaindex import NylonMeRetriever
|
|
68
|
+
|
|
69
|
+
retriever = NylonMeRetriever(target="127.0.0.1:50051", owner="alice", budget=5)
|
|
70
|
+
nodes = retriever.retrieve("上次出差住在哪里?")
|
|
71
|
+
for n in nodes:
|
|
72
|
+
print(n.node.text, n.score)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 配置
|
|
76
|
+
|
|
77
|
+
两个适配器都暴露同样的字段:
|
|
78
|
+
|
|
79
|
+
| 字段 | 默认值 | 说明 |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| `target` | `127.0.0.1:50051` | NylonME gRPC 地址(也读 `NYLON_SERVER`) |
|
|
82
|
+
| `owner` | `default` | 记忆归属(也读 `NYLON_OWNER`) |
|
|
83
|
+
| `tenant` | `default` | 租户(也读 `NYLON_TENANT`) |
|
|
84
|
+
| `budget` | `5` | 共振召回预算 |
|
|
85
|
+
| `task` | `None` | 可选任务上下文 |
|
|
86
|
+
|
|
87
|
+
引擎默认监听 `127.0.0.1:50051`(gRPC)和 `50052`(REST/UI)。用 Docker 一键起:
|
|
88
|
+
`docker compose up -d`。
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
src/nylonme_integrations/__init__.py
|
|
4
|
+
src/nylonme_integrations/_core.py
|
|
5
|
+
src/nylonme_integrations/langchain.py
|
|
6
|
+
src/nylonme_integrations/llamaindex.py
|
|
7
|
+
src/nylonme_integrations/py.typed
|
|
8
|
+
src/nylonme_integrations.egg-info/PKG-INFO
|
|
9
|
+
src/nylonme_integrations.egg-info/SOURCES.txt
|
|
10
|
+
src/nylonme_integrations.egg-info/dependency_links.txt
|
|
11
|
+
src/nylonme_integrations.egg-info/requires.txt
|
|
12
|
+
src/nylonme_integrations.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
nylonme_integrations
|