mcpField
C
Coalent

Coalent

本地服务
coalent.ai记忆与知识126 周前更新

关于 Coalent

Coalent 为 AI Agent 和检索增强应用提供上下文复用与新鲜度管理。它跨查询缓存基于来源的事实,并在来源变化时仅使相关缓存单元失效;可叠加在现有检索器之上。

主要功能

  1. 01跨查询语义缓存
  2. 02基于来源的原子事实
  3. 03来源变更时定向失效
  4. 04跨单元证据召回
  5. 05读取失败后修复缓存
  6. 06可接入自有检索器和模型

适用场景

  1. 01在 Agent 查询间复用来源事实
  2. 02文档修改后更新缓存答案
  3. 03回答涉及多份文档的问题
  4. 04读取失败后修复上下文

MCP 相关

coalent-mcp 服务通过七种工具向 MCP 客户端提供缓存上下文与新鲜度操作。支持 stdio 和 HTTP 模式,也可让多个客户端共享一个缓存。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"nisarg-pujara-vectorlink-coalent": {
"command": "uvx",
"args": [
"coalent"
],
"env": {
"OPENAI_API_KEY": "<OPENAI_API_KEY>",
"COALENT_MCP_TOKEN": "<COALENT_MCP_TOKEN>"
}
}
}
}
启动命令uvx coalent
需要配置的环境变量
OPENAI_API_KEY密钥Required in folder (--watch) mode for semantic embeddings (text-embedding-3-small) and build synthesis (gpt-4o-mini); the server exits loudly without it rather than degrade. Factory (--cache-factory) mode brings its own models and needs no key.
COALENT_MCP_TOKEN密钥Optional shared secret for --transport http: when set, every HTTP request must carry Authorization: Bearer <token>. Unused over stdio.

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypicoalent0.7.0

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

Coalent

为 AI Agent 和 RAG 提供实时、来源失效时同步失效的上下文。
只需构建一次理解,即可随处复用,并自动保持最新。

pypi python license typed tests discord

📖 文档  ·  coalent.ai  ·  💬 Discord

快速入门 · v0.7 新功能 · 门控阶梯 · 使用自己的技术栈 · MCP · LangChain · 基准测试 · 命令行


你的 Agent 每次调用都会重新读取相同的来源;一旦来源发生变化,所有缓存的答案就会悄无声息地出错。

Coalent 只构建一次理解,根据查询的含义进行缓存,并在底层来源发生变化时精准失效。正确性不输于重新读取所有内容,成本却低得多,而且永不过时。

为什么选择 Coalent

每个上下文层都不得不在三件事之间取舍。Coalent 旨在同时兼顾这三点:

  • 🧠 提取式理解,而非分块。 它会缓存由你的大模型提取的、与查询无关且基于来源的原子声明,保留每个数字和事实,让一个缓存单元能够回答之后许多不同的问题。每个单元都会保留原始证据,因此如果命中内容无法充分覆盖查询,就会回退到检索,而不是给出依据不足的回答。
  • ♻️ 在查询、Agent 和文档之间复用。 语义缓存以查询的含义为键:再次提问,或由另一个 Agent 提问,都能命中热缓存。跨单元召回会汇集多个单元中的声明,以回答证据分散在不同文档中的多跳问题,无需额外调用大模型。
  • 🌿 来源可溯,内容常新。 每个单元都会记住它使用的确切来源。某个来源变更时,只有实际用到它的单元会变为过时,精准、自动且延迟更新。

Coalent 位于检索之上——可接入任意检索器(向量数据库、混合搜索、GraphRAG、工具、API)。它是新鲜度与复用层,而不是又一个检索器——刻意与 GraphRAG 预先构建整张图的开销相反:它轻量、单元彼此独立,仅在查询实际需要时延迟构建,并通过标记单个单元为过时来刷新(无需改造整张图)。

v0.7 新增——自愈版本。失败链路如下:读取失败时, 你的 Agent 会调用 repair(read_id),缓存会重新提取构建时遗漏的内容—— 并永久修复。在同一套冻结的 605 道题测试装置上测得:0.826,相比 v0.6 最强配置的 0.774,在相同的约 983 个 token 服务预算下提升 5.3 个百分点, 最终拒答减少 69%。此外,默认读取路径切换为 pool:使用语义嵌入器时,读取路径会自动设为 "pool"(read_path="unit" 仍是字节级不变的备用选项)。参见 v0.7 新增内容。

v0.6.1 新增——MCP 服务:coalent-mcp 让你只需一行配置,即可将缓存接入 Claude Code、Cursor 或任何 MCP 客户端(在 Claude Code / Cursor 中使用);而 langchain-coalent 则让你现有的 LangChain 技术栈成为缓存的底层支撑。两者都只增加功能,不做破坏性更改。

v0.6——pool 读取路径(read_path="pool"):每次读取都会提供按 token 预算打包、全局排序的新鲜声明池。在同一基准测试中测得:981 个上下文 token 时准确率为 0.731——比朴素方案测得的最高准确率(top-12:1,729 个 token 时为 0.731)少约 43% 的 token。此外,还有默认关闭的行为层,在同一数据存储上测得拒答减少 33%、准确率提升 3.1 个百分点。

安装

pip install coalent          # the core has zero required dependencies

