为你的企业构建语义发现层

在上一篇文章中,我论述了企业不需要另一个聊天机器人。它们需要的是一种让公司内部的人能够互相发现的方式——一个位于底层、在助手层之下的语义发现层。

这是工程层面的后续内容。如果你正在构建类似的东西——或者在评估别人声称他们已经构建的东西——这些就是关键的决策,来源于 PeopleMesh 作为一个开源项目的当前实现方式。

我会让数学部分尽量轻松。决定一个发现系统好坏的,大多不是数学。而是表示、检索、排名,以及你在它们之间划定的边界纪律。

1、系统的形态

在做任何具体决策之前,脑海中先有个全局图是有帮助的。语义发现层通常有四个组成部分:顶层的客户端、包含服务的后端、用于嵌入和LLM工作的模型层,以及同时存储向量及其周边数据的存储层。

┌──────────┐  ┌──────────────┐  ┌────────────┐
│ Browser  │  │  MCP Client  │  │ FEEDS/CRON │
│  (SPA)   │  │(Claude, GPT, │  │  (ingest)  │
└────┬─────┘  │  Agents...)  │  └─────┬──────┘
     │ REST   └──────┬───────┘        │ REST
     │               │ MCP/HTTP       │
     ▼               ▼                ▼
┌─────────────────────────────────────────────┐
│              Application backend            │
│                                             │
│  REST API ◄──► Services ◄──► MCP Tools      │
│                    │                        │
│            ┌───────┴────────┐               │
│            │  Embeddings +  │               │
│            │      LLM       │               │
│            └───────┬────────┘               │
│                    │                        │
│                    ▼                        │
│         PostgreSQL + pgvector               │
└─────────────────────────────────────────────┘

有三点值得立即注意。

同一个服务层同时响应REST和MCP请求,因此Claude或ChatGPT中的AI代理获得与Web UI相同的排名质量。向量存储和关系数据存在于同一个数据库中(这比人们想象的更重要),我们稍后会回到这一点。LLM是一个组件,而不是产品的中心。

在PeopleMesh中,我使用LangChain作为模型提供者的抽象层,PostgreSQL配合pgvector用于存储,Docling用于解析简历。具体的技术栈不如其背后的架构纪律重要。

2、表示即产品

这是整篇文章中最重要的一句话,所以我再重复一遍:表示即产品。

大多数演示都是从选择一个嵌入模型并输入原始文本开始的。这恰恰是大多数系统开始显得平庸的地方。

你嵌入什么决定了系统能找到什么。一个个人资料不是一串字节。它是一系列关于什么重要的选择。职位?非常重要。技能?是的,但先要标准化。自由文本简介?是的,但要精简。位置?可能作为元数据,而不是嵌入文本。工作年限?几乎肯定是元数据。

一个人节点在嵌入之前被塑造成的简化版本大致如下:

Role: Platform Engineer
Skills: Java, Kubernetes, distributed systems, PostgreSQL
Tools: Terraform, ArgoCD, Prometheus
Industries: Fintech, regulated environments
Languages: English, Italian
Soft skills: technical leadership, mentoring
Bio: Building reliable infrastructure for trading systems.
     Comfortable owning incident response and architecture review.

这个字符串——而不是原始的配置文件JSON——才是被嵌入的内容。职位、社区、项目也是如此。不同的节点类型,但每一种都在接触嵌入模型之前被转换为一个经过深思熟虑的、可比较的文本形态。

塑造这个字符串的决策并不光鲜。它们看起来更像产品判断而非ML工作。但它们也决定了系统是让人感觉精准还是平庸。

3、没人告诉你的技能字典

几乎每个教程都跳过了一点:技能标准化。

真实的个人资料是混乱的。一个人写"k8s",另一个写"Kubernetes",还有一个写"容器编排"。没有标准化,这三个在系统中看起来就是三种不同的技能。语义模型可以在很大程度上弥补这一点,但你是在迫使每次检索去做本应在写入时就完成的工作。

