Skip to content

Commit cb99a7d

Browse files
committed
feat: refactor agent prompts and add utility functions for system prompt parsing
1 parent c09f8b6 commit cb99a7d

File tree

3 files changed

+75
-27
lines changed

3 files changed

+75
-27
lines changed

packages/service/core/workflow/dispatch/ai/agent/constants.ts

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,13 @@ export enum SubAppIds {
77
fileRead = 'file_read'
88
}
99

10-
export const getTopAgentDefaultPrompt = () => {
11-
return `你是一位Supervisor Agent,具备以下核心能力:
12-
13-
## 核心能力
14-
1. **计划制定与管理**:根据用户需求制定详细的执行计划,并实时跟踪和调整计划进度
15-
2. **工具调用编排**:可以调用各种工具来完成特定任务,支持并行和串行工具调用
16-
3. **上下文理解**:能够理解对话历史、文档内容和当前状态
17-
4. **自主决策**:根据当前情况和计划进度做出最优决策
18-
19-
## 工作流程
20-
1. **需求分析**:深入理解用户需求,识别关键目标和约束条件
21-
2. **计划制定**:使用 plan_agent 工具制定详细的执行计划
22-
3. **工具编排**:根据计划选择和调用合适的工具
23-
4. **结果处理**:分析工具返回结果,判断是否满足预期
24-
5. **计划调整**:根据执行结果动态调整计划, 再次使用 plan_agent 工具去更新计划进度
25-
6. **更新粒度**:将任务拆分为多个 TODO 去做, 确保每次得到结果后去更新一个或多个 TODO 的状态
26-
7. **最终输出**:给出完整、准确的回答
27-
28-
## 特殊指令
10+
export const getTopAgentConstantPrompt = () => {
11+
return `## 特殊指令
2912
- 对于复杂任务,必须先使用 plan_agent 制定计划
3013
- 在执行过程中如需调整计划,再次调用 plan_agent
3114
- 始终保持计划的可见性和可追踪性
3215
- 每次有新的进度完成时,都要调用 plan_agent 更新计划
33-
- 遇到错误时要有容错和重试机制
34-
35-
请始终保持专业、准确、有条理的回答风格,确保用户能够清楚了解执行进度和结果。`;
16+
- 遇到错误时要有容错和重试机制`;
3617
};
3718

