# 外部系统智能体会话与消息 API Base URL 为 Gateway 的 `/api`(部署若由反向代理配置了前缀,以网关实际暴露地址为准)。所有接口沿用现有 `Authorization: Bearer ` 鉴权;无效或过期 token 返回 `401`。 ## 会话隔离键 外部系统创建和检索会话时使用以下**精确拼写**的 metadata 键,三个值均为字符串: | 键 | 类型 | 约定 | | --- | --- | --- | | `agent_id` | string | 智能体 ID | | `task_id` | string | 任务 ID;数字也必须传字符串 | | `chat_type` | string | 页面决定的隔离标识;UTF-8 原样保存、原样比较、原样返回,不做 trim、大小写转换或枚举校验 | `chat_type` 的可用长度大于 64 字符(metadata 存为 JSON 对象)。存量未带 `chat_type` 的线程保持原有行为;只有检索条件中显式提供 `chat_type` 时才会要求该字段精确相等。 ## 1. 创建与按隔离键查找会话 ### `POST /api/threads` | 参数 | 位置 | 必填 | 类型 | 说明 | | --- | --- | --- | --- | --- | | `metadata.agent_id` | body | 是(外部集成约定) | string | 智能体 ID | | `metadata.task_id` | body | 是(外部集成约定) | string | 任务 ID | | `metadata.chat_type` | body | 是(新会话) | string | 页面隔离键 | | `thread_id` | body | 否 | string | 不传则服务端生成 UUID | | `assistant_id` | body | 否 | string | 现有兼容字段 | ```json { "metadata": { "agent_id": "c353429a73e146ae9e6926054b2d155a", "task_id": "108", "chat_type": "测试分析" } } ``` ```json { "thread_id": "c7cefe92-84f8-4f31-aed0-a16f7b151cc2", "status": "idle", "created_at": "2026-08-22T10:00:00+00:00", "updated_at": "2026-08-22T10:00:00+00:00", "metadata": { "agent_id": "c353429a73e146ae9e6926054b2d155a", "task_id": "108", "chat_type": "测试分析" }, "values": {}, "interrupts": {} } ``` ### `POST /api/threads/search` | 参数 | 位置 | 必填 | 类型 | 默认/范围 | 说明 | | --- | --- | --- | --- | --- | --- | | `metadata` | body | 否 | object | `{}` | 所有提供的键均做精确 AND 匹配 | | `limit` | body | 否 | integer | `100`,`1..1000` | 最多返回条数 | | `offset` | body | 否 | integer | `0`,`>=0` | 结果偏移量 | ```json { "metadata": { "agent_id": "c353429a73e146ae9e6926054b2d155a", "task_id": "108", "chat_type": "测试分析" }, "limit": 1 } ``` ```json [ { "thread_id": "c7cefe92-84f8-4f31-aed0-a16f7b151cc2", "status": "idle", "created_at": "2026-08-22T10:00:00+00:00", "updated_at": "2026-08-22T10:05:10+00:00", "metadata": { "agent_id": "c353429a73e146ae9e6926054b2d155a", "task_id": "108", "chat_type": "测试分析" }, "values": {}, "interrupts": {} } ] ``` 匹配结果按 `updated_at` **倒序**,并以 `thread_id` 倒序作同时间稳定排序。响应返回完整 metadata。 ## 2. 读取会话消息 ### `GET /api/threads/{thread_id}/messages` | 参数 | 位置 | 必填 | 类型 | 默认/范围 | 说明 | | --- | --- | --- | --- | --- | --- | | `thread_id` | path | 是 | string | - | 会话 ID | | `limit` | query | 否 | integer | `200`,`1..1000` | 返回消息数 | | `offset` | query | 否 | integer | `0`,`>=0` | 从最早消息起跳过的消息数 | 消息按照会话内实际写入顺序(时间正序)返回,`total` 为分页前总条数。接口读取最新 LangGraph checkpoint,并使用与 `state`/流式消息相同的序列化路径:不按展示用途裁剪 `additional_kwargs`、`tool_calls`、隐藏消息或供应商扩展字段。 ```json { "total": 2, "messages": [ { "type": "human", "id": "msg-1", "content": [{"type": "text", "text": "隐藏上下文"}], "additional_kwargs": {"hide_from_ui": true, "client_ts": "2026-08-22T18:00:00+08:00"} }, { "type": "ai", "id": "msg-2", "content": "这是回答", "tool_calls": [{"name": "lookup", "args": {"keyword": "测试"}, "id": "call-1"}], "additional_kwargs": {"reasoning_content": "完整思考字段", "hide_from_ui": false} } ] } ``` `hide_from_ui` 位于消息的 `additional_kwargs.hide_from_ui`(若该消息实际带有此字段)。`tool_calls[].args` 不被转换:LangChain 已解析的标准 `tool_calls` 通常是 JSON 对象;供应商原始工具调用若保留在 `additional_kwargs`,其原始字符串/对象形态也保持不变。 ## 3. 删除一轮对话 ### `DELETE /api/threads/{thread_id}/messages/{message_id}` `message_id` 应取自消息列表中用户消息(`type: "human"`)的 `id`。删除该问题及其后的 AI、工具、中间消息,直到下一条用户消息之前;若传入的是非用户消息 ID,仅删除该消息。删除会写入新的 checkpoint,随后读取消息列表即可获得已删除后的结果。 成功示例: ```json { "ok": true, "deleted_ids": ["question-1", "answer-1", "tool-1"], "remaining": 2 } ``` ## 4. 删除整个会话 ### `DELETE /api/threads/{thread_id}` 清理该线程的 checkpoint(含消息)、线程 metadata 与该线程目录下的上传文件/工作区/生成产物。会话检索不再返回该线程。 ```json {"success": true, "message": "Deleted local thread data for c7cefe92-84f8-4f31-aed0-a16f7b151cc2"} ``` ## HTTP 错误 | 状态码 | 触发条件 | 响应体示例 | | --- | --- | --- | | 401 | 缺少、无效或过期的 Bearer token | `{"detail":"Authentication required"}` | | 403 | token 没有对应线程权限 | `{"detail":"Permission denied: threads:read"}` | | 404 | 线程不存在、无权访问、或 `message_id` 不存在 | `{"detail":"Thread xxx not found"}` | | 409 | 上述接口当前不使用 409 | 不适用 | | 422 | 分页参数越界,或请求体字段类型不合法 | FastAPI 标准校验错误对象 | | 429 | 上述接口本身未配置限流;如部署侧网关限流,由部署网关返回其配置的响应体 | 不适用 | | 500 | checkpoint 或持久化读取/写入失败 | `{"detail":"Failed to get thread messages"}` 等 | 时间字段 `created_at` 与 `updated_at` 使用 ISO 8601、带 UTC 偏移量;不是毫秒时间戳。 ## 兼容性与生命周期 - 既有 `/threads`、`/runs/stream`、`/models` 调用不改动;仅新增消息查询,并修复单轮删除的 checkpoint 持久化。 - 普通线程未配置通用自动过期策略、单任务会话数上限或 `chat_type` 枚举;保留至调用方删除或运维侧另行清理。AI 写作等独立业务的专用清理策略不适用于本接口。 - 外部系统的联调 task、预置线程、发布窗口和联系人属于部署运维信息,不在代码中硬编码;请在目标测试环境创建后补入联调单。 - Swagger 地址为 `/docs`;OpenAPI JSON 为 `/openapi.json`。