PeopleMesh维护一个全局技能字典作为单独的表 skills.skill_definition,有四个发挥价值的列:

  • name — 规范形式
  • aliases — 同义词和显示变体
  • usage_count — 有多少个人资料引用了它
  • embedding — 技能本身的语义向量

当保存个人资料时,传入的技能术语首先与名称和别名进行匹配、标准化,然后嵌入文本从规范值构建。这个字典成为混乱的人类书写和下游结构化匹配之间的连接组织。

它还解锁了一个悄然强大的能力:技能级别的相似性。"PostgreSQL"和"MySQL"不是同一个技能,但它们的嵌入很接近。当排名稍后想知道一个候选人是否在需求的"邻近区域"内时,字典已经知道了。

4、为什么选择pgvector而不是托管向量数据库

这是一个有真正权衡的真实架构决策。以下是诚实的版本。

托管向量数据库——Pinecone、Weaviate、Qdrant Cloud——在大规模向量搜索方面表现出色。如果你有数亿个向量和严格的延迟要求,你可能应该使用其中一个。

大多数企业内部发现系统没有数亿个向量。它们只有数十万个。在这个规模下,有三点因素使决策倾向于PostgreSQL内部的pgvector。

事务一致性。 当用户撤销同意时,他们的向量和关系数据需要一起消失,而不是最终消失。跨系统的一致性是一个没人想在凌晨2点调试的尖锐问题。

运维简单性。 一个数据库需要备份,一个需要迁移,一个需要轮换凭据,一套监控仪表板。对大多数团队来说,第二个专业化数据系统的认知开销比看起来更昂贵。

当内容和嵌入存在于同一个存储中时,GDPR合规更容易。 数据导出、删除、保留执行——它们都变成了单数据库操作。使用外部向量数据库,你是在做分布式删除,并祈祷最终一致性不会在监管审计时给你带来麻烦。

权衡是真实的:pgvector不会带你到十亿规模的工作负载。但对于企业内部的发现层来说,这个上限很少是真正的约束。

5、查询解析:结构加意图

这就是LLM做我真正想让它做的工作的地方。

用户输入:"高级后端工程师,Kubernetes,欧洲,必须会说英语。"

你不想把这个字符串直接扔给向量搜索。在今天的PeopleMesh中,你想从中提取两类信号。

结构:管道其余部分可以推理的显式字段。地理 = 欧洲。语言 = 英语。资历 = 高级。其中一些成为预过滤器。其他成为排名输入或解释字段。

意图:语义核心。"精通Kubernetes的后端工程师。"在PeopleMesh中,这变成 embedding_text,即用于检索的紧凑短语。

PeopleMesh组装一个同时携带两者的 SearchQuery 对象:

{
  "must_have": {
    "skills": ["Kubernetes"],
    "skills_with_level": [],
    "roles": ["backend engineer"],
    "languages": ["English"],
    "location": ["Europe"],
    "industries": []
  },
  "nice_to_have": {
    "skills": [],
    "skills_with_level": [],
    "industries": [],
    "experience": []
  },
  "seniority": "senior",
  "negative_filters": {
    "seniority": null,
    "skills": [],
    "location": []
  },
  "keywords": ["backend engineer"],
  "embedding_text": "backend engineer with Kubernetes",
  "result_scope": "people"
}

embedding_text 被嵌入并与向量存储匹配。结构化字段然后驱动后续的过滤、排名和解释步骤。例如,在当前的实现中,位置和口语可以在重新评分之前缩小候选人范围,而资历、地理和必选项覆盖等信号塑造最终得分。

这是我为语言模型偏好的角色:不是生成答案,而是足够好地阅读混乱的人类输入以结构化它。不是预言机,而是翻译器。

6、混合排名是产品质量所在

如果你把纯向量相似性当作排名,你会得到一个演示很美但在生产中失败的系统。

向量相似性擅长在正确的邻域中找到东西。它不擅长判断候选人是否真正满足必选项、是否居住在正确的国家、是否说所需语言或具有正确的资历。这些信号需要自己的评分路径。

在今天的PeopleMesh中,人员结果的得分大致为:

