dify 解析笔记-工具篇

  1. 入口
    image
    选择工具duckduckgo
    发送消息后,后台的接口:
    1.chat-messages:https://cloud.dify.ai/console/api/apps/a21e7956-378f-47ea-9ce6-3d390d4674b4/chat-messages
    载荷
{"response_mode":"streaming","conversation_id":"","query":"hello","inputs":{},"model_config":{"pre_prompt":"","prompt_type":"simple","chat_prompt_config":{},"completion_prompt_config":{},"user_input_form":[],"dataset_query_variable":"","opening_statement":null,"more_like_this":{"enabled":false},"suggested_questions":[],"suggested_questions_after_answer":{"enabled":false},"text_to_speech":{"enabled":false},"speech_to_text":{"enabled":false},"retriever_resource":{"enabled":true},"sensitive_word_avoidance":{"enabled":false,"type":"","configs":[]},"agent_mode":{"max_iteration":5,"enabled":true,"strategy":"function_call","tools":[{"provider_id":"duckduckgo","provider_type":"builtin","provider_name":"duckduckgo","tool_name":"ddgo_ai","tool_label":"DuckDuckGo AI聊天","tool_parameters":{"query":"","model":""},"enabled":true}],"prompt":null},"dataset_configs":{"retrieval_model":"multiple","datasets":{"datasets":[]}},"file_upload":{"image":{"enabled":false,"number_limits":3,"detail":"high","transfer_methods":["remote_url","local_file"]}},"annotation_reply":{"enabled":false},"supportAnnotation":true,"appId":"a21e7956-378f-47ea-9ce6-3d390d4674b4","supportCitationHitInfo":true,"model":{"provider":"openai","name":"gpt-4o-mini","mode":"chat","completion_params":{}}}}

响应结果

