/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}
去中心化 AI 会话数据分片加密索引:基于 Ceramic 动态数据流的实战

在去中心化存储体系中,IPFS 和 Arweave 擅长处理静态、不可变(Immutable)的大文件;但在面对 AI 连续多轮对话、流式追加消息、以及按用户 DID(去中心化身份)动态变更权限 的场景时,纯静态存储显得捉襟见肘:
- 每次用户追加一句话,如果都要重新打包上传整个 JSON 并生成全新的 IPFS CID,会产生大量的孤儿数据碎片与索引开销;
- 缺乏类似数据库的动态更新日志(Mutable Stream)与按字段加密能力。
Ceramic Network(去中心化动态数据流协议) 弥补了这一拼图。
Ceramic 允许开发者基于 DID(Decentralized Identifier) 创建可变的数据流(Streams),每一个 Stream 拥有确定性的 StreamID,支持追加提交(Commits),并在底层通过密码学签名与以太坊状态自动锚定(Anchor)。
本文实战复盘如何结合 Ceramic ComposeDB 与 DID 细粒度分片加密,构建一套去中心化的动态 AI 会话索引系统。
一、基于 Ceramic 的去中心化可变会话拓扑
graph TD
UserDID[用户去中心化身份 DID: did:pkh:eip155:1:0xRich…] –> CeramicClient[Ceramic ComposeDB 客户端]
CeramicClient –> ChatStream[动态会话流 (StreamID: kjzl6c…)]
subgraph Stream 内部增量追加提交 (Commits)
ChatStream –> Commit0[Genesis: 会话创建 (元数据 & 访问策略)]
Commit0 –> Commit1[Commit 1: 用户 Prompt (AES-GCM 分片密文)]
Commit1 –> Commit2[Commit 2: AI 回答 (AES-GCM 分片密文)]
end
ChatStream –> CeramicNode[Ceramic 去中心化节点网络]
CeramicNode –> EthAnchor[定期将 State Merkle Root 锚定至以太坊/Arbitrum 链上]
二、定义 ComposeDB 动态会话模型(GraphQL Schema)
使用 ComposeDB,我们可以通过标准的 GraphQL SDL 定义结构化的会话模型:
# composable-chat.graphql
type ChatMessage @createModel(description: "去中心化 AI 对话消息") {
sender: DID! @documentAccount
sessionId: String! @string(maxLength: 64)
encryptedContent: String! @string(maxLength: 8000) # AES 加密密文
role: String! @string(maxLength: 16)
createdAt: DateTime!
}
type ChatSession @createModel(description: "AI 会话元数据") {
owner: DID! @documentAccount
title: String! @string(maxLength: 128)
modelName: String! @string(maxLength: 64)
lastUpdated: DateTime!
}
三、全栈代码实现:从 DID 认证到动态追加对话
// lib/ceramicChatService.ts
import { CeramicClient } from '@ceramicnetwork/http-client';
import { ComposeClient } from '@composedb/client';
import { DIDSession } from 'did-session';
import { EthereumWebAuth, getAccountId } from '@did-session/ethereum';
const CERAMIC_URL = process.env.CERAMIC_NODE_URL || 'https://ceramic-clay.3boxlabs.com';
export class CeramicChatEngine {
private ceramic: CeramicClient;
private composeClient: ComposeClient;
constructor(definition: any) {
this.ceramic = new CeramicClient(CERAMIC_URL);
this.composeClient = new ComposeClient({
ceramic: this.ceramic,
definition,
});
}
// 1. 用户使用钱包对 DID Session 进行一次性授权签名
public async authenticate(ethProvider: any) {
const accountId = await getAccountId(ethProvider, window.ethereum.selectedAddress);
const authMethod = await EthereumWebAuth.getAuthMethod(ethProvider, accountId);
// 创建有效期为 7 天的去中心化 DID 会话 (无需频繁签名弹窗)
const session = await DIDSession.authorize(authMethod, {
resources: this.composeClient.resources,
});
this.ceramic.did = session.did;
this.composeClient.setDID(session.did);
console.log(`🔑 [Ceramic Authenticated] Logged in as DID: ${session.did.parent}`);
return session.did.parent;
}
// 2. 动态向特定会话中追加一条加密消息
public async appendChatMessage(sessionId: string, role: 'user' | 'assistant', encryptedText: string) {
const mutation = `
mutation CreateMessage($input: CreateChatMessageInput!) {
createChatMessage(input: $input) {
document {
id
sessionId
role
createdAt
}
}
}
`;
const variables = {
input: {
content: {
sessionId,
role,
encryptedContent: encryptedText,
createdAt: new Date().toISOString(),
},
},
};
const res = await this.composeClient.executeQuery(mutation, variables);
console.log(`✅ [Message Appended to Ceramic] Doc ID: ${(res.data as any)?.createChatMessage.document.id}`);
return res.data;
}
// 3. 根据 SessionId 毫秒级查询历史对话数据流
public async fetchSessionMessages(sessionId: string) {
const query = `
query GetMessages($sessionId: String!) {
chatMessageIndex(filters: { where: { sessionId: { equalTo: $sessionId } } }, first: 50) {
edges {
node {
id
role
encryptedContent
createdAt
}
}
}
}
`;
const res = await this.composeClient.executeQuery(query, { sessionId });
return (res.data as any)?.chatMessageIndex.edges.map((e: any) => e.node);
}
}
四、极客架构收益与生产调优
Ceramic 动态数据流为去中心化 AI 应用补齐了最后一块“可变关系型存储”的拼图。


