perf(agent-runner): improve session registry and orchestrator efficiency

- Add pre-computed _authorized_ids (frozenset) at session registration for O(1) lookup
- Refactor is_resource_allowed() from linear search to set membership check
- Add thread-safe locking to get_session_registry() singleton
- Cache _session_registry and _state_store references in orchestrator __init__
- Add asyncio.gather() for parallel resource building in AgentResourceBuilder
- Create shared test fixtures in tests/unit_tests/agent/conftest.py
- Update test files to import from shared conftest.py

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
huanghuoguoguo
2026-05-11 21:45:26 +08:00
parent d6b8f48e73
commit dc82fb584a
23 changed files with 4438 additions and 677 deletions

View File

@@ -14,6 +14,7 @@ LangBot 最终只保留 Agent Runner 的宿主能力:
- 归一结果:`AgentRunResult` -> 当前 Pipeline 的 `Message` / `MessageChunk`
- 隔离错误:插件异常、协议错误、超时、结果过大不能破坏主流程
- 迁移旧配置:把旧内置 runner 配置迁到官方 AgentRunner 插件配置
- 转发调用:插件 runtime 只维护已安装插件本身的运行实例Pipeline 不创建插件实例或 runner 实例
LangBot 不再长期维护内置业务 runner 分支。`local-agent`、Dify、n8n、Coze、DashScope、Langflow、Tbox 等都迁到官方 AgentRunner 插件。
@@ -45,6 +46,8 @@ SDK Runtime RUN_AGENT -> plugin AgentRunner.run()
- `ChatMessageHandler` 不解析 `plugin:*`,不实例化 wrapper不知道 runner 组件细节。
- `PipelineService.get_pipeline_metadata()` 不直接访问插件 runtime而是读取 registry。
-`RequestRunner` 只作为迁移参考,不作为最终运行路径。
- 插件是无状态执行单元:多个 Pipeline 可以绑定同一个 runner id并分别保存自己的 `ai.runner_config[id]`;运行时 LangBot 只把当前绑定配置放入 `ctx.config` 转发给同一个插件 runner。
- 禁止按 Pipeline 或 runner config 创建多个插件实例。需要跨请求持久化的状态必须走明确授权的 plugin storage / workspace storage / 外部服务,不能隐式保存在 per-pipeline 插件对象里。
- EBA 只做字段预留,不在本轮实现 EventBus、EventRouter、平台动作执行。
## 3. 新增 LangBot 模块
@@ -138,7 +141,7 @@ class AgentRunnerDescriptor(BaseModel):
- `input`: 从 `query.user_message``query.message_chain` 构造
- `resources`: 由 `resource_builder` 注入
- `runtime`: host/version/workspace/bot/pipeline/query/trace/deadline
- `config`: 当前 runner id 对应的实例配置
- `config`: 当前 Pipeline 对该 runner id 的绑定配置,即 `ai.runner_config[runner_id]`
保留 SDK legacy helper 是 SDK 的责任LangBot 不再构造 PoC 的 `query_id/session/messages/user_message/extra_config` 上下文。
@@ -148,7 +151,7 @@ class AgentRunnerDescriptor(BaseModel):
1. runner manifest 声明的 `spec.permissions`
2. Pipeline 的 `extensions_preferences`
3. runner 实例配置中选择的资源范围
3. 当前 Pipeline runner 绑定配置中选择的资源范围
输出写入 `ctx.resources`,至少覆盖:
@@ -215,6 +218,8 @@ async def run_from_query(query: pipeline_query.Query) -> AsyncGenerator[Message
## 4. 配置模型直接切换
配置模型表达的是 Pipeline 到 runner id 的绑定,不表达插件实例。插件安装后由 plugin runtime 管理单个插件运行实例;不同 Pipeline 选择同一个 runner id 时,只是保存不同的 `runner_config[id]`,调用时随 `AgentRunContext.config` 传入。
目标格式:
```json
@@ -322,7 +327,7 @@ async def run_from_query(query: pipeline_query.Query) -> AsyncGenerator[Message
### Step 6权限和资源裁剪
- resource builder 根据 manifest / pipeline / instance config 裁剪
- resource builder 根据 manifest / pipeline / runner binding config 裁剪
- proxy action 校验 resource scope
- 禁止插件用 unrestricted API 访问未授权知识库、工具、模型
@@ -365,6 +370,7 @@ async def run_from_query(query: pipeline_query.Query) -> AsyncGenerator[Message
- `ChatMessageHandler` 不包含插件 runner 解析和 wrapper。
- `PipelineService` 不直接拼插件 runner metadata。
- 所有 runner 配置使用 `ai.runner.id` + `ai.runner_config`
- 插件 runtime 不为每个 Pipeline 或 runner 配置创建插件实例;`runner_config` 只作为绑定配置随 `ctx.config` 传入。
- 旧内置 runner 不再作为 LangBot 内部运行分支执行。
- 插件只能访问 `ctx.resources` 授权的模型、工具、知识库和文件。
- EBA 相关字段只作为 context/result 预留,不执行平台动作。

View File

@@ -158,7 +158,7 @@ class AgentRunContext(BaseModel):
- `input` 是 runner 的主输入,不再强制等同于纯文本消息。
- `resources` 列出 LangBot 已授权给 runner 的工具、知识库、模型、文件等。
- `runtime` 提供 host 信息、workspace/bot/pipeline 标识、trace id、deadline 等。
- `config` 是当前 runner 的实例配置,替代当前 `extra_config`
- `config` 是当前 Pipeline 或未来事件绑定对该 runner id 的绑定配置,替代当前 `extra_config`
为了兼容现有实现SDK 可提供:
@@ -224,6 +224,10 @@ SDK 应把这些能力按 capability 分组。LangBot 在调用 runner 前根据
当前阶段 runner 配置仍跟 Pipeline 绑定,并且仍然作为 Pipeline 的一个 stage 执行。也就是说Bot 收到私聊/群聊消息后仍按现有 Pipeline 流转,只是在 AI runner stage 中选择插件化 Agent Runner。
这里的“绑定配置”不代表插件实例。插件安装后由插件 runtime 维护插件本身的运行实例LangBot 不会因为多个 Pipeline 选择同一个 runner id 而创建多个插件实例或 runner 实例。不同 Pipeline 可以保存不同的 `runner_config[id]`,调用时 LangBot 只把当前绑定配置放进 `AgentRunContext.config` 转发给同一个插件 runner。
插件 runner 应按无状态执行单元设计。需要跨请求保存的 conversation id、外部平台状态或用户状态应通过明确授权的 plugin storage、workspace storage、外部服务或 context runtime state 管理,不能隐式依赖 per-pipeline 插件对象状态。
后续 EBA EventRouter 落地后,同一套 `AgentRunnerDescriptor``AgentRunOrchestrator` 需要支持直接与 Bot 的事件触发器绑定。届时 Bot event handler 可以绕过完整 Pipeline直接选择某个 Agent Runner 处理 `message.received``group.member_joined``friend.request_received` 等事件。
Pipeline AI 配置建议从:
@@ -317,7 +321,7 @@ LangBot 执行前做三层裁剪:
- 插件 manifest 声明的权限。
- Pipeline 或 Bot 绑定的扩展范围。
- 用户在 runner 配置中选择的资源范围。
- 用户在 Pipeline runner 绑定配置中选择的资源范围。
最终写入 `ctx.resources`,并在 proxy action 里再次校验。
@@ -403,4 +407,5 @@ SDK
- 插件可以声明多个 `AgentRunner` 组件,每个组件独立暴露 manifest、配置 schema、能力和权限。
- 本阶段不把 `action.requested` 作为必须实现的运行结果。它只是为未来 EBA 平台动作预留的返回类型;当前 Pipeline stage 中如收到该类型,只记录 telemetry不执行动作。
- 当前 runner 配置先跟 Pipeline 绑定,仍然在 Pipeline 的 AI runner stage 中执行;后续需要支持直接与 Bot 的事件触发器绑定。
- Pipeline/Event 绑定只保存 runner id 和绑定配置,不创建插件实例或 runner 实例;插件 runner 按无状态转发调用处理,跨请求状态必须显式存储。
- 内置 `RequestRunner` 最终强制迁移为插件形态,避免长期保留“内置 runner 分支”和“插件 runner 分支”两套执行体系。