快速开始

可直接运行——StubSynthesizer 无需 API 密钥,让你十秒内体验完整流程:

from coalent import SemanticCache, InMemoryRetriever, StubSynthesizer

# 1. Any retriever — a vector DB, a tool, an API. (In-memory here for the demo.)
retriever = InMemoryRetriever()
retriever.add("confluence:hr", "Leave policy: 21 days of annual leave per year.")

# 2. Build the cache. Swap StubSynthesizer for a real LLM below.
cache = SemanticCache(retriever, StubSynthesizer())

# 3. Ask. The first call builds understanding and caches it; the next is a warm hit.
result = cache.get("what is our leave policy?")
print(result.context["understanding"])
print(result.cache_hit)        # False (cold) -> True on the next call

# 4. A source changed? Only the units that used it go stale — surgically.
cache.source_changed("confluence:hr", text="Leave policy: now 25 days.")
# the next matching read rebuilds just that one unit, lazily

(上面的免密钥演示运行的是经典的 unit 读取路径——由于没有可用的语义嵌入器,缓存会明确提示这一点并回退。接入真正的嵌入器,如下所示,默认路径就会变为经测试验证的 pool 读取路径。)

接入真正的模型——任何文本输入、文本输出的大模型都可以。在 v0.4 中,合成器默认构建提取式理解(与查询无关、保留每项事实的原子声明),缓存也会自动启用跨单元召回:

from coalent import SemanticCache, LLMSynthesizer, OpenAIProvider, OpenAIEmbedder

cache = SemanticCache(
    retriever,
    LLMSynthesizer(OpenAIProvider(), model="gpt-4o-mini"),   # extract=True by default (v0.4)
    embedder=OpenAIEmbedder(),   # match queries by MEANING (recommended for real use)
)
# ^ with a semantic embedder, v0.7 resolves the default read path to "pool" — the
#   measured path. Pass read_path="unit" for the pre-0.7 unit default, byte-identical.
# Multi-hop across documents? recall is already on; raise its trigger to bridge units:
#   SemanticCache(retriever, synth, embedder=..., recall_threshold=0.7)

pool 读取路径——自 v0.7 起的默认路径(只要有可用的语义嵌入器):每次读取都会提供按预算打包、全局排序的新鲜声明池,而不是一个路由到的单元。只需接入归属信息:提供一个 3 行的 pool_header 可调用对象,根据你自己的语料元数据,将每个单元映射为 [title | source | date]。这是经测试验证的最佳路径——在一个包含 605 道新闻问题的基准测试(严格评分)中,使用内置基础标题时准确率为 0.68,使用此可调用对象时为 0.73;两者使用相同的数据存储和查询:

DOC_META = {  # your corpus metadata, keyed by artifact id
    "docs:azure-refresh": {"title": "Azure region refresh", "source": "CloudWire", "date": "2026-05-02"},
}

def pool_header(unit) -> str:   # the [title | source | date] golden path — 3 lines
    meta = DOC_META.get(unit.evidence[0].artifact_id if unit.evidence else "")
    return f"[{meta['title']} | {meta['source']} | {meta['date']}]" if meta else f"[source: {unit.id}]"

cache = SemanticCache(retriever, synthesizer, embedder=OpenAIEmbedder(),
                      pool_header=pool_header)   # pool is the resolved default (v0.7)
result = cache.get("which regions got the refresh?")
result.context["pool"]   # the packed, attributed claim payload — hand it to your answer model

可运行的免 API 密钥演示(包括拒答循环):examples/pool_read_path.py。

在 Claude Code / Cursor 中使用(MCP)

coalent-mcp 可向任何 MCP 客户端提供来自 Coalent 缓存的新鲜、带来源归属的信息 —— 源内容一有变化,相关信息就会立即失效。只需一行,即可将其接入 Claude Code:

pip install "coalent[mcp,openai]"
claude mcp add coalent -- coalent-mcp --cache-factory my_cache:build

(对于 Cursor / Claude Desktop / 任何 MCP 客户端:在其 MCP 配置中注册相同的 coalent-mcp ... 命令。)

使用自己的缓存(--cache-factory module:function)——主要模式。 工厂会返回一个完整构建好的 SemanticCache:你的向量数据库、嵌入模型、大模型,以及所有参数。服务端只负责添加协议连接层——经测量,这层带来的质量损失为零:工厂模式逐字节复现了该库自身的基准测试结果(基于从我们的 n=605 新闻基准中抽取的 100 个问题进行验证,得分为 0.710;置信区间完全一致,100/100 次提供服务,98/100 个答案负载与库的运行结果逐字节一致)。

# my_cache.py — importable from the directory you launch in
from coalent import (SemanticCache, LLMSynthesizer, OpenAIProvider,
                     OpenAIEmbedder, SQLiteCognitionStore)

def build() -> SemanticCache:
    return SemanticCache(
        my_vector_retriever,                  # YOUR vector DB / retriever
        LLMSynthesizer(OpenAIProvider()),     # YOUR synthesis model
        embedder=OpenAIEmbedder(),            # YOUR embedder
        read_path="pool",
        residual_spans=True, query_keys=True, # the behavioral stack, opt-in as ever
        pool_header=my_metadata_header,       # [title | source | date] — the measured golden path
        store=SQLiteCognitionStore("kb.db"),  # persistence is yours too
    )

