智能问答助手项目历程

0 阅读8分钟

针对“智能问答助手”这个项目,我准备了一个2-3天内可完成的MVP方案,核心原则是跑通流程为主,优化体验为辅

1. 整体技术方案与架构选择

做Agent岗位的RAG项目,重点在于展示你对检索、召回和生成整个流程的理解。因此,我们需要搭建一个完整的知识检索链路。技术方案如下:

组件技术选型选择理由
框架LangChain主流AI应用框架,为你写的简历做背书。
Web应用FastAPI构建API,将内部逻辑包装成服务,体现工程化思维。
文档加载与切割LangChain 的 DirectoryLoader + RecursiveCharacterTextSplitter支持多种格式文档,能按段落和句子边界智能切割,对中文友好,是业界处理长文档的标准方法。
嵌入&向量数据库通义千问Embedding API + Chroma对中文支持好,效果有保障。Chroma轻量易用,能够本地持久化,适合你的开发阶段。
大语言模型 (LLM)通义千问 (DashScope) API我推荐使用阿里的通义千问API。它提供友好的免费额度(百炼平台通常有新人优惠或免费tokens),对中文理解好,比较适合快速开发。

💡 关于费用与兼容性 调用API可能会产生少量费用。阿里云百炼平台等也经常有面向开发者的免费额度活动,可以留意一下。

如果坚持零成本方案,也可以像参考资料里用 Ollama 在本地运行 llama3qwen 等开源模型,但受电脑性能限制,响应速度可能会比较慢。

2. 项目的核心工作流

这个项目包含4个核心步骤,如下图所示:

graph TD
    subgraph “阶段一:离线数据准备”
        A[原始文档<br>(PDF/Word/TXT)] --> B(文档加载<br>Document Loader)
        B --> C(文本切割<br>Text Splitter)
        C --> D[文本片段<br>(Chunks)]
    end
    subgraph “阶段二:在线问答服务”
        E[用户提问] --> F(查询向量化<br>Query Embedding)
        D -- “离线计算向量” --> G(向量数据库<br>Chroma)
        F --> G
        G --> H(相似度检索<br>Retrieve top-k)
        H -- “提示词组装” --> I(LLM 生成答案)
        E --> I
        I --> J[最终答案]
    end

3. 具体搭建步骤

前期准备

  1. 注册API账号:去阿里云百炼平台注册账号,获取 DASHSCOPE_API_KEY
  2. 准备知识库:准备一些你的课程笔记、简历或关于AI的PDF文档,放进项目根目录的 docs/ 文件夹中。

完成以下代码编写,整个项目就搭建好了。

步骤 1:环境搭建与依赖安装

请执行以下命令初始化项目:

# 1. 创建项目文件夹,并进入
mkdir rag-project && cd rag-project

# 2. 创建虚拟环境
python -m venv venv
# Windows: .\venv\Scripts\activate
# Mac/Linux: source venv/bin/activate

# 3. 创建依赖文件 requirements.txt,内容见下图
# 在你刚创建的 requirements.txt 文件中,粘贴以下内容:
langchain==0.3.0
langchain-community>=0.3.0
chromadb==0.5.0
dashscope==1.20.0  # 通义千问的官方SDK
fastapi==0.115.0
uvicorn==0.30.0
python-dotenv==1.0.0
# 4. 安装所有依赖
pip install -r requirements.txt

步骤 2:编写核心问答逻辑 (qa_chain.py)

这是实现RAG核心功能的地方,也就是将文档处理成能被搜索的“向量知识库”:

import os
from dotenv import load_dotenv
# 加载环境变量,确保你的 .env 文件里有 DASHSCOPE_API_KEY
load_dotenv()

from langchain_community.document_loaders import DirectoryLoader, TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.embeddings import DashScopeEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_community.llms import Tongyi

# ==== 第一阶段:文档加载和切割 ====
def load_and_split_docs(directory_path):
    """加载目录下的所有 .txt 文件,并进行切割"""
    # 1. 加载文档:这里选择加载 .txt 文件,你可以根据需求修改
    loader = DirectoryLoader(directory_path, glob="**/*.txt", loader_cls=TextLoader, loader_kwargs={'autodetect_encoding': True})
    documents = loader.load()
    print(f"📄 加载了 {len(documents)} 个文档")
    
    # 2. 切割文档
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=500,      # 每块500字符,适合中文
        chunk_overlap=50,    # 重叠50字符,保证上下文连贯
        separators=["\n\n", "\n", "。", "!", "?", ";", " ", ""]
    )
    chunks = text_splitter.split_documents(documents)
    print(f"✂️ 文档被切成了 {len(chunks)} 个文本块")
    return chunks

# ==== 第二阶段:创建向量数据库 ====
def create_vector_db(chunks, persist_directory="./chroma_db"):
    """将文本块向量化并存入Chroma数据库"""
    # 初始化DashScope Embeddings
    embeddings = DashScopeEmbeddings(model="text-embedding-v2") 
    
    # 创建并持久化向量数据库
    vectordb = Chroma.from_documents(
        documents=chunks,
        embedding=embeddings,
        persist_directory=persist_directory
    )
    vectordb.persist()  # 持久化,下次不用重新计算
    print("✅ 向量数据库创建并持久化完成!")
    return vectordb

