### What problem does this PR solve? ### Type of change - [x] Refactoringtags/v0.20.0
| "created_at": cpn_obj.output("_created_time"), | "created_at": cpn_obj.output("_created_time"), | ||||
| }) | }) | ||||
| def _append_path(cpn_id): | |||||
| if self.path[-1] == cpn_id: | |||||
| return | |||||
| self.path.append(cpn_id) | |||||
| def _extend_path(cpn_ids): | |||||
| for cpn_id in cpn_ids: | |||||
| _append_path(cpn_id) | |||||
| self.error = "" | self.error = "" | ||||
| idx = len(self.path) - 1 | idx = len(self.path) - 1 | ||||
| partials = [] | partials = [] | ||||
| # post processing of components invocation | # post processing of components invocation | ||||
| for i in range(idx, to): | for i in range(idx, to): | ||||
| cpn = self.get_component(self.path[i]) | cpn = self.get_component(self.path[i]) | ||||
| if cpn["obj"].component_name.lower() == "message": | |||||
| if isinstance(cpn["obj"].output("content"), partial): | |||||
| cpn_obj = self.get_component_obj(self.path[i]) | |||||
| if cpn_obj.component_name.lower() == "message": | |||||
| if isinstance(cpn_obj.output("content"), partial): | |||||
| _m = "" | _m = "" | ||||
| for m in cpn["obj"].output("content")(): | |||||
| for m in cpn_obj.output("content")(): | |||||
| if not m: | if not m: | ||||
| continue | continue | ||||
| if m == "<think>": | if m == "<think>": | ||||
| else: | else: | ||||
| yield decorate("message", {"content": m}) | yield decorate("message", {"content": m}) | ||||
| _m += m | _m += m | ||||
| cpn["obj"].set_output("content", _m) | |||||
| cpn_obj.set_output("content", _m) | |||||
| else: | else: | ||||
| yield decorate("message", {"content": cpn["obj"].output("content")}) | |||||
| yield decorate("message", {"content": cpn_obj.output("content")}) | |||||
| yield decorate("message_end", {"reference": self.get_reference()}) | yield decorate("message_end", {"reference": self.get_reference()}) | ||||
| while partials: | while partials: | ||||
| _cpn = self.get_component(partials[0]) | |||||
| if isinstance(_cpn["obj"].output("content"), partial): | |||||
| _cpn_obj = self.get_component_obj(partials[0]) | |||||
| if isinstance(_cpn_obj.output("content"), partial): | |||||
| break | break | ||||
| yield _node_finished(_cpn["obj"]) | |||||
| yield _node_finished(_cpn_obj) | |||||
| partials.pop(0) | partials.pop(0) | ||||
| if cpn["obj"].error(): | |||||
| ex = cpn["obj"].exception_handler() | |||||
| if ex and ex["comment"]: | |||||
| yield decorate("message", {"content": ex["comment"]}) | |||||
| yield decorate("message_end", {}) | |||||
| other_branch = False | |||||
| if cpn_obj.error(): | |||||
| ex = cpn_obj.exception_handler() | |||||
| if ex and ex["goto"]: | if ex and ex["goto"]: | ||||
| self.path.append(ex["goto"]) | |||||
| elif not ex or not ex["default_value"]: | |||||
| self.error = cpn["obj"].error() | |||||
| self.path.extend(ex["goto"]) | |||||
| other_branch = True | |||||
| elif ex and ex["default_value"]: | |||||
| yield decorate("message", {"content": ex["default_value"]}) | |||||
| yield decorate("message_end", {}) | |||||
| else: | |||||
| self.error = cpn_obj.error() | |||||
| if cpn["obj"].component_name.lower() != "iteration": | |||||
| if isinstance(cpn["obj"].output("content"), partial): | |||||
| if cpn_obj.component_name.lower() != "iteration": | |||||
| if isinstance(cpn_obj.output("content"), partial): | |||||
| if self.error: | if self.error: | ||||
| cpn["obj"].set_output("content", None) | |||||
| yield _node_finished(cpn["obj"]) | |||||
| cpn_obj.set_output("content", None) | |||||
| yield _node_finished(cpn_obj) | |||||
| else: | else: | ||||
| partials.append(self.path[i]) | partials.append(self.path[i]) | ||||
| else: | else: | ||||
| yield _node_finished(cpn["obj"]) | |||||
| if cpn["obj"].component_name.lower() == "iterationitem" and cpn["obj"].end(): | |||||
| iter = cpn["obj"].get_parent() | |||||
| yield _node_finished(cpn_obj) | |||||
| def _append_path(cpn_id): | |||||
| nonlocal other_branch | |||||
| if other_branch: | |||||
| return | |||||
| if self.path[-1] == cpn_id: | |||||
| return | |||||
| self.path.append(cpn_id) | |||||
| def _extend_path(cpn_ids): | |||||
| nonlocal other_branch | |||||
| if other_branch: | |||||
| return | |||||
| for cpn_id in cpn_ids: | |||||
| _append_path(cpn_id) | |||||
| if cpn_obj.component_name.lower() == "iterationitem" and cpn_obj.end(): | |||||
| iter = cpn_obj.get_parent() | |||||
| yield _node_finished(iter) | yield _node_finished(iter) | ||||
| _extend_path(self.get_component(cpn["parent_id"])["downstream"]) | _extend_path(self.get_component(cpn["parent_id"])["downstream"]) | ||||
| elif cpn["obj"].component_name.lower() in ["categorize", "switch"]: | |||||
| _extend_path(cpn["obj"].output("_next")) | |||||
| elif cpn["obj"].component_name.lower() == "iteration": | |||||
| _append_path(cpn["obj"].get_start()) | |||||
| elif not cpn["downstream"] and cpn["obj"].get_parent(): | |||||
| _append_path(cpn["obj"].get_parent().get_start()) | |||||
| elif cpn_obj.component_name.lower() in ["categorize", "switch"]: | |||||
| _extend_path(cpn_obj.output("_next")) | |||||
| elif cpn_obj.component_name.lower() == "iteration": | |||||
| _append_path(cpn_obj.get_start()) | |||||
| elif not cpn["downstream"] and cpn_obj.get_parent(): | |||||
| _append_path(cpn_obj.get_parent().get_start()) | |||||
| else: | else: | ||||
| _extend_path(cpn["downstream"]) | _extend_path(cpn["downstream"]) | ||||
| break | break | ||||
| idx = to | idx = to | ||||
| if any([self.get_component(c)["obj"].component_name.lower() == "userfillup" for c in self.path[idx:]]): | |||||
| if any([self.get_component_obj(c).component_name.lower() == "userfillup" for c in self.path[idx:]]): | |||||
| path = [c for c in self.path[idx:] if self.get_component(c)["obj"].component_name.lower() == "userfillup"] | path = [c for c in self.path[idx:] if self.get_component(c)["obj"].component_name.lower() == "userfillup"] | ||||
| path.extend([c for c in self.path[idx:] if self.get_component(c)["obj"].component_name.lower() != "userfillup"]) | path.extend([c for c in self.path[idx:] if self.get_component(c)["obj"].component_name.lower() != "userfillup"]) | ||||
| another_inputs = {} | another_inputs = {} | ||||
| tips = "" | tips = "" | ||||
| for c in path: | for c in path: | ||||
| o = self.get_component(c)["obj"] | |||||
| o = self.get_component_obj(c) | |||||
| if o.component_name.lower() == "userfillup": | if o.component_name.lower() == "userfillup": | ||||
| another_inputs.update(o.get_input_elements()) | another_inputs.update(o.get_input_elements()) | ||||
| if o.get_param("enable_tips"): | if o.get_param("enable_tips"): |
| prompt, msg = self._prepare_prompt_variables() | prompt, msg = self._prepare_prompt_variables() | ||||
| downstreams = self._canvas.get_component(self._id)["downstream"] if self._canvas.get_component(self._id) else [] | downstreams = self._canvas.get_component(self._id)["downstream"] if self._canvas.get_component(self._id) else [] | ||||
| if any([self._canvas.get_component_obj(cid).component_name.lower()=="message" for cid in downstreams]) and not self._param.output_structure: | |||||
| ex = self.exception_handler() | |||||
| if any([self._canvas.get_component_obj(cid).component_name.lower()=="message" for cid in downstreams]) and not self._param.output_structure and not (ex and ex["goto"]): | |||||
| self.set_output("content", partial(self.stream_output_with_tools, prompt, msg)) | self.set_output("content", partial(self.stream_output_with_tools, prompt, msg)) | ||||
| return | return | ||||
| if ans.find("**ERROR**") >= 0: | if ans.find("**ERROR**") >= 0: | ||||
| logging.error(f"Agent._chat got error. response: {ans}") | logging.error(f"Agent._chat got error. response: {ans}") | ||||
| self.set_output("_ERROR", ans) | |||||
| if self.get_exception_default_value(): | |||||
| self.set_output("content", self.get_exception_default_value()) | |||||
| else: | |||||
| self.set_output("_ERROR", ans) | |||||
| return | return | ||||
| self.set_output("content", ans) | self.set_output("content", ans) | ||||
| answer_without_toolcall = "" | answer_without_toolcall = "" | ||||
| use_tools = [] | use_tools = [] | ||||
| for delta_ans,_ in self._react_with_tools_streamly(msg, use_tools): | for delta_ans,_ in self._react_with_tools_streamly(msg, use_tools): | ||||
| if delta_ans.find("**ERROR**") >= 0: | |||||
| if self.get_exception_default_value(): | |||||
| self.set_output("content", self.get_exception_default_value()) | |||||
| yield self.get_exception_default_value() | |||||
| else: | |||||
| self.set_output("_ERROR", delta_ans) | |||||
| answer_without_toolcall += delta_ans | answer_without_toolcall += delta_ans | ||||
| yield delta_ans | yield delta_ans | ||||
| hist = deepcopy(history) | hist = deepcopy(history) | ||||
| last_calling = "" | last_calling = "" | ||||
| if len(hist) > 3: | if len(hist) > 3: | ||||
| self.callback("Multi-turn conversation optimization", {}, " running ...") | |||||
| user_request = full_question(messages=history, chat_mdl=self.chat_mdl) | user_request = full_question(messages=history, chat_mdl=self.chat_mdl) | ||||
| self.callback("Multi-turn conversation optimization", {}, user_request) | |||||
| else: | else: | ||||
| user_request = history[-1]["content"] | user_request = history[-1]["content"] | ||||
| cited = True | cited = True | ||||
| yield "", token_count | yield "", token_count | ||||
| if not cited and need2cite: | |||||
| self.callback("gen_citations", {}, " running ...") | |||||
| _hist = hist | _hist = hist | ||||
| if len(hist) > 12: | if len(hist) > 12: | ||||
| _hist = [hist[0], hist[1], *hist[-10:]] | _hist = [hist[0], hist[1], *hist[-10:]] | ||||
| if not need2cite or cited: | if not need2cite or cited: | ||||
| return | return | ||||
| txt = "" | |||||
| for delta_ans in self._gen_citations(entire_txt): | for delta_ans in self._gen_citations(entire_txt): | ||||
| yield delta_ans, 0 | yield delta_ans, 0 | ||||
| txt += delta_ans | |||||
| self.callback("gen_citations", {}, txt) | |||||
| def append_user_content(hist, content): | def append_user_content(hist, content): | ||||
| if hist[-1]["role"] == "user": | if hist[-1]["role"] == "user": | ||||
| else: | else: | ||||
| hist.append({"role": "user", "content": content}) | hist.append({"role": "user", "content": content}) | ||||
| self.callback("analyze_task", {}, " running ...") | |||||
| task_desc = analyze_task(self.chat_mdl, user_request, tool_metas) | task_desc = analyze_task(self.chat_mdl, user_request, tool_metas) | ||||
| self.callback("analyze_task", {}, task_desc) | |||||
| for _ in range(self._param.max_rounds + 1): | for _ in range(self._param.max_rounds + 1): | ||||
| response, tk = next_step(self.chat_mdl, hist, tool_metas, task_desc) | response, tk = next_step(self.chat_mdl, hist, tool_metas, task_desc) | ||||
| # self.callback("next_step", {}, str(response)[:256]+"...") | # self.callback("next_step", {}, str(response)[:256]+"...") |
| self.delay_after_error = 2.0 | self.delay_after_error = 2.0 | ||||
| self.exception_method = None | self.exception_method = None | ||||
| self.exception_default_value = None | self.exception_default_value = None | ||||
| self.exception_comment = None | |||||
| self.exception_goto = None | self.exception_goto = None | ||||
| self.debug_inputs = {} | self.debug_inputs = {} | ||||
| def as_dict(self): | def as_dict(self): | ||||
| def _recursive_convert_obj_to_dict(obj): | def _recursive_convert_obj_to_dict(obj): | ||||
| ret_dict = {} | ret_dict = {} | ||||
| if isinstance(obj, dict): | |||||
| for k,v in obj.items(): | |||||
| if isinstance(v, dict) or (v and type(v).__name__ not in dir(builtins)): | |||||
| ret_dict[k] = _recursive_convert_obj_to_dict(v) | |||||
| else: | |||||
| ret_dict[k] = v | |||||
| return ret_dict | |||||
| for attr_name in list(obj.__dict__): | for attr_name in list(obj.__dict__): | ||||
| if attr_name in [_FEEDED_DEPRECATED_PARAMS, _DEPRECATED_PARAMS, _USER_FEEDED_PARAMS, _IS_RAW_CONF]: | if attr_name in [_FEEDED_DEPRECATED_PARAMS, _DEPRECATED_PARAMS, _USER_FEEDED_PARAMS, _IS_RAW_CONF]: | ||||
| continue | continue | ||||
| if isinstance(attr, pd.DataFrame): | if isinstance(attr, pd.DataFrame): | ||||
| ret_dict[attr_name] = attr.to_dict() | ret_dict[attr_name] = attr.to_dict() | ||||
| continue | continue | ||||
| if attr and type(attr).__name__ not in dir(builtins): | |||||
| if isinstance(attr, dict) or (attr and type(attr).__name__ not in dir(builtins)): | |||||
| ret_dict[attr_name] = _recursive_convert_obj_to_dict(attr) | ret_dict[attr_name] = _recursive_convert_obj_to_dict(attr) | ||||
| else: | else: | ||||
| ret_dict[attr_name] = attr | ret_dict[attr_name] = attr | ||||
| try: | try: | ||||
| self._invoke(**kwargs) | self._invoke(**kwargs) | ||||
| except Exception as e: | except Exception as e: | ||||
| self._param.outputs["_ERROR"] = {"value": str(e)} | |||||
| if self.get_exception_default_value(): | |||||
| self.set_exception_default_value() | |||||
| else: | |||||
| self.set_output("_ERROR", str(e)) | |||||
| logging.exception(e) | logging.exception(e) | ||||
| self._param.debug_inputs = {} | self._param.debug_inputs = {} | ||||
| self.set_output("_elapsed_time", time.perf_counter() - self.output("_created_time")) | self.set_output("_elapsed_time", time.perf_counter() - self.output("_created_time")) | ||||
| def output(self, var_nm: str=None) -> Union[dict[str, Any], Any]: | def output(self, var_nm: str=None) -> Union[dict[str, Any], Any]: | ||||
| if var_nm: | if var_nm: | ||||
| return self._param.outputs.get(var_nm, {}).get("value") | |||||
| return self._param.outputs.get(var_nm, {}).get("value", "") | |||||
| return {k: o.get("value") for k,o in self._param.outputs.items()} | return {k: o.get("value") for k,o in self._param.outputs.items()} | ||||
| def set_output(self, key: str, value: Any): | def set_output(self, key: str, value: Any): | ||||
| def string_format(content: str, kv: dict[str, str]) -> str: | def string_format(content: str, kv: dict[str, str]) -> str: | ||||
| for n, v in kv.items(): | for n, v in kv.items(): | ||||
| content = re.sub( | content = re.sub( | ||||
| r"\{%s\}" % re.escape(n), re.escape(v), content | |||||
| r"\{%s\}" % re.escape(n), v, content | |||||
| ) | ) | ||||
| return content | return content | ||||
| return | return | ||||
| return { | return { | ||||
| "goto": self._param.exception_goto, | "goto": self._param.exception_goto, | ||||
| "comment": self._param.exception_comment, | |||||
| "default_value": self._param.exception_default_value | "default_value": self._param.exception_default_value | ||||
| } | } | ||||
| def get_exception_default_value(self): | def get_exception_default_value(self): | ||||
| if self._param.exception_method != "comment": | |||||
| return "" | |||||
| return self._param.exception_default_value | return self._param.exception_default_value | ||||
| def set_exception_default_value(self): | |||||
| self.set_output("result", self.get_exception_default_value()) | |||||
| @abstractmethod | @abstractmethod | ||||
| def thoughts(self) -> str: | def thoughts(self) -> str: | ||||
| ... | ... |
| self.set_input_value(k, v) | self.set_input_value(k, v) | ||||
| def thoughts(self) -> str: | def thoughts(self) -> str: | ||||
| return "☕ Here we go..." | |||||
| return "" |
| import json_repair | import json_repair | ||||
| from copy import deepcopy | from copy import deepcopy | ||||
| from functools import partial | from functools import partial | ||||
| from api.db import LLMType | |||||
| from api.db.services.llm_service import LLMBundle, TenantLLMService | from api.db.services.llm_service import LLMBundle, TenantLLMService | ||||
| from agent.component.base import ComponentBase, ComponentParamBase | from agent.component.base import ComponentBase, ComponentParamBase | ||||
| from api.utils.api_utils import timeout | from api.utils.api_utils import timeout | ||||
| self.visual_files_var = None | self.visual_files_var = None | ||||
| def check(self): | def check(self): | ||||
| self.check_decimal_float(self.temperature, "[Agent] Temperature") | |||||
| self.check_decimal_float(self.presence_penalty, "[Agent] Presence penalty") | |||||
| self.check_decimal_float(self.frequency_penalty, "[Agent] Frequency penalty") | |||||
| self.check_nonnegative_number(self.max_tokens, "[Agent] Max tokens") | |||||
| self.check_decimal_float(self.top_p, "[Agent] Top P") | |||||
| self.check_decimal_float(float(self.temperature), "[Agent] Temperature") | |||||
| self.check_decimal_float(float(self.presence_penalty), "[Agent] Presence penalty") | |||||
| self.check_decimal_float(float(self.frequency_penalty), "[Agent] Frequency penalty") | |||||
| self.check_nonnegative_number(int(self.max_tokens), "[Agent] Max tokens") | |||||
| self.check_decimal_float(float(self.top_p), "[Agent] Top P") | |||||
| self.check_empty(self.llm_id, "[Agent] LLM") | self.check_empty(self.llm_id, "[Agent] LLM") | ||||
| self.check_empty(self.sys_prompt, "[Agent] System prompt") | self.check_empty(self.sys_prompt, "[Agent] System prompt") | ||||
| self.check_empty(self.prompts, "[Agent] User prompt") | self.check_empty(self.prompts, "[Agent] User prompt") | ||||
| def gen_conf(self): | def gen_conf(self): | ||||
| conf = {} | conf = {} | ||||
| if self.max_tokens > 0: | |||||
| conf["max_tokens"] = self.max_tokens | |||||
| if self.temperature > 0: | |||||
| conf["temperature"] = self.temperature | |||||
| if self.top_p > 0: | |||||
| conf["top_p"] = self.top_p | |||||
| if self.presence_penalty > 0: | |||||
| conf["presence_penalty"] = self.presence_penalty | |||||
| if self.frequency_penalty > 0: | |||||
| conf["frequency_penalty"] = self.frequency_penalty | |||||
| def get_attr(nm): | |||||
| try: | |||||
| return getattr(self, nm) | |||||
| except Exception: | |||||
| pass | |||||
| if int(self.max_tokens) > 0 and get_attr("maxTokensEnabled"): | |||||
| conf["max_tokens"] = int(self.max_tokens) | |||||
| if float(self.temperature) > 0 and get_attr("temperatureEnabled"): | |||||
| conf["temperature"] = float(self.temperature) | |||||
| if float(self.top_p) > 0 and get_attr("topPEnabled"): | |||||
| conf["top_p"] = float(self.top_p) | |||||
| if float(self.presence_penalty) > 0 and get_attr("presencePenaltyEnabled"): | |||||
| conf["presence_penalty"] = float(self.presence_penalty) | |||||
| if float(self.frequency_penalty) > 0 and get_attr("frequencyPenaltyEnabled"): | |||||
| conf["frequency_penalty"] = float(self.frequency_penalty) | |||||
| return conf | return conf | ||||
| if not self.imgs: | if not self.imgs: | ||||
| self.imgs = [] | self.imgs = [] | ||||
| self.imgs = [img for img in self.imgs if img[:len("data:image/")] == "data:image/"] | self.imgs = [img for img in self.imgs if img[:len("data:image/")] == "data:image/"] | ||||
| if self.imgs and TenantLLMService.llm_id2llm_type(self._param.llm_id) == LLMType.CHAT.value: | |||||
| self.chat_mdl = LLMBundle(self._canvas.get_tenant_id(), LLMType.IMAGE2TEXT.value, | |||||
| self._param.llm_id, max_retries=self._param.max_retries, | |||||
| retry_interval=self._param.delay_after_error | |||||
| ) | |||||
| args = {} | args = {} | ||||
| vars = self.get_input_elements() if not self._param.debug_inputs else self._param.debug_inputs | vars = self.get_input_elements() if not self._param.debug_inputs else self._param.debug_inputs | ||||
| return | return | ||||
| downstreams = self._canvas.get_component(self._id)["downstream"] if self._canvas.get_component(self._id) else [] | downstreams = self._canvas.get_component(self._id)["downstream"] if self._canvas.get_component(self._id) else [] | ||||
| if any([self._canvas.get_component_obj(cid).component_name.lower()=="message" for cid in downstreams]) and not self._param.output_structure: | |||||
| ex = self.exception_handler() | |||||
| if any([self._canvas.get_component_obj(cid).component_name.lower()=="message" for cid in downstreams]) and not self._param.output_structure and not (ex and ex["goto"]): | |||||
| self.set_output("content", partial(self._stream_output, prompt, msg)) | self.set_output("content", partial(self._stream_output, prompt, msg)) | ||||
| return | return | ||||
| break | break | ||||
| if error: | if error: | ||||
| self.set_output("_ERROR", error) | |||||
| if self.get_exception_default_value(): | if self.get_exception_default_value(): | ||||
| self.set_output("content", self.get_exception_default_value()) | self.set_output("content", self.get_exception_default_value()) | ||||
| else: | |||||
| self.set_output("_ERROR", error) | |||||
| def _stream_output(self, prompt, msg): | def _stream_output(self, prompt, msg): | ||||
| _, msg = message_fit_in([{"role": "system", "content": prompt}, *msg], int(self.chat_mdl.max_length * 0.97)) | _, msg = message_fit_in([{"role": "system", "content": prompt}, *msg], int(self.chat_mdl.max_length * 0.97)) | ||||
| answer = "" | answer = "" | ||||
| for ans in self._generate_streamly(msg): | for ans in self._generate_streamly(msg): | ||||
| if ans.find("**ERROR**") >= 0: | |||||
| if self.get_exception_default_value(): | |||||
| self.set_output("content", self.get_exception_default_value()) | |||||
| yield self.get_exception_default_value() | |||||
| else: | |||||
| self.set_output("_ERROR", ans) | |||||
| return | |||||
| yield ans | yield ans | ||||
| answer += ans | answer += ans | ||||
| self.set_output("content", answer) | self.set_output("content", answer) | ||||
| def thoughts(self) -> str: | def thoughts(self) -> str: | ||||
| _, msg = self._prepare_prompt_variables() | _, msg = self._prepare_prompt_variables() | ||||
| return f"I’m thinking and planning the next move, starting from the prompt:<br/>“{msg[-1]['content']}”<span class=\"collapse\"> (tap to see full text)</span>" | |||||
| return "⌛Give me a moment—starting from: \n\n" + re.sub(r"(User's query:|[\\]+)", '', msg[-1]['content'], flags=re.DOTALL) + "\n\nI’ll figure out our best next move." |
| self.set_output("content", content) | self.set_output("content", content) | ||||
| def thoughts(self) -> str: | def thoughts(self) -> str: | ||||
| return "Thinking ..." | |||||
| return "" |
| { | |||||
| "id": 8, | |||||
| "title": "Generate SEO Blog", | |||||
| "description": "This is a multi-agent version of the SEO blog generation workflow. It simulates a small team of AI “writers”, where each agent plays a specialized role — just like a real editorial team.", | |||||
| "canvas_type": "Agent", | |||||
| "dsl": { | |||||
| "components": { | |||||
| "Agent:LuckyApplesGrab": { | |||||
| "downstream": [ | |||||
| "Message:ModernSwansThrow" | |||||
| ], | |||||
| "obj": { | |||||
| "component_name": "Agent", | |||||
| "params": { | |||||
| "delay_after_error": 1, | |||||
| "description": "", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.5, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 3, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Precise", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.5, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "The user query is {sys.query}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Lead Agent**, responsible for initiating the multi-agent SEO blog generation process. You will receive the user\u2019s topic and blog goal, interpret the intent, and coordinate the downstream writing agents.\n\n# Goals\n\n1. Parse the user's initial input.\n\n2. Generate a high-level blog intent summary and writing plan.\n\n3. Provide clear instructions to the following Sub_Agents:\n\n - `Outline Agent` \u2192 Create the blog outline.\n\n - `Body Agent` \u2192 Write all sections based on outline.\n\n - `Editor Agent` \u2192 Polish and finalize the blog post.\n\n4. Merge outputs into a complete, readable blog draft in Markdown format.\n\n# Input\n\nYou will receive:\n\n- Blog topic\n\n- Target audience\n\n- Blog goal (e.g., SEO, education, product marketing)\n\n# Output Format\n\n```markdown\n\n## Parsed Writing Plan\n\n- **Topic**: [Extracted from user input]\n\n- **Audience**: [Summarized from user input]\n\n- **Intent**: [Inferred goal and style]\n\n- **Blog Type**: [e.g., Tutorial / Informative Guide / Marketing Content]\n\n- **Long-tail Keywords**: \n\n - keyword 1\n\n - keyword 2\n\n - keyword 3\n\n - ...\n\n## Instructions for Outline Agent\n\nPlease generate a structured outline including H2 and H3 headings. Assign 1\u20132 relevant keywords to each section. Keep it aligned with the user\u2019s intent and audience level.\n\n## Instructions for Body Agent\n\nWrite the full content based on the outline. Each section should be concise (500\u2013600 words), informative, and optimized for SEO. Use `Tavily Search` only when additional examples or context are needed.\n\n## Instructions for Editor Agent\n\nReview and refine the combined content. Improve transitions, ensure keyword integration, and add a meta title + meta description. Maintain Markdown formatting.\n\n\n## Guides\n\n- Do not generate blog content directly.\n\n- Focus on correct intent recognition and instruction generation.\n\n- Keep communication to downstream agents simple, scoped, and accurate.\n\n\n## Input Examples (and how to handle them)\n\nInput: \"I want to write about RAGFlow.\"\n\u2192 Output: Informative Guide, Audience: AI developers, Intent: explain what RAGFlow is and its use cases\n\nInput: \"Need a blog to promote our prompt design tool.\"\n\u2192 Output: Marketing Content, Audience: product managers or tool adopters, Intent: raise awareness and interest in the product\n\nInput: \"How to get more Google traffic using AI\"\n\u2192 Output: How-to, Audience: SEO marketers, Intent: guide readers on applying AI for SEO growth", | |||||
| "temperature": "0.1", | |||||
| "temperatureEnabled": true, | |||||
| "tools": [ | |||||
| { | |||||
| "component_name": "Agent", | |||||
| "id": "Agent:SlickSpidersTurn", | |||||
| "name": "Outline Agent", | |||||
| "params": { | |||||
| "delay_after_error": 1, | |||||
| "description": "Generates a clear and SEO-friendly blog outline using H2/H3 headings based on the topic, audience, and intent provided by the lead agent. Each section includes suggested keywords for optimized downstream writing.\n", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.3, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 2, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Balance", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.2, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "{sys.query}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Outline Agent**, a sub-agent in a multi-agent SEO blog writing system. You operate under the instruction of the `Lead Agent`, and your sole responsibility is to create a clear, well-structured, and SEO-optimized blog outline.\n\n# Tool Access:\n\n- You have access to a search tool called `Tavily Search`.\n\n- If you are unsure how to structure a section, you may call this tool to search for related blog outlines or content from Google.\n\n- Do not overuse it. Your job is to extract **structure**, not to write paragraphs.\n\n\n# Goals\n\n1. Create a well-structured outline with appropriate H2 and H3 headings.\n\n2. Ensure logical flow from introduction to conclusion.\n\n3. Assign 1\u20132 suggested long-tail keywords to each major section for SEO alignment.\n\n4. Make the structure suitable for downstream paragraph writing.\n\n\n\n\n#Note\n\n- Use concise, scannable section titles.\n\n- Do not write full paragraphs.\n\n- Prioritize clarity, logical progression, and SEO alignment.\n\n\n\n- If the blog type is \u201cTutorial\u201d or \u201cHow-to\u201d, include step-based sections.\n\n\n# Input\n\nYou will receive:\n\n- Writing Type (e.g., Tutorial, Informative Guide)\n\n- Target Audience\n\n- User Intent Summary\n\n- 3\u20135 long-tail keywords\n\n\nUse this information to design a structure that both informs readers and maximizes search engine visibility.\n\n# Output Format\n\n```markdown\n\n## Blog Title (suggested)\n\n[Give a short, SEO-friendly title suggestion]\n\n## Outline\n\n### Introduction\n\n- Purpose of the article\n\n- Brief context\n\n- **Suggested keywords**: [keyword1, keyword2]\n\n### H2: [Section Title 1]\n\n- [Short description of what this section will cover]\n\n- **Suggested keywords**: [keyword1, keyword2]\n\n### H2: [Section Title 2]\n\n- [Short description of what this section will cover]\n\n- **Suggested keywords**: [keyword1, keyword2]\n\n### H2: [Section Title 3]\n\n- [Optional H3 Subsection Title A]\n\n - [Explanation of sub-point]\n\n- [Optional H3 Subsection Title B]\n\n - [Explanation of sub-point]\n\n- **Suggested keywords**: [keyword1]\n\n### Conclusion\n\n- Recap key takeaways\n\n- Optional CTA (Call to Action)\n\n- **Suggested keywords**: [keyword3]\n\n", | |||||
| "temperature": 0.5, | |||||
| "temperatureEnabled": true, | |||||
| "tools": [ | |||||
| { | |||||
| "component_name": "TavilySearch", | |||||
| "name": "TavilySearch", | |||||
| "params": { | |||||
| "api_key": "", | |||||
| "days": 7, | |||||
| "exclude_domains": [], | |||||
| "include_answer": false, | |||||
| "include_domains": [], | |||||
| "include_image_descriptions": false, | |||||
| "include_images": false, | |||||
| "include_raw_content": true, | |||||
| "max_results": 5, | |||||
| "outputs": { | |||||
| "formalized_content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| }, | |||||
| "json": { | |||||
| "type": "Array<Object>", | |||||
| "value": [] | |||||
| } | |||||
| }, | |||||
| "query": "sys.query", | |||||
| "search_depth": "basic", | |||||
| "topic": "general" | |||||
| } | |||||
| } | |||||
| ], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.85, | |||||
| "user_prompt": "This is the order you need to send to the agent.", | |||||
| "visual_files_var": "" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "component_name": "Agent", | |||||
| "id": "Agent:IcyPawsRescue", | |||||
| "name": "Body Agent", | |||||
| "params": { | |||||
| "delay_after_error": 1, | |||||
| "description": "Writes the full blog content section-by-section following the outline structure. It integrates target keywords naturally and uses Tavily Search only when additional facts or examples are needed.\n", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.5, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 3, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Precise", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.5, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "{sys.query}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Body Agent**, a sub-agent in a multi-agent SEO blog writing system. You operate under the instruction of the `Lead Agent`, and your job is to write the full blog content based on the outline created by the `OutlineWriter_Agent`.\n\n\n\n# Tool Access:\n\nYou can use the `Tavily Search` tool to retrieve relevant content, statistics, or examples to support each section you're writing.\n\nUse it **only** when the provided outline lacks enough information, or if the section requires factual grounding.\n\nAlways cite the original link or indicate source where possible.\n\n\n# Goals\n\n1. Write each section (based on H2/H3 structure) as a complete and natural blog paragraph.\n\n2. Integrate the suggested long-tail keywords naturally into each section.\n\n3. When appropriate, use the `Tavily Search` tool to enrich your writing with relevant facts, examples, or quotes.\n\n4. Ensure each section is clear, engaging, and informative, suitable for both human readers and search engines.\n\n\n# Style Guidelines\n\n- Write in a tone appropriate to the audience. Be explanatory, not promotional, unless it's a marketing blog.\n\n- Avoid generic filler content. Prioritize clarity, structure, and value.\n\n- Ensure SEO keywords are embedded seamlessly, not forcefully.\n\n\n\n- Maintain writing rhythm. Vary sentence lengths. Use transitions between ideas.\n\n\n# Input\n\n\nYou will receive:\n\n- Blog title\n\n- Structured outline (including section titles, keywords, and descriptions)\n\n- Target audience\n\n- Blog type and user intent\n\nYou must **follow the outline strictly**. Write content **section-by-section**, based on the structure.\n\n\n# Output Format\n\n```markdown\n\n## H2: [Section Title]\n\n[Your generated content for this section \u2014 500-600 words, using keywords naturally.]\n\n", | |||||
| "temperature": 0.2, | |||||
| "temperatureEnabled": true, | |||||
| "tools": [ | |||||
| { | |||||
| "component_name": "TavilySearch", | |||||
| "name": "TavilySearch", | |||||
| "params": { | |||||
| "api_key": "", | |||||
| "days": 7, | |||||
| "exclude_domains": [], | |||||
| "include_answer": false, | |||||
| "include_domains": [], | |||||
| "include_image_descriptions": false, | |||||
| "include_images": false, | |||||
| "include_raw_content": true, | |||||
| "max_results": 5, | |||||
| "outputs": { | |||||
| "formalized_content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| }, | |||||
| "json": { | |||||
| "type": "Array<Object>", | |||||
| "value": [] | |||||
| } | |||||
| }, | |||||
| "query": "sys.query", | |||||
| "search_depth": "basic", | |||||
| "topic": "general" | |||||
| } | |||||
| } | |||||
| ], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.75, | |||||
| "user_prompt": "This is the order you need to send to the agent.", | |||||
| "visual_files_var": "" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "component_name": "Agent", | |||||
| "id": "Agent:TenderAdsAllow", | |||||
| "name": "Editor Agent", | |||||
| "params": { | |||||
| "delay_after_error": 1, | |||||
| "description": "Polishes and finalizes the entire blog post. Enhances clarity, checks keyword usage, improves flow, and generates a meta title and description for SEO. Operates after all sections are completed.\n\n", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.5, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 2, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Precise", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.5, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "{sys.query}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Editor Agent**, the final agent in a multi-agent SEO blog writing workflow. You are responsible for finalizing the blog post for both human readability and SEO effectiveness.\n\n# Goals\n\n1. Polish the entire blog content for clarity, coherence, and style.\n\n2. Improve transitions between sections, ensure logical flow.\n\n3. Verify that keywords are used appropriately and effectively.\n\n4. Conduct a lightweight SEO audit \u2014 checking keyword density, structure (H1/H2/H3), and overall searchability.\n\n\n\n## Integration Responsibilities\n\n- Maintain alignment with Lead Agent's original intent and audience\n\n- Preserve the structure and keyword strategy from Outline Agent\n\n- Enhance and polish Body Agent's content without altering core information\n\n# Style Guidelines\n\n- Be precise. Avoid bloated or vague language.\n\n- Maintain an informative and engaging tone, suitable to the target audience.\n\n- Do not remove keywords unless absolutely necessary for clarity.\n\n- Ensure paragraph flow and section continuity.\n\n\n\n# Input\n\nYou will receive:\n\n- Full blog content, written section-by-section\n\n- Original outline with suggested keywords\n\n- Target audience and writing type\n\n# Output Format\n\n```markdown\n\n[The revised, fully polished blog post content goes here.]\n", | |||||
| "temperature": 0.2, | |||||
| "temperatureEnabled": true, | |||||
| "tools": [], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.75, | |||||
| "user_prompt": "This is the order you need to send to the agent.", | |||||
| "visual_files_var": "" | |||||
| } | |||||
| } | |||||
| ], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.75, | |||||
| "user_prompt": "", | |||||
| "visual_files_var": "" | |||||
| } | |||||
| }, | |||||
| "upstream": [ | |||||
| "begin" | |||||
| ] | |||||
| }, | |||||
| "Message:ModernSwansThrow": { | |||||
| "downstream": [], | |||||
| "obj": { | |||||
| "component_name": "Message", | |||||
| "params": { | |||||
| "content": [ | |||||
| "{Agent:LuckyApplesGrab@content}" | |||||
| ] | |||||
| } | |||||
| }, | |||||
| "upstream": [ | |||||
| "Agent:LuckyApplesGrab" | |||||
| ] | |||||
| }, | |||||
| "begin": { | |||||
| "downstream": [ | |||||
| "Agent:LuckyApplesGrab" | |||||
| ], | |||||
| "obj": { | |||||
| "component_name": "Begin", | |||||
| "params": { | |||||
| "enablePrologue": true, | |||||
| "inputs": {}, | |||||
| "mode": "conversational", | |||||
| "prologue": "Hi! I'm your SEO blog assistant.\n\nTo get started, please tell me:\n1. What topic you want the blog to cover\n2. Who is the target audience\n3. What you hope to achieve with this blog (e.g., SEO traffic, teaching beginners, promoting a product)\n" | |||||
| } | |||||
| }, | |||||
| "upstream": [] | |||||
| } | |||||
| }, | |||||
| "globals": { | |||||
| "sys.conversation_turns": 0, | |||||
| "sys.files": [], | |||||
| "sys.query": "", | |||||
| "sys.user_id": "" | |||||
| }, | |||||
| "graph": { | |||||
| "edges": [ | |||||
| { | |||||
| "data": { | |||||
| "isHovered": false | |||||
| }, | |||||
| "id": "xy-edge__beginstart-Agent:LuckyApplesGrabend", | |||||
| "source": "begin", | |||||
| "sourceHandle": "start", | |||||
| "target": "Agent:LuckyApplesGrab", | |||||
| "targetHandle": "end" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "isHovered": false | |||||
| }, | |||||
| "id": "xy-edge__Agent:LuckyApplesGrabstart-Message:ModernSwansThrowend", | |||||
| "source": "Agent:LuckyApplesGrab", | |||||
| "sourceHandle": "start", | |||||
| "target": "Message:ModernSwansThrow", | |||||
| "targetHandle": "end" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "isHovered": false | |||||
| }, | |||||
| "id": "xy-edge__Agent:LuckyApplesGrabagentBottom-Agent:SlickSpidersTurnagentTop", | |||||
| "source": "Agent:LuckyApplesGrab", | |||||
| "sourceHandle": "agentBottom", | |||||
| "target": "Agent:SlickSpidersTurn", | |||||
| "targetHandle": "agentTop" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "isHovered": false | |||||
| }, | |||||
| "id": "xy-edge__Agent:LuckyApplesGrabagentBottom-Agent:IcyPawsRescueagentTop", | |||||
| "source": "Agent:LuckyApplesGrab", | |||||
| "sourceHandle": "agentBottom", | |||||
| "target": "Agent:IcyPawsRescue", | |||||
| "targetHandle": "agentTop" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "isHovered": false | |||||
| }, | |||||
| "id": "xy-edge__Agent:LuckyApplesGrabagentBottom-Agent:TenderAdsAllowagentTop", | |||||
| "source": "Agent:LuckyApplesGrab", | |||||
| "sourceHandle": "agentBottom", | |||||
| "target": "Agent:TenderAdsAllow", | |||||
| "targetHandle": "agentTop" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "isHovered": false | |||||
| }, | |||||
| "id": "xy-edge__Agent:SlickSpidersTurntool-Tool:ThreeWallsRingend", | |||||
| "source": "Agent:SlickSpidersTurn", | |||||
| "sourceHandle": "tool", | |||||
| "target": "Tool:ThreeWallsRing", | |||||
| "targetHandle": "end" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "isHovered": false | |||||
| }, | |||||
| "id": "xy-edge__Agent:IcyPawsRescuetool-Tool:FloppyJokesItchend", | |||||
| "source": "Agent:IcyPawsRescue", | |||||
| "sourceHandle": "tool", | |||||
| "target": "Tool:FloppyJokesItch", | |||||
| "targetHandle": "end" | |||||
| } | |||||
| ], | |||||
| "nodes": [ | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "enablePrologue": true, | |||||
| "inputs": {}, | |||||
| "mode": "conversational", | |||||
| "prologue": "Hi! I'm your SEO blog assistant.\n\nTo get started, please tell me:\n1. What topic you want the blog to cover\n2. Who is the target audience\n3. What you hope to achieve with this blog (e.g., SEO traffic, teaching beginners, promoting a product)\n" | |||||
| }, | |||||
| "label": "Begin", | |||||
| "name": "begin" | |||||
| }, | |||||
| "dragging": false, | |||||
| "id": "begin", | |||||
| "measured": { | |||||
| "height": 48, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": 38.19445084117184, | |||||
| "y": 183.9781832844475 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "left", | |||||
| "targetPosition": "right", | |||||
| "type": "beginNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "delay_after_error": 1, | |||||
| "description": "", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.5, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 3, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Precise", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.5, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "The user query is {sys.query}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Lead Agent**, responsible for initiating the multi-agent SEO blog generation process. You will receive the user\u2019s topic and blog goal, interpret the intent, and coordinate the downstream writing agents.\n\n# Goals\n\n1. Parse the user's initial input.\n\n2. Generate a high-level blog intent summary and writing plan.\n\n3. Provide clear instructions to the following Sub_Agents:\n\n - `Outline Agent` \u2192 Create the blog outline.\n\n - `Body Agent` \u2192 Write all sections based on outline.\n\n - `Editor Agent` \u2192 Polish and finalize the blog post.\n\n4. Merge outputs into a complete, readable blog draft in Markdown format.\n\n# Input\n\nYou will receive:\n\n- Blog topic\n\n- Target audience\n\n- Blog goal (e.g., SEO, education, product marketing)\n\n# Output Format\n\n```markdown\n\n## Parsed Writing Plan\n\n- **Topic**: [Extracted from user input]\n\n- **Audience**: [Summarized from user input]\n\n- **Intent**: [Inferred goal and style]\n\n- **Blog Type**: [e.g., Tutorial / Informative Guide / Marketing Content]\n\n- **Long-tail Keywords**: \n\n - keyword 1\n\n - keyword 2\n\n - keyword 3\n\n - ...\n\n## Instructions for Outline Agent\n\nPlease generate a structured outline including H2 and H3 headings. Assign 1\u20132 relevant keywords to each section. Keep it aligned with the user\u2019s intent and audience level.\n\n## Instructions for Body Agent\n\nWrite the full content based on the outline. Each section should be concise (500\u2013600 words), informative, and optimized for SEO. Use `Tavily Search` only when additional examples or context are needed.\n\n## Instructions for Editor Agent\n\nReview and refine the combined content. Improve transitions, ensure keyword integration, and add a meta title + meta description. Maintain Markdown formatting.\n\n\n## Guides\n\n- Do not generate blog content directly.\n\n- Focus on correct intent recognition and instruction generation.\n\n- Keep communication to downstream agents simple, scoped, and accurate.\n\n\n## Input Examples (and how to handle them)\n\nInput: \"I want to write about RAGFlow.\"\n\u2192 Output: Informative Guide, Audience: AI developers, Intent: explain what RAGFlow is and its use cases\n\nInput: \"Need a blog to promote our prompt design tool.\"\n\u2192 Output: Marketing Content, Audience: product managers or tool adopters, Intent: raise awareness and interest in the product\n\nInput: \"How to get more Google traffic using AI\"\n\u2192 Output: How-to, Audience: SEO marketers, Intent: guide readers on applying AI for SEO growth", | |||||
| "temperature": "0.1", | |||||
| "temperatureEnabled": true, | |||||
| "tools": [], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.75, | |||||
| "user_prompt": "", | |||||
| "visual_files_var": "" | |||||
| }, | |||||
| "label": "Agent", | |||||
| "name": "Lead Agent" | |||||
| }, | |||||
| "id": "Agent:LuckyApplesGrab", | |||||
| "measured": { | |||||
| "height": 84, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": 350, | |||||
| "y": 200 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "agentNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "content": [ | |||||
| "{Agent:LuckyApplesGrab@content}" | |||||
| ] | |||||
| }, | |||||
| "label": "Message", | |||||
| "name": "Response" | |||||
| }, | |||||
| "dragging": false, | |||||
| "id": "Message:ModernSwansThrow", | |||||
| "measured": { | |||||
| "height": 56, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": 669.394830760932, | |||||
| "y": 190.72421137520644 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "messageNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "delay_after_error": 1, | |||||
| "description": "Generates a clear and SEO-friendly blog outline using H2/H3 headings based on the topic, audience, and intent provided by the lead agent. Each section includes suggested keywords for optimized downstream writing.\n", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.3, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 2, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Balance", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.2, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "{sys.query}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Outline Agent**, a sub-agent in a multi-agent SEO blog writing system. You operate under the instruction of the `Lead Agent`, and your sole responsibility is to create a clear, well-structured, and SEO-optimized blog outline.\n\n# Tool Access:\n\n- You have access to a search tool called `Tavily Search`.\n\n- If you are unsure how to structure a section, you may call this tool to search for related blog outlines or content from Google.\n\n- Do not overuse it. Your job is to extract **structure**, not to write paragraphs.\n\n\n# Goals\n\n1. Create a well-structured outline with appropriate H2 and H3 headings.\n\n2. Ensure logical flow from introduction to conclusion.\n\n3. Assign 1\u20132 suggested long-tail keywords to each major section for SEO alignment.\n\n4. Make the structure suitable for downstream paragraph writing.\n\n\n\n\n#Note\n\n- Use concise, scannable section titles.\n\n- Do not write full paragraphs.\n\n- Prioritize clarity, logical progression, and SEO alignment.\n\n\n\n- If the blog type is \u201cTutorial\u201d or \u201cHow-to\u201d, include step-based sections.\n\n\n# Input\n\nYou will receive:\n\n- Writing Type (e.g., Tutorial, Informative Guide)\n\n- Target Audience\n\n- User Intent Summary\n\n- 3\u20135 long-tail keywords\n\n\nUse this information to design a structure that both informs readers and maximizes search engine visibility.\n\n# Output Format\n\n```markdown\n\n## Blog Title (suggested)\n\n[Give a short, SEO-friendly title suggestion]\n\n## Outline\n\n### Introduction\n\n- Purpose of the article\n\n- Brief context\n\n- **Suggested keywords**: [keyword1, keyword2]\n\n### H2: [Section Title 1]\n\n- [Short description of what this section will cover]\n\n- **Suggested keywords**: [keyword1, keyword2]\n\n### H2: [Section Title 2]\n\n- [Short description of what this section will cover]\n\n- **Suggested keywords**: [keyword1, keyword2]\n\n### H2: [Section Title 3]\n\n- [Optional H3 Subsection Title A]\n\n - [Explanation of sub-point]\n\n- [Optional H3 Subsection Title B]\n\n - [Explanation of sub-point]\n\n- **Suggested keywords**: [keyword1]\n\n### Conclusion\n\n- Recap key takeaways\n\n- Optional CTA (Call to Action)\n\n- **Suggested keywords**: [keyword3]\n\n", | |||||
| "temperature": 0.5, | |||||
| "temperatureEnabled": true, | |||||
| "tools": [ | |||||
| { | |||||
| "component_name": "TavilySearch", | |||||
| "name": "TavilySearch", | |||||
| "params": { | |||||
| "api_key": "", | |||||
| "days": 7, | |||||
| "exclude_domains": [], | |||||
| "include_answer": false, | |||||
| "include_domains": [], | |||||
| "include_image_descriptions": false, | |||||
| "include_images": false, | |||||
| "include_raw_content": true, | |||||
| "max_results": 5, | |||||
| "outputs": { | |||||
| "formalized_content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| }, | |||||
| "json": { | |||||
| "type": "Array<Object>", | |||||
| "value": [] | |||||
| } | |||||
| }, | |||||
| "query": "sys.query", | |||||
| "search_depth": "basic", | |||||
| "topic": "general" | |||||
| } | |||||
| } | |||||
| ], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.85, | |||||
| "user_prompt": "This is the order you need to send to the agent.", | |||||
| "visual_files_var": "" | |||||
| }, | |||||
| "label": "Agent", | |||||
| "name": "Outline Agent" | |||||
| }, | |||||
| "dragging": false, | |||||
| "id": "Agent:SlickSpidersTurn", | |||||
| "measured": { | |||||
| "height": 84, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": 100.60137004146719, | |||||
| "y": 411.67654846431367 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "agentNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "delay_after_error": 1, | |||||
| "description": "Writes the full blog content section-by-section following the outline structure. It integrates target keywords naturally and uses Tavily Search only when additional facts or examples are needed.\n", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.5, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 3, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Precise", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.5, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "{sys.query}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Body Agent**, a sub-agent in a multi-agent SEO blog writing system. You operate under the instruction of the `Lead Agent`, and your job is to write the full blog content based on the outline created by the `OutlineWriter_Agent`.\n\n\n\n# Tool Access:\n\nYou can use the `Tavily Search` tool to retrieve relevant content, statistics, or examples to support each section you're writing.\n\nUse it **only** when the provided outline lacks enough information, or if the section requires factual grounding.\n\nAlways cite the original link or indicate source where possible.\n\n\n# Goals\n\n1. Write each section (based on H2/H3 structure) as a complete and natural blog paragraph.\n\n2. Integrate the suggested long-tail keywords naturally into each section.\n\n3. When appropriate, use the `Tavily Search` tool to enrich your writing with relevant facts, examples, or quotes.\n\n4. Ensure each section is clear, engaging, and informative, suitable for both human readers and search engines.\n\n\n# Style Guidelines\n\n- Write in a tone appropriate to the audience. Be explanatory, not promotional, unless it's a marketing blog.\n\n- Avoid generic filler content. Prioritize clarity, structure, and value.\n\n- Ensure SEO keywords are embedded seamlessly, not forcefully.\n\n\n\n- Maintain writing rhythm. Vary sentence lengths. Use transitions between ideas.\n\n\n# Input\n\n\nYou will receive:\n\n- Blog title\n\n- Structured outline (including section titles, keywords, and descriptions)\n\n- Target audience\n\n- Blog type and user intent\n\nYou must **follow the outline strictly**. Write content **section-by-section**, based on the structure.\n\n\n# Output Format\n\n```markdown\n\n## H2: [Section Title]\n\n[Your generated content for this section \u2014 500-600 words, using keywords naturally.]\n\n", | |||||
| "temperature": 0.2, | |||||
| "temperatureEnabled": true, | |||||
| "tools": [ | |||||
| { | |||||
| "component_name": "TavilySearch", | |||||
| "name": "TavilySearch", | |||||
| "params": { | |||||
| "api_key": "", | |||||
| "days": 7, | |||||
| "exclude_domains": [], | |||||
| "include_answer": false, | |||||
| "include_domains": [], | |||||
| "include_image_descriptions": false, | |||||
| "include_images": false, | |||||
| "include_raw_content": true, | |||||
| "max_results": 5, | |||||
| "outputs": { | |||||
| "formalized_content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| }, | |||||
| "json": { | |||||
| "type": "Array<Object>", | |||||
| "value": [] | |||||
| } | |||||
| }, | |||||
| "query": "sys.query", | |||||
| "search_depth": "basic", | |||||
| "topic": "general" | |||||
| } | |||||
| } | |||||
| ], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.75, | |||||
| "user_prompt": "This is the order you need to send to the agent.", | |||||
| "visual_files_var": "" | |||||
| }, | |||||
| "label": "Agent", | |||||
| "name": "Body Agent" | |||||
| }, | |||||
| "dragging": false, | |||||
| "id": "Agent:IcyPawsRescue", | |||||
| "measured": { | |||||
| "height": 84, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": 439.3374395738501, | |||||
| "y": 366.1408588516909 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "agentNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "delay_after_error": 1, | |||||
| "description": "Polishes and finalizes the entire blog post. Enhances clarity, checks keyword usage, improves flow, and generates a meta title and description for SEO. Operates after all sections are completed.\n\n", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.5, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 2, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Precise", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.5, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "{sys.query}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Editor Agent**, the final agent in a multi-agent SEO blog writing workflow. You are responsible for finalizing the blog post for both human readability and SEO effectiveness.\n\n# Goals\n\n1. Polish the entire blog content for clarity, coherence, and style.\n\n2. Improve transitions between sections, ensure logical flow.\n\n3. Verify that keywords are used appropriately and effectively.\n\n4. Conduct a lightweight SEO audit \u2014 checking keyword density, structure (H1/H2/H3), and overall searchability.\n\n\n\n## Integration Responsibilities\n\n- Maintain alignment with Lead Agent's original intent and audience\n\n- Preserve the structure and keyword strategy from Outline Agent\n\n- Enhance and polish Body Agent's content without altering core information\n\n# Style Guidelines\n\n- Be precise. Avoid bloated or vague language.\n\n- Maintain an informative and engaging tone, suitable to the target audience.\n\n- Do not remove keywords unless absolutely necessary for clarity.\n\n- Ensure paragraph flow and section continuity.\n\n\n\n# Input\n\nYou will receive:\n\n- Full blog content, written section-by-section\n\n- Original outline with suggested keywords\n\n- Target audience and writing type\n\n# Output Format\n\n```markdown\n\n[The revised, fully polished blog post content goes here.]\n", | |||||
| "temperature": 0.2, | |||||
| "temperatureEnabled": true, | |||||
| "tools": [], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.75, | |||||
| "user_prompt": "This is the order you need to send to the agent.", | |||||
| "visual_files_var": "" | |||||
| }, | |||||
| "label": "Agent", | |||||
| "name": "Editor Agent" | |||||
| }, | |||||
| "dragging": false, | |||||
| "id": "Agent:TenderAdsAllow", | |||||
| "measured": { | |||||
| "height": 84, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": 730.8513124709204, | |||||
| "y": 327.351197329827 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "agentNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "description": "This is an agent for a specific task.", | |||||
| "user_prompt": "This is the order you need to send to the agent." | |||||
| }, | |||||
| "label": "Tool", | |||||
| "name": "flow.tool_0" | |||||
| }, | |||||
| "dragging": false, | |||||
| "id": "Tool:ThreeWallsRing", | |||||
| "measured": { | |||||
| "height": 48, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": -26.93431957115564, | |||||
| "y": 531.4384641920368 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "toolNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "description": "This is an agent for a specific task.", | |||||
| "user_prompt": "This is the order you need to send to the agent." | |||||
| }, | |||||
| "label": "Tool", | |||||
| "name": "flow.tool_1" | |||||
| }, | |||||
| "dragging": false, | |||||
| "id": "Tool:FloppyJokesItch", | |||||
| "measured": { | |||||
| "height": 48, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": 414.6786783453011, | |||||
| "y": 499.39483076093194 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "toolNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "text": "This is a multi-agent version of the SEO blog generation workflow. It simulates a small team of AI \u201cwriters\u201d, where each agent plays a specialized role \u2014 just like a real editorial team.\n\nInstead of one AI doing everything in order, this version uses a **Lead Agent** to assign tasks to different sub-agents, who then write and edit the blog in parallel. The Lead Agent manages everything and produces the final output.\n\n### Why use multi-agent format?\n\n- Better control over each stage of writing \n- Easier to reuse agents across tasks \n- More human-like workflow (planning \u2192 writing \u2192 editing \u2192 publishing) \n- Easier to scale and customize for advanced users\n\n### Flow Summary:\n\n1. `LeadWriter_Agent` takes your input and creates a plan\n2. It sends that plan to:\n - `OutlineWriter_Agent`: build blog structure\n - `BodyWriter_Agent`: write full content\n - `FinalEditor_Agent`: polish and finalize\n3. `LeadWriter_Agent` collects all results and outputs the final blog post\n" | |||||
| }, | |||||
| "label": "Note", | |||||
| "name": "Workflow Overall Description" | |||||
| }, | |||||
| "dragHandle": ".note-drag-handle", | |||||
| "dragging": false, | |||||
| "height": 208, | |||||
| "id": "Note:ElevenVansInvent", | |||||
| "measured": { | |||||
| "height": 208, | |||||
| "width": 518 | |||||
| }, | |||||
| "position": { | |||||
| "x": -336.6586460874556, | |||||
| "y": 113.43253511344867 | |||||
| }, | |||||
| "resizing": false, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "noteNode", | |||||
| "width": 518 | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "text": "**Purpose**: \nThis is the central agent that controls the entire writing process.\n\n**What it does**:\n- Reads your blog topic and intent\n- Generates a clear writing plan (topic, audience, goal, keywords)\n- Sends instructions to all sub-agents\n- Waits for their responses and checks quality\n- If any section is missing or weak, it can request a rewrite\n- Finally, it assembles all parts into a complete blog and sends it back to you\n" | |||||
| }, | |||||
| "label": "Note", | |||||
| "name": "Lead Agent" | |||||
| }, | |||||
| "dragHandle": ".note-drag-handle", | |||||
| "dragging": false, | |||||
| "height": 146, | |||||
| "id": "Note:EmptyClubsGreet", | |||||
| "measured": { | |||||
| "height": 146, | |||||
| "width": 334 | |||||
| }, | |||||
| "position": { | |||||
| "x": 390.1408623279084, | |||||
| "y": 2.6521144030202493 | |||||
| }, | |||||
| "resizing": false, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "noteNode", | |||||
| "width": 334 | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "text": "**Purpose**: \nThis agent is responsible for building the blog's structure. It creates an outline that shows what the article will cover and how it's organized.\n\n**What it does**:\n- Suggests a blog title that matches the topic and keywords \n- Breaks the article into sections using H2 and H3 headers \n- Adds a short description of what each section should include \n- Assigns SEO keywords to each section for better search visibility \n- Uses search data (via Tavily Search) to find how similar blogs are structured" | |||||
| }, | |||||
| "label": "Note", | |||||
| "name": "Outline Agent" | |||||
| }, | |||||
| "dragHandle": ".note-drag-handle", | |||||
| "dragging": false, | |||||
| "height": 157, | |||||
| "id": "Note:CurlyTigersDouble", | |||||
| "measured": { | |||||
| "height": 157, | |||||
| "width": 394 | |||||
| }, | |||||
| "position": { | |||||
| "x": -60.03139680691618, | |||||
| "y": 595.8208080534818 | |||||
| }, | |||||
| "resizing": false, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "noteNode", | |||||
| "width": 394 | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "text": "**Purpose**: \nThis agent is in charge of writing the full blog content, section by section, based on the outline it receives.\n\n**What it does**:\n- Takes each section heading from the outline (H2 / H3)\n- Writes a complete paragraph (150\u2013220 words) under each section\n- Naturally includes the keywords provided for that section\n- Uses the Tavily Search tool to add real-world examples, definitions, or facts if needed\n- Makes sure each section is clear, useful, and easy to read\n" | |||||
| }, | |||||
| "label": "Note", | |||||
| "name": "Body Agent" | |||||
| }, | |||||
| "dragHandle": ".note-drag-handle", | |||||
| "dragging": false, | |||||
| "height": 164, | |||||
| "id": "Note:StrongKingsCamp", | |||||
| "measured": { | |||||
| "height": 164, | |||||
| "width": 408 | |||||
| }, | |||||
| "position": { | |||||
| "x": 446.54943226110845, | |||||
| "y": 590.9443887062529 | |||||
| }, | |||||
| "resizing": false, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "noteNode", | |||||
| "width": 408 | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "text": "**Purpose**: \nThis agent reviews, polishes, and finalizes the blog post written by the BodyWriter_Agent. It ensures everything is clean, smooth, and SEO-compliant.\n\n**What it does**:\n- Improves grammar, sentence flow, and transitions \n- Makes sure the content reads naturally and professionally \n- Checks whether keywords are present and well integrated (but not overused) \n- Verifies that the structure follows the correct H1/H2/H3 format \n" | |||||
| }, | |||||
| "label": "Note", | |||||
| "name": "Editor Agent" | |||||
| }, | |||||
| "dragHandle": ".note-drag-handle", | |||||
| "dragging": false, | |||||
| "height": 147, | |||||
| "id": "Note:OpenOttersShow", | |||||
| "measured": { | |||||
| "height": 147, | |||||
| "width": 357 | |||||
| }, | |||||
| "position": { | |||||
| "x": 976.6858726228803, | |||||
| "y": 422.7404806291804 | |||||
| }, | |||||
| "resizing": false, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "noteNode", | |||||
| "width": 357 | |||||
| } | |||||
| ] | |||||
| }, | |||||
| "history": [], | |||||
| "messages": [], | |||||
| "path": [], | |||||
| "retrieval": [] | |||||
| }, | |||||
| "avatar": "data:image/jpeg;base64,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" | |||||
| } |
| { | |||||
| "id": 12, | |||||
| "title": "Generate SEO Blog", | |||||
| "description": "This workflow automatically generates a complete SEO-optimized blog article based on a simple user input. You don’t need any writing experience. Just provide a topic or short request — the system will handle the rest.", | |||||
| "canvas_type": "Marketing", | |||||
| "dsl": { | |||||
| "components": { | |||||
| "Agent:BetterSitesSend": { | |||||
| "downstream": [ | |||||
| "Agent:EagerNailsRemain" | |||||
| ], | |||||
| "obj": { | |||||
| "component_name": "Agent", | |||||
| "params": { | |||||
| "delay_after_error": 1, | |||||
| "description": "", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.3, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 3, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Balance", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.2, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "The parse and keyword agent output is {Agent:ClearRabbitsScream@content}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Outline_Agent**, responsible for generating a clear and SEO-optimized blog outline based on the user's parsed writing intent and keyword strategy.\n\n# Tool Access:\n\n- You have access to a search tool called `Tavily Search`.\n\n- If you are unsure how to structure a section, you may call this tool to search for related blog outlines or content from Google.\n\n- Do not overuse it. Your job is to extract **structure**, not to write paragraphs.\n\n\n# Goals\n\n1. Create a well-structured outline with appropriate H2 and H3 headings.\n\n2. Ensure logical flow from introduction to conclusion.\n\n3. Assign 1\u20132 suggested long-tail keywords to each major section for SEO alignment.\n\n4. Make the structure suitable for downstream paragraph writing.\n\n\n\n\n#Note\n\n- Use concise, scannable section titles.\n\n- Do not write full paragraphs.\n\n- Prioritize clarity, logical progression, and SEO alignment.\n\n\n\n- If the blog type is \u201cTutorial\u201d or \u201cHow-to\u201d, include step-based sections.\n\n\n# Input\n\nYou will receive:\n\n- Writing Type (e.g., Tutorial, Informative Guide)\n\n- Target Audience\n\n- User Intent Summary\n\n- 3\u20135 long-tail keywords\n\n\nUse this information to design a structure that both informs readers and maximizes search engine visibility.\n\n# Output Format\n\n```markdown\n\n## Blog Title (suggested)\n\n[Give a short, SEO-friendly title suggestion]\n\n## Outline\n\n### Introduction\n\n- Purpose of the article\n\n- Brief context\n\n- **Suggested keywords**: [keyword1, keyword2]\n\n### H2: [Section Title 1]\n\n- [Short description of what this section will cover]\n\n- **Suggested keywords**: [keyword1, keyword2]\n\n### H2: [Section Title 2]\n\n- [Short description of what this section will cover]\n\n- **Suggested keywords**: [keyword1, keyword2]\n\n### H2: [Section Title 3]\n\n- [Optional H3 Subsection Title A]\n\n - [Explanation of sub-point]\n\n- [Optional H3 Subsection Title B]\n\n - [Explanation of sub-point]\n\n- **Suggested keywords**: [keyword1]\n\n### Conclusion\n\n- Recap key takeaways\n\n- Optional CTA (Call to Action)\n\n- **Suggested keywords**: [keyword3]\n\n", | |||||
| "temperature": 0.5, | |||||
| "temperatureEnabled": true, | |||||
| "tools": [ | |||||
| { | |||||
| "component_name": "TavilySearch", | |||||
| "name": "TavilySearch", | |||||
| "params": { | |||||
| "api_key": "", | |||||
| "days": 7, | |||||
| "exclude_domains": [], | |||||
| "include_answer": false, | |||||
| "include_domains": [], | |||||
| "include_image_descriptions": false, | |||||
| "include_images": false, | |||||
| "include_raw_content": true, | |||||
| "max_results": 5, | |||||
| "outputs": { | |||||
| "formalized_content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| }, | |||||
| "json": { | |||||
| "type": "Array<Object>", | |||||
| "value": [] | |||||
| } | |||||
| }, | |||||
| "query": "sys.query", | |||||
| "search_depth": "basic", | |||||
| "topic": "general" | |||||
| } | |||||
| } | |||||
| ], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.85, | |||||
| "user_prompt": "", | |||||
| "visual_files_var": "" | |||||
| } | |||||
| }, | |||||
| "upstream": [ | |||||
| "Agent:ClearRabbitsScream" | |||||
| ] | |||||
| }, | |||||
| "Agent:ClearRabbitsScream": { | |||||
| "downstream": [ | |||||
| "Agent:BetterSitesSend" | |||||
| ], | |||||
| "obj": { | |||||
| "component_name": "Agent", | |||||
| "params": { | |||||
| "delay_after_error": 1, | |||||
| "description": "", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.5, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 1, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Precise", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.5, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "The user query is {sys.query}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Parse_And_Keyword_Agent**, responsible for interpreting a user's blog writing request and generating a structured writing intent summary and keyword strategy for SEO-optimized content generation.\n\n# Goals\n\n1. Extract and infer the user's true writing intent, even if the input is informal or vague.\n\n2. Identify the writing type, target audience, and implied goal.\n\n3. Suggest 3\u20135 long-tail keywords based on the input and context.\n\n4. Output all data in a Markdown format for downstream agents.\n\n# Operating Guidelines\n\n\n- If the user's input lacks clarity, make reasonable and **conservative** assumptions based on SEO best practices.\n\n- Always choose one clear \"Writing Type\" from the list below.\n\n- Your job is not to write the blog \u2014 only to structure the brief.\n\n# Output Format\n\n```markdown\n## Writing Type\n\n[Choose one: Tutorial / Informative Guide / Marketing Content / Case Study / Opinion Piece / How-to / Comparison Article]\n\n## Target Audience\n\n[Try to be specific based on clues in the input: e.g., marketing managers, junior developers, SEO beginners]\n\n## User Intent Summary\n\n[A 1\u20132 sentence summary of what the user wants to achieve with the blog post]\n\n## Suggested Long-tail Keywords\n\n- keyword 1\n\n- keyword 2\n\n- keyword 3\n\n- keyword 4 (optional)\n\n- keyword 5 (optional)\n\n\n\n\n## Input Examples (and how to handle them)\n\nInput: \"I want to write about RAGFlow.\"\n\u2192 Output: Informative Guide, Audience: AI developers, Intent: explain what RAGFlow is and its use cases\n\nInput: \"Need a blog to promote our prompt design tool.\"\n\u2192 Output: Marketing Content, Audience: product managers or tool adopters, Intent: raise awareness and interest in the product\n\n\n\nInput: \"How to get more Google traffic using AI\"\n\u2192 Output: How-to, Audience: SEO marketers, Intent: guide readers on applying AI for SEO growth", | |||||
| "temperature": 0.2, | |||||
| "temperatureEnabled": true, | |||||
| "tools": [], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.75, | |||||
| "user_prompt": "", | |||||
| "visual_files_var": "" | |||||
| } | |||||
| }, | |||||
| "upstream": [ | |||||
| "begin" | |||||
| ] | |||||
| }, | |||||
| "Agent:EagerNailsRemain": { | |||||
| "downstream": [ | |||||
| "Agent:LovelyHeadsOwn" | |||||
| ], | |||||
| "obj": { | |||||
| "component_name": "Agent", | |||||
| "params": { | |||||
| "delay_after_error": 1, | |||||
| "description": "", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.5, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 5, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Precise", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.5, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "The parse and keyword agent output is {Agent:ClearRabbitsScream@content}\n\n\n\nThe Ouline agent output is {Agent:BetterSitesSend@content}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Body_Agent**, responsible for generating the full content of each section of an SEO-optimized blog based on the provided outline and keyword strategy.\n\n# Tool Access:\n\nYou can use the `Tavily Search` tool to retrieve relevant content, statistics, or examples to support each section you're writing.\n\nUse it **only** when the provided outline lacks enough information, or if the section requires factual grounding.\n\nAlways cite the original link or indicate source where possible.\n\n\n# Goals\n\n1. Write each section (based on H2/H3 structure) as a complete and natural blog paragraph.\n\n2. Integrate the suggested long-tail keywords naturally into each section.\n\n3. When appropriate, use the `Tavily Search` tool to enrich your writing with relevant facts, examples, or quotes.\n\n4. Ensure each section is clear, engaging, and informative, suitable for both human readers and search engines.\n\n\n# Style Guidelines\n\n- Write in a tone appropriate to the audience. Be explanatory, not promotional, unless it's a marketing blog.\n\n- Avoid generic filler content. Prioritize clarity, structure, and value.\n\n- Ensure SEO keywords are embedded seamlessly, not forcefully.\n\n\n\n- Maintain writing rhythm. Vary sentence lengths. Use transitions between ideas.\n\n\n# Input\n\n\nYou will receive:\n\n- Blog title\n\n- Structured outline (including section titles, keywords, and descriptions)\n\n- Target audience\n\n- Blog type and user intent\n\nYou must **follow the outline strictly**. Write content **section-by-section**, based on the structure.\n\n\n# Output Format\n\n```markdown\n\n## H2: [Section Title]\n\n[Your generated content for this section \u2014 500-600 words, using keywords naturally.]\n\n", | |||||
| "temperature": 0.2, | |||||
| "temperatureEnabled": true, | |||||
| "tools": [ | |||||
| { | |||||
| "component_name": "TavilySearch", | |||||
| "name": "TavilySearch", | |||||
| "params": { | |||||
| "api_key": "", | |||||
| "days": 7, | |||||
| "exclude_domains": [], | |||||
| "include_answer": false, | |||||
| "include_domains": [], | |||||
| "include_image_descriptions": false, | |||||
| "include_images": false, | |||||
| "include_raw_content": true, | |||||
| "max_results": 5, | |||||
| "outputs": { | |||||
| "formalized_content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| }, | |||||
| "json": { | |||||
| "type": "Array<Object>", | |||||
| "value": [] | |||||
| } | |||||
| }, | |||||
| "query": "sys.query", | |||||
| "search_depth": "basic", | |||||
| "topic": "general" | |||||
| } | |||||
| } | |||||
| ], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.75, | |||||
| "user_prompt": "", | |||||
| "visual_files_var": "" | |||||
| } | |||||
| }, | |||||
| "upstream": [ | |||||
| "Agent:BetterSitesSend" | |||||
| ] | |||||
| }, | |||||
| "Agent:LovelyHeadsOwn": { | |||||
| "downstream": [ | |||||
| "Message:LegalBeansBet" | |||||
| ], | |||||
| "obj": { | |||||
| "component_name": "Agent", | |||||
| "params": { | |||||
| "delay_after_error": 1, | |||||
| "description": "", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.5, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 5, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Precise", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.5, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "The parse and keyword agent output is {Agent:ClearRabbitsScream@content}\n\nThe Ouline agent output is {Agent:BetterSitesSend@content}\n\nThe Body agent output is {Agent:EagerNailsRemain@content}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Editor_Agent**, responsible for finalizing the blog post for both human readability and SEO effectiveness.\n\n# Goals\n\n1. Polish the entire blog content for clarity, coherence, and style.\n\n2. Improve transitions between sections, ensure logical flow.\n\n3. Verify that keywords are used appropriately and effectively.\n\n4. Conduct a lightweight SEO audit \u2014 checking keyword density, structure (H1/H2/H3), and overall searchability.\n\n\n\n# Style Guidelines\n\n- Be precise. Avoid bloated or vague language.\n\n- Maintain an informative and engaging tone, suitable to the target audience.\n\n- Do not remove keywords unless absolutely necessary for clarity.\n\n- Ensure paragraph flow and section continuity.\n\n\n# Input\n\nYou will receive:\n\n- Full blog content, written section-by-section\n\n- Original outline with suggested keywords\n\n- Target audience and writing type\n\n# Output Format\n\n```markdown\n\n[The revised, fully polished blog post content goes here.]\n\n", | |||||
| "temperature": 0.2, | |||||
| "temperatureEnabled": true, | |||||
| "tools": [], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.75, | |||||
| "user_prompt": "", | |||||
| "visual_files_var": "" | |||||
| } | |||||
| }, | |||||
| "upstream": [ | |||||
| "Agent:EagerNailsRemain" | |||||
| ] | |||||
| }, | |||||
| "Message:LegalBeansBet": { | |||||
| "downstream": [], | |||||
| "obj": { | |||||
| "component_name": "Message", | |||||
| "params": { | |||||
| "content": [ | |||||
| "{Agent:LovelyHeadsOwn@content}" | |||||
| ] | |||||
| } | |||||
| }, | |||||
| "upstream": [ | |||||
| "Agent:LovelyHeadsOwn" | |||||
| ] | |||||
| }, | |||||
| "begin": { | |||||
| "downstream": [ | |||||
| "Agent:ClearRabbitsScream" | |||||
| ], | |||||
| "obj": { | |||||
| "component_name": "Begin", | |||||
| "params": { | |||||
| "enablePrologue": true, | |||||
| "inputs": {}, | |||||
| "mode": "conversational", | |||||
| "prologue": "Hi! I'm your SEO blog assistant.\n\nTo get started, please tell me:\n1. What topic you want the blog to cover\n2. Who is the target audience\n3. What you hope to achieve with this blog (e.g., SEO traffic, teaching beginners, promoting a product)\n" | |||||
| } | |||||
| }, | |||||
| "upstream": [] | |||||
| } | |||||
| }, | |||||
| "globals": { | |||||
| "sys.conversation_turns": 0, | |||||
| "sys.files": [], | |||||
| "sys.query": "", | |||||
| "sys.user_id": "" | |||||
| }, | |||||
| "graph": { | |||||
| "edges": [ | |||||
| { | |||||
| "data": { | |||||
| "isHovered": false | |||||
| }, | |||||
| "id": "xy-edge__beginstart-Agent:ClearRabbitsScreamend", | |||||
| "source": "begin", | |||||
| "sourceHandle": "start", | |||||
| "target": "Agent:ClearRabbitsScream", | |||||
| "targetHandle": "end" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "isHovered": false | |||||
| }, | |||||
| "id": "xy-edge__Agent:ClearRabbitsScreamstart-Agent:BetterSitesSendend", | |||||
| "source": "Agent:ClearRabbitsScream", | |||||
| "sourceHandle": "start", | |||||
| "target": "Agent:BetterSitesSend", | |||||
| "targetHandle": "end" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "isHovered": false | |||||
| }, | |||||
| "id": "xy-edge__Agent:BetterSitesSendtool-Tool:SharpPensBurnend", | |||||
| "source": "Agent:BetterSitesSend", | |||||
| "sourceHandle": "tool", | |||||
| "target": "Tool:SharpPensBurn", | |||||
| "targetHandle": "end" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "isHovered": false | |||||
| }, | |||||
| "id": "xy-edge__Agent:BetterSitesSendstart-Agent:EagerNailsRemainend", | |||||
| "source": "Agent:BetterSitesSend", | |||||
| "sourceHandle": "start", | |||||
| "target": "Agent:EagerNailsRemain", | |||||
| "targetHandle": "end" | |||||
| }, | |||||
| { | |||||
| "id": "xy-edge__Agent:EagerNailsRemaintool-Tool:WickedDeerHealend", | |||||
| "source": "Agent:EagerNailsRemain", | |||||
| "sourceHandle": "tool", | |||||
| "target": "Tool:WickedDeerHeal", | |||||
| "targetHandle": "end" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "isHovered": false | |||||
| }, | |||||
| "id": "xy-edge__Agent:EagerNailsRemainstart-Agent:LovelyHeadsOwnend", | |||||
| "source": "Agent:EagerNailsRemain", | |||||
| "sourceHandle": "start", | |||||
| "target": "Agent:LovelyHeadsOwn", | |||||
| "targetHandle": "end" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "isHovered": false | |||||
| }, | |||||
| "id": "xy-edge__Agent:LovelyHeadsOwnstart-Message:LegalBeansBetend", | |||||
| "source": "Agent:LovelyHeadsOwn", | |||||
| "sourceHandle": "start", | |||||
| "target": "Message:LegalBeansBet", | |||||
| "targetHandle": "end" | |||||
| } | |||||
| ], | |||||
| "nodes": [ | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "enablePrologue": true, | |||||
| "inputs": {}, | |||||
| "mode": "conversational", | |||||
| "prologue": "Hi! I'm your SEO blog assistant.\n\nTo get started, please tell me:\n1. What topic you want the blog to cover\n2. Who is the target audience\n3. What you hope to achieve with this blog (e.g., SEO traffic, teaching beginners, promoting a product)\n" | |||||
| }, | |||||
| "label": "Begin", | |||||
| "name": "begin" | |||||
| }, | |||||
| "id": "begin", | |||||
| "measured": { | |||||
| "height": 48, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": 50, | |||||
| "y": 200 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "left", | |||||
| "targetPosition": "right", | |||||
| "type": "beginNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "delay_after_error": 1, | |||||
| "description": "", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.5, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 1, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Precise", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.5, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "The user query is {sys.query}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Parse_And_Keyword_Agent**, responsible for interpreting a user's blog writing request and generating a structured writing intent summary and keyword strategy for SEO-optimized content generation.\n\n# Goals\n\n1. Extract and infer the user's true writing intent, even if the input is informal or vague.\n\n2. Identify the writing type, target audience, and implied goal.\n\n3. Suggest 3\u20135 long-tail keywords based on the input and context.\n\n4. Output all data in a Markdown format for downstream agents.\n\n# Operating Guidelines\n\n\n- If the user's input lacks clarity, make reasonable and **conservative** assumptions based on SEO best practices.\n\n- Always choose one clear \"Writing Type\" from the list below.\n\n- Your job is not to write the blog \u2014 only to structure the brief.\n\n# Output Format\n\n```markdown\n## Writing Type\n\n[Choose one: Tutorial / Informative Guide / Marketing Content / Case Study / Opinion Piece / How-to / Comparison Article]\n\n## Target Audience\n\n[Try to be specific based on clues in the input: e.g., marketing managers, junior developers, SEO beginners]\n\n## User Intent Summary\n\n[A 1\u20132 sentence summary of what the user wants to achieve with the blog post]\n\n## Suggested Long-tail Keywords\n\n- keyword 1\n\n- keyword 2\n\n- keyword 3\n\n- keyword 4 (optional)\n\n- keyword 5 (optional)\n\n\n\n\n## Input Examples (and how to handle them)\n\nInput: \"I want to write about RAGFlow.\"\n\u2192 Output: Informative Guide, Audience: AI developers, Intent: explain what RAGFlow is and its use cases\n\nInput: \"Need a blog to promote our prompt design tool.\"\n\u2192 Output: Marketing Content, Audience: product managers or tool adopters, Intent: raise awareness and interest in the product\n\n\n\nInput: \"How to get more Google traffic using AI\"\n\u2192 Output: How-to, Audience: SEO marketers, Intent: guide readers on applying AI for SEO growth", | |||||
| "temperature": 0.2, | |||||
| "temperatureEnabled": true, | |||||
| "tools": [], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.75, | |||||
| "user_prompt": "", | |||||
| "visual_files_var": "" | |||||
| }, | |||||
| "label": "Agent", | |||||
| "name": "Parse And Keyword Agent" | |||||
| }, | |||||
| "dragging": false, | |||||
| "id": "Agent:ClearRabbitsScream", | |||||
| "measured": { | |||||
| "height": 84, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": 344.7766966202233, | |||||
| "y": 234.82202253184496 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "agentNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "delay_after_error": 1, | |||||
| "description": "", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.3, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 3, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Balance", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.2, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "The parse and keyword agent output is {Agent:ClearRabbitsScream@content}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Outline_Agent**, responsible for generating a clear and SEO-optimized blog outline based on the user's parsed writing intent and keyword strategy.\n\n# Tool Access:\n\n- You have access to a search tool called `Tavily Search`.\n\n- If you are unsure how to structure a section, you may call this tool to search for related blog outlines or content from Google.\n\n- Do not overuse it. Your job is to extract **structure**, not to write paragraphs.\n\n\n# Goals\n\n1. Create a well-structured outline with appropriate H2 and H3 headings.\n\n2. Ensure logical flow from introduction to conclusion.\n\n3. Assign 1\u20132 suggested long-tail keywords to each major section for SEO alignment.\n\n4. Make the structure suitable for downstream paragraph writing.\n\n\n\n\n#Note\n\n- Use concise, scannable section titles.\n\n- Do not write full paragraphs.\n\n- Prioritize clarity, logical progression, and SEO alignment.\n\n\n\n- If the blog type is \u201cTutorial\u201d or \u201cHow-to\u201d, include step-based sections.\n\n\n# Input\n\nYou will receive:\n\n- Writing Type (e.g., Tutorial, Informative Guide)\n\n- Target Audience\n\n- User Intent Summary\n\n- 3\u20135 long-tail keywords\n\n\nUse this information to design a structure that both informs readers and maximizes search engine visibility.\n\n# Output Format\n\n```markdown\n\n## Blog Title (suggested)\n\n[Give a short, SEO-friendly title suggestion]\n\n## Outline\n\n### Introduction\n\n- Purpose of the article\n\n- Brief context\n\n- **Suggested keywords**: [keyword1, keyword2]\n\n### H2: [Section Title 1]\n\n- [Short description of what this section will cover]\n\n- **Suggested keywords**: [keyword1, keyword2]\n\n### H2: [Section Title 2]\n\n- [Short description of what this section will cover]\n\n- **Suggested keywords**: [keyword1, keyword2]\n\n### H2: [Section Title 3]\n\n- [Optional H3 Subsection Title A]\n\n - [Explanation of sub-point]\n\n- [Optional H3 Subsection Title B]\n\n - [Explanation of sub-point]\n\n- **Suggested keywords**: [keyword1]\n\n### Conclusion\n\n- Recap key takeaways\n\n- Optional CTA (Call to Action)\n\n- **Suggested keywords**: [keyword3]\n\n", | |||||
| "temperature": 0.5, | |||||
| "temperatureEnabled": true, | |||||
| "tools": [ | |||||
| { | |||||
| "component_name": "TavilySearch", | |||||
| "name": "TavilySearch", | |||||
| "params": { | |||||
| "api_key": "", | |||||
| "days": 7, | |||||
| "exclude_domains": [], | |||||
| "include_answer": false, | |||||
| "include_domains": [], | |||||
| "include_image_descriptions": false, | |||||
| "include_images": false, | |||||
| "include_raw_content": true, | |||||
| "max_results": 5, | |||||
| "outputs": { | |||||
| "formalized_content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| }, | |||||
| "json": { | |||||
| "type": "Array<Object>", | |||||
| "value": [] | |||||
| } | |||||
| }, | |||||
| "query": "sys.query", | |||||
| "search_depth": "basic", | |||||
| "topic": "general" | |||||
| } | |||||
| } | |||||
| ], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.85, | |||||
| "user_prompt": "", | |||||
| "visual_files_var": "" | |||||
| }, | |||||
| "label": "Agent", | |||||
| "name": "Outline Agent" | |||||
| }, | |||||
| "dragging": false, | |||||
| "id": "Agent:BetterSitesSend", | |||||
| "measured": { | |||||
| "height": 84, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": 613.4368763415628, | |||||
| "y": 164.3074269048589 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "agentNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "description": "This is an agent for a specific task.", | |||||
| "user_prompt": "This is the order you need to send to the agent." | |||||
| }, | |||||
| "label": "Tool", | |||||
| "name": "flow.tool_0" | |||||
| }, | |||||
| "dragging": false, | |||||
| "id": "Tool:SharpPensBurn", | |||||
| "measured": { | |||||
| "height": 44, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": 580.1877078861457, | |||||
| "y": 287.7669662022325 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "toolNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "delay_after_error": 1, | |||||
| "description": "", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.5, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 5, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Precise", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.5, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "The parse and keyword agent output is {Agent:ClearRabbitsScream@content}\n\n\n\nThe Ouline agent output is {Agent:BetterSitesSend@content}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Body_Agent**, responsible for generating the full content of each section of an SEO-optimized blog based on the provided outline and keyword strategy.\n\n# Tool Access:\n\nYou can use the `Tavily Search` tool to retrieve relevant content, statistics, or examples to support each section you're writing.\n\nUse it **only** when the provided outline lacks enough information, or if the section requires factual grounding.\n\nAlways cite the original link or indicate source where possible.\n\n\n# Goals\n\n1. Write each section (based on H2/H3 structure) as a complete and natural blog paragraph.\n\n2. Integrate the suggested long-tail keywords naturally into each section.\n\n3. When appropriate, use the `Tavily Search` tool to enrich your writing with relevant facts, examples, or quotes.\n\n4. Ensure each section is clear, engaging, and informative, suitable for both human readers and search engines.\n\n\n# Style Guidelines\n\n- Write in a tone appropriate to the audience. Be explanatory, not promotional, unless it's a marketing blog.\n\n- Avoid generic filler content. Prioritize clarity, structure, and value.\n\n- Ensure SEO keywords are embedded seamlessly, not forcefully.\n\n\n\n- Maintain writing rhythm. Vary sentence lengths. Use transitions between ideas.\n\n\n# Input\n\n\nYou will receive:\n\n- Blog title\n\n- Structured outline (including section titles, keywords, and descriptions)\n\n- Target audience\n\n- Blog type and user intent\n\nYou must **follow the outline strictly**. Write content **section-by-section**, based on the structure.\n\n\n# Output Format\n\n```markdown\n\n## H2: [Section Title]\n\n[Your generated content for this section \u2014 500-600 words, using keywords naturally.]\n\n", | |||||
| "temperature": 0.2, | |||||
| "temperatureEnabled": true, | |||||
| "tools": [ | |||||
| { | |||||
| "component_name": "TavilySearch", | |||||
| "name": "TavilySearch", | |||||
| "params": { | |||||
| "api_key": "", | |||||
| "days": 7, | |||||
| "exclude_domains": [], | |||||
| "include_answer": false, | |||||
| "include_domains": [], | |||||
| "include_image_descriptions": false, | |||||
| "include_images": false, | |||||
| "include_raw_content": true, | |||||
| "max_results": 5, | |||||
| "outputs": { | |||||
| "formalized_content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| }, | |||||
| "json": { | |||||
| "type": "Array<Object>", | |||||
| "value": [] | |||||
| } | |||||
| }, | |||||
| "query": "sys.query", | |||||
| "search_depth": "basic", | |||||
| "topic": "general" | |||||
| } | |||||
| } | |||||
| ], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.75, | |||||
| "user_prompt": "", | |||||
| "visual_files_var": "" | |||||
| }, | |||||
| "label": "Agent", | |||||
| "name": "Body Agent" | |||||
| }, | |||||
| "dragging": false, | |||||
| "id": "Agent:EagerNailsRemain", | |||||
| "measured": { | |||||
| "height": 84, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": 889.0614605692713, | |||||
| "y": 247.00973041799065 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "agentNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "description": "This is an agent for a specific task.", | |||||
| "user_prompt": "This is the order you need to send to the agent." | |||||
| }, | |||||
| "label": "Tool", | |||||
| "name": "flow.tool_1" | |||||
| }, | |||||
| "dragging": false, | |||||
| "id": "Tool:WickedDeerHeal", | |||||
| "measured": { | |||||
| "height": 44, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": 853.2006404239659, | |||||
| "y": 364.37541577229143 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "toolNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "delay_after_error": 1, | |||||
| "description": "", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.5, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 5, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Precise", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.5, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "The parse and keyword agent output is {Agent:ClearRabbitsScream@content}\n\nThe Ouline agent output is {Agent:BetterSitesSend@content}\n\nThe Body agent output is {Agent:EagerNailsRemain@content}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Editor_Agent**, responsible for finalizing the blog post for both human readability and SEO effectiveness.\n\n# Goals\n\n1. Polish the entire blog content for clarity, coherence, and style.\n\n2. Improve transitions between sections, ensure logical flow.\n\n3. Verify that keywords are used appropriately and effectively.\n\n4. Conduct a lightweight SEO audit \u2014 checking keyword density, structure (H1/H2/H3), and overall searchability.\n\n\n\n# Style Guidelines\n\n- Be precise. Avoid bloated or vague language.\n\n- Maintain an informative and engaging tone, suitable to the target audience.\n\n- Do not remove keywords unless absolutely necessary for clarity.\n\n- Ensure paragraph flow and section continuity.\n\n\n# Input\n\nYou will receive:\n\n- Full blog content, written section-by-section\n\n- Original outline with suggested keywords\n\n- Target audience and writing type\n\n# Output Format\n\n```markdown\n\n[The revised, fully polished blog post content goes here.]\n\n", | |||||
| "temperature": 0.2, | |||||
| "temperatureEnabled": true, | |||||
| "tools": [], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.75, | |||||
| "user_prompt": "", | |||||
| "visual_files_var": "" | |||||
| }, | |||||
| "label": "Agent", | |||||
| "name": "Editor Agent" | |||||
| }, | |||||
| "dragging": false, | |||||
| "id": "Agent:LovelyHeadsOwn", | |||||
| "measured": { | |||||
| "height": 84, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": 1160.3332919804993, | |||||
| "y": 149.50806732882472 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "agentNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "content": [ | |||||
| "{Agent:LovelyHeadsOwn@content}" | |||||
| ] | |||||
| }, | |||||
| "label": "Message", | |||||
| "name": "Response" | |||||
| }, | |||||
| "dragging": false, | |||||
| "id": "Message:LegalBeansBet", | |||||
| "measured": { | |||||
| "height": 56, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": 1370.6665839609984, | |||||
| "y": 267.0323933738015 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "messageNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "text": "This workflow automatically generates a complete SEO-optimized blog article based on a simple user input. You don\u2019t need any writing experience. Just provide a topic or short request \u2014 the system will handle the rest.\n\nThe process includes the following key stages:\n\n1. **Understanding your topic and goals**\n2. **Designing the blog structure**\n3. **Writing high-quality content**\n\n\n" | |||||
| }, | |||||
| "label": "Note", | |||||
| "name": "Workflow Overall Description" | |||||
| }, | |||||
| "dragHandle": ".note-drag-handle", | |||||
| "dragging": false, | |||||
| "height": 205, | |||||
| "id": "Note:SlimyGhostsWear", | |||||
| "measured": { | |||||
| "height": 205, | |||||
| "width": 415 | |||||
| }, | |||||
| "position": { | |||||
| "x": -284.3143151688742, | |||||
| "y": 150.47632147913419 | |||||
| }, | |||||
| "resizing": false, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "noteNode", | |||||
| "width": 415 | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "text": "**Purpose**: \nThis agent reads the user\u2019s input and figures out what kind of blog needs to be written.\n\n**What it does**:\n- Understands the main topic you want to write about \n- Identifies who the blog is for (e.g., beginners, marketers, developers) \n- Determines the writing purpose (e.g., SEO traffic, product promotion, education) \n- Suggests 3\u20135 long-tail SEO keywords related to the topic" | |||||
| }, | |||||
| "label": "Note", | |||||
| "name": "Parse And Keyword Agent" | |||||
| }, | |||||
| "dragHandle": ".note-drag-handle", | |||||
| "dragging": false, | |||||
| "height": 152, | |||||
| "id": "Note:EmptyChairsShake", | |||||
| "measured": { | |||||
| "height": 152, | |||||
| "width": 340 | |||||
| }, | |||||
| "position": { | |||||
| "x": 295.04147626768133, | |||||
| "y": 372.2755718118446 | |||||
| }, | |||||
| "resizing": false, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "noteNode", | |||||
| "width": 340 | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "text": "**Purpose**: \nThis agent builds the blog structure \u2014 just like writing a table of contents before you start writing the full article.\n\n**What it does**:\n- Suggests a clear blog title that includes important keywords \n- Breaks the article into sections using H2 and H3 headings (like a professional blog layout) \n- Assigns 1\u20132 recommended keywords to each section to help with SEO \n- Follows the writing goal and target audience set in the previous step" | |||||
| }, | |||||
| "label": "Note", | |||||
| "name": "Outline Agent" | |||||
| }, | |||||
| "dragHandle": ".note-drag-handle", | |||||
| "dragging": false, | |||||
| "height": 146, | |||||
| "id": "Note:TallMelonsNotice", | |||||
| "measured": { | |||||
| "height": 146, | |||||
| "width": 343 | |||||
| }, | |||||
| "position": { | |||||
| "x": 598.5644991893463, | |||||
| "y": 5.801054564756448 | |||||
| }, | |||||
| "resizing": false, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "noteNode", | |||||
| "width": 343 | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "text": "**Purpose**: \nThis agent is responsible for writing the actual content of the blog \u2014 paragraph by paragraph \u2014 based on the outline created earlier.\n\n**What it does**:\n- Looks at each H2/H3 section in the outline \n- Writes 150\u2013220 words of clear, helpful, and well-structured content per section \n- Includes the suggested SEO keywords naturally (not keyword stuffing) \n- Uses real examples or facts if needed (by calling a web search tool like Tavily)" | |||||
| }, | |||||
| "label": "Note", | |||||
| "name": "Body Agent" | |||||
| }, | |||||
| "dragHandle": ".note-drag-handle", | |||||
| "dragging": false, | |||||
| "height": 137, | |||||
| "id": "Note:RipeCougarsBuild", | |||||
| "measured": { | |||||
| "height": 137, | |||||
| "width": 319 | |||||
| }, | |||||
| "position": { | |||||
| "x": 860.4854129814981, | |||||
| "y": 427.2196835690842 | |||||
| }, | |||||
| "resizing": false, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "noteNode", | |||||
| "width": 319 | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "text": "**Purpose**: \nThis agent reviews the entire blog draft to make sure it is smooth, professional, and SEO-friendly. It acts like a human editor before publishing.\n\n**What it does**:\n- Polishes the writing: improves sentence clarity, fixes awkward phrasing \n- Makes sure the content flows well from one section to the next \n- Double-checks keyword usage: are they present, natural, and not overused? \n- Verifies the blog structure (H1, H2, H3 headings) is correct \n- Adds two key SEO elements:\n - **Meta Title** (shows up in search results)\n - **Meta Description** (summary for Google and social sharing)" | |||||
| }, | |||||
| "label": "Note", | |||||
| "name": "Editor Agent" | |||||
| }, | |||||
| "dragHandle": ".note-drag-handle", | |||||
| "height": 146, | |||||
| "id": "Note:OpenTurkeysSell", | |||||
| "measured": { | |||||
| "height": 146, | |||||
| "width": 320 | |||||
| }, | |||||
| "position": { | |||||
| "x": 1129, | |||||
| "y": -30 | |||||
| }, | |||||
| "resizing": false, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "noteNode", | |||||
| "width": 320 | |||||
| } | |||||
| ] | |||||
| }, | |||||
| "history": [], | |||||
| "messages": [], | |||||
| "path": [], | |||||
| "retrieval": [] | |||||
| }, | |||||
| "avatar": "data:image/jpeg;base64,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" | |||||
| } |
| { | |||||
| "id": 4, | |||||
| "title": "Generate SEO Blog", | |||||
| "description": "This workflow automatically generates a complete SEO-optimized blog article based on a simple user input. You don’t need any writing experience. Just provide a topic or short request — the system will handle the rest.", | |||||
| "canvas_type": "Recommended", | |||||
| "dsl": { | |||||
| "components": { | |||||
| "Agent:BetterSitesSend": { | |||||
| "downstream": [ | |||||
| "Agent:EagerNailsRemain" | |||||
| ], | |||||
| "obj": { | |||||
| "component_name": "Agent", | |||||
| "params": { | |||||
| "delay_after_error": 1, | |||||
| "description": "", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.3, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 3, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Balance", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.2, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "The parse and keyword agent output is {Agent:ClearRabbitsScream@content}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Outline_Agent**, responsible for generating a clear and SEO-optimized blog outline based on the user's parsed writing intent and keyword strategy.\n\n# Tool Access:\n\n- You have access to a search tool called `Tavily Search`.\n\n- If you are unsure how to structure a section, you may call this tool to search for related blog outlines or content from Google.\n\n- Do not overuse it. Your job is to extract **structure**, not to write paragraphs.\n\n\n# Goals\n\n1. Create a well-structured outline with appropriate H2 and H3 headings.\n\n2. Ensure logical flow from introduction to conclusion.\n\n3. Assign 1\u20132 suggested long-tail keywords to each major section for SEO alignment.\n\n4. Make the structure suitable for downstream paragraph writing.\n\n\n\n\n#Note\n\n- Use concise, scannable section titles.\n\n- Do not write full paragraphs.\n\n- Prioritize clarity, logical progression, and SEO alignment.\n\n\n\n- If the blog type is \u201cTutorial\u201d or \u201cHow-to\u201d, include step-based sections.\n\n\n# Input\n\nYou will receive:\n\n- Writing Type (e.g., Tutorial, Informative Guide)\n\n- Target Audience\n\n- User Intent Summary\n\n- 3\u20135 long-tail keywords\n\n\nUse this information to design a structure that both informs readers and maximizes search engine visibility.\n\n# Output Format\n\n```markdown\n\n## Blog Title (suggested)\n\n[Give a short, SEO-friendly title suggestion]\n\n## Outline\n\n### Introduction\n\n- Purpose of the article\n\n- Brief context\n\n- **Suggested keywords**: [keyword1, keyword2]\n\n### H2: [Section Title 1]\n\n- [Short description of what this section will cover]\n\n- **Suggested keywords**: [keyword1, keyword2]\n\n### H2: [Section Title 2]\n\n- [Short description of what this section will cover]\n\n- **Suggested keywords**: [keyword1, keyword2]\n\n### H2: [Section Title 3]\n\n- [Optional H3 Subsection Title A]\n\n - [Explanation of sub-point]\n\n- [Optional H3 Subsection Title B]\n\n - [Explanation of sub-point]\n\n- **Suggested keywords**: [keyword1]\n\n### Conclusion\n\n- Recap key takeaways\n\n- Optional CTA (Call to Action)\n\n- **Suggested keywords**: [keyword3]\n\n", | |||||
| "temperature": 0.5, | |||||
| "temperatureEnabled": true, | |||||
| "tools": [ | |||||
| { | |||||
| "component_name": "TavilySearch", | |||||
| "name": "TavilySearch", | |||||
| "params": { | |||||
| "api_key": "", | |||||
| "days": 7, | |||||
| "exclude_domains": [], | |||||
| "include_answer": false, | |||||
| "include_domains": [], | |||||
| "include_image_descriptions": false, | |||||
| "include_images": false, | |||||
| "include_raw_content": true, | |||||
| "max_results": 5, | |||||
| "outputs": { | |||||
| "formalized_content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| }, | |||||
| "json": { | |||||
| "type": "Array<Object>", | |||||
| "value": [] | |||||
| } | |||||
| }, | |||||
| "query": "sys.query", | |||||
| "search_depth": "basic", | |||||
| "topic": "general" | |||||
| } | |||||
| } | |||||
| ], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.85, | |||||
| "user_prompt": "", | |||||
| "visual_files_var": "" | |||||
| } | |||||
| }, | |||||
| "upstream": [ | |||||
| "Agent:ClearRabbitsScream" | |||||
| ] | |||||
| }, | |||||
| "Agent:ClearRabbitsScream": { | |||||
| "downstream": [ | |||||
| "Agent:BetterSitesSend" | |||||
| ], | |||||
| "obj": { | |||||
| "component_name": "Agent", | |||||
| "params": { | |||||
| "delay_after_error": 1, | |||||
| "description": "", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.5, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 1, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Precise", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.5, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "The user query is {sys.query}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Parse_And_Keyword_Agent**, responsible for interpreting a user's blog writing request and generating a structured writing intent summary and keyword strategy for SEO-optimized content generation.\n\n# Goals\n\n1. Extract and infer the user's true writing intent, even if the input is informal or vague.\n\n2. Identify the writing type, target audience, and implied goal.\n\n3. Suggest 3\u20135 long-tail keywords based on the input and context.\n\n4. Output all data in a Markdown format for downstream agents.\n\n# Operating Guidelines\n\n\n- If the user's input lacks clarity, make reasonable and **conservative** assumptions based on SEO best practices.\n\n- Always choose one clear \"Writing Type\" from the list below.\n\n- Your job is not to write the blog \u2014 only to structure the brief.\n\n# Output Format\n\n```markdown\n## Writing Type\n\n[Choose one: Tutorial / Informative Guide / Marketing Content / Case Study / Opinion Piece / How-to / Comparison Article]\n\n## Target Audience\n\n[Try to be specific based on clues in the input: e.g., marketing managers, junior developers, SEO beginners]\n\n## User Intent Summary\n\n[A 1\u20132 sentence summary of what the user wants to achieve with the blog post]\n\n## Suggested Long-tail Keywords\n\n- keyword 1\n\n- keyword 2\n\n- keyword 3\n\n- keyword 4 (optional)\n\n- keyword 5 (optional)\n\n\n\n\n## Input Examples (and how to handle them)\n\nInput: \"I want to write about RAGFlow.\"\n\u2192 Output: Informative Guide, Audience: AI developers, Intent: explain what RAGFlow is and its use cases\n\nInput: \"Need a blog to promote our prompt design tool.\"\n\u2192 Output: Marketing Content, Audience: product managers or tool adopters, Intent: raise awareness and interest in the product\n\n\n\nInput: \"How to get more Google traffic using AI\"\n\u2192 Output: How-to, Audience: SEO marketers, Intent: guide readers on applying AI for SEO growth", | |||||
| "temperature": 0.2, | |||||
| "temperatureEnabled": true, | |||||
| "tools": [], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.75, | |||||
| "user_prompt": "", | |||||
| "visual_files_var": "" | |||||
| } | |||||
| }, | |||||
| "upstream": [ | |||||
| "begin" | |||||
| ] | |||||
| }, | |||||
| "Agent:EagerNailsRemain": { | |||||
| "downstream": [ | |||||
| "Agent:LovelyHeadsOwn" | |||||
| ], | |||||
| "obj": { | |||||
| "component_name": "Agent", | |||||
| "params": { | |||||
| "delay_after_error": 1, | |||||
| "description": "", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.5, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 5, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Precise", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.5, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "The parse and keyword agent output is {Agent:ClearRabbitsScream@content}\n\n\n\nThe Ouline agent output is {Agent:BetterSitesSend@content}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Body_Agent**, responsible for generating the full content of each section of an SEO-optimized blog based on the provided outline and keyword strategy.\n\n# Tool Access:\n\nYou can use the `Tavily Search` tool to retrieve relevant content, statistics, or examples to support each section you're writing.\n\nUse it **only** when the provided outline lacks enough information, or if the section requires factual grounding.\n\nAlways cite the original link or indicate source where possible.\n\n\n# Goals\n\n1. Write each section (based on H2/H3 structure) as a complete and natural blog paragraph.\n\n2. Integrate the suggested long-tail keywords naturally into each section.\n\n3. When appropriate, use the `Tavily Search` tool to enrich your writing with relevant facts, examples, or quotes.\n\n4. Ensure each section is clear, engaging, and informative, suitable for both human readers and search engines.\n\n\n# Style Guidelines\n\n- Write in a tone appropriate to the audience. Be explanatory, not promotional, unless it's a marketing blog.\n\n- Avoid generic filler content. Prioritize clarity, structure, and value.\n\n- Ensure SEO keywords are embedded seamlessly, not forcefully.\n\n\n\n- Maintain writing rhythm. Vary sentence lengths. Use transitions between ideas.\n\n\n# Input\n\n\nYou will receive:\n\n- Blog title\n\n- Structured outline (including section titles, keywords, and descriptions)\n\n- Target audience\n\n- Blog type and user intent\n\nYou must **follow the outline strictly**. Write content **section-by-section**, based on the structure.\n\n\n# Output Format\n\n```markdown\n\n## H2: [Section Title]\n\n[Your generated content for this section \u2014 500-600 words, using keywords naturally.]\n\n", | |||||
| "temperature": 0.2, | |||||
| "temperatureEnabled": true, | |||||
| "tools": [ | |||||
| { | |||||
| "component_name": "TavilySearch", | |||||
| "name": "TavilySearch", | |||||
| "params": { | |||||
| "api_key": "", | |||||
| "days": 7, | |||||
| "exclude_domains": [], | |||||
| "include_answer": false, | |||||
| "include_domains": [], | |||||
| "include_image_descriptions": false, | |||||
| "include_images": false, | |||||
| "include_raw_content": true, | |||||
| "max_results": 5, | |||||
| "outputs": { | |||||
| "formalized_content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| }, | |||||
| "json": { | |||||
| "type": "Array<Object>", | |||||
| "value": [] | |||||
| } | |||||
| }, | |||||
| "query": "sys.query", | |||||
| "search_depth": "basic", | |||||
| "topic": "general" | |||||
| } | |||||
| } | |||||
| ], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.75, | |||||
| "user_prompt": "", | |||||
| "visual_files_var": "" | |||||
| } | |||||
| }, | |||||
| "upstream": [ | |||||
| "Agent:BetterSitesSend" | |||||
| ] | |||||
| }, | |||||
| "Agent:LovelyHeadsOwn": { | |||||
| "downstream": [ | |||||
| "Message:LegalBeansBet" | |||||
| ], | |||||
| "obj": { | |||||
| "component_name": "Agent", | |||||
| "params": { | |||||
| "delay_after_error": 1, | |||||
| "description": "", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.5, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 5, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Precise", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.5, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "The parse and keyword agent output is {Agent:ClearRabbitsScream@content}\n\nThe Ouline agent output is {Agent:BetterSitesSend@content}\n\nThe Body agent output is {Agent:EagerNailsRemain@content}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Editor_Agent**, responsible for finalizing the blog post for both human readability and SEO effectiveness.\n\n# Goals\n\n1. Polish the entire blog content for clarity, coherence, and style.\n\n2. Improve transitions between sections, ensure logical flow.\n\n3. Verify that keywords are used appropriately and effectively.\n\n4. Conduct a lightweight SEO audit \u2014 checking keyword density, structure (H1/H2/H3), and overall searchability.\n\n\n\n# Style Guidelines\n\n- Be precise. Avoid bloated or vague language.\n\n- Maintain an informative and engaging tone, suitable to the target audience.\n\n- Do not remove keywords unless absolutely necessary for clarity.\n\n- Ensure paragraph flow and section continuity.\n\n\n# Input\n\nYou will receive:\n\n- Full blog content, written section-by-section\n\n- Original outline with suggested keywords\n\n- Target audience and writing type\n\n# Output Format\n\n```markdown\n\n[The revised, fully polished blog post content goes here.]\n\n", | |||||
| "temperature": 0.2, | |||||
| "temperatureEnabled": true, | |||||
| "tools": [], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.75, | |||||
| "user_prompt": "", | |||||
| "visual_files_var": "" | |||||
| } | |||||
| }, | |||||
| "upstream": [ | |||||
| "Agent:EagerNailsRemain" | |||||
| ] | |||||
| }, | |||||
| "Message:LegalBeansBet": { | |||||
| "downstream": [], | |||||
| "obj": { | |||||
| "component_name": "Message", | |||||
| "params": { | |||||
| "content": [ | |||||
| "{Agent:LovelyHeadsOwn@content}" | |||||
| ] | |||||
| } | |||||
| }, | |||||
| "upstream": [ | |||||
| "Agent:LovelyHeadsOwn" | |||||
| ] | |||||
| }, | |||||
| "begin": { | |||||
| "downstream": [ | |||||
| "Agent:ClearRabbitsScream" | |||||
| ], | |||||
| "obj": { | |||||
| "component_name": "Begin", | |||||
| "params": { | |||||
| "enablePrologue": true, | |||||
| "inputs": {}, | |||||
| "mode": "conversational", | |||||
| "prologue": "Hi! I'm your SEO blog assistant.\n\nTo get started, please tell me:\n1. What topic you want the blog to cover\n2. Who is the target audience\n3. What you hope to achieve with this blog (e.g., SEO traffic, teaching beginners, promoting a product)\n" | |||||
| } | |||||
| }, | |||||
| "upstream": [] | |||||
| } | |||||
| }, | |||||
| "globals": { | |||||
| "sys.conversation_turns": 0, | |||||
| "sys.files": [], | |||||
| "sys.query": "", | |||||
| "sys.user_id": "" | |||||
| }, | |||||
| "graph": { | |||||
| "edges": [ | |||||
| { | |||||
| "data": { | |||||
| "isHovered": false | |||||
| }, | |||||
| "id": "xy-edge__beginstart-Agent:ClearRabbitsScreamend", | |||||
| "source": "begin", | |||||
| "sourceHandle": "start", | |||||
| "target": "Agent:ClearRabbitsScream", | |||||
| "targetHandle": "end" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "isHovered": false | |||||
| }, | |||||
| "id": "xy-edge__Agent:ClearRabbitsScreamstart-Agent:BetterSitesSendend", | |||||
| "source": "Agent:ClearRabbitsScream", | |||||
| "sourceHandle": "start", | |||||
| "target": "Agent:BetterSitesSend", | |||||
| "targetHandle": "end" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "isHovered": false | |||||
| }, | |||||
| "id": "xy-edge__Agent:BetterSitesSendtool-Tool:SharpPensBurnend", | |||||
| "source": "Agent:BetterSitesSend", | |||||
| "sourceHandle": "tool", | |||||
| "target": "Tool:SharpPensBurn", | |||||
| "targetHandle": "end" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "isHovered": false | |||||
| }, | |||||
| "id": "xy-edge__Agent:BetterSitesSendstart-Agent:EagerNailsRemainend", | |||||
| "source": "Agent:BetterSitesSend", | |||||
| "sourceHandle": "start", | |||||
| "target": "Agent:EagerNailsRemain", | |||||
| "targetHandle": "end" | |||||
| }, | |||||
| { | |||||
| "id": "xy-edge__Agent:EagerNailsRemaintool-Tool:WickedDeerHealend", | |||||
| "source": "Agent:EagerNailsRemain", | |||||
| "sourceHandle": "tool", | |||||
| "target": "Tool:WickedDeerHeal", | |||||
| "targetHandle": "end" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "isHovered": false | |||||
| }, | |||||
| "id": "xy-edge__Agent:EagerNailsRemainstart-Agent:LovelyHeadsOwnend", | |||||
| "source": "Agent:EagerNailsRemain", | |||||
| "sourceHandle": "start", | |||||
| "target": "Agent:LovelyHeadsOwn", | |||||
| "targetHandle": "end" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "isHovered": false | |||||
| }, | |||||
| "id": "xy-edge__Agent:LovelyHeadsOwnstart-Message:LegalBeansBetend", | |||||
| "source": "Agent:LovelyHeadsOwn", | |||||
| "sourceHandle": "start", | |||||
| "target": "Message:LegalBeansBet", | |||||
| "targetHandle": "end" | |||||
| } | |||||
| ], | |||||
| "nodes": [ | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "enablePrologue": true, | |||||
| "inputs": {}, | |||||
| "mode": "conversational", | |||||
| "prologue": "Hi! I'm your SEO blog assistant.\n\nTo get started, please tell me:\n1. What topic you want the blog to cover\n2. Who is the target audience\n3. What you hope to achieve with this blog (e.g., SEO traffic, teaching beginners, promoting a product)\n" | |||||
| }, | |||||
| "label": "Begin", | |||||
| "name": "begin" | |||||
| }, | |||||
| "id": "begin", | |||||
| "measured": { | |||||
| "height": 48, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": 50, | |||||
| "y": 200 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "left", | |||||
| "targetPosition": "right", | |||||
| "type": "beginNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "delay_after_error": 1, | |||||
| "description": "", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.5, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 1, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Precise", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.5, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "The user query is {sys.query}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Parse_And_Keyword_Agent**, responsible for interpreting a user's blog writing request and generating a structured writing intent summary and keyword strategy for SEO-optimized content generation.\n\n# Goals\n\n1. Extract and infer the user's true writing intent, even if the input is informal or vague.\n\n2. Identify the writing type, target audience, and implied goal.\n\n3. Suggest 3\u20135 long-tail keywords based on the input and context.\n\n4. Output all data in a Markdown format for downstream agents.\n\n# Operating Guidelines\n\n\n- If the user's input lacks clarity, make reasonable and **conservative** assumptions based on SEO best practices.\n\n- Always choose one clear \"Writing Type\" from the list below.\n\n- Your job is not to write the blog \u2014 only to structure the brief.\n\n# Output Format\n\n```markdown\n## Writing Type\n\n[Choose one: Tutorial / Informative Guide / Marketing Content / Case Study / Opinion Piece / How-to / Comparison Article]\n\n## Target Audience\n\n[Try to be specific based on clues in the input: e.g., marketing managers, junior developers, SEO beginners]\n\n## User Intent Summary\n\n[A 1\u20132 sentence summary of what the user wants to achieve with the blog post]\n\n## Suggested Long-tail Keywords\n\n- keyword 1\n\n- keyword 2\n\n- keyword 3\n\n- keyword 4 (optional)\n\n- keyword 5 (optional)\n\n\n\n\n## Input Examples (and how to handle them)\n\nInput: \"I want to write about RAGFlow.\"\n\u2192 Output: Informative Guide, Audience: AI developers, Intent: explain what RAGFlow is and its use cases\n\nInput: \"Need a blog to promote our prompt design tool.\"\n\u2192 Output: Marketing Content, Audience: product managers or tool adopters, Intent: raise awareness and interest in the product\n\n\n\nInput: \"How to get more Google traffic using AI\"\n\u2192 Output: How-to, Audience: SEO marketers, Intent: guide readers on applying AI for SEO growth", | |||||
| "temperature": 0.2, | |||||
| "temperatureEnabled": true, | |||||
| "tools": [], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.75, | |||||
| "user_prompt": "", | |||||
| "visual_files_var": "" | |||||
| }, | |||||
| "label": "Agent", | |||||
| "name": "Parse And Keyword Agent" | |||||
| }, | |||||
| "dragging": false, | |||||
| "id": "Agent:ClearRabbitsScream", | |||||
| "measured": { | |||||
| "height": 84, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": 344.7766966202233, | |||||
| "y": 234.82202253184496 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "agentNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "delay_after_error": 1, | |||||
| "description": "", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.3, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 3, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Balance", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.2, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "The parse and keyword agent output is {Agent:ClearRabbitsScream@content}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Outline_Agent**, responsible for generating a clear and SEO-optimized blog outline based on the user's parsed writing intent and keyword strategy.\n\n# Tool Access:\n\n- You have access to a search tool called `Tavily Search`.\n\n- If you are unsure how to structure a section, you may call this tool to search for related blog outlines or content from Google.\n\n- Do not overuse it. Your job is to extract **structure**, not to write paragraphs.\n\n\n# Goals\n\n1. Create a well-structured outline with appropriate H2 and H3 headings.\n\n2. Ensure logical flow from introduction to conclusion.\n\n3. Assign 1\u20132 suggested long-tail keywords to each major section for SEO alignment.\n\n4. Make the structure suitable for downstream paragraph writing.\n\n\n\n\n#Note\n\n- Use concise, scannable section titles.\n\n- Do not write full paragraphs.\n\n- Prioritize clarity, logical progression, and SEO alignment.\n\n\n\n- If the blog type is \u201cTutorial\u201d or \u201cHow-to\u201d, include step-based sections.\n\n\n# Input\n\nYou will receive:\n\n- Writing Type (e.g., Tutorial, Informative Guide)\n\n- Target Audience\n\n- User Intent Summary\n\n- 3\u20135 long-tail keywords\n\n\nUse this information to design a structure that both informs readers and maximizes search engine visibility.\n\n# Output Format\n\n```markdown\n\n## Blog Title (suggested)\n\n[Give a short, SEO-friendly title suggestion]\n\n## Outline\n\n### Introduction\n\n- Purpose of the article\n\n- Brief context\n\n- **Suggested keywords**: [keyword1, keyword2]\n\n### H2: [Section Title 1]\n\n- [Short description of what this section will cover]\n\n- **Suggested keywords**: [keyword1, keyword2]\n\n### H2: [Section Title 2]\n\n- [Short description of what this section will cover]\n\n- **Suggested keywords**: [keyword1, keyword2]\n\n### H2: [Section Title 3]\n\n- [Optional H3 Subsection Title A]\n\n - [Explanation of sub-point]\n\n- [Optional H3 Subsection Title B]\n\n - [Explanation of sub-point]\n\n- **Suggested keywords**: [keyword1]\n\n### Conclusion\n\n- Recap key takeaways\n\n- Optional CTA (Call to Action)\n\n- **Suggested keywords**: [keyword3]\n\n", | |||||
| "temperature": 0.5, | |||||
| "temperatureEnabled": true, | |||||
| "tools": [ | |||||
| { | |||||
| "component_name": "TavilySearch", | |||||
| "name": "TavilySearch", | |||||
| "params": { | |||||
| "api_key": "", | |||||
| "days": 7, | |||||
| "exclude_domains": [], | |||||
| "include_answer": false, | |||||
| "include_domains": [], | |||||
| "include_image_descriptions": false, | |||||
| "include_images": false, | |||||
| "include_raw_content": true, | |||||
| "max_results": 5, | |||||
| "outputs": { | |||||
| "formalized_content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| }, | |||||
| "json": { | |||||
| "type": "Array<Object>", | |||||
| "value": [] | |||||
| } | |||||
| }, | |||||
| "query": "sys.query", | |||||
| "search_depth": "basic", | |||||
| "topic": "general" | |||||
| } | |||||
| } | |||||
| ], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.85, | |||||
| "user_prompt": "", | |||||
| "visual_files_var": "" | |||||
| }, | |||||
| "label": "Agent", | |||||
| "name": "Outline Agent" | |||||
| }, | |||||
| "dragging": false, | |||||
| "id": "Agent:BetterSitesSend", | |||||
| "measured": { | |||||
| "height": 84, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": 613.4368763415628, | |||||
| "y": 164.3074269048589 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "agentNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "description": "This is an agent for a specific task.", | |||||
| "user_prompt": "This is the order you need to send to the agent." | |||||
| }, | |||||
| "label": "Tool", | |||||
| "name": "flow.tool_0" | |||||
| }, | |||||
| "dragging": false, | |||||
| "id": "Tool:SharpPensBurn", | |||||
| "measured": { | |||||
| "height": 44, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": 580.1877078861457, | |||||
| "y": 287.7669662022325 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "toolNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "delay_after_error": 1, | |||||
| "description": "", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.5, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 5, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Precise", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.5, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "The parse and keyword agent output is {Agent:ClearRabbitsScream@content}\n\n\n\nThe Ouline agent output is {Agent:BetterSitesSend@content}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Body_Agent**, responsible for generating the full content of each section of an SEO-optimized blog based on the provided outline and keyword strategy.\n\n# Tool Access:\n\nYou can use the `Tavily Search` tool to retrieve relevant content, statistics, or examples to support each section you're writing.\n\nUse it **only** when the provided outline lacks enough information, or if the section requires factual grounding.\n\nAlways cite the original link or indicate source where possible.\n\n\n# Goals\n\n1. Write each section (based on H2/H3 structure) as a complete and natural blog paragraph.\n\n2. Integrate the suggested long-tail keywords naturally into each section.\n\n3. When appropriate, use the `Tavily Search` tool to enrich your writing with relevant facts, examples, or quotes.\n\n4. Ensure each section is clear, engaging, and informative, suitable for both human readers and search engines.\n\n\n# Style Guidelines\n\n- Write in a tone appropriate to the audience. Be explanatory, not promotional, unless it's a marketing blog.\n\n- Avoid generic filler content. Prioritize clarity, structure, and value.\n\n- Ensure SEO keywords are embedded seamlessly, not forcefully.\n\n\n\n- Maintain writing rhythm. Vary sentence lengths. Use transitions between ideas.\n\n\n# Input\n\n\nYou will receive:\n\n- Blog title\n\n- Structured outline (including section titles, keywords, and descriptions)\n\n- Target audience\n\n- Blog type and user intent\n\nYou must **follow the outline strictly**. Write content **section-by-section**, based on the structure.\n\n\n# Output Format\n\n```markdown\n\n## H2: [Section Title]\n\n[Your generated content for this section \u2014 500-600 words, using keywords naturally.]\n\n", | |||||
| "temperature": 0.2, | |||||
| "temperatureEnabled": true, | |||||
| "tools": [ | |||||
| { | |||||
| "component_name": "TavilySearch", | |||||
| "name": "TavilySearch", | |||||
| "params": { | |||||
| "api_key": "", | |||||
| "days": 7, | |||||
| "exclude_domains": [], | |||||
| "include_answer": false, | |||||
| "include_domains": [], | |||||
| "include_image_descriptions": false, | |||||
| "include_images": false, | |||||
| "include_raw_content": true, | |||||
| "max_results": 5, | |||||
| "outputs": { | |||||
| "formalized_content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| }, | |||||
| "json": { | |||||
| "type": "Array<Object>", | |||||
| "value": [] | |||||
| } | |||||
| }, | |||||
| "query": "sys.query", | |||||
| "search_depth": "basic", | |||||
| "topic": "general" | |||||
| } | |||||
| } | |||||
| ], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.75, | |||||
| "user_prompt": "", | |||||
| "visual_files_var": "" | |||||
| }, | |||||
| "label": "Agent", | |||||
| "name": "Body Agent" | |||||
| }, | |||||
| "dragging": false, | |||||
| "id": "Agent:EagerNailsRemain", | |||||
| "measured": { | |||||
| "height": 84, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": 889.0614605692713, | |||||
| "y": 247.00973041799065 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "agentNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "description": "This is an agent for a specific task.", | |||||
| "user_prompt": "This is the order you need to send to the agent." | |||||
| }, | |||||
| "label": "Tool", | |||||
| "name": "flow.tool_1" | |||||
| }, | |||||
| "dragging": false, | |||||
| "id": "Tool:WickedDeerHeal", | |||||
| "measured": { | |||||
| "height": 44, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": 853.2006404239659, | |||||
| "y": 364.37541577229143 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "toolNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "delay_after_error": 1, | |||||
| "description": "", | |||||
| "exception_comment": "", | |||||
| "exception_default_value": "", | |||||
| "exception_goto": [], | |||||
| "exception_method": null, | |||||
| "frequencyPenaltyEnabled": false, | |||||
| "frequency_penalty": 0.5, | |||||
| "llm_id": "deepseek-chat@DeepSeek", | |||||
| "maxTokensEnabled": false, | |||||
| "max_retries": 3, | |||||
| "max_rounds": 5, | |||||
| "max_tokens": 4096, | |||||
| "mcp": [], | |||||
| "message_history_window_size": 12, | |||||
| "outputs": { | |||||
| "content": { | |||||
| "type": "string", | |||||
| "value": "" | |||||
| } | |||||
| }, | |||||
| "parameter": "Precise", | |||||
| "presencePenaltyEnabled": false, | |||||
| "presence_penalty": 0.5, | |||||
| "prompts": [ | |||||
| { | |||||
| "content": "The parse and keyword agent output is {Agent:ClearRabbitsScream@content}\n\nThe Ouline agent output is {Agent:BetterSitesSend@content}\n\nThe Body agent output is {Agent:EagerNailsRemain@content}", | |||||
| "role": "user" | |||||
| } | |||||
| ], | |||||
| "sys_prompt": "# Role\n\nYou are the **Editor_Agent**, responsible for finalizing the blog post for both human readability and SEO effectiveness.\n\n# Goals\n\n1. Polish the entire blog content for clarity, coherence, and style.\n\n2. Improve transitions between sections, ensure logical flow.\n\n3. Verify that keywords are used appropriately and effectively.\n\n4. Conduct a lightweight SEO audit \u2014 checking keyword density, structure (H1/H2/H3), and overall searchability.\n\n\n\n# Style Guidelines\n\n- Be precise. Avoid bloated or vague language.\n\n- Maintain an informative and engaging tone, suitable to the target audience.\n\n- Do not remove keywords unless absolutely necessary for clarity.\n\n- Ensure paragraph flow and section continuity.\n\n\n# Input\n\nYou will receive:\n\n- Full blog content, written section-by-section\n\n- Original outline with suggested keywords\n\n- Target audience and writing type\n\n# Output Format\n\n```markdown\n\n[The revised, fully polished blog post content goes here.]\n\n", | |||||
| "temperature": 0.2, | |||||
| "temperatureEnabled": true, | |||||
| "tools": [], | |||||
| "topPEnabled": false, | |||||
| "top_p": 0.75, | |||||
| "user_prompt": "", | |||||
| "visual_files_var": "" | |||||
| }, | |||||
| "label": "Agent", | |||||
| "name": "Editor Agent" | |||||
| }, | |||||
| "dragging": false, | |||||
| "id": "Agent:LovelyHeadsOwn", | |||||
| "measured": { | |||||
| "height": 84, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": 1160.3332919804993, | |||||
| "y": 149.50806732882472 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "agentNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "content": [ | |||||
| "{Agent:LovelyHeadsOwn@content}" | |||||
| ] | |||||
| }, | |||||
| "label": "Message", | |||||
| "name": "Response" | |||||
| }, | |||||
| "dragging": false, | |||||
| "id": "Message:LegalBeansBet", | |||||
| "measured": { | |||||
| "height": 56, | |||||
| "width": 200 | |||||
| }, | |||||
| "position": { | |||||
| "x": 1370.6665839609984, | |||||
| "y": 267.0323933738015 | |||||
| }, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "messageNode" | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "text": "This workflow automatically generates a complete SEO-optimized blog article based on a simple user input. You don\u2019t need any writing experience. Just provide a topic or short request \u2014 the system will handle the rest.\n\nThe process includes the following key stages:\n\n1. **Understanding your topic and goals**\n2. **Designing the blog structure**\n3. **Writing high-quality content**\n\n\n" | |||||
| }, | |||||
| "label": "Note", | |||||
| "name": "Workflow Overall Description" | |||||
| }, | |||||
| "dragHandle": ".note-drag-handle", | |||||
| "dragging": false, | |||||
| "height": 205, | |||||
| "id": "Note:SlimyGhostsWear", | |||||
| "measured": { | |||||
| "height": 205, | |||||
| "width": 415 | |||||
| }, | |||||
| "position": { | |||||
| "x": -284.3143151688742, | |||||
| "y": 150.47632147913419 | |||||
| }, | |||||
| "resizing": false, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "noteNode", | |||||
| "width": 415 | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "text": "**Purpose**: \nThis agent reads the user\u2019s input and figures out what kind of blog needs to be written.\n\n**What it does**:\n- Understands the main topic you want to write about \n- Identifies who the blog is for (e.g., beginners, marketers, developers) \n- Determines the writing purpose (e.g., SEO traffic, product promotion, education) \n- Suggests 3\u20135 long-tail SEO keywords related to the topic" | |||||
| }, | |||||
| "label": "Note", | |||||
| "name": "Parse And Keyword Agent" | |||||
| }, | |||||
| "dragHandle": ".note-drag-handle", | |||||
| "dragging": false, | |||||
| "height": 152, | |||||
| "id": "Note:EmptyChairsShake", | |||||
| "measured": { | |||||
| "height": 152, | |||||
| "width": 340 | |||||
| }, | |||||
| "position": { | |||||
| "x": 295.04147626768133, | |||||
| "y": 372.2755718118446 | |||||
| }, | |||||
| "resizing": false, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "noteNode", | |||||
| "width": 340 | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "text": "**Purpose**: \nThis agent builds the blog structure \u2014 just like writing a table of contents before you start writing the full article.\n\n**What it does**:\n- Suggests a clear blog title that includes important keywords \n- Breaks the article into sections using H2 and H3 headings (like a professional blog layout) \n- Assigns 1\u20132 recommended keywords to each section to help with SEO \n- Follows the writing goal and target audience set in the previous step" | |||||
| }, | |||||
| "label": "Note", | |||||
| "name": "Outline Agent" | |||||
| }, | |||||
| "dragHandle": ".note-drag-handle", | |||||
| "dragging": false, | |||||
| "height": 146, | |||||
| "id": "Note:TallMelonsNotice", | |||||
| "measured": { | |||||
| "height": 146, | |||||
| "width": 343 | |||||
| }, | |||||
| "position": { | |||||
| "x": 598.5644991893463, | |||||
| "y": 5.801054564756448 | |||||
| }, | |||||
| "resizing": false, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "noteNode", | |||||
| "width": 343 | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "text": "**Purpose**: \nThis agent is responsible for writing the actual content of the blog \u2014 paragraph by paragraph \u2014 based on the outline created earlier.\n\n**What it does**:\n- Looks at each H2/H3 section in the outline \n- Writes 150\u2013220 words of clear, helpful, and well-structured content per section \n- Includes the suggested SEO keywords naturally (not keyword stuffing) \n- Uses real examples or facts if needed (by calling a web search tool like Tavily)" | |||||
| }, | |||||
| "label": "Note", | |||||
| "name": "Body Agent" | |||||
| }, | |||||
| "dragHandle": ".note-drag-handle", | |||||
| "dragging": false, | |||||
| "height": 137, | |||||
| "id": "Note:RipeCougarsBuild", | |||||
| "measured": { | |||||
| "height": 137, | |||||
| "width": 319 | |||||
| }, | |||||
| "position": { | |||||
| "x": 860.4854129814981, | |||||
| "y": 427.2196835690842 | |||||
| }, | |||||
| "resizing": false, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "noteNode", | |||||
| "width": 319 | |||||
| }, | |||||
| { | |||||
| "data": { | |||||
| "form": { | |||||
| "text": "**Purpose**: \nThis agent reviews the entire blog draft to make sure it is smooth, professional, and SEO-friendly. It acts like a human editor before publishing.\n\n**What it does**:\n- Polishes the writing: improves sentence clarity, fixes awkward phrasing \n- Makes sure the content flows well from one section to the next \n- Double-checks keyword usage: are they present, natural, and not overused? \n- Verifies the blog structure (H1, H2, H3 headings) is correct \n- Adds two key SEO elements:\n - **Meta Title** (shows up in search results)\n - **Meta Description** (summary for Google and social sharing)" | |||||
| }, | |||||
| "label": "Note", | |||||
| "name": "Editor Agent" | |||||
| }, | |||||
| "dragHandle": ".note-drag-handle", | |||||
| "height": 146, | |||||
| "id": "Note:OpenTurkeysSell", | |||||
| "measured": { | |||||
| "height": 146, | |||||
| "width": 320 | |||||
| }, | |||||
| "position": { | |||||
| "x": 1129, | |||||
| "y": -30 | |||||
| }, | |||||
| "resizing": false, | |||||
| "selected": false, | |||||
| "sourcePosition": "right", | |||||
| "targetPosition": "left", | |||||
| "type": "noteNode", | |||||
| "width": 320 | |||||
| } | |||||
| ] | |||||
| }, | |||||
| "history": [], | |||||
| "messages": [], | |||||
| "path": [], | |||||
| "retrieval": [] | |||||
| }, | |||||
| "avatar": "data:image/jpeg;base64,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" | |||||
| } |
| def tool_call(self, name: str, arguments: dict[str, Any]) -> Any: | def tool_call(self, name: str, arguments: dict[str, Any]) -> Any: | ||||
| assert name in self.tools_map, f"LLM tool {name} does not exist" | assert name in self.tools_map, f"LLM tool {name} does not exist" | ||||
| self.callback(name, arguments, " running ...") | |||||
| if isinstance(self.tools_map[name], MCPToolCallSession): | if isinstance(self.tools_map[name], MCPToolCallSession): | ||||
| resp = self.tools_map[name].tool_call(name, arguments, 60) | resp = self.tools_map[name].tool_call(name, arguments, 60) | ||||
| else: | else: | ||||
| resp = self.tools_map[name].invoke(**arguments) | resp = self.tools_map[name].invoke(**arguments) | ||||
| self.callback(name, arguments, resp) | |||||
| return resp | return resp | ||||
| def get_tool_obj(self, name): | def get_tool_obj(self, name): |
| return get_error_data_result(f"Can't find agent by ID: {agent_id}") | return get_error_data_result(f"Can't find agent by ID: {agent_id}") | ||||
| canvas = Canvas(json.dumps(cvs.dsl), objs[0].tenant_id) | canvas = Canvas(json.dumps(cvs.dsl), objs[0].tenant_id) | ||||
| return get_result(data=canvas.get_component_input_form("begin")) | |||||
| return get_result(data={ | |||||
| "title": cvs.title, | |||||
| "avatar": cvs.avatar, | |||||
| "inputs": canvas.get_component_input_form("begin") | |||||
| }) | |||||
| assert e, "Session not found!" | assert e, "Session not found!" | ||||
| if not conv.message: | if not conv.message: | ||||
| conv.message = [] | conv.message = [] | ||||
| canvas = Canvas(json.dumps(conv.dsl), tenant_id, session_id) | |||||
| if not isinstance(conv.dsl, str): | |||||
| conv.dsl = json.dumps(conv.dsl, ensure_ascii=False) | |||||
| canvas = Canvas(conv.dsl, tenant_id, agent_id) | |||||
| else: | else: | ||||
| e, cvs = UserCanvasService.get_by_id(agent_id) | e, cvs = UserCanvasService.get_by_id(agent_id) | ||||
| assert e, "Agent not found." | assert e, "Agent not found." | ||||
| if not isinstance(cvs.dsl, str): | if not isinstance(cvs.dsl, str): | ||||
| cvs.dsl = json.dumps(cvs.dsl, ensure_ascii=False) | cvs.dsl = json.dumps(cvs.dsl, ensure_ascii=False) | ||||
| session_id=get_uuid() | session_id=get_uuid() | ||||
| canvas = Canvas(cvs.dsl, tenant_id, session_id) | |||||
| canvas = Canvas(cvs.dsl, tenant_id, agent_id) | |||||
| canvas.reset() | |||||
| conv = { | conv = { | ||||
| "id": session_id, | "id": session_id, | ||||
| "dialog_id": cvs.id, | "dialog_id": cvs.id, |
| class RAGFlowHtmlParser: | class RAGFlowHtmlParser: | ||||
| def __call__(self, fnm, binary=None): | def __call__(self, fnm, binary=None): | ||||
| txt = "" | |||||
| if binary: | if binary: | ||||
| encoding = find_codec(binary) | encoding = find_codec(binary) | ||||
| txt = binary.decode(encoding, errors="ignore") | txt = binary.decode(encoding, errors="ignore") |
| "q2": "二季度", | "q2": "二季度", | ||||
| "q3": "三季度", | "q3": "三季度", | ||||
| "q4": "四季度", | "q4": "四季度", | ||||
| "周一": ["礼拜一", "星期一"], | |||||
| "周二": ["礼拜二", "星期二"], | |||||
| "周三": ["礼拜三", "星期三"], | |||||
| "周四": ["礼拜四", "星期四"], | |||||
| "周五": ["礼拜五", "星期五"], | |||||
| "周六": ["礼拜六", "星期六"], | |||||
| "周日": ["礼拜日", "星期日", "星期天", "礼拜天"], | |||||
| "上班": "办公" | "上班": "办公" | ||||
| } | } |