Oopenvela-robotfeat:ai_conversation
a9fed717创建于 4月20日历史提交

AI Chat Demo 插件开发指南

1. 概述

欢迎大家想基于此 demo 开发自己的 ai 服务,可以遵循 plugin 接口的标准来自己实现demo

1.1 架构说明

ai_conversation (核心层)
    ↓
conversation_plugin (插件管理层)
    ↓
volc_plugin / custom_plugin (具体服务实现)

1.2 核心概念

- 插件接口: `conversation_engine_plugin_t` 定义了所有插件必须实现的标准接口

- 事件回调: 通过 `conversation_engine_callback_t` 向上层传递对话事件

- MCP 工具: 支持函数调用,扩展 AI 能力


2. 插件接口规范

2.1 插件结构

typedef struct conversation_engine_plugin_s {
    const char* name;                          // 插件名称
    int priv_size;                             // 私有数据大小
    int (*init)(void* engine, const conversation_engine_init_params_t* param);
    int (*uninit)(void* engine);
    int (*event_cb)(void* engine, conversation_engine_callback_t callback, void* cookie);
    int (*start)(void* engine);
    int (*write_audio)(void* engine, const char* data, int len);
    int (*finish)(void* engine);
    int (*cancel)(void* engine);
    int (*mcp_response)(void* engine, char* result);
    conversation_engine_env_params_t* (*get_env)(void* engine);
} conversation_engine_plugin_t;

2.2 必须实现的函数

函数 说明 返回值
init 初始化插件,建立连接 0 成功,负数失败
uninit 清理资源,断开连接 0 成功,负数失败
event_cb 设置事件回调函数 0 成功,负数失败
start 开始对话,准备接收音频 0 成功,负数失败
write_audio 写入音频数据 0 成功,负数失败
finish 结束音频输入,等待响应 0 成功,负数失败
cancel 取消当前对话 0 成功,负数失败
mcp_response 返回 MCP 工具执行结果 0 成功,负数失败
get_env 获取环境参数 环境参数指针

3. 开发步骤

3.1 创建插件目录结构

src/conversation/
├── plugin/                    # 插件框架(已存在)
│   ├── ai_conversation_plugin.h
│   ├── ai_conversation_plugin.c
│   └── ai_conversation_defs.h
└── your_service/              # 你的服务插件目录
    ├── ai_your_service_conversation.c
    └── ai_your_service_conversation.h

3.2 定义插件实例

conversation_engine_plugin_t your_service_conversation_engine_plugin = {
    .name = "your_service_conversation",
    .priv_size = sizeof(your_service_conversation_engine_t),
    .init = your_service_init,
    .uninit = your_service_uninit,
    .event_cb = your_service_event_cb,
    .start = your_service_start,
    .write_audio = your_service_write_audio,
    .finish = your_service_finish,
    .cancel = your_service_cancel,
    .mcp_response = your_service_mcp_response,
    .get_env = your_service_get_env,
};

4. 事件处理

4.1 事件类型

typedef enum {
    conversation_engine_event_unknown,
    conversation_engine_event_start,           // 对话开始
    conversation_engine_event_stop,            // 对话停止
    conversation_engine_event_complete,        // 对话完成
    conversation_engine_event_input_text,      // 输入文本
    conversation_engine_event_audio_start,     // 音频开始
    conversation_engine_event_audio,           // 音频数据
    conversation_engine_event_text,            // 文本响应
    conversation_engine_event_mcp_call,        // MCP 工具调用
    conversation_engine_event_mcp_argument,    // MCP 参数
    conversation_engine_event_error,           // 错误事件
} conversation_engine_event_t;

4.2 触发事件回调

static void your_service_send_event(your_service_conversation_engine_t* engine,
                                   conversation_engine_event_t event,
                                   const char* result, int len,
                                   conversation_engine_error_t error_code)
{
    if (engine->event_callback) {
        conversation_engine_result_t res = {
            .result = result,
            .len = len,
            .error_code = error_code
        };
        engine->event_callback(event, &res, engine->event_cookie);
    }
}

4.3 处理服务响应

当你的服务返回响应时,需要根据响应类型触发相应的事件:

// 处理文本响应
void your_service_handle_text_response(your_service_conversation_engine_t* engine, 
                                       const char* text)
{
    your_service_send_event(engine, conversation_engine_event_text, 
                           text, strlen(text), conversation_engine_error_success);
}

// 处理音频响应
void your_service_handle_audio_response(your_service_conversation_engine_t* engine,
                                        const char* audio_data, int len)
{
    your_service_send_event(engine, conversation_engine_event_audio_start, 
                           NULL, 0, conversation_engine_error_success);
    your_service_send_event(engine, conversation_engine_event_audio, 
                           audio_data, len, conversation_engine_error_success);
}