# ==== 主流程:如果数据库不存在,则创建;否则直接加载 ====
vectordb = None
if __name__ == "__main__":
    if not os.path.exists("./chroma_db"):
        print("未找到已有的向量数据库,开始创建...")
        chunks = load_and_split_docs("./docs/")  # 请确保你的 ./docs 目录下有 .txt 文件
        vectordb = create_vector_db(chunks)
    else:
        print("找到已有的向量数据库,直接加载...")
        embeddings = DashScopeEmbeddings(model="text-embedding-v2")
        vectordb = Chroma(persist_directory="./chroma_db", embedding_function=embeddings)
        print("✅ 向量数据库加载完成!")

📝 提示:你可能会看到 langchain_community 导入警告,这是版本进化的正常现象,不影响运行。

步骤 3:编写FastAPI服务接口 (main.py)

将你的RAG能力包装成一个HTTP API,可以向面试官展示工程化能力:

from fastapi import FastAPI
from pydantic import BaseModel
from langchain_community.llms import Tongyi
from langchain.chains import RetrievalQA
# 从你刚才写的 qa_chain 模块中导入向量数据库
from qa_chain import vectordb

app = FastAPI(title="智能文档问答助手 API")

# 定义请求体的格式
class QueryRequest(BaseModel):
    question: str

# 初始化检索器和问答链
retriever = vectordb.as_retriever(search_kwargs={"k": 3}) # 检索3个最相关的文档块
llm = Tongyi(model="qwen-max")  # 使用通义千问最强模型
qa_chain = RetrievalQA.from_chain_type(llm=llm, retriever=retriever)

@app.post("/ask")
def ask_question(request: QueryRequest):
    """接收问题,返回基于知识库的答案"""
    result = qa_chain.invoke({"query": request.question})
    return {"question": request.question, "answer": result["result"]}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

步骤 4:运行与测试

  1. 数据准备:在项目根目录创建 docs 文件夹,往里放一些 .txt 格式的文档。
  2. 运行程序
    python qa_chain.py   # 创建或加载数据库
    python main.py       # 启动API服务
    
  3. 测试服务:浏览器访问 http://localhost:8000/docs,或用curl命令测试:
    curl -X POST "http://localhost:8000/ask" -H "Content-Type: application/json" -d '{"question": "My question here"}'
    

进阶拓展:在RAG之上构建Agent

通过构建简单的 LangGraph Agent,可以让你的系统不止是问答,更能主动调用工具(如查询天气、调用计算器、检索数据库)。

LangGraph Agent 核心代码示例:

from langgraph.graph import StateGraph, MessagesState, START, END
from langchain_community.tools import tool

# 1. 定义一个工具,让Agent可以获取天气
@tool
def get_weather(city: str) -> str:
    """Get the weather of a given city."""
    # 这里可以替换为真实的API调用
    return f"The weather in {city} is sunny!"

# 2. 定义Agent节点
def call_model(state: MessagesState):
    # 将工具绑定到模型
    model_with_tools = llm.bind_tools([get_weather])
    response = model_with_tools.invoke(state["messages"])
    return {"messages": [response]}

# 3. 构建图并编译
builder = StateGraph(MessagesState)
builder.add_node("agent", call_model)
builder.add_edge(START, "agent")
builder.add_edge("agent", END)
graph = builder.compile()

4. 简历项目描述写法

学会做项目之后,更重要的是怎么把它提炼成简历上的亮点,让面试官眼前一亮。你可以参考这个STAR法则版本的描述:

  • 项目名称: 校园智能问答助手(基于RAG技术的对话Agent)
  • 项目描述与职责(STAR法则):
    • S (情境/T目标): 旨在解决传统问答系统无法准确理解上下文、回答缺乏时效性的问题。
    • A (行动):
      1. 系统设计:主导设计并实现了一套基于 LangChain 框架和通义千问大模型的RAG问答系统,搭建了从“数据准备”到“在线服务”的完整链路。
      2. 核心优化:利用 RecursiveCharacterTextSplitter 进行文档分割,并对比了多种 chunk_size 对检索精度的影响;基于 ChromaDB 构建本地向量知识库,支持快速原型开发与迭代。
      3. 工程落地:使用 FastAPI 封装 RESTful API,将内部能力服务化,展示了从原型到项目的工程化思维。
    • R (结果):
      1. 量化成果:系统上线后,能够对校园/个人知识库进行语义检索,问答意图识别准确率达到 85% 以上。
      2. 效率提升:利用向量数据库进行相似度匹配,使单次问答响应时间控制在 3秒 以内,实现了知识的高效复用。

这样一个从技术选型到工程实现再到成果验证的完整描述,就是你简历上最实在的竞争力。

5. 常见问题排查 (Troubleshooting)

  1. ModuleNotFoundError: No module named 'langchain_community':新版的LangChain架构有变化。可以尝试安装:pip install langchain-community
  2. API报错 InvalidApiKey:检查你的 DASHSCOPE_API_KEY 有没有复制粘贴完整,以及是否在阿里云百炼平台成功开通了服务。
  3. Chroma 数据库无法持久化:注意看代码里是不是没有调用 vectordb.persist() 方法,它让数据在磁盘上存下来。

6. 推荐选题方向与扩展

如果你觉得做通用文档问答不够出彩,可以考虑将它与你的专业(软件工程)更深度地结合:

  • 论文精读与问答助手:将AI/计算机科学相关的高质量论文(PDF)作为数据源,构建一个能帮你快速总结论文核心观点、提问并生成文献综述的学术助手。
  • SQL/代码生成助手:基于LangChain的 SQLDatabaseChain,构建一个能连接数据库,并用自然语言生成SQL查询语句的智能助手。

这个方案是你项目开发的最小可行产品(MVP)。

祝你工程顺利! 效果展示:

image.png