mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-10-30 04:15:45 +08:00
183 lines
9.5 KiB
Plaintext
183 lines
9.5 KiB
Plaintext
---
|
||
title: "运行上下文 API"
|
||
---
|
||
|
||
AgentRunner 和 EventProcessor 使用当前运行的 API,访问已授权的模型、工具、知识库和上下文。这两个组件不提供 `self.plugin`。
|
||
|
||
## 访问方式
|
||
|
||
```python
|
||
# Inside an EventProcessor handler
|
||
api = ctx.api
|
||
|
||
# Inside AgentRunner.run(ctx)
|
||
api = self.get_run_api(ctx)
|
||
```
|
||
|
||
以下示例中的 `api` 均指当前运行的 API。 除 `get_allowed_*` 同步方法和流式上下文/迭代接口外,下文方法均使用 `await` 调用。不要跨运行保存或复用这个对象。
|
||
|
||
### 配置与授权
|
||
|
||
`ctx.config` 是处理器或 Runner 实例的配置;`self.get_plugin_config()` 读取插件级配置。清单中的 `spec.permissions` 只声明需要的权限,实际可用资源还取决于用户配置和当前事件。
|
||
|
||
```yaml
|
||
spec:
|
||
capabilities:
|
||
tool_calling: true
|
||
permissions:
|
||
tools: [detail, call]
|
||
```
|
||
|
||
这是回复消息和调用工具所需的最小配置。需要其他能力时,在 `spec.permissions` 中按需添加:
|
||
|
||
| `spec.permissions` | 可选操作 |
|
||
| --- | --- |
|
||
| `models` | `invoke`, `stream`, `rerank`, `count_tokens` |
|
||
| `tools` | `detail`, `call` |
|
||
| `knowledge_bases` | `list`, `retrieve` |
|
||
| `history` | `page`, `search` |
|
||
| `events` | `get`, `page` |
|
||
| `storage` | `plugin`, `workspace` |
|
||
| `interactions` | `request` |
|
||
|
||
查询实际授权的资源:
|
||
|
||
```python
|
||
models = api.get_allowed_models() # Each item has model_id and operations
|
||
tools = api.get_allowed_tools() # Each item has tool_name and parameters
|
||
knowledge_bases = api.get_allowed_knowledge_bases() # Each item has kb_id
|
||
```
|
||
|
||
上下文能力可通过 `api.ctx.context.available_apis` 检查。某项为 `False` 时不要调用对应接口;只在清单中声明权限不会自动启用它。
|
||
|
||
## 回复与日志
|
||
|
||
| EventProcessor 方法 | 用途 |
|
||
| --- | --- |
|
||
| `await ctx.reply(text)` | 向当前事件的会话发送文本,返回动作结果。 |
|
||
| `await ctx.log(text, level="info")` | 记录日志;级别为 `debug`、`info`、`warning`、`error`。 |
|
||
| `ctx.reply_stream()` | 以异步上下文管理器更新同一条回复。 |
|
||
|
||
`ctx.reply(text)` 等价于 `await api.call_tool("event_reply", {"text": text})`。需要当前事件具有回复目标,并且 `event_reply` 已被授权。日志和独立 Agent 返回的文本不会自动发送到平台。
|
||
|
||
### 流式回复
|
||
|
||
```python
|
||
async with api.reply_stream() as reply:
|
||
await reply.update("Processing…")
|
||
await reply.update("Processing complete.")
|
||
result = reply.result
|
||
```
|
||
|
||
EventProcessor 也可使用 `ctx.reply_stream()`,它会同时记录动作的开始与结果。
|
||
|
||
`update(text)` 接收**当前完整文本**,不是新增片段;返回本次动作结果。正常退出时完成回复。支持流式且开启流式回复的消息事件会更新平台消息;其他可回复事件会缓存文本,在成功结束时发送一次。异常或取消时丢弃缓存中的未完成文本,已显示的内容不保证能撤回。调试模式仅模拟平台发送。
|
||
|
||
此接口需要 `available_apis.reply_stream` 和 `event_reply` 权限。模型的流式输出与平台的流式发送是两个接口,需要插件主动连接。
|
||
|
||
## 模型、工具与知识库
|
||
|
||
模型调用的参数和用量结构见[通用 API](/zh/plugin/dev/apis/common)。运行 API 还提供以下方法:
|
||
|
||
| 方法 | 返回或用途 |
|
||
| --- | --- |
|
||
| `invoke_llm(llm_model_uuid, messages, ...)` | `Message` |
|
||
| `invoke_llm_with_usage(llm_model_uuid, messages, ...)` | `LLMInvokeResult` |
|
||
| `invoke_llm_stream(llm_model_uuid, messages, ...)` | 异步迭代 `MessageChunk` |
|
||
| `invoke_llm_stream_events(llm_model_uuid, messages, ...)` | 异步迭代 `LLMStreamEvent` |
|
||
| `count_tokens(llm_model_uuid, messages, funcs=None, extra_args=None, timeout=None)` | 模型输入 token 数,`int` |
|
||
| `invoke_rerank(rerank_model_uuid, query, documents, top_k=None, extra_args=None, timeout=30.0)` | 带 `index`、`relevance_score` 的列表 |
|
||
| `get_tool_detail(tool_name)` | 工具说明与参数 schema,`dict` |
|
||
| `call_tool(tool_name, parameters)` | 工具结果,`dict`;无需 `session`、`query_id` |
|
||
| `retrieve_knowledge(kb_id, query_text, top_k=5, filters=None)` | 检索结果列表 |
|
||
|
||
四个模型调用方法还支持 `remove_think=None`;非流式调用支持 `timeout=None`。调用超时受本次运行的剩余时间约束。资源列表可能为空,不能直接假定存在第一个模型或知识库。
|
||
|
||
```python
|
||
allowed = {tool.tool_name for tool in api.get_allowed_tools()}
|
||
if "event_get_actor" in allowed:
|
||
actor = await api.call_tool("event_get_actor", {})
|
||
```
|
||
|
||
`event_*` 工具由 LangBot 固定事件中的目标,`platform_*` 工具允许按 schema 指定目标。使用实际授权列表中的名称与参数;无参数工具传 `{}`。
|
||
|
||
## 历史与事件
|
||
|
||
当前输入不包含完整历史。按需读取当前运行范围内的记录;不能通过传入其他会话 ID 扩大访问范围。
|
||
|
||
| 方法 | 返回值 |
|
||
| --- | --- |
|
||
| `get_prompt()` | 生效的提示词列表;能力标识为 `prompt_get` |
|
||
| `history_page(conversation_id=None, before_cursor=None, after_cursor=None, limit=50, direction="backward", include_attachments=False)` | `HistoryPage` |
|
||
| `history_search(query, filters=None, top_k=10)` | `HistorySearchResult` |
|
||
| `event_get(event_id)` | `AgentEventRecord` |
|
||
| `event_page(conversation_id=None, event_types=None, before_cursor=None, limit=50)` | `EventPage` |
|
||
| `steering_pull(mode="all", limit=None)` | `SteeringPullResult`;读取运行中排队的追加输入 |
|
||
|
||
```python
|
||
if api.ctx.context.available_apis.history_page:
|
||
page = await api.history_page(limit=20)
|
||
for item in page.items:
|
||
print(item.model_dump())
|
||
if page.has_more and page.prev_cursor:
|
||
older = await api.history_page(before_cursor=page.prev_cursor, limit=20)
|
||
```
|
||
|
||
分页结果是 SDK 对象,使用 `.items`、`.has_more`、`.prev_cursor`、`.next_cursor`,不是字典下标。读取旧记录使用 `before_cursor`;读取新记录使用 `after_cursor` 和 `direction="forward"`。历史搜索可能只提供文本匹配。`steering_pull` 的 `mode` 可为 `all`、`one` 或 `one-at-a-time`,用于支持追加输入的 Runner。
|
||
|
||
## 状态与存储
|
||
|
||
| 方法 | 返回值 |
|
||
| --- | --- |
|
||
| `state_get(scope, key)` | `{"value": ...}` |
|
||
| `state_set(scope, key, value)` | `{"success": ...}` |
|
||
| `state_delete(scope, key)` | `{"success": ...}` |
|
||
| `state_list(scope, prefix=None, limit=100)` | `{"keys": [...], "has_more": ...}` |
|
||
|
||
状态需要 `available_apis.state` 和宿主允许的作用域:`conversation`(当前会话)、`actor`(当前用户)、`subject`(当前群组或对象)、`runner`(Runner 实例)。值必须可 JSON 序列化,建议使用 `external.` 等键前缀。状态由 LangBot 持久化,接口返回字典。
|
||
|
||
```python
|
||
if api.ctx.context.available_apis.state:
|
||
await api.state_set("conversation", "external.last_topic", "setup")
|
||
value = await api.state_get("conversation", "external.last_topic")
|
||
```
|
||
|
||
插件和工作空间存储使用 `set_plugin_storage`、`get_plugin_storage`、`get_plugin_storage_keys`、`delete_plugin_storage`,以及对应的 `*_workspace_storage*` 方法。参数与[通用 API](/zh/plugin/dev/apis/common)一致,值为 `bytes`,分别受 `api.ctx.resources.storage.plugin_storage` 和 `workspace_storage` 授权限制。
|
||
|
||
## 运行记录
|
||
|
||
以下接口按同名 `available_apis` 标识检查能力,只能操作当前授权范围内的运行。
|
||
|
||
| 方法 | 返回值 |
|
||
| --- | --- |
|
||
| `run_get(run_id=None)` | `AgentRun` |
|
||
| `run_list(conversation_id=None, statuses=None, before_cursor=None, limit=50)` | `RunPage` |
|
||
| `run_events_page(run_id=None, before_cursor=None, after_cursor=None, limit=50, direction="forward")` | `RunEventPage` |
|
||
| `run_cancel(run_id=None, reason=None)` | `AgentRun` |
|
||
| `run_append_result(result)` | `AgentRunEvent` |
|
||
| `run_finalize(run_id=None, status=None, reason=None)` | `AgentRun` |
|
||
|
||
`run_id=None` 默认当前运行。普通 EventProcessor 处理函数返回后会自动结束,通常不需要手动追加或结束运行记录。AgentRunner 通过 `yield AgentRunResult` 上报结果,避免同时用 `run_append_result` 重复记录相同结果。
|
||
|
||
## 结构化交互(AgentRunner)
|
||
|
||
需要用户确认或填写表单时,通过 `yield AgentRunResult.interaction_requested(ctx.run_id, request)` 请求交互。`request` 可以是 `InteractionRequest` 对象或字典,必填字段为 `interaction_id`、`title`、`fallback_text`;可选字段有 `kind`(`form`、`confirmation`、`choice`)、`fields`、`actions`、`expires_at`。
|
||
|
||
清单需声明 `spec.capabilities.interactions: true` 和 `spec.permissions.interactions: [request]`,并获得宿主授权。界面支持情况见 `ctx.delivery.interactions`;提交结果以 `interaction.submitted` 事件返回。这是 Runner 的结果事件,不是 `ctx.api` 方法,EventProcessor 的普通处理函数不直接提供此接口。
|
||
|
||
## 错误处理
|
||
|
||
```python
|
||
from langbot_plugin.api.proxies.agent_run import PermissionDeniedError
|
||
from langbot_plugin.api.entities.builtin.agent_runner.errors import AgentAPIException
|
||
|
||
try:
|
||
result = await api.call_tool("event_get_actor", {})
|
||
except PermissionDeniedError as exc:
|
||
await ctx.log(str(exc), level="warning")
|
||
except AgentAPIException as exc:
|
||
await ctx.log(f"{exc.error.code}: {exc.error.message}", level="error")
|
||
```
|
||
|
||
这是 EventProcessor 中的示例。`PermissionDeniedError` 表示资源、操作或能力未授权;`AgentAPIException.error` 包含 `code`、`message`、`retryable`、`details`。发送消息等动作超时后,结果可能不确定,不应仅依据 `retryable` 自动重发。
|