# Memory Search 上游参数增量兼容设计 ## 目标 扩展 Memory Gateway 的 `POST /memories/search`,在保留现有用户鉴权、 `scope` 搜索编排、资源隔离、软删除和覆盖修改能力的前提下,支持上游 搜索接口的全部请求选项。 本次只修改 `/memories/search`,不新增 `/memories/get`,也不提供上游路径的 线协议兼容接口。 ## 请求模型 保留现有字段: - `user_id`:必填,始终用于 Gateway 用户鉴权和本地数据隔离。 - `user_key`:必填,用于 Gateway 用户鉴权。 - `conversation_id`:可选,供 `current_chat` scope 生成 session 过滤条件。 - `query`:必填。 - `scope`:保留 `current_chat`、`resources`、`all_user_memory`。 - `app_id`、`project_id`:默认 `default`。 新增或扩展字段: - `agent_id`:可选。存在时,上游搜索使用 `agent_id`;不存在时使用 Gateway 鉴权用户的 `user_id`。请求中不会同时向上游发送两种 owner ID。 - `method`:支持 `keyword`、`vector`、`hybrid`、`agentic`,默认 `hybrid`。 - `top_k`:支持 `-1` 或 `1..100`,保留 Gateway 默认值 `8`。 - `radius`:可选,范围 `0..1`。 - `include_profile`:布尔值,默认 `true`。 - `enable_llm_rerank`:布尔值,默认 `true`。 - `filters`:可选对象,支持上游开放字段过滤 DSL,包括嵌套 `AND`、`OR`。 `agent_id` 只改变上游记忆 owner,不替代 Gateway 的 `user_id/user_key` 鉴权。 这可以防止调用者绕过 Gateway 用户体系,同时允许同一已认证用户查询被授权 使用的 agent memory。当前版本不新增 agent 权限表,因此仅校验 Gateway 用户 凭据,不声明 agent 的独立所有权关系。 ## 搜索编排与过滤器合并 每一次上游 search 调用都必须透传: - owner:`agent_id` 或 `user_id`,二选一; - `query`; - `method`; - `top_k`; - `radius`,仅在请求提供时发送; - `include_profile`; - `enable_llm_rerank`; - `app_id`; - `project_id`; - 合并后的 `filters`。 现有 scope 继续生成内部 session 条件: - `current_chat`:`session_id = chat:{conversation_id}`; - `resources`:按批次生成 `session_id in [...]`; - `all_user_memory`:不生成 session 条件。 当请求同时提供自定义 `filters` 和 scope session 条件时,使用以下结构合并: ```json { "AND": [ {"自定义过滤条件": "..."}, {"session_id": "scope 生成的条件"} ] } ``` 仅存在其中一个条件时直接使用该条件;两者都不存在时不发送 `filters`。 Gateway 不解析或重写自定义过滤 DSL 的内部字段,由上游执行完整校验。 `agent_id` 与所有 scope 均可组合。对于没有对应数据的组合,上游自然返回空数组; Gateway 不额外禁止这些组合,以保持接口简单并完整透传搜索能力。 ## 响应标准化 继续返回 Gateway 的统一结构: ```json { "results": [] } ``` 每个结果新增 `memory_type`: | 上游数组 | `memory_type` | |---|---| | `episodes` | `episode` | | `profiles` | `profile` | | `agent_cases` | `agent_case` | | `agent_skills` | `agent_skill` | | `unprocessed_messages` | `unprocessed_message` | 其余字段保持现状:`id`、`session_id`、`text`、`score`、`source_scope`、 `resource_id`、`resource_uri` 和 `raw`。 profile 和 agent skill 等没有 `session_id` 的结果允许返回 `null`。资源映射只对 能匹配当前用户资源 session 的结果生效,不泄露其他用户的内部资源 URI。 所有类型的结果继续按现有顺序执行: 1. 合并各 scope 的结果; 2. 应用当前用户的 memory tombstone; 3. 按 memory ID 应用当前用户的 active override; 4. 返回统一结果。 ## 错误处理 - 不合法的 `method`、`top_k` 或 `radius` 由 Gateway 请求模型返回 HTTP 422。 - 上游过滤 DSL 错误和其他 HTTP 错误继续由现有 client 行为向外传播。 - 不改变当前 `current_chat` 缺少 `conversation_id` 时跳过该 scope 的行为。 - 不为 `agent_id` 引入新的数据库表或权限模型。 ## 代码改动 - `core/api.py` - 扩展 `SearchMemoriesRequest`。 - 将新增参数传给 service。 - `core/service.py` - 扩展 `search_memories` 和 `_search_payload`。 - 合并自定义 filters 与 scope filters。 - 标准化结果时增加 `memory_type`。 - `tests/test_gateway.py` - 验证默认参数透传。 - 验证全部自定义搜索选项透传。 - 验证 agent owner 与用户鉴权身份分离。 - 验证 filters 与 scope 条件使用 `AND` 合并。 - 验证五类结果的 `memory_type`。 - `README.md` - 更新 `/memories/search` 参数和响应说明。 ## 验收标准 1. 未提供新字段时,上游收到 `method=hybrid`、`include_profile=true`、 `enable_llm_rerank=true`。 2. 所有上游搜索选项均能通过 Gateway 请求并原样传递。 3. `top_k=-1` 被接受,`top_k=0` 和范围外值被拒绝。 4. 自定义 filters 不会覆盖 scope 的资源或聊天 session 隔离条件。 5. 设置 `agent_id` 后,上游只收到 `agent_id`,Gateway 仍使用 `user_id/user_key` 完成鉴权。 6. 每个搜索结果包含准确的 `memory_type`。 7. 现有 tombstone、override、资源 URI 隔离测试继续通过。