微信扫码
与创始人交个朋友
我要投稿
一、上期回顾
首先回顾一下我们之前本地化模型部署与应用里完成的应用
我们基于Ollama完成了本地化模型的部署,并且通过MaxKB以及本地建立的知识库,完成了一个基于RAG的知识库问答系统。但正如我们上次实践的结尾所言。仅仅是接入一个本地化的知识库,还是无法解决一些依赖现有系统的问题。
以优惠券为例,我们可以根据知识库设定优惠券的基本规则。但是如果涉及到具体某个优惠券的信息而言,仅凭知识库无法完成对具体数据的判断。
二、Dify的介绍与安装
Dify是什么?
用他们自己的官网(https://dify.ai/)介绍来说他们是:The Innovation Engine for GenAl Applications——它是生成式AI应用的创新引擎
Dify是GitHub的开源的项目(https://github.com/langgenius/dify)
Dify的特性
对比我们之前用到的MaxKB来说,Dify无疑是一个全面加强的生成式AI的创建引擎
他的能力不仅包含MaxKB的RAG引擎。也同时可以本地化部署,更可以建立业务场景更为复杂的Agent以及Workflow。当然这也只是Dify的主要特性。
随着我们进行安装部署后,在我们的一步步探索中,将逐步发现Dify的强大能力。
Dify的安装与部署
我们来到Dify的github主页并且clone代码到本地
https://github.com/langgenius/dify
然后在代码的根目录执行
cd dockercp .env.example .envdocker 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中。
第一个AI应用
我们再回到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
这里提供了通过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',\nYou are a text classification engine that analyzes text data and assigns categories based on user input or automatically determined categories.\n### Task\nYour 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\nThe 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\nDO NOT include anything other than the JSON array in your response.\n### Memory\nHere 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赋能”了。
53AI,企业落地应用大模型首选服务商
产品:大模型应用平台+智能体定制开发+落地咨询服务
承诺:先做场景POC验证,看到效果再签署服务协议。零风险落地应用大模型,已交付160+中大型企业
2024-11-16
通过Reranking来优化RAG:提升信息检索的精准度
2024-11-16
从RAG到TAG:探索表增强生成(TAG)的力量
2024-11-15
复旦发布:最佳RAG方案
2024-11-15
破解PDF解析难题:RAG中高效解析复杂PDF的最佳选择
2024-11-15
RAG技术全解析:从基础到前沿,掌握智能问答新动向
2024-11-15
RAG在未来会消失吗?附RAG的5种切分策略
2024-11-15
HtmlRAG:利用 HTML 结构化信息增强 RAG 系统的知识检索能力和准确性
2024-11-15
打造自己的RAG解析大模型:表格数据标注的三条黄金规则
2024-07-18
2024-07-09
2024-05-05
2024-07-09
2024-05-19
2024-06-20
2024-07-07
2024-07-07
2024-07-08
2024-07-09
2024-11-06
2024-11-06
2024-11-05
2024-11-04
2024-10-27
2024-10-25
2024-10-21
2024-10-21