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

# 执行引擎

`Runner` 是执行引擎的核心：它协调智能体、工具与回调，共同响应用户输入，同时管理信息流、状态变化，以及与模型、工具、存储的交互。VeADK 的执行引擎完全兼容 Google ADK 的 `Runner`，其完整机制可参见 [Google ADK 运行时文档](https://google.github.io/adk-docs/runtime/)。

## 多租户隔离

面向企业级多租户场景，`Runner` 通过 `app_name`、`user_id`、`session_id` 三个维度实现数据隔离：

| 数据 | 隔离维度 |
| - | - |
| 短期会话 | `app_name`、`user_id`、`session_id` |
| 长期记忆 | `app_name`、`user_id` |
| 知识库 | `app_name` |

## 最简运行

`Runner.run()` 直接运行一个智能体，处理输入并返回最终文本响应，适合本地测试：

```python lines theme={null}
import asyncio
from veadk import Agent, Runner

agent = Agent()
runner = Runner(agent=agent)

response = asyncio.run(runner.run("北京的天气怎么样？"))
print(response)
```

<Note>
  `run()` 封装度较高。当 `Runner` 配置了短期会话时，它会按需自动创建会话。若需要更细粒度地控制执行过程，使用 `run_async()`。
</Note>

## 使用 Harness 增强执行

VeADK 1.0.1 提供可挂载到 `Runner` 的 Harness 插件，用于在每轮调用前准备上下文、压缩较大的工具结果，并检查最终回答是否有工具结果支持。基础插件随 VeADK 提供；需要 Headroom 压缩实现时安装 `harness` 依赖组：

```bash lines theme={null}
pip install "veadk-python[harness]==1.0.1"
```

```python lines theme={null}
from veadk import Agent, Runner
from veadk.extensions.harness.plugins import build_harness_plugins

agent = Agent(name="research_agent")
runner = Runner(
    agent=agent,
    app_name="research",
    plugins=build_harness_plugins(
        components=["invocation_context", "compactor", "response_verification"],
        profile="research",
    ),
)
```

| 组件 | 作用 |
| - | - |
| `invocation_context` | 为当前任务准备锚点、近期上下文和工具使用约束。 |
| `compactor` | 压缩过大的工具结果，同时保留与任务有关的事实。 |
| `response_verification` | 记录工具结果，并检查最终回答中的关键结论是否有依据。 |

## 从 AgentKit 智能体中心发现远程智能体

部署 Harness 服务时，可以启用 AgentKit A2A Registry，使运行时按每轮请求从指定智能体中心发现匹配的远程智能体：

```bash lines theme={null}
export REGISTRY_TYPE="agentkit_a2a"
export REGISTRY_SPACE_ID="your-agent-center-id"
export REGISTRY_TOP_K="3"
```

`REGISTRY_TOP_K` 控制每轮最多召回的候选数量，默认值为 `3`。运行时需要访问 AgentKit A2A Registry；远程 Agent Card 声明鉴权方式时，还需要相应的 API Key 或 Identity OpenAPI 权限。OAuth2 远程调用的凭据处理见[出站认证](/productions/veadk/archives/1.0.1/zh/components/security/outbound#a2a-远程智能体鉴权)。

## 流式处理事件

`Runner.run_async()` 返回一个异步生成器，逐个产出智能体执行过程中的事件。相比 `run()` 只拿到最终文本，遍历事件可以获得思考过程、工具调用与结果、以及流式增量，便于自行开发上层逻辑。

```python lines theme={null}
import asyncio
from google.genai.types import Content, Part
from veadk import Agent, Runner

APP_NAME, USER_ID, SESSION_ID = "app", "user", "session"

agent = Agent()
runner = Runner(agent=agent, app_name=APP_NAME, user_id=USER_ID)

message = Content(role="user", parts=[Part(text="北京的天气怎么样？")])

async def main():
    async for event in runner.run_async(
        user_id=USER_ID,
        session_id=SESSION_ID,
        new_message=message,
    ):
        ...  # 见下文解析事件

asyncio.run(main())
```

<Note>
  `run_async()` 在调用前需已存在对应会话。若直接使用它，请确保 `session_id` 对应的会话已创建。
</Note>

## 解析事件

每个事件描述了执行过程中的一步。其常用字段如下：

| 字段 | 说明 |
| - | - |
| `author` | 产出该事件的智能体或工具名称 |
| `content` | 事件内容，包含 `role` 与 `parts` 列表 |
| `partial` | 是否为流式输出的增量片段 |
| `usage_metadata` | 本步的 token 用量 |
| `invocation_id` | 本次调用的标识 |

`content.parts` 中的每个 `part` 可能是不同类型，据此区分处理：

| part 字段 | 含义 |
| - | - |
| `text` | 模型输出的文本 |
| `thought` | 标记该片段为模型的思考过程 |
| `function_call` | 模型发起的工具调用，含 `name` 与 `args` |
| `function_response` | 工具返回的结果，含 `name` 与 `response` |

事件还提供了便捷方法：`is_final_response()` 判断是否为最终回复，`get_function_calls()` 与 `get_function_responses()` 分别取出本事件中的工具调用与结果。

```python lines theme={null}
async for event in runner.run_async(
    user_id=USER_ID, session_id=SESSION_ID, new_message=message,
):
    # 工具调用与结果
    for call in event.get_function_calls():
        print("调用工具:", call.name, call.args)
    for resp in event.get_function_responses():
        print("工具结果:", resp.name, resp.response)

    # 区分思考与文本
    if event.content:
        for part in event.content.parts:
            if part.thought:
                continue  # 模型思考过程，可按需展示
            if part.text:
                print(part.text)

    # 最终回复
    if event.is_final_response() and event.content:
        final_text = "".join(p.text for p in event.content.parts if p.text)
```
