回调函数
Agent中使用钩子函数
在钩子函数中可以使用以下的函数或是对象来实现回调函数:
在回调函数中,有以下的全局对象:
- __yao_agent_global,全局对象
- assistant,全局对象,助手对象
- context,全局对象,上下文对象
- Send,向前端发送信息的函数
- Assets,读取资源对象
- MakeCall,调用其它助手函数
- MakePlan,创建计划组件函数
- Set,全局对象设置函数
- Get,全局对象获取函数
- Clear,全局对象清除函数
- Replace,替换字符串中占位符函数
__yao_agent_global,全局对象
此对象主要是用于脚本内部进行脚本传递引用对象。
js
global := &GlobalVariables{
Assistant: ast,
Contents: contents,
GinContext: c,
ChatContext: context,
}
全局函数
Send
Send函数用于发送消息到前端。
js
/**
* Send 发送消息到前端
* @param msg 消息文本或是消息对象
* @param save 是否保存到历史记录中
*/
function Send(message: string | object,save?: boolean): void;
示例
在前端调用action。
前端支持的组件类型:
- guide,支持弹出框等用户交互
- text,支持文本消息
- page,嵌入iframe网页
- plan,计划组件
- tool,工具组件
- think,思考组件
- loading,显示正在加载
- error,显示错误信息
在前端使用iframe显示页面。
ts
Send(
{
text: '',
type: 'page', //page类型,显示一个网页
props: {
url: `/https://wttr.in/${lastLine.props['arguments']['location']}`
},
done: true //结束消息
},
true //是否保存到历史记录中
);
在前端使用guide组件显示交互信息。
ts
Send(
{
text: markdown, //markdown格式的文本
type: 'guide',
done: true,
props: {
title: '用户信息',
actions: [
{
namespace: context.pathname,
primary: 'id',
title: '用户信息',
action: [
{
type: 'Common.confirm',
payload: {
title: '测试',
content: '测试'
}
}
],
name: 'user_info',
icon: 'icon-book',
data_item: {
title: '用户信息',
description: '用户信息',
icon: 'icon-book',
action: 'Common.refresh'
}
}
]
}
},
false
);
Assets
Assets函数用于获取资源对象。读取助手assets目录下的资源文件。
js
/**
* Assets 获取资源对象
* @param name assets 目录下的文件名称,一般是文本文件。
* @param data 资源对象 用于替换资源对象中中的对象。占位符为{{ xxx }}
* @returns 资源对象
*/
function Assets(name:string,data:{}): string;
Replace
使用对象,替换模板中的占位符,返回替换后的字符串。
ts
/**
* Replace 替换全局变量,占位符为{{ xxx }}
* @param template 模板字符串
* @param value 对象值
*/
function Replace(template: string, value: object): string;
MakeCall功能
在hook钩子函数中调用其它助手,并传入回调函数。
注意: 不要调用同一个助手对象,否则会触发同一个Done钩子函数,最后出现死循环。
js
//make a call
const call1 = MakeCall(
assistant.assistant_id, //助手ID
'你好,编写一个笑话', //用户输入,一般是用户的提问
{
options: {
//调用聊天模型时的选项,比如temperature,top_p等参数
max_tokens: 8192,
temperature: 0.7,
top_p: 1
}
},
1 //retry_times,重试次数
);
// 配置完成事件回调
call1.On('done', (msg) => {
console.log('done event triggered');
console.log(msg);
});
// 配置流式消息回调
call1.On('message', (msg) => {
console.log('message event triggered');
console.log(msg);
});
// 调用并返回结果
const result = call1.Run();
console.log('result:');
console.log(result);
MakePlan
创建一个Plan对象。
ts
/**
* MakePlan 创建一个计划对象
* @param planId 计划ID
* @returns 计划对象
*/
function MakePlan(planId: string): Plan;
多个助手调用的数据共享
在Hook钩子函数处理过程中,如果需要共享数据,可以使用Context上下文本中的一个共享内存空间。
这个内容共享功能是在api的调用过程中自动创建的,所有在一个请求过程中所的助手都能引用。
Set
在全局的Plan共享内存空间使用Key设置对象值。
ts
/**
* Set 设置全局变量
* @param key 全局变量键
* @param value 全局变量值
*/
function Set(key: string, value: any): void;
Get
根据Key获取全局的Plan共享内存空间。
ts
/**
* Get 获取全局变量
* @param key 全局变量键
* @returns 全局变量值
*/
function Get(key: string): any;
Del
根据Key删除全局的Plan共享内存空间。
ts
/**
* Del 删除全局变量
* @param key 全局变量键
*/
function Del(key: string): void;
Clear
清空全局的Plan共享内存空间。
ts
/**
* Clear 清除全局变量
*/
function Clear(): void;
Done钩子函数功能
自定义Tool工具函数
ts
/**
* called only once, when the call openai api done,open ai return messages
*
* @param input input messages
* @param output messages
* @returns
*/
export function Done(
input: neo.ChatMessage[], //用户输入的消息,包含历史消息
output: neo.ChatMessage[] //AI返回的消息
): any | null | string {
// console.log('__yao_agent_global');
// console.log(__yao_agent_global);
// console.log('context');
// console.log(context);
console.log('output');
console.log(output); //ai返回的消息
// 解析ai function call回调函数
if (
output.length > 0 &&
output[output.length - 1].props != null &&
output[output.length - 1].props['function'] !== '' //通过props['function']判断是否是自定义的函数调用
) {
const lastLine = output[output.length - 1];
const funcName = lastLine.props['function']; //获取函数名
if (funcName == 'get_weather') {
// 使用Send函数给用户发送消息
Send(
{
text: '',
type: 'page', //page类型,显示一个网页
props: {
url: `/https://wttr.in/${lastLine.props['arguments']['location']}` //解析参数,参考tools.yao配置文件中的参数
},
done: true //结束消息
},
true //是否保存到历史记录中
);
// 如果不使用Send,使用以下的方式返回消息到前端,但是这里无法保存到历史记录中
return {
output: [
{
text: '完成...',
type: 'text'
}
]
};
} else if (funcName == 'find_user') {
const [user] = new ModelProxy<IAdminUser>('admin.user').Get({
wheres: [
{
column: 'name',
op: 'like',
value: `%${lastLine.props['arguments']['username']}%`
}
]
});
if (user) {
// 将用户数据转换为markdown格式输出
const markdown = `## 用户信息
\`\`\`json
${JSON.stringify(user, null, 2)}
\`\`\``;
Send(
{
text: markdown, //使用text类型,可以在前端显示消息
type: 'guide', //使用guide类型,可以在前端显示消息,并且在前端使用action进行用户交互。
done: true,
props: {
//使用props配置前端actions
title: '用户信息',
actions: [
{
namespace: context.pathname,
primary: 'id',
title: '用户信息',
action: [
{
type: 'Common.confirm',
payload: {
title: '测试',
content: '测试'
}
}
],
name: 'user_info',
icon: 'icon-book',
data_item: {
title: '用户信息',
description: '用户信息',
icon: 'icon-book',
action: 'Common.refresh'
}
}
]
}
},
false //是否保存到历史记录中
);
return null;
} else {
return {
output: [{ text: '用户不存在' }] as neo.ChatMessage[]
};
}
}
return {
output: [
{ text: '错误的调用,不支持的函数调用:' + funcName }
] as neo.ChatMessage[]
};
}
}
对象说明
ts
/**
* 创建并返回一个计划对象
* @param planId 计划ID
* @returns 计划对象
*/
export declare function Plan(planId:string): Plan;
type Method:string;//同一个脚本中的方法名称
type Process:string;//yao处理器
type Callback {//yao处理器回调,同时配置回调函数名和回调函数参数
name:string;
args:any[];
}
/**
* 回调助手,并传入回调函数
* @param assistantId 助手ID
* @param input 输入,常用的是用户的提问。
* @param callback 回调函数,接收4种类型的参数
* 1. Function: 普通函数
* 2. Callback: 对象,对象的name属性为回调函数名,args属性为回调函数参数
* 3. Method: 方法,当前脚本中的方法名称
* 4. Process: 处理器,调用其它处理器,处理器名称需要包含"."
* @options 选项,调用聊天模型时的选项,比如temperature,top_p等参数
*/
export declare function Call(assistantId:string,input:string,callback:null|Function|Callback|Method|Process,options:{[key:string]:any}): void;
Message类型定义
ts
/**
* Message 消息对象
*/
interface Message {
/** 消息ID */
id?: string;
/** 文本内容 */
text?: string;
/** 消息类型: error, text, plan, table, form, page, file, video, audio, image, markdown, json等 */
type?: string;
/** 类型相关的属性 */
props?: Record<string, any>;
/** 标记消息是否完成 */
done?: boolean;
/** 标记是否为新消息 */
new?: boolean;
/** 标记是否为增量消息 */
delta?: boolean;
/** 会话动作列表 */
actions?: Action[];
/** 文件附件列表 */
attachments?: Attachment[];
/** 消息角色: user, assistant, system等 */
role?: string;
/** 消息名称 */
name?: string;
/** 助手ID (当role为assistant时) */
assistant_id?: string;
/** 助手名称 (当role为assistant时) */
assistant_name?: string;
/** 助手头像 (当role为assistant时) */
assistant_avatar?: string;
/** 消息提及列表 (当role为user时) */
mentions?: Mention[];
/** 消息数据 */
data?: Record<string, any>;
/** 消息是否待处理 */
pending?: boolean;
/** 消息是否隐藏 (不在UI和历史记录中显示) */
hidden?: boolean;
/** 消息是否需要重试 */
retry?: boolean;
/** 消息是否静默 (不在UI和历史记录中显示) */
silent?: boolean;
/** 工具调用ID */
tool_call_id?: string;
/** 函数调用列表 */
tool_calls?: FunctionCall[];
}
/**
* 提及对象
*/
interface Mention {
/** 助手ID */
assistant_id: string;
/** 名称 */
name: string;
/** 头像 */
avatar?: string;
}
/**
* 附件对象
*/
interface Attachment {
/** 文件名 */
name?: string;
/** 文件URL */
url?: string;
/** 文件描述 */
description?: string;
/** 文件类型 */
type?: string;
/** 内容类型 */
content_type?: string;
/** 文件大小(字节) */
bytes?: number;
/** 创建时间戳 */
created_at?: number;
/** 文件ID */
file_id?: string;
/** 会话ID */
chat_id?: string;
/** 助手ID */
assistant_id?: string;
}
/**
* 动作对象
*/
interface Action {
/** 动作名称 */
name?: string;
/** 动作类型 */
type: string;
/** 动作载荷 */
payload?: any;
}
回调函数示例:
ts
/**
* 示例回调函数
* @param msg 消息对象
* @param args 其他参数,如果使用处理器定义,则args为处理器定义的参数
*/
function exampleCallback(msg: Message,..args:any[]) {
console.log('收到消息:', msg.Text);
}
/**
* 使用回调函数的示例
*/
function useCallbackExample() {
// 使用普通函数作为回调
Call('neo', '你好', exampleCallback);
// 使用对象形式的回调
Call('neo', '你好', {
name: 'exampleCallback',
args: [] // 如果回调函数不需要参数,可以留空数组
});
// 使用当前脚本中的方法作为回调
Call('neo', '你好', 'exampleCallback');
// 使用处理器作为回调
Call('neo', '你好', '处理器名称.方法名称');
}
测试
js
function callback(msg:) {}
function test() {
Call('neo', '你好', 'callback');
Call('neo', '你好', function () {
console.log('回调函数');
});
}