rawScore = weightEmbedding * embeddingScore
  + weightMustHave * mustHaveCoverage
  + weightNiceToHave * niceToHaveBonus
  + weightLanguage * languageScore
  + weightIndustry * industryScore
  + weightGeography * geographyScore
  + weightSeniority * seniorityScore
finalScore = rawScore * mustHavePenaltyFactor * negativeSkillsPenaltyFactor

有几点值得注意。

惩罚因子是显式的,而非隐式的。 必备技能的部分缺失会以乘法方式降低得分,而不是消失在某个不透明的启发式中。必备技能覆盖的完全缺失会被严厉得多地处理,并可以将结果归零。这是一个产品决策,不仅仅是数学决策。

权重是可配置的,而非硬编码的。 不同的组织关注不同的信号。银行非常重视行业和语言。初创公司可能比地理位置更看重技能匹配。在PeopleMesh中,权重覆盖是搜索选项的一部分,而其他调节旋钮如 peoplemesh.search.candidate-pool-sizepeoplemesh.skills.match-threshold 控制排名管道周围的召回和技能相似性行为。

得分分解在API响应中暴露。 UI不只是显示"85%匹配"——它显示为什么:语义相似性、必选项覆盖、地理、语言、惩罚以及背后的活跃权重。这使得结果可解释。人们信任他们能看到推理的系统。

对于非人员节点如职位、社区、活动和项目,PeopleMesh使用相关的评分路径,包含关键词贡献和略有不同的权重组合。同样的思路,不同的信号。

这是大多数"AI搜索"教程跳过的部分。也是实际产品所在之处。

7、MCP角度:发现即工具

最后一个架构选择,它比我预期的更重要。

PeopleMesh中的REST端点和MCP工具处理程序都委托给同一个服务层。有一条明确的分层规则:mcp -> service -> repository -> database,没有捷径。MCP只是另一种传输方式,不是并行管道。

实际后果:ChatGPT、Claude或任何支持MCP的客户端内的AI代理可以作为一个工具调用发现层,它获得与在Web UI中输入的用户相同的排名质量。没有"AI模式"。没有第二个管道。相同的逻辑、相同的解释、相同的同意执行。

这与上一篇文章的宣言直接相关。我们不需要聊天窗口成为产品。我们需要的是底层的坚实智能,以及一个干净的接口,让任何客户端——浏览器、代理、批处理作业——都能提出相同的问题并信任相同的答案。

智能作为工具。不是舞台。

8、真正困难的是什么

如果你只从这篇文章中记住一个操作层面的教训,那就是这个。困难的部分不在炒作所在之处。

嵌入提供者不是困难的部分。像LangChain4j这样的抽象使提供者切换变得可管理。真正的工作紧接着才开始:重新嵌入、重新调整阈值、检查结果质量是否发生了变化。

向量数据库不是困难的部分。对于PeopleMesh当前的规模,pgvector可以处理工作负载。

困难的部分是:

  • 选择嵌入什么和保留什么作为元数据
  • 标准化你的领域词汇,使检索有干净的数据可用
  • 设计能与真实用户接触后存活的混合排名
  • 使解释可见,让人们信任结果
  • 将同意机制编入数据模式中,而不是叠加在上面

这些是产品工程决策。它们不会成为好的推文截图。但它们决定了系统在六个月后是否真正有用。

9、如果你想让模型消失,就把其余部分做好

一个运行良好的发现系统有一种安静的满足感。用户输入自然语言,得到感觉正确的答案,从不去想中间的模型。智能变得不可见。这就是目标。

达到这个目标不是靠选择最花哨的LLM。而是认真对待表示。把排名当作产品来对待,而不是默认值。把同意和可解释性放在它们应该在的地方——在基础层,而不是润色层。

如果你正在构建这样的系统,PeopleMesh 在Apache-2.0下开源。复刻它,从有效的部分学习,忽略不适合你上下文的部分。我很想看到你构建了什么,也很想收到关于我们做错了什么的反馈。


原文链接: How to Build a Semantic Discovery Layer for Your Company

汇智网翻译整理,转载请标明出处