赞
踩
用他们自己的官网(https://dify.ai/)介绍来说他们是:The Innovation Engine for GenAl Applications——它是生成式AI应用的创新引擎
Dify是GitHub的开源的项目(https://github.com/langgenius/dify)
对比我们之前用到的MaxKB来说,Dify无疑是一个全面加强的生成式AI的创建引擎
他的能力不仅包含MaxKB的RAG引擎。也同时可以本地化部署,更可以建立业务场景更为复杂的Agent以及Workflow。当然这也只是Dify的主要特性。
随着我们进行安装部署后,在我们的一步步探索中,将逐步发现Dify的强大能力。
Dify的安装与部署
我们来到Dify的github主页并且clone代码到本地
https://github.com/langgenius/dify
然后在代码的根目录执行
cd docker``cp .env.example .env``docker compose up -d
没错,这又是一个基于docker的项目,等待拉取对应组件并且安装后。Dify就算安装成功了
我们可以看到安装并且运行中的Dify包含nginx,redis,poestgresql等等多个部分。相比MaxKB的结构来说就已经复杂了好多。
这里我们可以看到,其中nginx组件把容器中的80端口映射到本机的80端口了。
没错,我们想体验本地化部署的Dify,访问http://localhost/apps这个地址就好了。
首次登录会进行进入初始化页面,会要求提供一个你的邮箱作为管理员账户。设置好后,就可以进入Dify的主页了
首先我们聚焦到右上角的设置区
在这里我们又看到了熟悉的配置模型的内容,以及我们的老朋友Ollama。当然几乎所有知名的AI提供商,都可以配置在Dify中。这里我们配置了本地的Ollama以及智谱-AI。
Ollama的配置主要是localhost:11434的端口配置,其他AI提供商的则是需要在对应网站获取API-EKY并且配置到Dify中。
我们再回到Dify主页,先可以简单设置一个聊天工具。
在创建完成后我们在这个应用的配置页面,发现了一些熟悉的东西,M阿西KB创建应用时候出现过的提示词、本地知识库Dify是全面支持的。另外右上角,我们可以随时随意的切换这个应用所使用的模型。同时也可以在这里进行简单的测试,没有问题后就可以把这个应用发布了
发布完成后,会在Dify的主页看到这个应用。
打造期待的工作流
在Dify中我们可以设置三类应用,分别是聊天助手、Agent、工作流。
回顾一下上一次我们设想的客服助手需要实现的功能。
那么这个流程现在是可以通过Dify的工作流实现的了。
根据Dify的工作流的组件
工作流是由我们自行定义和组合的节点组成的顺序执行的流程
结合我们的业务流程图。发现所有我们所需的节点都有解决方案。
在业务流程中,问题分类,对应Dify的问题分类器节点。而 function call部分则对应着HTTP请求。
为了验证我们的流程,我们建立一个电商助手的工作流:
它能支持三类问题:1.优惠券问题 2.订单问题 3.其他问题
一、如果提问内容与优惠券问题相关联,则会1.调用优惠券信息接口 2.调用优惠券知识库 3.把以上内容作为上下文传入优惠券推理模型,由模型结合问题给出答案
二、如果提问内容与订单问题相关联,则会1.调用订单信息接口 2.将订单信息接口上下文传入优惠券推理模型,由模型结合问题给出答案
三、其他类的问题,则直接把用户问题接入通用处理大模型
根据以上基本应用需求。我们规划的工作流如下
为此我们也建立了两个模拟接口分别是优惠券信息与订单信息
这里仅以优惠券信息为例
`@RequestMapping("/coupon")` `public String coupon(){` `Map<String ,String> coupon = new HashMap<>();` `coupon.put("valid_start_time","2018-06-18 10:53:22");` `coupon.put("valid_end_time","2025-10-20 10:53:25");` `coupon.put("name","新人礼包券");` `coupon.put("id","4dbaee58d68ef8ea");` `coupon.put("current_time", DateUtil.now());` `Map<String ,String> coupon2 = new HashMap<>();` `coupon2.put("valid_start_time","2018-06-18 10:53:22");` `coupon2.put("valid_end_time","2023-10-20 10:53:25");` `coupon2.put("name","回归礼包券");` `coupon2.put("id","51dee58d68ef8ea");` `coupon.put("current_time", DateUtil.now());` `List<Map<String,String>> couponList = new ArrayList<>();` `couponList.add(coupon);` `couponList.add(coupon2);` `return JSONUtil.toJsonStr(couponList);` `}`
这里包括valid_end_time优惠券过期时间,以及当前时间current_time
同时我们也在Dify中设置了优惠券规则的知识库,规定了优惠券过期的判断依据
所有组件都准备完毕后,剩下的工作流配置就没有障碍了。
下面我们逐一介绍Dify流程中我们用到的几个节点以及配置内容
开始节点
开始节点是流程的开始,这里可以自定义整个工作流的入参,这里我们配置了两个参数chat,以及userid。chat是用户提出的问题,userid则是记录用户的id。在后续的场景中,可能会产生依据userid进行查询某个API的可能性。
问题分类器
本质上还是一个语言模型,他会根据前置节点的输入信息进行合理的推断,从而进行流程的路由分发工作
这里的分类尽量要贴合前置节点(本例中的开始节点中的chat内容)
HTTP请求
这里的配置与一般的http请求配置方式是一致的。这里不再赘述,这里特别提一点,参数值params里是可以指定之前节点中的各种参数值的,这里我加了一个参数userid,其值来源就是在开始节点中的入参userid。
知识检索
这里的配置特别提示的就是查询变量,这里也是需要指定一个查询变量的。依据这个变量进行RAG检索以及召回动作。
LLM模型
这个就是一个标准的语言模型的节点了。我们可以配置具体的模型,相关的提示词,另外这里特别强调一下,本地化的模型特别的“不听话”,所以提示词的建立还是需要一些技巧,慢慢引导模型懂你的意思的。这个过程可以单独建立一个语言模型应用不断尝试。最终打磨出适合的提示词。
结束
这里是工作流的重点,需要配置的内容是返回值。在这个例子中我们返回的是前一步优惠券推理模型的输出结果。以文字形式输出。
再补全其他两个分支的工作流,这时我们再完整的看下这个工作流
然后可以点运行并且在输入参数后进行流程测试
发布、调试、集成到其他系统
在线测试满意之后,我们就可以把这个应用发布出来了。应
这里提供了通过API访问这个工作流应用的说明文档。
curl -X POST 'http://localhost/v1/workflows/run' \``--header 'Authorization: Bearer app-v46HdwGDpo2kUUcBbmSHobwD' \``--header 'Content-Type: application/json' \``--data-raw '{` `"inputs": { "chat":"哪张优惠券可用?","userId": "123"},` `"response_mode": "streaming",` `"user": "abc-123"``}'``
data: {"event": "workflow_started", "workflow_run_id": "fdb58da5-87d5-4a65-8c82-214539f573a2", "task_id": "6dc14f97-cc31-404f-911b-42d4967c8e23", "data": {"id": "fdb58da5-87d5-4a65-8c82-214539f573a2", "workflow_id": "df3ab5a5-e15e-4c10-aa34-f4730dc85853", "sequence_number": 14, "inputs": {"chat": "\u4f18\u60e0\u5238", "sys.files": [], "sys.user_id": "abc-123"}, "created_at": 1720061525}}`` ``data: {"event": "node_started", "workflow_run_id": "fdb58da5-87d5-4a65-8c82-214539f573a2", "task_id": "6dc14f97-cc31-404f-911b-42d4967c8e23", "data": {"id": "59f4329b-9879-4a66-b428-9e90cc939139", "node_id": "1720001015245", "node_type": "start", "title": "\u5f00\u59cb", "index": 1, "predecessor_node_id": null, "inputs": null, "created_at": 1720061525, "extras": {}}}`` ``data: {"event": "node_finished", "workflow_run_id": "fdb58da5-87d5-4a65-8c82-214539f573a2", "task_id": "6dc14f97-cc31-404f-911b-42d4967c8e23", "data": {"id": "59f4329b-9879-4a66-b428-9e90cc939139", "node_id": "1720001015245", "node_type": "start", "title": "\u5f00\u59cb", "index": 1, "predecessor_node_id": null, "inputs": {"chat": "\u4f18\u60e0\u5238", "sys.files": [], "sys.user_id": "abc-123"}, "process_data": null, "outputs": {"chat": "\u4f18\u60e0\u5238", "sys.files": [], "sys.user_id": "abc-123"}, "status": "succeeded", "error": null, "elapsed_time": 0.0009632089931983501, "execution_metadata": null, "created_at": 1720061525, "finished_at": 1720061524, "files": []}}`` ``data: {"event": "node_started", "workflow_run_id": "fdb58da5-87d5-4a65-8c82-214539f573a2", "task_id": "6dc14f97-cc31-404f-911b-42d4967c8e23", "data": {"id": "45588b3f-7011-400e-ac88-2d22b8d12d76", "node_id": "1720058356548", "node_type": "question-classifier", "title": "\u95ee\u9898\u5206\u7c7b\u5668", "index": 2, "predecessor_node_id": "1720001015245", "inputs": null, "created_at": 1720061525, "extras": {}}}`` ``data: {"event": "node_finished", "workflow_run_id": "fdb58da5-87d5-4a65-8c82-214539f573a2", "task_id": "6dc14f97-cc31-404f-911b-42d4967c8e23", "data": {"id": "45588b3f-7011-400e-ac88-2d22b8d12d76", "node_id": "1720058356548", "node_type": "question-classifier", "title": "\u95ee\u9898\u5206\u7c7b\u5668", "index": 2, "predecessor_node_id": "1720001015245", "inputs": {"query": "\u4f18\u60e0\u5238"}, "process_data": {"model_mode": "chat", "prompts": [{"role": "system", "text": "\n ### Job Description',\n You are a text classification engine that analyzes text data and assigns categories based on user input or automatically determined categories.\n ### Task\n Your task is to assign one categories ONLY to the input text and only one category may be assigned returned in the output.Additionally, you need to extract the key words from the text that are related to the classification.\n ### Format\n The input text is in the variable text_field.Categories are specified as a category list with two filed category_id and category_name in the variable categories .Classification instructions may be included to improve the classification accuracy.\n ### Constraint\n DO NOT include anything other than the JSON array in your response.\n ### Memory\n Here is the chat histories between human and assistant, inside <histories></histories> XML tags.\n <histories>\n \n </histories>\n", "files": []}, {"role": "user", "text": "\n { \"input_text\": [\"I recently had a great experience with your company. The service was prompt and the staff was very friendly.\"],\n \"categories\": [{\"category_id\":\"f5660049-284f-41a7-b301-fd24176a711c\",\"category_name\":\"Customer Service\"},{\"category_id\":\"8d007d06-f2c9-4be5-8ff6-cd4381c13c60\",\"category_name\":\"Satisfaction\"},{\"category_id\":\"5fbbbb18-9843-466d-9b8e-b9bfbb9482c8\",\"category_name\":\"Sales\"},{\"category_id\":\"23623c75-7184-4a2e-8226-466c2e4631e4\",\"category_name\":\"Product\"}],\n \"classification_instructions\": [\"classify the text based on the feedback provided by customer\"]}\n", "files": []}, {"role": "assistant", "text": "\n```json\n {\"keywords\": [\"recently\", \"great experience\", \"company\", \"service\", \"prompt\", \"staff\", \"friendly\"],\n \"category_id\": \"f5660049-284f-41a7-b301-fd24176a711c\",\n \"category_name\": \"Customer Service\"}\n```\n", "files": []}, {"role": "user", "text": "\n {\"input_text\": [\"bad service, slow to bring the food\"],\n \"categories\": [{\"category_id\":\"80fb86a0-4454-4bf5-924c-f253fdd83c02\",\"category_name\":\"Food Quality\"},{\"category_id\":\"f6ff5bc3-aca0-4e4a-8627-e760d0aca78f\",\"category_name\":\"Experience\"},{\"category_id\":\"cc771f63-74e7-4c61-882e-3eda9d8ba5d7\",\"category_name\":\"Price\"}],\n \"classification_instructions\": []}\n", "files": []}, {"role": "assistant", "text": "\n```json\n {\"keywords\": [\"bad service\", \"slow\", \"food\", \"tip\", \"terrible\", \"waitresses\"],\n \"category_id\": \"f6ff5bc3-aca0-4e4a-8627-e760d0aca78f\",\n \"category_name\": \"Experience\"}\n```\n", "files": []}, {"role": "user", "text": "\n '{\"input_text\": [\"\u4f18\u60e0\u5238\"],',\n '\"categories\": [{\"category_id\": \"1\", \"category_name\": \"\u4f18\u60e0\u5238\u95ee\u7b54\"}, {\"category_id\": \"2\", \"category_name\": \"\u666e\u901a\u95ee\u7b54\"}], ',\n '\"classification_instructions\": [\"\"]}'\n", "files": []}], "usage": {"prompt_tokens": 887, "prompt_unit_price": "0", "prompt_price_unit": "0", "prompt_price": "0.0000000", "completion_tokens": 138, "completion_unit_price": "0", "completion_price_unit": "0", "completion_price": "0.0000000", "total_tokens": 1025, "total_price": "0.0000000", "currency": "USD", "latency": 7.283583379001357}}, "outputs": {"class_name": "\u4f18\u60e0\u5238\u95ee\u7b54"}, "status": "succeeded", "error": null, "elapsed_time": 7.29491296201013, "execution_metadata": {"total_tokens": 1025, "total_price": "0.0000000", "currency": "USD"}, "created_at": 1720061525, "finished_at": 1720061531, "files": []}}`` ``data: {"event": "node_started", "workflow_run_id": "fdb58da5-87d5-4a65-8c82-214539f573a2", "task_id": "6dc14f97-cc31-404f-911b-42d4967c8e23", "data": {"id": "2e05dc89-a9e5-4461-a226-80368e1ba1b3", "node_id": "1720058784300", "node_type": "http-request", "title": "HTTP \u8bf7\u6c42 2", "index": 3, "predecessor_node_id": "1720058356548", "inputs": null, "created_at": 1720061532, "extras": {}}}`` ``data: {"event": "node_finished", "workflow_run_id": "fdb58da5-87d5-4a65-8c82-214539f573a2", "task_id": "6dc14f97-cc31-404f-911b-42d4967c8e23", "data": {"id": "2e05dc89-a9e5-4461-a226-80368e1ba1b3", "node_id": "1720058784300", "node_type": "http-request", "title": "HTTP \u8bf7\u6c42 2", "index": 3, "predecessor_node_id": "1720058356548", "inputs": null, "process_data": {"request": "GET http://host.docker.internal:8080/coupon HTTP/1.1\n\n"}, "outputs": {"status_code": 200, "body": "[{\"valid_start_time\":\"2018-06-18 10:53:22\",\"name\":\"\u65b0\u4eba\u793c\u5305\u5238\",\"valid_end_time\":\"2025-10-20 10:53:25\",\"id\":\"4dbaee58d68ef8ea\",\"current_time\":\"2024-07-04 10:52:11\"},{\"valid_start_time\":\"2018-06-18 10:53:22\",\"name\":\"\u56de\u5f52\u793c\u5305\u5238\",\"valid_end_time\":\"2023-10-20 10:53:25\",\"id\":\"51dee58d68ef8ea\"}]", "headers": {"content-type": "text/plain;charset=UTF-8", "content-length": "299", "date": "Thu, 04 Jul 2024 02:52:11 GMT", "cache-status": "47ea977ee374;fwd=stale;detail=match", "via": "1.1 47ea977ee374 (squid/6.1)", "connection": "keep-alive"}, "files": []}, "status": "succeeded", "error": null, "elapsed_time": 0.06886870801099576, "execution_metadata": null, "created_at": 1720061532, "finished_at": 1720061531, "files": []}}`` ``data: {"event": "node_started", "workflow_run_id": "fdb58da5-87d5-4a65-8c82-214539f573a2", "task_id": "6dc14f97-cc31-404f-911b-42d4967c8e23", "data": {"id": "7b3e53a1-69e8-4be1-b159-62a311a7c29d", "node_id": "1720001028973", "node_type": "knowledge-retrieval", "title": "\u77e5\u8bc6\u68c0\u7d22", "index": 4, "predecessor_node_id": "1720058784300", "inputs": null, "created_at": 1720061532, "extras": {}}}`` ``data: {"event": "node_finished", "workflow_run_id": "fdb58da5-87d5-4a65-8c82-214539f573a2", "task_id": "6dc14f97-cc31-404f-911b-42d4967c8e23", "data": {"id": "7b3e53a1-69e8-4be1-b159-62a311a7c29d", "node_id": "1720001028973", "node_type": "knowledge-retrieval", "title": "\u77e5\u8bc6\u68c0\u7d22", "index": 4, "predecessor_node_id": "1720058784300", "inputs": {"query": "\u4f18\u60e0\u5238"}, "process_data": null, "outputs": {"result": [{"metadata": {"_source": "knowledge", "position": 1, "dataset_id": "9521cccb-313a-42a0-8a2f-ecc040970964", "dataset_name": "\u4f18\u60e0\u5238\u89c4\u5219", "document_id": "6790853d-cd4a-4dfa-8062-ddd1c15aa594", "document_name": "\u4f18\u60e0\u5238\u89c4\u5219.docx", "document_data_source_type": "upload_file", "segment_id": "a36d593d-c3c4-44cb-8ea0-758560fa72fe", "retriever_from": "workflow", "score": 0.54185438, "segment_hit_count": 10, "segment_word_count": 50, "segment_position": 1, "segment_index_node_hash": "1350de447714b3750a132bef35b6e4b16c5c89360c5ca9683ecaa50a31a81e29"}, "title": "\u4f18\u60e0\u5238\u89c4\u5219.docx", "content": "\u5f53\u4f18\u60e0\u5238\u7684valid_end_time\u5c5e\u6027\u5c0f\u4e8ecurrent_time\u5f53\u524d\u65f6\u95f4\u65f6\uff0c\u4f18\u60e0\u5238\u5224\u5b9a\u4e3a\u8fc7\u671f\u3002"}]}, "status": "succeeded", "error": null, "elapsed_time": 0.021647582994773984, "execution_metadata": null, "created_at": 1720061532, "finished_at": 1720061531, "files": []}}`` ``data: {"event": "node_started", "workflow_run_id": "fdb58da5-87d5-4a65-8c82-214539f573a2", "task_id": "6dc14f97-cc31-404f-911b-42d4967c8e23", "data": {"id": "861b49f6-530c-4fb2-92f1-3d690a1e27f0", "node_id": "1720058769328", "node_type": "llm", "title": "LLM 2", "index": 5, "predecessor_node_id": "1720001028973", "inputs": null, "created_at": 1720061532, "extras": {}}}`` ``event: ping`` ``data: {"event": "node_finished", "workflow_run_id": "fdb58da5-87d5-4a65-8c82-214539f573a2", "task_id": "6dc14f97-cc31-404f-911b-42d4967c8e23", "data": {"id": "861b49f6-530c-4fb2-92f1-3d690a1e27f0", "node_id": "1720058769328", "node_type": "llm", "title": "LLM 2", "index": 5, "predecessor_node_id": "1720001028973", "inputs": {"#context#": "\u5f53\u4f18\u60e0\u5238\u7684valid_end_time\u5c5e\u6027\u5c0f\u4e8ecurrent_time\u5f53\u524d\u65f6\u95f4\u65f6\uff0c\u4f18\u60e0\u5238\u5224\u5b9a\u4e3a\u8fc7\u671f\u3002"}, "process_data": {"model_mode": "chat", "prompts": [{"role": "system", "text": "\u6839\u636e[{\"valid_start_time\":\"2018-06-18 10:53:22\",\"name\":\"\u65b0\u4eba\u793c\u5305\u5238\",\"valid_end_time\":\"2025-10-20 10:53:25\",\"id\":\"4dbaee58d68ef8ea\",\"current_time\":\"2024-07-04 10:52:11\"},{\"valid_start_time\":\"2018-06-18 10:53:22\",\"name\":\"\u56de\u5f52\u793c\u5305\u5238\",\"valid_end_time\":\"2023-10-20 10:53:25\",\"id\":\"51dee58d68ef8ea\"}]\u662f\u4f18\u60e0\u5238\u7684\u5217\u8868\uff0c\u5305\u542b\u5230\u671f\u65f6\u95f4\u548c\u5f53\u524d\u65f6\u95f4\uff0c\u4f60\u4ec5\u9700\u8981\u6839\u636e\u8fd9\u4e24\u4e2a\u65f6\u95f4\u8fdb\u884c\u5224\u65ad\u3002\u4ee5\u3010\u53ef\u7528\u7684\u4f18\u60e0\u5238\u540d\u79f0\uff1axxx\uff0c\u5230\u671f\u65f6\u95f4\u4e3ayyy \u3011\u8fd9\u79cd\u683c\u5f0f\u8f93\u51fa\u3002\u4e0d\u9700\u8981\u8f93\u51fa\u63a8\u7406\u8fc7\u7a0b\uff0c\u4ec5\u6309\u89c4\u5b9a\u683c\u5f0f\u8f93\u51fa", "files": []}, {"role": "user", "text": "\u6839\u636e[{\"valid_start_time\":\"2018-06-18 10:53:22\",\"name\":\"\u65b0\u4eba\u793c\u5305\u5238\",\"valid_end_time\":\"2025-10-20 10:53:25\",\"id\":\"4dbaee58d68ef8ea\",\"current_time\":\"2024-07-04 10:52:11\"},{\"valid_start_time\":\"2018-06-18 10:53:22\",\"name\":\"\u56de\u5f52\u793c\u5305\u5238\",\"valid_end_time\":\"2023-10-20 10:53:25\",\"id\":\"51dee58d68ef8ea\"}]\u662f\u4f18\u60e0\u5238\u7684\u5217\u8868\uff0c\u5305\u542b\u5230\u671f\u65f6\u95f4\u548c\u5f53\u524d\u65f6\u95f4\uff0c\u4f60\u4ec5\u9700\u8981\u5f53\u4f18\u60e0\u5238\u7684valid_end_time\u5c5e\u6027\u5c0f\u4e8ecurrent_time\u5f53\u524d\u65f6\u95f4\u65f6\uff0c\u4f18\u60e0\u5238\u5224\u5b9a\u4e3a\u8fc7\u671f\u3002\u4ece\u77e5\u8bc6\u68c0\u7d22\u5185\u5bb9\u4e2d\uff0c\u6839\u636e\u8fd9\u4e24\u4e2a\u65f6\u95f4\u8fdb\u884c\u5224\u65ad\u3002\u4ee5\u3010\u53ef\u7528\u7684\u4f18\u60e0\u5238\u540d\u79f0\uff1axxx\uff0c\u5230\u671f\u65f6\u95f4\u4e3ayyy \u3011\u8fd9\u79cd\u683c\u5f0f\u8f93\u51fa\u3002\u4e0d\u9700\u8981\u8f93\u51fa\u63a8\u7406\u8fc7\u7a0b\uff0c\u4ec5\u6309\u89c4\u5b9a\u683c\u5f0f\u8f93\u51fa", "files": []}]}, "outputs": {"text": "\u6839\u636e\u63d0\u4f9b\u7684\u4f18\u60e0\u5238\u5217\u8868\uff1a\n\n1. \u65b0\u4eba\u793c\u5305\u5238\uff08id: 4dbaee58d68ef8ea\uff09\uff0cvalid_end_time: 2025-10-20 10:53:25\uff0ccurrent_\u65f6\u95f4: 2024-07-04 10:52:11\u3002\u8be5\u5238\u5c1a\u672a\u8fc7\u671f\u3002\n\n2. \u56de\u5f52\u793c\u5305\u5238\uff08id: 51dee58d68ef8ea\uff09\uff0cvalid_end_time: 2023-10-20 10:53:25\uff0ccurrent_\u65f6\u95f4: 2024-07-04 10:52:11\u3002\u8be5\u5238\u5df2\u8fc7\u671f\u3002\n\n\u8f93\u51fa\u683c\u5f0f\u5982\u4e0b\uff1a\n\n\u3010\u53ef\u7528\u7684\u4f18\u60e0\u5238\u540d\u79f0\uff1a\u65b0\u4eba\u793c\u5305\u5238\uff0c\u5230\u671f\u65f6\u95f4\u4e3a2025-10-20 10:53:25\u3011\n\u3010\u5df2\u8fc7\u671f\u7684\u4f18\u60e0\u5238\u540d\u79f0\uff1a\u56de\u5f52\u793c\u5305\u5238\uff0c\u5230\u671f\u65f6\u95f4\u4e3a2023-10-20 10:53:25\u3011", "usage": {"prompt_tokens": 483, "prompt_unit_price": "0", "prompt_price_unit": "0", "prompt_price": "0.0000000", "completion_tokens": 239, "completion_unit_price": "0", "completion_price_unit": "0", "completion_price": "0.0000000", "total_tokens": 722, "total_price": "0.0000000", "currency": "USD", "latency": 8.947470255021472}}, "status": "succeeded", "error": null, "elapsed_time": 8.956229670991888, "execution_metadata": {"total_tokens": 722, "total_price": "0.0000000", "currency": "USD"}, "created_at": 1720061532, "finished_at": 1720061540, "files": []}}`` ``data: {"event": "node_started", "workflow_run_id": "fdb58da5-87d5-4a65-8c82-214539f573a2", "task_id": "6dc14f97-cc31-404f-911b-42d4967c8e23", "data": {"id": "98189293-b1c5-4a91-8b81-13b318eef349", "node_id": "1720061330502", "node_type": "end", "title": "\u7ed3\u675f", "index": 6, "predecessor_node_id": "1720058769328", "inputs": null, "created_at": 1720061541, "extras": {}}}`` ``data: {"event": "node_finished", "workflow_run_id": "fdb58da5-87d5-4a65-8c82-214539f573a2", "task_id": "6dc14f97-cc31-404f-911b-42d4967c8e23", "data": {"id": "98189293-b1c5-4a91-8b81-13b318eef349", "node_id": "1720061330502", "node_type": "end", "title": "\u7ed3\u675f", "index": 6, "predecessor_node_id": "1720058769328", "inputs": null, "process_data": null, "outputs": null, "status": "succeeded", "error": null, "elapsed_time": 0.0010395830031484365, "execution_metadata": null, "created_at": 1720061541, "finished_at": 1720061540, "files": []}}`` ``data: {"event": "workflow_finished", "workflow_run_id": "fdb58da5-87d5-4a65-8c82-214539f573a2", "task_id": "6dc14f97-cc31-404f-911b-42d4967c8e23", "data": {"id": "fdb58da5-87d5-4a65-8c82-214539f573a2", "workflow_id": "df3ab5a5-e15e-4c10-aa34-f4730dc85853", "sequence_number": 14, "status": "succeeded", "outputs": null, "error": null, "elapsed_time": 16.399369008024223, "total_tokens": 1747, "total_steps": 6, "created_by": {"id": "6caaa9b1-0abd-4de7-b780-ddc5ff5f3c2a", "user": "abc-123"}, "created_at": 1720061525, "finished_at": 1720061540, "files": []}}
这里有一些小困难,就是返回的是流式信息
为此,我们特别设计了一个处理流式返回值的方法如下
import cn.hutool.http.HttpResponse;``import cn.hutool.http.HttpUtil;``import cn.hutool.json.JSONObject;``import cn.hutool.json.JSONUtil;`` ``public class WorkFlowApi {` `private static final String URL = "http://localhost/v1/workflows/run";` `private static final String AUTH_TOKEN = "app-v46HdwGDpo2kUUcBbmSHobwD";`` ` `public void runWorkflow(String chat, String userId) {` `JSONObject json = new JSONObject();` `json.putOpt("inputs", new JSONObject().putOpt("chat", chat).putOpt("user", userId));` `json.putOpt("response_mode", "streaming");` `json.putOpt("user", userId);`` ` `HttpResponse response = HttpUtil.createPost(URL)` `.header("Authorization", "Bearer " + AUTH_TOKEN)` `.header("Content-Type", "application/json")` `.body(json.toString())` `.execute();`` ` `if (response.isOk()) {` `String responseBody = response.body();` `// 解析响应数据` `String[] lines = responseBody.split("\n");` `for (String line : lines) {` `if (line.startsWith("data:")) {` `String data = line.substring("data:".length());` `JSONObject dataJson = JSONUtil.parseObj(data);` `if (dataJson.containsKey("event") && dataJson.getStr("event").equals("node_finished")) {` `JSONObject outputs = dataJson.getJSONObject("data").getJSONObject("outputs");` `if (outputs != null && outputs.containsKey("text")) {` `System.out.println(outputs.getStr("text"));` `}` `}` `}` `}`` ` `} else {` `System.out.println("Failed to execute workflow: " + response.getStatus());` `}` `}`` ` `public static void main(String[] args) {` `WorkFlowApi runner = new WorkFlowApi();` `runner.runWorkflow("优惠券", "abc-123");` `}``}``
点击main方法进行调试,发现结果可以顺利的解析出来了。
这样,我们就已经把一个完整的商城助手应用建立起来,并且把它发布出来并且可以结合到任何其他系统中,为相关的系统进行“AI赋能”了。
由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。
但是具体到个人,只能说是:
“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。
这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。
我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。
我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。
该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。
恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。
到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?
对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。
学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。
如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。
保证100%免费
】Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。