240 lines
9.7 KiB
Markdown
240 lines
9.7 KiB
Markdown
# Working 与 Coding 场景
|
||
|
||
Hy Memory 的公开 `scene` 参数支持三个值:
|
||
|
||
| `scene` | 用途 | 存储与检索路径 |
|
||
|---|---|---|
|
||
| `"chat"` | 闲聊、个人事实、一般问答 | 通用 memory pipeline |
|
||
| `"working"` | 文档、办公、研究、财经、内容创作和电脑操作等生产力任务 | working 双层 memory |
|
||
| `"coding"` | 编码、调试、测试、构建、API/SDK、脚本、SQL 等软件工程任务 | coding 双层 memory,并附带版本演进链 |
|
||
|
||
working 与 coding 复用同一套生产力 pipeline 结构和数据 schema,但使用不同的抽取规范、SQLite 文件和向量集合,数据不会混在一起。
|
||
|
||
## 1. 写入路由
|
||
|
||
### 显式指定 scene
|
||
|
||
生产力写入需要包含 tool message 或 assistant `tool_calls`:
|
||
|
||
```python
|
||
from hy_memory import HyMemoryClient
|
||
|
||
client = HyMemoryClient(mode="pro")
|
||
|
||
messages = [
|
||
{"role": "user", "content": "Fix the timeout in the search client."},
|
||
{
|
||
"role": "assistant",
|
||
"content": "",
|
||
"tool_calls": [
|
||
{
|
||
"id": "call_1",
|
||
"type": "function",
|
||
"function": {
|
||
"name": "apply_patch",
|
||
"arguments": '{"path":"src/search.py"}'
|
||
},
|
||
}
|
||
],
|
||
},
|
||
{
|
||
"role": "tool",
|
||
"tool_call_id": "call_1",
|
||
"name": "apply_patch",
|
||
"content": "Patch applied successfully",
|
||
},
|
||
]
|
||
|
||
result = client.add(
|
||
messages,
|
||
scene="coding",
|
||
user_id="user_123",
|
||
workspace_id="github.com/example/service",
|
||
branch="fix/search-timeout",
|
||
)
|
||
```
|
||
|
||
公开行为:
|
||
|
||
- `scene="chat"`:跳过 scene judge;tool 轨迹会被移除后进入 chat pipeline。
|
||
- `scene="working"`:跳过 scene judge,进入 working pipeline。
|
||
- `scene="coding"`:跳过 scene judge,进入 coding pipeline,并尝试记录版本演进链。
|
||
- 显式 `working/coding` 但输入没有 tool/tool_calls:当前实现会回退 chat pipeline。
|
||
- 非法 scene 会抛出 `ValueError`。
|
||
|
||
### 不指定 scene
|
||
|
||
`scene=None` 时:
|
||
|
||
- 输入没有 tool/tool_calls:直接进入 chat pipeline,不调用 scene judge LLM。
|
||
- 输入包含 tool/tool_calls:使用 user query 与工具名的有界摘要进行一次 `chat / working / coding` 三分类。
|
||
- judge 失败或输出无法解析:回退 chat。
|
||
- 判定为 chat 后,tool 轨迹会被移除再进入 chat pipeline。
|
||
|
||
分类边界:
|
||
|
||
- `coding`:代码或开发产物是工作对象或实现媒介,包括源码、脚本、SQL、notebook、测试、构建、编译/运行错误、API/SDK 和代码评审。
|
||
- `working`:存在明确生产力操作或交付物,但代码不是核心工作媒介,例如文档、PPT、表格、翻译、财经/业务分析、研究报告、邮件日程、项目管理、设计、文件整理、软件安装和设备操作。
|
||
- `chat`:闲聊、个人信息、建议和一般事实问答。仅使用 search/browser 工具不会自动变成 working。
|
||
|
||
## 2. 搜索路由
|
||
|
||
显式传 `scene` 会直接选择对应检索路径,不调用 judge/rewrite LLM:
|
||
|
||
```python
|
||
result = client.search(
|
||
"Which timeout implementation was finally kept?",
|
||
scene="coding",
|
||
user_ids=["user_123"],
|
||
workspace_id="github.com/example/service",
|
||
branch="fix/search-timeout",
|
||
limit=5,
|
||
)
|
||
```
|
||
|
||
默认与 agentic 行为:
|
||
|
||
| 调用方式 | 当前行为 |
|
||
|---|---|
|
||
| `search(query="...", search_mode="default")` | 固定走 chat/normal light search,零 LLM |
|
||
| `search(queries=[...], search_mode="default")` | Coding 开启时分类并 rewrite;仅 Query Rewrite 开启时只 rewrite/time;两者关闭时零 LLM |
|
||
| `search(query="...", search_mode="agentic")` | LLM 三分类、query rewrite 和时间范围解析 |
|
||
| `search(queries=[...], search_mode="agentic")` | 同上,前置 query 作为上下文 |
|
||
| 任意模式显式传 `scene` | scene 优先,零 judge/rewrite LLM |
|
||
|
||
`search_mode="agentic"` 使用有界 query 视图,单 query 与多 query 都会走 judge/rewrite。`search_mode="default"` 的单 query 保证不调用该 LLM。
|
||
|
||
default 多-query 超过 `MEMORY_QUERY_REWRITE_MAX_CHARS` 时不改写;Coding 开启时仍做有界
|
||
场景分类,关闭时直接使用最后一条 query。
|
||
|
||
若 coding 功能被 `MEMORY_CODING_ENABLED=false` 关闭,生产力搜索会安全回退 chat/normal 检索。
|
||
|
||
## 3. Extractor 输入窗口
|
||
|
||
working/coding extractor 将输入分成:
|
||
|
||
- `LAST 5 USER TURNS`:之前 write 的历史,只用于指代消解和上下文,不重复抽取。
|
||
- `NEW MESSAGES`:本次 `add()` 传入的全部消息,全部作为抽取主体,不受 last-5 裁剪。
|
||
|
||
当前压缩规则:
|
||
|
||
- tool result 默认最大 `2048` bytes,保留头尾并省略中段;由 `MEMORY_CODING_TOOL_RESULT_MAX_BYTES` 配置。
|
||
- 单条 assistant 文本超过 `6000` 字符时,默认保留前 `3000` 和后 `3000` 字符。
|
||
- 历史按 user-turn 窗口裁剪;一个 user-turn 包含该 user 消息以及下一条 user 消息前的 assistant/tool 消息。
|
||
- `MEMORY_EXTRACT_HISTORY_TURNS` 控制 store 回读多少历史,默认 5;当前 extractor 最终最多注入最近 5 个 user-turn,因此大于 5 的配置不会扩大 prompt 中的历史窗口。
|
||
|
||
例如本次写入包含 10 个 user-turn 时,10 个 turn 都进入 `NEW MESSAGES`;历史区另外最多提供最近 5 个 user-turn。
|
||
|
||
working/coding 的 Extractor、经验 Reconcile、事实 Reconcile 与跨 session 进展总结均有
|
||
中英文模板。路由优先检查本次新输入前 10 个有效语言字符;Extractor 只看本次 NEW user
|
||
messages,不使用历史或 tool result 决定语言。中文开头后接大量代码、路径或错误信息时仍走
|
||
中文模板;英文开头后面偶尔出现中文术语时保持英文模板。
|
||
|
||
## 4. 返回结构
|
||
|
||
working/coding 写入返回双层结果:
|
||
|
||
```python
|
||
{
|
||
"success": True,
|
||
"scene": "productivity",
|
||
"request_id": "...",
|
||
"ops": [...],
|
||
"ops_summary": {...},
|
||
"experience_ids": [...],
|
||
"fact_ops": [...],
|
||
"fact_ops_summary": {...},
|
||
"fact_ids": [...],
|
||
"memory_id": "..." or None,
|
||
"elapsed_ms": 123.4,
|
||
}
|
||
```
|
||
|
||
`scene="coding"` 还会返回 `chain_rounds`。出于历史兼容,该字段当前统计本次识别并处理
|
||
的 diff hunk 数,而不保证等于最终合并后的唯一演进 round 数。`0` 表示没有识别到可记录
|
||
的代码修改,不代表双层 memory 写入失败。
|
||
|
||
working/coding 搜索返回:
|
||
|
||
```python
|
||
{
|
||
"request_id": "...",
|
||
"scene": "productivity",
|
||
"facts": [...],
|
||
"experiences": [...],
|
||
"elapsed_ms": 123.4,
|
||
}
|
||
```
|
||
|
||
`limit` 分别限制 facts 与 experiences,因此两层最多各返回 `limit` 条。
|
||
|
||
`scene="coding"` 额外返回 `chain_block` 和 `chain_used`:
|
||
|
||
- `chain_block` 是与已召回 fact 对齐的版本演进上下文;无法挂链时为 `""`。
|
||
- `chain_used` 是已经进入 chain block 的 `facts` 下标。
|
||
- SDK 不会从 `facts` 删除这些条目。调用方若要拼成“chain block + 剩余 facts”,需自行按 `chain_used` 过滤。
|
||
|
||
## 5. 存储与作用域
|
||
|
||
默认本地文件:
|
||
|
||
```text
|
||
<coding db directory>/
|
||
├── coding_memory.db # working 经验/事实 metadata
|
||
├── coding_memory_cv.db # coding 经验/事实 metadata
|
||
├── coding_memory_trace.db # working/coding 共用的历史消息
|
||
└── hy_code_chain/
|
||
└── hy_code.db # coding 版本演进链
|
||
```
|
||
|
||
向量集合:
|
||
|
||
| 变体 | 经验层 | 事实层 |
|
||
|---|---|---|
|
||
| working | `{base}_coding_keys` | `{base}_working_facts` |
|
||
| coding | `{base}_coding_keys_cv` | `{base}_working_facts_cv` |
|
||
|
||
同一个 client 可以交替使用 working 与 coding;实现会按变体分别缓存 writer/store。
|
||
|
||
`workspace_id` 与 `branch` 用于生产力 memory 的作用域:
|
||
|
||
- 不传 `workspace_id`:不按 workspace 过滤。
|
||
- 传 `workspace_id`:精确匹配该 workspace。
|
||
- `branch` 只有在同时传 `workspace_id` 时生效。
|
||
- branch 过滤会保留 `branch IS NULL` 的历史数据,避免未记录分支的通用经验被误删。
|
||
|
||
建议写入和搜索使用相同的规范化 `workspace_id`。版本链的 owner 由 `user_id` 与 `workspace_id` 共同构成,避免不同用户或仓库的 patch 串链。
|
||
|
||
## 6. Coding 版本演进链
|
||
|
||
版本演进链由 `hy_memory/coding/chain_store.py` 实现。它不调用 LLM 或 embedding,而是从以下来源识别修改:
|
||
|
||
- 设置 `MEMORY_CODING_CHAIN_REPO_ROOT` 后,从本地 Git 工作区或变更中读取 diff。
|
||
- 从工具轨迹中识别带 path、old、new 的确定性替换动作。
|
||
|
||
无法可靠解析的编辑形式会被跳过。链层是 best-effort:记录失败不会阻断 working/coding 的双层 memory 写入或检索。
|
||
|
||
## 7. 配置
|
||
|
||
| 变量 | 默认值 | 作用 |
|
||
|---|---|---|
|
||
| `MEMORY_CODING_ENABLED` | `true` | 启用 working/coding pipeline |
|
||
| `MEMORY_CODING_DB_PATH` | `{DATA_DIR}/data/coding_memory.db` | working 基础 SQLite 路径;coding/trace 路径由此派生 |
|
||
| `MEMORY_CODING_TOOL_RESULT_MAX_BYTES` | `2048` | 单条 tool result 的字节上限 |
|
||
| `MEMORY_CODING_VERBATIM_FALLBACK_ENABLED` | `false` | 模型无结果时是否保存原文 fact;默认关闭,避免 assistant/tool trace 直接展示 |
|
||
| `MEMORY_EXTRACT_HISTORY_TURNS` | `5` | 回读的历史 user-turn 数;当前 prompt 最终最多使用 5 |
|
||
| `MEMORY_CODING_CHAIN_REPO_ROOT` | 空 | coding 版本链读取本地 Git diff 的仓库路径 |
|
||
|
||
`HCM_*` 变量属于版本链的高级调优项,不是稳定的公共配置契约;普通接入不应依赖其默认值。
|
||
|
||
## 8. 定向验证
|
||
|
||
```bash
|
||
python -m pytest -q \
|
||
tests/coding/test_write_scene_routing.py \
|
||
tests/coding/test_search_scene_routing.py \
|
||
tests/coding/test_scene_coding_variant.py \
|
||
tests/coding/test_scene_coding_search.py \
|
||
tests/coding/test_coding_pipeline_log.py
|
||
```
|