这里的新鲜度由信号驱动:文档发生变化时,你的摄取流水线会调用 source_changed 工具,受影响的信息会立即失效。(在工厂模式下同时添加 --watch DIR,也能在文件编辑时触发该工具——但只负责失效;它不会将内容摄取到你的索引中,且只有当你的 artifact ID 与相对于监视目录的路径相同时才会匹配。)

零配置文件夹模式(--watch DIR)——演示入口。 指定一个文档文件夹,即可获得推荐的 v0.6 部署方案(池化路径、残留片段、查询键、SQLite 持久化、自动添加 [path | modified date] 来源归属),完全无需编写代码:

claude mcp add coalent --env OPENAI_API_KEY=$OPENAI_API_KEY -- coalent-mcp --watch ./docs

每次读取前都会重新扫描监视中的文件(mtime + 内容哈希),然后才提供结果——保存文件后不会得到过时答案;未更改的文件夹重启后会保持完全预热状态。**真实数据:**在同一组 100 个问题的验证测试中,文件夹模式得分为 0.46,而工厂构建的缓存为 0.71(拒答数分别为 40 次和 18 次)——这是通用段落分块器和按需构建键孔的实测代价。你可以用它在一分钟内体验新鲜度循环;要达到生产级质量,请使用自己的技术栈。有一点需要说明:关于刚添加文件的问题,在读取触发该文件的首次构建之前,预热缓存可能会如实拒答——这是拒答,而不是过时或错误的答案。

供多个 Agent 共用一个缓存(--transport http)。

COALENT_MCP_TOKEN=<secret> coalent-mcp --cache-factory my_cache:build --transport http --port 8765

一个长期运行的进程,多个并发 MCP 客户端,共用一个缓存——效果共享叠加,不会发生存储竞态(已验证:两个并发客户端的 20 次读取结果全部与顺序执行的参考结果一致,且没有重复构建)。设置 COALENT_MCP_TOKEN 后,每个请求都必须携带 Authorization: Bearer <token>——请绑定到 localhost 或可信网络。由此可知,stdio 模式下每次启动都会创建独立进程,因此切勿让两个应用指向同一个 --store 路径——HTTP 模式才是共享缓存的解决方案。

七种工具: get_context(query, budget?) → 带来源归属、按预算打包的负载 + 一个 read_id · report_refusal(read_id) / report_success(read_id) → 通过 MCP 实现的行为修复循环 · source_changed(artifact_id, text?) → 自带新鲜度信号源(会通过哈希检测内容未变的情况并跳过) · list_sources() · cache_stats() · refresh()。

LangChain

langchain-coalent 让 Coalent 成为原生支持 LangChain 的新鲜度/复用层——优先使用自有资源:你现有的 VectorStore(或检索器)、嵌入模型和聊天模型都会直接成为缓存的底层组件,无需更改。

pip install langchain-coalent
from langchain_coalent import create_coalent_cache, CoalentRetriever

cache = create_coalent_cache(my_vectorstore, llm=my_chat_model, embeddings=my_embeddings)
retriever = CoalentRetriever(cache=cache)      # drop-in LangChain BaseRetriever

docs = retriever.invoke("what is our leave policy?")
docs[0].page_content              # the served, attributed context payload
docs[0].metadata["read_id"]       # -> cache.report_refusal() / report_success()
docs[0].metadata["cache_hit"]     # True == served with zero LLM spend

cache.source_changed("policy.md", text=new_text)   # surgical, provenance-keyed invalidation

create_coalent_cache 会传入 Coalent 的所有参数;软件包还附带一个可运行的 LangGraph 风格示例,展示拒答→修复循环。仅依赖 coalent>=0.6 和 langchain-core>=0.3。

v0.7 新增内容

具备自愈能力的版本——也是默认读取路径切换的版本。读取操作现在会附带自身的不确定性,缓存则新增了一条由 Agent 驱动的显式失败链——每一级仅在读取失败时触发,因此读取成功时不会产生任何额外开销。有一项有意做出的默认设置变更(即下文第一项中的读取路径);所有新的 v0.7 参数默认关闭,在启用前不会产生任何字节级影响(由测试保证)。详情请参阅变更日志。

在与 v0.5 以来每个基准版本相同的冻结新闻测试环境中测得(609 篇文章、605 个留出问题、严格评分 + 锁定的裁定规则):完整的 v0.7 组合得分为 0.826,而最强的 v0.6 配置为 0.774——在约 983 个 token 的服务预算完全相同的情况下提升 5.3 个百分点,最终拒答数减少 69%(61 → 19)。仅在失败时触发修复,准确率与始终启用修复相当,而提取调用量仅为其 14%。

Agent 式循环——由你的评估器做出判断,缓存负责自我修复:

cache = SemanticCache(
    retriever, synthesizer, embedder=OpenAIEmbedder(),
    # read_path resolves to "pool" automatically under a semantic embedder (v0.7 default)
    gap_detector=True,               # observe-only: the read reports its own holes
    repair_extractor=my_extractor,   # BYO callable(span, region, existing_claims) -> [claims]
)

