Agent+向量数据库实战入门:从零构建智能问答系统

1次阅读
没有评论

共计 5708 个字符,预计需要花费 15 分钟才能阅读完成。

image.webp

背景痛点:为什么选择 Agent+ 向量数据库

传统问答系统通常基于规则匹配或简单的关键词检索,存在明显的局限性:

Agent+ 向量数据库实战入门:从零构建智能问答系统

  • 语义理解不足:无法处理用户问法的多样性,例如 ” 怎么重置密码 ” 和 ” 忘记密码怎么办 ” 本质相同,但传统系统可能无法关联
  • 知识更新滞后:需要手动维护知识库,难以适应快速变化的信息
  • 上下文缺失:多轮对话中难以保持连贯性,每次交互都是独立判断

Agent 与向量数据库的组合正好解决这些问题:

  • Agent 作为 ” 大脑 ” 处理复杂决策和上下文管理
  • 向量数据库实现语义相似度检索,突破关键词匹配的限制
  • 两者结合形成检索增强生成 (RAG) 的完整链路

技术选型:框架与数据库对比

Agent 框架选择

主流选项包括 LangChain、Semantic Kernel 等,对比如下:

  • LangChain
  • 优势:生态丰富,文档完善,社区活跃
  • 特点:提供标准化 Chain/Tool 抽象,内置多种工具集成

  • Semantic Kernel

  • 优势:微软系产品,与 Azure 深度集成
  • 特点:强类型设计,适合企业级开发

对于初学者,推荐 LangChain:

  1. 学习曲线平缓
  2. 示例代码丰富
  3. 支持快速原型开发

向量数据库选择

常见选项性能对比(基于公开基准测试):

数据库 写入速度 查询延迟 分布式支持 免费额度
Pinecone ★★★★☆ ★★★★★ 有限
Weaviate ★★★★☆ ★★★★☆
Milvus ★★★☆☆ ★★★★☆ 完整

建议选择:

  • 快速验证:Pinecone(本文示例)
  • 开源自建:Weaviate
  • 大规模生产:Milvus

核心实现:三步构建智能问答

1. Agent 决策流程设计

典型的工作流程:

  1. 用户输入自然语言问题
  2. Agent 解析意图,判断是否需要检索知识库
  3. 调用向量数据库进行语义搜索
  4. 结合检索结果生成最终回复
  5. 维护对话状态(可选)

关键实现类:

from langchain.agents import AgentExecutor, create_react_agent
from langchain import hub

# 加载预定义提示模板
prompt = hub.pull("hwchase17/react-chat")

# 创建带有检索工具的 Agent
agent = create_react_agent(llm=ChatOpenAI(model="gpt-3.5-turbo", temperature=0),
    tools=[retriever_tool],  # 后文会实现
    prompt=prompt
)

agent_executor = AgentExecutor(
    agent=agent, 
    tools=[retriever_tool],
    verbose=True
)

2. 文本向量化与索引构建

完整代码示例(需先安装 pinecone-client 和 sentence-transformers):

import pinecone
from sentence_transformers import SentenceTransformer

# 初始化嵌入模型
encoder = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')

def create_index(texts: list[str], index_name="qa-index"):
    """
    创建向量索引
    :param texts: 原始文本列表
    :param index_name: 索引名称
    """
    # 连接 Pinecone
    pinecone.init(api_key="YOUR_KEY", environment="us-west1-gcp")

    # 检查索引是否存在
    if index_name not in pinecone.list_indexes():
        pinecone.create_index(
            name=index_name,
            dimension=384,  # 匹配模型输出维度
            metric="cosine"
        )

    # 生成嵌入向量
    embeddings = encoder.encode(texts)

    # 存储到数据库
    index = pinecone.Index(index_name)
    vectors = [(f"vec_{i}", emb.tolist(), {"text": text}) 
        for i, (emb, text) in enumerate(zip(embeddings, texts))
    ]
    index.upsert(vectors=vectors)

3. 实现 RAG 流程

检索增强生成的关键组件:

from langchain.vectorstores import Pinecone
from langchain.chains import RetrievalQA

# 创建检索器
vectorstore = Pinecone(index=pinecone.Index("qa-index"),
    embedding_function=encoder.encode,
    text_key="text"
)

retriever = vectorstore.as_retriever(
    search_type="similarity",
    search_kwargs={"k": 3}  # 返回 top3 结果
)

# 转换为 Agent 可用的工具
retriever_tool = Tool(
    name="Knowledge Base",
    func=lambda q: str(retriever.get_relevant_documents(q)),
    description="""
    当需要回答具体技术问题时使用,输入应该是完整的问题语句
    """
)

性能优化:让系统更快更稳

批量处理策略

避免频繁的小请求:

  1. 对批量问题预处理为向量
  2. 使用 batch_query 接口减少网络开销
  3. 设置合理的超时时间

示例配置:

# 优化后的检索配置
retriever = vectorstore.as_retriever(
    search_type="mmr",  # 最大边际相关性,避免重复结果
    search_kwargs={
        "k": 5,
        "batch_size": 10,  # 批量处理
        "score_threshold": 0.7  # 相似度阈值
    }
)

缓存机制

避免重复计算相同问题:

