☰
AI 不得写下你从未说过的话:freehire 经验银行与证据门设计(Provenance 决定可写入 CV)
2026/10/22 13:11:28 网站建设 项目流程

【免费下载链接】freehire

freehire — the open-source search engine for job seekers

项目地址:https://gitcode.com/GitHub_Trending/fr/freehire
点击查看免费下载

在 freehire 这个开源求职搜索引擎里,AI 助手可以帮你改写简历(CV),但它有一个铁律:AI 不得写下你从未说过的话。实现这个铁律的是两套机制——经验银行(experience bank)与证据门(evidence gate):前者把你说过的每一段真实经历沉淀为带来源标签(Provenance)的证据,后者在写入 CV 前逐条核验“这句话是谁说的”。本文带你完整看懂这套 Provenance 决定可写入 CV 的设计。

问题:AI 改简历为什么容易“编造经历”

让大模型直接改写简历,最常见的事故不是文笔不好,而是它自信地补全你没有的经历——“主导过 Kubernetes 迁移”“管理 5 人团队”。模型不是在撒谎,它只是在统计意义上猜了一个高频答案。而招聘方会核验学位,也会背调项目,一句凭空出现的经历足以毁掉整份 CV。

一种常见做法是在 system prompt 里写“不要编造”。但 prompt 纪律是会衰减的:对话越长,模型越容易忘记规则。freehire 的答案是——把规则从提示词搬进数据:给每条经历打上“谁说的”标签,把校验放进服务层代码,模型绕过它的可能性降为零。

经验银行:把经历变成可累积的证据

经验银行的代码位于 internal/candidate/experience/,由两张表构成(见迁移 0047_experience_bank.sql):

实体粒度说明
Employment一段经历发生的“地方”一份工作(job)或一个项目(project),含公司、角色、时间、技术栈
Atom一条 CV 级别的证据claim(这句话本身)+ context(怎么做的)+ metrics(数字)+ skills(规范技能词)+provenance(来源)

关键点是累积:上传的简历解析只是缓存,重新上传就会覆盖;定制后的 CV 又随职位被丢弃。而银行只增不删——导入永不删除,只有本人可以删除。你在第 3 次改简历时对 AI 说“我确实做过这次迁移”,第 4 次改简历时它不用再问你一遍。

Provenance 四标签:每条证据必须交代“谁在说话”

每条 Atom 的 provenance 字段只有四种合法值,数据库约束直接拒绝其他值(0047_experience_bank.sql):

Provenance谁在说话能否写入 CV
cv_import候选人(自己的简历)✅
stated_in_chat候选人(自己的话,AI 核对过原句)✅
manual候选人(自己手动录入)✅
agent_inferred模型(自己的推断)❌ 直到本人确认并被重新打标

对应的判定函数只有一个谓词:Publishable()(experience.go)——前三者放行,agent_inferred拒绝,未知值一律拒绝。这是“失败安全(fail closed)”:宁可少写,不可写假。

更妙的是标签不由调用方自报。存储层从“入口点声明的作者(Author)”推导标签,请求体里带的 provenance 字段一律被忽略(author.go)。这堵死了“洗白”路线:把推断先存成agent_inferred,再编辑、再读出manual、最后引用进 CV——改词不等于重新声明,改写型编辑(AuthorRewrite)只能继承原标签;标签缺失或无法识别时,一律落回agent_inferred。

证据门:写入 CV 前的最后一道检查

CV 的写入路径只有一个包 internal/candidate/cvedit/,其中 policy.go 定义了证据门规则:

  1. 默认即声明:文档中除“呈现型”字段(模板、边距、页头联系方式等,见presentationShapes豁免清单)外,一切字段都默认是“关于候选人的声明”——工作经历、技能、教育、认证、项目,甚至将来新增的字段。方向刻意反着来:新字段必须被显式豁免,而不是默认放行。旧版清单曾只列“哪些字段算声明”,结果没人核验过的学历和证书就悄悄上了 CV。
  2. AI 必须引用证据 ID:模型发起的写入操作(set/insert)必须携带evidence_id——它引用的银行条目 ID。一个操作没引用,整批操作全部拒绝,防止假声明混在真声明里搭车(policy.go)。
  3. 只约束 AI,不约束本人:规则是“模型的推断不得上页”,候选人写自己的经历是银行的记录来源,向他本人要引用只会让编辑器不可用。
  4. 引用必须真实可查:门去经验银行里验证这个 ID 存在、属于本人、且Publishable()为真。银行里没有的证据,引用无效。