r = cache.get(
    question,
    subs=planner_subquestions,       # your planner's decomposition (optional)
    constraints={"dates": ["2023-10-05"], "sources": ["TechCrunch"]},  # intent metadata (optional)
)
answer = my_answerer(r.context["pool"])          # your model, your prompt
r.sources                                        # artifact ids behind the payload
r.max_source_age_s                               # freshness age of this serve
r.gaps                                           # [{probe, span, source, kind}, ...] — the read's own doubt

if failed(answer):                               # the failure chain — each rung ONLY on failure
    cache.repair(r.read_id)                      # re-extract what the build missed — PERMANENT
    r2 = cache.get(question, subs=planner_subquestions)   # repaired claims now compete
    answer = my_answerer(r2.context["pool"])
    if failed(answer):
        r3 = cache.reprobe(r2.read_id)           # entity-probe re-rank of the same pool
        answer = my_answerer(r3.context["pool"]) if r3 else answer
    if failed(answer):
        r4 = cache.serve_unserved(r2.read_id)    # last rung: force-pack admitted-but-unserved claims
        answer = my_answerer(r4.context["pool"]) if r4 else answer
  • 不兼容变更 — 默认读取路径现在解析为 pool。 read_path 现在默认为 None,并且只要有语义嵌入器可用,就会解析为 "pool" — 即所有配置了密钥的真实部署(设置了 OPENAI_API_KEY,或使用任何非词法的 embedder=)。Pool 是经过测量的路径(所有已发布的 v0.6/v0.7 数值;0.7 测试套件证据已满足切换标准 — 上文为 0.826 对 0.774)。无需密钥的零配置部署会回退到 unit 路径,并发出醒目警告,指出两种解决办法(设置 OPENAI_API_KEY / 传入 embedder=)。退出选项: 显式设置 read_path="unit" 仍受到完整支持,且与 0.7 之前的默认行为逐字节一致;显式指定的 read_path 始终优先于解析结果。
  • 读取结果会附带自身的来源信息和不确定性。 Result.sources(实际支撑载荷的 artifact ID)、Result.max_source_age_s(服务时的时效年龄),以及在启用 gap_detector=True 时的 Result.probes / probe_coverage / gaps:针对每个探针,判断是否有原始证据句子得分高于所有主张(extraction_hole → 修复空间),或没有内容命中该探针(corpus_hole → 路由到工具)。按设计仅供观察:启用与关闭时的服务结果逐字节一致(已固定验证),句子层级在服务时成本为 $0(惰性加载,仅嵌入一次并缓存)。
  • repair(read_id) — 注入器。 消耗读取结果已存入的缺口和约束候选项,以及读取结果附近的桥接候选项;每个候选项调用一次锚定文本片段的 BYO 抽取器(库本身仍不会调用 LLM);机械式拒绝近似重复项和缺陷项(缺少先行词的代词主语、截断的文本片段);然后对存储进行仅追加、带来源标记、永久的改进 — 成本仅支付一次,此后每次读取都会受益。返回 RepairReport。
  • serve_unserved(read_id) 和 reprobe(read_id, hint=None) — 拒绝后的补救步骤。 强制纳入在筛选竞争中落败的主张,或使用从已服务内容中提取的实体探针,对未改变的池重新排序。只进行嵌入 — 不调用 LLM、不检索、不修改存储 — 并且按约定仅在拒绝时运行,因此不会撤销正确读取的回答。
  • get() 中的 subs= / constraints=。 规划器将读取分解结果(subs=["...", ...] — 优先于 decompose= 可调用对象)和元数据意图(constraints={"dates": ..., "sources": ..., "entities": ...} — 键之间为 AND,同一键内为 OR;未命中时回退为 OR,而不是让读取结果无内容)。约束仅用于馈送:它们会存储修复候选项,但绝不影响池评分或服务结果(已固定验证)。
  • 摄取元数据弥补了 v0.6 的归因缺口。 retriever.add(..., meta={"title": ..., "source": ..., "date": ...}) 会将元数据放在 unit 上(source_meta),默认 pool 标题会呈现经过测量的 [title | source | date] 最佳路径,无需 pool_header 可调用对象。未附元数据的摄取与 0.6 逐字节一致。
  • 切换状态: 在 0.6.0 中预先登记的 pool 路径默认值切换,已在 0.7.0 中实施 — 依据 0.7 测试套件证据及维护者的明确决定(2026-09-15),替代了从未按指定方式运行的三个预先登记门槛。此设计为条件式(按约定,pool 需要语义嵌入器,因此词法回退仍使用 unit,并会发出醒目警告)。这不是弃用:read_path="unit" 仍受到完整支持,不会发出 DeprecationWarning;而 serve="pool"(v0.5 预览版)在 0.7 中保持不变。

v0.6 有哪些新变化

