这是提交给Sanity Challenge,路径一:发布一个能查询真实内容的智能体

我构建了什么

超过 4000 万大学生在各自为政的奖学金公告中摸索。接受第二笔奖金来支付住宿费或学费,可能会触发自动审计标记、要求立即法律追回的催缴通知,以及永久取消资格。ScholarStack 提供了一个权威的合规引擎,其中 Sanity Content Lake 作为唯一事实来源。

印度的高等教育奖学金在官方公告和项目章程中埋藏着严格的法律契约。中央部委、邦福利局和企业基金会在其中加入了禁止学生同时接受经济援助的法定条款。

根据邦税收法规和中央福利指南,违反这些契约会触发严厉制裁:

  • 立即取消所有奖学金发放。
  • 强制法律追回已发放资金并加收罚息。
  • 列入国家和邦福利登记系统的黑名单。

大学生常常持有多个优秀奖学金录取,却不知道同时获得资助是否合法。合规验证仍然依赖分散在数十个互不相连的部门门户上的四十页政府公告。

Initial Website

ScholarStack是一个自动化的多奖项奖学金合规与禁止叠加规则手册验证引擎。由Sanity Content Lake和Sanity Context MCP提供支持,它将官方奖学金规则手册、确切法律条款和学生决策历史视为结构化内容。

当学生检查两个奖项是否可以同时持有时,ScholarStack 执行五个步骤:

  1. 它通过 Context MCP 交叉引用存储在 Sanity 中的官方规则手册。
  2. 它逐字提取反叠加契约,并附上引文、处罚措施以及政府公告文件的直接链接。
  3. 它以零幻觉标记合规冲突。
  4. 它闭环处理:如果存在冲突,学生可以直接在门户中执行正式放弃。此操作会将一条结构化studentDecision记录提交回 Sanity Content Lake。
  5. 它将决策延续下去: 在后续查询中,引擎会查询有效的学生放弃记录,排除已放弃的奖项,并动态重新评估资格。

共识方法 vs. ScholarStack

功能维度 共识方法(通用聊天机器人) ScholarStack 合规引擎(Sanity Lake)
数据基础 抓取的 HTML 段落和扁平文本块 Sanity Content Lake 中的结构化文档模式
法律依据 虚构的例外情况和无依据的模型输出 从公报中逐字引用的法定条款
冲突处理 猜测或抹平相互矛盾的规则 并排展示契约条款,并附上源 PDF 链接
状态管理 浏览器刷新后即丢失的临时聊天记忆 双向写回 Sanity(studentDecision)
决策延续 在后续问题中重新提示同一冲突 放弃记录在所有未来评估中持续生效
验证关卡 没有文档链接的未经验证声明 通过 Ground-Truth Oracle 丰富的直接 PDF 链接
界面 通用的整页聊天对话框 聚焦机构助学金门户的布局

核心原语

ScholarStack 引入了三个命名原语来定义其合规框架:

1. 法定不可叠加契约

公报中颁布的、禁止同时领取多项教育奖项的法律条款。ScholarStack 将每个契约建模为一个独立的结构化对象,包含逐字条款文本、章节引用、制裁措施和已认可的例外情况。

2. 有状态放弃台账

一个双向 Sanity Content Lake 模式(studentDecision),用于记录行政放弃声明。当学生解决奖项冲突时,引擎会写入一条不可变记录,其中包含指向保留和放弃计划的引用指针。

3. Ground-Truth 验证 Oracle

一个评估流水线,直接从 Sanity 文档中投射经过验证的公报条款和官方 PDF 链接。ScholarStack 通过从 Sanity 直接查询文档来丰富结果。


演示

观看视频演示: https://youtu.be/_J6TshhPy7c


实时门户与遥测可视化

Live Telemetry and Verification Oracle Modal

Portal Telemetry & Verification Oracle 模态框展示了 Sanity Content Lake 和 Context MCP 工具中的实时运营指标。

Stateful Relinquishment Ledger

Student Relinquishment Ledger 追踪已提交的studentDecision文档,无需页面刷新即可实时更新。

Indexed Policy Directory

Policy Directory 展示了 36 个已索引的奖学金计划,按 Central、State、Corporate CSR 和 Autonomous Institute 管辖区分类。


关键演示场景

