Files
LangBot/zh/plugin/dev/apis/agent-run.mdx
T

183 lines
9.5 KiB
Plaintext
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.
---
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` 自动重发。