data: {"event": "agent_thought", "conversation_id": "79d01e67-3b26-4d83-b138-8cce734d7610", "message_id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "created_at": 1726822243, "task_id": "397553c1-805d-45f7-b64e-4976b808c961", "id": "7409b3c5-8952-498e-bd9d-e36a168a53e6", "position": 1, "thought": "", "observation": "", "tool": "", "tool_labels": {}, "tool_input": "", "message_files": []}

data: {"event": "agent_message", "conversation_id": "79d01e67-3b26-4d83-b138-8cce734d7610", "message_id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "created_at": 1726822243, "task_id": "397553c1-805d-45f7-b64e-4976b808c961", "id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "answer": "Hello"}

data: {"event": "agent_message", "conversation_id": "79d01e67-3b26-4d83-b138-8cce734d7610", "message_id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "created_at": 1726822243, "task_id": "397553c1-805d-45f7-b64e-4976b808c961", "id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "answer": "!"}

data: {"event": "agent_message", "conversation_id": "79d01e67-3b26-4d83-b138-8cce734d7610", "message_id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "created_at": 1726822243, "task_id": "397553c1-805d-45f7-b64e-4976b808c961", "id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "answer": " How"}

data: {"event": "agent_message", "conversation_id": "79d01e67-3b26-4d83-b138-8cce734d7610", "message_id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "created_at": 1726822243, "task_id": "397553c1-805d-45f7-b64e-4976b808c961", "id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "answer": " can"}

data: {"event": "agent_message", "conversation_id": "79d01e67-3b26-4d83-b138-8cce734d7610", "message_id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "created_at": 1726822243, "task_id": "397553c1-805d-45f7-b64e-4976b808c961", "id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "answer": " I"}

data: {"event": "agent_message", "conversation_id": "79d01e67-3b26-4d83-b138-8cce734d7610", "message_id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "created_at": 1726822243, "task_id": "397553c1-805d-45f7-b64e-4976b808c961", "id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "answer": " assist"}

data: {"event": "agent_message", "conversation_id": "79d01e67-3b26-4d83-b138-8cce734d7610", "message_id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "created_at": 1726822243, "task_id": "397553c1-805d-45f7-b64e-4976b808c961", "id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "answer": " you"}

data: {"event": "agent_message", "conversation_id": "79d01e67-3b26-4d83-b138-8cce734d7610", "message_id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "created_at": 1726822243, "task_id": "397553c1-805d-45f7-b64e-4976b808c961", "id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "answer": " today"}

data: {"event": "agent_message", "conversation_id": "79d01e67-3b26-4d83-b138-8cce734d7610", "message_id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "created_at": 1726822243, "task_id": "397553c1-805d-45f7-b64e-4976b808c961", "id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "answer": "?"}

data: {"event": "agent_message", "conversation_id": "79d01e67-3b26-4d83-b138-8cce734d7610", "message_id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "created_at": 1726822243, "task_id": "397553c1-805d-45f7-b64e-4976b808c961", "id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "answer": ""}

data: {"event": "agent_thought", "conversation_id": "79d01e67-3b26-4d83-b138-8cce734d7610", "message_id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "created_at": 1726822243, "task_id": "397553c1-805d-45f7-b64e-4976b808c961", "id": "7409b3c5-8952-498e-bd9d-e36a168a53e6", "position": 1, "thought": "Hello! How can I assist you today?", "observation": "", "tool": "", "tool_labels": {}, "tool_input": "", "message_files": []}

data: {"event": "message_end", "conversation_id": "79d01e67-3b26-4d83-b138-8cce734d7610", "message_id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "created_at": 1726822243, "task_id": "397553c1-805d-45f7-b64e-4976b808c961", "id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "metadata": {"usage": {"prompt_tokens": 8, "prompt_unit_price": "0.15", "prompt_price_unit": "0.000001", "prompt_price": "0.0000012", "completion_tokens": 9, "completion_unit_price": "0.60", "completion_price_unit": "0.000001", "completion_price": "0.0000054", "total_tokens": 17, "total_price": "0.0000066", "currency": "USD", "latency": 0.5811177659779787}}}

data: {"event": "tts_message_end", "conversation_id": "79d01e67-3b26-4d83-b138-8cce734d7610", "message_id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3", "created_at": 1726822243, "task_id": "397553c1-805d-45f7-b64e-4976b808c961", "audio": ""}


2.https://cloud.dify.ai/console/api/apps/a21e7956-378f-47ea-9ce6-3d390d4674b4/chat-messages?conversation_id=79d01e67-3b26-4d83-b138-8cce734d7610
参数

conversation_id:79d01e67-3b26-4d83-b138-8cce734d7610

响应结果

{
  "limit": 20,
  "has_more": false,
  "data": [
    {
      "id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3",
      "conversation_id": "79d01e67-3b26-4d83-b138-8cce734d7610",
      "inputs": {},
      "query": "hello",
      "message": [
        {
          "role": "user",
          "text": "hello",
          "files": []
        }
      ],
      "message_tokens": 8,
      "answer": "Hello! How can I assist you today?",
      "answer_tokens": 9,
      "provider_response_latency": 0.6008692521136254,
      "from_source": "console",
      "from_end_user_id": null,
      "from_account_id": "b010bb9b-9098-4f07-a10e-39a6b6686d03",
      "feedbacks": [],
      "workflow_run_id": null,
      "annotation": null,
      "annotation_hit_history": null,
      "created_at": 1726822243,
      "agent_thoughts": [
        {
          "id": "7409b3c5-8952-498e-bd9d-e36a168a53e6",
          "chain_id": null,
          "message_id": "4692090d-09a4-4cdd-b768-2dc6d13e45f3",
          "position": 1,
          "thought": "Hello! How can I assist you today?",
          "tool": "",
          "tool_labels": {},
          "tool_input": "",
          "created_at": 1726822242,
          "observation": "",
          "files": []
        }
      ],
      "message_files": [],
      "metadata": {},
      "status": "normal",
      "error": null
    }
  ]
}

后端源码 console/app/completion

api.add_resource(ChatMessageApi, "/apps/<uuid:app_id>/chat-messages")
class ChatMessageApi(Resource):
    @setup_required
    @login_required
    @account_initialization_required
    @get_app_model(mode=[AppMode.CHAT, AppMode.AGENT_CHAT])
    def post(self, app_model):
        parser = reqparse.RequestParser()
        parser.add_argument("inputs", type=dict, required=True, location="json")
        parser.add_argument("query", type=str, required=True, location="json")
        parser.add_argument("files", type=list, required=False, location="json")
        parser.add_argument("model_config", type=dict, required=True, location="json")
        parser.add_argument("conversation_id", type=uuid_value, location="json")
        parser.add_argument("response_mode", type=str, choices=["blocking", "streaming"], location="json")
        parser.add_argument("retriever_from", type=str, required=False, default="dev", location="json")
        args = parser.parse_args()

        streaming = args["response_mode"] != "blocking"
        args["auto_generate_name"] = False

        account = flask_login.current_user

        try:
            response = AppGenerateService.generate(
                app_model=app_model, user=account, args=args, invoke_from=InvokeFrom.DEBUGGER, streaming=streaming
            )

问题

  1. app_model是怎么来的
  2. tenant_id到底是什么?

AppGenerateService.generate

            if app_model.mode == AppMode.COMPLETION.value:
                return rate_limit.generate(
                    CompletionAppGenerator().generate(
                        app_model=app_model, user=user, args=args, invoke_from=invoke_from, stream=streaming
                    ),
                    request_id,
                )
            elif app_model.mode == AppMode.AGENT_CHAT.value or app_model.is_agent:
                return rate_limit.generate(
                    AgentChatAppGenerator().generate(
                        app_model=app_model, user=user, args=args, invoke_from=invoke_from, stream=streaming
                    ),
                    request_id,
                )
            elif app_model.mode == AppMode.CHAT.value:
                return rate_limit.generate(
                    ChatAppGenerator().generate(
                        app_model=app_model, user=user, args=args, invoke_from=invoke_from, stream=streaming
                    ),
                    request_id,
                )

ChatAppGenerator

    def generate(
        self, app_model: App,
        user: Union[Account, EndUser],
        args: Any,
        invoke_from: InvokeFrom,
        stream: bool = True,
    ) -> Union[dict, Generator[dict, None, None]]:
        # new thread
        worker_thread = threading.Thread(target=self._generate_worker, kwargs={
            'flask_app': current_app._get_current_object(),
            'application_generate_entity': application_generate_entity,
            'queue_manager': queue_manager,
            'conversation_id': conversation.id,
            'message_id': message.id,
        })

    def _generate_worker(self, flask_app: Flask,
                         application_generate_entity: ChatAppGenerateEntity,
                         queue_manager: AppQueueManager,
                         conversation_id: str,
                         message_id: str) -> None:
                runner = ChatAppRunner()
                runner.run(
                    application_generate_entity=application_generate_entity,
                    queue_manager=queue_manager,
                    conversation=conversation,
                    message=message
                )

ChatAppRunner无fc_agent_runner

AgentChatAppGenerator含有fc_agent_runner

                # get conversation and message
                conversation = self._get_conversation(conversation_id)
                message = self._get_message(message_id)

                # chatbot app
                runner = AgentChatAppRunner()
                runner.run(
                    application_generate_entity=application_generate_entity,
                    queue_manager=queue_manager,
                    conversation=conversation,
                    message=message,
                )

AgentChatAppRunner

        elif agent_entity.strategy == AgentEntity.Strategy.FUNCTION_CALLING:
            runner_cls = FunctionCallAgentRunner
        runner = runner_cls(
            tenant_id=app_config.tenant_id,
            application_generate_entity=application_generate_entity,
            conversation=conversation,
            app_config=app_config,
            model_config=application_generate_entity.model_conf,
            config=agent_entity,
            queue_manager=queue_manager,
            message=message,
            user_id=application_generate_entity.user_id,
            memory=memory,
            prompt_messages=prompt_message,
            variables_pool=tool_variables,
            db_variables=tool_conversation_variables,
            model_instance=model_instance
        )
	invoke_result = runner.run(
            message=message,
            query=query,
            inputs=inputs,
        )

FunctionCallAgentRunner

            # save thought
            self.save_agent_thought(
                agent_thought=agent_thought, 
                tool_name=tool_call_names,
                tool_input=tool_call_inputs,
                thought=response,
                tool_invoke_meta=None,
                observation=None,
                answer=response,
                messages_ids=[],
                llm_usage=current_llm_usage
            )
            self.queue_manager.publish(QueueAgentThoughtEvent(
                agent_thought_id=agent_thought.id
            ), PublishFrom.APPLICATION_MANAGER)
            
            final_answer += response + '\n'

            # call tools
            tool_responses = []
            for tool_call_id, tool_call_name, tool_call_args in tool_calls:
                tool_instance = tool_instances.get(tool_call_name)
                if not tool_instance:
                    tool_response = {
                        "tool_call_id": tool_call_id,
                        "tool_call_name": tool_call_name,
                        "tool_response": f"there is not a tool named {tool_call_name}",
                        "meta": ToolInvokeMeta.error_instance(f"there is not a tool named {tool_call_name}").to_dict()
                    }
                else:
                    # invoke tool
                    tool_invoke_response, message_files, tool_invoke_meta = ToolEngine.agent_invoke(
                        tool=tool_instance,
                        tool_parameters=tool_call_args,
                        user_id=self.user_id,
                        tenant_id=self.tenant_id,
                        message=self.message,
                        invoke_from=self.application_generate_entity.invoke_from,
                        agent_tool_callback=self.agent_callback,
                        trace_manager=trace_manager,
                    )

toolEngine

    def agent_invoke(
        tool: Tool, tool_parameters: Union[str, dict],
        user_id: str, tenant_id: str, message: Message, invoke_from: InvokeFrom,
        agent_tool_callback: DifyAgentCallbackHandler,
        trace_manager: Optional[TraceQueueManager] = None
    ) -> tuple[str, list[tuple[MessageFile, bool]], ToolInvokeMeta]:
	

作者:Gim

出处:https://www.cnblogs.com/Gimm/p/18422804

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   踩坑大王  阅读(1707)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
more_horiz
keyboard_arrow_up light_mode palette
选择主题
点击右上角即可分享
微信分享提示