Skip to content

Commit b7379d5

Browse files
authored
Merge branch 'main' into main_assistant_v3_to_assistant
2 parents 96c7d19 + 0ed7bbf commit b7379d5

File tree

18 files changed

+492
-118
lines changed

18 files changed

+492
-118
lines changed

app-builder/plugins/aipp-custom-model-center/src/main/resources/sql/data/tr_t_model_import.sql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,5 @@ INSERT INTO "public"."store_app" ("like_count", "download_count", "source", "ico
6363
INSERT INTO "public"."store_tool" ("name", "schema", "runnables", "extensions", "unique_name", "version", "is_latest", "group_name", "definition_name", "definition_group_name") VALUES ('模型配置应用', '{"name":"模型配置应用","description":"当你想要配置模型的时候,请使用我!","manualIntervention":false,"parameters":{"type":"object","properties":{"aippId":{"description":"the aipp id of the waterFlow tool","default":"0b4fe5a430104edfbe0dc6cff0ebea19","type":"string"},"tenantId":{"description":"the tenant id of the waterFlow tool","default":"31f20efc7e0848deab6a6bc10fc3021e","type":"string"},"inputParams":{"type":"object","properties":{"Question":{"type":"string","description":"这是用户输入的问题。"}},"required":["Question"],"order":["Question"]},"version":{"description":"the aipp version of the waterFlow tool","default":"1.0.0","type":"string"}},"required":["tenantId","aippId","version","inputParams"]},"return":{"type":"object","properties":{}},"order":["tenantId","aippId","version","inputParams"]}', '{"FIT":{"fitableId":"water.flow.invoke","genericableId":"07b51bd246594c159d403164369ce1db"},"APP":{"aippId":"0b4fe5a430104edfbe0dc6cff0ebea19","appCategory":"chatbot","version":"1.0.0","appId":"cec6bfe7cb3a444f8a26a97ea513e501"}}', 'null', '7a76cbd2-881d-469b-b2df-76abed7d0b61', '1.0.0', 't', '7a76cbd2-881d-469b-b2df-76abed7d0b61', '7a76cbd2-881d-469b-b2df-76abed7d0b61', '7a76cbd2-881d-469b-b2df-76abed7d0b61') ON CONFLICT ("unique_name", "version") DO NOTHING;
6464

6565
INSERT INTO "public"."store_tag" ("tool_unique_name", "name") VALUES ('7a76cbd2-881d-469b-b2df-76abed7d0b61', 'APP') ON CONFLICT ("tool_unique_name", "name") DO NOTHING;
66-
INSERT INTO "public"."store_tag" ("tool_unique_name", "name") VALUES ('7a76cbd2-881d-469b-b2df-76abed7d0b61', 'APP_TYPE_B653EDB7EB5A49BE91ABCD2C5877C6AD') ON CONFLICT ("tool_unique_name", "name") DO NOTHING;
66+
INSERT INTO "public"."store_tag" ("tool_unique_name", "name") VALUES ('7a76cbd2-881d-469b-b2df-76abed7d0b61', 'APP_TYPE_B653EDB7EB5A49BE91ABCD2C5877C6AD') ON CONFLICT ("tool_unique_name", "name") DO NOTHING;
67+
INSERT INTO "public"."store_tag" ("tool_unique_name", "name") VALUES ('7a76cbd2-881d-469b-b2df-76abed7d0b61', 'BUILTIN') ON CONFLICT ("tool_unique_name", "name") DO NOTHING;

app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/service/impl/AgentInfoGenerateServiceImpl.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import modelengine.fit.jober.aipp.service.AippModelService;
2626
import modelengine.fit.jober.aipp.util.UUIDUtil;
2727
import modelengine.fitframework.annotation.Component;
28+
import modelengine.fitframework.annotation.Value;
2829
import modelengine.fitframework.log.Logger;
2930
import modelengine.fitframework.util.IoUtils;
3031
import modelengine.fitframework.util.MapBuilder;
@@ -40,6 +41,8 @@
4041
import java.util.HashSet;
4142
import java.util.List;
4243
import java.util.Map;
44+
import java.util.stream.Collectors;
45+
import java.util.stream.Stream;
4346

4447
/**
4548
* 表示 {@link AgentInfoGenerateService} 的默认实现。
@@ -65,13 +68,17 @@ public class AgentInfoGenerateServiceImpl implements AgentInfoGenerateService {
6568

6669
private final String agentNameFormat = "^[\\u4E00-\\u9FA5A-Za-z0-9][\\u4E00-\\u9FA5A-Za-z0-9-_]*$";
6770

71+
private final String systemCreator;
72+
6873
public AgentInfoGenerateServiceImpl(AippModelService aippModelService, AippModelCenter aippModelCenter,
69-
PluginToolService toolService, LocaleService localeService, AppBuilderAppRepository appRepository) {
74+
PluginToolService toolService, LocaleService localeService, AppBuilderAppRepository appRepository,
75+
@Value("${app-engine.plugin.system-creator}") String systemCreator) {
7076
this.aippModelService = aippModelService;
7177
this.aippModelCenter = aippModelCenter;
7278
this.toolService = toolService;
7379
this.localeService = localeService;
7480
this.appRepository = appRepository;
81+
this.systemCreator = systemCreator;
7582
}
7683

7784
@Override
@@ -100,7 +107,16 @@ public String generateGreeting(String desc, OperationContext context) {
100107

101108
@Override
102109
public String generatePrompt(String desc, OperationContext context) {
103-
return this.generateByTemplate(desc, "prompt/promptGeneratePrompt.txt", context);
110+
String prompt = this.generateByTemplate(desc, "prompt/promptGeneratePrompt.txt", context);
111+
String format;
112+
try {
113+
format = IoUtils.content(AgentInfoGenerateService.class.getClassLoader(),
114+
"prompt/promptGeneratePromptFormat.txt");
115+
} catch (IOException e) {
116+
log.error("read prompt format file fail.", e);
117+
throw new AippException(AippErrCode.EXTRACT_FILE_FAILED);
118+
}
119+
return StringUtils.format(format, prompt);
104120
}
105121

106122
@Override
@@ -110,7 +126,9 @@ public List<String> selectTools(String desc, String creator, OperationContext co
110126

111127
private ArrayList<String> getToolsResult(String desc, String creator, OperationContext context) {
112128
StringBuilder toolsCandidate = new StringBuilder();
113-
ListResult<PluginToolData> tools = this.getTools(creator);
129+
ListResult<PluginToolData> creatorTools = this.getTools(creator);
130+
ListResult<PluginToolData> systemTools = this.getTools(this.systemCreator);
131+
ListResult<PluginToolData> tools = this.merge(creatorTools, systemTools);
114132
int count = tools.getCount();
115133
List<PluginToolData> toolData = tools.getData();
116134
for (int i = 0; i < count; i++) {
@@ -136,6 +154,20 @@ private ArrayList<String> getToolsResult(String desc, String creator, OperationC
136154
return toolsResult;
137155
}
138156

157+
private ListResult<PluginToolData> merge(ListResult<PluginToolData> tool1, ListResult<PluginToolData> tools2) {
158+
if (tool1 == null || tool1.getCount() == 0) {
159+
return tools2;
160+
} else if (tools2 == null || tools2.getCount() == 0) {
161+
return tool1;
162+
}
163+
ListResult<PluginToolData> tools = ListResult.create(new ArrayList<>(), 0);
164+
tools.setCount(tool1.getCount() + tools2.getCount());
165+
List<PluginToolData> mergedData = Stream.concat(tool1.getData().stream(), tools2.getData().stream())
166+
.collect(Collectors.toList());
167+
tools.setData(mergedData);
168+
return tools;
169+
}
170+
139171
private ListResult<PluginToolData> getTools(String creator) {
140172
PluginToolQuery pluginQuery = new PluginToolQuery.Builder().toolName(null).includeTags(new HashSet<String>() {{
141173
add("FIT");

app-builder/plugins/aipp-plugin/src/main/resources/application.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ app-engine:
6060
max-length: 20000
6161
user-context:
6262
max-length: 500
63+
plugin:
64+
system-creator: 'system'
6365
elsa:
6466
endpoint:
6567
elsaKey:

app-builder/plugins/aipp-plugin/src/main/resources/prompt/promptGeneratePrompt.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
You ara a prompt generator, Your job is to generate prompt from the input of the user.
1+
You are a prompt generator, Your job is to generate prompt from the input of the user.
22
**NOTE THAT THE PROMPT MUST INSTRUCT THE AGENT TO USE TOOL AS MUCH AS POSSIBLE**
33

44
The Prompt must follow the style of the example below:
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{0}
2+
3+
<tool_usage>
4+
你的回答有两种情况:
5+
6+
无需调用外部工具:
7+
如果问题可通过已有对话历史或直接推理得到答案,直接输出最终结果,不需使用任何标签包装,也不显示详细思考过程。
8+
9+
需要调用外部工具解决的复杂问题:
10+
必须采用以下严格的标签体系输出,每个标签之间空一行,且仅展示真实的工具调用结果:
11+
<reasoning>...</reasoning>:展示你内部的思考过程。注意,这部分内容可以展示给用户,但仅限于描述思路,不应包含任何伪造的工具调用结果。
12+
<step>...</step>:描述你准备调用工具的原因和计划。此处仅说明你需要调用哪个工具以及原因,工具的名称对人类阅读要友好,切勿直接模拟或输出工具返回内容。
13+
<tool>...</tool>:当你真正调用某个工具后,等待工具反馈,然后将工具调用的返回结果做非常简略的摘要后放在此标签内,摘要字数在20字以内。绝对禁止在未获得真实工具反馈前预先构造。 <tool> 标签内容。
14+
<final>...</final>:在获取所有真实工具调用结果后,将整合信息给出最终答案。
15+
重要要求:
16+
- 无论用户是否明确要求展示思考过程,都要展示思考过程
17+
- 不要输出tool_call标签。
18+
- 答案必须详细完整,不仅仅是工具返回结果的简单总结,而是对结果进行深入分析和整合,并提供背景解释、推理过程和可行性分析。
19+
- 确保所有关键信息得到展开,避免省略任何重要内容。
20+
- 如果适用,可以提供额外的解释、使用建议或应用场景,以增强回答的实用性。
21+
- 请使用标准 Markdown 语法输出答案,保证语法完整,不要拆分列表结构。
22+
- 输出此标签后,不得追加任何其他内容或标签。
23+
严格要求:
24+
切勿在中间思考或工具调用计划中,提前生成伪造的 <tool> 或 <final> 标签内容。必须在实际调用工具并获得反馈后,再以 <tool> 标签展示真实结果,再生成 <final> 标签输出最终答案。
25+
如果历史对话中已包含真实的工具调用结果,应直接使用这些信息构造最终答案,避免重复调用或展示多余标签。
26+
在所有工具调用完成之前,不得输出 <final> 标签;只有在确认所有真实工具反馈后,才生成最终答案。
27+
</tool_usage>

app-builder/plugins/aipp-plugin/src/main/resources/sql/data/tr_t_interview.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
INSERT INTO "public"."app_builder_app" ("id", "name", "create_by", "create_at", "update_by", "update_at", "config_id", "flow_graph_id", "tenant_id", "type", "version", "attributes", "state", "app_built_type", "app_category", "collection_usr_cnt", "is_deleted", "path", "app_type", "app_suite_id", "is_active", "status", "unique_name", "publish_at", "app_id", "user_group_id") VALUES ('fd8166b5005e4d66a77d318f3b1dd5e5', '面试助手', 'Jade', '2025-04-28 08:36:13.767496', 'Jade', '2025-04-28 08:37:15.197182', '68da40b4e47e4743a59c2beac9002dc7', '24f72de428124eb19fd12db36ebcfd34', '31f20efc7e0848deab6a6bc10fc3021e', 'app', '1.0.0', '{"icon": "", "name": "面试助手", "greeting": "", "store_id": "e8bbd29c-e529-4c8e-abdb-b355b2d8dcdf", "is_update": false, "description": "", "publishedUpdateLog": "", "publishedDescription": ""}', 'active', 'workflow', 'chatbot', 0, 0, '3v8ZU1cMRV0oRcqu', '4db152b24f94473ab683b1acbfe3c865', 'ec6f8e93a80541bb930fc22678ef7043', 't', 'published', 'e8bbd29c-e529-4c8e-abdb-b355b2d8dcdf', '2025-04-28 08:39:03', 'fd8166b5005e4d66a77d318f3b1dd5e5', '*') ON CONFLICT (id) DO NOTHING;
1+
INSERT INTO "public"."app_builder_app" ("id", "name", "create_by", "create_at", "update_by", "update_at", "config_id", "flow_graph_id", "tenant_id", "type", "version", "attributes", "state", "app_built_type", "app_category", "collection_usr_cnt", "is_deleted", "path", "app_type", "app_suite_id", "is_active", "status", "unique_name", "publish_at", "app_id", "user_group_id") VALUES ('fd8166b5005e4d66a77d318f3b1dd5e5', '面试助手', 'system', '2025-04-28 08:36:13.767496', 'system', '2025-04-28 08:37:15.197182', '68da40b4e47e4743a59c2beac9002dc7', '24f72de428124eb19fd12db36ebcfd34', '31f20efc7e0848deab6a6bc10fc3021e', 'app', '1.0.0', '{"icon": "", "name": "面试助手", "greeting": "", "store_id": "e8bbd29c-e529-4c8e-abdb-b355b2d8dcdf", "is_update": false, "description": "", "publishedUpdateLog": "", "publishedDescription": ""}', 'active', 'workflow', 'chatbot', 0, 0, '3v8ZU1cMRV0oRcqu', '4db152b24f94473ab683b1acbfe3c865', 'ec6f8e93a80541bb930fc22678ef7043', 't', 'published', 'e8bbd29c-e529-4c8e-abdb-b355b2d8dcdf', '2025-04-28 08:39:03', 'fd8166b5005e4d66a77d318f3b1dd5e5', '*') ON CONFLICT (id) DO NOTHING;
22

33
INSERT INTO "public"."app_builder_config" ("id", "form_id", "app_id", "tenant_id", "create_by", "create_at", "update_by", "update_at", "is_deleted") VALUES ('68da40b4e47e4743a59c2beac9002dc7', 'b8986770a6ffef44bbf2a9f26d6fc1be', 'fd8166b5005e4d66a77d318f3b1dd5e5', '31f20efc7e0848deab6a6bc10fc3021e', 'Jade', '2025-04-28 08:36:13.767496', 'Jade', '2025-04-28 08:37:15.197182', 0) ON CONFLICT (id) DO NOTHING;
44

app-builder/plugins/aipp-plugin/src/test/java/modelengine/fit/jober/aipp/service/AgentInfoGenerateServiceImplTest.java

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import modelengine.jade.store.service.PluginToolService;
2626

2727
import org.jetbrains.annotations.NotNull;
28+
import org.junit.jupiter.api.Assertions;
2829
import org.junit.jupiter.api.BeforeEach;
2930
import org.junit.jupiter.api.DisplayName;
3031
import org.junit.jupiter.api.Test;
@@ -68,7 +69,7 @@ void beforeAll() {
6869
this.aippModelCenter,
6970
this.toolService,
7071
this.localeService,
71-
this.appRepository);
72+
this.appRepository, "system");
7273
}
7374

7475
@Test
@@ -101,7 +102,7 @@ void shouldOkWhenGeneratePrompt() {
101102
when(model.getTag()).thenReturn("llm_tag");
102103
when(this.aippModelCenter.getDefaultModel(any(), any())).thenReturn(model);
103104
when(aippModelService.chat(anyString(), anyString(), anyDouble(), anyString())).thenReturn("PROMPT");
104-
assertThat(this.agentInfoGenerateService.generatePrompt("DESC", null)).isEqualTo("PROMPT");
105+
assertThat(this.agentInfoGenerateService.generatePrompt("DESC", null)).startsWith("PROMPT");
105106
}
106107

107108
@Test
@@ -135,6 +136,81 @@ void shouldOkWhenSelectTools() {
135136
"UNIQUENAME3");
136137
}
137138

139+
@Test
140+
void testMerge_tool1IsNull_returnsTools2() {
141+
ListResult<PluginToolData> tools2 = new ListResult<>(List.of(new PluginToolData()), 1);
142+
ListResult<PluginToolData> result = this.invokeMerge(null, tools2);
143+
Assertions.assertSame(tools2, result);
144+
}
145+
146+
/**
147+
* 测试当 tool1 的 count 为 0 时是否正确返回 tools2
148+
*/
149+
@Test
150+
void testMerge_tool1IsEmpty_returnsTools2() {
151+
ListResult<PluginToolData> tool1 = new ListResult<>(new ArrayList<>(), 0);
152+
ListResult<PluginToolData> tools2 = new ListResult<>(List.of(new PluginToolData()), 1);
153+
ListResult<PluginToolData> result = this.invokeMerge(tool1, tools2);
154+
Assertions.assertSame(tools2, result);
155+
}
156+
157+
/**
158+
* 测试当 tools2 为 null 时是否正确返回 tool1
159+
*/
160+
@Test
161+
void testMerge_tools2IsNull_returnsTool1() {
162+
ListResult<PluginToolData> tool1 = new ListResult<>(List.of(new PluginToolData()), 1);
163+
ListResult<PluginToolData> result = invokeMerge(tool1, null);
164+
Assertions.assertSame(tool1, result);
165+
}
166+
167+
/**
168+
* 测试当 tools2 的 count 为 0 时是否正确返回 tool1
169+
*/
170+
@Test
171+
void testMerge_tools2IsEmpty_returnsTool1() {
172+
ListResult<PluginToolData> tool1 = new ListResult<>(List.of(new PluginToolData()), 1);
173+
ListResult<PluginToolData> tools2 = new ListResult<>(new ArrayList<>(), 0);
174+
ListResult<PluginToolData> result = invokeMerge(tool1, tools2);
175+
Assertions.assertSame(tool1, result);
176+
}
177+
178+
/**
179+
* 测试正常情况下两个列表能否成功合并
180+
*/
181+
@Test
182+
void testMerge_bothValid_mergeCorrectly() {
183+
PluginToolData data1 = new PluginToolData();
184+
PluginToolData data2 = new PluginToolData();
185+
ListResult<PluginToolData> tool1 = new ListResult<>(List.of(data1), 1);
186+
ListResult<PluginToolData> tools2 = new ListResult<>(List.of(data2), 1);
187+
188+
ListResult<PluginToolData> result = invokeMerge(tool1, tools2);
189+
190+
Assertions.assertNotNull(result);
191+
Assertions.assertEquals(2, result.getCount());
192+
Assertions.assertTrue(result.getData().contains(data1));
193+
Assertions.assertTrue(result.getData().contains(data2));
194+
}
195+
196+
/**
197+
* 利用反射机制调用私有方法 merge
198+
*
199+
* @param tool1 第一个 ListResult 参数
200+
* @param tools2 第二个 ListResult 参数
201+
* @return 合并后的 ListResult 结果
202+
*/
203+
private ListResult<PluginToolData> invokeMerge(ListResult<PluginToolData> tool1, ListResult<PluginToolData> tools2) {
204+
try {
205+
var method = AgentInfoGenerateServiceImpl.class.getDeclaredMethod("merge",
206+
ListResult.class, ListResult.class);
207+
method.setAccessible(true);
208+
return (ListResult<PluginToolData>) method.invoke(this.agentInfoGenerateService, tool1, tools2);
209+
} catch (Exception e) {
210+
throw new RuntimeException("Failed to invoke private method 'merge'", e);
211+
}
212+
}
213+
138214
@NotNull
139215
private ModelListDto getModelListDto() {
140216
List<ModelAccessInfo> modelAccessInfos = new ArrayList<>();

0 commit comments

Comments
 (0)