场景 查询的奖项 基于 Sanity 的发现 操作 / 结果
1. 直接冲突陷阱 Goa Home Nursing + Samsung Star Scholar 禁止:Goa 第 7(b) 条禁止同一课程的并行资助。Samsung 第 4.3 条禁止外部资助。 展示逐字引用、处罚条款和来源 PDF 链接。提供一键放弃。
2. 矛盾解决 学生放弃 Goa Nursing 以保留 Samsung 放弃文档通过以下方式提交至 Sanity Content Lake@sanity/client。 在 Sanity 中永久更新账本;更新学生上下文。
3. 州级结转 已交回的 Goa + FTII Fellowship + Samsung 允许:引擎检测到 Goa 已在 Sanity 中合法交回。FTII 第 4.2 条允许并行的中央奖项。 批准,零重复冲突标记。
4. 反向评估 Samsung Star Scholar + Central Post-Matric SC/ST 禁止:Central Sector 第 5.1(iv) 条规定,若收到另一项奖学金,须依法追回。 引用官方公报中的双重追回警告。
5. 零幻觉拒绝 Eiffel Excellence(法国)+ Rhodes Scholarship(牛津) 超出范围:该计划未在已验证的 Sanity 语料库中索引。 拒绝编造规则;引导用户提交公报。

代码

项目结构与文件组织

ScholarStack/
├── studio/                     # Sanity Studio v5 Configuration & Schemas
│   ├── schemaTypes/
│   │   ├── scholarshipScheme.ts # Structured rulebook schema with stackingRule object
│   │   ├── studentDecision.ts   # Formal relinquishment schema with document references
│   │   └── index.ts             # Schema registry
│   └── sanity.config.ts        # Sanity Studio project configuration (axvnim0k)
├── agent/                      # Compliance Intelligence Backend
│   ├── src/
│   │   ├── contextMcpClient.ts # Sanity Context MCP client (initial_context, groq_query, etc.)
│   │   ├── evaluator.ts        # Gemini 2.5 Flash reasoning & ground-truth enrichment
│   │   ├── sanityClient.ts     # Direct Sanity Client mutations and GROQ queries
│   │   └── server.ts           # Express API server with /health/deep telemetry
│   └── tsconfig.json
├── web/                        # Institutional Financial Aid Portal
│   ├── public/
│   │   ├── index.html          # Tailwind & DaisyUI institutional layout
│   │   ├── style.css           # Compiled production stylesheet
│   │   └── app.js              # State management, telemetry modal & audit dossier export
│   ├── input.css               # Tailwind directives and print stylesheet
│   └── tailwind.config.js      # DaisyUI theme configuration
├── scripts/
│   ├── seedCorpus.ts           # Populates 36 verified schemes into Sanity Lake
│   ├── verifyLiveUrls.ts       # Validates all official document URLs
│   └── testChecks.ts           # Automated test suite for multi-award evaluations
└── SUBMISSION.md               # DEV.to Path One Challenge Submission

数据流图

sequenceDiagram
    autonumber
    actor Student as Student / Counselor
    participant UI as ScholarStack Portal (Web)
    participant Server as Express Backend
    participant MCP as Sanity Context MCP
    participant Lake as Sanity Content Lake
    participant Gemini as Google Gemini 2.5 Flash

    Student->>UI: Selects awards ("Goa Nursing + Samsung Star")
    UI->>Server: POST /api/evaluate {question, studentId}
    Server->>MCP: Query Context MCP (groq_query, initial_context)
    MCP->>Lake: Execute GROQ: Fetch active schemes & studentDecision references
    Lake-->>MCP: Returns structured scheme schemas & relinquishment history
    MCP-->>Server: Formatted context with exact non-stacking clauses
    Server->>Gemini: Prompt with legal rulebooks, student history & strict non-stacking rules
    Gemini-->>Server: Structured compliance verdict (PROHIBITED, clauses, citations)
    Server->>Server: Enrich official document URLs from verified Sanity documents
    Server-->>UI: JSON response with side-by-side evidence & PDF links
    UI-->>Student: Displays Crimson Conflict Banner + Verbatim Quotes

    opt Student Relinquishes Conflicting Award (Closing the Loop)
        Student->>UI: Selects "Record Relinquishment" (Surrender Goa, Retain Samsung)
        UI->>Server: POST /api/resolve {studentId, retainedId, surrenderedId, notes}
        Server->>Lake: @sanity/client.create(studentDecision document)
        Lake-->>Server: Document committed (_id: decision-xyz)
        Server-->>UI: Resolution confirmed
        UI->>UI: Live update Student Ledger view
    end

    opt Follow-Up Inquiry (Decision Carryover)
        Student->>UI: "I surrendered Goa. Can I accept FTII alongside Samsung?"
        UI->>Server: POST /api/evaluate {question, studentId}
        Server->>MCP: Fetch active schemes + studentDecision for studentId
        Lake-->>MCP: Returns active relinquishment (Goa = SURRENDERED)
        Server->>Gemini: Prompt contains Goa as legally surrendered
        Gemini-->>Server: Verdict: PERMITTED (evaluates Samsung vs FTII only)
        Server-->>UI: Green Permitted Banner (Zero Hallucination)
    end

