当我们在讨论 AI 代理与数据库的集成时,通常的想象是在应用层构建一个独立的服务,通过 API 调用 LLM,再将结果写回数据库。这种架构带来了额外的复杂性:需要管理服务部署、处理网络延迟、确保数据一致性,以及维护代理状态与数据库状态的同步。但开源项目 pgclaw 提出了一个截然不同的思路:为什么不让 AI 代理直接‘住’在数据库的每一行里?
pgclaw 是一个仅用约 400 行 SQL 实现的 PostgreSQL 扩展,它引入了一个名为 claw 的自定义数据类型。将一个 claw 列添加到表中,就等于为每一行数据配备了一个专属的 AI 助手(或称 “Clawdbot”)。这个想法初看有些激进,但细究其实现,却是一套精巧利用 PostgreSQL 原生能力(触发器、后台工作进程、JSONB、自定义类型)构建的异步事件驱动架构。本文将深入解析 pgclaw 的三个核心工程实现:异步处理架构、状态持久化机制与跨行通信模式,并给出可落地的配置参数与监控清单。
一、 架构核心:触发器、队列与后台工作进程的异步流水线
pgclaw 的运作机制可以概括为一个高效的生产者 - 消费者模型,全部在数据库内部完成。其核心流程如下:
- 触发器作为生产者:当用户对启用了
claw列的表执行INSERT或UPDATE操作后,通过执行SELECT claw_watch('table_name');注册的AFTER行级触发器会立即被激活。根据 PostgreSQL 官方文档,AFTER触发器在数据操作完成且约束检查通过后执行,此时可以安全地访问已被修改的行的 “新” 值。pgclaw 的触发器将相关行的标识符(如主键)和上下文信息序列化后,作为一条作业任务插入到专用的claw.queue表中。 - 后台工作进程作为消费者:PostgreSQL 的后台工作进程(Background Worker)是一个常驻进程,pgclaw 利用其持续轮询
claw.queue表。当发现新任务时,工作进程根据任务类型进行处理:- 对于普通 LLM 代理:工作进程会从
claw.agents表中读取对应的代理定义(包括系统指令soul和操作指令instructions),结合当前行的数据构建提示词(Prompt),然后通过名为rig的轻量级 Rust 库调用配置好的 LLM 提供商(如 Anthropic Claude、OpenAI GPT、本地 Ollama 等)。 - 对于 Claude Code 代理:如果代理定义了
workspace字段,工作进程会为其在服务器文件系统上创建一个独立的工作空间目录,挂载必要的上下文文件(SOUL.md,AGENTS.md,context.json),然后通过claude-agent-sdk启动一个完整的 Claude Code 会话,该代理可以在此空间内读写文件、运行代码、执行 Shell 命令。
- 对于普通 LLM 代理:工作进程会从
- 结果回写与历史记录:LLM 或 Claude Code 的响应被期望包含一个结构化的 JSON 对象,其中键为需要更新的列名,值为新的列值。工作进程解析此响应,并对原表发起一个
UPDATE操作,将 AI 的 “思考结果” 直接写回对应的行。同时,完整的请求与响应上下文会被记录到claw.history表中,为后续的多轮对话提供记忆。
可落地参数:
- 延迟容忍度:整个异步流程(触发 -> 入队 -> 轮询 -> LLM 调用 -> 回写)通常需要 1-2 秒。这意味着此方案适用于对延迟不敏感的后台处理场景,如工单自动分类、内容摘要、数据清洗,而非实时聊天。
- 并发与队列深度监控:需监控
claw.queue表的记录数。如果队列持续增长,可能表明后台工作进程处理能力不足或 LLM API 响应变慢。可考虑增加max_parallel_workers或优化提示词以减少 Token 消耗。 - 触发器配置要点:
claw_watch()创建的触发器是AFTER EACH ROW类型。对于高频写入的大表,需注意触发器开销。可通过WHEN子句(尽管 pgclaw 当前未使用)进行条件过滤,例如仅当某些关键字段发生变化时才触发 AI 代理,以避免不必要的 LLM 调用。
二、 状态持久化:让代理拥有记忆与身份
一个没有记忆的 AI 代理只是每次对话的 “陌生人”。pgclaw 通过数据库表本身,为代理提供了优雅的状态持久化方案。
1. 代理定义表 (claw.agents):此表是代理的 “身份证” 和 “大脑蓝图”。每一行定义了一个可复用的代理。核心字段包括:
id:代理的唯一标识符。soul:定义代理的 “灵魂” 或系统角色,例如 “你是一个严谨的客服工单分类员”。instructions:具体任务指令,例如 “阅读工单内容,设置优先级为低 / 中 / 高 / 紧急,并生成摘要”。memory:一个JSONB字段,用于存储代理的长期记忆。这是状态持久化的关键。代理在响应中可以返回一个包含{"__memory": {...}}键的 JSON,工作进程会将其合并更新到该字段中。例如,一个客服代理可以用它来记录常见问题模式、用户偏好或未解决的疑难杂症。workspace:如果非空,则此代理为 Claude Code 代理,该字段指定工作空间目录的路径模板。
通过在 claw 列定义中引用代理 ID(如 claw(agent => 'ticket-triage')),同一份定义可以被成千上万行数据共享,同时每行代理又通过各自的 memory 字段维护独立的状态。
2. 历史记录表 (claw.history):此表自动记录每一次代理调用的详细信息,包括时间戳、关联的行、原始请求、完整响应和元数据。这不仅是审计和调试的宝贵资源,更为实现多轮对话提供了可能。未来的扩展可以让代理在响应时查询其自身的历史记录,从而实现连贯的上下文对话。
可落地清单:
memory字段设计规范:建议将memory设计为结构化的 JSON 对象,而非任意文本。例如:{"learned_patterns": ["..."], "user_context": {...}, "last_actions": [...]}。这便于查询和后续处理。- 历史数据清理策略:
claw.history表可能快速增长。需建立归档或定期清理策略(如保留最近 30 天记录),避免影响主数据库性能。可考虑使用 PostgreSQL 的分区表功能按时间分区。 - 状态恢复与回滚:得益于 PostgreSQL 的 ACID 特性,对
memory字段的更新是事务性的。如果整个代理调用链中的某一步失败,事务可以回滚,确保数据库状态的一致性。这是将状态内置于数据库的核心优势之一。
三、 跨行通信:从独立个体到协同网络
单个行内代理的能力有限,真正的威力在于代理之间能够通信与协作。pgclaw 设计了一套基于 “频道”(Channel)的轻量级发布 - 订阅模型,实现跨行甚至跨表的代理通信。
通信三要素:
- 绑定 (
claw.bindings):将代理与一个命名的频道关联。例如,INSERT INTO claw.bindings (channel, agent_id) VALUES ('telegram', 'support-bot');意味着support-bot代理订阅了telegram频道。 - 路由 (
claw.route()):这是一个 PostgreSQL 函数,用于向特定频道发送消息。函数签名类似于claw.route(channel, agent_id_filter, user_id, session_id, message)。消息被投递后,会触发绑定到该频道且符合过滤条件的代理进行处理。 - 出箱 (
claw.outbox):代理处理完路由过来的消息后,生成的响应不会直接写回某个具体的行,而是插入到claw.outbox表中。外部系统(如一个 Telegram 机器人服务)可以轮询此表,获取响应并发送给最终用户。
此外,claw.heartbeats 表允许为代理注册定期执行的任务(心跳),例如 “每 30 分钟检查一次未处理工单”。这使代理不仅能被动响应变化,还能主动发起行动。
可落地模式:
- 客服流水线:
ticket-ingestion代理接收原始用户消息并存入tickets表,触发行内triage代理进行初步分类。triage代理根据复杂度,通过claw.route('escalation', ...)将棘手工单路由给senior-support代理频道,由更专业的代理处理。所有交互状态均持久化在各自的行和memory中。 - 数据管道监控:多个数据管道任务作为行存储在
tasks表中,每个任务有一个claw代理监控其状态。一个全局的heartbeat代理定期检查所有pending任务,并通过频道通知对应的处理代理,形成自愈合的数据处理网络。
四、 风险、限制与部署考量
尽管设计精巧,pgclaw 并非银弹,在采用前需审慎评估其边界。
1. 性能与延迟:LLM API 调用是主要延迟源,且受网络波动影响。后台工作进程是单点(尽管可配置并行度)。不适用于在线交易处理(OLTP)中对延迟敏感的读写操作。
2. 安全与成本:LLM API 密钥存储在 postgresql.conf 文件中,需通过严格的文件权限和可能的外部密钥管理服务(如 HashiCorp Vault)进行保护。无节制的代理触发可能导致巨大的 API 调用成本,需在触发器层面或通过代理内部的指令设计进行限流。Claude Code 代理拥有文件系统访问权限,必须在严格隔离的环境(如容器、沙盒)中运行。
3. 复杂性内聚:将业务逻辑(AI 代理行为)深度嵌入数据库,使得调试和跟踪变得复杂。需要熟悉 PostgreSQL 内部机制(触发器、后台工作进程)以及 pgclaw 自身的表结构。
部署清单:
- 环境:PostgreSQL 17+,Rust 工具链,
cargo-pgrx。 - 配置:在
postgresql.conf中设置shared_preload_libraries = 'pgclaw',并提供pgclaw.api_key、pgclaw.database等必要参数。 - 初始化:在目标数据库中执行
CREATE EXTENSION pgclaw;,然后创建claw.agents定义和业务表结构。 - 监控:重点关注
claw.queue(积压)、claw.history(增长速率)以及 PostgreSQL 日志中后台工作进程的错误信息。
结语
pgclaw 项目展示了一种极具创见的数据库系统设计思路:将智能体作为一等公民嵌入数据存储层。它摒弃了在数据库之外构建复杂中介层的传统做法,转而利用数据库引擎本身提供的可靠性与并发原语,构建了一个自包含、可持久化状态、并能相互通信的 AI 代理网络。虽然当前版本更适合特定的异步批处理场景,且存在延迟与安全方面的考量,但它无疑为 “AI-Native Database” 的未来形态提供了一个激动人心的原型。对于正在探索如何将 LLM 能力更深度、更有机地集成到自身数据工作流中的工程师而言,pgclaw 的架构思想值得深入研究和借鉴。
资料来源
- calebwin/pgclaw GitHub 仓库:https://github.com/calebwin/pgclaw
- PostgreSQL 17 CREATE TRIGGER 文档:https://www.postgresql.org/docs/current/sql-createtrigger.html