Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
029a9f4
feat: Configurable output of `reason` for `Intent recognition`
wangliang181230 Mar 24, 2026
eba4501
show the system prompt in the execution detail
wangliang181230 Mar 24, 2026
df360a5
小调整
wangliang181230 Mar 24, 2026
983a7c7
Merge remote-tracking branch 'upstream/v2' into feat/intent-node/conf…
wangliang181230 Mar 24, 2026
a4005c3
feat: The prompt template for the `Intent Recognition` is configurable
wangliang181230 Mar 24, 2026
41f77a5
optimize
wangliang181230 Mar 24, 2026
6209d1f
小调整。
wangliang181230 Mar 24, 2026
b5fce70
修复NPE
wangliang181230 Mar 24, 2026
7168af4
fix tooltip
wangliang181230 Mar 24, 2026
51a198f
小调整。
wangliang181230 Mar 24, 2026
2f5c472
样式优化。
wangliang181230 Mar 24, 2026
5e3d595
当不输出理由时,无需解析理由
wangliang181230 Mar 24, 2026
a39b3a5
小调整
wangliang181230 Mar 24, 2026
425d82b
顺便修复几个问题。
wangliang181230 Mar 24, 2026
bc1113d
修正连接点的y坐标
wangliang181230 Mar 24, 2026
1da185c
Merge remote-tracking branch 'upstream/v2' into feat/intent-node/conf…
wangliang181230 Mar 24, 2026
9c89113
小调整。
wangliang181230 Mar 24, 2026
625ce9b
小调整。
wangliang181230 Mar 24, 2026
384024a
简化意图识别。
wangliang181230 Mar 24, 2026
c98eb26
注释小调整。
wangliang181230 Mar 25, 2026
3fdb5a7
fix: fix the style of the ai-chat-node
wangliang181230 Mar 24, 2026
2833087
意图识别:提示词模板,区分语言。
wangliang181230 Mar 25, 2026
5380ff3
小调整。
wangliang181230 Mar 25, 2026
596485b
小调整。
wangliang181230 Mar 25, 2026
19cb98f
小调整。
wangliang181230 Mar 25, 2026
f024925
Merge remote-tracking branch 'upstream/v2' into feat/intent-node/conf…
wangliang181230 Mar 25, 2026
480277e
提示词优化。
wangliang181230 Mar 25, 2026
fdc78bd
Merge remote-tracking branch 'upstream/v2' into feat/intent-node/conf…
wangliang181230 Mar 25, 2026
cc9bbfb
revert
wangliang181230 Mar 25, 2026
d430380
Merge remote-tracking branch 'upstream/v2' into feat/intent-node/conf…
wangliang181230 Mar 25, 2026
6e45759
向下兼容处理
wangliang181230 Mar 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/application/flow/step_node/intent_node/i_intent_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ class IntentNodeSerializer(serializers.Serializer):
model_id_type = serializers.CharField(required=False, default='custom', label=_("Model id type"))
model_id_reference = serializers.ListField(required=False, child=serializers.CharField(), allow_empty=True,
label=_("Reference Field"))
prompt_template = serializers.CharField(required=False, allow_blank=True, allow_null=True, label=_("Prompt template"))
content_list = serializers.ListField(required=True, label=_("Text content"))
dialogue_number = serializers.IntegerField(required=True, label=
_("Number of multi-round conversations"))
model_params_setting = serializers.DictField(required=False,
label=_("Model parameter settings"))
branch = IntentBranchSerializer(many=True)
output_reason = serializers.BooleanField(required=False, label=_("Output reason"), default=True)


class IIntentNode(INode):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from application.flow.step_node.intent_node.i_intent_node import IIntentNode
from models_provider.models import Model
from models_provider.tools import get_model_instance_by_model_workspace_id, get_model_credential
from .prompt_template import PROMPT_TEMPLATE
from .prompt_template import DEFAULT_PROMPT_TEMPLATE


def get_default_model_params_setting(model_id):
Expand Down Expand Up @@ -52,7 +52,7 @@ def save_context(self, details, workflow_manage):
self.context['branch_id'] = details.get('branch_id')
self.context['category'] = details.get('category')

