20.最小 Django 包装方案:为 RAG/Agent 项目增加产品壳层
说到模版需要简单提一嘴Django的工作模式,Django属于MVT架构的web框架,M代表model他负责在后端定义数据模型,这种模型将来会涉及到数据库的操作,V代表view视图层,虽然说是视图层,但是我个人感觉view和咱们看到的网站页面没有半毛钱关系,在这里view当中,我们主要写业务逻辑,逻辑写好后相关的的返回结果会传递给模版Template层,模版才是咱们最终能看到的页面。文件,将访问请
这次在做什么
前面已经搭建起了RAG论文检索智能体的AI内核,但是这个项目没有合适的对外壳层,看起来始终像是工程师代码,所以这次需要对这个AI内核进行包装,让项目变得更像是一个可以使用的产品。
目前智能体系统已经使用LangGraph实现编排,存在工作流:
选工具->执行工具->工具执行结果和问题结果->交给大模型重新经大模型思考->返回答案
在工具层,目前已经手写了一条RAG的工具,其中包括:文档切分、embedding、FASII检索、Rerank以及基于上下文生成回答。此外,本地工具还包括表达式计算、时间和语言模型工具,外部工具有联网搜索MCP工具。
在工程化方面,目前的系统包括会话管理,异常处理、系统日志以及FastAPI封装的服务接口。
现阶段适合计划交给Django的能力包括:
1.用户上传论文/文档
- 上传页面
- 文件记录
- 文件列表
- 上传状态
- 文件归属到哪个用户/哪个会话/哪个任务
2.发起问答
- 聊天页面
- 输入框
- 问答记录展示
- 调用FastAPI/ask
3.查看历史会话
- 会话列表页
- 单个会话详情页
- 每轮user/assistant
- 按时间查看历史
4.展示检索片段和回答结果
目前系统能做到的能力是系统获得会话id以及用户问题后,能得到工具运行的回答,返回用了哪个会话id、用户原始问题以及对应的回答结果。未来还将进行扩展,当用户使用RAG功能时,返回的结果不光是最终答案,还要有检索到的知识,让用户知道这些回答是基于哪些知识来的。
5.基础任务记录 / 管理
未来将下列功能列入Django的数据库模型和后台管理,包括:
- 一次上传任务
- 一次问答任务
- 文档处理状态
- 最近会话
- 最近提问
- 最近上传的论文
项目总体结构设计暂定如下:
今天的目标
- 一个 Django 项目骨架
- 一个聊天页
- 一个上传页占位版
- 一条 Django 调 FastAPI /ask 的调用链路
Django是一个集成好的环境,在安装好Django库以后,可以原来的RAG论文检索智能体根目录通过命令创建Django壳层的工作目录:
django-admin startproject config django_shell
创建好Django的工作目录后在Django目录下有manage.py文件,这个从这个文件可以创建app以及启动Django服务。今天要实现一个聊天页面,以及一个文档上传页,所以先创建两个app分别是chat以及documents:
cd django_shell
python manage.py startapp chat
python manage.py startapp documents
在Django的工作目录下有config子目录,子目录下有setting.py文件,这个文件会有Django的运行配置,包括数据库、路由以及项目的app等,今天要创建两个应用,首先需要在配置文件中注册应用并设置模版目录。
说到模版需要简单提一嘴Django的工作模式,Django属于MVT架构的web框架,M代表model他负责在后端定义数据模型,这种模型将来会涉及到数据库的操作,V代表view视图层,虽然说是视图层,但是我个人感觉view和咱们看到的网站页面没有半毛钱关系,在这里view当中,我们主要写业务逻辑,逻辑写好后相关的的返回结果会传递给模版Template层,模版才是咱们最终能看到的页面。
INSTALLED_APPS = [
...
"chat",
"documents",
]
TEMPLATES[0]["DIRS"] = [BASE_DIR / "templates"]
ALLOWED_HOSTS = ["127.0.0.1", "localhost"]
通常我们访问一个网站需要什么?一般需要连接,是的,连接是我们访问网站需要的地址也叫路由,Django项目有自己的跟理由,一般根路由负责分配任务到某一个具体的app,所以根路由的配置在项目的config子目录下,修改该目录下的url.py文件,将访问请求分配到具体的app,在app中会继续配置应用路由,应用路由会根据任务具体需求配置处理的view视图业务。但是先修改config目录下的路由:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path("admin/", admin.site.urls),
path("", include("chat.urls")),
path("documents/", include("documents.urls")),
]
在配置中有写path("", include("chat.urls")),这表示当传入默认请求,主路由会将业务分配到chat应用到子路由中处理,下一步给chat应用到子路由配置具体的处理view逻辑:
from django.urls import path
from . import views
urlpatterns = [
path("", views.chat_home, name="chat_home"),
]
在这个配置中,path("", views.chat_home, name="chat_home")中为默认请求地址(空地址),配置视图层的views.chat_home业务逻辑,并且为这个子路由取了一个代称chat_home,未来在模版层,项目可以使用代称使用该路由。
刚刚有讲子路由会将空地址分配给视图层的views.chat_home处理业务逻辑,下一步便是在view层中处理具体业务,这里我个人对view层的理解是view层的输入一般是一些网络请求,返回结果模版层渲染时所需的业务处理。下一步在chat应用的view.py写业务处理逻辑:
from django.shortcuts import render
from .services.ai_client import ask_ai
def chat_home(request):
result = None
error = None
if request.method == "POST":
session_id = request.POST.get("session_id", "").strip()
question = request.POST.get("question", "").strip()
if session_id and question:
try:
result = ask_ai(session_id=session_id, question=question)
except Exception as e:
error = str(e)
else:
error = "session_id 和 question 不能为空"
return render(
request,
"chat/chat_home.html",
{
"result": result,
"error": error,
}
)
Django做的目的并不是覆盖原有论文检索智能体系统,他的目的是做一个产品外壳,原来的论文检索智能体内核仍会保留,所以在这里将会通过HTTP请求调用FastAPI服务使用智能体,但是这里需要写一个中间件用来连接Django外壳与智能体内核,在chat应用下创建一个services目录,再新建ai_client.py文件:
import requests
FASTAPI_BASE_URL = "http://127.0.0.1:8000"
def ask_ai(session_id: str, question: str) -> dict:
resp = requests.post(
f"{FASTAPI_BASE_URL}/ask",
json={
"session_id": session_id,
"question": question,
},
timeout=120,
)
resp.raise_for_status()
return resp.json()
至此,现已完成view视图层的业务逻辑,随后创建页面模版Template,在根目录的模版目录创建templates/子目录,随后创建与app对应的模版目录app/,然后创建chat_home.html:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Paper RAG Agent</title>
</head>
<body>
<h1>Paper RAG Agent with Django Shell</h1>
<form method="post">
{% csrf_token %}
<div>
<label>Session ID:</label>
<input type="text" name="session_id" value="demo-session">
</div>
<div>
<label>Question:</label>
<textarea name="question" rows="6" cols="80"></textarea>
</div>
<button type="submit">Ask</button>
</form>
{% if error %}
<hr>
<h3>Error</h3>
<p>{{ error }}</p>
{% endif %}
{% if result %}
<hr>
<h3>Result</h3>
<p><strong>Session:</strong> {{ result.session_id }}</p>
<p><strong>Question:</strong> {{ result.question }}</p>
<p><strong>Answer:</strong> {{ result.answer }}</p>
{% endif %}
</body>
</html>
至此我们有了聊天页,同样的原理下一步创建文档上传页,首先在documents应用下创建子路由django_shell/documents/urls.py:
from django.urls import path
from . import views
urlpatterns = [
path("upload/", views.upload_page, name="upload_page"),
]
接着创建视图逻辑django_shell/documents/views.py:
from django.shortcuts import render
def upload_page(request):
return render(request, "documents/upload.html")
在模版层创建文档上传模版django_shell/templates/documents/upload.html:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Upload Papers</title>
</head>
<body>
<h1>Upload Papers</h1>
<p>这里先做最小上传页面占位,下一步再接文件保存和知识库重建。</p>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="file" name="paper_file">
<button type="submit">Upload</button>
</form>
</body>
</html>
遇到问题
项目启动应该先启动FastAPI的AI核心,然后再启动Django壳,首先运行:
uvicorn app.main:app --reload
随后:
cd django_shell
python manage.py runserver
但是这里有个坑,Django服务服务默认在8000端口启动,FastAPI已经在8000端口启动了,所以Django的服务需要在另一个端口运行,启动命令应该改为:
python manage.py runserver 8001
如果这篇文章对你有帮助,可以点个赞~
完整代码地址(分支选择feature/djiango-wrapper):https://github.com/1186141415/Paper-RAG-Agent-with-LangGraph
更多推荐


所有评论(0)