以池为先的版本。以下所有 n=605 的数据均来自同一套冻结测试配置——包含 609 篇文章的新闻语料库、605 个留出问题、gpt-4.1-mini 答题器和严格评分——与测量 v0.5 数据时使用的配置相同。完整详情请见 CHANGELOG 和 UPGRADE-0.5-to-0.6.md。

  • read_path="pool"——以声明池为先的读取路径(在 0.6 中需选择启用;使用语义嵌入器时,自 v0.7 起为解析后的默认值)。通过按预算打包全局新鲜声明池来回答问题;单元仍是所有权、新鲜度和来源信息的骨架。测得结果:严格准确率为 0.731 @ 平均上下文 981 个 token——与朴素 top-9(0.711 @ 1,311)相当,token 数减少约 25%;与朴素方法测得的最佳点(top-12:0.731 @ 1,729)相比,token 数减少约 43%。结论是用更少 token 达到同等水平(置信区间有重叠),而非准确率胜出。黄金声明在服务顺序中的排名:池顺序下 p50/p75/p90 = 1/6/15。
  • 默认提供来源归属信息,并测量了标题梯度。 现在,pool_header=None 会渲染内置的逐来源标题。相同存储、相同查询:不透明 ID 0.641 → 发布默认值 0.678 → 你的 [title | source | date] 元数据回调 0.731。差距受限于单元元数据(媒体和日期信息在你的语料库中,而不在单元上)——请接入该回调(见上方快速入门)。
  • 行为链路(默认全部关闭):跨度 → 回退 → 修复 → 键。 residual_spans=True 会将提取器遗漏的承载事实的句子作为第 2 层跨度保存在单元上(绝不进入池)。当你的答题器拒答时,report_refusal(read_id) 会返回带来源归属信息的重试载荷;report_success(read_id) 会确认救援成功,并且在启用 query_keys=True 时,生成持久的备用键;带有有损标记的单元会在下次重建时以仅追加的方式自我修复。通过完整链路测得:拒答次数 91 → 61(−33%),最终准确率提升 3.1 个百分点,token 数增加 2.1%(同一存储对比),没有新增错误答案;键命中类别在改写后的再次查询中,首次回答成功率从 0% → 61%。
  • 自适应服务门控(serve_gate=None)——根据池自身的噪声上限进行调整;显式指定浮点数则会禁用自适应(便于复现基准测试)。通过 $0 回放门控后才发布:两组各有 605/605 个服务决策完全一致,构建次数为零,LLM 调用次数为零。
  • 加固与管线完善: 每个载荷接口都带有来源归属信息(池载荷和升级原始数据);不同所有者之间的近重复声明会保留为佐证;新增 14 个可观测性事件(pool_served、residual_fallback、key_confirmed,……);新增 reranker 钩子(仅影响服务顺序——绝不会导致错误服务);新增 claim_index 自带池存储;修复了 v0.5 池预览中一个陈旧服务问题。
  • 已弃用: serve="pool"(v0.5 预览功能)——在 0.6 和 0.7 中仍可原样使用;请迁移到 read_path="pool"。在 0.6 中,默认读取路径仍为 "unit"(与 v0.5 行为完全一致),并受五项预先注册的切换门控约束——v0.7 已切换(见 v0.7 有哪些新变化)。
坦诚说明限制(实测结果,而非假设)
  • 拒答回退能处理约 20% 的自然拒答(载荷中包含答案原文时为 33%)——实验室问题中 68% 的数据只适用于载荷按设计包含答案的情况。这是对提取尾部问题的净改善,并非第二个检索器。
  • 在主题相近且密集的语料库中,查询键可能在同组文章之间冲突(观察到 3/605 次读取;答案仍然正确)。此类情况下请将 key_floor 提高到默认值 0.85 以上。键会将拒答后的往返流程转为首次直接作答;对于多样化的改写,不会提升最终准确率。
  • 发布默认标题只能归属单元已知的信息——从 0.678 到 0.731 的差距受限于单元元数据;目前可通过 pool_header 回调消除这一差距;可选的摄取时元数据字段计划在 v0.7 中推出。

v0.5 有哪些新内容

池化版本——我们在真实新闻数据(MultiHopRAG,609 篇文章、第三方问题)上进行了为期一个月的预注册基准测试,结果催生了以下可选择启用的功能:

  • preset="multi_hop" — 一个参数即可启用跨单元召回和第 2 跳桥接,并采用经过校准的阈值。显式传入的 kwargs 始终优先。
  • 来源扩展(widen_chunks=24)— 由未命中触发的构建会读取主导来源中最多 N 个数据块,而不只是检索到的狭窄片段。端到端效果:重建次数从 460 降至 31,热缓存轮次的准确率从持续下降转为不断提升。摄取时绝不会触发。
  • 来源溯源准入(provenance_admission=True)— 精确文本包含探测可避免重复理解:覆盖充分的读取直接返回,无需构建;覆盖不足时则在原处扩展并重建。
  • 自适应命中门控(adaptive_hit=True)— 随着缓存增长,自动校准评分膨胀问题(已证实,固定阈值会在规模扩大时接受所有内容)。
  • 池化服务预览(serve="pool"、serve_budget=600、pool_header=...)— 提供按 Token 预算排序的全局新鲜声明池,而非单个路由单元(实验性功能;v0.6 中由 read_path="pool" 取代——该预览在 0.6 和 0.7 中仍可原样使用)。 留出集 n=605:准确率为 0.699,而单元服务为 0.579(z=6.66);在 Token 数仅为朴素方法 k9 方案(当时测得的最佳结果)的 0.79 倍时,统计上与其持平;95% 的空值诚实性。 来源发生变化时,过期单元的声明会立即从池中屏蔽。
  • fast="auto" — 存在 numpy 时启用由 numpy 加速的读取路径(pip install "coalent[fast]");结果与纯 Python 核心严格保持等价。
  • 可观测性(on_event=...)— 结构化的新鲜度事件:构建、重建、准入复用、阻止过期读取、召回和桥接活动。
  • 已弃用:select_floor(已由池化服务取代)。