def execute(self, model_id, dialogue_number, history_chat_record, user_input, branch,
def execute(self, model_id, prompt_template, dialogue_number, history_chat_record, user_input, branch, output_reason,
model_params_setting=None, model_id_type=None, model_id_reference=None, **kwargs) -> NodeResult:
# 处理引用类型
if model_id_type == 'reference' and model_id_reference:
Expand All @@ -75,18 +75,19 @@ def execute(self, model_id, dialogue_number, history_chat_record, user_input, br
)

# 获取历史对话
history_message = self.get_history_message(history_chat_record, dialogue_number)
history_message = self.get_history_message(history_chat_record, dialogue_number) if history_chat_record and dialogue_number > 0 else []
self.context['history_message'] = history_message

# 保存问题到上下文
self.context['user_input'] = user_input

# 构建分类提示词
prompt = self.build_classification_prompt(user_input, branch)
prompt_template = self.workflow_manage.generate_prompt(prompt_template) if prompt_template else None
prompt = self.build_classification_prompt(prompt_template, user_input, branch, output_reason)
self.context['system'] = prompt

# 生成消息列表
system = self.build_system_prompt()
message_list = self.generate_message_list(system, prompt, history_message)
message_list = self.generate_message_list(prompt, history_message)
self.context['message_list'] = message_list

# 调用模型进行分类
Expand All @@ -104,7 +105,7 @@ def execute(self, model_id, dialogue_number, history_chat_record, user_input, br
'history_message': history_message,
'user_input': user_input,
'branch_id': matched_branch['id'],
'reason': self.parse_result_reason(r.content),
'reason': self.parse_result_reason(r.content) if output_reason is not False else '',
'category': matched_branch.get('content', matched_branch['id'])
}, {}, _write_context=write_context)

Expand Down Expand Up @@ -134,11 +135,7 @@ def get_history_message(history_chat_record, dialogue_number):
message.content = re.sub('<form_rander>[\d\D]*?<\/form_rander>', '', message.content)
return history_message

def build_system_prompt(self) -> str:
"""构建系统提示词"""
return "你是一个专业的意图识别助手,请根据用户输入和意图选项,准确识别用户的真实意图。"

def build_classification_prompt(self, user_input: str, branch: List[Dict]) -> str:
def build_classification_prompt(self, prompt_template: str, user_input: str, branch: List[Dict], output_reason: bool) -> str:
"""构建分类提示词"""

classification_list = []
Expand All @@ -160,18 +157,19 @@ def build_classification_prompt(self, user_input: str, branch: List[Dict]) -> st
})
classification_id += 1