我如何使用 Sanity

ScholarStack 依赖 Sanity 作为结构化法律知识库以及主动审计账本用于学生合规决策。

1. 结构化 Schema(消除向量搜索幻觉)

标准的检索方法将规则手册视为扁平文本块。在评估两个方案能否叠加时,扁平文本嵌入常常模糊了法定禁止与例外之间的界限。

在 ScholarStack 中,每项奖学金都在 Sanity 中以清晰的 schema 边界建模:

// studio/schemaTypes/scholarshipScheme.ts
export const scholarshipScheme = defineType({
  name: 'scholarshipScheme',
  title: 'Scholarship Scheme',
  type: 'document',
  fields: [
    defineField({name: 'title', title: 'Scheme Title', type: 'string'}),
    defineField({name: 'authority', title: 'Governing Authority', type: 'string'}),
    defineField({
      name: 'category',
      title: 'Category',
      type: 'string',
      options: {list: ['central', 'state', 'corporate', 'institute']},
    }),
    defineField({name: 'officialDocumentUrl', title: 'Official Rulebook PDF URL', type: 'url'}),
    defineField({name: 'documentTitle', title: 'Formal Document Title', type: 'string'}),
    defineField({name: 'summary', title: 'Scope & Purpose', type: 'text'}),
    defineField({name: 'benefits', title: 'Financial Benefits', type: 'string'}),
    defineField({
      name: 'stackingRule',
      title: 'Non-Stacking Regulation',
      type: 'object',
      fields: [
        defineField({name: 'hasNonStackingRestriction', title: 'Has Restriction', type: 'boolean'}),
        defineField({name: 'exactClauseText', title: 'Verbatim Clause Text', type: 'text'}),
        defineField({name: 'clauseReference', title: 'Clause Reference / Section', type: 'string'}),
        defineField({name: 'consequenceOfViolation', title: 'Penalty of Violation', type: 'text'}),
        defineField({name: 'allowedExceptions', title: 'Allowed Exceptions', type: 'text'}),
      ]
    }),
  ]
})

学生裁决以一等文档形式存储,并带有强引用:

// studio/schemaTypes/studentDecision.ts
export const studentDecision = defineType({
  name: 'studentDecision',
  title: 'Student Compliance Decision',
  type: 'document',
  fields: [
    defineField({name: 'studentId', title: 'Student Identifier', type: 'string'}),
    defineField({
      name: 'retainedScheme',
      title: 'Retained Scholarship Scheme',
      type: 'reference',
      to: [{type: 'scholarshipScheme'}],
    }),
    defineField({
      name: 'surrenderedScheme',
      title: 'Surrendered Scholarship Scheme',
      type: 'reference',
      to: [{type: 'scholarshipScheme'}],
    }),
    defineField({name: 'resolvedAt', title: 'Resolved At', type: 'datetime'}),
    defineField({name: 'resolutionStatus', title: 'Status', type: 'string'}),
    defineField({name: 'notes', title: 'Administrative Notes', type: 'text'}),
  ],
})

使用这种结构,我们的智能体投射出经过验证的契约和强引用,保证事实确定性。


2. 播种 36 个已验证方案(为知识库预算而设计)

Sanity Challenge 指南指出:

“知识库处于 beta 阶段,目前最多索引 150 个文档。请针对该预算进行设计,或者通过启用了嵌入的 Context MCP 端点将你的智能体指向完整数据集。两者都计入 Path One。”

