CangjieMagic框架:使用华为仓颉编程语言编写,专门用于开发AI Agent,支持鸿蒙、Windows、macOS、Linux等系统。
这篇文章剖析一下 CangjieMagic 框架中的 NaiveExecutor。
1 NaiveExecutor是什么?
提问 使用 发送请求 返回回答 返回结果 回答 用户 Agent NaiveExecutor 大语言模型
NaiveExecutor是一种简单直接的执行器,它的工作方式就像我们直接问一个人问题,然后等待回答一样简单。没有复杂的思考过程,没有繁琐的工具调用,就是"问一嘴,答一句"。
举个例子:当你问朋友"今天天气怎么样?",朋友直接看看窗外说"今天天气晴朗"。这就是NaiveExecutor的工作方式!
2 NaiveExecutor的提示词模板
先来看看这个执行器使用的提示词模板:
cangjie
private let NAIVE_PROMPT = """
{systemPrompt}
{retrieval}
{memory}
{dialog}
"""
这个模板就像我们做菜的配方,分为四个部分:
- systemPrompt:相当于告诉厨师"你要做一道什么菜"
- retrieval:相当于提供菜谱和参考资料
- memory:相当于厨师的经验和记忆
- dialog:相当于之前的交流和反馈
举个生活例子:当你去理发店时,你会告诉理发师你想要什么发型(systemPrompt),可能会出示一张照片作参考(retrieval),理发师会记得你上次的喜好(memory),然后你们还会讨论细节(dialog)。
3 构建完整提示词的过程
发送给 系统提示 完整提示词 检索内容 记忆内容 对话历史 大语言模型
让我们看看getFullSystemPrompt
成员函数是如何工作的:
cangjie
private func getFullSystemPrompt(task: AgentTask): String {
// The system prompt of a naive agent may be empty
let sysPrompt = if (task.agent.systemPrompt != "") {
task.agent.systemPrompt
} else {
"Answer user question"
}
return NAIVE_PROMPT.format(
("retrieval", ReactPromptUtils.buildAgentRetrievalPrompt(task)),
("systemPrompt", sysPrompt),
("memory", ReactPromptUtils.buildAgentMemoryPrompt(task)),
("dialog", ReactPromptUtils.buildAgentDialogPrompt(task))
)
}
这段代码做了什么呢?想象你在教一个孩子回答问题:
- 首先,你会告诉孩子他的角色:"你现在是一名小老师"(系统提示)
- 如果没有特别说明角色,就简单地说:"请回答问题"
- 然后你可能会给孩子一本参考书(检索内容)
- 提醒孩子之前学过的知识(记忆内容)
- 告诉孩子提问者之前问了什么(对话历史)
这样,孩子就有了完整的上下文,可以开始回答问题了!
4 同步执行过程详解
用户 NaiveExecutor Agent 大语言模型 提出问题 创建任务对象 构建完整提示词 发送请求 返回回答 返回结果 用户 NaiveExecutor Agent 大语言模型
现在来看看run
成员函数的实现:
cangjie
override public func run(agent: Agent, request: AgentRequest): AgentResponse {
let task = AgentTask(agent, request)
let dialog = task.execInfo.dialog
LogUtils.info("${agent.name} runs")
dialog.addMessage([
ChatMessage.system(getFullSystemPrompt(task)),
ChatMessage.user(request.question)
])
LogUtils.info(agent.name, dialog)
let assistantMsg = ModelUtils.makeChat(agent.model, dialog).getOrThrow()
dialog.addMessage(assistantMsg)
LogUtils.info(agent.name, assistantMsg)
return AgentResponse(assistantMsg.content, execInfo: task.execInfo)
}
我们来用一个日常场景解释这个过程:
想象你在咖啡店点咖啡:
- 创建任务对象 :服务员接到你的订单(
AgentTask
) - 获取对话对象 :服务员拿出记录本(
dialog
) - 记录日志 :服务员告诉同事"有新订单"(
LogUtils.info
) - 添加系统提示和用户问题 :服务员记下你是谁、想要什么咖啡(
dialog.addMessage
) - 向模型发送请求 :服务员把订单交给咖啡师(
ModelUtils.makeChat
) - 获取回答 :咖啡师制作咖啡并告知结果(
assistantMsg
) - 记录回答 :服务员记录咖啡师的反馈(
dialog.addMessage(assistantMsg)
) - 返回结果 :服务员把咖啡送到你的桌子(
return AgentResponse
)
这个过程非常直接:收到问题,发送给模型,获取回答,返回结果。没有复杂的中间步骤!
5 异步执行:流式返回
块1 块2 块3 块n 用户提问 NaiveExecutor 创建对话 异步发送请求 返回结果 用户界面
接下来是asyncRun
成员函数,让我们看看它是如何工作的:
cangjie
override public func asyncRun(agent: Agent, request: AgentRequest): AsyncAgentResponse {
let task = AgentTask(agent, request)
let dialog = task.execInfo.dialog
LogUtils.info("${agent.name} async runs")
dialog.addMessage([
ChatMessage.system(getFullSystemPrompt(task)),
ChatMessage.user(request.question)
])
LogUtils.info(agent.name, dialog)
let asyncChatResp = agent.model.asyncCreate(
ChatRequest(dialog, temperature: agent.temperature)
)
if (request.verbose) {
task.execInfo.verboseChannel.close()
}
return AsyncAgentResponse(asyncChatResp.contentIter, execInfo: task.execInfo)
}
这就像是看电视直播与录播的区别:
- 同步执行(录播):节目录制完成后才能观看
- 异步执行(直播):节目边制作边播出,观众可以实时看到
举个例子:你在看一场足球比赛直播,进球的瞬间就能看到,不用等到整场比赛结束。同样,使用异步执行,用户不用等待完整回答生成,可以看到AI一点一点生成的内容。
这对于长回答特别有用!想象你问AI写一篇作文,使用异步执行,你可以看到它一句一句地"写"出来,而不是盯着空白屏幕等待整篇作文。
6 NaiveExecutor与其他Executor的对比
执行器类型 NaiveExecutor ReactExecutor PlanReactExecutor 优点: 简单高效 优点: 低延迟 缺点: 不支持工具 优点: 支持工具调用 优点: 思考-行动循环 缺点: 复杂度高 优点: 分解复杂问题 优点: 多步骤规划 缺点: 执行时间长
不同的执行器就像不同类型的交通工具:
- NaiveExecutor:像一辆自行车,简单、灵活,适合短途旅行
- ReactExecutor:像一辆汽车,功能更强,可以走更远的路
- PlanReactExecutor:像一次航空旅行,需要规划航线,但能解决复杂问题
6.1 NaiveExecutor适用场景:
- 问答系统:比如一个简单的FAQ机器人,用户问"你们的营业时间是几点到几点?",直接返回答案。
- 文档助手:结合RAG系统,回答关于特定文档的问题,如"公司政策中对请假有什么规定?"
- 聊天机器人:简单的闲聊对话,不需要执行复杂操作。
- 内容生成:如写诗、写故事等纯文本生成任务。
6.2 代码实例:文档问答助手
cangjie
@agent[
model: "deepseek:deepseek-chat",
executor: "naive", // 使用NaiveExecutor
rag: {
source: "./公司政策.md",
mode: "static"
}
]
class 政策顾问 {
@prompt(
"你是公司的政策顾问"
"根据公司政策文档回答员工的问题"
)
}
main() {
let advisor = 政策顾问()
let result = advisor.chat("年假有多少天?")
println(result)
}
这个例子中,我们创建了一个使用NaiveExecutor的Agent,它能够回答关于公司政策的问题,不需要复杂的工具调用,简单直接!
7 NaiveExecutor的设计亮点
NaiveExecutor设计亮点 代码复用 日志完善 同步异步统一 错误处理 兼容RAG和记忆 利用ReactPromptUtils 避免重复代码 详细执行日志 方便调试排错 统一接口 灵活应用 使用getOrThrow 确保响应有效 支持知识检索 支持历史记忆
NaiveExecutor虽然简单,但设计非常精巧:
- 代码复用:像厨师虽然做简单菜式,但仍然使用专业刀具一样,NaiveExecutor复用了框架的通用组件。
- 日志完善:就像飞行员的黑匣子,记录所有执行过程,方便调试。
- 同步异步统一:可以想象成一家餐厅既提供堂食也提供外卖,满足不同需求。
- 错误处理:像有安全气囊的汽车,当出现问题时能够妥善处理。
- 兼容RAG和记忆:虽然是简单执行器,但保留了"查资料"和"记笔记"的能力。
8 总结
问题 NaiveExecutor 构建提示词 调用模型 返回结果 简单直接 支持RAG 支持记忆 同步异步
这篇文章剖析了CangjieMagic框架中的NaiveExecutor:
- 它是什么:一个简单直接的执行器,"问一嘴,答一句"
- 它怎么工作:构建提示词,发送给模型,获取回答
- 它的特点:简单高效,支持RAG和记忆,但不支持工具调用
- 适用场景:简单问答、文档咨询、内容生成等
NaiveExecutor就像我们生活中的"微波炉",可能不如专业厨具功能强大,但对于很多日常需求来说,它简单、高效、足够好用!
在你开发自己的AI应用时,如果不需要复杂的工具调用和推理,可以考虑使用NaiveExecutor,它会让你的开发过程更加简单,同时也能提供良好的用户体验。