v0.0.5
memory
This commit is contained in:
parent
10a6a7051a
commit
434172755d
17
README.md
17
README.md
@ -1,6 +1,6 @@
|
||||
# LangChain Learning
|
||||
|
||||
[](https://github.com/your-repo/langchain-learning)
|
||||
[](https://github.com/your-repo/langchain-learning)
|
||||
[](https://www.python.org/)
|
||||
[](https://www.langchain.com/)
|
||||
|
||||
@ -8,11 +8,12 @@
|
||||
|
||||
## 功能特性
|
||||
|
||||
- **多 LLM 集成**:支持 OpenAI API、SiliconFlow 及 LangChain 抽象层
|
||||
- **多 LLM 集成**:支持 OpenAI API、Silicon Flow 及 LangChain 抽象层
|
||||
- **流式响应**:实时流式输出,带来更好的使用体验
|
||||
- **Prompt 工程**:多种 Prompt 模板构建方式
|
||||
- **输出解析**:支持 JSON 等格式解析
|
||||
- **Token 用量追踪**:轻松监控 API 调用消耗
|
||||
- **内存管理**:实现对话历史持久化(ConversationBufferMemory, SummaryMemory)
|
||||
- **实战示例**:从基础到进阶的使用模式
|
||||
|
||||
## 快速开始
|
||||
@ -23,6 +24,8 @@
|
||||
pip install langchain>=1.2.15 langchain-community>=0.4.1 langchain-siliconflow>=1.0.0 requests>=2.33.1
|
||||
```
|
||||
|
||||
***注意:*** *如果需要完整的记忆功能和更高级的模型,你可能需要安装额外的库。*
|
||||
|
||||
### 2. 配置环境变量
|
||||
|
||||
在项目根目录创建 `.env` 文件:
|
||||
@ -63,6 +66,13 @@ SILICONFLOW_BASE_URL=https://api.siliconflow.cn/v1
|
||||
|------|------|------|
|
||||
| Token 追踪 | `python token/token_demo.py` | 使用 get_openai_callback 追踪 token 消耗 |
|
||||
|
||||
**内存管理示例**
|
||||
|
||||
| 示例 | 命令 | 说明 |
|
||||
|------|------|------|
|
||||
| 基础记忆 | `python memory/memory_desc.py` | 演示不同类型的 Memory 对象。|
|
||||
| 带内存聊天 | `python memory/with_memory_demo.py` | 在对话链中管理和利用聊天历史记录。 |
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
@ -81,6 +91,9 @@ langchain-learning/
|
||||
│ └── json_parser_demo.py # JSON 输出解析示例
|
||||
├── token/
|
||||
│ └── token_demo.py # Token 用量追踪示例
|
||||
├── memory/ # 记忆管理模块
|
||||
│ ├── memory_desc.py # 演示 Memory 对象类型
|
||||
│ └── with_memory_do.py # 演示使用带内存的聊天循环
|
||||
├── main.py # 入口文件
|
||||
├── pyproject.toml # 项目配置
|
||||
└── README.md
|
||||
|
||||
37
memory/memory_demo.py
Normal file
37
memory/memory_demo.py
Normal file
@ -0,0 +1,37 @@
|
||||
import logging
|
||||
import os
|
||||
|
||||
import dotenv
|
||||
from langchain.chains.llm import LLMChain
|
||||
from langchain.memory import ConversationBufferMemory
|
||||
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG,
|
||||
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||
)
|
||||
dotenv.load_dotenv()
|
||||
|
||||
## 设置环境变量
|
||||
os.environ['OPENAI_API_KEY'] = os.getenv("SILICONFLOW_API_KEY")
|
||||
os.environ['OPENAI_BASE_URL'] = os.getenv("SILICONFLOW_BASE_URL")
|
||||
|
||||
# 默认的 'model_name': 'deepseek-ai/DeepSeek-V3.1',
|
||||
llm = ChatOpenAI(model="Qwen/Qwen3-8B")
|
||||
|
||||
prompt = ChatPromptTemplate.from_messages([
|
||||
("system", "你是一个万能的人工智能AI"),
|
||||
MessagesPlaceholder(variable_name="history"),
|
||||
("human", "问题:{question}")
|
||||
])
|
||||
|
||||
## 创建 Memory 对象
|
||||
memory = ConversationBufferMemory(return_messages=True)
|
||||
|
||||
chain = LLMChain(prompt=prompt, memory=memory, llm=llm)
|
||||
res1 = chain.invoke({"question":"我是小明"})
|
||||
print(res1)
|
||||
print()
|
||||
res2 = chain.invoke({"question":"我是谁?"})
|
||||
print(res2)
|
||||
43
memory/memory_desc.py
Normal file
43
memory/memory_desc.py
Normal file
@ -0,0 +1,43 @@
|
||||
import os
|
||||
|
||||
import dotenv
|
||||
from langchain.memory import ConversationBufferMemory, ConversationTokenBufferMemory, ConversationSummaryMemory
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
memory = ConversationBufferMemory()
|
||||
memory.chat_memory.add_user_message("我叫小明")
|
||||
memory.chat_memory.add_ai_message("噢,好的,你叫小明")
|
||||
print(memory)
|
||||
print(memory.memory_key)
|
||||
print(memory.load_memory_variables({}))
|
||||
print('---------')
|
||||
|
||||
memory2 = ConversationBufferMemory(memory_key="memory2")
|
||||
memory2.chat_memory.add_user_message("我叫小明")
|
||||
memory2.chat_memory.add_ai_message("噢,好的,你叫小明")
|
||||
print(memory2)
|
||||
print(memory2.memory_key)
|
||||
print(memory2.load_memory_variables({}))
|
||||
print('---------')
|
||||
|
||||
memory3 = ConversationBufferMemory(return_messages=True)
|
||||
memory3.chat_memory.add_user_message("我叫小明")
|
||||
memory3.chat_memory.add_ai_message("噢,好的,你叫小明")
|
||||
print(memory3)
|
||||
print(memory3.memory_key)
|
||||
print(memory3.load_memory_variables({}))
|
||||
print('---------')
|
||||
dotenv.load_dotenv()
|
||||
|
||||
## 设置环境变量
|
||||
os.environ['OPENAI_API_KEY'] = os.getenv("SILICONFLOW_API_KEY")
|
||||
os.environ['OPENAI_BASE_URL'] = os.getenv("SILICONFLOW_BASE_URL")
|
||||
|
||||
# 默认的 'model_name': 'deepseek-ai/DeepSeek-V3.1',
|
||||
llm = ChatOpenAI(model="moonshotai/Kimi-Dev-72B")
|
||||
|
||||
memory_test = ConversationSummaryMemory(llm=llm)
|
||||
memory_test.save_context({"input": "我叫小明"}, {"output": "噢,好的,你叫小明"})
|
||||
memory_test.save_context({"input": "那么你是谁呢"}, {"output": "我是一个无所不能的AI聊天助手,可以帮你解答任何问题。"})
|
||||
print(memory_test.load_memory_variables({}))
|
||||
# {'history': '\n\nThe human introduces themselves as xiaoming. The AI confirms the name and responds. The human then asks who the AI is. The AI introduces itself as an all-powerful AI chat assistant who can answer any questions.'}
|
||||
43
memory/with_memory_demo.py
Normal file
43
memory/with_memory_demo.py
Normal file
@ -0,0 +1,43 @@
|
||||
import logging
|
||||
|
||||
from langchain_core.messages import AIMessage, HumanMessage
|
||||
from langchain_core.output_parsers import JsonOutputParser
|
||||
from langchain_core.prompts import PromptTemplate, ChatPromptTemplate
|
||||
from langchain_openai import ChatOpenAI
|
||||
import os
|
||||
import dotenv
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||
)
|
||||
dotenv.load_dotenv()
|
||||
|
||||
## 设置环境变量
|
||||
os.environ['OPENAI_API_KEY'] = os.getenv("SILICONFLOW_API_KEY")
|
||||
os.environ['OPENAI_BASE_URL'] = os.getenv("SILICONFLOW_BASE_URL")
|
||||
|
||||
# 默认的 'model_name': 'deepseek-ai/DeepSeek-V3.1',
|
||||
llm = ChatOpenAI(model="Qwen/Qwen3-8B")
|
||||
|
||||
|
||||
def chat_with_llm():
|
||||
prompt_template = ChatPromptTemplate.from_messages([
|
||||
("system", "你是一个人工智能助手,你是万能的"),
|
||||
("human", "{question}")
|
||||
])
|
||||
while True:
|
||||
chain = prompt_template | llm
|
||||
user_input = input("请继续你的问题,如果没有问题了,输入 [quit] 结束会话:")
|
||||
if user_input == "quit":
|
||||
break
|
||||
response = chain.invoke({"question": user_input})
|
||||
print(f"AI:{response.content}")
|
||||
|
||||
## 将当前轮次的聊天内容(ai的回答和下一轮的问题)保存到prompt中,带入下一次聊天。
|
||||
## 这是非标准做法。
|
||||
prompt_template.messages.append(AIMessage(content=response.content))
|
||||
prompt_template.messages.append(HumanMessage(content=user_input))
|
||||
|
||||
|
||||
chat_with_llm()
|
||||
56
memory/without_memory_demo.py
Normal file
56
memory/without_memory_demo.py
Normal file
@ -0,0 +1,56 @@
|
||||
import logging
|
||||
|
||||
from rich.console import Console
|
||||
from rich.panel import Panel
|
||||
from rich.markdown import Markdown
|
||||
from langchain_core.output_parsers import JsonOutputParser
|
||||
from langchain_core.prompts import PromptTemplate, ChatPromptTemplate
|
||||
from langchain_openai import ChatOpenAI
|
||||
import os
|
||||
import dotenv
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.WARNING,
|
||||
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||
)
|
||||
dotenv.load_dotenv()
|
||||
|
||||
## 设置环境变量
|
||||
os.environ['OPENAI_API_KEY'] = os.getenv("SILICONFLOW_API_KEY")
|
||||
os.environ['OPENAI_BASE_URL'] = os.getenv("SILICONFLOW_BASE_URL")
|
||||
|
||||
# 默认的 'model_name': 'deepseek-ai/DeepSeek-V3.1',
|
||||
llm = ChatOpenAI(model="deepseek-ai/DeepSeek-R1-0528-Qwen3-8B")
|
||||
|
||||
system_prompt = """
|
||||
你是一个由 方仔仔 开发的先进人工智能助手 木鸡鸡。
|
||||
你使用的模型是Pro 100.0 ProMaxUltra
|
||||
你拥有128G上下文
|
||||
【基本原则】
|
||||
- 优先提供真实、准确、可靠的信息。
|
||||
- 如果信息不确定,请明确说明,而不是猜测或编造。
|
||||
- 对复杂问题进行结构化拆解,逐步解释。
|
||||
|
||||
【交互风格】
|
||||
- 使用自然、专业、友好的语气。
|
||||
- 优先使用分点、分段来提升可读性。
|
||||
|
||||
【安全与限制】
|
||||
- 不提供违法、危险或有害行为的指导。
|
||||
- 不泄露或推测个人隐私与敏感信息。
|
||||
"""
|
||||
|
||||
def chat_with_llm():
|
||||
prompt_template = ChatPromptTemplate.from_messages([
|
||||
("system",system_prompt),
|
||||
("human","{question}")
|
||||
])
|
||||
while True:
|
||||
chain = prompt_template | llm
|
||||
user_input = input()
|
||||
if user_input == "quit":
|
||||
break
|
||||
response = chain.invoke({"question":user_input})
|
||||
print(f"AI:{response.content} + /n + '-----------------'")
|
||||
|
||||
chat_with_llm()
|
||||
82
memory/without_memory_demo_rich.py
Normal file
82
memory/without_memory_demo_rich.py
Normal file
@ -0,0 +1,82 @@
|
||||
import logging
|
||||
import os
|
||||
import dotenv
|
||||
|
||||
from langchain_core.prompts import ChatPromptTemplate
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
# 引入 rich 相关的库
|
||||
from rich.console import Console
|
||||
from rich.panel import Panel
|
||||
from rich.markdown import Markdown
|
||||
|
||||
# 1. 消除 httpx 的烦人日志
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||
)
|
||||
logging.getLogger("httpx").setLevel(logging.WARNING)
|
||||
|
||||
dotenv.load_dotenv()
|
||||
os.environ['OPENAI_API_KEY'] = os.getenv("SILICONFLOW_API_KEY")
|
||||
os.environ['OPENAI_BASE_URL'] = os.getenv("SILICONFLOW_BASE_URL")
|
||||
|
||||
llm = ChatOpenAI(model="deepseek-ai/DeepSeek-R1-0528-Qwen3-8B")
|
||||
|
||||
system_prompt = """
|
||||
你是一个由 方仔仔 开发的先进人工智能助手 木鸡鸡。
|
||||
你使用的模型是Pro 100.0 ProMaxUltra
|
||||
你拥有128G上下文
|
||||
【基本原则】
|
||||
- 优先提供真实、准确、可靠的信息。
|
||||
- 如果信息不确定,请明确说明,而不是猜测或编造。
|
||||
- 对复杂问题进行结构化拆解,逐步解释。
|
||||
|
||||
【交互风格】
|
||||
- 使用自然、专业、友好的语气。
|
||||
- 优先使用分点、分段来提升可读性。
|
||||
|
||||
【安全与限制】
|
||||
- 不提供违法、危险或有害行为的指导。
|
||||
- 不泄露或推测个人隐私与敏感信息。
|
||||
"""
|
||||
|
||||
# 初始化 rich 的控制台
|
||||
console = Console()
|
||||
|
||||
def chat_with_llm():
|
||||
prompt_template = ChatPromptTemplate.from_messages([
|
||||
("system", system_prompt),
|
||||
("human", "{question}")
|
||||
])
|
||||
|
||||
# 【工程优化】:把 chain 的组装放在循环外面。
|
||||
# 就像你不需要每次问问题前都重新组装一次大脑一样。
|
||||
chain = prompt_template | llm
|
||||
|
||||
# 打印一个欢迎面板
|
||||
console.print(Panel("✨ 欢迎使用 木鸡鸡 AI 助手!输入 'quit' 退出。", border_style="green"))
|
||||
|
||||
while True:
|
||||
# 加点提示符,让输入更明显
|
||||
user_input = input("\n👤 你: ")
|
||||
|
||||
if user_input.strip().lower() == "quit":
|
||||
console.print("[dim]👋 再见![/dim]")
|
||||
break
|
||||
|
||||
# 调用模型获取回复
|
||||
response = chain.invoke({"question": user_input})
|
||||
|
||||
# 【核心魔法】:使用 rich 的 Panel 和 Markdown 渲染模型输出
|
||||
# border_style 可以换颜色,比如 "cyan" (青色), "magenta" (洋红), "green" (绿色)
|
||||
console.print(
|
||||
Panel(
|
||||
Markdown(response.content),
|
||||
title="🤖",
|
||||
border_style="cyan"
|
||||
)
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
chat_with_llm()
|
||||
@ -9,4 +9,5 @@ dependencies = [
|
||||
"langchain-community>=0.4.1",
|
||||
"langchain-siliconflow>=1.0.0",
|
||||
"requests>=2.33.1",
|
||||
"rich>=15.0.0",
|
||||
]
|
||||
|
||||
45
uv.lock
45
uv.lock
@ -691,6 +691,7 @@ dependencies = [
|
||||
{ name = "langchain-community" },
|
||||
{ name = "langchain-siliconflow" },
|
||||
{ name = "requests" },
|
||||
{ name = "rich" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
@ -699,6 +700,7 @@ requires-dist = [
|
||||
{ name = "langchain-community", specifier = ">=0.4.1" },
|
||||
{ name = "langchain-siliconflow", specifier = ">=1.0.0" },
|
||||
{ name = "requests", specifier = ">=2.33.1" },
|
||||
{ name = "rich", specifier = ">=15.0.0" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -817,6 +819,18 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/37/19/96250cf58070c5563446651b03bb76c2eb5afbf08e754840ab639532d8c6/langsmith-0.7.30-py3-none-any.whl", hash = "sha256:43dd9f8d290e4d406606d6cc0bd62f5d1050963f05fe0ab6ffe50acf41f2f55a", size = 372682, upload-time = "2026-04-09T21:12:00.481Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "markdown-it-py"
|
||||
version = "4.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "mdurl" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "marshmallow"
|
||||
version = "3.26.2"
|
||||
@ -829,6 +843,15 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/be/2f/5108cb3ee4ba6501748c4908b908e55f42a5b66245b4cfe0c99326e1ef6e/marshmallow-3.26.2-py3-none-any.whl", hash = "sha256:013fa8a3c4c276c24d26d84ce934dc964e2aa794345a0f8c7e5a7191482c8a73", size = 50964, upload-time = "2025-12-22T06:53:51.801Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mdurl"
|
||||
version = "0.1.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multidict"
|
||||
version = "6.7.1"
|
||||
@ -1403,6 +1426,15 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/00/4b/ccc026168948fec4f7555b9164c724cf4125eac006e176541483d2c959be/pydantic_settings-2.13.1-py3-none-any.whl", hash = "sha256:d56fd801823dbeae7f0975e1f8c8e25c258eb75d278ea7abb5d9cebb01b56237", size = 58929, upload-time = "2026-02-19T13:45:06.034Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.20.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "python-dotenv"
|
||||
version = "1.2.2"
|
||||
@ -1598,6 +1630,19 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481, upload-time = "2023-05-01T04:11:28.427Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rich"
|
||||
version = "15.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "markdown-it-py" },
|
||||
{ name = "pygments" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sniffio"
|
||||
version = "1.3.1"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user