code - 本地智能问答助手(Ollama + RAG)

数据向量化

#读取 现有json文件,不需要分割的数据直接构建
import json
from langchain_experimental.text_splitter import SemanticChunker
from langchain_community.vectorstores import FAISS
from langchain_core.documents import Document


# 读取文件内容
with open("./iciba_data_multi.json", encoding="utf-8") as f:
    json_data = json.load(f)

# 加载embedding模型
from langchain_huggingface import HuggingFaceEmbeddings
MODEL_PATH = "/Users/t-mac/.cache/huggingface/hub/models--Qwen--Qwen3-Embedding-0.6B/snapshots/c54f2e6e80b2d7b7de06f51cec4959f6b3e03418"

# mps mac芯片mps加速
embeddings = HuggingFaceEmbeddings(
    model_name=MODEL_PATH,
    model_kwargs={"device": "mps"},
    encode_kwargs={"normalize_embeddings": True}
)

# 2. 准备文档列表
# 这里我们不再使用 text_splitter,而是手动构建 Document 列表
documents = []

for item in json_data:
    # 拼接文本:英文+中文
    full_text = f"{item['content']} {item['note']}"

    # 构建 LangChain 的 Document 对象
    # page_content 是要向量化的内容
    # metadata 是你想保留但不参与向量化的信息(比如日期)
    doc = Document(
        page_content=full_text,
        metadata={"date": item["date"]}
    )
    documents.append(doc)

# 从文档列表创建 FAISS 向量库
vector_store = FAISS.from_documents(documents=documents, embedding=embeddings)
# 【可选】持久化存储:将索引保存到本地磁盘
vector_store.save_local("faiss_index")

Ollama 运行 Qwen3.5-2B

❯ ollama run qwen3.5:2b
pulling manifest
pulling b709d81508a0: 100% ▕██████████████████████████████████████▏ 2.7 GB
pulling 9be69ef46306: 100% ▕██████████████████████████████████████▏  11 KB
pulling 9371364b27a5: 100% ▕██████████████████████████████████████▏   65 B
pulling ee043a99abe5: 100% ▕██████████████████████████████████████▏  473 B
verifying sha256 digest
writing manifest
success
>>>

线阶段:RAG 问答

# 在线阶段:RAG 问答
# 1. 核心思路
# 创建一个 “检索工具”,AI 回答问题前,先调用这个工具找相关文档,再结合文档回答(避免瞎编)。
import json
from langchain.agents import create_agent
from langchain_core.tools import tool
from langchain_ollama import ChatOllama

# ==========================================
# 1. 初始化模型
# ==========================================
model = ChatOllama(
    model="qwen3.5:2b",
    base_url="http://localhost:11434",
    temperature=0.7,
)

# ==========================================
# 2. 模拟你的知识库数据 (实际使用时请替换为你的向量库检索逻辑)
# ==========================================
# 这里为了演示,我直接把你的 JSON 数据放在这里,实际应替换为 vector_store.similarity_search(query)
@tool
def search_docs(query: str) -> str:
    """
    在文档库中搜索相关信息。
    如果用户询问关于日期、格言或特定事件的内容,请使用此工具。
    """
    # --- 实际逻辑替换结束 ---
    formatted_results = []
    results = ensemble_retriever.invoke(query)
    for doc in results:
        text = f"内容: {doc.page_content}"
        formatted_results.append(text)

    return "\n---\n".join(formatted_results)

# ==========================================
# 3. 创建 AI Agent
# ==========================================
agent = create_agent(
    model=model,
    tools=[search_docs],
    system_prompt="""你是每日一词的助手。
    1. 回答用户问题前,必须先调用 search_docs 工具查找信息。
    2. 只能根据搜索到的 [内容] 和 [备注] 进行回答。
    3. 如果搜索不到相关信息,请直接说“我在日记中没找到相关内容”,不要编造。
    4. 回答时直接输出工具查询的内容。
    """
)

# ==========================================
# 4. 问答循环
# ==========================================
print("🤖 助手已就绪,请问关于这些日期的格言,你想知道什么?")

while True:
    try:
        query = input("\n请输入你的问题 (输入 q 退出): ")
        if query.lower() == 'q':
            break
        # 调用 Agent
        # 注意:这里使用 invoke 传入字典
        response = agent.invoke({
            "messages": [{"role": "user", "content": query}]
        })

        # 【关键优化】:正确提取回复内容
        # response["messages"] 是一个列表,[-1] 是最后一条消息对象
        # .content 是获取该对象中的文本内容
        final_answer = response["messages"][-1].content

        print("\n📝 助手回答:")
        print(final_answer)
        print("-" * 30)

    except Exception as e:
        print(f"发生错误: {e}")

结果

18799-k9nc2tok82r.png

添加新评论