落地并存测服全端:智能体 Graph/路由、后台切 8180、主账与部署脚本齐备,便于线上重发与验收。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
linmianxun
2026-09-13 21:15:58 +08:00
co-authored by Cursor
parent 0eb1adecc8
commit 8103b3b651
143 changed files with 8968 additions and 277 deletions
@@ -0,0 +1,125 @@
-- 001_runtime_core_v1.sql
-- 新系统运行账核心表(inquiry_robot_runtime)
-- 禁止对现网 ytd_runtime 执行。
-- Graph checkpoint 表由 LangGraph PostgresSaver.setup() 另建,不在此脚本。
CREATE TABLE IF NOT EXISTS schema_migrations (
version TEXT PRIMARY KEY,
applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
description TEXT NOT NULL DEFAULT ''
);
-- 企微入站 inbox:回调只写入;Worker/通道线程认领
CREATE TABLE IF NOT EXISTS agent_inbox (
id UUID PRIMARY KEY,
message_id TEXT NOT NULL,
sender_id TEXT NOT NULL,
chat_id TEXT NOT NULL DEFAULT '',
chat_type TEXT NOT NULL DEFAULT '',
payload JSONB NOT NULL,
state TEXT NOT NULL DEFAULT 'pending',
claimed_at TIMESTAMPTZ,
claimed_by TEXT NOT NULL DEFAULT '',
attempts INT NOT NULL DEFAULT 0,
last_error TEXT NOT NULL DEFAULT '',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT agent_inbox_message_id_uq UNIQUE (message_id)
);
CREATE INDEX IF NOT EXISTS idx_agent_inbox_state_created
ON agent_inbox (state, created_at);
-- 企微出站 outbox:发送成功 ≠ 业务成功;过期可丢弃
CREATE TABLE IF NOT EXISTS agent_outbox (
id UUID PRIMARY KEY,
dedupe_key TEXT NOT NULL DEFAULT '',
touser TEXT NOT NULL,
content TEXT NOT NULL DEFAULT '',
msg_type TEXT NOT NULL DEFAULT 'text',
payload JSONB NOT NULL DEFAULT '{}'::jsonb,
state TEXT NOT NULL DEFAULT 'pending',
claimed_at TIMESTAMPTZ,
claimed_by TEXT NOT NULL DEFAULT '',
attempts INT NOT NULL DEFAULT 0,
last_error TEXT NOT NULL DEFAULT '',
max_age_seconds INT NOT NULL DEFAULT 86400,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE UNIQUE INDEX IF NOT EXISTS uq_agent_outbox_dedupe
ON agent_outbox (dedupe_key)
WHERE dedupe_key <> '';
CREATE INDEX IF NOT EXISTS idx_agent_outbox_state_created
ON agent_outbox (state, created_at);
-- 会话:活动工单与打断栈(非六态真相)
CREATE TABLE IF NOT EXISTS conversation_session (
thread_id TEXT PRIMARY KEY,
sender_id TEXT NOT NULL,
active_inquiry_no TEXT NOT NULL DEFAULT '',
interrupt_stack JSONB NOT NULL DEFAULT '[]'::jsonb,
meta JSONB NOT NULL DEFAULT '{}'::jsonb,
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_conversation_session_sender
ON conversation_session (sender_id);
-- 停等账:waitVersion(与卡片/H5 绑定)
CREATE TABLE IF NOT EXISTS suspend_wait (
thread_id TEXT NOT NULL,
wait_version INT NOT NULL,
pause_name TEXT NOT NULL DEFAULT '',
inquiry_no TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'open',
payload JSONB NOT NULL DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
closed_at TIMESTAMPTZ,
PRIMARY KEY (thread_id, wait_version)
);
-- 补问 / 卡片 token(H5 TTL 约 30 分钟由应用写入 expires_at)
CREATE TABLE IF NOT EXISTS clarification_binding (
token TEXT PRIMARY KEY,
thread_id TEXT NOT NULL,
wait_version INT NOT NULL,
sender_id TEXT NOT NULL DEFAULT '',
allowed_actions JSONB NOT NULL DEFAULT '[]'::jsonb,
expires_at TIMESTAMPTZ NOT NULL,
consumed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_clarification_thread_wait
ON clarification_binding (thread_id, wait_version);
-- 可选:PG 任务认领表(与 Redis Stream 二选一做真相;骨架两套都建好,业务接入时只留一条)
CREATE TABLE IF NOT EXISTS agent_job (
id UUID PRIMARY KEY,
job_type TEXT NOT NULL,
idempotency_key TEXT NOT NULL DEFAULT '',
payload JSONB NOT NULL,
state TEXT NOT NULL DEFAULT 'pending',
claimed_at TIMESTAMPTZ,
claimed_by TEXT NOT NULL DEFAULT '',
attempts INT NOT NULL DEFAULT 0,
last_error TEXT NOT NULL DEFAULT '',
result JSONB,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE UNIQUE INDEX IF NOT EXISTS uq_agent_job_idem
ON agent_job (job_type, idempotency_key)
WHERE idempotency_key <> '';
CREATE INDEX IF NOT EXISTS idx_agent_job_state_created
ON agent_job (state, created_at);
INSERT INTO schema_migrations (version, description)
VALUES ('001_runtime_core_v1', 'inbox/outbox/session/suspend/clarification/job 核心表')
ON CONFLICT (version) DO NOTHING;
@@ -0,0 +1,25 @@
-- 002_dead_letter_v1.sql
-- 死信表:失败任务落点(框架壳,不含业务重放逻辑)
-- 禁止对现网 ytd_runtime 执行。
CREATE TABLE IF NOT EXISTS agent_dead_letter (
id UUID PRIMARY KEY,
source TEXT NOT NULL DEFAULT '',
source_id TEXT NOT NULL DEFAULT '',
job_type TEXT NOT NULL DEFAULT '',
payload JSONB NOT NULL DEFAULT '{}'::jsonb,
error TEXT NOT NULL DEFAULT '',
attempts INT NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
replayed_at TIMESTAMPTZ
);
CREATE INDEX IF NOT EXISTS idx_agent_dead_letter_created
ON agent_dead_letter (created_at DESC);
CREATE INDEX IF NOT EXISTS idx_agent_dead_letter_job_type
ON agent_dead_letter (job_type, created_at DESC);
INSERT INTO schema_migrations (version, description)
VALUES ('002_dead_letter_v1', 'agent_dead_letter 死信表壳')
ON CONFLICT (version) DO NOTHING;
+21 -4
View File
@@ -1,7 +1,24 @@
# PostgreSQL 运行账迁移
后续在此目录添加版本化 SQL(inbox / outbox / checkpoint / 任务认领等)。
- 只对当前环境变量 `PG_DATABASE` / `PG_DSN` 执行(新系统 **`inquiry_robot_runtime`**)。
- **禁止**对现网 `ytd_runtime` 执行迁移(代码会拒绝)。
- 只对当前环境变量 `PG_DATABASE` 执行(新系统 `inquiry_robot_runtime`)。
- **禁止**对现网 `ytd_runtime` 执行迁移。
- 骨架阶段不建业务表。
## 文件
| 文件 | 内容 |
|---|---|
| `001_runtime_core_v1.sql` | inbox / outbox / conversation_session / suspend_wait / clarification_binding / agent_job |
## Graph checkpoint
LangGraph `PostgresSaver.setup()` 会在连接库内另建 checkpoint 表,与上表分开。
## 怎么跑
```text
cd inquiry-agent
python -m agent.runtime_db.migrate --list
python -m agent.runtime_db.migrate
```
需已配置 `PG_DSN` 或 `PG_HOST`+`PG_DATABASE`+`PG_USER`(及密码)。