完整数据和方法见 基准测试 部分和 CHANGELOG。

v0.4 有哪些新内容

两项此前仅供选择启用的预览功能现已成为默认功能,因为它们在 Coalent 面向的结构化/高复用语料上表现严格更好,而在其他场景中则免费或处于休眠状态。两项功能都可通过一行配置恢复到 v0.3 的精确行为(extract=False、cross_unit_recall=False)。

  • 🎯 抽取式理解(extract=True,默认启用)。 合成器不再生成问题导向的散文式摘要,而是提取一组与查询无关、以来源为依据的原子声明。同一单元现在可以回答之后提出的许多不同问题,而且不会遗漏任何数字——我们的测试中,散文式摘要会悄然丢失来源中约 40% 的数字。
  • 🔗 跨单元声明召回(cross_unit_recall=True,默认启用)。 当一个单元对查询的覆盖不足时,缓存会汇总所有新鲜单元中的逐条声明记忆(MaxSim),并呈现桥接事实——无需额外调用 LLM,即可回答朴素检索从结构上无法回答的多跳问题(证据所在文档与问题并不相似)。单跳场景下处于休眠状态/不产生额外开销;使用非语义嵌入器时会自动关闭。结果通过 result.recalled 提供。
  • 🛡️ 精确度与服务选项(可选启用,默认关闭): hit_margin(拒绝有歧义的平分结果)、select_floor(按语义提供原子声明,减少 Token)、residual_floor(找回抽取器遗漏的数字片段)。何时使用各选项,请参见门控阶梯。

从 v0.3 升级?请参阅 UPGRADE-0.3-to-0.4.md — 仅增量升级,有一项行为变化(理解结果现为声明,而非散文)。

工作原理

        query ──► embed ──► semantic cache
                               │  hit & fresh?  ──► serve cached understanding  (no retrieval, no LLM)
                               │  miss / stale? ─┐
                               ▼                 ▼
                          your Retriever ──► your Synthesizer ──► Cognition unit
                          (vector/tool/API)   (LLM or passthrough)  { understanding
                               ▲                                      + raw evidence
                               │                                      + provenance }
   source changed ────────────┘   dirties ONLY the units that used that source
  1. 嵌入查询,并查找含义相似的现有单元。
  2. 命中且未过期 → 返回缓存的理解结果(不检索,也不调用 LLM)。
  3. 未命中或已过期 → 检索、综合理解结果、保留原始证据、记录溯源信息(使用的确切来源),并将结果缓存。
  4. 来源发生变化 → source_changed(id) 只会标记溯源信息包含该 id 的单元;这些单元会在下次读取时延迟重建。

通过比较内容哈希跳过未变化的内容,因此无操作的更改不会产生任何成本。

读取路径——层层关卡

这是单元读取路径(read_path="unit"——与 v0.5 的行为完全一致;也是无密钥回退路径,以及绕过 v0.7 池默认值、保持字节级一致的入口)。在语义嵌入器下,v0.6 的池路径——自 v0.7 起解析后的默认路径——会以全局声明池打包取代单元路由,并使这些单元路由参数失效;池路径自身的参数见 UPGRADE-0.5-to-0.6.md。

Coalent 根据单元了解什么来匹配——嵌入的是它的理解,而不是查询中的词语——因此,*"有多少天年假?"会命中你的休假单元,而"交换政策"*则不会。每次 get(query) 都会依次通过一组固定的关卡。默认值采用纯余弦相似度——无需额外模型,也没有重型依赖——且每个关卡都是可调参数。触发顺序如下:

#关卡默认值触发条件 → 结果
1hit_threshold——匹配自动(OpenAI 约为 0.33)最佳单元的混合得分(0.7·topic + 0.3·seed)低于此值 → 未命中 → 检索并合成一个新单元
2hit_margin——精度保护0.0(关闭)最佳单元领先第二名的幅度小于此边际 → 存在歧义 → 改为构建查询自身的单元
3新鲜度来源信息 / TTL匹配的单元已变脏或过期 → 重新生成
4覆盖度——能否回答?每条声明的最大余弦相似度匹配的单元对当前查询的覆盖程度(一条完美匹配的声明即视为已覆盖)
5cross_unit_recall开启(v0.4)覆盖度 < recall_threshold → 汇集所有新鲜单元中的最佳声明(MaxSim),可能提高覆盖度。休眠时零开销,不调用 LLM
6coverage_scorer(S2)None(关闭)处于模糊区间 [coverage_floor, coverage_ceiling) 时 → 通过交叉编码器 / NLI / LLM 蕴含检查覆盖余弦相似度
7coverage_floor——RAG 下限自动(约为 0.28)覆盖度仍低于此值 → 升级:追加新鲜的原始检索结果(不调用 LLM),让覆盖不足的命中回退到检索,而非错误作答
8select_floor——提供结果None(按词法裁剪)按含义提供单元中的原子内容(每条声明的余弦相似度 ≥ 下限),而不是按关键词裁剪——只保留与查询相关的事实,减少 token