// 处理 MCP 工具调用
void your_service_handle_mcp_call(your_service_conversation_engine_t* engine,
                                  const char* tool_name, const char* call_id,
                                  const char* arguments)
{
    // 保存工具调用信息
    if (engine->call_tool_name) free(engine->call_tool_name);
    if (engine->call_tool_id) free(engine->call_tool_id);
    
    engine->call_tool_name = strdup(tool_name);
    engine->call_tool_id = strdup(call_id);
    
    // 触发 MCP 调用事件
    char* mcp_data = malloc(strlen(tool_name) + strlen(call_id) + strlen(arguments) + 3);
    sprintf(mcp_data, "%s|%s|%s", tool_name, call_id, arguments);
    
    your_service_send_event(engine, conversation_engine_event_mcp_call,
                           mcp_data, strlen(mcp_data), conversation_engine_error_success);
    
    free(mcp_data);
}

5. 注册插件

5.1 在 ai_conversation.c 中注册

// 在 ai_conversation.c 顶部添加
extern conversation_engine_plugin_t your_service_conversation_engine_plugin;

// 在 ai_conversation_create_engine 函数中添加插件选择逻辑
conversation_handle_t ai_conversation_create_engine(const conversation_init_params_t* param)
{
    conversation_engine_plugin_t* plugin = NULL;
    
    switch (param->engine_type) {
        case CONVERSATION_ENGINE_TYPE_VOLC:
            plugin = &volc_conversation_engine_plugin;
            break;
        case CONVERSATION_ENGINE_TYPE_YOUR_SERVICE:  // 新增
            plugin = &your_service_conversation_engine_plugin;
            break;
        default:
            CON_ERR("Unknown engine type: %d", param->engine_type);
            return NULL;
    }
    
    // ... 其余代码
}

5.2 在 ai_conversation.h 中添加枚举

typedef enum {
    CONVERSATION_ENGINE_TYPE_VOLC,
    CONVERSATION_ENGINE_TYPE_YOUR_SERVICE,  // 新增
} conversation_engine_type;

6. 配置与编译

6.1 添加 Kconfig 选项

config AI_YOUR_SERVICE_PLUGIN
    bool "Your service plugin"
    depends on AI_CONVERSATION_DEMO
    default n
    help
      Enable your custom AI service plugin

config YOUR_SERVICE_API_KEY
    string "Your service API key"
    depends on AI_YOUR_SERVICE_PLUGIN
    default "YOUR_API_KEY"
    help
      API key for your service

config YOUR_SERVICE_API_URL
    string "Your service API URL"
    depends on AI_YOUR_SERVICE_PLUGIN
    default "https://api.yourservice.com"
    help
      API endpoint URL for your service

6.2 修改 Makefile

ifeq ($(CONFIG_AI_YOUR_SERVICE_PLUGIN),y)
  CSRCS += conversation/your_service/ai_your_service_conversation.c
endif

7. 参考示例

完整的火山服务插件实现位于:

  • src/conversation/volc/ai_volc_conversation.c

  • src/conversation/volc/ai_volc_conversation.h

建议开发者参考该实现,理解插件接口的使用方式和最佳实践。


8. 附录

8.1 完整示例代码

参见 src/conversation/volc/ 目录下的火山服务插件实现。

8.2 接口头文件

  • include/ai_conversation.h - 对话引擎公共接口

  • src/conversation/plugin/ai_conversation_plugin.h - 插件接口定义

  • src/conversation/plugin/ai_conversation_defs.h - 插件相关类型定义

9. 快速开始

9.1 最小化插件模板

// ai_minimal_conversation.c

#include "ai_conversation_plugin.h"
#include "ai_log.h"

typedef struct {
    conversation_engine_callback_t event_callback;
    void* event_cookie;
    conversation_engine_init_params_t config;
    conversation_engine_env_params_t env;
} minimal_engine_t;

static int minimal_init(void* engine, const conversation_engine_init_params_t* param)
{
    CON_INFO("Minimal plugin initialized");
    return 0;
}

static int minimal_uninit(void* engine)
{
    CON_INFO("Minimal plugin uninitialized");
    return 0;
}

static int minimal_event_cb(void* engine, conversation_engine_callback_t callback, void* cookie)
{
    CON_INFO("Minimal plugin minimal_event_cb");
    return 0;
}

static int minimal_start(void* engine)
{
    CON_INFO("Minimal plugin start");
    return 0;
}

static int minimal_write_audio(void* engine, const char* data, int len)
{
    // 处理音频数据
    return 0;
}

static int minimal_finish(void* engine)
{
    CON_INFO("Minimal plugin finish");
    return 0;
}

static int minimal_cancel(void* engine)
{
    return 0;
}

static int minimal_mcp_response(void* engine, char* result)
{
    return 0;
}

static conversation_engine_env_params_t* minimal_get_env(void* engine)
{
    minimal_engine_t* e = (minimal_engine_t*)engine;
    return &e->env;
}

conversation_engine_plugin_t minimal_conversation_engine_plugin = {
    .name = "minimal_conversation",
    .priv_size = sizeof(minimal_engine_t),
    .init = minimal_init,
    .uninit = minimal_uninit,
    .event_cb = minimal_event_cb,
    .start = minimal_start,
    .write_audio = minimal_write_audio,
    .finish = minimal_finish,
    .cancel = minimal_cancel,
    .mcp_response = minimal_mcp_response,
    .get_env = minimal_get_env,
};