from langchain.cache import InMemoryCache

# 启用基础缓存
langchain.llm_cache = InMemoryCache()

# 生产环境建议使用 RedisCache
# from langchain.cache import RedisCache
# langchain.llm_cache = RedisCache(redis_url="redis://localhost:6379/0")

相似度阈值调优

通过评估确定最佳阈值:

  1. 准备测试问题集
  2. 在不同阈值下运行检索
  3. 计算准确率 / 召回率
  4. 选择 F1 分数最高的阈值

避坑指南:常见问题解决方案

处理 OOM 问题

当处理大文档时的分块策略:

from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,  # 每个块约 1000 字符
    chunk_overlap=200,  # 块间重叠 200 字符
    length_function=len
)

chunks = splitter.split_documents(large_docs)  # 对大文档分块

冷启动优化

预加载常用查询:

# 服务启动时预热缓存
warmup_queries = ["常见问题", "联系方式", "使用指南"]
for query in warmup_queries:
    retriever.get_relevant_documents(query)

对话状态持久化

使用数据库保存会话历史:

from langchain.memory import MongoDBChatMessageHistory

message_history = MongoDBChatMessageHistory(
    session_id="user123",
    connection_string="mongodb://localhost:27017/"
)

# 在 Agent 中集成
agent_executor = AgentExecutor(
    agent=agent,
    tools=tools,
    memory=ConversationBufferMemory(chat_memory=message_history)
)

完整代码示例

环境准备:

pip install langchain openai pinecone-client sentence-transformers

完整实现:

import os
from typing import List
import pinecone
from langchain.agents import AgentExecutor, Tool, create_react_agent
from langchain_community.vectorstores import Pinecone as PineconeStore
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from sentence_transformers import SentenceTransformer

# 初始化组件
encoder = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)

class QASystem:
    def __init__(self, index_name: str = "qa-demo"):
        """初始化问答系统"""
        # 配置 Pinecone
        pinecone.init(api_key=os.getenv("PINECONE_API_KEY"),
            environment="us-west1-gcp"
        )

        # 创建 / 连接索引
        self._setup_index(index_name)
        self.vectorstore = PineconeStore(index=pinecone.Index(index_name),
            embedding_function=encoder.encode,
            text_key="text"
        )

        # 构建 Agent
        self.agent = self._build_agent()

    def _setup_index(self, name: str):
        """设置向量索引"""
        if name not in pinecone.list_indexes():
            pinecone.create_index(
                name=name,
                dimension=384,
                metric="cosine"
            )

    def _build_agent(self):
        """构建 Agent 执行器"""
        # 定义检索工具
        retriever = self.vectorstore.as_retriever(search_kwargs={"k": 3, "score_threshold": 0.7}
        )

        tools = [
            Tool(
                name="KnowledgeSearch",
                func=lambda q: str(retriever.get_relevant_documents(q)),
                description="用于查询技术知识库"
            )
        ]

        # 使用 ReAct 模式
        prompt = ChatPromptTemplate.from_template(
            """ 你是一个技术支持助手,请根据工具查询结果回答问题。已知信息:{knowledge}
            问题:{input}"""
        )

        agent = create_react_agent(llm, tools, prompt)
        return AgentExecutor(agent=agent, tools=tools, verbose=True)

    def add_knowledge(self, texts: List[str]):
        """添加知识文本"""
        embeddings = encoder.encode(texts)
        records = [(f"doc_{i}", emb.tolist(), {"text": text})
            for i, (text, emb) in enumerate(zip(texts, embeddings))
        ]
        self.vectorstore.index.upsert(vectors=records)

    def query(self, question: str) -> str:
        """执行查询"""
        result = self.agent.invoke({"input": question})
        return result["output"]

# 使用示例
if __name__ == "__main__":
    qa = QASystem()

    # 添加知识(实际应用可改为从数据库加载)knowledge = [
        "密码重置需要验证邮箱和手机号",
        "退货政策要求商品未拆封",
        "客服工作时间是工作日 9 -18 点"
    ]
    qa.add_knowledge(knowledge)

    # 测试查询
    print(qa.query("如何重置密码?"))
    print(qa.query("周末能联系客服吗?"))

延伸应用场景

本方案可轻松适配到其他场景:

  1. 客服机器人
  2. 集成到企业微信 / 钉钉
  3. 添加工单创建工具

  4. 知识库搜索

  5. 对接 Confluence/Notion
  6. 支持 PDF/PPT 等文件解析

  7. 智能教学助手

  8. 关联课程资料
  9. 实现错题解析功能

关键扩展点:

  • 增加多模态支持(图片 / 视频检索)
  • 结合用户画像个性化结果
  • 添加反馈学习机制

总结

通过本文的实践,我们完成了:

  1. 理解 Agent+ 向量数据库的协同价值
  2. 掌握 LangChain 与 Pinecone 的核心用法
  3. 实现完整的 RAG 流程
  4. 学习性能优化与问题排查方法

建议下一步:

  • 尝试接入真实业务数据
  • 探索更复杂的 Agent 工作流
  • 监控系统表现持续优化

智能问答系统的开发是一个迭代过程,本文方案可作为坚实起点,随着业务需求不断演进完善。

正文完
 0
评论(没有评论)