此外还有一个构建时参数——residual_floor:将提取器丢弃的含数字源文本片段(最佳每条声明的余弦相似度 < 下限)保留为额外原子。仅使用嵌入。 其他钩子:route_by_claim(通过大型单元的声明进行晚期交互路由)、relevance_gate(在合成前接入自有重排器)、depth(合成完整度与成本)、calibrate_thresholds() / suggest_thresholds()。

不同工作负载该用哪个参数——默认设置针对结构化、单跳复用进行了调优;数据特征不同时可使用以下参数:

使用……适用场景
recall_threshold ≈ 0.7多跳 / 跨文档问题——让召回功能弥合覆盖不完整的读取结果(实现完整的多跳收益)
hit_margin > 0矛盾多 / 冲突多的语料库,其中相近的得分难以区分(代价是重建次数增加——干净的数据应保持关闭)
select_floor大型单元中的同义改写较多的查询(查询与声明没有共同词语时,按关键词裁剪会漏掉内容)
residual_floor提取器可能会漏掉数字的杂乱真实文本(低成本保险)
coverage_scorer(S2)高风险歧义场景,错误提供结果的代价较高(每次边界读取会增加一次判定调用)

stats() 会报告 hit_rate、escalation_rate 和当前生效的阈值,让你准确了解——并调优——缓存的行为。

自带技术栈

Coalent 只拥有一个精简契约,其余一切都交由你的工具处理。

检索器——从一行代码到完全掌控,任你选择:

你已有……使用
Qdrant / Chroma / pgvector内置适配器(自带客户端)
其他向量数据库扩展 BaseVectorRetriever
现有搜索函数FunctionRetriever
多个需要融合的数据源CompositeRetriever
其他任何情况实现 Retriever(一个方法)
from coalent import QdrantRetriever

retriever = QdrantRetriever(client=my_client, collection="docs", embed=my_embed)

合成器——将证据转化为理解:

  • LLMSynthesizer — 通过你的 LLM(OpenAI、Anthropic 或任何提供商)生成结构化、基于引文的理解。instruction 和 fields 由你负责;来源 / 严格 JSON / 引文封装由 Coalent 负责,因此无论你要求什么,都能记录溯源信息。
  • JSONPassthroughSynthesizer — 适用于已有结构化工具 / API JSON:将其直接作为理解缓存,不调用 LLM。

嵌入——缓存如何按含义匹配查询。安装 coalent[openai] 并设置 OPENAI_API_KEY 后,缓存会自动使用 OpenAI 嵌入;否则会发出警告并回退到词汇匹配器。你可以随时覆盖:

from coalent import SemanticCache, OpenAIEmbedder, FunctionEmbedder

cache = SemanticCache(retriever, synthesizer, embedder=OpenAIEmbedder("text-embedding-3-large"))
# or a local model: embedder=FunctionEmbedder(lambda t: my_model.encode(t).tolist())

使用真正的嵌入器进行语义匹配——无密钥时回退的 HashingEmbedder 按关键词重叠匹配,而不是按含义匹配,因此措辞不同但相似的查询可能无法命中缓存。

存储——持久可靠,重启后仍可使用(启动时会重建失效关系图):

from coalent import SemanticCache, SQLiteCognitionStore   # stdlib, no server
from coalent import RedisCognitionStore                   # shared across processes / hosts

cache = SemanticCache(retriever, synthesizer, store=SQLiteCognitionStore("coalent.db"))

任意 Agent 框架——读取 API 只需调用一次,因此可以随处接入。内置了用于图节点和 MCP 工具的辅助工具:

from coalent import make_cognition_node, build_mcp_tools

node = make_cognition_node(cache)     # a graph node: state -> { context: fresh understanding }
tools = build_mcp_tools(cache)        # expose the cache as an MCP tool

关于完整的独立 MCP 服务(新鲜度循环、七种工具、HTTP 传输),请参阅下一节;关于 LangChain,请参阅 langchain-coalent。

基准测试

真实场景:v0.7 失败链(n=605)

以下所有基准均使用相同的固定测试环境(609 篇真实新闻文章、605 个留出问题、gpt-4.1-mini 答题器、严格评分 + 锁定的仲裁规则),衡量完整的 v0.7 组合,相较于我们自己的最强 v0.6 配置——而非简单基线:

方案准确率上下文 token 数最终拒答数
最强 v0.6 配置(元数据头 + 行为栈)0.774~98361
v0.7 组合(subs + gap detector + constraints → 失败链)0.826~98319(−69%)
  • 在服务预算完全相同的情况下提升 5.3 个百分点——服务 token 数零增加;该链只会在读取失败时增加成本(仅在失败时触发修复,准确率与始终启用相当,但提取调用仅为其 14%)。
  • 57 次修复的来源: 首轮处理 37 次(分解 + 元数据服务),repair() 10 次,serve_unserved() 6 次,reprobe() 4 次——每一环都有其价值。
  • 每一环只会在读取失败时触发——拒答绝不是正确答案,因此后续环节无从造成破坏。修复是永久性的:相关声明会连同各自的溯源信息一起加入存储,因此所有用户今后每次读取都会受益。
真实场景:池读取路径(v0.6,n=605)

