> ## Documentation Index
> Fetch the complete documentation index at: https://powercontext.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Source

> 采集成功不等于留下知识。Source 只证明这件事发生过。

采集成功，但 Memory (经过选择、以后还会用到的项目知识。) 搜索仍是空的。这多半不是写入失败。

Source (记录发生过什么。采集不会自动写成长期知识。) 只记录当时发生了什么。一条用户提示词、一次任务结果，或者宿主捕获的回合，都可以成为 Source。它不负责判断内容值不值得长期留着。那个判断属于 Memory、Experience、Skill 或 Handoff。

你可以先把这两步分开看。Source 已经安全存下来了，可复用的知识还要等抽取窗口跑完才会出现。

> [!NOTE]
>
> 安装参数、接口说明和部署配置，以 [官方文档](https://oceanbase.github.io/powercontext/) 的最新发布版本为准。这页帮你分清证据、日志位置和处理进度。

## 先拿到稳定身份

引用一条 Source 时，PowerContext 看 `source_type` 和 `source_id` 这两个字段。

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
SourceRef
├── source_type
└── source_id
```

完整身份还要加上 `scope_id`。同一个 `source_type` 和 `source_id` 可以出现在不同 Scope 里，彼此互不影响。

内置的内容 Source 采集成功后，会同时返回 SourceRef 和这条 Scope 内部的日志位置。

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "status": "accepted",
  "source": {
    "source_type": "content",
    "source_id": "openapi-task-1"
  },
  "position": 1
}
```

`source_id` 要稳定，也要能重现。宿主通常按 Scope、会话、轮次或内容来生成它，这样重试时还是同一条。

## 已采集和引用式不一样

身份定下来之后，还要分清这条 Source 存的是快照，还是只存了一个外部引用。Source 适配器有两种落地方式。

| 类型 | 保存什么 | 读取方式 |
| - | - | - |
| `captured` | PowerContext 保存内容快照和元数据 | 直接从持久层读取 |
| `referenced` | PowerContext 保存外部材料的引用 | 读取时由适配器解析 |

提示词、任务结果和事件文本适合做成已采集 Source。别的系统自己管的材料，更适合做成引用式 Source。

差别很实际。已采集内容是当时的快照。引用式材料下次再解析时，外面的内容可能已经变了。

## 一条 Scope 内共用一条日志

Source 存进当前 Scope 之后，还会拿到一个只在这个 Scope 里有意义的位置。位置从 1 开始，并且单调递增。不同 Source 适配器共用同一条序列，幂等重试也不会占新位置。

假设先后捕获两条内容。

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
content/openapi-task-1 → position 1
content/openapi-task-2 → position 2
```

Source 日志只解决顺序问题。它不表示哪条 Source 已经被处理，也不表示已经生成 Memory。

## 触发器只选窗口

处理进度不看位置本身，而看触发器选出的窗口。`SourceWindowTrigger` 只负责选窗口。它比较当前最大位置和游标，然后返回下一段固定窗口。

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
state.sequence = 0
high_watermark = 2
limit = 1

ProcessSourceWindow(after=0, through=1)
```

下一次激活得到下一段。

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
ProcessSourceWindow(after=1, through=2)
```

游标已经到 2 时，就不再返回动作。

窗口写作 `(after, through]`，不含 `after`，包含 `through`。`source_window_limit` 只限制一次处理多少条，不限制日志总长度。

触发器不读取模型，也不执行抽取。它只返回新状态和待执行动作。

## 游标记录消费进度

窗口选出来以后，真正记住“处理到哪了”的是游标。这里有两个容易混的数字。游标 `序号` 表示业务上处理到哪个 Source 位置。已保存游标 `generation` 是保存这条游标时的并发控制版本。

举例来说，游标可能表示已经处理到位置 12，同时数据库行的生成是 4。它们没有数值对应关系。

PowerContext 处理 Source 窗口时，会先完成抽取和 Memory apply，再保存新的游标。Memory apply 失败时不能提前推进游标，否则失败窗口会被跳过。

## 采集不会自动产生 Memory

下面的调用只创建 Source。

```http theme={"theme":{"light":"github-light","dark":"github-dark"}}
POST /v1/sources/content
```

要得到 Memory，还有两条路。你已经知道要保存什么时，直接调用显式 Memory 写入。或者配置生成流程，由调度器或 `flush_memory` 处理未消费的 Source 窗口。

即使抽取正常运行，模型也可能认为当前窗口没有值得新增或修订的内容。Source 被处理，不保证 Memory Revision 一定变化。

> [!NOTE]
>
> `flush_memory` 处理待消费 Source。它不是 `remember_memory` 的另一种写法。

## 幂等和冲突

同一 Scope 中再次采集相同 Source 标识时，结果只有两种。持久层序列化后的载荷字节完全相同，就返回原来的位置。载荷字节不同，就返回冲突，并且不覆盖旧 Source。

比较的是序列化后的字节，不是意思相不相等。元数据即使是同一组键值，只要键顺序变了、字节变了，也可能冲突。重试应复用同一序列化输入。

所以不要长期复用固定 `source_id`，却每次写入不同内容。

并发行为同样有明确约束。多条不同 Source 并发写入时，位置保持连续，没有缺口。同一 Source 的相同载荷并发重试，最终都指向同一个位置。两个工作进程同时更新游标时，只有符合预期生成的写入会成功。

## Source 不只来自聊天

Source 不只来自聊天宿主。工作连续性也会把事件保存为精确 Source，例如工作契约（Work Contract）、Handoff 边界、Handoff 确认回执和 Task Outcome。

这样 Handoff 报告就可以从日志投影工作历史，而不必改写底层 Handoff Artifact。

## 用 OpenAPI 案例推演

先捕获第一条证据。

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "scope_id": "project:powercontext-101",
  "source_id": "openapi-task-1",
  "content": "The OpenAPI contract changed. Regenerate the checked-in client and run contract tests.",
  "metadata": {
    "origin": "tutorial"
  }
}
```

然后核对这四件事。响应中的 SourceRef 应是 `content/openapi-task-1`。位置应大于 0。相同请求重试应返回同一位置。修改内容后复用同一 ID 应返回冲突。

核对完再决定，这是只需要保留的证据，还是应该显式写成 Memory。别急着把所有 Source 都变成长期知识。

## 卡住时先对这几条

### 采集成功，但 Memory 没变化

先看生成能力，再看游标是否到达采集位置。两者都正常时，抽取仍可能得到无变更。

### 刷新返回 idle

调度器可能已经先处理了窗口。比较 `current_cursor` 与采集位置，不要只看 `idle` 字样。

### 重试变成冲突

检查是否复用了 `source_id`，但规范形式内容或元数据已经变了。

### 不同宿主出现相同位置

只要它们使用同一 Scope 和 Server，这很正常。所有适配器共用 Scope 内部日志。

## 怎么知道分清了

1. Source 标识同时包含 Scope、type 和 ID。
2. 日志位置和游标序号是两回事。
3. 游标序号和游标 generation 也是两回事。
4. 窗口按 `(after, through]` 理解。
5. 采集成功不等于已经写入 Memory。
6. 幂等重试会回到原来的位置。

对不上时，先对[排错](https://powercontext.mintlify.site/zh/start/troubleshooting.md)。要亲手走一遍采集和抽取，看 [Source 与 Memory](https://powercontext.mintlify.site/zh/basic-usage/source-and-memory.md)。

## 下一步

> [card] [再看长期知识怎么留下](https://powercontext.mintlify.site/zh/mental-model/memory.md)
>
> Memory 回答以后还要知道什么。显式写入不需要先创建 Source。

> [card] [亲手走一遍采集](https://powercontext.mintlify.site/zh/basic-usage/source-and-memory.md)
>
> 对象已经清楚时，先采集一条 Source，再看它会不会变成 Memory。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.