知识库项目三分钟讲解:完整示例与五个追问
讲项目时,先说项目性质和自己的责任,再沿一条请求解释实现,最后给验证依据与限制。以下由作者 IT枫斗者基于当前 Java 知识库教学服务填写;文档与身份用于合成教学场景,没有真实客户和生产经历。第一人称属于作者示范。读者必须按自己实际实现、复现或阅读的范围替换,不能把这段口述当作个人商业经历。
三分钟讲解全文
下面的时间仅用于练习分配,实际时长取决于语速,不是一次已经测量的录音。可先读完,再合上页面按请求链复述。
0:00—0:30:项目性质、问题与职责
“这是我用于教学的 Java 21、Spring Boot 知识库服务,使用合成文档,默认运行在本机。我负责服务端身份约束、文档版本和检索证据返回。它要解释一个具体问题:文档更新、收紧权限或删除后,当前用户还能用哪份原文回答问题。项目没有企业客户和线上流量,下面说的是本地实现及公开验证范围。”
0:30—1:15:从请求入口讲到证据
“登录后服务端签发不透明 Bearer token,数据库存 token 哈希;后续请求通过会话关联数据库用户取得租户和角色。检索先连接文档的当前版本,排除删除墓碑,再按当前角色过滤。默认模式对问题与文档提取英文词项和中文二元词项,覆盖分数达到 0.6 才保留证据。回答使用最高分文档的原文,引用里有文档 ID、版本和完整正文;没有候选时返回 refused=true 和空引用。因此我把它称为本地词项检索与原文摘录。”
1:15—2:00:用一次权限变化说明关键取舍
“重点场景是公开文档变成 ADMIN 可见。测试先创建包含 cobalt 的 READER 文档,再携带 expectedVersion=1 更新为 ADMIN 的第二版;reader 继续搜 cobalt 应拒答,直接读取是 404。不能因为第一版曾公开,就回退到第一版。实现上只读取 current_version;更新和删除先锁定本租户文档行,再检查预期版本,旧值冲突返回 409。更新在事务中保存新版本并切换指针,删除写墓碑,历史仍保留。这里验证的是状态与可见性,没有承诺物理擦除。”
2:00—2:35:给出可以打开的验证证据
“公开报告记录默认 H2 路径 17 项测试通过,另有独立 Java 进程在 127.0.0.1:8085 的 23 次 HTTP 检查,包含应用进程重启后的版本和会话检查。包内有 JUnit XML、smoke 原始响应和源码哈希。这些数字分别对应不同验证口径,不能相加成准确率。它们支持已列场景的断言,也不代表断电恢复、线上负载或所有并发交错都已验证。”
2:35—3:00:把扩展与未测部分说清楚
“可选 Spring AI 与 pgvector 路径有真实向量库存储测试,使用三维确定性 fixture;公开报告中真实模型 API 和语义质量未测,而且回答仍是原文摘录。默认每份文档是一个检索单元,没有分块。下一步若扩展同义问法或检索质量,需要固定文档快照、题集和判断规则,再运行真实模型评测,才能讨论效果;当前没有性能和业务收益数字。”
五个追问的完整回答
追问一:客户端能否传 tenant 或 role,让自己看到其他租户?
示范回答:“调用者身份来自服务端会话,不由文档请求体或自定义 header 决定。Auth.security 用 Bearer 的 SHA-256 哈希查会话,并关联 app_users 读取 tenant 与 role。文档的 minRole 表示文档所需级别,不能把它理解成当前用户的身份。Knowledge.list 的 SQL 先限定租户、未删除和当前版本,再做角色检查;另一租户即使是 ADMIN,也不能读取这份文档。不存在或不可见的文档统一 404,reader 写入返回 403。公开测试 serverOwnsTenantAndRole 与 tenantIsolationForReadUpdateDeleteAndSearch 分别检查身份注入和跨租户操作。”
边界补充:“每个请求重新读取用户角色,所以角色修改影响既有 token 的后续请求;已经认证、正在执行中的请求以认证时身份为准。我不会把它说成能中断所有在途请求。当前是固定演示身份,生产注册、密码重置、TLS、限流和完整审计不在项目范围内。”
追问二:为什么更新后不查旧版本?两个编辑者同时提交怎么办?
示范回答:“历史存在不等于仍可访问。新版本可能已经收紧权限,文档也可能已删除;回退旧公开内容会绕过当前状态。Knowledge.list 只连接 kb_documents.current_version,并排除 deleted=TRUE。update 和 delete 在事务中,先按租户与未删除条件执行 FOR UPDATE 行锁,再读取当前可见文档,比较 expectedVersion。两个编辑者拿到同一版本时,先成功的更新会推进版本;后一个持旧值提交应得到 409,需要重新读取后决定是否修改。”
边界补充:“这是代码所采用的冲突处理方式。公开的 staleVersionConflicts 测试验证陈旧版本的更新与删除返回 409,不是所有并发时序的压力验证;permissionChangeCannotFallBackToPublicOldVersion 检查权限收紧后不回退。删除保留墓碑与历史,没有实现历史恢复接口。我也不会把单机事务描述成跨服务事务或完整分布式一致性。”
追问三:这是不是模型问答?score=1 能否说明回答完全正确?
示范回答:“默认 mode 是 local-lexical-extractive,没有调用 embedding 或聊天模型。Knowledge.tokens 提取词项,search 用命中的问题词项数量除以问题词项总数,空词项集合得 0,至少 0.6 才进入候选。命中时 answer 取排序后第一条证据的完整正文,quote 也来自保存的正文。score=1 只能说明提取出的查询词项全部出现,不能说明文档回答了问题,更不是答案正确概率。”
边界补充:“例如同一组词可能出现在无关语境,同义改写也可能没有共同词项;这两类都需要额外评测。无候选时 refused=true、citations=[],说明没有满足当前规则的证据,不能声称系统已经判断所有语义问题都无答案。现有 citationsAreExactAndVersioned 与 unknownQuestionRefusesWithoutCitation 只验证引用一致和固定无命中输入,没有证明一般语义质量。”
追问四:既然有 Spring AI 与 pgvector,通过测试为什么还不能写语义 RAG 效果?
示范回答:“实现确实提供官方 EmbeddingModel 和 PgVectorStore 接入。使用真实模型的 ai 模式需要同时启用 Maven 的 -Pai 与运行时 ai profile,另行准备 PostgreSQL/pgvector 和模型配置;单独启 Maven profile 只是让相应代码参与编译。公开向量集成测试用真实 PostgreSQL,但 EmbeddingModel 是三维确定性 fixture:文本含 java 返回一组固定向量,否则返回另一组。它适合稳定检查向量存储、tenant/minRole metadata 过滤、更新删除和旧候选处理,没有验证模型如何理解自然语言。”
边界补充:“AiConfiguration.Gateway.search 做 metadata 过滤后,Knowledge.search 再对权威数据库的当前可见文档及版本进行核对,避免旧向量成为证据。公开报告最终 22 项里是 21 通过、1 跳过,跳过的是 LiveEmbeddingTest;liveModelApi 和 semanticRagQuality 都明确未测。0.75 是向量候选阈值,未做语义质量校准;该路径仍返回原文,没有聊天模型生成答案。”
追问五:你凭什么说项目做完了?如果继续做,先补什么?
示范回答:“我只说教学范围内已实现并有公开验证,不说生产可用。项目包有 README、API、实现和验证材料;公开报告能看到默认 17 项测试、最终 ai 编译验证 22 项及跳过项、独立进程 23 次 HTTP 检查。要核对具体主张,打开对应 JUnit 用例或 smoke 响应,而不是只看 passed 字段。报告与源码用 manifest 哈希对应,下载包也有 SHA-256,可以确认材料属于同一版本。这些是项目既有证据,不是读者自己的执行结果。”
边界补充:“后续若评估检索质量,我会先建立固定文档快照、问题和相关证据标注,把检索相关性、原文支持与回答正确性分开判断;真实模型调用需要另行运行并记录配置。若准备公开部署,则先补身份管理、凭据替换、TLS、限流和审计。这些是后续计划,当前没有完成证明。我不会给出尚未测量的吞吐、延迟,也没有真实客户收益或学员录用结果。”
填写示例与练习表
先将“项目已有事实”和“本人参与证据”分开记录。下表已填写作者示范的事实栏,读者操作栏说明应产出什么。作者的报告可以作为核对依据,不能替代本人复跑或修改记录。
| 练习项 | 作者示范:已经能核对的内容 | 你需要执行并记录 |
|---|---|---|
| 开场与职责 | 合成文档、本机教学服务;作者讲身份、版本与证据返回 | 录一段开场;明确本人是运行、阅读、补测试还是改实现 |
| 请求链 | Bearer → 会话关联用户 → 当前可见版本 → 词项评分 → 原文与引用 | 画出或口述这五步;记录 Auth.security、Knowledge.list/search 的定位 |
| 权限反例 | cobalt 文档从 READER 更新为 ADMIN,reader 不回退旧公开版本 | 保存创建、更新、reader 检索与读取的身份、请求、状态码及响应 |
| 版本与删除 | 旧 expectedVersion 冲突;正确版本删除后不再返回证据 | 记录实际 ID、版本及 409/204;核对删除后的 refused 和 citations |
| 证据口径 | 默认 17;最终 22 中 21 通过、1 跳过;HTTP 检查 23 次 | 若亲自复跑,记录命令、环境和自己的实际结果,保留失败与跳过项 |
| 能力限制 | 本地词项原文摘录;pgvector 是三维 fixture,真实模型与语义质量未测 | 在录音中明确说出两项限制;未执行向量路径时直接说明 |
| 复盘动作 | 对“架构”“准确率”等空泛词追问实现位置与判断规则 | 回听并标出无依据的主语、数字和结果,重录相应段落 |
仅阅读者的已填写表达示例:“我目前完成了源码阅读和公开报告核对,能说明从 Bearer 身份到当前可见文档、再到原文引用的流程。我还没有本机运行或代码提交,公开报告的测试结果属于原项目;下一步先复现权限收紧场景,再记录实际响应。”这段话适合学习复述,不能直接改成简历中的实现职责。
仅复现者的填写示例:在确实执行并保留上述请求后,可以说“我基于公开教学服务复现文档收紧权限后的拒答与旧版本写入冲突,保存请求和响应,并沿 list/update/search 分析原因;未改后端实现”。如果仅运行部分步骤,删除没有做过的内容;如果有新增提交,再补准确的改动位置和新旧输出,不套用作者职责。
建议做两轮练习:第一轮对照全文录音,用表格定位遗漏;第二轮只看职责与证据索引,连续讲述并回答五个追问。讲超时优先压缩背景,保留关键请求、验证条件与边界;讲不满时补触发输入和代码位置,不填虚构事故或业务成绩。
自查标准:什么情况下可以交给别人追问
- 性质和主语清楚:听者能区分合成教学项目、作者实现和你的实际参与;没有虚构任职、客户或生产故事。
- 链路可核对:能定位身份来源、当前版本选择、角色过滤和引用构造;不会把 minRole 当调用者身份。
- 反例完整:能说出权限收紧前后的身份、输入、预期状态和引用变化;知道删除不是物理擦除。
- 结果有条件:说明默认 H2、演示身份、合成文档;自己的结果附命令与输出,原项目报告明确归属。
- 数字不混算:不把重叠的测试数量相加,不把覆盖分数或 fixture 通过转换成语义准确率,也不补性能数字。
- 未测会直说:能说明真实模型 API、语义质量、线上负载等未验证范围;后续计划使用“拟验证”,不使用“已完成”。
六项都能用具体材料解释,再让同伴根据五个追问打断讲述。任何一项说不清,就回到对应请求或源码补证据;背熟全文不能替代实际参与,也没有求职结果保证。
代码与报告来源
源码与验证材料下载内,knowledge-service/README.md 和 API.md 给出环境与契约;src/main/java/cn/itfeng/knowledge/Auth.java 对应身份,Knowledge.java 对应当前版本、事务与检索,Api.java 对应接口。默认场景对应 src/test/java/cn/itfeng/knowledge/ApiIntegrationTest.java,持久化对应 PersistenceIntegrationTest.java;向量实现与 fixture 分别在 src/ai/java/cn/itfeng/knowledge/AiConfiguration.java、src/ai-test/java/cn/itfeng/knowledge/PgVectorIntegrationTest.java。仓库位置均在 examples/knowledge-service/ 下。
公开报告对应 docs/verification/knowledge-service/report.json;包内 verification/report.json、smoke.json、JUnit XML 和源码 manifest 可核对原始依据。独立进程记录由包内 tools/verify.py 生成,重启检查不等于断电或硬件故障测试。这里引用既有报告,没有把建议步骤编造为新执行结果。
表达原则参考项目简历指南与原有单文件实验样例;后者的七个回放场景不能用于替代本服务的验证记录。
回看简历逐句改写或修改室目录,按项目到简历路线补个人实践,用项目表达资料归档。需要运行入口时,返回知识库项目说明或首跑指南;继续训练条件变化下的回答,可进入Java 面试追问实战。
