在构建一个完整的智能体(Agent)系统时,数据模型设计是基础中的基础。作为一名长期从事AI系统开发的工程师,我深刻理解一个合理的数据架构对整个系统可维护性和扩展性的重要性。今天要分享的这套数据模型,是我在实际项目中经过多次迭代验证的成果,特别适合需要处理复杂对话场景和知识检索的AI系统。
这套模型的核心思想是将智能体系统的持久化数据划分为三大类:状态数据、消息数据和知识数据。这种分类方式源于我在多个项目中的实践经验——它能有效避免数据混乱,让系统各部分职责更清晰。下面我会结合具体表结构设计,详细说明每类数据的处理方式。
在开始设计具体表结构前,我们需要明确智能体系统中所有需要持久化的数据可以归纳为三类:
这种分类方式的一个实际好处是,当系统需要扩展时,我们可以清楚地知道新功能应该归属于哪一类数据。例如,如果要增加用户反馈功能,它显然属于消息数据;如果要增加多语言支持,则主要涉及状态数据中的配置项。
在设计过程中,我始终坚持以下几个原则:
这些原则不是凭空而来的。在早期项目中,我曾因为将Agent配置硬编码在代码中,导致每次修改都需要重新部署,给运维带来很大麻烦。后来通过将配置移入数据库,不仅提高了灵活性,还实现了配置的热更新。
Agent表是整个系统的控制中心,它把传统上硬编码在程序中的配置项全部外移到数据库:
sql复制CREATE TABLE agent (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL, -- 唯一标识名称
description TEXT, -- 面向用户的描述
system_prompt TEXT, -- 定义Agent行为的核心指令
model TEXT, -- 默认模型标识
allowed_tools JSONB, -- 可访问工具白名单
allowed_kbs JSONB, -- 可访问知识库白名单
chat_options JSONB, -- 对话参数(温度/top_p等)
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
这里有几个设计细节值得注意:
在实际使用中,这个表的一个典型记录可能如下:
json复制{
"name": "customer_service_agent",
"description": "处理客户咨询的专用助手",
"system_prompt": "你是一个专业、友好的客户服务代表...",
"model": "gpt-4",
"allowed_tools": ["product_lookup", "ticket_system"],
"allowed_kbs": ["product_manual", "faq"],
"chat_options": {
"temperature": 0.7,
"max_tokens": 1000
}
}
ChatSession表的设计相对简单,但它承担着重要的组织作用:
sql复制CREATE TABLE chat_session (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
agent_id UUID REFERENCES agent(id) ON DELETE SET NULL,
title TEXT, -- 自动生成的对话摘要
metadata JSONB, -- 扩展信息(语言/设备等)
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
在实际应用中,我通常会在这个表中添加一些衍生字段:
提示:metadata字段非常适合存储一些不固定但有用的信息,比如用户设备类型、地理位置等。这些信息可以在后续分析中发挥重要作用。
这是系统中最核心的表之一,它记录了对话的完整过程:
sql复制CREATE TABLE chat_message (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
session_id UUID NOT NULL REFERENCES chat_session(id) ON DELETE CASCADE,
role TEXT NOT NULL, -- user/assistant/system/tool
content TEXT, -- 消息正文
metadata JSONB, -- 结构化元数据
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
role字段的几种典型取值:
一个实际的消息记录示例:
json复制{
"session_id": "a1b2c3d4...",
"role": "tool",
"content": "查询结果:产品库存剩余15件",
"metadata": {
"tool_name": "inventory_check",
"parameters": {"product_id": "12345"},
"execution_time": 235
}
}
知识库系统由三个关联表组成,形成了完整的数据链路:
sql复制CREATE TABLE knowledge_base (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
description TEXT,
metadata JSONB, -- 分类/标签等信息
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
sql复制CREATE TABLE document (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
kb_id UUID NOT NULL REFERENCES knowledge_base(id) ON DELETE CASCADE,
filename TEXT NOT NULL,
filetype TEXT, -- pdf/docx/txt等
size BIGINT, -- 字节大小
metadata JSONB, -- 解析参数/页数等
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
sql复制CREATE TABLE chunk_bge_m3 (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
kb_id UUID NOT NULL REFERENCES knowledge_base(id) ON DELETE CASCADE,
doc_id UUID NOT NULL REFERENCES document(id) ON DELETE CASCADE,
content TEXT NOT NULL, -- 文本内容
metadata JSONB, -- 位置信息
embedding VECTOR(1024) NOT NULL, -- 向量表示
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- 向量索引
CREATE INDEX idx_chunk_embedding ON chunk_bge_m3
USING ivfflat (embedding vector_l2_ops) WITH (lists = 100);
在实践中有几个优化点:
在RAG场景中,向量检索是性能瓶颈之一。经过多次测试,我总结出以下优化方案:
索引参数调优:ivfflat的lists参数需要根据数据量调整,一般规则是:
查询优化:
sql复制-- 好的实践:限制返回数量并使用近似搜索
SELECT id, content
FROM chunk_bge_m3
ORDER BY embedding <-> '[0.1, 0.2, ...]'::vector
LIMIT 5;
sql复制SELECT id, content
FROM chunk_bge_m3
WHERE content LIKE '%重要术语%'
ORDER BY embedding <-> '[...]'::vector
LIMIT 5;
重建对话上下文是Agent系统的核心能力。高效的实现方式是:
sql复制-- 获取完整对话历史
SELECT role, content, metadata
FROM chat_message
WHERE session_id = '...'
ORDER BY created_at
LIMIT 20; -- 防止token超限
在实际处理时还需要考虑:
对于高并发系统,我推荐以下优化措施:
问题:当知识库更新后,如何确保对话使用的是最新数据?
解决方案:
问题:有时候检索到的片段与问题相关性不高
优化方案:
问题:随着对话轮数增加,系统响应变慢
应对策略:
这套基础架构可以根据需求进行多种扩展:
一个典型的扩展表示例:
sql复制CREATE TABLE agent_version (
id UUID PRIMARY KEY,
agent_id UUID REFERENCES agent(id),
version INT NOT NULL,
config JSONB NOT NULL,
created_by TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
在实际项目中,这套数据模型已经支持了日均百万级的对话请求。它的优势在于清晰的层次划分和灵活的扩展能力,当新增需求来临时,我们总能快速找到合适的位置进行扩展,而不会破坏现有结构的完整性。