配置智能体

最近更新时间:2025-03-11 18:19:32

我的收藏

前提条件

说明:
配置智能体前,您需要先创建智能体并为其部署服务访问地址,具体操作请参见 自定义服务接入智能体
已创建智能体。
已为智能体部署服务访问地址。

智能体定义字典

上下文变量 ContextVariable

定义结构:
/**
* 上下文变量对象
* 每一种上下文对象对应一种具体数据结构
*/
interface ContextVariable{
// 上下文类型,全局唯一,决定 value 的数据结构
name: string
// 上下文解析器参数,Agent 发布时定义,Client 可根据此策略调整上下文收集细节,如文本截取长度等
resolverOptions: any;
}
用户自定义 prompt:
name:userInputPrompt
描述:用户对话时手动输入的原始内容。
解析参数:无
采集结果:
interface UserInputPromptContextVariable{
name: "userInputPrompt";
value: string;
}
用户信息:
name:userInfo
描述:当前用户相关信息。
解析参数:无
采集结果:
interface UserInfoContextVariable{
name: "userInfo";
value: {
id: string; // 用户 ID
name: string; // 用户英文名
nickname: string; // 用户昵称
}
}
工作空间版本控制信息:
name:vcs
描述:当前工作空间对应的版本控制信息。
解析参数:无
采集结果:
interface VCSContextVariable{
name: "vcs";
value: {
type: string; // vcs 类型,如 git
branchName: string; // 分支名
upstreamBranchName: string; // 远端分支名
remoteUrl: string; // 远端仓库地址
remotes: string[]; // 远端仓库列表
}
}
知识库:
name:knowledgeBase
描述:知识库列表。
解析参数:
interface KnowledgeBaseResolverOptions{
knowledgeBaseIds?: string[]; // 目标知识库 id 列表
recallByAgent?: boolean; // 是否由 Agent 执行召回,为 false 时,由客户端执行召回动作,此时上报的上下文中应包含 references 属性内容
}
采集结果:
interface KnowledgeBaseContextVariable{
name: "knowledgeBase";
value: {
knowledgeBaseId: string; // 知识库 id
references?: {
score: number; // 检索得分
chunk: string; // 句向量对应的文本块
metadata: {
fileName: string; // 文件名称,例如:/指南/开发指南.md
sourceType: 'doc' | 'code'; // 文件类型 doc or code
source: string; // 文件来源,例如:/home/xxx/xxx.py 或者 github.com/xxx/xxx/xxx/xxx.py
startPos?: number; // chunk 开始行号(可为空)
endPos?: number; // chunk 结束行号(可为空)
};
}[]
}[];
}
激活的编辑器内容:
name:activeEditor
描述:激活的编辑器内容。
解析参数:
interface ActiveEditorResolverOptions{
contentBeforeSelectionLines?: number; // 选区前文本行数,为空时不获取,为0时仅获取当前行选区前的内容
contentAfterSelectionLines?: number; // 选区后文本行数,为空时不获取,为0时仅获取当前行选区后的内容
}
采集结果:
interface ActiveEditorContextVariable{
name: "activeEditor";
value: {
filePath: string; // 文件路径
language: string; // 内容语言:java/javascript/...
content: string; // 文件内容
cursorOffset: number; // 光标位置,从0开始
startLine: number; // 起始行,从1开始
startColumn: number; // 起始列,从1开始
endLine: number; // 结束行,从1开始
endColumn: number; // 结束列,从1开始
selectedRanges: {
content: string; // 选中文件内容
startLine: number; // 起始行,从1开始
startColumn: number; // 起始列,从1开始
endLine: number; // 结束行,从1开始
endColumn: number; // 结束列,从1开始
contentBeforeSelection?: string; // 选区前文本
contentAfterSelection?: string; // 选区后文本
}[];
visibleRange: {
content: string; // 可视区文件内容
startLine: number; // 起始行,从1开始
startColumn: number; // 起始列,从1开始
endLine: number; // 结束行,从1开始
endColumn: number; // 结束列,从1开始
}
};
}
全局提示词:
name:globalPrompts
描述:全局提示词,作为限定规则置于用户问题之前。
解析参数:无
采集结果:
interface GlobalPromptsContextVariable{
name: "globalPrompts";
value: {
role: string; // 角色
content: string; // 全局提示词内容
}[];
}
包管理文件:
name:packageFiles
描述:项目包管理文件列表。
解析参数:
interface PackageFilesResolverOptions{
maximumNumber: number; // 最大文件个数
}
采集结果:
interface PackageFilesContextVariable{
name: "packageFiles";
value: [{
filepath: string; // 文件本地路径
content: string; // 文件内容
}];
}

交互动作 Action