与下方 v0.5 数据使用同一套测试配置——609 篇真实新闻文章、605 个冻结的留出问题、gpt-4.1-mini 答题器、严格评分——并以 naive 自身的 token 扩展曲线作为公平性对照;现在测试范围扩展到了 naive 实测的最佳点:

组别准确率上下文 token 数
naive top-90.7111,311
naive top-12(实测最佳)0.7311,729
Coalent read_path="pool"(默认设置 + 元数据标题)0.731981
  • 结论是准确率持平、token 更少,而非准确率胜出。 每组两两比较的置信区间均有重叠。准确率为 0.731、上下文 token 数为 981,准确率与 naive top-9 相同,所需上下文 token 少约 25%;与 naive 实测最佳点相比,所需上下文 token 少约 43%(仅为其预算的 57%)——此外还能实现仅靠检索无法做到的事(新鲜度、来源归属和行为累积)。
  • 服务排序: 在池中的顺序里,黄金声明的排名为 p50/p75/p90 = 1/6/15(仅统计包含该声明的查询),使用默认余弦排序——没有重排器。
  • 标题效果经实测,而非凭感觉: 不透明 ID 为 0.641 → 默认配置为 0.678 → 你提供的 [title | source | date] 可调用项为 0.731。上表中的 0.731 使用了元数据可调用项;请配置 pool_header(参见快速入门)。
  • 行为机制栈(可选启用):最终准确率 +3.1 个百分点,token 数 +2.1%,拒答率 −33%,没有新增的错误答案——同一存储、同一总体,完整运行 report_refusal/report_success 循环后的对比。
  • 在这套测试配置中,v0.5 的基准点为 0.699 @ ~1,036:v0.6 重写版保持了这一水平(置信区间有重叠),同时修复了过时内容服务漏洞,并默认启用来源归属。
真实场景:MultiHopRAG(v0.5,预注册)

609 篇真实新闻文章、第三方黄金问题,由 gpt-4.1-mini 作答并采用精确匹配评分——该语料对分块检索极为有利(问题根据文章句子生成),因此被选作对抗性测试。我们采用多数基准测试忽略的公平性对照:在相同数据流上测试 naive 自身的 token 扩展曲线(k4:0.58 @ 590 tok · k6:0.64 @ 882 · k9:0.71 @ 1311,n=605 个留出样本)。

  • 池服务(serve="pool",缓存已预热):0.699 @ ~1,036 个 token——优于 naive k6(配对 McNemar z=3.22),并且在统计上与 naive k9 组持平;当时这是其实测最佳点,而本方案所需 token 仅为其 0.79 倍(z=0.60)。我们并未声称在此胜过这条曲线;结论是以更少 token 达到同等水平,并实现仅靠检索无法做到的事(新鲜度、来源归属和复用累积)。
  • 如实处理无答案情况(n=100 个不可回答问题):池的拒答率为 95%,naive 为 85–88%。
  • 构建层(冷启动、即时构建):拓宽后的单元读取其来源中位数为 23 个分块,而 keyhole 构建为 2 个;重建变动次数从 460 → 31;热运行准确率从衰减(−0.03)转为累积提升(+0.04)。
  • 错误归因率为 2–6%;跨单元召回在约 90% 的读取中触发(已完整埋点)。

更早的基准测试历史——v0.4 结构化场景研究,以及基准透明度说明(我们的发现、修复内容及方法)——请参阅文档。

CLI

安装 Coalent 后即可使用 coalent 命令——它是面向认知缓存的 redis-cli(底层使用 SQLite 存储):

$ coalent ls
STATUS  HITS  AGE SRC  ID                  QUERY
fresh      6   2m   2  cog:c95a9d2897e0af  what is our leave policy?
dirty      1  12m   1  cog:7f1a0b9c3d2e4f  remote work rules

$ coalent show cog:c95a9d2897e0af      # understanding + provenance + raw evidence
$ coalent invalidate confluence:98231  # fire a change event
$ coalent stats

文档

📚 完整文档:coalent.ai/docs——概念、来源归属与新鲜度、检索器、合成器、持久化、实用示例(向量搜索、MCP 与工具、Agent),以及完整的 get() / 数据模型参考。

安装选项

pip install coalent                 # core, zero required deps
pip install "coalent[openai]"       # OpenAI provider      (also: anthropic)
pip install "coalent[qdrant]"       # vector adapters      (also: chroma, pgvector)
pip install "coalent[redis]"        # distributed store
pip install "coalent[dev]"          # tests + lint + types

参与贡献

欢迎提交问题和 PR。推送前请运行检查门禁:

pip install -e ".[dev]"
pytest && ruff check src && mypy src

请注意一项 CI 实际情况:项目将 mypy 的分析目标固定为 3.10 (pyproject.toml 中的 python_version),但如果安装了 numpy >= 2.5(Python 3.12+ 上 [fast] 额外依赖会解析到此版本),其存根会使用 3.10 分析目标无法解析的语法。在这种情况下,请运行 mypy src --python-version 3.12,使其与当前解释器版本一致——这与 CI 矩阵的做法完全相同。

状态与许可

Alpha — API 可能会在 1.0 版之前发生变化。类型标注完整(mypy --strict),已通过 lint 检查和测试。

基于 Apache-2.0 许可。

值得信赖的上下文,而不只是廉价。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。