llm-hippocampus 0.0.1__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.
- llm_hippocampus-0.0.1/LICENSE +21 -0
- llm_hippocampus-0.0.1/PKG-INFO +123 -0
- llm_hippocampus-0.0.1/README.md +85 -0
- llm_hippocampus-0.0.1/llm_hippocampus/__init__.py +1 -0
- llm_hippocampus-0.0.1/llm_hippocampus/context/__init__.py +1 -0
- llm_hippocampus-0.0.1/llm_hippocampus/context/context_manager.py +40 -0
- llm_hippocampus-0.0.1/llm_hippocampus/context/context_processing.py +8 -0
- llm_hippocampus-0.0.1/llm_hippocampus/context/context_retrieval.py +132 -0
- llm_hippocampus-0.0.1/llm_hippocampus/env.py +24 -0
- llm_hippocampus-0.0.1/llm_hippocampus/session.py +247 -0
- llm_hippocampus-0.0.1/llm_hippocampus/shared/__init__.py +1 -0
- llm_hippocampus-0.0.1/llm_hippocampus/shared/cached_llm.py +50 -0
- llm_hippocampus-0.0.1/llm_hippocampus/shared/logger.py +10 -0
- llm_hippocampus-0.0.1/llm_hippocampus/shared/memory.py +124 -0
- llm_hippocampus-0.0.1/llm_hippocampus/shared/utils.py +4 -0
- llm_hippocampus-0.0.1/llm_hippocampus.egg-info/PKG-INFO +123 -0
- llm_hippocampus-0.0.1/llm_hippocampus.egg-info/SOURCES.txt +21 -0
- llm_hippocampus-0.0.1/llm_hippocampus.egg-info/dependency_links.txt +1 -0
- llm_hippocampus-0.0.1/llm_hippocampus.egg-info/requires.txt +19 -0
- llm_hippocampus-0.0.1/llm_hippocampus.egg-info/top_level.txt +1 -0
- llm_hippocampus-0.0.1/pyproject.toml +67 -0
- llm_hippocampus-0.0.1/setup.cfg +4 -0
- llm_hippocampus-0.0.1/setup.py +36 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2024 Redis, Inc.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
@@ -0,0 +1,123 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: llm-hippocampus
|
3
|
+
Version: 0.0.1
|
4
|
+
Summary: LLM Hippocampus — a Context Engineering playground
|
5
|
+
Home-page:
|
6
|
+
Author: joelz
|
7
|
+
Author-email: joelz <zhongbj_2621@163.com>
|
8
|
+
Project-URL: Repository, https://github.com/redis-developer/redis-rag-workbench.git
|
9
|
+
Project-URL: Bug Tracker, https://github.com/redis-developer/redis-rag-workbench/issues
|
10
|
+
Keywords: python,redis,langchain,openai
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
12
|
+
Classifier: Intended Audience :: Developers
|
13
|
+
Classifier: Programming Language :: Python
|
14
|
+
Requires-Python: >=3.11
|
15
|
+
Description-Content-Type: text/markdown
|
16
|
+
License-File: LICENSE
|
17
|
+
Requires-Dist: openai>=1.63.0
|
18
|
+
Requires-Dist: python-dotenv>=1.0.0
|
19
|
+
Requires-Dist: langchain>=0.3.19
|
20
|
+
Requires-Dist: tiktoken>=0.9.0
|
21
|
+
Requires-Dist: redis>=5.2.1
|
22
|
+
Requires-Dist: langchain-community>=0.3.18
|
23
|
+
Requires-Dist: langchain-huggingface>=0.1.2
|
24
|
+
Requires-Dist: langchain-openai>=0.3.6
|
25
|
+
Requires-Dist: langchain-experimental>=0.3.4
|
26
|
+
Requires-Dist: python-ulid>=2.7.0
|
27
|
+
Requires-Dist: pandas==2.2.3
|
28
|
+
Requires-Dist: hf-xet>=1.1.8
|
29
|
+
Requires-Dist: redisvl>=0.8.2
|
30
|
+
Requires-Dist: sentence-transformers>=5.1.0
|
31
|
+
Requires-Dist: langchain-redis>=0.2.3
|
32
|
+
Provides-Extra: dev
|
33
|
+
Requires-Dist: mypy<2.0.0,>=1.8.0; extra == "dev"
|
34
|
+
Requires-Dist: ruff<1.0.0,>=0.2.2; extra == "dev"
|
35
|
+
Dynamic: author
|
36
|
+
Dynamic: license-file
|
37
|
+
Dynamic: requires-python
|
38
|
+
|
39
|
+
<div align="center">
|
40
|
+
<h1>🚀 LLM Hippocampus</h1>
|
41
|
+
|
42
|
+
[](https://opensource.org/licenses/MIT)
|
43
|
+

|
44
|
+

|
45
|
+

|
46
|
+
|
47
|
+
🎯 Build up and manage the LLM 's memory
|
48
|
+
|
49
|
+
</div>
|
50
|
+
|
51
|
+
🔥 **LLM Hippocampus** helping your project for building and experimenting with **Context Engineering** applications. harness the full power of Redis for **lightning-fast vector search**, **intelligent semantic caching**, **persistent LLM memory**, and **smart context engineering **.
|
52
|
+
|
53
|
+
✨ **What makes this special?**
|
54
|
+
- 🚀 **One-command setup** - pip install llm-hippocampus
|
55
|
+
- ⚡ **LLM support** - OpenAI
|
56
|
+
- 🎯 **Redis-powered** - Vector search, caching, and memory management
|
57
|
+
- 🐳 **Docker ready** - Building...
|
58
|
+
- 🔧 **Developer-first** - Support to Hot load by installing llm-hippocampus
|
59
|
+
|
60
|
+
---
|
61
|
+
|
62
|
+
## Table of Contents
|
63
|
+
|
64
|
+
- [Quick Start](#quick-start)
|
65
|
+
- [Prerequisites](#prerequisites)
|
66
|
+
- [Getting Started](#getting-started)
|
67
|
+
- [Available Commands](#available-commands)
|
68
|
+
- [Development Workflows](#development-workflows)
|
69
|
+
- [Environment Configuration](#environment-configuration)
|
70
|
+
- [Using Google VertexAI](#using-google-vertexai)
|
71
|
+
- [Project Structure](#project-structure)
|
72
|
+
- [Connecting to Redis Cloud](#connecting-to-redis-cloud)
|
73
|
+
- [Troubleshooting](#troubleshooting)
|
74
|
+
- [Contributing](#contributing)
|
75
|
+
- [License](#license)
|
76
|
+
- [Learn More](#learn-more)
|
77
|
+
|
78
|
+
|
79
|
+
## Quick Start
|
80
|
+
|
81
|
+
**Get up and install in your project:**
|
82
|
+
|
83
|
+
```bash
|
84
|
+
pip install llm-hippocampus
|
85
|
+
or
|
86
|
+
uv add llm-hippocampus
|
87
|
+
```
|
88
|
+
|
89
|
+
Welcome to LLM Hippocampus! 🎉
|
90
|
+
|
91
|
+
---
|
92
|
+
|
93
|
+
## Prerequisites
|
94
|
+
|
95
|
+
1. Make sure you have the following tools available:
|
96
|
+
- [python](https://www.docker.com/products/docker-desktop/) 3.11+
|
97
|
+
- [uv](https://docs.astral.sh/uv/)
|
98
|
+
- [Redis Stack](https://redis.io/)
|
99
|
+
2. Setup one or more of the following:
|
100
|
+
- [OpenAI API](https://platform.openai.com/)
|
101
|
+
- You will need an API Key
|
102
|
+
|
103
|
+
## Getting Started
|
104
|
+
|
105
|
+
|
106
|
+
### Development Workflows
|
107
|
+
- Building
|
108
|
+
|
109
|
+
|
110
|
+
## Project Structure
|
111
|
+
|
112
|
+
|
113
|
+
## Contributing
|
114
|
+
|
115
|
+
🤝 Contributions are welcome! Please feel free to submit a Pull Request.
|
116
|
+
|
117
|
+
## License
|
118
|
+
|
119
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
120
|
+
|
121
|
+
## Troubleshooting
|
122
|
+
|
123
|
+
## Learn More
|
@@ -0,0 +1,85 @@
|
|
1
|
+
<div align="center">
|
2
|
+
<h1>🚀 LLM Hippocampus</h1>
|
3
|
+
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
5
|
+

|
6
|
+

|
7
|
+

|
8
|
+
|
9
|
+
🎯 Build up and manage the LLM 's memory
|
10
|
+
|
11
|
+
</div>
|
12
|
+
|
13
|
+
🔥 **LLM Hippocampus** helping your project for building and experimenting with **Context Engineering** applications. harness the full power of Redis for **lightning-fast vector search**, **intelligent semantic caching**, **persistent LLM memory**, and **smart context engineering **.
|
14
|
+
|
15
|
+
✨ **What makes this special?**
|
16
|
+
- 🚀 **One-command setup** - pip install llm-hippocampus
|
17
|
+
- ⚡ **LLM support** - OpenAI
|
18
|
+
- 🎯 **Redis-powered** - Vector search, caching, and memory management
|
19
|
+
- 🐳 **Docker ready** - Building...
|
20
|
+
- 🔧 **Developer-first** - Support to Hot load by installing llm-hippocampus
|
21
|
+
|
22
|
+
---
|
23
|
+
|
24
|
+
## Table of Contents
|
25
|
+
|
26
|
+
- [Quick Start](#quick-start)
|
27
|
+
- [Prerequisites](#prerequisites)
|
28
|
+
- [Getting Started](#getting-started)
|
29
|
+
- [Available Commands](#available-commands)
|
30
|
+
- [Development Workflows](#development-workflows)
|
31
|
+
- [Environment Configuration](#environment-configuration)
|
32
|
+
- [Using Google VertexAI](#using-google-vertexai)
|
33
|
+
- [Project Structure](#project-structure)
|
34
|
+
- [Connecting to Redis Cloud](#connecting-to-redis-cloud)
|
35
|
+
- [Troubleshooting](#troubleshooting)
|
36
|
+
- [Contributing](#contributing)
|
37
|
+
- [License](#license)
|
38
|
+
- [Learn More](#learn-more)
|
39
|
+
|
40
|
+
|
41
|
+
## Quick Start
|
42
|
+
|
43
|
+
**Get up and install in your project:**
|
44
|
+
|
45
|
+
```bash
|
46
|
+
pip install llm-hippocampus
|
47
|
+
or
|
48
|
+
uv add llm-hippocampus
|
49
|
+
```
|
50
|
+
|
51
|
+
Welcome to LLM Hippocampus! 🎉
|
52
|
+
|
53
|
+
---
|
54
|
+
|
55
|
+
## Prerequisites
|
56
|
+
|
57
|
+
1. Make sure you have the following tools available:
|
58
|
+
- [python](https://www.docker.com/products/docker-desktop/) 3.11+
|
59
|
+
- [uv](https://docs.astral.sh/uv/)
|
60
|
+
- [Redis Stack](https://redis.io/)
|
61
|
+
2. Setup one or more of the following:
|
62
|
+
- [OpenAI API](https://platform.openai.com/)
|
63
|
+
- You will need an API Key
|
64
|
+
|
65
|
+
## Getting Started
|
66
|
+
|
67
|
+
|
68
|
+
### Development Workflows
|
69
|
+
- Building
|
70
|
+
|
71
|
+
|
72
|
+
## Project Structure
|
73
|
+
|
74
|
+
|
75
|
+
## Contributing
|
76
|
+
|
77
|
+
🤝 Contributions are welcome! Please feel free to submit a Pull Request.
|
78
|
+
|
79
|
+
## License
|
80
|
+
|
81
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
82
|
+
|
83
|
+
## Troubleshooting
|
84
|
+
|
85
|
+
## Learn More
|
@@ -0,0 +1 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
@@ -0,0 +1 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
from typing import Dict, Optional
|
3
|
+
|
4
|
+
class ContextManager:
|
5
|
+
_instance = None
|
6
|
+
|
7
|
+
def __new__(cls):
|
8
|
+
if cls._instance is None:
|
9
|
+
cls._instance = super().__new__(cls)
|
10
|
+
cls._instance._context = {}
|
11
|
+
return cls._instance
|
12
|
+
|
13
|
+
def set(self, key: str, value: str) -> None:
|
14
|
+
"""添加或更新上下文键值对"""
|
15
|
+
self._context[key] = value
|
16
|
+
|
17
|
+
def get(self, key: str, default: Optional[str] = None) -> Optional[str]:
|
18
|
+
"""获取上下文值"""
|
19
|
+
return self._context.get(key, default)
|
20
|
+
|
21
|
+
def delete(self, key: str) -> None:
|
22
|
+
"""删除上下文键值对"""
|
23
|
+
if key in self._context:
|
24
|
+
del self._context[key]
|
25
|
+
|
26
|
+
def clear(self) -> None:
|
27
|
+
"""清空所有上下文数据"""
|
28
|
+
self._context.clear()
|
29
|
+
|
30
|
+
def get_all(self) -> Dict[str, str]:
|
31
|
+
"""获取所有上下文数据"""
|
32
|
+
return self._context.copy()
|
33
|
+
|
34
|
+
|
35
|
+
def test():
|
36
|
+
print()
|
37
|
+
|
38
|
+
|
39
|
+
if __name__ == '__main__':
|
40
|
+
None
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
from typing import List, Callable
|
4
|
+
from enum import Enum
|
5
|
+
|
6
|
+
class ContextSource(Enum):
|
7
|
+
PROMPT_GENERATED = "prompt_generated"
|
8
|
+
EXTERNAL_KNOWLEDGE = "external_knowledge"
|
9
|
+
DYNAMIC_ASSEMBLED = "dynamic_assembled"
|
10
|
+
|
11
|
+
class ContextRetrieval:
|
12
|
+
def __init__(self, context_manager):
|
13
|
+
self.context_manager = context_manager
|
14
|
+
# 注册外部知识检索器(示例接口)
|
15
|
+
self.external_retrievers = {
|
16
|
+
"default": self._default_external_retriever
|
17
|
+
}
|
18
|
+
|
19
|
+
def generate_prompt_based_context(self, task_type: str, reasoning_framework: str = "basic") -> str:
|
20
|
+
"""基于提示的生成:创建任务优化的指令框架
|
21
|
+
Args:
|
22
|
+
task_type: 任务类型,如"text_classification"、"nl2sql"、"summarization"
|
23
|
+
reasoning_framework: 推理框架类型,如"basic"、"chain_of_thought"、"tree_of_thought"
|
24
|
+
Returns:
|
25
|
+
生成的提示上下文字符串
|
26
|
+
"""
|
27
|
+
# 基础提示模板库
|
28
|
+
prompt_templates = {
|
29
|
+
"text_classification": """你是一个文本分类专家。基于以下上下文信息,将文本分类到预定义类别中:
|
30
|
+
{context}
|
31
|
+
文本:{input}
|
32
|
+
要求:输出最可能的类别名称,无需解释。""",
|
33
|
+
"nl2sql": """你是一个SQL生成专家。基于以下数据库模式信息,将自然语言转换为SQL查询:
|
34
|
+
{context}
|
35
|
+
用户问题:{input}
|
36
|
+
要求:输出标准SQL,不包含解释和多余文本。""",
|
37
|
+
"summarization": """你是一个文本摘要专家。基于以下上下文信息,生成简洁准确的摘要:
|
38
|
+
{context}
|
39
|
+
文本:{input}
|
40
|
+
要求:摘要长度不超过{max_length}字,保留关键信息。"""
|
41
|
+
}
|
42
|
+
|
43
|
+
# 推理框架增强
|
44
|
+
reasoning_enhancements = {
|
45
|
+
"basic": "",
|
46
|
+
"chain_of_thought": "思考过程:让我逐步分析...",
|
47
|
+
"tree_of_thought": "可能的思考方向:\n1. ...\n2. ...\n结论:..."
|
48
|
+
}
|
49
|
+
|
50
|
+
# 获取基础模板
|
51
|
+
base_template = prompt_templates.get(task_type, prompt_templates["text_classification"])
|
52
|
+
# 添加推理框架
|
53
|
+
enhanced_template = f"{base_template}\n{reasoning_enhancements.get(reasoning_framework, '')}"
|
54
|
+
|
55
|
+
# 存储生成的提示模板到上下文
|
56
|
+
self.context_manager.set(f"prompt_template_{task_type}", enhanced_template)
|
57
|
+
return enhanced_template
|
58
|
+
|
59
|
+
def retrieve_external_knowledge(self, query: str, retriever_name: str = "default", **kwargs) -> str:
|
60
|
+
"""外部知识检索:访问动态信息源
|
61
|
+
Args:
|
62
|
+
query: 检索查询词
|
63
|
+
retriever_name: 检索器名称
|
64
|
+
**kwargs: 检索参数(如top_k、filter条件等)
|
65
|
+
Returns:
|
66
|
+
检索到的知识文本
|
67
|
+
"""
|
68
|
+
if retriever_name not in self.external_retrievers:
|
69
|
+
raise ValueError(f"Retriever {retriever_name} not registered")
|
70
|
+
|
71
|
+
# 调用注册的检索器
|
72
|
+
knowledge = self.external_retrievers[retriever_name](query, **kwargs)
|
73
|
+
# 存储检索结果到上下文
|
74
|
+
self.context_manager.set(f"external_knowledge_{query[:30]}", knowledge)
|
75
|
+
return knowledge
|
76
|
+
|
77
|
+
def assemble_dynamic_context(self, context_ids: List[str], assembly_strategy: str = "sequential") -> str:
|
78
|
+
"""动态上下文组装:将多个上下文组件整合成优化的输入
|
79
|
+
Args:
|
80
|
+
context_ids: 上下文组件ID列表
|
81
|
+
assembly_strategy: 组装策略,如"sequential"、"priority_based"、"summary_based"
|
82
|
+
Returns:
|
83
|
+
组装后的完整上下文
|
84
|
+
"""
|
85
|
+
# 获取所有上下文组件
|
86
|
+
context_components = []
|
87
|
+
for cid in context_ids:
|
88
|
+
component = self.context_manager.get(cid)
|
89
|
+
if component:
|
90
|
+
context_components.append((cid, component))
|
91
|
+
|
92
|
+
# 应用组装策略
|
93
|
+
if assembly_strategy == "sequential":
|
94
|
+
assembled = "\n\n".join([f"[{cid}]: {comp}" for cid, comp in context_components])
|
95
|
+
elif assembly_strategy == "priority_based":
|
96
|
+
# 按ID中包含的优先级关键词排序
|
97
|
+
context_components.sort(key=lambda x: "priority" in x[0], reverse=True)
|
98
|
+
assembled = "\n\n".join([f"[{cid}]: {comp}" for cid, comp in context_components])
|
99
|
+
elif assembly_strategy == "summary_based":
|
100
|
+
# 生成组件摘要(简化实现)
|
101
|
+
summaries = [f"[{cid}摘要]: {comp[:100]}..." for cid, comp in context_components]
|
102
|
+
assembled = "\n\n".join(summaries + ["\n完整内容:\n" + "\n\n".join([comp for _, comp in context_components])])
|
103
|
+
else:
|
104
|
+
assembled = "\n\n".join([comp for _, comp in context_components])
|
105
|
+
|
106
|
+
# 存储组装结果
|
107
|
+
self.context_manager.set("assembled_context", assembled)
|
108
|
+
return assembled
|
109
|
+
|
110
|
+
def _default_external_retriever(self, query: str, top_k: int = 3) -> str:
|
111
|
+
"""默认外部知识检索器(示例实现)
|
112
|
+
实际应用中可替换为调用搜索引擎、数据库或API
|
113
|
+
"""
|
114
|
+
# 模拟外部检索结果
|
115
|
+
mock_knowledge = [
|
116
|
+
f"[检索结果1] 关于'{query}'的信息:这是模拟的外部知识,实际应用中应替换为真实API调用。",
|
117
|
+
f"[检索结果2] 相关数据:{len(query)}个字符,{query.count(' ')+1}个词。",
|
118
|
+
f"[检索结果3] 时间戳:{self.context_manager.get('current_timestamp', '未知')}"
|
119
|
+
]
|
120
|
+
return "\n\n".join(mock_knowledge[:top_k])
|
121
|
+
|
122
|
+
def register_retriever(self, name: str, retriever_func: Callable) -> None:
|
123
|
+
"""注册自定义外部知识检索器"""
|
124
|
+
self.external_retrievers[name] = retriever_func
|
125
|
+
|
126
|
+
|
127
|
+
def test():
|
128
|
+
print()
|
129
|
+
|
130
|
+
|
131
|
+
if __name__ == '__main__':
|
132
|
+
None
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
from dotenv import load_dotenv
|
3
|
+
from .shared.utils import str_to_bool
|
4
|
+
import os
|
5
|
+
load_dotenv()
|
6
|
+
|
7
|
+
TOP_K = int(os.environ.get("DEFAULT_TOP_K", 3))
|
8
|
+
DISTANCE_THRESHOLD = float(os.environ.get("DEFAULT_DISTANCE_THRESHOLD", 0.30))
|
9
|
+
REDIS_URL = os.environ.get("REDIS_URL", "redis://:redis@192.168.65.166:6377")
|
10
|
+
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
|
11
|
+
CHUNK_SIZE = int(os.environ.get("DEFAULT_CHUNK_SIZE", 500))
|
12
|
+
CHUNKING_TECHNIQUE = os.environ.get(
|
13
|
+
"DEFAULT_CHUNKING_TECHNIQUE", "Recursive Character"
|
14
|
+
)
|
15
|
+
USE_SEMANTIC_CACHE = str_to_bool(
|
16
|
+
os.environ.get("DEFAULT_USE_SEMANTIC_CACHE")
|
17
|
+
)
|
18
|
+
USE_RERANKERS = str_to_bool(os.environ.get("DEFAULT_USE_RERANKERS"))
|
19
|
+
RERANKER_MODEL = os.environ.get("DEFAULT_RERANKER_MODEL", "D:/model/Qwen3-Reranker-0.6B")
|
20
|
+
RERANKER_TYPE = os.environ.get("DEFAULT_RERANKER_TYPE", "HuggingFace")
|
21
|
+
USE_CHAT_HISTORY = str_to_bool(os.environ.get("DEFAULT_USE_CHAT_HISTORY"))
|
22
|
+
USE_RAGAS = str_to_bool(os.environ.get("DEFAULT_USE_RAGAS"))
|
23
|
+
EMBEDDING_MODEL_PROVIDER = "openai"
|
24
|
+
EMBEDDING_MODEL = os.environ.get("EMBEDDING_MODEL", "D:/model/Qwen3-Embedding-0.6B")
|
@@ -0,0 +1,247 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
import os.path
|
3
|
+
from typing import List
|
4
|
+
|
5
|
+
from langchain.chains import create_retrieval_chain
|
6
|
+
from langchain.chains.combine_documents import create_stuff_documents_chain
|
7
|
+
from langchain_core.prompts import ChatPromptTemplate
|
8
|
+
from langchain_openai import (
|
9
|
+
OpenAIEmbeddings,
|
10
|
+
)
|
11
|
+
from langchain_redis import RedisChatMessageHistory, RedisVectorStore
|
12
|
+
from langchain_core.messages.chat import ChatMessage
|
13
|
+
from redisvl.extensions.llmcache import SemanticCache
|
14
|
+
from redisvl.utils.rerank import HFCrossEncoderReranker
|
15
|
+
from redisvl.utils.utils import create_ulid
|
16
|
+
from .shared.cached_llm import CachedLLM
|
17
|
+
from .shared.logger import logger
|
18
|
+
from . import env
|
19
|
+
|
20
|
+
os.environ["TOKENIZERS_PARALLELISM"] = "false"
|
21
|
+
|
22
|
+
class Session:
|
23
|
+
def __init__(self, llm, session_id = None, embedding = None, rerankers = None) -> None:
|
24
|
+
missing_vars = []
|
25
|
+
self.session_id = create_ulid() if session_id is None else session_id
|
26
|
+
self.redis_url = env.REDIS_URL
|
27
|
+
self.openai_api_key = env.OPENAI_API_KEY
|
28
|
+
|
29
|
+
self.initialized = False
|
30
|
+
self.RERANKERS = {}
|
31
|
+
if rerankers and env.USE_RERANKERS:
|
32
|
+
self.RERANKERS = rerankers
|
33
|
+
|
34
|
+
# Initialize non-API dependent variables
|
35
|
+
self.chunk_size = env.CHUNK_SIZE
|
36
|
+
self.chunking_technique = env.CHUNKING_TECHNIQUE
|
37
|
+
self.chat_history = None
|
38
|
+
self.N = 0
|
39
|
+
self.count = 0
|
40
|
+
self.use_semantic_cache = env.USE_SEMANTIC_CACHE
|
41
|
+
self.use_rerankers = env.USE_RERANKERS
|
42
|
+
self.top_k = env.TOP_K
|
43
|
+
self.distance_threshold = env.DISTANCE_THRESHOLD
|
44
|
+
self.use_chat_history = env.USE_CHAT_HISTORY
|
45
|
+
self.use_ragas = env.USE_RERANKERS
|
46
|
+
self.reranker_type = env.RERANKER_TYPE
|
47
|
+
logger.info("Initializing LLM")
|
48
|
+
self.llm = llm.get('llm')
|
49
|
+
self.llm_provider = llm.get('provider')
|
50
|
+
if not self.llm or not self.llm_provider:
|
51
|
+
missing_vars.append(llm)
|
52
|
+
self.cached_llm = None
|
53
|
+
self.vector_store = None
|
54
|
+
self.llmcache = None
|
55
|
+
self.index_name = None
|
56
|
+
if embedding:
|
57
|
+
self.embedding_model_provider = embedding['provider']
|
58
|
+
self.embedding = embedding['embedding']
|
59
|
+
else:
|
60
|
+
self.embedding = self.get_embedding_model()
|
61
|
+
self.embedding_model_provider = env.EMBEDDING_MODEL_PROVIDER
|
62
|
+
|
63
|
+
if missing_vars:
|
64
|
+
raise ValueError(f"模型初始化记忆发生异常,未设置必要的环境变量或传入的{missing_vars}不正确")
|
65
|
+
|
66
|
+
def initialize(self):
|
67
|
+
# Initialize rerankers
|
68
|
+
if self.use_rerankers:
|
69
|
+
logger.info("Initializing rerankers")
|
70
|
+
|
71
|
+
self.RERANKERS = {
|
72
|
+
"HuggingFace": HFCrossEncoderReranker(env.RERANKER_MODEL),
|
73
|
+
}
|
74
|
+
logger.info("Rerankers initialized")
|
75
|
+
|
76
|
+
# Init chat history if use_chat_history is True
|
77
|
+
if self.use_chat_history:
|
78
|
+
self.chat_history = RedisChatMessageHistory(
|
79
|
+
session_id=self.session_id,
|
80
|
+
redis_url=self.redis_url,
|
81
|
+
index_name="chat_history", # Use a common index for all chat histories
|
82
|
+
)
|
83
|
+
chats = {"session_id": self.session_id, "chat_history": self.chat_history}
|
84
|
+
logger.debug(f"加载对话历史,{chats}")
|
85
|
+
else:
|
86
|
+
self.chat_history = None
|
87
|
+
|
88
|
+
self.initialized = True
|
89
|
+
|
90
|
+
def get_embedding_model(self):
|
91
|
+
"""Get the right embedding model based on settings and config"""
|
92
|
+
print(
|
93
|
+
f"Embeddings for provider: {env.EMBEDDING_MODEL_PROVIDER} and model: {env.EMBEDDING_MODEL}"
|
94
|
+
)
|
95
|
+
match env.EMBEDDING_MODEL_PROVIDER.lower():
|
96
|
+
case "openai":
|
97
|
+
return OpenAIEmbeddings(model=env.EMBEDDING_MODEL)
|
98
|
+
|
99
|
+
return None
|
100
|
+
|
101
|
+
def build_chain(self, history: List[ChatMessage]):
|
102
|
+
retriever = self.vector_store.as_retriever(search_kwargs={"k": self.top_k})
|
103
|
+
|
104
|
+
messages = [
|
105
|
+
(
|
106
|
+
"system",
|
107
|
+
"""You are a helpful AI assistant. Use the following pieces of
|
108
|
+
context to answer the user's question. If you don't know the
|
109
|
+
answer, just say that you don't know, don't try to make up an
|
110
|
+
answer. Please be as detailed as possible with your
|
111
|
+
answers.""",
|
112
|
+
),
|
113
|
+
("system", "Context: {context}"),
|
114
|
+
]
|
115
|
+
|
116
|
+
if self.use_chat_history:
|
117
|
+
for msg in history:
|
118
|
+
messages.append((msg["role"], msg["content"]))
|
119
|
+
|
120
|
+
messages.append(("human", "{input}"))
|
121
|
+
messages.append(
|
122
|
+
(
|
123
|
+
"system",
|
124
|
+
"Provide a helpful and accurate answer based on the given context and question:",
|
125
|
+
)
|
126
|
+
)
|
127
|
+
prompt = ChatPromptTemplate.from_messages(messages)
|
128
|
+
|
129
|
+
combine_docs_chain = create_stuff_documents_chain(self.cached_llm, prompt)
|
130
|
+
rag_chain = create_retrieval_chain(retriever, combine_docs_chain)
|
131
|
+
|
132
|
+
return rag_chain
|
133
|
+
|
134
|
+
def update_chat_history(
|
135
|
+
self, history: List[ChatMessage], use_chat_history: bool
|
136
|
+
):
|
137
|
+
self.use_chat_history = use_chat_history
|
138
|
+
|
139
|
+
if self.use_chat_history:
|
140
|
+
if self.chat_history is None:
|
141
|
+
self.chat_history = RedisChatMessageHistory(
|
142
|
+
session_id=self.session_id,
|
143
|
+
redis_url=self.redis_url,
|
144
|
+
index_name="chat_history",
|
145
|
+
)
|
146
|
+
|
147
|
+
else:
|
148
|
+
if self.chat_history:
|
149
|
+
try:
|
150
|
+
self.chat_history.clear()
|
151
|
+
except Exception as e:
|
152
|
+
logger.debug(f"清理会话历史异常: {str(e)}")
|
153
|
+
|
154
|
+
history.clear()
|
155
|
+
|
156
|
+
return history
|
157
|
+
|
158
|
+
def get_chat_history(self):
|
159
|
+
if self.chat_history and self.use_chat_history:
|
160
|
+
messages = self.chat_history.messages
|
161
|
+
formatted_history = []
|
162
|
+
for msg in messages:
|
163
|
+
if msg.type == "human":
|
164
|
+
formatted_history.append(f"👤 **Human**: {msg.content}\n")
|
165
|
+
elif msg.type == "ai":
|
166
|
+
formatted_history.append(f"🤖 **AI**: {msg.content}\n")
|
167
|
+
return "\n".join(formatted_history)
|
168
|
+
return "No chat history available."
|
169
|
+
|
170
|
+
def update_top_k(self, new_top_k: int):
|
171
|
+
self.top_k = new_top_k
|
172
|
+
|
173
|
+
def make_semantic_cache(self) -> SemanticCache:
|
174
|
+
semantic_cache_index_name = f"llmcache:{self.index_name}"
|
175
|
+
return SemanticCache(
|
176
|
+
name=semantic_cache_index_name,
|
177
|
+
redis_url=self.redis_url,
|
178
|
+
distance_threshold=self.distance_threshold,
|
179
|
+
)
|
180
|
+
|
181
|
+
def clear_semantic_cache(self):
|
182
|
+
# Always make a new SemanticCache in case use_semantic_cache is False
|
183
|
+
semantic_cache = self.make_semantic_cache()
|
184
|
+
semantic_cache.clear()
|
185
|
+
|
186
|
+
def update_semantic_cache(self, use_semantic_cache: bool):
|
187
|
+
self.use_semantic_cache = use_semantic_cache
|
188
|
+
if self.use_semantic_cache and self.index_name:
|
189
|
+
self.llmcache = self.make_semantic_cache()
|
190
|
+
else:
|
191
|
+
self.llmcache = None
|
192
|
+
|
193
|
+
|
194
|
+
def update_distance_threshold(self, new_threshold: float):
|
195
|
+
self.distance_threshold = new_threshold
|
196
|
+
if self.index_name:
|
197
|
+
self.llmcache = self.make_semantic_cache()
|
198
|
+
self.update_llm()
|
199
|
+
|
200
|
+
def get_last_cache_status(self) -> bool:
|
201
|
+
if isinstance(self.cached_llm, CachedLLM):
|
202
|
+
return self.cached_llm.get_last_cache_status()
|
203
|
+
return False
|
204
|
+
|
205
|
+
def rerank_results(self, query, results):
|
206
|
+
if not self.use_reranker:
|
207
|
+
return results, None, None
|
208
|
+
|
209
|
+
reranker = self.RERANKERS[self.reranker_type]
|
210
|
+
original_results = [r.page_content for r in results]
|
211
|
+
|
212
|
+
reranked_results, scores = reranker.rank(query=query, docs=original_results)
|
213
|
+
|
214
|
+
# Reconstruct the results with reranked order, using fuzzy matching
|
215
|
+
reranked_docs = []
|
216
|
+
for reranked in reranked_results:
|
217
|
+
reranked_content = (
|
218
|
+
reranked["content"] if isinstance(reranked, dict) else reranked
|
219
|
+
)
|
220
|
+
best_match = max(
|
221
|
+
results, key=lambda r: self.similarity(r.page_content, reranked_content)
|
222
|
+
)
|
223
|
+
reranked_docs.append(best_match)
|
224
|
+
|
225
|
+
rerank_info = {
|
226
|
+
"original_order": original_results,
|
227
|
+
"reranked_order": [
|
228
|
+
r["content"] if isinstance(r, dict) else r for r in reranked_results
|
229
|
+
],
|
230
|
+
"original_scores": [1.0]
|
231
|
+
* len(results), # Assuming original scores are not available
|
232
|
+
"reranked_scores": scores,
|
233
|
+
}
|
234
|
+
|
235
|
+
return reranked_docs, rerank_info, original_results
|
236
|
+
|
237
|
+
def similarity(self, s1, s2):
|
238
|
+
# Simple similarity measure based on common words
|
239
|
+
words1 = set(s1.lower().split())
|
240
|
+
words2 = set(s2.lower().split())
|
241
|
+
return len(words1.intersection(words2)) / len(words1.union(words2))
|
242
|
+
|
243
|
+
def rerankers(self):
|
244
|
+
return self.RERANKERS
|
245
|
+
|
246
|
+
def update_embedding_model_provider(self, new_provider: str):
|
247
|
+
self.embedding_model_provider = new_provider
|
@@ -0,0 +1 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
from typing import Any, Optional
|
3
|
+
|
4
|
+
from langchain_core.prompt_values import ChatPromptValue, StringPromptValue
|
5
|
+
from langchain_core.runnables.base import Runnable
|
6
|
+
from langchain_core.runnables.config import RunnableConfig
|
7
|
+
|
8
|
+
|
9
|
+
class CachedLLM(Runnable):
|
10
|
+
def __init__(self, llm, llmcache):
|
11
|
+
self.llm = llm
|
12
|
+
self.llmcache = llmcache
|
13
|
+
self.last_is_cache_hit = False
|
14
|
+
|
15
|
+
def invoke(
|
16
|
+
self, input: Any, config: Optional[RunnableConfig] = None, **kwargs
|
17
|
+
) -> str:
|
18
|
+
if isinstance(input, dict):
|
19
|
+
question = input.get("query") or input.get("input")
|
20
|
+
elif isinstance(input, str):
|
21
|
+
question = input
|
22
|
+
elif isinstance(input, StringPromptValue):
|
23
|
+
question = input.text
|
24
|
+
elif isinstance(input, ChatPromptValue):
|
25
|
+
# Extract the last human message from the chat history
|
26
|
+
human_message = next(
|
27
|
+
m for m in reversed(input.messages) if m.type == "human"
|
28
|
+
)
|
29
|
+
question = human_message.content.strip()
|
30
|
+
else:
|
31
|
+
raise ValueError(f"Unexpected input type: {type(input)}")
|
32
|
+
|
33
|
+
if not isinstance(question, str):
|
34
|
+
raise TypeError(f"Question must be a string, got {type(question)}")
|
35
|
+
|
36
|
+
cached_responses = self.llmcache.check(
|
37
|
+
prompt=question, return_fields=["prompt", "response", "metadata"]
|
38
|
+
)
|
39
|
+
if cached_responses:
|
40
|
+
self.last_is_cache_hit = True
|
41
|
+
return cached_responses[0]["response"]
|
42
|
+
|
43
|
+
self.last_is_cache_hit = False
|
44
|
+
response = self.llm.invoke(input, **kwargs)
|
45
|
+
text = response.content if hasattr(response, "content") else str(response)
|
46
|
+
self.llmcache.store(prompt=question, response=text)
|
47
|
+
return text
|
48
|
+
|
49
|
+
def get_last_cache_status(self) -> bool:
|
50
|
+
return self.last_is_cache_hit
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
from typing import List
|
3
|
+
|
4
|
+
from langchain_core.prompts import ChatPromptTemplate
|
5
|
+
from langchain_redis import RedisVectorStore
|
6
|
+
from redisvl.index import SearchIndex
|
7
|
+
from . import logger
|
8
|
+
|
9
|
+
class Memory:
|
10
|
+
index: SearchIndex
|
11
|
+
def __init__(self, redis_url: str):
|
12
|
+
logger.info(f"初始化记忆模块,Redis URL: {redis_url}")
|
13
|
+
self.redis_url = redis_url
|
14
|
+
|
15
|
+
@property
|
16
|
+
def client(self):
|
17
|
+
"""Redis client accessor."""
|
18
|
+
return self.index.client
|
19
|
+
|
20
|
+
def _check_vector_store_exists(self, index_name: str) -> bool:
|
21
|
+
"""Check if a vector store exists for the given index name."""
|
22
|
+
try:
|
23
|
+
self.client.ft(index_name).info()
|
24
|
+
return True
|
25
|
+
except Exception:
|
26
|
+
return False
|
27
|
+
|
28
|
+
def _cleanup_vector_store(self, index_name: str) -> bool:
|
29
|
+
"""Clean up the vector store index and its documents."""
|
30
|
+
if not self._check_vector_store_exists(index_name):
|
31
|
+
return True
|
32
|
+
|
33
|
+
try:
|
34
|
+
self.client.ft(index_name).dropindex(delete_documents=True)
|
35
|
+
logger.info(f"Successfully cleaned up vector store: {index_name}")
|
36
|
+
return True
|
37
|
+
except Exception as e:
|
38
|
+
logger.warning(f"Could not clean up vector store {index_name}: {e}")
|
39
|
+
return False
|
40
|
+
|
41
|
+
def get_chat_history(chat_history, use_chat_history: bool):
|
42
|
+
if chat_history and use_chat_history:
|
43
|
+
messages = chat_history.messages
|
44
|
+
formatted_history = []
|
45
|
+
for msg in messages:
|
46
|
+
if msg.type == "human":
|
47
|
+
formatted_history.append(f"👤 **Human**: {msg.content}\n")
|
48
|
+
elif msg.type == "ai":
|
49
|
+
formatted_history.append(f"🤖 **AI**: {msg.content}\n")
|
50
|
+
return "\n".join(formatted_history)
|
51
|
+
return "No chat history available."
|
52
|
+
|
53
|
+
|
54
|
+
def build_chain(self, history: List[any]):
|
55
|
+
retriever = self.vector_store.as_retriever(search_kwargs={"k": self.top_k})
|
56
|
+
|
57
|
+
messages = [
|
58
|
+
(
|
59
|
+
"system",
|
60
|
+
"""You are a helpful AI assistant. Use the following pieces of
|
61
|
+
context to answer the user's question. If you don't know the
|
62
|
+
answer, just say that you don't know, don't try to make up an
|
63
|
+
answer. Please be as detailed as possible with your
|
64
|
+
answers.""",
|
65
|
+
),
|
66
|
+
("system", "Context: {context}"),
|
67
|
+
]
|
68
|
+
|
69
|
+
if self.use_chat_history:
|
70
|
+
for msg in history:
|
71
|
+
messages.append((msg["role"], msg["content"]))
|
72
|
+
|
73
|
+
messages.append(("human", "{input}"))
|
74
|
+
messages.append(
|
75
|
+
(
|
76
|
+
"system",
|
77
|
+
"Provide a helpful and accurate answer based on the given context and question:",
|
78
|
+
)
|
79
|
+
)
|
80
|
+
prompt = ChatPromptTemplate.from_messages(messages)
|
81
|
+
|
82
|
+
# combine_docs_chain = create_stuff_documents_chain(self.cached_llm, prompt)
|
83
|
+
# rag_chain = create_retrieval_chain(retriever, combine_docs_chain)
|
84
|
+
|
85
|
+
# return rag_chain
|
86
|
+
|
87
|
+
def load_vector_store(self, index_name: str, embeddings) -> RedisVectorStore:
|
88
|
+
try:
|
89
|
+
# Get the metadata
|
90
|
+
metadata = self.get_pdf_metadata(index_name)
|
91
|
+
if not metadata:
|
92
|
+
# Try to reprocess from file
|
93
|
+
return self._reprocess_from_file(index_name, embeddings)
|
94
|
+
|
95
|
+
# Check if vector store exists
|
96
|
+
documents = None
|
97
|
+
if not self._check_vector_store_exists(index_name):
|
98
|
+
logger.info(f"Vector store missing for {index_name}, reprocessing")
|
99
|
+
vector_store = RedisVectorStore.from_documents(
|
100
|
+
documents,
|
101
|
+
embeddings,
|
102
|
+
redis_url=self.redis_url,
|
103
|
+
index_name=index_name,
|
104
|
+
key_prefix=f"pdf:{index_name}",
|
105
|
+
)
|
106
|
+
logger.info(f"Created vector store during reprocessing for {index_name}")
|
107
|
+
|
108
|
+
# Vector store exists, load it
|
109
|
+
vector_store = RedisVectorStore(
|
110
|
+
embeddings,
|
111
|
+
redis_url=self.redis_url,
|
112
|
+
index_name=index_name,
|
113
|
+
key_prefix=f"pdf:{index_name}",
|
114
|
+
)
|
115
|
+
|
116
|
+
logger.info(f"Successfully loaded PDF: {metadata.filename}")
|
117
|
+
return vector_store
|
118
|
+
|
119
|
+
except Exception as e:
|
120
|
+
logger.error(f"Failed to load PDF {index_name}: {e}")
|
121
|
+
raise
|
122
|
+
|
123
|
+
if __name__ == '__main__':
|
124
|
+
None
|
@@ -0,0 +1,123 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: llm-hippocampus
|
3
|
+
Version: 0.0.1
|
4
|
+
Summary: LLM Hippocampus — a Context Engineering playground
|
5
|
+
Home-page:
|
6
|
+
Author: joelz
|
7
|
+
Author-email: joelz <zhongbj_2621@163.com>
|
8
|
+
Project-URL: Repository, https://github.com/redis-developer/redis-rag-workbench.git
|
9
|
+
Project-URL: Bug Tracker, https://github.com/redis-developer/redis-rag-workbench/issues
|
10
|
+
Keywords: python,redis,langchain,openai
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
12
|
+
Classifier: Intended Audience :: Developers
|
13
|
+
Classifier: Programming Language :: Python
|
14
|
+
Requires-Python: >=3.11
|
15
|
+
Description-Content-Type: text/markdown
|
16
|
+
License-File: LICENSE
|
17
|
+
Requires-Dist: openai>=1.63.0
|
18
|
+
Requires-Dist: python-dotenv>=1.0.0
|
19
|
+
Requires-Dist: langchain>=0.3.19
|
20
|
+
Requires-Dist: tiktoken>=0.9.0
|
21
|
+
Requires-Dist: redis>=5.2.1
|
22
|
+
Requires-Dist: langchain-community>=0.3.18
|
23
|
+
Requires-Dist: langchain-huggingface>=0.1.2
|
24
|
+
Requires-Dist: langchain-openai>=0.3.6
|
25
|
+
Requires-Dist: langchain-experimental>=0.3.4
|
26
|
+
Requires-Dist: python-ulid>=2.7.0
|
27
|
+
Requires-Dist: pandas==2.2.3
|
28
|
+
Requires-Dist: hf-xet>=1.1.8
|
29
|
+
Requires-Dist: redisvl>=0.8.2
|
30
|
+
Requires-Dist: sentence-transformers>=5.1.0
|
31
|
+
Requires-Dist: langchain-redis>=0.2.3
|
32
|
+
Provides-Extra: dev
|
33
|
+
Requires-Dist: mypy<2.0.0,>=1.8.0; extra == "dev"
|
34
|
+
Requires-Dist: ruff<1.0.0,>=0.2.2; extra == "dev"
|
35
|
+
Dynamic: author
|
36
|
+
Dynamic: license-file
|
37
|
+
Dynamic: requires-python
|
38
|
+
|
39
|
+
<div align="center">
|
40
|
+
<h1>🚀 LLM Hippocampus</h1>
|
41
|
+
|
42
|
+
[](https://opensource.org/licenses/MIT)
|
43
|
+

|
44
|
+

|
45
|
+

|
46
|
+
|
47
|
+
🎯 Build up and manage the LLM 's memory
|
48
|
+
|
49
|
+
</div>
|
50
|
+
|
51
|
+
🔥 **LLM Hippocampus** helping your project for building and experimenting with **Context Engineering** applications. harness the full power of Redis for **lightning-fast vector search**, **intelligent semantic caching**, **persistent LLM memory**, and **smart context engineering **.
|
52
|
+
|
53
|
+
✨ **What makes this special?**
|
54
|
+
- 🚀 **One-command setup** - pip install llm-hippocampus
|
55
|
+
- ⚡ **LLM support** - OpenAI
|
56
|
+
- 🎯 **Redis-powered** - Vector search, caching, and memory management
|
57
|
+
- 🐳 **Docker ready** - Building...
|
58
|
+
- 🔧 **Developer-first** - Support to Hot load by installing llm-hippocampus
|
59
|
+
|
60
|
+
---
|
61
|
+
|
62
|
+
## Table of Contents
|
63
|
+
|
64
|
+
- [Quick Start](#quick-start)
|
65
|
+
- [Prerequisites](#prerequisites)
|
66
|
+
- [Getting Started](#getting-started)
|
67
|
+
- [Available Commands](#available-commands)
|
68
|
+
- [Development Workflows](#development-workflows)
|
69
|
+
- [Environment Configuration](#environment-configuration)
|
70
|
+
- [Using Google VertexAI](#using-google-vertexai)
|
71
|
+
- [Project Structure](#project-structure)
|
72
|
+
- [Connecting to Redis Cloud](#connecting-to-redis-cloud)
|
73
|
+
- [Troubleshooting](#troubleshooting)
|
74
|
+
- [Contributing](#contributing)
|
75
|
+
- [License](#license)
|
76
|
+
- [Learn More](#learn-more)
|
77
|
+
|
78
|
+
|
79
|
+
## Quick Start
|
80
|
+
|
81
|
+
**Get up and install in your project:**
|
82
|
+
|
83
|
+
```bash
|
84
|
+
pip install llm-hippocampus
|
85
|
+
or
|
86
|
+
uv add llm-hippocampus
|
87
|
+
```
|
88
|
+
|
89
|
+
Welcome to LLM Hippocampus! 🎉
|
90
|
+
|
91
|
+
---
|
92
|
+
|
93
|
+
## Prerequisites
|
94
|
+
|
95
|
+
1. Make sure you have the following tools available:
|
96
|
+
- [python](https://www.docker.com/products/docker-desktop/) 3.11+
|
97
|
+
- [uv](https://docs.astral.sh/uv/)
|
98
|
+
- [Redis Stack](https://redis.io/)
|
99
|
+
2. Setup one or more of the following:
|
100
|
+
- [OpenAI API](https://platform.openai.com/)
|
101
|
+
- You will need an API Key
|
102
|
+
|
103
|
+
## Getting Started
|
104
|
+
|
105
|
+
|
106
|
+
### Development Workflows
|
107
|
+
- Building
|
108
|
+
|
109
|
+
|
110
|
+
## Project Structure
|
111
|
+
|
112
|
+
|
113
|
+
## Contributing
|
114
|
+
|
115
|
+
🤝 Contributions are welcome! Please feel free to submit a Pull Request.
|
116
|
+
|
117
|
+
## License
|
118
|
+
|
119
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
120
|
+
|
121
|
+
## Troubleshooting
|
122
|
+
|
123
|
+
## Learn More
|
@@ -0,0 +1,21 @@
|
|
1
|
+
LICENSE
|
2
|
+
README.md
|
3
|
+
pyproject.toml
|
4
|
+
setup.py
|
5
|
+
llm_hippocampus/__init__.py
|
6
|
+
llm_hippocampus/env.py
|
7
|
+
llm_hippocampus/session.py
|
8
|
+
llm_hippocampus.egg-info/PKG-INFO
|
9
|
+
llm_hippocampus.egg-info/SOURCES.txt
|
10
|
+
llm_hippocampus.egg-info/dependency_links.txt
|
11
|
+
llm_hippocampus.egg-info/requires.txt
|
12
|
+
llm_hippocampus.egg-info/top_level.txt
|
13
|
+
llm_hippocampus/context/__init__.py
|
14
|
+
llm_hippocampus/context/context_manager.py
|
15
|
+
llm_hippocampus/context/context_processing.py
|
16
|
+
llm_hippocampus/context/context_retrieval.py
|
17
|
+
llm_hippocampus/shared/__init__.py
|
18
|
+
llm_hippocampus/shared/cached_llm.py
|
19
|
+
llm_hippocampus/shared/logger.py
|
20
|
+
llm_hippocampus/shared/memory.py
|
21
|
+
llm_hippocampus/shared/utils.py
|
@@ -0,0 +1 @@
|
|
1
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
openai>=1.63.0
|
2
|
+
python-dotenv>=1.0.0
|
3
|
+
langchain>=0.3.19
|
4
|
+
tiktoken>=0.9.0
|
5
|
+
redis>=5.2.1
|
6
|
+
langchain-community>=0.3.18
|
7
|
+
langchain-huggingface>=0.1.2
|
8
|
+
langchain-openai>=0.3.6
|
9
|
+
langchain-experimental>=0.3.4
|
10
|
+
python-ulid>=2.7.0
|
11
|
+
pandas==2.2.3
|
12
|
+
hf-xet>=1.1.8
|
13
|
+
redisvl>=0.8.2
|
14
|
+
sentence-transformers>=5.1.0
|
15
|
+
langchain-redis>=0.2.3
|
16
|
+
|
17
|
+
[dev]
|
18
|
+
mypy<2.0.0,>=1.8.0
|
19
|
+
ruff<1.0.0,>=0.2.2
|
@@ -0,0 +1 @@
|
|
1
|
+
llm_hippocampus
|
@@ -0,0 +1,67 @@
|
|
1
|
+
[project]
|
2
|
+
name = "llm-hippocampus"
|
3
|
+
version = "0.0.1"
|
4
|
+
description = "LLM Hippocampus — a Context Engineering playground"
|
5
|
+
authors = [
|
6
|
+
{ name = "joelz", email = "zhongbj_2621@163.com" }
|
7
|
+
]
|
8
|
+
readme = "README.md"
|
9
|
+
requires-python=">=3.11,<3.14"
|
10
|
+
keywords = ["python", "redis", "langchain", "openai"]
|
11
|
+
classifiers = [
|
12
|
+
"Development Status :: 4 - Beta",
|
13
|
+
"Intended Audience :: Developers",
|
14
|
+
"Programming Language :: Python"
|
15
|
+
]
|
16
|
+
dependencies = [
|
17
|
+
"openai>=1.63.0",
|
18
|
+
"python-dotenv>=1.0.0",
|
19
|
+
"langchain>=0.3.19",
|
20
|
+
"tiktoken>=0.9.0",
|
21
|
+
"redis>=5.2.1",
|
22
|
+
"langchain-community>=0.3.18",
|
23
|
+
"langchain-huggingface>=0.1.2",
|
24
|
+
"langchain-openai>=0.3.6",
|
25
|
+
"langchain-experimental>=0.3.4",
|
26
|
+
"python-ulid>=2.7.0",
|
27
|
+
"pandas==2.2.3",
|
28
|
+
"hf-xet>=1.1.8",
|
29
|
+
"redisvl>=0.8.2",
|
30
|
+
"sentence-transformers>=5.1.0",
|
31
|
+
"langchain-redis>=0.2.3",
|
32
|
+
]
|
33
|
+
|
34
|
+
[project.urls]
|
35
|
+
Repository = "https://github.com/redis-developer/redis-rag-workbench.git"
|
36
|
+
"Bug Tracker" = "https://github.com/redis-developer/redis-rag-workbench/issues"
|
37
|
+
|
38
|
+
[project.optional-dependencies]
|
39
|
+
dev = [
|
40
|
+
"mypy<2.0.0,>=1.8.0",
|
41
|
+
"ruff<1.0.0,>=0.2.2",
|
42
|
+
]
|
43
|
+
|
44
|
+
[tool.ruff]
|
45
|
+
target-version = "py38"
|
46
|
+
|
47
|
+
[tool.ruff.lint]
|
48
|
+
select = [
|
49
|
+
"E", # pycodestyle errors
|
50
|
+
"W", # pycodestyle warnings
|
51
|
+
"F", # pyflakes
|
52
|
+
"I", # isort
|
53
|
+
"B", # flake8-bugbear
|
54
|
+
"C4", # flake8-comprehensions
|
55
|
+
"UP", # pyupgrade
|
56
|
+
"ARG001", # unused arguments in functions
|
57
|
+
]
|
58
|
+
ignore = [
|
59
|
+
"E501", # line too long, handled by black
|
60
|
+
"B008", # do not perform function calls in argument defaults
|
61
|
+
"W191", # indentation contains tabs
|
62
|
+
"B904", # Allow raising exceptions without from e, for HTTPException
|
63
|
+
]
|
64
|
+
|
65
|
+
[tool.ruff.lint.pyupgrade]
|
66
|
+
# Preserve types, even if a file imports `from __future__ import annotations`.
|
67
|
+
keep-runtime-typing = true
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
from setuptools import setup, find_packages
|
4
|
+
|
5
|
+
setup(
|
6
|
+
name="llm-hippocampus", # 包的名字(PyPI 上必须唯一,重名会传不上去)
|
7
|
+
version="0.0.1", # 版本号(格式:主版本.次版本.修订号,比如 0.0.1)
|
8
|
+
author="joelz",
|
9
|
+
author_email="zhongbj_26210@163.com",
|
10
|
+
description="llm-hippocampus",
|
11
|
+
long_description=open("README.md", encoding="utf-8").read(), # 从 README 读取详细描述
|
12
|
+
long_description_content_type="text/markdown", # 说明 README 是 Markdown 格式
|
13
|
+
url="",
|
14
|
+
packages=find_packages(), # 自动找到所有包
|
15
|
+
classifiers=[ # 分类标签(帮助别人在 PyPI 上搜到你的包)
|
16
|
+
],
|
17
|
+
python_requires=">=3.11", # 支持的 Python 版本
|
18
|
+
install_requires=[ # 你的包依赖的其他包(比如需要 requests 就写进去)
|
19
|
+
"openai>=1.63.0",
|
20
|
+
"python-dotenv>=1.0.0",
|
21
|
+
"langchain>=0.3.19",
|
22
|
+
"tiktoken>=0.9.0",
|
23
|
+
"redis>=5.2.1",
|
24
|
+
"langchain-community>=0.3.18",
|
25
|
+
"langchain-huggingface>=0.1.2",
|
26
|
+
"langchain-openai>=0.3.6",
|
27
|
+
"langchain-experimental>=0.3.4",
|
28
|
+
"python-ulid>=2.7.0",
|
29
|
+
"pandas==2.2.3",
|
30
|
+
"hf-xet>=1.1.8",
|
31
|
+
"redisvl>=0.8.2",
|
32
|
+
"sentence-transformers>=5.1.0",
|
33
|
+
"langchain-redis>=0.2.3",
|
34
|
+
]
|
35
|
+
)
|
36
|
+
|