本文将详细介绍如何将本地部署的Ollama大模型(特别是Qwen系列)接入LangChain框架,让你能够充分利用LangChain提供的丰富工具和组件,构建功能强大的本地AI应用。
1. 环境准备与安装
在开始之前,需要确保已经完成以下基础环境的配置。
1.1 安装必要的库
bash
# 安装LangChain核心库
pip install langchain
# 安装LangChain社区库和Ollama集成包
pip install langchain-core langchain-community
# 安装Ollama LangChain专用支持包
pip install -U langchain-ollama
# 如需要处理文档,安装额外依赖
pip install chromadb transformers torch sentence-transformers
1.2 启动Ollama服务
确保Ollama服务正在运行,并且已经拉取了所需的模型:
bash
# 启动Ollama服务
ollama serve
# 拉取Qwen模型(以Qwen3 8B为例)
ollama pull qwen3:8b
# 启动模型(以Qwen3 8B为例)
ollama run qwen3:8b
可以通过以下命令验证模型是否可用:
bash
curl http://localhost:11434/api/tags
2. 基础连接与对话
2.1 最简单的连接方式
python
from langchain_community.chat_models import ChatOllama
from langchain_core.messages import HumanMessage
# 初始化Ollama聊天模型
llm = ChatOllama(
model="qwen3:8b", # 使用已下载的模型名称
base_url="http://localhost:11434", # Ollama服务地址
temperature=0.7, # 控制生成随机性
num_predict=512 # 最大生成长度
)
# 测试单轮对话
messages = [HumanMessage(content="你好,请介绍一下你自己")]
response = llm.invoke(messages)
def main():
print(response.content)
if __name__ == "__main__":
main()
会有如下输出
<think>
好的,用户让我介绍一下自己。首先,我需要确保回答符合规定,不涉及任何敏感内容。用户可能只是想了解我的基本信息,或者他们可能对我的功能和用途感兴趣。我应该先介绍我的身份,即通义千问,然后说明我的主要功能,比如回答问题、创作文字、逻辑推理等。同时,要提到我的训练数据和语言支持,这样用户能知道我的能力和限制。还要注意保持口语化,避免使用专业术语,让用户容易理解。另外,可能需要询问用户是否有具体的问题或需要帮助的地方,这样能更好地引导对话。需要检查是否有遗漏的重要信息,比如多语言支持,或者是否需要强调我的应用场景。最后,确保整体回答简洁明了,结构清晰,符合用户的需求。
</think>
你好!我是通义千问,是阿里巴巴集团旗下的通义实验室自主研发的超大规模语言模型。我的训练数据来自互联网上的大量文本,涵盖了广泛的领域和知识,能够理解和生成多种语言的内容。
我的主要功能包括:
1. **回答问题**:无论是日常生活中的疑问,还是专业领域的知识,我都可以尽力提供帮助。
2. **创作文字**:我可以撰写文章、故事、诗歌、剧本等,满足不同场景的创作需求。
3. **逻辑推理**:在数学、编程、逻辑谜题等方面,我能够进行分析和推导。
4. **多语言支持**:我支持多种语言,包括中文、英文、日文、韩文、法文、西班牙文等,能够与不同语言的用户进行交流。
5. **代码生成与解释**:我可以编写和解释多种编程语言的代码,帮助用户解决编程问题。
我的目标是成为用户在各种场景下的智能助手,提供高效、准确的信息和服务。如果你有任何问题或需要帮助,欢迎随时告诉我!
3. 实现多轮对话系统
要实现有记忆的对话,需要使用对话链和记忆组件:
python
"""
pip install -qU langchain langchain-ollama
"""
import httpx
from langchain_core.runnables import RunnableLambda
from langchain_ollama import ChatOllama
from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import trim_messages, filter_messages, BaseMessage
class LocalTokenCounter:
"""用 /api/generate 的 prompt_eval_count 拿真实 token 数"""
def __init__(self, model: str, base_url: str = "http://localhost:11434"):
self.model = model
self.base_url = base_url.rstrip("/")
def invoke(self, messages: list[BaseMessage]) -> int:
prompt = "\n".join(f"{m.type}: {m.content}" for m in messages)
# 开一次空生成,只算 token 不采样
resp = httpx.post(
f"{self.base_url}/api/generate",
json={
"model": self.model,
"prompt": prompt,
"options": {"num_predict": 0}, # 不生成新 token
"stream": False,
},
timeout=10,
)
resp.raise_for_status()
return resp.json()["prompt_eval_count"] # 真实 token 数
class OllamaChatBot:
def __init__(self, model_name: str = "qwen3:8b"):
# 1. 大模型
self.llm = ChatOllama(
model=model_name,
base_url="http://localhost:11434",
temperature=0.7,
num_predict=1000,
)
# 2. 轻量级内存历史(可换成 Redis / File 持久化)
self.store = {} # session_id -> InMemoryChatMessageHistory
token_counter = LocalTokenCounter(model_name)
# 3. 滑动窗口:保留最近 5 轮(10 条消息)
self.trimmer = trim_messages(
max_tokens=2048, # 也可改成 max_tokens=xxx
strategy="last",
token_counter=token_counter.invoke,
include_system=True,
allow_partial=False,
)
# 4. 提示模板(新写法)
self.prompt = ChatPromptTemplate.from_messages(
[
("system", "你是一个友好的 AI 助手,用中文与用户进行自然流畅的对话。"),
MessagesPlaceholder(variable_name="history"),
("human", "{input}"),
]
)
# 5. 链:trimmer -> prompt -> llm
# 新增包装函数
def _format_messages(messages: list):
return {"history": messages}
# 链:trimmer -> 格式化 -> prompt -> llm
chain = (
RunnableLambda(lambda data: {
"history": self.trimmer.invoke(data["history"]), # 只裁剪历史
"input": data["input"] # 原样保留
})
| self.prompt
| self.llm
)
# 6. 包装成带历史记录的 Runnable
self.chain_with_history = RunnableWithMessageHistory(
chain,
self._get_session_history,
input_messages_key="input",
history_messages_key="history",
)
def _get_session_history(self, session_id: str) -> InMemoryChatMessageHistory:
if session_id not in self.store:
self.store[session_id] = InMemoryChatMessageHistory()
return self.store[session_id]
# 2. chat 方法把两个字段一起传
def chat(self, user_input: str, session_id: str = "default") -> str:
history = self._get_session_history(session_id).messages
output = self.chain_with_history.invoke(
{"history": history, "input": user_input}, # ① 一次性给齐
config={"configurable": {"session_id": session_id}},
)
return output.content
# ---------------- 使用示例 ----------------
if __name__ == "__main__":
bot = OllamaChatBot("qwen3:8b")
print("开始对话,输入 退出/q 结束\n")
while True:
user = input("你: ").strip()
if user.lower() in {"退出", "q", "quit", "exit"}:
break
reply = bot.chat(user)
print(f"AI:{reply}\n")
输出如下
开始对话,输入 退出/q 结束
你: dd
AI:<think>
嗯,用户发来了“dd”,看起来像是一个简短的输入。首先,我需要确认用户的需求是什么。在中文交流中,“dd”可能有多种含义,比如缩写、网络用语,或者是误输入。考虑到用户可能是在测试我的反应,或者想开始一段对话,但没有提供足够的信息。
接下来,我要保持友好和开放的态度,避免让用户感到被忽视。可以先回应一个简单的问候,比如“你好!有什么我可以帮助你的吗?”,这样既礼貌又鼓励用户进一步说明需求。同时,也要准备好处理可能的其他情况,比如用户可能想进行某种特定的互动,或者有更深层次的问题需要解答。
另外,考虑到用户可能是在使用某种快捷方式或表情符号,但“dd”通常不常见,所以更可能是简短的输入。这时候,提供一个友好的回应,引导用户详细说明他们的需求,会更有效。确保回复简洁,但足够开放,让用户感到被重视和支持。
</think>
你好!有什么我可以帮助你的吗?😊
你: 今晚的月色真好
AI:<think>
好的,用户说"今晚的月色真好",我需要回应。首先,用户可能是在表达对今晚月亮的欣赏,所以我要用温暖、友好的语气回应。可以提到月色的美好,比如像轻纱、银色的光辉,或者营造一种宁静的氛围。
接下来,考虑用户可能的意图。他们可能只是单纯地分享感受,或者想展开关于自然的对话。我应该回应得具体一些,让用户感受到被理解和共鸣。比如,可以提到月亮的圆缺、月光洒在地面的样子,或者引发一些诗意的联想。
然后,要确保语言自然流畅,避免生硬。使用比喻和生动的描述会让回应更生动。比如"像轻纱一样笼罩大地"或者"仿佛整个世界都被镀上了一层银色的光辉"。这些表达能增加画面感,让对话更有趣味性。
同时,要注意保持对话的开放性,鼓励用户继续分享他们的感受。比如问"你是在窗边看的还是在户外?"或者"有没有特别喜欢的赏月地点?"这样可以引导用户进一步交流,让对话更深入。
另外,考虑到用户可能有不同的喜好,比如有人喜欢安静赏月,有人喜欢和朋友一起。所以回应中可以加入一些选项,比如"你是在窗边看的还是在户外?",这样既符合用户当前的表达,又为后续对话留下空间。
还要注意语气要友好,带点温暖和关怀。比如用"月色真美"这样的感叹,或者用"真美"来表达赞赏。同时,加入一些情感元素,比如"让人心情平静",可以增强回应的感染力。
最后,确保回应简洁自然,不过于冗长。避免使用复杂的句子结构,保持口语化,让对话轻松愉快。例如,用"今晚的月色确实很美,像轻纱一样笼罩大地,银色的光辉洒在大地上,让人的心情也跟着平静下来。你是在窗边看的还是在户外?"这样的句子,既生动又自然。
总结来说,回应需要包含:1. 对月色的赞美和生动描述;2. 询问用户的具体情境,引导进一步交流;3. 保持友好和温暖的语气;4. 语言自然流畅,避免生硬。
</think>
今晚的月色确实很美,像轻纱一样笼罩大地,银色的光辉洒在大地上,让人的心情也跟着平静下来。你是在窗边看的还是在户外?✨
你:
PS:朋友,看到这儿,如果正巧也是晚上,祝你有一个美好的夜晚!!!!