return PROMPT_TEMPLATE.format(
classification_list=classification_list,
user_input=user_input
# 构建输出JSON结构
reason_field = ',\n"reason": ""' if output_reason is not False else ''
output_json = f'{{\n"classificationId": 0{reason_field}\n}}'

return (prompt_template or DEFAULT_PROMPT_TEMPLATE).format(
classification_list=json.dumps(classification_list, ensure_ascii=False),
user_input=user_input,
output_json=output_json
)

def generate_message_list(self, system: str, prompt: str, history_message):
def generate_message_list(self, prompt: str, history_message):
"""生成消息列表"""
if system is None or len(system) == 0:
return [*history_message, HumanMessage(self.workflow_manage.generate_prompt(prompt))]
else:
return [SystemMessage(self.workflow_manage.generate_prompt(system)), *history_message,
HumanMessage(self.workflow_manage.generate_prompt(prompt))]
return [*history_message, HumanMessage(self.workflow_manage.generate_prompt(prompt))]

def parse_classification_result(self, result: str, branch: List[Dict]) -> Dict[str, Any]:
"""解析分类结果"""
Expand All @@ -191,14 +189,23 @@ def get_branch_by_id(category_id: int):
return None

try:
result_json = json.loads(result)
classification_id = result_json.get('classificationId')
classification_id = None

# 如果长度小于5,先尝试解析为数字(增加自由度,在自定义提示词模板时,可提示大模型只输出意图分类的ID值)
if len(result) < 5:
classification_id = self.to_int(result)

# 尝试解析为 JSON
if classification_id is None:
result_json = json.loads(result)
classification_id = result_json.get('classificationId')

# 如果是 0 ,返回其他分支
matched_branch = get_branch_by_id(classification_id)
if matched_branch:
return matched_branch

except Exception as e:
except Exception:
# json 解析失败,re 提取
numbers = re.findall(r'"classificationId":\s*(\d+)', result)
if numbers:
Expand All @@ -216,7 +223,7 @@ def parse_result_reason(self, result: str):
try:
result_json = json.loads(result)
return result_json.get('reason', '')
except Exception as e:
except Exception:
reason_patterns = [
r'"reason":\s*"([^"]*)"', # 标准格式
r'"reason":\s*"([^"]*)', # 缺少结束引号
Expand All @@ -232,6 +239,12 @@ def parse_result_reason(self, result: str):

return ''

def to_int(self, str):
try:
return int(str)
except ValueError:
return None

def find_other_branch(self, branch: List[Dict]) -> Dict[str, Any] | None:
"""查找其他分支"""
for b in branch:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@


PROMPT_TEMPLATE = """# Role
DEFAULT_PROMPT_TEMPLATE = """# Role
You are an intention classification expert, good at being able to judge which classification the user's input belongs to.
## Skills
Expand All @@ -20,10 +20,7 @@
- Strictly ensure that the output is in a valid JSON format.
- Do not add prefix ```json or suffix ```
- The answer needs to include the following fields such as:
{{
"classificationId": 0,
"reason": ""
}}
{output_json}
## Limit
- Please do not reply in text."""
8 changes: 4 additions & 4 deletions ui/src/components/execution-detail-card/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@
{{ $t('views.application.form.roleSettings.label') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
{{ data.system || '-' }}
<pre>{{ data.system || '-' }}</pre>
</div>
</div>
<div class="card-never border-r-6 mt-8" v-if="!isKnowLedge">
Expand Down Expand Up @@ -256,7 +256,7 @@
{{ $t('views.application.form.roleSettings.label') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
{{ data.system || '-' }}
<pre>{{ data.system || '-' }}</pre>
</div>
</div>
<div class="card-never border-r-6 mt-8" v-if="data.type !== WorkflowType.Application">
Expand Down Expand Up @@ -545,7 +545,7 @@
{{ $t('views.application.form.roleSettings.label') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
{{ data.system || '-' }}
<pre>{{ data.system || '-' }}</pre>
</div>
</div>
<div class="card-never border-r-6 mt-8" v-if="!isKnowLedge">
Expand Down Expand Up @@ -631,7 +631,7 @@
{{ $t('views.application.form.roleSettings.label') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
{{ data.system || '-' }}
<pre>{{ data.system || '-' }}</pre>
</div>
</div>
<div class="card-never border-r-6 mt-8" v-if="!isKnowLedge">
Expand Down
5 changes: 5 additions & 0 deletions ui/src/locales/lang/en-US/views/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ export default {
- Please use concise and professional language to answer the user's question.
`,
},
prompt_template: {
label: 'Prompt Template',
requiredMessage: 'Please enter Prompt template',
tooltip: 'Please pay attention to the placeholders in the template: {classification_list}、{user_input}、{output_json}',
},
historyRecord: {
label: 'Chat History',
},
Expand Down
28 changes: 27 additions & 1 deletion ui/src/locales/lang/en-US/workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ export default {
result: 'Search Results',
searchParam: 'Search Parameters',
select_variable: 'Select Variable',
valueMessage: `Value or name `,
valueMessage: 'Value or name',

searchQuestion: {
label: 'Search Question',
Expand Down Expand Up @@ -447,9 +447,34 @@ You are a master of problem optimization, adept at accurately inferring user int
classify: {
label: 'Intent classify',
},
output_reason: 'Output Reason',
input: {
label: 'Input',
},
default_prompt_template: `# Role
You are an intention classification expert, good at being able to judge which classification the user's input belongs to.

## Skills
Skill 1: Clearly determine which of the following intention classifications the user's input belongs to.
Intention classification list:
{classification_list}

Note:
- Please determine the match between the user's input content and the Intention classification list content, without judging or categorizing the match with the classification ID.
- **When classifying, you must give higher weight to the context and intent continuity shown in the historical conversation. Do not rely solely on the literal meaning of the current input; instead, prioritize the most consistent classification with the previous dialogue flow.**

## User Input
{user_input}

## Reply requirements
- The answer must be returned in JSON format.
- Strictly ensure that the output is in a valid JSON format.
- Do not add prefix \`\`\`json or suffix \`\`\`
- The answer needs to include the following fields such as:
{output_json}

## Limit
- Please do not reply in text.`,
},
applicationNode: {
label: 'Agent Node',
Expand Down Expand Up @@ -541,6 +566,7 @@ You are a master of problem optimization, adept at accurately inferring user int
},
SystemPromptPlaceholder: 'System Prompt, can reference variables in the system, such as',
UserPromptPlaceholder: 'User Prompt, can reference variables in the system, such as',
PromptTemplatePlaceholder: 'Prompt Template, can reference variables in the system, such as',
initiator: 'Iniiator',
abnormalInformation: 'Abnormal Information',
}
5 changes: 5 additions & 0 deletions ui/src/locales/lang/zh-CN/views/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ export default {
回答要求:
- 请使用中文回答用户问题`,
},
prompt_template: {
label: '提示词模板',
requiredMessage: '请输入提示词模板',
tooltip: '请注意模板中的占位符: {classification_list}、{user_input}、{output_json}',
},
historyRecord: {
label: '历史聊天记录',
},
Expand Down
26 changes: 26 additions & 0 deletions ui/src/locales/lang/zh-CN/workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -439,9 +439,34 @@ export default {
classify: {
label: '意图分类',
},
output_reason: '输出理由',
input: {
label: '输入',
},
default_prompt_template: `# 角色
你是一位意图分类专家,擅长判断用户输入属于哪个分类。

## 技能
技能1:明确判断用户输入属于以下哪种意图分类。
意图分类列表:
{classification_list}

注:
- 请判断用户输入内容与意图分类列表内容之间的匹配度,注意不要以分类ID作为评判或归类的依据。
- **在分类时,必须更加重视历史对话中表现的上下文和意图连贯性。不要仅依赖当前输入的字面意思;相反,应优先考虑与先前对话流程最匹配的分类。**

## 用户输入
{user_input}

## 回复要求
- 回复内容必须以JSON格式返回。
- 严格确保输出为有效的JSON格式。
- 不要添加前缀 \`\`\`json 或 后缀 \`\`\`
- 回复内容需要包含以下字段:
{output_json}

## 限制
- 请勿以文本形式回复。`,
},
applicationNode: {
label: '智能体节点',
Expand Down Expand Up @@ -532,6 +557,7 @@ export default {
},
SystemPromptPlaceholder: '系统提示词,可以引用系统中的变量:如',
UserPromptPlaceholder: '用户提示词,可以引用系统中的变量:如',
PromptTemplatePlaceholder: '提示词模板,可以引用系统中的变量:如',
initiator: '发起人',
abnormalInformation: '异常信息'

Expand Down
5 changes: 5 additions & 0 deletions ui/src/locales/lang/zh-Hant/views/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ export default {
回答要求:
- 請使用中文回答用戶問題`,
},
prompt_template: {
label: '提示詞模板',
requiredMessage: '請輸入提示詞模板',
tooltip: '請注意模板中的佔位符: {classification_list}、{user_input}、{output_json}',
},
historyRecord: {
label: '歷史對話紀錄',
},
Expand Down
26 changes: 26 additions & 0 deletions ui/src/locales/lang/zh-Hant/workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -439,9 +439,34 @@ export default {
classify: {
label: '意圖分類',
},
output_reason: '輸出理由',
input: {
label: '輸入',
},
default_prompt_template: `# 角色
你是一位意圖分類專家,擅長判斷用戶輸入屬於哪個分類。

## 技能
技能1:明確判斷用戶輸入屬於以下哪種意圖分類。
意圖分類列表:
{classification_list}

注:
- 請判斷用戶輸入內容與意圖分類列表內容之間的匹配度,注意不要以分類ID作爲評判或歸類的依據。
- **在分類時,必須更加重視歷史對話中表現的上下文和意圖連貫性。不要僅依賴當前輸入的字面意思;相反,應優先考慮與先前對話流程最匹配的分類。**

## 用戶輸入
{user_input}

## 回覆要求
- 回覆內容必須以JSON格式返回。
- 嚴格確保輸出爲有效的JSON格式。
- 不要添加前綴 \`\`\`json 或 後綴 \`\`\`
- 回覆內容需要包含以下字段:
{output_json}

## 限制
- 請勿以文本形式回覆。`,
},
applicationNode: {
label: '智能體節點',
Expand Down Expand Up @@ -526,6 +551,7 @@ export default {
},
SystemPromptPlaceholder: '系統提示詞,可以引用系統中的變量:如',
UserPromptPlaceholder: '用戶提示詞,可以引用系統中的變量:如',
PromptTemplatePlaceholder: '提示詞模板,可以引用系統中的變量:如',
initiator: '發起人',
abnormalInformation: '異常信息',
}
2 changes: 1 addition & 1 deletion ui/src/styles/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ html {
font-size: 100%;
}

body {
body, .card-never pre {
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
font-family: 'PingFang SC', AlibabaPuHuiTi !important;
Expand Down
Loading
Loading