Files
NotesAgentic/docs/development/AI-Core与Agent-Core开发说明.md
T

346 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AI Core 与 Agent Core 开发说明
> 本文档用于团队开发和模块联调,记录当前已经落地的核心边界与使用方式。
> 更新日期:2026-09-01。第一阶段 AI Core、Agent Core、Extension Core 和 Model Core 主链路已经完成;第二阶段 Agent Trace 持久化和可恢复 SSE 已落地,后端当前回归基线为 80 项测试通过。
## 当前实现
当前已经建立第一条可运行链路:
```text
FastAPI
→ Provider Registry
→ Agent Runtime
→ Permission Manager
→ Tool Registry
→ Skill Runtime / Plugin Runtime
→ Agent Trace / SSE
```
对应代码:
```text
backend/app/
├── providers/
│ ├── base.py Provider Protocol 与统一 Turn
│ ├── registry.py Provider 注册、发现、模型列表和连接测试
│ └── mock.py 离线开发 Provider
├── agent/
│ ├── runtime.py Agent Loop、限制、取消、Trace 和 SSE
│ ├── trace_repository.py Run/Event SQLite 持久化、分页、摘要与脱敏
│ ├── tools.py Tool 注册、参数校验、隔离执行和结果转换
│ ├── permissions.py 权限策略、确认请求和会话授权
│ └── builtin_tools.py 无副作用的内置开发 Tool
├── extensions/
│ └── runtime.py Skill/Plugin Manifest、生命周期、依赖与 Tool Contribution
└── container.py AI Core 依赖组装
backend/extensions/
├── skills/knowledge-assistant/ 内置知识库 Skill
└── plugins/text-tools/ 内置示例 Plugin
```
Router 只负责 HTTP/SSE 与错误转换,不实现 Agent、Tool 或 Provider 业务逻辑。
## 模块边界
当前实现属于范涵宇负责的 AI Core / Agent Core
- Provider 抽象与注册;
- Agent Run 生命周期;
- Tool Registry
- Tool 参数校验与执行隔离;
- Permission
- Step、Timeout、Token Budget、取消;
- Tool 并发上限与 run 级网络权限;
- SQLite Trace、分页快照与可恢复 SSE;
- Skill Manifest、Prompt、Tool/Permission/模型能力解析;
- Plugin Manifest、生命周期和 Tool Contribution
- Skill 调用内置 Tool 与 Plugin Tool
- 公共 Contract 和 API 接入。
以下内容保持接口,不在本模块实现:
- Note、NoteBlock、Markdown Parser:由 Knowledge Core 提供;
- FTS5、Vector、RRF、Reranker、Citation:由 Retrieval Core 提供;
- 文件系统和 API Key 明文读取:由 Rust Host 提供;
- MCP Plugin Host、Frontend Extension Slot:按技术基线放在第二阶段实现。
## Provider
默认注册离线 Provider
```text
provider_id = mock
model = mock-1
```
它支持:
```text
chat
tool_calling
streaming
```
普通 Chat 请求:
```json
{
"provider_id": "mock",
"model": "mock-1",
"messages": [
{"role": "user", "content": "hello"}
]
}
```
`POST /api/chat` 返回 ModelEvent SSE。OpenAI-Compatible Adapter 直接消费上游 SSEOllama Adapter 直接消费 JSONL`TextDelta` 是真实增量内容,不再等待整段回答完成。
另外已经实现以下可配置 Adapter:
```text
openai_chat / openai_compatible
ollama
```
创建 Ollama Provider
```json
{
"provider_type": "ollama",
"name": "Local Ollama",
"base_url": "http://127.0.0.1:11434",
"default_model": "qwen3:latest"
}
```
创建 OpenAI-Compatible Provider
```json
{
"provider_type": "openai_compatible",
"name": "OpenAI Compatible",
"base_url": "https://api.openai.com/v1",
"default_model": "<model>",
"credential_id": "openai-main"
}
```
凭证 ID `openai-main` 可以对应开发环境变量 `AINOTE_CREDENTIAL_OPENAI_MAIN`。当前 Web 联调版也允许设置页通过 Credential API 提交 API Key,由 `EncryptedCredentialStore` 使用 Fernet 加密保存;前端 Store、Provider Config、日志和读取响应都不保存或返回明文。未来接入 Tauri 后,由 Rust Host 从 Stronghold 注入或替换存储实现。
Provider 配置生命周期接口已经可用:
```text
GET /api/providers
GET /api/providers/presets
POST /api/providers
GET /api/providers/{provider_id}
PATCH /api/providers/{provider_id}
DELETE /api/providers/{provider_id}
GET /api/providers/{provider_id}/models
POST /api/providers/test
GET /api/credentials/{credential_id}
PUT /api/credentials/{credential_id}
DELETE /api/credentials/{credential_id}
```
设置页现已提供 OpenAI、DeepSeek 和 Ollama 预设,并在保存后自动获取、排序和去重模型列表。模型发现会区分凭据缺失、鉴权失败、限流、超时和上游不可用等错误。
## Agent Run
创建普通 Agent Run
```json
{
"input": "hello",
"provider_id": "mock",
"model": "mock-1",
"max_steps": 10
}
```
请求:
```text
POST /api/agent/runs
```
创建后通过以下接口读取状态和事件:
```text
GET /api/agent/runs/{run_id}
GET /api/agent/runs/{run_id}/events
GET /api/agent/runs/{run_id}/trace?after_sequence=-1&limit=200
POST /api/agent/runs/{run_id}/cancel
```
Run 与 AgentEvent 已写入 SQLite`run_id + sequence` 是幂等键。SSE 每帧包含 `id: sequence`;客户端可以通过 `Last-Event-ID` 请求头或 `after_sequence` 查询参数恢复缺失事件。Trace API 返回平铺事件、下一游标、分页状态、模型/工具调用统计、耗时、Token Usage 和创建 Run 时的配置快照,不负责生成前端树形布局。
运行时内存仍只保留最近 2000 个事件用于实时订阅,完整 Trace 以 SQLite 为准。AI Core 重启后,已经终止的 Run 可以继续查询和回放;重启前未终止的 Run 会收束为 `AGENT_PROCESS_RESTARTED`,避免永久停在 `running`。API Key、Authorization、Password、Secret、常见 `sk-`/Bearer 值在入库前脱敏,超长字符串和集合会截断。
## Tool Calling
当前注册以下内置 Tool
```text
system.echo
math.add
notes.search
rag.search
notes.read
notes.create
notes.update
notes.list
notes.move
tasks.create
tasks.update
tasks.list
attachments.read
audio.transcribe
```
Mock Provider 使用下面的开发语法产生 Tool Call:
```text
/tool system.echo {"text":"hello tool"}
/tool math.add {"left":1,"right":2}
```
Agent Run 需要显式声明 `allowed_tools`
```json
{
"input": "/tool math.add {\"left\":1,\"right\":2}",
"provider_id": "mock",
"model": "mock-1",
"allowed_tools": ["math.add"]
}
```
Tool 参数由独立 Pydantic Model 再次校验。Tool 的异常、非法参数、超时和权限拒绝统一转换为 `ToolResult`,不会直接打断 API 进程。
`notes.search` / `rag.search` 返回的 Citation 会由 Agent Runtime 收集到 `AgentRun.citations`,并产生 `Citation` Trace Event。Note 写操作调用 `note_service`,检索调用 Retrieval Engine,不直接访问 SQLite。
## Permission
Permission Policy 当前支持:
```text
allow
confirm
deny
```
需要确认时,Agent 状态进入 `waiting_permission`,并发出 `PermissionRequired` 事件。前端使用:
```text
POST /api/agent/runs/{run_id}/permissions/{request_id}
```
提交以下决策之一:
```json
{"decision":"allow_once"}
{"decision":"allow_session"}
{"decision":"deny"}
```
默认需要确认的高影响权限包括 `notes.write``notes.delete``tasks.write``network.request``secrets.use`。权限命名空间采用白名单,未知权限默认拒绝。
## Knowledge / Retrieval 接入
Knowledge Core 与 Retrieval Core 已通过 Tool Registry 接入 Agent。Agent Runtime 仍只依赖 Tool Contract,不直接依赖具体服务:
```python
tool_registry.register(
definition=tool_definition,
arguments_model=arguments_model,
executor=executor,
)
```
第一批已经接入:
```text
notes.search
notes.read
notes.create
notes.update
notes.list
rag.search
```
写操作 Executor 调用 Knowledge Core Service,不直接访问 SQLite;检索 Executor 调用 Retrieval Core Service,不直接拼接 FTS5 或 sqlite-vec SQL。
## Extension Core
### Skill Runtime
Skill Package 由 `skill.yaml` 和可选 `prompt.md` 组成。安装时使用 Pydantic 校验 Manifest,并解析:
```text
permissions
tools
retrieval
model.required_capabilities
```
Skill 启用前检查 Tool 是否已注册、Tool 所需权限是否已在 Manifest 声明。创建 Agent Run 时,Skill Runtime 生成 Agent Configuration,注入 System Prompt、允许的 Tool、权限和 Retrieval Config。模型缺少 `chat``tool_calling` 等必要 Capability 时拒绝启动。
生命周期接口:
```text
GET /api/skills
POST /api/skills/install
GET /api/skills/{skill_id}
POST /api/skills/{skill_id}/enable
POST /api/skills/{skill_id}/disable
DELETE /api/skills/{skill_id}
```
### Plugin Runtime
第一阶段 Plugin Runtime 完成 Manifest 校验、安装、启用、停用、卸载和 Tool Contribution。第三方代码不会直接 import 到 AI Core;当前 Declarative Plugin Host 只执行宿主实现的白名单 handler,MCP Host 留到第二阶段。
启用 Plugin 时将 Tool 注册到统一 Tool Registry,并标记 `source=plugin`;停用或异常时注销 Tool。启用中的 Skill 依赖某 Plugin Tool 时,Plugin 不能直接卸载。
生命周期接口:
```text
GET /api/plugins
POST /api/plugins/install
GET /api/plugins/{plugin_id}
POST /api/plugins/{plugin_id}/enable
POST /api/plugins/{plugin_id}/disable
PUT /api/plugins/{plugin_id}/permissions
DELETE /api/plugins/{plugin_id}
```
Plugin Manifest 中的权限只是声明,不代表已经授权。带权限的 Plugin 安装后进入 `permission_required`,Host 必须通过权限接口记录用户授权,之后才能启用。JSON Schema 在安装阶段校验,Tool 调用时再次校验实际参数。
内置示例 `text-tools` 注册 `text.uppercase`。内置 `knowledge-assistant` Skill 同时声明 `notes.search``text.uppercase`,用于验证完整链路:
```text
Skill Manifest
→ Agent Configuration
→ Tool Registry
→ Plugin Tool
→ Tool Result
→ Agent Loop
```
## 当前限制与下一步
前端智能体页面已经完成中文联调:运行状态、Agent Event、内置 Tool、Permission 和常用事件详情字段均通过集中标签映射展示中文;`notes.search` 等技术 ID 继续保留,便于与后端 Trace、日志和接口契约对应。
- 已实现 Mock、OpenAI-Compatible Chat Completions 与 Ollama AdapterOpenAI Responses 和 Anthropic Messages 尚未实现。
- Provider 配置暂存内存,后续通过 Repository 接入 SQLitePATCH 已支持用显式 `null` 清空 base URL、默认模型和凭据引用。
- Run/Trace 已通过 Repository 接入 SQLite;后续增加按保留策略归档和 Benchmark 引用保护。
- Permission 已有核心等待/恢复机制,前端确认 UI 已完成联调和中文展示。
- Task 已持久化到 SQLiteAttachment Tool 读取 Host 管理目录中的 UTF-8 文件。
- `audio.transcribe` 当前消费 Host 预生成的 transcriptfaster-whisper 与说话人分离仍按技术基线在第二阶段接入。
- Extension 安装记录暂存内存;后续接入持久化 Registry 与版本升级流程。
- 当前 Plugin Host 只支持内置声明式白名单 handler;MCP Bridge、独立进程健康检查与 UI Contribution 在第二阶段实现。