支持确认按钮树状结构两种交互动作的智能体下发。
确认按钮
树状结构
interface ConfirmAction{
action: "confirm";
state: any;
data: {
title: string; // 按钮文本
message: string; // 描述信息
command?: string; // 可选,有值时以此 command 发起标准 Agent 对话请求,不再发送 Action 反馈请求
prompt?: string; // 可选,有值时以此 prompt 发起标准 Agent 对话请求,不再发送 Action 反馈请求
}
}
interface TreeAction{
action: "tree";
state: any;
data: {
treeId: string;// 树 ID,agent 下唯一
rootPId: string; // 根节点的父 ID
// 树节点列表
nodes : {
id: string; // 节点 ID
pId: string; // 父节点 ID
type: string; // 节点类型
name: string; // 节点名称
description: string;// 描述
labels : string[];// 标签列表
}[];
// 树节点支持的操作列表
nodeActions: {
nodeType: string; // 树节点类型
nodeAction : "expand" | "click"; // 树节点操作类型,展开、点击
command?: string; // 可选,有值时以此 command 发起标准 Agent 对话请求,不再发送 Action 反馈请求
prompt?: string; // 可选,有值时以此 prompt 发起标准 Agent 对话请求,不再发送 Action 反馈请求
promptByNodeProperty?: string; // 可选,有值时以此 node 的某个属性发起标准 Agent 对话请求,不再发送 Action 反馈请求
}[];
}
}

示例

智能体服务的实现不限语言,下面以 javascript 为例,实现智能体接收请求、处理参数、请求对话模型、响应数据的过程。
const http = require('http');

// 创建HTTP服务器
const server = http.createServer(async (req, res) => {
const {
agent, // agent 名称
command, // command 名称
agentDefinition, // agent 原始定义
contextVariables // 上下文变量列表
} = await parseBody(req);
// 从请求中获取body
console.log('agent:', agent);
console.log('command:', command);
// 获取上下文信息
const userInfo = contextVariables?.find(ctx => ctx.name === 'userInfo') || {};

// 设置响应头,指定内容类型为 text/event-stream,这是 SSE 所需的
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');

// 生成消息ID,在一次响应中需要保持唯一
const messageId = Date.now();

// 根据 command 执行不同业务
if (command == 'default') {
// 默认指令推送欢迎信息文本
res.write(createMessageChunk(messageId, `你好,${userInfo.value?.nickname} !\\n`));
res.write(createMessageChunk(messageId, `欢迎访问 Agent hello !`));
// 推送一个交互按钮 action
res.write(
createActionChunk(
'confirm',
{},
{
title: '获取版本号',
command: 'version',
prompt: ''
}
)
);
// 发送响应数据结束标识
res.write(`data: [Done]\\n`);
// 结束响应
res.end();
} else if (command == 'version') {
// 版本指令返回版本信息
res.write(createMessageChunk(messageId, `当前版本是 v1.0.0 \\n`));
// 发送响应数据结束标识
res.write(`data: [Done]\\n`);
// 结束响应
res.end();
} else if (command == 'xxx') {
// 如果是 xxx 指令,则发起对话请求
// 获取配置的消息模版
const messageTemplates = getMessageTemplates(command, agentDefinition);
// 根据消息模板和上下文变量列表,拼装 prompt 消息列表
const messages = [{
role : 'system',
content : 'xxxxx'
},{
role : 'user',
content : 'xxxxx'
}];
const baseRequestConfig = {
headers: cropHeadersreq.headers), // 复用原请求头中的认证信息
responseType: 'stream',
timeout: 180 * 1000,
};

const payload = {
...req.body, // 附加原请求中的其他参数
contextVariables: null, // 移除
messageTemplates: null, // 移除
agentDefinition: null, // 移除
modelConfiguration: null, // 移除
messages, // 处理后的消息列表
stream: true, // 流式
};

// 请求平台的模型对话接口
const fetcher = axios.create({
baseURL: CPILOT_SERVER_ENDPOINT, // 平台 API 地址
timeout: 3000 * 1000,
});
const { stream, headers } = await fetcher.post('/chat/completions', payload, baseRequestConfig);
// 直接将请求返回的 res 对接 pipe 给客户端响应输出流中
res.writeHead(200);
stream.pipe(res);
}
});

// 创建一个文本消息 chunk
function createMessageChunk(id, content) {
const msg = JSON.stringify({
id: id,
model: 'happy',
object: '',
created: Date.now() / 1000,
choices: [{ index: 0, delta: { role: 'assistant', content: content }, logprobs: null, finish_reason: '' }],
usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 }
});
return `data: ${msg}\\n\\n`;
}

// 创建一个 action chunk
function createActionChunk(action, state, data) {
const msg = JSON.stringify({
action,
state,
data
});
return `event: copilot_action\\ndata: ${msg}\\n\\n`;
}

// 解析请求体
async function parseBody(req) {
return new Promise((resolve, reject) => {
let body = '';
req.on('data', chunk => {
body += chunk.toString();
});
req.on('end', () => {
if (req.headers['content-type'] === 'application/json') {
try {
const data = JSON.parse(body);
resolve(data); // 这里可以访问到解析后的 JSON 数据
} catch (error) {
reject(error);
}
} else {
reject(new Error('content-type error'));
}
});
});
}

// 从 agent 定义中获取配置的消息模板
function getMessageTemplates(command, agent) {
const messageTemplates = [];
agent?.commands?.find(commandDefinition => {
if (commandDefinition.name === command) {
messageTemplates.push(...commandDefinition?.messageTemplates);
}
});
return messageTemplates;
}

// 复制原请求头
function cropHeaders(headers) {
const croppedHeaders = JSON.parse(JSON.stringify(headers));
delete croppedHeaders['Host'];
delete croppedHeaders['Host'.toLowerCase()];
delete croppedHeaders['Content-Length'];
delete croppedHeaders['Content-Length'.toLowerCase()];
return croppedHeaders;
}

// 监听端口
const PORT = 18080;
server.listen(PORT, () => {
console.log(`Server is running at http://localhost:${PORT}`);
});