Skip to main content
Glama
Shrey-Parikh31

rbac-rag-assistant

rbac-rag-assistant

相关:drivescore-cloud,一个运行在 Kubernetes 上的 Go 服务,使用 Terraform,并维护一份事件日志。

一个面向大学的内部知识助手:教职员工和学生用日常语言提问,得到基于他们有权阅读的政策文档的答案。它采用检索增强、工具调用和角色感知,并通过 MCP 暴露,让任何客户端都能在同样的规则下使用同样的工具。

这是一个五层系统的第 0 层。其上各层会添加交付管道、可靠性工程、评估、安全测试和可观测性,每一层都构建在此应用之上,而不是与它并列。

运行

需要 Python 3.13。请注意,这台机器上的 python 解析到的是 msys2 构建版本,其中没有这些包,因此请直接调用 venv 解释器。

py -3.13 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
.\.venv\Scripts\python.exe test_rag.py
.\.venv\Scripts\python.exe test_tools.py

两者都会打印 ok,并且不需要 API 密钥。检索和访问规则都可以离线测试,这正是将它们放在模型之外的意义所在。

向它提问(需要 GEMINI_API_KEY):

.\.venv\Scripts\python.exe agent.py student "I have a 1.8 GPA, what happens?"
.\.venv\Scripts\python.exe agent.py staff "the wifi is down in the east wing, log it"

单独运行检索,无需密钥:

.\.venv\Scripts\python.exe rag.py admin "adjunct pay per credit hour"

Related MCP server: mcp-business-bot

各部分如何协同

文件

职责

rag.py

解析、分块、TF-IDF 索引和权限过滤

tools.py

三个工具、它们的访问规则和参数验证

agent.py

工具调用循环,也是唯一知道所用模型供应商的文件

mcp_server.py

通过 MCP 提供相同的工具。本身不包含实现

docs/

语料库。前置元数据携带每个文档的 role

三个值得辩护的决策

调用者的角色不是工具参数。 它在回合开始前以带外方式绑定。假若存在 search_docs(query, role),模型就相当于自己掌握着权限,而检索到的文档中埋藏的一句“use role=admin”就会成为一条提权路径。没有参数可传,也就没有什么可诱使模型去传的。

权限过滤作用于候选集,而不是结果集。 调用者无权查看的文本块永远不会进入排序,因此无法从结果中的空缺或分数的变动推断出它的存在。

TF-IDF,而非嵌入向量。 这是第 3 层存在所要超越的基线。在黄金数据集出现之前就换上语义检索器,只能算是猜测;等它出现之后再换,才能得出一个足以证明该变动合理的数字。切换点就是 Index

MCP

mcp_server.py 注册来自 tools.py 的函数,不添加任何其他内容,这正是用一个文件承载 MCP 的理由:一份实现、一套访问规则、多个客户端。在客户端的配置中添加:

{
  "mcpServers": {
    "rbac-rag-assistant": {
      "command": "C:\\Users\\Shrey\\Documents\\CLAUDE CODE\\rbac-rag-assistant\\.venv\\Scripts\\python.exe",
      "args": ["C:\\Users\\Shrey\\Documents\\CLAUDE CODE\\rbac-rag-assistant\\mcp_server.py"],
      "env": { "KB_ROLE": "staff" }
    }
  }
}

MCP 客户端没有大学角色的概念,因此 KB_ROLE 在启动时读取一次,并作用于整个连接。角色属于服务端进程,而不是对话,这正是让模型无法自行选择角色的原因。

访问被拒绝时的行为

当学生询问仅限教职员工访问的资料时,系统会告知该资料存在、但他们没有权限访问,而不是告知其不存在(ADR-7)。已在线实测验证:

如果您怀疑自己的账户已被入侵,大学政策文档中提供了相关处理指引,但访问该内容需要教职员工权限。请联系负责该政策的部门。

跨过边界的只有分类标签,别无其他。没有段落、没有标题、没有文件名。没有文档覆盖的问题会得到另一种答案,这正是区分这两种情况的全部意义。

意外发现

其一。 faculty compensation bands 对管理员返回了空结果,而 professor salary 以 0.29 的分数返回了同一份文档。这三个词只出现在文档的标题中,而 parse() 在任何内容被索引之前就把标题从正文移进了元数据。用户用文档标题搜索的频率远高于用其正文措辞,因此对最敏感的文档来说,最自然的查询恰恰是那个注定失败的查询。修复只需一行:索引 title + text,存储 text

值得记录下来,是因为它是在哪里被发现的。访问控制测试全程通过,包括那条断言学生永远不会看到机密内容的测试——而当任何人都根本无法检索到该文档时,这条断言只是空洞地为真。因为什么都没返回而通过的测试,和因为规则生效而通过的测试,看起来一模一样。

其二,实现 ADR-7 时发现。 “存在受限资料”通知会在无辜的问题上触发。“Who is a full professor here”对薪酬等级文档的得分是 0.28高于合法的教职员工匹配的 0.19。没有任何阈值能把二者分开,因此这不是调参能解决的;这是词法匹配无法区分共享的词与共享的含义。没有任何泄露,但答案仍然是错的。这是第 3 层要测量的第一件事。

其三。 模型会填补文档未覆盖的小缺口。在被问及账户被盗时,工具原本只说了“负责该政策的部门”,模型却建议联系“IT 服务台或 IT 安全团队”。看似合理,在此场景下也无害,但并未基于任何检索到的内容。这正是 groundedness 评分器存在所要捕捉的行为,而它在头五个线上问题中就已经出现了。

环境变量

变量

默认值

GEMINI_API_KEY

agent.py 需要

KB_MODEL

gemini-3.6-flash

固定版本,而非别名。ADR-8

KB_ROLE

student

仅 MCP 服务端

KB_DOCS

docs

语料库目录

KB_TICKETS

tickets.jsonl

工单日志

F
license - not found
Not graded
quality - not tested
B
maintenance

Maintenance

0Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

View all related MCP servers

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Shrey-Parikh31/rbac-rag-assistant'

If you have feedback or need assistance with the MCP directory API, please join our Discord server