被拒绝时模型收到的错误信息本身就是一条提示:“这句话关于候选人,需要你提供 evidence_id……如果银行里没有,先问候选人,并用 experience_add 记录答案”——错误信息是模型自我纠正的唯一通道。

从对话到落笔:一次 experience_add 的完整旅程

AI 助手在所有预设下都注册了经验工具(assistant_experience_tools.go),因为“候选人说出自己经历”的时刻无法预约。以experience_add为例:

  1. 模型调用experience_add,把成就写成一粒 Atom,并附上said参数——候选人原句的逐字拷贝;
  2. 入口点把said与本次会话的真实记录(transcript)比对(authorFor→assistant.UserSaid,见 assistant_experience_tools.go 和 message.go);
  3. 原句确实在你说的话里→ 标签为stated_in_chat,这条证据升级为“你说的话”,可写入 CV。这是唯一能让标签升格的路径,因为它依赖模型之外的东西(你的聊天记录)做了确认;
  4. 原句对不上——改写、概括、甚至捏造 → 记为agent_inferred。记录但不拒绝:模型需要把自己的假设记在案上才能回头问你。返回结果里会明确写着:can_write_cv: false,“请让候选人确认后再写入 CV”。

注意比对时连否定句都会被识别(“我没有主导过这次迁移”不能为“主导过这次迁移”作证),而查不到记录时宁严勿松:无法验证即视为模型所言。

其他值得细看的失败安全设计

  • 数字不参与归一化:ClaimKey去标点、去多余空格、小写化,但保留数字——“20s to 1s”和“30s to 1s”是两件事,绝不能合并成一条(experience.go)。去重交给唯一索引,重复上传同一份 CV 不可能产生重复证据。
  • 检索不调用模型:技能用与职位侧同一本词典(规范 slug)做集合交集,再加文本重叠兜底(“带了 5 个人”不携带任何技能标签,但仍是证据)。零分数的弱匹配直接不返回——对模型来说,弱匹配读起来就像证据。
  • 近义重复不自动合并:改写出相似措辞的两条只会标记为“软重复”,由你决定合并,系统永不静默改写证据。

总结:Provenance 是搬进数据的诚实之墙

设计问题freehire 的答案
规则放哪里放数据与服务层,不靠 system prompt
标签谁定入口点声明 Author,存储层推导,请求体自报无效
未知情况怎么办一律落为agent_inferred,拒绝发布(失败安全)
模型推断要不要保留保留(agent_inferred),等待本人确认升格
本人写自己的经历无需引用,不受证据门约束

最终效果正是文章标题那句话:AI 不得写下你从未说过的话。它写下的每一句 CV 内容都必须能追溯到一粒银行里的证据,而一粒证据能否发布,取决于 provenance——你的简历,只说你说过的话。

延伸阅读

  • 经验银行设计说明:internal/candidate/experience/AGENTS.md
  • 证据门与编辑策略:internal/candidate/cvedit/AGENTS.md、policy.go
  • 原始提案:openspec/changes/experience-bank/proposal.md
  • 数据库表结构:migrations/0047_experience_bank.sql
  • AI 助手工具实现:internal/api/handler/assistant_experience_tools.go

【免费下载链接】freehire

freehire — the open-source search engine for job seekers

项目地址:https://gitcode.com/GitHub_Trending/fr/freehire
点击查看免费下载

相关推荐

上一篇:AI 短剧卷到配音层!这个新出的开源声优模型,凭什么让全网盯着看
下一篇:图谱里的"社区":Graphify 如何发现代码的隐秘组织

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询