我们正是为这一知识库预算设计了 ScholarStack。使用scripts/seedCorpus.ts,我们播种了36 本真实的奖学金规则手册到 Sanity Content Lake,涵盖四个不同的司法管辖区:

  1. 中央部委方案(10 个方案):
    • 中央部门 Post-Matric SC/ST/OBC 奖学金(NSP)
    • PM YASASVI Pre-Matric 方案
    • AICTE Pragati 女生奖学金
    • AICTE Saksham 残障人士奖学金
    • 总理研究奖学金(PMRF)
    • INSPIRE 高等教育奖学金(SHE)
    • SC/ST 国家海外奖学金
    • Ishan Uday 东北地区特别奖学金
    • 国家 Means-cum-Merit 奖学金(NMMS)
    • 中央部门利息补贴方案(CSIS)
  2. 邦福利局(9 个方案):
    • 果阿社会福利局 - 家庭护理津贴
    • 马哈拉施特拉 MahaDBT Post-Matric OBC 奖学金
    • 卡纳塔克 Vidyasiri e-PASS 食宿方案
    • 西孟加拉 Swami Vivekananda Merit-cum-Means(SVMCM)
    • 德里 SC/ST/OBC 邦级 Merit 奖学金
    • 北方邦 Post-Matric 奖学金与学费报销
    • 泰米尔纳德邦 Post-Matric SC/ST 福利奖学金
    • 拉贾斯坦邦 Post-Matric 奖学金方案
    • 喀拉拉邦 Aspire 奖学金方案
  3. 企业 CSR 项目(9 个方案):
    • Samsung Star Scholar CSR 项目
    • Reliance Foundation 本科生奖学金
    • Tata Trusts 医学与医疗保健研究资助
    • Aditya Birla Group 奖学金
    • ONGC Foundation SC/ST 学生奖学金
    • Kotak Kanya 优秀女生奖学金
    • HDFC Bank Parivartan ECSS 项目
    • Infosys Foundation STEM Stars 奖学金
    • Siemens 奖学金项目
  4. 顶尖自治学院(8 个方案):
    • IIT Guwahati Merit-cum-Means 学院奖学金
    • 印度电影电视学院(FTII)学生奖学金
    • IIT Bombay Institute Merit-cum-Means (MCM) Scholarship
    • BITS Pilani Merit-cum-Need (MCN) Scholarship
    • CSIR-UGC Junior Research Fellowship (JRF)
    • FTII Freeship & Academic Project Grant
    • IIM Ahmedabad Need-Based Financial Aid
    • IISc Bangalore Institute Fellowship

每一条记录都包含直接从已发布的政府公报和官方项目章程中逐字复制的条款文本。


3. 通过 Sanity Context MCP 进行查询(使用了 4 个工具)

ScholarStack 连接到位于以下地址的官方 Sanity Context MCP 端点:
https://api.sanity.io/v2026-03-03/context/mcp/axvnim0k/production

该智能体利用了全部四个 Sanity Context MCP 工具:

  • initial_context:在冷启动时将 schema 指南、数据集结构和可用工具拉入推理循环。
  • groq_query:运行轻量级 GROQ 投影以提取活跃计划、不可叠加条款和官方文档链接,而无需获取庞大的文档负载。
  • schema_explorer:检查以下两者之间的引用属性studentDecision文档和scholarshipScheme规则手册。
  • array_field_reader:遍历 scheme 文档上的数组和 Portable Text 字段,而不会造成负载裁剪或膨胀。

4. 处理矛盾并闭环

当两份奖学金规则手册因禁止同时获奖而相互矛盾时,ScholarStack:

  1. 呈现矛盾:并排显示 Scheme A 的条款和 Scheme B 的条款,并附上确切措辞和处罚条款。
  2. 提供来源验证:嵌入指向官方政府和公司 PDF 规则手册的直接链接,以便学生可以在源文档中验证该条款。
  3. 写回 Sanity:当学生执行正式放弃时,后端调用@sanity/client以提交一个studentDecision文档,其中包含指向保留和放弃奖项的引用指针。
  4. 将决定延续下去:后续评估会查询 Sanity Lake 以获取活跃的学生放弃记录。如果某个奖项已被正式放弃,合规引擎会将其排除在活跃冲突计算之外。

Sanity 项目详情


智能体会话

本次智能体会话的开发记录——涵盖 Sanity Studio 配置、Context MCP 工具集成、schema 数据填充、零幻觉验证以及界面优化——已发布并嵌入在上方。