3819
export const StopAgentTool: ChatCompletionTool = {

packages/service/core/workflow/dispatch/ai/agent/index.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import {
3434
initToolNodes,
3535
parseToolArgs
3636
} from '../utils';
37-
import { getFileReadTool, getTopAgentDefaultPrompt, StopAgentTool, SubAppIds } from './constants';
37+
import { getFileReadTool, getTopAgentConstantPrompt, StopAgentTool, SubAppIds } from './constants';
3838
import { runWorkflow } from '../..';
3939
import type { ChatCompletionTool } from '@fastgpt/global/core/ai/type';
4040
import type { ToolNodeItemType } from './type';
@@ -44,6 +44,8 @@ import { transferPlanAgent } from '../sub/plan';
4444
import { transferModelAgent } from '../sub/model';
4545
import { PlanAgentTool } from '../sub/plan/constants';
4646
import { ModelAgentTool } from '../sub/model/constants';
47+
import { getSubIdsByAgentSystem, parseAgentSystem } from './utils';
48+
import { getChildAppPreviewNode } from '../../../../../core/app/plugin/controller';
4749

4850
export type DispatchAgentModuleProps = ModuleDispatchProps<{
4951
[NodeInputKeyEnum.history]?: ChatItemType[];
@@ -101,7 +103,8 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise
101103
}
102104

103105
// Init tool params
104-
const toolNodeIds = filterToolNodeIdByEdges({ nodeId, edges: runtimeEdges });
106+
// const toolNodeIds = filterToolNodeIdByEdges({ nodeId, edges: runtimeEdges });
107+
const toolNodeIds = getSubIdsByAgentSystem(systemPrompt);
105108
const toolNodes = getToolNodesByIds({ toolNodeIds, runtimeNodes });
106109
// TODO: 补充系统 agent
107110
const toolNodesMap = new Map<string, ToolNodeItemType>();
@@ -118,10 +121,12 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise
118121

119122
const subApps = getSubApps({ toolNodes, urls: fileLinks });
120123

124+
const combinedSystemPrompt = `${parseAgentSystem({ systemPrompt, toolNodesMap })}\n\n${getTopAgentConstantPrompt()}`;
125+
121126
// TODO: 把 files 加入 query 中。
122127
const messages: ChatItemType[] = (() => {
123128
const value: ChatItemType[] = [
124-
...getSystemPrompt_ChatItemType(systemPrompt || getTopAgentDefaultPrompt()),
129+
...getSystemPrompt_ChatItemType(combinedSystemPrompt),
125130
// Add file input prompt to histories
126131
...chatHistories,
127132
{
@@ -436,7 +441,7 @@ const getSubApps = ({
436441
type: 'function',
437442
function: {
438443
name: item.nodeId,
439-
description: item.intro || item.name,
444+
description: `调用${item.flowNodeType}:${item.name || item.intro}完成任务`,
440445
parameters: item.jsonSchema
441446
}
442447
};
@@ -459,7 +464,7 @@ const getSubApps = ({
459464
type: 'function',
460465
function: {
461466
name: item.nodeId,
462-
description: item.toolDescription || item.intro || item.name,
467+
description: `调用${item.flowNodeType}:${item.name || item.toolDescription || item.intro}完成任务`,
463468
parameters: {
464469
type: 'object',
465470
properties,
@@ -468,6 +473,7 @@ const getSubApps = ({
468473
}
469474
};
470475
});
476+
console.dir(nodeTools, { depth: null });
471477

472478
return [...systemTools, ...nodeTools];
473479
};
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import type { ToolNodeItemType } from './type';
2+
3+
const namespaceMap = new Map<string, string>([
4+
['a', '子应用'],
5+
['t', '工具'],
6+
['d', '知识库'],
7+
['m', '模型']
8+
]);
9+
10+
// e.g: {{@a.appId@}} -> a.appId
11+
const buildPattern = (options?: { prefix?: string }): RegExp => {
12+
const config = {
13+
prefix: '@',
14+
...options
15+
};
16+
17+
const escapedPrefix = config.prefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
18+
return new RegExp(`\\{\\{${escapedPrefix}([^${escapedPrefix}]+)${escapedPrefix}\\}\\}`, 'g');
19+
};
20+
21+
export const getSubIdsByAgentSystem = (
22+
systemPrompt: string,
23+
options?: { prefix?: string }
24+
): string[] => {
25+
const pattern = buildPattern(options);
26+
const ids: string[] = [];
27+
let match;
28+
29+
while ((match = pattern.exec(systemPrompt)) !== null) {
30+
const fullName = match[1];
31+
const [, id] = fullName.split('.');
32+
if (id) {
33+
ids.push(id);
34+
}
35+
}
36+
37+
return ids;
38+
};
39+
40+
export const parseAgentSystem = ({
41+
systemPrompt,
42+
toolNodesMap,
43+
options
44+
}: {
45+
systemPrompt: string;
46+
toolNodesMap: Map<string, ToolNodeItemType>;
47+
options?: { prefix?: string };
48+
}): string => {
49+
const pattern = buildPattern(options);
50+
51+
const processedPrompt = systemPrompt.replace(pattern, (_, toolName) => {
52+
const [namespace, id] = toolName.split('.');
53+
const toolNode = toolNodesMap.get(id);
54+
const name = toolNode?.name || toolNode?.toolDescription || toolNode?.intro || 'unknown';
55+
56+
const prefix = namespaceMap.get(namespace) ?? 'unknown';
57+
return `${prefix}:${name}`;
58+
});
59+
60+
return processedPrompt;
61+
};

0 commit comments

Comments
 (0)