14.8 客户端集成指南
本指南详细介绍如何将 IDE 客户端(或任何 ACP 兼容客户端)连接到 `rust-agent-host` 服务端,包括传输层选择、会话管理、每轮模型配置传递和流式输出处理。
快速开始
1. 启动 Host 服务端
**Stdio 模式**(本地子进程,标准 ACP 模式):
cargo run -p rust-agent-host -- --mode stdio
**WebSocket 模式**(远程部署):
cargo run -p rust-agent-host -- --mode ws --bind 127.0.0.1:9876
2. 配置 LLM 提供商
通过 `host.toml` 配置文件:
[provider]
provider = "openai"
model = "agnes-2.0-flash"
api_key = "$AGNES_API_KEY"
base_url = "https://apihub.agnes-ai.com/v1"
temperature = 0.3
max_tokens = 8192
context_window_tokens = 128000
max_output_tokens = 8192
[agents]
coding = true
general = true
analysis = true
[dev_pipeline]
enabled = true
agent_id = "dev-pipeline"
max_iterations = 3
或通过环境变量 / CLI 参数:
AGNES_API_KEY=sk-xxx \
cargo run -p rust-agent-host -- \
--mode stdio \
--provider deepseek \
--model agnes-2.0-flash \
--workspace-root /path/to/project
传输层集成
Stdio 模式集成
适用于 IDE 将 host 作为本地子进程启动的场景。
// TypeScript 示例:启动 host 子进程
import { spawn } from 'child_process';
const hostProcess = spawn('cargo', [
'run', '-p', 'rust-agent-host', '--',
'--mode', 'stdio',
'--provider', 'deepseek',
'--api-key', '$AGNES_API_KEY'
], {
stdio: ['pipe', 'pipe', 'pipe']
});
// 通过 stdin/stdout 发送/接收 JSON-RPC 消息
hostProcess.stdin.write(JSON.stringify(initializeRequest) + '\n');
hostProcess.stdout.on('data', (data) => {
const messages = data.toString().split('\n').filter(Boolean);
for (const msg of messages) {
const response = JSON.parse(msg);
handleAcpMessage(response);
}
});
WebSocket 模式集成
适用于远程部署或多客户端共享场景。
// TypeScript 示例:WebSocket 连接
const ws = new WebSocket('ws://127.0.0.1:9876/acp');
ws.onopen = () => {
ws.send(JSON.stringify(initializeRequest));
};
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
handleAcpMessage(message);
};
ACP 协议交互流程
步骤 1:初始化
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocol_version": "0.14"
}
}
响应中包含可用 Agent 列表:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocol_version": "0.14",
"_meta": {
"raf": {
"version": "0.1.0",
"agents": [
{
"id": "coding",
"agent_type": "CodingAgent",
"name": "coding",
"description": "代码专家智能体",
"has_subagents": false,
"is_default": true
},
{
"id": "dev-pipeline",
"agent_type": "WorkflowAgent",
"name": "dev-pipeline",
"description": "图工作流 [dev-pipeline]: 8 节点, 8 条边",
"has_subagents": true,
"is_default": false
}
]
}
}
}
}
步骤 2:创建会话
指定目标 Agent(可选,不指定则使用默认 Agent):
{
"jsonrpc": "2.0",
"id": 2,
"method": "session/new",
"params": {
"_meta": {
"raf": {
"agent_id": "coding"
}
}
}
}
步骤 3:发送提示(带每轮模型配置)
{
"jsonrpc": "2.0",
"id": 3,
"method": "session/prompt",
"params": {
"session_id": "<从步骤2获取>",
"prompt": [
{
"type": "text",
"text": "请分析这段代码的性能瓶颈"
}
],
"_meta": {
"raf": {
"agent_id": "coding",
"model_config": {
"temperature": 0.2,
"max_tokens": 4096,
"thinking": true,
"thinking_level": "high"
}
}
}
}
}
步骤 4:处理流式输出
Host 通过 `session/update` 通知推送流式输出:
// 文本内容
{
"jsonrpc": "2.0",
"method": "session/update",
"params": {
"session_id": "...",
"update": {
"type": "agent_message_chunk",
"content": { "type": "text", "text": "分析结果:" }
},
"_meta": {
"raf.agent_id": "coding",
"raf.status": "executing"
}
}
}
// 思考内容(thinking=true 时)
{
"jsonrpc": "2.0",
"method": "session/update",
"params": {
"session_id": "...",
"update": {
"type": "agent_thought_chunk",
"content": { "type": "text", "text": "首先检查循环复杂度..." }
}
}
}
// 工具调用
{
"jsonrpc": "2.0",
"method": "session/update",
"params": {
"session_id": "...",
"update": {
"type": "tool_call",
"tool_call": {
"id": "call_001",
"title": "read_file",
"status": "pending"
}
}
}
}
步骤 5:接收完成响应
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"stop_reason": "end_turn"
}
}
每轮模型配置详解
配置字段参考
| 字段 | 类型 | 范围 | 说明 | |------|------|------|------| | `temperature` | float | 0.0 - 2.0 | 低值=确定性,高值=创造性 | | `max_tokens` | uint | > 0 | 单轮最大输出 token 数 | | `thinking` | bool | true/false | 是否启用推理模式 | | `thinking_level` | string | "high" / "max" | 推理深度(仅 thinking=true 时) | | `context_window_tokens` | uint | > 0 | 覆盖压缩预算计算 | | `max_output_tokens` | uint | > 0 | 覆盖压缩预算计算 | | `model_id` | string | - | 模型 ID(仅元数据,不切换客户端) |
场景示例
**场景 1:快速问答(低延迟)**
{
"raf": {
"model_config": {
"temperature": 0.1,
"max_tokens": 1024,
"thinking": false
}
}
}
**场景 2:深度代码重构**
{
"raf": {
"model_config": {
"temperature": 0.3,
"max_tokens": 8192,
"thinking": true,
"thinking_level": "high"
}
}
}
**场景 3:最大推理深度(复杂架构设计)**
{
"raf": {
"model_config": {
"temperature": 0.5,
"max_tokens": 16384,
"thinking": true,
"thinking_level": "max"
}
}
}
客户端 UI 建议
IDE 客户端应在聊天窗口中提供模型配置选择器:
┌─────────────────────────────────────────────┐
│ 聊天窗口 [⚙ 配置] │
├─────────────────────────────────────────────┤
│ │
│ [用户]: 请重构这个函数 │
│ │
│ [Agent]: 好的,我来分析... │
│ ┌─ 思考过程 ──────────────────────┐ │
│ │ 首先检查函数复杂度... │ │
│ └──────────────────────────────────┘ │
│ │
├─────────────────────────────────────────────┤
│ [输入消息...] [发送] │
├─────────────────────────────────────────────┤
│ 模型: agnes-2.0-flash | 温度: 0.3 | │
│ 思考: ✓ high | max_tokens: 8192 │
└─────────────────────────────────────────────┘
工作流 Agent 与 HITL
Dev Pipeline 工作流
`dev-pipeline` 是 6 阶段编码工作流,支持人工确认(HITL):
1. **需求分析** → 人工确认需求 2. **测试设计** → 人工确认测试用例 3. **架构设计** → 人工确认架构 4. **任务规划** → 人工确认任务分解 5. **编码实现**(alpha + beta 双路并行) 6. **回归测试 + 审查**
HITL 确认流程
当工作流暂停等待确认时,Host 发送 `session/request_permission`:
{
"jsonrpc": "2.0",
"id": 10,
"method": "session/request_permission",
"params": {
"session_id": "...",
"tool_call": {
"id": "hitl_p1_confirm",
"title": "人工确认 — 节点 p1_confirm",
"status": "pending"
},
"options": [
{
"id": "confirm",
"title": "确认",
"kind": "allow_once"
},
{
"id": "revise",
"title": "提供修改建议",
"kind": "reject_once"
}
],
"_meta": {
"raf.agent_id": "p1_confirm",
"raf.halt_type": "human_confirmation"
}
}
}
客户端响应
**确认**:
{
"jsonrpc": "2.0",
"id": 10,
"result": {
"outcome": {
"type": "selected",
"option_id": "confirm"
}
}
}
**提供修改建议**:
{
"jsonrpc": "2.0",
"id": 10,
"result": {
"outcome": {
"type": "selected",
"option_id": "revise"
},
"_meta": {
"raf": {
"feedback": "请增加对边界条件的处理"
}
}
}
}
标签化流式输出
工作流 Agent 的每个子 Agent 输出都带有 `_meta.raf.agent_id` 标签,客户端可据此渲染多 Agent 视图:
{
"method": "session/update",
"params": {
"session_id": "...",
"update": { "type": "agent_message_chunk", "content": { "text": "需求分析完成" } },
"_meta": {
"raf.agent_id": "requirements-analyst",
"raf.status": "executing"
}
}
}
客户端可根据 `raf.agent_id` 将输出路由到不同的 UI 区域:
┌─ requirements-analyst ─────────┐
│ 需求分析完成 │
└────────────────────────────────┘
┌─ test-designer ────────────────┐
│ 正在设计测试用例... │
└────────────────────────────────┘
取消会话
{
"jsonrpc": "2.0",
"method": "session/cancel",
"params": {
"session_id": "..."
}
}
Host 会设置取消令牌,Agent 在下一个工具循环迭代时中断。
错误处理
Agent 未找到
如果 `_meta.raf.agent_id` 指定的 Agent 不存在,Host 返回空响应:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"stop_reason": "end_turn"
}
}
(日志中会记录 `warn: Agent not found`)
模型配置解析失败
如果 `_meta.raf.model_config` 格式错误,Host 静默回退到默认配置(日志中记录 debug 信息)。
完整客户端示例
以下是一个完整的 TypeScript 客户端示例:
interface AcpClient {
initialize(): Promise<AgentList>;
createSession(agentId?: string): Promise<string>;
prompt(
sessionId: string,
message: string,
modelConfig?: ModelConfig
): AsyncIterator<SessionUpdate>;
cancel(sessionId: string): Promise<void>;
}
interface ModelConfig {
temperature?: number;
max_tokens?: number;
thinking?: boolean;
thinking_level?: 'high' | 'max';
}
class RustAgentHostClient implements AcpClient {
private nextId = 1;
constructor(private transport: JsonRpcTransport) {}
async initialize(): Promise<AgentList> {
const response = await this.transport.request('initialize', {
protocol_version: '0.14'
});
return response._meta?.raf?.agents ?? [];
}
async createSession(agentId?: string): Promise<string> {
const params: any = {};
if (agentId) {
params._meta = { raf: { agent_id: agentId } };
}
const response = await this.transport.request('session/new', params);
return response.session_id;
}
async *prompt(
sessionId: string,
message: string,
modelConfig?: ModelConfig
): AsyncIterator<SessionUpdate> {
const meta: any = {};
if (modelConfig) {
meta.raf = { model_config: modelConfig };
}
const promptId = this.nextId++;
const updates = this.transport.sendNotificationAndListen(
'session/prompt',
{
session_id: sessionId,
prompt: [{ type: 'text', text: message }],
_meta: meta
},
promptId
);
for await (const update of updates) {
yield update;
if (update.stop_reason) break;
}
}
async cancel(sessionId: string): Promise<void> {
await this.transport.sendNotification('session/cancel', {
session_id: sessionId
});
}
}
// 使用示例
async function main() {
const transport = new StdioTransport('cargo run -p rust-agent-host -- --mode stdio');
const client = new RustAgentHostClient(transport);
// 1. 初始化
const agents = await client.initialize();
console.log('可用 Agent:', agents);
// 2. 创建会话
const sessionId = await client.createSession('coding');
// 3. 发送提示(带每轮模型配置)
const stream = client.prompt(
sessionId,
'请重构这个函数',
{
temperature: 0.3,
max_tokens: 8192,
thinking: true,
thinking_level: 'high'
}
);
// 4. 处理流式输出
for await (const update of stream) {
if (update.type === 'agent_message_chunk') {
process.stdout.write(update.content.text);
} else if (update.type === 'agent_thought_chunk') {
// 渲染思考内容
console.log('\n[思考]', update.content.text);
} else if (update.type === 'tool_call') {
console.log('\n[工具调用]', update.tool_call.title);
}
}
}
下一步
- [14.1 Host Service 概述](overview.md) - [14.2 ACP 协议与消息格式](acp-protocol.md) - [14.3 传输层](transports.md) - [14.7 IDE 集成与每轮模型配置](ide-integration.md)